Browse code

Merge branch 'files-from' into merge, pull request #116

Matt Domsch authored on 2013/05/11 23:30:10
Showing 4 changed files
... ...
@@ -96,6 +96,7 @@ class Config(object):
96 96
     website_error = ""
97 97
     website_endpoint = "http://%(bucket)s.s3-website-%(location)s.amazonaws.com/"
98 98
     additional_destinations = []
99
+    files_from = []
99 100
     cache_file = ""
100 101
     add_headers = ""
101 102
 
... ...
@@ -14,6 +14,7 @@ from HashCache import HashCache
14 14
 from logging import debug, info, warning, error
15 15
 
16 16
 import os
17
+import sys
17 18
 import glob
18 19
 import copy
19 20
 
... ...
@@ -140,7 +141,45 @@ def handle_exclude_include_walk(root, dirs, files):
140 140
         else:
141 141
             debug(u"PASS: %r" % (file))
142 142
 
143
-def fetch_local_list(args, recursive = None):
143
+
144
+def _get_filelist_from_file(cfg, local_path):
145
+    def _append(d, key, value):
146
+        if key not in d:
147
+            d[key] = [value]
148
+        else:
149
+            d[key].append(value)
150
+
151
+    filelist = {}
152
+    for fname in cfg.files_from:
153
+        if fname == u'-':
154
+            f = sys.stdin
155
+        else:
156
+            try:
157
+                f = open(fname, 'r')
158
+            except IOError, e:
159
+                warning(u"--files-from input file %s could not be opened for reading (%s), skipping." % (fname, e.strerror))
160
+                continue
161
+                
162
+        for line in f:
163
+            line = line.strip()
164
+            line = os.path.normpath(os.path.join(local_path, line))
165
+            dirname = os.path.dirname(line)
166
+            basename = os.path.basename(line)
167
+            _append(filelist, dirname, basename)
168
+        if f != sys.stdin:
169
+            f.close()
170
+
171
+    # reformat to match os.walk()
172
+    result = []
173
+    keys = filelist.keys()
174
+    keys.sort()
175
+    for key in keys:
176
+        values = filelist[key]
177
+        values.sort()
178
+        result.append((key, [], values))
179
+    return result
180
+
181
+def fetch_local_list(args, is_src = False, recursive = None):
144 182
     def _get_filelist_local(loc_list, local_uri, cache):
145 183
         info(u"Compiling list of local files...")
146 184
 
... ...
@@ -155,11 +194,15 @@ def fetch_local_list(args, recursive = None):
155 155
         if local_uri.isdir():
156 156
             local_base = deunicodise(local_uri.basename())
157 157
             local_path = deunicodise(local_uri.path())
158
-            if cfg.follow_symlinks:
159
-                filelist = _fswalk_follow_symlinks(local_path)
158
+            if is_src and len(cfg.files_from):
159
+                filelist = _get_filelist_from_file(cfg, local_path)
160
+                single_file = False
160 161
             else:
161
-                filelist = _fswalk_no_symlinks(local_path)
162
-            single_file = False
162
+                if cfg.follow_symlinks:
163
+                    filelist = _fswalk_follow_symlinks(local_path)
164
+                else:
165
+                    filelist = _fswalk_no_symlinks(local_path)
166
+                single_file = False
163 167
         else:
164 168
             local_base = ""
165 169
             local_path = deunicodise(local_uri.dirname())
... ...
@@ -271,7 +271,7 @@ def cmd_object_put(args):
271 271
     if len(args) == 0:
272 272
         raise ParameterError("Nothing to upload. Expecting a local file or directory.")
273 273
 
274
-    local_list, single_file_local = fetch_local_list(args)
274
+    local_list, single_file_local = fetch_local_list(args, is_src = True)
275 275
 
276 276
     local_list, exclude_list = filter_exclude_include(local_list)
277 277
 
... ...
@@ -726,7 +726,7 @@ def cmd_sync_remote2local(args):
726 726
     s3 = S3(Config())
727 727
 
728 728
     destination_base = args[-1]
729
-    local_list, single_file_local = fetch_local_list(destination_base, recursive = True)
729
+    local_list, single_file_local = fetch_local_list(destination_base, is_src = False, recursive = True)
730 730
     remote_list = fetch_remote_list(args[:-1], recursive = True, require_attribs = True)
731 731
 
732 732
     local_count = len(local_list)
... ...
@@ -1165,7 +1165,7 @@ def cmd_sync_local2remote(args):
1165 1165
         error(u"or disable encryption with --no-encrypt parameter.")
1166 1166
         sys.exit(1)
1167 1167
 
1168
-    local_list, single_file_local = fetch_local_list(args[:-1], recursive = True)
1168
+    local_list, single_file_local = fetch_local_list(args[:-1], is_src = True, recursive = True)
1169 1169
 
1170 1170
     destinations = [args[-1]]
1171 1171
     if cfg.additional_destinations:
... ...
@@ -1785,6 +1785,7 @@ def main():
1785 1785
     optparser.add_option(      "--rinclude", dest="rinclude", action="append", metavar="REGEXP", help="Same as --include but uses REGEXP (regular expression) instead of GLOB")
1786 1786
     optparser.add_option(      "--rinclude-from", dest="rinclude_from", action="append", metavar="FILE", help="Read --rinclude REGEXPs from FILE")
1787 1787
 
1788
+    optparser.add_option(      "--files-from", dest="files_from", action="append", metavar="FILE", help="Read list of source-file names from FILE. Use - to read from stdin.")
1788 1789
     optparser.add_option(      "--bucket-location", dest="bucket_location", help="Datacentre to create bucket in. As of now the datacenters are: US (default), EU, ap-northeast-1, ap-southeast-1, sa-east-1, us-west-1 and us-west-2")
1789 1790
     optparser.add_option(      "--reduced-redundancy", "--rr", dest="reduced_redundancy", action="store_true", help="Store object with 'Reduced redundancy'. Lower per-GB price. [put, cp, mv]")
1790 1791
 
... ...
@@ -1966,6 +1967,8 @@ def main():
1966 1966
 
1967 1967
     if options.additional_destinations:
1968 1968
         cfg.additional_destinations = options.additional_destinations
1969
+    if options.files_from:
1970
+        cfg.files_from = options.files_from
1969 1971
 
1970 1972
     ## Set output and filesystem encoding for printing out filenames.
1971 1973
     sys.stdout = codecs.getwriter(cfg.encoding)(sys.stdout, "replace")
... ...
@@ -225,6 +225,10 @@ Same as --include but uses REGEXP (regular expression) instead of GLOB
225 225
 \fB\-\-rinclude\-from\fR=FILE
226 226
 Read --rinclude REGEXPs from FILE
227 227
 .TP
228
+\fB\-\-files\-from\fR=FILE
229
+Read list of source-file names from FILE. Use - to read from stdin.
230
+May be repeated.
231
+.TP
228 232
 \fB\-\-bucket\-location\fR=BUCKET_LOCATION
229 233
 Datacentre to create bucket in. As of now the datacenters are: US (default), EU, ap-northeast-1, ap-southeast-1, sa-east-1, us-west-1 and us-west-2
230 234
 .TP