| ... | ... |
@@ -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 |