222 |
222 |
def _dest_container_path(self, dest_container_path):
|
223 |
223 |
if self['destination_container']:
|
224 |
224 |
return (self['destination_container'], dest_container_path)
|
225 |
|
dst = dest_container_path.split(':')
|
226 |
|
return (dst[0], dst[1]) if len(dst) > 1 else (None, dst[0])
|
|
225 |
if dest_container_path:
|
|
226 |
dst = dest_container_path.split(':')
|
|
227 |
if len(dst) > 1:
|
|
228 |
try:
|
|
229 |
self.client.container = dst[0]
|
|
230 |
self.client.get_container_info(dst[0])
|
|
231 |
except ClientError as err:
|
|
232 |
if err.status in (404, 204):
|
|
233 |
raiseCLIError(
|
|
234 |
'Destination container %s not found' % dst[0])
|
|
235 |
raise
|
|
236 |
return (dst[0], dst[1])
|
|
237 |
return(None, dst[0])
|
|
238 |
raiseCLIError('No destination container:path provided')
|
227 |
239 |
|
228 |
240 |
def extract_container_and_path(
|
229 |
241 |
self,
|
... | ... | |
518 |
530 |
class store_copy(_store_container_command):
|
519 |
531 |
"""Copy objects from container to (another) container
|
520 |
532 |
Semantics:
|
521 |
|
copy cont:path path2
|
522 |
|
. will copy all <obj> prefixed with path, as path2<obj>
|
523 |
|
. or as path2 if path corresponds to just one whole object
|
|
533 |
copy cont:path dir
|
|
534 |
. transfer path as dir/path
|
524 |
535 |
copy cont:path cont2:
|
525 |
|
. will copy all <obj> prefixed with path to container cont2
|
526 |
|
copy cont:path [cont2:]path2 --exact-match
|
527 |
|
. will copy at most one <obj> as a new object named path2,
|
528 |
|
. provided path corresponds to a whole object path
|
529 |
|
copy cont:path [cont2:]path2 --replace
|
530 |
|
. will copy all <obj> prefixed with path, replacing path with path2
|
531 |
|
where <obj> is a full file or directory object path.
|
|
536 |
. trasnfer all <obj> prefixed with path to container cont2
|
|
537 |
copy cont:path [cont2:]path2
|
|
538 |
. transfer path to path2
|
532 |
539 |
Use options:
|
533 |
540 |
1. <container1>:<path1> [container2:]<path2> : if container2 is not given,
|
534 |
541 |
destination is container1:path2
|
... | ... | |
550 |
557 |
recursive=FlagArgument(
|
551 |
558 |
'copy directory and contents',
|
552 |
559 |
('-r', '--recursive')),
|
553 |
|
src_prefix=ValueArgument(
|
554 |
|
'Prefix of source objects (similar to prefix*)',
|
555 |
|
'--prefix',
|
|
560 |
prefix=FlagArgument(
|
|
561 |
'Match objects prefixed with src path (feels like src_path*)',
|
|
562 |
'--with-prefix',
|
556 |
563 |
default=''),
|
557 |
|
src_suffix=ValueArgument(
|
558 |
|
'Suffix of source objects (similar to *suffix)',
|
559 |
|
'--suffix',
|
|
564 |
suffix=ValueArgument(
|
|
565 |
'Suffix of source objects (feels like *suffix)',
|
|
566 |
'--with-suffix',
|
560 |
567 |
default=''),
|
561 |
|
dst_prefix=ValueArgument(
|
562 |
|
'Prefix all destination objects with dst path',
|
563 |
|
'--prefix-dst',
|
|
568 |
add_prefix=ValueArgument('Prefix targets', '--add-prefix', default=''),
|
|
569 |
add_suffix=ValueArgument('Suffix targets', '--add-suffix', default=''),
|
|
570 |
prefix_replace=ValueArgument(
|
|
571 |
'Prefix of src to replace with dst path + add_prefix, if matched',
|
|
572 |
'--prefix-to-replace',
|
564 |
573 |
default=''),
|
565 |
|
dst_suffix=ValueArgument(
|
566 |
|
'Suffix all destination objects with dst path',
|
567 |
|
'--suffix-dst',
|
568 |
|
default=''),
|
569 |
|
replace=ValueArgument(
|
570 |
|
'Set the part of src path to replace with dst path',
|
571 |
|
'--replace')
|
|
574 |
suffix_replace=ValueArgument(
|
|
575 |
'Suffix of src to replace with add_suffix, if matched',
|
|
576 |
'--suffix-to-replace',
|
|
577 |
default='')
|
572 |
578 |
)
|
573 |
579 |
|
574 |
580 |
def _get_all(self, prefix):
|
575 |
581 |
return self.client.container_get(prefix=prefix).json
|
576 |
582 |
|
577 |
|
def _objlist(self, src_cnt, src_path, dst_cnt, dst_path):
|
|
583 |
def _get_src_objects(self, src_cnt, src_path):
|
|
584 |
"""Get a list of the source objects to be called
|
|
585 |
|
|
586 |
:param src_cnt: (str) source container
|
|
587 |
|
|
588 |
:param src_path: (str) source path
|
|
589 |
|
|
590 |
:returns: (method, params) a method that returns a list when called
|
|
591 |
or (object) if it is a single object
|
|
592 |
"""
|
578 |
593 |
if src_path and src_path[-1] == '/':
|
579 |
594 |
src_path = src_path[:-1]
|
580 |
595 |
self.client.container = src_cnt
|
581 |
|
(src_list_foo, src_list_args) = (None, {})
|
582 |
596 |
|
|
597 |
if self['prefix']:
|
|
598 |
return (self._get_all, dict(prefix=src_path))
|
583 |
599 |
try:
|
584 |
|
list_all = False
|
585 |
600 |
srcobj = self.client.get_object_info(src_path)
|
586 |
601 |
except ClientError as srcerr:
|
587 |
|
if srcerr not in (404, 204):
|
|
602 |
if srcerr.status == 404:
|
|
603 |
raiseCLIError(
|
|
604 |
'Source object %s not in cont. %s' % (src_path, src_cnt),
|
|
605 |
details=['Hint: --with-prefix to match multiple objects'])
|
|
606 |
elif srcerr.status not in (204,):
|
588 |
607 |
raise
|
589 |
|
src_list_foo = self.client.list_objects
|
590 |
|
list_all = True
|
591 |
|
else:
|
592 |
|
if self._is_dir(srcobj):
|
593 |
|
if not self['recursive']:
|
594 |
|
raiseCLIError(
|
595 |
|
'Object %s of cont. %s is a dir' % (
|
596 |
|
src_path,
|
597 |
|
src_cnt),
|
598 |
|
details=['Use --recursive to access directories'])
|
599 |
|
self['src_prefix'] = self.path
|
600 |
|
finally:
|
601 |
|
if self['src_prefix']:
|
602 |
|
if not self.path.startswith(self['src_prefix']):
|
603 |
|
raiseCLIError('Path %s conflicts with prefix %s' % (
|
604 |
|
self.path,
|
605 |
|
self['src_prefix']))
|
606 |
|
src_list_foo = self._get_all,
|
607 |
|
src_list_args = dict(prefix=self['src_prefix'])
|
608 |
|
elif list_all:
|
609 |
|
src_list_foo = self.client.list_objects
|
610 |
|
|
611 |
|
if dst_path and dst_path[-1] == '/':
|
|
608 |
return (self.client.list_objects, {})
|
|
609 |
if self._is_dir(srcobj):
|
|
610 |
if not self['recursive']:
|
|
611 |
raiseCLIError(
|
|
612 |
'Object %s of cont. %s is a dir' % (src_path, src_cnt),
|
|
613 |
details=['Use --recursive to access directories'])
|
|
614 |
return (self._get_all, dict(prefix=src_path))
|
|
615 |
srcobj['name'] = src_path
|
|
616 |
return srcobj
|
|
617 |
|
|
618 |
def _objlist(self, dst_cont, dst_path):
|
|
619 |
src_iter = self._get_src_objects(self.container, self.path)
|
|
620 |
src_N = isinstance(src_iter, tuple)
|
|
621 |
add_prefix = self['add_prefix'].strip('/')
|
|
622 |
|
|
623 |
if dst_path and dst_path.endswith('/'):
|
612 |
624 |
dst_path = dst_path[:-1]
|
613 |
|
if src_list_foo:
|
614 |
|
# N src objects
|
615 |
|
(p, s) = (self['dst_prefix'], self['dst_suffix'])
|
616 |
|
if p or s:
|
617 |
|
for obj in src_list_foo(**src_list_args):
|
618 |
|
name = obj['name']
|
619 |
|
if not name.endswith(self['src_suffix']):
|
620 |
|
continue
|
621 |
|
name = '%s%s%s' % (
|
622 |
|
self['dst_prefix'],
|
623 |
|
name,
|
624 |
|
self['dst_suffix'])
|
625 |
|
else:
|
626 |
|
pass
|
627 |
|
# 1 src object
|
628 |
625 |
|
|
626 |
self.client.container = dst_cont
|
|
627 |
try:
|
|
628 |
dstobj = self.client.get_object_info(dst_path)
|
|
629 |
except ClientError as trgerr:
|
|
630 |
if trgerr.status in (404,):
|
|
631 |
if src_N:
|
|
632 |
raiseCLIError(
|
|
633 |
'Cannot merge multiple paths to path %s' % dst_path,
|
|
634 |
details=[
|
|
635 |
'Try to use / or a directory as destination',
|
|
636 |
'or create the destination dir (/store mkdir)',
|
|
637 |
'or use a single object as source'])
|
|
638 |
elif trgerr.status not in (204,):
|
|
639 |
raise
|
|
640 |
else:
|
|
641 |
if self._is_dir(dstobj):
|
|
642 |
add_prefix = '%s/%s' % (dst_path.strip('/'), add_prefix)
|
|
643 |
elif src_N:
|
|
644 |
raiseCLIError(
|
|
645 |
'Cannot merge multiple paths to path' % dst_path,
|
|
646 |
details=[
|
|
647 |
'Try to use / or a directory as destination',
|
|
648 |
'or create the destination dir (/store mkdir)',
|
|
649 |
'or use a single object as source'])
|
|
650 |
|
|
651 |
self.client.container = self.container
|
|
652 |
if src_N:
|
|
653 |
(method, kwargs) = src_iter
|
|
654 |
for obj in method(**kwargs):
|
|
655 |
name = obj['name']
|
|
656 |
if name.endswith(self['suffix']):
|
|
657 |
yield (name, self._get_new_object(name, add_prefix))
|
|
658 |
elif src_iter['name'].endswith(self['suffix']):
|
|
659 |
name = src_iter['name']
|
|
660 |
yield (name, self._get_new_object(dst_path or name, add_prefix))
|
|
661 |
else:
|
|
662 |
raiseCLIError('Source path %s conflicts with suffix %s' % (
|
|
663 |
src_iter['name'],
|
|
664 |
self['suffix']))
|
629 |
665 |
|
630 |
|
"""
|
631 |
|
def _objlist(self, dst_path):
|
632 |
|
if self['exact_match']:
|
633 |
|
return [(dst_path or self.path, self.path)]
|
634 |
|
r = self.client.container_get(prefix=self.path)
|
635 |
|
if len(r.json) == 1:
|
636 |
|
obj = r.json[0]
|
637 |
|
return [(obj['name'], dst_path or obj['name'])]
|
638 |
|
start = len(self.path) if self['replace'] else 0
|
639 |
|
return [(obj['name'], '%s%s' % (
|
640 |
|
dst_path,
|
641 |
|
obj['name'][start:])) for obj in r.json]
|
642 |
|
"""
|
|
666 |
def _get_new_object(self, obj, add_prefix):
|
|
667 |
if self['prefix_replace'] and obj.startswith(self['prefix_replace']):
|
|
668 |
obj = obj[len(self['prefix_replace']):]
|
|
669 |
if self['suffix_replace'] and obj.endswith(self['suffix_replace']):
|
|
670 |
obj = obj[:-len(self['suffix_replace'])]
|
|
671 |
return add_prefix + obj + self['add_suffix']
|
643 |
672 |
|
644 |
673 |
@errors.generic.all
|
645 |
674 |
@errors.pithos.connection
|
646 |
675 |
@errors.pithos.container
|
647 |
676 |
def _run(self, dst_cont, dst_path):
|
648 |
|
for lala in self._src_objlist(self.container, self.path):
|
649 |
|
print('I HAVE %s : %s !' % lala)
|
650 |
|
return
|
651 |
677 |
no_source_object = True
|
652 |
|
for src_object, dst_object in self._objlist(dst_path):
|
|
678 |
for src_object, dst_object in self._objlist(dst_cont, dst_path):
|
653 |
679 |
no_source_object = False
|
654 |
680 |
self.client.copy_object(
|
655 |
681 |
src_container=self.container,
|
656 |
682 |
src_object=src_object,
|
657 |
|
dst_container=dst_cont or self.container,
|
|
683 |
dst_container=dst_cont,
|
658 |
684 |
dst_object=dst_object,
|
659 |
685 |
source_version=self['source_version'],
|
660 |
686 |
public=self['public'],
|
... | ... | |
673 |
699 |
path_is_optional=False)
|
674 |
700 |
(dst_cont, dst_path) = self._dest_container_path(
|
675 |
701 |
destination_container___path)
|
676 |
|
self._run(dst_cont=dst_cont, dst_path=dst_path or '')
|
|
702 |
self._run(dst_cont=dst_cont or self.container, dst_path=dst_path or '')
|
677 |
703 |
|
678 |
704 |
|
679 |
705 |
@command(pithos_cmds)
|