+ container, sep, object = path.partition('/')
+ if object:
+ self.client.update_object_metadata(container, object, **meta)
+ elif container:
+ self.client.update_container_metadata(container, **meta)
+ else:
+ self.client.update_account_metadata(**meta)
+
+@cli_command('update')
+class UpdateObject(Command):
+ syntax = '<container>/<object> path [key=val] [...]'
+ description = 'update object metadata/data (default mode: append)'
+
+ def add_options(self, parser):
+ parser.add_option('-a', action='store_true', dest='append',
+ default=True, help='append data')
+ parser.add_option('--offset', action='store',
+ dest='offset',
+ default=None, help='starting offest to be updated')
+ parser.add_option('--range', action='store', dest='content-range',
+ default=None, help='range of data to be updated')
+ parser.add_option('--chunked', action='store_true', dest='chunked',
+ default=False, help='set chunked transfer mode')
+ parser.add_option('--content-encoding', action='store',
+ dest='content_encoding', default=None,
+ help='provide the object MIME content type')
+ parser.add_option('--content-disposition', action='store', type='str',
+ dest='content_disposition', default=None,
+ help='provide the presentation style of the object')
+ parser.add_option('--manifest', action='store', type='str',
+ dest='x_object_manifest', default=None,
+ help='use for large file support')
+ parser.add_option('--sharing', action='store',
+ dest='x_object_sharing', default=None,
+ help='define sharing object policy')
+ parser.add_option('--nosharing', action='store_true',
+ dest='no_sharing', default=None,
+ help='clear object sharing policy')
+ parser.add_option('-f', action='store',
+ dest='srcpath', default=None,
+ help='file descriptor to read from: pass - for standard input')
+ parser.add_option('--public', action='store_true',
+ dest='x_object_public', default=False,
+ help='make object publicly accessible')
+ parser.add_option('--replace', action='store_true',
+ dest='replace', default=False,
+ help='override metadata')
+
+ def execute(self, path, *args):
+ if path.find('=') != -1:
+ raise Fault('Missing path argument')
+
+ #prepare user defined meta
+ meta = {}
+ for arg in args:
+ key, sep, val = arg.partition('=')
+ meta[key] = val
+
+
+ attrs = ['content_encoding', 'content_disposition', 'x_object_sharing',
+ 'x_object_public', 'replace']
+ args = self._build_args(attrs)
+
+ if self.no_sharing:
+ args['x_object_sharing'] = ''
+
+ container, sep, object = path.partition('/')
+
+ f = None
+ if self.srcpath:
+ f = open(self.srcpath) if self.srcpath != '-' else stdin
+
+ if self.chunked:
+ self.client.update_object_using_chunks(container, object, f,
+ meta=meta, **args)
+ else:
+ self.client.update_object(container, object, f, meta=meta, **args)
+ if f:
+ f.close()
+
+@cli_command('move', 'mv')
+class MoveObject(Command):
+ syntax = '<src container>/<src object> [<dst container>/]<dst object>'
+ description = 'move an object to a different location'
+
+ def add_options(self, parser):
+ parser.add_option('--public', action='store_true',
+ dest='public', default=False,
+ help='make object publicly accessible')
+ parser.add_option('--content-type', action='store',
+ dest='content_type', default=None,
+ help='change object\'s content type')
+
+ def execute(self, src, dst, *args):
+ src_container, sep, src_object = src.partition('/')
+ dst_container, sep, dst_object = dst.partition('/')
+ if not sep:
+ dst_container = src_container
+ dst_object = dst
+
+ #prepare user defined meta
+ meta = {}
+ for arg in args:
+ key, sep, val = arg.partition('=')
+ meta[key] = val
+
+ args = {'content_type':self.content_type} if self.content_type else {}
+ self.client.move_object(src_container, src_object, dst_container,
+ dst_object, meta, self.public, **args)
+
+@cli_command('unset')
+class UnsetObject(Command):
+ syntax = '<container>/[<object>] key [key] [...]'
+ description = 'delete metadata info'
+
+ def execute(self, path, *args):
+ #in case of account fix the args
+ if len(args) == 0:
+ args = list(args)
+ args.append(path)
+ args = tuple(args)
+ path = ''
+ meta = []
+ for key in args:
+ meta.append(key)
+ container, sep, object = path.partition('/')
+ if object:
+ self.client.delete_object_metadata(container, object, meta)
+ elif container:
+ self.client.delete_container_metadata(container, meta)
+ else:
+ self.client.delete_account_metadata(meta)
+
+@cli_command('group')
+class CreateGroup(Command):
+ syntax = 'key=val [key=val] [...]'
+ description = 'create account groups'
+
+ def execute(self, *args):
+ groups = {}
+ for arg in args:
+ key, sep, val = arg.partition('=')
+ groups[key] = val
+ self.client.set_account_groups(**groups)
+
+@cli_command('ungroup')
+class DeleteGroup(Command):
+ syntax = 'key [key] [...]'
+ description = 'delete account groups'
+
+ def execute(self, *args):
+ groups = []
+ for arg in args:
+ groups.append(arg)
+ self.client.unset_account_groups(groups)
+
+@cli_command('policy')
+class SetPolicy(Command):
+ syntax = 'container key=val [key=val] [...]'
+ description = 'set container policies'
+
+ def execute(self, path, *args):
+ if path.find('=') != -1:
+ raise Fault('Missing container argument')
+
+ container, sep, object = path.partition('/')
+
+ if object:
+ raise Fault('Only containers have policies')
+
+ policies = {}
+ for arg in args:
+ key, sep, val = arg.partition('=')
+ policies[key] = val
+
+ self.client.set_container_policies(container, **policies)