def _dest_container_path(self, dest_container_path):
if self['destination_container']:
return (self['destination_container'], dest_container_path)
- dst = dest_container_path.split(':')
- return (dst[0], dst[1]) if len(dst) > 1 else (None, dst[0])
+ if dest_container_path:
+ dst = dest_container_path.split(':')
+ if len(dst) > 1:
+ try:
+ self.client.container = dst[0]
+ self.client.get_container_info(dst[0])
+ except ClientError as err:
+ if err.status in (404, 204):
+ raiseCLIError(
+ 'Destination container %s not found' % dst[0])
+ raise
+ return (dst[0], dst[1])
+ return(None, dst[0])
+ raiseCLIError('No destination container:path provided')
def extract_container_and_path(
self,
class store_copy(_store_container_command):
"""Copy objects from container to (another) container
Semantics:
- copy cont:path path2
- . will copy all <obj> prefixed with path, as path2<obj>
- . or as path2 if path corresponds to just one whole object
+ copy cont:path dir
+ . transfer path as dir/path
copy cont:path cont2:
- . will copy all <obj> prefixed with path to container cont2
- copy cont:path [cont2:]path2 --exact-match
- . will copy at most one <obj> as a new object named path2,
- . provided path corresponds to a whole object path
- copy cont:path [cont2:]path2 --replace
- . will copy all <obj> prefixed with path, replacing path with path2
- where <obj> is a full file or directory object path.
+ . trasnfer all <obj> prefixed with path to container cont2
+ copy cont:path [cont2:]path2
+ . transfer path to path2
Use options:
1. <container1>:<path1> [container2:]<path2> : if container2 is not given,
destination is container1:path2
recursive=FlagArgument(
'copy directory and contents',
('-r', '--recursive')),
- src_prefix=ValueArgument(
- 'Prefix of source objects (similar to prefix*)',
- '--prefix',
+ prefix=FlagArgument(
+ 'Match objects prefixed with src path (feels like src_path*)',
+ '--with-prefix',
default=''),
- src_suffix=ValueArgument(
- 'Suffix of source objects (similar to *suffix)',
- '--suffix',
+ suffix=ValueArgument(
+ 'Suffix of source objects (feels like *suffix)',
+ '--with-suffix',
default=''),
- dst_prefix=ValueArgument(
- 'Prefix all destination objects with dst path',
- '--prefix-dst',
+ add_prefix=ValueArgument('Prefix targets', '--add-prefix', default=''),
+ add_suffix=ValueArgument('Suffix targets', '--add-suffix', default=''),
+ prefix_replace=ValueArgument(
+ 'Prefix of src to replace with dst path + add_prefix, if matched',
+ '--prefix-to-replace',
default=''),
- dst_suffix=ValueArgument(
- 'Suffix all destination objects with dst path',
- '--suffix-dst',
- default=''),
- replace=ValueArgument(
- 'Set the part of src path to replace with dst path',
- '--replace')
+ suffix_replace=ValueArgument(
+ 'Suffix of src to replace with add_suffix, if matched',
+ '--suffix-to-replace',
+ default='')
)
def _get_all(self, prefix):
return self.client.container_get(prefix=prefix).json
- def _objlist(self, src_cnt, src_path, dst_cnt, dst_path):
+ def _get_src_objects(self, src_cnt, src_path):
+ """Get a list of the source objects to be called
+
+ :param src_cnt: (str) source container
+
+ :param src_path: (str) source path
+
+ :returns: (method, params) a method that returns a list when called
+ or (object) if it is a single object
+ """
if src_path and src_path[-1] == '/':
src_path = src_path[:-1]
self.client.container = src_cnt
- (src_list_foo, src_list_args) = (None, {})
+ if self['prefix']:
+ return (self._get_all, dict(prefix=src_path))
try:
- list_all = False
srcobj = self.client.get_object_info(src_path)
except ClientError as srcerr:
- if srcerr not in (404, 204):
+ if srcerr.status == 404:
+ raiseCLIError(
+ 'Source object %s not in cont. %s' % (src_path, src_cnt),
+ details=['Hint: --with-prefix to match multiple objects'])
+ elif srcerr.status not in (204,):
raise
- src_list_foo = self.client.list_objects
- list_all = True
- else:
- if self._is_dir(srcobj):
- if not self['recursive']:
- raiseCLIError(
- 'Object %s of cont. %s is a dir' % (
- src_path,
- src_cnt),
- details=['Use --recursive to access directories'])
- self['src_prefix'] = self.path
- finally:
- if self['src_prefix']:
- if not self.path.startswith(self['src_prefix']):
- raiseCLIError('Path %s conflicts with prefix %s' % (
- self.path,
- self['src_prefix']))
- src_list_foo = self._get_all,
- src_list_args = dict(prefix=self['src_prefix'])
- elif list_all:
- src_list_foo = self.client.list_objects
-
- if dst_path and dst_path[-1] == '/':
+ return (self.client.list_objects, {})
+ if self._is_dir(srcobj):
+ if not self['recursive']:
+ raiseCLIError(
+ 'Object %s of cont. %s is a dir' % (src_path, src_cnt),
+ details=['Use --recursive to access directories'])
+ return (self._get_all, dict(prefix=src_path))
+ srcobj['name'] = src_path
+ return srcobj
+
+ def _objlist(self, dst_cont, dst_path):
+ src_iter = self._get_src_objects(self.container, self.path)
+ src_N = isinstance(src_iter, tuple)
+ add_prefix = self['add_prefix'].strip('/')
+
+ if dst_path and dst_path.endswith('/'):
dst_path = dst_path[:-1]
- if src_list_foo:
- # N src objects
- (p, s) = (self['dst_prefix'], self['dst_suffix'])
- if p or s:
- for obj in src_list_foo(**src_list_args):
- name = obj['name']
- if not name.endswith(self['src_suffix']):
- continue
- name = '%s%s%s' % (
- self['dst_prefix'],
- name,
- self['dst_suffix'])
- else:
- pass
- # 1 src object
+ self.client.container = dst_cont
+ try:
+ dstobj = self.client.get_object_info(dst_path)
+ except ClientError as trgerr:
+ if trgerr.status in (404,):
+ if src_N:
+ raiseCLIError(
+ 'Cannot merge multiple paths to path %s' % dst_path,
+ details=[
+ 'Try to use / or a directory as destination',
+ 'or create the destination dir (/store mkdir)',
+ 'or use a single object as source'])
+ elif trgerr.status not in (204,):
+ raise
+ else:
+ if self._is_dir(dstobj):
+ add_prefix = '%s/%s' % (dst_path.strip('/'), add_prefix)
+ elif src_N:
+ raiseCLIError(
+ 'Cannot merge multiple paths to path' % dst_path,
+ details=[
+ 'Try to use / or a directory as destination',
+ 'or create the destination dir (/store mkdir)',
+ 'or use a single object as source'])
+
+ self.client.container = self.container
+ if src_N:
+ (method, kwargs) = src_iter
+ for obj in method(**kwargs):
+ name = obj['name']
+ if name.endswith(self['suffix']):
+ yield (name, self._get_new_object(name, add_prefix))
+ elif src_iter['name'].endswith(self['suffix']):
+ name = src_iter['name']
+ yield (name, self._get_new_object(dst_path or name, add_prefix))
+ else:
+ raiseCLIError('Source path %s conflicts with suffix %s' % (
+ src_iter['name'],
+ self['suffix']))
- """
- def _objlist(self, dst_path):
- if self['exact_match']:
- return [(dst_path or self.path, self.path)]
- r = self.client.container_get(prefix=self.path)
- if len(r.json) == 1:
- obj = r.json[0]
- return [(obj['name'], dst_path or obj['name'])]
- start = len(self.path) if self['replace'] else 0
- return [(obj['name'], '%s%s' % (
- dst_path,
- obj['name'][start:])) for obj in r.json]
- """
+ def _get_new_object(self, obj, add_prefix):
+ if self['prefix_replace'] and obj.startswith(self['prefix_replace']):
+ obj = obj[len(self['prefix_replace']):]
+ if self['suffix_replace'] and obj.endswith(self['suffix_replace']):
+ obj = obj[:-len(self['suffix_replace'])]
+ return add_prefix + obj + self['add_suffix']
@errors.generic.all
@errors.pithos.connection
@errors.pithos.container
def _run(self, dst_cont, dst_path):
- for lala in self._src_objlist(self.container, self.path):
- print('I HAVE %s : %s !' % lala)
- return
no_source_object = True
- for src_object, dst_object in self._objlist(dst_path):
+ for src_object, dst_object in self._objlist(dst_cont, dst_path):
no_source_object = False
self.client.copy_object(
src_container=self.container,
src_object=src_object,
- dst_container=dst_cont or self.container,
+ dst_container=dst_cont,
dst_object=dst_object,
source_version=self['source_version'],
public=self['public'],
path_is_optional=False)
(dst_cont, dst_path) = self._dest_container_path(
destination_container___path)
- self._run(dst_cont=dst_cont, dst_path=dst_path or '')
+ self._run(dst_cont=dst_cont or self.container, dst_path=dst_path or '')
@command(pithos_cmds)