Ghozlane TOUMI has proposed merging lp:~ghoz/duplicity/swift-prefix into 
lp:duplicity.

Requested reviews:
  duplicity-team (duplicity-team)

For more details, see:
https://code.launchpad.net/~ghoz/duplicity/swift-prefix/+merge/295017

per request from the ML :

Right now duplicity's swift backend only accept a container as target 
(swift://container)
trying to use a prefix / pseudo folder (swift://container/backup/path ) results 
in a JSON exception.

This patch adds the abiliy to use path in the swift backend, in order to have 
multiple backups to the same container neatly organized.

It borrows some code from the S3 backend, and is quite unobtrusive 
-- 
Your team duplicity-team is requested to review the proposed merge of 
lp:~ghoz/duplicity/swift-prefix into lp:duplicity.
=== modified file 'bin/duplicity.1'
--- bin/duplicity.1	2016-03-05 11:18:43 +0000
+++ bin/duplicity.1	2016-05-18 08:19:06 +0000
@@ -1175,7 +1175,7 @@
 .BR "Swift" " (Openstack)"
 .PP
 .RS
-swift://container_name
+swift://container_name[/prefix]
 .PP
 See also
 .B "A NOTE ON SWIFT (OPENSTACK OBJECT STORAGE) ACCESS"

=== modified file 'duplicity/backends/swiftbackend.py'
--- duplicity/backends/swiftbackend.py	2015-11-25 08:58:18 +0000
+++ duplicity/backends/swiftbackend.py	2016-05-18 08:19:06 +0000
@@ -90,7 +90,16 @@
 
         conn_kwargs['os_options'] = os_options
 
-        self.container = parsed_url.path.lstrip('/')
+        # This folds the null prefix and all null parts, which means that:
+        #  //MyContainer/ and //MyContainer are equivalent.
+        #  //MyContainer//My/Prefix/ and //MyContainer/My/Prefix are equivalent.
+        url_parts = [x for x in parsed_url.path.split('/') if x != '']
+
+        self.container = url_parts.pop(0)
+        if url_parts:
+            self.prefix = '%s/' % '/'.join(url_parts)
+        else:
+            self.prefix= ''
 
         container_metadata = None
         try:
@@ -118,24 +127,25 @@
                 return log.ErrorCode.backend_not_found
 
     def _put(self, source_path, remote_filename):
-        self.conn.put_object(self.container, remote_filename,
+        self.conn.put_object(self.container, self.prefix + remote_filename,
                              file(source_path.name))
 
     def _get(self, remote_filename, local_path):
-        headers, body = self.conn.get_object(self.container, remote_filename)
+        headers, body = self.conn.get_object(self.container, self.prefix + remote_filename)
         with open(local_path.name, 'wb') as f:
             for chunk in body:
                 f.write(chunk)
 
     def _list(self):
-        headers, objs = self.conn.get_container(self.container, full_listing=True)
-        return [o['name'] for o in objs]
+        headers, objs = self.conn.get_container(self.container, full_listing=True, path=self.prefix)
+        # removes prefix from return values. should check for the prefix ?
+        return [o['name'][len(self.prefix):] for o in objs]
 
     def _delete(self, filename):
-        self.conn.delete_object(self.container, filename)
+        self.conn.delete_object(self.container, self.prefix + filename)
 
     def _query(self, filename):
-        sobject = self.conn.head_object(self.container, filename)
+        sobject = self.conn.head_object(self.container, self.prefix + filename)
         return {'size': int(sobject['content-length'])}
 
 duplicity.backend.register_backend("swift", SwiftBackend)

_______________________________________________
Mailing list: https://launchpad.net/~duplicity-team
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~duplicity-team
More help   : https://help.launchpad.net/ListHelp

Reply via email to