Browse code

* s3cmd: Improved 'sync'

git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3cmd/trunk@148 830e0280-6d2a-0410-9c65-932aecc39d9d

Michal Ludvig authored on 2007/09/13 15:13:31
Showing 2 changed files
... ...
@@ -1,5 +1,6 @@
1 1
 2007-09-13  Michal Ludvig  <michal@logix.cz>
2 2
 
3
+	* s3cmd: Improved 'sync'
3 4
 	* S3/S3.py: Support for buckets with over 1000 objects.
4 5
 
5 6
 2007-09-03  Michal Ludvig  <michal@logix.cz>
... ...
@@ -176,7 +176,10 @@ def cmd_object_put(args):
176 176
 		error("object name will be prefixed to all stored filenames.")
177 177
 		sys.exit(1)
178 178
 	
179
+	seq = 0
180
+	total = len(args)
179 181
 	for file in args:
182
+		seq += 1
180 183
 		uri_arg_final = str(uri)
181 184
 		if len(args) > 1 or uri.object() == "":
182 185
 			uri_arg_final += os.path.basename(file)
... ...
@@ -187,8 +190,9 @@ def cmd_object_put(args):
187 187
 		if Config().encrypt:
188 188
 			exitcode, real_filename, extra_headers["x-amz-meta-s3tools-gpgenc"] = gpg_encrypt(file)
189 189
 		response = s3.object_put_uri(real_filename, uri_final, extra_headers)
190
-		output("File '%s' stored as %s (%d bytes)" %
191
-			(file, uri_final, response["size"]))
190
+		output("File '%s' stored as %s (%d bytes) [%d of %d]" %
191
+			(file, uri_final, response["size"],
192
+			seq, total))
192 193
 		if Config().acl_public:
193 194
 			output("Public URL of the object is: %s" %
194 195
 				(uri.public_url()))
... ...
@@ -261,6 +265,8 @@ def cmd_sync(agrs):
261 261
 	if S3Uri(src).type != "file":
262 262
 		raise ParameterError("Source must be a local path instead of: %s" % src)
263 263
 	dst = args.pop(0)
264
+	if not dst.endswith('/'):
265
+		dst += "/"
264 266
 	dst_uri = S3Uri(dst)
265 267
 	if dst_uri.type != "s3":
266 268
 		raise ParameterError("Destination must be a S3 URI instead of: %s" % dst)
... ...
@@ -279,6 +285,10 @@ def cmd_sync(agrs):
279 279
 			full_name = os.path.join(root, f)
280 280
 			if not os.path.isfile(full_name):
281 281
 				continue
282
+			if os.path.islink(full_name):
283
+				## Synchronize symlinks... one day
284
+				## for now skip over
285
+				continue
282 286
 			file = full_name[loc_base_len:]
283 287
 			sr = os.stat_result(os.lstat(full_name))
284 288
 			loc_list[file] = {
... ...
@@ -287,6 +297,7 @@ def cmd_sync(agrs):
287 287
 				'mtime' : sr.st_mtime,
288 288
 				## TODO: Possibly more to save here...
289 289
 			}
290
+	loc_count = len(loc_list)
290 291
 	
291 292
 	output("Retrieving list of remote files...")
292 293
 	response = s3.bucket_list(dst_uri.bucket(), prefix = dst_uri.object())
... ...
@@ -294,14 +305,17 @@ def cmd_sync(agrs):
294 294
 	rem_base = dst_uri.object()
295 295
 	rem_base_len = len(rem_base)
296 296
 	rem_list = {}
297
+	rem_count = len(response['list'])
297 298
 	for object in response['list']:
298
-		key = object['Key'][rem_base_len:]
299
+		key = object['Key'][rem_base_len:].encode('utf-8')
299 300
 		rem_list[key] = { 
300 301
 			'size' : int(object['Size']),
301 302
 			# 'mtime' : dateS3toUnix(object['LastModified']), ## That's upload time, not our lastmod time :-(
302 303
 			'md5' : object['ETag'][1:-1],
303
-			'object_key' : object['Key'],
304
+			'object_key' : object['Key'].encode('utf-8'),
304 305
 		}
306
+	output("Found %d local files, %d remote files" % (loc_count, rem_count))
307
+
305 308
 	output("Verifying checksums...")
306 309
 	for file in loc_list.keys():
307 310
 		debug("Checking %s ..." % file)
... ...
@@ -328,22 +342,27 @@ def cmd_sync(agrs):
328 328
 			del(rem_list[file])
329 329
 
330 330
 	output("Summary: %d local files to upload, %d remote files to delete" % (len(loc_list), len(rem_list)))
331
-	if cfg.delete_removed:
332
-		for file in rem_list:
333
-			uri = S3Uri("s3://" + dst_uri.bucket()+"/"+rem_list[file]['object_key'])
331
+	for file in rem_list:
332
+		uri = S3Uri("s3://" + dst_uri.bucket()+"/"+rem_list[file]['object_key'])
333
+		if cfg.delete_removed:
334 334
 			response = s3.object_delete_uri(uri)
335
-			output("%s deleted" % uri)
335
+			output("deleted '%s'" % uri)
336
+		else:
337
+			output("not-deleted '%s'" % uri)
336 338
 
337 339
 	total_size = 0
340
+	total_count = len(loc_list)
341
+	seq = 0
338 342
 	dst_base = dst_uri.uri()
339 343
 	if not dst_base[-1] == "/": dst_base += "/"
340 344
 	file_list = loc_list.keys()
341 345
 	file_list.sort()
342 346
 	for file in file_list:
347
+		seq += 1
343 348
 		src = loc_list[file]['full_name']
344 349
 		uri = S3Uri(dst_base + file)
345 350
 		response = s3.object_put_uri(src, uri)
346
-		output("%s stored as %s (%d bytes)" % (src, uri, response["size"]))
351
+		output("stored '%s' as '%s' (%d bytes) [%d of %d]" % (src, uri, response["size"], seq, total_count))
347 352
 		total_size += response["size"]
348 353
 	output("Done. Uploaded %d bytes." % total_size)
349 354