/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/builtins.py

  • Committer: Jelmer Vernooij
  • Date: 2019-03-04 00:16:27 UTC
  • mfrom: (7293 work)
  • mto: This revision was merged to the branch mainline in revision 7318.
  • Revision ID: jelmer@jelmer.uk-20190304001627-v6u7o6pf97tukhek
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
84
84
    RevisionInfo,
85
85
    )
86
86
from .sixish import (
87
 
    BytesIO,
88
87
    PY3,
89
88
    text_type,
90
89
    viewitems,
119
118
        and the full URL to the actual branch
120
119
    """
121
120
    # This path is meant to be relative to the existing branch
122
 
    this_url = _get_branch_location(control_dir,
123
 
        possible_transports=possible_transports)
 
121
    this_url = _get_branch_location(
 
122
        control_dir, possible_transports=possible_transports)
124
123
    # Perhaps the target control dir supports colocated branches?
125
124
    try:
126
 
        root = controldir.ControlDir.open(this_url,
127
 
            possible_transports=possible_transports)
 
125
        root = controldir.ControlDir.open(
 
126
            this_url, possible_transports=possible_transports)
128
127
    except errors.NotBranchError:
129
128
        return (False, this_url)
130
129
    else:
131
130
        try:
132
 
            wt = control_dir.open_workingtree()
 
131
            control_dir.open_workingtree()
133
132
        except (errors.NoWorkingTree, errors.NotLocalUrl):
134
133
            return (False, this_url)
135
134
        else:
151
150
        (colocated, this_url) = _is_colocated(control_dir, possible_transports)
152
151
 
153
152
        if colocated:
154
 
            return urlutils.join_segment_parameters(this_url,
155
 
                {"branch": urlutils.escape(location)})
 
153
            return urlutils.join_segment_parameters(
 
154
                this_url, {"branch": urlutils.escape(location)})
156
155
        else:
157
156
            return urlutils.join(this_url, '..', urlutils.escape(location))
158
157
    return location
168
167
    """
169
168
    try:
170
169
        # Perhaps it's a colocated branch?
171
 
        return control_dir.open_branch(location, 
172
 
            possible_transports=possible_transports)
 
170
        return control_dir.open_branch(
 
171
            location, possible_transports=possible_transports)
173
172
    except (errors.NotBranchError, errors.NoColocatedBranchSupport):
174
173
        this_url = _get_branch_location(control_dir)
175
174
        return Branch.open(
188
187
        if location is None:
189
188
            location = "."
190
189
        try:
191
 
            return Branch.open(location,
192
 
                possible_transports=possible_transports)
 
190
            return Branch.open(
 
191
                location, possible_transports=possible_transports)
193
192
        except errors.NotBranchError:
194
193
            near = "."
195
 
    cdir = controldir.ControlDir.open(near,
196
 
        possible_transports=possible_transports)
197
 
    return open_sibling_branch(cdir, location,
198
 
        possible_transports=possible_transports)
 
194
    cdir = controldir.ControlDir.open(
 
195
        near, possible_transports=possible_transports)
 
196
    return open_sibling_branch(
 
197
        cdir, location, possible_transports=possible_transports)
199
198
 
200
199
 
201
200
def iter_sibling_branches(control_dir, possible_transports=None):
204
203
    :param control_dir: Control directory for which to look up the siblings
205
204
    :return: Iterator over tuples with branch name and branch object
206
205
    """
207
 
    seen_urls = set()
208
206
    try:
209
207
        reference = control_dir.get_branch_reference()
210
208
    except errors.NotBranchError:
211
 
        # There is no active branch, just return the colocated branches.
212
 
        for name, branch in viewitems(control_dir.get_branches()):
213
 
            yield name, branch
214
 
        return
 
209
        reference = None
215
210
    if reference is not None:
216
 
        ref_branch = Branch.open(reference,
217
 
            possible_transports=possible_transports)
 
211
        try:
 
212
            ref_branch = Branch.open(
 
213
                reference, possible_transports=possible_transports)
 
214
        except errors.NotBranchError:
 
215
            ref_branch = None
218
216
    else:
219
217
        ref_branch = None
220
218
    if ref_branch is None or ref_branch.name:
225
223
    else:
226
224
        repo = ref_branch.controldir.find_repository()
227
225
        for branch in repo.find_branches(using=True):
228
 
            name = urlutils.relative_url(repo.user_url,
229
 
                branch.user_url).rstrip("/")
 
226
            name = urlutils.relative_url(
 
227
                repo.user_url, branch.user_url).rstrip("/")
230
228
            yield name, branch
231
229
 
232
230
 
258
256
            if view_files:
259
257
                file_list = view_files
260
258
                view_str = views.view_display_str(view_files)
261
 
                note(gettext("Ignoring files outside view. View is %s") % view_str)
 
259
                note(gettext("Ignoring files outside view. View is %s"),
 
260
                     view_str)
262
261
    return tree, file_list
263
262
 
264
263
 
274
273
 
275
274
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
276
275
    """Get a revision tree. Not suitable for commands that change the tree.
277
 
    
 
276
 
278
277
    Specifically, the basis tree in dirstate trees is coupled to the dirstate
279
278
    and doing a commit/uncommit/pull will at best fail due to changing the
280
279
    basis revision data.
386
385
                            short_name='S'),
387
386
                     Option('versioned', help='Only show versioned files.',
388
387
                            short_name='V'),
389
 
                     Option('no-pending', help='Don\'t show pending merges.',
390
 
                           ),
 
388
                     Option('no-pending', help='Don\'t show pending merges.'),
391
389
                     Option('no-classify',
392
 
                            help='Do not mark object type using indicator.',
393
 
                           ),
 
390
                            help='Do not mark object type using indicator.'),
394
391
                     ]
395
392
    aliases = ['st', 'stat']
396
393
 
404
401
        from .status import show_tree_status
405
402
 
406
403
        if revision and len(revision) > 2:
407
 
            raise errors.BzrCommandError(gettext('brz status --revision takes exactly'
408
 
                                         ' one or two revision specifiers'))
 
404
            raise errors.BzrCommandError(
 
405
                gettext('brz status --revision takes exactly'
 
406
                        ' one or two revision specifiers'))
409
407
 
410
408
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
411
409
        # Avoid asking for specific files when that is not needed.
449
447
    def run(self, revision_id=None, revision=None, directory=u'.'):
450
448
        if revision_id is not None and revision is not None:
451
449
            raise errors.BzrCommandError(gettext('You can only supply one of'
452
 
                                         ' revision_id or --revision'))
 
450
                                                 ' revision_id or --revision'))
453
451
        if revision_id is None and revision is None:
454
 
            raise errors.BzrCommandError(gettext('You must supply either'
455
 
                                         ' --revision or a revision_id'))
 
452
            raise errors.BzrCommandError(
 
453
                gettext('You must supply either --revision or a revision_id'))
456
454
 
457
455
        b = controldir.ControlDir.open_containing_tree_or_branch(directory)[1]
458
456
 
459
457
        revisions = b.repository.revisions
460
458
        if revisions is None:
461
 
            raise errors.BzrCommandError(gettext('Repository %r does not support '
462
 
                'access to raw revision texts'))
 
459
            raise errors.BzrCommandError(
 
460
                gettext('Repository %r does not support '
 
461
                        'access to raw revision texts'))
463
462
 
464
463
        with b.repository.lock_read():
465
464
            # TODO: jam 20060112 should cat-revision always output utf-8?
468
467
                try:
469
468
                    self.print_revision(revisions, revision_id)
470
469
                except errors.NoSuchRevision:
471
 
                    msg = gettext("The repository {0} contains no revision {1}.").format(
472
 
                        b.repository.base, revision_id.decode('utf-8'))
 
470
                    msg = gettext(
 
471
                        "The repository {0} contains no revision {1}.").format(
 
472
                            b.repository.base, revision_id.decode('utf-8'))
473
473
                    raise errors.BzrCommandError(msg)
474
474
            elif revision is not None:
475
475
                for rev in revision:
498
498
 
499
499
    def run(self, location_list, force=False):
500
500
        if not location_list:
501
 
            location_list=['.']
 
501
            location_list = ['.']
502
502
 
503
503
        for location in location_list:
504
504
            d = controldir.ControlDir.open(location)
506
506
            try:
507
507
                working = d.open_workingtree()
508
508
            except errors.NoWorkingTree:
509
 
                raise errors.BzrCommandError(gettext("No working tree to remove"))
 
509
                raise errors.BzrCommandError(
 
510
                    gettext("No working tree to remove"))
510
511
            except errors.NotLocalUrl:
511
 
                raise errors.BzrCommandError(gettext("You cannot remove the working tree"
512
 
                                             " of a remote path"))
 
512
                raise errors.BzrCommandError(
 
513
                    gettext("You cannot remove the working tree"
 
514
                            " of a remote path"))
513
515
            if not force:
514
516
                if (working.has_changes()):
515
517
                    raise errors.UncommittedChanges(working)
517
519
                    raise errors.ShelvedChanges(working)
518
520
 
519
521
            if working.user_url != working.branch.user_url:
520
 
                raise errors.BzrCommandError(gettext("You cannot remove the working tree"
521
 
                                             " from a lightweight checkout"))
 
522
                raise errors.BzrCommandError(
 
523
                    gettext("You cannot remove the working tree"
 
524
                            " from a lightweight checkout"))
522
525
 
523
526
            d.destroy_workingtree()
524
527
 
539
542
    that, you can supply --revision to force the state of the tree.
540
543
    """
541
544
 
542
 
    takes_options = ['revision', 'directory',
 
545
    takes_options = [
 
546
        'revision', 'directory',
543
547
        Option('force',
544
548
               help='Reset the tree even if it doesn\'t appear to be'
545
549
                    ' corrupted.'),
553
557
            try:
554
558
                tree.check_state()
555
559
            except errors.BzrError:
556
 
                pass # There seems to be a real error here, so we'll reset
 
560
                pass  # There seems to be a real error here, so we'll reset
557
561
            else:
558
562
                # Refuse
559
563
                raise errors.BzrCommandError(gettext(
566
570
            revision_ids = [r.as_revision_id(tree.branch) for r in revision]
567
571
        try:
568
572
            tree.reset_state(revision_ids)
569
 
        except errors.BzrError as e:
 
573
        except errors.BzrError:
570
574
            if revision_ids is None:
571
 
                extra = (gettext(', the header appears corrupt, try passing -r -1'
572
 
                         ' to set the state to the last commit'))
 
575
                extra = gettext(', the header appears corrupt, try passing '
 
576
                                '-r -1 to set the state to the last commit')
573
577
            else:
574
578
                extra = ''
575
 
            raise errors.BzrCommandError(gettext('failed to reset the tree state{0}').format(extra))
 
579
            raise errors.BzrCommandError(
 
580
                gettext('failed to reset the tree state{0}').format(extra))
576
581
 
577
582
 
578
583
class cmd_revno(Command):
591
596
    @display_command
592
597
    def run(self, tree=False, location=u'.', revision=None):
593
598
        if revision is not None and tree:
594
 
            raise errors.BzrCommandError(gettext("--tree and --revision can "
595
 
                "not be used together"))
 
599
            raise errors.BzrCommandError(
 
600
                gettext("--tree and --revision can not be used together"))
596
601
 
597
602
        if tree:
598
603
            try:
615
620
                revid = b.last_revision()
616
621
        try:
617
622
            revno_t = b.revision_id_to_dotted_revno(revid)
618
 
        except errors.NoSuchRevision:
 
623
        except (errors.NoSuchRevision, errors.GhostRevisionsHaveNoRevno):
619
624
            revno_t = ('???',)
620
625
        revno = ".".join(str(n) for n in revno_t)
621
626
        self.cleanup_now()
629
634
    takes_args = ['revision_info*']
630
635
    takes_options = [
631
636
        'revision',
632
 
        custom_help('directory',
633
 
            help='Branch to examine, '
634
 
                 'rather than the one containing the working directory.'),
 
637
        custom_help('directory', help='Branch to examine, '
 
638
                    'rather than the one containing the working directory.'),
635
639
        Option('tree', help='Show revno of working tree.'),
636
640
        ]
637
641
 
676
680
 
677
681
        self.cleanup_now()
678
682
        for revno, revid in revinfos:
679
 
            self.outf.write('%*s %s\n' % (maxlen, revno, revid.decode('utf-8')))
 
683
            self.outf.write(
 
684
                '%*s %s\n' % (maxlen, revno, revid.decode('utf-8')))
680
685
 
681
686
 
682
687
class cmd_add(Command):
715
720
    branches that will be merged later (without showing the two different
716
721
    adds as a conflict). It is also useful when merging another project
717
722
    into a subdirectory of this one.
718
 
    
 
723
 
719
724
    Any files matching patterns in the ignore list will not be added
720
725
    unless they are explicitly mentioned.
721
 
    
722
 
    In recursive mode, files larger than the configuration option 
 
726
 
 
727
    In recursive mode, files larger than the configuration option
723
728
    add.maximum_file_size will be skipped. Named items are never skipped due
724
729
    to file size.
725
730
    """
729
734
               help="Don't recursively add the contents of directories.",
730
735
               short_name='N'),
731
736
        Option('dry-run',
732
 
               help="Show what would be done, but don't actually do anything."),
 
737
               help="Show what would be done, but don't actually do "
 
738
                    "anything."),
733
739
        'verbose',
734
740
        Option('file-ids-from',
735
741
               type=text_type,
746
752
        if file_ids_from is not None:
747
753
            try:
748
754
                base_tree, base_path = WorkingTree.open_containing(
749
 
                                            file_ids_from)
 
755
                    file_ids_from)
750
756
            except errors.NoWorkingTree:
751
757
                base_branch, base_path = Branch.open_containing(
752
 
                                            file_ids_from)
 
758
                    file_ids_from)
753
759
                base_tree = base_branch.basis_tree()
754
760
 
755
 
            action = breezy.add.AddFromBaseAction(base_tree, base_path,
756
 
                          to_file=self.outf, should_print=(not is_quiet()))
757
 
        else:
758
 
            action = breezy.add.AddWithSkipLargeAction(to_file=self.outf,
 
761
            action = breezy.add.AddFromBaseAction(
 
762
                base_tree, base_path, to_file=self.outf,
759
763
                should_print=(not is_quiet()))
 
764
        else:
 
765
            action = breezy.add.AddWithSkipLargeAction(
 
766
                to_file=self.outf, should_print=(not is_quiet()))
760
767
 
761
768
        if base_tree:
762
769
            self.add_cleanup(base_tree.lock_read().unlock)
763
770
        tree, file_list = tree_files_for_add(file_list)
764
 
        added, ignored = tree.smart_add(file_list, not
765
 
            no_recurse, action=action, save=not dry_run)
 
771
        added, ignored = tree.smart_add(
 
772
            file_list, not no_recurse, action=action, save=not dry_run)
766
773
        self.cleanup_now()
767
774
        if len(ignored) > 0:
768
775
            if verbose:
769
776
                for glob in sorted(ignored):
770
777
                    for path in ignored[glob]:
771
778
                        self.outf.write(
772
 
                         gettext("ignored {0} matching \"{1}\"\n").format(
773
 
                         path, glob))
 
779
                            gettext("ignored {0} matching \"{1}\"\n").format(
 
780
                                path, glob))
774
781
 
775
782
 
776
783
class cmd_mkdir(Command):
851
858
        'revision',
852
859
        'show-ids',
853
860
        Option('kind',
854
 
               help='List entries of a particular kind: file, directory, symlink.',
 
861
               help='List entries of a particular kind: file, directory, '
 
862
                    'symlink.',
855
863
               type=text_type),
856
864
        ]
857
865
    takes_args = ['file*']
859
867
    @display_command
860
868
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
861
869
        if kind and kind not in ['file', 'directory', 'symlink']:
862
 
            raise errors.BzrCommandError(gettext('invalid kind %r specified') % (kind,))
 
870
            raise errors.BzrCommandError(
 
871
                gettext('invalid kind %r specified') % (kind,))
863
872
 
864
873
        revision = _get_one_revision('inventory', revision)
865
874
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
876
885
        self.add_cleanup(tree.lock_read().unlock)
877
886
        if file_list is not None:
878
887
            paths = tree.find_related_paths_across_trees(
879
 
                    file_list, extra_trees, require_versioned=True)
 
888
                file_list, extra_trees, require_versioned=True)
880
889
            # find_ids_across_trees may include some paths that don't
881
890
            # exist in 'tree'.
882
891
            entries = tree.iter_entries_by_dir(specific_files=paths)
889
898
            if path == "":
890
899
                continue
891
900
            if show_ids:
892
 
                self.outf.write('%-50s %s\n' % (path, entry.file_id.decode('utf-8')))
 
901
                self.outf.write('%-50s %s\n' % (
 
902
                    path, entry.file_id.decode('utf-8')))
893
903
            else:
894
904
                self.outf.write(path)
895
905
                self.outf.write('\n')
917
927
    encoding_type = 'replace'
918
928
 
919
929
    def run(self, names_list):
920
 
        import shutil
921
930
        if names_list is None:
922
931
            names_list = []
923
932
        if len(names_list) < 2:
924
933
            raise errors.BzrCommandError(gettext("missing file argument"))
925
 
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
 
934
        tree, rel_names = WorkingTree.open_containing_paths(
 
935
            names_list, canonicalize=False)
926
936
        for file_name in rel_names[0:-1]:
927
937
            if file_name == '':
928
 
                raise errors.BzrCommandError(gettext("can not copy root of branch"))
 
938
                raise errors.BzrCommandError(
 
939
                    gettext("can not copy root of branch"))
929
940
        self.add_cleanup(tree.lock_tree_write().unlock)
930
941
        into_existing = osutils.isdir(names_list[-1])
931
942
        if not into_existing:
932
943
            try:
933
944
                (src, dst) = rel_names
934
945
            except IndexError:
935
 
                raise errors.BzrCommandError(gettext('to copy multiple files the'
936
 
                                                     ' destination must be a versioned'
937
 
                                                     ' directory'))
 
946
                raise errors.BzrCommandError(
 
947
                    gettext('to copy multiple files the'
 
948
                            ' destination must be a versioned'
 
949
                            ' directory'))
938
950
            pairs = [(src, dst)]
939
951
        else:
940
 
            pairs = [(n, osutils.joinpath([rel_names[-1], osutils.basename(n)]))
941
 
                     for n in rel_names[:-1]]
 
952
            pairs = [
 
953
                (n, osutils.joinpath([rel_names[-1], osutils.basename(n)]))
 
954
                for n in rel_names[:-1]]
942
955
 
943
956
        for src, dst in pairs:
944
957
            try:
945
958
                src_kind = tree.stored_kind(src)
946
959
            except errors.NoSuchFile:
947
960
                raise errors.BzrCommandError(
948
 
                        gettext('Could not copy %s => %s: %s is not versioned.')
949
 
                        % (src, dst, src))
 
961
                    gettext('Could not copy %s => %s: %s is not versioned.')
 
962
                    % (src, dst, src))
950
963
            if src_kind is None:
951
964
                raise errors.BzrCommandError(
952
965
                    gettext('Could not copy %s => %s . %s is not versioned\\.'
953
 
                        % (src, dst, src)))
 
966
                            % (src, dst, src)))
954
967
            if src_kind == 'directory':
955
968
                raise errors.BzrCommandError(
956
969
                    gettext('Could not copy %s => %s . %s is a directory.'
957
 
                        % (src, dst, src)))
 
970
                            % (src, dst, src)))
958
971
            dst_parent = osutils.split(dst)[0]
959
972
            if dst_parent != '':
960
973
                try:
961
974
                    dst_parent_kind = tree.stored_kind(dst_parent)
962
975
                except errors.NoSuchFile:
963
976
                    raise errors.BzrCommandError(
964
 
                            gettext('Could not copy %s => %s: %s is not versioned.')
965
 
                            % (src, dst, dst_parent))
 
977
                        gettext('Could not copy %s => %s: %s is not versioned.')
 
978
                        % (src, dst, dst_parent))
966
979
                if dst_parent_kind != 'directory':
967
980
                    raise errors.BzrCommandError(
968
 
                            gettext('Could not copy to %s: %s is not a directory.')
969
 
                            % (dst_parent, dst_parent))
 
981
                        gettext('Could not copy to %s: %s is not a directory.')
 
982
                        % (dst_parent, dst_parent))
970
983
 
971
984
            tree.copy_one(src, dst)
972
985
 
994
1007
 
995
1008
    takes_args = ['names*']
996
1009
    takes_options = [Option("after", help="Move only the brz identifier"
997
 
        " of the file, because the file has already been moved."),
998
 
        Option('auto', help='Automatically guess renames.'),
999
 
        Option('dry-run', help='Avoid making changes when guessing renames.'),
1000
 
        ]
 
1010
                            " of the file, because the file has already been moved."),
 
1011
                     Option('auto', help='Automatically guess renames.'),
 
1012
                     Option(
 
1013
                         'dry-run', help='Avoid making changes when guessing renames.'),
 
1014
                     ]
1001
1015
    aliases = ['move', 'rename']
1002
1016
    encoding_type = 'replace'
1003
1017
 
1010
1024
            names_list = []
1011
1025
        if len(names_list) < 2:
1012
1026
            raise errors.BzrCommandError(gettext("missing file argument"))
1013
 
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
 
1027
        tree, rel_names = WorkingTree.open_containing_paths(
 
1028
            names_list, canonicalize=False)
1014
1029
        for file_name in rel_names[0:-1]:
1015
1030
            if file_name == '':
1016
 
                raise errors.BzrCommandError(gettext("can not move root of branch"))
 
1031
                raise errors.BzrCommandError(
 
1032
                    gettext("can not move root of branch"))
1017
1033
        self.add_cleanup(tree.lock_tree_write().unlock)
1018
1034
        self._run(tree, names_list, rel_names, after)
1019
1035
 
1020
1036
    def run_auto(self, names_list, after, dry_run):
1021
1037
        if names_list is not None and len(names_list) > 1:
1022
 
            raise errors.BzrCommandError(gettext('Only one path may be specified to'
1023
 
                                         ' --auto.'))
 
1038
            raise errors.BzrCommandError(
 
1039
                gettext('Only one path may be specified to --auto.'))
1024
1040
        if after:
1025
 
            raise errors.BzrCommandError(gettext('--after cannot be specified with'
1026
 
                                         ' --auto.'))
 
1041
            raise errors.BzrCommandError(
 
1042
                gettext('--after cannot be specified with --auto.'))
1027
1043
        work_tree, file_list = WorkingTree.open_containing_paths(
1028
1044
            names_list, default_directory='.')
1029
1045
        self.add_cleanup(work_tree.lock_tree_write().unlock)
1030
1046
        rename_map.RenameMap.guess_renames(
1031
 
                work_tree.basis_tree(), work_tree, dry_run)
 
1047
            work_tree.basis_tree(), work_tree, dry_run)
1032
1048
 
1033
1049
    def _run(self, tree, names_list, rel_names, after):
1034
1050
        into_existing = osutils.isdir(names_list[-1])
1039
1055
            #    a directory, but now doesn't exist in the working tree
1040
1056
            #    and the target is an existing directory, just rename it)
1041
1057
            if (not tree.case_sensitive
1042
 
                and rel_names[0].lower() == rel_names[1].lower()):
 
1058
                    and rel_names[0].lower() == rel_names[1].lower()):
1043
1059
                into_existing = False
1044
1060
            else:
1045
1061
                # 'fix' the case of a potential 'from'
1046
1062
                from_path = tree.get_canonical_path(rel_names[0])
1047
1063
                if (not osutils.lexists(names_list[0]) and
1048
1064
                    tree.is_versioned(from_path) and
1049
 
                    tree.stored_kind(from_path) == "directory"):
 
1065
                        tree.stored_kind(from_path) == "directory"):
1050
1066
                    into_existing = False
1051
1067
        # move/rename
1052
1068
        if into_existing:
1060
1076
        else:
1061
1077
            if len(names_list) != 2:
1062
1078
                raise errors.BzrCommandError(gettext('to mv multiple files the'
1063
 
                                             ' destination must be a versioned'
1064
 
                                             ' directory'))
 
1079
                                                     ' destination must be a versioned'
 
1080
                                                     ' directory'))
1065
1081
 
1066
1082
            # for cicp file-systems: the src references an existing inventory
1067
1083
            # item:
1088
1104
                if after:
1089
1105
                    # If 'after' is specified, the tail must refer to a file on disk.
1090
1106
                    if dest_parent:
1091
 
                        dest_parent_fq = osutils.pathjoin(tree.basedir, dest_parent)
 
1107
                        dest_parent_fq = osutils.pathjoin(
 
1108
                            tree.basedir, dest_parent)
1092
1109
                    else:
1093
1110
                        # pathjoin with an empty tail adds a slash, which breaks
1094
1111
                        # relpath :(
1095
1112
                        dest_parent_fq = tree.basedir
1096
1113
 
1097
1114
                    dest_tail = osutils.canonical_relpath(
1098
 
                                    dest_parent_fq,
1099
 
                                    osutils.pathjoin(dest_parent_fq, spec_tail))
 
1115
                        dest_parent_fq,
 
1116
                        osutils.pathjoin(dest_parent_fq, spec_tail))
1100
1117
                else:
1101
1118
                    # not 'after', so case as specified is used
1102
1119
                    dest_tail = spec_tail
1114
1131
    __doc__ = """Turn this branch into a mirror of another branch.
1115
1132
 
1116
1133
    By default, this command only works on branches that have not diverged.
1117
 
    Branches are considered diverged if the destination branch's most recent 
1118
 
    commit is one that has not been merged (directly or indirectly) into the 
 
1134
    Branches are considered diverged if the destination branch's most recent
 
1135
    commit is one that has not been merged (directly or indirectly) into the
1119
1136
    parent.
1120
1137
 
1121
1138
    If branches have diverged, you can use 'brz merge' to integrate the changes
1142
1159
 
1143
1160
    _see_also = ['push', 'update', 'status-flags', 'send']
1144
1161
    takes_options = ['remember', 'overwrite', 'revision',
1145
 
        custom_help('verbose',
1146
 
            help='Show logs of pulled revisions.'),
1147
 
        custom_help('directory',
1148
 
            help='Branch to pull into, '
1149
 
                 'rather than the one containing the working directory.'),
1150
 
        Option('local',
1151
 
            help="Perform a local pull in a bound "
1152
 
                 "branch.  Local pulls are not applied to "
1153
 
                 "the master branch."
1154
 
            ),
1155
 
        Option('show-base',
1156
 
            help="Show base revision text in conflicts."),
1157
 
        Option('overwrite-tags',
1158
 
            help="Overwrite tags only."),
1159
 
        ]
 
1162
                     custom_help('verbose',
 
1163
                                 help='Show logs of pulled revisions.'),
 
1164
                     custom_help('directory',
 
1165
                                 help='Branch to pull into, '
 
1166
                                 'rather than the one containing the working directory.'),
 
1167
                     Option('local',
 
1168
                            help="Perform a local pull in a bound "
 
1169
                            "branch.  Local pulls are not applied to "
 
1170
                            "the master branch."
 
1171
                            ),
 
1172
                     Option('show-base',
 
1173
                            help="Show base revision text in conflicts."),
 
1174
                     Option('overwrite-tags',
 
1175
                            help="Overwrite tags only."),
 
1176
                     ]
1160
1177
    takes_args = ['location?']
1161
1178
    encoding_type = 'replace'
1162
1179
 
1194
1211
        if location is not None:
1195
1212
            try:
1196
1213
                mergeable = bundle.read_mergeable_from_url(location,
1197
 
                    possible_transports=possible_transports)
 
1214
                                                           possible_transports=possible_transports)
1198
1215
            except errors.NotABundle:
1199
1216
                mergeable = None
1200
1217
 
1202
1219
        if location is None:
1203
1220
            if stored_loc is None:
1204
1221
                raise errors.BzrCommandError(gettext("No pull location known or"
1205
 
                                             " specified."))
 
1222
                                                     " specified."))
1206
1223
            else:
1207
1224
                display_url = urlutils.unescape_for_display(stored_loc,
1208
 
                        self.outf.encoding)
 
1225
                                                            self.outf.encoding)
1209
1226
                if not is_quiet():
1210
 
                    self.outf.write(gettext("Using saved parent location: %s\n") % display_url)
 
1227
                    self.outf.write(
 
1228
                        gettext("Using saved parent location: %s\n") % display_url)
1211
1229
                location = stored_loc
1212
1230
 
1213
1231
        revision = _get_one_revision('pull', revision)
1221
1239
            branch_from = branch_to
1222
1240
        else:
1223
1241
            branch_from = Branch.open(location,
1224
 
                possible_transports=possible_transports)
 
1242
                                      possible_transports=possible_transports)
1225
1243
            self.add_cleanup(branch_from.lock_read().unlock)
1226
1244
            # Remembers if asked explicitly or no previous location is set
1227
1245
            if (remember
1228
 
                or (remember is None and branch_to.get_parent() is None)):
 
1246
                    or (remember is None and branch_to.get_parent() is None)):
1229
1247
                # FIXME: This shouldn't be done before the pull
1230
1248
                # succeeds... -- vila 2012-01-02
1231
1249
                branch_to.set_parent(branch_from.base)
1288
1306
 
1289
1307
    _see_also = ['pull', 'update', 'working-trees']
1290
1308
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
1291
 
        Option('create-prefix',
1292
 
               help='Create the path leading up to the branch '
1293
 
                    'if it does not already exist.'),
1294
 
        custom_help('directory',
1295
 
            help='Branch to push from, '
1296
 
                 'rather than the one containing the working directory.'),
1297
 
        Option('use-existing-dir',
1298
 
               help='By default push will fail if the target'
1299
 
                    ' directory exists, but does not already'
1300
 
                    ' have a control directory.  This flag will'
1301
 
                    ' allow push to proceed.'),
1302
 
        Option('stacked',
1303
 
            help='Create a stacked branch that references the public location '
1304
 
                'of the parent branch.'),
1305
 
        Option('stacked-on',
1306
 
            help='Create a stacked branch that refers to another branch '
1307
 
                'for the commit history. Only the work not present in the '
1308
 
                'referenced branch is included in the branch created.',
1309
 
            type=text_type),
1310
 
        Option('strict',
1311
 
               help='Refuse to push if there are uncommitted changes in'
1312
 
               ' the working tree, --no-strict disables the check.'),
1313
 
        Option('no-tree',
1314
 
               help="Don't populate the working tree, even for protocols"
1315
 
               " that support it."),
1316
 
        Option('overwrite-tags',
1317
 
              help="Overwrite tags only."),
1318
 
        Option('lossy', help="Allow lossy push, i.e. dropping metadata "
1319
 
                             "that can't be represented in the target.")
1320
 
        ]
 
1309
                     Option('create-prefix',
 
1310
                            help='Create the path leading up to the branch '
 
1311
                            'if it does not already exist.'),
 
1312
                     custom_help('directory',
 
1313
                                 help='Branch to push from, '
 
1314
                                 'rather than the one containing the working directory.'),
 
1315
                     Option('use-existing-dir',
 
1316
                            help='By default push will fail if the target'
 
1317
                            ' directory exists, but does not already'
 
1318
                            ' have a control directory.  This flag will'
 
1319
                            ' allow push to proceed.'),
 
1320
                     Option('stacked',
 
1321
                            help='Create a stacked branch that references the public location '
 
1322
                            'of the parent branch.'),
 
1323
                     Option('stacked-on',
 
1324
                            help='Create a stacked branch that refers to another branch '
 
1325
                            'for the commit history. Only the work not present in the '
 
1326
                            'referenced branch is included in the branch created.',
 
1327
                            type=text_type),
 
1328
                     Option('strict',
 
1329
                            help='Refuse to push if there are uncommitted changes in'
 
1330
                            ' the working tree, --no-strict disables the check.'),
 
1331
                     Option('no-tree',
 
1332
                            help="Don't populate the working tree, even for protocols"
 
1333
                            " that support it."),
 
1334
                     Option('overwrite-tags',
 
1335
                            help="Overwrite tags only."),
 
1336
                     Option('lossy', help="Allow lossy push, i.e. dropping metadata "
 
1337
                            "that can't be represented in the target.")
 
1338
                     ]
1321
1339
    takes_args = ['location?']
1322
1340
    encoding_type = 'replace'
1323
1341
 
1324
1342
    def run(self, location=None, remember=None, overwrite=False,
1325
 
        create_prefix=False, verbose=False, revision=None,
1326
 
        use_existing_dir=False, directory=None, stacked_on=None,
1327
 
        stacked=False, strict=None, no_tree=False,
1328
 
        overwrite_tags=False, lossy=False):
 
1343
            create_prefix=False, verbose=False, revision=None,
 
1344
            use_existing_dir=False, directory=None, stacked_on=None,
 
1345
            stacked=False, strict=None, no_tree=False,
 
1346
            overwrite_tags=False, lossy=False):
1329
1347
        from .push import _show_push_branch
1330
1348
 
1331
1349
        if overwrite:
1379
1397
                        "No push location known or specified. To push to the "
1380
1398
                        "parent branch (at %s), use 'brz push :parent'." %
1381
1399
                        urlutils.unescape_for_display(parent_loc,
1382
 
                            self.outf.encoding)))
 
1400
                                                      self.outf.encoding)))
1383
1401
                else:
1384
1402
                    raise errors.BzrCommandError(gettext(
1385
1403
                        "No push location known or specified."))
1386
1404
            else:
1387
1405
                display_url = urlutils.unescape_for_display(stored_loc,
1388
 
                        self.outf.encoding)
 
1406
                                                            self.outf.encoding)
1389
1407
                note(gettext("Using saved push location: %s") % display_url)
1390
1408
                location = stored_loc
1391
1409
 
1392
1410
        _show_push_branch(br_from, revision_id, location, self.outf,
1393
 
            verbose=verbose, overwrite=overwrite, remember=remember,
1394
 
            stacked_on=stacked_on, create_prefix=create_prefix,
1395
 
            use_existing_dir=use_existing_dir, no_tree=no_tree,
1396
 
            lossy=lossy)
 
1411
                          verbose=verbose, overwrite=overwrite, remember=remember,
 
1412
                          stacked_on=stacked_on, create_prefix=create_prefix,
 
1413
                          use_existing_dir=use_existing_dir, no_tree=no_tree,
 
1414
                          lossy=lossy)
1397
1415
 
1398
1416
 
1399
1417
class cmd_branch(Command):
1413
1431
    _see_also = ['checkout']
1414
1432
    takes_args = ['from_location', 'to_location?']
1415
1433
    takes_options = ['revision',
1416
 
        Option('hardlink', help='Hard-link working tree files where possible.'),
1417
 
        Option('files-from', type=text_type,
1418
 
               help="Get file contents from this tree."),
1419
 
        Option('no-tree',
1420
 
            help="Create a branch without a working-tree."),
1421
 
        Option('switch',
1422
 
            help="Switch the checkout in the current directory "
1423
 
                 "to the new branch."),
1424
 
        Option('stacked',
1425
 
            help='Create a stacked branch referring to the source branch. '
1426
 
                'The new branch will depend on the availability of the source '
1427
 
                'branch for all operations.'),
1428
 
        Option('standalone',
1429
 
               help='Do not use a shared repository, even if available.'),
1430
 
        Option('use-existing-dir',
1431
 
               help='By default branch will fail if the target'
1432
 
                    ' directory exists, but does not already'
1433
 
                    ' have a control directory.  This flag will'
1434
 
                    ' allow branch to proceed.'),
1435
 
        Option('bind',
1436
 
            help="Bind new branch to from location."),
1437
 
        ]
 
1434
                     Option(
 
1435
                         'hardlink', help='Hard-link working tree files where possible.'),
 
1436
                     Option('files-from', type=text_type,
 
1437
                            help="Get file contents from this tree."),
 
1438
                     Option('no-tree',
 
1439
                            help="Create a branch without a working-tree."),
 
1440
                     Option('switch',
 
1441
                            help="Switch the checkout in the current directory "
 
1442
                            "to the new branch."),
 
1443
                     Option('stacked',
 
1444
                            help='Create a stacked branch referring to the source branch. '
 
1445
                            'The new branch will depend on the availability of the source '
 
1446
                            'branch for all operations.'),
 
1447
                     Option('standalone',
 
1448
                            help='Do not use a shared repository, even if available.'),
 
1449
                     Option('use-existing-dir',
 
1450
                            help='By default branch will fail if the target'
 
1451
                            ' directory exists, but does not already'
 
1452
                            ' have a control directory.  This flag will'
 
1453
                            ' allow branch to proceed.'),
 
1454
                     Option('bind',
 
1455
                            help="Bind new branch to from location."),
 
1456
                     ]
1438
1457
 
1439
1458
    def run(self, from_location, to_location=None, revision=None,
1440
1459
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1461
1480
            revision_id = br_from.last_revision()
1462
1481
        if to_location is None:
1463
1482
            to_location = urlutils.derive_to_location(from_location)
1464
 
        to_transport = transport.get_transport(to_location)
 
1483
        to_transport = transport.get_transport(to_location, purpose='write')
1465
1484
        try:
1466
1485
            to_transport.mkdir('.')
1467
1486
        except errors.FileExists:
1471
1490
            except errors.NotBranchError:
1472
1491
                if not use_existing_dir:
1473
1492
                    raise errors.BzrCommandError(gettext('Target directory "%s" '
1474
 
                        'already exists.') % to_location)
 
1493
                                                         'already exists.') % to_location)
1475
1494
                else:
1476
1495
                    to_dir = None
1477
1496
            else:
1517
1536
        # We therefore need a try/except here and not just 'if stacked:'
1518
1537
        try:
1519
1538
            note(gettext('Created new stacked branch referring to %s.') %
1520
 
                branch.get_stacked_on_url())
 
1539
                 branch.get_stacked_on_url())
1521
1540
        except (errors.NotStacked, _mod_branch.UnstackableBranchFormat,
1522
 
            errors.UnstackableRepositoryFormat) as e:
1523
 
            note(ngettext('Branched %d revision.', 'Branched %d revisions.', branch.revno()) % branch.revno())
 
1541
                errors.UnstackableRepositoryFormat) as e:
 
1542
            revno = branch.revno()
 
1543
            if revno is not None:
 
1544
                note(ngettext('Branched %d revision.',
 
1545
                              'Branched %d revisions.',
 
1546
                              branch.revno()) % revno)
 
1547
            else:
 
1548
                note(gettext('Created new branch.'))
1524
1549
        if bind:
1525
1550
            # Bind to the parent
1526
1551
            parent_branch = Branch.open(from_location)
1531
1556
            wt, _ = WorkingTree.open_containing('.')
1532
1557
            _mod_switch.switch(wt.controldir, branch)
1533
1558
            note(gettext('Switched to branch: %s'),
1534
 
                urlutils.unescape_for_display(branch.base, 'utf-8'))
 
1559
                 urlutils.unescape_for_display(branch.base, 'utf-8'))
1535
1560
 
1536
1561
 
1537
1562
class cmd_branches(Command):
1543
1568
 
1544
1569
    takes_args = ['location?']
1545
1570
    takes_options = [
1546
 
                  Option('recursive', short_name='R',
1547
 
                         help='Recursively scan for branches rather than '
1548
 
                              'just looking in the specified location.')]
 
1571
        Option('recursive', short_name='R',
 
1572
               help='Recursively scan for branches rather than '
 
1573
               'just looking in the specified location.')]
1549
1574
 
1550
1575
    def run(self, location=".", recursive=False):
1551
1576
        if recursive:
1552
 
            t = transport.get_transport(location)
 
1577
            t = transport.get_transport(location, purpose='read')
1553
1578
            if not t.listable():
1554
1579
                raise errors.BzrCommandError(
1555
1580
                    "Can't scan this type of location.")
1587
1612
class cmd_checkout(Command):
1588
1613
    __doc__ = """Create a new checkout of an existing branch.
1589
1614
 
1590
 
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
1591
 
    the branch found in '.'. This is useful if you have removed the working tree
1592
 
    or if it was never created - i.e. if you pushed the branch to its current
1593
 
    location using SFTP.
 
1615
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree
 
1616
    for the branch found in '.'. This is useful if you have removed the working
 
1617
    tree or if it was never created - i.e. if you pushed the branch to its
 
1618
    current location using SFTP.
1594
1619
 
1595
 
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
1596
 
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
1597
 
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
1598
 
    is derived from the BRANCH_LOCATION by stripping a leading scheme or drive
1599
 
    identifier, if any. For example, "checkout lp:foo-bar" will attempt to
1600
 
    create ./foo-bar.
 
1620
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION
 
1621
    will be used.  In other words, "checkout ../foo/bar" will attempt to create
 
1622
    ./bar.  If the BRANCH_LOCATION has no / or path separator embedded, the
 
1623
    TO_LOCATION is derived from the BRANCH_LOCATION by stripping a leading
 
1624
    scheme or drive identifier, if any. For example, "checkout lp:foo-bar" will
 
1625
    attempt to create ./foo-bar.
1601
1626
 
1602
1627
    To retrieve the branch as of a particular revision, supply the --revision
1603
 
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
1604
 
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
1605
 
    code.)
 
1628
    parameter, as in "checkout foo/bar -r 5". Note that this will be
 
1629
    immediately out of date [so you cannot commit] but it may be useful (i.e.
 
1630
    to examine old code.)
1606
1631
    """
1607
1632
 
1608
1633
    _see_also = ['checkouts', 'branch', 'working-trees', 'remove-tree']
1647
1672
        # if the source and to_location are the same,
1648
1673
        # and there is no working tree,
1649
1674
        # then reconstitute a branch
1650
 
        if (osutils.abspath(to_location) ==
1651
 
            osutils.abspath(branch_location)):
 
1675
        if osutils.abspath(to_location) == osutils.abspath(branch_location):
1652
1676
            try:
1653
1677
                source.controldir.open_workingtree()
1654
1678
            except errors.NoWorkingTree:
1691
1715
 
1692
1716
    This will perform a merge of the destination revision (the tip of the
1693
1717
    branch, or the specified revision) into the working tree, and then make
1694
 
    that revision the basis revision for the working tree.  
 
1718
    that revision the basis revision for the working tree.
1695
1719
 
1696
1720
    You can use this to visit an older revision, or to update a working tree
1697
1721
    that is out of date from its branch.
1698
 
    
 
1722
 
1699
1723
    If there are any uncommitted changes in the tree, they will be carried
1700
1724
    across and remain as uncommitted changes after the update.  To discard
1701
1725
    these changes, use 'brz revert'.  The uncommitted changes may conflict
1712
1736
    out the old content of that file to a new location.
1713
1737
 
1714
1738
    The 'dir' argument, if given, must be the location of the root of a
1715
 
    working tree to update.  By default, the working tree that contains the 
 
1739
    working tree to update.  By default, the working tree that contains the
1716
1740
    current working directory is used.
1717
1741
    """
1718
1742
 
1767
1791
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
1768
1792
            revno = branch.revision_id_to_dotted_revno(revision_id)
1769
1793
            note(gettext("Tree is up to date at revision {0} of branch {1}"
1770
 
                        ).format('.'.join(map(str, revno)), branch_location))
 
1794
                         ).format('.'.join(map(str, revno)), branch_location))
1771
1795
            return 0
1772
1796
        view_info = _get_view_info_for_change_reporter(tree)
1773
1797
        change_reporter = delta._ChangeReporter(
1782
1806
                show_base=show_base)
1783
1807
        except errors.NoSuchRevision as e:
1784
1808
            raise errors.BzrCommandError(gettext(
1785
 
                                  "branch has no revision %s\n"
1786
 
                                  "brz update --revision only works"
1787
 
                                  " for a revision in the branch history")
1788
 
                                  % (e.revision))
 
1809
                "branch has no revision %s\n"
 
1810
                "brz update --revision only works"
 
1811
                " for a revision in the branch history")
 
1812
                % (e.revision))
1789
1813
        revno = tree.branch.revision_id_to_dotted_revno(
1790
1814
            _mod_revision.ensure_null(tree.last_revision()))
1791
1815
        note(gettext('Updated to revision {0} of branch {1}').format(
1793
1817
        parent_ids = tree.get_parent_ids()
1794
1818
        if parent_ids[1:] and parent_ids[1:] != existing_pending_merges:
1795
1819
            note(gettext('Your local commits will now show as pending merges with '
1796
 
                 "'brz status', and can be committed with 'brz commit'."))
 
1820
                         "'brz status', and can be committed with 'brz commit'."))
1797
1821
        if conflicts != 0:
1798
1822
            return 1
1799
1823
        else:
1855
1879
    """
1856
1880
    takes_args = ['file*']
1857
1881
    takes_options = ['verbose',
1858
 
        Option('new', help='Only remove files that have never been committed.'),
1859
 
        RegistryOption.from_kwargs('file-deletion-strategy',
1860
 
            'The file deletion mode to be used.',
1861
 
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1862
 
            safe='Backup changed files (default).',
1863
 
            keep='Delete from brz but leave the working copy.',
1864
 
            no_backup='Don\'t backup changed files.'),
1865
 
        ]
 
1882
                     Option(
 
1883
                         'new', help='Only remove files that have never been committed.'),
 
1884
                     RegistryOption.from_kwargs('file-deletion-strategy',
 
1885
                                                'The file deletion mode to be used.',
 
1886
                                                title='Deletion Strategy', value_switches=True, enum_switch=False,
 
1887
                                                safe='Backup changed files (default).',
 
1888
                                                keep='Delete from brz but leave the working copy.',
 
1889
                                                no_backup='Don\'t backup changed files.'),
 
1890
                     ]
1866
1891
    aliases = ['rm', 'del']
1867
1892
    encoding_type = 'replace'
1868
1893
 
1869
1894
    def run(self, file_list, verbose=False, new=False,
1870
 
        file_deletion_strategy='safe'):
 
1895
            file_deletion_strategy='safe'):
1871
1896
 
1872
1897
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1873
1898
 
1879
1904
        # some such?
1880
1905
        if new:
1881
1906
            added = tree.changes_from(tree.basis_tree(),
1882
 
                specific_files=file_list).added
 
1907
                                      specific_files=file_list).added
1883
1908
            file_list = sorted([f[0] for f in added], reverse=True)
1884
1909
            if len(file_list) == 0:
1885
1910
                raise errors.BzrCommandError(gettext('No matching files.'))
1894
1919
            file_list = sorted(missing, reverse=True)
1895
1920
            file_deletion_strategy = 'keep'
1896
1921
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1897
 
            keep_files=file_deletion_strategy=='keep',
1898
 
            force=(file_deletion_strategy=='no-backup'))
1899
 
 
1900
 
 
1901
 
class cmd_file_id(Command):
1902
 
    __doc__ = """Print file_id of a particular file or directory.
1903
 
 
1904
 
    The file_id is assigned when the file is first added and remains the
1905
 
    same through all revisions where the file exists, even when it is
1906
 
    moved or renamed.
1907
 
    """
1908
 
 
1909
 
    hidden = True
1910
 
    _see_also = ['inventory', 'ls']
1911
 
    takes_args = ['filename']
1912
 
 
1913
 
    @display_command
1914
 
    def run(self, filename):
1915
 
        tree, relpath = WorkingTree.open_containing(filename)
1916
 
        file_id = tree.path2id(relpath)
1917
 
        if file_id is None:
1918
 
            raise errors.NotVersionedError(filename)
1919
 
        else:
1920
 
            self.outf.write(file_id.decode('utf-8') + '\n')
1921
 
 
1922
 
 
1923
 
class cmd_file_path(Command):
1924
 
    __doc__ = """Print path of file_ids to a file or directory.
1925
 
 
1926
 
    This prints one line for each directory down to the target,
1927
 
    starting at the branch root.
1928
 
    """
1929
 
 
1930
 
    hidden = True
1931
 
    takes_args = ['filename']
1932
 
 
1933
 
    @display_command
1934
 
    def run(self, filename):
1935
 
        tree, relpath = WorkingTree.open_containing(filename)
1936
 
        fid = tree.path2id(relpath)
1937
 
        if fid is None:
1938
 
            raise errors.NotVersionedError(filename)
1939
 
        segments = osutils.splitpath(relpath)
1940
 
        for pos in range(1, len(segments) + 1):
1941
 
            path = osutils.joinpath(segments[:pos])
1942
 
            self.outf.write("%s\n" % tree.path2id(path))
 
1922
                    keep_files=file_deletion_strategy == 'keep',
 
1923
                    force=(file_deletion_strategy == 'no-backup'))
1943
1924
 
1944
1925
 
1945
1926
class cmd_reconcile(Command):
1990
1971
        self.add_cleanup(branch.lock_read().unlock)
1991
1972
        graph = branch.repository.get_graph()
1992
1973
        history = list(graph.iter_lefthand_ancestry(branch.last_revision(),
1993
 
            [_mod_revision.NULL_REVISION]))
 
1974
                                                    [_mod_revision.NULL_REVISION]))
1994
1975
        for revid in reversed(history):
1995
1976
            self.outf.write(revid)
1996
1977
            self.outf.write('\n')
2018
1999
        self.add_cleanup(b.repository.lock_read().unlock)
2019
2000
        graph = b.repository.get_graph()
2020
2001
        revisions = [revid for revid, parents in
2021
 
            graph.iter_ancestry([last_revision])]
 
2002
                     graph.iter_ancestry([last_revision])]
2022
2003
        for revision_id in reversed(revisions):
2023
2004
            if _mod_revision.is_null(revision_id):
2024
2005
                continue
2054
2035
        Option('create-prefix',
2055
2036
               help='Create the path leading up to the branch '
2056
2037
                    'if it does not already exist.'),
2057
 
         RegistryOption('format',
2058
 
                help='Specify a format for this branch. '
2059
 
                'See "help formats" for a full list.',
2060
 
                lazy_registry=('breezy.controldir', 'format_registry'),
2061
 
                converter=lambda name: controldir.format_registry.make_controldir(name),
2062
 
                value_switches=True,
2063
 
                title="Branch format",
2064
 
                ),
2065
 
         Option('append-revisions-only',
2066
 
                help='Never change revnos or the existing log.'
2067
 
                '  Append revisions to it only.'),
2068
 
         Option('no-tree',
2069
 
                'Create a branch without a working tree.')
2070
 
         ]
 
2038
        RegistryOption('format',
 
2039
                       help='Specify a format for this branch. '
 
2040
                       'See "help formats" for a full list.',
 
2041
                       lazy_registry=('breezy.controldir', 'format_registry'),
 
2042
                       converter=lambda name: controldir.format_registry.make_controldir(
 
2043
                            name),
 
2044
                       value_switches=True,
 
2045
                       title="Branch format",
 
2046
                       ),
 
2047
        Option('append-revisions-only',
 
2048
               help='Never change revnos or the existing log.'
 
2049
               '  Append revisions to it only.'),
 
2050
        Option('no-tree',
 
2051
               'Create a branch without a working tree.')
 
2052
        ]
 
2053
 
2071
2054
    def run(self, location=None, format=None, append_revisions_only=False,
2072
2055
            create_prefix=False, no_tree=False):
2073
2056
        if format is None:
2075
2058
        if location is None:
2076
2059
            location = u'.'
2077
2060
 
2078
 
        to_transport = transport.get_transport(location)
 
2061
        to_transport = transport.get_transport(location, purpose='write')
2079
2062
 
2080
2063
        # The path has to exist to initialize a
2081
2064
        # branch inside of it.
2087
2070
        except errors.NoSuchFile:
2088
2071
            if not create_prefix:
2089
2072
                raise errors.BzrCommandError(gettext("Parent directory of %s"
2090
 
                    " does not exist."
2091
 
                    "\nYou may supply --create-prefix to create all"
2092
 
                    " leading parent directories.")
2093
 
                    % location)
 
2073
                                                     " does not exist."
 
2074
                                                     "\nYou may supply --create-prefix to create all"
 
2075
                                                     " leading parent directories.")
 
2076
                                             % location)
2094
2077
            to_transport.create_prefix()
2095
2078
 
2096
2079
        try:
2097
 
            a_controldir = controldir.ControlDir.open_from_transport(to_transport)
 
2080
            a_controldir = controldir.ControlDir.open_from_transport(
 
2081
                to_transport)
2098
2082
        except errors.NotBranchError:
2099
2083
            # really a NotBzrDir error...
2100
2084
            create_branch = controldir.ControlDir.create_branch_convenience
2110
2094
            from .transport.local import LocalTransport
2111
2095
            if a_controldir.has_branch():
2112
2096
                if (isinstance(to_transport, LocalTransport)
2113
 
                    and not a_controldir.has_workingtree()):
2114
 
                        raise errors.BranchExistsWithoutWorkingTree(location)
 
2097
                        and not a_controldir.has_workingtree()):
 
2098
                    raise errors.BranchExistsWithoutWorkingTree(location)
2115
2099
                raise errors.AlreadyBranchError(location)
2116
2100
            branch = a_controldir.create_branch()
2117
2101
            if not no_tree and not a_controldir.has_workingtree():
2121
2105
                branch.set_append_revisions_only(True)
2122
2106
            except errors.UpgradeRequired:
2123
2107
                raise errors.BzrCommandError(gettext('This branch format cannot be set'
2124
 
                    ' to append-revisions-only.  Try --default.'))
 
2108
                                                     ' to append-revisions-only.  Try --default.'))
2125
2109
        if not is_quiet():
2126
2110
            from .info import describe_layout, describe_format
2127
2111
            try:
2132
2116
            layout = describe_layout(repository, branch, tree).lower()
2133
2117
            format = describe_format(a_controldir, repository, branch, tree)
2134
2118
            self.outf.write(gettext("Created a {0} (format: {1})\n").format(
2135
 
                  layout, format))
 
2119
                layout, format))
2136
2120
            if repository.is_shared():
2137
 
                #XXX: maybe this can be refactored into transport.path_or_url()
 
2121
                # XXX: maybe this can be refactored into transport.path_or_url()
2138
2122
                url = repository.controldir.root_transport.external_url()
2139
2123
                try:
2140
2124
                    url = urlutils.local_path_from_url(url)
2148
2132
 
2149
2133
    New branches created under the repository directory will store their
2150
2134
    revisions in the repository, not in the branch directory.  For branches
2151
 
    with shared history, this reduces the amount of storage needed and 
 
2135
    with shared history, this reduces the amount of storage needed and
2152
2136
    speeds up the creation of new branches.
2153
2137
 
2154
2138
    If the --no-trees option is given then the branches in the repository
2155
 
    will not have working trees by default.  They will still exist as 
2156
 
    directories on disk, but they will not have separate copies of the 
 
2139
    will not have working trees by default.  They will still exist as
 
2140
    directories on disk, but they will not have separate copies of the
2157
2141
    files at a certain revision.  This can be useful for repositories that
2158
2142
    store branches which are interacted with through checkouts or remote
2159
2143
    branches, such as on a server.
2174
2158
    _see_also = ['init', 'branch', 'checkout', 'repositories']
2175
2159
    takes_args = ["location"]
2176
2160
    takes_options = [RegistryOption('format',
2177
 
                            help='Specify a format for this repository. See'
2178
 
                                 ' "brz help formats" for details.',
2179
 
                            lazy_registry=('breezy.controldir', 'format_registry'),
2180
 
                            converter=lambda name: controldir.format_registry.make_controldir(name),
2181
 
                            value_switches=True, title='Repository format'),
 
2161
                                    help='Specify a format for this repository. See'
 
2162
                                    ' "brz help formats" for details.',
 
2163
                                    lazy_registry=(
 
2164
                                        'breezy.controldir', 'format_registry'),
 
2165
                                    converter=lambda name: controldir.format_registry.make_controldir(
 
2166
                                        name),
 
2167
                                    value_switches=True, title='Repository format'),
2182
2168
                     Option('no-trees',
2183
 
                             help='Branches in the repository will default to'
2184
 
                                  ' not having a working tree.'),
2185
 
                    ]
 
2169
                            help='Branches in the repository will default to'
 
2170
                            ' not having a working tree.'),
 
2171
                     ]
2186
2172
    aliases = ["init-repo"]
2187
2173
 
2188
2174
    def run(self, location, format=None, no_trees=False):
2192
2178
        if location is None:
2193
2179
            location = '.'
2194
2180
 
2195
 
        to_transport = transport.get_transport(location)
 
2181
        to_transport = transport.get_transport(location, purpose='write')
2196
2182
 
2197
2183
        if format.fixed_components:
2198
2184
            repo_format_name = None
2201
2187
 
2202
2188
        (repo, newdir, require_stacking, repository_policy) = (
2203
2189
            format.initialize_on_transport_ex(to_transport,
2204
 
            create_prefix=True, make_working_trees=not no_trees,
2205
 
            shared_repo=True, force_new_repo=True,
2206
 
            use_existing_dir=True,
2207
 
            repo_format_name=repo_format_name))
 
2190
                                              create_prefix=True, make_working_trees=not no_trees,
 
2191
                                              shared_repo=True, force_new_repo=True,
 
2192
                                              use_existing_dir=True,
 
2193
                                              repo_format_name=repo_format_name))
2208
2194
        if not is_quiet():
2209
2195
            from .info import show_bzrdir_info
2210
2196
            show_bzrdir_info(newdir, verbose=0, outfile=self.outf)
2225
2211
 
2226
2212
    Note that when using the -r argument with a range of revisions, the
2227
2213
    differences are computed between the two specified revisions.  That
2228
 
    is, the command does not show the changes introduced by the first 
2229
 
    revision in the range.  This differs from the interpretation of 
 
2214
    is, the command does not show the changes introduced by the first
 
2215
    revision in the range.  This differs from the interpretation of
2230
2216
    revision ranges used by "brz log" which includes the first revision
2231
2217
    in the range.
2232
2218
 
2258
2244
            brz diff -c2
2259
2245
 
2260
2246
        To see the changes introduced by revision X::
2261
 
        
 
2247
 
2262
2248
            brz diff -cX
2263
2249
 
2264
2250
        Note that in the case of a merge, the -c option shows the changes
2306
2292
               help='Set prefixes added to old and new filenames, as '
2307
2293
                    'two values separated by a colon. (eg "old/:new/").'),
2308
2294
        Option('old',
2309
 
            help='Branch/tree to compare from.',
2310
 
            type=text_type,
2311
 
            ),
 
2295
               help='Branch/tree to compare from.',
 
2296
               type=text_type,
 
2297
               ),
2312
2298
        Option('new',
2313
 
            help='Branch/tree to compare to.',
2314
 
            type=text_type,
2315
 
            ),
 
2299
               help='Branch/tree to compare to.',
 
2300
               type=text_type,
 
2301
               ),
2316
2302
        'revision',
2317
2303
        'change',
2318
2304
        Option('using',
2319
 
            help='Use this command to compare files.',
2320
 
            type=text_type,
2321
 
            ),
 
2305
               help='Use this command to compare files.',
 
2306
               type=text_type,
 
2307
               ),
2322
2308
        RegistryOption('format',
2323
 
            short_name='F',
2324
 
            help='Diff format to use.',
2325
 
            lazy_registry=('breezy.diff', 'format_registry'),
2326
 
            title='Diff format'),
 
2309
                       short_name='F',
 
2310
                       help='Diff format to use.',
 
2311
                       lazy_registry=('breezy.diff', 'format_registry'),
 
2312
                       title='Diff format'),
2327
2313
        Option('context',
2328
 
            help='How many lines of context to show.',
2329
 
            type=int,
2330
 
            ),
 
2314
               help='How many lines of context to show.',
 
2315
               type=int,
 
2316
               ),
2331
2317
        ]
2332
2318
    aliases = ['di', 'dif']
2333
2319
    encoding_type = 'exact'
2337
2323
            prefix=None, old=None, new=None, using=None, format=None,
2338
2324
            context=None):
2339
2325
        from .diff import (get_trees_and_branches_to_diff_locked,
2340
 
            show_diff_trees)
 
2326
                           show_diff_trees)
2341
2327
 
2342
2328
        if prefix == u'0':
2343
2329
            # diff -p0 format
2355
2341
 
2356
2342
        if revision and len(revision) > 2:
2357
2343
            raise errors.BzrCommandError(gettext('brz diff --revision takes exactly'
2358
 
                                         ' one or two revision specifiers'))
 
2344
                                                 ' one or two revision specifiers'))
2359
2345
 
2360
2346
        if using is not None and format is not None:
2361
2347
            raise errors.BzrCommandError(gettext(
2440
2426
        self.add_cleanup(wt.lock_read().unlock)
2441
2427
        basis = wt.basis_tree()
2442
2428
        self.add_cleanup(basis.lock_read().unlock)
2443
 
        root_id = wt.get_root_id()
2444
2429
        for path in wt.all_versioned_paths():
2445
2430
            if basis.has_filename(path):
2446
2431
                continue
2457
2442
class cmd_root(Command):
2458
2443
    __doc__ = """Show the tree root directory.
2459
2444
 
2460
 
    The root is the nearest enclosing directory with a .bzr control
 
2445
    The root is the nearest enclosing directory with a control
2461
2446
    directory."""
2462
2447
 
2463
2448
    takes_args = ['filename?']
 
2449
 
2464
2450
    @display_command
2465
2451
    def run(self, filename=None):
2466
2452
        """Print the branch root."""
2608
2594
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
2609
2595
      bzr-explorer shell, or the Loggerhead web interface.  See the Bazaar
2610
2596
      Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/> and
2611
 
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
 
2597
      <http://wiki.bazaar.canonical.com/IDEIntegration>.
2612
2598
 
2613
2599
      You may find it useful to add the aliases below to ``breezy.conf``::
2614
2600
 
2642
2628
    takes_args = ['file*']
2643
2629
    _see_also = ['log-formats', 'revisionspec']
2644
2630
    takes_options = [
2645
 
            Option('forward',
2646
 
                   help='Show from oldest to newest.'),
2647
 
            'timezone',
2648
 
            custom_help('verbose',
2649
 
                   help='Show files changed in each revision.'),
2650
 
            'show-ids',
2651
 
            'revision',
2652
 
            Option('change',
2653
 
                   type=breezy.option._parse_revision_str,
2654
 
                   short_name='c',
2655
 
                   help='Show just the specified revision.'
2656
 
                   ' See also "help revisionspec".'),
2657
 
            'log-format',
2658
 
            RegistryOption('authors',
2659
 
                'What names to list as authors - first, all or committer.',
2660
 
                title='Authors',
2661
 
                lazy_registry=('breezy.log', 'author_list_registry'),
2662
 
            ),
2663
 
            Option('levels',
2664
 
                   short_name='n',
2665
 
                   help='Number of levels to display - 0 for all, 1 for flat.',
2666
 
                   argname='N',
2667
 
                   type=_parse_levels),
2668
 
            Option('message',
2669
 
                   help='Show revisions whose message matches this '
2670
 
                        'regular expression.',
2671
 
                   type=text_type,
2672
 
                   hidden=True),
2673
 
            Option('limit',
2674
 
                   short_name='l',
2675
 
                   help='Limit the output to the first N revisions.',
2676
 
                   argname='N',
2677
 
                   type=_parse_limit),
2678
 
            Option('show-diff',
2679
 
                   short_name='p',
2680
 
                   help='Show changes made in each revision as a patch.'),
2681
 
            Option('include-merged',
2682
 
                   help='Show merged revisions like --levels 0 does.'),
2683
 
            Option('include-merges', hidden=True,
2684
 
                   help='Historical alias for --include-merged.'),
2685
 
            Option('omit-merges',
2686
 
                   help='Do not report commits with more than one parent.'),
2687
 
            Option('exclude-common-ancestry',
2688
 
                   help='Display only the revisions that are not part'
2689
 
                   ' of both ancestries (require -rX..Y).'
2690
 
                   ),
2691
 
            Option('signatures',
2692
 
                   help='Show digital signature validity.'),
2693
 
            ListOption('match',
2694
 
                short_name='m',
2695
 
                help='Show revisions whose properties match this '
2696
 
                'expression.',
2697
 
                type=text_type),
2698
 
            ListOption('match-message',
2699
 
                   help='Show revisions whose message matches this '
2700
 
                   'expression.',
2701
 
                type=text_type),
2702
 
            ListOption('match-committer',
 
2631
        Option('forward',
 
2632
               help='Show from oldest to newest.'),
 
2633
        'timezone',
 
2634
        custom_help('verbose',
 
2635
                    help='Show files changed in each revision.'),
 
2636
        'show-ids',
 
2637
        'revision',
 
2638
        Option('change',
 
2639
               type=breezy.option._parse_revision_str,
 
2640
               short_name='c',
 
2641
               help='Show just the specified revision.'
 
2642
               ' See also "help revisionspec".'),
 
2643
        'log-format',
 
2644
        RegistryOption('authors',
 
2645
                       'What names to list as authors - first, all or committer.',
 
2646
                       title='Authors',
 
2647
                       lazy_registry=(
 
2648
                           'breezy.log', 'author_list_registry'),
 
2649
                       ),
 
2650
        Option('levels',
 
2651
               short_name='n',
 
2652
               help='Number of levels to display - 0 for all, 1 for flat.',
 
2653
               argname='N',
 
2654
               type=_parse_levels),
 
2655
        Option('message',
 
2656
               help='Show revisions whose message matches this '
 
2657
               'regular expression.',
 
2658
               type=text_type,
 
2659
               hidden=True),
 
2660
        Option('limit',
 
2661
               short_name='l',
 
2662
               help='Limit the output to the first N revisions.',
 
2663
               argname='N',
 
2664
               type=_parse_limit),
 
2665
        Option('show-diff',
 
2666
               short_name='p',
 
2667
               help='Show changes made in each revision as a patch.'),
 
2668
        Option('include-merged',
 
2669
               help='Show merged revisions like --levels 0 does.'),
 
2670
        Option('include-merges', hidden=True,
 
2671
               help='Historical alias for --include-merged.'),
 
2672
        Option('omit-merges',
 
2673
               help='Do not report commits with more than one parent.'),
 
2674
        Option('exclude-common-ancestry',
 
2675
               help='Display only the revisions that are not part'
 
2676
               ' of both ancestries (require -rX..Y).'
 
2677
               ),
 
2678
        Option('signatures',
 
2679
               help='Show digital signature validity.'),
 
2680
        ListOption('match',
 
2681
                   short_name='m',
 
2682
                   help='Show revisions whose properties match this '
 
2683
                   'expression.',
 
2684
                   type=text_type),
 
2685
        ListOption('match-message',
 
2686
                   help='Show revisions whose message matches this '
 
2687
                   'expression.',
 
2688
                   type=text_type),
 
2689
        ListOption('match-committer',
2703
2690
                   help='Show revisions whose committer matches this '
2704
2691
                   'expression.',
2705
 
                type=text_type),
2706
 
            ListOption('match-author',
 
2692
                   type=text_type),
 
2693
        ListOption('match-author',
2707
2694
                   help='Show revisions whose authors match this '
2708
2695
                   'expression.',
2709
 
                type=text_type),
2710
 
            ListOption('match-bugs',
 
2696
                   type=text_type),
 
2697
        ListOption('match-bugs',
2711
2698
                   help='Show revisions whose bugs match this '
2712
2699
                   'expression.',
2713
 
                type=text_type)
2714
 
            ]
 
2700
                   type=text_type)
 
2701
        ]
2715
2702
    encoding_type = 'replace'
2716
2703
 
2717
2704
    @display_command
2746
2733
        if include_merged is None:
2747
2734
            include_merged = False
2748
2735
        if (exclude_common_ancestry
2749
 
            and (revision is None or len(revision) != 2)):
 
2736
                and (revision is None or len(revision) != 2)):
2750
2737
            raise errors.BzrCommandError(gettext(
2751
2738
                '--exclude-common-ancestry requires -r with two revisions'))
2752
2739
        if include_merged:
2823
2810
        if log_format is None:
2824
2811
            log_format = log.log_formatter_registry.get_default(b)
2825
2812
        # Make a non-encoding output to include the diffs - bug 328007
2826
 
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
 
2813
        unencoded_output = ui.ui_factory.make_output_stream(
 
2814
            encoding_type='exact')
2827
2815
        lf = log_format(show_ids=show_ids, to_file=self.outf,
2828
2816
                        to_exact_file=unencoded_output,
2829
2817
                        show_timezone=timezone,
2846
2834
        # file that isn't a directory without showing a delta" case.
2847
2835
        partial_history = revision and b.repository._format.supports_chks
2848
2836
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2849
 
            or delta_type or partial_history)
 
2837
                              or delta_type or partial_history)
2850
2838
 
2851
2839
        match_dict = {}
2852
2840
        if match:
2922
2910
        rev_id2 = revision_range[1].rev_id
2923
2911
    return rev_id1, rev_id2
2924
2912
 
 
2913
 
2925
2914
def get_log_format(long=False, short=False, line=False, default='long'):
2926
2915
    log_format = default
2927
2916
    if long:
2947
2936
        tree, relpath = WorkingTree.open_containing(filename)
2948
2937
        with tree.lock_read():
2949
2938
            touching_revs = log.find_touching_revisions(
2950
 
                    tree.branch.repository, tree.branch.last_revision(), tree, relpath)
 
2939
                tree.branch.repository, tree.branch.last_revision(), tree, relpath)
2951
2940
            for revno, revision_id, what in reversed(list(touching_revs)):
2952
2941
                self.outf.write("%6d %s\n" % (revno, what))
2953
2942
 
2959
2948
    _see_also = ['status', 'cat']
2960
2949
    takes_args = ['path?']
2961
2950
    takes_options = [
2962
 
            'verbose',
2963
 
            'revision',
2964
 
            Option('recursive', short_name='R',
2965
 
                   help='Recurse into subdirectories.'),
2966
 
            Option('from-root',
2967
 
                   help='Print paths relative to the root of the branch.'),
2968
 
            Option('unknown', short_name='u',
2969
 
                help='Print unknown files.'),
2970
 
            Option('versioned', help='Print versioned files.',
2971
 
                   short_name='V'),
2972
 
            Option('ignored', short_name='i',
2973
 
                help='Print ignored files.'),
2974
 
            Option('kind', short_name='k',
2975
 
                   help='List entries of a particular kind: file, directory, symlink.',
2976
 
                   type=text_type),
2977
 
            'null',
2978
 
            'show-ids',
2979
 
            'directory',
2980
 
            ]
 
2951
        'verbose',
 
2952
        'revision',
 
2953
        Option('recursive', short_name='R',
 
2954
               help='Recurse into subdirectories.'),
 
2955
        Option('from-root',
 
2956
               help='Print paths relative to the root of the branch.'),
 
2957
        Option('unknown', short_name='u',
 
2958
               help='Print unknown files.'),
 
2959
        Option('versioned', help='Print versioned files.',
 
2960
               short_name='V'),
 
2961
        Option('ignored', short_name='i',
 
2962
               help='Print ignored files.'),
 
2963
        Option('kind', short_name='k',
 
2964
               help=('List entries of a particular kind: file, '
 
2965
                     'directory, symlink, tree-reference.'),
 
2966
               type=text_type),
 
2967
        'null',
 
2968
        'show-ids',
 
2969
        'directory',
 
2970
        ]
 
2971
 
2981
2972
    @display_command
2982
2973
    def run(self, revision=None, verbose=False,
2983
2974
            recursive=False, from_root=False,
2988
2979
            raise errors.BzrCommandError(gettext('invalid kind specified'))
2989
2980
 
2990
2981
        if verbose and null:
2991
 
            raise errors.BzrCommandError(gettext('Cannot set both --verbose and --null'))
 
2982
            raise errors.BzrCommandError(
 
2983
                gettext('Cannot set both --verbose and --null'))
2992
2984
        all = not (unknown or versioned or ignored)
2993
2985
 
2994
 
        selection = {'I':ignored, '?':unknown, 'V':versioned}
 
2986
        selection = {'I': ignored, '?': unknown, 'V': versioned}
2995
2987
 
2996
2988
        if path is None:
2997
2989
            fs_path = '.'
2998
2990
        else:
2999
2991
            if from_root:
3000
2992
                raise errors.BzrCommandError(gettext('cannot specify both --from-root'
3001
 
                                             ' and PATH'))
 
2993
                                                     ' and PATH'))
3002
2994
            fs_path = path
3003
2995
        tree, branch, relpath = \
3004
2996
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
3023
3015
                note(gettext("Ignoring files outside view. View is %s") % view_str)
3024
3016
 
3025
3017
        self.add_cleanup(tree.lock_read().unlock)
3026
 
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
3027
 
            from_dir=relpath, recursive=recursive):
 
3018
        for fp, fc, fkind, entry in tree.list_files(
 
3019
                include_root=False, from_dir=relpath, recursive=recursive):
3028
3020
            # Apply additional masking
3029
3021
            if not all and not selection[fc]:
3030
3022
                continue
3048
3040
            ui.ui_factory.clear_term()
3049
3041
            if verbose:
3050
3042
                outstring = '%-8s %s' % (fc, outstring)
3051
 
                if show_ids and fid is not None:
3052
 
                    outstring = "%-50s %s" % (outstring, fid.decode('utf-8'))
 
3043
                if show_ids and getattr(entry, 'file_id', None) is not None:
 
3044
                    outstring = "%-50s %s" % (outstring, entry.file_id.decode('utf-8'))
3053
3045
                self.outf.write(outstring + '\n')
3054
3046
            elif null:
3055
3047
                self.outf.write(fp + '\0')
3056
3048
                if show_ids:
3057
 
                    if fid is not None:
3058
 
                        self.outf.write(fid.decode('utf-8'))
 
3049
                    if getattr(entry, 'file_id', None) is not None:
 
3050
                        self.outf.write(entry.file_id.decode('utf-8'))
3059
3051
                    self.outf.write('\0')
3060
3052
                self.outf.flush()
3061
3053
            else:
3062
3054
                if show_ids:
3063
 
                    if fid is not None:
3064
 
                        my_id = fid.decode('utf-8')
 
3055
                    if getattr(entry, 'file_id', None) is not None:
 
3056
                        my_id = entry.file_id.decode('utf-8')
3065
3057
                    else:
3066
3058
                        my_id = ''
3067
3059
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
3090
3082
 
3091
3083
    If a .bzrignore file does not exist, the ignore command
3092
3084
    will create one and add the specified files or patterns to the newly
3093
 
    created file. The ignore command will also automatically add the 
 
3085
    created file. The ignore command will also automatically add the
3094
3086
    .bzrignore file to be versioned. Creating a .bzrignore file without
3095
3087
    the use of the ignore command will require an explicit add command.
3096
3088
 
3098
3090
    After adding, editing or deleting that file either indirectly by
3099
3091
    using this command or directly by using an editor, be sure to commit
3100
3092
    it.
3101
 
    
 
3093
 
3102
3094
    Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
3103
3095
    the global ignore file can be found in the application data directory as
3104
3096
    C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
3108
3100
    Patterns prefixed with '!' are exceptions to ignore patterns and take
3109
3101
    precedence over regular ignores.  Such exceptions are used to specify
3110
3102
    files that should be versioned which would otherwise be ignored.
3111
 
    
 
3103
 
3112
3104
    Patterns prefixed with '!!' act as regular ignore patterns, but have
3113
3105
    precedence over the '!' exception patterns.
3114
3106
 
3115
 
    :Notes: 
3116
 
        
 
3107
    :Notes:
 
3108
 
3117
3109
    * Ignore patterns containing shell wildcards must be quoted from
3118
3110
      the shell on Unix.
3119
3111
 
3148
3140
        Ignore everything but the "debian" toplevel directory::
3149
3141
 
3150
3142
            brz ignore "RE:(?!debian/).*"
3151
 
        
 
3143
 
3152
3144
        Ignore everything except the "local" toplevel directory,
3153
3145
        but always ignore autosave files ending in ~, even under local/::
3154
 
        
 
3146
 
3155
3147
            brz ignore "*"
3156
3148
            brz ignore "!./local"
3157
3149
            brz ignore "!!*~"
3160
3152
    _see_also = ['status', 'ignored', 'patterns']
3161
3153
    takes_args = ['name_pattern*']
3162
3154
    takes_options = ['directory',
3163
 
        Option('default-rules',
3164
 
               help='Display the default ignore rules that brz uses.')
3165
 
        ]
 
3155
                     Option('default-rules',
 
3156
                            help='Display the default ignore rules that brz uses.')
 
3157
                     ]
3166
3158
 
3167
3159
    def run(self, name_pattern_list=None, default_rules=None,
3168
3160
            directory=u'.'):
3174
3166
            return
3175
3167
        if not name_pattern_list:
3176
3168
            raise errors.BzrCommandError(gettext("ignore requires at least one "
3177
 
                "NAME_PATTERN or --default-rules."))
 
3169
                                                 "NAME_PATTERN or --default-rules."))
3178
3170
        name_pattern_list = [globbing.normalize_pattern(p)
3179
3171
                             for p in name_pattern_list]
3180
3172
        bad_patterns = ''
3184
3176
                bad_patterns_count += 1
3185
3177
                bad_patterns += ('\n  %s' % p)
3186
3178
        if bad_patterns:
3187
 
            msg = (ngettext('Invalid ignore pattern found. %s', 
 
3179
            msg = (ngettext('Invalid ignore pattern found. %s',
3188
3180
                            'Invalid ignore patterns found. %s',
3189
3181
                            bad_patterns_count) % bad_patterns)
3190
3182
            ui.ui_factory.show_error(msg)
3191
3183
            raise lazy_regex.InvalidPattern('')
3192
3184
        for name_pattern in name_pattern_list:
3193
3185
            if (name_pattern[0] == '/' or
3194
 
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
 
3186
                    (len(name_pattern) > 1 and name_pattern[1] == ':')):
3195
3187
                raise errors.BzrCommandError(gettext(
3196
3188
                    "NAME_PATTERN should not be an absolute path"))
3197
3189
        tree, relpath = WorkingTree.open_containing(directory)
3199
3191
        ignored = globbing.Globster(name_pattern_list)
3200
3192
        matches = []
3201
3193
        self.add_cleanup(tree.lock_read().unlock)
3202
 
        for entry in tree.list_files():
3203
 
            id = entry[3]
 
3194
        for filename, fc, fkind, entry in tree.list_files():
 
3195
            id = getattr(entry, 'file_id', None)
3204
3196
            if id is not None:
3205
 
                filename = entry[0]
3206
3197
                if ignored.match(filename):
3207
3198
                    matches.append(filename)
3208
3199
        if len(matches) > 0:
3209
3200
            self.outf.write(gettext("Warning: the following files are version "
3210
 
                  "controlled and match your ignore pattern:\n%s"
3211
 
                  "\nThese files will continue to be version controlled"
3212
 
                  " unless you 'brz remove' them.\n") % ("\n".join(matches),))
 
3201
                                    "controlled and match your ignore pattern:\n%s"
 
3202
                                    "\nThese files will continue to be version controlled"
 
3203
                                    " unless you 'brz remove' them.\n") % ("\n".join(matches),))
3213
3204
 
3214
3205
 
3215
3206
class cmd_ignored(Command):
3231
3222
    def run(self, directory=u'.'):
3232
3223
        tree = WorkingTree.open_containing(directory)[0]
3233
3224
        self.add_cleanup(tree.lock_read().unlock)
3234
 
        for path, file_class, kind, file_id, entry in tree.list_files():
 
3225
        for path, file_class, kind, entry in tree.list_files():
3235
3226
            if file_class != 'I':
3236
3227
                continue
3237
 
            ## XXX: Slightly inefficient since this was already calculated
 
3228
            # XXX: Slightly inefficient since this was already calculated
3238
3229
            pat = tree.is_ignored(path)
3239
3230
            self.outf.write('%-50s %s\n' % (path, pat))
3240
3231
 
3256
3247
        except ValueError:
3257
3248
            raise errors.BzrCommandError(gettext("not a valid revision-number: %r")
3258
3249
                                         % revno)
3259
 
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
 
3250
        revid = WorkingTree.open_containing(
 
3251
            directory)[0].branch.get_rev_id(revno)
3260
3252
        self.outf.write("%s\n" % revid.decode('utf-8'))
3261
3253
 
3262
3254
 
3292
3284
    encoding_type = 'exact'
3293
3285
    takes_args = ['dest', 'branch_or_subdir?']
3294
3286
    takes_options = ['directory',
3295
 
        Option('format',
3296
 
               help="Type of file to export to.",
3297
 
               type=text_type),
3298
 
        'revision',
3299
 
        Option('filters', help='Apply content filters to export the '
3300
 
                'convenient form.'),
3301
 
        Option('root',
3302
 
               type=text_type,
3303
 
               help="Name of the root directory inside the exported file."),
3304
 
        Option('per-file-timestamps',
3305
 
               help='Set modification time of files to that of the last '
3306
 
                    'revision in which it was changed.'),
3307
 
        Option('uncommitted',
3308
 
               help='Export the working tree contents rather than that of the '
3309
 
                    'last revision.'),
3310
 
        ]
 
3287
                     Option('format',
 
3288
                            help="Type of file to export to.",
 
3289
                            type=text_type),
 
3290
                     'revision',
 
3291
                     Option('filters', help='Apply content filters to export the '
 
3292
                            'convenient form.'),
 
3293
                     Option('root',
 
3294
                            type=text_type,
 
3295
                            help="Name of the root directory inside the exported file."),
 
3296
                     Option('per-file-timestamps',
 
3297
                            help='Set modification time of files to that of the last '
 
3298
                            'revision in which it was changed.'),
 
3299
                     Option('uncommitted',
 
3300
                            help='Export the working tree contents rather than that of the '
 
3301
                            'last revision.'),
 
3302
                     ]
 
3303
 
3311
3304
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
3312
 
        root=None, filters=False, per_file_timestamps=False, uncommitted=False,
3313
 
        directory=u'.'):
 
3305
            root=None, filters=False, per_file_timestamps=False, uncommitted=False,
 
3306
            directory=u'.'):
3314
3307
        from .export import export, guess_format, get_root_name
3315
3308
 
3316
3309
        if branch_or_subdir is None:
3328
3321
            export_tree = tree
3329
3322
        else:
3330
3323
            export_tree = _get_one_revision_tree(
3331
 
                    'export', revision, branch=b,
3332
 
                    tree=tree)
 
3324
                'export', revision, branch=b,
 
3325
                tree=tree)
3333
3326
 
3334
3327
        if format is None:
3335
3328
            format = guess_format(dest)
3345
3338
        if filters:
3346
3339
            from breezy.filter_tree import ContentFilterTree
3347
3340
            export_tree = ContentFilterTree(
3348
 
                    export_tree, export_tree._content_filter_stack)
 
3341
                export_tree, export_tree._content_filter_stack)
3349
3342
 
3350
3343
        try:
3351
3344
            export(export_tree, dest, format, root, subdir,
3366
3359
 
3367
3360
    _see_also = ['ls']
3368
3361
    takes_options = ['directory',
3369
 
        Option('name-from-revision', help='The path name in the old tree.'),
3370
 
        Option('filters', help='Apply content filters to display the '
3371
 
                'convenience form.'),
3372
 
        'revision',
3373
 
        ]
 
3362
                     Option('name-from-revision',
 
3363
                            help='The path name in the old tree.'),
 
3364
                     Option('filters', help='Apply content filters to display the '
 
3365
                            'convenience form.'),
 
3366
                     'revision',
 
3367
                     ]
3374
3368
    takes_args = ['filename']
3375
3369
    encoding_type = 'exact'
3376
3370
 
3379
3373
            filters=False, directory=None):
3380
3374
        if revision is not None and len(revision) != 1:
3381
3375
            raise errors.BzrCommandError(gettext("brz cat --revision takes exactly"
3382
 
                                         " one revision specifier"))
 
3376
                                                 " one revision specifier"))
3383
3377
        tree, branch, relpath = \
3384
3378
            _open_directory_or_containing_tree_or_branch(filename, directory)
3385
3379
        self.add_cleanup(branch.lock_read().unlock)
3387
3381
                         name_from_revision, filters)
3388
3382
 
3389
3383
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
3390
 
        filtered):
 
3384
             filtered):
3391
3385
        import shutil
3392
3386
        if tree is None:
3393
3387
            tree = b.basis_tree()
3394
3388
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
3395
3389
        self.add_cleanup(rev_tree.lock_read().unlock)
3396
3390
 
3397
 
        old_file_id = rev_tree.path2id(relpath)
3398
 
 
3399
 
        # TODO: Split out this code to something that generically finds the
3400
 
        # best id for a path across one or more trees; it's like
3401
 
        # find_ids_across_trees but restricted to find just one. -- mbp
3402
 
        # 20110705.
3403
3391
        if name_from_revision:
3404
3392
            # Try in revision if requested
3405
 
            if old_file_id is None:
 
3393
            if not rev_tree.is_versioned(relpath):
3406
3394
                raise errors.BzrCommandError(gettext(
3407
3395
                    "{0!r} is not present in revision {1}").format(
3408
3396
                        filename, rev_tree.get_revision_id()))
3409
 
            else:
3410
 
                actual_file_id = old_file_id
 
3397
            rev_tree_path = relpath
3411
3398
        else:
3412
 
            cur_file_id = tree.path2id(relpath)
3413
 
            if cur_file_id is not None and rev_tree.has_id(cur_file_id):
3414
 
                actual_file_id = cur_file_id
3415
 
            elif old_file_id is not None:
3416
 
                actual_file_id = old_file_id
3417
 
            else:
3418
 
                raise errors.BzrCommandError(gettext(
3419
 
                    "{0!r} is not present in revision {1}").format(
3420
 
                        filename, rev_tree.get_revision_id()))
3421
 
        relpath = rev_tree.id2path(actual_file_id)
 
3399
            try:
 
3400
                rev_tree_path = _mod_tree.find_previous_path(
 
3401
                    tree, rev_tree, relpath)
 
3402
            except errors.NoSuchFile:
 
3403
                rev_tree_path = None
 
3404
 
 
3405
            if rev_tree_path is None:
 
3406
                # Path didn't exist in working tree
 
3407
                if not rev_tree.is_versioned(relpath):
 
3408
                    raise errors.BzrCommandError(gettext(
 
3409
                        "{0!r} is not present in revision {1}").format(
 
3410
                            filename, rev_tree.get_revision_id()))
 
3411
                else:
 
3412
                    # Fall back to the same path in the basis tree, if present.
 
3413
                    rev_tree_path = relpath
 
3414
 
3422
3415
        if filtered:
3423
3416
            from .filter_tree import ContentFilterTree
3424
 
            filter_tree = ContentFilterTree(rev_tree,
3425
 
                rev_tree._content_filter_stack)
3426
 
            fileobj = filter_tree.get_file(relpath, actual_file_id)
 
3417
            filter_tree = ContentFilterTree(
 
3418
                rev_tree, rev_tree._content_filter_stack)
 
3419
            fileobj = filter_tree.get_file(rev_tree_path)
3427
3420
        else:
3428
 
            fileobj = rev_tree.get_file(relpath, actual_file_id)
 
3421
            fileobj = rev_tree.get_file(rev_tree_path)
3429
3422
        shutil.copyfileobj(fileobj, self.outf)
3430
3423
        self.cleanup_now()
3431
3424
 
3433
3426
class cmd_local_time_offset(Command):
3434
3427
    __doc__ = """Show the offset in seconds from GMT to local time."""
3435
3428
    hidden = True
 
3429
 
3436
3430
    @display_command
3437
3431
    def run(self):
3438
3432
        self.outf.write("%s\n" % osutils.local_time_offset())
3439
3433
 
3440
3434
 
3441
 
 
3442
3435
class cmd_commit(Command):
3443
3436
    __doc__ = """Commit changes into a new revision.
3444
3437
 
3458
3451
      If selected files are specified, only changes to those files are
3459
3452
      committed.  If a directory is specified then the directory and
3460
3453
      everything within it is committed.
3461
 
  
 
3454
 
3462
3455
      When excludes are given, they take precedence over selected files.
3463
3456
      For example, to commit only changes within foo, but not changes
3464
3457
      within foo/bar::
3465
 
  
 
3458
 
3466
3459
        brz commit foo -x foo/bar
3467
 
  
 
3460
 
3468
3461
      A selective commit after a merge is not yet supported.
3469
3462
 
3470
3463
    :Custom authors:
3475
3468
      "John Doe <jdoe@example.com>". If there is more than one author of
3476
3469
      the change you can specify the option multiple times, once for each
3477
3470
      author.
3478
 
  
 
3471
 
3479
3472
    :Checks:
3480
3473
 
3481
3474
      A common mistake is to forget to add a new file or directory before
3486
3479
 
3487
3480
    :Things to note:
3488
3481
 
3489
 
      If you accidentially commit the wrong changes or make a spelling
 
3482
      If you accidentally commit the wrong changes or make a spelling
3490
3483
      mistake in the commit message say, you can use the uncommit command
3491
3484
      to undo it. See ``brz help uncommit`` for details.
3492
3485
 
3499
3492
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
3500
3493
    takes_args = ['selected*']
3501
3494
    takes_options = [
3502
 
            ListOption('exclude', type=text_type, short_name='x',
3503
 
                help="Do not consider changes made to a given path."),
3504
 
            Option('message', type=text_type,
3505
 
                   short_name='m',
3506
 
                   help="Description of the new revision."),
3507
 
            'verbose',
3508
 
             Option('unchanged',
3509
 
                    help='Commit even if nothing has changed.'),
3510
 
             Option('file', type=text_type,
3511
 
                    short_name='F',
3512
 
                    argname='msgfile',
3513
 
                    help='Take commit message from this file.'),
3514
 
             Option('strict',
3515
 
                    help="Refuse to commit if there are unknown "
3516
 
                    "files in the working tree."),
3517
 
             Option('commit-time', type=text_type,
3518
 
                    help="Manually set a commit time using commit date "
3519
 
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
3520
 
             ListOption('fixes', type=text_type,
3521
 
                    help="Mark a bug as being fixed by this revision "
3522
 
                         "(see \"brz help bugs\")."),
3523
 
             ListOption('author', type=text_type,
3524
 
                    help="Set the author's name, if it's different "
3525
 
                         "from the committer."),
3526
 
             Option('local',
3527
 
                    help="Perform a local commit in a bound "
3528
 
                         "branch.  Local commits are not pushed to "
3529
 
                         "the master branch until a normal commit "
3530
 
                         "is performed."
3531
 
                    ),
3532
 
             Option('show-diff', short_name='p',
3533
 
                    help='When no message is supplied, show the diff along'
3534
 
                    ' with the status summary in the message editor.'),
3535
 
             Option('lossy', 
3536
 
                    help='When committing to a foreign version control '
3537
 
                    'system do not push data that can not be natively '
3538
 
                    'represented.'),
3539
 
             ]
 
3495
        ListOption(
 
3496
            'exclude', type=text_type, short_name='x',
 
3497
            help="Do not consider changes made to a given path."),
 
3498
        Option('message', type=text_type,
 
3499
               short_name='m',
 
3500
               help="Description of the new revision."),
 
3501
        'verbose',
 
3502
        Option('unchanged',
 
3503
               help='Commit even if nothing has changed.'),
 
3504
        Option('file', type=text_type,
 
3505
               short_name='F',
 
3506
               argname='msgfile',
 
3507
               help='Take commit message from this file.'),
 
3508
        Option('strict',
 
3509
               help="Refuse to commit if there are unknown "
 
3510
               "files in the working tree."),
 
3511
        Option('commit-time', type=text_type,
 
3512
               help="Manually set a commit time using commit date "
 
3513
               "format, e.g. '2009-10-10 08:00:00 +0100'."),
 
3514
        ListOption(
 
3515
            'bugs', type=text_type,
 
3516
            help="Link to a related bug. (see \"brz help bugs\")."),
 
3517
        ListOption(
 
3518
            'fixes', type=text_type,
 
3519
            help="Mark a bug as being fixed by this revision "
 
3520
                 "(see \"brz help bugs\")."),
 
3521
        ListOption(
 
3522
            'author', type=text_type,
 
3523
            help="Set the author's name, if it's different "
 
3524
                 "from the committer."),
 
3525
        Option('local',
 
3526
               help="Perform a local commit in a bound "
 
3527
                    "branch.  Local commits are not pushed to "
 
3528
                    "the master branch until a normal commit "
 
3529
                    "is performed."
 
3530
               ),
 
3531
        Option('show-diff', short_name='p',
 
3532
               help='When no message is supplied, show the diff along'
 
3533
               ' with the status summary in the message editor.'),
 
3534
        Option('lossy',
 
3535
               help='When committing to a foreign version control '
 
3536
               'system do not push data that can not be natively '
 
3537
               'represented.'), ]
3540
3538
    aliases = ['ci', 'checkin']
3541
3539
 
3542
 
    def _iter_bug_fix_urls(self, fixes, branch):
3543
 
        default_bugtracker  = None
 
3540
    def _iter_bug_urls(self, bugs, branch, status):
 
3541
        default_bugtracker = None
3544
3542
        # Configure the properties for bug fixing attributes.
3545
 
        for fixed_bug in fixes:
3546
 
            tokens = fixed_bug.split(':')
 
3543
        for bug in bugs:
 
3544
            tokens = bug.split(':')
3547
3545
            if len(tokens) == 1:
3548
3546
                if default_bugtracker is None:
3549
3547
                    branch_config = branch.get_config_stack()
3555
3553
                        "'tracker:id' or specify a default bug tracker "
3556
3554
                        "using the `bugtracker` option.\nSee "
3557
3555
                        "\"brz help bugs\" for more information on this "
3558
 
                        "feature. Commit refused.") % fixed_bug)
 
3556
                        "feature. Commit refused.") % bug)
3559
3557
                tag = default_bugtracker
3560
3558
                bug_id = tokens[0]
3561
3559
            elif len(tokens) != 2:
3562
3560
                raise errors.BzrCommandError(gettext(
3563
3561
                    "Invalid bug %s. Must be in the form of 'tracker:id'. "
3564
3562
                    "See \"brz help bugs\" for more information on this "
3565
 
                    "feature.\nCommit refused.") % fixed_bug)
 
3563
                    "feature.\nCommit refused.") % bug)
3566
3564
            else:
3567
3565
                tag, bug_id = tokens
3568
3566
            try:
3569
 
                yield bugtracker.get_bug_url(tag, branch, bug_id)
 
3567
                yield bugtracker.get_bug_url(tag, branch, bug_id), status
3570
3568
            except bugtracker.UnknownBugTrackerAbbreviation:
3571
3569
                raise errors.BzrCommandError(gettext(
3572
 
                    'Unrecognized bug %s. Commit refused.') % fixed_bug)
 
3570
                    'Unrecognized bug %s. Commit refused.') % bug)
3573
3571
            except bugtracker.MalformedBugIdentifier as e:
3574
3572
                raise errors.BzrCommandError(gettext(
3575
3573
                    u"%s\nCommit refused.") % (e,))
3576
3574
 
3577
3575
    def run(self, message=None, file=None, verbose=False, selected_list=None,
3578
 
            unchanged=False, strict=False, local=False, fixes=None,
 
3576
            unchanged=False, strict=False, local=False, fixes=None, bugs=None,
3579
3577
            author=None, show_diff=False, exclude=None, commit_time=None,
3580
3578
            lossy=False):
 
3579
        import itertools
3581
3580
        from .commit import (
3582
3581
            PointlessCommit,
3583
3582
            )
3611
3610
 
3612
3611
        if fixes is None:
3613
3612
            fixes = []
 
3613
        if bugs is None:
 
3614
            bugs = []
3614
3615
        bug_property = bugtracker.encode_fixes_bug_urls(
3615
 
            self._iter_bug_fix_urls(fixes, tree.branch))
 
3616
            itertools.chain(
 
3617
                self._iter_bug_urls(bugs, tree.branch, bugtracker.RELATED),
 
3618
                self._iter_bug_urls(fixes, tree.branch, bugtracker.FIXED)))
3616
3619
        if bug_property:
3617
3620
            properties[u'bugs'] = bug_property
3618
3621
 
3631
3634
                warning_msg = (
3632
3635
                    'The commit message is a file name: "%(f)s".\n'
3633
3636
                    '(use --file "%(f)s" to take commit message from that file)'
3634
 
                    % { 'f': message })
 
3637
                    % {'f': message})
3635
3638
                ui.ui_factory.show_warning(warning_msg)
3636
3639
            if '\r' in message:
3637
3640
                message = message.replace('\r\n', '\n')
3651
3654
                # No message supplied: make one up.
3652
3655
                # text is the status of the tree
3653
3656
                text = make_commit_message_template_encoded(tree,
3654
 
                        selected_list, diff=show_diff,
3655
 
                        output_encoding=osutils.get_user_encoding())
 
3657
                                                            selected_list, diff=show_diff,
 
3658
                                                            output_encoding=osutils.get_user_encoding())
3656
3659
                # start_message is the template generated from hooks
3657
3660
                # XXX: Warning - looks like hooks return unicode,
3658
3661
                # make_commit_message_template_encoded returns user encoding.
3660
3663
                # avoid this.
3661
3664
                my_message = set_commit_message(commit_obj)
3662
3665
                if my_message is None:
3663
 
                    start_message = generate_commit_message_template(commit_obj)
 
3666
                    start_message = generate_commit_message_template(
 
3667
                        commit_obj)
3664
3668
                    if start_message is not None:
3665
3669
                        start_message = start_message.encode(
3666
 
                                osutils.get_user_encoding())
 
3670
                            osutils.get_user_encoding())
3667
3671
                    my_message = edit_commit_message_encoded(text,
3668
 
                        start_message=start_message)
 
3672
                                                             start_message=start_message)
3669
3673
                if my_message is None:
3670
3674
                    raise errors.BzrCommandError(gettext("please specify a commit"
3671
 
                        " message with either --message or --file"))
 
3675
                                                         " message with either --message or --file"))
3672
3676
                if my_message == "":
3673
3677
                    raise errors.BzrCommandError(gettext("Empty commit message specified."
3674
 
                            " Please specify a commit message with either"
3675
 
                            " --message or --file or leave a blank message"
3676
 
                            " with --message \"\"."))
 
3678
                                                         " Please specify a commit message with either"
 
3679
                                                         " --message or --file or leave a blank message"
 
3680
                                                         " with --message \"\"."))
3677
3681
            return my_message
3678
3682
 
3679
3683
        # The API permits a commit with a filter of [] to mean 'select nothing'
3691
3695
                        lossy=lossy)
3692
3696
        except PointlessCommit:
3693
3697
            raise errors.BzrCommandError(gettext("No changes to commit."
3694
 
                " Please 'brz add' the files you want to commit, or use"
3695
 
                " --unchanged to force an empty commit."))
 
3698
                                                 " Please 'brz add' the files you want to commit, or use"
 
3699
                                                 " --unchanged to force an empty commit."))
3696
3700
        except ConflictsInTree:
3697
3701
            raise errors.BzrCommandError(gettext('Conflicts detected in working '
3698
 
                'tree.  Use "brz conflicts" to list, "brz resolve FILE" to'
3699
 
                ' resolve.'))
 
3702
                                                 'tree.  Use "brz conflicts" to list, "brz resolve FILE" to'
 
3703
                                                 ' resolve.'))
3700
3704
        except StrictCommitFailed:
3701
3705
            raise errors.BzrCommandError(gettext("Commit refused because there are"
3702
 
                              " unknown files in the working tree."))
 
3706
                                                 " unknown files in the working tree."))
3703
3707
        except errors.BoundBranchOutOfDate as e:
3704
3708
            e.extra_help = (gettext("\n"
3705
 
                'To commit to master branch, run update and then commit.\n'
3706
 
                'You can also pass --local to commit to continue working '
3707
 
                'disconnected.'))
 
3709
                                    'To commit to master branch, run update and then commit.\n'
 
3710
                                    'You can also pass --local to commit to continue working '
 
3711
                                    'disconnected.'))
3708
3712
            raise
3709
3713
 
3710
3714
 
3808
3812
    tried.
3809
3813
 
3810
3814
    For more information on upgrades, see the Bazaar Upgrade Guide,
3811
 
    http://doc.bazaar.canonical.com/latest/en/upgrade-guide/.
 
3815
    https://www.breezy-vcs.org/doc/en/upgrade-guide/.
3812
3816
    """
3813
3817
 
3814
3818
    _see_also = ['check', 'reconcile', 'formats']
3815
3819
    takes_args = ['url?']
3816
3820
    takes_options = [
3817
3821
        RegistryOption('format',
3818
 
            help='Upgrade to a specific format.  See "brz help'
3819
 
                 ' formats" for details.',
3820
 
            lazy_registry=('breezy.controldir', 'format_registry'),
3821
 
            converter=lambda name: controldir.format_registry.make_controldir(name),
3822
 
            value_switches=True, title='Branch format'),
 
3822
                       help='Upgrade to a specific format.  See "brz help'
 
3823
                       ' formats" for details.',
 
3824
                       lazy_registry=('breezy.controldir', 'format_registry'),
 
3825
                       converter=lambda name: controldir.format_registry.make_controldir(
 
3826
                           name),
 
3827
                       value_switches=True, title='Branch format'),
3823
3828
        Option('clean',
3824
 
            help='Remove the backup.bzr directory if successful.'),
 
3829
               help='Remove the backup.bzr directory if successful.'),
3825
3830
        Option('dry-run',
3826
 
            help="Show what would be done, but don't actually do anything."),
 
3831
               help="Show what would be done, but don't actually do anything."),
3827
3832
    ]
3828
3833
 
3829
3834
    def run(self, url='.', format=None, clean=False, dry_run=False):
3849
3854
 
3850
3855
            brz whoami "Frank Chu <fchu@example.com>"
3851
3856
    """
3852
 
    takes_options = [ 'directory',
3853
 
                      Option('email',
3854
 
                             help='Display email address only.'),
3855
 
                      Option('branch',
3856
 
                             help='Set identity for the current branch instead of '
3857
 
                                  'globally.'),
3858
 
                    ]
 
3857
    takes_options = ['directory',
 
3858
                     Option('email',
 
3859
                            help='Display email address only.'),
 
3860
                     Option('branch',
 
3861
                            help='Set identity for the current branch instead of '
 
3862
                            'globally.'),
 
3863
                     ]
3859
3864
    takes_args = ['name?']
3860
3865
    encoding_type = 'replace'
3861
3866
 
3880
3885
 
3881
3886
        if email:
3882
3887
            raise errors.BzrCommandError(gettext("--email can only be used to display existing "
3883
 
                                         "identity"))
 
3888
                                                 "identity"))
3884
3889
 
3885
3890
        # display a warning if an email address isn't included in the given name.
3886
3891
        try:
3887
3892
            _mod_config.extract_email_address(name)
3888
 
        except _mod_config.NoEmailInUsername as e:
 
3893
        except _mod_config.NoEmailInUsername:
3889
3894
            warning('"%s" does not seem to contain an email address.  '
3890
3895
                    'This is allowed, but not recommended.', name)
3891
3896
 
3916
3921
    _see_also = ['info']
3917
3922
    takes_args = ['nickname?']
3918
3923
    takes_options = ['directory']
 
3924
 
3919
3925
    def run(self, nickname=None, directory=u'.'):
3920
3926
        branch = Branch.open_containing(directory)[0]
3921
3927
        if nickname is None:
3964
3970
            if equal_pos == -1:
3965
3971
                self.print_alias(name)
3966
3972
            else:
3967
 
                self.set_alias(name[:equal_pos], name[equal_pos+1:])
 
3973
                self.set_alias(name[:equal_pos], name[equal_pos + 1:])
3968
3974
 
3969
3975
    def remove_alias(self, alias_name):
3970
3976
        if alias_name is None:
4049
4055
    """
4050
4056
    # NB: this is used from the class without creating an instance, which is
4051
4057
    # why it does not have a self parameter.
 
4058
 
4052
4059
    def get_transport_type(typestring):
4053
4060
        """Parse and return a transport specifier."""
4054
4061
        if typestring == "sftp":
4068
4075
    takes_args = ['testspecs*']
4069
4076
    takes_options = ['verbose',
4070
4077
                     Option('one',
4071
 
                             help='Stop when one test fails.',
4072
 
                             short_name='1',
4073
 
                             ),
 
4078
                            help='Stop when one test fails.',
 
4079
                            short_name='1',
 
4080
                            ),
4074
4081
                     Option('transport',
4075
4082
                            help='Use a different transport by default '
4076
4083
                                 'throughout the test suite.',
4090
4097
                     Option('list-only',
4091
4098
                            help='List the tests instead of running them.'),
4092
4099
                     RegistryOption('parallel',
4093
 
                        help="Run the test suite in parallel.",
4094
 
                        lazy_registry=('breezy.tests', 'parallel_registry'),
4095
 
                        value_switches=False,
4096
 
                        ),
 
4100
                                    help="Run the test suite in parallel.",
 
4101
                                    lazy_registry=(
 
4102
                                        'breezy.tests', 'parallel_registry'),
 
4103
                                    value_switches=False,
 
4104
                                    ),
4097
4105
                     Option('randomize', type=text_type, argname="SEED",
4098
4106
                            help='Randomize the order of tests using the given'
4099
4107
                                 ' seed or "now" for the current time.'),
4113
4121
                                help='Turn on a selftest debug flag.'),
4114
4122
                     ListOption('starting-with', type=text_type, argname='TESTID',
4115
4123
                                param_name='starting_with', short_name='s',
4116
 
                                help=
4117
 
                                'Load only the tests starting with TESTID.'),
 
4124
                                help='Load only the tests starting with TESTID.'),
4118
4125
                     Option('sync',
4119
4126
                            help="By default we disable fsync and fdatasync"
4120
4127
                                 " while running the test suite.")
4148
4155
            from . import tests
4149
4156
        except ImportError:
4150
4157
            raise errors.BzrCommandError("tests not available. Install the "
4151
 
                "breezy tests to run the breezy testsuite.")
 
4158
                                         "breezy tests to run the breezy testsuite.")
4152
4159
 
4153
4160
        if testspecs_list is not None:
4154
4161
            pattern = '|'.join(testspecs_list)
4163
4170
                    "to use --subunit."))
4164
4171
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunnerv1
4165
4172
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
4166
 
            # stdout, which would corrupt the subunit stream. 
 
4173
            # stdout, which would corrupt the subunit stream.
4167
4174
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
4168
4175
            # following code can be deleted when it's sufficiently deployed
4169
4176
            # -- vila/mgz 20100514
4170
4177
            if (sys.platform == "win32"
4171
 
                and getattr(sys.stdout, 'fileno', None) is not None):
 
4178
                    and getattr(sys.stdout, 'fileno', None) is not None):
4172
4179
                import msvcrt
4173
4180
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
4174
4181
        if subunit2:
4195
4202
        if not sync:
4196
4203
            self._disable_fsync()
4197
4204
        selftest_kwargs = {"verbose": verbose,
4198
 
                          "pattern": pattern,
4199
 
                          "stop_on_failure": one,
4200
 
                          "transport": transport,
4201
 
                          "test_suite_factory": test_suite_factory,
4202
 
                          "lsprof_timed": lsprof_timed,
4203
 
                          "lsprof_tests": lsprof_tests,
4204
 
                          "matching_tests_first": first,
4205
 
                          "list_only": list_only,
4206
 
                          "random_seed": randomize,
4207
 
                          "exclude_pattern": exclude_pattern,
4208
 
                          "strict": strict,
4209
 
                          "load_list": load_list,
4210
 
                          "debug_flags": debugflag,
4211
 
                          "starting_with": starting_with
4212
 
                          }
 
4205
                           "pattern": pattern,
 
4206
                           "stop_on_failure": one,
 
4207
                           "transport": transport,
 
4208
                           "test_suite_factory": test_suite_factory,
 
4209
                           "lsprof_timed": lsprof_timed,
 
4210
                           "lsprof_tests": lsprof_tests,
 
4211
                           "matching_tests_first": first,
 
4212
                           "list_only": list_only,
 
4213
                           "random_seed": randomize,
 
4214
                           "exclude_pattern": exclude_pattern,
 
4215
                           "strict": strict,
 
4216
                           "load_list": load_list,
 
4217
                           "debug_flags": debugflag,
 
4218
                           "starting_with": starting_with
 
4219
                           }
4213
4220
        selftest_kwargs.update(self.additional_selftest_args)
4214
4221
 
4215
4222
        # Make deprecation warnings visible, unless -Werror is set
4280
4287
        base_rev_id = graph.find_unique_lca(last1, last2)
4281
4288
 
4282
4289
        self.outf.write(gettext('merge base is revision %s\n') %
4283
 
                base_rev_id.decode('utf-8'))
 
4290
                        base_rev_id.decode('utf-8'))
4284
4291
 
4285
4292
 
4286
4293
class cmd_merge(Command):
4381
4388
        Option('uncommitted', help='Apply uncommitted changes'
4382
4389
               ' from a working copy, instead of branch changes.'),
4383
4390
        Option('pull', help='If the destination is already'
4384
 
                ' completely merged into the source, pull from the'
4385
 
                ' source rather than merging.  When this happens,'
4386
 
                ' you do not need to commit the result.'),
 
4391
               ' completely merged into the source, pull from the'
 
4392
               ' source rather than merging.  When this happens,'
 
4393
               ' you do not need to commit the result.'),
4387
4394
        custom_help('directory',
4388
 
               help='Branch to merge into, '
 
4395
                    help='Branch to merge into, '
4389
4396
                    'rather than the one containing the working directory.'),
4390
4397
        Option('preview', help='Instead of merging, show a diff of the'
4391
4398
               ' merge.'),
4392
4399
        Option('interactive', help='Select changes interactively.',
4393
 
            short_name='i')
 
4400
               short_name='i')
4394
4401
    ]
4395
4402
 
4396
4403
    def run(self, location=None, revision=None, force=False,
4403
4410
        if merge_type is None:
4404
4411
            merge_type = _mod_merge.Merge3Merger
4405
4412
 
4406
 
        if directory is None: directory = u'.'
 
4413
        if directory is None:
 
4414
            directory = u'.'
4407
4415
        possible_transports = []
4408
4416
        merger = None
4409
4417
        allow_pending = True
4410
4418
        verified = 'inapplicable'
4411
4419
 
4412
4420
        tree = WorkingTree.open_containing(directory)[0]
4413
 
        if tree.branch.revno() == 0:
 
4421
        if tree.branch.last_revision() == _mod_revision.NULL_REVISION:
4414
4422
            raise errors.BzrCommandError(gettext('Merging into empty branches not currently supported, '
4415
 
                                         'https://bugs.launchpad.net/bzr/+bug/308562'))
4416
 
 
4417
 
        try:
4418
 
            basis_tree = tree.revision_tree(tree.last_revision())
4419
 
        except errors.NoSuchRevision:
4420
 
            basis_tree = tree.basis_tree()
 
4423
                                                 'https://bugs.launchpad.net/bzr/+bug/308562'))
4421
4424
 
4422
4425
        # die as quickly as possible if there are uncommitted changes
4423
4426
        if not force:
4433
4436
        if location is not None:
4434
4437
            try:
4435
4438
                mergeable = bundle.read_mergeable_from_url(location,
4436
 
                    possible_transports=possible_transports)
 
4439
                                                           possible_transports=possible_transports)
4437
4440
            except errors.NotABundle:
4438
4441
                mergeable = None
4439
4442
            else:
4440
4443
                if uncommitted:
4441
4444
                    raise errors.BzrCommandError(gettext('Cannot use --uncommitted'
4442
 
                        ' with bundles or merge directives.'))
 
4445
                                                         ' with bundles or merge directives.'))
4443
4446
 
4444
4447
                if revision is not None:
4445
4448
                    raise errors.BzrCommandError(gettext(
4446
4449
                        'Cannot use -r with merge directives or bundles'))
4447
4450
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
4448
 
                   mergeable)
 
4451
                                                                    mergeable)
4449
4452
 
4450
4453
        if merger is None and uncommitted:
4451
4454
            if revision is not None and len(revision) > 0:
4452
4455
                raise errors.BzrCommandError(gettext('Cannot use --uncommitted and'
4453
 
                    ' --revision at the same time.'))
 
4456
                                                     ' --revision at the same time.'))
4454
4457
            merger = self.get_merger_from_uncommitted(tree, location, None)
4455
4458
            allow_pending = False
4456
4459
 
4457
4460
        if merger is None:
4458
4461
            merger, allow_pending = self._get_merger_from_branch(tree,
4459
 
                location, revision, remember, possible_transports, None)
 
4462
                                                                 location, revision, remember, possible_transports, None)
4460
4463
 
4461
4464
        merger.merge_type = merge_type
4462
4465
        merger.reprocess = reprocess
4463
4466
        merger.show_base = show_base
4464
4467
        self.sanity_check_merger(merger)
4465
4468
        if (merger.base_rev_id == merger.other_rev_id and
4466
 
            merger.other_rev_id is not None):
 
4469
                merger.other_rev_id is not None):
4467
4470
            # check if location is a nonexistent file (and not a branch) to
4468
4471
            # disambiguate the 'Nothing to do'
4469
4472
            if merger.interesting_files:
4470
4473
                if not merger.other_tree.has_filename(
4471
 
                    merger.interesting_files[0]):
 
4474
                        merger.interesting_files[0]):
4472
4475
                    note(gettext("merger: ") + str(merger))
4473
4476
                    raise errors.PathsDoNotExist([location])
4474
4477
            note(gettext('Nothing to do.'))
4475
4478
            return 0
4476
4479
        if pull and not preview:
4477
4480
            if merger.interesting_files is not None:
4478
 
                raise errors.BzrCommandError(gettext('Cannot pull individual files'))
 
4481
                raise errors.BzrCommandError(
 
4482
                    gettext('Cannot pull individual files'))
4479
4483
            if (merger.base_rev_id == tree.last_revision()):
4480
4484
                result = tree.pull(merger.other_branch, False,
4481
4485
                                   merger.other_rev_id)
4540
4544
 
4541
4545
    def sanity_check_merger(self, merger):
4542
4546
        if (merger.show_base and
4543
 
            not merger.merge_type is _mod_merge.Merge3Merger):
 
4547
                merger.merge_type is not _mod_merge.Merge3Merger):
4544
4548
            raise errors.BzrCommandError(gettext("Show-base is not supported for this"
4545
 
                                         " merge type. %s") % merger.merge_type)
 
4549
                                                 " merge type. %s") % merger.merge_type)
4546
4550
        if merger.reprocess is None:
4547
4551
            if merger.show_base:
4548
4552
                merger.reprocess = False
4551
4555
                merger.reprocess = merger.merge_type.supports_reprocess
4552
4556
        if merger.reprocess and not merger.merge_type.supports_reprocess:
4553
4557
            raise errors.BzrCommandError(gettext("Conflict reduction is not supported"
4554
 
                                         " for merge type %s.") %
 
4558
                                                 " for merge type %s.") %
4555
4559
                                         merger.merge_type)
4556
4560
        if merger.reprocess and merger.show_base:
4557
4561
            raise errors.BzrCommandError(gettext("Cannot do conflict reduction and"
4558
 
                                         " show base."))
 
4562
                                                 " show base."))
4559
4563
 
4560
4564
        if (merger.merge_type.requires_file_merge_plan and
4561
4565
            (not getattr(merger.this_tree, 'plan_file_merge', None) or
4563
4567
             (merger.base_tree is not None and
4564
4568
                 not getattr(merger.base_tree, 'plan_file_merge', None)))):
4565
4569
            raise errors.BzrCommandError(
4566
 
                 gettext('Plan file merge unsupported: '
4567
 
                         'Merge type incompatible with tree formats.'))
 
4570
                gettext('Plan file merge unsupported: '
 
4571
                        'Merge type incompatible with tree formats.'))
4568
4572
 
4569
4573
    def _get_merger_from_branch(self, tree, location, revision, remember,
4570
4574
                                possible_transports, pb):
4571
4575
        """Produce a merger from a location, assuming it refers to a branch."""
4572
4576
        # find the branch locations
4573
4577
        other_loc, user_location = self._select_branch_location(tree, location,
4574
 
            revision, -1)
 
4578
                                                                revision, -1)
4575
4579
        if revision is not None and len(revision) == 2:
4576
4580
            base_loc, _unused = self._select_branch_location(tree,
4577
 
                location, revision, 0)
 
4581
                                                             location, revision, 0)
4578
4582
        else:
4579
4583
            base_loc = other_loc
4580
4584
        # Open the branches
4581
4585
        other_branch, other_path = Branch.open_containing(other_loc,
4582
 
            possible_transports)
 
4586
                                                          possible_transports)
4583
4587
        if base_loc == other_loc:
4584
4588
            base_branch = other_branch
4585
4589
        else:
4586
4590
            base_branch, base_path = Branch.open_containing(base_loc,
4587
 
                possible_transports)
 
4591
                                                            possible_transports)
4588
4592
        # Find the revision ids
4589
4593
        other_revision_id = None
4590
4594
        base_revision_id = None
4602
4606
        # - user ask to remember or there is no previous location set to merge
4603
4607
        #   from and user didn't ask to *not* remember
4604
4608
        if (user_location is not None
4605
 
            and ((remember
4606
 
                  or (remember is None
4607
 
                      and tree.branch.get_submit_branch() is None)))):
 
4609
            and ((remember or
 
4610
                 (remember is None and
 
4611
                  tree.branch.get_submit_branch() is None)))):
4608
4612
            tree.branch.set_submit_branch(other_branch.base)
4609
4613
        # Merge tags (but don't set them in the master branch yet, the user
4610
4614
        # might revert this merge).  Commit will propagate them.
4611
4615
        other_branch.tags.merge_to(tree.branch.tags, ignore_master=True)
4612
4616
        merger = _mod_merge.Merger.from_revision_ids(tree,
4613
 
            other_revision_id, base_revision_id, other_branch, base_branch)
 
4617
                                                     other_revision_id, base_revision_id, other_branch, base_branch)
4614
4618
        if other_path != '':
4615
4619
            allow_pending = False
4616
4620
            merger.interesting_files = [other_path]
4651
4655
            will be the user-entered location.
4652
4656
        """
4653
4657
        if (revision is not None and index is not None
4654
 
            and revision[index] is not None):
 
4658
                and revision[index] is not None):
4655
4659
            branch = revision[index].get_branch()
4656
4660
            if branch is not None:
4657
4661
                return branch, branch
4673
4677
            stored_location_type = "parent"
4674
4678
        mutter("%s", stored_location)
4675
4679
        if stored_location is None:
4676
 
            raise errors.BzrCommandError(gettext("No location specified or remembered"))
 
4680
            raise errors.BzrCommandError(
 
4681
                gettext("No location specified or remembered"))
4677
4682
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
4678
4683
        note(gettext("{0} remembered {1} location {2}").format(verb_string,
4679
 
                stored_location_type, display_url))
 
4684
                                                               stored_location_type, display_url))
4680
4685
        return stored_location
4681
4686
 
4682
4687
 
4704
4709
    """
4705
4710
    takes_args = ['file*']
4706
4711
    takes_options = [
4707
 
            'merge-type',
4708
 
            'reprocess',
4709
 
            Option('show-base',
4710
 
                   help="Show base revision text in conflicts."),
4711
 
            ]
 
4712
        'merge-type',
 
4713
        'reprocess',
 
4714
        Option('show-base',
 
4715
               help="Show base revision text in conflicts."),
 
4716
        ]
4712
4717
 
4713
4718
    def run(self, file_list=None, merge_type=None, show_base=False,
4714
4719
            reprocess=False):
4719
4724
        self.add_cleanup(tree.lock_write().unlock)
4720
4725
        parents = tree.get_parent_ids()
4721
4726
        if len(parents) != 2:
4722
 
            raise errors.BzrCommandError(gettext("Sorry, remerge only works after normal"
4723
 
                                         " merges.  Not cherrypicking or"
4724
 
                                         " multi-merges."))
4725
 
        repository = tree.branch.repository
 
4727
            raise errors.BzrCommandError(
 
4728
                gettext("Sorry, remerge only works after normal"
 
4729
                        " merges.  Not cherrypicking or multi-merges."))
4726
4730
        interesting_files = None
4727
4731
        new_conflicts = []
4728
4732
        conflicts = tree.conflicts()
4735
4739
                if tree.kind(filename) != "directory":
4736
4740
                    continue
4737
4741
 
4738
 
                for path, ie in tree.iter_entries_by_dir(specific_files=[filename]):
 
4742
                for path, ie in tree.iter_entries_by_dir(
 
4743
                        specific_files=[filename]):
4739
4744
                    interesting_files.add(path)
4740
4745
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4741
4746
        else:
4793
4798
    update command.
4794
4799
 
4795
4800
    Uncommitted changes to files that are reverted will be discarded.
4796
 
    Howver, by default, any files that have been manually changed will be
 
4801
    However, by default, any files that have been manually changed will be
4797
4802
    backed up first.  (Files changed only by merge are not backed up.)  Backup
4798
4803
    files have '.~#~' appended to their name, where # is a number.
4799
4804
 
4849
4854
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4850
4855
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
4851
4856
        tree.revert(file_list, rev_tree, not no_backup, None,
4852
 
            report_changes=True)
 
4857
                    report_changes=True)
4853
4858
 
4854
4859
 
4855
4860
class cmd_assert_fail(Command):
4868
4873
 
4869
4874
    _see_also = ['topics']
4870
4875
    takes_options = [
4871
 
            Option('long', 'Show help on all commands.'),
4872
 
            ]
 
4876
        Option('long', 'Show help on all commands.'),
 
4877
        ]
4873
4878
    takes_args = ['topic?']
4874
4879
    aliases = ['?', '--help', '-?', '-h']
4875
4880
 
4904
4909
    To filter on a range of revisions, you can use the command -r begin..end
4905
4910
    -r revision requests a specific revision, -r ..end or -r begin.. are
4906
4911
    also valid.
4907
 
            
 
4912
 
4908
4913
    :Exit values:
4909
4914
        1 - some missing revisions
4910
4915
        0 - no missing revisions
4946
4951
        'show-ids',
4947
4952
        'verbose',
4948
4953
        custom_help('revision',
4949
 
             help='Filter on other branch revisions (inclusive). '
4950
 
                'See "help revisionspec" for details.'),
 
4954
                    help='Filter on other branch revisions (inclusive). '
 
4955
                    'See "help revisionspec" for details.'),
4951
4956
        Option('my-revision',
4952
 
            type=_parse_revision_str,
4953
 
            help='Filter on local branch revisions (inclusive). '
4954
 
                'See "help revisionspec" for details.'),
 
4957
               type=_parse_revision_str,
 
4958
               help='Filter on local branch revisions (inclusive). '
 
4959
               'See "help revisionspec" for details.'),
4955
4960
        Option('include-merged',
4956
4961
               'Show all revisions in addition to the mainline ones.'),
4957
4962
        Option('include-merges', hidden=True,
4967
4972
            include_merged=None, revision=None, my_revision=None,
4968
4973
            directory=u'.'):
4969
4974
        from breezy.missing import find_unmerged, iter_log_revisions
 
4975
 
4970
4976
        def message(s):
4971
4977
            if not is_quiet():
4972
4978
                self.outf.write(s)
4994
5000
            other_branch = parent
4995
5001
            if other_branch is None:
4996
5002
                raise errors.BzrCommandError(gettext("No peer location known"
4997
 
                                             " or specified."))
 
5003
                                                     " or specified."))
4998
5004
            display_url = urlutils.unescape_for_display(parent,
4999
5005
                                                        self.outf.encoding)
5000
5006
            message(gettext("Using saved parent location: {0}\n").format(
5008
5014
 
5009
5015
        local_revid_range = _revision_range_to_revid_range(
5010
5016
            _get_revision_range(my_revision, local_branch,
5011
 
                self.name()))
 
5017
                                self.name()))
5012
5018
 
5013
5019
        remote_revid_range = _revision_range_to_revid_range(
5014
5020
            _get_revision_range(revision,
5015
 
                remote_branch, self.name()))
 
5021
                                remote_branch, self.name()))
5016
5022
 
5017
5023
        local_extra, remote_extra = find_unmerged(
5018
5024
            local_branch, remote_branch, restrict,
5031
5037
        status_code = 0
5032
5038
        if local_extra and not theirs_only:
5033
5039
            message(ngettext("You have %d extra revision:\n",
5034
 
                             "You have %d extra revisions:\n", 
 
5040
                             "You have %d extra revisions:\n",
5035
5041
                             len(local_extra)) %
5036
 
                len(local_extra))
 
5042
                    len(local_extra))
5037
5043
            rev_tag_dict = {}
5038
5044
            if local_branch.supports_tags():
5039
5045
                rev_tag_dict = local_branch.tags.get_reverse_tag_dict()
5040
5046
            for revision in iter_log_revisions(local_extra,
5041
 
                                local_branch.repository,
5042
 
                                verbose,
5043
 
                                rev_tag_dict):
 
5047
                                               local_branch.repository,
 
5048
                                               verbose,
 
5049
                                               rev_tag_dict):
5044
5050
                lf.log_revision(revision)
5045
5051
            printed_local = True
5046
5052
            status_code = 1
5053
5059
            message(ngettext("You are missing %d revision:\n",
5054
5060
                             "You are missing %d revisions:\n",
5055
5061
                             len(remote_extra)) %
5056
 
                len(remote_extra))
 
5062
                    len(remote_extra))
5057
5063
            if remote_branch.supports_tags():
5058
5064
                rev_tag_dict = remote_branch.tags.get_reverse_tag_dict()
5059
5065
            for revision in iter_log_revisions(remote_extra,
5060
 
                                remote_branch.repository,
5061
 
                                verbose,
5062
 
                                rev_tag_dict):
 
5066
                                               remote_branch.repository,
 
5067
                                               verbose,
 
5068
                                               rev_tag_dict):
5063
5069
                lf.log_revision(revision)
5064
5070
            status_code = 1
5065
5071
 
5105
5111
    _see_also = ['repositories']
5106
5112
    takes_args = ['branch_or_repo?']
5107
5113
    takes_options = [
5108
 
        Option('clean-obsolete-packs', 'Delete obsolete packs to save disk space.'),
 
5114
        Option('clean-obsolete-packs',
 
5115
               'Delete obsolete packs to save disk space.'),
5109
5116
        ]
5110
5117
 
5111
5118
    def run(self, branch_or_repo='.', clean_obsolete_packs=False):
5150
5157
class cmd_testament(Command):
5151
5158
    __doc__ = """Show testament (signing-form) of a revision."""
5152
5159
    takes_options = [
5153
 
            'revision',
5154
 
            Option('long', help='Produce long-format testament.'),
5155
 
            Option('strict',
5156
 
                   help='Produce a strict-format testament.')]
 
5160
        'revision',
 
5161
        Option('long', help='Produce long-format testament.'),
 
5162
        Option('strict',
 
5163
               help='Produce a strict-format testament.')]
5157
5164
    takes_args = ['branch?']
5158
5165
    encoding_type = 'exact'
 
5166
 
5159
5167
    @display_command
5160
5168
    def run(self, branch=u'.', revision=None, long=False, strict=False):
5161
 
        from .testament import Testament, StrictTestament
 
5169
        from .bzr.testament import Testament, StrictTestament
5162
5170
        if strict is True:
5163
5171
            testament_class = StrictTestament
5164
5172
        else:
5216
5224
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
5217
5225
        self.add_cleanup(tree.lock_read().unlock)
5218
5226
        if wt is not None and revision is None:
5219
 
            file_id = wt.path2id(relpath)
5220
 
        else:
5221
 
            file_id = tree.path2id(relpath)
5222
 
        if file_id is None:
5223
 
            raise errors.NotVersionedError(filename)
5224
 
        if wt is not None and revision is None:
 
5227
            if not wt.is_versioned(relpath):
 
5228
                raise errors.NotVersionedError(relpath)
5225
5229
            # If there is a tree and we're not annotating historical
5226
5230
            # versions, annotate the working tree's content.
5227
5231
            annotate_file_tree(wt, relpath, self.outf, long, all,
5228
 
                show_ids=show_ids, file_id=file_id)
 
5232
                               show_ids=show_ids)
5229
5233
        else:
 
5234
            if not tree.is_versioned(relpath):
 
5235
                raise errors.NotVersionedError(relpath)
5230
5236
            annotate_file_tree(tree, relpath, self.outf, long, all,
5231
 
                show_ids=show_ids, branch=branch, file_id=file_id)
 
5237
                               show_ids=show_ids, branch=branch)
5232
5238
 
5233
5239
 
5234
5240
class cmd_re_sign(Command):
5235
5241
    __doc__ = """Create a digital signature for an existing revision."""
5236
5242
    # TODO be able to replace existing ones.
5237
5243
 
5238
 
    hidden = True # is this right ?
 
5244
    hidden = True  # is this right ?
5239
5245
    takes_args = ['revision_id*']
5240
5246
    takes_options = ['directory', 'revision']
5241
5247
 
5242
5248
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
5243
5249
        if revision_id_list is not None and revision is not None:
5244
 
            raise errors.BzrCommandError(gettext('You can only supply one of revision_id or --revision'))
 
5250
            raise errors.BzrCommandError(
 
5251
                gettext('You can only supply one of revision_id or --revision'))
5245
5252
        if revision_id_list is None and revision is None:
5246
 
            raise errors.BzrCommandError(gettext('You must supply either --revision or a revision_id'))
 
5253
            raise errors.BzrCommandError(
 
5254
                gettext('You must supply either --revision or a revision_id'))
5247
5255
        b = WorkingTree.open_containing(directory)[0].branch
5248
5256
        self.add_cleanup(b.lock_write().unlock)
5249
5257
        return self._run(b, revision_id_list, revision)
5256
5264
                for revision_id in revision_id_list:
5257
5265
                    revision_id = cache_utf8.encode(revision_id)
5258
5266
                    b.repository.sign_revision(revision_id, gpg_strategy)
5259
 
            except:
 
5267
            except BaseException:
5260
5268
                b.repository.abort_write_group()
5261
5269
                raise
5262
5270
            else:
5267
5275
                b.repository.start_write_group()
5268
5276
                try:
5269
5277
                    b.repository.sign_revision(rev_id, gpg_strategy)
5270
 
                except:
 
5278
                except BaseException:
5271
5279
                    b.repository.abort_write_group()
5272
5280
                    raise
5273
5281
                else:
5281
5289
                if to_revid is None:
5282
5290
                    to_revno = b.revno()
5283
5291
                if from_revno is None or to_revno is None:
5284
 
                    raise errors.BzrCommandError(gettext('Cannot sign a range of non-revision-history revisions'))
 
5292
                    raise errors.BzrCommandError(
 
5293
                        gettext('Cannot sign a range of non-revision-history revisions'))
5285
5294
                b.repository.start_write_group()
5286
5295
                try:
5287
5296
                    for revno in range(from_revno, to_revno + 1):
5288
5297
                        b.repository.sign_revision(b.get_rev_id(revno),
5289
5298
                                                   gpg_strategy)
5290
 
                except:
 
5299
                except BaseException:
5291
5300
                    b.repository.abort_write_group()
5292
5301
                    raise
5293
5302
                else:
5294
5303
                    b.repository.commit_write_group()
5295
5304
            else:
5296
 
                raise errors.BzrCommandError(gettext('Please supply either one revision, or a range.'))
 
5305
                raise errors.BzrCommandError(
 
5306
                    gettext('Please supply either one revision, or a range.'))
5297
5307
 
5298
5308
 
5299
5309
class cmd_bind(Command):
5318
5328
            try:
5319
5329
                location = b.get_old_bound_location()
5320
5330
            except errors.UpgradeRequired:
5321
 
                raise errors.BzrCommandError(gettext('No location supplied.  '
5322
 
                    'This format does not remember old locations.'))
 
5331
                raise errors.BzrCommandError(
 
5332
                    gettext('No location supplied.  '
 
5333
                            'This format does not remember old locations.'))
5323
5334
            else:
5324
5335
                if location is None:
5325
5336
                    if b.get_bound_location() is not None:
5333
5344
        try:
5334
5345
            b.bind(b_other)
5335
5346
        except errors.DivergedBranches:
5336
 
            raise errors.BzrCommandError(gettext('These branches have diverged.'
5337
 
                                         ' Try merging, and then bind again.'))
 
5347
            raise errors.BzrCommandError(
 
5348
                gettext('These branches have diverged.'
 
5349
                        ' Try merging, and then bind again.'))
5338
5350
        if b.get_config().has_explicit_nickname():
5339
5351
            b.nick = b_other.nick
5340
5352
 
5378
5390
    # information in shared branches as well.
5379
5391
    _see_also = ['commit']
5380
5392
    takes_options = ['verbose', 'revision',
5381
 
                    Option('dry-run', help='Don\'t actually make changes.'),
5382
 
                    Option('force', help='Say yes to all questions.'),
5383
 
                    Option('keep-tags',
5384
 
                           help='Keep tags that point to removed revisions.'),
5385
 
                    Option('local',
5386
 
                           help="Only remove the commits from the local branch"
5387
 
                                " when in a checkout."
5388
 
                           ),
5389
 
                    ]
 
5393
                     Option('dry-run', help='Don\'t actually make changes.'),
 
5394
                     Option('force', help='Say yes to all questions.'),
 
5395
                     Option('keep-tags',
 
5396
                            help='Keep tags that point to removed revisions.'),
 
5397
                     Option('local',
 
5398
                            help="Only remove the commits from the local "
 
5399
                            "branch when in a checkout."
 
5400
                            ),
 
5401
                     ]
5390
5402
    takes_args = ['location?']
5391
5403
    aliases = []
5392
5404
    encoding_type = 'replace'
5448
5460
 
5449
5461
        if dry_run:
5450
5462
            self.outf.write(gettext('Dry-run, pretending to remove'
5451
 
                            ' the above revisions.\n'))
 
5463
                                    ' the above revisions.\n'))
5452
5464
        else:
5453
 
            self.outf.write(gettext('The above revision(s) will be removed.\n'))
 
5465
            self.outf.write(
 
5466
                gettext('The above revision(s) will be removed.\n'))
5454
5467
 
5455
5468
        if not force:
5456
5469
            if not ui.ui_factory.confirm_action(
5464
5477
               last_rev_id, rev_id)
5465
5478
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
5466
5479
                 revno=revno, local=local, keep_tags=keep_tags)
5467
 
        self.outf.write(gettext('You can restore the old tip by running:\n'
5468
 
             '  brz pull . -r revid:%s\n') % last_rev_id.decode('utf-8'))
 
5480
        self.outf.write(
 
5481
            gettext('You can restore the old tip by running:\n'
 
5482
                    '  brz pull . -r revid:%s\n')
 
5483
            % last_rev_id.decode('utf-8'))
5469
5484
 
5470
5485
 
5471
5486
class cmd_break_lock(Command):
5491
5506
        Option('config',
5492
5507
               help='LOCATION is the directory where the config lock is.'),
5493
5508
        Option('force',
5494
 
            help='Do not ask for confirmation before breaking the lock.'),
 
5509
               help='Do not ask for confirmation before breaking the lock.'),
5495
5510
        ]
5496
5511
 
5497
5512
    def run(self, location=None, config=False, force=False):
5499
5514
            location = u'.'
5500
5515
        if force:
5501
5516
            ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
5502
 
                None,
5503
 
                {'breezy.lockdir.break': True})
 
5517
                                                               None,
 
5518
                                                               {'breezy.lockdir.break': True})
5504
5519
        if config:
5505
5520
            conf = _mod_config.LockableConfig(file_name=location)
5506
5521
            conf.break_lock()
5535
5550
        Option('inet',
5536
5551
               help='Serve on stdin/out for use from inetd or sshd.'),
5537
5552
        RegistryOption('protocol',
5538
 
               help="Protocol to serve.",
5539
 
               lazy_registry=('breezy.transport', 'transport_server_registry'),
5540
 
               value_switches=True),
 
5553
                       help="Protocol to serve.",
 
5554
                       lazy_registry=('breezy.transport',
 
5555
                                      'transport_server_registry'),
 
5556
                       value_switches=True),
5541
5557
        Option('listen',
5542
 
               help='Listen for connections on nominated address.', type=text_type),
 
5558
               help='Listen for connections on nominated address.',
 
5559
               type=text_type),
5543
5560
        Option('port',
5544
5561
               help='Listen for connections on nominated port.  Passing 0 as '
5545
5562
                    'the port number will result in a dynamically allocated '
5546
5563
                    'port.  The default port depends on the protocol.',
5547
5564
               type=int),
5548
5565
        custom_help('directory',
5549
 
               help='Serve contents of this directory.'),
 
5566
                    help='Serve contents of this directory.'),
5550
5567
        Option('allow-writes',
5551
5568
               help='By default the server is a readonly server.  Supplying '
5552
5569
                    '--allow-writes enables write access to the contents of '
5555
5572
                    'external authentication is arranged supplying this '
5556
5573
                    'option leads to global uncontrolled write access to your '
5557
5574
                    'file system.'
5558
 
                ),
 
5575
               ),
5559
5576
        Option('client-timeout', type=float,
5560
5577
               help='Override the default idle client timeout (5min).'),
5561
5578
        ]
5562
5579
 
5563
5580
    def run(self, listen=None, port=None, inet=False, directory=None,
5564
5581
            allow_writes=False, protocol=None, client_timeout=None):
5565
 
        from . import transport
 
5582
        from . import location, transport
5566
5583
        if directory is None:
5567
5584
            directory = osutils.getcwd()
5568
5585
        if protocol is None:
5569
5586
            protocol = transport.transport_server_registry.get()
5570
 
        url = transport.location_to_url(directory)
 
5587
        url = location.location_to_url(directory)
5571
5588
        if not allow_writes:
5572
5589
            url = 'readonly+' + url
5573
5590
        t = transport.get_transport_from_url(url)
5591
5608
    _see_also = ['split']
5592
5609
    takes_args = ['tree']
5593
5610
    takes_options = [
5594
 
            Option('reference', help='Join by reference.', hidden=True),
5595
 
            ]
 
5611
        Option('reference', help='Join by reference.', hidden=True),
 
5612
        ]
5596
5613
 
5597
5614
    def run(self, tree, reference=False):
5598
5615
        from breezy.mutabletree import BadReferenceTarget
5612
5629
                # XXX: Would be better to just raise a nicely printable
5613
5630
                # exception from the real origin.  Also below.  mbp 20070306
5614
5631
                raise errors.BzrCommandError(
5615
 
                       gettext("Cannot join {0}.  {1}").format(tree, e.reason))
 
5632
                    gettext("Cannot join {0}.  {1}").format(tree, e.reason))
5616
5633
        else:
5617
5634
            try:
5618
5635
                containing_tree.subsume(sub_tree)
5619
5636
            except errors.BadSubsumeSource as e:
5620
5637
                raise errors.BzrCommandError(
5621
 
                       gettext("Cannot join {0}.  {1}").format(tree, e.reason))
 
5638
                    gettext("Cannot join {0}.  {1}").format(tree, e.reason))
5622
5639
 
5623
5640
 
5624
5641
class cmd_split(Command):
5638
5655
 
5639
5656
    def run(self, tree):
5640
5657
        containing_tree, subdir = WorkingTree.open_containing(tree)
5641
 
        sub_id = containing_tree.path2id(subdir)
5642
 
        if sub_id is None:
 
5658
        if not containing_tree.is_versioned(subdir):
5643
5659
            raise errors.NotVersionedError(subdir)
5644
5660
        try:
5645
 
            containing_tree.extract(subdir, sub_id)
 
5661
            containing_tree.extract(subdir)
5646
5662
        except errors.RootNotRich:
5647
5663
            raise errors.RichRootUpgradeRequired(containing_tree.branch.base)
5648
5664
 
5672
5688
 
5673
5689
    takes_options = [
5674
5690
        'directory',
5675
 
        RegistryOption.from_kwargs('patch-type',
 
5691
        RegistryOption.from_kwargs(
 
5692
            'patch-type',
5676
5693
            'The type of patch to include in the directive.',
5677
5694
            title='Patch type',
5678
5695
            value_switches=True,
5682
5699
            plain='No patch, just directive.'),
5683
5700
        Option('sign', help='GPG-sign the directive.'), 'revision',
5684
5701
        Option('mail-to', type=text_type,
5685
 
            help='Instead of printing the directive, email to this address.'),
 
5702
               help='Instead of printing the directive, email to this '
 
5703
               'address.'),
5686
5704
        Option('message', type=text_type, short_name='m',
5687
 
            help='Message to use when committing this merge.')
 
5705
               help='Message to use when committing this merge.')
5688
5706
        ]
5689
5707
 
5690
5708
    encoding_type = 'exact'
5708
5726
        if submit_branch is None:
5709
5727
            submit_branch = branch.get_parent()
5710
5728
        if submit_branch is None:
5711
 
            raise errors.BzrCommandError(gettext('No submit branch specified or known'))
 
5729
            raise errors.BzrCommandError(
 
5730
                gettext('No submit branch specified or known'))
5712
5731
 
5713
5732
        stored_public_branch = branch.get_public_branch()
5714
5733
        if public_branch is None:
5717
5736
            # FIXME: Should be done only if we succeed ? -- vila 2012-01-03
5718
5737
            branch.set_public_branch(public_branch)
5719
5738
        if not include_bundle and public_branch is None:
5720
 
            raise errors.BzrCommandError(gettext('No public branch specified or'
5721
 
                                         ' known'))
 
5739
            raise errors.BzrCommandError(
 
5740
                gettext('No public branch specified or known'))
5722
5741
        base_revision_id = None
5723
5742
        if revision is not None:
5724
5743
            if len(revision) > 2:
5725
 
                raise errors.BzrCommandError(gettext('brz merge-directive takes '
5726
 
                    'at most two one revision identifiers'))
 
5744
                raise errors.BzrCommandError(
 
5745
                    gettext('brz merge-directive takes '
 
5746
                            'at most two one revision identifiers'))
5727
5747
            revision_id = revision[-1].as_revision_id(branch)
5728
5748
            if len(revision) == 2:
5729
5749
                base_revision_id = revision[0].as_revision_id(branch)
5763
5783
      branch.
5764
5784
 
5765
5785
    `brz send` creates a compact data set that, when applied using brz
5766
 
    merge, has the same effect as merging from the source branch.  
5767
 
    
 
5786
    merge, has the same effect as merging from the source branch.
 
5787
 
5768
5788
    By default the merge directive is self-contained and can be applied to any
5769
5789
    branch containing submit_branch in its ancestory without needing access to
5770
5790
    the source branch.
5771
 
    
 
5791
 
5772
5792
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
5773
5793
    revisions, but only a structured request to merge from the
5774
5794
    public_location.  In that case the public_branch is needed and it must be
5800
5820
    If the preferred client can't be found (or used), your editor will be used.
5801
5821
 
5802
5822
    To use a specific mail program, set the mail_client configuration option.
5803
 
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
5804
 
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
5805
 
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
5806
 
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
5807
 
    supported clients.
 
5823
    Supported values for specific clients are "claws", "evolution", "kmail",
 
5824
    "mail.app" (MacOS X's Mail.app), "mutt", and "thunderbird"; generic options
 
5825
    are "default", "editor", "emacsclient", "mapi", and "xdg-email".  Plugins
 
5826
    may also add supported clients.
5808
5827
 
5809
5828
    If mail is being sent, a to address is required.  This can be supplied
5810
5829
    either on the commandline, by setting the submit_to configuration
5811
5830
    option in the branch itself or the child_submit_to configuration option
5812
5831
    in the submit branch.
5813
5832
 
5814
 
    Two formats are currently supported: "4" uses revision bundle format 4 and
5815
 
    merge directive format 2.  It is significantly faster and smaller than
5816
 
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
5817
 
    default.  "0.9" uses revision bundle format 0.9 and merge directive
5818
 
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
5819
 
 
5820
5833
    The merge directives created by brz send may be applied using brz merge or
5821
5834
    brz pull by specifying a file containing a merge directive as the location.
5822
5835
 
5897
5910
    branch is used in the merge instructions.  This means that a local mirror
5898
5911
    can be used as your actual submit branch, once you have set public_branch
5899
5912
    for that mirror.
5900
 
 
5901
 
    Two formats are currently supported: "4" uses revision bundle format 4 and
5902
 
    merge directive format 2.  It is significantly faster and smaller than
5903
 
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
5904
 
    default.  "0.9" uses revision bundle format 0.9 and merge directive
5905
 
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
5906
5913
    """
5907
5914
 
5908
5915
    takes_options = [
5940
5947
            output = '-'
5941
5948
        from .send import send
5942
5949
        return send(submit_branch, revision, public_branch, remember,
5943
 
                         format, no_bundle, no_patch, output,
5944
 
                         kwargs.get('from', '.'), None, None, None,
5945
 
                         self.outf, strict=strict)
 
5950
                    format, no_bundle, no_patch, output,
 
5951
                    kwargs.get('from', '.'), None, None, None,
 
5952
                    self.outf, strict=strict)
5946
5953
 
5947
5954
 
5948
5955
class cmd_tag(Command):
5961
5968
    To rename a tag (change the name but keep it on the same revsion), run ``brz
5962
5969
    tag new-name -r tag:old-name`` and then ``brz tag --delete oldname``.
5963
5970
 
5964
 
    If no tag name is specified it will be determined through the 
 
5971
    If no tag name is specified it will be determined through the
5965
5972
    'automatic_tag_name' hook. This can e.g. be used to automatically tag
5966
5973
    upstream releases by reading configure.ac. See ``brz help hooks`` for
5967
5974
    details.
5971
5978
    takes_args = ['tag_name?']
5972
5979
    takes_options = [
5973
5980
        Option('delete',
5974
 
            help='Delete this tag rather than placing it.',
5975
 
            ),
 
5981
               help='Delete this tag rather than placing it.',
 
5982
               ),
5976
5983
        custom_help('directory',
5977
 
            help='Branch in which to place the tag.'),
 
5984
                    help='Branch in which to place the tag.'),
5978
5985
        Option('force',
5979
 
            help='Replace existing tags.',
5980
 
            ),
 
5986
               help='Replace existing tags.',
 
5987
               ),
5981
5988
        'revision',
5982
5989
        ]
5983
5990
 
5991
5998
        self.add_cleanup(branch.lock_write().unlock)
5992
5999
        if delete:
5993
6000
            if tag_name is None:
5994
 
                raise errors.BzrCommandError(gettext("No tag specified to delete."))
 
6001
                raise errors.BzrCommandError(
 
6002
                    gettext("No tag specified to delete."))
5995
6003
            branch.tags.delete_tag(tag_name)
5996
6004
            note(gettext('Deleted tag %s.') % tag_name)
5997
6005
        else:
6033
6041
    _see_also = ['tag']
6034
6042
    takes_options = [
6035
6043
        custom_help('directory',
6036
 
            help='Branch whose tags should be displayed.'),
 
6044
                    help='Branch whose tags should be displayed.'),
6037
6045
        RegistryOption('sort',
6038
 
            'Sort tags by different criteria.', title='Sorting',
6039
 
            lazy_registry=('breezy.tag', 'tag_sort_methods')
6040
 
            ),
 
6046
                       'Sort tags by different criteria.', title='Sorting',
 
6047
                       lazy_registry=('breezy.tag', 'tag_sort_methods')
 
6048
                       ),
6041
6049
        'show-ids',
6042
6050
        'revision',
6043
6051
    ]
6079
6087
            self.outf.write('%-20s %s\n' % (tag, revspec))
6080
6088
 
6081
6089
    def _tags_for_range(self, branch, revision):
6082
 
        range_valid = True
6083
6090
        rev1, rev2 = _get_revision_range(revision, branch, self.name())
6084
6091
        revid1, revid2 = rev1.rev_id, rev2.rev_id
6085
6092
        # _get_revision_range will always set revid2 if it's not specified.
6097
6104
        tagged_revids = branch.tags.get_reverse_tag_dict()
6098
6105
        found = []
6099
6106
        for r in branch.iter_merge_sorted_revisions(
6100
 
            start_revision_id=revid2, stop_revision_id=revid1,
6101
 
            stop_rule='include'):
 
6107
                start_revision_id=revid2, stop_revision_id=revid1,
 
6108
                stop_rule='include'):
6102
6109
            revid_tags = tagged_revids.get(r[0], None)
6103
6110
            if revid_tags:
6104
6111
                found.extend([(tag, r[0]) for tag in revid_tags])
6131
6138
            tree='Reconfigure to be an unbound branch with a working tree.',
6132
6139
            checkout='Reconfigure to be a bound branch with a working tree.',
6133
6140
            lightweight_checkout='Reconfigure to be a lightweight'
6134
 
                ' checkout (with no local history).',
 
6141
            ' checkout (with no local history).',
6135
6142
            ),
6136
6143
        RegistryOption.from_kwargs(
6137
6144
            'repository_type',
6139
6146
            help='Location fo the repository.',
6140
6147
            value_switches=True, enum_switch=False,
6141
6148
            standalone='Reconfigure to be a standalone branch '
6142
 
                '(i.e. stop using shared repository).',
 
6149
            '(i.e. stop using shared repository).',
6143
6150
            use_shared='Reconfigure to use a shared repository.',
6144
6151
            ),
6145
6152
        RegistryOption.from_kwargs(
6148
6155
            help='Whether new branches in the repository have trees.',
6149
6156
            value_switches=True, enum_switch=False,
6150
6157
            with_trees='Reconfigure repository to create '
6151
 
                'working trees on branches by default.',
 
6158
            'working trees on branches by default.',
6152
6159
            with_no_trees='Reconfigure repository to not create '
6153
 
                'working trees on branches by default.'
 
6160
            'working trees on branches by default.'
6154
6161
            ),
6155
6162
        Option('bind-to', help='Branch to bind checkout to.', type=text_type),
6156
6163
        Option('force',
6157
 
            help='Perform reconfiguration even if local changes'
6158
 
            ' will be lost.'),
 
6164
               help='Perform reconfiguration even if local changes'
 
6165
               ' will be lost.'),
6159
6166
        Option('stacked-on',
6160
 
            help='Reconfigure a branch to be stacked on another branch.',
6161
 
            type=text_type,
6162
 
            ),
 
6167
               help='Reconfigure a branch to be stacked on another branch.',
 
6168
               type=text_type,
 
6169
               ),
6163
6170
        Option('unstacked',
6164
 
            help='Reconfigure a branch to be unstacked.  This '
6165
 
                'may require copying substantial data into it.',
6166
 
            ),
 
6171
               help='Reconfigure a branch to be unstacked.  This '
 
6172
               'may require copying substantial data into it.',
 
6173
               ),
6167
6174
        ]
6168
6175
 
6169
6176
    def run(self, location=None, bind_to=None, force=False,
6171
6178
            stacked_on=None, unstacked=None):
6172
6179
        directory = controldir.ControlDir.open(location)
6173
6180
        if stacked_on and unstacked:
6174
 
            raise errors.BzrCommandError(gettext("Can't use both --stacked-on and --unstacked"))
 
6181
            raise errors.BzrCommandError(
 
6182
                gettext("Can't use both --stacked-on and --unstacked"))
6175
6183
        elif stacked_on is not None:
6176
6184
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
6177
6185
        elif unstacked:
6181
6189
        # to ban it.
6182
6190
        if (tree_type is None and
6183
6191
            repository_type is None and
6184
 
            repository_trees is None):
 
6192
                repository_trees is None):
6185
6193
            if stacked_on or unstacked:
6186
6194
                return
6187
6195
            else:
6188
6196
                raise errors.BzrCommandError(gettext('No target configuration '
6189
 
                    'specified'))
 
6197
                                                     'specified'))
6190
6198
        reconfiguration = None
6191
6199
        if tree_type == 'branch':
6192
6200
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
6245
6253
    takes_args = ['to_location?']
6246
6254
    takes_options = ['directory',
6247
6255
                     Option('force',
6248
 
                        help='Switch even if local commits will be lost.'),
 
6256
                            help='Switch even if local commits will be lost.'),
6249
6257
                     'revision',
6250
6258
                     Option('create-branch', short_name='b',
6251
 
                        help='Create the target branch from this one before'
6252
 
                             ' switching to it.'),
 
6259
                            help='Create the target branch from this one before'
 
6260
                            ' switching to it.'),
6253
6261
                     Option('store',
6254
 
                        help='Store and restore uncommitted changes in the'
6255
 
                             ' branch.'),
6256
 
                    ]
 
6262
                            help='Store and restore uncommitted changes in the'
 
6263
                            ' branch.'),
 
6264
                     ]
6257
6265
 
6258
6266
    def run(self, to_location=None, force=False, create_branch=False,
6259
6267
            revision=None, directory=u'.', store=False):
6262
6270
        revision = _get_one_revision('switch', revision)
6263
6271
        possible_transports = []
6264
6272
        control_dir = controldir.ControlDir.open_containing(tree_location,
6265
 
            possible_transports=possible_transports)[0]
 
6273
                                                            possible_transports=possible_transports)[0]
6266
6274
        if to_location is None:
6267
6275
            if revision is None:
6268
6276
                raise errors.BzrCommandError(gettext('You must supply either a'
6269
 
                                             ' revision or a location'))
 
6277
                                                     ' revision or a location'))
6270
6278
            to_location = tree_location
6271
6279
        try:
6272
6280
            branch = control_dir.open_branch(
6279
6287
            if branch is None:
6280
6288
                raise errors.BzrCommandError(
6281
6289
                    gettext('cannot create branch without source branch'))
6282
 
            to_location = lookup_new_sibling_branch(control_dir, to_location,
6283
 
                 possible_transports=possible_transports)
6284
 
            to_branch = branch.controldir.sprout(to_location,
6285
 
                 possible_transports=possible_transports,
6286
 
                 source_branch=branch).open_branch()
 
6290
            to_location = lookup_new_sibling_branch(
 
6291
                control_dir, to_location,
 
6292
                possible_transports=possible_transports)
 
6293
            if revision is not None:
 
6294
                revision = revision.as_revision_id(branch)
 
6295
            to_branch = branch.controldir.sprout(
 
6296
                to_location,
 
6297
                possible_transports=possible_transports,
 
6298
                revision_id=revision,
 
6299
                source_branch=branch).open_branch()
6287
6300
        else:
6288
6301
            try:
6289
6302
                to_branch = Branch.open(to_location,
6290
 
                    possible_transports=possible_transports)
 
6303
                                        possible_transports=possible_transports)
6291
6304
            except errors.NotBranchError:
6292
 
                to_branch = open_sibling_branch(control_dir, to_location,
 
6305
                to_branch = open_sibling_branch(
 
6306
                    control_dir, to_location,
6293
6307
                    possible_transports=possible_transports)
6294
 
        if revision is not None:
6295
 
            revision = revision.as_revision_id(to_branch)
 
6308
            if revision is not None:
 
6309
                revision = revision.as_revision_id(to_branch)
6296
6310
        try:
6297
6311
            switch.switch(control_dir, to_branch, force, revision_id=revision,
6298
6312
                          store_uncommitted=store)
6299
6313
        except controldir.BranchReferenceLoop:
6300
6314
            raise errors.BzrCommandError(
6301
 
                    gettext('switching would create a branch reference loop. '
6302
 
                            'Use the "bzr up" command to switch to a '
6303
 
                            'different revision.'))
 
6315
                gettext('switching would create a branch reference loop. '
 
6316
                        'Use the "bzr up" command to switch to a '
 
6317
                        'different revision.'))
6304
6318
        if had_explicit_nick:
6305
 
            branch = control_dir.open_branch() #get the new branch!
 
6319
            branch = control_dir.open_branch()  # get the new branch!
6306
6320
            branch.nick = to_branch.nick
6307
 
        note(gettext('Switched to branch: %s'),
6308
 
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
6309
 
 
 
6321
        if to_branch.name:
 
6322
            if to_branch.controldir.control_url != control_dir.control_url:
 
6323
                note(gettext('Switched to branch %s at %s'),
 
6324
                     to_branch.name, urlutils.unescape_for_display(to_branch.base, 'utf-8'))
 
6325
            else:
 
6326
                note(gettext('Switched to branch %s'), to_branch.name)
 
6327
        else:
 
6328
            note(gettext('Switched to branch at %s'),
 
6329
                 urlutils.unescape_for_display(to_branch.base, 'utf-8'))
6310
6330
 
6311
6331
 
6312
6332
class cmd_view(Command):
6375
6395
    takes_args = ['file*']
6376
6396
    takes_options = [
6377
6397
        Option('all',
6378
 
            help='Apply list or delete action to all views.',
6379
 
            ),
 
6398
               help='Apply list or delete action to all views.',
 
6399
               ),
6380
6400
        Option('delete',
6381
 
            help='Delete the view.',
6382
 
            ),
 
6401
               help='Delete the view.',
 
6402
               ),
6383
6403
        Option('name',
6384
 
            help='Name of the view to define, list or delete.',
6385
 
            type=text_type,
6386
 
            ),
 
6404
               help='Name of the view to define, list or delete.',
 
6405
               type=text_type,
 
6406
               ),
6387
6407
        Option('switch',
6388
 
            help='Name of the view to switch to.',
6389
 
            type=text_type,
6390
 
            ),
 
6408
               help='Name of the view to switch to.',
 
6409
               type=text_type,
 
6410
               ),
6391
6411
        ]
6392
6412
 
6393
6413
    def run(self, file_list,
6397
6417
            switch=None,
6398
6418
            ):
6399
6419
        tree, file_list = WorkingTree.open_containing_paths(file_list,
6400
 
            apply_view=False)
 
6420
                                                            apply_view=False)
6401
6421
        current_view, view_dict = tree.views.get_view_info()
6402
6422
        if name is None:
6403
6423
            name = current_view
6412
6432
                tree.views.set_view_info(None, {})
6413
6433
                self.outf.write(gettext("Deleted all views.\n"))
6414
6434
            elif name is None:
6415
 
                raise errors.BzrCommandError(gettext("No current view to delete"))
 
6435
                raise errors.BzrCommandError(
 
6436
                    gettext("No current view to delete"))
6416
6437
            else:
6417
6438
                tree.views.delete_view(name)
6418
6439
                self.outf.write(gettext("Deleted '%s' view.\n") % name)
6425
6446
                    "Both --switch and --all specified"))
6426
6447
            elif switch == 'off':
6427
6448
                if current_view is None:
6428
 
                    raise errors.BzrCommandError(gettext("No current view to disable"))
 
6449
                    raise errors.BzrCommandError(
 
6450
                        gettext("No current view to disable"))
6429
6451
                tree.views.set_view_info(None, view_dict)
6430
 
                self.outf.write(gettext("Disabled '%s' view.\n") % (current_view))
 
6452
                self.outf.write(gettext("Disabled '%s' view.\n") %
 
6453
                                (current_view))
6431
6454
            else:
6432
6455
                tree.views.set_view_info(switch, view_dict)
6433
6456
                view_str = views.view_display_str(tree.views.lookup_view())
6434
 
                self.outf.write(gettext("Using '{0}' view: {1}\n").format(switch, view_str))
 
6457
                self.outf.write(
 
6458
                    gettext("Using '{0}' view: {1}\n").format(switch, view_str))
6435
6459
        elif all:
6436
6460
            if view_dict:
6437
6461
                self.outf.write(gettext('Views defined:\n'))
6453
6477
                    "Cannot change the 'off' pseudo view"))
6454
6478
            tree.views.set_view(name, sorted(file_list))
6455
6479
            view_str = views.view_display_str(tree.views.lookup_view())
6456
 
            self.outf.write(gettext("Using '{0}' view: {1}\n").format(name, view_str))
 
6480
            self.outf.write(
 
6481
                gettext("Using '{0}' view: {1}\n").format(name, view_str))
6457
6482
        else:
6458
6483
            # list the files
6459
6484
            if name is None:
6461
6486
                self.outf.write(gettext('No current view.\n'))
6462
6487
            else:
6463
6488
                view_str = views.view_display_str(tree.views.lookup_view(name))
6464
 
                self.outf.write(gettext("'{0}' view is: {1}\n").format(name, view_str))
 
6489
                self.outf.write(
 
6490
                    gettext("'{0}' view is: {1}\n").format(name, view_str))
6465
6491
 
6466
6492
 
6467
6493
class cmd_hooks(Command):
6487
6513
class cmd_remove_branch(Command):
6488
6514
    __doc__ = """Remove a branch.
6489
6515
 
6490
 
    This will remove the branch from the specified location but 
 
6516
    This will remove the branch from the specified location but
6491
6517
    will keep any working tree or repository in place.
6492
6518
 
6493
6519
    :Examples:
6501
6527
    takes_args = ["location?"]
6502
6528
 
6503
6529
    takes_options = ['directory',
6504
 
        Option('force', help='Remove branch even if it is the active branch.')]
 
6530
                     Option('force', help='Remove branch even if it is the active branch.')]
6505
6531
 
6506
6532
    aliases = ["rmbranch"]
6507
6533
 
6513
6539
            except errors.NotBranchError:
6514
6540
                active_branch = None
6515
6541
            if (active_branch is not None and
6516
 
                br.control_url == active_branch.control_url):
 
6542
                    br.control_url == active_branch.control_url):
6517
6543
                raise errors.BzrCommandError(
6518
6544
                    gettext("Branch is active. Use --force to remove it."))
6519
6545
        br.controldir.destroy_branch(br.name)
6549
6575
 
6550
6576
        change_editor = PROGRAM @new_path @old_path
6551
6577
 
6552
 
    where @new_path is replaced with the path of the new version of the 
6553
 
    file and @old_path is replaced with the path of the old version of 
6554
 
    the file.  The PROGRAM should save the new file with the desired 
 
6578
    where @new_path is replaced with the path of the new version of the
 
6579
    file and @old_path is replaced with the path of the old version of
 
6580
    the file.  The PROGRAM should save the new file with the desired
6555
6581
    contents of the file in the working tree.
6556
 
        
 
6582
 
6557
6583
    """
6558
6584
 
6559
6585
    takes_args = ['file*']
6582
6608
            writer = breezy.option.diff_writer_registry.get()
6583
6609
        try:
6584
6610
            shelver = Shelver.from_args(writer(self.outf), revision, all,
6585
 
                file_list, message, destroy=destroy, directory=directory)
 
6611
                                        file_list, message, destroy=destroy, directory=directory)
6586
6612
            try:
6587
6613
                shelver.run()
6588
6614
            finally:
6665
6691
                     Option('dry-run', help='Show files to delete instead of'
6666
6692
                            ' deleting them.'),
6667
6693
                     Option('force', help='Do not prompt before deleting.')]
 
6694
 
6668
6695
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
6669
6696
            force=False, directory=u'.'):
6670
6697
        from .clean_tree import clean_tree
6687
6714
    hidden = True
6688
6715
 
6689
6716
    takes_args = ['path?', 'location?']
 
6717
    takes_options = [
 
6718
        Option('force-unversioned',
 
6719
               help='Set reference even if path is not versioned.'),
 
6720
        ]
6690
6721
 
6691
 
    def run(self, path=None, location=None):
 
6722
    def run(self, path=None, location=None, force_unversioned=False):
6692
6723
        branchdir = '.'
6693
6724
        if path is not None:
6694
6725
            branchdir = path
6695
 
        tree, branch, relpath =(
 
6726
        tree, branch, relpath = (
6696
6727
            controldir.ControlDir.open_containing_tree_or_branch(branchdir))
6697
6728
        if path is not None:
6698
6729
            path = relpath
6702
6733
            info = viewitems(branch._get_all_reference_info())
6703
6734
            self._display_reference_info(tree, branch, info)
6704
6735
        else:
6705
 
            if not tree.is_versioned(path):
 
6736
            if not tree.is_versioned(path) and not force_unversioned:
6706
6737
                raise errors.NotVersionedError(path)
6707
6738
            if location is None:
6708
6739
                info = [(path, branch.get_reference_info(path))]
6724
6755
 
6725
6756
    hidden = True
6726
6757
    takes_options = [Option('plugin',
6727
 
                            help='Export help text from named command '\
 
6758
                            help='Export help text from named command '
6728
6759
                                 '(defaults to all built in commands).',
6729
6760
                            type=text_type),
6730
6761
                     Option('include-duplicates',
6731
6762
                            help='Output multiple copies of the same msgid '
6732
6763
                                 'string if it appears more than once.'),
6733
 
                            ]
 
6764
                     ]
6734
6765
 
6735
6766
    def run(self, plugin=None, include_duplicates=False):
6736
6767
        from .export_pot import export_pot
6800
6831
            cmd_reconcile().run(".")
6801
6832
 
6802
6833
 
 
6834
class cmd_grep(Command):
 
6835
    """Print lines matching PATTERN for specified files and revisions.
 
6836
 
 
6837
    This command searches the specified files and revisions for a given
 
6838
    pattern.  The pattern is specified as a Python regular expressions[1].
 
6839
 
 
6840
    If the file name is not specified, the revisions starting with the
 
6841
    current directory are searched recursively. If the revision number is
 
6842
    not specified, the working copy is searched. To search the last committed
 
6843
    revision, use the '-r -1' or '-r last:1' option.
 
6844
 
 
6845
    Unversioned files are not searched unless explicitly specified on the
 
6846
    command line. Unversioned directores are not searched.
 
6847
 
 
6848
    When searching a pattern, the output is shown in the 'filepath:string'
 
6849
    format. If a revision is explicitly searched, the output is shown as
 
6850
    'filepath~N:string', where N is the revision number.
 
6851
 
 
6852
    --include and --exclude options can be used to search only (or exclude
 
6853
    from search) files with base name matches the specified Unix style GLOB
 
6854
    pattern.  The GLOB pattern an use *, ?, and [...] as wildcards, and \\
 
6855
    to quote wildcard or backslash character literally. Note that the glob
 
6856
    pattern is not a regular expression.
 
6857
 
 
6858
    [1] http://docs.python.org/library/re.html#regular-expression-syntax
 
6859
    """
 
6860
 
 
6861
    encoding_type = 'replace'
 
6862
    takes_args = ['pattern', 'path*']
 
6863
    takes_options = [
 
6864
        'verbose',
 
6865
        'revision',
 
6866
        Option('color', type=text_type, argname='when',
 
6867
               help='Show match in color. WHEN is never, always or auto.'),
 
6868
        Option('diff', short_name='p',
 
6869
               help='Grep for pattern in changeset for each revision.'),
 
6870
        ListOption('exclude', type=text_type, argname='glob', short_name='X',
 
6871
                   help="Skip files whose base name matches GLOB."),
 
6872
        ListOption('include', type=text_type, argname='glob', short_name='I',
 
6873
                   help="Search only files whose base name matches GLOB."),
 
6874
        Option('files-with-matches', short_name='l',
 
6875
               help='Print only the name of each input file in '
 
6876
               'which PATTERN is found.'),
 
6877
        Option('files-without-match', short_name='L',
 
6878
               help='Print only the name of each input file in '
 
6879
               'which PATTERN is not found.'),
 
6880
        Option('fixed-string', short_name='F',
 
6881
               help='Interpret PATTERN is a single fixed string (not regex).'),
 
6882
        Option('from-root',
 
6883
               help='Search for pattern starting from the root of the branch. '
 
6884
               '(implies --recursive)'),
 
6885
        Option('ignore-case', short_name='i',
 
6886
               help='Ignore case distinctions while matching.'),
 
6887
        Option('levels',
 
6888
               help='Number of levels to display - 0 for all, 1 for collapsed '
 
6889
               '(1 is default).',
 
6890
               argname='N',
 
6891
               type=_parse_levels),
 
6892
        Option('line-number', short_name='n',
 
6893
               help='Show 1-based line number.'),
 
6894
        Option('no-recursive',
 
6895
               help="Don't recurse into subdirectories. (default is --recursive)"),
 
6896
        Option('null', short_name='Z',
 
6897
               help='Write an ASCII NUL (\\0) separator '
 
6898
               'between output lines rather than a newline.'),
 
6899
        ]
 
6900
 
 
6901
    @display_command
 
6902
    def run(self, verbose=False, ignore_case=False, no_recursive=False,
 
6903
            from_root=False, null=False, levels=None, line_number=False,
 
6904
            path_list=None, revision=None, pattern=None, include=None,
 
6905
            exclude=None, fixed_string=False, files_with_matches=False,
 
6906
            files_without_match=False, color=None, diff=False):
 
6907
        from breezy import _termcolor
 
6908
        from . import grep
 
6909
        import re
 
6910
        if path_list is None:
 
6911
            path_list = ['.']
 
6912
        else:
 
6913
            if from_root:
 
6914
                raise errors.BzrCommandError(
 
6915
                    'cannot specify both --from-root and PATH.')
 
6916
 
 
6917
        if files_with_matches and files_without_match:
 
6918
            raise errors.BzrCommandError(
 
6919
                'cannot specify both '
 
6920
                '-l/--files-with-matches and -L/--files-without-matches.')
 
6921
 
 
6922
        global_config = _mod_config.GlobalConfig()
 
6923
 
 
6924
        if color is None:
 
6925
            color = global_config.get_user_option('grep_color')
 
6926
 
 
6927
        if color is None:
 
6928
            color = 'never'
 
6929
 
 
6930
        if color not in ['always', 'never', 'auto']:
 
6931
            raise errors.BzrCommandError('Valid values for --color are '
 
6932
                                         '"always", "never" or "auto".')
 
6933
 
 
6934
        if levels is None:
 
6935
            levels = 1
 
6936
 
 
6937
        print_revno = False
 
6938
        if revision is not None or levels == 0:
 
6939
            # print revision numbers as we may be showing multiple revisions
 
6940
            print_revno = True
 
6941
 
 
6942
        eol_marker = '\n'
 
6943
        if null:
 
6944
            eol_marker = '\0'
 
6945
 
 
6946
        if not ignore_case and grep.is_fixed_string(pattern):
 
6947
            # if the pattern isalnum, implicitly use to -F for faster grep
 
6948
            fixed_string = True
 
6949
        elif ignore_case and fixed_string:
 
6950
            # GZ 2010-06-02: Fall back to regexp rather than lowercasing
 
6951
            #                pattern and text which will cause pain later
 
6952
            fixed_string = False
 
6953
            pattern = re.escape(pattern)
 
6954
 
 
6955
        patternc = None
 
6956
        re_flags = re.MULTILINE
 
6957
        if ignore_case:
 
6958
            re_flags |= re.IGNORECASE
 
6959
 
 
6960
        if not fixed_string:
 
6961
            patternc = grep.compile_pattern(
 
6962
                pattern.encode(grep._user_encoding), re_flags)
 
6963
 
 
6964
        if color == 'always':
 
6965
            show_color = True
 
6966
        elif color == 'never':
 
6967
            show_color = False
 
6968
        elif color == 'auto':
 
6969
            show_color = _termcolor.allow_color()
 
6970
 
 
6971
        opts = grep.GrepOptions()
 
6972
 
 
6973
        opts.verbose = verbose
 
6974
        opts.ignore_case = ignore_case
 
6975
        opts.no_recursive = no_recursive
 
6976
        opts.from_root = from_root
 
6977
        opts.null = null
 
6978
        opts.levels = levels
 
6979
        opts.line_number = line_number
 
6980
        opts.path_list = path_list
 
6981
        opts.revision = revision
 
6982
        opts.pattern = pattern
 
6983
        opts.include = include
 
6984
        opts.exclude = exclude
 
6985
        opts.fixed_string = fixed_string
 
6986
        opts.files_with_matches = files_with_matches
 
6987
        opts.files_without_match = files_without_match
 
6988
        opts.color = color
 
6989
        opts.diff = False
 
6990
 
 
6991
        opts.eol_marker = eol_marker
 
6992
        opts.print_revno = print_revno
 
6993
        opts.patternc = patternc
 
6994
        opts.recursive = not no_recursive
 
6995
        opts.fixed_string = fixed_string
 
6996
        opts.outf = self.outf
 
6997
        opts.show_color = show_color
 
6998
 
 
6999
        if diff:
 
7000
            # options not used:
 
7001
            # files_with_matches, files_without_match
 
7002
            # levels(?), line_number, from_root
 
7003
            # include, exclude
 
7004
            # These are silently ignored.
 
7005
            grep.grep_diff(opts)
 
7006
        elif revision is None:
 
7007
            grep.workingtree_grep(opts)
 
7008
        else:
 
7009
            grep.versioned_grep(opts)
 
7010
 
 
7011
 
6803
7012
def _register_lazy_builtins():
6804
7013
    # register lazy builtins from other modules; called at startup and should
6805
7014
    # be only called once.
6806
7015
    for (name, aliases, module_name) in [
6807
 
        ('cmd_bisect', [], 'breezy.bisect'),
6808
 
        ('cmd_bundle_info', [], 'breezy.bundle.commands'),
6809
 
        ('cmd_config', [], 'breezy.config'),
6810
 
        ('cmd_dump_btree', [], 'breezy.bzr.debug_commands'),
6811
 
        ('cmd_version_info', [], 'breezy.cmd_version_info'),
6812
 
        ('cmd_resolve', ['resolved'], 'breezy.conflicts'),
6813
 
        ('cmd_conflicts', [], 'breezy.conflicts'),
6814
 
        ('cmd_ping', [], 'breezy.bzr.smart.ping'),
6815
 
        ('cmd_sign_my_commits', [], 'breezy.commit_signature_commands'),
6816
 
        ('cmd_verify_signatures', [], 'breezy.commit_signature_commands'),
6817
 
        ('cmd_test_script', [], 'breezy.cmd_test_script'),
6818
 
        ]:
 
7016
            ('cmd_bisect', [], 'breezy.bisect'),
 
7017
            ('cmd_bundle_info', [], 'breezy.bundle.commands'),
 
7018
            ('cmd_config', [], 'breezy.config'),
 
7019
            ('cmd_dump_btree', [], 'breezy.bzr.debug_commands'),
 
7020
            ('cmd_file_id', [], 'breezy.bzr.debug_commands'),
 
7021
            ('cmd_file_path', [], 'breezy.bzr.debug_commands'),
 
7022
            ('cmd_version_info', [], 'breezy.cmd_version_info'),
 
7023
            ('cmd_resolve', ['resolved'], 'breezy.conflicts'),
 
7024
            ('cmd_conflicts', [], 'breezy.conflicts'),
 
7025
            ('cmd_ping', [], 'breezy.bzr.smart.ping'),
 
7026
            ('cmd_sign_my_commits', [], 'breezy.commit_signature_commands'),
 
7027
            ('cmd_verify_signatures', [], 'breezy.commit_signature_commands'),
 
7028
            ('cmd_test_script', [], 'breezy.cmd_test_script'),
 
7029
            ]:
6819
7030
        builtin_command_registry.register_lazy(name, aliases, module_name)