← Back to team overview

duplicity-team team mailing list archive

[Merge] lp:~mterry/duplicity/giobackend-display-name-0.7 into lp:duplicity

 

Michael Terry has proposed merging lp:~mterry/duplicity/giobackend-display-name-0.7 into lp:duplicity.

Requested reviews:
  duplicity-team (duplicity-team)

For more details, see:
https://code.launchpad.net/~mterry/duplicity/giobackend-display-name-0.7/+merge/328632

I was doing some testing on the google-drive: GIO backend (this is not the gdoc: duplicity backend, but rather using GNOME's abstraction layer to talk to Google through the giobackend code) and noticed some problems.

(A) Getting a list of files was broken because this backend chooses to use internal IDs for all its filename. Only the display_name() call gets the real user-set filename. Which, OK. We can use that instead. This will work for google-drive: as well as all other backends, since that is the user-set/user-visible name that we want to work with anyway.

(B) Getting files wasn't working because we had been passing NOFOLLOW_SYMLINKS. Apparently the google-drive: backend treats all internal files as symlinks to other internal files? Doesn't matter, we can avoid having to care about what a backup does in that regard by simply not passing that flag. It was a level of precaution that we don't really need. Normally, duplicity will always be dealing with real files. If it's trying to get a symlink, it's because the user manually created one. In which case, maybe we should follow it, since the user wants us to.

Together, these fixes let google-drive: work (and maybe other similarly bizarre GIO backends). I also tested on a couple other backends (SSH and local) and they worked fine still.
-- 
Your team duplicity-team is requested to review the proposed merge of lp:~mterry/duplicity/giobackend-display-name-0.7 into lp:duplicity.
=== modified file 'CHANGELOG'
--- CHANGELOG	2017-07-20 12:06:01 +0000
+++ CHANGELOG	2017-08-05 22:24:26 +0000
@@ -1,4 +1,28 @@
+<<<<<<< TREE
 New in v0.8.00 (2016/07/??)
+=======
+New in v0.7.14 (2017/07/??)
+---------------------------
+* Merged in lp:~dawgfoto/duplicity/skip_sync_collection_status
+  - collection-status should not sync metadata
+  - up-to-date local metadata is not needed as collection-status is
+    generated from remote file list
+  - syncing metadata might require to download several GBs
+* Fixed slowness in 'collection-status' by basing the status on the
+  remote system only.  The local cache is treated as empty.
+* Fixed encrypted remote manifest handling to merely put out a non-fatal
+  error message and continue if the private key is not available.
+
+
+New in v0.7.13.1 (2017/06/18)
+-----------------------------
+* Fixed problem in dist/makedist when building on Mac where AppleDouble
+  files were being created in the tarball.  See:
+  https://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x
+
+
+New in v0.7.13 (2017/06/12)
+>>>>>>> MERGE-SOURCE
 ---------------------------
 * Merged in lp:~aaron-whitehouse/duplicity/remove-python26
   - Remove Python 2.6 support references and tests.

=== modified file 'Changelog.GNU'
--- Changelog.GNU	2017-07-20 12:06:01 +0000
+++ Changelog.GNU	2017-08-05 22:24:26 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
 2017-07-20  Kenneth Loafman  <kenneth@xxxxxxxxxxx>
 
     * Fixed encrypted remote manifest handling to merely put out a non-fatal
@@ -31,6 +32,27 @@
       - Also see https://code.launchpad.net/~dawgfoto/duplicity/replicate/+merge/322836.
 
 2017-06-19  Kenneth Loafman  <kenneth@xxxxxxxxxxx>
+=======
+2017-07-20  Kenneth Loafman  <kenneth@xxxxxxxxxxx>
+
+    * Fixed encrypted remote manifest handling to merely put out a non-fatal
+      error message and continue if the private key is not available.
+
+2017-07-18  Kenneth Loafman  <kenneth@xxxxxxxxxxx>
+
+    * Fixed slowness in 'collection-status' by basing the status on the
+      remote system only.  The local cache is treated as empty.
+
+2017-07-11  Kenneth Loafman  <kenneth@xxxxxxxxxxx>
+
+    * Merged in lp:~dawgfoto/duplicity/skip_sync_collection_status
+      - collection-status should not sync metadata
+      - up-to-date local metadata is not needed as collection-status is
+        generated from remote file list
+      - syncing metadata might require to download several GBs
+
+2017-06-18  Kenneth Loafman  <kenneth@xxxxxxxxxxx>
+>>>>>>> MERGE-SOURCE
 
     * Fixed problem in dist/makedist when building on Mac where AppleDouble
       files were being created in the tarball.  See:

=== modified file 'bin/duplicity'
--- bin/duplicity	2017-07-19 17:52:30 +0000
+++ bin/duplicity	2017-08-05 22:24:26 +0000
@@ -61,6 +61,7 @@
 from duplicity import tempdir
 from duplicity import util
 
+
 if '--pydevd' in sys.argv or os.getenv('PYDEVD', None):
     # The following is for starting remote debugging in Eclipse with Pydev.
     # Adjust the path to your location and version of Eclipse and Pydev.
@@ -1520,8 +1521,13 @@
 
     # get current collection status
     col_stats = collections.CollectionsStatus(globals.backend,
+<<<<<<< TREE
                                               globals.archive_dir_path,
                                               action).set_values()
+=======
+                                              globals.archive_dir,
+                                              action).set_values()
+>>>>>>> MERGE-SOURCE
 
     while True:
         # if we have to clean up the last partial, then col_stats are invalidated
@@ -1551,8 +1557,13 @@
                     log.Notice(_("Cleaning up previous partial %s backup set, restarting." % action))
                     last_backup.delete()
                     col_stats = collections.CollectionsStatus(globals.backend,
+<<<<<<< TREE
                                                               globals.archive_dir_path,
                                                               action).set_values()
+=======
+                                                              globals.archive_dir,
+                                                              action).set_values()
+>>>>>>> MERGE-SOURCE
                     continue
             break
         break

=== modified file 'duplicity/backends/giobackend.py'
--- duplicity/backends/giobackend.py	2017-02-20 00:05:17 +0000
+++ duplicity/backends/giobackend.py	2017-08-05 22:24:26 +0000
@@ -116,8 +116,11 @@
 
     def __copy_file(self, source, target):
         from gi.repository import Gio  # @UnresolvedImport
+        # Don't pass NOFOLLOW_SYMLINKS here. Some backends (e.g. google-drive:)
+        # use symlinks internally for all files. In the normal course of
+        # events, we never deal with symlinks anyway, just tarballs.
         source.copy(target,
-                    Gio.FileCopyFlags.OVERWRITE | Gio.FileCopyFlags.NOFOLLOW_SYMLINKS,
+                    Gio.FileCopyFlags.OVERWRITE,
                     None, self.__copy_progress, None)
 
     def _error_code(self, operation, e):
@@ -150,12 +153,18 @@
     def _list(self):
         from gi.repository import Gio  # @UnresolvedImport
         files = []
-        enum = self.remote_file.enumerate_children(Gio.FILE_ATTRIBUTE_STANDARD_NAME,
-                                                   Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
+        # We grab display name, rather than file name because some backends
+        # (e.g. google-drive:) use filesystem-specific IDs as file names and
+        # only expose the "normal" name as display names. We need the display
+        # name, because we try to parse them. If the backend does this sort of
+        # trickery, it will accept both versions of the filename, so we
+        # shouldn't get into any trouble doing this.
+        enum = self.remote_file.enumerate_children(Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+                                                   Gio.FileQueryInfoFlags.NONE,
                                                    None)
         info = enum.next_file(None)
         while info:
-            files.append(info.get_name())
+            files.append(info.get_display_name())
             info = enum.next_file(None)
         return files
 

=== modified file 'duplicity/collections.py'
--- duplicity/collections.py	2017-07-20 12:06:01 +0000
+++ duplicity/collections.py	2017-08-05 22:24:26 +0000
@@ -143,11 +143,19 @@
                                                remote_filename)
         self.remote_manifest_name = remote_filename
 
+<<<<<<< TREE
         if self.action not in ["collection-status", "replicate"]:
             local_filename_list = globals.archive_dir_path.listdir()
         else:
             local_filename_list = []
         for local_filename in local_filename_list:
+=======
+        if self.action not in ["collection-status"]:
+            local_filename_list = globals.archive_dir.listdir()
+        else:
+            local_filename_list = []
+        for local_filename in local_filename_list:
+>>>>>>> MERGE-SOURCE
             pr = file_naming.parse(local_filename)
             if (pr and pr.manifest and pr.type == self.type and
                     pr.time == self.time and
@@ -170,11 +178,19 @@
         except Exception:
             log.Debug(_("BackupSet.delete: missing %s") % [util.ufn(f) for f in rfn])
             pass
+<<<<<<< TREE
         if self.action not in ["collection-status", "replicate"]:
             local_filename_list = globals.archive_dir_path.listdir()
         else:
             local_filename_list = []
         for lfn in local_filename_list:
+=======
+        if self.action not in ["collection-status"]:
+            local_filename_list = globals.archive_dir.listdir()
+        else:
+            local_filename_list = []
+        for lfn in local_filename_list:
+>>>>>>> MERGE-SOURCE
             pr = file_naming.parse(lfn)
             if (pr and pr.time == self.time and
                     pr.start_time == self.start_time and
@@ -592,13 +608,22 @@
     """
     Hold information about available chains and sets
     """
+<<<<<<< TREE
     def __init__(self, backend, archive_dir_path, action):
+=======
+    def __init__(self, backend, archive_dir, action):
+>>>>>>> MERGE-SOURCE
         """
         Make new object.  Does not set values
         """
         self.backend = backend
+<<<<<<< TREE
         self.archive_dir_path = archive_dir_path
         self.action = action
+=======
+        self.archive_dir = archive_dir
+        self.action = action
+>>>>>>> MERGE-SOURCE
 
         # Will hold (signature chain, backup chain) pair of active
         # (most recent) chains
@@ -702,10 +727,17 @@
                   len(backend_filename_list))
 
         # get local filename list
+<<<<<<< TREE
         if self.action not in ["collection-status", "replicate"]:
             local_filename_list = self.archive_dir_path.listdir()
         else:
             local_filename_list = []
+=======
+        if self.action not in ["collection-status"]:
+            local_filename_list = self.archive_dir.listdir()
+        else:
+            local_filename_list = []
+>>>>>>> MERGE-SOURCE
         log.Debug(ngettext("%d file exists in cache",
                            "%d files exist in cache",
                            len(local_filename_list)) %
@@ -902,10 +934,17 @@
             if filelist is not None:
                 return filelist
             elif local:
+<<<<<<< TREE
                 if self.action not in ["collection-status", "replicate"]:
                     return self.archive_dir_path.listdir()
                 else:
                     return []
+=======
+                if self.action not in ["collection-status"]:
+                    return self.archive_dir.listdir()
+                else:
+                    return []
+>>>>>>> MERGE-SOURCE
             else:
                 return self.backend.list()
 

=== modified file 'po/duplicity.pot'
--- po/duplicity.pot	2017-07-20 12:06:01 +0000
+++ po/duplicity.pot	2017-08-05 22:24:26 +0000
@@ -8,7 +8,11 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: Kenneth Loafman <kenneth@xxxxxxxxxxx>\n"
+<<<<<<< TREE
 "POT-Creation-Date: 2017-07-20 06:56-0500\n"
+=======
+"POT-Creation-Date: 2017-07-20 06:47-0500\n"
+>>>>>>> MERGE-SOURCE
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -18,219 +22,220 @@
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
 
-#: ../bin/duplicity:132
+#: ../bin/duplicity:133
 msgid "Reuse configured PASSPHRASE as SIGN_PASSPHRASE"
 msgstr ""
 
-#: ../bin/duplicity:139
+#: ../bin/duplicity:140
 msgid "Reuse configured SIGN_PASSPHRASE as PASSPHRASE"
 msgstr ""
 
-#: ../bin/duplicity:178
+#: ../bin/duplicity:179
 msgid "PASSPHRASE variable not set, asking user."
 msgstr ""
 
-#: ../bin/duplicity:193
+#: ../bin/duplicity:194
 msgid "GnuPG passphrase for signing key:"
 msgstr ""
 
-#: ../bin/duplicity:198
+#: ../bin/duplicity:199
 msgid "GnuPG passphrase:"
 msgstr ""
 
-#: ../bin/duplicity:203
+#: ../bin/duplicity:204
 msgid "Retype passphrase for signing key to confirm: "
 msgstr ""
 
-#: ../bin/duplicity:205
+#: ../bin/duplicity:206
 msgid "Retype passphrase to confirm: "
 msgstr ""
 
-#: ../bin/duplicity:208
+#: ../bin/duplicity:209
 msgid "First and second passphrases do not match!  Please try again."
 msgstr ""
 
-#: ../bin/duplicity:215
+#: ../bin/duplicity:216
 msgid ""
 "Cannot use empty passphrase with symmetric encryption!  Please try again."
 msgstr ""
 
-#: ../bin/duplicity:272
+#: ../bin/duplicity:273
 #, python-format
 msgid ""
 "File %s complete in backup set.\n"
 "Continuing restart on file %s."
 msgstr ""
 
-#: ../bin/duplicity:281
+#: ../bin/duplicity:282
 #, python-format
 msgid ""
 "File %s missing in backup set.\n"
 "Continuing restart on file %s."
 msgstr ""
 
-#: ../bin/duplicity:330
+#: ../bin/duplicity:331
 #, python-format
 msgid "File %s was corrupted during upload."
 msgstr ""
 
-#: ../bin/duplicity:363
+#: ../bin/duplicity:364
 msgid ""
 "Restarting backup, but current encryption settings do not match original "
 "settings"
 msgstr ""
 
-#: ../bin/duplicity:386
+#: ../bin/duplicity:387
 #, python-format
 msgid "Restarting after volume %s, file %s, block %s"
 msgstr ""
 
-#: ../bin/duplicity:456
+#: ../bin/duplicity:457
 #, python-format
 msgid "Processed volume %d"
 msgstr ""
 
-#: ../bin/duplicity:606
+#: ../bin/duplicity:607
 msgid ""
 "Fatal Error: Unable to start incremental backup.  Old signatures not found "
 "and incremental specified"
 msgstr ""
 
-#: ../bin/duplicity:610
+#: ../bin/duplicity:611
 msgid "No signatures found, switching to full backup."
 msgstr ""
 
-#: ../bin/duplicity:624
+#: ../bin/duplicity:625
 msgid "Backup Statistics"
 msgstr ""
 
-#: ../bin/duplicity:730
+#: ../bin/duplicity:731
 #, python-format
 msgid "%s not found in archive - no files restored."
 msgstr ""
 
-#: ../bin/duplicity:734
+#: ../bin/duplicity:735
 msgid "No files found in archive - nothing restored."
 msgstr ""
 
-#: ../bin/duplicity:767
+#: ../bin/duplicity:768
 #, python-format
 msgid "Processed volume %d of %d"
 msgstr ""
 
-#: ../bin/duplicity:801
+#: ../bin/duplicity:802
 #, python-format
 msgid "Invalid data - %s hash mismatch for file:"
 msgstr ""
 
-#: ../bin/duplicity:804
+#: ../bin/duplicity:805
 #, python-format
 msgid "Calculated hash: %s"
 msgstr ""
 
-#: ../bin/duplicity:805
+#: ../bin/duplicity:806
 #, python-format
 msgid "Manifest hash: %s"
 msgstr ""
 
-#: ../bin/duplicity:844
+#: ../bin/duplicity:845
 #, python-format
 msgid "Volume was signed by key %s, not %s"
 msgstr ""
 
-#: ../bin/duplicity:876
+#: ../bin/duplicity:877
 #, python-format
 msgid "Verify complete: %s, %s."
 msgstr ""
 
-#: ../bin/duplicity:877
+#: ../bin/duplicity:878
 #, python-format
 msgid "%d file compared"
 msgid_plural "%d files compared"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../bin/duplicity:879
+#: ../bin/duplicity:880
 #, python-format
 msgid "%d difference found"
 msgid_plural "%d differences found"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../bin/duplicity:898
+#: ../bin/duplicity:899
 msgid "No extraneous files found, nothing deleted in cleanup."
 msgstr ""
 
-#: ../bin/duplicity:903
+#: ../bin/duplicity:904
 msgid "Deleting this file from backend:"
 msgid_plural "Deleting these files from backend:"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../bin/duplicity:914
+#: ../bin/duplicity:915
 msgid "Found the following file to delete:"
 msgid_plural "Found the following files to delete:"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../bin/duplicity:917
+#: ../bin/duplicity:918
 msgid "Run duplicity again with the --force option to actually delete."
 msgstr ""
 
-#: ../bin/duplicity:960
+#: ../bin/duplicity:961
 msgid "There are backup set(s) at time(s):"
 msgstr ""
 
-#: ../bin/duplicity:962
+#: ../bin/duplicity:963
 msgid "Which can't be deleted because newer sets depend on them."
 msgstr ""
 
-#: ../bin/duplicity:966
+#: ../bin/duplicity:967
 msgid ""
 "Current active backup chain is older than specified time.  However, it will "
 "not be deleted.  To remove all your backups, manually purge the repository."
 msgstr ""
 
-#: ../bin/duplicity:972
+#: ../bin/duplicity:973
 msgid "No old backup sets found, nothing deleted."
 msgstr ""
 
-#: ../bin/duplicity:975
+#: ../bin/duplicity:976
 msgid "Deleting backup chain at time:"
 msgid_plural "Deleting backup chains at times:"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../bin/duplicity:987
+#: ../bin/duplicity:988
 #, python-format
 msgid "Deleting any incremental signature chain rooted at %s"
 msgstr ""
 
-#: ../bin/duplicity:989
+#: ../bin/duplicity:990
 #, python-format
 msgid "Deleting any incremental backup chain rooted at %s"
 msgstr ""
 
-#: ../bin/duplicity:992
+#: ../bin/duplicity:993
 #, python-format
 msgid "Deleting complete signature chain %s"
 msgstr ""
 
-#: ../bin/duplicity:994
+#: ../bin/duplicity:995
 #, python-format
 msgid "Deleting complete backup chain %s"
 msgstr ""
 
-#: ../bin/duplicity:1000
+#: ../bin/duplicity:1001
 msgid "Found old backup chain at the following time:"
 msgid_plural "Found old backup chains at the following times:"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../bin/duplicity:1004
+#: ../bin/duplicity:1005
 msgid "Rerun command with --force option to actually delete."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1027
 msgid "No old backup sets found."
 msgstr ""
@@ -251,80 +256,143 @@
 msgstr ""
 
 #: ../bin/duplicity:1197
+=======
+#: ../bin/duplicity:1082
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Deleting local %s (not authoritative at backend)."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1202
+=======
+#: ../bin/duplicity:1087
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Unable to delete %s: %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1233 ../duplicity/dup_temp.py:266
+=======
+#: ../bin/duplicity:1118 ../duplicity/dup_temp.py:266
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Failed to read %s: %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1247
+=======
+#: ../bin/duplicity:1132
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Copying %s to local cache."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1295
+=======
+#: ../bin/duplicity:1180
+>>>>>>> MERGE-SOURCE
 msgid "Local and Remote metadata are synchronized, no sync needed."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1300
+=======
+#: ../bin/duplicity:1185
+>>>>>>> MERGE-SOURCE
 msgid "Synchronizing remote metadata to local cache..."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1312
+=======
+#: ../bin/duplicity:1197
+>>>>>>> MERGE-SOURCE
 msgid "Sync would copy the following from remote to local:"
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1315
+=======
+#: ../bin/duplicity:1200
+>>>>>>> MERGE-SOURCE
 msgid "Sync would remove the following spurious local files:"
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1358
+=======
+#: ../bin/duplicity:1243
+>>>>>>> MERGE-SOURCE
 msgid "Unable to get free space on temp."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1366
+=======
+#: ../bin/duplicity:1251
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Temp space has %d available, backup needs approx %d."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1369
+=======
+#: ../bin/duplicity:1254
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Temp has %d available, backup will use approx %d."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1377
+=======
+#: ../bin/duplicity:1262
+>>>>>>> MERGE-SOURCE
 msgid "Unable to get max open files."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1381
+=======
+#: ../bin/duplicity:1266
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid ""
 "Max open files of %s is too low, should be >= 1024.\n"
 "Use 'ulimit -n 1024' or higher to correct.\n"
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1432
+=======
+#: ../bin/duplicity:1317
+>>>>>>> MERGE-SOURCE
 msgid ""
 "RESTART: The first volume failed to upload before termination.\n"
 "         Restart is impossible...starting backup from beginning."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1438
+=======
+#: ../bin/duplicity:1323
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid ""
 "RESTART: Volumes %d to %d failed to upload before termination.\n"
 "         Restarting backup at volume %d."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1445
+=======
+#: ../bin/duplicity:1330
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid ""
 "RESTART: Impossible backup state: manifest has %d vols, remote has %d vols.\n"
@@ -333,7 +401,11 @@
 "         backup then restart the backup from the beginning."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1466
+=======
+#: ../bin/duplicity:1351
+>>>>>>> MERGE-SOURCE
 msgid ""
 "\n"
 "PYTHONOPTIMIZE in the environment causes duplicity to fail to\n"
@@ -343,17 +415,29 @@
 "See https://bugs.launchpad.net/duplicity/+bug/931175\n";
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1489
+=======
+#: ../bin/duplicity:1374
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Acquiring lockfile %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1547
+=======
+#: ../bin/duplicity:1432
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Last %s backup left a partial set, restarting."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1551
+=======
+#: ../bin/duplicity:1436
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Cleaning up previous partial %s backup set, restarting."
 msgstr ""
@@ -376,21 +460,37 @@
 "encryption passphrase."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1684
+=======
+#: ../bin/duplicity:1567
+>>>>>>> MERGE-SOURCE
 msgid "INT intercepted...exiting."
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1692
+=======
+#: ../bin/duplicity:1575
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "GPG error detail: %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1702
+=======
+#: ../bin/duplicity:1585
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "User error detail: %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../bin/duplicity:1712
+=======
+#: ../bin/duplicity:1595
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Backend error detail: %s"
 msgstr ""
@@ -941,142 +1041,263 @@
 msgid "Writing %s of type %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:171 ../duplicity/collections.py:185
+=======
+#: ../duplicity/collections.py:165 ../duplicity/collections.py:179
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "BackupSet.delete: missing %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:210
+=======
+#: ../duplicity/collections.py:204
+>>>>>>> MERGE-SOURCE
 msgid "Fatal Error: No manifests found for most recent backup"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:219
+=======
+#: ../duplicity/collections.py:213
+>>>>>>> MERGE-SOURCE
 msgid ""
 "Fatal Error: Remote manifest does not match local one.  Either the remote "
 "backup set or the local archive directory has been corrupted."
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:227
+=======
+#: ../duplicity/collections.py:221
+>>>>>>> MERGE-SOURCE
 msgid "Fatal Error: Neither remote nor local manifest is readable."
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:238
+=======
+#: ../duplicity/collections.py:232
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Processing local manifest %s (%s)"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:249
 #, python-format
 msgid "Error processing remote manifest (%s): %s"
 msgstr ""
 
 #: ../duplicity/collections.py:252
+=======
+#: ../duplicity/collections.py:243
+#, python-format
+msgid "Error processing remote manifest (%s): %s"
+msgstr ""
+
+#: ../duplicity/collections.py:246
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Processing remote manifest %s (%s)"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:337
+=======
+#: ../duplicity/collections.py:331
+>>>>>>> MERGE-SOURCE
 msgid "Preferring Backupset over previous one!"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:340
+=======
+#: ../duplicity/collections.py:334
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Ignoring incremental Backupset (start_time: %s; needed: %s)"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:345
+=======
+#: ../duplicity/collections.py:339
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Added incremental Backupset (start_time: %s / end_time: %s)"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:415
+=======
+#: ../duplicity/collections.py:409
+>>>>>>> MERGE-SOURCE
 msgid "Chain start time: "
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:416
+=======
+#: ../duplicity/collections.py:410
+>>>>>>> MERGE-SOURCE
 msgid "Chain end time: "
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:417
+=======
+#: ../duplicity/collections.py:411
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Number of contained backup sets: %d"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:419
+=======
+#: ../duplicity/collections.py:413
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Total number of contained volumes: %d"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:421 ../duplicity/collections.py:1225
+=======
+#: ../duplicity/collections.py:415 ../duplicity/collections.py:1219
+>>>>>>> MERGE-SOURCE
 msgid "Type of backup set:"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:421 ../duplicity/collections.py:1225
+=======
+#: ../duplicity/collections.py:415 ../duplicity/collections.py:1219
+>>>>>>> MERGE-SOURCE
 msgid "Time:"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:421
+=======
+#: ../duplicity/collections.py:415
+>>>>>>> MERGE-SOURCE
 msgid "Num volumes:"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:425 ../duplicity/collections.py:1231
+=======
+#: ../duplicity/collections.py:419 ../duplicity/collections.py:1225
+>>>>>>> MERGE-SOURCE
 msgid "Full"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:428 ../duplicity/collections.py:1233
+=======
+#: ../duplicity/collections.py:422 ../duplicity/collections.py:1227
+>>>>>>> MERGE-SOURCE
 msgid "Incremental"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:488
+=======
+#: ../duplicity/collections.py:482
+>>>>>>> MERGE-SOURCE
 msgid "local"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:490
+=======
+#: ../duplicity/collections.py:484
+>>>>>>> MERGE-SOURCE
 msgid "remote"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:646
+=======
+#: ../duplicity/collections.py:640
+>>>>>>> MERGE-SOURCE
 msgid "Collection Status"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:648
+=======
+#: ../duplicity/collections.py:642
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Connecting with backend: %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:650
+=======
+#: ../duplicity/collections.py:644
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Archive dir: %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:653
+=======
+#: ../duplicity/collections.py:647
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Found %d secondary backup chain."
 msgid_plural "Found %d secondary backup chains."
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:658
+=======
+#: ../duplicity/collections.py:652
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Secondary chain %d of %d:"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:664
+=======
+#: ../duplicity/collections.py:658
+>>>>>>> MERGE-SOURCE
 msgid "Found primary backup chain with matching signature chain:"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:668
+=======
+#: ../duplicity/collections.py:662
+>>>>>>> MERGE-SOURCE
 msgid "No backup chains with active signatures found"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:671
+=======
+#: ../duplicity/collections.py:665
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Also found %d backup set not part of any chain,"
 msgid_plural "Also found %d backup sets not part of any chain,"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:675
+=======
+#: ../duplicity/collections.py:669
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "and %d incomplete backup set."
 msgid_plural "and %d incomplete backup sets."
@@ -1084,112 +1305,196 @@
 msgstr[1] ""
 
 #. "cleanup" is a hard-coded command, so do not translate it
+<<<<<<< TREE
 #: ../duplicity/collections.py:680
+=======
+#: ../duplicity/collections.py:674
+>>>>>>> MERGE-SOURCE
 msgid "These may be deleted by running duplicity with the \"cleanup\" command."
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:683
+=======
+#: ../duplicity/collections.py:677
+>>>>>>> MERGE-SOURCE
 msgid "No orphaned or incomplete backup sets found."
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:699
+=======
+#: ../duplicity/collections.py:693
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "%d file exists on backend"
 msgid_plural "%d files exist on backend"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:709
+=======
+#: ../duplicity/collections.py:703
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "%d file exists in cache"
 msgid_plural "%d files exist in cache"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:762
+=======
+#: ../duplicity/collections.py:756
+>>>>>>> MERGE-SOURCE
 msgid "Warning, discarding last backup set, because of missing signature file."
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:785
+=======
+#: ../duplicity/collections.py:779
+>>>>>>> MERGE-SOURCE
 msgid "Warning, found the following local orphaned signature file:"
 msgid_plural "Warning, found the following local orphaned signature files:"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:794
+=======
+#: ../duplicity/collections.py:788
+>>>>>>> MERGE-SOURCE
 msgid "Warning, found the following remote orphaned signature file:"
 msgid_plural "Warning, found the following remote orphaned signature files:"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:803
+=======
+#: ../duplicity/collections.py:797
+>>>>>>> MERGE-SOURCE
 msgid "Warning, found signatures but no corresponding backup files"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:807
+=======
+#: ../duplicity/collections.py:801
+>>>>>>> MERGE-SOURCE
 msgid ""
 "Warning, found incomplete backup sets, probably left from aborted session"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:811
+=======
+#: ../duplicity/collections.py:805
+>>>>>>> MERGE-SOURCE
 msgid "Warning, found the following orphaned backup file:"
 msgid_plural "Warning, found the following orphaned backup files:"
 msgstr[0] ""
 msgstr[1] ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:828
+=======
+#: ../duplicity/collections.py:822
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Extracting backup chains from list of files: %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:839
+=======
+#: ../duplicity/collections.py:833
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "File %s is part of known set"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:842
+=======
+#: ../duplicity/collections.py:836
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "File %s is not part of a known set; creating new set"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:847
+=======
+#: ../duplicity/collections.py:841
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Ignoring file (rejected by backup set) '%s'"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:863
+=======
+#: ../duplicity/collections.py:857
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Found backup chain %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:868
+=======
+#: ../duplicity/collections.py:862
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Added set %s to pre-existing chain %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:872
+=======
+#: ../duplicity/collections.py:866
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Found orphaned set %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:1026
+=======
+#: ../duplicity/collections.py:1020
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid ""
 "No signature chain for the requested time. Using oldest available chain, "
 "starting at time %s."
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:1223
+=======
+#: ../duplicity/collections.py:1217
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "File: %s"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:1224
+=======
+#: ../duplicity/collections.py:1218
+>>>>>>> MERGE-SOURCE
 #, python-format
 msgid "Total number of backup: %d"
 msgstr ""
 
+<<<<<<< TREE
 #: ../duplicity/collections.py:1225
+=======
+#: ../duplicity/collections.py:1219
+>>>>>>> MERGE-SOURCE
 msgid "Type of file change:"
 msgstr ""
 

=== modified file 'testing/unit/test_collections.py'
--- testing/unit/test_collections.py	2017-07-19 17:52:30 +0000
+++ testing/unit/test_collections.py	2017-08-05 22:24:26 +0000
@@ -98,7 +98,11 @@
     def test_backup_chains(self):
         """Test basic backup chain construction"""
         random.shuffle(filename_list1)
+<<<<<<< TREE
         cs = collections.CollectionsStatus(None, globals.archive_dir_path, "full")
+=======
+        cs = collections.CollectionsStatus(None, globals.archive_dir, "full")
+>>>>>>> MERGE-SOURCE
         chains, orphaned, incomplete = cs.get_backup_chains(filename_list1)  # @UnusedVariable
         if len(chains) != 1 or len(orphaned) != 0:
             print(chains)
@@ -119,7 +123,11 @@
             assert cs.matched_chain_pair[0].end_time == 1029826800
             assert len(cs.all_backup_chains) == 1, cs.all_backup_chains
 
+<<<<<<< TREE
         cs = collections.CollectionsStatus(self.real_backend, globals.archive_dir_path, "full").set_values()
+=======
+        cs = collections.CollectionsStatus(self.real_backend, globals.archive_dir, "full").set_values()
+>>>>>>> MERGE-SOURCE
         check_cs(cs)
         assert cs.matched_chain_pair[0].islocal()
 
@@ -132,13 +140,21 @@
 
     def test_sig_chains(self):
         """Test making signature chains from filename list"""
+<<<<<<< TREE
         cs = collections.CollectionsStatus(None, globals.archive_dir_path, "full")
+=======
+        cs = collections.CollectionsStatus(None, globals.archive_dir, "full")
+>>>>>>> MERGE-SOURCE
         chains, orphaned_paths = cs.get_signature_chains(local=1)
         self.sig_chains_helper(chains, orphaned_paths)
 
     def test_sig_chains2(self):
         """Test making signature chains from filename list on backend"""
+<<<<<<< TREE
         cs = collections.CollectionsStatus(self.archive_dir_backend, globals.archive_dir_path, "full")
+=======
+        cs = collections.CollectionsStatus(self.archive_dir_backend, globals.archive_dir, "full")
+>>>>>>> MERGE-SOURCE
         chains, orphaned_paths = cs.get_signature_chains(local=None)
         self.sig_chains_helper(chains, orphaned_paths)
 
@@ -195,7 +211,11 @@
             p = self.output_dir.append(filename)
             p.touch()
 
+<<<<<<< TREE
         cs = collections.CollectionsStatus(self.output_dir_backend, globals.archive_dir_path, "full")
+=======
+        cs = collections.CollectionsStatus(self.output_dir_backend, globals.archive_dir, "full")
+>>>>>>> MERGE-SOURCE
         cs.set_values()
         return cs
 


References