Revision 6736f171

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)
b/version
1
0.8next
1
0.7next

Also available in: Unified diff