o `+H@sdZddlmZddlmZddlmZddlZddlZddlmZddlm Z ddlmZddlm Z Gd d d e Z Gd d d eZ Gd dde ZGdddeZedZddZddZddZdS)z-Create and edit manifest for session contents)map)range)objectN)config)log)utilc@eZdZdZdS) ManifestErrorz5 Exception raised when problem with manifest N__name__ __module__ __qualname____doc__rr4/usr/lib/python3/dist-packages/duplicity/manifest.pyr %r c@s~eZdZdZdddZddZddZd d Zd d Zd dZ ddZ e Z ddZ ddZ ddZddZddZddZdS)Manifestz8 List of volumes and information about each one NcCs"d|_d|_i|_||_g|_dS)z Create blank Manifest @param fh: fileobj for manifest @type fh: DupPath @rtype: Manifest @return: manifest N)hostname local_dirnamevolume_info_dictfh files_changed)selfrrrr__init__0s   zManifest.__init__cCsTtj|_tjj|_|jr(|jr|jd|j|jr(|jdt|j|S)z Set information about directory from config, and write to manifest file. @rtype: Manifest @return: manifest Hostname %s Localdir %s ) rr local_pathnamerrwriteencodeQuoterrrr set_dirinfo@s zManifest.set_dirinfocCstjrdS|jr1|jtjkr1|jtjkr1tdtj|jf}tjj}dt tjt |jf}n+|j rZ|j tj j krZtdtj j |j f}tjj }dt tj j t |j f}ndSt|dtd||dS)z Return None if dirinfo is the same, otherwise error message Does not raise an error message if hostname or local_dirname are not available. @rtype: string @return: None or error message NzWFatal Error: Backup source host has changed. Current hostname: %s Previous hostname: %sz%s %sz^Fatal Error: Backup source directory has changed. Current directory: %s Previous directory: %sz zAborting because you may have accidentally tried to backup two different data sets to the same remote location, or using the same archive directory. If this is not a mistake, use the --allow-source-mismatch switch to avoid seeing this message)rallow_source_mismatchrfqdn_r ErrorCodehostname_mismatchrescaperrrsource_dir_mismatch FatalError)rerrmsgcode code_extrarrr check_dirinfoQs0       zManifest.check_dirinfocCsZ|r||_|jr)|jdt|j|jD]}|jd|dt|dfqdSdS)N Filelist %d %-7s %s r)rrrlenr )rrfileinforrrset_files_changed_info{s "zManifest.set_files_changed_infocCs2|j}||j|<|jr|j|ddSdS)z Add volume info vi to manifest and write to manifest @param vi: volume info to add @type vi: VolumeInfo @return: void  N) volume_numberrrr to_string)rvivol_numrrradd_volume_infos  zManifest.add_volume_infocCs,z|j|=WdStytd|fw)z Remove volume vol_num from the manifest @param vol_num: volume number to delete @type vi: int @return: void z!Volume %d not present in manifestN)r Exceptionr )rr9rrrdel_volume_infos   zManifest.del_volume_infocsd}jr|dj7}jr|dtj7}|dtj7}jD]}|d|dt|df7}q&tj}| fdd }d |d t ||f}|S) z Return string version of self (just concatenate vi strings) @rtype: string @return: self in string form rrr/r0r1rcsj|SN)rr7)r9r!rrvol_num_to_stringsz-Manifest.to_string..vol_num_to_strings%s%s r5) rrrr r2rlistrkeyssortjoinr)rresultr3 vol_num_listr?rr!rr7s  zManifest.to_stringc sfdd}|d|_|jdur|j|_|d|_d}d}tdtj}|}|D]!}t| d}| ||j }t ||}t td |q-t|d|dD]} || qXt td |d} tjdurtd tjtjB} | }|rt| d } | dkrd d} tt| | dd|_| t|jkrt td|jr|jjnd| t|jfd|_ |S)z< Initialize self from string s, return self cs<t|ts |}td|tj}|sdSt|dS)zW Return the value of a field by parsing s, or None if no field s(^|\n)%s\s(.*?) N) isinstancebytesrresearchIUnquotegroup) fieldnamemsrr get_fields z'Manifest.from_string..get_fieldrNlocaldirrs.(?:^|\n)(volume\s.*(?:\n.*)*?)(?=\nvolume\s|$)r1zFound manifest volume %szFound %s volumes in manifests-(^|\n)filelist\s([0-9]+)\n(.*?)(\nvolume\s|$)rFcSs&|}|dd|ddfS)Nrr=r1)stripsplitrC)liner3rrrparse_fileinfos z,Manifest.from_string..parse_fileinfor5zHManifest file '%s' is corrupt: File count says %d, File list contains %dT)!rdecoderrIcompilerKfinditer VolumeInfo from_stringrMr:r6maxrDebugr%rr<Infor file_changedSrJintr@rrUrr2Errorrbasecorrupt_filelist) rrQrR highest_vol latest_vol vi_regexp vi_iteratormatchr8i filecountfilelist_regexprWrrPrr^sB          zManifest.from_stringcCs|jSr>)rr!rrrget_files_changedszManifest.get_files_changedcCst|j}|t|j}|||kr#ttddStt|D]}||||ks=ttddSq)|j |j ksJ|j |j krSttddSdS)zO Two manifests are equal if they contain the same volume infos z4Manifests not equal because different volume numbersFz/Manifests not equal because volume lists differz7Manifests not equal because hosts or directories differT) r@rrArBrNoticer%rr2rr)rothervi_list1vi_list2rmrrr__eq__s"  zManifest.__eq__cC || S)zN Defines !=. Not doing this always leads to annoying bugs... rurrrrrr__ne__ zManifest.__ne__cCs<|rJ|d}|||rJ|dS)z@ Write string version of manifest to given path wbN)existsopenrr7closesetdata)rpathfoutrrr write_to_paths    zManifest.write_to_pathcsHtdkrtddjrdffddtjDS)zM Return list of volume numbers that may contain index_prefix r1rrYcs g|] }j|r|qSr)rcontains).0r9 index_prefixrrr *s z3Manifest.get_containing_volumes..)r2rG __class__rr@rrA)rrrrrget_containing_volumes$szManifest.get_containing_volumesr>)r r r rrr"r.r4r:r<r7__str__r^rpruryrrrrrrr,s  * < rc@r)VolumeInfoErrorzN Raised when there is a problem initializing a VolumeInfo from string Nr rrrrr.rrc@s^eZdZdZddZddZddZdd Zd d ZeZ d d Z ddZ ddZ dddZ dS)r]z+ Information about a single volume cCs(d|_d|_d|_d|_d|_i|_dS)zVolumeInfo initializerN)r6 start_index start_block end_index end_blockhashesr!rrrr9s  zVolumeInfo.__init__cCs"||_||_||_||_||_|S)z Set essential VolumeInfo information, return self Call with starting and ending paths stored in the volume. If a multivol diff gets split between volumes, count it as being part of both volumes. )r6rrrr)r vol_numberrrrrrrrset_infoBs  zVolumeInfo.set_infocCs2t|tr |}t|tr|}||j|<dS)zF Set the value of hash hash_name (e.g. "MD5") to data N)rGrHrZr)r hash_namedatarrrset_hashTs  zVolumeInfo.set_hashcCsd|jsdSzd|jdfWStyYnwzd|jdfWSty(Ynwt|jdS)z Return pair (hash_type, hash_data) SHA1 is the best hash, and MD5 is the second best hash. None is returned if no hash is available. NSHA1MD5r)rKeyErrorr@itemsr!rrr get_best_hash^s  zVolumeInfo.get_best_hashcCsdd}dd}d|jg}d}|d|||j||jf|d|||j||jf|jD]}|d |||j|fq3d |S) zJ Return nicely formatted string reporting all information cSs|r d|}t|SdS)z8Return printable version of index without any whitespace/.)rCr )indexrQrrrindex_to_stringus z-VolumeInfo.to_string..index_to_stringcSs|durdSt|S)N )strr)xrrrbfmt}s z"VolumeInfo.to_string..bfmts Volume %d:s s%sStartingPath %s %ss%sEndingPath %s %ss %sHash %s %sr5) r6appendrrrrrrrC)rrrslist whitespacekeyrrrr7qs   zVolumeInfo.to_stringc CsVdd}|d}td|dtj}|s td|dft|d|_|ddD]l}|s3q.|}|d }|dd}|d krRt t d nI|d kro||d|_ t|dkrkt|d|_q.d|_q.|d kr||d|_t|dkrt|d|_q.d|_q.|d kr||d|dq.|j dus|jdurtd|S)zG Initialize self from string s as created by to_string cSs"t|}|dkr dSt|dS)z8 Return tuple index from string rrr)rLtuplerUrPrrrstring_to_indexsz/VolumeInfo.from_string..string_to_indexr5s^Volume ([0-9]+):rzBad first line '%s'r1NsVolumez&Warning, found extra Volume identifiers startingpaths endingpathshashzStart or end index not set)rTrUrIrJrKrrdrMr6lowerrWarnr%rr2rrrr) rrQrlinelistrOrV line_split field_name other_fieldsrrrr^s>      zVolumeInfo.from_stringcCst|tsttddS|j|jkrttddS|j|jkr,ttddS|j|jkr;ttddSt|j }| t|j }| ||kr^ttddSdS)z$ Used in test suite zOther is not VolumeInfoNzVolume numbers don't matchzstart_indicies don't matchzend_index don't matchzHashes don't matchr1) rGr]rrqr%r6rrr@rrrB)rrr hash_list1 hash_list2rrrrus(    zVolumeInfo.__eq__cCrv)z Defines != rwrxrrrryrzzVolumeInfo.__ne__r1cCsH|r|jdt||ko|jkSS|j|ko!|jkSS)a Return true if volume might contain index If recursive is true, then return true if any index starting with index_prefix could be contained. Otherwise, just check if index_prefix itself is between starting and ending indicies. N)rr2r)rr recursiverrrrs  zVolumeInfo.containsN)r1)r r r rrrrrr7rr^ruryrrrrrr]5s  2r]s (\s|[\\"'])cCslt|s|Sg}tdt|D]}|||d}t|r)|dt|q||qdd|S)zM Return quoted version of s safe to put in a manifest or volume info rr1s\x%02xs"%s"r=)nonnormal_char_rerJrr2rordrC)rQrrmcharrrrr s   r cCstjjdkr t|S|S)NrX)sys version_infomajorchr)chrrr maybe_chrs rcCst|ddkrt|ddkr|S|d|dksJg}d}|t|dkr|||d}|dkrut||ddks@Jtjjdkr^|t||d |d d jdd d n|t t||d |d d |d 7}n |||d7}|t|dks(d |S)zE Return original string from quoted_string produced by above r"'r1\rrXrFbig) byteorderr=) rr2rrrrrdrZto_bytesrrC) quoted_string return_listrmrrrrrL s"  0$   rL)rbuiltinsrrrrIr duplicityrrrr;r rrr]r[rr rrLrrrrs*        <