Merge lp:~mterry/duplicity/look-at-partials-during-sync into lp:duplicity/0.6

Proposed by Michael Terry
Status: Merged
Merged at revision: 761
Proposed branch: lp:~mterry/duplicity/look-at-partials-during-sync
Merge into: lp:duplicity/0.6
Diff against target: 129 lines (+29/-18)
1 file modified
duplicity-bin (+29/-18)
To merge this branch: bzr merge lp:~mterry/duplicity/look-at-partials-during-sync
Reviewer Review Type Date Requested Status
duplicity-team Pending
Review via email: mp+67375@code.launchpad.net

Description of the change

To fix bug 703142, we need to pay attention to local partial metadata files (see comment 8 in that bug).

This patch makes sure (A) that when we have a local-partial, we don't copy remote->local-final and (B) that we delete a local-final if we have a local-partial already.

It's fine to not have a local-final in these situations because clearly we got interrupted during the signature writing. Which means we still have a partial manifest hanging around, we will resume the backup, and the last volume will be re-uploaded. Thus, the signature and manifest will get re-uploaded anyway. So any remote or local-final signature at the start of the run is forgettable.

This patch also ensures that we run sync_archives() during a collection-status. But it makes sure to avoid a regression of bug 777377 by adding an argument that allows decryption or not. Without running sync_archives during a collection-status, we'd still hit bug 703142 during that operation.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'duplicity-bin'
2--- duplicity-bin 2011-06-27 11:18:01 +0000
3+++ duplicity-bin 2011-07-08 19:27:10 +0000
4@@ -815,7 +815,7 @@
5 _("Rerun command with --force option to actually delete."))
6
7
8-def sync_archive():
9+def sync_archive(decrypt):
10 """
11 Synchronize local archive manifest file and sig chains to remote archives.
12 Copy missing files from remote to local as needed to make sure the local
13@@ -824,7 +824,7 @@
14 @rtype: void
15 @return: void
16 """
17- suffixes = [".g", ".gpg", ".z", ".gz"]
18+ suffixes = [".g", ".gpg", ".z", ".gz", ".part"]
19
20 def get_metafiles(filelist):
21 """
22@@ -832,30 +832,31 @@
23 Files of interest are:
24 sigtar - signature files
25 manifest - signature files
26+ duplicity partial versions of the above
27 Files excluded are:
28 non-duplicity files
29- duplicity partial files
30
31 @rtype: list
32 @return: list of duplicity metadata files
33 """
34 metafiles = {}
35+ partials = {}
36 need_passphrase = False
37 for fn in filelist:
38 pr = file_naming.parse(fn)
39 if not pr:
40 continue
41- if pr.partial:
42- continue
43 if pr.encrypted:
44 need_passphrase = True
45 if pr.type in ["full-sig", "new-sig"] or pr.manifest:
46 base, ext = os.path.splitext(fn)
47- if ext in suffixes:
48+ if ext not in suffixes:
49+ base = fn
50+ if pr.partial:
51+ partials[base] = fn
52+ else:
53 metafiles[base] = fn
54- else:
55- metafiles[fn] = fn
56- return metafiles, need_passphrase
57+ return metafiles, partials, need_passphrase
58
59 def copy_raw(src_iter, filename):
60 """
61@@ -954,11 +955,11 @@
62
63 # get remote metafile list
64 remlist = globals.backend.list()
65- remote_metafiles, rem_needpass = get_metafiles(remlist)
66+ remote_metafiles, ignored, rem_needpass = get_metafiles(remlist)
67
68 # get local metafile list
69 loclist = globals.archive_dir.listdir()
70- local_metafiles, loc_needpass = get_metafiles(loclist)
71+ local_metafiles, local_partials, loc_needpass = get_metafiles(loclist)
72
73 # we have the list of metafiles on both sides. remote is always
74 # authoritative. figure out which are local spurious (should not
75@@ -970,11 +971,18 @@
76 local_spurious = []
77
78 for key in remote_keys:
79- if not key in local_keys:
80+ # If we lost our cache, re-get the remote file. But don't do it if we
81+ # already have a local partial. The local partial will already be
82+ # complete in this case (seems we got interrupted before we could move
83+ # it to its final location).
84+ if key not in local_keys and key not in local_partials:
85 local_missing.append(key)
86
87 for key in local_keys:
88- if not key in remote_keys:
89+ # If we have a file locally that is unnecessary, delete it. Also
90+ # delete final versions of partial files because if we have both, it
91+ # means the write of the final version got interrupted.
92+ if key not in remote_keys or key in local_partials:
93 local_spurious.append(key)
94
95 # finally finish the process
96@@ -986,8 +994,11 @@
97 if not globals.dry_run:
98 log.Notice(_("Synchronizing remote metadata to local cache..."))
99 if local_missing and (rem_needpass or loc_needpass):
100- # password for the --encrypt-key
101- globals.gpg_profile.passphrase = get_passphrase(1, "sync")
102+ if decrypt:
103+ # password for the --encrypt-key
104+ globals.gpg_profile.passphrase = get_passphrase(1, "sync")
105+ else:
106+ local_missing = [] # don't download if we can't decrypt
107 for fn in local_spurious:
108 remove_local(fn)
109 for fn in local_missing:
110@@ -1176,8 +1187,8 @@
111 check_resources(action)
112
113 # check archive synch with remote, fix if needed
114- if action not in ["collection-status"]:
115- sync_archive()
116+ decrypt = action not in ["collection-status"]
117+ sync_archive(decrypt)
118
119 # get current collection status
120 col_stats = collections.CollectionsStatus(globals.backend,
121@@ -1249,7 +1260,7 @@
122 elif action == "remove-all-but-n-full" or action == "remove-all-inc-of-but-n-full":
123 remove_all_but_n_full(col_stats)
124 elif action == "sync":
125- sync_archive(col_stats)
126+ sync_archive(True)
127 else:
128 assert action == "inc" or action == "full", action
129 # the passphrase for full and inc is used by --sign-key

Subscribers

People subscribed via source and target branches

to all changes: