Revision 6736f171 kamaki/cli/commands/pithos_cli.py
b/kamaki/cli/commands/pithos_cli.py | ||
---|---|---|
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) |
Also available in: Unified diff