/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: 2018-05-06 11:48:54 UTC
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@jelmer.uk-20180506114854-h4qd9ojaqy8wxjsd
Move .mailmap to root.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
import sys
24
24
 
25
25
import breezy.bzr
26
 
import breezy.git
27
 
 
28
 
from . import (
29
 
    errors,
30
 
    )
31
26
 
32
27
from . import lazy_import
33
28
lazy_import.lazy_import(globals(), """
37
32
from breezy import (
38
33
    branch as _mod_branch,
39
34
    bugtracker,
 
35
    bundle,
40
36
    cache_utf8,
41
37
    controldir,
42
38
    directory_service,
43
39
    delta,
44
40
    config as _mod_config,
 
41
    errors,
45
42
    globbing,
46
43
    gpg,
47
44
    hooks,
48
45
    lazy_regex,
49
46
    log,
50
47
    merge as _mod_merge,
51
 
    mergeable as _mod_mergeable,
52
48
    merge_directive,
53
49
    osutils,
54
50
    reconfigure,
87
83
    RevisionInfo,
88
84
    )
89
85
from .sixish import (
90
 
    PY3,
 
86
    BytesIO,
91
87
    text_type,
92
88
    viewitems,
93
89
    viewvalues,
121
117
        and the full URL to the actual branch
122
118
    """
123
119
    # This path is meant to be relative to the existing branch
124
 
    this_url = _get_branch_location(
125
 
        control_dir, possible_transports=possible_transports)
 
120
    this_url = _get_branch_location(control_dir,
 
121
        possible_transports=possible_transports)
126
122
    # Perhaps the target control dir supports colocated branches?
127
123
    try:
128
 
        root = controldir.ControlDir.open(
129
 
            this_url, possible_transports=possible_transports)
 
124
        root = controldir.ControlDir.open(this_url,
 
125
            possible_transports=possible_transports)
130
126
    except errors.NotBranchError:
131
127
        return (False, this_url)
132
128
    else:
133
129
        try:
134
 
            control_dir.open_workingtree()
 
130
            wt = control_dir.open_workingtree()
135
131
        except (errors.NoWorkingTree, errors.NotLocalUrl):
136
132
            return (False, this_url)
137
133
        else:
153
149
        (colocated, this_url) = _is_colocated(control_dir, possible_transports)
154
150
 
155
151
        if colocated:
156
 
            return urlutils.join_segment_parameters(
157
 
                this_url, {"branch": urlutils.escape(location)})
 
152
            return urlutils.join_segment_parameters(this_url,
 
153
                {"branch": urlutils.escape(location)})
158
154
        else:
159
155
            return urlutils.join(this_url, '..', urlutils.escape(location))
160
156
    return location
170
166
    """
171
167
    try:
172
168
        # Perhaps it's a colocated branch?
173
 
        return control_dir.open_branch(
174
 
            location, possible_transports=possible_transports)
 
169
        return control_dir.open_branch(location, 
 
170
            possible_transports=possible_transports)
175
171
    except (errors.NotBranchError, errors.NoColocatedBranchSupport):
176
172
        this_url = _get_branch_location(control_dir)
177
173
        return Branch.open(
190
186
        if location is None:
191
187
            location = "."
192
188
        try:
193
 
            return Branch.open(
194
 
                location, possible_transports=possible_transports)
 
189
            return Branch.open(location,
 
190
                possible_transports=possible_transports)
195
191
        except errors.NotBranchError:
196
192
            near = "."
197
 
    cdir = controldir.ControlDir.open(
198
 
        near, possible_transports=possible_transports)
199
 
    return open_sibling_branch(
200
 
        cdir, location, possible_transports=possible_transports)
 
193
    cdir = controldir.ControlDir.open(near,
 
194
        possible_transports=possible_transports)
 
195
    return open_sibling_branch(cdir, location,
 
196
        possible_transports=possible_transports)
201
197
 
202
198
 
203
199
def iter_sibling_branches(control_dir, possible_transports=None):
206
202
    :param control_dir: Control directory for which to look up the siblings
207
203
    :return: Iterator over tuples with branch name and branch object
208
204
    """
 
205
    seen_urls = set()
209
206
    try:
210
207
        reference = control_dir.get_branch_reference()
211
208
    except errors.NotBranchError:
212
 
        reference = None
 
209
        # There is no active branch, just return the colocated branches.
 
210
        for name, branch in viewitems(control_dir.get_branches()):
 
211
            yield name, branch
 
212
        return
213
213
    if reference is not None:
214
 
        try:
215
 
            ref_branch = Branch.open(
216
 
                reference, possible_transports=possible_transports)
217
 
        except errors.NotBranchError:
218
 
            ref_branch = None
 
214
        ref_branch = Branch.open(reference,
 
215
            possible_transports=possible_transports)
219
216
    else:
220
217
        ref_branch = None
221
218
    if ref_branch is None or ref_branch.name:
226
223
    else:
227
224
        repo = ref_branch.controldir.find_repository()
228
225
        for branch in repo.find_branches(using=True):
229
 
            name = urlutils.relative_url(
230
 
                repo.user_url, branch.user_url).rstrip("/")
 
226
            name = urlutils.relative_url(repo.user_url,
 
227
                branch.user_url).rstrip("/")
231
228
            yield name, branch
232
229
 
233
230
 
259
256
            if view_files:
260
257
                file_list = view_files
261
258
                view_str = views.view_display_str(view_files)
262
 
                note(gettext("Ignoring files outside view. View is %s"),
263
 
                     view_str)
 
259
                note(gettext("Ignoring files outside view. View is %s") % view_str)
264
260
    return tree, file_list
265
261
 
266
262
 
276
272
 
277
273
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
278
274
    """Get a revision tree. Not suitable for commands that change the tree.
279
 
 
 
275
    
280
276
    Specifically, the basis tree in dirstate trees is coupled to the dirstate
281
277
    and doing a commit/uncommit/pull will at best fail due to changing the
282
278
    basis revision data.
351
347
        Not versioned and not matching an ignore pattern.
352
348
 
353
349
    Additionally for directories, symlinks and files with a changed
354
 
    executable bit, Breezy indicates their type using a trailing
 
350
    executable bit, Bazaar indicates their type using a trailing
355
351
    character: '/', '@' or '*' respectively. These decorations can be
356
352
    disabled using the '--no-classify' option.
357
353
 
388
384
                            short_name='S'),
389
385
                     Option('versioned', help='Only show versioned files.',
390
386
                            short_name='V'),
391
 
                     Option('no-pending', help='Don\'t show pending merges.'),
 
387
                     Option('no-pending', help='Don\'t show pending merges.',
 
388
                           ),
392
389
                     Option('no-classify',
393
 
                            help='Do not mark object type using indicator.'),
 
390
                            help='Do not mark object type using indicator.',
 
391
                           ),
394
392
                     ]
395
393
    aliases = ['st', 'stat']
396
394
 
404
402
        from .status import show_tree_status
405
403
 
406
404
        if revision and len(revision) > 2:
407
 
            raise errors.BzrCommandError(
408
 
                gettext('brz status --revision takes exactly'
409
 
                        ' one or two revision specifiers'))
 
405
            raise errors.BzrCommandError(gettext('brz status --revision takes exactly'
 
406
                                         ' one or two revision specifiers'))
410
407
 
411
408
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
412
409
        # Avoid asking for specific files when that is not needed.
450
447
    def run(self, revision_id=None, revision=None, directory=u'.'):
451
448
        if revision_id is not None and revision is not None:
452
449
            raise errors.BzrCommandError(gettext('You can only supply one of'
453
 
                                                 ' revision_id or --revision'))
 
450
                                         ' revision_id or --revision'))
454
451
        if revision_id is None and revision is None:
455
 
            raise errors.BzrCommandError(
456
 
                gettext('You must supply either --revision or a revision_id'))
 
452
            raise errors.BzrCommandError(gettext('You must supply either'
 
453
                                         ' --revision or a revision_id'))
457
454
 
458
455
        b = controldir.ControlDir.open_containing_tree_or_branch(directory)[1]
459
456
 
460
 
        revisions = getattr(b.repository, "revisions", None)
 
457
        revisions = b.repository.revisions
461
458
        if revisions is None:
462
 
            raise errors.BzrCommandError(
463
 
                gettext('Repository %r does not support '
464
 
                        'access to raw revision texts') % b.repository)
 
459
            raise errors.BzrCommandError(gettext('Repository %r does not support '
 
460
                'access to raw revision texts'))
465
461
 
466
462
        with b.repository.lock_read():
467
463
            # TODO: jam 20060112 should cat-revision always output utf-8?
470
466
                try:
471
467
                    self.print_revision(revisions, revision_id)
472
468
                except errors.NoSuchRevision:
473
 
                    msg = gettext(
474
 
                        "The repository {0} contains no revision {1}.").format(
475
 
                            b.repository.base, revision_id.decode('utf-8'))
 
469
                    msg = gettext("The repository {0} contains no revision {1}.").format(
 
470
                        b.repository.base, revision_id)
476
471
                    raise errors.BzrCommandError(msg)
477
472
            elif revision is not None:
478
473
                for rev in revision:
501
496
 
502
497
    def run(self, location_list, force=False):
503
498
        if not location_list:
504
 
            location_list = ['.']
 
499
            location_list=['.']
505
500
 
506
501
        for location in location_list:
507
502
            d = controldir.ControlDir.open(location)
509
504
            try:
510
505
                working = d.open_workingtree()
511
506
            except errors.NoWorkingTree:
512
 
                raise errors.BzrCommandError(
513
 
                    gettext("No working tree to remove"))
 
507
                raise errors.BzrCommandError(gettext("No working tree to remove"))
514
508
            except errors.NotLocalUrl:
515
 
                raise errors.BzrCommandError(
516
 
                    gettext("You cannot remove the working tree"
517
 
                            " of a remote path"))
 
509
                raise errors.BzrCommandError(gettext("You cannot remove the working tree"
 
510
                                             " of a remote path"))
518
511
            if not force:
519
512
                if (working.has_changes()):
520
513
                    raise errors.UncommittedChanges(working)
522
515
                    raise errors.ShelvedChanges(working)
523
516
 
524
517
            if working.user_url != working.branch.user_url:
525
 
                raise errors.BzrCommandError(
526
 
                    gettext("You cannot remove the working tree"
527
 
                            " from a lightweight checkout"))
 
518
                raise errors.BzrCommandError(gettext("You cannot remove the working tree"
 
519
                                             " from a lightweight checkout"))
528
520
 
529
521
            d.destroy_workingtree()
530
522
 
545
537
    that, you can supply --revision to force the state of the tree.
546
538
    """
547
539
 
548
 
    takes_options = [
549
 
        'revision', 'directory',
 
540
    takes_options = ['revision', 'directory',
550
541
        Option('force',
551
542
               help='Reset the tree even if it doesn\'t appear to be'
552
543
                    ' corrupted.'),
555
546
 
556
547
    def run(self, revision=None, directory='.', force=False):
557
548
        tree, _ = WorkingTree.open_containing(directory)
558
 
        self.enter_context(tree.lock_tree_write())
 
549
        self.add_cleanup(tree.lock_tree_write().unlock)
559
550
        if not force:
560
551
            try:
561
552
                tree.check_state()
562
553
            except errors.BzrError:
563
 
                pass  # There seems to be a real error here, so we'll reset
 
554
                pass # There seems to be a real error here, so we'll reset
564
555
            else:
565
556
                # Refuse
566
557
                raise errors.BzrCommandError(gettext(
573
564
            revision_ids = [r.as_revision_id(tree.branch) for r in revision]
574
565
        try:
575
566
            tree.reset_state(revision_ids)
576
 
        except errors.BzrError:
 
567
        except errors.BzrError as e:
577
568
            if revision_ids is None:
578
 
                extra = gettext(', the header appears corrupt, try passing '
579
 
                                '-r -1 to set the state to the last commit')
 
569
                extra = (gettext(', the header appears corrupt, try passing -r -1'
 
570
                         ' to set the state to the last commit'))
580
571
            else:
581
572
                extra = ''
582
 
            raise errors.BzrCommandError(
583
 
                gettext('failed to reset the tree state{0}').format(extra))
 
573
            raise errors.BzrCommandError(gettext('failed to reset the tree state{0}').format(extra))
584
574
 
585
575
 
586
576
class cmd_revno(Command):
599
589
    @display_command
600
590
    def run(self, tree=False, location=u'.', revision=None):
601
591
        if revision is not None and tree:
602
 
            raise errors.BzrCommandError(
603
 
                gettext("--tree and --revision can not be used together"))
 
592
            raise errors.BzrCommandError(gettext("--tree and --revision can "
 
593
                "not be used together"))
604
594
 
605
595
        if tree:
606
596
            try:
607
597
                wt = WorkingTree.open_containing(location)[0]
608
 
                self.enter_context(wt.lock_read())
 
598
                self.add_cleanup(wt.lock_read().unlock)
609
599
            except (errors.NoWorkingTree, errors.NotLocalUrl):
610
600
                raise errors.NoWorkingTree(location)
611
601
            b = wt.branch
612
602
            revid = wt.last_revision()
613
603
        else:
614
604
            b = Branch.open_containing(location)[0]
615
 
            self.enter_context(b.lock_read())
 
605
            self.add_cleanup(b.lock_read().unlock)
616
606
            if revision:
617
607
                if len(revision) != 1:
618
608
                    raise errors.BzrCommandError(gettext(
623
613
                revid = b.last_revision()
624
614
        try:
625
615
            revno_t = b.revision_id_to_dotted_revno(revid)
626
 
        except (errors.NoSuchRevision, errors.GhostRevisionsHaveNoRevno):
 
616
        except errors.NoSuchRevision:
627
617
            revno_t = ('???',)
628
618
        revno = ".".join(str(n) for n in revno_t)
629
619
        self.cleanup_now()
637
627
    takes_args = ['revision_info*']
638
628
    takes_options = [
639
629
        'revision',
640
 
        custom_help('directory', help='Branch to examine, '
641
 
                    'rather than the one containing the working directory.'),
 
630
        custom_help('directory',
 
631
            help='Branch to examine, '
 
632
                 'rather than the one containing the working directory.'),
642
633
        Option('tree', help='Show revno of working tree.'),
643
634
        ]
644
635
 
649
640
        try:
650
641
            wt = WorkingTree.open_containing(directory)[0]
651
642
            b = wt.branch
652
 
            self.enter_context(wt.lock_read())
 
643
            self.add_cleanup(wt.lock_read().unlock)
653
644
        except (errors.NoWorkingTree, errors.NotLocalUrl):
654
645
            wt = None
655
646
            b = Branch.open_containing(directory)[0]
656
 
            self.enter_context(b.lock_read())
 
647
            self.add_cleanup(b.lock_read().unlock)
657
648
        revision_ids = []
658
649
        if revision is not None:
659
650
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
679
670
            except errors.NoSuchRevision:
680
671
                revno = '???'
681
672
            maxlen = max(maxlen, len(revno))
682
 
            revinfos.append((revno, revision_id))
 
673
            revinfos.append([revno, revision_id])
683
674
 
684
675
        self.cleanup_now()
685
 
        for revno, revid in revinfos:
686
 
            self.outf.write(
687
 
                '%*s %s\n' % (maxlen, revno, revid.decode('utf-8')))
 
676
        for ri in revinfos:
 
677
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
688
678
 
689
679
 
690
680
class cmd_add(Command):
723
713
    branches that will be merged later (without showing the two different
724
714
    adds as a conflict). It is also useful when merging another project
725
715
    into a subdirectory of this one.
726
 
 
 
716
    
727
717
    Any files matching patterns in the ignore list will not be added
728
718
    unless they are explicitly mentioned.
729
 
 
730
 
    In recursive mode, files larger than the configuration option
 
719
    
 
720
    In recursive mode, files larger than the configuration option 
731
721
    add.maximum_file_size will be skipped. Named items are never skipped due
732
722
    to file size.
733
723
    """
737
727
               help="Don't recursively add the contents of directories.",
738
728
               short_name='N'),
739
729
        Option('dry-run',
740
 
               help="Show what would be done, but don't actually do "
741
 
                    "anything."),
 
730
               help="Show what would be done, but don't actually do anything."),
742
731
        'verbose',
743
732
        Option('file-ids-from',
744
733
               type=text_type,
750
739
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
751
740
            file_ids_from=None):
752
741
        import breezy.add
753
 
        tree, file_list = tree_files_for_add(file_list)
754
 
 
755
 
        if file_ids_from is not None and not tree.supports_setting_file_ids():
756
 
            warning(
757
 
                gettext('Ignoring --file-ids-from, since the tree does not '
758
 
                        'support setting file ids.'))
759
 
            file_ids_from = None
760
742
 
761
743
        base_tree = None
762
744
        if file_ids_from is not None:
763
745
            try:
764
746
                base_tree, base_path = WorkingTree.open_containing(
765
 
                    file_ids_from)
 
747
                                            file_ids_from)
766
748
            except errors.NoWorkingTree:
767
749
                base_branch, base_path = Branch.open_containing(
768
 
                    file_ids_from)
 
750
                                            file_ids_from)
769
751
                base_tree = base_branch.basis_tree()
770
752
 
771
 
            action = breezy.add.AddFromBaseAction(
772
 
                base_tree, base_path, to_file=self.outf,
 
753
            action = breezy.add.AddFromBaseAction(base_tree, base_path,
 
754
                          to_file=self.outf, should_print=(not is_quiet()))
 
755
        else:
 
756
            action = breezy.add.AddWithSkipLargeAction(to_file=self.outf,
773
757
                should_print=(not is_quiet()))
774
 
        else:
775
 
            action = breezy.add.AddWithSkipLargeAction(
776
 
                to_file=self.outf, should_print=(not is_quiet()))
777
758
 
778
759
        if base_tree:
779
 
            self.enter_context(base_tree.lock_read())
780
 
        added, ignored = tree.smart_add(
781
 
            file_list, not no_recurse, action=action, save=not dry_run)
 
760
            self.add_cleanup(base_tree.lock_read().unlock)
 
761
        tree, file_list = tree_files_for_add(file_list)
 
762
        added, ignored = tree.smart_add(file_list, not
 
763
            no_recurse, action=action, save=not dry_run)
782
764
        self.cleanup_now()
783
765
        if len(ignored) > 0:
784
766
            if verbose:
785
767
                for glob in sorted(ignored):
786
768
                    for path in ignored[glob]:
787
769
                        self.outf.write(
788
 
                            gettext("ignored {0} matching \"{1}\"\n").format(
789
 
                                path, glob))
 
770
                         gettext("ignored {0} matching \"{1}\"\n").format(
 
771
                         path, glob))
790
772
 
791
773
 
792
774
class cmd_mkdir(Command):
866
848
    takes_options = [
867
849
        'revision',
868
850
        'show-ids',
869
 
        Option('include-root',
870
 
               help='Include the entry for the root of the tree, if any.'),
871
851
        Option('kind',
872
 
               help='List entries of a particular kind: file, directory, '
873
 
                    'symlink.',
 
852
               help='List entries of a particular kind: file, directory, symlink.',
874
853
               type=text_type),
875
854
        ]
876
855
    takes_args = ['file*']
877
856
 
878
857
    @display_command
879
 
    def run(self, revision=None, show_ids=False, kind=None, include_root=False,
880
 
            file_list=None):
 
858
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
881
859
        if kind and kind not in ['file', 'directory', 'symlink']:
882
 
            raise errors.BzrCommandError(
883
 
                gettext('invalid kind %r specified') % (kind,))
 
860
            raise errors.BzrCommandError(gettext('invalid kind %r specified') % (kind,))
884
861
 
885
862
        revision = _get_one_revision('inventory', revision)
886
863
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
887
 
        self.enter_context(work_tree.lock_read())
 
864
        self.add_cleanup(work_tree.lock_read().unlock)
888
865
        if revision is not None:
889
866
            tree = revision.as_tree(work_tree.branch)
890
867
 
891
868
            extra_trees = [work_tree]
892
 
            self.enter_context(tree.lock_read())
 
869
            self.add_cleanup(tree.lock_read().unlock)
893
870
        else:
894
871
            tree = work_tree
895
872
            extra_trees = []
896
873
 
897
 
        self.enter_context(tree.lock_read())
 
874
        self.add_cleanup(tree.lock_read().unlock)
898
875
        if file_list is not None:
899
876
            paths = tree.find_related_paths_across_trees(
900
 
                file_list, extra_trees, require_versioned=True)
 
877
                    file_list, extra_trees, require_versioned=True)
901
878
            # find_ids_across_trees may include some paths that don't
902
879
            # exist in 'tree'.
903
880
            entries = tree.iter_entries_by_dir(specific_files=paths)
907
884
        for path, entry in sorted(entries):
908
885
            if kind and kind != entry.kind:
909
886
                continue
910
 
            if path == "" and not include_root:
 
887
            if path == "":
911
888
                continue
912
889
            if show_ids:
913
 
                self.outf.write('%-50s %s\n' % (
914
 
                    path, entry.file_id.decode('utf-8')))
 
890
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
915
891
            else:
916
892
                self.outf.write(path)
917
893
                self.outf.write('\n')
939
915
    encoding_type = 'replace'
940
916
 
941
917
    def run(self, names_list):
 
918
        import shutil
942
919
        if names_list is None:
943
920
            names_list = []
944
921
        if len(names_list) < 2:
945
922
            raise errors.BzrCommandError(gettext("missing file argument"))
946
 
        tree, rel_names = WorkingTree.open_containing_paths(
947
 
            names_list, canonicalize=False)
 
923
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
948
924
        for file_name in rel_names[0:-1]:
949
925
            if file_name == '':
950
 
                raise errors.BzrCommandError(
951
 
                    gettext("can not copy root of branch"))
952
 
        self.enter_context(tree.lock_tree_write())
 
926
                raise errors.BzrCommandError(gettext("can not copy root of branch"))
 
927
        self.add_cleanup(tree.lock_tree_write().unlock)
953
928
        into_existing = osutils.isdir(names_list[-1])
954
929
        if not into_existing:
955
930
            try:
956
931
                (src, dst) = rel_names
957
932
            except IndexError:
958
 
                raise errors.BzrCommandError(
959
 
                    gettext('to copy multiple files the'
960
 
                            ' destination must be a versioned'
961
 
                            ' directory'))
 
933
                raise errors.BzrCommandError(gettext('to copy multiple files the'
 
934
                                                     ' destination must be a versioned'
 
935
                                                     ' directory'))
962
936
            pairs = [(src, dst)]
963
937
        else:
964
 
            pairs = [
965
 
                (n, osutils.joinpath([rel_names[-1], osutils.basename(n)]))
966
 
                for n in rel_names[:-1]]
 
938
            pairs = [(n, osutils.joinpath([rel_names[-1], osutils.basename(n)]))
 
939
                     for n in rel_names[:-1]]
967
940
 
968
941
        for src, dst in pairs:
969
942
            try:
970
943
                src_kind = tree.stored_kind(src)
971
944
            except errors.NoSuchFile:
972
945
                raise errors.BzrCommandError(
973
 
                    gettext('Could not copy %s => %s: %s is not versioned.')
974
 
                    % (src, dst, src))
 
946
                        gettext('Could not copy %s => %s: %s is not versioned.')
 
947
                        % (src, dst, src))
975
948
            if src_kind is None:
976
949
                raise errors.BzrCommandError(
977
 
                    gettext('Could not copy %s => %s . %s is not versioned\\.'
978
 
                            % (src, dst, src)))
 
950
                    gettext('Could not copy %s => %s . %s is not versioned\.'
 
951
                        % (src, dst, src)))
979
952
            if src_kind == 'directory':
980
953
                raise errors.BzrCommandError(
981
954
                    gettext('Could not copy %s => %s . %s is a directory.'
982
 
                            % (src, dst, src)))
 
955
                        % (src, dst, src)))
983
956
            dst_parent = osutils.split(dst)[0]
984
957
            if dst_parent != '':
985
958
                try:
986
959
                    dst_parent_kind = tree.stored_kind(dst_parent)
987
960
                except errors.NoSuchFile:
988
961
                    raise errors.BzrCommandError(
989
 
                        gettext('Could not copy %s => %s: %s is not versioned.')
990
 
                        % (src, dst, dst_parent))
 
962
                            gettext('Could not copy %s => %s: %s is not versioned.')
 
963
                            % (src, dst, dst_parent))
991
964
                if dst_parent_kind != 'directory':
992
965
                    raise errors.BzrCommandError(
993
 
                        gettext('Could not copy to %s: %s is not a directory.')
994
 
                        % (dst_parent, dst_parent))
 
966
                            gettext('Could not copy to %s: %s is not a directory.')
 
967
                            % (dst_parent, dst_parent))
995
968
 
996
969
            tree.copy_one(src, dst)
997
970
 
1019
992
 
1020
993
    takes_args = ['names*']
1021
994
    takes_options = [Option("after", help="Move only the brz identifier"
1022
 
                            " of the file, because the file has already been moved."),
1023
 
                     Option('auto', help='Automatically guess renames.'),
1024
 
                     Option(
1025
 
                         'dry-run', help='Avoid making changes when guessing renames.'),
1026
 
                     ]
 
995
        " of the file, because the file has already been moved."),
 
996
        Option('auto', help='Automatically guess renames.'),
 
997
        Option('dry-run', help='Avoid making changes when guessing renames.'),
 
998
        ]
1027
999
    aliases = ['move', 'rename']
1028
1000
    encoding_type = 'replace'
1029
1001
 
1036
1008
            names_list = []
1037
1009
        if len(names_list) < 2:
1038
1010
            raise errors.BzrCommandError(gettext("missing file argument"))
1039
 
        tree, rel_names = WorkingTree.open_containing_paths(
1040
 
            names_list, canonicalize=False)
 
1011
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
1041
1012
        for file_name in rel_names[0:-1]:
1042
1013
            if file_name == '':
1043
 
                raise errors.BzrCommandError(
1044
 
                    gettext("can not move root of branch"))
1045
 
        self.enter_context(tree.lock_tree_write())
 
1014
                raise errors.BzrCommandError(gettext("can not move root of branch"))
 
1015
        self.add_cleanup(tree.lock_tree_write().unlock)
1046
1016
        self._run(tree, names_list, rel_names, after)
1047
1017
 
1048
1018
    def run_auto(self, names_list, after, dry_run):
1049
1019
        if names_list is not None and len(names_list) > 1:
1050
 
            raise errors.BzrCommandError(
1051
 
                gettext('Only one path may be specified to --auto.'))
 
1020
            raise errors.BzrCommandError(gettext('Only one path may be specified to'
 
1021
                                         ' --auto.'))
1052
1022
        if after:
1053
 
            raise errors.BzrCommandError(
1054
 
                gettext('--after cannot be specified with --auto.'))
 
1023
            raise errors.BzrCommandError(gettext('--after cannot be specified with'
 
1024
                                         ' --auto.'))
1055
1025
        work_tree, file_list = WorkingTree.open_containing_paths(
1056
1026
            names_list, default_directory='.')
1057
 
        self.enter_context(work_tree.lock_tree_write())
 
1027
        self.add_cleanup(work_tree.lock_tree_write().unlock)
1058
1028
        rename_map.RenameMap.guess_renames(
1059
 
            work_tree.basis_tree(), work_tree, dry_run)
 
1029
                work_tree.basis_tree(), work_tree, dry_run)
1060
1030
 
1061
1031
    def _run(self, tree, names_list, rel_names, after):
1062
1032
        into_existing = osutils.isdir(names_list[-1])
1067
1037
            #    a directory, but now doesn't exist in the working tree
1068
1038
            #    and the target is an existing directory, just rename it)
1069
1039
            if (not tree.case_sensitive
1070
 
                    and rel_names[0].lower() == rel_names[1].lower()):
 
1040
                and rel_names[0].lower() == rel_names[1].lower()):
1071
1041
                into_existing = False
1072
1042
            else:
1073
1043
                # 'fix' the case of a potential 'from'
1074
 
                from_path = tree.get_canonical_path(rel_names[0])
 
1044
                from_path = tree.get_canonical_inventory_path(rel_names[0])
1075
1045
                if (not osutils.lexists(names_list[0]) and
1076
1046
                    tree.is_versioned(from_path) and
1077
 
                        tree.stored_kind(from_path) == "directory"):
 
1047
                    tree.stored_kind(from_path) == "directory"):
1078
1048
                    into_existing = False
1079
1049
        # move/rename
1080
1050
        if into_existing:
1081
1051
            # move into existing directory
1082
1052
            # All entries reference existing inventory items, so fix them up
1083
1053
            # for cicp file-systems.
1084
 
            rel_names = list(tree.get_canonical_paths(rel_names))
 
1054
            rel_names = tree.get_canonical_inventory_paths(rel_names)
1085
1055
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
1086
1056
                if not is_quiet():
1087
1057
                    self.outf.write("%s => %s\n" % (src, dest))
1088
1058
        else:
1089
1059
            if len(names_list) != 2:
1090
1060
                raise errors.BzrCommandError(gettext('to mv multiple files the'
1091
 
                                                     ' destination must be a versioned'
1092
 
                                                     ' directory'))
 
1061
                                             ' destination must be a versioned'
 
1062
                                             ' directory'))
1093
1063
 
1094
1064
            # for cicp file-systems: the src references an existing inventory
1095
1065
            # item:
1096
 
            src = tree.get_canonical_path(rel_names[0])
 
1066
            src = tree.get_canonical_inventory_path(rel_names[0])
1097
1067
            # Find the canonical version of the destination:  In all cases, the
1098
1068
            # parent of the target must be in the inventory, so we fetch the
1099
1069
            # canonical version from there (we do not always *use* the
1100
1070
            # canonicalized tail portion - we may be attempting to rename the
1101
1071
            # case of the tail)
1102
 
            canon_dest = tree.get_canonical_path(rel_names[1])
 
1072
            canon_dest = tree.get_canonical_inventory_path(rel_names[1])
1103
1073
            dest_parent = osutils.dirname(canon_dest)
1104
1074
            spec_tail = osutils.basename(rel_names[1])
1105
1075
            # For a CICP file-system, we need to avoid creating 2 inventory
1116
1086
                if after:
1117
1087
                    # If 'after' is specified, the tail must refer to a file on disk.
1118
1088
                    if dest_parent:
1119
 
                        dest_parent_fq = osutils.pathjoin(
1120
 
                            tree.basedir, dest_parent)
 
1089
                        dest_parent_fq = osutils.pathjoin(tree.basedir, dest_parent)
1121
1090
                    else:
1122
1091
                        # pathjoin with an empty tail adds a slash, which breaks
1123
1092
                        # relpath :(
1124
1093
                        dest_parent_fq = tree.basedir
1125
1094
 
1126
1095
                    dest_tail = osutils.canonical_relpath(
1127
 
                        dest_parent_fq,
1128
 
                        osutils.pathjoin(dest_parent_fq, spec_tail))
 
1096
                                    dest_parent_fq,
 
1097
                                    osutils.pathjoin(dest_parent_fq, spec_tail))
1129
1098
                else:
1130
1099
                    # not 'after', so case as specified is used
1131
1100
                    dest_tail = spec_tail
1143
1112
    __doc__ = """Turn this branch into a mirror of another branch.
1144
1113
 
1145
1114
    By default, this command only works on branches that have not diverged.
1146
 
    Branches are considered diverged if the destination branch's most recent
1147
 
    commit is one that has not been merged (directly or indirectly) into the
 
1115
    Branches are considered diverged if the destination branch's most recent 
 
1116
    commit is one that has not been merged (directly or indirectly) into the 
1148
1117
    parent.
1149
1118
 
1150
1119
    If branches have diverged, you can use 'brz merge' to integrate the changes
1171
1140
 
1172
1141
    _see_also = ['push', 'update', 'status-flags', 'send']
1173
1142
    takes_options = ['remember', 'overwrite', 'revision',
1174
 
                     custom_help('verbose',
1175
 
                                 help='Show logs of pulled revisions.'),
1176
 
                     custom_help('directory',
1177
 
                                 help='Branch to pull into, '
1178
 
                                 'rather than the one containing the working directory.'),
1179
 
                     Option('local',
1180
 
                            help="Perform a local pull in a bound "
1181
 
                            "branch.  Local pulls are not applied to "
1182
 
                            "the master branch."
1183
 
                            ),
1184
 
                     Option('show-base',
1185
 
                            help="Show base revision text in conflicts."),
1186
 
                     Option('overwrite-tags',
1187
 
                            help="Overwrite tags only."),
1188
 
                     ]
 
1143
        custom_help('verbose',
 
1144
            help='Show logs of pulled revisions.'),
 
1145
        custom_help('directory',
 
1146
            help='Branch to pull into, '
 
1147
                 'rather than the one containing the working directory.'),
 
1148
        Option('local',
 
1149
            help="Perform a local pull in a bound "
 
1150
                 "branch.  Local pulls are not applied to "
 
1151
                 "the master branch."
 
1152
            ),
 
1153
        Option('show-base',
 
1154
            help="Show base revision text in conflicts."),
 
1155
        Option('overwrite-tags',
 
1156
            help="Overwrite tags only."),
 
1157
        ]
1189
1158
    takes_args = ['location?']
1190
1159
    encoding_type = 'replace'
1191
1160
 
1208
1177
        try:
1209
1178
            tree_to = WorkingTree.open_containing(directory)[0]
1210
1179
            branch_to = tree_to.branch
1211
 
            self.enter_context(tree_to.lock_write())
 
1180
            self.add_cleanup(tree_to.lock_write().unlock)
1212
1181
        except errors.NoWorkingTree:
1213
1182
            tree_to = None
1214
1183
            branch_to = Branch.open_containing(directory)[0]
1215
 
            self.enter_context(branch_to.lock_write())
 
1184
            self.add_cleanup(branch_to.lock_write().unlock)
1216
1185
            if show_base:
1217
1186
                warning(gettext("No working tree, ignoring --show-base"))
1218
1187
 
1222
1191
        possible_transports = []
1223
1192
        if location is not None:
1224
1193
            try:
1225
 
                mergeable = _mod_mergeable.read_mergeable_from_url(
1226
 
                    location, possible_transports=possible_transports)
 
1194
                mergeable = bundle.read_mergeable_from_url(location,
 
1195
                    possible_transports=possible_transports)
1227
1196
            except errors.NotABundle:
1228
1197
                mergeable = None
1229
1198
 
1231
1200
        if location is None:
1232
1201
            if stored_loc is None:
1233
1202
                raise errors.BzrCommandError(gettext("No pull location known or"
1234
 
                                                     " specified."))
 
1203
                                             " specified."))
1235
1204
            else:
1236
1205
                display_url = urlutils.unescape_for_display(stored_loc,
1237
 
                                                            self.outf.encoding)
 
1206
                        self.outf.encoding)
1238
1207
                if not is_quiet():
1239
 
                    self.outf.write(
1240
 
                        gettext("Using saved parent location: %s\n") % display_url)
 
1208
                    self.outf.write(gettext("Using saved parent location: %s\n") % display_url)
1241
1209
                location = stored_loc
1242
1210
 
1243
1211
        revision = _get_one_revision('pull', revision)
1251
1219
            branch_from = branch_to
1252
1220
        else:
1253
1221
            branch_from = Branch.open(location,
1254
 
                                      possible_transports=possible_transports)
1255
 
            self.enter_context(branch_from.lock_read())
 
1222
                possible_transports=possible_transports)
 
1223
            self.add_cleanup(branch_from.lock_read().unlock)
1256
1224
            # Remembers if asked explicitly or no previous location is set
1257
1225
            if (remember
1258
 
                    or (remember is None and branch_to.get_parent() is None)):
 
1226
                or (remember is None and branch_to.get_parent() is None)):
1259
1227
                # FIXME: This shouldn't be done before the pull
1260
1228
                # succeeds... -- vila 2012-01-02
1261
1229
                branch_to.set_parent(branch_from.base)
1318
1286
 
1319
1287
    _see_also = ['pull', 'update', 'working-trees']
1320
1288
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
1321
 
                     Option('create-prefix',
1322
 
                            help='Create the path leading up to the branch '
1323
 
                            'if it does not already exist.'),
1324
 
                     custom_help('directory',
1325
 
                                 help='Branch to push from, '
1326
 
                                 'rather than the one containing the working directory.'),
1327
 
                     Option('use-existing-dir',
1328
 
                            help='By default push will fail if the target'
1329
 
                            ' directory exists, but does not already'
1330
 
                            ' have a control directory.  This flag will'
1331
 
                            ' allow push to proceed.'),
1332
 
                     Option('stacked',
1333
 
                            help='Create a stacked branch that references the public location '
1334
 
                            'of the parent branch.'),
1335
 
                     Option('stacked-on',
1336
 
                            help='Create a stacked branch that refers to another branch '
1337
 
                            'for the commit history. Only the work not present in the '
1338
 
                            'referenced branch is included in the branch created.',
1339
 
                            type=text_type),
1340
 
                     Option('strict',
1341
 
                            help='Refuse to push if there are uncommitted changes in'
1342
 
                            ' the working tree, --no-strict disables the check.'),
1343
 
                     Option('no-tree',
1344
 
                            help="Don't populate the working tree, even for protocols"
1345
 
                            " that support it."),
1346
 
                     Option('overwrite-tags',
1347
 
                            help="Overwrite tags only."),
1348
 
                     Option('lossy', help="Allow lossy push, i.e. dropping metadata "
1349
 
                            "that can't be represented in the target.")
1350
 
                     ]
 
1289
        Option('create-prefix',
 
1290
               help='Create the path leading up to the branch '
 
1291
                    'if it does not already exist.'),
 
1292
        custom_help('directory',
 
1293
            help='Branch to push from, '
 
1294
                 'rather than the one containing the working directory.'),
 
1295
        Option('use-existing-dir',
 
1296
               help='By default push will fail if the target'
 
1297
                    ' directory exists, but does not already'
 
1298
                    ' have a control directory.  This flag will'
 
1299
                    ' allow push to proceed.'),
 
1300
        Option('stacked',
 
1301
            help='Create a stacked branch that references the public location '
 
1302
                'of the parent branch.'),
 
1303
        Option('stacked-on',
 
1304
            help='Create a stacked branch that refers to another branch '
 
1305
                'for the commit history. Only the work not present in the '
 
1306
                'referenced branch is included in the branch created.',
 
1307
            type=text_type),
 
1308
        Option('strict',
 
1309
               help='Refuse to push if there are uncommitted changes in'
 
1310
               ' the working tree, --no-strict disables the check.'),
 
1311
        Option('no-tree',
 
1312
               help="Don't populate the working tree, even for protocols"
 
1313
               " that support it."),
 
1314
        Option('overwrite-tags',
 
1315
              help="Overwrite tags only."),
 
1316
        Option('lossy', help="Allow lossy push, i.e. dropping metadata "
 
1317
                             "that can't be represented in the target.")
 
1318
        ]
1351
1319
    takes_args = ['location?']
1352
1320
    encoding_type = 'replace'
1353
1321
 
1354
1322
    def run(self, location=None, remember=None, overwrite=False,
1355
 
            create_prefix=False, verbose=False, revision=None,
1356
 
            use_existing_dir=False, directory=None, stacked_on=None,
1357
 
            stacked=False, strict=None, no_tree=False,
1358
 
            overwrite_tags=False, lossy=False):
1359
 
        from .location import location_to_url
 
1323
        create_prefix=False, verbose=False, revision=None,
 
1324
        use_existing_dir=False, directory=None, stacked_on=None,
 
1325
        stacked=False, strict=None, no_tree=False,
 
1326
        overwrite_tags=False, lossy=False):
1360
1327
        from .push import _show_push_branch
1361
1328
 
1362
1329
        if overwrite:
1384
1351
                more_warning='Uncommitted changes will not be pushed.')
1385
1352
        # Get the stacked_on branch, if any
1386
1353
        if stacked_on is not None:
1387
 
            stacked_on = location_to_url(stacked_on, 'read')
1388
1354
            stacked_on = urlutils.normalize_url(stacked_on)
1389
1355
        elif stacked:
1390
1356
            parent_url = br_from.get_parent()
1411
1377
                        "No push location known or specified. To push to the "
1412
1378
                        "parent branch (at %s), use 'brz push :parent'." %
1413
1379
                        urlutils.unescape_for_display(parent_loc,
1414
 
                                                      self.outf.encoding)))
 
1380
                            self.outf.encoding)))
1415
1381
                else:
1416
1382
                    raise errors.BzrCommandError(gettext(
1417
1383
                        "No push location known or specified."))
1418
1384
            else:
1419
1385
                display_url = urlutils.unescape_for_display(stored_loc,
1420
 
                                                            self.outf.encoding)
 
1386
                        self.outf.encoding)
1421
1387
                note(gettext("Using saved push location: %s") % display_url)
1422
1388
                location = stored_loc
1423
1389
 
1424
1390
        _show_push_branch(br_from, revision_id, location, self.outf,
1425
 
                          verbose=verbose, overwrite=overwrite, remember=remember,
1426
 
                          stacked_on=stacked_on, create_prefix=create_prefix,
1427
 
                          use_existing_dir=use_existing_dir, no_tree=no_tree,
1428
 
                          lossy=lossy)
 
1391
            verbose=verbose, overwrite=overwrite, remember=remember,
 
1392
            stacked_on=stacked_on, create_prefix=create_prefix,
 
1393
            use_existing_dir=use_existing_dir, no_tree=no_tree,
 
1394
            lossy=lossy)
1429
1395
 
1430
1396
 
1431
1397
class cmd_branch(Command):
1442
1408
    parameter, as in "branch foo/bar -r 5".
1443
1409
    """
1444
1410
 
1445
 
    aliase = ['sprout']
1446
1411
    _see_also = ['checkout']
1447
1412
    takes_args = ['from_location', 'to_location?']
1448
1413
    takes_options = ['revision',
1449
 
                     Option(
1450
 
                         'hardlink', help='Hard-link working tree files where possible.'),
1451
 
                     Option('files-from', type=text_type,
1452
 
                            help="Get file contents from this tree."),
1453
 
                     Option('no-tree',
1454
 
                            help="Create a branch without a working-tree."),
1455
 
                     Option('switch',
1456
 
                            help="Switch the checkout in the current directory "
1457
 
                            "to the new branch."),
1458
 
                     Option('stacked',
1459
 
                            help='Create a stacked branch referring to the source branch. '
1460
 
                            'The new branch will depend on the availability of the source '
1461
 
                            'branch for all operations.'),
1462
 
                     Option('standalone',
1463
 
                            help='Do not use a shared repository, even if available.'),
1464
 
                     Option('use-existing-dir',
1465
 
                            help='By default branch will fail if the target'
1466
 
                            ' directory exists, but does not already'
1467
 
                            ' have a control directory.  This flag will'
1468
 
                            ' allow branch to proceed.'),
1469
 
                     Option('bind',
1470
 
                            help="Bind new branch to from location."),
1471
 
                     Option('no-recurse-nested',
1472
 
                            help='Do not recursively check out nested trees.'),
1473
 
                     Option('colocated-branch', short_name='b',
1474
 
                            type=str, help='Name of colocated branch to sprout.'),
1475
 
                     ]
 
1414
        Option('hardlink', help='Hard-link working tree files where possible.'),
 
1415
        Option('files-from', type=text_type,
 
1416
               help="Get file contents from this tree."),
 
1417
        Option('no-tree',
 
1418
            help="Create a branch without a working-tree."),
 
1419
        Option('switch',
 
1420
            help="Switch the checkout in the current directory "
 
1421
                 "to the new branch."),
 
1422
        Option('stacked',
 
1423
            help='Create a stacked branch referring to the source branch. '
 
1424
                'The new branch will depend on the availability of the source '
 
1425
                'branch for all operations.'),
 
1426
        Option('standalone',
 
1427
               help='Do not use a shared repository, even if available.'),
 
1428
        Option('use-existing-dir',
 
1429
               help='By default branch will fail if the target'
 
1430
                    ' directory exists, but does not already'
 
1431
                    ' have a control directory.  This flag will'
 
1432
                    ' allow branch to proceed.'),
 
1433
        Option('bind',
 
1434
            help="Bind new branch to from location."),
 
1435
        ]
1476
1436
 
1477
1437
    def run(self, from_location, to_location=None, revision=None,
1478
1438
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1479
1439
            use_existing_dir=False, switch=False, bind=False,
1480
 
            files_from=None, no_recurse_nested=False, colocated_branch=None):
 
1440
            files_from=None):
1481
1441
        from breezy import switch as _mod_switch
1482
1442
        accelerator_tree, br_from = controldir.ControlDir.open_tree_or_branch(
1483
 
            from_location, name=colocated_branch)
1484
 
        if no_recurse_nested:
1485
 
            recurse = 'none'
1486
 
        else:
1487
 
            recurse = 'down'
 
1443
            from_location)
1488
1444
        if not (hardlink or files_from):
1489
1445
            # accelerator_tree is usually slower because you have to read N
1490
1446
            # files (no readahead, lots of seeks, etc), but allow the user to
1493
1449
        if files_from is not None and files_from != from_location:
1494
1450
            accelerator_tree = WorkingTree.open(files_from)
1495
1451
        revision = _get_one_revision('branch', revision)
1496
 
        self.enter_context(br_from.lock_read())
 
1452
        self.add_cleanup(br_from.lock_read().unlock)
1497
1453
        if revision is not None:
1498
1454
            revision_id = revision.as_revision_id(br_from)
1499
1455
        else:
1502
1458
            # RBC 20060209
1503
1459
            revision_id = br_from.last_revision()
1504
1460
        if to_location is None:
1505
 
            to_location = urlutils.derive_to_location(from_location)
1506
 
        to_transport = transport.get_transport(to_location, purpose='write')
 
1461
            to_location = getattr(br_from, "name", None)
 
1462
            if not to_location:
 
1463
                to_location = urlutils.derive_to_location(from_location)
 
1464
        to_transport = transport.get_transport(to_location)
1507
1465
        try:
1508
1466
            to_transport.mkdir('.')
1509
1467
        except errors.FileExists:
1513
1471
            except errors.NotBranchError:
1514
1472
                if not use_existing_dir:
1515
1473
                    raise errors.BzrCommandError(gettext('Target directory "%s" '
1516
 
                                                         'already exists.') % to_location)
 
1474
                        'already exists.') % to_location)
1517
1475
                else:
1518
1476
                    to_dir = None
1519
1477
            else:
1536
1494
                    possible_transports=[to_transport],
1537
1495
                    accelerator_tree=accelerator_tree, hardlink=hardlink,
1538
1496
                    stacked=stacked, force_new_repo=standalone,
1539
 
                    create_tree_if_local=not no_tree, source_branch=br_from,
1540
 
                    recurse=recurse)
 
1497
                    create_tree_if_local=not no_tree, source_branch=br_from)
1541
1498
                branch = to_dir.open_branch(
1542
1499
                    possible_transports=[
1543
1500
                        br_from.controldir.root_transport, to_transport])
1552
1509
            except errors.NoRepositoryPresent:
1553
1510
                to_repo = to_dir.create_repository()
1554
1511
            to_repo.fetch(br_from.repository, revision_id=revision_id)
1555
 
            branch = br_from.sprout(
1556
 
                to_dir, revision_id=revision_id)
 
1512
            branch = br_from.sprout(to_dir, revision_id=revision_id)
1557
1513
        br_from.tags.merge_to(branch.tags)
1558
1514
 
1559
1515
        # If the source branch is stacked, the new branch may
1561
1517
        # We therefore need a try/except here and not just 'if stacked:'
1562
1518
        try:
1563
1519
            note(gettext('Created new stacked branch referring to %s.') %
1564
 
                 branch.get_stacked_on_url())
 
1520
                branch.get_stacked_on_url())
1565
1521
        except (errors.NotStacked, _mod_branch.UnstackableBranchFormat,
1566
 
                errors.UnstackableRepositoryFormat) as e:
1567
 
            revno = branch.revno()
1568
 
            if revno is not None:
1569
 
                note(ngettext('Branched %d revision.',
1570
 
                              'Branched %d revisions.',
1571
 
                              branch.revno()) % revno)
1572
 
            else:
1573
 
                note(gettext('Created new branch.'))
 
1522
            errors.UnstackableRepositoryFormat) as e:
 
1523
            note(ngettext('Branched %d revision.', 'Branched %d revisions.', branch.revno()) % branch.revno())
1574
1524
        if bind:
1575
1525
            # Bind to the parent
1576
1526
            parent_branch = Branch.open(from_location)
1581
1531
            wt, _ = WorkingTree.open_containing('.')
1582
1532
            _mod_switch.switch(wt.controldir, branch)
1583
1533
            note(gettext('Switched to branch: %s'),
1584
 
                 urlutils.unescape_for_display(branch.base, 'utf-8'))
 
1534
                urlutils.unescape_for_display(branch.base, 'utf-8'))
1585
1535
 
1586
1536
 
1587
1537
class cmd_branches(Command):
1593
1543
 
1594
1544
    takes_args = ['location?']
1595
1545
    takes_options = [
1596
 
        Option('recursive', short_name='R',
1597
 
               help='Recursively scan for branches rather than '
1598
 
               'just looking in the specified location.')]
 
1546
                  Option('recursive', short_name='R',
 
1547
                         help='Recursively scan for branches rather than '
 
1548
                              'just looking in the specified location.')]
1599
1549
 
1600
1550
    def run(self, location=".", recursive=False):
1601
1551
        if recursive:
1602
 
            t = transport.get_transport(location, purpose='read')
 
1552
            t = transport.get_transport(location)
1603
1553
            if not t.listable():
1604
1554
                raise errors.BzrCommandError(
1605
1555
                    "Can't scan this type of location.")
1631
1581
                else:
1632
1582
                    prefix = " "
1633
1583
                self.outf.write("%s %s\n" % (
1634
 
                    prefix, (name if PY3 else name.encode(self.outf.encoding))))
 
1584
                    prefix, name.encode(self.outf.encoding)))
1635
1585
 
1636
1586
 
1637
1587
class cmd_checkout(Command):
1638
1588
    __doc__ = """Create a new checkout of an existing branch.
1639
1589
 
1640
 
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree
1641
 
    for the branch found in '.'. This is useful if you have removed the working
1642
 
    tree or if it was never created - i.e. if you pushed the branch to its
1643
 
    current location using SFTP.
 
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.
1644
1594
 
1645
 
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION
1646
 
    will be used.  In other words, "checkout ../foo/bar" will attempt to create
1647
 
    ./bar.  If the BRANCH_LOCATION has no / or path separator embedded, the
1648
 
    TO_LOCATION is derived from the BRANCH_LOCATION by stripping a leading
1649
 
    scheme or drive identifier, if any. For example, "checkout lp:foo-bar" will
1650
 
    attempt to create ./foo-bar.
 
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.
1651
1601
 
1652
1602
    To retrieve the branch as of a particular revision, supply the --revision
1653
 
    parameter, as in "checkout foo/bar -r 5". Note that this will be
1654
 
    immediately out of date [so you cannot commit] but it may be useful (i.e.
1655
 
    to examine old code.)
 
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.)
1656
1606
    """
1657
1607
 
1658
1608
    _see_also = ['checkouts', 'branch', 'working-trees', 'remove-tree']
1697
1647
        # if the source and to_location are the same,
1698
1648
        # and there is no working tree,
1699
1649
        # then reconstitute a branch
1700
 
        if osutils.abspath(to_location) == osutils.abspath(branch_location):
 
1650
        if (osutils.abspath(to_location) ==
 
1651
            osutils.abspath(branch_location)):
1701
1652
            try:
1702
1653
                source.controldir.open_workingtree()
1703
1654
            except errors.NoWorkingTree:
1707
1658
                               accelerator_tree, hardlink)
1708
1659
 
1709
1660
 
1710
 
class cmd_clone(Command):
1711
 
    __doc__ = """Clone a control directory.
1712
 
    """
1713
 
 
1714
 
    takes_args = ['from_location', 'to_location?']
1715
 
    takes_options = ['revision',
1716
 
                     Option('no-recurse-nested',
1717
 
                            help='Do not recursively check out nested trees.'),
1718
 
                     ]
1719
 
 
1720
 
    def run(self, from_location, to_location=None, revision=None, no_recurse_nested=False):
1721
 
        accelerator_tree, br_from = controldir.ControlDir.open_tree_or_branch(
1722
 
            from_location)
1723
 
        if no_recurse_nested:
1724
 
            recurse = 'none'
1725
 
        else:
1726
 
            recurse = 'down'
1727
 
        revision = _get_one_revision('branch', revision)
1728
 
        self.enter_context(br_from.lock_read())
1729
 
        if revision is not None:
1730
 
            revision_id = revision.as_revision_id(br_from)
1731
 
        else:
1732
 
            # FIXME - wt.last_revision, fallback to branch, fall back to
1733
 
            # None or perhaps NULL_REVISION to mean copy nothing
1734
 
            # RBC 20060209
1735
 
            revision_id = br_from.last_revision()
1736
 
        if to_location is None:
1737
 
            to_location = urlutils.derive_to_location(from_location)
1738
 
        target_controldir = br_from.controldir.clone(to_location, revision_id=revision_id)
1739
 
        note(gettext('Created new control directory.'))
1740
 
 
1741
 
 
1742
1661
class cmd_renames(Command):
1743
1662
    __doc__ = """Show list of renamed files.
1744
1663
    """
1751
1670
    @display_command
1752
1671
    def run(self, dir=u'.'):
1753
1672
        tree = WorkingTree.open_containing(dir)[0]
1754
 
        self.enter_context(tree.lock_read())
 
1673
        self.add_cleanup(tree.lock_read().unlock)
1755
1674
        old_tree = tree.basis_tree()
1756
 
        self.enter_context(old_tree.lock_read())
 
1675
        self.add_cleanup(old_tree.lock_read().unlock)
1757
1676
        renames = []
1758
1677
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1759
 
        for change in iterator:
1760
 
            if change.path[0] == change.path[1]:
1761
 
                continue
1762
 
            if None in change.path:
1763
 
                continue
1764
 
            renames.append(change.path)
 
1678
        for f, paths, c, v, p, n, k, e in iterator:
 
1679
            if paths[0] == paths[1]:
 
1680
                continue
 
1681
            if None in (paths):
 
1682
                continue
 
1683
            renames.append(paths)
1765
1684
        renames.sort()
1766
1685
        for old_name, new_name in renames:
1767
1686
            self.outf.write("%s => %s\n" % (old_name, new_name))
1772
1691
 
1773
1692
    This will perform a merge of the destination revision (the tip of the
1774
1693
    branch, or the specified revision) into the working tree, and then make
1775
 
    that revision the basis revision for the working tree.
 
1694
    that revision the basis revision for the working tree.  
1776
1695
 
1777
1696
    You can use this to visit an older revision, or to update a working tree
1778
1697
    that is out of date from its branch.
1779
 
 
 
1698
    
1780
1699
    If there are any uncommitted changes in the tree, they will be carried
1781
1700
    across and remain as uncommitted changes after the update.  To discard
1782
1701
    these changes, use 'brz revert'.  The uncommitted changes may conflict
1785
1704
    If the tree's branch is bound to a master branch, brz will also update
1786
1705
    the branch from the master.
1787
1706
 
1788
 
    You cannot update just a single file or directory, because each Breezy
 
1707
    You cannot update just a single file or directory, because each Bazaar
1789
1708
    working tree has just a single basis revision.  If you want to restore a
1790
1709
    file that has been removed locally, use 'brz revert' instead of 'brz
1791
1710
    update'.  If you want to restore a file to its state in a previous
1793
1712
    out the old content of that file to a new location.
1794
1713
 
1795
1714
    The 'dir' argument, if given, must be the location of the root of a
1796
 
    working tree to update.  By default, the working tree that contains the
 
1715
    working tree to update.  By default, the working tree that contains the 
1797
1716
    current working directory is used.
1798
1717
    """
1799
1718
 
1824
1743
            possible_transports=possible_transports)
1825
1744
        if master is not None:
1826
1745
            branch_location = master.base
1827
 
            self.enter_context(tree.lock_write())
 
1746
            tree.lock_write()
1828
1747
        else:
1829
1748
            branch_location = tree.branch.base
1830
 
            self.enter_context(tree.lock_tree_write())
 
1749
            tree.lock_tree_write()
 
1750
        self.add_cleanup(tree.unlock)
1831
1751
        # get rid of the final '/' and be ready for display
1832
1752
        branch_location = urlutils.unescape_for_display(
1833
1753
            branch_location.rstrip('/'),
1847
1767
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
1848
1768
            revno = branch.revision_id_to_dotted_revno(revision_id)
1849
1769
            note(gettext("Tree is up to date at revision {0} of branch {1}"
1850
 
                         ).format('.'.join(map(str, revno)), branch_location))
 
1770
                        ).format('.'.join(map(str, revno)), branch_location))
1851
1771
            return 0
1852
1772
        view_info = _get_view_info_for_change_reporter(tree)
1853
1773
        change_reporter = delta._ChangeReporter(
1862
1782
                show_base=show_base)
1863
1783
        except errors.NoSuchRevision as e:
1864
1784
            raise errors.BzrCommandError(gettext(
1865
 
                "branch has no revision %s\n"
1866
 
                "brz update --revision only works"
1867
 
                " for a revision in the branch history")
1868
 
                % (e.revision))
 
1785
                                  "branch has no revision %s\n"
 
1786
                                  "brz update --revision only works"
 
1787
                                  " for a revision in the branch history")
 
1788
                                  % (e.revision))
1869
1789
        revno = tree.branch.revision_id_to_dotted_revno(
1870
1790
            _mod_revision.ensure_null(tree.last_revision()))
1871
1791
        note(gettext('Updated to revision {0} of branch {1}').format(
1873
1793
        parent_ids = tree.get_parent_ids()
1874
1794
        if parent_ids[1:] and parent_ids[1:] != existing_pending_merges:
1875
1795
            note(gettext('Your local commits will now show as pending merges with '
1876
 
                         "'brz status', and can be committed with 'brz commit'."))
 
1796
                 "'brz status', and can be committed with 'brz commit'."))
1877
1797
        if conflicts != 0:
1878
1798
            return 1
1879
1799
        else:
1927
1847
class cmd_remove(Command):
1928
1848
    __doc__ = """Remove files or directories.
1929
1849
 
1930
 
    This makes Breezy stop tracking changes to the specified files. Breezy will
 
1850
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
1931
1851
    delete them if they can easily be recovered using revert otherwise they
1932
1852
    will be backed up (adding an extension of the form .~#~). If no options or
1933
 
    parameters are given Breezy will scan for files that are being tracked by
1934
 
    Breezy but missing in your tree and stop tracking them for you.
 
1853
    parameters are given Bazaar will scan for files that are being tracked by
 
1854
    Bazaar but missing in your tree and stop tracking them for you.
1935
1855
    """
1936
1856
    takes_args = ['file*']
1937
1857
    takes_options = ['verbose',
1938
 
                     Option(
1939
 
                         'new', help='Only remove files that have never been committed.'),
1940
 
                     RegistryOption.from_kwargs('file-deletion-strategy',
1941
 
                                                'The file deletion mode to be used.',
1942
 
                                                title='Deletion Strategy', value_switches=True, enum_switch=False,
1943
 
                                                safe='Backup changed files (default).',
1944
 
                                                keep='Delete from brz but leave the working copy.',
1945
 
                                                no_backup='Don\'t backup changed files.'),
1946
 
                     ]
 
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
        ]
1947
1866
    aliases = ['rm', 'del']
1948
1867
    encoding_type = 'replace'
1949
1868
 
1950
1869
    def run(self, file_list, verbose=False, new=False,
1951
 
            file_deletion_strategy='safe'):
 
1870
        file_deletion_strategy='safe'):
1952
1871
 
1953
1872
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1954
1873
 
1955
1874
        if file_list is not None:
1956
1875
            file_list = [f for f in file_list]
1957
1876
 
1958
 
        self.enter_context(tree.lock_write())
 
1877
        self.add_cleanup(tree.lock_write().unlock)
1959
1878
        # Heuristics should probably all move into tree.remove_smart or
1960
1879
        # some such?
1961
1880
        if new:
1962
1881
            added = tree.changes_from(tree.basis_tree(),
1963
 
                                      specific_files=file_list).added
1964
 
            file_list = sorted([f.path[1] for f in added], reverse=True)
 
1882
                specific_files=file_list).added
 
1883
            file_list = sorted([f[0] for f in added], reverse=True)
1965
1884
            if len(file_list) == 0:
1966
1885
                raise errors.BzrCommandError(gettext('No matching files.'))
1967
1886
        elif file_list is None:
1970
1889
            missing = []
1971
1890
            for change in tree.iter_changes(tree.basis_tree()):
1972
1891
                # Find paths in the working tree that have no kind:
1973
 
                if change.path[1] is not None and change.kind[1] is None:
1974
 
                    missing.append(change.path[1])
 
1892
                if change[1][1] is not None and change[6][1] is None:
 
1893
                    missing.append(change[1][1])
1975
1894
            file_list = sorted(missing, reverse=True)
1976
1895
            file_deletion_strategy = 'keep'
1977
1896
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1978
 
                    keep_files=file_deletion_strategy == 'keep',
1979
 
                    force=(file_deletion_strategy == 'no-backup'))
 
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
        i = tree.path2id(relpath)
 
1917
        if i is None:
 
1918
            raise errors.NotVersionedError(filename)
 
1919
        else:
 
1920
            self.outf.write(i + '\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))
1980
1943
 
1981
1944
 
1982
1945
class cmd_reconcile(Command):
2024
1987
    @display_command
2025
1988
    def run(self, location="."):
2026
1989
        branch = Branch.open_containing(location)[0]
2027
 
        self.enter_context(branch.lock_read())
 
1990
        self.add_cleanup(branch.lock_read().unlock)
2028
1991
        graph = branch.repository.get_graph()
2029
1992
        history = list(graph.iter_lefthand_ancestry(branch.last_revision(),
2030
 
                                                    [_mod_revision.NULL_REVISION]))
 
1993
            [_mod_revision.NULL_REVISION]))
2031
1994
        for revid in reversed(history):
2032
1995
            self.outf.write(revid)
2033
1996
            self.outf.write('\n')
2052
2015
            b = wt.branch
2053
2016
            last_revision = wt.last_revision()
2054
2017
 
2055
 
        self.enter_context(b.repository.lock_read())
 
2018
        self.add_cleanup(b.repository.lock_read().unlock)
2056
2019
        graph = b.repository.get_graph()
2057
2020
        revisions = [revid for revid, parents in
2058
 
                     graph.iter_ancestry([last_revision])]
 
2021
            graph.iter_ancestry([last_revision])]
2059
2022
        for revision_id in reversed(revisions):
2060
2023
            if _mod_revision.is_null(revision_id):
2061
2024
                continue
2062
 
            self.outf.write(revision_id.decode('utf-8') + '\n')
 
2025
            self.outf.write(revision_id + '\n')
2063
2026
 
2064
2027
 
2065
2028
class cmd_init(Command):
2085
2048
        brz commit -m "imported project"
2086
2049
    """
2087
2050
 
2088
 
    _see_also = ['init-shared-repository', 'branch', 'checkout']
 
2051
    _see_also = ['init-repository', 'branch', 'checkout']
2089
2052
    takes_args = ['location?']
2090
2053
    takes_options = [
2091
2054
        Option('create-prefix',
2092
2055
               help='Create the path leading up to the branch '
2093
2056
                    'if it does not already exist.'),
2094
 
        RegistryOption('format',
2095
 
                       help='Specify a format for this branch. '
2096
 
                       'See "help formats" for a full list.',
2097
 
                       lazy_registry=('breezy.controldir', 'format_registry'),
2098
 
                       converter=lambda name: controldir.format_registry.make_controldir(
2099
 
                            name),
2100
 
                       value_switches=True,
2101
 
                       title="Branch format",
2102
 
                       ),
2103
 
        Option('append-revisions-only',
2104
 
               help='Never change revnos or the existing log.'
2105
 
               '  Append revisions to it only.'),
2106
 
        Option('no-tree',
2107
 
               'Create a branch without a working tree.')
2108
 
        ]
2109
 
 
 
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
         ]
2110
2071
    def run(self, location=None, format=None, append_revisions_only=False,
2111
2072
            create_prefix=False, no_tree=False):
2112
2073
        if format is None:
2114
2075
        if location is None:
2115
2076
            location = u'.'
2116
2077
 
2117
 
        to_transport = transport.get_transport(location, purpose='write')
 
2078
        to_transport = transport.get_transport(location)
2118
2079
 
2119
2080
        # The path has to exist to initialize a
2120
2081
        # branch inside of it.
2126
2087
        except errors.NoSuchFile:
2127
2088
            if not create_prefix:
2128
2089
                raise errors.BzrCommandError(gettext("Parent directory of %s"
2129
 
                                                     " does not exist."
2130
 
                                                     "\nYou may supply --create-prefix to create all"
2131
 
                                                     " leading parent directories.")
2132
 
                                             % location)
 
2090
                    " does not exist."
 
2091
                    "\nYou may supply --create-prefix to create all"
 
2092
                    " leading parent directories.")
 
2093
                    % location)
2133
2094
            to_transport.create_prefix()
2134
2095
 
2135
2096
        try:
2136
 
            a_controldir = controldir.ControlDir.open_from_transport(
2137
 
                to_transport)
 
2097
            a_controldir = controldir.ControlDir.open_from_transport(to_transport)
2138
2098
        except errors.NotBranchError:
2139
2099
            # really a NotBzrDir error...
2140
2100
            create_branch = controldir.ControlDir.create_branch_convenience
2150
2110
            from .transport.local import LocalTransport
2151
2111
            if a_controldir.has_branch():
2152
2112
                if (isinstance(to_transport, LocalTransport)
2153
 
                        and not a_controldir.has_workingtree()):
2154
 
                    raise errors.BranchExistsWithoutWorkingTree(location)
 
2113
                    and not a_controldir.has_workingtree()):
 
2114
                        raise errors.BranchExistsWithoutWorkingTree(location)
2155
2115
                raise errors.AlreadyBranchError(location)
2156
2116
            branch = a_controldir.create_branch()
2157
2117
            if not no_tree and not a_controldir.has_workingtree():
2161
2121
                branch.set_append_revisions_only(True)
2162
2122
            except errors.UpgradeRequired:
2163
2123
                raise errors.BzrCommandError(gettext('This branch format cannot be set'
2164
 
                                                     ' to append-revisions-only.  Try --default.'))
 
2124
                    ' to append-revisions-only.  Try --default.'))
2165
2125
        if not is_quiet():
2166
2126
            from .info import describe_layout, describe_format
2167
2127
            try:
2172
2132
            layout = describe_layout(repository, branch, tree).lower()
2173
2133
            format = describe_format(a_controldir, repository, branch, tree)
2174
2134
            self.outf.write(gettext("Created a {0} (format: {1})\n").format(
2175
 
                layout, format))
 
2135
                  layout, format))
2176
2136
            if repository.is_shared():
2177
 
                # XXX: maybe this can be refactored into transport.path_or_url()
 
2137
                #XXX: maybe this can be refactored into transport.path_or_url()
2178
2138
                url = repository.controldir.root_transport.external_url()
2179
2139
                try:
2180
2140
                    url = urlutils.local_path_from_url(url)
2183
2143
                self.outf.write(gettext("Using shared repository: %s\n") % url)
2184
2144
 
2185
2145
 
2186
 
class cmd_init_shared_repository(Command):
 
2146
class cmd_init_repository(Command):
2187
2147
    __doc__ = """Create a shared repository for branches to share storage space.
2188
2148
 
2189
2149
    New branches created under the repository directory will store their
2190
2150
    revisions in the repository, not in the branch directory.  For branches
2191
 
    with shared history, this reduces the amount of storage needed and
 
2151
    with shared history, this reduces the amount of storage needed and 
2192
2152
    speeds up the creation of new branches.
2193
2153
 
2194
2154
    If the --no-trees option is given then the branches in the repository
2195
 
    will not have working trees by default.  They will still exist as
2196
 
    directories on disk, but they will not have separate copies of the
 
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 
2197
2157
    files at a certain revision.  This can be useful for repositories that
2198
2158
    store branches which are interacted with through checkouts or remote
2199
2159
    branches, such as on a server.
2201
2161
    :Examples:
2202
2162
        Create a shared repository holding just branches::
2203
2163
 
2204
 
            brz init-shared-repo --no-trees repo
 
2164
            brz init-repo --no-trees repo
2205
2165
            brz init repo/trunk
2206
2166
 
2207
2167
        Make a lightweight checkout elsewhere::
2214
2174
    _see_also = ['init', 'branch', 'checkout', 'repositories']
2215
2175
    takes_args = ["location"]
2216
2176
    takes_options = [RegistryOption('format',
2217
 
                                    help='Specify a format for this repository. See'
2218
 
                                    ' "brz help formats" for details.',
2219
 
                                    lazy_registry=(
2220
 
                                        'breezy.controldir', 'format_registry'),
2221
 
                                    converter=lambda name: controldir.format_registry.make_controldir(
2222
 
                                        name),
2223
 
                                    value_switches=True, title='Repository 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'),
2224
2182
                     Option('no-trees',
2225
 
                            help='Branches in the repository will default to'
2226
 
                            ' not having a working tree.'),
2227
 
                     ]
2228
 
    aliases = ["init-shared-repo", "init-repo"]
 
2183
                             help='Branches in the repository will default to'
 
2184
                                  ' not having a working tree.'),
 
2185
                    ]
 
2186
    aliases = ["init-repo"]
2229
2187
 
2230
2188
    def run(self, location, format=None, no_trees=False):
2231
2189
        if format is None:
2234
2192
        if location is None:
2235
2193
            location = '.'
2236
2194
 
2237
 
        to_transport = transport.get_transport(location, purpose='write')
 
2195
        to_transport = transport.get_transport(location)
2238
2196
 
2239
2197
        if format.fixed_components:
2240
2198
            repo_format_name = None
2243
2201
 
2244
2202
        (repo, newdir, require_stacking, repository_policy) = (
2245
2203
            format.initialize_on_transport_ex(to_transport,
2246
 
                                              create_prefix=True, make_working_trees=not no_trees,
2247
 
                                              shared_repo=True, force_new_repo=True,
2248
 
                                              use_existing_dir=True,
2249
 
                                              repo_format_name=repo_format_name))
 
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))
2250
2208
        if not is_quiet():
2251
2209
            from .info import show_bzrdir_info
2252
2210
            show_bzrdir_info(newdir, verbose=0, outfile=self.outf)
2267
2225
 
2268
2226
    Note that when using the -r argument with a range of revisions, the
2269
2227
    differences are computed between the two specified revisions.  That
2270
 
    is, the command does not show the changes introduced by the first
2271
 
    revision in the range.  This differs from the interpretation of
 
2228
    is, the command does not show the changes introduced by the first 
 
2229
    revision in the range.  This differs from the interpretation of 
2272
2230
    revision ranges used by "brz log" which includes the first revision
2273
2231
    in the range.
2274
2232
 
2300
2258
            brz diff -c2
2301
2259
 
2302
2260
        To see the changes introduced by revision X::
2303
 
 
 
2261
        
2304
2262
            brz diff -cX
2305
2263
 
2306
2264
        Note that in the case of a merge, the -c option shows the changes
2348
2306
               help='Set prefixes added to old and new filenames, as '
2349
2307
                    'two values separated by a colon. (eg "old/:new/").'),
2350
2308
        Option('old',
2351
 
               help='Branch/tree to compare from.',
2352
 
               type=text_type,
2353
 
               ),
 
2309
            help='Branch/tree to compare from.',
 
2310
            type=text_type,
 
2311
            ),
2354
2312
        Option('new',
2355
 
               help='Branch/tree to compare to.',
2356
 
               type=text_type,
2357
 
               ),
 
2313
            help='Branch/tree to compare to.',
 
2314
            type=text_type,
 
2315
            ),
2358
2316
        'revision',
2359
2317
        'change',
2360
2318
        Option('using',
2361
 
               help='Use this command to compare files.',
2362
 
               type=text_type,
2363
 
               ),
 
2319
            help='Use this command to compare files.',
 
2320
            type=text_type,
 
2321
            ),
2364
2322
        RegistryOption('format',
2365
 
                       short_name='F',
2366
 
                       help='Diff format to use.',
2367
 
                       lazy_registry=('breezy.diff', 'format_registry'),
2368
 
                       title='Diff format'),
 
2323
            short_name='F',
 
2324
            help='Diff format to use.',
 
2325
            lazy_registry=('breezy.diff', 'format_registry'),
 
2326
            title='Diff format'),
2369
2327
        Option('context',
2370
 
               help='How many lines of context to show.',
2371
 
               type=int,
2372
 
               ),
2373
 
        RegistryOption.from_kwargs(
2374
 
            'color',
2375
 
            help='Color mode to use.',
2376
 
            title='Color Mode', value_switches=False, enum_switch=True,
2377
 
            never='Never colorize output.',
2378
 
            auto='Only colorize output if terminal supports it and STDOUT is a'
2379
 
            ' TTY.',
2380
 
            always='Always colorize output (default).'),
2381
 
        Option(
2382
 
            'check-style',
2383
 
            help=('Warn if trailing whitespace or spurious changes have been'
2384
 
                  '  added.'))
 
2328
            help='How many lines of context to show.',
 
2329
            type=int,
 
2330
            ),
2385
2331
        ]
2386
 
 
2387
2332
    aliases = ['di', 'dif']
2388
2333
    encoding_type = 'exact'
2389
2334
 
2390
2335
    @display_command
2391
2336
    def run(self, revision=None, file_list=None, diff_options=None,
2392
2337
            prefix=None, old=None, new=None, using=None, format=None,
2393
 
            context=None, color='never'):
 
2338
            context=None):
2394
2339
        from .diff import (get_trees_and_branches_to_diff_locked,
2395
 
                           show_diff_trees)
 
2340
            show_diff_trees)
2396
2341
 
2397
2342
        if prefix == u'0':
2398
2343
            # diff -p0 format
2410
2355
 
2411
2356
        if revision and len(revision) > 2:
2412
2357
            raise errors.BzrCommandError(gettext('brz diff --revision takes exactly'
2413
 
                                                 ' one or two revision specifiers'))
 
2358
                                         ' one or two revision specifiers'))
2414
2359
 
2415
2360
        if using is not None and format is not None:
2416
2361
            raise errors.BzrCommandError(gettext(
2420
2365
        (old_tree, new_tree,
2421
2366
         old_branch, new_branch,
2422
2367
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
2423
 
            file_list, revision, old, new, self._exit_stack, apply_view=True)
 
2368
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
2424
2369
        # GNU diff on Windows uses ANSI encoding for filenames
2425
2370
        path_encoding = osutils.get_diff_header_encoding()
2426
 
        outf = self.outf
2427
 
        if color == 'auto':
2428
 
            from .terminal import has_ansi_colors
2429
 
            if has_ansi_colors():
2430
 
                color = 'always'
2431
 
            else:
2432
 
                color = 'never'
2433
 
        if 'always' == color:
2434
 
            from .colordiff import DiffWriter
2435
 
            outf = DiffWriter(outf)
2436
 
        return show_diff_trees(old_tree, new_tree, outf,
 
2371
        return show_diff_trees(old_tree, new_tree, self.outf,
2437
2372
                               specific_files=specific_files,
2438
2373
                               external_diff_options=diff_options,
2439
2374
                               old_label=old_label, new_label=new_label,
2458
2393
    @display_command
2459
2394
    def run(self, show_ids=False, directory=u'.'):
2460
2395
        tree = WorkingTree.open_containing(directory)[0]
2461
 
        self.enter_context(tree.lock_read())
 
2396
        self.add_cleanup(tree.lock_read().unlock)
2462
2397
        old = tree.basis_tree()
2463
 
        self.enter_context(old.lock_read())
2464
 
        delta = tree.changes_from(old)
2465
 
        for change in delta.removed:
2466
 
            self.outf.write(change.path[0])
2467
 
            if show_ids:
2468
 
                self.outf.write(' ')
2469
 
                self.outf.write(change.file_id)
2470
 
            self.outf.write('\n')
 
2398
        self.add_cleanup(old.lock_read().unlock)
 
2399
        for path, ie in old.iter_entries_by_dir():
 
2400
            if not tree.has_id(ie.file_id):
 
2401
                self.outf.write(path)
 
2402
                if show_ids:
 
2403
                    self.outf.write(' ')
 
2404
                    self.outf.write(ie.file_id)
 
2405
                self.outf.write('\n')
2471
2406
 
2472
2407
 
2473
2408
class cmd_modified(Command):
2481
2416
    @display_command
2482
2417
    def run(self, null=False, directory=u'.'):
2483
2418
        tree = WorkingTree.open_containing(directory)[0]
2484
 
        self.enter_context(tree.lock_read())
 
2419
        self.add_cleanup(tree.lock_read().unlock)
2485
2420
        td = tree.changes_from(tree.basis_tree())
2486
2421
        self.cleanup_now()
2487
 
        for change in td.modified:
 
2422
        for path, id, kind, text_modified, meta_modified in td.modified:
2488
2423
            if null:
2489
 
                self.outf.write(change.path[1] + '\0')
 
2424
                self.outf.write(path + '\0')
2490
2425
            else:
2491
 
                self.outf.write(osutils.quotefn(change.path[1]) + '\n')
 
2426
                self.outf.write(osutils.quotefn(path) + '\n')
2492
2427
 
2493
2428
 
2494
2429
class cmd_added(Command):
2502
2437
    @display_command
2503
2438
    def run(self, null=False, directory=u'.'):
2504
2439
        wt = WorkingTree.open_containing(directory)[0]
2505
 
        self.enter_context(wt.lock_read())
 
2440
        self.add_cleanup(wt.lock_read().unlock)
2506
2441
        basis = wt.basis_tree()
2507
 
        self.enter_context(basis.lock_read())
 
2442
        self.add_cleanup(basis.lock_read().unlock)
 
2443
        root_id = wt.get_root_id()
2508
2444
        for path in wt.all_versioned_paths():
2509
2445
            if basis.has_filename(path):
2510
2446
                continue
2521
2457
class cmd_root(Command):
2522
2458
    __doc__ = """Show the tree root directory.
2523
2459
 
2524
 
    The root is the nearest enclosing directory with a control
 
2460
    The root is the nearest enclosing directory with a .bzr control
2525
2461
    directory."""
2526
2462
 
2527
2463
    takes_args = ['filename?']
2528
 
 
2529
2464
    @display_command
2530
2465
    def run(self, filename=None):
2531
2466
        """Print the branch root."""
2673
2608
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
2674
2609
      bzr-explorer shell, or the Loggerhead web interface.  See the Bazaar
2675
2610
      Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/> and
2676
 
      <http://wiki.bazaar.canonical.com/IDEIntegration>.
 
2611
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
2677
2612
 
2678
2613
      You may find it useful to add the aliases below to ``breezy.conf``::
2679
2614
 
2707
2642
    takes_args = ['file*']
2708
2643
    _see_also = ['log-formats', 'revisionspec']
2709
2644
    takes_options = [
2710
 
        Option('forward',
2711
 
               help='Show from oldest to newest.'),
2712
 
        'timezone',
2713
 
        custom_help('verbose',
2714
 
                    help='Show files changed in each revision.'),
2715
 
        'show-ids',
2716
 
        'revision',
2717
 
        Option('change',
2718
 
               type=breezy.option._parse_revision_str,
2719
 
               short_name='c',
2720
 
               help='Show just the specified revision.'
2721
 
               ' See also "help revisionspec".'),
2722
 
        'log-format',
2723
 
        RegistryOption('authors',
2724
 
                       'What names to list as authors - first, all or committer.',
2725
 
                       title='Authors',
2726
 
                       lazy_registry=(
2727
 
                           'breezy.log', 'author_list_registry'),
2728
 
                       ),
2729
 
        Option('levels',
2730
 
               short_name='n',
2731
 
               help='Number of levels to display - 0 for all, 1 for flat.',
2732
 
               argname='N',
2733
 
               type=_parse_levels),
2734
 
        Option('message',
2735
 
               help='Show revisions whose message matches this '
2736
 
               'regular expression.',
2737
 
               type=text_type,
2738
 
               hidden=True),
2739
 
        Option('limit',
2740
 
               short_name='l',
2741
 
               help='Limit the output to the first N revisions.',
2742
 
               argname='N',
2743
 
               type=_parse_limit),
2744
 
        Option('show-diff',
2745
 
               short_name='p',
2746
 
               help='Show changes made in each revision as a patch.'),
2747
 
        Option('include-merged',
2748
 
               help='Show merged revisions like --levels 0 does.'),
2749
 
        Option('include-merges', hidden=True,
2750
 
               help='Historical alias for --include-merged.'),
2751
 
        Option('omit-merges',
2752
 
               help='Do not report commits with more than one parent.'),
2753
 
        Option('exclude-common-ancestry',
2754
 
               help='Display only the revisions that are not part'
2755
 
               ' of both ancestries (require -rX..Y).'
2756
 
               ),
2757
 
        Option('signatures',
2758
 
               help='Show digital signature validity.'),
2759
 
        ListOption('match',
2760
 
                   short_name='m',
2761
 
                   help='Show revisions whose properties match this '
2762
 
                   'expression.',
2763
 
                   type=text_type),
2764
 
        ListOption('match-message',
2765
 
                   help='Show revisions whose message matches this '
2766
 
                   'expression.',
2767
 
                   type=text_type),
2768
 
        ListOption('match-committer',
 
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',
2769
2703
                   help='Show revisions whose committer matches this '
2770
2704
                   'expression.',
2771
 
                   type=text_type),
2772
 
        ListOption('match-author',
 
2705
                type=text_type),
 
2706
            ListOption('match-author',
2773
2707
                   help='Show revisions whose authors match this '
2774
2708
                   'expression.',
2775
 
                   type=text_type),
2776
 
        ListOption('match-bugs',
 
2709
                type=text_type),
 
2710
            ListOption('match-bugs',
2777
2711
                   help='Show revisions whose bugs match this '
2778
2712
                   'expression.',
2779
 
                   type=text_type)
2780
 
        ]
 
2713
                type=text_type)
 
2714
            ]
2781
2715
    encoding_type = 'replace'
2782
2716
 
2783
2717
    @display_command
2812
2746
        if include_merged is None:
2813
2747
            include_merged = False
2814
2748
        if (exclude_common_ancestry
2815
 
                and (revision is None or len(revision) != 2)):
 
2749
            and (revision is None or len(revision) != 2)):
2816
2750
            raise errors.BzrCommandError(gettext(
2817
2751
                '--exclude-common-ancestry requires -r with two revisions'))
2818
2752
        if include_merged:
2838
2772
        if file_list:
2839
2773
            # find the file ids to log and check for directory filtering
2840
2774
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2841
 
                revision, file_list, self._exit_stack)
 
2775
                revision, file_list, self.add_cleanup)
2842
2776
            for relpath, file_id, kind in file_info_list:
2843
2777
                if file_id is None:
2844
2778
                    raise errors.BzrCommandError(gettext(
2862
2796
                location = '.'
2863
2797
            dir, relpath = controldir.ControlDir.open_containing(location)
2864
2798
            b = dir.open_branch()
2865
 
            self.enter_context(b.lock_read())
 
2799
            self.add_cleanup(b.lock_read().unlock)
2866
2800
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2867
2801
 
2868
2802
        if b.get_config_stack().get('validate_signatures_in_log'):
2889
2823
        if log_format is None:
2890
2824
            log_format = log.log_formatter_registry.get_default(b)
2891
2825
        # Make a non-encoding output to include the diffs - bug 328007
2892
 
        unencoded_output = ui.ui_factory.make_output_stream(
2893
 
            encoding_type='exact')
 
2826
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
2894
2827
        lf = log_format(show_ids=show_ids, to_file=self.outf,
2895
2828
                        to_exact_file=unencoded_output,
2896
2829
                        show_timezone=timezone,
2913
2846
        # file that isn't a directory without showing a delta" case.
2914
2847
        partial_history = revision and b.repository._format.supports_chks
2915
2848
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2916
 
                              or delta_type or partial_history)
 
2849
            or delta_type or partial_history)
2917
2850
 
2918
2851
        match_dict = {}
2919
2852
        if match:
2989
2922
        rev_id2 = revision_range[1].rev_id
2990
2923
    return rev_id1, rev_id2
2991
2924
 
2992
 
 
2993
2925
def get_log_format(long=False, short=False, line=False, default='long'):
2994
2926
    log_format = default
2995
2927
    if long:
3015
2947
        tree, relpath = WorkingTree.open_containing(filename)
3016
2948
        with tree.lock_read():
3017
2949
            touching_revs = log.find_touching_revisions(
3018
 
                tree.branch.repository, tree.branch.last_revision(), tree, relpath)
 
2950
                    tree.branch.repository, tree.branch.last_revision(), tree, relpath)
3019
2951
            for revno, revision_id, what in reversed(list(touching_revs)):
3020
2952
                self.outf.write("%6d %s\n" % (revno, what))
3021
2953
 
3027
2959
    _see_also = ['status', 'cat']
3028
2960
    takes_args = ['path?']
3029
2961
    takes_options = [
3030
 
        'verbose',
3031
 
        'revision',
3032
 
        Option('recursive', short_name='R',
3033
 
               help='Recurse into subdirectories.'),
3034
 
        Option('from-root',
3035
 
               help='Print paths relative to the root of the branch.'),
3036
 
        Option('unknown', short_name='u',
3037
 
               help='Print unknown files.'),
3038
 
        Option('versioned', help='Print versioned files.',
3039
 
               short_name='V'),
3040
 
        Option('ignored', short_name='i',
3041
 
               help='Print ignored files.'),
3042
 
        Option('kind', short_name='k',
3043
 
               help=('List entries of a particular kind: file, '
3044
 
                     'directory, symlink, tree-reference.'),
3045
 
               type=text_type),
3046
 
        'null',
3047
 
        'show-ids',
3048
 
        'directory',
3049
 
        ]
3050
 
 
 
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
            ]
3051
2981
    @display_command
3052
2982
    def run(self, revision=None, verbose=False,
3053
2983
            recursive=False, from_root=False,
3058
2988
            raise errors.BzrCommandError(gettext('invalid kind specified'))
3059
2989
 
3060
2990
        if verbose and null:
3061
 
            raise errors.BzrCommandError(
3062
 
                gettext('Cannot set both --verbose and --null'))
 
2991
            raise errors.BzrCommandError(gettext('Cannot set both --verbose and --null'))
3063
2992
        all = not (unknown or versioned or ignored)
3064
2993
 
3065
 
        selection = {'I': ignored, '?': unknown, 'V': versioned}
 
2994
        selection = {'I':ignored, '?':unknown, 'V':versioned}
3066
2995
 
3067
2996
        if path is None:
3068
2997
            fs_path = '.'
3069
2998
        else:
3070
2999
            if from_root:
3071
3000
                raise errors.BzrCommandError(gettext('cannot specify both --from-root'
3072
 
                                                     ' and PATH'))
 
3001
                                             ' and PATH'))
3073
3002
            fs_path = path
3074
3003
        tree, branch, relpath = \
3075
3004
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
3093
3022
                view_str = views.view_display_str(view_files)
3094
3023
                note(gettext("Ignoring files outside view. View is %s") % view_str)
3095
3024
 
3096
 
        self.enter_context(tree.lock_read())
3097
 
        for fp, fc, fkind, entry in tree.list_files(
3098
 
                include_root=False, from_dir=relpath, recursive=recursive):
 
3025
        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):
3099
3028
            # Apply additional masking
3100
3029
            if not all and not selection[fc]:
3101
3030
                continue
3119
3048
            ui.ui_factory.clear_term()
3120
3049
            if verbose:
3121
3050
                outstring = '%-8s %s' % (fc, outstring)
3122
 
                if show_ids and getattr(entry, 'file_id', None) is not None:
3123
 
                    outstring = "%-50s %s" % (outstring, entry.file_id.decode('utf-8'))
 
3051
                if show_ids and fid is not None:
 
3052
                    outstring = "%-50s %s" % (outstring, fid)
3124
3053
                self.outf.write(outstring + '\n')
3125
3054
            elif null:
3126
3055
                self.outf.write(fp + '\0')
3127
3056
                if show_ids:
3128
 
                    if getattr(entry, 'file_id', None) is not None:
3129
 
                        self.outf.write(entry.file_id.decode('utf-8'))
 
3057
                    if fid is not None:
 
3058
                        self.outf.write(fid)
3130
3059
                    self.outf.write('\0')
3131
3060
                self.outf.flush()
3132
3061
            else:
3133
3062
                if show_ids:
3134
 
                    if getattr(entry, 'file_id', None) is not None:
3135
 
                        my_id = entry.file_id.decode('utf-8')
 
3063
                    if fid is not None:
 
3064
                        my_id = fid
3136
3065
                    else:
3137
3066
                        my_id = ''
3138
3067
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
3161
3090
 
3162
3091
    If a .bzrignore file does not exist, the ignore command
3163
3092
    will create one and add the specified files or patterns to the newly
3164
 
    created file. The ignore command will also automatically add the
 
3093
    created file. The ignore command will also automatically add the 
3165
3094
    .bzrignore file to be versioned. Creating a .bzrignore file without
3166
3095
    the use of the ignore command will require an explicit add command.
3167
3096
 
3169
3098
    After adding, editing or deleting that file either indirectly by
3170
3099
    using this command or directly by using an editor, be sure to commit
3171
3100
    it.
3172
 
 
3173
 
    Breezy also supports a global ignore file ~/.config/breezy/ignore. On
3174
 
    Windows the global ignore file can be found in the application data
3175
 
    directory as
3176
 
    C:\\Documents and Settings\\<user>\\Application Data\\Breezy\\3.0\\ignore.
 
3101
    
 
3102
    Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
 
3103
    the global ignore file can be found in the application data directory as
 
3104
    C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
3177
3105
    Global ignores are not touched by this command. The global ignore file
3178
3106
    can be edited directly using an editor.
3179
3107
 
3180
3108
    Patterns prefixed with '!' are exceptions to ignore patterns and take
3181
3109
    precedence over regular ignores.  Such exceptions are used to specify
3182
3110
    files that should be versioned which would otherwise be ignored.
3183
 
 
 
3111
    
3184
3112
    Patterns prefixed with '!!' act as regular ignore patterns, but have
3185
3113
    precedence over the '!' exception patterns.
3186
3114
 
3187
 
    :Notes:
3188
 
 
 
3115
    :Notes: 
 
3116
        
3189
3117
    * Ignore patterns containing shell wildcards must be quoted from
3190
3118
      the shell on Unix.
3191
3119
 
3220
3148
        Ignore everything but the "debian" toplevel directory::
3221
3149
 
3222
3150
            brz ignore "RE:(?!debian/).*"
3223
 
 
 
3151
        
3224
3152
        Ignore everything except the "local" toplevel directory,
3225
3153
        but always ignore autosave files ending in ~, even under local/::
3226
 
 
 
3154
        
3227
3155
            brz ignore "*"
3228
3156
            brz ignore "!./local"
3229
3157
            brz ignore "!!*~"
3232
3160
    _see_also = ['status', 'ignored', 'patterns']
3233
3161
    takes_args = ['name_pattern*']
3234
3162
    takes_options = ['directory',
3235
 
                     Option('default-rules',
3236
 
                            help='Display the default ignore rules that brz uses.')
3237
 
                     ]
 
3163
        Option('default-rules',
 
3164
               help='Display the default ignore rules that brz uses.')
 
3165
        ]
3238
3166
 
3239
3167
    def run(self, name_pattern_list=None, default_rules=None,
3240
3168
            directory=u'.'):
3246
3174
            return
3247
3175
        if not name_pattern_list:
3248
3176
            raise errors.BzrCommandError(gettext("ignore requires at least one "
3249
 
                                                 "NAME_PATTERN or --default-rules."))
 
3177
                "NAME_PATTERN or --default-rules."))
3250
3178
        name_pattern_list = [globbing.normalize_pattern(p)
3251
3179
                             for p in name_pattern_list]
3252
3180
        bad_patterns = ''
3256
3184
                bad_patterns_count += 1
3257
3185
                bad_patterns += ('\n  %s' % p)
3258
3186
        if bad_patterns:
3259
 
            msg = (ngettext('Invalid ignore pattern found. %s',
 
3187
            msg = (ngettext('Invalid ignore pattern found. %s', 
3260
3188
                            'Invalid ignore patterns found. %s',
3261
3189
                            bad_patterns_count) % bad_patterns)
3262
3190
            ui.ui_factory.show_error(msg)
3263
3191
            raise lazy_regex.InvalidPattern('')
3264
3192
        for name_pattern in name_pattern_list:
3265
3193
            if (name_pattern[0] == '/' or
3266
 
                    (len(name_pattern) > 1 and name_pattern[1] == ':')):
 
3194
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
3267
3195
                raise errors.BzrCommandError(gettext(
3268
3196
                    "NAME_PATTERN should not be an absolute path"))
3269
3197
        tree, relpath = WorkingTree.open_containing(directory)
3270
3198
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
3271
3199
        ignored = globbing.Globster(name_pattern_list)
3272
3200
        matches = []
3273
 
        self.enter_context(tree.lock_read())
3274
 
        for filename, fc, fkind, entry in tree.list_files():
3275
 
            id = getattr(entry, 'file_id', None)
 
3201
        self.add_cleanup(tree.lock_read().unlock)
 
3202
        for entry in tree.list_files():
 
3203
            id = entry[3]
3276
3204
            if id is not None:
 
3205
                filename = entry[0]
3277
3206
                if ignored.match(filename):
3278
3207
                    matches.append(filename)
3279
3208
        if len(matches) > 0:
3280
3209
            self.outf.write(gettext("Warning: the following files are version "
3281
 
                                    "controlled and match your ignore pattern:\n%s"
3282
 
                                    "\nThese files will continue to be version controlled"
3283
 
                                    " unless you 'brz remove' them.\n") % ("\n".join(matches),))
 
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),))
3284
3213
 
3285
3214
 
3286
3215
class cmd_ignored(Command):
3301
3230
    @display_command
3302
3231
    def run(self, directory=u'.'):
3303
3232
        tree = WorkingTree.open_containing(directory)[0]
3304
 
        self.enter_context(tree.lock_read())
3305
 
        for path, file_class, kind, entry in tree.list_files():
 
3233
        self.add_cleanup(tree.lock_read().unlock)
 
3234
        for path, file_class, kind, file_id, entry in tree.list_files():
3306
3235
            if file_class != 'I':
3307
3236
                continue
3308
 
            # XXX: Slightly inefficient since this was already calculated
 
3237
            ## XXX: Slightly inefficient since this was already calculated
3309
3238
            pat = tree.is_ignored(path)
3310
3239
            self.outf.write('%-50s %s\n' % (path, pat))
3311
3240
 
3327
3256
        except ValueError:
3328
3257
            raise errors.BzrCommandError(gettext("not a valid revision-number: %r")
3329
3258
                                         % revno)
3330
 
        revid = WorkingTree.open_containing(
3331
 
            directory)[0].branch.get_rev_id(revno)
3332
 
        self.outf.write("%s\n" % revid.decode('utf-8'))
 
3259
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
 
3260
        self.outf.write("%s\n" % revid)
3333
3261
 
3334
3262
 
3335
3263
class cmd_export(Command):
3361
3289
      =================       =========================
3362
3290
    """
3363
3291
    encoding = 'exact'
3364
 
    encoding_type = 'exact'
3365
3292
    takes_args = ['dest', 'branch_or_subdir?']
3366
3293
    takes_options = ['directory',
3367
 
                     Option('format',
3368
 
                            help="Type of file to export to.",
3369
 
                            type=text_type),
3370
 
                     'revision',
3371
 
                     Option('filters', help='Apply content filters to export the '
3372
 
                            'convenient form.'),
3373
 
                     Option('root',
3374
 
                            type=text_type,
3375
 
                            help="Name of the root directory inside the exported file."),
3376
 
                     Option('per-file-timestamps',
3377
 
                            help='Set modification time of files to that of the last '
3378
 
                            'revision in which it was changed.'),
3379
 
                     Option('uncommitted',
3380
 
                            help='Export the working tree contents rather than that of the '
3381
 
                            'last revision.'),
3382
 
                     ]
3383
 
 
 
3294
        Option('format',
 
3295
               help="Type of file to export to.",
 
3296
               type=text_type),
 
3297
        'revision',
 
3298
        Option('filters', help='Apply content filters to export the '
 
3299
                'convenient form.'),
 
3300
        Option('root',
 
3301
               type=text_type,
 
3302
               help="Name of the root directory inside the exported file."),
 
3303
        Option('per-file-timestamps',
 
3304
               help='Set modification time of files to that of the last '
 
3305
                    'revision in which it was changed.'),
 
3306
        Option('uncommitted',
 
3307
               help='Export the working tree contents rather than that of the '
 
3308
                    'last revision.'),
 
3309
        ]
3384
3310
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
3385
 
            root=None, filters=False, per_file_timestamps=False, uncommitted=False,
3386
 
            directory=u'.'):
3387
 
        from .export import export, guess_format, get_root_name
 
3311
        root=None, filters=False, per_file_timestamps=False, uncommitted=False,
 
3312
        directory=u'.'):
 
3313
        from .export import export
3388
3314
 
3389
3315
        if branch_or_subdir is None:
3390
3316
            branch_or_subdir = directory
3392
3318
        (tree, b, subdir) = controldir.ControlDir.open_containing_tree_or_branch(
3393
3319
            branch_or_subdir)
3394
3320
        if tree is not None:
3395
 
            self.enter_context(tree.lock_read())
 
3321
            self.add_cleanup(tree.lock_read().unlock)
3396
3322
 
3397
3323
        if uncommitted:
3398
3324
            if tree is None:
3400
3326
                    gettext("--uncommitted requires a working tree"))
3401
3327
            export_tree = tree
3402
3328
        else:
3403
 
            export_tree = _get_one_revision_tree(
3404
 
                'export', revision, branch=b,
3405
 
                tree=tree)
3406
 
 
3407
 
        if format is None:
3408
 
            format = guess_format(dest)
3409
 
 
3410
 
        if root is None:
3411
 
            root = get_root_name(dest)
3412
 
 
3413
 
        if not per_file_timestamps:
3414
 
            force_mtime = time.time()
3415
 
        else:
3416
 
            force_mtime = None
3417
 
 
3418
 
        if filters:
3419
 
            from breezy.filter_tree import ContentFilterTree
3420
 
            export_tree = ContentFilterTree(
3421
 
                export_tree, export_tree._content_filter_stack)
3422
 
 
 
3329
            export_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
3423
3330
        try:
3424
 
            export(export_tree, dest, format, root, subdir,
 
3331
            export(export_tree, dest, format, root, subdir, filtered=filters,
3425
3332
                   per_file_timestamps=per_file_timestamps)
3426
3333
        except errors.NoSuchExportFormat as e:
3427
3334
            raise errors.BzrCommandError(
3439
3346
 
3440
3347
    _see_also = ['ls']
3441
3348
    takes_options = ['directory',
3442
 
                     Option('name-from-revision',
3443
 
                            help='The path name in the old tree.'),
3444
 
                     Option('filters', help='Apply content filters to display the '
3445
 
                            'convenience form.'),
3446
 
                     'revision',
3447
 
                     ]
 
3349
        Option('name-from-revision', help='The path name in the old tree.'),
 
3350
        Option('filters', help='Apply content filters to display the '
 
3351
                'convenience form.'),
 
3352
        'revision',
 
3353
        ]
3448
3354
    takes_args = ['filename']
3449
3355
    encoding_type = 'exact'
3450
3356
 
3453
3359
            filters=False, directory=None):
3454
3360
        if revision is not None and len(revision) != 1:
3455
3361
            raise errors.BzrCommandError(gettext("brz cat --revision takes exactly"
3456
 
                                                 " one revision specifier"))
 
3362
                                         " one revision specifier"))
3457
3363
        tree, branch, relpath = \
3458
3364
            _open_directory_or_containing_tree_or_branch(filename, directory)
3459
 
        self.enter_context(branch.lock_read())
 
3365
        self.add_cleanup(branch.lock_read().unlock)
3460
3366
        return self._run(tree, branch, relpath, filename, revision,
3461
3367
                         name_from_revision, filters)
3462
3368
 
3463
3369
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
3464
 
             filtered):
3465
 
        import shutil
 
3370
        filtered):
3466
3371
        if tree is None:
3467
3372
            tree = b.basis_tree()
3468
3373
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
3469
 
        self.enter_context(rev_tree.lock_read())
3470
 
 
 
3374
        self.add_cleanup(rev_tree.lock_read().unlock)
 
3375
 
 
3376
        old_file_id = rev_tree.path2id(relpath)
 
3377
 
 
3378
        # TODO: Split out this code to something that generically finds the
 
3379
        # best id for a path across one or more trees; it's like
 
3380
        # find_ids_across_trees but restricted to find just one. -- mbp
 
3381
        # 20110705.
3471
3382
        if name_from_revision:
3472
3383
            # Try in revision if requested
3473
 
            if not rev_tree.is_versioned(relpath):
 
3384
            if old_file_id is None:
3474
3385
                raise errors.BzrCommandError(gettext(
3475
3386
                    "{0!r} is not present in revision {1}").format(
3476
3387
                        filename, rev_tree.get_revision_id()))
3477
 
            rev_tree_path = relpath
 
3388
            else:
 
3389
                actual_file_id = old_file_id
3478
3390
        else:
3479
 
            try:
3480
 
                rev_tree_path = _mod_tree.find_previous_path(
3481
 
                    tree, rev_tree, relpath)
3482
 
            except errors.NoSuchFile:
3483
 
                rev_tree_path = None
3484
 
 
3485
 
            if rev_tree_path is None:
3486
 
                # Path didn't exist in working tree
3487
 
                if not rev_tree.is_versioned(relpath):
3488
 
                    raise errors.BzrCommandError(gettext(
3489
 
                        "{0!r} is not present in revision {1}").format(
3490
 
                            filename, rev_tree.get_revision_id()))
3491
 
                else:
3492
 
                    # Fall back to the same path in the basis tree, if present.
3493
 
                    rev_tree_path = relpath
3494
 
 
 
3391
            cur_file_id = tree.path2id(relpath)
 
3392
            if cur_file_id is not None and rev_tree.has_id(cur_file_id):
 
3393
                actual_file_id = cur_file_id
 
3394
            elif old_file_id is not None:
 
3395
                actual_file_id = old_file_id
 
3396
            else:
 
3397
                raise errors.BzrCommandError(gettext(
 
3398
                    "{0!r} is not present in revision {1}").format(
 
3399
                        filename, rev_tree.get_revision_id()))
 
3400
        relpath = rev_tree.id2path(actual_file_id)
3495
3401
        if filtered:
3496
3402
            from .filter_tree import ContentFilterTree
3497
 
            filter_tree = ContentFilterTree(
3498
 
                rev_tree, rev_tree._content_filter_stack)
3499
 
            fileobj = filter_tree.get_file(rev_tree_path)
 
3403
            filter_tree = ContentFilterTree(rev_tree,
 
3404
                rev_tree._content_filter_stack)
 
3405
            content = filter_tree.get_file_text(relpath, actual_file_id)
3500
3406
        else:
3501
 
            fileobj = rev_tree.get_file(rev_tree_path)
3502
 
        shutil.copyfileobj(fileobj, self.outf)
 
3407
            content = rev_tree.get_file_text(relpath, actual_file_id)
3503
3408
        self.cleanup_now()
 
3409
        self.outf.write(content)
3504
3410
 
3505
3411
 
3506
3412
class cmd_local_time_offset(Command):
3507
3413
    __doc__ = """Show the offset in seconds from GMT to local time."""
3508
3414
    hidden = True
3509
 
 
3510
3415
    @display_command
3511
3416
    def run(self):
3512
3417
        self.outf.write("%s\n" % osutils.local_time_offset())
3513
3418
 
3514
3419
 
 
3420
 
3515
3421
class cmd_commit(Command):
3516
3422
    __doc__ = """Commit changes into a new revision.
3517
3423
 
3531
3437
      If selected files are specified, only changes to those files are
3532
3438
      committed.  If a directory is specified then the directory and
3533
3439
      everything within it is committed.
3534
 
 
 
3440
  
3535
3441
      When excludes are given, they take precedence over selected files.
3536
3442
      For example, to commit only changes within foo, but not changes
3537
3443
      within foo/bar::
3538
 
 
 
3444
  
3539
3445
        brz commit foo -x foo/bar
3540
 
 
 
3446
  
3541
3447
      A selective commit after a merge is not yet supported.
3542
3448
 
3543
3449
    :Custom authors:
3548
3454
      "John Doe <jdoe@example.com>". If there is more than one author of
3549
3455
      the change you can specify the option multiple times, once for each
3550
3456
      author.
3551
 
 
 
3457
  
3552
3458
    :Checks:
3553
3459
 
3554
3460
      A common mistake is to forget to add a new file or directory before
3559
3465
 
3560
3466
    :Things to note:
3561
3467
 
3562
 
      If you accidentally commit the wrong changes or make a spelling
 
3468
      If you accidentially commit the wrong changes or make a spelling
3563
3469
      mistake in the commit message say, you can use the uncommit command
3564
3470
      to undo it. See ``brz help uncommit`` for details.
3565
3471
 
3572
3478
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
3573
3479
    takes_args = ['selected*']
3574
3480
    takes_options = [
3575
 
        ListOption(
3576
 
            'exclude', type=text_type, short_name='x',
3577
 
            help="Do not consider changes made to a given path."),
3578
 
        Option('message', type=text_type,
3579
 
               short_name='m',
3580
 
               help="Description of the new revision."),
3581
 
        'verbose',
3582
 
        Option('unchanged',
3583
 
               help='Commit even if nothing has changed.'),
3584
 
        Option('file', type=text_type,
3585
 
               short_name='F',
3586
 
               argname='msgfile',
3587
 
               help='Take commit message from this file.'),
3588
 
        Option('strict',
3589
 
               help="Refuse to commit if there are unknown "
3590
 
               "files in the working tree."),
3591
 
        Option('commit-time', type=text_type,
3592
 
               help="Manually set a commit time using commit date "
3593
 
               "format, e.g. '2009-10-10 08:00:00 +0100'."),
3594
 
        ListOption(
3595
 
            'bugs', type=text_type,
3596
 
            help="Link to a related bug. (see \"brz help bugs\")."),
3597
 
        ListOption(
3598
 
            'fixes', type=text_type,
3599
 
            help="Mark a bug as being fixed by this revision "
3600
 
                 "(see \"brz help bugs\")."),
3601
 
        ListOption(
3602
 
            'author', type=text_type,
3603
 
            help="Set the author's name, if it's different "
3604
 
                 "from the committer."),
3605
 
        Option('local',
3606
 
               help="Perform a local commit in a bound "
3607
 
                    "branch.  Local commits are not pushed to "
3608
 
                    "the master branch until a normal commit "
3609
 
                    "is performed."
3610
 
               ),
3611
 
        Option('show-diff', short_name='p',
3612
 
               help='When no message is supplied, show the diff along'
3613
 
               ' with the status summary in the message editor.'),
3614
 
        Option('lossy',
3615
 
               help='When committing to a foreign version control '
3616
 
               'system do not push data that can not be natively '
3617
 
               'represented.'), ]
 
3481
            ListOption('exclude', type=text_type, short_name='x',
 
3482
                help="Do not consider changes made to a given path."),
 
3483
            Option('message', type=text_type,
 
3484
                   short_name='m',
 
3485
                   help="Description of the new revision."),
 
3486
            'verbose',
 
3487
             Option('unchanged',
 
3488
                    help='Commit even if nothing has changed.'),
 
3489
             Option('file', type=text_type,
 
3490
                    short_name='F',
 
3491
                    argname='msgfile',
 
3492
                    help='Take commit message from this file.'),
 
3493
             Option('strict',
 
3494
                    help="Refuse to commit if there are unknown "
 
3495
                    "files in the working tree."),
 
3496
             Option('commit-time', type=text_type,
 
3497
                    help="Manually set a commit time using commit date "
 
3498
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
 
3499
             ListOption('fixes', type=text_type,
 
3500
                    help="Mark a bug as being fixed by this revision "
 
3501
                         "(see \"brz help bugs\")."),
 
3502
             ListOption('author', type=text_type,
 
3503
                    help="Set the author's name, if it's different "
 
3504
                         "from the committer."),
 
3505
             Option('local',
 
3506
                    help="Perform a local commit in a bound "
 
3507
                         "branch.  Local commits are not pushed to "
 
3508
                         "the master branch until a normal commit "
 
3509
                         "is performed."
 
3510
                    ),
 
3511
             Option('show-diff', short_name='p',
 
3512
                    help='When no message is supplied, show the diff along'
 
3513
                    ' with the status summary in the message editor.'),
 
3514
             Option('lossy', 
 
3515
                    help='When committing to a foreign version control '
 
3516
                    'system do not push data that can not be natively '
 
3517
                    'represented.'),
 
3518
             ]
3618
3519
    aliases = ['ci', 'checkin']
3619
3520
 
3620
 
    def _iter_bug_urls(self, bugs, branch, status):
3621
 
        default_bugtracker = None
 
3521
    def _iter_bug_fix_urls(self, fixes, branch):
 
3522
        default_bugtracker  = None
3622
3523
        # Configure the properties for bug fixing attributes.
3623
 
        for bug in bugs:
3624
 
            tokens = bug.split(':')
 
3524
        for fixed_bug in fixes:
 
3525
            tokens = fixed_bug.split(':')
3625
3526
            if len(tokens) == 1:
3626
3527
                if default_bugtracker is None:
3627
3528
                    branch_config = branch.get_config_stack()
3633
3534
                        "'tracker:id' or specify a default bug tracker "
3634
3535
                        "using the `bugtracker` option.\nSee "
3635
3536
                        "\"brz help bugs\" for more information on this "
3636
 
                        "feature. Commit refused.") % bug)
 
3537
                        "feature. Commit refused.") % fixed_bug)
3637
3538
                tag = default_bugtracker
3638
3539
                bug_id = tokens[0]
3639
3540
            elif len(tokens) != 2:
3640
3541
                raise errors.BzrCommandError(gettext(
3641
3542
                    "Invalid bug %s. Must be in the form of 'tracker:id'. "
3642
3543
                    "See \"brz help bugs\" for more information on this "
3643
 
                    "feature.\nCommit refused.") % bug)
 
3544
                    "feature.\nCommit refused.") % fixed_bug)
3644
3545
            else:
3645
3546
                tag, bug_id = tokens
3646
3547
            try:
3647
 
                yield bugtracker.get_bug_url(tag, branch, bug_id), status
 
3548
                yield bugtracker.get_bug_url(tag, branch, bug_id)
3648
3549
            except bugtracker.UnknownBugTrackerAbbreviation:
3649
3550
                raise errors.BzrCommandError(gettext(
3650
 
                    'Unrecognized bug %s. Commit refused.') % bug)
 
3551
                    'Unrecognized bug %s. Commit refused.') % fixed_bug)
3651
3552
            except bugtracker.MalformedBugIdentifier as e:
3652
3553
                raise errors.BzrCommandError(gettext(
3653
3554
                    u"%s\nCommit refused.") % (e,))
3654
3555
 
3655
3556
    def run(self, message=None, file=None, verbose=False, selected_list=None,
3656
 
            unchanged=False, strict=False, local=False, fixes=None, bugs=None,
 
3557
            unchanged=False, strict=False, local=False, fixes=None,
3657
3558
            author=None, show_diff=False, exclude=None, commit_time=None,
3658
3559
            lossy=False):
3659
 
        import itertools
3660
3560
        from .commit import (
3661
3561
            PointlessCommit,
3662
3562
            )
3690
3590
 
3691
3591
        if fixes is None:
3692
3592
            fixes = []
3693
 
        if bugs is None:
3694
 
            bugs = []
3695
3593
        bug_property = bugtracker.encode_fixes_bug_urls(
3696
 
            itertools.chain(
3697
 
                self._iter_bug_urls(bugs, tree.branch, bugtracker.RELATED),
3698
 
                self._iter_bug_urls(fixes, tree.branch, bugtracker.FIXED)))
 
3594
            self._iter_bug_fix_urls(fixes, tree.branch))
3699
3595
        if bug_property:
3700
 
            properties[u'bugs'] = bug_property
 
3596
            properties['bugs'] = bug_property
3701
3597
 
3702
3598
        if local and not tree.branch.get_bound_location():
3703
3599
            raise errors.LocalRequiresBoundBranch()
3714
3610
                warning_msg = (
3715
3611
                    'The commit message is a file name: "%(f)s".\n'
3716
3612
                    '(use --file "%(f)s" to take commit message from that file)'
3717
 
                    % {'f': message})
 
3613
                    % { 'f': message })
3718
3614
                ui.ui_factory.show_warning(warning_msg)
3719
3615
            if '\r' in message:
3720
3616
                message = message.replace('\r\n', '\n')
3726
3622
        def get_message(commit_obj):
3727
3623
            """Callback to get commit message"""
3728
3624
            if file:
3729
 
                with open(file, 'rb') as f:
 
3625
                with open(file) as f:
3730
3626
                    my_message = f.read().decode(osutils.get_user_encoding())
3731
3627
            elif message is not None:
3732
3628
                my_message = message
3734
3630
                # No message supplied: make one up.
3735
3631
                # text is the status of the tree
3736
3632
                text = make_commit_message_template_encoded(tree,
3737
 
                                                            selected_list, diff=show_diff,
3738
 
                                                            output_encoding=osutils.get_user_encoding())
 
3633
                        selected_list, diff=show_diff,
 
3634
                        output_encoding=osutils.get_user_encoding())
3739
3635
                # start_message is the template generated from hooks
3740
3636
                # XXX: Warning - looks like hooks return unicode,
3741
3637
                # make_commit_message_template_encoded returns user encoding.
3743
3639
                # avoid this.
3744
3640
                my_message = set_commit_message(commit_obj)
3745
3641
                if my_message is None:
3746
 
                    start_message = generate_commit_message_template(
3747
 
                        commit_obj)
3748
 
                    if start_message is not None:
3749
 
                        start_message = start_message.encode(
3750
 
                            osutils.get_user_encoding())
 
3642
                    start_message = generate_commit_message_template(commit_obj)
3751
3643
                    my_message = edit_commit_message_encoded(text,
3752
 
                                                             start_message=start_message)
 
3644
                        start_message=start_message)
3753
3645
                if my_message is None:
3754
3646
                    raise errors.BzrCommandError(gettext("please specify a commit"
3755
 
                                                         " message with either --message or --file"))
 
3647
                        " message with either --message or --file"))
3756
3648
                if my_message == "":
3757
3649
                    raise errors.BzrCommandError(gettext("Empty commit message specified."
3758
 
                                                         " Please specify a commit message with either"
3759
 
                                                         " --message or --file or leave a blank message"
3760
 
                                                         " with --message \"\"."))
 
3650
                            " Please specify a commit message with either"
 
3651
                            " --message or --file or leave a blank message"
 
3652
                            " with --message \"\"."))
3761
3653
            return my_message
3762
3654
 
3763
3655
        # The API permits a commit with a filter of [] to mean 'select nothing'
3775
3667
                        lossy=lossy)
3776
3668
        except PointlessCommit:
3777
3669
            raise errors.BzrCommandError(gettext("No changes to commit."
3778
 
                                                 " Please 'brz add' the files you want to commit, or use"
3779
 
                                                 " --unchanged to force an empty commit."))
 
3670
                " Please 'brz add' the files you want to commit, or use"
 
3671
                " --unchanged to force an empty commit."))
3780
3672
        except ConflictsInTree:
3781
3673
            raise errors.BzrCommandError(gettext('Conflicts detected in working '
3782
 
                                                 'tree.  Use "brz conflicts" to list, "brz resolve FILE" to'
3783
 
                                                 ' resolve.'))
 
3674
                'tree.  Use "brz conflicts" to list, "brz resolve FILE" to'
 
3675
                ' resolve.'))
3784
3676
        except StrictCommitFailed:
3785
3677
            raise errors.BzrCommandError(gettext("Commit refused because there are"
3786
 
                                                 " unknown files in the working tree."))
 
3678
                              " unknown files in the working tree."))
3787
3679
        except errors.BoundBranchOutOfDate as e:
3788
3680
            e.extra_help = (gettext("\n"
3789
 
                                    'To commit to master branch, run update and then commit.\n'
3790
 
                                    'You can also pass --local to commit to continue working '
3791
 
                                    'disconnected.'))
 
3681
                'To commit to master branch, run update and then commit.\n'
 
3682
                'You can also pass --local to commit to continue working '
 
3683
                'disconnected.'))
3792
3684
            raise
3793
3685
 
3794
3686
 
3812
3704
    unreferenced ancestors
3813
3705
        Texts that are ancestors of other texts, but
3814
3706
        are not properly referenced by the revision ancestry.  This is a
3815
 
        subtle problem that Breezy can work around.
 
3707
        subtle problem that Bazaar can work around.
3816
3708
 
3817
3709
    unique file texts
3818
3710
        This is the total number of unique file contents
3824
3716
        entries are modified, but the file contents are not.  It does not
3825
3717
        indicate a problem.
3826
3718
 
3827
 
    If no restrictions are specified, all data that is found at the given
 
3719
    If no restrictions are specified, all Bazaar data that is found at the given
3828
3720
    location will be checked.
3829
3721
 
3830
3722
    :Examples:
3866
3758
    __doc__ = """Upgrade a repository, branch or working tree to a newer format.
3867
3759
 
3868
3760
    When the default format has changed after a major new release of
3869
 
    Bazaar/Breezy, you may be informed during certain operations that you
 
3761
    Bazaar, you may be informed during certain operations that you
3870
3762
    should upgrade. Upgrading to a newer format may improve performance
3871
3763
    or make new features available. It may however limit interoperability
3872
 
    with older repositories or with older versions of Bazaar or Breezy.
 
3764
    with older repositories or with older versions of Bazaar.
3873
3765
 
3874
3766
    If you wish to upgrade to a particular format rather than the
3875
3767
    current default, that can be specified using the --format option.
3891
3783
    If the conversion of a branch fails, remaining branches are still
3892
3784
    tried.
3893
3785
 
3894
 
    For more information on upgrades, see the Breezy Upgrade Guide,
3895
 
    https://www.breezy-vcs.org/doc/en/upgrade-guide/.
 
3786
    For more information on upgrades, see the Bazaar Upgrade Guide,
 
3787
    http://doc.bazaar.canonical.com/latest/en/upgrade-guide/.
3896
3788
    """
3897
3789
 
3898
3790
    _see_also = ['check', 'reconcile', 'formats']
3899
3791
    takes_args = ['url?']
3900
3792
    takes_options = [
3901
3793
        RegistryOption('format',
3902
 
                       help='Upgrade to a specific format.  See "brz help'
3903
 
                       ' formats" for details.',
3904
 
                       lazy_registry=('breezy.controldir', 'format_registry'),
3905
 
                       converter=lambda name: controldir.format_registry.make_controldir(
3906
 
                           name),
3907
 
                       value_switches=True, title='Branch format'),
 
3794
            help='Upgrade to a specific format.  See "brz help'
 
3795
                 ' formats" for details.',
 
3796
            lazy_registry=('breezy.controldir', 'format_registry'),
 
3797
            converter=lambda name: controldir.format_registry.make_controldir(name),
 
3798
            value_switches=True, title='Branch format'),
3908
3799
        Option('clean',
3909
 
               help='Remove the backup.bzr directory if successful.'),
 
3800
            help='Remove the backup.bzr directory if successful.'),
3910
3801
        Option('dry-run',
3911
 
               help="Show what would be done, but don't actually do anything."),
 
3802
            help="Show what would be done, but don't actually do anything."),
3912
3803
    ]
3913
3804
 
3914
3805
    def run(self, url='.', format=None, clean=False, dry_run=False):
3934
3825
 
3935
3826
            brz whoami "Frank Chu <fchu@example.com>"
3936
3827
    """
3937
 
    takes_options = ['directory',
3938
 
                     Option('email',
3939
 
                            help='Display email address only.'),
3940
 
                     Option('branch',
3941
 
                            help='Set identity for the current branch instead of '
3942
 
                            'globally.'),
3943
 
                     ]
 
3828
    takes_options = [ 'directory',
 
3829
                      Option('email',
 
3830
                             help='Display email address only.'),
 
3831
                      Option('branch',
 
3832
                             help='Set identity for the current branch instead of '
 
3833
                                  'globally.'),
 
3834
                    ]
3944
3835
    takes_args = ['name?']
3945
3836
    encoding_type = 'replace'
3946
3837
 
3965
3856
 
3966
3857
        if email:
3967
3858
            raise errors.BzrCommandError(gettext("--email can only be used to display existing "
3968
 
                                                 "identity"))
 
3859
                                         "identity"))
3969
3860
 
3970
3861
        # display a warning if an email address isn't included in the given name.
3971
3862
        try:
3972
3863
            _mod_config.extract_email_address(name)
3973
 
        except _mod_config.NoEmailInUsername:
 
3864
        except _mod_config.NoEmailInUsername as e:
3974
3865
            warning('"%s" does not seem to contain an email address.  '
3975
3866
                    'This is allowed, but not recommended.', name)
3976
3867
 
3980
3871
                c = Branch.open_containing(u'.')[0].get_config_stack()
3981
3872
            else:
3982
3873
                b = Branch.open(directory)
3983
 
                self.enter_context(b.lock_write())
 
3874
                self.add_cleanup(b.lock_write().unlock)
3984
3875
                c = b.get_config_stack()
3985
3876
        else:
3986
3877
            c = _mod_config.GlobalStack()
4001
3892
    _see_also = ['info']
4002
3893
    takes_args = ['nickname?']
4003
3894
    takes_options = ['directory']
4004
 
 
4005
3895
    def run(self, nickname=None, directory=u'.'):
4006
3896
        branch = Branch.open_containing(directory)[0]
4007
3897
        if nickname is None:
4050
3940
            if equal_pos == -1:
4051
3941
                self.print_alias(name)
4052
3942
            else:
4053
 
                self.set_alias(name[:equal_pos], name[equal_pos + 1:])
 
3943
                self.set_alias(name[:equal_pos], name[equal_pos+1:])
4054
3944
 
4055
3945
    def remove_alias(self, alias_name):
4056
3946
        if alias_name is None:
4135
4025
    """
4136
4026
    # NB: this is used from the class without creating an instance, which is
4137
4027
    # why it does not have a self parameter.
4138
 
 
4139
4028
    def get_transport_type(typestring):
4140
4029
        """Parse and return a transport specifier."""
4141
4030
        if typestring == "sftp":
4155
4044
    takes_args = ['testspecs*']
4156
4045
    takes_options = ['verbose',
4157
4046
                     Option('one',
4158
 
                            help='Stop when one test fails.',
4159
 
                            short_name='1',
4160
 
                            ),
 
4047
                             help='Stop when one test fails.',
 
4048
                             short_name='1',
 
4049
                             ),
4161
4050
                     Option('transport',
4162
4051
                            help='Use a different transport by default '
4163
4052
                                 'throughout the test suite.',
4177
4066
                     Option('list-only',
4178
4067
                            help='List the tests instead of running them.'),
4179
4068
                     RegistryOption('parallel',
4180
 
                                    help="Run the test suite in parallel.",
4181
 
                                    lazy_registry=(
4182
 
                                        'breezy.tests', 'parallel_registry'),
4183
 
                                    value_switches=False,
4184
 
                                    ),
 
4069
                        help="Run the test suite in parallel.",
 
4070
                        lazy_registry=('breezy.tests', 'parallel_registry'),
 
4071
                        value_switches=False,
 
4072
                        ),
4185
4073
                     Option('randomize', type=text_type, argname="SEED",
4186
4074
                            help='Randomize the order of tests using the given'
4187
4075
                                 ' seed or "now" for the current time.'),
4201
4089
                                help='Turn on a selftest debug flag.'),
4202
4090
                     ListOption('starting-with', type=text_type, argname='TESTID',
4203
4091
                                param_name='starting_with', short_name='s',
4204
 
                                help='Load only the tests starting with TESTID.'),
 
4092
                                help=
 
4093
                                'Load only the tests starting with TESTID.'),
4205
4094
                     Option('sync',
4206
4095
                            help="By default we disable fsync and fdatasync"
4207
4096
                                 " while running the test suite.")
4235
4124
            from . import tests
4236
4125
        except ImportError:
4237
4126
            raise errors.BzrCommandError("tests not available. Install the "
4238
 
                                         "breezy tests to run the breezy testsuite.")
 
4127
                "breezy tests to run the breezy testsuite.")
4239
4128
 
4240
4129
        if testspecs_list is not None:
4241
4130
            pattern = '|'.join(testspecs_list)
4250
4139
                    "to use --subunit."))
4251
4140
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunnerv1
4252
4141
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
4253
 
            # stdout, which would corrupt the subunit stream.
 
4142
            # stdout, which would corrupt the subunit stream. 
4254
4143
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
4255
4144
            # following code can be deleted when it's sufficiently deployed
4256
4145
            # -- vila/mgz 20100514
4257
4146
            if (sys.platform == "win32"
4258
 
                    and getattr(sys.stdout, 'fileno', None) is not None):
 
4147
                and getattr(sys.stdout, 'fileno', None) is not None):
4259
4148
                import msvcrt
4260
4149
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
4261
4150
        if subunit2:
4282
4171
        if not sync:
4283
4172
            self._disable_fsync()
4284
4173
        selftest_kwargs = {"verbose": verbose,
4285
 
                           "pattern": pattern,
4286
 
                           "stop_on_failure": one,
4287
 
                           "transport": transport,
4288
 
                           "test_suite_factory": test_suite_factory,
4289
 
                           "lsprof_timed": lsprof_timed,
4290
 
                           "lsprof_tests": lsprof_tests,
4291
 
                           "matching_tests_first": first,
4292
 
                           "list_only": list_only,
4293
 
                           "random_seed": randomize,
4294
 
                           "exclude_pattern": exclude_pattern,
4295
 
                           "strict": strict,
4296
 
                           "load_list": load_list,
4297
 
                           "debug_flags": debugflag,
4298
 
                           "starting_with": starting_with
4299
 
                           }
 
4174
                          "pattern": pattern,
 
4175
                          "stop_on_failure": one,
 
4176
                          "transport": transport,
 
4177
                          "test_suite_factory": test_suite_factory,
 
4178
                          "lsprof_timed": lsprof_timed,
 
4179
                          "lsprof_tests": lsprof_tests,
 
4180
                          "matching_tests_first": first,
 
4181
                          "list_only": list_only,
 
4182
                          "random_seed": randomize,
 
4183
                          "exclude_pattern": exclude_pattern,
 
4184
                          "strict": strict,
 
4185
                          "load_list": load_list,
 
4186
                          "debug_flags": debugflag,
 
4187
                          "starting_with": starting_with
 
4188
                          }
4300
4189
        selftest_kwargs.update(self.additional_selftest_args)
4301
4190
 
4302
4191
        # Make deprecation warnings visible, unless -Werror is set
4358
4247
 
4359
4248
        branch1 = Branch.open_containing(branch)[0]
4360
4249
        branch2 = Branch.open_containing(other)[0]
4361
 
        self.enter_context(branch1.lock_read())
4362
 
        self.enter_context(branch2.lock_read())
 
4250
        self.add_cleanup(branch1.lock_read().unlock)
 
4251
        self.add_cleanup(branch2.lock_read().unlock)
4363
4252
        last1 = ensure_null(branch1.last_revision())
4364
4253
        last2 = ensure_null(branch2.last_revision())
4365
4254
 
4366
4255
        graph = branch1.repository.get_graph(branch2.repository)
4367
4256
        base_rev_id = graph.find_unique_lca(last1, last2)
4368
4257
 
4369
 
        self.outf.write(gettext('merge base is revision %s\n') %
4370
 
                        base_rev_id.decode('utf-8'))
 
4258
        self.outf.write(gettext('merge base is revision %s\n') % base_rev_id)
4371
4259
 
4372
4260
 
4373
4261
class cmd_merge(Command):
4392
4280
    through OTHER, excluding BASE but including OTHER, will be merged.  If this
4393
4281
    causes some revisions to be skipped, i.e. if the destination branch does
4394
4282
    not already contain revision BASE, such a merge is commonly referred to as
4395
 
    a "cherrypick". Unlike a normal merge, Breezy does not currently track
 
4283
    a "cherrypick". Unlike a normal merge, Bazaar does not currently track
4396
4284
    cherrypicks. The changes look like a normal commit, and the history of the
4397
4285
    changes from the other branch is not stored in the commit.
4398
4286
 
4468
4356
        Option('uncommitted', help='Apply uncommitted changes'
4469
4357
               ' from a working copy, instead of branch changes.'),
4470
4358
        Option('pull', help='If the destination is already'
4471
 
               ' completely merged into the source, pull from the'
4472
 
               ' source rather than merging.  When this happens,'
4473
 
               ' you do not need to commit the result.'),
 
4359
                ' completely merged into the source, pull from the'
 
4360
                ' source rather than merging.  When this happens,'
 
4361
                ' you do not need to commit the result.'),
4474
4362
        custom_help('directory',
4475
 
                    help='Branch to merge into, '
 
4363
               help='Branch to merge into, '
4476
4364
                    'rather than the one containing the working directory.'),
4477
4365
        Option('preview', help='Instead of merging, show a diff of the'
4478
4366
               ' merge.'),
4479
4367
        Option('interactive', help='Select changes interactively.',
4480
 
               short_name='i')
 
4368
            short_name='i')
4481
4369
    ]
4482
4370
 
4483
4371
    def run(self, location=None, revision=None, force=False,
4490
4378
        if merge_type is None:
4491
4379
            merge_type = _mod_merge.Merge3Merger
4492
4380
 
4493
 
        if directory is None:
4494
 
            directory = u'.'
 
4381
        if directory is None: directory = u'.'
4495
4382
        possible_transports = []
4496
4383
        merger = None
4497
4384
        allow_pending = True
4498
4385
        verified = 'inapplicable'
4499
4386
 
4500
4387
        tree = WorkingTree.open_containing(directory)[0]
4501
 
        if tree.branch.last_revision() == _mod_revision.NULL_REVISION:
 
4388
        if tree.branch.revno() == 0:
4502
4389
            raise errors.BzrCommandError(gettext('Merging into empty branches not currently supported, '
4503
 
                                                 'https://bugs.launchpad.net/bzr/+bug/308562'))
 
4390
                                         'https://bugs.launchpad.net/bzr/+bug/308562'))
 
4391
 
 
4392
        try:
 
4393
            basis_tree = tree.revision_tree(tree.last_revision())
 
4394
        except errors.NoSuchRevision:
 
4395
            basis_tree = tree.basis_tree()
4504
4396
 
4505
4397
        # die as quickly as possible if there are uncommitted changes
4506
4398
        if not force:
4511
4403
        change_reporter = delta._ChangeReporter(
4512
4404
            unversioned_filter=tree.is_ignored, view_info=view_info)
4513
4405
        pb = ui.ui_factory.nested_progress_bar()
4514
 
        self.enter_context(pb)
4515
 
        self.enter_context(tree.lock_write())
 
4406
        self.add_cleanup(pb.finished)
 
4407
        self.add_cleanup(tree.lock_write().unlock)
4516
4408
        if location is not None:
4517
4409
            try:
4518
 
                mergeable = _mod_mergeable.read_mergeable_from_url(
4519
 
                    location, possible_transports=possible_transports)
 
4410
                mergeable = bundle.read_mergeable_from_url(location,
 
4411
                    possible_transports=possible_transports)
4520
4412
            except errors.NotABundle:
4521
4413
                mergeable = None
4522
4414
            else:
4523
4415
                if uncommitted:
4524
4416
                    raise errors.BzrCommandError(gettext('Cannot use --uncommitted'
4525
 
                                                         ' with bundles or merge directives.'))
 
4417
                        ' with bundles or merge directives.'))
4526
4418
 
4527
4419
                if revision is not None:
4528
4420
                    raise errors.BzrCommandError(gettext(
4529
4421
                        'Cannot use -r with merge directives or bundles'))
4530
4422
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
4531
 
                                                                    mergeable)
 
4423
                   mergeable)
4532
4424
 
4533
4425
        if merger is None and uncommitted:
4534
4426
            if revision is not None and len(revision) > 0:
4535
4427
                raise errors.BzrCommandError(gettext('Cannot use --uncommitted and'
4536
 
                                                     ' --revision at the same time.'))
 
4428
                    ' --revision at the same time.'))
4537
4429
            merger = self.get_merger_from_uncommitted(tree, location, None)
4538
4430
            allow_pending = False
4539
4431
 
4540
4432
        if merger is None:
4541
4433
            merger, allow_pending = self._get_merger_from_branch(tree,
4542
 
                                                                 location, revision, remember, possible_transports, None)
 
4434
                location, revision, remember, possible_transports, None)
4543
4435
 
4544
4436
        merger.merge_type = merge_type
4545
4437
        merger.reprocess = reprocess
4546
4438
        merger.show_base = show_base
4547
4439
        self.sanity_check_merger(merger)
4548
4440
        if (merger.base_rev_id == merger.other_rev_id and
4549
 
                merger.other_rev_id is not None):
 
4441
            merger.other_rev_id is not None):
4550
4442
            # check if location is a nonexistent file (and not a branch) to
4551
4443
            # disambiguate the 'Nothing to do'
4552
4444
            if merger.interesting_files:
4553
4445
                if not merger.other_tree.has_filename(
4554
 
                        merger.interesting_files[0]):
 
4446
                    merger.interesting_files[0]):
4555
4447
                    note(gettext("merger: ") + str(merger))
4556
4448
                    raise errors.PathsDoNotExist([location])
4557
4449
            note(gettext('Nothing to do.'))
4558
4450
            return 0
4559
4451
        if pull and not preview:
4560
4452
            if merger.interesting_files is not None:
4561
 
                raise errors.BzrCommandError(
4562
 
                    gettext('Cannot pull individual files'))
 
4453
                raise errors.BzrCommandError(gettext('Cannot pull individual files'))
4563
4454
            if (merger.base_rev_id == tree.last_revision()):
4564
4455
                result = tree.pull(merger.other_branch, False,
4565
4456
                                   merger.other_rev_id)
4580
4471
    def _get_preview(self, merger):
4581
4472
        tree_merger = merger.make_merger()
4582
4473
        tt = tree_merger.make_preview_transform()
4583
 
        self.enter_context(tt)
 
4474
        self.add_cleanup(tt.finalize)
4584
4475
        result_tree = tt.get_preview_tree()
4585
4476
        return result_tree
4586
4477
 
4624
4515
 
4625
4516
    def sanity_check_merger(self, merger):
4626
4517
        if (merger.show_base and
4627
 
                merger.merge_type is not _mod_merge.Merge3Merger):
 
4518
            not merger.merge_type is _mod_merge.Merge3Merger):
4628
4519
            raise errors.BzrCommandError(gettext("Show-base is not supported for this"
4629
 
                                                 " merge type. %s") % merger.merge_type)
 
4520
                                         " merge type. %s") % merger.merge_type)
4630
4521
        if merger.reprocess is None:
4631
4522
            if merger.show_base:
4632
4523
                merger.reprocess = False
4635
4526
                merger.reprocess = merger.merge_type.supports_reprocess
4636
4527
        if merger.reprocess and not merger.merge_type.supports_reprocess:
4637
4528
            raise errors.BzrCommandError(gettext("Conflict reduction is not supported"
4638
 
                                                 " for merge type %s.") %
 
4529
                                         " for merge type %s.") %
4639
4530
                                         merger.merge_type)
4640
4531
        if merger.reprocess and merger.show_base:
4641
4532
            raise errors.BzrCommandError(gettext("Cannot do conflict reduction and"
4642
 
                                                 " show base."))
 
4533
                                         " show base."))
4643
4534
 
4644
4535
        if (merger.merge_type.requires_file_merge_plan and
4645
4536
            (not getattr(merger.this_tree, 'plan_file_merge', None) or
4647
4538
             (merger.base_tree is not None and
4648
4539
                 not getattr(merger.base_tree, 'plan_file_merge', None)))):
4649
4540
            raise errors.BzrCommandError(
4650
 
                gettext('Plan file merge unsupported: '
4651
 
                        'Merge type incompatible with tree formats.'))
 
4541
                 gettext('Plan file merge unsupported: '
 
4542
                         'Merge type incompatible with tree formats.'))
4652
4543
 
4653
4544
    def _get_merger_from_branch(self, tree, location, revision, remember,
4654
4545
                                possible_transports, pb):
4655
4546
        """Produce a merger from a location, assuming it refers to a branch."""
4656
4547
        # find the branch locations
4657
4548
        other_loc, user_location = self._select_branch_location(tree, location,
4658
 
                                                                revision, -1)
 
4549
            revision, -1)
4659
4550
        if revision is not None and len(revision) == 2:
4660
4551
            base_loc, _unused = self._select_branch_location(tree,
4661
 
                                                             location, revision, 0)
 
4552
                location, revision, 0)
4662
4553
        else:
4663
4554
            base_loc = other_loc
4664
4555
        # Open the branches
4665
4556
        other_branch, other_path = Branch.open_containing(other_loc,
4666
 
                                                          possible_transports)
 
4557
            possible_transports)
4667
4558
        if base_loc == other_loc:
4668
4559
            base_branch = other_branch
4669
4560
        else:
4670
4561
            base_branch, base_path = Branch.open_containing(base_loc,
4671
 
                                                            possible_transports)
 
4562
                possible_transports)
4672
4563
        # Find the revision ids
4673
4564
        other_revision_id = None
4674
4565
        base_revision_id = None
4686
4577
        # - user ask to remember or there is no previous location set to merge
4687
4578
        #   from and user didn't ask to *not* remember
4688
4579
        if (user_location is not None
4689
 
            and ((remember or
4690
 
                 (remember is None and
4691
 
                  tree.branch.get_submit_branch() is None)))):
 
4580
            and ((remember
 
4581
                  or (remember is None
 
4582
                      and tree.branch.get_submit_branch() is None)))):
4692
4583
            tree.branch.set_submit_branch(other_branch.base)
4693
4584
        # Merge tags (but don't set them in the master branch yet, the user
4694
4585
        # might revert this merge).  Commit will propagate them.
4695
4586
        other_branch.tags.merge_to(tree.branch.tags, ignore_master=True)
4696
4587
        merger = _mod_merge.Merger.from_revision_ids(tree,
4697
 
                                                     other_revision_id, base_revision_id, other_branch, base_branch)
 
4588
            other_revision_id, base_revision_id, other_branch, base_branch)
4698
4589
        if other_path != '':
4699
4590
            allow_pending = False
4700
4591
            merger.interesting_files = [other_path]
4735
4626
            will be the user-entered location.
4736
4627
        """
4737
4628
        if (revision is not None and index is not None
4738
 
                and revision[index] is not None):
 
4629
            and revision[index] is not None):
4739
4630
            branch = revision[index].get_branch()
4740
4631
            if branch is not None:
4741
4632
                return branch, branch
4757
4648
            stored_location_type = "parent"
4758
4649
        mutter("%s", stored_location)
4759
4650
        if stored_location is None:
4760
 
            raise errors.BzrCommandError(
4761
 
                gettext("No location specified or remembered"))
 
4651
            raise errors.BzrCommandError(gettext("No location specified or remembered"))
4762
4652
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
4763
4653
        note(gettext("{0} remembered {1} location {2}").format(verb_string,
4764
 
                                                               stored_location_type, display_url))
 
4654
                stored_location_type, display_url))
4765
4655
        return stored_location
4766
4656
 
4767
4657
 
4789
4679
    """
4790
4680
    takes_args = ['file*']
4791
4681
    takes_options = [
4792
 
        'merge-type',
4793
 
        'reprocess',
4794
 
        Option('show-base',
4795
 
               help="Show base revision text in conflicts."),
4796
 
        ]
 
4682
            'merge-type',
 
4683
            'reprocess',
 
4684
            Option('show-base',
 
4685
                   help="Show base revision text in conflicts."),
 
4686
            ]
4797
4687
 
4798
4688
    def run(self, file_list=None, merge_type=None, show_base=False,
4799
4689
            reprocess=False):
4801
4691
        if merge_type is None:
4802
4692
            merge_type = _mod_merge.Merge3Merger
4803
4693
        tree, file_list = WorkingTree.open_containing_paths(file_list)
4804
 
        self.enter_context(tree.lock_write())
 
4694
        self.add_cleanup(tree.lock_write().unlock)
4805
4695
        parents = tree.get_parent_ids()
4806
4696
        if len(parents) != 2:
4807
 
            raise errors.BzrCommandError(
4808
 
                gettext("Sorry, remerge only works after normal"
4809
 
                        " merges.  Not cherrypicking or multi-merges."))
 
4697
            raise errors.BzrCommandError(gettext("Sorry, remerge only works after normal"
 
4698
                                         " merges.  Not cherrypicking or"
 
4699
                                         " multi-merges."))
 
4700
        repository = tree.branch.repository
4810
4701
        interesting_files = None
4811
4702
        new_conflicts = []
4812
4703
        conflicts = tree.conflicts()
4819
4710
                if tree.kind(filename) != "directory":
4820
4711
                    continue
4821
4712
 
4822
 
                for path, ie in tree.iter_entries_by_dir(
4823
 
                        specific_files=[filename]):
 
4713
                for path, ie in tree.iter_entries_by_dir(specific_files=[filename]):
4824
4714
                    interesting_files.add(path)
4825
4715
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4826
4716
        else:
4878
4768
    update command.
4879
4769
 
4880
4770
    Uncommitted changes to files that are reverted will be discarded.
4881
 
    However, by default, any files that have been manually changed will be
 
4771
    Howver, by default, any files that have been manually changed will be
4882
4772
    backed up first.  (Files changed only by merge are not backed up.)  Backup
4883
4773
    files have '.~#~' appended to their name, where # is a number.
4884
4774
 
4924
4814
    def run(self, revision=None, no_backup=False, file_list=None,
4925
4815
            forget_merges=None):
4926
4816
        tree, file_list = WorkingTree.open_containing_paths(file_list)
4927
 
        self.enter_context(tree.lock_tree_write())
 
4817
        self.add_cleanup(tree.lock_tree_write().unlock)
4928
4818
        if forget_merges:
4929
4819
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4930
4820
        else:
4934
4824
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4935
4825
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
4936
4826
        tree.revert(file_list, rev_tree, not no_backup, None,
4937
 
                    report_changes=True)
 
4827
            report_changes=True)
4938
4828
 
4939
4829
 
4940
4830
class cmd_assert_fail(Command):
4953
4843
 
4954
4844
    _see_also = ['topics']
4955
4845
    takes_options = [
4956
 
        Option('long', 'Show help on all commands.'),
4957
 
        ]
 
4846
            Option('long', 'Show help on all commands.'),
 
4847
            ]
4958
4848
    takes_args = ['topic?']
4959
4849
    aliases = ['?', '--help', '-?', '-h']
4960
4850
 
4989
4879
    To filter on a range of revisions, you can use the command -r begin..end
4990
4880
    -r revision requests a specific revision, -r ..end or -r begin.. are
4991
4881
    also valid.
4992
 
 
 
4882
            
4993
4883
    :Exit values:
4994
4884
        1 - some missing revisions
4995
4885
        0 - no missing revisions
5031
4921
        'show-ids',
5032
4922
        'verbose',
5033
4923
        custom_help('revision',
5034
 
                    help='Filter on other branch revisions (inclusive). '
5035
 
                    'See "help revisionspec" for details.'),
 
4924
             help='Filter on other branch revisions (inclusive). '
 
4925
                'See "help revisionspec" for details.'),
5036
4926
        Option('my-revision',
5037
 
               type=_parse_revision_str,
5038
 
               help='Filter on local branch revisions (inclusive). '
5039
 
               'See "help revisionspec" for details.'),
 
4927
            type=_parse_revision_str,
 
4928
            help='Filter on local branch revisions (inclusive). '
 
4929
                'See "help revisionspec" for details.'),
5040
4930
        Option('include-merged',
5041
4931
               'Show all revisions in addition to the mainline ones.'),
5042
4932
        Option('include-merges', hidden=True,
5052
4942
            include_merged=None, revision=None, my_revision=None,
5053
4943
            directory=u'.'):
5054
4944
        from breezy.missing import find_unmerged, iter_log_revisions
5055
 
 
5056
4945
        def message(s):
5057
4946
            if not is_quiet():
5058
4947
                self.outf.write(s)
5073
4962
            restrict = 'remote'
5074
4963
 
5075
4964
        local_branch = Branch.open_containing(directory)[0]
5076
 
        self.enter_context(local_branch.lock_read())
 
4965
        self.add_cleanup(local_branch.lock_read().unlock)
5077
4966
 
5078
4967
        parent = local_branch.get_parent()
5079
4968
        if other_branch is None:
5080
4969
            other_branch = parent
5081
4970
            if other_branch is None:
5082
4971
                raise errors.BzrCommandError(gettext("No peer location known"
5083
 
                                                     " or specified."))
 
4972
                                             " or specified."))
5084
4973
            display_url = urlutils.unescape_for_display(parent,
5085
4974
                                                        self.outf.encoding)
5086
4975
            message(gettext("Using saved parent location: {0}\n").format(
5090
4979
        if remote_branch.base == local_branch.base:
5091
4980
            remote_branch = local_branch
5092
4981
        else:
5093
 
            self.enter_context(remote_branch.lock_read())
 
4982
            self.add_cleanup(remote_branch.lock_read().unlock)
5094
4983
 
5095
4984
        local_revid_range = _revision_range_to_revid_range(
5096
4985
            _get_revision_range(my_revision, local_branch,
5097
 
                                self.name()))
 
4986
                self.name()))
5098
4987
 
5099
4988
        remote_revid_range = _revision_range_to_revid_range(
5100
4989
            _get_revision_range(revision,
5101
 
                                remote_branch, self.name()))
 
4990
                remote_branch, self.name()))
5102
4991
 
5103
4992
        local_extra, remote_extra = find_unmerged(
5104
4993
            local_branch, remote_branch, restrict,
5117
5006
        status_code = 0
5118
5007
        if local_extra and not theirs_only:
5119
5008
            message(ngettext("You have %d extra revision:\n",
5120
 
                             "You have %d extra revisions:\n",
 
5009
                             "You have %d extra revisions:\n", 
5121
5010
                             len(local_extra)) %
5122
 
                    len(local_extra))
 
5011
                len(local_extra))
5123
5012
            rev_tag_dict = {}
5124
5013
            if local_branch.supports_tags():
5125
5014
                rev_tag_dict = local_branch.tags.get_reverse_tag_dict()
5126
5015
            for revision in iter_log_revisions(local_extra,
5127
 
                                               local_branch.repository,
5128
 
                                               verbose,
5129
 
                                               rev_tag_dict):
 
5016
                                local_branch.repository,
 
5017
                                verbose,
 
5018
                                rev_tag_dict):
5130
5019
                lf.log_revision(revision)
5131
5020
            printed_local = True
5132
5021
            status_code = 1
5139
5028
            message(ngettext("You are missing %d revision:\n",
5140
5029
                             "You are missing %d revisions:\n",
5141
5030
                             len(remote_extra)) %
5142
 
                    len(remote_extra))
 
5031
                len(remote_extra))
5143
5032
            if remote_branch.supports_tags():
5144
5033
                rev_tag_dict = remote_branch.tags.get_reverse_tag_dict()
5145
5034
            for revision in iter_log_revisions(remote_extra,
5146
 
                                               remote_branch.repository,
5147
 
                                               verbose,
5148
 
                                               rev_tag_dict):
 
5035
                                remote_branch.repository,
 
5036
                                verbose,
 
5037
                                rev_tag_dict):
5149
5038
                lf.log_revision(revision)
5150
5039
            status_code = 1
5151
5040
 
5162
5051
            message(gettext("Branches are up to date.\n"))
5163
5052
        self.cleanup_now()
5164
5053
        if not status_code and parent is None and other_branch is not None:
5165
 
            self.enter_context(local_branch.lock_write())
 
5054
            self.add_cleanup(local_branch.lock_write().unlock)
5166
5055
            # handle race conditions - a parent might be set while we run.
5167
5056
            if local_branch.get_parent() is None:
5168
5057
                local_branch.set_parent(remote_branch.base)
5191
5080
    _see_also = ['repositories']
5192
5081
    takes_args = ['branch_or_repo?']
5193
5082
    takes_options = [
5194
 
        Option('clean-obsolete-packs',
5195
 
               'Delete obsolete packs to save disk space.'),
 
5083
        Option('clean-obsolete-packs', 'Delete obsolete packs to save disk space.'),
5196
5084
        ]
5197
5085
 
5198
5086
    def run(self, branch_or_repo='.', clean_obsolete_packs=False):
5213
5101
 
5214
5102
    --verbose shows the path where each plugin is located.
5215
5103
 
5216
 
    A plugin is an external component for Breezy that extends the
5217
 
    revision control system, by adding or replacing code in Breezy.
 
5104
    A plugin is an external component for Bazaar that extends the
 
5105
    revision control system, by adding or replacing code in Bazaar.
5218
5106
    Plugins can do a variety of things, including overriding commands,
5219
5107
    adding new commands, providing additional network transports and
5220
5108
    customizing log output.
5237
5125
class cmd_testament(Command):
5238
5126
    __doc__ = """Show testament (signing-form) of a revision."""
5239
5127
    takes_options = [
5240
 
        'revision',
5241
 
        Option('long', help='Produce long-format testament.'),
5242
 
        Option('strict',
5243
 
               help='Produce a strict-format testament.')]
 
5128
            'revision',
 
5129
            Option('long', help='Produce long-format testament.'),
 
5130
            Option('strict',
 
5131
                   help='Produce a strict-format testament.')]
5244
5132
    takes_args = ['branch?']
5245
5133
    encoding_type = 'exact'
5246
 
 
5247
5134
    @display_command
5248
5135
    def run(self, branch=u'.', revision=None, long=False, strict=False):
5249
 
        from .bzr.testament import Testament, StrictTestament
 
5136
        from .testament import Testament, StrictTestament
5250
5137
        if strict is True:
5251
5138
            testament_class = StrictTestament
5252
5139
        else:
5255
5142
            b = Branch.open_containing(branch)[0]
5256
5143
        else:
5257
5144
            b = Branch.open(branch)
5258
 
        self.enter_context(b.lock_read())
 
5145
        self.add_cleanup(b.lock_read().unlock)
5259
5146
        if revision is None:
5260
5147
            rev_id = b.last_revision()
5261
5148
        else:
5298
5185
        wt, branch, relpath = \
5299
5186
            _open_directory_or_containing_tree_or_branch(filename, directory)
5300
5187
        if wt is not None:
5301
 
            self.enter_context(wt.lock_read())
 
5188
            self.add_cleanup(wt.lock_read().unlock)
5302
5189
        else:
5303
 
            self.enter_context(branch.lock_read())
 
5190
            self.add_cleanup(branch.lock_read().unlock)
5304
5191
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
5305
 
        self.enter_context(tree.lock_read())
5306
 
        if wt is not None and revision is None:
5307
 
            if not wt.is_versioned(relpath):
5308
 
                raise errors.NotVersionedError(relpath)
 
5192
        self.add_cleanup(tree.lock_read().unlock)
 
5193
        if wt is not None and revision is None:
 
5194
            file_id = wt.path2id(relpath)
 
5195
        else:
 
5196
            file_id = tree.path2id(relpath)
 
5197
        if file_id is None:
 
5198
            raise errors.NotVersionedError(filename)
 
5199
        if wt is not None and revision is None:
5309
5200
            # If there is a tree and we're not annotating historical
5310
5201
            # versions, annotate the working tree's content.
5311
5202
            annotate_file_tree(wt, relpath, self.outf, long, all,
5312
 
                               show_ids=show_ids)
 
5203
                show_ids=show_ids, file_id=file_id)
5313
5204
        else:
5314
 
            if not tree.is_versioned(relpath):
5315
 
                raise errors.NotVersionedError(relpath)
5316
5205
            annotate_file_tree(tree, relpath, self.outf, long, all,
5317
 
                               show_ids=show_ids, branch=branch)
 
5206
                show_ids=show_ids, branch=branch, file_id=file_id)
5318
5207
 
5319
5208
 
5320
5209
class cmd_re_sign(Command):
5321
5210
    __doc__ = """Create a digital signature for an existing revision."""
5322
5211
    # TODO be able to replace existing ones.
5323
5212
 
5324
 
    hidden = True  # is this right ?
 
5213
    hidden = True # is this right ?
5325
5214
    takes_args = ['revision_id*']
5326
5215
    takes_options = ['directory', 'revision']
5327
5216
 
5328
5217
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
5329
5218
        if revision_id_list is not None and revision is not None:
5330
 
            raise errors.BzrCommandError(
5331
 
                gettext('You can only supply one of revision_id or --revision'))
 
5219
            raise errors.BzrCommandError(gettext('You can only supply one of revision_id or --revision'))
5332
5220
        if revision_id_list is None and revision is None:
5333
 
            raise errors.BzrCommandError(
5334
 
                gettext('You must supply either --revision or a revision_id'))
 
5221
            raise errors.BzrCommandError(gettext('You must supply either --revision or a revision_id'))
5335
5222
        b = WorkingTree.open_containing(directory)[0].branch
5336
 
        self.enter_context(b.lock_write())
 
5223
        self.add_cleanup(b.lock_write().unlock)
5337
5224
        return self._run(b, revision_id_list, revision)
5338
5225
 
5339
5226
    def _run(self, b, revision_id_list, revision):
5340
 
        from .repository import WriteGroup
5341
5227
        gpg_strategy = gpg.GPGStrategy(b.get_config_stack())
5342
5228
        if revision_id_list is not None:
5343
 
            with WriteGroup(b.repository):
 
5229
            b.repository.start_write_group()
 
5230
            try:
5344
5231
                for revision_id in revision_id_list:
5345
5232
                    revision_id = cache_utf8.encode(revision_id)
5346
5233
                    b.repository.sign_revision(revision_id, gpg_strategy)
 
5234
            except:
 
5235
                b.repository.abort_write_group()
 
5236
                raise
 
5237
            else:
 
5238
                b.repository.commit_write_group()
5347
5239
        elif revision is not None:
5348
5240
            if len(revision) == 1:
5349
5241
                revno, rev_id = revision[0].in_history(b)
5350
 
                with WriteGroup(b.repository):
 
5242
                b.repository.start_write_group()
 
5243
                try:
5351
5244
                    b.repository.sign_revision(rev_id, gpg_strategy)
 
5245
                except:
 
5246
                    b.repository.abort_write_group()
 
5247
                    raise
 
5248
                else:
 
5249
                    b.repository.commit_write_group()
5352
5250
            elif len(revision) == 2:
5353
5251
                # are they both on rh- if so we can walk between them
5354
5252
                # might be nice to have a range helper for arbitrary
5358
5256
                if to_revid is None:
5359
5257
                    to_revno = b.revno()
5360
5258
                if from_revno is None or to_revno is None:
5361
 
                    raise errors.BzrCommandError(
5362
 
                        gettext('Cannot sign a range of non-revision-history revisions'))
5363
 
                with WriteGroup(b.repository):
 
5259
                    raise errors.BzrCommandError(gettext('Cannot sign a range of non-revision-history revisions'))
 
5260
                b.repository.start_write_group()
 
5261
                try:
5364
5262
                    for revno in range(from_revno, to_revno + 1):
5365
5263
                        b.repository.sign_revision(b.get_rev_id(revno),
5366
5264
                                                   gpg_strategy)
 
5265
                except:
 
5266
                    b.repository.abort_write_group()
 
5267
                    raise
 
5268
                else:
 
5269
                    b.repository.commit_write_group()
5367
5270
            else:
5368
 
                raise errors.BzrCommandError(
5369
 
                    gettext('Please supply either one revision, or a range.'))
 
5271
                raise errors.BzrCommandError(gettext('Please supply either one revision, or a range.'))
5370
5272
 
5371
5273
 
5372
5274
class cmd_bind(Command):
5391
5293
            try:
5392
5294
                location = b.get_old_bound_location()
5393
5295
            except errors.UpgradeRequired:
5394
 
                raise errors.BzrCommandError(
5395
 
                    gettext('No location supplied.  '
5396
 
                            'This format does not remember old locations.'))
 
5296
                raise errors.BzrCommandError(gettext('No location supplied.  '
 
5297
                    'This format does not remember old locations.'))
5397
5298
            else:
5398
5299
                if location is None:
5399
5300
                    if b.get_bound_location() is not None:
5407
5308
        try:
5408
5309
            b.bind(b_other)
5409
5310
        except errors.DivergedBranches:
5410
 
            raise errors.BzrCommandError(
5411
 
                gettext('These branches have diverged.'
5412
 
                        ' Try merging, and then bind again.'))
 
5311
            raise errors.BzrCommandError(gettext('These branches have diverged.'
 
5312
                                         ' Try merging, and then bind again.'))
5413
5313
        if b.get_config().has_explicit_nickname():
5414
5314
            b.nick = b_other.nick
5415
5315
 
5453
5353
    # information in shared branches as well.
5454
5354
    _see_also = ['commit']
5455
5355
    takes_options = ['verbose', 'revision',
5456
 
                     Option('dry-run', help='Don\'t actually make changes.'),
5457
 
                     Option('force', help='Say yes to all questions.'),
5458
 
                     Option('keep-tags',
5459
 
                            help='Keep tags that point to removed revisions.'),
5460
 
                     Option('local',
5461
 
                            help="Only remove the commits from the local "
5462
 
                            "branch when in a checkout."
5463
 
                            ),
5464
 
                     ]
 
5356
                    Option('dry-run', help='Don\'t actually make changes.'),
 
5357
                    Option('force', help='Say yes to all questions.'),
 
5358
                    Option('keep-tags',
 
5359
                           help='Keep tags that point to removed revisions.'),
 
5360
                    Option('local',
 
5361
                           help="Only remove the commits from the local branch"
 
5362
                                " when in a checkout."
 
5363
                           ),
 
5364
                    ]
5465
5365
    takes_args = ['location?']
5466
5366
    aliases = []
5467
5367
    encoding_type = 'replace'
5479
5379
            b = control.open_branch()
5480
5380
 
5481
5381
        if tree is not None:
5482
 
            self.enter_context(tree.lock_write())
 
5382
            self.add_cleanup(tree.lock_write().unlock)
5483
5383
        else:
5484
 
            self.enter_context(b.lock_write())
 
5384
            self.add_cleanup(b.lock_write().unlock)
5485
5385
        return self._run(b, tree, dry_run, verbose, revision, force,
5486
 
                         local, keep_tags, location)
 
5386
                         local, keep_tags)
5487
5387
 
5488
5388
    def _run(self, b, tree, dry_run, verbose, revision, force, local,
5489
 
             keep_tags, location):
 
5389
             keep_tags):
5490
5390
        from .log import log_formatter, show_log
5491
5391
        from .uncommit import uncommit
5492
5392
 
5523
5423
 
5524
5424
        if dry_run:
5525
5425
            self.outf.write(gettext('Dry-run, pretending to remove'
5526
 
                                    ' the above revisions.\n'))
 
5426
                            ' the above revisions.\n'))
5527
5427
        else:
5528
 
            self.outf.write(
5529
 
                gettext('The above revision(s) will be removed.\n'))
 
5428
            self.outf.write(gettext('The above revision(s) will be removed.\n'))
5530
5429
 
5531
5430
        if not force:
5532
5431
            if not ui.ui_factory.confirm_action(
5540
5439
               last_rev_id, rev_id)
5541
5440
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
5542
5441
                 revno=revno, local=local, keep_tags=keep_tags)
5543
 
        if location != '.':
5544
 
            self.outf.write(
5545
 
                gettext('You can restore the old tip by running:\n'
5546
 
                        '  brz pull -d %s %s -r revid:%s\n')
5547
 
                % (location, location, last_rev_id.decode('utf-8')))
5548
 
        else:
5549
 
            self.outf.write(
5550
 
                gettext('You can restore the old tip by running:\n'
5551
 
                        '  brz pull . -r revid:%s\n')
5552
 
                % last_rev_id.decode('utf-8'))
 
5442
        self.outf.write(gettext('You can restore the old tip by running:\n'
 
5443
             '  brz pull . -r revid:%s\n') % last_rev_id)
5553
5444
 
5554
5445
 
5555
5446
class cmd_break_lock(Command):
5567
5458
    :Examples:
5568
5459
        brz break-lock
5569
5460
        brz break-lock brz+ssh://example.com/brz/foo
5570
 
        brz break-lock --conf ~/.config/breezy
 
5461
        brz break-lock --conf ~/.bazaar
5571
5462
    """
5572
5463
 
5573
5464
    takes_args = ['location?']
5575
5466
        Option('config',
5576
5467
               help='LOCATION is the directory where the config lock is.'),
5577
5468
        Option('force',
5578
 
               help='Do not ask for confirmation before breaking the lock.'),
 
5469
            help='Do not ask for confirmation before breaking the lock.'),
5579
5470
        ]
5580
5471
 
5581
5472
    def run(self, location=None, config=False, force=False):
5583
5474
            location = u'.'
5584
5475
        if force:
5585
5476
            ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
5586
 
                                                               None,
5587
 
                                                               {'breezy.lockdir.break': True})
 
5477
                None,
 
5478
                {'breezy.lockdir.break': True})
5588
5479
        if config:
5589
5480
            conf = _mod_config.LockableConfig(file_name=location)
5590
5481
            conf.break_lock()
5619
5510
        Option('inet',
5620
5511
               help='Serve on stdin/out for use from inetd or sshd.'),
5621
5512
        RegistryOption('protocol',
5622
 
                       help="Protocol to serve.",
5623
 
                       lazy_registry=('breezy.transport',
5624
 
                                      'transport_server_registry'),
5625
 
                       value_switches=True),
 
5513
               help="Protocol to serve.",
 
5514
               lazy_registry=('breezy.transport', 'transport_server_registry'),
 
5515
               value_switches=True),
5626
5516
        Option('listen',
5627
 
               help='Listen for connections on nominated address.',
5628
 
               type=text_type),
 
5517
               help='Listen for connections on nominated address.', type=text_type),
5629
5518
        Option('port',
5630
5519
               help='Listen for connections on nominated port.  Passing 0 as '
5631
5520
                    'the port number will result in a dynamically allocated '
5632
5521
                    'port.  The default port depends on the protocol.',
5633
5522
               type=int),
5634
5523
        custom_help('directory',
5635
 
                    help='Serve contents of this directory.'),
 
5524
               help='Serve contents of this directory.'),
5636
5525
        Option('allow-writes',
5637
5526
               help='By default the server is a readonly server.  Supplying '
5638
5527
                    '--allow-writes enables write access to the contents of '
5641
5530
                    'external authentication is arranged supplying this '
5642
5531
                    'option leads to global uncontrolled write access to your '
5643
5532
                    'file system.'
5644
 
               ),
 
5533
                ),
5645
5534
        Option('client-timeout', type=float,
5646
5535
               help='Override the default idle client timeout (5min).'),
5647
5536
        ]
5648
5537
 
5649
5538
    def run(self, listen=None, port=None, inet=False, directory=None,
5650
5539
            allow_writes=False, protocol=None, client_timeout=None):
5651
 
        from . import location, transport
 
5540
        from . import transport
5652
5541
        if directory is None:
5653
5542
            directory = osutils.getcwd()
5654
5543
        if protocol is None:
5655
5544
            protocol = transport.transport_server_registry.get()
5656
 
        url = location.location_to_url(directory)
 
5545
        url = transport.location_to_url(directory)
5657
5546
        if not allow_writes:
5658
5547
            url = 'readonly+' + url
5659
5548
        t = transport.get_transport_from_url(url)
5677
5566
    _see_also = ['split']
5678
5567
    takes_args = ['tree']
5679
5568
    takes_options = [
5680
 
        Option('reference', help='Join by reference.', hidden=True),
5681
 
        ]
 
5569
            Option('reference', help='Join by reference.', hidden=True),
 
5570
            ]
5682
5571
 
5683
5572
    def run(self, tree, reference=False):
5684
5573
        from breezy.mutabletree import BadReferenceTarget
5698
5587
                # XXX: Would be better to just raise a nicely printable
5699
5588
                # exception from the real origin.  Also below.  mbp 20070306
5700
5589
                raise errors.BzrCommandError(
5701
 
                    gettext("Cannot join {0}.  {1}").format(tree, e.reason))
 
5590
                       gettext("Cannot join {0}.  {1}").format(tree, e.reason))
5702
5591
        else:
5703
5592
            try:
5704
5593
                containing_tree.subsume(sub_tree)
5705
5594
            except errors.BadSubsumeSource as e:
5706
5595
                raise errors.BzrCommandError(
5707
 
                    gettext("Cannot join {0}.  {1}").format(tree, e.reason))
 
5596
                       gettext("Cannot join {0}.  {1}").format(tree, e.reason))
5708
5597
 
5709
5598
 
5710
5599
class cmd_split(Command):
5724
5613
 
5725
5614
    def run(self, tree):
5726
5615
        containing_tree, subdir = WorkingTree.open_containing(tree)
5727
 
        if not containing_tree.is_versioned(subdir):
 
5616
        sub_id = containing_tree.path2id(subdir)
 
5617
        if sub_id is None:
5728
5618
            raise errors.NotVersionedError(subdir)
5729
5619
        try:
5730
 
            containing_tree.extract(subdir)
 
5620
            containing_tree.extract(subdir, sub_id)
5731
5621
        except errors.RootNotRich:
5732
5622
            raise errors.RichRootUpgradeRequired(containing_tree.branch.base)
5733
5623
 
5757
5647
 
5758
5648
    takes_options = [
5759
5649
        'directory',
5760
 
        RegistryOption.from_kwargs(
5761
 
            'patch-type',
 
5650
        RegistryOption.from_kwargs('patch-type',
5762
5651
            'The type of patch to include in the directive.',
5763
5652
            title='Patch type',
5764
5653
            value_switches=True,
5768
5657
            plain='No patch, just directive.'),
5769
5658
        Option('sign', help='GPG-sign the directive.'), 'revision',
5770
5659
        Option('mail-to', type=text_type,
5771
 
               help='Instead of printing the directive, email to this '
5772
 
               'address.'),
 
5660
            help='Instead of printing the directive, email to this address.'),
5773
5661
        Option('message', type=text_type, short_name='m',
5774
 
               help='Message to use when committing this merge.')
 
5662
            help='Message to use when committing this merge.')
5775
5663
        ]
5776
5664
 
5777
5665
    encoding_type = 'exact'
5795
5683
        if submit_branch is None:
5796
5684
            submit_branch = branch.get_parent()
5797
5685
        if submit_branch is None:
5798
 
            raise errors.BzrCommandError(
5799
 
                gettext('No submit branch specified or known'))
 
5686
            raise errors.BzrCommandError(gettext('No submit branch specified or known'))
5800
5687
 
5801
5688
        stored_public_branch = branch.get_public_branch()
5802
5689
        if public_branch is None:
5805
5692
            # FIXME: Should be done only if we succeed ? -- vila 2012-01-03
5806
5693
            branch.set_public_branch(public_branch)
5807
5694
        if not include_bundle and public_branch is None:
5808
 
            raise errors.BzrCommandError(
5809
 
                gettext('No public branch specified or known'))
 
5695
            raise errors.BzrCommandError(gettext('No public branch specified or'
 
5696
                                         ' known'))
5810
5697
        base_revision_id = None
5811
5698
        if revision is not None:
5812
5699
            if len(revision) > 2:
5813
 
                raise errors.BzrCommandError(
5814
 
                    gettext('brz merge-directive takes '
5815
 
                            'at most two one revision identifiers'))
 
5700
                raise errors.BzrCommandError(gettext('brz merge-directive takes '
 
5701
                    'at most two one revision identifiers'))
5816
5702
            revision_id = revision[-1].as_revision_id(branch)
5817
5703
            if len(revision) == 2:
5818
5704
                base_revision_id = revision[0].as_revision_id(branch)
5852
5738
      branch.
5853
5739
 
5854
5740
    `brz send` creates a compact data set that, when applied using brz
5855
 
    merge, has the same effect as merging from the source branch.
5856
 
 
 
5741
    merge, has the same effect as merging from the source branch.  
 
5742
    
5857
5743
    By default the merge directive is self-contained and can be applied to any
5858
5744
    branch containing submit_branch in its ancestory without needing access to
5859
5745
    the source branch.
5860
 
 
5861
 
    If --no-bundle is specified, then Breezy doesn't send the contents of the
 
5746
    
 
5747
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
5862
5748
    revisions, but only a structured request to merge from the
5863
5749
    public_location.  In that case the public_branch is needed and it must be
5864
5750
    up-to-date and accessible to the recipient.  The public_branch is always
5889
5775
    If the preferred client can't be found (or used), your editor will be used.
5890
5776
 
5891
5777
    To use a specific mail program, set the mail_client configuration option.
5892
 
    Supported values for specific clients are "claws", "evolution", "kmail",
5893
 
    "mail.app" (MacOS X's Mail.app), "mutt", and "thunderbird"; generic options
5894
 
    are "default", "editor", "emacsclient", "mapi", and "xdg-email".  Plugins
5895
 
    may also add supported clients.
 
5778
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
 
5779
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
 
5780
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
 
5781
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
 
5782
    supported clients.
5896
5783
 
5897
5784
    If mail is being sent, a to address is required.  This can be supplied
5898
5785
    either on the commandline, by setting the submit_to configuration
5899
5786
    option in the branch itself or the child_submit_to configuration option
5900
5787
    in the submit branch.
5901
5788
 
 
5789
    Two formats are currently supported: "4" uses revision bundle format 4 and
 
5790
    merge directive format 2.  It is significantly faster and smaller than
 
5791
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
 
5792
    default.  "0.9" uses revision bundle format 0.9 and merge directive
 
5793
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
 
5794
 
5902
5795
    The merge directives created by brz send may be applied using brz merge or
5903
5796
    brz pull by specifying a file containing a merge directive as the location.
5904
5797
 
5979
5872
    branch is used in the merge instructions.  This means that a local mirror
5980
5873
    can be used as your actual submit branch, once you have set public_branch
5981
5874
    for that mirror.
 
5875
 
 
5876
    Two formats are currently supported: "4" uses revision bundle format 4 and
 
5877
    merge directive format 2.  It is significantly faster and smaller than
 
5878
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
 
5879
    default.  "0.9" uses revision bundle format 0.9 and merge directive
 
5880
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
5982
5881
    """
5983
5882
 
5984
5883
    takes_options = [
6016
5915
            output = '-'
6017
5916
        from .send import send
6018
5917
        return send(submit_branch, revision, public_branch, remember,
6019
 
                    format, no_bundle, no_patch, output,
6020
 
                    kwargs.get('from', '.'), None, None, None,
6021
 
                    self.outf, strict=strict)
 
5918
                         format, no_bundle, no_patch, output,
 
5919
                         kwargs.get('from', '.'), None, None, None,
 
5920
                         self.outf, strict=strict)
6022
5921
 
6023
5922
 
6024
5923
class cmd_tag(Command):
6037
5936
    To rename a tag (change the name but keep it on the same revsion), run ``brz
6038
5937
    tag new-name -r tag:old-name`` and then ``brz tag --delete oldname``.
6039
5938
 
6040
 
    If no tag name is specified it will be determined through the
 
5939
    If no tag name is specified it will be determined through the 
6041
5940
    'automatic_tag_name' hook. This can e.g. be used to automatically tag
6042
5941
    upstream releases by reading configure.ac. See ``brz help hooks`` for
6043
5942
    details.
6047
5946
    takes_args = ['tag_name?']
6048
5947
    takes_options = [
6049
5948
        Option('delete',
6050
 
               help='Delete this tag rather than placing it.',
6051
 
               ),
 
5949
            help='Delete this tag rather than placing it.',
 
5950
            ),
6052
5951
        custom_help('directory',
6053
 
                    help='Branch in which to place the tag.'),
 
5952
            help='Branch in which to place the tag.'),
6054
5953
        Option('force',
6055
 
               help='Replace existing tags.',
6056
 
               ),
 
5954
            help='Replace existing tags.',
 
5955
            ),
6057
5956
        'revision',
6058
5957
        ]
6059
5958
 
6064
5963
            revision=None,
6065
5964
            ):
6066
5965
        branch, relpath = Branch.open_containing(directory)
6067
 
        self.enter_context(branch.lock_write())
 
5966
        self.add_cleanup(branch.lock_write().unlock)
6068
5967
        if delete:
6069
5968
            if tag_name is None:
6070
 
                raise errors.BzrCommandError(
6071
 
                    gettext("No tag specified to delete."))
 
5969
                raise errors.BzrCommandError(gettext("No tag specified to delete."))
6072
5970
            branch.tags.delete_tag(tag_name)
6073
5971
            note(gettext('Deleted tag %s.') % tag_name)
6074
5972
        else:
6110
6008
    _see_also = ['tag']
6111
6009
    takes_options = [
6112
6010
        custom_help('directory',
6113
 
                    help='Branch whose tags should be displayed.'),
 
6011
            help='Branch whose tags should be displayed.'),
6114
6012
        RegistryOption('sort',
6115
 
                       'Sort tags by different criteria.', title='Sorting',
6116
 
                       lazy_registry=('breezy.tag', 'tag_sort_methods')
6117
 
                       ),
 
6013
            'Sort tags by different criteria.', title='Sorting',
 
6014
            lazy_registry=('breezy.tag', 'tag_sort_methods')
 
6015
            ),
6118
6016
        'show-ids',
6119
6017
        'revision',
6120
6018
    ]
6128
6026
        if not tags:
6129
6027
            return
6130
6028
 
6131
 
        self.enter_context(branch.lock_read())
 
6029
        self.add_cleanup(branch.lock_read().unlock)
6132
6030
        if revision:
6133
6031
            # Restrict to the specified range
6134
6032
            tags = self._tags_for_range(branch, revision)
6149
6047
                    # which are not in this branch. Fail gracefully ...
6150
6048
                    revno = '?'
6151
6049
                tags[index] = (tag, revno)
6152
 
        else:
6153
 
            tags = [(tag, revid.decode('utf-8')) for (tag, revid) in tags]
6154
6050
        self.cleanup_now()
6155
6051
        for tag, revspec in tags:
6156
6052
            self.outf.write('%-20s %s\n' % (tag, revspec))
6157
6053
 
6158
6054
    def _tags_for_range(self, branch, revision):
 
6055
        range_valid = True
6159
6056
        rev1, rev2 = _get_revision_range(revision, branch, self.name())
6160
6057
        revid1, revid2 = rev1.rev_id, rev2.rev_id
6161
6058
        # _get_revision_range will always set revid2 if it's not specified.
6173
6070
        tagged_revids = branch.tags.get_reverse_tag_dict()
6174
6071
        found = []
6175
6072
        for r in branch.iter_merge_sorted_revisions(
6176
 
                start_revision_id=revid2, stop_revision_id=revid1,
6177
 
                stop_rule='include'):
 
6073
            start_revision_id=revid2, stop_revision_id=revid1,
 
6074
            stop_rule='include'):
6178
6075
            revid_tags = tagged_revids.get(r[0], None)
6179
6076
            if revid_tags:
6180
6077
                found.extend([(tag, r[0]) for tag in revid_tags])
6207
6104
            tree='Reconfigure to be an unbound branch with a working tree.',
6208
6105
            checkout='Reconfigure to be a bound branch with a working tree.',
6209
6106
            lightweight_checkout='Reconfigure to be a lightweight'
6210
 
            ' checkout (with no local history).',
 
6107
                ' checkout (with no local history).',
6211
6108
            ),
6212
6109
        RegistryOption.from_kwargs(
6213
6110
            'repository_type',
6215
6112
            help='Location fo the repository.',
6216
6113
            value_switches=True, enum_switch=False,
6217
6114
            standalone='Reconfigure to be a standalone branch '
6218
 
            '(i.e. stop using shared repository).',
 
6115
                '(i.e. stop using shared repository).',
6219
6116
            use_shared='Reconfigure to use a shared repository.',
6220
6117
            ),
6221
6118
        RegistryOption.from_kwargs(
6224
6121
            help='Whether new branches in the repository have trees.',
6225
6122
            value_switches=True, enum_switch=False,
6226
6123
            with_trees='Reconfigure repository to create '
6227
 
            'working trees on branches by default.',
 
6124
                'working trees on branches by default.',
6228
6125
            with_no_trees='Reconfigure repository to not create '
6229
 
            'working trees on branches by default.'
 
6126
                'working trees on branches by default.'
6230
6127
            ),
6231
6128
        Option('bind-to', help='Branch to bind checkout to.', type=text_type),
6232
6129
        Option('force',
6233
 
               help='Perform reconfiguration even if local changes'
6234
 
               ' will be lost.'),
 
6130
            help='Perform reconfiguration even if local changes'
 
6131
            ' will be lost.'),
6235
6132
        Option('stacked-on',
6236
 
               help='Reconfigure a branch to be stacked on another branch.',
6237
 
               type=text_type,
6238
 
               ),
 
6133
            help='Reconfigure a branch to be stacked on another branch.',
 
6134
            type=text_type,
 
6135
            ),
6239
6136
        Option('unstacked',
6240
 
               help='Reconfigure a branch to be unstacked.  This '
6241
 
               'may require copying substantial data into it.',
6242
 
               ),
 
6137
            help='Reconfigure a branch to be unstacked.  This '
 
6138
                'may require copying substantial data into it.',
 
6139
            ),
6243
6140
        ]
6244
6141
 
6245
6142
    def run(self, location=None, bind_to=None, force=False,
6247
6144
            stacked_on=None, unstacked=None):
6248
6145
        directory = controldir.ControlDir.open(location)
6249
6146
        if stacked_on and unstacked:
6250
 
            raise errors.BzrCommandError(
6251
 
                gettext("Can't use both --stacked-on and --unstacked"))
 
6147
            raise errors.BzrCommandError(gettext("Can't use both --stacked-on and --unstacked"))
6252
6148
        elif stacked_on is not None:
6253
6149
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
6254
6150
        elif unstacked:
6258
6154
        # to ban it.
6259
6155
        if (tree_type is None and
6260
6156
            repository_type is None and
6261
 
                repository_trees is None):
 
6157
            repository_trees is None):
6262
6158
            if stacked_on or unstacked:
6263
6159
                return
6264
6160
            else:
6265
6161
                raise errors.BzrCommandError(gettext('No target configuration '
6266
 
                                                     'specified'))
 
6162
                    'specified'))
6267
6163
        reconfiguration = None
6268
6164
        if tree_type == 'branch':
6269
6165
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
6322
6218
    takes_args = ['to_location?']
6323
6219
    takes_options = ['directory',
6324
6220
                     Option('force',
6325
 
                            help='Switch even if local commits will be lost.'),
 
6221
                        help='Switch even if local commits will be lost.'),
6326
6222
                     'revision',
6327
6223
                     Option('create-branch', short_name='b',
6328
 
                            help='Create the target branch from this one before'
6329
 
                            ' switching to it.'),
 
6224
                        help='Create the target branch from this one before'
 
6225
                             ' switching to it.'),
6330
6226
                     Option('store',
6331
 
                            help='Store and restore uncommitted changes in the'
6332
 
                            ' branch.'),
6333
 
                     ]
 
6227
                        help='Store and restore uncommitted changes in the'
 
6228
                             ' branch.'),
 
6229
                    ]
6334
6230
 
6335
6231
    def run(self, to_location=None, force=False, create_branch=False,
6336
6232
            revision=None, directory=u'.', store=False):
6337
6233
        from . import switch
6338
6234
        tree_location = directory
6339
6235
        revision = _get_one_revision('switch', revision)
6340
 
        control_dir = controldir.ControlDir.open_containing(tree_location)[0]
6341
 
        possible_transports = [control_dir.root_transport]
 
6236
        possible_transports = []
 
6237
        control_dir = controldir.ControlDir.open_containing(tree_location,
 
6238
            possible_transports=possible_transports)[0]
6342
6239
        if to_location is None:
6343
6240
            if revision is None:
6344
6241
                raise errors.BzrCommandError(gettext('You must supply either a'
6345
 
                                                     ' revision or a location'))
 
6242
                                             ' revision or a location'))
6346
6243
            to_location = tree_location
6347
6244
        try:
6348
6245
            branch = control_dir.open_branch(
6351
6248
        except errors.NotBranchError:
6352
6249
            branch = None
6353
6250
            had_explicit_nick = False
6354
 
        else:
6355
 
            possible_transports.append(branch.user_transport)
6356
6251
        if create_branch:
6357
6252
            if branch is None:
6358
6253
                raise errors.BzrCommandError(
6359
6254
                    gettext('cannot create branch without source branch'))
6360
 
            to_location = lookup_new_sibling_branch(
6361
 
                control_dir, to_location,
6362
 
                possible_transports=possible_transports)
6363
 
            if revision is not None:
6364
 
                revision = revision.as_revision_id(branch)
6365
 
            to_branch = branch.controldir.sprout(
6366
 
                to_location,
6367
 
                possible_transports=possible_transports,
6368
 
                revision_id=revision,
6369
 
                source_branch=branch).open_branch()
 
6255
            to_location = lookup_new_sibling_branch(control_dir, to_location,
 
6256
                 possible_transports=possible_transports)
 
6257
            to_branch = branch.controldir.sprout(to_location,
 
6258
                 possible_transports=possible_transports,
 
6259
                 source_branch=branch).open_branch()
6370
6260
        else:
6371
6261
            try:
6372
 
                to_branch = Branch.open(
6373
 
                    to_location, possible_transports=possible_transports)
 
6262
                to_branch = Branch.open(to_location,
 
6263
                    possible_transports=possible_transports)
6374
6264
            except errors.NotBranchError:
6375
 
                to_branch = open_sibling_branch(
6376
 
                    control_dir, to_location,
 
6265
                to_branch = open_sibling_branch(control_dir, to_location,
6377
6266
                    possible_transports=possible_transports)
6378
 
            if revision is not None:
6379
 
                revision = revision.as_revision_id(to_branch)
6380
 
        possible_transports.append(to_branch.user_transport)
 
6267
        if revision is not None:
 
6268
            revision = revision.as_revision_id(to_branch)
6381
6269
        try:
6382
6270
            switch.switch(control_dir, to_branch, force, revision_id=revision,
6383
 
                          store_uncommitted=store,
6384
 
                          possible_transports=possible_transports)
 
6271
                          store_uncommitted=store)
6385
6272
        except controldir.BranchReferenceLoop:
6386
6273
            raise errors.BzrCommandError(
6387
 
                gettext('switching would create a branch reference loop. '
6388
 
                        'Use the "bzr up" command to switch to a '
6389
 
                        'different revision.'))
 
6274
                    gettext('switching would create a branch reference loop. '
 
6275
                            'Use the "bzr up" command to switch to a '
 
6276
                            'different revision.'))
6390
6277
        if had_explicit_nick:
6391
 
            branch = control_dir.open_branch()  # get the new branch!
 
6278
            branch = control_dir.open_branch() #get the new branch!
6392
6279
            branch.nick = to_branch.nick
6393
 
        if to_branch.name:
6394
 
            if to_branch.controldir.control_url != control_dir.control_url:
6395
 
                note(gettext('Switched to branch %s at %s'),
6396
 
                     to_branch.name, urlutils.unescape_for_display(to_branch.base, 'utf-8'))
6397
 
            else:
6398
 
                note(gettext('Switched to branch %s'), to_branch.name)
6399
 
        else:
6400
 
            note(gettext('Switched to branch at %s'),
6401
 
                 urlutils.unescape_for_display(to_branch.base, 'utf-8'))
 
6280
        note(gettext('Switched to branch: %s'),
 
6281
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
 
6282
 
6402
6283
 
6403
6284
 
6404
6285
class cmd_view(Command):
6467
6348
    takes_args = ['file*']
6468
6349
    takes_options = [
6469
6350
        Option('all',
6470
 
               help='Apply list or delete action to all views.',
6471
 
               ),
 
6351
            help='Apply list or delete action to all views.',
 
6352
            ),
6472
6353
        Option('delete',
6473
 
               help='Delete the view.',
6474
 
               ),
 
6354
            help='Delete the view.',
 
6355
            ),
6475
6356
        Option('name',
6476
 
               help='Name of the view to define, list or delete.',
6477
 
               type=text_type,
6478
 
               ),
 
6357
            help='Name of the view to define, list or delete.',
 
6358
            type=text_type,
 
6359
            ),
6479
6360
        Option('switch',
6480
 
               help='Name of the view to switch to.',
6481
 
               type=text_type,
6482
 
               ),
 
6361
            help='Name of the view to switch to.',
 
6362
            type=text_type,
 
6363
            ),
6483
6364
        ]
6484
6365
 
6485
6366
    def run(self, file_list,
6489
6370
            switch=None,
6490
6371
            ):
6491
6372
        tree, file_list = WorkingTree.open_containing_paths(file_list,
6492
 
                                                            apply_view=False)
 
6373
            apply_view=False)
6493
6374
        current_view, view_dict = tree.views.get_view_info()
6494
6375
        if name is None:
6495
6376
            name = current_view
6504
6385
                tree.views.set_view_info(None, {})
6505
6386
                self.outf.write(gettext("Deleted all views.\n"))
6506
6387
            elif name is None:
6507
 
                raise errors.BzrCommandError(
6508
 
                    gettext("No current view to delete"))
 
6388
                raise errors.BzrCommandError(gettext("No current view to delete"))
6509
6389
            else:
6510
6390
                tree.views.delete_view(name)
6511
6391
                self.outf.write(gettext("Deleted '%s' view.\n") % name)
6518
6398
                    "Both --switch and --all specified"))
6519
6399
            elif switch == 'off':
6520
6400
                if current_view is None:
6521
 
                    raise errors.BzrCommandError(
6522
 
                        gettext("No current view to disable"))
 
6401
                    raise errors.BzrCommandError(gettext("No current view to disable"))
6523
6402
                tree.views.set_view_info(None, view_dict)
6524
 
                self.outf.write(gettext("Disabled '%s' view.\n") %
6525
 
                                (current_view))
 
6403
                self.outf.write(gettext("Disabled '%s' view.\n") % (current_view))
6526
6404
            else:
6527
6405
                tree.views.set_view_info(switch, view_dict)
6528
6406
                view_str = views.view_display_str(tree.views.lookup_view())
6529
 
                self.outf.write(
6530
 
                    gettext("Using '{0}' view: {1}\n").format(switch, view_str))
 
6407
                self.outf.write(gettext("Using '{0}' view: {1}\n").format(switch, view_str))
6531
6408
        elif all:
6532
6409
            if view_dict:
6533
6410
                self.outf.write(gettext('Views defined:\n'))
6549
6426
                    "Cannot change the 'off' pseudo view"))
6550
6427
            tree.views.set_view(name, sorted(file_list))
6551
6428
            view_str = views.view_display_str(tree.views.lookup_view())
6552
 
            self.outf.write(
6553
 
                gettext("Using '{0}' view: {1}\n").format(name, view_str))
 
6429
            self.outf.write(gettext("Using '{0}' view: {1}\n").format(name, view_str))
6554
6430
        else:
6555
6431
            # list the files
6556
6432
            if name is None:
6558
6434
                self.outf.write(gettext('No current view.\n'))
6559
6435
            else:
6560
6436
                view_str = views.view_display_str(tree.views.lookup_view(name))
6561
 
                self.outf.write(
6562
 
                    gettext("'{0}' view is: {1}\n").format(name, view_str))
 
6437
                self.outf.write(gettext("'{0}' view is: {1}\n").format(name, view_str))
6563
6438
 
6564
6439
 
6565
6440
class cmd_hooks(Command):
6585
6460
class cmd_remove_branch(Command):
6586
6461
    __doc__ = """Remove a branch.
6587
6462
 
6588
 
    This will remove the branch from the specified location but
 
6463
    This will remove the branch from the specified location but 
6589
6464
    will keep any working tree or repository in place.
6590
6465
 
6591
6466
    :Examples:
6599
6474
    takes_args = ["location?"]
6600
6475
 
6601
6476
    takes_options = ['directory',
6602
 
                     Option('force', help='Remove branch even if it is the active branch.')]
 
6477
        Option('force', help='Remove branch even if it is the active branch.')]
6603
6478
 
6604
6479
    aliases = ["rmbranch"]
6605
6480
 
6611
6486
            except errors.NotBranchError:
6612
6487
                active_branch = None
6613
6488
            if (active_branch is not None and
6614
 
                    br.control_url == active_branch.control_url):
 
6489
                br.control_url == active_branch.control_url):
6615
6490
                raise errors.BzrCommandError(
6616
6491
                    gettext("Branch is active. Use --force to remove it."))
6617
6492
        br.controldir.destroy_branch(br.name)
6645
6520
    editor program to decide what the file remaining in the working copy
6646
6521
    should look like.  To do this, add the configuration option
6647
6522
 
6648
 
        change_editor = PROGRAM {new_path} {old_path}
 
6523
        change_editor = PROGRAM @new_path @old_path
6649
6524
 
6650
 
    where {new_path} is replaced with the path of the new version of the
6651
 
    file and {old_path} is replaced with the path of the old version of
6652
 
    the file.  The PROGRAM should save the new file with the desired
 
6525
    where @new_path is replaced with the path of the new version of the 
 
6526
    file and @old_path is replaced with the path of the old version of 
 
6527
    the file.  The PROGRAM should save the new file with the desired 
6653
6528
    contents of the file in the working tree.
6654
 
 
 
6529
        
6655
6530
    """
6656
6531
 
6657
6532
    takes_args = ['file*']
6680
6555
            writer = breezy.option.diff_writer_registry.get()
6681
6556
        try:
6682
6557
            shelver = Shelver.from_args(writer(self.outf), revision, all,
6683
 
                                        file_list, message, destroy=destroy, directory=directory)
 
6558
                file_list, message, destroy=destroy, directory=directory)
6684
6559
            try:
6685
6560
                shelver.run()
6686
6561
            finally:
6692
6567
        if directory is None:
6693
6568
            directory = u'.'
6694
6569
        tree = WorkingTree.open_containing(directory)[0]
6695
 
        self.enter_context(tree.lock_read())
 
6570
        self.add_cleanup(tree.lock_read().unlock)
6696
6571
        manager = tree.get_shelf_manager()
6697
6572
        shelves = manager.active_shelves()
6698
6573
        if len(shelves) == 0:
6699
6574
            note(gettext('No shelved changes.'))
6700
6575
            return 0
6701
6576
        for shelf_id in reversed(shelves):
6702
 
            message = manager.get_metadata(shelf_id).get(b'message')
 
6577
            message = manager.get_metadata(shelf_id).get('message')
6703
6578
            if message is None:
6704
6579
                message = '<no message>'
6705
6580
            self.outf.write('%3d: %s\n' % (shelf_id, message))
6763
6638
                     Option('dry-run', help='Show files to delete instead of'
6764
6639
                            ' deleting them.'),
6765
6640
                     Option('force', help='Do not prompt before deleting.')]
6766
 
 
6767
6641
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
6768
6642
            force=False, directory=u'.'):
6769
6643
        from .clean_tree import clean_tree
6786
6660
    hidden = True
6787
6661
 
6788
6662
    takes_args = ['path?', 'location?']
6789
 
    takes_options = [
6790
 
        'directory',
6791
 
        Option('force-unversioned',
6792
 
               help='Set reference even if path is not versioned.'),
6793
 
        ]
6794
6663
 
6795
 
    def run(self, path=None, directory='.', location=None, force_unversioned=False):
6796
 
        tree, branch, relpath = (
6797
 
            controldir.ControlDir.open_containing_tree_or_branch(directory))
 
6664
    def run(self, path=None, location=None):
 
6665
        branchdir = '.'
 
6666
        if path is not None:
 
6667
            branchdir = path
 
6668
        tree, branch, relpath =(
 
6669
            controldir.ControlDir.open_containing_tree_or_branch(branchdir))
 
6670
        if path is not None:
 
6671
            path = relpath
6798
6672
        if tree is None:
6799
6673
            tree = branch.basis_tree()
6800
6674
        if path is None:
6801
 
            with tree.lock_read():
6802
 
                info = [
6803
 
                    (path, tree.get_reference_info(path, branch))
6804
 
                    for path in tree.iter_references()]
6805
 
                self._display_reference_info(tree, branch, info)
 
6675
            info = viewitems(branch._get_all_reference_info())
 
6676
            self._display_reference_info(tree, branch, info)
6806
6677
        else:
6807
 
            if not tree.is_versioned(path) and not force_unversioned:
 
6678
            if not tree.is_versioned(path):
6808
6679
                raise errors.NotVersionedError(path)
6809
6680
            if location is None:
6810
 
                info = [(path, tree.get_reference_info(path, branch))]
 
6681
                info = [(path, branch.get_reference_info(path))]
6811
6682
                self._display_reference_info(tree, branch, info)
6812
6683
            else:
6813
 
                tree.set_reference_info(path, location)
 
6684
                branch.set_reference_info(
 
6685
                    path, location, file_id=tree.path2id(path))
6814
6686
 
6815
6687
    def _display_reference_info(self, tree, branch, info):
6816
6688
        ref_list = []
6817
 
        for path, location in info:
 
6689
        for path, (location, file_id) in info:
6818
6690
            ref_list.append((path, location))
6819
6691
        for path, location in sorted(ref_list):
6820
6692
            self.outf.write('%s %s\n' % (path, location))
6825
6697
 
6826
6698
    hidden = True
6827
6699
    takes_options = [Option('plugin',
6828
 
                            help='Export help text from named command '
 
6700
                            help='Export help text from named command '\
6829
6701
                                 '(defaults to all built in commands).',
6830
6702
                            type=text_type),
6831
6703
                     Option('include-duplicates',
6832
6704
                            help='Output multiple copies of the same msgid '
6833
6705
                                 'string if it appears more than once.'),
6834
 
                     ]
 
6706
                            ]
6835
6707
 
6836
6708
    def run(self, plugin=None, include_duplicates=False):
6837
6709
        from .export_pot import export_pot
6871
6743
        from .transform import link_tree
6872
6744
        target_tree = WorkingTree.open_containing(".")[0]
6873
6745
        source_tree = WorkingTree.open(location)
6874
 
        with target_tree.lock_write(), source_tree.lock_read():
6875
 
            link_tree(target_tree, source_tree)
 
6746
        target_tree.lock_write()
 
6747
        try:
 
6748
            source_tree.lock_read()
 
6749
            try:
 
6750
                link_tree(target_tree, source_tree)
 
6751
            finally:
 
6752
                source_tree.unlock()
 
6753
        finally:
 
6754
            target_tree.unlock()
6876
6755
 
6877
6756
 
6878
6757
class cmd_fetch_ghosts(Command):
6892
6771
        if len(installed) > 0:
6893
6772
            self.outf.write("Installed:\n")
6894
6773
            for rev in installed:
6895
 
                self.outf.write(rev.decode('utf-8') + "\n")
 
6774
                self.outf.write(rev + "\n")
6896
6775
        if len(failed) > 0:
6897
6776
            self.outf.write("Still missing:\n")
6898
6777
            for rev in failed:
6899
 
                self.outf.write(rev.decode('utf-8') + "\n")
 
6778
                self.outf.write(rev + "\n")
6900
6779
        if not no_fix and len(installed) > 0:
6901
6780
            cmd_reconcile().run(".")
6902
6781
 
6903
6782
 
6904
 
class cmd_grep(Command):
6905
 
    """Print lines matching PATTERN for specified files and revisions.
6906
 
 
6907
 
    This command searches the specified files and revisions for a given
6908
 
    pattern.  The pattern is specified as a Python regular expressions[1].
6909
 
 
6910
 
    If the file name is not specified, the revisions starting with the
6911
 
    current directory are searched recursively. If the revision number is
6912
 
    not specified, the working copy is searched. To search the last committed
6913
 
    revision, use the '-r -1' or '-r last:1' option.
6914
 
 
6915
 
    Unversioned files are not searched unless explicitly specified on the
6916
 
    command line. Unversioned directores are not searched.
6917
 
 
6918
 
    When searching a pattern, the output is shown in the 'filepath:string'
6919
 
    format. If a revision is explicitly searched, the output is shown as
6920
 
    'filepath~N:string', where N is the revision number.
6921
 
 
6922
 
    --include and --exclude options can be used to search only (or exclude
6923
 
    from search) files with base name matches the specified Unix style GLOB
6924
 
    pattern.  The GLOB pattern an use *, ?, and [...] as wildcards, and \\
6925
 
    to quote wildcard or backslash character literally. Note that the glob
6926
 
    pattern is not a regular expression.
6927
 
 
6928
 
    [1] http://docs.python.org/library/re.html#regular-expression-syntax
6929
 
    """
6930
 
 
6931
 
    encoding_type = 'replace'
6932
 
    takes_args = ['pattern', 'path*']
6933
 
    takes_options = [
6934
 
        'verbose',
6935
 
        'revision',
6936
 
        Option('color', type=text_type, argname='when',
6937
 
               help='Show match in color. WHEN is never, always or auto.'),
6938
 
        Option('diff', short_name='p',
6939
 
               help='Grep for pattern in changeset for each revision.'),
6940
 
        ListOption('exclude', type=text_type, argname='glob', short_name='X',
6941
 
                   help="Skip files whose base name matches GLOB."),
6942
 
        ListOption('include', type=text_type, argname='glob', short_name='I',
6943
 
                   help="Search only files whose base name matches GLOB."),
6944
 
        Option('files-with-matches', short_name='l',
6945
 
               help='Print only the name of each input file in '
6946
 
               'which PATTERN is found.'),
6947
 
        Option('files-without-match', short_name='L',
6948
 
               help='Print only the name of each input file in '
6949
 
               'which PATTERN is not found.'),
6950
 
        Option('fixed-string', short_name='F',
6951
 
               help='Interpret PATTERN is a single fixed string (not regex).'),
6952
 
        Option('from-root',
6953
 
               help='Search for pattern starting from the root of the branch. '
6954
 
               '(implies --recursive)'),
6955
 
        Option('ignore-case', short_name='i',
6956
 
               help='Ignore case distinctions while matching.'),
6957
 
        Option('levels',
6958
 
               help='Number of levels to display - 0 for all, 1 for collapsed '
6959
 
               '(1 is default).',
6960
 
               argname='N',
6961
 
               type=_parse_levels),
6962
 
        Option('line-number', short_name='n',
6963
 
               help='Show 1-based line number.'),
6964
 
        Option('no-recursive',
6965
 
               help="Don't recurse into subdirectories. (default is --recursive)"),
6966
 
        Option('null', short_name='Z',
6967
 
               help='Write an ASCII NUL (\\0) separator '
6968
 
               'between output lines rather than a newline.'),
6969
 
        ]
6970
 
 
6971
 
    @display_command
6972
 
    def run(self, verbose=False, ignore_case=False, no_recursive=False,
6973
 
            from_root=False, null=False, levels=None, line_number=False,
6974
 
            path_list=None, revision=None, pattern=None, include=None,
6975
 
            exclude=None, fixed_string=False, files_with_matches=False,
6976
 
            files_without_match=False, color=None, diff=False):
6977
 
        from breezy import _termcolor
6978
 
        from . import grep
6979
 
        import re
6980
 
        if path_list is None:
6981
 
            path_list = ['.']
6982
 
        else:
6983
 
            if from_root:
6984
 
                raise errors.BzrCommandError(
6985
 
                    'cannot specify both --from-root and PATH.')
6986
 
 
6987
 
        if files_with_matches and files_without_match:
6988
 
            raise errors.BzrCommandError(
6989
 
                'cannot specify both '
6990
 
                '-l/--files-with-matches and -L/--files-without-matches.')
6991
 
 
6992
 
        global_config = _mod_config.GlobalConfig()
6993
 
 
6994
 
        if color is None:
6995
 
            color = global_config.get_user_option('grep_color')
6996
 
 
6997
 
        if color is None:
6998
 
            color = 'never'
6999
 
 
7000
 
        if color not in ['always', 'never', 'auto']:
7001
 
            raise errors.BzrCommandError('Valid values for --color are '
7002
 
                                         '"always", "never" or "auto".')
7003
 
 
7004
 
        if levels is None:
7005
 
            levels = 1
7006
 
 
7007
 
        print_revno = False
7008
 
        if revision is not None or levels == 0:
7009
 
            # print revision numbers as we may be showing multiple revisions
7010
 
            print_revno = True
7011
 
 
7012
 
        eol_marker = '\n'
7013
 
        if null:
7014
 
            eol_marker = '\0'
7015
 
 
7016
 
        if not ignore_case and grep.is_fixed_string(pattern):
7017
 
            # if the pattern isalnum, implicitly use to -F for faster grep
7018
 
            fixed_string = True
7019
 
        elif ignore_case and fixed_string:
7020
 
            # GZ 2010-06-02: Fall back to regexp rather than lowercasing
7021
 
            #                pattern and text which will cause pain later
7022
 
            fixed_string = False
7023
 
            pattern = re.escape(pattern)
7024
 
 
7025
 
        patternc = None
7026
 
        re_flags = re.MULTILINE
7027
 
        if ignore_case:
7028
 
            re_flags |= re.IGNORECASE
7029
 
 
7030
 
        if not fixed_string:
7031
 
            patternc = grep.compile_pattern(
7032
 
                pattern.encode(grep._user_encoding), re_flags)
7033
 
 
7034
 
        if color == 'always':
7035
 
            show_color = True
7036
 
        elif color == 'never':
7037
 
            show_color = False
7038
 
        elif color == 'auto':
7039
 
            show_color = _termcolor.allow_color()
7040
 
 
7041
 
        opts = grep.GrepOptions()
7042
 
 
7043
 
        opts.verbose = verbose
7044
 
        opts.ignore_case = ignore_case
7045
 
        opts.no_recursive = no_recursive
7046
 
        opts.from_root = from_root
7047
 
        opts.null = null
7048
 
        opts.levels = levels
7049
 
        opts.line_number = line_number
7050
 
        opts.path_list = path_list
7051
 
        opts.revision = revision
7052
 
        opts.pattern = pattern
7053
 
        opts.include = include
7054
 
        opts.exclude = exclude
7055
 
        opts.fixed_string = fixed_string
7056
 
        opts.files_with_matches = files_with_matches
7057
 
        opts.files_without_match = files_without_match
7058
 
        opts.color = color
7059
 
        opts.diff = False
7060
 
 
7061
 
        opts.eol_marker = eol_marker
7062
 
        opts.print_revno = print_revno
7063
 
        opts.patternc = patternc
7064
 
        opts.recursive = not no_recursive
7065
 
        opts.fixed_string = fixed_string
7066
 
        opts.outf = self.outf
7067
 
        opts.show_color = show_color
7068
 
 
7069
 
        if diff:
7070
 
            # options not used:
7071
 
            # files_with_matches, files_without_match
7072
 
            # levels(?), line_number, from_root
7073
 
            # include, exclude
7074
 
            # These are silently ignored.
7075
 
            grep.grep_diff(opts)
7076
 
        elif revision is None:
7077
 
            grep.workingtree_grep(opts)
7078
 
        else:
7079
 
            grep.versioned_grep(opts)
7080
 
 
7081
 
 
7082
 
class cmd_patch(Command):
7083
 
    """Apply a named patch to the current tree.
7084
 
 
7085
 
    """
7086
 
 
7087
 
    takes_args = ['filename?']
7088
 
    takes_options = [Option('strip', type=int, short_name='p',
7089
 
                            help=("Strip the smallest prefix containing num "
7090
 
                                  "leading slashes from filenames.")),
7091
 
                     Option('silent', help='Suppress chatter.')]
7092
 
 
7093
 
    def run(self, filename=None, strip=None, silent=False):
7094
 
        from .patch import patch_tree
7095
 
        wt = WorkingTree.open_containing('.')[0]
7096
 
        if strip is None:
7097
 
            strip = 1
7098
 
        my_file = None
7099
 
        if filename is None:
7100
 
            my_file = getattr(sys.stdin, 'buffer', sys.stdin)
7101
 
        else:
7102
 
            my_file = open(filename, 'rb')
7103
 
        patches = [my_file.read()]
7104
 
        return patch_tree(wt, patches, strip, quiet=is_quiet(), out=self.outf)
7105
 
 
7106
 
 
7107
 
class cmd_resolve_location(Command):
7108
 
    __doc__ = """Expand a location to a full URL.
7109
 
 
7110
 
    :Examples:
7111
 
        Look up a Launchpad URL.
7112
 
 
7113
 
            brz resolve-location lp:brz
7114
 
    """
7115
 
    takes_args = ['location']
7116
 
    hidden = True
7117
 
 
7118
 
    def run(self, location):
7119
 
        from .location import location_to_url
7120
 
        url = location_to_url(location)
7121
 
        display_url = urlutils.unescape_for_display(url, self.outf.encoding)
7122
 
        self.outf.write('%s\n' % display_url)
7123
 
 
7124
 
 
7125
6783
def _register_lazy_builtins():
7126
6784
    # register lazy builtins from other modules; called at startup and should
7127
6785
    # be only called once.
7128
6786
    for (name, aliases, module_name) in [
7129
 
            ('cmd_bisect', [], 'breezy.bisect'),
7130
 
            ('cmd_bundle_info', [], 'breezy.bzr.bundle.commands'),
7131
 
            ('cmd_config', [], 'breezy.config'),
7132
 
            ('cmd_dump_btree', [], 'breezy.bzr.debug_commands'),
7133
 
            ('cmd_file_id', [], 'breezy.bzr.debug_commands'),
7134
 
            ('cmd_file_path', [], 'breezy.bzr.debug_commands'),
7135
 
            ('cmd_version_info', [], 'breezy.cmd_version_info'),
7136
 
            ('cmd_resolve', ['resolved'], 'breezy.conflicts'),
7137
 
            ('cmd_conflicts', [], 'breezy.conflicts'),
7138
 
            ('cmd_ping', [], 'breezy.bzr.smart.ping'),
7139
 
            ('cmd_sign_my_commits', [], 'breezy.commit_signature_commands'),
7140
 
            ('cmd_verify_signatures', [], 'breezy.commit_signature_commands'),
7141
 
            ('cmd_test_script', [], 'breezy.cmd_test_script'),
7142
 
            ]:
 
6787
        ('cmd_bisect', [], 'breezy.bisect'),
 
6788
        ('cmd_bundle_info', [], 'breezy.bundle.commands'),
 
6789
        ('cmd_config', [], 'breezy.config'),
 
6790
        ('cmd_dump_btree', [], 'breezy.bzr.debug_commands'),
 
6791
        ('cmd_dpush', [], 'breezy.foreign'),
 
6792
        ('cmd_version_info', [], 'breezy.cmd_version_info'),
 
6793
        ('cmd_resolve', ['resolved'], 'breezy.conflicts'),
 
6794
        ('cmd_conflicts', [], 'breezy.conflicts'),
 
6795
        ('cmd_ping', [], 'breezy.bzr.smart.ping'),
 
6796
        ('cmd_sign_my_commits', [], 'breezy.commit_signature_commands'),
 
6797
        ('cmd_verify_signatures', [], 'breezy.commit_signature_commands'),
 
6798
        ('cmd_test_script', [], 'breezy.cmd_test_script'),
 
6799
        ]:
7143
6800
        builtin_command_registry.register_lazy(name, aliases, module_name)