/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: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""builtin brz commands"""
18
18
 
 
19
from __future__ import absolute_import
 
20
 
19
21
import errno
20
22
import os
21
23
import sys
22
24
 
23
 
import breezy.bzr
24
 
import breezy.git
25
 
 
26
 
from . import (
27
 
    errors,
28
 
    )
 
25
import breezy.bzr.bzrdir
29
26
 
30
27
from . import lazy_import
31
28
lazy_import.lazy_import(globals(), """
33
30
 
34
31
import breezy
35
32
from breezy import (
36
 
    branch as _mod_branch,
37
33
    bugtracker,
 
34
    bundle,
 
35
    btree_index,
38
36
    cache_utf8,
39
37
    controldir,
40
38
    directory_service,
41
39
    delta,
42
40
    config as _mod_config,
 
41
    errors,
43
42
    globbing,
44
 
    gpg,
45
43
    hooks,
46
 
    lazy_regex,
47
44
    log,
48
45
    merge as _mod_merge,
49
 
    mergeable as _mod_mergeable,
50
46
    merge_directive,
51
47
    osutils,
52
48
    reconfigure,
53
49
    rename_map,
54
50
    revision as _mod_revision,
 
51
    static_tuple,
55
52
    symbol_versioning,
56
53
    timestamp,
57
54
    transport,
58
 
    tree as _mod_tree,
59
55
    ui,
60
56
    urlutils,
61
57
    views,
 
58
    gpg,
62
59
    )
63
60
from breezy.branch import Branch
64
61
from breezy.conflicts import ConflictList
65
62
from breezy.transport import memory
 
63
from breezy.revisionspec import RevisionSpec, RevisionInfo
66
64
from breezy.smtp_connection import SMTPConnection
67
65
from breezy.workingtree import WorkingTree
68
66
from breezy.i18n import gettext, ngettext
80
78
    custom_help,
81
79
    _parse_revision_str,
82
80
    )
83
 
from .revisionspec import (
84
 
    RevisionSpec,
85
 
    RevisionInfo,
86
 
    )
 
81
from .sixish import (
 
82
    BytesIO,
 
83
    text_type,
 
84
    viewitems,
 
85
    viewvalues,
 
86
)
87
87
from .trace import mutter, note, warning, is_quiet, get_verbosity_level
88
88
 
89
89
 
113
113
        and the full URL to the actual branch
114
114
    """
115
115
    # This path is meant to be relative to the existing branch
116
 
    this_url = _get_branch_location(
117
 
        control_dir, possible_transports=possible_transports)
 
116
    this_url = _get_branch_location(control_dir,
 
117
        possible_transports=possible_transports)
118
118
    # Perhaps the target control dir supports colocated branches?
119
119
    try:
120
 
        root = controldir.ControlDir.open(
121
 
            this_url, possible_transports=possible_transports)
 
120
        root = controldir.ControlDir.open(this_url,
 
121
            possible_transports=possible_transports)
122
122
    except errors.NotBranchError:
123
123
        return (False, this_url)
124
124
    else:
125
125
        try:
126
 
            control_dir.open_workingtree()
 
126
            wt = control_dir.open_workingtree()
127
127
        except (errors.NoWorkingTree, errors.NotLocalUrl):
128
128
            return (False, this_url)
129
129
        else:
145
145
        (colocated, this_url) = _is_colocated(control_dir, possible_transports)
146
146
 
147
147
        if colocated:
148
 
            return urlutils.join_segment_parameters(
149
 
                this_url, {"branch": urlutils.escape(location)})
 
148
            return urlutils.join_segment_parameters(this_url,
 
149
                {"branch": urlutils.escape(location)})
150
150
        else:
151
151
            return urlutils.join(this_url, '..', urlutils.escape(location))
152
152
    return location
162
162
    """
163
163
    try:
164
164
        # Perhaps it's a colocated branch?
165
 
        return control_dir.open_branch(
166
 
            location, possible_transports=possible_transports)
 
165
        return control_dir.open_branch(location, 
 
166
            possible_transports=possible_transports)
167
167
    except (errors.NotBranchError, errors.NoColocatedBranchSupport):
168
168
        this_url = _get_branch_location(control_dir)
169
169
        return Branch.open(
182
182
        if location is None:
183
183
            location = "."
184
184
        try:
185
 
            return Branch.open(
186
 
                location, possible_transports=possible_transports)
 
185
            return Branch.open(location,
 
186
                possible_transports=possible_transports)
187
187
        except errors.NotBranchError:
188
188
            near = "."
189
 
    cdir = controldir.ControlDir.open(
190
 
        near, possible_transports=possible_transports)
191
 
    return open_sibling_branch(
192
 
        cdir, location, possible_transports=possible_transports)
 
189
    cdir = controldir.ControlDir.open(near,
 
190
        possible_transports=possible_transports)
 
191
    return open_sibling_branch(cdir, location,
 
192
        possible_transports=possible_transports)
193
193
 
194
194
 
195
195
def iter_sibling_branches(control_dir, possible_transports=None):
198
198
    :param control_dir: Control directory for which to look up the siblings
199
199
    :return: Iterator over tuples with branch name and branch object
200
200
    """
 
201
    seen_urls = set()
201
202
    try:
202
203
        reference = control_dir.get_branch_reference()
203
204
    except errors.NotBranchError:
204
 
        reference = None
 
205
        # There is no active branch, just return the colocated branches.
 
206
        for name, branch in viewitems(control_dir.get_branches()):
 
207
            yield name, branch
 
208
        return
205
209
    if reference is not None:
206
 
        try:
207
 
            ref_branch = Branch.open(
208
 
                reference, possible_transports=possible_transports)
209
 
        except errors.NotBranchError:
210
 
            ref_branch = None
 
210
        ref_branch = Branch.open(reference,
 
211
            possible_transports=possible_transports)
211
212
    else:
212
213
        ref_branch = None
213
214
    if ref_branch is None or ref_branch.name:
214
215
        if ref_branch is not None:
215
 
            control_dir = ref_branch.controldir
216
 
        for name, branch in control_dir.get_branches().items():
 
216
            control_dir = ref_branch.bzrdir
 
217
        for name, branch in viewitems(control_dir.get_branches()):
217
218
            yield name, branch
218
219
    else:
219
 
        repo = ref_branch.controldir.find_repository()
 
220
        repo = ref_branch.bzrdir.find_repository()
220
221
        for branch in repo.find_branches(using=True):
221
 
            name = urlutils.relative_url(
222
 
                repo.user_url, branch.user_url).rstrip("/")
 
222
            name = urlutils.relative_url(repo.user_url,
 
223
                branch.user_url).rstrip("/")
223
224
            yield name, branch
224
225
 
225
226
 
241
242
            if view_files:
242
243
                for filename in file_list:
243
244
                    if not osutils.is_inside_any(view_files, filename):
244
 
                        raise views.FileOutsideView(filename, view_files)
 
245
                        raise errors.FileOutsideView(filename, view_files)
245
246
        file_list = file_list[:]
246
247
        file_list[0] = tree.abspath(relpath)
247
248
    else:
251
252
            if view_files:
252
253
                file_list = view_files
253
254
                view_str = views.view_display_str(view_files)
254
 
                note(gettext("Ignoring files outside view. View is %s"),
255
 
                     view_str)
 
255
                note(gettext("Ignoring files outside view. View is %s") % view_str)
256
256
    return tree, file_list
257
257
 
258
258
 
260
260
    if revisions is None:
261
261
        return None
262
262
    if len(revisions) != 1:
263
 
        raise errors.CommandError(gettext(
 
263
        raise errors.BzrCommandError(gettext(
264
264
            'brz %s --revision takes exactly one revision identifier') % (
265
265
                command_name,))
266
266
    return revisions[0]
268
268
 
269
269
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
270
270
    """Get a revision tree. Not suitable for commands that change the tree.
271
 
 
 
271
    
272
272
    Specifically, the basis tree in dirstate trees is coupled to the dirstate
273
273
    and doing a commit/uncommit/pull will at best fail due to changing the
274
274
    basis revision data.
296
296
        current_view = tree.views.get_view_info()[0]
297
297
        if current_view is not None:
298
298
            view_info = (current_view, tree.views.lookup_view())
299
 
    except views.ViewsNotSupported:
 
299
    except errors.ViewsNotSupported:
300
300
        pass
301
301
    return view_info
302
302
 
343
343
        Not versioned and not matching an ignore pattern.
344
344
 
345
345
    Additionally for directories, symlinks and files with a changed
346
 
    executable bit, Breezy indicates their type using a trailing
 
346
    executable bit, Bazaar indicates their type using a trailing
347
347
    character: '/', '@' or '*' respectively. These decorations can be
348
348
    disabled using the '--no-classify' option.
349
349
 
380
380
                            short_name='S'),
381
381
                     Option('versioned', help='Only show versioned files.',
382
382
                            short_name='V'),
383
 
                     Option('no-pending', help='Don\'t show pending merges.'),
 
383
                     Option('no-pending', help='Don\'t show pending merges.',
 
384
                           ),
384
385
                     Option('no-classify',
385
 
                            help='Do not mark object type using indicator.'),
 
386
                            help='Do not mark object type using indicator.',
 
387
                           ),
386
388
                     ]
387
389
    aliases = ['st', 'stat']
388
390
 
396
398
        from .status import show_tree_status
397
399
 
398
400
        if revision and len(revision) > 2:
399
 
            raise errors.CommandError(
400
 
                gettext('brz status --revision takes exactly'
401
 
                        ' one or two revision specifiers'))
 
401
            raise errors.BzrCommandError(gettext('brz status --revision takes exactly'
 
402
                                         ' one or two revision specifiers'))
402
403
 
403
404
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
404
405
        # Avoid asking for specific files when that is not needed.
441
442
    @display_command
442
443
    def run(self, revision_id=None, revision=None, directory=u'.'):
443
444
        if revision_id is not None and revision is not None:
444
 
            raise errors.CommandError(gettext('You can only supply one of'
445
 
                                                 ' revision_id or --revision'))
 
445
            raise errors.BzrCommandError(gettext('You can only supply one of'
 
446
                                         ' revision_id or --revision'))
446
447
        if revision_id is None and revision is None:
447
 
            raise errors.CommandError(
448
 
                gettext('You must supply either --revision or a revision_id'))
 
448
            raise errors.BzrCommandError(gettext('You must supply either'
 
449
                                         ' --revision or a revision_id'))
449
450
 
450
451
        b = controldir.ControlDir.open_containing_tree_or_branch(directory)[1]
451
452
 
452
 
        revisions = getattr(b.repository, "revisions", None)
 
453
        revisions = b.repository.revisions
453
454
        if revisions is None:
454
 
            raise errors.CommandError(
455
 
                gettext('Repository %r does not support '
456
 
                        'access to raw revision texts') % b.repository)
 
455
            raise errors.BzrCommandError(gettext('Repository %r does not support '
 
456
                'access to raw revision texts'))
457
457
 
458
 
        with b.repository.lock_read():
 
458
        b.repository.lock_read()
 
459
        try:
459
460
            # TODO: jam 20060112 should cat-revision always output utf-8?
460
461
            if revision_id is not None:
461
462
                revision_id = cache_utf8.encode(revision_id)
462
463
                try:
463
464
                    self.print_revision(revisions, revision_id)
464
465
                except errors.NoSuchRevision:
465
 
                    msg = gettext(
466
 
                        "The repository {0} contains no revision {1}.").format(
467
 
                            b.repository.base, revision_id.decode('utf-8'))
468
 
                    raise errors.CommandError(msg)
 
466
                    msg = gettext("The repository {0} contains no revision {1}.").format(
 
467
                        b.repository.base, revision_id)
 
468
                    raise errors.BzrCommandError(msg)
469
469
            elif revision is not None:
470
470
                for rev in revision:
471
471
                    if rev is None:
472
 
                        raise errors.CommandError(
 
472
                        raise errors.BzrCommandError(
473
473
                            gettext('You cannot specify a NULL revision.'))
474
474
                    rev_id = rev.as_revision_id(b)
475
475
                    self.print_revision(revisions, rev_id)
 
476
        finally:
 
477
            b.repository.unlock()
 
478
        
 
479
 
 
480
class cmd_dump_btree(Command):
 
481
    __doc__ = """Dump the contents of a btree index file to stdout.
 
482
 
 
483
    PATH is a btree index file, it can be any URL. This includes things like
 
484
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
 
485
 
 
486
    By default, the tuples stored in the index file will be displayed. With
 
487
    --raw, we will uncompress the pages, but otherwise display the raw bytes
 
488
    stored in the index.
 
489
    """
 
490
 
 
491
    # TODO: Do we want to dump the internal nodes as well?
 
492
    # TODO: It would be nice to be able to dump the un-parsed information,
 
493
    #       rather than only going through iter_all_entries. However, this is
 
494
    #       good enough for a start
 
495
    hidden = True
 
496
    encoding_type = 'exact'
 
497
    takes_args = ['path']
 
498
    takes_options = [Option('raw', help='Write the uncompressed bytes out,'
 
499
                                        ' rather than the parsed tuples.'),
 
500
                    ]
 
501
 
 
502
    def run(self, path, raw=False):
 
503
        dirname, basename = osutils.split(path)
 
504
        t = transport.get_transport(dirname)
 
505
        if raw:
 
506
            self._dump_raw_bytes(t, basename)
 
507
        else:
 
508
            self._dump_entries(t, basename)
 
509
 
 
510
    def _get_index_and_bytes(self, trans, basename):
 
511
        """Create a BTreeGraphIndex and raw bytes."""
 
512
        bt = btree_index.BTreeGraphIndex(trans, basename, None)
 
513
        bytes = trans.get_bytes(basename)
 
514
        bt._file = BytesIO(bytes)
 
515
        bt._size = len(bytes)
 
516
        return bt, bytes
 
517
 
 
518
    def _dump_raw_bytes(self, trans, basename):
 
519
        import zlib
 
520
 
 
521
        # We need to parse at least the root node.
 
522
        # This is because the first page of every row starts with an
 
523
        # uncompressed header.
 
524
        bt, bytes = self._get_index_and_bytes(trans, basename)
 
525
        for page_idx, page_start in enumerate(range(0, len(bytes),
 
526
                                                    btree_index._PAGE_SIZE)):
 
527
            page_end = min(page_start + btree_index._PAGE_SIZE, len(bytes))
 
528
            page_bytes = bytes[page_start:page_end]
 
529
            if page_idx == 0:
 
530
                self.outf.write('Root node:\n')
 
531
                header_end, data = bt._parse_header_from_bytes(page_bytes)
 
532
                self.outf.write(page_bytes[:header_end])
 
533
                page_bytes = data
 
534
            self.outf.write('\nPage %d\n' % (page_idx,))
 
535
            if len(page_bytes) == 0:
 
536
                self.outf.write('(empty)\n');
 
537
            else:
 
538
                decomp_bytes = zlib.decompress(page_bytes)
 
539
                self.outf.write(decomp_bytes)
 
540
                self.outf.write('\n')
 
541
 
 
542
    def _dump_entries(self, trans, basename):
 
543
        try:
 
544
            st = trans.stat(basename)
 
545
        except errors.TransportNotPossible:
 
546
            # We can't stat, so we'll fake it because we have to do the 'get()'
 
547
            # anyway.
 
548
            bt, _ = self._get_index_and_bytes(trans, basename)
 
549
        else:
 
550
            bt = btree_index.BTreeGraphIndex(trans, basename, st.st_size)
 
551
        for node in bt.iter_all_entries():
 
552
            # Node is made up of:
 
553
            # (index, key, value, [references])
 
554
            try:
 
555
                refs = node[3]
 
556
            except IndexError:
 
557
                refs_as_tuples = None
 
558
            else:
 
559
                refs_as_tuples = static_tuple.as_tuples(refs)
 
560
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
 
561
            self.outf.write('%s\n' % (as_tuple,))
476
562
 
477
563
 
478
564
class cmd_remove_tree(Command):
493
579
 
494
580
    def run(self, location_list, force=False):
495
581
        if not location_list:
496
 
            location_list = ['.']
 
582
            location_list=['.']
497
583
 
498
584
        for location in location_list:
499
585
            d = controldir.ControlDir.open(location)
501
587
            try:
502
588
                working = d.open_workingtree()
503
589
            except errors.NoWorkingTree:
504
 
                raise errors.CommandError(
505
 
                    gettext("No working tree to remove"))
 
590
                raise errors.BzrCommandError(gettext("No working tree to remove"))
506
591
            except errors.NotLocalUrl:
507
 
                raise errors.CommandError(
508
 
                    gettext("You cannot remove the working tree"
509
 
                            " of a remote path"))
 
592
                raise errors.BzrCommandError(gettext("You cannot remove the working tree"
 
593
                                             " of a remote path"))
510
594
            if not force:
511
595
                if (working.has_changes()):
512
596
                    raise errors.UncommittedChanges(working)
514
598
                    raise errors.ShelvedChanges(working)
515
599
 
516
600
            if working.user_url != working.branch.user_url:
517
 
                raise errors.CommandError(
518
 
                    gettext("You cannot remove the working tree"
519
 
                            " from a lightweight checkout"))
 
601
                raise errors.BzrCommandError(gettext("You cannot remove the working tree"
 
602
                                             " from a lightweight checkout"))
520
603
 
521
604
            d.destroy_workingtree()
522
605
 
537
620
    that, you can supply --revision to force the state of the tree.
538
621
    """
539
622
 
540
 
    takes_options = [
541
 
        'revision', 'directory',
 
623
    takes_options = ['revision', 'directory',
542
624
        Option('force',
543
625
               help='Reset the tree even if it doesn\'t appear to be'
544
626
                    ' corrupted.'),
547
629
 
548
630
    def run(self, revision=None, directory='.', force=False):
549
631
        tree, _ = WorkingTree.open_containing(directory)
550
 
        self.enter_context(tree.lock_tree_write())
 
632
        self.add_cleanup(tree.lock_tree_write().unlock)
551
633
        if not force:
552
634
            try:
553
635
                tree.check_state()
554
636
            except errors.BzrError:
555
 
                pass  # There seems to be a real error here, so we'll reset
 
637
                pass # There seems to be a real error here, so we'll reset
556
638
            else:
557
639
                # Refuse
558
 
                raise errors.CommandError(gettext(
 
640
                raise errors.BzrCommandError(gettext(
559
641
                    'The tree does not appear to be corrupt. You probably'
560
642
                    ' want "brz revert" instead. Use "--force" if you are'
561
643
                    ' sure you want to reset the working tree.'))
565
647
            revision_ids = [r.as_revision_id(tree.branch) for r in revision]
566
648
        try:
567
649
            tree.reset_state(revision_ids)
568
 
        except errors.BzrError:
 
650
        except errors.BzrError as e:
569
651
            if revision_ids is None:
570
 
                extra = gettext(', the header appears corrupt, try passing '
571
 
                                '-r -1 to set the state to the last commit')
 
652
                extra = (gettext(', the header appears corrupt, try passing -r -1'
 
653
                         ' to set the state to the last commit'))
572
654
            else:
573
655
                extra = ''
574
 
            raise errors.CommandError(
575
 
                gettext('failed to reset the tree state{0}').format(extra))
 
656
            raise errors.BzrCommandError(gettext('failed to reset the tree state{0}').format(extra))
576
657
 
577
658
 
578
659
class cmd_revno(Command):
591
672
    @display_command
592
673
    def run(self, tree=False, location=u'.', revision=None):
593
674
        if revision is not None and tree:
594
 
            raise errors.CommandError(
595
 
                gettext("--tree and --revision can not be used together"))
 
675
            raise errors.BzrCommandError(gettext("--tree and --revision can "
 
676
                "not be used together"))
596
677
 
597
678
        if tree:
598
679
            try:
599
680
                wt = WorkingTree.open_containing(location)[0]
600
 
                self.enter_context(wt.lock_read())
 
681
                self.add_cleanup(wt.lock_read().unlock)
601
682
            except (errors.NoWorkingTree, errors.NotLocalUrl):
602
683
                raise errors.NoWorkingTree(location)
603
684
            b = wt.branch
604
685
            revid = wt.last_revision()
605
686
        else:
606
687
            b = Branch.open_containing(location)[0]
607
 
            self.enter_context(b.lock_read())
 
688
            self.add_cleanup(b.lock_read().unlock)
608
689
            if revision:
609
690
                if len(revision) != 1:
610
 
                    raise errors.CommandError(gettext(
 
691
                    raise errors.BzrCommandError(gettext(
611
692
                        "Revision numbers only make sense for single "
612
693
                        "revisions, not ranges"))
613
694
                revid = revision[0].as_revision_id(b)
615
696
                revid = b.last_revision()
616
697
        try:
617
698
            revno_t = b.revision_id_to_dotted_revno(revid)
618
 
        except (errors.NoSuchRevision, errors.GhostRevisionsHaveNoRevno):
 
699
        except errors.NoSuchRevision:
619
700
            revno_t = ('???',)
620
701
        revno = ".".join(str(n) for n in revno_t)
621
702
        self.cleanup_now()
629
710
    takes_args = ['revision_info*']
630
711
    takes_options = [
631
712
        'revision',
632
 
        custom_help('directory', help='Branch to examine, '
633
 
                    'rather than the one containing the working directory.'),
 
713
        custom_help('directory',
 
714
            help='Branch to examine, '
 
715
                 'rather than the one containing the working directory.'),
634
716
        Option('tree', help='Show revno of working tree.'),
635
717
        ]
636
718
 
641
723
        try:
642
724
            wt = WorkingTree.open_containing(directory)[0]
643
725
            b = wt.branch
644
 
            self.enter_context(wt.lock_read())
 
726
            self.add_cleanup(wt.lock_read().unlock)
645
727
        except (errors.NoWorkingTree, errors.NotLocalUrl):
646
728
            wt = None
647
729
            b = Branch.open_containing(directory)[0]
648
 
            self.enter_context(b.lock_read())
 
730
            self.add_cleanup(b.lock_read().unlock)
649
731
        revision_ids = []
650
732
        if revision is not None:
651
733
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
671
753
            except errors.NoSuchRevision:
672
754
                revno = '???'
673
755
            maxlen = max(maxlen, len(revno))
674
 
            revinfos.append((revno, revision_id))
 
756
            revinfos.append([revno, revision_id])
675
757
 
676
758
        self.cleanup_now()
677
 
        for revno, revid in revinfos:
678
 
            self.outf.write(
679
 
                '%*s %s\n' % (maxlen, revno, revid.decode('utf-8')))
 
759
        for ri in revinfos:
 
760
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
680
761
 
681
762
 
682
763
class cmd_add(Command):
715
796
    branches that will be merged later (without showing the two different
716
797
    adds as a conflict). It is also useful when merging another project
717
798
    into a subdirectory of this one.
718
 
 
 
799
    
719
800
    Any files matching patterns in the ignore list will not be added
720
801
    unless they are explicitly mentioned.
721
 
 
722
 
    In recursive mode, files larger than the configuration option
 
802
    
 
803
    In recursive mode, files larger than the configuration option 
723
804
    add.maximum_file_size will be skipped. Named items are never skipped due
724
805
    to file size.
725
806
    """
729
810
               help="Don't recursively add the contents of directories.",
730
811
               short_name='N'),
731
812
        Option('dry-run',
732
 
               help="Show what would be done, but don't actually do "
733
 
                    "anything."),
 
813
               help="Show what would be done, but don't actually do anything."),
734
814
        'verbose',
735
815
        Option('file-ids-from',
736
 
               type=str,
 
816
               type=text_type,
737
817
               help='Lookup file ids from this tree.'),
738
818
        ]
739
819
    encoding_type = 'replace'
742
822
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
743
823
            file_ids_from=None):
744
824
        import breezy.add
745
 
        tree, file_list = tree_files_for_add(file_list)
746
 
 
747
 
        if file_ids_from is not None and not tree.supports_setting_file_ids():
748
 
            warning(
749
 
                gettext('Ignoring --file-ids-from, since the tree does not '
750
 
                        'support setting file ids.'))
751
 
            file_ids_from = None
752
825
 
753
826
        base_tree = None
754
827
        if file_ids_from is not None:
755
828
            try:
756
829
                base_tree, base_path = WorkingTree.open_containing(
757
 
                    file_ids_from)
 
830
                                            file_ids_from)
758
831
            except errors.NoWorkingTree:
759
832
                base_branch, base_path = Branch.open_containing(
760
 
                    file_ids_from)
 
833
                                            file_ids_from)
761
834
                base_tree = base_branch.basis_tree()
762
835
 
763
 
            action = breezy.add.AddFromBaseAction(
764
 
                base_tree, base_path, to_file=self.outf,
 
836
            action = breezy.add.AddFromBaseAction(base_tree, base_path,
 
837
                          to_file=self.outf, should_print=(not is_quiet()))
 
838
        else:
 
839
            action = breezy.add.AddWithSkipLargeAction(to_file=self.outf,
765
840
                should_print=(not is_quiet()))
766
 
        else:
767
 
            action = breezy.add.AddWithSkipLargeAction(
768
 
                to_file=self.outf, should_print=(not is_quiet()))
769
841
 
770
842
        if base_tree:
771
 
            self.enter_context(base_tree.lock_read())
772
 
        added, ignored = tree.smart_add(
773
 
            file_list, not no_recurse, action=action, save=not dry_run)
 
843
            self.add_cleanup(base_tree.lock_read().unlock)
 
844
        tree, file_list = tree_files_for_add(file_list)
 
845
        added, ignored = tree.smart_add(file_list, not
 
846
            no_recurse, action=action, save=not dry_run)
774
847
        self.cleanup_now()
775
848
        if len(ignored) > 0:
776
849
            if verbose:
777
850
                for glob in sorted(ignored):
778
851
                    for path in ignored[glob]:
779
852
                        self.outf.write(
780
 
                            gettext("ignored {0} matching \"{1}\"\n").format(
781
 
                                path, glob))
 
853
                         gettext("ignored {0} matching \"{1}\"\n").format(
 
854
                         path, glob))
782
855
 
783
856
 
784
857
class cmd_mkdir(Command):
799
872
 
800
873
    @classmethod
801
874
    def add_file_with_parents(cls, wt, relpath):
802
 
        if wt.is_versioned(relpath):
 
875
        if wt.path2id(relpath) is not None:
803
876
            return
804
877
        cls.add_file_with_parents(wt, osutils.dirname(relpath))
805
878
        wt.add([relpath])
858
931
    takes_options = [
859
932
        'revision',
860
933
        'show-ids',
861
 
        Option('include-root',
862
 
               help='Include the entry for the root of the tree, if any.'),
863
934
        Option('kind',
864
 
               help='List entries of a particular kind: file, directory, '
865
 
                    'symlink.',
866
 
               type=str),
 
935
               help='List entries of a particular kind: file, directory, symlink.',
 
936
               type=text_type),
867
937
        ]
868
938
    takes_args = ['file*']
869
939
 
870
940
    @display_command
871
 
    def run(self, revision=None, show_ids=False, kind=None, include_root=False,
872
 
            file_list=None):
 
941
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
873
942
        if kind and kind not in ['file', 'directory', 'symlink']:
874
 
            raise errors.CommandError(
875
 
                gettext('invalid kind %r specified') % (kind,))
 
943
            raise errors.BzrCommandError(gettext('invalid kind %r specified') % (kind,))
876
944
 
877
945
        revision = _get_one_revision('inventory', revision)
878
946
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
879
 
        self.enter_context(work_tree.lock_read())
 
947
        self.add_cleanup(work_tree.lock_read().unlock)
880
948
        if revision is not None:
881
949
            tree = revision.as_tree(work_tree.branch)
882
950
 
883
951
            extra_trees = [work_tree]
884
 
            self.enter_context(tree.lock_read())
 
952
            self.add_cleanup(tree.lock_read().unlock)
885
953
        else:
886
954
            tree = work_tree
887
955
            extra_trees = []
888
956
 
889
 
        self.enter_context(tree.lock_read())
 
957
        self.add_cleanup(tree.lock_read().unlock)
890
958
        if file_list is not None:
891
 
            paths = tree.find_related_paths_across_trees(
892
 
                file_list, extra_trees, require_versioned=True)
 
959
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
960
                                      require_versioned=True)
893
961
            # find_ids_across_trees may include some paths that don't
894
962
            # exist in 'tree'.
895
 
            entries = tree.iter_entries_by_dir(specific_files=paths)
 
963
            entries = tree.iter_entries_by_dir(specific_file_ids=file_ids)
896
964
        else:
897
965
            entries = tree.iter_entries_by_dir()
898
966
 
899
967
        for path, entry in sorted(entries):
900
968
            if kind and kind != entry.kind:
901
969
                continue
902
 
            if path == "" and not include_root:
 
970
            if path == "":
903
971
                continue
904
972
            if show_ids:
905
 
                self.outf.write('%-50s %s\n' % (
906
 
                    path, entry.file_id.decode('utf-8')))
 
973
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
907
974
            else:
908
975
                self.outf.write(path)
909
976
                self.outf.write('\n')
910
977
 
911
978
 
912
 
class cmd_cp(Command):
913
 
    __doc__ = """Copy a file.
914
 
 
915
 
    :Usage:
916
 
        brz cp OLDNAME NEWNAME
917
 
 
918
 
        brz cp SOURCE... DESTINATION
919
 
 
920
 
    If the last argument is a versioned directory, all the other names
921
 
    are copied into it.  Otherwise, there must be exactly two arguments
922
 
    and the file is copied to a new name.
923
 
 
924
 
    Files cannot be copied between branches. Only files can be copied
925
 
    at the moment.
926
 
    """
927
 
 
928
 
    takes_args = ['names*']
929
 
    takes_options = []
930
 
    aliases = ['copy']
931
 
    encoding_type = 'replace'
932
 
 
933
 
    def run(self, names_list):
934
 
        if names_list is None:
935
 
            names_list = []
936
 
        if len(names_list) < 2:
937
 
            raise errors.CommandError(gettext("missing file argument"))
938
 
        tree, rel_names = WorkingTree.open_containing_paths(
939
 
            names_list, canonicalize=False)
940
 
        for file_name in rel_names[0:-1]:
941
 
            if file_name == '':
942
 
                raise errors.CommandError(
943
 
                    gettext("can not copy root of branch"))
944
 
        self.enter_context(tree.lock_tree_write())
945
 
        into_existing = osutils.isdir(names_list[-1])
946
 
        if not into_existing:
947
 
            try:
948
 
                (src, dst) = rel_names
949
 
            except IndexError:
950
 
                raise errors.CommandError(
951
 
                    gettext('to copy multiple files the'
952
 
                            ' destination must be a versioned'
953
 
                            ' directory'))
954
 
            pairs = [(src, dst)]
955
 
        else:
956
 
            pairs = [
957
 
                (n, osutils.joinpath([rel_names[-1], osutils.basename(n)]))
958
 
                for n in rel_names[:-1]]
959
 
 
960
 
        for src, dst in pairs:
961
 
            try:
962
 
                src_kind = tree.stored_kind(src)
963
 
            except errors.NoSuchFile:
964
 
                raise errors.CommandError(
965
 
                    gettext('Could not copy %s => %s: %s is not versioned.')
966
 
                    % (src, dst, src))
967
 
            if src_kind is None:
968
 
                raise errors.CommandError(
969
 
                    gettext('Could not copy %s => %s . %s is not versioned\\.'
970
 
                            % (src, dst, src)))
971
 
            if src_kind == 'directory':
972
 
                raise errors.CommandError(
973
 
                    gettext('Could not copy %s => %s . %s is a directory.'
974
 
                            % (src, dst, src)))
975
 
            dst_parent = osutils.split(dst)[0]
976
 
            if dst_parent != '':
977
 
                try:
978
 
                    dst_parent_kind = tree.stored_kind(dst_parent)
979
 
                except errors.NoSuchFile:
980
 
                    raise errors.CommandError(
981
 
                        gettext('Could not copy %s => %s: %s is not versioned.')
982
 
                        % (src, dst, dst_parent))
983
 
                if dst_parent_kind != 'directory':
984
 
                    raise errors.CommandError(
985
 
                        gettext('Could not copy to %s: %s is not a directory.')
986
 
                        % (dst_parent, dst_parent))
987
 
 
988
 
            tree.copy_one(src, dst)
989
 
 
990
 
 
991
979
class cmd_mv(Command):
992
980
    __doc__ = """Move or rename a file.
993
981
 
1011
999
 
1012
1000
    takes_args = ['names*']
1013
1001
    takes_options = [Option("after", help="Move only the brz identifier"
1014
 
                            " of the file, because the file has already been moved."),
1015
 
                     Option('auto', help='Automatically guess renames.'),
1016
 
                     Option(
1017
 
                         'dry-run', help='Avoid making changes when guessing renames.'),
1018
 
                     ]
 
1002
        " of the file, because the file has already been moved."),
 
1003
        Option('auto', help='Automatically guess renames.'),
 
1004
        Option('dry-run', help='Avoid making changes when guessing renames.'),
 
1005
        ]
1019
1006
    aliases = ['move', 'rename']
1020
1007
    encoding_type = 'replace'
1021
1008
 
1023
1010
        if auto:
1024
1011
            return self.run_auto(names_list, after, dry_run)
1025
1012
        elif dry_run:
1026
 
            raise errors.CommandError(gettext('--dry-run requires --auto.'))
 
1013
            raise errors.BzrCommandError(gettext('--dry-run requires --auto.'))
1027
1014
        if names_list is None:
1028
1015
            names_list = []
1029
1016
        if len(names_list) < 2:
1030
 
            raise errors.CommandError(gettext("missing file argument"))
1031
 
        tree, rel_names = WorkingTree.open_containing_paths(
1032
 
            names_list, canonicalize=False)
 
1017
            raise errors.BzrCommandError(gettext("missing file argument"))
 
1018
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
1033
1019
        for file_name in rel_names[0:-1]:
1034
1020
            if file_name == '':
1035
 
                raise errors.CommandError(
1036
 
                    gettext("can not move root of branch"))
1037
 
        self.enter_context(tree.lock_tree_write())
 
1021
                raise errors.BzrCommandError(gettext("can not move root of branch"))
 
1022
        self.add_cleanup(tree.lock_tree_write().unlock)
1038
1023
        self._run(tree, names_list, rel_names, after)
1039
1024
 
1040
1025
    def run_auto(self, names_list, after, dry_run):
1041
1026
        if names_list is not None and len(names_list) > 1:
1042
 
            raise errors.CommandError(
1043
 
                gettext('Only one path may be specified to --auto.'))
 
1027
            raise errors.BzrCommandError(gettext('Only one path may be specified to'
 
1028
                                         ' --auto.'))
1044
1029
        if after:
1045
 
            raise errors.CommandError(
1046
 
                gettext('--after cannot be specified with --auto.'))
 
1030
            raise errors.BzrCommandError(gettext('--after cannot be specified with'
 
1031
                                         ' --auto.'))
1047
1032
        work_tree, file_list = WorkingTree.open_containing_paths(
1048
1033
            names_list, default_directory='.')
1049
 
        self.enter_context(work_tree.lock_tree_write())
1050
 
        rename_map.RenameMap.guess_renames(
1051
 
            work_tree.basis_tree(), work_tree, dry_run)
 
1034
        self.add_cleanup(work_tree.lock_tree_write().unlock)
 
1035
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
1052
1036
 
1053
1037
    def _run(self, tree, names_list, rel_names, after):
1054
1038
        into_existing = osutils.isdir(names_list[-1])
1059
1043
            #    a directory, but now doesn't exist in the working tree
1060
1044
            #    and the target is an existing directory, just rename it)
1061
1045
            if (not tree.case_sensitive
1062
 
                    and rel_names[0].lower() == rel_names[1].lower()):
 
1046
                and rel_names[0].lower() == rel_names[1].lower()):
1063
1047
                into_existing = False
1064
1048
            else:
1065
1049
                # 'fix' the case of a potential 'from'
1066
 
                from_path = tree.get_canonical_path(rel_names[0])
 
1050
                from_id = tree.path2id(
 
1051
                            tree.get_canonical_inventory_path(rel_names[0]))
1067
1052
                if (not osutils.lexists(names_list[0]) and
1068
 
                    tree.is_versioned(from_path) and
1069
 
                        tree.stored_kind(from_path) == "directory"):
 
1053
                    from_id and tree.stored_kind(from_id) == "directory"):
1070
1054
                    into_existing = False
1071
1055
        # move/rename
1072
1056
        if into_existing:
1073
1057
            # move into existing directory
1074
1058
            # All entries reference existing inventory items, so fix them up
1075
1059
            # for cicp file-systems.
1076
 
            rel_names = list(tree.get_canonical_paths(rel_names))
 
1060
            rel_names = tree.get_canonical_inventory_paths(rel_names)
1077
1061
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
1078
1062
                if not is_quiet():
1079
1063
                    self.outf.write("%s => %s\n" % (src, dest))
1080
1064
        else:
1081
1065
            if len(names_list) != 2:
1082
 
                raise errors.CommandError(gettext('to mv multiple files the'
1083
 
                                                     ' destination must be a versioned'
1084
 
                                                     ' directory'))
 
1066
                raise errors.BzrCommandError(gettext('to mv multiple files the'
 
1067
                                             ' destination must be a versioned'
 
1068
                                             ' directory'))
1085
1069
 
1086
1070
            # for cicp file-systems: the src references an existing inventory
1087
1071
            # item:
1088
 
            src = tree.get_canonical_path(rel_names[0])
 
1072
            src = tree.get_canonical_inventory_path(rel_names[0])
1089
1073
            # Find the canonical version of the destination:  In all cases, the
1090
1074
            # parent of the target must be in the inventory, so we fetch the
1091
1075
            # canonical version from there (we do not always *use* the
1092
1076
            # canonicalized tail portion - we may be attempting to rename the
1093
1077
            # case of the tail)
1094
 
            canon_dest = tree.get_canonical_path(rel_names[1])
 
1078
            canon_dest = tree.get_canonical_inventory_path(rel_names[1])
1095
1079
            dest_parent = osutils.dirname(canon_dest)
1096
1080
            spec_tail = osutils.basename(rel_names[1])
1097
1081
            # For a CICP file-system, we need to avoid creating 2 inventory
1108
1092
                if after:
1109
1093
                    # If 'after' is specified, the tail must refer to a file on disk.
1110
1094
                    if dest_parent:
1111
 
                        dest_parent_fq = osutils.pathjoin(
1112
 
                            tree.basedir, dest_parent)
 
1095
                        dest_parent_fq = osutils.pathjoin(tree.basedir, dest_parent)
1113
1096
                    else:
1114
1097
                        # pathjoin with an empty tail adds a slash, which breaks
1115
1098
                        # relpath :(
1116
1099
                        dest_parent_fq = tree.basedir
1117
1100
 
1118
1101
                    dest_tail = osutils.canonical_relpath(
1119
 
                        dest_parent_fq,
1120
 
                        osutils.pathjoin(dest_parent_fq, spec_tail))
 
1102
                                    dest_parent_fq,
 
1103
                                    osutils.pathjoin(dest_parent_fq, spec_tail))
1121
1104
                else:
1122
1105
                    # not 'after', so case as specified is used
1123
1106
                    dest_tail = spec_tail
1135
1118
    __doc__ = """Turn this branch into a mirror of another branch.
1136
1119
 
1137
1120
    By default, this command only works on branches that have not diverged.
1138
 
    Branches are considered diverged if the destination branch's most recent
1139
 
    commit is one that has not been merged (directly or indirectly) into the
 
1121
    Branches are considered diverged if the destination branch's most recent 
 
1122
    commit is one that has not been merged (directly or indirectly) into the 
1140
1123
    parent.
1141
1124
 
1142
1125
    If branches have diverged, you can use 'brz merge' to integrate the changes
1163
1146
 
1164
1147
    _see_also = ['push', 'update', 'status-flags', 'send']
1165
1148
    takes_options = ['remember', 'overwrite', 'revision',
1166
 
                     custom_help('verbose',
1167
 
                                 help='Show logs of pulled revisions.'),
1168
 
                     custom_help('directory',
1169
 
                                 help='Branch to pull into, '
1170
 
                                 'rather than the one containing the working directory.'),
1171
 
                     Option('local',
1172
 
                            help="Perform a local pull in a bound "
1173
 
                            "branch.  Local pulls are not applied to "
1174
 
                            "the master branch."
1175
 
                            ),
1176
 
                     Option('show-base',
1177
 
                            help="Show base revision text in conflicts."),
1178
 
                     Option('overwrite-tags',
1179
 
                            help="Overwrite tags only."),
1180
 
                     ]
 
1149
        custom_help('verbose',
 
1150
            help='Show logs of pulled revisions.'),
 
1151
        custom_help('directory',
 
1152
            help='Branch to pull into, '
 
1153
                 'rather than the one containing the working directory.'),
 
1154
        Option('local',
 
1155
            help="Perform a local pull in a bound "
 
1156
                 "branch.  Local pulls are not applied to "
 
1157
                 "the master branch."
 
1158
            ),
 
1159
        Option('show-base',
 
1160
            help="Show base revision text in conflicts."),
 
1161
        Option('overwrite-tags',
 
1162
            help="Overwrite tags only."),
 
1163
        ]
1181
1164
    takes_args = ['location?']
1182
1165
    encoding_type = 'replace'
1183
1166
 
1200
1183
        try:
1201
1184
            tree_to = WorkingTree.open_containing(directory)[0]
1202
1185
            branch_to = tree_to.branch
1203
 
            self.enter_context(tree_to.lock_write())
 
1186
            self.add_cleanup(tree_to.lock_write().unlock)
1204
1187
        except errors.NoWorkingTree:
1205
1188
            tree_to = None
1206
1189
            branch_to = Branch.open_containing(directory)[0]
1207
 
            self.enter_context(branch_to.lock_write())
 
1190
            self.add_cleanup(branch_to.lock_write().unlock)
1208
1191
            if show_base:
1209
1192
                warning(gettext("No working tree, ignoring --show-base"))
1210
1193
 
1214
1197
        possible_transports = []
1215
1198
        if location is not None:
1216
1199
            try:
1217
 
                mergeable = _mod_mergeable.read_mergeable_from_url(
1218
 
                    location, possible_transports=possible_transports)
 
1200
                mergeable = bundle.read_mergeable_from_url(location,
 
1201
                    possible_transports=possible_transports)
1219
1202
            except errors.NotABundle:
1220
1203
                mergeable = None
1221
1204
 
1222
1205
        stored_loc = branch_to.get_parent()
1223
1206
        if location is None:
1224
1207
            if stored_loc is None:
1225
 
                raise errors.CommandError(gettext("No pull location known or"
1226
 
                                                     " specified."))
 
1208
                raise errors.BzrCommandError(gettext("No pull location known or"
 
1209
                                             " specified."))
1227
1210
            else:
1228
1211
                display_url = urlutils.unescape_for_display(stored_loc,
1229
 
                                                            self.outf.encoding)
 
1212
                        self.outf.encoding)
1230
1213
                if not is_quiet():
1231
 
                    self.outf.write(
1232
 
                        gettext("Using saved parent location: %s\n") % display_url)
 
1214
                    self.outf.write(gettext("Using saved parent location: %s\n") % display_url)
1233
1215
                location = stored_loc
1234
1216
 
1235
1217
        revision = _get_one_revision('pull', revision)
1236
1218
        if mergeable is not None:
1237
1219
            if revision is not None:
1238
 
                raise errors.CommandError(gettext(
 
1220
                raise errors.BzrCommandError(gettext(
1239
1221
                    'Cannot use -r with merge directives or bundles'))
1240
1222
            mergeable.install_revisions(branch_to.repository)
1241
1223
            base_revision_id, revision_id, verified = \
1243
1225
            branch_from = branch_to
1244
1226
        else:
1245
1227
            branch_from = Branch.open(location,
1246
 
                                      possible_transports=possible_transports)
1247
 
            self.enter_context(branch_from.lock_read())
 
1228
                possible_transports=possible_transports)
 
1229
            self.add_cleanup(branch_from.lock_read().unlock)
1248
1230
            # Remembers if asked explicitly or no previous location is set
1249
1231
            if (remember
1250
 
                    or (remember is None and branch_to.get_parent() is None)):
 
1232
                or (remember is None and branch_to.get_parent() is None)):
1251
1233
                # FIXME: This shouldn't be done before the pull
1252
1234
                # succeeds... -- vila 2012-01-02
1253
1235
                branch_to.set_parent(branch_from.base)
1310
1292
 
1311
1293
    _see_also = ['pull', 'update', 'working-trees']
1312
1294
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
1313
 
                     Option('create-prefix',
1314
 
                            help='Create the path leading up to the branch '
1315
 
                            'if it does not already exist.'),
1316
 
                     custom_help('directory',
1317
 
                                 help='Branch to push from, '
1318
 
                                 'rather than the one containing the working directory.'),
1319
 
                     Option('use-existing-dir',
1320
 
                            help='By default push will fail if the target'
1321
 
                            ' directory exists, but does not already'
1322
 
                            ' have a control directory.  This flag will'
1323
 
                            ' allow push to proceed.'),
1324
 
                     Option('stacked',
1325
 
                            help='Create a stacked branch that references the public location '
1326
 
                            'of the parent branch.'),
1327
 
                     Option('stacked-on',
1328
 
                            help='Create a stacked branch that refers to another branch '
1329
 
                            'for the commit history. Only the work not present in the '
1330
 
                            'referenced branch is included in the branch created.',
1331
 
                            type=str),
1332
 
                     Option('strict',
1333
 
                            help='Refuse to push if there are uncommitted changes in'
1334
 
                            ' the working tree, --no-strict disables the check.'),
1335
 
                     Option('no-tree',
1336
 
                            help="Don't populate the working tree, even for protocols"
1337
 
                            " that support it."),
1338
 
                     Option('overwrite-tags',
1339
 
                            help="Overwrite tags only."),
1340
 
                     Option('lossy', help="Allow lossy push, i.e. dropping metadata "
1341
 
                            "that can't be represented in the target.")
1342
 
                     ]
 
1295
        Option('create-prefix',
 
1296
               help='Create the path leading up to the branch '
 
1297
                    'if it does not already exist.'),
 
1298
        custom_help('directory',
 
1299
            help='Branch to push from, '
 
1300
                 'rather than the one containing the working directory.'),
 
1301
        Option('use-existing-dir',
 
1302
               help='By default push will fail if the target'
 
1303
                    ' directory exists, but does not already'
 
1304
                    ' have a control directory.  This flag will'
 
1305
                    ' allow push to proceed.'),
 
1306
        Option('stacked',
 
1307
            help='Create a stacked branch that references the public location '
 
1308
                'of the parent branch.'),
 
1309
        Option('stacked-on',
 
1310
            help='Create a stacked branch that refers to another branch '
 
1311
                'for the commit history. Only the work not present in the '
 
1312
                'referenced branch is included in the branch created.',
 
1313
            type=text_type),
 
1314
        Option('strict',
 
1315
               help='Refuse to push if there are uncommitted changes in'
 
1316
               ' the working tree, --no-strict disables the check.'),
 
1317
        Option('no-tree',
 
1318
               help="Don't populate the working tree, even for protocols"
 
1319
               " that support it."),
 
1320
        Option('overwrite-tags',
 
1321
              help="Overwrite tags only."),
 
1322
        ]
1343
1323
    takes_args = ['location?']
1344
1324
    encoding_type = 'replace'
1345
1325
 
1346
1326
    def run(self, location=None, remember=None, overwrite=False,
1347
 
            create_prefix=False, verbose=False, revision=None,
1348
 
            use_existing_dir=False, directory=None, stacked_on=None,
1349
 
            stacked=False, strict=None, no_tree=False,
1350
 
            overwrite_tags=False, lossy=False):
1351
 
        from .location import location_to_url
 
1327
        create_prefix=False, verbose=False, revision=None,
 
1328
        use_existing_dir=False, directory=None, stacked_on=None,
 
1329
        stacked=False, strict=None, no_tree=False,
 
1330
        overwrite_tags=False):
1352
1331
        from .push import _show_push_branch
1353
1332
 
1354
1333
        if overwrite:
1376
1355
                more_warning='Uncommitted changes will not be pushed.')
1377
1356
        # Get the stacked_on branch, if any
1378
1357
        if stacked_on is not None:
1379
 
            stacked_on = location_to_url(stacked_on, 'read')
1380
1358
            stacked_on = urlutils.normalize_url(stacked_on)
1381
1359
        elif stacked:
1382
1360
            parent_url = br_from.get_parent()
1390
1368
                    # error by the feedback given to them. RBC 20080227.
1391
1369
                    stacked_on = parent_url
1392
1370
            if not stacked_on:
1393
 
                raise errors.CommandError(gettext(
 
1371
                raise errors.BzrCommandError(gettext(
1394
1372
                    "Could not determine branch to refer to."))
1395
1373
 
1396
1374
        # Get the destination location
1399
1377
            if stored_loc is None:
1400
1378
                parent_loc = br_from.get_parent()
1401
1379
                if parent_loc:
1402
 
                    raise errors.CommandError(gettext(
 
1380
                    raise errors.BzrCommandError(gettext(
1403
1381
                        "No push location known or specified. To push to the "
1404
1382
                        "parent branch (at %s), use 'brz push :parent'." %
1405
1383
                        urlutils.unescape_for_display(parent_loc,
1406
 
                                                      self.outf.encoding)))
 
1384
                            self.outf.encoding)))
1407
1385
                else:
1408
 
                    raise errors.CommandError(gettext(
 
1386
                    raise errors.BzrCommandError(gettext(
1409
1387
                        "No push location known or specified."))
1410
1388
            else:
1411
1389
                display_url = urlutils.unescape_for_display(stored_loc,
1412
 
                                                            self.outf.encoding)
 
1390
                        self.outf.encoding)
1413
1391
                note(gettext("Using saved push location: %s") % display_url)
1414
1392
                location = stored_loc
1415
1393
 
1416
1394
        _show_push_branch(br_from, revision_id, location, self.outf,
1417
 
                          verbose=verbose, overwrite=overwrite, remember=remember,
1418
 
                          stacked_on=stacked_on, create_prefix=create_prefix,
1419
 
                          use_existing_dir=use_existing_dir, no_tree=no_tree,
1420
 
                          lossy=lossy)
 
1395
            verbose=verbose, overwrite=overwrite, remember=remember,
 
1396
            stacked_on=stacked_on, create_prefix=create_prefix,
 
1397
            use_existing_dir=use_existing_dir, no_tree=no_tree)
1421
1398
 
1422
1399
 
1423
1400
class cmd_branch(Command):
1432
1409
 
1433
1410
    To retrieve the branch as of a particular revision, supply the --revision
1434
1411
    parameter, as in "branch foo/bar -r 5".
 
1412
 
 
1413
    The synonyms 'clone' and 'get' for this command are deprecated.
1435
1414
    """
1436
1415
 
1437
 
    aliase = ['sprout']
1438
1416
    _see_also = ['checkout']
1439
1417
    takes_args = ['from_location', 'to_location?']
1440
1418
    takes_options = ['revision',
1441
 
                     Option(
1442
 
                         'hardlink', help='Hard-link working tree files where possible.'),
1443
 
                     Option('files-from', type=str,
1444
 
                            help="Get file contents from this tree."),
1445
 
                     Option('no-tree',
1446
 
                            help="Create a branch without a working-tree."),
1447
 
                     Option('switch',
1448
 
                            help="Switch the checkout in the current directory "
1449
 
                            "to the new branch."),
1450
 
                     Option('stacked',
1451
 
                            help='Create a stacked branch referring to the source branch. '
1452
 
                            'The new branch will depend on the availability of the source '
1453
 
                            'branch for all operations.'),
1454
 
                     Option('standalone',
1455
 
                            help='Do not use a shared repository, even if available.'),
1456
 
                     Option('use-existing-dir',
1457
 
                            help='By default branch will fail if the target'
1458
 
                            ' directory exists, but does not already'
1459
 
                            ' have a control directory.  This flag will'
1460
 
                            ' allow branch to proceed.'),
1461
 
                     Option('bind',
1462
 
                            help="Bind new branch to from location."),
1463
 
                     Option('no-recurse-nested',
1464
 
                            help='Do not recursively check out nested trees.'),
1465
 
                     Option('colocated-branch', short_name='b',
1466
 
                            type=str, help='Name of colocated branch to sprout.'),
1467
 
                     ]
 
1419
        Option('hardlink', help='Hard-link working tree files where possible.'),
 
1420
        Option('files-from', type=str,
 
1421
               help="Get file contents from this tree."),
 
1422
        Option('no-tree',
 
1423
            help="Create a branch without a working-tree."),
 
1424
        Option('switch',
 
1425
            help="Switch the checkout in the current directory "
 
1426
                 "to the new branch."),
 
1427
        Option('stacked',
 
1428
            help='Create a stacked branch referring to the source branch. '
 
1429
                'The new branch will depend on the availability of the source '
 
1430
                'branch for all operations.'),
 
1431
        Option('standalone',
 
1432
               help='Do not use a shared repository, even if available.'),
 
1433
        Option('use-existing-dir',
 
1434
               help='By default branch will fail if the target'
 
1435
                    ' directory exists, but does not already'
 
1436
                    ' have a control directory.  This flag will'
 
1437
                    ' allow branch to proceed.'),
 
1438
        Option('bind',
 
1439
            help="Bind new branch to from location."),
 
1440
        ]
 
1441
    aliases = ['get', 'clone']
1468
1442
 
1469
1443
    def run(self, from_location, to_location=None, revision=None,
1470
1444
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1471
1445
            use_existing_dir=False, switch=False, bind=False,
1472
 
            files_from=None, no_recurse_nested=False, colocated_branch=None):
 
1446
            files_from=None):
1473
1447
        from breezy import switch as _mod_switch
 
1448
        if self.invoked_as in ['get', 'clone']:
 
1449
            ui.ui_factory.show_user_warning(
 
1450
                'deprecated_command',
 
1451
                deprecated_name=self.invoked_as,
 
1452
                recommended_name='branch',
 
1453
                deprecated_in_version='2.4')
1474
1454
        accelerator_tree, br_from = controldir.ControlDir.open_tree_or_branch(
1475
 
            from_location, name=colocated_branch)
1476
 
        if no_recurse_nested:
1477
 
            recurse = 'none'
1478
 
        else:
1479
 
            recurse = 'down'
 
1455
            from_location)
1480
1456
        if not (hardlink or files_from):
1481
1457
            # accelerator_tree is usually slower because you have to read N
1482
1458
            # files (no readahead, lots of seeks, etc), but allow the user to
1485
1461
        if files_from is not None and files_from != from_location:
1486
1462
            accelerator_tree = WorkingTree.open(files_from)
1487
1463
        revision = _get_one_revision('branch', revision)
1488
 
        self.enter_context(br_from.lock_read())
 
1464
        self.add_cleanup(br_from.lock_read().unlock)
1489
1465
        if revision is not None:
1490
1466
            revision_id = revision.as_revision_id(br_from)
1491
1467
        else:
1494
1470
            # RBC 20060209
1495
1471
            revision_id = br_from.last_revision()
1496
1472
        if to_location is None:
1497
 
            to_location = urlutils.derive_to_location(from_location)
1498
 
        to_transport = transport.get_transport(to_location, purpose='write')
 
1473
            to_location = getattr(br_from, "name", None)
 
1474
            if not to_location:
 
1475
                to_location = urlutils.derive_to_location(from_location)
 
1476
        to_transport = transport.get_transport(to_location)
1499
1477
        try:
1500
1478
            to_transport.mkdir('.')
1501
1479
        except errors.FileExists:
1504
1482
                    to_transport)
1505
1483
            except errors.NotBranchError:
1506
1484
                if not use_existing_dir:
1507
 
                    raise errors.CommandError(gettext('Target directory "%s" '
1508
 
                                                         'already exists.') % to_location)
 
1485
                    raise errors.BzrCommandError(gettext('Target directory "%s" '
 
1486
                        'already exists.') % to_location)
1509
1487
                else:
1510
1488
                    to_dir = None
1511
1489
            else:
1516
1494
                else:
1517
1495
                    raise errors.AlreadyBranchError(to_location)
1518
1496
        except errors.NoSuchFile:
1519
 
            raise errors.CommandError(gettext('Parent of "%s" does not exist.')
 
1497
            raise errors.BzrCommandError(gettext('Parent of "%s" does not exist.')
1520
1498
                                         % to_location)
1521
1499
        else:
1522
1500
            to_dir = None
1523
1501
        if to_dir is None:
1524
1502
            try:
1525
1503
                # preserve whatever source format we have.
1526
 
                to_dir = br_from.controldir.sprout(
1527
 
                    to_transport.base, revision_id,
1528
 
                    possible_transports=[to_transport],
1529
 
                    accelerator_tree=accelerator_tree, hardlink=hardlink,
1530
 
                    stacked=stacked, force_new_repo=standalone,
1531
 
                    create_tree_if_local=not no_tree, source_branch=br_from,
1532
 
                    recurse=recurse)
 
1504
                to_dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1505
                                            possible_transports=[to_transport],
 
1506
                                            accelerator_tree=accelerator_tree,
 
1507
                                            hardlink=hardlink, stacked=stacked,
 
1508
                                            force_new_repo=standalone,
 
1509
                                            create_tree_if_local=not no_tree,
 
1510
                                            source_branch=br_from)
1533
1511
                branch = to_dir.open_branch(
1534
1512
                    possible_transports=[
1535
 
                        br_from.controldir.root_transport, to_transport])
 
1513
                        br_from.bzrdir.root_transport, to_transport])
1536
1514
            except errors.NoSuchRevision:
1537
1515
                to_transport.delete_tree('.')
1538
1516
                msg = gettext("The branch {0} has no revision {1}.").format(
1539
1517
                    from_location, revision)
1540
 
                raise errors.CommandError(msg)
 
1518
                raise errors.BzrCommandError(msg)
1541
1519
        else:
1542
1520
            try:
1543
1521
                to_repo = to_dir.open_repository()
1544
1522
            except errors.NoRepositoryPresent:
1545
1523
                to_repo = to_dir.create_repository()
1546
1524
            to_repo.fetch(br_from.repository, revision_id=revision_id)
1547
 
            branch = br_from.sprout(
1548
 
                to_dir, revision_id=revision_id)
 
1525
            branch = br_from.sprout(to_dir, revision_id=revision_id)
1549
1526
        br_from.tags.merge_to(branch.tags)
1550
1527
 
1551
1528
        # If the source branch is stacked, the new branch may
1553
1530
        # We therefore need a try/except here and not just 'if stacked:'
1554
1531
        try:
1555
1532
            note(gettext('Created new stacked branch referring to %s.') %
1556
 
                 branch.get_stacked_on_url())
1557
 
        except (errors.NotStacked, _mod_branch.UnstackableBranchFormat,
1558
 
                errors.UnstackableRepositoryFormat) as e:
1559
 
            revno = branch.revno()
1560
 
            if revno is not None:
1561
 
                note(ngettext('Branched %d revision.',
1562
 
                              'Branched %d revisions.',
1563
 
                              branch.revno()) % revno)
1564
 
            else:
1565
 
                note(gettext('Created new branch.'))
 
1533
                branch.get_stacked_on_url())
 
1534
        except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1535
            errors.UnstackableRepositoryFormat) as e:
 
1536
            note(ngettext('Branched %d revision.', 'Branched %d revisions.', branch.revno()) % branch.revno())
1566
1537
        if bind:
1567
1538
            # Bind to the parent
1568
1539
            parent_branch = Branch.open(from_location)
1571
1542
        if switch:
1572
1543
            # Switch to the new branch
1573
1544
            wt, _ = WorkingTree.open_containing('.')
1574
 
            _mod_switch.switch(wt.controldir, branch)
 
1545
            _mod_switch.switch(wt.bzrdir, branch)
1575
1546
            note(gettext('Switched to branch: %s'),
1576
 
                 urlutils.unescape_for_display(branch.base, 'utf-8'))
 
1547
                urlutils.unescape_for_display(branch.base, 'utf-8'))
1577
1548
 
1578
1549
 
1579
1550
class cmd_branches(Command):
1585
1556
 
1586
1557
    takes_args = ['location?']
1587
1558
    takes_options = [
1588
 
        Option('recursive', short_name='R',
1589
 
               help='Recursively scan for branches rather than '
1590
 
               'just looking in the specified location.')]
 
1559
                  Option('recursive', short_name='R',
 
1560
                         help='Recursively scan for branches rather than '
 
1561
                              'just looking in the specified location.')]
1591
1562
 
1592
1563
    def run(self, location=".", recursive=False):
1593
1564
        if recursive:
1594
 
            t = transport.get_transport(location, purpose='read')
 
1565
            t = transport.get_transport(location)
1595
1566
            if not t.listable():
1596
 
                raise errors.CommandError(
 
1567
                raise errors.BzrCommandError(
1597
1568
                    "Can't scan this type of location.")
1598
1569
            for b in controldir.ControlDir.find_branches(t):
1599
1570
                self.outf.write("%s\n" % urlutils.unescape_for_display(
1610
1581
                if name == "":
1611
1582
                    continue
1612
1583
                active = (active_branch is not None and
1613
 
                          active_branch.user_url == branch.user_url)
 
1584
                          active_branch.base == branch.base)
1614
1585
                names[name] = active
1615
1586
            # Only mention the current branch explicitly if it's not
1616
1587
            # one of the colocated branches
1617
 
            if not any(names.values()) and active_branch is not None:
 
1588
            if not any(viewvalues(names)) and active_branch is not None:
1618
1589
                self.outf.write("* %s\n" % gettext("(default)"))
1619
1590
            for name in sorted(names):
1620
1591
                active = names[name]
1622
1593
                    prefix = "*"
1623
1594
                else:
1624
1595
                    prefix = " "
1625
 
                self.outf.write("%s %s\n" % (prefix, name))
 
1596
                self.outf.write("%s %s\n" % (
 
1597
                    prefix, name.encode(self.outf.encoding)))
1626
1598
 
1627
1599
 
1628
1600
class cmd_checkout(Command):
1629
1601
    __doc__ = """Create a new checkout of an existing branch.
1630
1602
 
1631
 
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree
1632
 
    for the branch found in '.'. This is useful if you have removed the working
1633
 
    tree or if it was never created - i.e. if you pushed the branch to its
1634
 
    current location using SFTP.
 
1603
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
 
1604
    the branch found in '.'. This is useful if you have removed the working tree
 
1605
    or if it was never created - i.e. if you pushed the branch to its current
 
1606
    location using SFTP.
1635
1607
 
1636
 
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION
1637
 
    will be used.  In other words, "checkout ../foo/bar" will attempt to create
1638
 
    ./bar.  If the BRANCH_LOCATION has no / or path separator embedded, the
1639
 
    TO_LOCATION is derived from the BRANCH_LOCATION by stripping a leading
1640
 
    scheme or drive identifier, if any. For example, "checkout lp:foo-bar" will
1641
 
    attempt to create ./foo-bar.
 
1608
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
 
1609
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
 
1610
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
 
1611
    is derived from the BRANCH_LOCATION by stripping a leading scheme or drive
 
1612
    identifier, if any. For example, "checkout lp:foo-bar" will attempt to
 
1613
    create ./foo-bar.
1642
1614
 
1643
1615
    To retrieve the branch as of a particular revision, supply the --revision
1644
 
    parameter, as in "checkout foo/bar -r 5". Note that this will be
1645
 
    immediately out of date [so you cannot commit] but it may be useful (i.e.
1646
 
    to examine old code.)
 
1616
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
 
1617
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
 
1618
    code.)
1647
1619
    """
1648
1620
 
1649
1621
    _see_also = ['checkouts', 'branch', 'working-trees', 'remove-tree']
1688
1660
        # if the source and to_location are the same,
1689
1661
        # and there is no working tree,
1690
1662
        # then reconstitute a branch
1691
 
        if osutils.abspath(to_location) == osutils.abspath(branch_location):
 
1663
        if (osutils.abspath(to_location) ==
 
1664
            osutils.abspath(branch_location)):
1692
1665
            try:
1693
 
                source.controldir.open_workingtree()
 
1666
                source.bzrdir.open_workingtree()
1694
1667
            except errors.NoWorkingTree:
1695
 
                source.controldir.create_workingtree(revision_id)
 
1668
                source.bzrdir.create_workingtree(revision_id)
1696
1669
                return
1697
1670
        source.create_checkout(to_location, revision_id, lightweight,
1698
1671
                               accelerator_tree, hardlink)
1699
1672
 
1700
1673
 
1701
 
class cmd_clone(Command):
1702
 
    __doc__ = """Clone a control directory.
1703
 
    """
1704
 
 
1705
 
    takes_args = ['from_location', 'to_location?']
1706
 
    takes_options = ['revision',
1707
 
                     Option('no-recurse-nested',
1708
 
                            help='Do not recursively check out nested trees.'),
1709
 
                     ]
1710
 
 
1711
 
    def run(self, from_location, to_location=None, revision=None, no_recurse_nested=False):
1712
 
        accelerator_tree, br_from = controldir.ControlDir.open_tree_or_branch(
1713
 
            from_location)
1714
 
        if no_recurse_nested:
1715
 
            recurse = 'none'
1716
 
        else:
1717
 
            recurse = 'down'
1718
 
        revision = _get_one_revision('branch', revision)
1719
 
        self.enter_context(br_from.lock_read())
1720
 
        if revision is not None:
1721
 
            revision_id = revision.as_revision_id(br_from)
1722
 
        else:
1723
 
            # FIXME - wt.last_revision, fallback to branch, fall back to
1724
 
            # None or perhaps NULL_REVISION to mean copy nothing
1725
 
            # RBC 20060209
1726
 
            revision_id = br_from.last_revision()
1727
 
        if to_location is None:
1728
 
            to_location = urlutils.derive_to_location(from_location)
1729
 
        target_controldir = br_from.controldir.clone(to_location, revision_id=revision_id)
1730
 
        note(gettext('Created new control directory.'))
1731
 
 
1732
 
 
1733
1674
class cmd_renames(Command):
1734
1675
    __doc__ = """Show list of renamed files.
1735
1676
    """
1742
1683
    @display_command
1743
1684
    def run(self, dir=u'.'):
1744
1685
        tree = WorkingTree.open_containing(dir)[0]
1745
 
        self.enter_context(tree.lock_read())
 
1686
        self.add_cleanup(tree.lock_read().unlock)
1746
1687
        old_tree = tree.basis_tree()
1747
 
        self.enter_context(old_tree.lock_read())
 
1688
        self.add_cleanup(old_tree.lock_read().unlock)
1748
1689
        renames = []
1749
1690
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1750
 
        for change in iterator:
1751
 
            if change.path[0] == change.path[1]:
1752
 
                continue
1753
 
            if None in change.path:
1754
 
                continue
1755
 
            renames.append(change.path)
 
1691
        for f, paths, c, v, p, n, k, e in iterator:
 
1692
            if paths[0] == paths[1]:
 
1693
                continue
 
1694
            if None in (paths):
 
1695
                continue
 
1696
            renames.append(paths)
1756
1697
        renames.sort()
1757
1698
        for old_name, new_name in renames:
1758
1699
            self.outf.write("%s => %s\n" % (old_name, new_name))
1763
1704
 
1764
1705
    This will perform a merge of the destination revision (the tip of the
1765
1706
    branch, or the specified revision) into the working tree, and then make
1766
 
    that revision the basis revision for the working tree.
 
1707
    that revision the basis revision for the working tree.  
1767
1708
 
1768
1709
    You can use this to visit an older revision, or to update a working tree
1769
1710
    that is out of date from its branch.
1770
 
 
 
1711
    
1771
1712
    If there are any uncommitted changes in the tree, they will be carried
1772
1713
    across and remain as uncommitted changes after the update.  To discard
1773
1714
    these changes, use 'brz revert'.  The uncommitted changes may conflict
1776
1717
    If the tree's branch is bound to a master branch, brz will also update
1777
1718
    the branch from the master.
1778
1719
 
1779
 
    You cannot update just a single file or directory, because each Breezy
 
1720
    You cannot update just a single file or directory, because each Bazaar
1780
1721
    working tree has just a single basis revision.  If you want to restore a
1781
1722
    file that has been removed locally, use 'brz revert' instead of 'brz
1782
1723
    update'.  If you want to restore a file to its state in a previous
1784
1725
    out the old content of that file to a new location.
1785
1726
 
1786
1727
    The 'dir' argument, if given, must be the location of the root of a
1787
 
    working tree to update.  By default, the working tree that contains the
 
1728
    working tree to update.  By default, the working tree that contains the 
1788
1729
    current working directory is used.
1789
1730
    """
1790
1731
 
1798
1739
 
1799
1740
    def run(self, dir=None, revision=None, show_base=None):
1800
1741
        if revision is not None and len(revision) != 1:
1801
 
            raise errors.CommandError(gettext(
 
1742
            raise errors.brzCommandError(gettext(
1802
1743
                "brz update --revision takes exactly one revision"))
1803
1744
        if dir is None:
1804
1745
            tree = WorkingTree.open_containing('.')[0]
1806
1747
            tree, relpath = WorkingTree.open_containing(dir)
1807
1748
            if relpath:
1808
1749
                # See bug 557886.
1809
 
                raise errors.CommandError(gettext(
 
1750
                raise errors.BzrCommandError(gettext(
1810
1751
                    "brz update can only update a whole tree, "
1811
1752
                    "not a file or subdirectory"))
1812
1753
        branch = tree.branch
1815
1756
            possible_transports=possible_transports)
1816
1757
        if master is not None:
1817
1758
            branch_location = master.base
1818
 
            self.enter_context(tree.lock_write())
 
1759
            tree.lock_write()
1819
1760
        else:
1820
1761
            branch_location = tree.branch.base
1821
 
            self.enter_context(tree.lock_tree_write())
 
1762
            tree.lock_tree_write()
 
1763
        self.add_cleanup(tree.unlock)
1822
1764
        # get rid of the final '/' and be ready for display
1823
1765
        branch_location = urlutils.unescape_for_display(
1824
1766
            branch_location.rstrip('/'),
1838
1780
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
1839
1781
            revno = branch.revision_id_to_dotted_revno(revision_id)
1840
1782
            note(gettext("Tree is up to date at revision {0} of branch {1}"
1841
 
                         ).format('.'.join(map(str, revno)), branch_location))
 
1783
                        ).format('.'.join(map(str, revno)), branch_location))
1842
1784
            return 0
1843
1785
        view_info = _get_view_info_for_change_reporter(tree)
1844
1786
        change_reporter = delta._ChangeReporter(
1852
1794
                old_tip=old_tip,
1853
1795
                show_base=show_base)
1854
1796
        except errors.NoSuchRevision as e:
1855
 
            raise errors.CommandError(gettext(
1856
 
                "branch has no revision %s\n"
1857
 
                "brz update --revision only works"
1858
 
                " for a revision in the branch history")
1859
 
                % (e.revision))
 
1797
            raise errors.BzrCommandError(gettext(
 
1798
                                  "branch has no revision %s\n"
 
1799
                                  "brz update --revision only works"
 
1800
                                  " for a revision in the branch history")
 
1801
                                  % (e.revision))
1860
1802
        revno = tree.branch.revision_id_to_dotted_revno(
1861
1803
            _mod_revision.ensure_null(tree.last_revision()))
1862
1804
        note(gettext('Updated to revision {0} of branch {1}').format(
1864
1806
        parent_ids = tree.get_parent_ids()
1865
1807
        if parent_ids[1:] and parent_ids[1:] != existing_pending_merges:
1866
1808
            note(gettext('Your local commits will now show as pending merges with '
1867
 
                         "'brz status', and can be committed with 'brz commit'."))
 
1809
                 "'brz status', and can be committed with 'brz commit'."))
1868
1810
        if conflicts != 0:
1869
1811
            return 1
1870
1812
        else:
1918
1860
class cmd_remove(Command):
1919
1861
    __doc__ = """Remove files or directories.
1920
1862
 
1921
 
    This makes Breezy stop tracking changes to the specified files. Breezy will
 
1863
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
1922
1864
    delete them if they can easily be recovered using revert otherwise they
1923
1865
    will be backed up (adding an extension of the form .~#~). If no options or
1924
 
    parameters are given Breezy will scan for files that are being tracked by
1925
 
    Breezy but missing in your tree and stop tracking them for you.
 
1866
    parameters are given Bazaar will scan for files that are being tracked by
 
1867
    Bazaar but missing in your tree and stop tracking them for you.
1926
1868
    """
1927
1869
    takes_args = ['file*']
1928
1870
    takes_options = ['verbose',
1929
 
                     Option(
1930
 
                         'new', help='Only remove files that have never been committed.'),
1931
 
                     RegistryOption.from_kwargs('file-deletion-strategy',
1932
 
                                                'The file deletion mode to be used.',
1933
 
                                                title='Deletion Strategy', value_switches=True, enum_switch=False,
1934
 
                                                safe='Backup changed files (default).',
1935
 
                                                keep='Delete from brz but leave the working copy.',
1936
 
                                                no_backup='Don\'t backup changed files.'),
1937
 
                     ]
 
1871
        Option('new', help='Only remove files that have never been committed.'),
 
1872
        RegistryOption.from_kwargs('file-deletion-strategy',
 
1873
            'The file deletion mode to be used.',
 
1874
            title='Deletion Strategy', value_switches=True, enum_switch=False,
 
1875
            safe='Backup changed files (default).',
 
1876
            keep='Delete from brz but leave the working copy.',
 
1877
            no_backup='Don\'t backup changed files.'),
 
1878
        ]
1938
1879
    aliases = ['rm', 'del']
1939
1880
    encoding_type = 'replace'
1940
1881
 
1941
1882
    def run(self, file_list, verbose=False, new=False,
1942
 
            file_deletion_strategy='safe'):
 
1883
        file_deletion_strategy='safe'):
1943
1884
 
1944
1885
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1945
1886
 
1946
1887
        if file_list is not None:
1947
1888
            file_list = [f for f in file_list]
1948
1889
 
1949
 
        self.enter_context(tree.lock_write())
 
1890
        self.add_cleanup(tree.lock_write().unlock)
1950
1891
        # Heuristics should probably all move into tree.remove_smart or
1951
1892
        # some such?
1952
1893
        if new:
1953
1894
            added = tree.changes_from(tree.basis_tree(),
1954
 
                                      specific_files=file_list).added
1955
 
            file_list = sorted([f.path[1] for f in added], reverse=True)
 
1895
                specific_files=file_list).added
 
1896
            file_list = sorted([f[0] for f in added], reverse=True)
1956
1897
            if len(file_list) == 0:
1957
 
                raise errors.CommandError(gettext('No matching files.'))
 
1898
                raise errors.BzrCommandError(gettext('No matching files.'))
1958
1899
        elif file_list is None:
1959
1900
            # missing files show up in iter_changes(basis) as
1960
1901
            # versioned-with-no-kind.
1961
1902
            missing = []
1962
1903
            for change in tree.iter_changes(tree.basis_tree()):
1963
1904
                # Find paths in the working tree that have no kind:
1964
 
                if change.path[1] is not None and change.kind[1] is None:
1965
 
                    missing.append(change.path[1])
 
1905
                if change[1][1] is not None and change[6][1] is None:
 
1906
                    missing.append(change[1][1])
1966
1907
            file_list = sorted(missing, reverse=True)
1967
1908
            file_deletion_strategy = 'keep'
1968
1909
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1969
 
                    keep_files=file_deletion_strategy == 'keep',
1970
 
                    force=(file_deletion_strategy == 'no-backup'))
 
1910
            keep_files=file_deletion_strategy=='keep',
 
1911
            force=(file_deletion_strategy=='no-backup'))
 
1912
 
 
1913
 
 
1914
class cmd_file_id(Command):
 
1915
    __doc__ = """Print file_id of a particular file or directory.
 
1916
 
 
1917
    The file_id is assigned when the file is first added and remains the
 
1918
    same through all revisions where the file exists, even when it is
 
1919
    moved or renamed.
 
1920
    """
 
1921
 
 
1922
    hidden = True
 
1923
    _see_also = ['inventory', 'ls']
 
1924
    takes_args = ['filename']
 
1925
 
 
1926
    @display_command
 
1927
    def run(self, filename):
 
1928
        tree, relpath = WorkingTree.open_containing(filename)
 
1929
        i = tree.path2id(relpath)
 
1930
        if i is None:
 
1931
            raise errors.NotVersionedError(filename)
 
1932
        else:
 
1933
            self.outf.write(i + '\n')
 
1934
 
 
1935
 
 
1936
class cmd_file_path(Command):
 
1937
    __doc__ = """Print path of file_ids to a file or directory.
 
1938
 
 
1939
    This prints one line for each directory down to the target,
 
1940
    starting at the branch root.
 
1941
    """
 
1942
 
 
1943
    hidden = True
 
1944
    takes_args = ['filename']
 
1945
 
 
1946
    @display_command
 
1947
    def run(self, filename):
 
1948
        tree, relpath = WorkingTree.open_containing(filename)
 
1949
        fid = tree.path2id(relpath)
 
1950
        if fid is None:
 
1951
            raise errors.NotVersionedError(filename)
 
1952
        segments = osutils.splitpath(relpath)
 
1953
        for pos in range(1, len(segments) + 1):
 
1954
            path = osutils.joinpath(segments[:pos])
 
1955
            self.outf.write("%s\n" % tree.path2id(path))
1971
1956
 
1972
1957
 
1973
1958
class cmd_reconcile(Command):
2015
2000
    @display_command
2016
2001
    def run(self, location="."):
2017
2002
        branch = Branch.open_containing(location)[0]
2018
 
        self.enter_context(branch.lock_read())
 
2003
        self.add_cleanup(branch.lock_read().unlock)
2019
2004
        graph = branch.repository.get_graph()
2020
2005
        history = list(graph.iter_lefthand_ancestry(branch.last_revision(),
2021
 
                                                    [_mod_revision.NULL_REVISION]))
 
2006
            [_mod_revision.NULL_REVISION]))
2022
2007
        for revid in reversed(history):
2023
2008
            self.outf.write(revid)
2024
2009
            self.outf.write('\n')
2043
2028
            b = wt.branch
2044
2029
            last_revision = wt.last_revision()
2045
2030
 
2046
 
        self.enter_context(b.repository.lock_read())
 
2031
        self.add_cleanup(b.repository.lock_read().unlock)
2047
2032
        graph = b.repository.get_graph()
2048
2033
        revisions = [revid for revid, parents in
2049
 
                     graph.iter_ancestry([last_revision])]
 
2034
            graph.iter_ancestry([last_revision])]
2050
2035
        for revision_id in reversed(revisions):
2051
2036
            if _mod_revision.is_null(revision_id):
2052
2037
                continue
2053
 
            self.outf.write(revision_id.decode('utf-8') + '\n')
 
2038
            self.outf.write(revision_id + '\n')
2054
2039
 
2055
2040
 
2056
2041
class cmd_init(Command):
2076
2061
        brz commit -m "imported project"
2077
2062
    """
2078
2063
 
2079
 
    _see_also = ['init-shared-repository', 'branch', 'checkout']
 
2064
    _see_also = ['init-repository', 'branch', 'checkout']
2080
2065
    takes_args = ['location?']
2081
2066
    takes_options = [
2082
2067
        Option('create-prefix',
2083
2068
               help='Create the path leading up to the branch '
2084
2069
                    'if it does not already exist.'),
2085
 
        RegistryOption('format',
2086
 
                       help='Specify a format for this branch. '
2087
 
                       'See "help formats" for a full list.',
2088
 
                       lazy_registry=('breezy.controldir', 'format_registry'),
2089
 
                       converter=lambda name: controldir.format_registry.make_controldir(
2090
 
                            name),
2091
 
                       value_switches=True,
2092
 
                       title="Branch format",
2093
 
                       ),
2094
 
        Option('append-revisions-only',
2095
 
               help='Never change revnos or the existing log.'
2096
 
               '  Append revisions to it only.'),
2097
 
        Option('no-tree',
2098
 
               'Create a branch without a working tree.')
2099
 
        ]
2100
 
 
 
2070
         RegistryOption('format',
 
2071
                help='Specify a format for this branch. '
 
2072
                'See "help formats".',
 
2073
                lazy_registry=('breezy.controldir', 'format_registry'),
 
2074
                converter=lambda name: controldir.format_registry.make_bzrdir(name),
 
2075
                value_switches=True,
 
2076
                title="Branch format",
 
2077
                ),
 
2078
         Option('append-revisions-only',
 
2079
                help='Never change revnos or the existing log.'
 
2080
                '  Append revisions to it only.'),
 
2081
         Option('no-tree',
 
2082
                'Create a branch without a working tree.')
 
2083
         ]
2101
2084
    def run(self, location=None, format=None, append_revisions_only=False,
2102
2085
            create_prefix=False, no_tree=False):
2103
2086
        if format is None:
2104
 
            format = controldir.format_registry.make_controldir('default')
 
2087
            format = controldir.format_registry.make_bzrdir('default')
2105
2088
        if location is None:
2106
2089
            location = u'.'
2107
2090
 
2108
 
        to_transport = transport.get_transport(location, purpose='write')
 
2091
        to_transport = transport.get_transport(location)
2109
2092
 
2110
2093
        # The path has to exist to initialize a
2111
2094
        # branch inside of it.
2116
2099
            to_transport.ensure_base()
2117
2100
        except errors.NoSuchFile:
2118
2101
            if not create_prefix:
2119
 
                raise errors.CommandError(gettext("Parent directory of %s"
2120
 
                                                     " does not exist."
2121
 
                                                     "\nYou may supply --create-prefix to create all"
2122
 
                                                     " leading parent directories.")
2123
 
                                             % location)
 
2102
                raise errors.BzrCommandError(gettext("Parent directory of %s"
 
2103
                    " does not exist."
 
2104
                    "\nYou may supply --create-prefix to create all"
 
2105
                    " leading parent directories.")
 
2106
                    % location)
2124
2107
            to_transport.create_prefix()
2125
2108
 
2126
2109
        try:
2127
 
            a_controldir = controldir.ControlDir.open_from_transport(
2128
 
                to_transport)
 
2110
            a_bzrdir = controldir.ControlDir.open_from_transport(to_transport)
2129
2111
        except errors.NotBranchError:
2130
2112
            # really a NotBzrDir error...
2131
2113
            create_branch = controldir.ControlDir.create_branch_convenience
2136
2118
            branch = create_branch(to_transport.base, format=format,
2137
2119
                                   possible_transports=[to_transport],
2138
2120
                                   force_new_tree=force_new_tree)
2139
 
            a_controldir = branch.controldir
 
2121
            a_bzrdir = branch.bzrdir
2140
2122
        else:
2141
2123
            from .transport.local import LocalTransport
2142
 
            if a_controldir.has_branch():
 
2124
            if a_bzrdir.has_branch():
2143
2125
                if (isinstance(to_transport, LocalTransport)
2144
 
                        and not a_controldir.has_workingtree()):
2145
 
                    raise errors.BranchExistsWithoutWorkingTree(location)
 
2126
                    and not a_bzrdir.has_workingtree()):
 
2127
                        raise errors.BranchExistsWithoutWorkingTree(location)
2146
2128
                raise errors.AlreadyBranchError(location)
2147
 
            branch = a_controldir.create_branch()
2148
 
            if not no_tree and not a_controldir.has_workingtree():
2149
 
                a_controldir.create_workingtree()
 
2129
            branch = a_bzrdir.create_branch()
 
2130
            if not no_tree and not a_bzrdir.has_workingtree():
 
2131
                a_bzrdir.create_workingtree()
2150
2132
        if append_revisions_only:
2151
2133
            try:
2152
2134
                branch.set_append_revisions_only(True)
2153
2135
            except errors.UpgradeRequired:
2154
 
                raise errors.CommandError(gettext('This branch format cannot be set'
2155
 
                                                     ' to append-revisions-only.  Try --default.'))
 
2136
                raise errors.BzrCommandError(gettext('This branch format cannot be set'
 
2137
                    ' to append-revisions-only.  Try --default.'))
2156
2138
        if not is_quiet():
2157
2139
            from .info import describe_layout, describe_format
2158
2140
            try:
2159
 
                tree = a_controldir.open_workingtree(recommend_upgrade=False)
 
2141
                tree = a_bzrdir.open_workingtree(recommend_upgrade=False)
2160
2142
            except (errors.NoWorkingTree, errors.NotLocalUrl):
2161
2143
                tree = None
2162
2144
            repository = branch.repository
2163
2145
            layout = describe_layout(repository, branch, tree).lower()
2164
 
            format = describe_format(a_controldir, repository, branch, tree)
 
2146
            format = describe_format(a_bzrdir, repository, branch, tree)
2165
2147
            self.outf.write(gettext("Created a {0} (format: {1})\n").format(
2166
 
                layout, format))
 
2148
                  layout, format))
2167
2149
            if repository.is_shared():
2168
 
                # XXX: maybe this can be refactored into transport.path_or_url()
2169
 
                url = repository.controldir.root_transport.external_url()
 
2150
                #XXX: maybe this can be refactored into transport.path_or_url()
 
2151
                url = repository.bzrdir.root_transport.external_url()
2170
2152
                try:
2171
2153
                    url = urlutils.local_path_from_url(url)
2172
 
                except urlutils.InvalidURL:
 
2154
                except errors.InvalidURL:
2173
2155
                    pass
2174
2156
                self.outf.write(gettext("Using shared repository: %s\n") % url)
2175
2157
 
2176
2158
 
2177
 
class cmd_init_shared_repository(Command):
 
2159
class cmd_init_repository(Command):
2178
2160
    __doc__ = """Create a shared repository for branches to share storage space.
2179
2161
 
2180
2162
    New branches created under the repository directory will store their
2181
2163
    revisions in the repository, not in the branch directory.  For branches
2182
 
    with shared history, this reduces the amount of storage needed and
 
2164
    with shared history, this reduces the amount of storage needed and 
2183
2165
    speeds up the creation of new branches.
2184
2166
 
2185
2167
    If the --no-trees option is given then the branches in the repository
2186
 
    will not have working trees by default.  They will still exist as
2187
 
    directories on disk, but they will not have separate copies of the
 
2168
    will not have working trees by default.  They will still exist as 
 
2169
    directories on disk, but they will not have separate copies of the 
2188
2170
    files at a certain revision.  This can be useful for repositories that
2189
2171
    store branches which are interacted with through checkouts or remote
2190
2172
    branches, such as on a server.
2192
2174
    :Examples:
2193
2175
        Create a shared repository holding just branches::
2194
2176
 
2195
 
            brz init-shared-repo --no-trees repo
 
2177
            brz init-repo --no-trees repo
2196
2178
            brz init repo/trunk
2197
2179
 
2198
2180
        Make a lightweight checkout elsewhere::
2205
2187
    _see_also = ['init', 'branch', 'checkout', 'repositories']
2206
2188
    takes_args = ["location"]
2207
2189
    takes_options = [RegistryOption('format',
2208
 
                                    help='Specify a format for this repository. See'
2209
 
                                    ' "brz help formats" for details.',
2210
 
                                    lazy_registry=(
2211
 
                                        'breezy.controldir', 'format_registry'),
2212
 
                                    converter=lambda name: controldir.format_registry.make_controldir(
2213
 
                                        name),
2214
 
                                    value_switches=True, title='Repository format'),
 
2190
                            help='Specify a format for this repository. See'
 
2191
                                 ' "brz help formats" for details.',
 
2192
                            lazy_registry=('breezy.controldir', 'format_registry'),
 
2193
                            converter=lambda name: controldir.format_registry.make_bzrdir(name),
 
2194
                            value_switches=True, title='Repository format'),
2215
2195
                     Option('no-trees',
2216
 
                            help='Branches in the repository will default to'
2217
 
                            ' not having a working tree.'),
2218
 
                     ]
2219
 
    aliases = ["init-shared-repo", "init-repo"]
 
2196
                             help='Branches in the repository will default to'
 
2197
                                  ' not having a working tree.'),
 
2198
                    ]
 
2199
    aliases = ["init-repo"]
2220
2200
 
2221
2201
    def run(self, location, format=None, no_trees=False):
2222
2202
        if format is None:
2223
 
            format = controldir.format_registry.make_controldir('default')
 
2203
            format = controldir.format_registry.make_bzrdir('default')
2224
2204
 
2225
2205
        if location is None:
2226
2206
            location = '.'
2227
2207
 
2228
 
        to_transport = transport.get_transport(location, purpose='write')
2229
 
 
2230
 
        if format.fixed_components:
2231
 
            repo_format_name = None
2232
 
        else:
2233
 
            repo_format_name = format.repository_format.get_format_string()
 
2208
        to_transport = transport.get_transport(location)
2234
2209
 
2235
2210
        (repo, newdir, require_stacking, repository_policy) = (
2236
2211
            format.initialize_on_transport_ex(to_transport,
2237
 
                                              create_prefix=True, make_working_trees=not no_trees,
2238
 
                                              shared_repo=True, force_new_repo=True,
2239
 
                                              use_existing_dir=True,
2240
 
                                              repo_format_name=repo_format_name))
 
2212
            create_prefix=True, make_working_trees=not no_trees,
 
2213
            shared_repo=True, force_new_repo=True,
 
2214
            use_existing_dir=True,
 
2215
            repo_format_name=format.repository_format.get_format_string()))
2241
2216
        if not is_quiet():
2242
2217
            from .info import show_bzrdir_info
2243
2218
            show_bzrdir_info(newdir, verbose=0, outfile=self.outf)
2258
2233
 
2259
2234
    Note that when using the -r argument with a range of revisions, the
2260
2235
    differences are computed between the two specified revisions.  That
2261
 
    is, the command does not show the changes introduced by the first
2262
 
    revision in the range.  This differs from the interpretation of
 
2236
    is, the command does not show the changes introduced by the first 
 
2237
    revision in the range.  This differs from the interpretation of 
2263
2238
    revision ranges used by "brz log" which includes the first revision
2264
2239
    in the range.
2265
2240
 
2291
2266
            brz diff -c2
2292
2267
 
2293
2268
        To see the changes introduced by revision X::
2294
 
 
 
2269
        
2295
2270
            brz diff -cX
2296
2271
 
2297
2272
        Note that in the case of a merge, the -c option shows the changes
2339
2314
               help='Set prefixes added to old and new filenames, as '
2340
2315
                    'two values separated by a colon. (eg "old/:new/").'),
2341
2316
        Option('old',
2342
 
               help='Branch/tree to compare from.',
2343
 
               type=str,
2344
 
               ),
 
2317
            help='Branch/tree to compare from.',
 
2318
            type=text_type,
 
2319
            ),
2345
2320
        Option('new',
2346
 
               help='Branch/tree to compare to.',
2347
 
               type=str,
2348
 
               ),
 
2321
            help='Branch/tree to compare to.',
 
2322
            type=text_type,
 
2323
            ),
2349
2324
        'revision',
2350
2325
        'change',
2351
2326
        Option('using',
2352
 
               help='Use this command to compare files.',
2353
 
               type=str,
2354
 
               ),
 
2327
            help='Use this command to compare files.',
 
2328
            type=text_type,
 
2329
            ),
2355
2330
        RegistryOption('format',
2356
 
                       short_name='F',
2357
 
                       help='Diff format to use.',
2358
 
                       lazy_registry=('breezy.diff', 'format_registry'),
2359
 
                       title='Diff format'),
 
2331
            short_name='F',
 
2332
            help='Diff format to use.',
 
2333
            lazy_registry=('breezy.diff', 'format_registry'),
 
2334
            title='Diff format'),
2360
2335
        Option('context',
2361
 
               help='How many lines of context to show.',
2362
 
               type=int,
2363
 
               ),
2364
 
        RegistryOption.from_kwargs(
2365
 
            'color',
2366
 
            help='Color mode to use.',
2367
 
            title='Color Mode', value_switches=False, enum_switch=True,
2368
 
            never='Never colorize output.',
2369
 
            auto='Only colorize output if terminal supports it and STDOUT is a'
2370
 
            ' TTY.',
2371
 
            always='Always colorize output (default).'),
2372
 
        Option(
2373
 
            'check-style',
2374
 
            help=('Warn if trailing whitespace or spurious changes have been'
2375
 
                  '  added.'))
 
2336
            help='How many lines of context to show.',
 
2337
            type=int,
 
2338
            ),
2376
2339
        ]
2377
 
 
2378
2340
    aliases = ['di', 'dif']
2379
2341
    encoding_type = 'exact'
2380
2342
 
2381
2343
    @display_command
2382
2344
    def run(self, revision=None, file_list=None, diff_options=None,
2383
2345
            prefix=None, old=None, new=None, using=None, format=None,
2384
 
            context=None, color='never'):
 
2346
            context=None):
2385
2347
        from .diff import (get_trees_and_branches_to_diff_locked,
2386
 
                           show_diff_trees)
 
2348
            show_diff_trees)
2387
2349
 
2388
 
        if prefix == u'0':
 
2350
        if prefix == '0':
2389
2351
            # diff -p0 format
2390
2352
            old_label = ''
2391
2353
            new_label = ''
2392
 
        elif prefix == u'1' or prefix is None:
 
2354
        elif prefix == '1' or prefix is None:
2393
2355
            old_label = 'old/'
2394
2356
            new_label = 'new/'
2395
 
        elif u':' in prefix:
2396
 
            old_label, new_label = prefix.split(u":")
 
2357
        elif ':' in prefix:
 
2358
            old_label, new_label = prefix.split(":")
2397
2359
        else:
2398
 
            raise errors.CommandError(gettext(
 
2360
            raise errors.BzrCommandError(gettext(
2399
2361
                '--prefix expects two values separated by a colon'
2400
2362
                ' (eg "old/:new/")'))
2401
2363
 
2402
2364
        if revision and len(revision) > 2:
2403
 
            raise errors.CommandError(gettext('brz diff --revision takes exactly'
2404
 
                                                 ' one or two revision specifiers'))
 
2365
            raise errors.BzrCommandError(gettext('brz diff --revision takes exactly'
 
2366
                                         ' one or two revision specifiers'))
2405
2367
 
2406
2368
        if using is not None and format is not None:
2407
 
            raise errors.CommandError(gettext(
 
2369
            raise errors.BzrCommandError(gettext(
2408
2370
                '{0} and {1} are mutually exclusive').format(
2409
2371
                '--using', '--format'))
2410
2372
 
2411
2373
        (old_tree, new_tree,
2412
2374
         old_branch, new_branch,
2413
2375
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
2414
 
            file_list, revision, old, new, self._exit_stack, apply_view=True)
 
2376
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
2415
2377
        # GNU diff on Windows uses ANSI encoding for filenames
2416
2378
        path_encoding = osutils.get_diff_header_encoding()
2417
 
        outf = self.outf
2418
 
        if color == 'auto':
2419
 
            from .terminal import has_ansi_colors
2420
 
            if has_ansi_colors():
2421
 
                color = 'always'
2422
 
            else:
2423
 
                color = 'never'
2424
 
        if 'always' == color:
2425
 
            from .colordiff import DiffWriter
2426
 
            outf = DiffWriter(outf)
2427
 
        return show_diff_trees(old_tree, new_tree, outf,
 
2379
        return show_diff_trees(old_tree, new_tree, sys.stdout,
2428
2380
                               specific_files=specific_files,
2429
2381
                               external_diff_options=diff_options,
2430
2382
                               old_label=old_label, new_label=new_label,
2449
2401
    @display_command
2450
2402
    def run(self, show_ids=False, directory=u'.'):
2451
2403
        tree = WorkingTree.open_containing(directory)[0]
2452
 
        self.enter_context(tree.lock_read())
 
2404
        self.add_cleanup(tree.lock_read().unlock)
2453
2405
        old = tree.basis_tree()
2454
 
        self.enter_context(old.lock_read())
2455
 
        delta = tree.changes_from(old)
2456
 
        for change in delta.removed:
2457
 
            self.outf.write(change.path[0])
2458
 
            if show_ids:
2459
 
                self.outf.write(' ')
2460
 
                self.outf.write(change.file_id)
2461
 
            self.outf.write('\n')
 
2406
        self.add_cleanup(old.lock_read().unlock)
 
2407
        for path, ie in old.iter_entries_by_dir():
 
2408
            if not tree.has_id(ie.file_id):
 
2409
                self.outf.write(path)
 
2410
                if show_ids:
 
2411
                    self.outf.write(' ')
 
2412
                    self.outf.write(ie.file_id)
 
2413
                self.outf.write('\n')
2462
2414
 
2463
2415
 
2464
2416
class cmd_modified(Command):
2472
2424
    @display_command
2473
2425
    def run(self, null=False, directory=u'.'):
2474
2426
        tree = WorkingTree.open_containing(directory)[0]
2475
 
        self.enter_context(tree.lock_read())
 
2427
        self.add_cleanup(tree.lock_read().unlock)
2476
2428
        td = tree.changes_from(tree.basis_tree())
2477
2429
        self.cleanup_now()
2478
 
        for change in td.modified:
 
2430
        for path, id, kind, text_modified, meta_modified in td.modified:
2479
2431
            if null:
2480
 
                self.outf.write(change.path[1] + '\0')
 
2432
                self.outf.write(path + '\0')
2481
2433
            else:
2482
 
                self.outf.write(osutils.quotefn(change.path[1]) + '\n')
 
2434
                self.outf.write(osutils.quotefn(path) + '\n')
2483
2435
 
2484
2436
 
2485
2437
class cmd_added(Command):
2493
2445
    @display_command
2494
2446
    def run(self, null=False, directory=u'.'):
2495
2447
        wt = WorkingTree.open_containing(directory)[0]
2496
 
        self.enter_context(wt.lock_read())
 
2448
        self.add_cleanup(wt.lock_read().unlock)
2497
2449
        basis = wt.basis_tree()
2498
 
        self.enter_context(basis.lock_read())
2499
 
        for path in wt.all_versioned_paths():
2500
 
            if basis.has_filename(path):
2501
 
                continue
2502
 
            if path == u'':
2503
 
                continue
 
2450
        self.add_cleanup(basis.lock_read().unlock)
 
2451
        root_id = wt.get_root_id()
 
2452
        for file_id in wt.all_file_ids():
 
2453
            if basis.has_id(file_id):
 
2454
                continue
 
2455
            if root_id == file_id:
 
2456
                continue
 
2457
            path = wt.id2path(file_id)
2504
2458
            if not os.access(osutils.pathjoin(wt.basedir, path), os.F_OK):
2505
2459
                continue
2506
2460
            if null:
2512
2466
class cmd_root(Command):
2513
2467
    __doc__ = """Show the tree root directory.
2514
2468
 
2515
 
    The root is the nearest enclosing directory with a control
 
2469
    The root is the nearest enclosing directory with a .bzr control
2516
2470
    directory."""
2517
2471
 
2518
2472
    takes_args = ['filename?']
2519
 
 
2520
2473
    @display_command
2521
2474
    def run(self, filename=None):
2522
2475
        """Print the branch root."""
2529
2482
        return int(limitstring)
2530
2483
    except ValueError:
2531
2484
        msg = gettext("The limit argument must be an integer.")
2532
 
        raise errors.CommandError(msg)
 
2485
        raise errors.BzrCommandError(msg)
2533
2486
 
2534
2487
 
2535
2488
def _parse_levels(s):
2537
2490
        return int(s)
2538
2491
    except ValueError:
2539
2492
        msg = gettext("The levels argument must be an integer.")
2540
 
        raise errors.CommandError(msg)
 
2493
        raise errors.BzrCommandError(msg)
2541
2494
 
2542
2495
 
2543
2496
class cmd_log(Command):
2664
2617
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
2665
2618
      bzr-explorer shell, or the Loggerhead web interface.  See the Bazaar
2666
2619
      Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/> and
2667
 
      <http://wiki.bazaar.canonical.com/IDEIntegration>.
 
2620
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
2668
2621
 
2669
 
      You may find it useful to add the aliases below to ``breezy.conf``::
 
2622
      You may find it useful to add the aliases below to ``bazaar.conf``::
2670
2623
 
2671
2624
        [ALIASES]
2672
2625
        tip = log -r-1
2698
2651
    takes_args = ['file*']
2699
2652
    _see_also = ['log-formats', 'revisionspec']
2700
2653
    takes_options = [
2701
 
        Option('forward',
2702
 
               help='Show from oldest to newest.'),
2703
 
        'timezone',
2704
 
        custom_help('verbose',
2705
 
                    help='Show files changed in each revision.'),
2706
 
        'show-ids',
2707
 
        'revision',
2708
 
        Option('change',
2709
 
               type=breezy.option._parse_revision_str,
2710
 
               short_name='c',
2711
 
               help='Show just the specified revision.'
2712
 
               ' See also "help revisionspec".'),
2713
 
        'log-format',
2714
 
        RegistryOption('authors',
2715
 
                       'What names to list as authors - first, all or committer.',
2716
 
                       title='Authors',
2717
 
                       lazy_registry=(
2718
 
                           'breezy.log', 'author_list_registry'),
2719
 
                       ),
2720
 
        Option('levels',
2721
 
               short_name='n',
2722
 
               help='Number of levels to display - 0 for all, 1 for flat.',
2723
 
               argname='N',
2724
 
               type=_parse_levels),
2725
 
        Option('message',
2726
 
               help='Show revisions whose message matches this '
2727
 
               'regular expression.',
2728
 
               type=str,
2729
 
               hidden=True),
2730
 
        Option('limit',
2731
 
               short_name='l',
2732
 
               help='Limit the output to the first N revisions.',
2733
 
               argname='N',
2734
 
               type=_parse_limit),
2735
 
        Option('show-diff',
2736
 
               short_name='p',
2737
 
               help='Show changes made in each revision as a patch.'),
2738
 
        Option('include-merged',
2739
 
               help='Show merged revisions like --levels 0 does.'),
2740
 
        Option('include-merges', hidden=True,
2741
 
               help='Historical alias for --include-merged.'),
2742
 
        Option('omit-merges',
2743
 
               help='Do not report commits with more than one parent.'),
2744
 
        Option('exclude-common-ancestry',
2745
 
               help='Display only the revisions that are not part'
2746
 
               ' of both ancestries (require -rX..Y).'
2747
 
               ),
2748
 
        Option('signatures',
2749
 
               help='Show digital signature validity.'),
2750
 
        ListOption('match',
2751
 
                   short_name='m',
2752
 
                   help='Show revisions whose properties match this '
2753
 
                   'expression.',
2754
 
                   type=str),
2755
 
        ListOption('match-message',
2756
 
                   help='Show revisions whose message matches this '
2757
 
                   'expression.',
2758
 
                   type=str),
2759
 
        ListOption('match-committer',
 
2654
            Option('forward',
 
2655
                   help='Show from oldest to newest.'),
 
2656
            'timezone',
 
2657
            custom_help('verbose',
 
2658
                   help='Show files changed in each revision.'),
 
2659
            'show-ids',
 
2660
            'revision',
 
2661
            Option('change',
 
2662
                   type=breezy.option._parse_revision_str,
 
2663
                   short_name='c',
 
2664
                   help='Show just the specified revision.'
 
2665
                   ' See also "help revisionspec".'),
 
2666
            'log-format',
 
2667
            RegistryOption('authors',
 
2668
                'What names to list as authors - first, all or committer.',
 
2669
                title='Authors',
 
2670
                lazy_registry=('breezy.log', 'author_list_registry'),
 
2671
            ),
 
2672
            Option('levels',
 
2673
                   short_name='n',
 
2674
                   help='Number of levels to display - 0 for all, 1 for flat.',
 
2675
                   argname='N',
 
2676
                   type=_parse_levels),
 
2677
            Option('message',
 
2678
                   help='Show revisions whose message matches this '
 
2679
                        'regular expression.',
 
2680
                   type=str,
 
2681
                   hidden=True),
 
2682
            Option('limit',
 
2683
                   short_name='l',
 
2684
                   help='Limit the output to the first N revisions.',
 
2685
                   argname='N',
 
2686
                   type=_parse_limit),
 
2687
            Option('show-diff',
 
2688
                   short_name='p',
 
2689
                   help='Show changes made in each revision as a patch.'),
 
2690
            Option('include-merged',
 
2691
                   help='Show merged revisions like --levels 0 does.'),
 
2692
            Option('include-merges', hidden=True,
 
2693
                   help='Historical alias for --include-merged.'),
 
2694
            Option('omit-merges',
 
2695
                   help='Do not report commits with more than one parent.'),
 
2696
            Option('exclude-common-ancestry',
 
2697
                   help='Display only the revisions that are not part'
 
2698
                   ' of both ancestries (require -rX..Y).'
 
2699
                   ),
 
2700
            Option('signatures',
 
2701
                   help='Show digital signature validity.'),
 
2702
            ListOption('match',
 
2703
                short_name='m',
 
2704
                help='Show revisions whose properties match this '
 
2705
                'expression.',
 
2706
                type=str),
 
2707
            ListOption('match-message',
 
2708
                   help='Show revisions whose message matches this '
 
2709
                   'expression.',
 
2710
                type=str),
 
2711
            ListOption('match-committer',
2760
2712
                   help='Show revisions whose committer matches this '
2761
2713
                   'expression.',
2762
 
                   type=str),
2763
 
        ListOption('match-author',
 
2714
                type=str),
 
2715
            ListOption('match-author',
2764
2716
                   help='Show revisions whose authors match this '
2765
2717
                   'expression.',
2766
 
                   type=str),
2767
 
        ListOption('match-bugs',
 
2718
                type=str),
 
2719
            ListOption('match-bugs',
2768
2720
                   help='Show revisions whose bugs match this '
2769
2721
                   'expression.',
2770
 
                   type=str)
2771
 
        ]
 
2722
                type=str)
 
2723
            ]
2772
2724
    encoding_type = 'replace'
2773
2725
 
2774
2726
    @display_command
2803
2755
        if include_merged is None:
2804
2756
            include_merged = False
2805
2757
        if (exclude_common_ancestry
2806
 
                and (revision is None or len(revision) != 2)):
2807
 
            raise errors.CommandError(gettext(
 
2758
            and (revision is None or len(revision) != 2)):
 
2759
            raise errors.BzrCommandError(gettext(
2808
2760
                '--exclude-common-ancestry requires -r with two revisions'))
2809
2761
        if include_merged:
2810
2762
            if levels is None:
2811
2763
                levels = 0
2812
2764
            else:
2813
 
                raise errors.CommandError(gettext(
 
2765
                raise errors.BzrCommandError(gettext(
2814
2766
                    '{0} and {1} are mutually exclusive').format(
2815
2767
                    '--levels', '--include-merged'))
2816
2768
 
2818
2770
            if len(change) > 1:
2819
2771
                raise errors.RangeInChangeOption()
2820
2772
            if revision is not None:
2821
 
                raise errors.CommandError(gettext(
 
2773
                raise errors.BzrCommandError(gettext(
2822
2774
                    '{0} and {1} are mutually exclusive').format(
2823
2775
                    '--revision', '--change'))
2824
2776
            else:
2825
2777
                revision = change
2826
2778
 
2827
 
        files = []
 
2779
        file_ids = []
2828
2780
        filter_by_dir = False
2829
2781
        if file_list:
2830
2782
            # find the file ids to log and check for directory filtering
2831
2783
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2832
 
                revision, file_list, self._exit_stack)
2833
 
            for relpath, kind in file_info_list:
2834
 
                if not kind:
2835
 
                    raise errors.CommandError(gettext(
 
2784
                revision, file_list, self.add_cleanup)
 
2785
            for relpath, file_id, kind in file_info_list:
 
2786
                if file_id is None:
 
2787
                    raise errors.BzrCommandError(gettext(
2836
2788
                        "Path unknown at end or start of revision range: %s") %
2837
2789
                        relpath)
2838
2790
                # If the relpath is the top of the tree, we log everything
2839
2791
                if relpath == '':
2840
 
                    files = []
 
2792
                    file_ids = []
2841
2793
                    break
2842
2794
                else:
2843
 
                    files.append(relpath)
 
2795
                    file_ids.append(file_id)
2844
2796
                filter_by_dir = filter_by_dir or (
2845
2797
                    kind in ['directory', 'tree-reference'])
2846
2798
        else:
2853
2805
                location = '.'
2854
2806
            dir, relpath = controldir.ControlDir.open_containing(location)
2855
2807
            b = dir.open_branch()
2856
 
            self.enter_context(b.lock_read())
 
2808
            self.add_cleanup(b.lock_read().unlock)
2857
2809
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2858
2810
 
2859
2811
        if b.get_config_stack().get('validate_signatures_in_log'):
2871
2823
            delta_type = 'full'
2872
2824
        if not show_diff:
2873
2825
            diff_type = None
2874
 
        elif files:
 
2826
        elif file_ids:
2875
2827
            diff_type = 'partial'
2876
2828
        else:
2877
2829
            diff_type = 'full'
2880
2832
        if log_format is None:
2881
2833
            log_format = log.log_formatter_registry.get_default(b)
2882
2834
        # Make a non-encoding output to include the diffs - bug 328007
2883
 
        unencoded_output = ui.ui_factory.make_output_stream(
2884
 
            encoding_type='exact')
 
2835
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
2885
2836
        lf = log_format(show_ids=show_ids, to_file=self.outf,
2886
2837
                        to_exact_file=unencoded_output,
2887
2838
                        show_timezone=timezone,
2903
2854
        # original algorithm - per-file-graph - for the "single
2904
2855
        # file that isn't a directory without showing a delta" case.
2905
2856
        partial_history = revision and b.repository._format.supports_chks
2906
 
        match_using_deltas = (len(files) != 1 or filter_by_dir
2907
 
                              or delta_type or partial_history)
 
2857
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2858
            or delta_type or partial_history)
2908
2859
 
2909
2860
        match_dict = {}
2910
2861
        if match:
2919
2870
            match_dict['bugs'] = match_bugs
2920
2871
 
2921
2872
        # Build the LogRequest and execute it
2922
 
        if len(files) == 0:
2923
 
            files = None
 
2873
        if len(file_ids) == 0:
 
2874
            file_ids = None
2924
2875
        rqst = make_log_request_dict(
2925
 
            direction=direction, specific_files=files,
 
2876
            direction=direction, specific_fileids=file_ids,
2926
2877
            start_revision=rev1, end_revision=rev2, limit=limit,
2927
2878
            message_search=message, delta_type=delta_type,
2928
2879
            diff_type=diff_type, _match_using_deltas=match_using_deltas,
2950
2901
            # b is taken from revision[0].get_branch(), and
2951
2902
            # show_log will use its revision_history. Having
2952
2903
            # different branches will lead to weird behaviors.
2953
 
            raise errors.CommandError(gettext(
 
2904
            raise errors.BzrCommandError(gettext(
2954
2905
                "brz %s doesn't accept two revisions in different"
2955
2906
                " branches.") % command_name)
2956
2907
        if start_spec.spec is None:
2966
2917
        else:
2967
2918
            rev2 = end_spec.in_history(branch)
2968
2919
    else:
2969
 
        raise errors.CommandError(gettext(
 
2920
        raise errors.BzrCommandError(gettext(
2970
2921
            'brz %s --revision takes one or two values.') % command_name)
2971
2922
    return rev1, rev2
2972
2923
 
2980
2931
        rev_id2 = revision_range[1].rev_id
2981
2932
    return rev_id1, rev_id2
2982
2933
 
2983
 
 
2984
2934
def get_log_format(long=False, short=False, line=False, default='long'):
2985
2935
    log_format = default
2986
2936
    if long:
3004
2954
    @display_command
3005
2955
    def run(self, filename):
3006
2956
        tree, relpath = WorkingTree.open_containing(filename)
3007
 
        with tree.lock_read():
3008
 
            touching_revs = log.find_touching_revisions(
3009
 
                tree.branch.repository, tree.branch.last_revision(), tree, relpath)
3010
 
            for revno, revision_id, what in reversed(list(touching_revs)):
3011
 
                self.outf.write("%6d %s\n" % (revno, what))
 
2957
        file_id = tree.path2id(relpath)
 
2958
        b = tree.branch
 
2959
        self.add_cleanup(b.lock_read().unlock)
 
2960
        touching_revs = log.find_touching_revisions(b, file_id)
 
2961
        for revno, revision_id, what in touching_revs:
 
2962
            self.outf.write("%6d %s\n" % (revno, what))
3012
2963
 
3013
2964
 
3014
2965
class cmd_ls(Command):
3018
2969
    _see_also = ['status', 'cat']
3019
2970
    takes_args = ['path?']
3020
2971
    takes_options = [
3021
 
        'verbose',
3022
 
        'revision',
3023
 
        Option('recursive', short_name='R',
3024
 
               help='Recurse into subdirectories.'),
3025
 
        Option('from-root',
3026
 
               help='Print paths relative to the root of the branch.'),
3027
 
        Option('unknown', short_name='u',
3028
 
               help='Print unknown files.'),
3029
 
        Option('versioned', help='Print versioned files.',
3030
 
               short_name='V'),
3031
 
        Option('ignored', short_name='i',
3032
 
               help='Print ignored files.'),
3033
 
        Option('kind', short_name='k',
3034
 
               help=('List entries of a particular kind: file, '
3035
 
                     'directory, symlink, tree-reference.'),
3036
 
               type=str),
3037
 
        'null',
3038
 
        'show-ids',
3039
 
        'directory',
3040
 
        ]
3041
 
 
 
2972
            'verbose',
 
2973
            'revision',
 
2974
            Option('recursive', short_name='R',
 
2975
                   help='Recurse into subdirectories.'),
 
2976
            Option('from-root',
 
2977
                   help='Print paths relative to the root of the branch.'),
 
2978
            Option('unknown', short_name='u',
 
2979
                help='Print unknown files.'),
 
2980
            Option('versioned', help='Print versioned files.',
 
2981
                   short_name='V'),
 
2982
            Option('ignored', short_name='i',
 
2983
                help='Print ignored files.'),
 
2984
            Option('kind', short_name='k',
 
2985
                   help='List entries of a particular kind: file, directory, symlink.',
 
2986
                   type=text_type),
 
2987
            'null',
 
2988
            'show-ids',
 
2989
            'directory',
 
2990
            ]
3042
2991
    @display_command
3043
2992
    def run(self, revision=None, verbose=False,
3044
2993
            recursive=False, from_root=False,
3045
2994
            unknown=False, versioned=False, ignored=False,
3046
2995
            null=False, kind=None, show_ids=False, path=None, directory=None):
3047
2996
 
3048
 
        if kind and kind not in ('file', 'directory', 'symlink', 'tree-reference'):
3049
 
            raise errors.CommandError(gettext('invalid kind specified'))
 
2997
        if kind and kind not in ('file', 'directory', 'symlink'):
 
2998
            raise errors.BzrCommandError(gettext('invalid kind specified'))
3050
2999
 
3051
3000
        if verbose and null:
3052
 
            raise errors.CommandError(
3053
 
                gettext('Cannot set both --verbose and --null'))
 
3001
            raise errors.BzrCommandError(gettext('Cannot set both --verbose and --null'))
3054
3002
        all = not (unknown or versioned or ignored)
3055
3003
 
3056
 
        selection = {'I': ignored, '?': unknown, 'V': versioned}
 
3004
        selection = {'I':ignored, '?':unknown, 'V':versioned}
3057
3005
 
3058
3006
        if path is None:
3059
3007
            fs_path = '.'
3060
3008
        else:
3061
3009
            if from_root:
3062
 
                raise errors.CommandError(gettext('cannot specify both --from-root'
3063
 
                                                     ' and PATH'))
 
3010
                raise errors.BzrCommandError(gettext('cannot specify both --from-root'
 
3011
                                             ' and PATH'))
3064
3012
            fs_path = path
3065
3013
        tree, branch, relpath = \
3066
3014
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
3084
3032
                view_str = views.view_display_str(view_files)
3085
3033
                note(gettext("Ignoring files outside view. View is %s") % view_str)
3086
3034
 
3087
 
        self.enter_context(tree.lock_read())
3088
 
        for fp, fc, fkind, entry in tree.list_files(
3089
 
                include_root=False, from_dir=relpath, recursive=recursive):
 
3035
        self.add_cleanup(tree.lock_read().unlock)
 
3036
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
3037
            from_dir=relpath, recursive=recursive):
3090
3038
            # Apply additional masking
3091
3039
            if not all and not selection[fc]:
3092
3040
                continue
3099
3047
                    else:
3100
3048
                        fullpath = fp
3101
3049
                    views.check_path_in_view(tree, fullpath)
3102
 
                except views.FileOutsideView:
 
3050
                except errors.FileOutsideView:
3103
3051
                    continue
3104
3052
 
3105
3053
            # Output the entry
3110
3058
            ui.ui_factory.clear_term()
3111
3059
            if verbose:
3112
3060
                outstring = '%-8s %s' % (fc, outstring)
3113
 
                if show_ids and getattr(entry, 'file_id', None) is not None:
3114
 
                    outstring = "%-50s %s" % (outstring, entry.file_id.decode('utf-8'))
 
3061
                if show_ids and fid is not None:
 
3062
                    outstring = "%-50s %s" % (outstring, fid)
3115
3063
                self.outf.write(outstring + '\n')
3116
3064
            elif null:
3117
3065
                self.outf.write(fp + '\0')
3118
3066
                if show_ids:
3119
 
                    if getattr(entry, 'file_id', None) is not None:
3120
 
                        self.outf.write(entry.file_id.decode('utf-8'))
 
3067
                    if fid is not None:
 
3068
                        self.outf.write(fid)
3121
3069
                    self.outf.write('\0')
3122
3070
                self.outf.flush()
3123
3071
            else:
3124
3072
                if show_ids:
3125
 
                    if getattr(entry, 'file_id', None) is not None:
3126
 
                        my_id = entry.file_id.decode('utf-8')
 
3073
                    if fid is not None:
 
3074
                        my_id = fid
3127
3075
                    else:
3128
3076
                        my_id = ''
3129
3077
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
3152
3100
 
3153
3101
    If a .bzrignore file does not exist, the ignore command
3154
3102
    will create one and add the specified files or patterns to the newly
3155
 
    created file. The ignore command will also automatically add the
 
3103
    created file. The ignore command will also automatically add the 
3156
3104
    .bzrignore file to be versioned. Creating a .bzrignore file without
3157
3105
    the use of the ignore command will require an explicit add command.
3158
3106
 
3160
3108
    After adding, editing or deleting that file either indirectly by
3161
3109
    using this command or directly by using an editor, be sure to commit
3162
3110
    it.
3163
 
 
3164
 
    Breezy also supports a global ignore file ~/.config/breezy/ignore. On
3165
 
    Windows the global ignore file can be found in the application data
3166
 
    directory as
3167
 
    C:\\Documents and Settings\\<user>\\Application Data\\Breezy\\3.0\\ignore.
 
3111
    
 
3112
    Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
 
3113
    the global ignore file can be found in the application data directory as
 
3114
    C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
3168
3115
    Global ignores are not touched by this command. The global ignore file
3169
3116
    can be edited directly using an editor.
3170
3117
 
3171
3118
    Patterns prefixed with '!' are exceptions to ignore patterns and take
3172
3119
    precedence over regular ignores.  Such exceptions are used to specify
3173
3120
    files that should be versioned which would otherwise be ignored.
3174
 
 
 
3121
    
3175
3122
    Patterns prefixed with '!!' act as regular ignore patterns, but have
3176
3123
    precedence over the '!' exception patterns.
3177
3124
 
3178
 
    :Notes:
3179
 
 
 
3125
    :Notes: 
 
3126
        
3180
3127
    * Ignore patterns containing shell wildcards must be quoted from
3181
3128
      the shell on Unix.
3182
3129
 
3206
3153
 
3207
3154
        Ignore .o files under the lib directory::
3208
3155
 
3209
 
            brz ignore "RE:lib/.*\\.o"
 
3156
            brz ignore "RE:lib/.*\.o"
3210
3157
 
3211
3158
        Ignore everything but the "debian" toplevel directory::
3212
3159
 
3213
3160
            brz ignore "RE:(?!debian/).*"
3214
 
 
 
3161
        
3215
3162
        Ignore everything except the "local" toplevel directory,
3216
3163
        but always ignore autosave files ending in ~, even under local/::
3217
 
 
 
3164
        
3218
3165
            brz ignore "*"
3219
3166
            brz ignore "!./local"
3220
3167
            brz ignore "!!*~"
3223
3170
    _see_also = ['status', 'ignored', 'patterns']
3224
3171
    takes_args = ['name_pattern*']
3225
3172
    takes_options = ['directory',
3226
 
                     Option('default-rules',
3227
 
                            help='Display the default ignore rules that brz uses.')
3228
 
                     ]
 
3173
        Option('default-rules',
 
3174
               help='Display the default ignore rules that brz uses.')
 
3175
        ]
3229
3176
 
3230
3177
    def run(self, name_pattern_list=None, default_rules=None,
3231
3178
            directory=u'.'):
3236
3183
                self.outf.write("%s\n" % pattern)
3237
3184
            return
3238
3185
        if not name_pattern_list:
3239
 
            raise errors.CommandError(gettext("ignore requires at least one "
3240
 
                                                 "NAME_PATTERN or --default-rules."))
 
3186
            raise errors.BzrCommandError(gettext("ignore requires at least one "
 
3187
                "NAME_PATTERN or --default-rules."))
3241
3188
        name_pattern_list = [globbing.normalize_pattern(p)
3242
3189
                             for p in name_pattern_list]
3243
3190
        bad_patterns = ''
3247
3194
                bad_patterns_count += 1
3248
3195
                bad_patterns += ('\n  %s' % p)
3249
3196
        if bad_patterns:
3250
 
            msg = (ngettext('Invalid ignore pattern found. %s',
 
3197
            msg = (ngettext('Invalid ignore pattern found. %s', 
3251
3198
                            'Invalid ignore patterns found. %s',
3252
3199
                            bad_patterns_count) % bad_patterns)
3253
3200
            ui.ui_factory.show_error(msg)
3254
 
            raise lazy_regex.InvalidPattern('')
 
3201
            raise errors.InvalidPattern('')
3255
3202
        for name_pattern in name_pattern_list:
3256
3203
            if (name_pattern[0] == '/' or
3257
 
                    (len(name_pattern) > 1 and name_pattern[1] == ':')):
3258
 
                raise errors.CommandError(gettext(
 
3204
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
 
3205
                raise errors.BzrCommandError(gettext(
3259
3206
                    "NAME_PATTERN should not be an absolute path"))
3260
3207
        tree, relpath = WorkingTree.open_containing(directory)
3261
3208
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
3262
3209
        ignored = globbing.Globster(name_pattern_list)
3263
3210
        matches = []
3264
 
        self.enter_context(tree.lock_read())
3265
 
        for filename, fc, fkind, entry in tree.list_files():
3266
 
            id = getattr(entry, 'file_id', None)
 
3211
        self.add_cleanup(tree.lock_read().unlock)
 
3212
        for entry in tree.list_files():
 
3213
            id = entry[3]
3267
3214
            if id is not None:
 
3215
                filename = entry[0]
3268
3216
                if ignored.match(filename):
3269
3217
                    matches.append(filename)
3270
3218
        if len(matches) > 0:
3271
3219
            self.outf.write(gettext("Warning: the following files are version "
3272
 
                                    "controlled and match your ignore pattern:\n%s"
3273
 
                                    "\nThese files will continue to be version controlled"
3274
 
                                    " unless you 'brz remove' them.\n") % ("\n".join(matches),))
 
3220
                  "controlled and match your ignore pattern:\n%s"
 
3221
                  "\nThese files will continue to be version controlled"
 
3222
                  " unless you 'brz remove' them.\n") % ("\n".join(matches),))
3275
3223
 
3276
3224
 
3277
3225
class cmd_ignored(Command):
3292
3240
    @display_command
3293
3241
    def run(self, directory=u'.'):
3294
3242
        tree = WorkingTree.open_containing(directory)[0]
3295
 
        self.enter_context(tree.lock_read())
3296
 
        for path, file_class, kind, entry in tree.list_files():
 
3243
        self.add_cleanup(tree.lock_read().unlock)
 
3244
        for path, file_class, kind, file_id, entry in tree.list_files():
3297
3245
            if file_class != 'I':
3298
3246
                continue
3299
 
            # XXX: Slightly inefficient since this was already calculated
 
3247
            ## XXX: Slightly inefficient since this was already calculated
3300
3248
            pat = tree.is_ignored(path)
3301
3249
            self.outf.write('%-50s %s\n' % (path, pat))
3302
3250
 
3316
3264
        try:
3317
3265
            revno = int(revno)
3318
3266
        except ValueError:
3319
 
            raise errors.CommandError(gettext("not a valid revision-number: %r")
 
3267
            raise errors.BzrCommandError(gettext("not a valid revision-number: %r")
3320
3268
                                         % revno)
3321
 
        revid = WorkingTree.open_containing(
3322
 
            directory)[0].branch.get_rev_id(revno)
3323
 
        self.outf.write("%s\n" % revid.decode('utf-8'))
 
3269
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
 
3270
        self.outf.write("%s\n" % revid)
3324
3271
 
3325
3272
 
3326
3273
class cmd_export(Command):
3352
3299
      =================       =========================
3353
3300
    """
3354
3301
    encoding = 'exact'
3355
 
    encoding_type = 'exact'
3356
3302
    takes_args = ['dest', 'branch_or_subdir?']
3357
3303
    takes_options = ['directory',
3358
 
                     Option('format',
3359
 
                            help="Type of file to export to.",
3360
 
                            type=str),
3361
 
                     'revision',
3362
 
                     Option('filters', help='Apply content filters to export the '
3363
 
                            'convenient form.'),
3364
 
                     Option('root',
3365
 
                            type=str,
3366
 
                            help="Name of the root directory inside the exported file."),
3367
 
                     Option('per-file-timestamps',
3368
 
                            help='Set modification time of files to that of the last '
3369
 
                            'revision in which it was changed.'),
3370
 
                     Option('uncommitted',
3371
 
                            help='Export the working tree contents rather than that of the '
3372
 
                            'last revision.'),
3373
 
                     ]
3374
 
 
 
3304
        Option('format',
 
3305
               help="Type of file to export to.",
 
3306
               type=text_type),
 
3307
        'revision',
 
3308
        Option('filters', help='Apply content filters to export the '
 
3309
                'convenient form.'),
 
3310
        Option('root',
 
3311
               type=str,
 
3312
               help="Name of the root directory inside the exported file."),
 
3313
        Option('per-file-timestamps',
 
3314
               help='Set modification time of files to that of the last '
 
3315
                    'revision in which it was changed.'),
 
3316
        Option('uncommitted',
 
3317
               help='Export the working tree contents rather than that of the '
 
3318
                    'last revision.'),
 
3319
        ]
3375
3320
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
3376
 
            root=None, filters=False, per_file_timestamps=False, uncommitted=False,
3377
 
            directory=u'.'):
3378
 
        from .export import export, guess_format, get_root_name
 
3321
        root=None, filters=False, per_file_timestamps=False, uncommitted=False,
 
3322
        directory=u'.'):
 
3323
        from .export import export
3379
3324
 
3380
3325
        if branch_or_subdir is None:
3381
3326
            branch_or_subdir = directory
3383
3328
        (tree, b, subdir) = controldir.ControlDir.open_containing_tree_or_branch(
3384
3329
            branch_or_subdir)
3385
3330
        if tree is not None:
3386
 
            self.enter_context(tree.lock_read())
 
3331
            self.add_cleanup(tree.lock_read().unlock)
3387
3332
 
3388
3333
        if uncommitted:
3389
3334
            if tree is None:
3390
 
                raise errors.CommandError(
 
3335
                raise errors.BzrCommandError(
3391
3336
                    gettext("--uncommitted requires a working tree"))
3392
3337
            export_tree = tree
3393
3338
        else:
3394
 
            export_tree = _get_one_revision_tree(
3395
 
                'export', revision, branch=b,
3396
 
                tree=tree)
3397
 
 
3398
 
        if format is None:
3399
 
            format = guess_format(dest)
3400
 
 
3401
 
        if root is None:
3402
 
            root = get_root_name(dest)
3403
 
 
3404
 
        if not per_file_timestamps:
3405
 
            force_mtime = time.time()
3406
 
        else:
3407
 
            force_mtime = None
3408
 
 
3409
 
        if filters:
3410
 
            from breezy.filter_tree import ContentFilterTree
3411
 
            export_tree = ContentFilterTree(
3412
 
                export_tree, export_tree._content_filter_stack)
3413
 
 
 
3339
            export_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
3414
3340
        try:
3415
 
            export(export_tree, dest, format, root, subdir,
 
3341
            export(export_tree, dest, format, root, subdir, filtered=filters,
3416
3342
                   per_file_timestamps=per_file_timestamps)
3417
3343
        except errors.NoSuchExportFormat as e:
3418
 
            raise errors.CommandError(
 
3344
            raise errors.BzrCommandError(
3419
3345
                gettext('Unsupported export format: %s') % e.format)
3420
3346
 
3421
3347
 
3430
3356
 
3431
3357
    _see_also = ['ls']
3432
3358
    takes_options = ['directory',
3433
 
                     Option('name-from-revision',
3434
 
                            help='The path name in the old tree.'),
3435
 
                     Option('filters', help='Apply content filters to display the '
3436
 
                            'convenience form.'),
3437
 
                     'revision',
3438
 
                     ]
 
3359
        Option('name-from-revision', help='The path name in the old tree.'),
 
3360
        Option('filters', help='Apply content filters to display the '
 
3361
                'convenience form.'),
 
3362
        'revision',
 
3363
        ]
3439
3364
    takes_args = ['filename']
3440
3365
    encoding_type = 'exact'
3441
3366
 
3443
3368
    def run(self, filename, revision=None, name_from_revision=False,
3444
3369
            filters=False, directory=None):
3445
3370
        if revision is not None and len(revision) != 1:
3446
 
            raise errors.CommandError(gettext("brz cat --revision takes exactly"
3447
 
                                                 " one revision specifier"))
 
3371
            raise errors.BzrCommandError(gettext("brz cat --revision takes exactly"
 
3372
                                         " one revision specifier"))
3448
3373
        tree, branch, relpath = \
3449
3374
            _open_directory_or_containing_tree_or_branch(filename, directory)
3450
 
        self.enter_context(branch.lock_read())
 
3375
        self.add_cleanup(branch.lock_read().unlock)
3451
3376
        return self._run(tree, branch, relpath, filename, revision,
3452
3377
                         name_from_revision, filters)
3453
3378
 
3454
3379
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
3455
 
             filtered):
3456
 
        import shutil
 
3380
        filtered):
3457
3381
        if tree is None:
3458
3382
            tree = b.basis_tree()
3459
3383
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
3460
 
        self.enter_context(rev_tree.lock_read())
3461
 
 
 
3384
        self.add_cleanup(rev_tree.lock_read().unlock)
 
3385
 
 
3386
        old_file_id = rev_tree.path2id(relpath)
 
3387
 
 
3388
        # TODO: Split out this code to something that generically finds the
 
3389
        # best id for a path across one or more trees; it's like
 
3390
        # find_ids_across_trees but restricted to find just one. -- mbp
 
3391
        # 20110705.
3462
3392
        if name_from_revision:
3463
3393
            # Try in revision if requested
3464
 
            if not rev_tree.is_versioned(relpath):
3465
 
                raise errors.CommandError(gettext(
 
3394
            if old_file_id is None:
 
3395
                raise errors.BzrCommandError(gettext(
3466
3396
                    "{0!r} is not present in revision {1}").format(
3467
3397
                        filename, rev_tree.get_revision_id()))
3468
 
            rev_tree_path = relpath
 
3398
            else:
 
3399
                actual_file_id = old_file_id
3469
3400
        else:
3470
 
            try:
3471
 
                rev_tree_path = _mod_tree.find_previous_path(
3472
 
                    tree, rev_tree, relpath)
3473
 
            except errors.NoSuchFile:
3474
 
                rev_tree_path = None
3475
 
 
3476
 
            if rev_tree_path is None:
3477
 
                # Path didn't exist in working tree
3478
 
                if not rev_tree.is_versioned(relpath):
3479
 
                    raise errors.CommandError(gettext(
3480
 
                        "{0!r} is not present in revision {1}").format(
3481
 
                            filename, rev_tree.get_revision_id()))
3482
 
                else:
3483
 
                    # Fall back to the same path in the basis tree, if present.
3484
 
                    rev_tree_path = relpath
3485
 
 
 
3401
            cur_file_id = tree.path2id(relpath)
 
3402
            if cur_file_id is not None and rev_tree.has_id(cur_file_id):
 
3403
                actual_file_id = cur_file_id
 
3404
            elif old_file_id is not None:
 
3405
                actual_file_id = old_file_id
 
3406
            else:
 
3407
                raise errors.BzrCommandError(gettext(
 
3408
                    "{0!r} is not present in revision {1}").format(
 
3409
                        filename, rev_tree.get_revision_id()))
3486
3410
        if filtered:
3487
3411
            from .filter_tree import ContentFilterTree
3488
 
            filter_tree = ContentFilterTree(
3489
 
                rev_tree, rev_tree._content_filter_stack)
3490
 
            fileobj = filter_tree.get_file(rev_tree_path)
 
3412
            filter_tree = ContentFilterTree(rev_tree,
 
3413
                rev_tree._content_filter_stack)
 
3414
            content = filter_tree.get_file_text(actual_file_id)
3491
3415
        else:
3492
 
            fileobj = rev_tree.get_file(rev_tree_path)
3493
 
        shutil.copyfileobj(fileobj, self.outf)
 
3416
            content = rev_tree.get_file_text(actual_file_id)
3494
3417
        self.cleanup_now()
 
3418
        self.outf.write(content)
3495
3419
 
3496
3420
 
3497
3421
class cmd_local_time_offset(Command):
3498
3422
    __doc__ = """Show the offset in seconds from GMT to local time."""
3499
3423
    hidden = True
3500
 
 
3501
3424
    @display_command
3502
3425
    def run(self):
3503
3426
        self.outf.write("%s\n" % osutils.local_time_offset())
3504
3427
 
3505
3428
 
 
3429
 
3506
3430
class cmd_commit(Command):
3507
3431
    __doc__ = """Commit changes into a new revision.
3508
3432
 
3522
3446
      If selected files are specified, only changes to those files are
3523
3447
      committed.  If a directory is specified then the directory and
3524
3448
      everything within it is committed.
3525
 
 
 
3449
  
3526
3450
      When excludes are given, they take precedence over selected files.
3527
3451
      For example, to commit only changes within foo, but not changes
3528
3452
      within foo/bar::
3529
 
 
 
3453
  
3530
3454
        brz commit foo -x foo/bar
3531
 
 
 
3455
  
3532
3456
      A selective commit after a merge is not yet supported.
3533
3457
 
3534
3458
    :Custom authors:
3539
3463
      "John Doe <jdoe@example.com>". If there is more than one author of
3540
3464
      the change you can specify the option multiple times, once for each
3541
3465
      author.
3542
 
 
 
3466
  
3543
3467
    :Checks:
3544
3468
 
3545
3469
      A common mistake is to forget to add a new file or directory before
3550
3474
 
3551
3475
    :Things to note:
3552
3476
 
3553
 
      If you accidentally commit the wrong changes or make a spelling
 
3477
      If you accidentially commit the wrong changes or make a spelling
3554
3478
      mistake in the commit message say, you can use the uncommit command
3555
3479
      to undo it. See ``brz help uncommit`` for details.
3556
3480
 
3563
3487
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
3564
3488
    takes_args = ['selected*']
3565
3489
    takes_options = [
3566
 
        ListOption(
3567
 
            'exclude', type=str, short_name='x',
3568
 
            help="Do not consider changes made to a given path."),
3569
 
        Option('message', type=str,
3570
 
               short_name='m',
3571
 
               help="Description of the new revision."),
3572
 
        'verbose',
3573
 
        Option('unchanged',
3574
 
               help='Commit even if nothing has changed.'),
3575
 
        Option('file', type=str,
3576
 
               short_name='F',
3577
 
               argname='msgfile',
3578
 
               help='Take commit message from this file.'),
3579
 
        Option('strict',
3580
 
               help="Refuse to commit if there are unknown "
3581
 
               "files in the working tree."),
3582
 
        Option('commit-time', type=str,
3583
 
               help="Manually set a commit time using commit date "
3584
 
               "format, e.g. '2009-10-10 08:00:00 +0100'."),
3585
 
        ListOption(
3586
 
            'bugs', type=str,
3587
 
            help="Link to a related bug. (see \"brz help bugs\")."),
3588
 
        ListOption(
3589
 
            'fixes', type=str,
3590
 
            help="Mark a bug as being fixed by this revision "
3591
 
                 "(see \"brz help bugs\")."),
3592
 
        ListOption(
3593
 
            'author', type=str,
3594
 
            help="Set the author's name, if it's different "
3595
 
                 "from the committer."),
3596
 
        Option('local',
3597
 
               help="Perform a local commit in a bound "
3598
 
                    "branch.  Local commits are not pushed to "
3599
 
                    "the master branch until a normal commit "
3600
 
                    "is performed."
3601
 
               ),
3602
 
        Option('show-diff', short_name='p',
3603
 
               help='When no message is supplied, show the diff along'
3604
 
               ' with the status summary in the message editor.'),
3605
 
        Option('lossy',
3606
 
               help='When committing to a foreign version control '
3607
 
               'system do not push data that can not be natively '
3608
 
               'represented.'), ]
 
3490
            ListOption('exclude', type=str, short_name='x',
 
3491
                help="Do not consider changes made to a given path."),
 
3492
            Option('message', type=text_type,
 
3493
                   short_name='m',
 
3494
                   help="Description of the new revision."),
 
3495
            'verbose',
 
3496
             Option('unchanged',
 
3497
                    help='Commit even if nothing has changed.'),
 
3498
             Option('file', type=str,
 
3499
                    short_name='F',
 
3500
                    argname='msgfile',
 
3501
                    help='Take commit message from this file.'),
 
3502
             Option('strict',
 
3503
                    help="Refuse to commit if there are unknown "
 
3504
                    "files in the working tree."),
 
3505
             Option('commit-time', type=str,
 
3506
                    help="Manually set a commit time using commit date "
 
3507
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
 
3508
             ListOption('fixes', type=str,
 
3509
                    help="Mark a bug as being fixed by this revision "
 
3510
                         "(see \"brz help bugs\")."),
 
3511
             ListOption('author', type=text_type,
 
3512
                    help="Set the author's name, if it's different "
 
3513
                         "from the committer."),
 
3514
             Option('local',
 
3515
                    help="Perform a local commit in a bound "
 
3516
                         "branch.  Local commits are not pushed to "
 
3517
                         "the master branch until a normal commit "
 
3518
                         "is performed."
 
3519
                    ),
 
3520
             Option('show-diff', short_name='p',
 
3521
                    help='When no message is supplied, show the diff along'
 
3522
                    ' with the status summary in the message editor.'),
 
3523
             Option('lossy', 
 
3524
                    help='When committing to a foreign version control '
 
3525
                    'system do not push data that can not be natively '
 
3526
                    'represented.'),
 
3527
             ]
3609
3528
    aliases = ['ci', 'checkin']
3610
3529
 
3611
 
    def _iter_bug_urls(self, bugs, branch, status):
3612
 
        default_bugtracker = None
 
3530
    def _iter_bug_fix_urls(self, fixes, branch):
 
3531
        default_bugtracker  = None
3613
3532
        # Configure the properties for bug fixing attributes.
3614
 
        for bug in bugs:
3615
 
            tokens = bug.split(':')
 
3533
        for fixed_bug in fixes:
 
3534
            tokens = fixed_bug.split(':')
3616
3535
            if len(tokens) == 1:
3617
3536
                if default_bugtracker is None:
3618
3537
                    branch_config = branch.get_config_stack()
3619
3538
                    default_bugtracker = branch_config.get(
3620
3539
                        "bugtracker")
3621
3540
                if default_bugtracker is None:
3622
 
                    raise errors.CommandError(gettext(
 
3541
                    raise errors.BzrCommandError(gettext(
3623
3542
                        "No tracker specified for bug %s. Use the form "
3624
3543
                        "'tracker:id' or specify a default bug tracker "
3625
3544
                        "using the `bugtracker` option.\nSee "
3626
3545
                        "\"brz help bugs\" for more information on this "
3627
 
                        "feature. Commit refused.") % bug)
 
3546
                        "feature. Commit refused.") % fixed_bug)
3628
3547
                tag = default_bugtracker
3629
3548
                bug_id = tokens[0]
3630
3549
            elif len(tokens) != 2:
3631
 
                raise errors.CommandError(gettext(
 
3550
                raise errors.BzrCommandError(gettext(
3632
3551
                    "Invalid bug %s. Must be in the form of 'tracker:id'. "
3633
3552
                    "See \"brz help bugs\" for more information on this "
3634
 
                    "feature.\nCommit refused.") % bug)
 
3553
                    "feature.\nCommit refused.") % fixed_bug)
3635
3554
            else:
3636
3555
                tag, bug_id = tokens
3637
3556
            try:
3638
 
                yield bugtracker.get_bug_url(tag, branch, bug_id), status
3639
 
            except bugtracker.UnknownBugTrackerAbbreviation:
3640
 
                raise errors.CommandError(gettext(
3641
 
                    'Unrecognized bug %s. Commit refused.') % bug)
3642
 
            except bugtracker.MalformedBugIdentifier as e:
3643
 
                raise errors.CommandError(gettext(
3644
 
                    u"%s\nCommit refused.") % (e,))
 
3557
                yield bugtracker.get_bug_url(tag, branch, bug_id)
 
3558
            except errors.UnknownBugTrackerAbbreviation:
 
3559
                raise errors.BzrCommandError(gettext(
 
3560
                    'Unrecognized bug %s. Commit refused.') % fixed_bug)
 
3561
            except errors.MalformedBugIdentifier as e:
 
3562
                raise errors.BzrCommandError(gettext(
 
3563
                    "%s\nCommit refused.") % (str(e),))
3645
3564
 
3646
3565
    def run(self, message=None, file=None, verbose=False, selected_list=None,
3647
 
            unchanged=False, strict=False, local=False, fixes=None, bugs=None,
 
3566
            unchanged=False, strict=False, local=False, fixes=None,
3648
3567
            author=None, show_diff=False, exclude=None, commit_time=None,
3649
3568
            lossy=False):
3650
 
        import itertools
3651
 
        from .commit import (
 
3569
        from .errors import (
3652
3570
            PointlessCommit,
3653
 
            )
3654
 
        from .errors import (
3655
3571
            ConflictsInTree,
3656
3572
            StrictCommitFailed
3657
3573
        )
3667
3583
            try:
3668
3584
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
3669
3585
            except ValueError as e:
3670
 
                raise errors.CommandError(gettext(
 
3586
                raise errors.BzrCommandError(gettext(
3671
3587
                    "Could not parse --commit-time: " + str(e)))
3672
3588
 
3673
3589
        properties = {}
3681
3597
 
3682
3598
        if fixes is None:
3683
3599
            fixes = []
3684
 
        if bugs is None:
3685
 
            bugs = []
3686
3600
        bug_property = bugtracker.encode_fixes_bug_urls(
3687
 
            itertools.chain(
3688
 
                self._iter_bug_urls(bugs, tree.branch, bugtracker.RELATED),
3689
 
                self._iter_bug_urls(fixes, tree.branch, bugtracker.FIXED)))
 
3601
            self._iter_bug_fix_urls(fixes, tree.branch))
3690
3602
        if bug_property:
3691
 
            properties[u'bugs'] = bug_property
 
3603
            properties['bugs'] = bug_property
3692
3604
 
3693
3605
        if local and not tree.branch.get_bound_location():
3694
3606
            raise errors.LocalRequiresBoundBranch()
3705
3617
                warning_msg = (
3706
3618
                    'The commit message is a file name: "%(f)s".\n'
3707
3619
                    '(use --file "%(f)s" to take commit message from that file)'
3708
 
                    % {'f': message})
 
3620
                    % { 'f': message })
3709
3621
                ui.ui_factory.show_warning(warning_msg)
3710
3622
            if '\r' in message:
3711
3623
                message = message.replace('\r\n', '\n')
3712
3624
                message = message.replace('\r', '\n')
3713
3625
            if file:
3714
 
                raise errors.CommandError(gettext(
 
3626
                raise errors.BzrCommandError(gettext(
3715
3627
                    "please specify either --message or --file"))
3716
3628
 
3717
3629
        def get_message(commit_obj):
3718
3630
            """Callback to get commit message"""
3719
3631
            if file:
3720
 
                with open(file, 'rb') as f:
 
3632
                f = open(file)
 
3633
                try:
3721
3634
                    my_message = f.read().decode(osutils.get_user_encoding())
 
3635
                finally:
 
3636
                    f.close()
3722
3637
            elif message is not None:
3723
3638
                my_message = message
3724
3639
            else:
3725
3640
                # No message supplied: make one up.
3726
3641
                # text is the status of the tree
3727
3642
                text = make_commit_message_template_encoded(tree,
3728
 
                                                            selected_list, diff=show_diff,
3729
 
                                                            output_encoding=osutils.get_user_encoding())
 
3643
                        selected_list, diff=show_diff,
 
3644
                        output_encoding=osutils.get_user_encoding())
3730
3645
                # start_message is the template generated from hooks
3731
3646
                # XXX: Warning - looks like hooks return unicode,
3732
3647
                # make_commit_message_template_encoded returns user encoding.
3734
3649
                # avoid this.
3735
3650
                my_message = set_commit_message(commit_obj)
3736
3651
                if my_message is None:
3737
 
                    start_message = generate_commit_message_template(
3738
 
                        commit_obj)
3739
 
                    if start_message is not None:
3740
 
                        start_message = start_message.encode(
3741
 
                            osutils.get_user_encoding())
 
3652
                    start_message = generate_commit_message_template(commit_obj)
3742
3653
                    my_message = edit_commit_message_encoded(text,
3743
 
                                                             start_message=start_message)
 
3654
                        start_message=start_message)
3744
3655
                if my_message is None:
3745
 
                    raise errors.CommandError(gettext("please specify a commit"
3746
 
                                                         " message with either --message or --file"))
 
3656
                    raise errors.BzrCommandError(gettext("please specify a commit"
 
3657
                        " message with either --message or --file"))
3747
3658
                if my_message == "":
3748
 
                    raise errors.CommandError(gettext("Empty commit message specified."
3749
 
                                                         " Please specify a commit message with either"
3750
 
                                                         " --message or --file or leave a blank message"
3751
 
                                                         " with --message \"\"."))
 
3659
                    raise errors.BzrCommandError(gettext("Empty commit message specified."
 
3660
                            " Please specify a commit message with either"
 
3661
                            " --message or --file or leave a blank message"
 
3662
                            " with --message \"\"."))
3752
3663
            return my_message
3753
3664
 
3754
3665
        # The API permits a commit with a filter of [] to mean 'select nothing'
3765
3676
                        exclude=tree.safe_relpath_files(exclude),
3766
3677
                        lossy=lossy)
3767
3678
        except PointlessCommit:
3768
 
            raise errors.CommandError(gettext("No changes to commit."
3769
 
                                                 " Please 'brz add' the files you want to commit, or use"
3770
 
                                                 " --unchanged to force an empty commit."))
 
3679
            raise errors.BzrCommandError(gettext("No changes to commit."
 
3680
                " Please 'brz add' the files you want to commit, or use"
 
3681
                " --unchanged to force an empty commit."))
3771
3682
        except ConflictsInTree:
3772
 
            raise errors.CommandError(gettext('Conflicts detected in working '
3773
 
                                                 'tree.  Use "brz conflicts" to list, "brz resolve FILE" to'
3774
 
                                                 ' resolve.'))
 
3683
            raise errors.BzrCommandError(gettext('Conflicts detected in working '
 
3684
                'tree.  Use "brz conflicts" to list, "brz resolve FILE" to'
 
3685
                ' resolve.'))
3775
3686
        except StrictCommitFailed:
3776
 
            raise errors.CommandError(gettext("Commit refused because there are"
3777
 
                                                 " unknown files in the working tree."))
 
3687
            raise errors.BzrCommandError(gettext("Commit refused because there are"
 
3688
                              " unknown files in the working tree."))
3778
3689
        except errors.BoundBranchOutOfDate as e:
3779
3690
            e.extra_help = (gettext("\n"
3780
 
                                    'To commit to master branch, run update and then commit.\n'
3781
 
                                    'You can also pass --local to commit to continue working '
3782
 
                                    'disconnected.'))
 
3691
                'To commit to master branch, run update and then commit.\n'
 
3692
                'You can also pass --local to commit to continue working '
 
3693
                'disconnected.'))
3783
3694
            raise
3784
3695
 
3785
3696
 
3803
3714
    unreferenced ancestors
3804
3715
        Texts that are ancestors of other texts, but
3805
3716
        are not properly referenced by the revision ancestry.  This is a
3806
 
        subtle problem that Breezy can work around.
 
3717
        subtle problem that Bazaar can work around.
3807
3718
 
3808
3719
    unique file texts
3809
3720
        This is the total number of unique file contents
3815
3726
        entries are modified, but the file contents are not.  It does not
3816
3727
        indicate a problem.
3817
3728
 
3818
 
    If no restrictions are specified, all data that is found at the given
 
3729
    If no restrictions are specified, all Bazaar data that is found at the given
3819
3730
    location will be checked.
3820
3731
 
3821
3732
    :Examples:
3857
3768
    __doc__ = """Upgrade a repository, branch or working tree to a newer format.
3858
3769
 
3859
3770
    When the default format has changed after a major new release of
3860
 
    Bazaar/Breezy, you may be informed during certain operations that you
 
3771
    Bazaar, you may be informed during certain operations that you
3861
3772
    should upgrade. Upgrading to a newer format may improve performance
3862
3773
    or make new features available. It may however limit interoperability
3863
 
    with older repositories or with older versions of Bazaar or Breezy.
 
3774
    with older repositories or with older versions of Bazaar.
3864
3775
 
3865
3776
    If you wish to upgrade to a particular format rather than the
3866
3777
    current default, that can be specified using the --format option.
3882
3793
    If the conversion of a branch fails, remaining branches are still
3883
3794
    tried.
3884
3795
 
3885
 
    For more information on upgrades, see the Breezy Upgrade Guide,
3886
 
    https://www.breezy-vcs.org/doc/en/upgrade-guide/.
 
3796
    For more information on upgrades, see the Bazaar Upgrade Guide,
 
3797
    http://doc.bazaar.canonical.com/latest/en/upgrade-guide/.
3887
3798
    """
3888
3799
 
3889
3800
    _see_also = ['check', 'reconcile', 'formats']
3890
3801
    takes_args = ['url?']
3891
3802
    takes_options = [
3892
3803
        RegistryOption('format',
3893
 
                       help='Upgrade to a specific format.  See "brz help'
3894
 
                       ' formats" for details.',
3895
 
                       lazy_registry=('breezy.controldir', 'format_registry'),
3896
 
                       converter=lambda name: controldir.format_registry.make_controldir(
3897
 
                           name),
3898
 
                       value_switches=True, title='Branch format'),
 
3804
            help='Upgrade to a specific format.  See "brz help'
 
3805
                 ' formats" for details.',
 
3806
            lazy_registry=('breezy.controldir', 'format_registry'),
 
3807
            converter=lambda name: controldir.format_registry.make_bzrdir(name),
 
3808
            value_switches=True, title='Branch format'),
3899
3809
        Option('clean',
3900
 
               help='Remove the backup.bzr directory if successful.'),
 
3810
            help='Remove the backup.bzr directory if successful.'),
3901
3811
        Option('dry-run',
3902
 
               help="Show what would be done, but don't actually do anything."),
 
3812
            help="Show what would be done, but don't actually do anything."),
3903
3813
    ]
3904
3814
 
3905
3815
    def run(self, url='.', format=None, clean=False, dry_run=False):
3925
3835
 
3926
3836
            brz whoami "Frank Chu <fchu@example.com>"
3927
3837
    """
3928
 
    takes_options = ['directory',
3929
 
                     Option('email',
3930
 
                            help='Display email address only.'),
3931
 
                     Option('branch',
3932
 
                            help='Set identity for the current branch instead of '
3933
 
                            'globally.'),
3934
 
                     ]
 
3838
    takes_options = [ 'directory',
 
3839
                      Option('email',
 
3840
                             help='Display email address only.'),
 
3841
                      Option('branch',
 
3842
                             help='Set identity for the current branch instead of '
 
3843
                                  'globally.'),
 
3844
                    ]
3935
3845
    takes_args = ['name?']
3936
3846
    encoding_type = 'replace'
3937
3847
 
3955
3865
            return
3956
3866
 
3957
3867
        if email:
3958
 
            raise errors.CommandError(gettext("--email can only be used to display existing "
3959
 
                                                 "identity"))
 
3868
            raise errors.BzrCommandError(gettext("--email can only be used to display existing "
 
3869
                                         "identity"))
3960
3870
 
3961
3871
        # display a warning if an email address isn't included in the given name.
3962
3872
        try:
3963
3873
            _mod_config.extract_email_address(name)
3964
 
        except _mod_config.NoEmailInUsername:
 
3874
        except errors.NoEmailInUsername as e:
3965
3875
            warning('"%s" does not seem to contain an email address.  '
3966
3876
                    'This is allowed, but not recommended.', name)
3967
3877
 
3971
3881
                c = Branch.open_containing(u'.')[0].get_config_stack()
3972
3882
            else:
3973
3883
                b = Branch.open(directory)
3974
 
                self.enter_context(b.lock_write())
 
3884
                self.add_cleanup(b.lock_write().unlock)
3975
3885
                c = b.get_config_stack()
3976
3886
        else:
3977
3887
            c = _mod_config.GlobalStack()
3992
3902
    _see_also = ['info']
3993
3903
    takes_args = ['nickname?']
3994
3904
    takes_options = ['directory']
3995
 
 
3996
3905
    def run(self, nickname=None, directory=u'.'):
3997
3906
        branch = Branch.open_containing(directory)[0]
3998
3907
        if nickname is None:
4041
3950
            if equal_pos == -1:
4042
3951
                self.print_alias(name)
4043
3952
            else:
4044
 
                self.set_alias(name[:equal_pos], name[equal_pos + 1:])
 
3953
                self.set_alias(name[:equal_pos], name[equal_pos+1:])
4045
3954
 
4046
3955
    def remove_alias(self, alias_name):
4047
3956
        if alias_name is None:
4048
 
            raise errors.CommandError(gettext(
 
3957
            raise errors.BzrCommandError(gettext(
4049
3958
                'brz alias --remove expects an alias to remove.'))
4050
3959
        # If alias is not found, print something like:
4051
3960
        # unalias: foo: not found
4056
3965
    def print_aliases(self):
4057
3966
        """Print out the defined aliases in a similar format to bash."""
4058
3967
        aliases = _mod_config.GlobalConfig().get_aliases()
4059
 
        for key, value in sorted(aliases.items()):
 
3968
        for key, value in sorted(viewitems(aliases)):
4060
3969
            self.outf.write('brz alias %s="%s"\n' % (key, value))
4061
3970
 
4062
3971
    @display_command
4126
4035
    """
4127
4036
    # NB: this is used from the class without creating an instance, which is
4128
4037
    # why it does not have a self parameter.
4129
 
 
4130
4038
    def get_transport_type(typestring):
4131
4039
        """Parse and return a transport specifier."""
4132
4040
        if typestring == "sftp":
4140
4048
            return test_server.FakeNFSServer
4141
4049
        msg = "No known transport type %s. Supported types are: sftp\n" %\
4142
4050
            (typestring)
4143
 
        raise errors.CommandError(msg)
 
4051
        raise errors.BzrCommandError(msg)
4144
4052
 
4145
4053
    hidden = True
4146
4054
    takes_args = ['testspecs*']
4147
4055
    takes_options = ['verbose',
4148
4056
                     Option('one',
4149
 
                            help='Stop when one test fails.',
4150
 
                            short_name='1',
4151
 
                            ),
 
4057
                             help='Stop when one test fails.',
 
4058
                             short_name='1',
 
4059
                             ),
4152
4060
                     Option('transport',
4153
4061
                            help='Use a different transport by default '
4154
4062
                                 'throughout the test suite.',
4168
4076
                     Option('list-only',
4169
4077
                            help='List the tests instead of running them.'),
4170
4078
                     RegistryOption('parallel',
4171
 
                                    help="Run the test suite in parallel.",
4172
 
                                    lazy_registry=(
4173
 
                                        'breezy.tests', 'parallel_registry'),
4174
 
                                    value_switches=False,
4175
 
                                    ),
 
4079
                        help="Run the test suite in parallel.",
 
4080
                        lazy_registry=('breezy.tests', 'parallel_registry'),
 
4081
                        value_switches=False,
 
4082
                        ),
4176
4083
                     Option('randomize', type=str, argname="SEED",
4177
4084
                            help='Randomize the order of tests using the given'
4178
4085
                                 ' seed or "now" for the current time.'),
4180
4087
                                short_name='x',
4181
4088
                                help='Exclude tests that match this regular'
4182
4089
                                ' expression.'),
4183
 
                     Option('subunit1',
4184
 
                            help='Output test progress via subunit v1.'),
4185
 
                     Option('subunit2',
4186
 
                            help='Output test progress via subunit v2.'),
 
4090
                     Option('subunit',
 
4091
                        help='Output test progress via subunit.'),
4187
4092
                     Option('strict', help='Fail on missing dependencies or '
4188
4093
                            'known failures.'),
4189
4094
                     Option('load-list', type=str, argname='TESTLISTFILE',
4192
4097
                                help='Turn on a selftest debug flag.'),
4193
4098
                     ListOption('starting-with', type=str, argname='TESTID',
4194
4099
                                param_name='starting_with', short_name='s',
4195
 
                                help='Load only the tests starting with TESTID.'),
 
4100
                                help=
 
4101
                                'Load only the tests starting with TESTID.'),
4196
4102
                     Option('sync',
4197
4103
                            help="By default we disable fsync and fdatasync"
4198
4104
                                 " while running the test suite.")
4208
4114
            lsprof_timed=None,
4209
4115
            first=False, list_only=False,
4210
4116
            randomize=None, exclude=None, strict=False,
4211
 
            load_list=None, debugflag=None, starting_with=None, subunit1=False,
4212
 
            subunit2=False, parallel=None, lsprof_tests=False, sync=False):
 
4117
            load_list=None, debugflag=None, starting_with=None, subunit=False,
 
4118
            parallel=None, lsprof_tests=False,
 
4119
            sync=False):
4213
4120
 
4214
4121
        # During selftest, disallow proxying, as it can cause severe
4215
4122
        # performance penalties and is only needed for thread
4217
4124
        # too heavily. The call should be as early as possible, as
4218
4125
        # error reporting for past duplicate imports won't have useful
4219
4126
        # backtraces.
4220
 
        if sys.version_info[0] < 3:
4221
 
            # TODO(pad.lv/1696545): Allow proxying on Python 3, since
4222
 
            # disallowing it currently leads to failures in many places.
4223
 
            lazy_import.disallow_proxying()
 
4127
        lazy_import.disallow_proxying()
4224
4128
 
4225
 
        try:
4226
 
            from . import tests
4227
 
        except ImportError as e:
4228
 
            raise errors.CommandError("tests not available. Install the "
4229
 
                                         "breezy tests to run the breezy testsuite.")
 
4129
        from . import tests
4230
4130
 
4231
4131
        if testspecs_list is not None:
4232
4132
            pattern = '|'.join(testspecs_list)
4233
4133
        else:
4234
4134
            pattern = ".*"
4235
 
        if subunit1:
 
4135
        if subunit:
4236
4136
            try:
4237
 
                from .tests import SubUnitBzrRunnerv1
 
4137
                from .tests import SubUnitBzrRunner
4238
4138
            except ImportError:
4239
 
                raise errors.CommandError(gettext(
4240
 
                    "subunit not available. subunit needs to be installed "
4241
 
                    "to use --subunit."))
4242
 
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunnerv1
 
4139
                raise errors.BzrCommandError(gettext("subunit not available. subunit "
 
4140
                    "needs to be installed to use --subunit."))
 
4141
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
4243
4142
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
4244
 
            # stdout, which would corrupt the subunit stream.
 
4143
            # stdout, which would corrupt the subunit stream. 
4245
4144
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
4246
4145
            # following code can be deleted when it's sufficiently deployed
4247
4146
            # -- vila/mgz 20100514
4248
4147
            if (sys.platform == "win32"
4249
 
                    and getattr(sys.stdout, 'fileno', None) is not None):
 
4148
                and getattr(sys.stdout, 'fileno', None) is not None):
4250
4149
                import msvcrt
4251
4150
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
4252
 
        if subunit2:
4253
 
            try:
4254
 
                from .tests import SubUnitBzrRunnerv2
4255
 
            except ImportError:
4256
 
                raise errors.CommandError(gettext(
4257
 
                    "subunit not available. subunit "
4258
 
                    "needs to be installed to use --subunit2."))
4259
 
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunnerv2
4260
 
 
4261
4151
        if parallel:
4262
4152
            self.additional_selftest_args.setdefault(
4263
4153
                'suite_decorators', []).append(parallel)
4264
4154
        if benchmark:
4265
 
            raise errors.CommandError(gettext(
 
4155
            raise errors.BzrCommandError(gettext(
4266
4156
                "--benchmark is no longer supported from brz 2.2; "
4267
4157
                "use bzr-usertest instead"))
4268
4158
        test_suite_factory = None
4273
4163
        if not sync:
4274
4164
            self._disable_fsync()
4275
4165
        selftest_kwargs = {"verbose": verbose,
4276
 
                           "pattern": pattern,
4277
 
                           "stop_on_failure": one,
4278
 
                           "transport": transport,
4279
 
                           "test_suite_factory": test_suite_factory,
4280
 
                           "lsprof_timed": lsprof_timed,
4281
 
                           "lsprof_tests": lsprof_tests,
4282
 
                           "matching_tests_first": first,
4283
 
                           "list_only": list_only,
4284
 
                           "random_seed": randomize,
4285
 
                           "exclude_pattern": exclude_pattern,
4286
 
                           "strict": strict,
4287
 
                           "load_list": load_list,
4288
 
                           "debug_flags": debugflag,
4289
 
                           "starting_with": starting_with
4290
 
                           }
 
4166
                          "pattern": pattern,
 
4167
                          "stop_on_failure": one,
 
4168
                          "transport": transport,
 
4169
                          "test_suite_factory": test_suite_factory,
 
4170
                          "lsprof_timed": lsprof_timed,
 
4171
                          "lsprof_tests": lsprof_tests,
 
4172
                          "matching_tests_first": first,
 
4173
                          "list_only": list_only,
 
4174
                          "random_seed": randomize,
 
4175
                          "exclude_pattern": exclude_pattern,
 
4176
                          "strict": strict,
 
4177
                          "load_list": load_list,
 
4178
                          "debug_flags": debugflag,
 
4179
                          "starting_with": starting_with
 
4180
                          }
4291
4181
        selftest_kwargs.update(self.additional_selftest_args)
4292
4182
 
4293
4183
        # Make deprecation warnings visible, unless -Werror is set
4349
4239
 
4350
4240
        branch1 = Branch.open_containing(branch)[0]
4351
4241
        branch2 = Branch.open_containing(other)[0]
4352
 
        self.enter_context(branch1.lock_read())
4353
 
        self.enter_context(branch2.lock_read())
 
4242
        self.add_cleanup(branch1.lock_read().unlock)
 
4243
        self.add_cleanup(branch2.lock_read().unlock)
4354
4244
        last1 = ensure_null(branch1.last_revision())
4355
4245
        last2 = ensure_null(branch2.last_revision())
4356
4246
 
4357
4247
        graph = branch1.repository.get_graph(branch2.repository)
4358
4248
        base_rev_id = graph.find_unique_lca(last1, last2)
4359
4249
 
4360
 
        self.outf.write(gettext('merge base is revision %s\n') %
4361
 
                        base_rev_id.decode('utf-8'))
 
4250
        self.outf.write(gettext('merge base is revision %s\n') % base_rev_id)
4362
4251
 
4363
4252
 
4364
4253
class cmd_merge(Command):
4383
4272
    through OTHER, excluding BASE but including OTHER, will be merged.  If this
4384
4273
    causes some revisions to be skipped, i.e. if the destination branch does
4385
4274
    not already contain revision BASE, such a merge is commonly referred to as
4386
 
    a "cherrypick". Unlike a normal merge, Breezy does not currently track
 
4275
    a "cherrypick". Unlike a normal merge, Bazaar does not currently track
4387
4276
    cherrypicks. The changes look like a normal commit, and the history of the
4388
4277
    changes from the other branch is not stored in the commit.
4389
4278
 
4406
4295
    committed to record the result of the merge.
4407
4296
 
4408
4297
    merge refuses to run if there are any uncommitted changes, unless
4409
 
    --force is given.  If --force is given, then the changes from the source
 
4298
    --force is given.  If --force is given, then the changes from the source 
4410
4299
    will be merged with the current working tree, including any uncommitted
4411
4300
    changes in the tree.  The --force option can also be used to create a
4412
4301
    merge revision which has more than two parents.
4459
4348
        Option('uncommitted', help='Apply uncommitted changes'
4460
4349
               ' from a working copy, instead of branch changes.'),
4461
4350
        Option('pull', help='If the destination is already'
4462
 
               ' completely merged into the source, pull from the'
4463
 
               ' source rather than merging.  When this happens,'
4464
 
               ' you do not need to commit the result.'),
 
4351
                ' completely merged into the source, pull from the'
 
4352
                ' source rather than merging.  When this happens,'
 
4353
                ' you do not need to commit the result.'),
4465
4354
        custom_help('directory',
4466
 
                    help='Branch to merge into, '
 
4355
               help='Branch to merge into, '
4467
4356
                    'rather than the one containing the working directory.'),
4468
4357
        Option('preview', help='Instead of merging, show a diff of the'
4469
4358
               ' merge.'),
4470
4359
        Option('interactive', help='Select changes interactively.',
4471
 
               short_name='i')
 
4360
            short_name='i')
4472
4361
    ]
4473
4362
 
4474
4363
    def run(self, location=None, revision=None, force=False,
4481
4370
        if merge_type is None:
4482
4371
            merge_type = _mod_merge.Merge3Merger
4483
4372
 
4484
 
        if directory is None:
4485
 
            directory = u'.'
 
4373
        if directory is None: directory = u'.'
4486
4374
        possible_transports = []
4487
4375
        merger = None
4488
4376
        allow_pending = True
4489
4377
        verified = 'inapplicable'
4490
4378
 
4491
4379
        tree = WorkingTree.open_containing(directory)[0]
4492
 
        if tree.branch.last_revision() == _mod_revision.NULL_REVISION:
4493
 
            raise errors.CommandError(gettext('Merging into empty branches not currently supported, '
4494
 
                                                 'https://bugs.launchpad.net/bzr/+bug/308562'))
 
4380
        if tree.branch.revno() == 0:
 
4381
            raise errors.BzrCommandError(gettext('Merging into empty branches not currently supported, '
 
4382
                                         'https://bugs.launchpad.net/bzr/+bug/308562'))
 
4383
 
 
4384
        try:
 
4385
            basis_tree = tree.revision_tree(tree.last_revision())
 
4386
        except errors.NoSuchRevision:
 
4387
            basis_tree = tree.basis_tree()
4495
4388
 
4496
4389
        # die as quickly as possible if there are uncommitted changes
4497
4390
        if not force:
4502
4395
        change_reporter = delta._ChangeReporter(
4503
4396
            unversioned_filter=tree.is_ignored, view_info=view_info)
4504
4397
        pb = ui.ui_factory.nested_progress_bar()
4505
 
        self.enter_context(pb)
4506
 
        self.enter_context(tree.lock_write())
 
4398
        self.add_cleanup(pb.finished)
 
4399
        self.add_cleanup(tree.lock_write().unlock)
4507
4400
        if location is not None:
4508
4401
            try:
4509
 
                mergeable = _mod_mergeable.read_mergeable_from_url(
4510
 
                    location, possible_transports=possible_transports)
 
4402
                mergeable = bundle.read_mergeable_from_url(location,
 
4403
                    possible_transports=possible_transports)
4511
4404
            except errors.NotABundle:
4512
4405
                mergeable = None
4513
4406
            else:
4514
4407
                if uncommitted:
4515
 
                    raise errors.CommandError(gettext('Cannot use --uncommitted'
4516
 
                                                         ' with bundles or merge directives.'))
 
4408
                    raise errors.BzrCommandError(gettext('Cannot use --uncommitted'
 
4409
                        ' with bundles or merge directives.'))
4517
4410
 
4518
4411
                if revision is not None:
4519
 
                    raise errors.CommandError(gettext(
 
4412
                    raise errors.BzrCommandError(gettext(
4520
4413
                        'Cannot use -r with merge directives or bundles'))
4521
4414
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
4522
 
                                                                    mergeable)
 
4415
                   mergeable, None)
4523
4416
 
4524
4417
        if merger is None and uncommitted:
4525
4418
            if revision is not None and len(revision) > 0:
4526
 
                raise errors.CommandError(gettext('Cannot use --uncommitted and'
4527
 
                                                     ' --revision at the same time.'))
 
4419
                raise errors.BzrCommandError(gettext('Cannot use --uncommitted and'
 
4420
                    ' --revision at the same time.'))
4528
4421
            merger = self.get_merger_from_uncommitted(tree, location, None)
4529
4422
            allow_pending = False
4530
4423
 
4531
4424
        if merger is None:
4532
4425
            merger, allow_pending = self._get_merger_from_branch(tree,
4533
 
                                                                 location, revision, remember, possible_transports, None)
 
4426
                location, revision, remember, possible_transports, None)
4534
4427
 
4535
4428
        merger.merge_type = merge_type
4536
4429
        merger.reprocess = reprocess
4537
4430
        merger.show_base = show_base
4538
4431
        self.sanity_check_merger(merger)
4539
4432
        if (merger.base_rev_id == merger.other_rev_id and
4540
 
                merger.other_rev_id is not None):
 
4433
            merger.other_rev_id is not None):
4541
4434
            # check if location is a nonexistent file (and not a branch) to
4542
4435
            # disambiguate the 'Nothing to do'
4543
4436
            if merger.interesting_files:
4544
4437
                if not merger.other_tree.has_filename(
4545
 
                        merger.interesting_files[0]):
 
4438
                    merger.interesting_files[0]):
4546
4439
                    note(gettext("merger: ") + str(merger))
4547
4440
                    raise errors.PathsDoNotExist([location])
4548
4441
            note(gettext('Nothing to do.'))
4549
4442
            return 0
4550
4443
        if pull and not preview:
4551
4444
            if merger.interesting_files is not None:
4552
 
                raise errors.CommandError(
4553
 
                    gettext('Cannot pull individual files'))
 
4445
                raise errors.BzrCommandError(gettext('Cannot pull individual files'))
4554
4446
            if (merger.base_rev_id == tree.last_revision()):
4555
4447
                result = tree.pull(merger.other_branch, False,
4556
4448
                                   merger.other_rev_id)
4557
4449
                result.report(self.outf)
4558
4450
                return 0
4559
4451
        if merger.this_basis is None:
4560
 
            raise errors.CommandError(gettext(
 
4452
            raise errors.BzrCommandError(gettext(
4561
4453
                "This branch has no commits."
4562
4454
                " (perhaps you would prefer 'brz pull')"))
4563
4455
        if preview:
4571
4463
    def _get_preview(self, merger):
4572
4464
        tree_merger = merger.make_merger()
4573
4465
        tt = tree_merger.make_preview_transform()
4574
 
        self.enter_context(tt)
 
4466
        self.add_cleanup(tt.finalize)
4575
4467
        result_tree = tt.get_preview_tree()
4576
4468
        return result_tree
4577
4469
 
4607
4499
        writer = breezy.option.diff_writer_registry.get()
4608
4500
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
4609
4501
                                   reporter=shelf_ui.ApplyReporter(),
4610
 
                                   diff_writer=writer(self.outf))
 
4502
                                   diff_writer=writer(sys.stdout))
4611
4503
        try:
4612
4504
            shelver.run()
4613
4505
        finally:
4615
4507
 
4616
4508
    def sanity_check_merger(self, merger):
4617
4509
        if (merger.show_base and
4618
 
                merger.merge_type is not _mod_merge.Merge3Merger):
4619
 
            raise errors.CommandError(gettext("Show-base is not supported for this"
4620
 
                                                 " merge type. %s") % merger.merge_type)
 
4510
            not merger.merge_type is _mod_merge.Merge3Merger):
 
4511
            raise errors.BzrCommandError(gettext("Show-base is not supported for this"
 
4512
                                         " merge type. %s") % merger.merge_type)
4621
4513
        if merger.reprocess is None:
4622
4514
            if merger.show_base:
4623
4515
                merger.reprocess = False
4625
4517
                # Use reprocess if the merger supports it
4626
4518
                merger.reprocess = merger.merge_type.supports_reprocess
4627
4519
        if merger.reprocess and not merger.merge_type.supports_reprocess:
4628
 
            raise errors.CommandError(gettext("Conflict reduction is not supported"
4629
 
                                                 " for merge type %s.") %
 
4520
            raise errors.BzrCommandError(gettext("Conflict reduction is not supported"
 
4521
                                         " for merge type %s.") %
4630
4522
                                         merger.merge_type)
4631
4523
        if merger.reprocess and merger.show_base:
4632
 
            raise errors.CommandError(gettext("Cannot do conflict reduction and"
4633
 
                                                 " show base."))
4634
 
 
4635
 
        if (merger.merge_type.requires_file_merge_plan and
4636
 
            (not getattr(merger.this_tree, 'plan_file_merge', None) or
4637
 
             not getattr(merger.other_tree, 'plan_file_merge', None) or
4638
 
             (merger.base_tree is not None and
4639
 
                 not getattr(merger.base_tree, 'plan_file_merge', None)))):
4640
 
            raise errors.CommandError(
4641
 
                gettext('Plan file merge unsupported: '
4642
 
                        'Merge type incompatible with tree formats.'))
 
4524
            raise errors.BzrCommandError(gettext("Cannot do conflict reduction and"
 
4525
                                         " show base."))
4643
4526
 
4644
4527
    def _get_merger_from_branch(self, tree, location, revision, remember,
4645
4528
                                possible_transports, pb):
4646
4529
        """Produce a merger from a location, assuming it refers to a branch."""
4647
4530
        # find the branch locations
4648
4531
        other_loc, user_location = self._select_branch_location(tree, location,
4649
 
                                                                revision, -1)
 
4532
            revision, -1)
4650
4533
        if revision is not None and len(revision) == 2:
4651
4534
            base_loc, _unused = self._select_branch_location(tree,
4652
 
                                                             location, revision, 0)
 
4535
                location, revision, 0)
4653
4536
        else:
4654
4537
            base_loc = other_loc
4655
4538
        # Open the branches
4656
4539
        other_branch, other_path = Branch.open_containing(other_loc,
4657
 
                                                          possible_transports)
 
4540
            possible_transports)
4658
4541
        if base_loc == other_loc:
4659
4542
            base_branch = other_branch
4660
4543
        else:
4661
4544
            base_branch, base_path = Branch.open_containing(base_loc,
4662
 
                                                            possible_transports)
 
4545
                possible_transports)
4663
4546
        # Find the revision ids
4664
4547
        other_revision_id = None
4665
4548
        base_revision_id = None
4677
4560
        # - user ask to remember or there is no previous location set to merge
4678
4561
        #   from and user didn't ask to *not* remember
4679
4562
        if (user_location is not None
4680
 
            and ((remember or
4681
 
                 (remember is None and
4682
 
                  tree.branch.get_submit_branch() is None)))):
 
4563
            and ((remember
 
4564
                  or (remember is None
 
4565
                      and tree.branch.get_submit_branch() is None)))):
4683
4566
            tree.branch.set_submit_branch(other_branch.base)
4684
4567
        # Merge tags (but don't set them in the master branch yet, the user
4685
4568
        # might revert this merge).  Commit will propagate them.
4686
4569
        other_branch.tags.merge_to(tree.branch.tags, ignore_master=True)
4687
 
        merger = _mod_merge.Merger.from_revision_ids(tree,
4688
 
                                                     other_revision_id, base_revision_id, other_branch, base_branch)
 
4570
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
 
4571
            other_revision_id, base_revision_id, other_branch, base_branch)
4689
4572
        if other_path != '':
4690
4573
            allow_pending = False
4691
4574
            merger.interesting_files = [other_path]
4726
4609
            will be the user-entered location.
4727
4610
        """
4728
4611
        if (revision is not None and index is not None
4729
 
                and revision[index] is not None):
 
4612
            and revision[index] is not None):
4730
4613
            branch = revision[index].get_branch()
4731
4614
            if branch is not None:
4732
4615
                return branch, branch
4748
4631
            stored_location_type = "parent"
4749
4632
        mutter("%s", stored_location)
4750
4633
        if stored_location is None:
4751
 
            raise errors.CommandError(
4752
 
                gettext("No location specified or remembered"))
 
4634
            raise errors.BzrCommandError(gettext("No location specified or remembered"))
4753
4635
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
4754
4636
        note(gettext("{0} remembered {1} location {2}").format(verb_string,
4755
 
                                                               stored_location_type, display_url))
 
4637
                stored_location_type, display_url))
4756
4638
        return stored_location
4757
4639
 
4758
4640
 
4780
4662
    """
4781
4663
    takes_args = ['file*']
4782
4664
    takes_options = [
4783
 
        'merge-type',
4784
 
        'reprocess',
4785
 
        Option('show-base',
4786
 
               help="Show base revision text in conflicts."),
4787
 
        ]
 
4665
            'merge-type',
 
4666
            'reprocess',
 
4667
            Option('show-base',
 
4668
                   help="Show base revision text in conflicts."),
 
4669
            ]
4788
4670
 
4789
4671
    def run(self, file_list=None, merge_type=None, show_base=False,
4790
4672
            reprocess=False):
4792
4674
        if merge_type is None:
4793
4675
            merge_type = _mod_merge.Merge3Merger
4794
4676
        tree, file_list = WorkingTree.open_containing_paths(file_list)
4795
 
        self.enter_context(tree.lock_write())
 
4677
        self.add_cleanup(tree.lock_write().unlock)
4796
4678
        parents = tree.get_parent_ids()
4797
4679
        if len(parents) != 2:
4798
 
            raise errors.CommandError(
4799
 
                gettext("Sorry, remerge only works after normal"
4800
 
                        " merges.  Not cherrypicking or multi-merges."))
4801
 
        interesting_files = None
 
4680
            raise errors.BzrCommandError(gettext("Sorry, remerge only works after normal"
 
4681
                                         " merges.  Not cherrypicking or"
 
4682
                                         " multi-merges."))
 
4683
        repository = tree.branch.repository
 
4684
        interesting_ids = None
4802
4685
        new_conflicts = []
4803
4686
        conflicts = tree.conflicts()
4804
4687
        if file_list is not None:
4805
 
            interesting_files = set()
 
4688
            interesting_ids = set()
4806
4689
            for filename in file_list:
4807
 
                if not tree.is_versioned(filename):
 
4690
                file_id = tree.path2id(filename)
 
4691
                if file_id is None:
4808
4692
                    raise errors.NotVersionedError(filename)
4809
 
                interesting_files.add(filename)
4810
 
                if tree.kind(filename) != "directory":
 
4693
                interesting_ids.add(file_id)
 
4694
                if tree.kind(file_id) != "directory":
4811
4695
                    continue
4812
4696
 
4813
 
                for path, ie in tree.iter_entries_by_dir(
4814
 
                        specific_files=[filename]):
4815
 
                    interesting_files.add(path)
 
4697
                # FIXME: Support nested trees
 
4698
                for name, ie in tree.root_inventory.iter_entries(file_id):
 
4699
                    interesting_ids.add(ie.file_id)
4816
4700
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4817
4701
        else:
4818
4702
            # Remerge only supports resolving contents conflicts
4819
4703
            allowed_conflicts = ('text conflict', 'contents conflict')
4820
4704
            restore_files = [c.path for c in conflicts
4821
4705
                             if c.typestring in allowed_conflicts]
4822
 
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_files)
 
4706
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
4823
4707
        tree.set_conflicts(ConflictList(new_conflicts))
4824
4708
        if file_list is not None:
4825
4709
            restore_files = file_list
4835
4719
        # have not yet been seen.
4836
4720
        tree.set_parent_ids(parents[:1])
4837
4721
        try:
4838
 
            merger = _mod_merge.Merger.from_revision_ids(tree, parents[1])
4839
 
            merger.interesting_files = interesting_files
 
4722
            merger = _mod_merge.Merger.from_revision_ids(None, tree, parents[1])
 
4723
            merger.interesting_ids = interesting_ids
4840
4724
            merger.merge_type = merge_type
4841
4725
            merger.show_base = show_base
4842
4726
            merger.reprocess = reprocess
4869
4753
    update command.
4870
4754
 
4871
4755
    Uncommitted changes to files that are reverted will be discarded.
4872
 
    However, by default, any files that have been manually changed will be
 
4756
    Howver, by default, any files that have been manually changed will be
4873
4757
    backed up first.  (Files changed only by merge are not backed up.)  Backup
4874
4758
    files have '.~#~' appended to their name, where # is a number.
4875
4759
 
4915
4799
    def run(self, revision=None, no_backup=False, file_list=None,
4916
4800
            forget_merges=None):
4917
4801
        tree, file_list = WorkingTree.open_containing_paths(file_list)
4918
 
        self.enter_context(tree.lock_tree_write())
 
4802
        self.add_cleanup(tree.lock_tree_write().unlock)
4919
4803
        if forget_merges:
4920
4804
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4921
4805
        else:
4925
4809
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4926
4810
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
4927
4811
        tree.revert(file_list, rev_tree, not no_backup, None,
4928
 
                    report_changes=True)
 
4812
            report_changes=True)
4929
4813
 
4930
4814
 
4931
4815
class cmd_assert_fail(Command):
4944
4828
 
4945
4829
    _see_also = ['topics']
4946
4830
    takes_options = [
4947
 
        Option('long', 'Show help on all commands.'),
4948
 
        ]
 
4831
            Option('long', 'Show help on all commands.'),
 
4832
            ]
4949
4833
    takes_args = ['topic?']
4950
4834
    aliases = ['?', '--help', '-?', '-h']
4951
4835
 
4980
4864
    To filter on a range of revisions, you can use the command -r begin..end
4981
4865
    -r revision requests a specific revision, -r ..end or -r begin.. are
4982
4866
    also valid.
4983
 
 
 
4867
            
4984
4868
    :Exit values:
4985
4869
        1 - some missing revisions
4986
4870
        0 - no missing revisions
5014
4898
        Option('reverse', 'Reverse the order of revisions.'),
5015
4899
        Option('mine-only',
5016
4900
               'Display changes in the local branch only.'),
5017
 
        Option('this', 'Same as --mine-only.'),
 
4901
        Option('this' , 'Same as --mine-only.'),
5018
4902
        Option('theirs-only',
5019
4903
               'Display changes in the remote branch only.'),
5020
4904
        Option('other', 'Same as --theirs-only.'),
5022
4906
        'show-ids',
5023
4907
        'verbose',
5024
4908
        custom_help('revision',
5025
 
                    help='Filter on other branch revisions (inclusive). '
5026
 
                    'See "help revisionspec" for details.'),
 
4909
             help='Filter on other branch revisions (inclusive). '
 
4910
                'See "help revisionspec" for details.'),
5027
4911
        Option('my-revision',
5028
 
               type=_parse_revision_str,
5029
 
               help='Filter on local branch revisions (inclusive). '
5030
 
               'See "help revisionspec" for details.'),
 
4912
            type=_parse_revision_str,
 
4913
            help='Filter on local branch revisions (inclusive). '
 
4914
                'See "help revisionspec" for details.'),
5031
4915
        Option('include-merged',
5032
4916
               'Show all revisions in addition to the mainline ones.'),
5033
4917
        Option('include-merges', hidden=True,
5043
4927
            include_merged=None, revision=None, my_revision=None,
5044
4928
            directory=u'.'):
5045
4929
        from breezy.missing import find_unmerged, iter_log_revisions
5046
 
 
5047
4930
        def message(s):
5048
4931
            if not is_quiet():
5049
4932
                self.outf.write(s)
5064
4947
            restrict = 'remote'
5065
4948
 
5066
4949
        local_branch = Branch.open_containing(directory)[0]
5067
 
        self.enter_context(local_branch.lock_read())
 
4950
        self.add_cleanup(local_branch.lock_read().unlock)
5068
4951
 
5069
4952
        parent = local_branch.get_parent()
5070
4953
        if other_branch is None:
5071
4954
            other_branch = parent
5072
4955
            if other_branch is None:
5073
 
                raise errors.CommandError(gettext("No peer location known"
5074
 
                                                     " or specified."))
 
4956
                raise errors.BzrCommandError(gettext("No peer location known"
 
4957
                                             " or specified."))
5075
4958
            display_url = urlutils.unescape_for_display(parent,
5076
4959
                                                        self.outf.encoding)
5077
4960
            message(gettext("Using saved parent location: {0}\n").format(
5081
4964
        if remote_branch.base == local_branch.base:
5082
4965
            remote_branch = local_branch
5083
4966
        else:
5084
 
            self.enter_context(remote_branch.lock_read())
 
4967
            self.add_cleanup(remote_branch.lock_read().unlock)
5085
4968
 
5086
4969
        local_revid_range = _revision_range_to_revid_range(
5087
4970
            _get_revision_range(my_revision, local_branch,
5088
 
                                self.name()))
 
4971
                self.name()))
5089
4972
 
5090
4973
        remote_revid_range = _revision_range_to_revid_range(
5091
4974
            _get_revision_range(revision,
5092
 
                                remote_branch, self.name()))
 
4975
                remote_branch, self.name()))
5093
4976
 
5094
4977
        local_extra, remote_extra = find_unmerged(
5095
4978
            local_branch, remote_branch, restrict,
5108
4991
        status_code = 0
5109
4992
        if local_extra and not theirs_only:
5110
4993
            message(ngettext("You have %d extra revision:\n",
5111
 
                             "You have %d extra revisions:\n",
 
4994
                             "You have %d extra revisions:\n", 
5112
4995
                             len(local_extra)) %
5113
 
                    len(local_extra))
 
4996
                len(local_extra))
5114
4997
            rev_tag_dict = {}
5115
4998
            if local_branch.supports_tags():
5116
4999
                rev_tag_dict = local_branch.tags.get_reverse_tag_dict()
5117
5000
            for revision in iter_log_revisions(local_extra,
5118
 
                                               local_branch.repository,
5119
 
                                               verbose,
5120
 
                                               rev_tag_dict):
 
5001
                                local_branch.repository,
 
5002
                                verbose,
 
5003
                                rev_tag_dict):
5121
5004
                lf.log_revision(revision)
5122
5005
            printed_local = True
5123
5006
            status_code = 1
5130
5013
            message(ngettext("You are missing %d revision:\n",
5131
5014
                             "You are missing %d revisions:\n",
5132
5015
                             len(remote_extra)) %
5133
 
                    len(remote_extra))
 
5016
                len(remote_extra))
5134
5017
            if remote_branch.supports_tags():
5135
5018
                rev_tag_dict = remote_branch.tags.get_reverse_tag_dict()
5136
5019
            for revision in iter_log_revisions(remote_extra,
5137
 
                                               remote_branch.repository,
5138
 
                                               verbose,
5139
 
                                               rev_tag_dict):
 
5020
                                remote_branch.repository,
 
5021
                                verbose,
 
5022
                                rev_tag_dict):
5140
5023
                lf.log_revision(revision)
5141
5024
            status_code = 1
5142
5025
 
5153
5036
            message(gettext("Branches are up to date.\n"))
5154
5037
        self.cleanup_now()
5155
5038
        if not status_code and parent is None and other_branch is not None:
5156
 
            self.enter_context(local_branch.lock_write())
 
5039
            self.add_cleanup(local_branch.lock_write().unlock)
5157
5040
            # handle race conditions - a parent might be set while we run.
5158
5041
            if local_branch.get_parent() is None:
5159
5042
                local_branch.set_parent(remote_branch.base)
5182
5065
    _see_also = ['repositories']
5183
5066
    takes_args = ['branch_or_repo?']
5184
5067
    takes_options = [
5185
 
        Option('clean-obsolete-packs',
5186
 
               'Delete obsolete packs to save disk space.'),
 
5068
        Option('clean-obsolete-packs', 'Delete obsolete packs to save disk space.'),
5187
5069
        ]
5188
5070
 
5189
5071
    def run(self, branch_or_repo='.', clean_obsolete_packs=False):
5204
5086
 
5205
5087
    --verbose shows the path where each plugin is located.
5206
5088
 
5207
 
    A plugin is an external component for Breezy that extends the
5208
 
    revision control system, by adding or replacing code in Breezy.
 
5089
    A plugin is an external component for Bazaar that extends the
 
5090
    revision control system, by adding or replacing code in Bazaar.
5209
5091
    Plugins can do a variety of things, including overriding commands,
5210
5092
    adding new commands, providing additional network transports and
5211
5093
    customizing log output.
5228
5110
class cmd_testament(Command):
5229
5111
    __doc__ = """Show testament (signing-form) of a revision."""
5230
5112
    takes_options = [
5231
 
        'revision',
5232
 
        Option('long', help='Produce long-format testament.'),
5233
 
        Option('strict',
5234
 
               help='Produce a strict-format testament.')]
 
5113
            'revision',
 
5114
            Option('long', help='Produce long-format testament.'),
 
5115
            Option('strict',
 
5116
                   help='Produce a strict-format testament.')]
5235
5117
    takes_args = ['branch?']
5236
5118
    encoding_type = 'exact'
5237
 
 
5238
5119
    @display_command
5239
5120
    def run(self, branch=u'.', revision=None, long=False, strict=False):
5240
 
        from .bzr.testament import Testament, StrictTestament
 
5121
        from .testament import Testament, StrictTestament
5241
5122
        if strict is True:
5242
5123
            testament_class = StrictTestament
5243
5124
        else:
5246
5127
            b = Branch.open_containing(branch)[0]
5247
5128
        else:
5248
5129
            b = Branch.open(branch)
5249
 
        self.enter_context(b.lock_read())
 
5130
        self.add_cleanup(b.lock_read().unlock)
5250
5131
        if revision is None:
5251
5132
            rev_id = b.last_revision()
5252
5133
        else:
5289
5170
        wt, branch, relpath = \
5290
5171
            _open_directory_or_containing_tree_or_branch(filename, directory)
5291
5172
        if wt is not None:
5292
 
            self.enter_context(wt.lock_read())
 
5173
            self.add_cleanup(wt.lock_read().unlock)
5293
5174
        else:
5294
 
            self.enter_context(branch.lock_read())
 
5175
            self.add_cleanup(branch.lock_read().unlock)
5295
5176
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
5296
 
        self.enter_context(tree.lock_read())
5297
 
        if wt is not None and revision is None:
5298
 
            if not wt.is_versioned(relpath):
5299
 
                raise errors.NotVersionedError(relpath)
 
5177
        self.add_cleanup(tree.lock_read().unlock)
 
5178
        if wt is not None and revision is None:
 
5179
            file_id = wt.path2id(relpath)
 
5180
        else:
 
5181
            file_id = tree.path2id(relpath)
 
5182
        if file_id is None:
 
5183
            raise errors.NotVersionedError(filename)
 
5184
        if wt is not None and revision is None:
5300
5185
            # If there is a tree and we're not annotating historical
5301
5186
            # versions, annotate the working tree's content.
5302
 
            annotate_file_tree(wt, relpath, self.outf, long, all,
5303
 
                               show_ids=show_ids)
 
5187
            annotate_file_tree(wt, file_id, self.outf, long, all,
 
5188
                show_ids=show_ids)
5304
5189
        else:
5305
 
            if not tree.is_versioned(relpath):
5306
 
                raise errors.NotVersionedError(relpath)
5307
 
            annotate_file_tree(tree, relpath, self.outf, long, all,
5308
 
                               show_ids=show_ids, branch=branch)
 
5190
            annotate_file_tree(tree, file_id, self.outf, long, all,
 
5191
                show_ids=show_ids, branch=branch)
5309
5192
 
5310
5193
 
5311
5194
class cmd_re_sign(Command):
5312
5195
    __doc__ = """Create a digital signature for an existing revision."""
5313
5196
    # TODO be able to replace existing ones.
5314
5197
 
5315
 
    hidden = True  # is this right ?
 
5198
    hidden = True # is this right ?
5316
5199
    takes_args = ['revision_id*']
5317
5200
    takes_options = ['directory', 'revision']
5318
5201
 
5319
5202
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
5320
5203
        if revision_id_list is not None and revision is not None:
5321
 
            raise errors.CommandError(
5322
 
                gettext('You can only supply one of revision_id or --revision'))
 
5204
            raise errors.BzrCommandError(gettext('You can only supply one of revision_id or --revision'))
5323
5205
        if revision_id_list is None and revision is None:
5324
 
            raise errors.CommandError(
5325
 
                gettext('You must supply either --revision or a revision_id'))
 
5206
            raise errors.BzrCommandError(gettext('You must supply either --revision or a revision_id'))
5326
5207
        b = WorkingTree.open_containing(directory)[0].branch
5327
 
        self.enter_context(b.lock_write())
 
5208
        self.add_cleanup(b.lock_write().unlock)
5328
5209
        return self._run(b, revision_id_list, revision)
5329
5210
 
5330
5211
    def _run(self, b, revision_id_list, revision):
5331
 
        from .repository import WriteGroup
 
5212
        from . import gpg
5332
5213
        gpg_strategy = gpg.GPGStrategy(b.get_config_stack())
5333
5214
        if revision_id_list is not None:
5334
 
            with WriteGroup(b.repository):
 
5215
            b.repository.start_write_group()
 
5216
            try:
5335
5217
                for revision_id in revision_id_list:
5336
 
                    revision_id = cache_utf8.encode(revision_id)
5337
5218
                    b.repository.sign_revision(revision_id, gpg_strategy)
 
5219
            except:
 
5220
                b.repository.abort_write_group()
 
5221
                raise
 
5222
            else:
 
5223
                b.repository.commit_write_group()
5338
5224
        elif revision is not None:
5339
5225
            if len(revision) == 1:
5340
5226
                revno, rev_id = revision[0].in_history(b)
5341
 
                with WriteGroup(b.repository):
 
5227
                b.repository.start_write_group()
 
5228
                try:
5342
5229
                    b.repository.sign_revision(rev_id, gpg_strategy)
 
5230
                except:
 
5231
                    b.repository.abort_write_group()
 
5232
                    raise
 
5233
                else:
 
5234
                    b.repository.commit_write_group()
5343
5235
            elif len(revision) == 2:
5344
5236
                # are they both on rh- if so we can walk between them
5345
5237
                # might be nice to have a range helper for arbitrary
5349
5241
                if to_revid is None:
5350
5242
                    to_revno = b.revno()
5351
5243
                if from_revno is None or to_revno is None:
5352
 
                    raise errors.CommandError(
5353
 
                        gettext('Cannot sign a range of non-revision-history revisions'))
5354
 
                with WriteGroup(b.repository):
 
5244
                    raise errors.BzrCommandError(gettext('Cannot sign a range of non-revision-history revisions'))
 
5245
                b.repository.start_write_group()
 
5246
                try:
5355
5247
                    for revno in range(from_revno, to_revno + 1):
5356
5248
                        b.repository.sign_revision(b.get_rev_id(revno),
5357
5249
                                                   gpg_strategy)
 
5250
                except:
 
5251
                    b.repository.abort_write_group()
 
5252
                    raise
 
5253
                else:
 
5254
                    b.repository.commit_write_group()
5358
5255
            else:
5359
 
                raise errors.CommandError(
5360
 
                    gettext('Please supply either one revision, or a range.'))
 
5256
                raise errors.BzrCommandError(gettext('Please supply either one revision, or a range.'))
5361
5257
 
5362
5258
 
5363
5259
class cmd_bind(Command):
5382
5278
            try:
5383
5279
                location = b.get_old_bound_location()
5384
5280
            except errors.UpgradeRequired:
5385
 
                raise errors.CommandError(
5386
 
                    gettext('No location supplied.  '
5387
 
                            'This format does not remember old locations.'))
 
5281
                raise errors.BzrCommandError(gettext('No location supplied.  '
 
5282
                    'This format does not remember old locations.'))
5388
5283
            else:
5389
5284
                if location is None:
5390
5285
                    if b.get_bound_location() is not None:
5391
 
                        raise errors.CommandError(
 
5286
                        raise errors.BzrCommandError(
5392
5287
                            gettext('Branch is already bound'))
5393
5288
                    else:
5394
 
                        raise errors.CommandError(
 
5289
                        raise errors.BzrCommandError(
5395
5290
                            gettext('No location supplied'
5396
5291
                                    ' and no previous location known'))
5397
5292
        b_other = Branch.open(location)
5398
5293
        try:
5399
5294
            b.bind(b_other)
5400
5295
        except errors.DivergedBranches:
5401
 
            raise errors.CommandError(
5402
 
                gettext('These branches have diverged.'
5403
 
                        ' Try merging, and then bind again.'))
 
5296
            raise errors.BzrCommandError(gettext('These branches have diverged.'
 
5297
                                         ' Try merging, and then bind again.'))
5404
5298
        if b.get_config().has_explicit_nickname():
5405
5299
            b.nick = b_other.nick
5406
5300
 
5419
5313
    def run(self, directory=u'.'):
5420
5314
        b, relpath = Branch.open_containing(directory)
5421
5315
        if not b.unbind():
5422
 
            raise errors.CommandError(gettext('Local branch is not bound'))
 
5316
            raise errors.BzrCommandError(gettext('Local branch is not bound'))
5423
5317
 
5424
5318
 
5425
5319
class cmd_uncommit(Command):
5444
5338
    # information in shared branches as well.
5445
5339
    _see_also = ['commit']
5446
5340
    takes_options = ['verbose', 'revision',
5447
 
                     Option('dry-run', help='Don\'t actually make changes.'),
5448
 
                     Option('force', help='Say yes to all questions.'),
5449
 
                     Option('keep-tags',
5450
 
                            help='Keep tags that point to removed revisions.'),
5451
 
                     Option('local',
5452
 
                            help="Only remove the commits from the local "
5453
 
                            "branch when in a checkout."
5454
 
                            ),
5455
 
                     ]
 
5341
                    Option('dry-run', help='Don\'t actually make changes.'),
 
5342
                    Option('force', help='Say yes to all questions.'),
 
5343
                    Option('keep-tags',
 
5344
                           help='Keep tags that point to removed revisions.'),
 
5345
                    Option('local',
 
5346
                           help="Only remove the commits from the local branch"
 
5347
                                " when in a checkout."
 
5348
                           ),
 
5349
                    ]
5456
5350
    takes_args = ['location?']
5457
5351
    aliases = []
5458
5352
    encoding_type = 'replace'
5470
5364
            b = control.open_branch()
5471
5365
 
5472
5366
        if tree is not None:
5473
 
            self.enter_context(tree.lock_write())
 
5367
            self.add_cleanup(tree.lock_write().unlock)
5474
5368
        else:
5475
 
            self.enter_context(b.lock_write())
 
5369
            self.add_cleanup(b.lock_write().unlock)
5476
5370
        return self._run(b, tree, dry_run, verbose, revision, force,
5477
 
                         local, keep_tags, location)
 
5371
                         local, keep_tags)
5478
5372
 
5479
5373
    def _run(self, b, tree, dry_run, verbose, revision, force, local,
5480
 
             keep_tags, location):
 
5374
             keep_tags):
5481
5375
        from .log import log_formatter, show_log
5482
5376
        from .uncommit import uncommit
5483
5377
 
5514
5408
 
5515
5409
        if dry_run:
5516
5410
            self.outf.write(gettext('Dry-run, pretending to remove'
5517
 
                                    ' the above revisions.\n'))
 
5411
                            ' the above revisions.\n'))
5518
5412
        else:
5519
 
            self.outf.write(
5520
 
                gettext('The above revision(s) will be removed.\n'))
 
5413
            self.outf.write(gettext('The above revision(s) will be removed.\n'))
5521
5414
 
5522
5415
        if not force:
5523
5416
            if not ui.ui_factory.confirm_action(
5531
5424
               last_rev_id, rev_id)
5532
5425
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
5533
5426
                 revno=revno, local=local, keep_tags=keep_tags)
5534
 
        if location != '.':
5535
 
            self.outf.write(
5536
 
                gettext('You can restore the old tip by running:\n'
5537
 
                        '  brz pull -d %s %s -r revid:%s\n')
5538
 
                % (location, location, last_rev_id.decode('utf-8')))
5539
 
        else:
5540
 
            self.outf.write(
5541
 
                gettext('You can restore the old tip by running:\n'
5542
 
                        '  brz pull . -r revid:%s\n')
5543
 
                % last_rev_id.decode('utf-8'))
 
5427
        self.outf.write(gettext('You can restore the old tip by running:\n'
 
5428
             '  brz pull . -r revid:%s\n') % last_rev_id)
5544
5429
 
5545
5430
 
5546
5431
class cmd_break_lock(Command):
5558
5443
    :Examples:
5559
5444
        brz break-lock
5560
5445
        brz break-lock brz+ssh://example.com/brz/foo
5561
 
        brz break-lock --conf ~/.config/breezy
 
5446
        brz break-lock --conf ~/.bazaar
5562
5447
    """
5563
5448
 
5564
5449
    takes_args = ['location?']
5566
5451
        Option('config',
5567
5452
               help='LOCATION is the directory where the config lock is.'),
5568
5453
        Option('force',
5569
 
               help='Do not ask for confirmation before breaking the lock.'),
 
5454
            help='Do not ask for confirmation before breaking the lock.'),
5570
5455
        ]
5571
5456
 
5572
5457
    def run(self, location=None, config=False, force=False):
5574
5459
            location = u'.'
5575
5460
        if force:
5576
5461
            ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
5577
 
                                                               None,
5578
 
                                                               {'breezy.lockdir.break': True})
 
5462
                None,
 
5463
                {'breezy.lockdir.break': True})
5579
5464
        if config:
5580
5465
            conf = _mod_config.LockableConfig(file_name=location)
5581
5466
            conf.break_lock()
5596
5481
    hidden = True
5597
5482
 
5598
5483
    def run(self):
5599
 
        self.outf.write("running\n")
5600
 
        self.outf.flush()
 
5484
        sys.stdout.write("running\n")
 
5485
        sys.stdout.flush()
5601
5486
        sys.stdin.readline()
5602
5487
 
5603
5488
 
5610
5495
        Option('inet',
5611
5496
               help='Serve on stdin/out for use from inetd or sshd.'),
5612
5497
        RegistryOption('protocol',
5613
 
                       help="Protocol to serve.",
5614
 
                       lazy_registry=('breezy.transport',
5615
 
                                      'transport_server_registry'),
5616
 
                       value_switches=True),
 
5498
               help="Protocol to serve.",
 
5499
               lazy_registry=('breezy.transport', 'transport_server_registry'),
 
5500
               value_switches=True),
5617
5501
        Option('listen',
5618
 
               help='Listen for connections on nominated address.',
5619
 
               type=str),
 
5502
               help='Listen for connections on nominated address.', type=str),
5620
5503
        Option('port',
5621
5504
               help='Listen for connections on nominated port.  Passing 0 as '
5622
5505
                    'the port number will result in a dynamically allocated '
5623
5506
                    'port.  The default port depends on the protocol.',
5624
5507
               type=int),
5625
5508
        custom_help('directory',
5626
 
                    help='Serve contents of this directory.'),
 
5509
               help='Serve contents of this directory.'),
5627
5510
        Option('allow-writes',
5628
5511
               help='By default the server is a readonly server.  Supplying '
5629
5512
                    '--allow-writes enables write access to the contents of '
5632
5515
                    'external authentication is arranged supplying this '
5633
5516
                    'option leads to global uncontrolled write access to your '
5634
5517
                    'file system.'
5635
 
               ),
 
5518
                ),
5636
5519
        Option('client-timeout', type=float,
5637
5520
               help='Override the default idle client timeout (5min).'),
5638
5521
        ]
5639
5522
 
5640
5523
    def run(self, listen=None, port=None, inet=False, directory=None,
5641
5524
            allow_writes=False, protocol=None, client_timeout=None):
5642
 
        from . import location, transport
 
5525
        from . import transport
5643
5526
        if directory is None:
5644
5527
            directory = osutils.getcwd()
5645
5528
        if protocol is None:
5646
5529
            protocol = transport.transport_server_registry.get()
5647
 
        url = location.location_to_url(directory)
 
5530
        url = transport.location_to_url(directory)
5648
5531
        if not allow_writes:
5649
5532
            url = 'readonly+' + url
5650
5533
        t = transport.get_transport_from_url(url)
5668
5551
    _see_also = ['split']
5669
5552
    takes_args = ['tree']
5670
5553
    takes_options = [
5671
 
        Option('reference', help='Join by reference.', hidden=True),
5672
 
        ]
 
5554
            Option('reference', help='Join by reference.', hidden=True),
 
5555
            ]
5673
5556
 
5674
5557
    def run(self, tree, reference=False):
5675
 
        from breezy.mutabletree import BadReferenceTarget
5676
5558
        sub_tree = WorkingTree.open(tree)
5677
5559
        parent_dir = osutils.dirname(sub_tree.basedir)
5678
5560
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
5679
5561
        repo = containing_tree.branch.repository
5680
5562
        if not repo.supports_rich_root():
5681
 
            raise errors.CommandError(gettext(
 
5563
            raise errors.BzrCommandError(gettext(
5682
5564
                "Can't join trees because %s doesn't support rich root data.\n"
5683
5565
                "You can use brz upgrade on the repository.")
5684
5566
                % (repo,))
5685
5567
        if reference:
5686
5568
            try:
5687
5569
                containing_tree.add_reference(sub_tree)
5688
 
            except BadReferenceTarget as e:
 
5570
            except errors.BadReferenceTarget as e:
5689
5571
                # XXX: Would be better to just raise a nicely printable
5690
5572
                # exception from the real origin.  Also below.  mbp 20070306
5691
 
                raise errors.CommandError(
5692
 
                    gettext("Cannot join {0}.  {1}").format(tree, e.reason))
 
5573
                raise errors.BzrCommandError(
 
5574
                       gettext("Cannot join {0}.  {1}").format(tree, e.reason))
5693
5575
        else:
5694
5576
            try:
5695
5577
                containing_tree.subsume(sub_tree)
5696
5578
            except errors.BadSubsumeSource as e:
5697
 
                raise errors.CommandError(
5698
 
                    gettext("Cannot join {0}.  {1}").format(tree, e.reason))
 
5579
                raise errors.BzrCommandError(
 
5580
                       gettext("Cannot join {0}.  {1}").format(tree, e.reason))
5699
5581
 
5700
5582
 
5701
5583
class cmd_split(Command):
5715
5597
 
5716
5598
    def run(self, tree):
5717
5599
        containing_tree, subdir = WorkingTree.open_containing(tree)
5718
 
        if not containing_tree.is_versioned(subdir):
 
5600
        sub_id = containing_tree.path2id(subdir)
 
5601
        if sub_id is None:
5719
5602
            raise errors.NotVersionedError(subdir)
5720
5603
        try:
5721
 
            containing_tree.extract(subdir)
 
5604
            containing_tree.extract(sub_id)
5722
5605
        except errors.RootNotRich:
5723
5606
            raise errors.RichRootUpgradeRequired(containing_tree.branch.base)
5724
5607
 
5748
5631
 
5749
5632
    takes_options = [
5750
5633
        'directory',
5751
 
        RegistryOption.from_kwargs(
5752
 
            'patch-type',
 
5634
        RegistryOption.from_kwargs('patch-type',
5753
5635
            'The type of patch to include in the directive.',
5754
5636
            title='Patch type',
5755
5637
            value_switches=True,
5759
5641
            plain='No patch, just directive.'),
5760
5642
        Option('sign', help='GPG-sign the directive.'), 'revision',
5761
5643
        Option('mail-to', type=str,
5762
 
               help='Instead of printing the directive, email to this '
5763
 
               'address.'),
 
5644
            help='Instead of printing the directive, email to this address.'),
5764
5645
        Option('message', type=str, short_name='m',
5765
 
               help='Message to use when committing this merge.')
 
5646
            help='Message to use when committing this merge.')
5766
5647
        ]
5767
5648
 
5768
5649
    encoding_type = 'exact'
5786
5667
        if submit_branch is None:
5787
5668
            submit_branch = branch.get_parent()
5788
5669
        if submit_branch is None:
5789
 
            raise errors.CommandError(
5790
 
                gettext('No submit branch specified or known'))
 
5670
            raise errors.BzrCommandError(gettext('No submit branch specified or known'))
5791
5671
 
5792
5672
        stored_public_branch = branch.get_public_branch()
5793
5673
        if public_branch is None:
5796
5676
            # FIXME: Should be done only if we succeed ? -- vila 2012-01-03
5797
5677
            branch.set_public_branch(public_branch)
5798
5678
        if not include_bundle and public_branch is None:
5799
 
            raise errors.CommandError(
5800
 
                gettext('No public branch specified or known'))
 
5679
            raise errors.BzrCommandError(gettext('No public branch specified or'
 
5680
                                         ' known'))
5801
5681
        base_revision_id = None
5802
5682
        if revision is not None:
5803
5683
            if len(revision) > 2:
5804
 
                raise errors.CommandError(
5805
 
                    gettext('brz merge-directive takes '
5806
 
                            'at most two one revision identifiers'))
 
5684
                raise errors.BzrCommandError(gettext('brz merge-directive takes '
 
5685
                    'at most two one revision identifiers'))
5807
5686
            revision_id = revision[-1].as_revision_id(branch)
5808
5687
            if len(revision) == 2:
5809
5688
                base_revision_id = revision[0].as_revision_id(branch)
5811
5690
            revision_id = branch.last_revision()
5812
5691
        revision_id = ensure_null(revision_id)
5813
5692
        if revision_id == NULL_REVISION:
5814
 
            raise errors.CommandError(gettext('No revisions to bundle.'))
 
5693
            raise errors.BzrCommandError(gettext('No revisions to bundle.'))
5815
5694
        directive = merge_directive.MergeDirective2.from_objects(
5816
5695
            branch.repository, revision_id, time.time(),
5817
5696
            osutils.local_time_offset(), submit_branch,
5843
5722
      branch.
5844
5723
 
5845
5724
    `brz send` creates a compact data set that, when applied using brz
5846
 
    merge, has the same effect as merging from the source branch.
5847
 
 
 
5725
    merge, has the same effect as merging from the source branch.  
 
5726
    
5848
5727
    By default the merge directive is self-contained and can be applied to any
5849
5728
    branch containing submit_branch in its ancestory without needing access to
5850
5729
    the source branch.
5851
 
 
5852
 
    If --no-bundle is specified, then Breezy doesn't send the contents of the
 
5730
    
 
5731
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
5853
5732
    revisions, but only a structured request to merge from the
5854
5733
    public_location.  In that case the public_branch is needed and it must be
5855
5734
    up-to-date and accessible to the recipient.  The public_branch is always
5880
5759
    If the preferred client can't be found (or used), your editor will be used.
5881
5760
 
5882
5761
    To use a specific mail program, set the mail_client configuration option.
5883
 
    Supported values for specific clients are "claws", "evolution", "kmail",
5884
 
    "mail.app" (MacOS X's Mail.app), "mutt", and "thunderbird"; generic options
5885
 
    are "default", "editor", "emacsclient", "mapi", and "xdg-email".  Plugins
5886
 
    may also add supported clients.
 
5762
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
 
5763
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
 
5764
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
 
5765
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
 
5766
    supported clients.
5887
5767
 
5888
5768
    If mail is being sent, a to address is required.  This can be supplied
5889
5769
    either on the commandline, by setting the submit_to configuration
5890
5770
    option in the branch itself or the child_submit_to configuration option
5891
5771
    in the submit branch.
5892
5772
 
 
5773
    Two formats are currently supported: "4" uses revision bundle format 4 and
 
5774
    merge directive format 2.  It is significantly faster and smaller than
 
5775
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
 
5776
    default.  "0.9" uses revision bundle format 0.9 and merge directive
 
5777
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
 
5778
 
5893
5779
    The merge directives created by brz send may be applied using brz merge or
5894
5780
    brz pull by specifying a file containing a merge directive as the location.
5895
5781
 
5915
5801
               help='Branch to generate the submission from, '
5916
5802
               'rather than the one containing the working directory.',
5917
5803
               short_name='f',
5918
 
               type=str),
 
5804
               type=text_type),
5919
5805
        Option('output', short_name='o',
5920
5806
               help='Write merge directive to this file or directory; '
5921
5807
                    'use - for stdout.',
5922
 
               type=str),
 
5808
               type=text_type),
5923
5809
        Option('strict',
5924
5810
               help='Refuse to send if there are uncommitted changes in'
5925
5811
               ' the working tree, --no-strict disables the check.'),
5926
5812
        Option('mail-to', help='Mail the request to this address.',
5927
 
               type=str),
 
5813
               type=text_type),
5928
5814
        'revision',
5929
5815
        'message',
5930
 
        Option('body', help='Body for the email.', type=str),
 
5816
        Option('body', help='Body for the email.', type=text_type),
5931
5817
        RegistryOption('format',
5932
5818
                       help='Use the specified output format.',
5933
5819
                       lazy_registry=('breezy.send', 'format_registry')),
5970
5856
    branch is used in the merge instructions.  This means that a local mirror
5971
5857
    can be used as your actual submit branch, once you have set public_branch
5972
5858
    for that mirror.
 
5859
 
 
5860
    Two formats are currently supported: "4" uses revision bundle format 4 and
 
5861
    merge directive format 2.  It is significantly faster and smaller than
 
5862
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
 
5863
    default.  "0.9" uses revision bundle format 0.9 and merge directive
 
5864
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
5973
5865
    """
5974
5866
 
5975
5867
    takes_options = [
5983
5875
               help='Branch to generate the submission from, '
5984
5876
               'rather than the one containing the working directory.',
5985
5877
               short_name='f',
5986
 
               type=str),
 
5878
               type=text_type),
5987
5879
        Option('output', short_name='o', help='Write directive to this file.',
5988
 
               type=str),
 
5880
               type=text_type),
5989
5881
        Option('strict',
5990
5882
               help='Refuse to bundle revisions if there are uncommitted'
5991
5883
               ' changes in the working tree, --no-strict disables the check.'),
6007
5899
            output = '-'
6008
5900
        from .send import send
6009
5901
        return send(submit_branch, revision, public_branch, remember,
6010
 
                    format, no_bundle, no_patch, output,
6011
 
                    kwargs.get('from', '.'), None, None, None,
6012
 
                    self.outf, strict=strict)
 
5902
                         format, no_bundle, no_patch, output,
 
5903
                         kwargs.get('from', '.'), None, None, None,
 
5904
                         self.outf, strict=strict)
6013
5905
 
6014
5906
 
6015
5907
class cmd_tag(Command):
6028
5920
    To rename a tag (change the name but keep it on the same revsion), run ``brz
6029
5921
    tag new-name -r tag:old-name`` and then ``brz tag --delete oldname``.
6030
5922
 
6031
 
    If no tag name is specified it will be determined through the
 
5923
    If no tag name is specified it will be determined through the 
6032
5924
    'automatic_tag_name' hook. This can e.g. be used to automatically tag
6033
5925
    upstream releases by reading configure.ac. See ``brz help hooks`` for
6034
5926
    details.
6038
5930
    takes_args = ['tag_name?']
6039
5931
    takes_options = [
6040
5932
        Option('delete',
6041
 
               help='Delete this tag rather than placing it.',
6042
 
               ),
 
5933
            help='Delete this tag rather than placing it.',
 
5934
            ),
6043
5935
        custom_help('directory',
6044
 
                    help='Branch in which to place the tag.'),
 
5936
            help='Branch in which to place the tag.'),
6045
5937
        Option('force',
6046
 
               help='Replace existing tags.',
6047
 
               ),
 
5938
            help='Replace existing tags.',
 
5939
            ),
6048
5940
        'revision',
6049
5941
        ]
6050
5942
 
6055
5947
            revision=None,
6056
5948
            ):
6057
5949
        branch, relpath = Branch.open_containing(directory)
6058
 
        self.enter_context(branch.lock_write())
 
5950
        self.add_cleanup(branch.lock_write().unlock)
6059
5951
        if delete:
6060
5952
            if tag_name is None:
6061
 
                raise errors.CommandError(
6062
 
                    gettext("No tag specified to delete."))
 
5953
                raise errors.BzrCommandError(gettext("No tag specified to delete."))
6063
5954
            branch.tags.delete_tag(tag_name)
6064
5955
            note(gettext('Deleted tag %s.') % tag_name)
6065
5956
        else:
6066
5957
            if revision:
6067
5958
                if len(revision) != 1:
6068
 
                    raise errors.CommandError(gettext(
 
5959
                    raise errors.BzrCommandError(gettext(
6069
5960
                        "Tags can only be placed on a single revision, "
6070
5961
                        "not on a range"))
6071
5962
                revision_id = revision[0].as_revision_id(branch)
6074
5965
            if tag_name is None:
6075
5966
                tag_name = branch.automatic_tag_name(revision_id)
6076
5967
                if tag_name is None:
6077
 
                    raise errors.CommandError(gettext(
 
5968
                    raise errors.BzrCommandError(gettext(
6078
5969
                        "Please specify a tag name."))
6079
5970
            try:
6080
5971
                existing_target = branch.tags.lookup_tag(tag_name)
6101
5992
    _see_also = ['tag']
6102
5993
    takes_options = [
6103
5994
        custom_help('directory',
6104
 
                    help='Branch whose tags should be displayed.'),
 
5995
            help='Branch whose tags should be displayed.'),
6105
5996
        RegistryOption('sort',
6106
 
                       'Sort tags by different criteria.', title='Sorting',
6107
 
                       lazy_registry=('breezy.tag', 'tag_sort_methods')
6108
 
                       ),
 
5997
            'Sort tags by different criteria.', title='Sorting',
 
5998
            lazy_registry=('breezy.tag', 'tag_sort_methods')
 
5999
            ),
6109
6000
        'show-ids',
6110
6001
        'revision',
6111
6002
    ]
6115
6006
        from .tag import tag_sort_methods
6116
6007
        branch, relpath = Branch.open_containing(directory)
6117
6008
 
6118
 
        tags = list(branch.tags.get_tag_dict().items())
 
6009
        tags = list(viewitems(branch.tags.get_tag_dict()))
6119
6010
        if not tags:
6120
6011
            return
6121
6012
 
6122
 
        self.enter_context(branch.lock_read())
 
6013
        self.add_cleanup(branch.lock_read().unlock)
6123
6014
        if revision:
6124
6015
            # Restrict to the specified range
6125
6016
            tags = self._tags_for_range(branch, revision)
6140
6031
                    # which are not in this branch. Fail gracefully ...
6141
6032
                    revno = '?'
6142
6033
                tags[index] = (tag, revno)
6143
 
        else:
6144
 
            tags = [(tag, revid.decode('utf-8')) for (tag, revid) in tags]
6145
6034
        self.cleanup_now()
6146
6035
        for tag, revspec in tags:
6147
6036
            self.outf.write('%-20s %s\n' % (tag, revspec))
6148
6037
 
6149
6038
    def _tags_for_range(self, branch, revision):
 
6039
        range_valid = True
6150
6040
        rev1, rev2 = _get_revision_range(revision, branch, self.name())
6151
6041
        revid1, revid2 = rev1.rev_id, rev2.rev_id
6152
6042
        # _get_revision_range will always set revid2 if it's not specified.
6164
6054
        tagged_revids = branch.tags.get_reverse_tag_dict()
6165
6055
        found = []
6166
6056
        for r in branch.iter_merge_sorted_revisions(
6167
 
                start_revision_id=revid2, stop_revision_id=revid1,
6168
 
                stop_rule='include'):
 
6057
            start_revision_id=revid2, stop_revision_id=revid1,
 
6058
            stop_rule='include'):
6169
6059
            revid_tags = tagged_revids.get(r[0], None)
6170
6060
            if revid_tags:
6171
6061
                found.extend([(tag, r[0]) for tag in revid_tags])
6198
6088
            tree='Reconfigure to be an unbound branch with a working tree.',
6199
6089
            checkout='Reconfigure to be a bound branch with a working tree.',
6200
6090
            lightweight_checkout='Reconfigure to be a lightweight'
6201
 
            ' checkout (with no local history).',
 
6091
                ' checkout (with no local history).',
6202
6092
            ),
6203
6093
        RegistryOption.from_kwargs(
6204
6094
            'repository_type',
6206
6096
            help='Location fo the repository.',
6207
6097
            value_switches=True, enum_switch=False,
6208
6098
            standalone='Reconfigure to be a standalone branch '
6209
 
            '(i.e. stop using shared repository).',
 
6099
                '(i.e. stop using shared repository).',
6210
6100
            use_shared='Reconfigure to use a shared repository.',
6211
6101
            ),
6212
6102
        RegistryOption.from_kwargs(
6215
6105
            help='Whether new branches in the repository have trees.',
6216
6106
            value_switches=True, enum_switch=False,
6217
6107
            with_trees='Reconfigure repository to create '
6218
 
            'working trees on branches by default.',
 
6108
                'working trees on branches by default.',
6219
6109
            with_no_trees='Reconfigure repository to not create '
6220
 
            'working trees on branches by default.'
 
6110
                'working trees on branches by default.'
6221
6111
            ),
6222
6112
        Option('bind-to', help='Branch to bind checkout to.', type=str),
6223
6113
        Option('force',
6224
 
               help='Perform reconfiguration even if local changes'
6225
 
               ' will be lost.'),
 
6114
            help='Perform reconfiguration even if local changes'
 
6115
            ' will be lost.'),
6226
6116
        Option('stacked-on',
6227
 
               help='Reconfigure a branch to be stacked on another branch.',
6228
 
               type=str,
6229
 
               ),
 
6117
            help='Reconfigure a branch to be stacked on another branch.',
 
6118
            type=text_type,
 
6119
            ),
6230
6120
        Option('unstacked',
6231
 
               help='Reconfigure a branch to be unstacked.  This '
6232
 
               'may require copying substantial data into it.',
6233
 
               ),
 
6121
            help='Reconfigure a branch to be unstacked.  This '
 
6122
                'may require copying substantial data into it.',
 
6123
            ),
6234
6124
        ]
6235
6125
 
6236
6126
    def run(self, location=None, bind_to=None, force=False,
6238
6128
            stacked_on=None, unstacked=None):
6239
6129
        directory = controldir.ControlDir.open(location)
6240
6130
        if stacked_on and unstacked:
6241
 
            raise errors.CommandError(
6242
 
                gettext("Can't use both --stacked-on and --unstacked"))
 
6131
            raise errors.BzrCommandError(gettext("Can't use both --stacked-on and --unstacked"))
6243
6132
        elif stacked_on is not None:
6244
6133
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
6245
6134
        elif unstacked:
6249
6138
        # to ban it.
6250
6139
        if (tree_type is None and
6251
6140
            repository_type is None and
6252
 
                repository_trees is None):
 
6141
            repository_trees is None):
6253
6142
            if stacked_on or unstacked:
6254
6143
                return
6255
6144
            else:
6256
 
                raise errors.CommandError(gettext('No target configuration '
6257
 
                                                     'specified'))
 
6145
                raise errors.BzrCommandError(gettext('No target configuration '
 
6146
                    'specified'))
6258
6147
        reconfiguration = None
6259
6148
        if tree_type == 'branch':
6260
6149
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
6313
6202
    takes_args = ['to_location?']
6314
6203
    takes_options = ['directory',
6315
6204
                     Option('force',
6316
 
                            help='Switch even if local commits will be lost.'),
 
6205
                        help='Switch even if local commits will be lost.'),
6317
6206
                     'revision',
6318
6207
                     Option('create-branch', short_name='b',
6319
 
                            help='Create the target branch from this one before'
6320
 
                            ' switching to it.'),
 
6208
                        help='Create the target branch from this one before'
 
6209
                             ' switching to it.'),
6321
6210
                     Option('store',
6322
 
                            help='Store and restore uncommitted changes in the'
6323
 
                            ' branch.'),
6324
 
                     ]
 
6211
                        help='Store and restore uncommitted changes in the'
 
6212
                             ' branch.'),
 
6213
                    ]
6325
6214
 
6326
6215
    def run(self, to_location=None, force=False, create_branch=False,
6327
6216
            revision=None, directory=u'.', store=False):
6328
6217
        from . import switch
6329
6218
        tree_location = directory
6330
6219
        revision = _get_one_revision('switch', revision)
6331
 
        control_dir = controldir.ControlDir.open_containing(tree_location)[0]
6332
 
        possible_transports = [control_dir.root_transport]
 
6220
        possible_transports = []
 
6221
        control_dir = controldir.ControlDir.open_containing(tree_location,
 
6222
            possible_transports=possible_transports)[0]
6333
6223
        if to_location is None:
6334
6224
            if revision is None:
6335
 
                raise errors.CommandError(gettext('You must supply either a'
6336
 
                                                     ' revision or a location'))
 
6225
                raise errors.BzrCommandError(gettext('You must supply either a'
 
6226
                                             ' revision or a location'))
6337
6227
            to_location = tree_location
6338
6228
        try:
6339
6229
            branch = control_dir.open_branch(
6342
6232
        except errors.NotBranchError:
6343
6233
            branch = None
6344
6234
            had_explicit_nick = False
6345
 
        else:
6346
 
            possible_transports.append(branch.user_transport)
6347
6235
        if create_branch:
6348
6236
            if branch is None:
6349
 
                raise errors.CommandError(
 
6237
                raise errors.BzrCommandError(
6350
6238
                    gettext('cannot create branch without source branch'))
6351
 
            to_location = lookup_new_sibling_branch(
6352
 
                control_dir, to_location,
6353
 
                possible_transports=possible_transports)
6354
 
            if revision is not None:
6355
 
                revision = revision.as_revision_id(branch)
6356
 
            to_branch = branch.controldir.sprout(
6357
 
                to_location,
6358
 
                possible_transports=possible_transports,
6359
 
                revision_id=revision,
6360
 
                source_branch=branch).open_branch()
 
6239
            to_location = lookup_new_sibling_branch(control_dir, to_location,
 
6240
                 possible_transports=possible_transports)
 
6241
            to_branch = branch.bzrdir.sprout(to_location,
 
6242
                 possible_transports=possible_transports,
 
6243
                 source_branch=branch).open_branch()
6361
6244
        else:
6362
6245
            try:
6363
 
                to_branch = Branch.open(
6364
 
                    to_location, possible_transports=possible_transports)
 
6246
                to_branch = Branch.open(to_location,
 
6247
                    possible_transports=possible_transports)
6365
6248
            except errors.NotBranchError:
6366
 
                to_branch = open_sibling_branch(
6367
 
                    control_dir, to_location,
 
6249
                to_branch = open_sibling_branch(control_dir, to_location,
6368
6250
                    possible_transports=possible_transports)
6369
 
            if revision is not None:
6370
 
                revision = revision.as_revision_id(to_branch)
6371
 
        possible_transports.append(to_branch.user_transport)
6372
 
        try:
6373
 
            switch.switch(control_dir, to_branch, force, revision_id=revision,
6374
 
                          store_uncommitted=store,
6375
 
                          possible_transports=possible_transports)
6376
 
        except controldir.BranchReferenceLoop:
6377
 
            raise errors.CommandError(
6378
 
                gettext('switching would create a branch reference loop. '
6379
 
                        'Use the "bzr up" command to switch to a '
6380
 
                        'different revision.'))
 
6251
        if revision is not None:
 
6252
            revision = revision.as_revision_id(to_branch)
 
6253
        switch.switch(control_dir, to_branch, force, revision_id=revision,
 
6254
                      store_uncommitted=store)
6381
6255
        if had_explicit_nick:
6382
 
            branch = control_dir.open_branch()  # get the new branch!
 
6256
            branch = control_dir.open_branch() #get the new branch!
6383
6257
            branch.nick = to_branch.nick
6384
 
        if to_branch.name:
6385
 
            if to_branch.controldir.control_url != control_dir.control_url:
6386
 
                note(gettext('Switched to branch %s at %s'),
6387
 
                     to_branch.name, urlutils.unescape_for_display(to_branch.base, 'utf-8'))
6388
 
            else:
6389
 
                note(gettext('Switched to branch %s'), to_branch.name)
6390
 
        else:
6391
 
            note(gettext('Switched to branch at %s'),
6392
 
                 urlutils.unescape_for_display(to_branch.base, 'utf-8'))
 
6258
        note(gettext('Switched to branch: %s'),
 
6259
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
 
6260
 
6393
6261
 
6394
6262
 
6395
6263
class cmd_view(Command):
6458
6326
    takes_args = ['file*']
6459
6327
    takes_options = [
6460
6328
        Option('all',
6461
 
               help='Apply list or delete action to all views.',
6462
 
               ),
 
6329
            help='Apply list or delete action to all views.',
 
6330
            ),
6463
6331
        Option('delete',
6464
 
               help='Delete the view.',
6465
 
               ),
 
6332
            help='Delete the view.',
 
6333
            ),
6466
6334
        Option('name',
6467
 
               help='Name of the view to define, list or delete.',
6468
 
               type=str,
6469
 
               ),
 
6335
            help='Name of the view to define, list or delete.',
 
6336
            type=text_type,
 
6337
            ),
6470
6338
        Option('switch',
6471
 
               help='Name of the view to switch to.',
6472
 
               type=str,
6473
 
               ),
 
6339
            help='Name of the view to switch to.',
 
6340
            type=text_type,
 
6341
            ),
6474
6342
        ]
6475
6343
 
6476
6344
    def run(self, file_list,
6480
6348
            switch=None,
6481
6349
            ):
6482
6350
        tree, file_list = WorkingTree.open_containing_paths(file_list,
6483
 
                                                            apply_view=False)
 
6351
            apply_view=False)
6484
6352
        current_view, view_dict = tree.views.get_view_info()
6485
6353
        if name is None:
6486
6354
            name = current_view
6487
6355
        if delete:
6488
6356
            if file_list:
6489
 
                raise errors.CommandError(gettext(
 
6357
                raise errors.BzrCommandError(gettext(
6490
6358
                    "Both --delete and a file list specified"))
6491
6359
            elif switch:
6492
 
                raise errors.CommandError(gettext(
 
6360
                raise errors.BzrCommandError(gettext(
6493
6361
                    "Both --delete and --switch specified"))
6494
6362
            elif all:
6495
6363
                tree.views.set_view_info(None, {})
6496
6364
                self.outf.write(gettext("Deleted all views.\n"))
6497
6365
            elif name is None:
6498
 
                raise errors.CommandError(
6499
 
                    gettext("No current view to delete"))
 
6366
                raise errors.BzrCommandError(gettext("No current view to delete"))
6500
6367
            else:
6501
6368
                tree.views.delete_view(name)
6502
6369
                self.outf.write(gettext("Deleted '%s' view.\n") % name)
6503
6370
        elif switch:
6504
6371
            if file_list:
6505
 
                raise errors.CommandError(gettext(
 
6372
                raise errors.BzrCommandError(gettext(
6506
6373
                    "Both --switch and a file list specified"))
6507
6374
            elif all:
6508
 
                raise errors.CommandError(gettext(
 
6375
                raise errors.BzrCommandError(gettext(
6509
6376
                    "Both --switch and --all specified"))
6510
6377
            elif switch == 'off':
6511
6378
                if current_view is None:
6512
 
                    raise errors.CommandError(
6513
 
                        gettext("No current view to disable"))
 
6379
                    raise errors.BzrCommandError(gettext("No current view to disable"))
6514
6380
                tree.views.set_view_info(None, view_dict)
6515
 
                self.outf.write(gettext("Disabled '%s' view.\n") %
6516
 
                                (current_view))
 
6381
                self.outf.write(gettext("Disabled '%s' view.\n") % (current_view))
6517
6382
            else:
6518
6383
                tree.views.set_view_info(switch, view_dict)
6519
6384
                view_str = views.view_display_str(tree.views.lookup_view())
6520
 
                self.outf.write(
6521
 
                    gettext("Using '{0}' view: {1}\n").format(switch, view_str))
 
6385
                self.outf.write(gettext("Using '{0}' view: {1}\n").format(switch, view_str))
6522
6386
        elif all:
6523
6387
            if view_dict:
6524
6388
                self.outf.write(gettext('Views defined:\n'))
6536
6400
                # No name given and no current view set
6537
6401
                name = 'my'
6538
6402
            elif name == 'off':
6539
 
                raise errors.CommandError(gettext(
 
6403
                raise errors.BzrCommandError(gettext(
6540
6404
                    "Cannot change the 'off' pseudo view"))
6541
6405
            tree.views.set_view(name, sorted(file_list))
6542
6406
            view_str = views.view_display_str(tree.views.lookup_view())
6543
 
            self.outf.write(
6544
 
                gettext("Using '{0}' view: {1}\n").format(name, view_str))
 
6407
            self.outf.write(gettext("Using '{0}' view: {1}\n").format(name, view_str))
6545
6408
        else:
6546
6409
            # list the files
6547
6410
            if name is None:
6549
6412
                self.outf.write(gettext('No current view.\n'))
6550
6413
            else:
6551
6414
                view_str = views.view_display_str(tree.views.lookup_view(name))
6552
 
                self.outf.write(
6553
 
                    gettext("'{0}' view is: {1}\n").format(name, view_str))
 
6415
                self.outf.write(gettext("'{0}' view is: {1}\n").format(name, view_str))
6554
6416
 
6555
6417
 
6556
6418
class cmd_hooks(Command):
6576
6438
class cmd_remove_branch(Command):
6577
6439
    __doc__ = """Remove a branch.
6578
6440
 
6579
 
    This will remove the branch from the specified location but
 
6441
    This will remove the branch from the specified location but 
6580
6442
    will keep any working tree or repository in place.
6581
6443
 
6582
6444
    :Examples:
6590
6452
    takes_args = ["location?"]
6591
6453
 
6592
6454
    takes_options = ['directory',
6593
 
                     Option('force', help='Remove branch even if it is the active branch.')]
 
6455
        Option('force', help='Remove branch even if it is the active branch.')]
6594
6456
 
6595
6457
    aliases = ["rmbranch"]
6596
6458
 
6597
6459
    def run(self, directory=None, location=None, force=False):
6598
6460
        br = open_nearby_branch(near=directory, location=location)
6599
 
        if not force and br.controldir.has_workingtree():
 
6461
        if not force and br.bzrdir.has_workingtree():
6600
6462
            try:
6601
 
                active_branch = br.controldir.open_branch(name="")
 
6463
                active_branch = br.bzrdir.open_branch(name="")
6602
6464
            except errors.NotBranchError:
6603
6465
                active_branch = None
6604
6466
            if (active_branch is not None and
6605
 
                    br.control_url == active_branch.control_url):
6606
 
                raise errors.CommandError(
 
6467
                br.control_url == active_branch.control_url):
 
6468
                raise errors.BzrCommandError(
6607
6469
                    gettext("Branch is active. Use --force to remove it."))
6608
 
        br.controldir.destroy_branch(br.name)
 
6470
        br.bzrdir.destroy_branch(br.name)
6609
6471
 
6610
6472
 
6611
6473
class cmd_shelve(Command):
6636
6498
    editor program to decide what the file remaining in the working copy
6637
6499
    should look like.  To do this, add the configuration option
6638
6500
 
6639
 
        change_editor = PROGRAM {new_path} {old_path}
 
6501
        change_editor = PROGRAM @new_path @old_path
6640
6502
 
6641
 
    where {new_path} is replaced with the path of the new version of the
6642
 
    file and {old_path} is replaced with the path of the old version of
6643
 
    the file.  The PROGRAM should save the new file with the desired
 
6503
    where @new_path is replaced with the path of the new version of the 
 
6504
    file and @old_path is replaced with the path of the old version of 
 
6505
    the file.  The PROGRAM should save the new file with the desired 
6644
6506
    contents of the file in the working tree.
6645
 
 
 
6507
        
6646
6508
    """
6647
6509
 
6648
6510
    takes_args = ['file*']
6670
6532
        if writer is None:
6671
6533
            writer = breezy.option.diff_writer_registry.get()
6672
6534
        try:
6673
 
            shelver = Shelver.from_args(writer(self.outf), revision, all,
6674
 
                                        file_list, message, destroy=destroy, directory=directory)
 
6535
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
 
6536
                file_list, message, destroy=destroy, directory=directory)
6675
6537
            try:
6676
6538
                shelver.run()
6677
6539
            finally:
6683
6545
        if directory is None:
6684
6546
            directory = u'.'
6685
6547
        tree = WorkingTree.open_containing(directory)[0]
6686
 
        self.enter_context(tree.lock_read())
 
6548
        self.add_cleanup(tree.lock_read().unlock)
6687
6549
        manager = tree.get_shelf_manager()
6688
6550
        shelves = manager.active_shelves()
6689
6551
        if len(shelves) == 0:
6690
6552
            note(gettext('No shelved changes.'))
6691
6553
            return 0
6692
6554
        for shelf_id in reversed(shelves):
6693
 
            message = manager.get_metadata(shelf_id).get(b'message')
 
6555
            message = manager.get_metadata(shelf_id).get('message')
6694
6556
            if message is None:
6695
6557
                message = '<no message>'
6696
6558
            self.outf.write('%3d: %s\n' % (shelf_id, message))
6754
6616
                     Option('dry-run', help='Show files to delete instead of'
6755
6617
                            ' deleting them.'),
6756
6618
                     Option('force', help='Do not prompt before deleting.')]
6757
 
 
6758
6619
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
6759
6620
            force=False, directory=u'.'):
6760
6621
        from .clean_tree import clean_tree
6777
6638
    hidden = True
6778
6639
 
6779
6640
    takes_args = ['path?', 'location?']
6780
 
    takes_options = [
6781
 
        'directory',
6782
 
        Option('force-unversioned',
6783
 
               help='Set reference even if path is not versioned.'),
6784
 
        ]
6785
6641
 
6786
 
    def run(self, path=None, directory='.', location=None, force_unversioned=False):
6787
 
        tree, branch, relpath = (
6788
 
            controldir.ControlDir.open_containing_tree_or_branch(directory))
 
6642
    def run(self, path=None, location=None):
 
6643
        branchdir = '.'
 
6644
        if path is not None:
 
6645
            branchdir = path
 
6646
        tree, branch, relpath =(
 
6647
            controldir.ControlDir.open_containing_tree_or_branch(branchdir))
 
6648
        if path is not None:
 
6649
            path = relpath
6789
6650
        if tree is None:
6790
6651
            tree = branch.basis_tree()
6791
6652
        if path is None:
6792
 
            with tree.lock_read():
6793
 
                info = [
6794
 
                    (path, tree.get_reference_info(path, branch))
6795
 
                    for path in tree.iter_references()]
6796
 
                self._display_reference_info(tree, branch, info)
 
6653
            info = viewitems(branch._get_all_reference_info())
 
6654
            self._display_reference_info(tree, branch, info)
6797
6655
        else:
6798
 
            if not tree.is_versioned(path) and not force_unversioned:
 
6656
            file_id = tree.path2id(path)
 
6657
            if file_id is None:
6799
6658
                raise errors.NotVersionedError(path)
6800
6659
            if location is None:
6801
 
                info = [(path, tree.get_reference_info(path, branch))]
 
6660
                info = [(file_id, branch.get_reference_info(file_id))]
6802
6661
                self._display_reference_info(tree, branch, info)
6803
6662
            else:
6804
 
                tree.set_reference_info(path, location)
 
6663
                branch.set_reference_info(file_id, path, location)
6805
6664
 
6806
6665
    def _display_reference_info(self, tree, branch, info):
6807
6666
        ref_list = []
6808
 
        for path, location in info:
 
6667
        for file_id, (path, location) in info:
 
6668
            try:
 
6669
                path = tree.id2path(file_id)
 
6670
            except errors.NoSuchId:
 
6671
                pass
6809
6672
            ref_list.append((path, location))
6810
6673
        for path, location in sorted(ref_list):
6811
6674
            self.outf.write('%s %s\n' % (path, location))
6815
6678
    __doc__ = """Export command helps and error messages in po format."""
6816
6679
 
6817
6680
    hidden = True
6818
 
    takes_options = [Option('plugin',
6819
 
                            help='Export help text from named command '
 
6681
    takes_options = [Option('plugin', 
 
6682
                            help='Export help text from named command '\
6820
6683
                                 '(defaults to all built in commands).',
6821
6684
                            type=str),
6822
6685
                     Option('include-duplicates',
6823
6686
                            help='Output multiple copies of the same msgid '
6824
6687
                                 'string if it appears more than once.'),
6825
 
                     ]
 
6688
                            ]
6826
6689
 
6827
6690
    def run(self, plugin=None, include_duplicates=False):
6828
6691
        from .export_pot import export_pot
6850
6713
        do_import(source, tree)
6851
6714
 
6852
6715
 
6853
 
class cmd_link_tree(Command):
6854
 
    __doc__ = """Hardlink matching files to another tree.
6855
 
 
6856
 
    Only files with identical content and execute bit will be linked.
6857
 
    """
6858
 
 
6859
 
    takes_args = ['location']
6860
 
 
6861
 
    def run(self, location):
6862
 
        from .transform import link_tree
6863
 
        target_tree = WorkingTree.open_containing(".")[0]
6864
 
        source_tree = WorkingTree.open(location)
6865
 
        with target_tree.lock_write(), source_tree.lock_read():
6866
 
            link_tree(target_tree, source_tree)
6867
 
 
6868
 
 
6869
6716
class cmd_fetch_ghosts(Command):
6870
6717
    __doc__ = """Attempt to retrieve ghosts from another branch.
6871
6718
 
6883
6730
        if len(installed) > 0:
6884
6731
            self.outf.write("Installed:\n")
6885
6732
            for rev in installed:
6886
 
                self.outf.write(rev.decode('utf-8') + "\n")
 
6733
                self.outf.write(rev + "\n")
6887
6734
        if len(failed) > 0:
6888
6735
            self.outf.write("Still missing:\n")
6889
6736
            for rev in failed:
6890
 
                self.outf.write(rev.decode('utf-8') + "\n")
 
6737
                self.outf.write(rev + "\n")
6891
6738
        if not no_fix and len(installed) > 0:
6892
6739
            cmd_reconcile().run(".")
6893
6740
 
6894
6741
 
6895
 
class cmd_grep(Command):
6896
 
    """Print lines matching PATTERN for specified files and revisions.
6897
 
 
6898
 
    This command searches the specified files and revisions for a given
6899
 
    pattern.  The pattern is specified as a Python regular expressions[1].
6900
 
 
6901
 
    If the file name is not specified, the revisions starting with the
6902
 
    current directory are searched recursively. If the revision number is
6903
 
    not specified, the working copy is searched. To search the last committed
6904
 
    revision, use the '-r -1' or '-r last:1' option.
6905
 
 
6906
 
    Unversioned files are not searched unless explicitly specified on the
6907
 
    command line. Unversioned directores are not searched.
6908
 
 
6909
 
    When searching a pattern, the output is shown in the 'filepath:string'
6910
 
    format. If a revision is explicitly searched, the output is shown as
6911
 
    'filepath~N:string', where N is the revision number.
6912
 
 
6913
 
    --include and --exclude options can be used to search only (or exclude
6914
 
    from search) files with base name matches the specified Unix style GLOB
6915
 
    pattern.  The GLOB pattern an use *, ?, and [...] as wildcards, and \\
6916
 
    to quote wildcard or backslash character literally. Note that the glob
6917
 
    pattern is not a regular expression.
6918
 
 
6919
 
    [1] http://docs.python.org/library/re.html#regular-expression-syntax
6920
 
    """
6921
 
 
6922
 
    encoding_type = 'replace'
6923
 
    takes_args = ['pattern', 'path*']
6924
 
    takes_options = [
6925
 
        'verbose',
6926
 
        'revision',
6927
 
        Option('color', type=str, argname='when',
6928
 
               help='Show match in color. WHEN is never, always or auto.'),
6929
 
        Option('diff', short_name='p',
6930
 
               help='Grep for pattern in changeset for each revision.'),
6931
 
        ListOption('exclude', type=str, argname='glob', short_name='X',
6932
 
                   help="Skip files whose base name matches GLOB."),
6933
 
        ListOption('include', type=str, argname='glob', short_name='I',
6934
 
                   help="Search only files whose base name matches GLOB."),
6935
 
        Option('files-with-matches', short_name='l',
6936
 
               help='Print only the name of each input file in '
6937
 
               'which PATTERN is found.'),
6938
 
        Option('files-without-match', short_name='L',
6939
 
               help='Print only the name of each input file in '
6940
 
               'which PATTERN is not found.'),
6941
 
        Option('fixed-string', short_name='F',
6942
 
               help='Interpret PATTERN is a single fixed string (not regex).'),
6943
 
        Option('from-root',
6944
 
               help='Search for pattern starting from the root of the branch. '
6945
 
               '(implies --recursive)'),
6946
 
        Option('ignore-case', short_name='i',
6947
 
               help='Ignore case distinctions while matching.'),
6948
 
        Option('levels',
6949
 
               help='Number of levels to display - 0 for all, 1 for collapsed '
6950
 
               '(1 is default).',
6951
 
               argname='N',
6952
 
               type=_parse_levels),
6953
 
        Option('line-number', short_name='n',
6954
 
               help='Show 1-based line number.'),
6955
 
        Option('no-recursive',
6956
 
               help="Don't recurse into subdirectories. (default is --recursive)"),
6957
 
        Option('null', short_name='Z',
6958
 
               help='Write an ASCII NUL (\\0) separator '
6959
 
               'between output lines rather than a newline.'),
6960
 
        ]
6961
 
 
6962
 
    @display_command
6963
 
    def run(self, verbose=False, ignore_case=False, no_recursive=False,
6964
 
            from_root=False, null=False, levels=None, line_number=False,
6965
 
            path_list=None, revision=None, pattern=None, include=None,
6966
 
            exclude=None, fixed_string=False, files_with_matches=False,
6967
 
            files_without_match=False, color=None, diff=False):
6968
 
        from breezy import _termcolor
6969
 
        from . import grep
6970
 
        import re
6971
 
        if path_list is None:
6972
 
            path_list = ['.']
6973
 
        else:
6974
 
            if from_root:
6975
 
                raise errors.CommandError(
6976
 
                    'cannot specify both --from-root and PATH.')
6977
 
 
6978
 
        if files_with_matches and files_without_match:
6979
 
            raise errors.CommandError(
6980
 
                'cannot specify both '
6981
 
                '-l/--files-with-matches and -L/--files-without-matches.')
6982
 
 
6983
 
        global_config = _mod_config.GlobalConfig()
6984
 
 
6985
 
        if color is None:
6986
 
            color = global_config.get_user_option('grep_color')
6987
 
 
6988
 
        if color is None:
6989
 
            color = 'never'
6990
 
 
6991
 
        if color not in ['always', 'never', 'auto']:
6992
 
            raise errors.CommandError('Valid values for --color are '
6993
 
                                         '"always", "never" or "auto".')
6994
 
 
6995
 
        if levels is None:
6996
 
            levels = 1
6997
 
 
6998
 
        print_revno = False
6999
 
        if revision is not None or levels == 0:
7000
 
            # print revision numbers as we may be showing multiple revisions
7001
 
            print_revno = True
7002
 
 
7003
 
        eol_marker = '\n'
7004
 
        if null:
7005
 
            eol_marker = '\0'
7006
 
 
7007
 
        if not ignore_case and grep.is_fixed_string(pattern):
7008
 
            # if the pattern isalnum, implicitly use to -F for faster grep
7009
 
            fixed_string = True
7010
 
        elif ignore_case and fixed_string:
7011
 
            # GZ 2010-06-02: Fall back to regexp rather than lowercasing
7012
 
            #                pattern and text which will cause pain later
7013
 
            fixed_string = False
7014
 
            pattern = re.escape(pattern)
7015
 
 
7016
 
        patternc = None
7017
 
        re_flags = re.MULTILINE
7018
 
        if ignore_case:
7019
 
            re_flags |= re.IGNORECASE
7020
 
 
7021
 
        if not fixed_string:
7022
 
            patternc = grep.compile_pattern(
7023
 
                pattern.encode(grep._user_encoding), re_flags)
7024
 
 
7025
 
        if color == 'always':
7026
 
            show_color = True
7027
 
        elif color == 'never':
7028
 
            show_color = False
7029
 
        elif color == 'auto':
7030
 
            show_color = _termcolor.allow_color()
7031
 
 
7032
 
        opts = grep.GrepOptions()
7033
 
 
7034
 
        opts.verbose = verbose
7035
 
        opts.ignore_case = ignore_case
7036
 
        opts.no_recursive = no_recursive
7037
 
        opts.from_root = from_root
7038
 
        opts.null = null
7039
 
        opts.levels = levels
7040
 
        opts.line_number = line_number
7041
 
        opts.path_list = path_list
7042
 
        opts.revision = revision
7043
 
        opts.pattern = pattern
7044
 
        opts.include = include
7045
 
        opts.exclude = exclude
7046
 
        opts.fixed_string = fixed_string
7047
 
        opts.files_with_matches = files_with_matches
7048
 
        opts.files_without_match = files_without_match
7049
 
        opts.color = color
7050
 
        opts.diff = False
7051
 
 
7052
 
        opts.eol_marker = eol_marker
7053
 
        opts.print_revno = print_revno
7054
 
        opts.patternc = patternc
7055
 
        opts.recursive = not no_recursive
7056
 
        opts.fixed_string = fixed_string
7057
 
        opts.outf = self.outf
7058
 
        opts.show_color = show_color
7059
 
 
7060
 
        if diff:
7061
 
            # options not used:
7062
 
            # files_with_matches, files_without_match
7063
 
            # levels(?), line_number, from_root
7064
 
            # include, exclude
7065
 
            # These are silently ignored.
7066
 
            grep.grep_diff(opts)
7067
 
        elif revision is None:
7068
 
            grep.workingtree_grep(opts)
7069
 
        else:
7070
 
            grep.versioned_grep(opts)
7071
 
 
7072
 
 
7073
 
class cmd_patch(Command):
7074
 
    """Apply a named patch to the current tree.
7075
 
 
7076
 
    """
7077
 
 
7078
 
    takes_args = ['filename?']
7079
 
    takes_options = [Option('strip', type=int, short_name='p',
7080
 
                            help=("Strip the smallest prefix containing num "
7081
 
                                  "leading slashes from filenames.")),
7082
 
                     Option('silent', help='Suppress chatter.')]
7083
 
 
7084
 
    def run(self, filename=None, strip=None, silent=False):
7085
 
        from .patch import patch_tree
7086
 
        wt = WorkingTree.open_containing('.')[0]
7087
 
        if strip is None:
7088
 
            strip = 1
7089
 
        my_file = None
7090
 
        if filename is None:
7091
 
            my_file = getattr(sys.stdin, 'buffer', sys.stdin)
7092
 
        else:
7093
 
            my_file = open(filename, 'rb')
7094
 
        patches = [my_file.read()]
7095
 
        return patch_tree(wt, patches, strip, quiet=is_quiet(), out=self.outf)
7096
 
 
7097
 
 
7098
 
class cmd_resolve_location(Command):
7099
 
    __doc__ = """Expand a location to a full URL.
7100
 
 
7101
 
    :Examples:
7102
 
        Look up a Launchpad URL.
7103
 
 
7104
 
            brz resolve-location lp:brz
7105
 
    """
7106
 
    takes_args = ['location']
7107
 
    hidden = True
7108
 
 
7109
 
    def run(self, location):
7110
 
        from .location import location_to_url
7111
 
        url = location_to_url(location)
7112
 
        display_url = urlutils.unescape_for_display(url, self.outf.encoding)
7113
 
        self.outf.write('%s\n' % display_url)
7114
 
 
7115
 
 
7116
6742
def _register_lazy_builtins():
7117
6743
    # register lazy builtins from other modules; called at startup and should
7118
6744
    # be only called once.
7119
6745
    for (name, aliases, module_name) in [
7120
 
            ('cmd_bisect', [], 'breezy.bisect'),
7121
 
            ('cmd_bundle_info', [], 'breezy.bzr.bundle.commands'),
7122
 
            ('cmd_config', [], 'breezy.config'),
7123
 
            ('cmd_dump_btree', [], 'breezy.bzr.debug_commands'),
7124
 
            ('cmd_file_id', [], 'breezy.bzr.debug_commands'),
7125
 
            ('cmd_file_path', [], 'breezy.bzr.debug_commands'),
7126
 
            ('cmd_version_info', [], 'breezy.cmd_version_info'),
7127
 
            ('cmd_resolve', ['resolved'], 'breezy.conflicts'),
7128
 
            ('cmd_conflicts', [], 'breezy.conflicts'),
7129
 
            ('cmd_ping', [], 'breezy.bzr.smart.ping'),
7130
 
            ('cmd_sign_my_commits', [], 'breezy.commit_signature_commands'),
7131
 
            ('cmd_verify_signatures', [], 'breezy.commit_signature_commands'),
7132
 
            ('cmd_test_script', [], 'breezy.cmd_test_script'),
7133
 
            ]:
 
6746
        ('cmd_bundle_info', [], 'breezy.bundle.commands'),
 
6747
        ('cmd_config', [], 'breezy.config'),
 
6748
        ('cmd_dpush', [], 'breezy.foreign'),
 
6749
        ('cmd_version_info', [], 'breezy.cmd_version_info'),
 
6750
        ('cmd_resolve', ['resolved'], 'breezy.conflicts'),
 
6751
        ('cmd_conflicts', [], 'breezy.conflicts'),
 
6752
        ('cmd_ping', [], 'breezy.smart.ping'),
 
6753
        ('cmd_sign_my_commits', [], 'breezy.commit_signature_commands'),
 
6754
        ('cmd_verify_signatures', [], 'breezy.commit_signature_commands'),
 
6755
        ('cmd_test_script', [], 'breezy.cmd_test_script'),
 
6756
        ]:
7134
6757
        builtin_command_registry.register_lazy(name, aliases, module_name)