← Back to team overview

duplicity-team team mailing list archive

[Merge] lp:~horgh/duplicity/copy-symlink-targets-721599 into lp:duplicity

 

Will Storey has proposed merging lp:~horgh/duplicity/copy-symlink-targets-721599 into lp:duplicity.

Requested reviews:
  duplicity-team (duplicity-team)

For more details, see:
https://code.launchpad.net/~horgh/duplicity/copy-symlink-targets-721599/+merge/312438

Hello,

I recently started using duplicity. I have a directory with many symlinks in it. I was hoping to be able to back the data up while dereferencing the symlinks as that is easier for my use case.

I see there is a bug report requesting such behaviour: https://bugs.launchpad.net/duplicity/+bug/721599

I understand why by design it would be acceptable to not dereference symlinks, but I think it can be useful to provide a flag to do it.

My solution is to add a flag called --copy-links. rsync has a flag with this name so that is why I picked the naem. This is rsync's brief description for it: "--copy-links transform symlink into referent file/dir".

I found that it was sufficient to change the os.lstat() call in path.py to os.stat() when this flag is enabled so that duplicity no longer actually sees symlinks. I did wonder if this is an acceptable place for it though, as path.py seems fairly low level to be worried about globals. But I saw elsewhere in this file and class that we access globals.

I've found that backup and restore behaviour works fine in manually tests with this update. If I run a second backup without the flag given, then the backed up version updates to hold the symlink, and vice versa.

I've not updated any documentation or anything yet as I thought I should get feedback whether this will be acceptable, and whether this approach is okay.

Please let me know if you have any thoughts on this or improvements I can make.

Thank you for your time!
-- 
Your team duplicity-team is requested to review the proposed merge of lp:~horgh/duplicity/copy-symlink-targets-721599 into lp:duplicity.
=== modified file 'duplicity/commandline.py'
--- duplicity/commandline.py	2016-11-21 17:06:39 +0000
+++ duplicity/commandline.py	2016-12-05 05:25:53 +0000
@@ -290,6 +290,10 @@
     parser.add_option("--config-dir", type="file", metavar=_("path"),
                       help=optparse.SUPPRESS_HELP)
 
+    # When symlinks are encountered, the item they point to is copied rather than
+    # the symlink.
+    parser.add_option("--copy-links", action="store_true")
+
     # for testing -- set current time
     parser.add_option("--current-time", type="int",
                       dest="current_time", help=optparse.SUPPRESS_HELP)

=== modified file 'duplicity/globals.py'
--- duplicity/globals.py	2016-11-21 17:06:39 +0000
+++ duplicity/globals.py	2016-12-05 05:25:53 +0000
@@ -274,6 +274,10 @@
 # enable data comparison on verify runs
 compare_data = False
 
+# When symlinks are encountered, the item they point to is copied rather than
+# the symlink.
+copy_links = False
+
 # When selected, triggers a dry-run before a full or incremental to compute
 # changes, then runs the real operation and keeps track of the real progress
 progress = False

=== modified file 'duplicity/path.py'
--- duplicity/path.py	2016-07-24 12:30:45 +0000
+++ duplicity/path.py	2016-12-05 05:25:53 +0000
@@ -517,7 +517,12 @@
     def setdata(self):
         """Refresh stat cache"""
         try:
-            self.stat = os.lstat(self.name)
+            # We may be asked to look at the target of symlinks rather than
+            # the link itself.
+            if globals.copy_links:
+                self.stat = os.stat(self.name)
+            else:
+                self.stat = os.lstat(self.name)
         except OSError as e:
             err_string = errno.errorcode[e[0]]
             if err_string in ["ENOENT", "ENOTDIR", "ELOOP", "ENOTCONN"]:


Follow ups