
    Jj              
       R   d Z ddlZddlZddlZddlZddlZej                            ej                            e	                    Z
ej                            e
          Zej                            de
           ej                            ed          ZdZ ej        d          ZdZd Zd Zd	 Zd"dZd Zed
fdZd Zd#dZd$dZedk    rddlZ eej                   dk    rej         d         ndZ!e!dk    rI e            D ]<Z" e#de"d         e"d         dz  e"d         $                    dd          fz             =dS e!dk    r9 eej                   dk     r e#d           dS  eej         d                     dS e!d!k    r e             dS  e             dS dS )%aQ  
PLANNING TEAM - sauvegarde de la base.

La base tient dans un seul fichier, mais le copier pendant que le serveur ecrit
donnerait une copie corrompue. On passe donc par l'API `backup` de SQLite, qui produit
une copie coherente meme si l'outil est en train de servir des pages.

Une copie par jour, gardee 30 jours, dans le dossier `sauvegardes`. Il est dans le
projet, donc Dropbox l'emporte aussi dans le cloud.

Toute sauvegarde est **verifiee** juste apres avoir ete ecrite : controle d'integrite
SQLite et comptage des lignes. Une sauvegarde qu'on n'a pas relue n'est pas une
sauvegarde.
    Nsauvegardes   z?^(planning|avant-restauration)-(\d{4}-\d{2}-\d{2})-(\d{6})\.db$)salariecreneau_typeabsencecp_soldecp_ajustementheures_ajustementdemandecomptec                      t           j                            t                    st          j        t                     t          S )N)ospathisdirDOSSIERmakedirs     (/opt/planning-team/travail/sauvegarde.py_dossierr   )   s-    7==!! 
GNr   c                     t          j        |           	 d                     d          D             fdt          D                                              S #                                  w xY w)zI{ table : nombre de lignes } d'une base, en ignorant les tables absentes.c                     h | ]
}|d          S )r   r   ).0ls     r   	<setcomp>z_compter.<locals>.<setcomp>3   s.     D D DaQqT D D Dr   z3SELECT name FROM sqlite_master WHERE type = 'table'c                 z    i | ]7}|v |                     d |z                                            d         8S )zSELECT COUNT(*) FROM %sr   )executefetchone)r   tcx	presentess     r   
<dictcomp>z_compter.<locals>.<dictcomp>5   sN     ; ; ;1	>> 2::7!;<<EEGGJ+9>>r   )sqlite3connectr   TABLES_SUIVIESclose)cheminr    r!   s    @@r   _compterr(   /   s    		 	 BD D2::A$C $C D D D	; ; ; ; ;'; ; ; 	







s   2A A5c                 0   t          j        |           }	 |                    d                                          d         }|                                 n# |                                 w xY w|dk    rt          d|z            t          |           S )zRRelit une sauvegarde : integrite SQLite et comptage. Leve si quelque chose cloche.zPRAGMA integrity_checkr   okzsauvegarde corrompue : %s)r#   r$   r   r   r&   IOErrorr(   )r'   r    verdicts      r   verifierr-   ;   s    		 	 B**566??AA!D








$2W<===Fs   -A A.Tplanningc                    ddl }| p|j        } t          j                            |           st          d| z            t          j                                        }|d|                    d          d}t          j        	                    t                      |          }d}t          j                            |          rit          j        	                    t                      d||                    d          |fz            }|d	z  }t          j                            |          it          j        |           }t          j        |          }		 |                    |	           |	                                 |                                 n-# |	                                 |                                 w xY wt          |          t!          |           fd
D             }
|
rt          d|
z            |rot#          dt          j                            |          dd	                    d t'                                                    D                       d           |t          j                            |          |                    d          t          j                            |          dS )a  
    Copie la base a chaud, puis relit la copie. Renvoie le chemin et le comptage.

    Le fichier n'ecrase jamais un fichier existant : si le nom est deja pris, on ajoute
    un suffixe. Ecraser une sauvegarde serait le pire des defauts pour un outil de
    sauvegarde.
    r   Nzbase introuvable : %s-z%Y-%m-%d-%H%M%Sz.db   z%s-%s-%d.db   c                     i | ]?}                     |          |         k    !||                              |          f@S r   )get)r   r   attenduscomptess     r   r"   zsauvegarder.<locals>.<dictcomp>g   sS     E E Egkk!nn&C&C Xa['++a..1&C&C&Cr   u/   la sauvegarde ne correspond pas à la base : %su#   Sauvegarde écrite et vérifiée : z (z, c              3   *   K   | ]\  }}d ||fz  V  dS )z%s %dNr   )r   r   ns      r   	<genexpr>zsauvegarder.<locals>.<genexpr>o   s/      PP17aV+PPPPPPr   )seconds)timespec)r'   nomquandoctetslignes)base	CHEMIN_DBr   r   existsr+   datetimenowstrftimejoinr   r#   r$   backupr&   r-   r(   printbasenamesorteditems	isoformatgetsize)sourcebavardprefixebd
maintenantr=   cibler8   originecopie	manquantsr5   r6   s              @@r   sauvegarderrX   G   s    #r|F7>>&!! 9.7888"&&((J!4!45F!G!G!G!G
HCGLLS))E	A
'..

 XZZ ')<)<=N)O)OQRS*T U U	Q '..

 
 of%%GOE""Eu 	uooGHE E E E E"E E EI XJYVWWW S!!%((((PPw}}8O8OPPPPPPPR 	S 	S 	S BG$4$4U$;$;))9)==gooe,,A A As   F *Gc                  n   t           j                            t                    sg S g } t          j        t                    D ]}t
                              |          }|st           j                            t          |          }|                    d          }| 	                    |||                    d          |                    d          d|dd         d|dd         d|dd         t           j        
                    |          d           |                     d	 d
           | S )zALes sauvegardes presentes, de la plus recente a la plus ancienne.   r2   r1   TN:   )r=   r'   genrer>   r?   c                     | d         S )Nr=   r   )ss    r   <lambda>zliste.<locals>.<lambda>   s
    % r   T)keyreverse)r   r   r   r   listdirMOTIFmatchrG   groupappendrN   sort)resultatr=   mr'   heures        r   listerm   u   s   7==!! 	Hz'"" 
 
KK 	gs++

&1771::&'ggajjjj%)))U1Q3ZZZqrrSgoof--
 
 	 	 	 	
 MM(($M777Or   c                    t           j                                        t          j        |           z
                                  }g }t                      D ]K}|d         dd         |k     r5t          j        |d                    |                    |d                    L|r#|r!t          d| t          |          fz             |S )zDSupprime les sauvegardes plus vieilles que la duree de conservation.)daysr>   N
   r'   r=   u,   Sauvegardes purgées (plus de %d jours) : %d)rD   datetoday	timedeltarM   rm   r   removerh   rI   len)garde_joursrP   limite	supprimesr`   s        r   purgerry      s    m!!##h&8k&J&J&JJUUWWFIWW ' 'W:crc?V##Iak"""QuX&&& /) /?c)nn-. 	/ 	/ 	/r   c                       t           j                                                                         t	           fdt                      D                       S )Nc              3   X   K   | ]$}|d          dd         k    o|d         dk    V  %dS )r>   Nrp   r^   r.   r   )r   r`   
aujourdhuis     r   r9   z+sauvegarde_du_jour_faite.<locals>.<genexpr>   sV       ! ! z#2#*,I7z1I ! ! ! ! ! !r   )rD   rq   rr   rM   anyrm   )r|   s   @r   sauvegarde_du_jour_faiter~      s^    $$&&0022J ! ! ! !! ! ! ! ! !r   c                 f    t                      rdS t          |           }t          |            |S )z@Une seule sauvegarde par jour : appelee au demarrage du serveur.N)rP   )r~   rX   ry   )rP   rj   s     r   sauvegarde_quotidienner      s;    !! t&)))H
&Or   c                    ddl }|p|j        }t          j                            t
          t          j                            |                     }t          j                            |          st          d| z            t          |           d}t          j                            |          rt          |dd          d         }t          j        |          }t          j        |          }	 |                    |           |                                 |                                 n-# |                                 |                                 w xY wt          |          }|r3t!          dt          j                            |          d	|d
           t          j                            |          ||dS )u   
    Remet une sauvegarde en place. La base actuelle est d'abord copiee de cote — on ne
    remplace jamais des donnees sans en garder une trace.
    r   Nzsauvegarde introuvable : %sFzavant-restauration)rP   rQ   r=   zRestauration faite depuis u1   . La base précédente a été sauvegardée sous .)	restaureebase_precedenter@   )rA   rB   r   r   rG   r   rJ   rC   r+   r-   rX   r#   r$   rH   r&   r(   rI   )	r=   rO   rP   rR   r'   avantrU   rT   r6   s	            r   	restaurerr      s   
 #r|FW\\'27#3#3C#8#899F7>>&!! <4s:;;;V E	w~~f WF5:NOOOPUVof%%GOF##Eu 	vG N,.G,<,<V,D,D,D,DeeeM 	N 	N 	N))&11e  s   2D0 0*E__main__r2   rX   rm   z%-28s %8.1f Ko  %sr=   r?   g      @r>   r[    r   rZ   z0usage : sauvegarde.py restaurer <nom-du-fichier>r1   ry   )NTr.   )T)NT)%__doc__rD   r   rer#   sysr   dirnameabspath__file__BASEPROJETinsertrG   r   GARDE_JOURScompilere   r%   r   r(   r-   rX   rm   ry   r~   r   r   __name__rA   rR   ru   argvactionr`   rI   replacer   r   r   <module>r      s     				 				  



	wrwx0011			 4   
',,v}
-
- 	
UVV<  	 	 		 	 	+A +A +A +A\  ( #4    ! ! !      D zCMMA--SXa[[=F 	T 	TAE'uXq{V3QwZ5G5GS5Q5QRS T T T T	T 	T 
;		3sx==1EEFFFFFIchqk"""""	8		# r   