From 26ecec0f6dec1b9fd2c91ffd0f642685b1b155a0 Mon Sep 17 00:00:00 2001
From: Taurus Cheung <Taurus.Cheung@harmonicinc.com>
Date: Fri, 13 Dec 2013 10:57:23 +0800
Subject: [PATCH] Add --object-name

Add parameter --object-name, which:
1) Sets target object name when upload single file
2) Sets object prefix when upload a directory

Change-Id: Idc4357c3355e66d31c100540b901e70db20b03c3
Closes-Bug: 1012979
---
 bin/swift            | 46 +++++++++++++++++++++++++++++++++-----------
 doc/manpages/swift.1 |  4 +++-
 2 files changed, 38 insertions(+), 12 deletions(-)

diff --git a/bin/swift b/bin/swift
index b61f47d0..ec712bba 100755
--- a/bin/swift
+++ b/bin/swift
@@ -762,6 +762,7 @@ st_upload_options = '''[--changed] [--segment-size <size>]
                     [--segment-container <container>] [--leave-segments]
                     [--object-threads <thread>] [--segment-threads <threads>]
                     [--header <header>] [--use-slo]
+                    [--object-name <object-name>]
                     <container> <file_or_directory>
 '''
 
@@ -798,6 +799,10 @@ Optional arguments:
   --use-slo             When used in conjunction with --segment-size will
                         create a Static Large Object instead of the default
                         Dynamic Large Object.
+  --object-name <object-name>
+                        Upload file and name object to <object-name> or upload
+                        dir and use <object-name> as object prefix instead of
+                        folder name
 '''.strip('\n')
 
 
@@ -838,6 +843,9 @@ def st_upload(parser, args, thread_manager):
         help='When used in conjunction with --segment-size will '
         'create a Static Large Object instead of the default '
         'Dynamic Large Object.')
+    parser.add_option(
+        '', '--object-name', dest='object_name',
+        help='Upload file and name object to the name specified')
     (options, args) = parse_args(parser, args)
     args = args[1:]
     if len(args) < 2:
@@ -872,12 +880,17 @@ def st_upload(parser, args, thread_manager):
         path = job['path']
         container = job.get('container', args[0])
         dir_marker = job.get('dir_marker', False)
+        object_name = job['object_name']
         try:
-            obj = path
-            if obj.startswith('./') or obj.startswith('.\\'):
-                obj = obj[2:]
-            if obj.startswith('/'):
-                obj = obj[1:]
+            if object_name is not None:
+                object_name.replace("\\", "/")
+                obj = object_name
+            else:
+                obj = path
+                if obj.startswith('./') or obj.startswith('.\\'):
+                    obj = obj[2:]
+                if obj.startswith('/'):
+                    obj = obj[1:]
             put_headers = {'x-object-meta-mtime': "%f" % getmtime(path)}
             if dir_marker:
                 if options.changed:
@@ -1045,17 +1058,22 @@ def st_upload(parser, args, thread_manager):
                 raise
             thread_manager.error('Local file %r not found', path)
 
-    def _upload_dir(path, object_queue):
+    def _upload_dir(path, object_queue, object_name):
         names = listdir(path)
         if not names:
-            object_queue.put({'path': path, 'dir_marker': True})
+            object_queue.put({'path': path, 'object_name': object_name,
+                             'dir_marker': True})
         else:
             for name in listdir(path):
                 subpath = join(path, name)
+                subobjname = None
+                if object_name is not None:
+                    subobjname = join(object_name, name)
                 if isdir(subpath):
-                    _upload_dir(subpath, object_queue)
+                    _upload_dir(subpath, object_queue, subobjname)
                 else:
-                    object_queue.put({'path': subpath})
+                    object_queue.put({'path': subpath,
+                                     'object_name': subobjname})
 
     create_connection = lambda: get_conn(options)
     conn = create_connection()
@@ -1085,6 +1103,12 @@ def st_upload(parser, args, thread_manager):
             'Error trying to create container %r: %s', args[0],
             err)
 
+    if options.object_name is not None:
+        if len(args[1:]) > 1:
+            thread_manager.error('object-name only be used with 1 file or dir')
+            return
+    object_name = options.object_name
+
     object_manager = thread_manager.queue_manager(
         _object_job, options.object_threads,
         connection_maker=create_connection)
@@ -1092,9 +1116,9 @@ def st_upload(parser, args, thread_manager):
         try:
             for arg in args[1:]:
                 if isdir(arg):
-                    _upload_dir(arg, object_queue)
+                    _upload_dir(arg, object_queue, object_name)
                 else:
-                    object_queue.put({'path': arg})
+                    object_queue.put({'path': arg, 'object_name': object_name})
         except ClientException as err:
             if err.http_status != 404:
                 raise
diff --git a/doc/manpages/swift.1 b/doc/manpages/swift.1
index aae6c9fb..a6292fc9 100644
--- a/doc/manpages/swift.1
+++ b/doc/manpages/swift.1
@@ -61,7 +61,9 @@ of container or objects being listed.
 .RS 4
 Uploads to the given container the files and directories specified by the
 remaining args. The -c or --changed is an option that will only upload files
-that have changed since the last upload. The -S <size> or --segment-size <size>
+that have changed since the last upload. The --object-name <object-name> is
+an option that will upload file and name object to <object-name> or upload dir
+and use <object-name> as object prefix. The -S <size> or --segment-size <size>
 and --leave-segments are options as well (see --help for more).
 .RE