~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

terminal_width can now returns None.

* bzrlib/win32utils.py:
(get_console_size): Fix typo in comment.

* bzrlib/ui/text.py:
(TextProgressView._show_line): Handle the no terminal present case.

* bzrlib/tests/test_osutils.py:
(TestTerminalWidth): Update tests.

* bzrlib/tests/blackbox/test_too_much.py:
Fix some imports.
(OldTests.test_bzr): Handle the no terminal present case.

* bzrlib/tests/__init__.py:
(VerboseTestResult.report_test_start): Handle the no terminal
present case.

* bzrlib/status.py:
(show_pending_merges): Handle the no terminal present case.
(show_pending_merges.show_log_message): Factor out some
code. Handle the no terminal present case.

* bzrlib/osutils.py:
(terminal_width): Return None if no precise value can be found.

* bzrlib/log.py:
(LineLogFormatter.__init__): Handle the no terminal present case.
(LineLogFormatter.truncate): Accept None as max_len meaning no
truncation.
(LineLogFormatter.log_string): 

* bzrlib/help.py:
(_help_commands_to_text): Handle the no terminal present case.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004-2010 Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
31
31
    bundle,
32
32
    btree_index,
33
33
    bzrdir,
34
 
    directory_service,
35
34
    delta,
36
35
    config,
37
36
    errors,
44
43
    reconfigure,
45
44
    rename_map,
46
45
    revision as _mod_revision,
47
 
    static_tuple,
48
46
    symbol_versioning,
49
 
    timestamp,
50
47
    transport,
51
48
    ui,
52
49
    urlutils,
260
257
    unknown
261
258
        Not versioned and not matching an ignore pattern.
262
259
 
263
 
    Additionally for directories, symlinks and files with an executable
264
 
    bit, Bazaar indicates their type using a trailing character: '/', '@'
265
 
    or '*' respectively.
266
 
 
267
260
    To see ignored files use 'bzr ignored'.  For details on the
268
261
    changes to file texts, use 'bzr diff'.
269
262
 
438
431
        for node in bt.iter_all_entries():
439
432
            # Node is made up of:
440
433
            # (index, key, value, [references])
441
 
            refs_as_tuples = static_tuple.as_tuples(node[3])
442
 
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
443
 
            self.outf.write('%s\n' % (as_tuple,))
 
434
            self.outf.write('%s\n' % (node[1:],))
444
435
 
445
436
 
446
437
class cmd_remove_tree(Command):
502
493
                wt.lock_read()
503
494
            except (errors.NoWorkingTree, errors.NotLocalUrl):
504
495
                raise errors.NoWorkingTree(location)
505
 
            self.add_cleanup(wt.unlock)
506
 
            revid = wt.last_revision()
507
496
            try:
508
 
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
509
 
            except errors.NoSuchRevision:
510
 
                revno_t = ('???',)
511
 
            revno = ".".join(str(n) for n in revno_t)
 
497
                revid = wt.last_revision()
 
498
                try:
 
499
                    revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
500
                except errors.NoSuchRevision:
 
501
                    revno_t = ('???',)
 
502
                revno = ".".join(str(n) for n in revno_t)
 
503
            finally:
 
504
                wt.unlock()
512
505
        else:
513
506
            b = Branch.open_containing(location)[0]
514
507
            b.lock_read()
515
 
            self.add_cleanup(b.unlock)
516
 
            revno = b.revno()
517
 
        self.cleanup_now()
 
508
            try:
 
509
                revno = b.revno()
 
510
            finally:
 
511
                b.unlock()
 
512
 
518
513
        self.outf.write(str(revno) + '\n')
519
514
 
520
515
 
542
537
            wt = WorkingTree.open_containing(directory)[0]
543
538
            b = wt.branch
544
539
            wt.lock_read()
545
 
            self.add_cleanup(wt.unlock)
546
540
        except (errors.NoWorkingTree, errors.NotLocalUrl):
547
541
            wt = None
548
542
            b = Branch.open_containing(directory)[0]
549
543
            b.lock_read()
550
 
            self.add_cleanup(b.unlock)
551
 
        revision_ids = []
552
 
        if revision is not None:
553
 
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
554
 
        if revision_info_list is not None:
555
 
            for rev_str in revision_info_list:
556
 
                rev_spec = RevisionSpec.from_string(rev_str)
557
 
                revision_ids.append(rev_spec.as_revision_id(b))
558
 
        # No arguments supplied, default to the last revision
559
 
        if len(revision_ids) == 0:
560
 
            if tree:
561
 
                if wt is None:
562
 
                    raise errors.NoWorkingTree(directory)
563
 
                revision_ids.append(wt.last_revision())
 
544
        try:
 
545
            revision_ids = []
 
546
            if revision is not None:
 
547
                revision_ids.extend(rev.as_revision_id(b) for rev in revision)
 
548
            if revision_info_list is not None:
 
549
                for rev_str in revision_info_list:
 
550
                    rev_spec = RevisionSpec.from_string(rev_str)
 
551
                    revision_ids.append(rev_spec.as_revision_id(b))
 
552
            # No arguments supplied, default to the last revision
 
553
            if len(revision_ids) == 0:
 
554
                if tree:
 
555
                    if wt is None:
 
556
                        raise errors.NoWorkingTree(directory)
 
557
                    revision_ids.append(wt.last_revision())
 
558
                else:
 
559
                    revision_ids.append(b.last_revision())
 
560
 
 
561
            revinfos = []
 
562
            maxlen = 0
 
563
            for revision_id in revision_ids:
 
564
                try:
 
565
                    dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
566
                    revno = '.'.join(str(i) for i in dotted_revno)
 
567
                except errors.NoSuchRevision:
 
568
                    revno = '???'
 
569
                maxlen = max(maxlen, len(revno))
 
570
                revinfos.append([revno, revision_id])
 
571
        finally:
 
572
            if wt is None:
 
573
                b.unlock()
564
574
            else:
565
 
                revision_ids.append(b.last_revision())
566
 
 
567
 
        revinfos = []
568
 
        maxlen = 0
569
 
        for revision_id in revision_ids:
570
 
            try:
571
 
                dotted_revno = b.revision_id_to_dotted_revno(revision_id)
572
 
                revno = '.'.join(str(i) for i in dotted_revno)
573
 
            except errors.NoSuchRevision:
574
 
                revno = '???'
575
 
            maxlen = max(maxlen, len(revno))
576
 
            revinfos.append([revno, revision_id])
577
 
 
578
 
        self.cleanup_now()
 
575
                wt.unlock()
 
576
 
579
577
        for ri in revinfos:
580
578
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
581
579
 
653
651
 
654
652
        if base_tree:
655
653
            base_tree.lock_read()
656
 
            self.add_cleanup(base_tree.unlock)
657
 
        tree, file_list = tree_files_for_add(file_list)
658
 
        added, ignored = tree.smart_add(file_list, not
659
 
            no_recurse, action=action, save=not dry_run)
660
 
        self.cleanup_now()
 
654
        try:
 
655
            file_list = self._maybe_expand_globs(file_list)
 
656
            tree, file_list = tree_files_for_add(file_list)
 
657
            added, ignored = tree.smart_add(file_list, not
 
658
                no_recurse, action=action, save=not dry_run)
 
659
        finally:
 
660
            if base_tree is not None:
 
661
                base_tree.unlock()
661
662
        if len(ignored) > 0:
662
663
            if verbose:
663
664
                for glob in sorted(ignored.keys()):
727
728
        revision = _get_one_revision('inventory', revision)
728
729
        work_tree, file_list = tree_files(file_list)
729
730
        work_tree.lock_read()
730
 
        self.add_cleanup(work_tree.unlock)
731
 
        if revision is not None:
732
 
            tree = revision.as_tree(work_tree.branch)
733
 
 
734
 
            extra_trees = [work_tree]
735
 
            tree.lock_read()
736
 
            self.add_cleanup(tree.unlock)
737
 
        else:
738
 
            tree = work_tree
739
 
            extra_trees = []
740
 
 
741
 
        if file_list is not None:
742
 
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
743
 
                                      require_versioned=True)
744
 
            # find_ids_across_trees may include some paths that don't
745
 
            # exist in 'tree'.
746
 
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
747
 
                             for file_id in file_ids if file_id in tree)
748
 
        else:
749
 
            entries = tree.inventory.entries()
750
 
 
751
 
        self.cleanup_now()
 
731
        try:
 
732
            if revision is not None:
 
733
                tree = revision.as_tree(work_tree.branch)
 
734
 
 
735
                extra_trees = [work_tree]
 
736
                tree.lock_read()
 
737
            else:
 
738
                tree = work_tree
 
739
                extra_trees = []
 
740
 
 
741
            if file_list is not None:
 
742
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
743
                                          require_versioned=True)
 
744
                # find_ids_across_trees may include some paths that don't
 
745
                # exist in 'tree'.
 
746
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
747
                                 for file_id in file_ids if file_id in tree)
 
748
            else:
 
749
                entries = tree.inventory.entries()
 
750
        finally:
 
751
            tree.unlock()
 
752
            if tree is not work_tree:
 
753
                work_tree.unlock()
 
754
 
752
755
        for path, entry in entries:
753
756
            if kind and kind != entry.kind:
754
757
                continue
800
803
            raise errors.BzrCommandError("missing file argument")
801
804
        tree, rel_names = tree_files(names_list, canonicalize=False)
802
805
        tree.lock_tree_write()
803
 
        self.add_cleanup(tree.unlock)
804
 
        self._run(tree, names_list, rel_names, after)
 
806
        try:
 
807
            self._run(tree, names_list, rel_names, after)
 
808
        finally:
 
809
            tree.unlock()
805
810
 
806
811
    def run_auto(self, names_list, after, dry_run):
807
812
        if names_list is not None and len(names_list) > 1:
812
817
                                         ' --auto.')
813
818
        work_tree, file_list = tree_files(names_list, default_branch='.')
814
819
        work_tree.lock_tree_write()
815
 
        self.add_cleanup(work_tree.unlock)
816
 
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
 
820
        try:
 
821
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
 
822
        finally:
 
823
            work_tree.unlock()
817
824
 
818
825
    def _run(self, tree, names_list, rel_names, after):
819
826
        into_existing = osutils.isdir(names_list[-1])
840
847
            # All entries reference existing inventory items, so fix them up
841
848
            # for cicp file-systems.
842
849
            rel_names = tree.get_canonical_inventory_paths(rel_names)
843
 
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
844
 
                if not is_quiet():
845
 
                    self.outf.write("%s => %s\n" % (src, dest))
 
850
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
851
                self.outf.write("%s => %s\n" % pair)
846
852
        else:
847
853
            if len(names_list) != 2:
848
854
                raise errors.BzrCommandError('to mv multiple files the'
892
898
            dest = osutils.pathjoin(dest_parent, dest_tail)
893
899
            mutter("attempting to move %s => %s", src, dest)
894
900
            tree.rename_one(src, dest, after=after)
895
 
            if not is_quiet():
896
 
                self.outf.write("%s => %s\n" % (src, dest))
 
901
            self.outf.write("%s => %s\n" % (src, dest))
897
902
 
898
903
 
899
904
class cmd_pull(Command):
900
905
    """Turn this branch into a mirror of another branch.
901
906
 
902
 
    By default, this command only works on branches that have not diverged.
903
 
    Branches are considered diverged if the destination branch's most recent 
904
 
    commit is one that has not been merged (directly or indirectly) into the 
905
 
    parent.
 
907
    This command only works on branches that have not diverged.  Branches are
 
908
    considered diverged if the destination branch's most recent commit is one
 
909
    that has not been merged (directly or indirectly) into the parent.
906
910
 
907
911
    If branches have diverged, you can use 'bzr merge' to integrate the changes
908
912
    from one into the other.  Once one branch has merged, the other should
909
913
    be able to pull it again.
910
914
 
911
 
    If you want to replace your local changes and just want your branch to
912
 
    match the remote one, use pull --overwrite. This will work even if the two
913
 
    branches have diverged.
 
915
    If you want to forget your local changes and just update your branch to
 
916
    match the remote one, use pull --overwrite.
914
917
 
915
918
    If there is no default location set, the first pull will set it.  After
916
919
    that, you can omit the location to use the default.  To change the
997
1000
 
998
1001
        if branch_from is not branch_to:
999
1002
            branch_from.lock_read()
1000
 
            self.add_cleanup(branch_from.unlock)
1001
 
        if revision is not None:
1002
 
            revision_id = revision.as_revision_id(branch_from)
1003
 
 
1004
 
        branch_to.lock_write()
1005
 
        self.add_cleanup(branch_to.unlock)
1006
 
        if tree_to is not None:
1007
 
            view_info = _get_view_info_for_change_reporter(tree_to)
1008
 
            change_reporter = delta._ChangeReporter(
1009
 
                unversioned_filter=tree_to.is_ignored,
1010
 
                view_info=view_info)
1011
 
            result = tree_to.pull(
1012
 
                branch_from, overwrite, revision_id, change_reporter,
1013
 
                possible_transports=possible_transports, local=local)
1014
 
        else:
1015
 
            result = branch_to.pull(
1016
 
                branch_from, overwrite, revision_id, local=local)
1017
 
 
1018
 
        result.report(self.outf)
1019
 
        if verbose and result.old_revid != result.new_revid:
1020
 
            log.show_branch_change(
1021
 
                branch_to, self.outf, result.old_revno,
1022
 
                result.old_revid)
 
1003
        try:
 
1004
            if revision is not None:
 
1005
                revision_id = revision.as_revision_id(branch_from)
 
1006
 
 
1007
            branch_to.lock_write()
 
1008
            try:
 
1009
                if tree_to is not None:
 
1010
                    view_info = _get_view_info_for_change_reporter(tree_to)
 
1011
                    change_reporter = delta._ChangeReporter(
 
1012
                        unversioned_filter=tree_to.is_ignored,
 
1013
                        view_info=view_info)
 
1014
                    result = tree_to.pull(
 
1015
                        branch_from, overwrite, revision_id, change_reporter,
 
1016
                        possible_transports=possible_transports, local=local)
 
1017
                else:
 
1018
                    result = branch_to.pull(
 
1019
                        branch_from, overwrite, revision_id, local=local)
 
1020
 
 
1021
                result.report(self.outf)
 
1022
                if verbose and result.old_revid != result.new_revid:
 
1023
                    log.show_branch_change(
 
1024
                        branch_to, self.outf, result.old_revno,
 
1025
                        result.old_revid)
 
1026
            finally:
 
1027
                branch_to.unlock()
 
1028
        finally:
 
1029
            if branch_from is not branch_to:
 
1030
                branch_from.unlock()
1023
1031
 
1024
1032
 
1025
1033
class cmd_push(Command):
1180
1188
                    ' directory exists, but does not already'
1181
1189
                    ' have a control directory.  This flag will'
1182
1190
                    ' allow branch to proceed.'),
1183
 
        Option('bind',
1184
 
            help="Bind new branch to from location."),
1185
1191
        ]
1186
1192
    aliases = ['get', 'clone']
1187
1193
 
1188
1194
    def run(self, from_location, to_location=None, revision=None,
1189
1195
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1190
 
            use_existing_dir=False, switch=False, bind=False):
 
1196
            use_existing_dir=False, switch=False):
1191
1197
        from bzrlib import switch as _mod_switch
1192
1198
        from bzrlib.tag import _merge_tags_if_possible
1193
1199
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1194
1200
            from_location)
 
1201
        if (accelerator_tree is not None and
 
1202
            accelerator_tree.supports_content_filtering()):
 
1203
            accelerator_tree = None
1195
1204
        revision = _get_one_revision('branch', revision)
1196
1205
        br_from.lock_read()
1197
 
        self.add_cleanup(br_from.unlock)
1198
 
        if revision is not None:
1199
 
            revision_id = revision.as_revision_id(br_from)
1200
 
        else:
1201
 
            # FIXME - wt.last_revision, fallback to branch, fall back to
1202
 
            # None or perhaps NULL_REVISION to mean copy nothing
1203
 
            # RBC 20060209
1204
 
            revision_id = br_from.last_revision()
1205
 
        if to_location is None:
1206
 
            to_location = urlutils.derive_to_location(from_location)
1207
 
        to_transport = transport.get_transport(to_location)
1208
1206
        try:
1209
 
            to_transport.mkdir('.')
1210
 
        except errors.FileExists:
1211
 
            if not use_existing_dir:
1212
 
                raise errors.BzrCommandError('Target directory "%s" '
1213
 
                    'already exists.' % to_location)
 
1207
            if revision is not None:
 
1208
                revision_id = revision.as_revision_id(br_from)
1214
1209
            else:
1215
 
                try:
1216
 
                    bzrdir.BzrDir.open_from_transport(to_transport)
1217
 
                except errors.NotBranchError:
1218
 
                    pass
 
1210
                # FIXME - wt.last_revision, fallback to branch, fall back to
 
1211
                # None or perhaps NULL_REVISION to mean copy nothing
 
1212
                # RBC 20060209
 
1213
                revision_id = br_from.last_revision()
 
1214
            if to_location is None:
 
1215
                to_location = urlutils.derive_to_location(from_location)
 
1216
            to_transport = transport.get_transport(to_location)
 
1217
            try:
 
1218
                to_transport.mkdir('.')
 
1219
            except errors.FileExists:
 
1220
                if not use_existing_dir:
 
1221
                    raise errors.BzrCommandError('Target directory "%s" '
 
1222
                        'already exists.' % to_location)
1219
1223
                else:
1220
 
                    raise errors.AlreadyBranchError(to_location)
1221
 
        except errors.NoSuchFile:
1222
 
            raise errors.BzrCommandError('Parent of "%s" does not exist.'
1223
 
                                         % to_location)
1224
 
        try:
1225
 
            # preserve whatever source format we have.
1226
 
            dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1227
 
                                        possible_transports=[to_transport],
1228
 
                                        accelerator_tree=accelerator_tree,
1229
 
                                        hardlink=hardlink, stacked=stacked,
1230
 
                                        force_new_repo=standalone,
1231
 
                                        create_tree_if_local=not no_tree,
1232
 
                                        source_branch=br_from)
1233
 
            branch = dir.open_branch()
1234
 
        except errors.NoSuchRevision:
1235
 
            to_transport.delete_tree('.')
1236
 
            msg = "The branch %s has no revision %s." % (from_location,
1237
 
                revision)
1238
 
            raise errors.BzrCommandError(msg)
1239
 
        _merge_tags_if_possible(br_from, branch)
1240
 
        # If the source branch is stacked, the new branch may
1241
 
        # be stacked whether we asked for that explicitly or not.
1242
 
        # We therefore need a try/except here and not just 'if stacked:'
1243
 
        try:
1244
 
            note('Created new stacked branch referring to %s.' %
1245
 
                branch.get_stacked_on_url())
1246
 
        except (errors.NotStacked, errors.UnstackableBranchFormat,
1247
 
            errors.UnstackableRepositoryFormat), e:
1248
 
            note('Branched %d revision(s).' % branch.revno())
1249
 
        if bind:
1250
 
            # Bind to the parent
1251
 
            parent_branch = Branch.open(from_location)
1252
 
            branch.bind(parent_branch)
1253
 
            note('New branch bound to %s' % from_location)
1254
 
        if switch:
1255
 
            # Switch to the new branch
1256
 
            wt, _ = WorkingTree.open_containing('.')
1257
 
            _mod_switch.switch(wt.bzrdir, branch)
1258
 
            note('Switched to branch: %s',
1259
 
                urlutils.unescape_for_display(branch.base, 'utf-8'))
 
1224
                    try:
 
1225
                        bzrdir.BzrDir.open_from_transport(to_transport)
 
1226
                    except errors.NotBranchError:
 
1227
                        pass
 
1228
                    else:
 
1229
                        raise errors.AlreadyBranchError(to_location)
 
1230
            except errors.NoSuchFile:
 
1231
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1232
                                             % to_location)
 
1233
            try:
 
1234
                # preserve whatever source format we have.
 
1235
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1236
                                            possible_transports=[to_transport],
 
1237
                                            accelerator_tree=accelerator_tree,
 
1238
                                            hardlink=hardlink, stacked=stacked,
 
1239
                                            force_new_repo=standalone,
 
1240
                                            create_tree_if_local=not no_tree,
 
1241
                                            source_branch=br_from)
 
1242
                branch = dir.open_branch()
 
1243
            except errors.NoSuchRevision:
 
1244
                to_transport.delete_tree('.')
 
1245
                msg = "The branch %s has no revision %s." % (from_location,
 
1246
                    revision)
 
1247
                raise errors.BzrCommandError(msg)
 
1248
            _merge_tags_if_possible(br_from, branch)
 
1249
            # If the source branch is stacked, the new branch may
 
1250
            # be stacked whether we asked for that explicitly or not.
 
1251
            # We therefore need a try/except here and not just 'if stacked:'
 
1252
            try:
 
1253
                note('Created new stacked branch referring to %s.' %
 
1254
                    branch.get_stacked_on_url())
 
1255
            except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1256
                errors.UnstackableRepositoryFormat), e:
 
1257
                note('Branched %d revision(s).' % branch.revno())
 
1258
            if switch:
 
1259
                # Switch to the new branch
 
1260
                wt, _ = WorkingTree.open_containing('.')
 
1261
                _mod_switch.switch(wt.bzrdir, branch)
 
1262
                note('Switched to branch: %s',
 
1263
                    urlutils.unescape_for_display(branch.base, 'utf-8'))
 
1264
        finally:
 
1265
            br_from.unlock()
1260
1266
 
1261
1267
 
1262
1268
class cmd_checkout(Command):
1341
1347
    def run(self, dir=u'.'):
1342
1348
        tree = WorkingTree.open_containing(dir)[0]
1343
1349
        tree.lock_read()
1344
 
        self.add_cleanup(tree.unlock)
1345
 
        new_inv = tree.inventory
1346
 
        old_tree = tree.basis_tree()
1347
 
        old_tree.lock_read()
1348
 
        self.add_cleanup(old_tree.unlock)
1349
 
        old_inv = old_tree.inventory
1350
 
        renames = []
1351
 
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1352
 
        for f, paths, c, v, p, n, k, e in iterator:
1353
 
            if paths[0] == paths[1]:
1354
 
                continue
1355
 
            if None in (paths):
1356
 
                continue
1357
 
            renames.append(paths)
1358
 
        renames.sort()
1359
 
        for old_name, new_name in renames:
1360
 
            self.outf.write("%s => %s\n" % (old_name, new_name))
 
1350
        try:
 
1351
            new_inv = tree.inventory
 
1352
            old_tree = tree.basis_tree()
 
1353
            old_tree.lock_read()
 
1354
            try:
 
1355
                old_inv = old_tree.inventory
 
1356
                renames = []
 
1357
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1358
                for f, paths, c, v, p, n, k, e in iterator:
 
1359
                    if paths[0] == paths[1]:
 
1360
                        continue
 
1361
                    if None in (paths):
 
1362
                        continue
 
1363
                    renames.append(paths)
 
1364
                renames.sort()
 
1365
                for old_name, new_name in renames:
 
1366
                    self.outf.write("%s => %s\n" % (old_name, new_name))
 
1367
            finally:
 
1368
                old_tree.unlock()
 
1369
        finally:
 
1370
            tree.unlock()
1361
1371
 
1362
1372
 
1363
1373
class cmd_update(Command):
1369
1379
 
1370
1380
    If you want to discard your local changes, you can just do a
1371
1381
    'bzr revert' instead of 'bzr commit' after the update.
1372
 
 
1373
 
    If the tree's branch is bound to a master branch, it will also update
1374
 
    the branch from the master.
1375
1382
    """
1376
1383
 
1377
1384
    _see_also = ['pull', 'working-trees', 'status-flags']
1378
1385
    takes_args = ['dir?']
1379
 
    takes_options = ['revision']
1380
1386
    aliases = ['up']
1381
1387
 
1382
 
    def run(self, dir='.', revision=None):
1383
 
        if revision is not None and len(revision) != 1:
1384
 
            raise errors.BzrCommandError(
1385
 
                        "bzr update --revision takes exactly one revision")
 
1388
    def run(self, dir='.'):
1386
1389
        tree = WorkingTree.open_containing(dir)[0]
1387
 
        branch = tree.branch
1388
1390
        possible_transports = []
1389
 
        master = branch.get_master_branch(
 
1391
        master = tree.branch.get_master_branch(
1390
1392
            possible_transports=possible_transports)
1391
1393
        if master is not None:
1392
1394
            tree.lock_write()
1393
 
            branch_location = master.base
1394
1395
        else:
1395
1396
            tree.lock_tree_write()
1396
 
            branch_location = tree.branch.base
1397
 
        self.add_cleanup(tree.unlock)
1398
 
        # get rid of the final '/' and be ready for display
1399
 
        branch_location = urlutils.unescape_for_display(branch_location[:-1],
1400
 
                                                        self.outf.encoding)
1401
 
        existing_pending_merges = tree.get_parent_ids()[1:]
1402
 
        if master is None:
1403
 
            old_tip = None
1404
 
        else:
1405
 
            # may need to fetch data into a heavyweight checkout
1406
 
            # XXX: this may take some time, maybe we should display a
1407
 
            # message
1408
 
            old_tip = branch.update(possible_transports)
1409
 
        if revision is not None:
1410
 
            revision_id = revision[0].as_revision_id(branch)
1411
 
        else:
1412
 
            revision_id = branch.last_revision()
1413
 
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
1414
 
            revno = branch.revision_id_to_revno(revision_id)
1415
 
            note("Tree is up to date at revision %d of branch %s" %
1416
 
                (revno, branch_location))
1417
 
            return 0
1418
 
        view_info = _get_view_info_for_change_reporter(tree)
1419
 
        change_reporter = delta._ChangeReporter(
1420
 
            unversioned_filter=tree.is_ignored,
1421
 
            view_info=view_info)
1422
1397
        try:
 
1398
            existing_pending_merges = tree.get_parent_ids()[1:]
 
1399
            last_rev = _mod_revision.ensure_null(tree.last_revision())
 
1400
            if last_rev == _mod_revision.ensure_null(
 
1401
                tree.branch.last_revision()):
 
1402
                # may be up to date, check master too.
 
1403
                if master is None or last_rev == _mod_revision.ensure_null(
 
1404
                    master.last_revision()):
 
1405
                    revno = tree.branch.revision_id_to_revno(last_rev)
 
1406
                    note("Tree is up to date at revision %d." % (revno,))
 
1407
                    return 0
 
1408
            view_info = _get_view_info_for_change_reporter(tree)
1423
1409
            conflicts = tree.update(
1424
 
                change_reporter,
1425
 
                possible_transports=possible_transports,
1426
 
                revision=revision_id,
1427
 
                old_tip=old_tip)
1428
 
        except errors.NoSuchRevision, e:
1429
 
            raise errors.BzrCommandError(
1430
 
                                  "branch has no revision %s\n"
1431
 
                                  "bzr update --revision only works"
1432
 
                                  " for a revision in the branch history"
1433
 
                                  % (e.revision))
1434
 
        revno = tree.branch.revision_id_to_revno(
1435
 
            _mod_revision.ensure_null(tree.last_revision()))
1436
 
        note('Updated to revision %d of branch %s' %
1437
 
             (revno, branch_location))
1438
 
        if tree.get_parent_ids()[1:] != existing_pending_merges:
1439
 
            note('Your local commits will now show as pending merges with '
1440
 
                 "'bzr status', and can be committed with 'bzr commit'.")
1441
 
        if conflicts != 0:
1442
 
            return 1
1443
 
        else:
1444
 
            return 0
 
1410
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
 
1411
                view_info=view_info), possible_transports=possible_transports)
 
1412
            revno = tree.branch.revision_id_to_revno(
 
1413
                _mod_revision.ensure_null(tree.last_revision()))
 
1414
            note('Updated to revision %d.' % (revno,))
 
1415
            if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1416
                note('Your local commits will now show as pending merges with '
 
1417
                     "'bzr status', and can be committed with 'bzr commit'.")
 
1418
            if conflicts != 0:
 
1419
                return 1
 
1420
            else:
 
1421
                return 0
 
1422
        finally:
 
1423
            tree.unlock()
1445
1424
 
1446
1425
 
1447
1426
class cmd_info(Command):
1518
1497
            file_list = [f for f in file_list]
1519
1498
 
1520
1499
        tree.lock_write()
1521
 
        self.add_cleanup(tree.unlock)
1522
 
        # Heuristics should probably all move into tree.remove_smart or
1523
 
        # some such?
1524
 
        if new:
1525
 
            added = tree.changes_from(tree.basis_tree(),
1526
 
                specific_files=file_list).added
1527
 
            file_list = sorted([f[0] for f in added], reverse=True)
1528
 
            if len(file_list) == 0:
1529
 
                raise errors.BzrCommandError('No matching files.')
1530
 
        elif file_list is None:
1531
 
            # missing files show up in iter_changes(basis) as
1532
 
            # versioned-with-no-kind.
1533
 
            missing = []
1534
 
            for change in tree.iter_changes(tree.basis_tree()):
1535
 
                # Find paths in the working tree that have no kind:
1536
 
                if change[1][1] is not None and change[6][1] is None:
1537
 
                    missing.append(change[1][1])
1538
 
            file_list = sorted(missing, reverse=True)
1539
 
            file_deletion_strategy = 'keep'
1540
 
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1541
 
            keep_files=file_deletion_strategy=='keep',
1542
 
            force=file_deletion_strategy=='force')
 
1500
        try:
 
1501
            # Heuristics should probably all move into tree.remove_smart or
 
1502
            # some such?
 
1503
            if new:
 
1504
                added = tree.changes_from(tree.basis_tree(),
 
1505
                    specific_files=file_list).added
 
1506
                file_list = sorted([f[0] for f in added], reverse=True)
 
1507
                if len(file_list) == 0:
 
1508
                    raise errors.BzrCommandError('No matching files.')
 
1509
            elif file_list is None:
 
1510
                # missing files show up in iter_changes(basis) as
 
1511
                # versioned-with-no-kind.
 
1512
                missing = []
 
1513
                for change in tree.iter_changes(tree.basis_tree()):
 
1514
                    # Find paths in the working tree that have no kind:
 
1515
                    if change[1][1] is not None and change[6][1] is None:
 
1516
                        missing.append(change[1][1])
 
1517
                file_list = sorted(missing, reverse=True)
 
1518
                file_deletion_strategy = 'keep'
 
1519
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1520
                keep_files=file_deletion_strategy=='keep',
 
1521
                force=file_deletion_strategy=='force')
 
1522
        finally:
 
1523
            tree.unlock()
1543
1524
 
1544
1525
 
1545
1526
class cmd_file_id(Command):
1765
1746
 
1766
1747
 
1767
1748
class cmd_init_repository(Command):
1768
 
    """Create a shared repository for branches to share storage space.
 
1749
    """Create a shared repository to hold branches.
1769
1750
 
1770
1751
    New branches created under the repository directory will store their
1771
 
    revisions in the repository, not in the branch directory.  For branches
1772
 
    with shared history, this reduces the amount of storage needed and 
1773
 
    speeds up the creation of new branches.
 
1752
    revisions in the repository, not in the branch directory.
1774
1753
 
1775
 
    If the --no-trees option is given then the branches in the repository
1776
 
    will not have working trees by default.  They will still exist as 
1777
 
    directories on disk, but they will not have separate copies of the 
1778
 
    files at a certain revision.  This can be useful for repositories that
1779
 
    store branches which are interacted with through checkouts or remote
1780
 
    branches, such as on a server.
 
1754
    If the --no-trees option is used then the branches in the repository
 
1755
    will not have working trees by default.
1781
1756
 
1782
1757
    :Examples:
1783
 
        Create a shared repository holding just branches::
 
1758
        Create a shared repositories holding just branches::
1784
1759
 
1785
1760
            bzr init-repo --no-trees repo
1786
1761
            bzr init repo/trunk
1852
1827
 
1853
1828
            bzr diff -r1
1854
1829
 
1855
 
        Difference between revision 3 and revision 1::
1856
 
 
1857
 
            bzr diff -r1..3
1858
 
 
1859
 
        Difference between revision 3 and revision 1 for branch xxx::
1860
 
 
1861
 
            bzr diff -r1..3 xxx
1862
 
 
1863
 
        To see the changes introduced in revision X::
1864
 
        
1865
 
            bzr diff -cX
1866
 
 
1867
 
        Note that in the case of a merge, the -c option shows the changes
1868
 
        compared to the left hand parent. To see the changes against
1869
 
        another parent, use::
1870
 
 
1871
 
            bzr diff -r<chosen_parent>..X
1872
 
 
1873
 
        The changes introduced by revision 2 (equivalent to -r1..2)::
1874
 
 
1875
 
            bzr diff -c2
 
1830
        Difference between revision 2 and revision 1::
 
1831
 
 
1832
            bzr diff -r1..2
 
1833
 
 
1834
        Difference between revision 2 and revision 1 for branch xxx::
 
1835
 
 
1836
            bzr diff -r1..2 xxx
1876
1837
 
1877
1838
        Show just the differences for file NEWS::
1878
1839
 
1971
1932
    def run(self, show_ids=False):
1972
1933
        tree = WorkingTree.open_containing(u'.')[0]
1973
1934
        tree.lock_read()
1974
 
        self.add_cleanup(tree.unlock)
1975
 
        old = tree.basis_tree()
1976
 
        old.lock_read()
1977
 
        self.add_cleanup(old.unlock)
1978
 
        for path, ie in old.inventory.iter_entries():
1979
 
            if not tree.has_id(ie.file_id):
1980
 
                self.outf.write(path)
1981
 
                if show_ids:
1982
 
                    self.outf.write(' ')
1983
 
                    self.outf.write(ie.file_id)
1984
 
                self.outf.write('\n')
 
1935
        try:
 
1936
            old = tree.basis_tree()
 
1937
            old.lock_read()
 
1938
            try:
 
1939
                for path, ie in old.inventory.iter_entries():
 
1940
                    if not tree.has_id(ie.file_id):
 
1941
                        self.outf.write(path)
 
1942
                        if show_ids:
 
1943
                            self.outf.write(' ')
 
1944
                            self.outf.write(ie.file_id)
 
1945
                        self.outf.write('\n')
 
1946
            finally:
 
1947
                old.unlock()
 
1948
        finally:
 
1949
            tree.unlock()
1985
1950
 
1986
1951
 
1987
1952
class cmd_modified(Command):
2023
1988
    def run(self, null=False):
2024
1989
        wt = WorkingTree.open_containing(u'.')[0]
2025
1990
        wt.lock_read()
2026
 
        self.add_cleanup(wt.unlock)
2027
 
        basis = wt.basis_tree()
2028
 
        basis.lock_read()
2029
 
        self.add_cleanup(basis.unlock)
2030
 
        basis_inv = basis.inventory
2031
 
        inv = wt.inventory
2032
 
        for file_id in inv:
2033
 
            if file_id in basis_inv:
2034
 
                continue
2035
 
            if inv.is_root(file_id) and len(basis_inv) == 0:
2036
 
                continue
2037
 
            path = inv.id2path(file_id)
2038
 
            if not os.access(osutils.abspath(path), os.F_OK):
2039
 
                continue
2040
 
            if null:
2041
 
                self.outf.write(path + '\0')
2042
 
            else:
2043
 
                self.outf.write(osutils.quotefn(path) + '\n')
 
1991
        try:
 
1992
            basis = wt.basis_tree()
 
1993
            basis.lock_read()
 
1994
            try:
 
1995
                basis_inv = basis.inventory
 
1996
                inv = wt.inventory
 
1997
                for file_id in inv:
 
1998
                    if file_id in basis_inv:
 
1999
                        continue
 
2000
                    if inv.is_root(file_id) and len(basis_inv) == 0:
 
2001
                        continue
 
2002
                    path = inv.id2path(file_id)
 
2003
                    if not os.access(osutils.abspath(path), os.F_OK):
 
2004
                        continue
 
2005
                    if null:
 
2006
                        self.outf.write(path + '\0')
 
2007
                    else:
 
2008
                        self.outf.write(osutils.quotefn(path) + '\n')
 
2009
            finally:
 
2010
                basis.unlock()
 
2011
        finally:
 
2012
            wt.unlock()
2044
2013
 
2045
2014
 
2046
2015
class cmd_root(Command):
2191
2160
    :Tips & tricks:
2192
2161
 
2193
2162
      GUI tools and IDEs are often better at exploring history than command
2194
 
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
2195
 
      bzr-explorer shell, or the Loggerhead web interface.  See the Plugin
2196
 
      Guide <http://doc.bazaar.canonical.com/plugins/en/> and
2197
 
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
 
2163
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
 
2164
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
 
2165
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
 
2166
 
 
2167
      Web interfaces are often better at exploring history than command line
 
2168
      tools, particularly for branches on servers. You may prefer Loggerhead
 
2169
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
2198
2170
 
2199
2171
      You may find it useful to add the aliases below to ``bazaar.conf``::
2200
2172
 
2303
2275
        filter_by_dir = False
2304
2276
        if file_list:
2305
2277
            # find the file ids to log and check for directory filtering
2306
 
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2307
 
                revision, file_list)
2308
 
            self.add_cleanup(b.unlock)
 
2278
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
 
2279
                file_list)
2309
2280
            for relpath, file_id, kind in file_info_list:
2310
2281
                if file_id is None:
2311
2282
                    raise errors.BzrCommandError(
2329
2300
                location = '.'
2330
2301
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2331
2302
            b = dir.open_branch()
2332
 
            b.lock_read()
2333
 
            self.add_cleanup(b.unlock)
2334
2303
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2335
2304
 
2336
2305
        # Decide on the type of delta & diff filtering to use
2346
2315
        else:
2347
2316
            diff_type = 'full'
2348
2317
 
2349
 
        # Build the log formatter
2350
 
        if log_format is None:
2351
 
            log_format = log.log_formatter_registry.get_default(b)
2352
 
        # Make a non-encoding output to include the diffs - bug 328007
2353
 
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
2354
 
        lf = log_format(show_ids=show_ids, to_file=self.outf,
2355
 
                        to_exact_file=unencoded_output,
2356
 
                        show_timezone=timezone,
2357
 
                        delta_format=get_verbosity_level(),
2358
 
                        levels=levels,
2359
 
                        show_advice=levels is None)
2360
 
 
2361
 
        # Choose the algorithm for doing the logging. It's annoying
2362
 
        # having multiple code paths like this but necessary until
2363
 
        # the underlying repository format is faster at generating
2364
 
        # deltas or can provide everything we need from the indices.
2365
 
        # The default algorithm - match-using-deltas - works for
2366
 
        # multiple files and directories and is faster for small
2367
 
        # amounts of history (200 revisions say). However, it's too
2368
 
        # slow for logging a single file in a repository with deep
2369
 
        # history, i.e. > 10K revisions. In the spirit of "do no
2370
 
        # evil when adding features", we continue to use the
2371
 
        # original algorithm - per-file-graph - for the "single
2372
 
        # file that isn't a directory without showing a delta" case.
2373
 
        partial_history = revision and b.repository._format.supports_chks
2374
 
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2375
 
            or delta_type or partial_history)
2376
 
 
2377
 
        # Build the LogRequest and execute it
2378
 
        if len(file_ids) == 0:
2379
 
            file_ids = None
2380
 
        rqst = make_log_request_dict(
2381
 
            direction=direction, specific_fileids=file_ids,
2382
 
            start_revision=rev1, end_revision=rev2, limit=limit,
2383
 
            message_search=message, delta_type=delta_type,
2384
 
            diff_type=diff_type, _match_using_deltas=match_using_deltas)
2385
 
        Logger(b, rqst).show(lf)
 
2318
        b.lock_read()
 
2319
        try:
 
2320
            # Build the log formatter
 
2321
            if log_format is None:
 
2322
                log_format = log.log_formatter_registry.get_default(b)
 
2323
            lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2324
                            show_timezone=timezone,
 
2325
                            delta_format=get_verbosity_level(),
 
2326
                            levels=levels,
 
2327
                            show_advice=levels is None)
 
2328
 
 
2329
            # Choose the algorithm for doing the logging. It's annoying
 
2330
            # having multiple code paths like this but necessary until
 
2331
            # the underlying repository format is faster at generating
 
2332
            # deltas or can provide everything we need from the indices.
 
2333
            # The default algorithm - match-using-deltas - works for
 
2334
            # multiple files and directories and is faster for small
 
2335
            # amounts of history (200 revisions say). However, it's too
 
2336
            # slow for logging a single file in a repository with deep
 
2337
            # history, i.e. > 10K revisions. In the spirit of "do no
 
2338
            # evil when adding features", we continue to use the
 
2339
            # original algorithm - per-file-graph - for the "single
 
2340
            # file that isn't a directory without showing a delta" case.
 
2341
            partial_history = revision and b.repository._format.supports_chks
 
2342
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2343
                or delta_type or partial_history)
 
2344
 
 
2345
            # Build the LogRequest and execute it
 
2346
            if len(file_ids) == 0:
 
2347
                file_ids = None
 
2348
            rqst = make_log_request_dict(
 
2349
                direction=direction, specific_fileids=file_ids,
 
2350
                start_revision=rev1, end_revision=rev2, limit=limit,
 
2351
                message_search=message, delta_type=delta_type,
 
2352
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2353
            Logger(b, rqst).show(lf)
 
2354
        finally:
 
2355
            b.unlock()
2386
2356
 
2387
2357
 
2388
2358
def _get_revision_range(revisionspec_list, branch, command_name):
2452
2422
    @display_command
2453
2423
    def run(self, filename):
2454
2424
        tree, relpath = WorkingTree.open_containing(filename)
 
2425
        b = tree.branch
2455
2426
        file_id = tree.path2id(relpath)
2456
 
        b = tree.branch
2457
 
        b.lock_read()
2458
 
        self.add_cleanup(b.unlock)
2459
 
        touching_revs = log.find_touching_revisions(b, file_id)
2460
 
        for revno, revision_id, what in touching_revs:
 
2427
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
2461
2428
            self.outf.write("%6d %s\n" % (revno, what))
2462
2429
 
2463
2430
 
2516
2483
        if from_root:
2517
2484
            if relpath:
2518
2485
                prefix = relpath + '/'
2519
 
        elif fs_path != '.' and not fs_path.endswith('/'):
 
2486
        elif fs_path != '.':
2520
2487
            prefix = fs_path + '/'
2521
2488
 
2522
2489
        if revision is not None or tree is None:
2531
2498
                note("Ignoring files outside view. View is %s" % view_str)
2532
2499
 
2533
2500
        tree.lock_read()
2534
 
        self.add_cleanup(tree.unlock)
2535
 
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2536
 
            from_dir=relpath, recursive=recursive):
2537
 
            # Apply additional masking
2538
 
            if not all and not selection[fc]:
2539
 
                continue
2540
 
            if kind is not None and fkind != kind:
2541
 
                continue
2542
 
            if apply_view:
2543
 
                try:
2544
 
                    if relpath:
2545
 
                        fullpath = osutils.pathjoin(relpath, fp)
2546
 
                    else:
2547
 
                        fullpath = fp
2548
 
                    views.check_path_in_view(tree, fullpath)
2549
 
                except errors.FileOutsideView:
2550
 
                    continue
 
2501
        try:
 
2502
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2503
                from_dir=relpath, recursive=recursive):
 
2504
                # Apply additional masking
 
2505
                if not all and not selection[fc]:
 
2506
                    continue
 
2507
                if kind is not None and fkind != kind:
 
2508
                    continue
 
2509
                if apply_view:
 
2510
                    try:
 
2511
                        if relpath:
 
2512
                            fullpath = osutils.pathjoin(relpath, fp)
 
2513
                        else:
 
2514
                            fullpath = fp
 
2515
                        views.check_path_in_view(tree, fullpath)
 
2516
                    except errors.FileOutsideView:
 
2517
                        continue
2551
2518
 
2552
 
            # Output the entry
2553
 
            if prefix:
2554
 
                fp = osutils.pathjoin(prefix, fp)
2555
 
            kindch = entry.kind_character()
2556
 
            outstring = fp + kindch
2557
 
            ui.ui_factory.clear_term()
2558
 
            if verbose:
2559
 
                outstring = '%-8s %s' % (fc, outstring)
2560
 
                if show_ids and fid is not None:
2561
 
                    outstring = "%-50s %s" % (outstring, fid)
2562
 
                self.outf.write(outstring + '\n')
2563
 
            elif null:
2564
 
                self.outf.write(fp + '\0')
2565
 
                if show_ids:
2566
 
                    if fid is not None:
2567
 
                        self.outf.write(fid)
2568
 
                    self.outf.write('\0')
2569
 
                self.outf.flush()
2570
 
            else:
2571
 
                if show_ids:
2572
 
                    if fid is not None:
2573
 
                        my_id = fid
2574
 
                    else:
2575
 
                        my_id = ''
2576
 
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
2577
 
                else:
 
2519
                # Output the entry
 
2520
                if prefix:
 
2521
                    fp = osutils.pathjoin(prefix, fp)
 
2522
                kindch = entry.kind_character()
 
2523
                outstring = fp + kindch
 
2524
                ui.ui_factory.clear_term()
 
2525
                if verbose:
 
2526
                    outstring = '%-8s %s' % (fc, outstring)
 
2527
                    if show_ids and fid is not None:
 
2528
                        outstring = "%-50s %s" % (outstring, fid)
2578
2529
                    self.outf.write(outstring + '\n')
 
2530
                elif null:
 
2531
                    self.outf.write(fp + '\0')
 
2532
                    if show_ids:
 
2533
                        if fid is not None:
 
2534
                            self.outf.write(fid)
 
2535
                        self.outf.write('\0')
 
2536
                    self.outf.flush()
 
2537
                else:
 
2538
                    if show_ids:
 
2539
                        if fid is not None:
 
2540
                            my_id = fid
 
2541
                        else:
 
2542
                            my_id = ''
 
2543
                        self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2544
                    else:
 
2545
                        self.outf.write(outstring + '\n')
 
2546
        finally:
 
2547
            tree.unlock()
2579
2548
 
2580
2549
 
2581
2550
class cmd_unknowns(Command):
2596
2565
 
2597
2566
    See ``bzr help patterns`` for details on the syntax of patterns.
2598
2567
 
2599
 
    If a .bzrignore file does not exist, the ignore command
2600
 
    will create one and add the specified files or patterns to the newly
2601
 
    created file. The ignore command will also automatically add the 
2602
 
    .bzrignore file to be versioned. Creating a .bzrignore file without
2603
 
    the use of the ignore command will require an explicit add command.
2604
 
 
2605
2568
    To remove patterns from the ignore list, edit the .bzrignore file.
2606
2569
    After adding, editing or deleting that file either indirectly by
2607
2570
    using this command or directly by using an editor, be sure to commit
2608
2571
    it.
2609
 
    
2610
 
    Patterns prefixed with '!' are exceptions to ignore patterns and take
2611
 
    precedence over regular ignores.  Such exceptions are used to specify
2612
 
    files that should be versioned which would otherwise be ignored.
2613
 
    
2614
 
    Patterns prefixed with '!!' act as regular ignore patterns, but have
2615
 
    precedence over the '!' exception patterns.
2616
2572
 
2617
2573
    Note: ignore patterns containing shell wildcards must be quoted from
2618
2574
    the shell on Unix.
2622
2578
 
2623
2579
            bzr ignore ./Makefile
2624
2580
 
2625
 
        Ignore .class files in all directories...::
 
2581
        Ignore class files in all directories::
2626
2582
 
2627
2583
            bzr ignore "*.class"
2628
2584
 
2629
 
        ...but do not ignore "special.class"::
2630
 
 
2631
 
            bzr ignore "!special.class"
2632
 
 
2633
2585
        Ignore .o files under the lib directory::
2634
2586
 
2635
2587
            bzr ignore "lib/**/*.o"
2641
2593
        Ignore everything but the "debian" toplevel directory::
2642
2594
 
2643
2595
            bzr ignore "RE:(?!debian/).*"
2644
 
        
2645
 
        Ignore everything except the "local" toplevel directory,
2646
 
        but always ignore "*~" autosave files, even under local/::
2647
 
        
2648
 
            bzr ignore "*"
2649
 
            bzr ignore "!./local"
2650
 
            bzr ignore "!!*~"
2651
2596
    """
2652
2597
 
2653
2598
    _see_also = ['status', 'ignored', 'patterns']
2711
2656
    def run(self):
2712
2657
        tree = WorkingTree.open_containing(u'.')[0]
2713
2658
        tree.lock_read()
2714
 
        self.add_cleanup(tree.unlock)
2715
 
        for path, file_class, kind, file_id, entry in tree.list_files():
2716
 
            if file_class != 'I':
2717
 
                continue
2718
 
            ## XXX: Slightly inefficient since this was already calculated
2719
 
            pat = tree.is_ignored(path)
2720
 
            self.outf.write('%-50s %s\n' % (path, pat))
 
2659
        try:
 
2660
            for path, file_class, kind, file_id, entry in tree.list_files():
 
2661
                if file_class != 'I':
 
2662
                    continue
 
2663
                ## XXX: Slightly inefficient since this was already calculated
 
2664
                pat = tree.is_ignored(path)
 
2665
                self.outf.write('%-50s %s\n' % (path, pat))
 
2666
        finally:
 
2667
            tree.unlock()
2721
2668
 
2722
2669
 
2723
2670
class cmd_lookup_revision(Command):
2826
2773
        tree, branch, relpath = \
2827
2774
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2828
2775
        branch.lock_read()
2829
 
        self.add_cleanup(branch.unlock)
2830
 
        return self._run(tree, branch, relpath, filename, revision,
2831
 
                         name_from_revision, filters)
 
2776
        try:
 
2777
            return self._run(tree, branch, relpath, filename, revision,
 
2778
                             name_from_revision, filters)
 
2779
        finally:
 
2780
            branch.unlock()
2832
2781
 
2833
2782
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
2834
2783
        filtered):
2835
2784
        if tree is None:
2836
2785
            tree = b.basis_tree()
2837
2786
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2838
 
        rev_tree.lock_read()
2839
 
        self.add_cleanup(rev_tree.unlock)
2840
2787
 
2841
2788
        old_file_id = rev_tree.path2id(relpath)
2842
2789
 
2877
2824
            chunks = content.splitlines(True)
2878
2825
            content = filtered_output_bytes(chunks, filters,
2879
2826
                ContentFilterContext(relpath, rev_tree))
2880
 
            self.cleanup_now()
2881
2827
            self.outf.writelines(content)
2882
2828
        else:
2883
 
            self.cleanup_now()
2884
2829
            self.outf.write(content)
2885
2830
 
2886
2831
 
2993
2938
             Option('strict',
2994
2939
                    help="Refuse to commit if there are unknown "
2995
2940
                    "files in the working tree."),
2996
 
             Option('commit-time', type=str,
2997
 
                    help="Manually set a commit time using commit date "
2998
 
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2999
2941
             ListOption('fixes', type=str,
3000
2942
                    help="Mark a bug as being fixed by this revision "
3001
2943
                         "(see \"bzr help bugs\")."),
3008
2950
                         "the master branch until a normal commit "
3009
2951
                         "is performed."
3010
2952
                    ),
3011
 
             Option('show-diff',
3012
 
                    help='When no message is supplied, show the diff along'
3013
 
                    ' with the status summary in the message editor.'),
 
2953
              Option('show-diff',
 
2954
                     help='When no message is supplied, show the diff along'
 
2955
                     ' with the status summary in the message editor.'),
3014
2956
             ]
3015
2957
    aliases = ['ci', 'checkin']
3016
2958
 
3035
2977
 
3036
2978
    def run(self, message=None, file=None, verbose=False, selected_list=None,
3037
2979
            unchanged=False, strict=False, local=False, fixes=None,
3038
 
            author=None, show_diff=False, exclude=None, commit_time=None):
 
2980
            author=None, show_diff=False, exclude=None):
3039
2981
        from bzrlib.errors import (
3040
2982
            PointlessCommit,
3041
2983
            ConflictsInTree,
3047
2989
            make_commit_message_template_encoded
3048
2990
        )
3049
2991
 
3050
 
        commit_stamp = offset = None
3051
 
        if commit_time is not None:
3052
 
            try:
3053
 
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
3054
 
            except ValueError, e:
3055
 
                raise errors.BzrCommandError(
3056
 
                    "Could not parse --commit-time: " + str(e))
3057
 
 
3058
2992
        # TODO: Need a blackbox test for invoking the external editor; may be
3059
2993
        # slightly problematic to run this cross-platform.
3060
2994
 
3080
3014
        if local and not tree.branch.get_bound_location():
3081
3015
            raise errors.LocalRequiresBoundBranch()
3082
3016
 
3083
 
        if message is not None:
3084
 
            try:
3085
 
                file_exists = osutils.lexists(message)
3086
 
            except UnicodeError:
3087
 
                # The commit message contains unicode characters that can't be
3088
 
                # represented in the filesystem encoding, so that can't be a
3089
 
                # file.
3090
 
                file_exists = False
3091
 
            if file_exists:
3092
 
                warning_msg = (
3093
 
                    'The commit message is a file name: "%(f)s".\n'
3094
 
                    '(use --file "%(f)s" to take commit message from that file)'
3095
 
                    % { 'f': message })
3096
 
                ui.ui_factory.show_warning(warning_msg)
3097
 
 
3098
3017
        def get_message(commit_obj):
3099
3018
            """Callback to get commit message"""
3100
3019
            my_message = message
3101
 
            if my_message is not None and '\r' in my_message:
3102
 
                my_message = my_message.replace('\r\n', '\n')
3103
 
                my_message = my_message.replace('\r', '\n')
3104
3020
            if my_message is None and not file:
3105
3021
                t = make_commit_message_template_encoded(tree,
3106
3022
                        selected_list, diff=show_diff,
3130
3046
                        specific_files=selected_list,
3131
3047
                        allow_pointless=unchanged, strict=strict, local=local,
3132
3048
                        reporter=None, verbose=verbose, revprops=properties,
3133
 
                        authors=author, timestamp=commit_stamp,
3134
 
                        timezone=offset,
 
3049
                        authors=author,
3135
3050
                        exclude=safe_relpath_files(tree, exclude))
3136
3051
        except PointlessCommit:
3137
3052
            # FIXME: This should really happen before the file is read in;
3547
3462
            verbose = not is_quiet()
3548
3463
            # TODO: should possibly lock the history file...
3549
3464
            benchfile = open(".perf_history", "at", buffering=1)
3550
 
            self.add_cleanup(benchfile.close)
3551
3465
        else:
3552
3466
            test_suite_factory = None
3553
3467
            benchfile = None
3554
 
        selftest_kwargs = {"verbose": verbose,
3555
 
                          "pattern": pattern,
3556
 
                          "stop_on_failure": one,
3557
 
                          "transport": transport,
3558
 
                          "test_suite_factory": test_suite_factory,
3559
 
                          "lsprof_timed": lsprof_timed,
3560
 
                          "lsprof_tests": lsprof_tests,
3561
 
                          "bench_history": benchfile,
3562
 
                          "matching_tests_first": first,
3563
 
                          "list_only": list_only,
3564
 
                          "random_seed": randomize,
3565
 
                          "exclude_pattern": exclude,
3566
 
                          "strict": strict,
3567
 
                          "load_list": load_list,
3568
 
                          "debug_flags": debugflag,
3569
 
                          "starting_with": starting_with
3570
 
                          }
3571
 
        selftest_kwargs.update(self.additional_selftest_args)
3572
 
        result = selftest(**selftest_kwargs)
 
3468
        try:
 
3469
            selftest_kwargs = {"verbose": verbose,
 
3470
                              "pattern": pattern,
 
3471
                              "stop_on_failure": one,
 
3472
                              "transport": transport,
 
3473
                              "test_suite_factory": test_suite_factory,
 
3474
                              "lsprof_timed": lsprof_timed,
 
3475
                              "lsprof_tests": lsprof_tests,
 
3476
                              "bench_history": benchfile,
 
3477
                              "matching_tests_first": first,
 
3478
                              "list_only": list_only,
 
3479
                              "random_seed": randomize,
 
3480
                              "exclude_pattern": exclude,
 
3481
                              "strict": strict,
 
3482
                              "load_list": load_list,
 
3483
                              "debug_flags": debugflag,
 
3484
                              "starting_with": starting_with
 
3485
                              }
 
3486
            selftest_kwargs.update(self.additional_selftest_args)
 
3487
            result = selftest(**selftest_kwargs)
 
3488
        finally:
 
3489
            if benchfile is not None:
 
3490
                benchfile.close()
3573
3491
        return int(not result)
3574
3492
 
3575
3493
 
3614
3532
        branch1 = Branch.open_containing(branch)[0]
3615
3533
        branch2 = Branch.open_containing(other)[0]
3616
3534
        branch1.lock_read()
3617
 
        self.add_cleanup(branch1.unlock)
3618
 
        branch2.lock_read()
3619
 
        self.add_cleanup(branch2.unlock)
3620
 
        last1 = ensure_null(branch1.last_revision())
3621
 
        last2 = ensure_null(branch2.last_revision())
3622
 
 
3623
 
        graph = branch1.repository.get_graph(branch2.repository)
3624
 
        base_rev_id = graph.find_unique_lca(last1, last2)
3625
 
 
3626
 
        print 'merge base is revision %s' % base_rev_id
 
3535
        try:
 
3536
            branch2.lock_read()
 
3537
            try:
 
3538
                last1 = ensure_null(branch1.last_revision())
 
3539
                last2 = ensure_null(branch2.last_revision())
 
3540
 
 
3541
                graph = branch1.repository.get_graph(branch2.repository)
 
3542
                base_rev_id = graph.find_unique_lca(last1, last2)
 
3543
 
 
3544
                print 'merge base is revision %s' % base_rev_id
 
3545
            finally:
 
3546
                branch2.unlock()
 
3547
        finally:
 
3548
            branch1.unlock()
3627
3549
 
3628
3550
 
3629
3551
class cmd_merge(Command):
3662
3584
    committed to record the result of the merge.
3663
3585
 
3664
3586
    merge refuses to run if there are any uncommitted changes, unless
3665
 
    --force is given. The --force option can also be used to create a
3666
 
    merge revision which has more than two parents.
3667
 
 
3668
 
    If one would like to merge changes from the working tree of the other
3669
 
    branch without merging any committed revisions, the --uncommitted option
3670
 
    can be given.
 
3587
    --force is given.
3671
3588
 
3672
3589
    To select only some changes to merge, use "merge -i", which will prompt
3673
3590
    you to apply each diff hunk and file change, similar to "shelve".
3685
3602
 
3686
3603
            bzr merge -r 81..82 ../bzr.dev
3687
3604
 
3688
 
        To apply a merge directive contained in /tmp/merge::
 
3605
        To apply a merge directive contained in /tmp/merge:
3689
3606
 
3690
3607
            bzr merge /tmp/merge
3691
 
 
3692
 
        To create a merge revision with three parents from two branches
3693
 
        feature1a and feature1b:
3694
 
 
3695
 
            bzr merge ../feature1a
3696
 
            bzr merge ../feature1b --force
3697
 
            bzr commit -m 'revision with three parents'
3698
3608
    """
3699
3609
 
3700
3610
    encoding_type = 'exact'
3758
3668
        view_info = _get_view_info_for_change_reporter(tree)
3759
3669
        change_reporter = delta._ChangeReporter(
3760
3670
            unversioned_filter=tree.is_ignored, view_info=view_info)
3761
 
        pb = ui.ui_factory.nested_progress_bar()
3762
 
        self.add_cleanup(pb.finished)
3763
 
        tree.lock_write()
3764
 
        self.add_cleanup(tree.unlock)
3765
 
        if location is not None:
3766
 
            try:
3767
 
                mergeable = bundle.read_mergeable_from_url(location,
3768
 
                    possible_transports=possible_transports)
3769
 
            except errors.NotABundle:
3770
 
                mergeable = None
 
3671
        cleanups = []
 
3672
        try:
 
3673
            pb = ui.ui_factory.nested_progress_bar()
 
3674
            cleanups.append(pb.finished)
 
3675
            tree.lock_write()
 
3676
            cleanups.append(tree.unlock)
 
3677
            if location is not None:
 
3678
                try:
 
3679
                    mergeable = bundle.read_mergeable_from_url(location,
 
3680
                        possible_transports=possible_transports)
 
3681
                except errors.NotABundle:
 
3682
                    mergeable = None
 
3683
                else:
 
3684
                    if uncommitted:
 
3685
                        raise errors.BzrCommandError('Cannot use --uncommitted'
 
3686
                            ' with bundles or merge directives.')
 
3687
 
 
3688
                    if revision is not None:
 
3689
                        raise errors.BzrCommandError(
 
3690
                            'Cannot use -r with merge directives or bundles')
 
3691
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3692
                       mergeable, pb)
 
3693
 
 
3694
            if merger is None and uncommitted:
 
3695
                if revision is not None and len(revision) > 0:
 
3696
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3697
                        ' --revision at the same time.')
 
3698
                merger = self.get_merger_from_uncommitted(tree, location, pb,
 
3699
                                                          cleanups)
 
3700
                allow_pending = False
 
3701
 
 
3702
            if merger is None:
 
3703
                merger, allow_pending = self._get_merger_from_branch(tree,
 
3704
                    location, revision, remember, possible_transports, pb)
 
3705
 
 
3706
            merger.merge_type = merge_type
 
3707
            merger.reprocess = reprocess
 
3708
            merger.show_base = show_base
 
3709
            self.sanity_check_merger(merger)
 
3710
            if (merger.base_rev_id == merger.other_rev_id and
 
3711
                merger.other_rev_id is not None):
 
3712
                note('Nothing to do.')
 
3713
                return 0
 
3714
            if pull:
 
3715
                if merger.interesting_files is not None:
 
3716
                    raise errors.BzrCommandError('Cannot pull individual files')
 
3717
                if (merger.base_rev_id == tree.last_revision()):
 
3718
                    result = tree.pull(merger.other_branch, False,
 
3719
                                       merger.other_rev_id)
 
3720
                    result.report(self.outf)
 
3721
                    return 0
 
3722
            if merger.this_basis is None:
 
3723
                raise errors.BzrCommandError(
 
3724
                    "This branch has no commits."
 
3725
                    " (perhaps you would prefer 'bzr pull')")
 
3726
            if preview:
 
3727
                return self._do_preview(merger, cleanups)
 
3728
            elif interactive:
 
3729
                return self._do_interactive(merger, cleanups)
3771
3730
            else:
3772
 
                if uncommitted:
3773
 
                    raise errors.BzrCommandError('Cannot use --uncommitted'
3774
 
                        ' with bundles or merge directives.')
3775
 
 
3776
 
                if revision is not None:
3777
 
                    raise errors.BzrCommandError(
3778
 
                        'Cannot use -r with merge directives or bundles')
3779
 
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
3780
 
                   mergeable, pb)
3781
 
 
3782
 
        if merger is None and uncommitted:
3783
 
            if revision is not None and len(revision) > 0:
3784
 
                raise errors.BzrCommandError('Cannot use --uncommitted and'
3785
 
                    ' --revision at the same time.')
3786
 
            merger = self.get_merger_from_uncommitted(tree, location, pb)
3787
 
            allow_pending = False
3788
 
 
3789
 
        if merger is None:
3790
 
            merger, allow_pending = self._get_merger_from_branch(tree,
3791
 
                location, revision, remember, possible_transports, pb)
3792
 
 
3793
 
        merger.merge_type = merge_type
3794
 
        merger.reprocess = reprocess
3795
 
        merger.show_base = show_base
3796
 
        self.sanity_check_merger(merger)
3797
 
        if (merger.base_rev_id == merger.other_rev_id and
3798
 
            merger.other_rev_id is not None):
3799
 
            note('Nothing to do.')
3800
 
            return 0
3801
 
        if pull:
3802
 
            if merger.interesting_files is not None:
3803
 
                raise errors.BzrCommandError('Cannot pull individual files')
3804
 
            if (merger.base_rev_id == tree.last_revision()):
3805
 
                result = tree.pull(merger.other_branch, False,
3806
 
                                   merger.other_rev_id)
3807
 
                result.report(self.outf)
3808
 
                return 0
3809
 
        if merger.this_basis is None:
3810
 
            raise errors.BzrCommandError(
3811
 
                "This branch has no commits."
3812
 
                " (perhaps you would prefer 'bzr pull')")
3813
 
        if preview:
3814
 
            return self._do_preview(merger)
3815
 
        elif interactive:
3816
 
            return self._do_interactive(merger)
3817
 
        else:
3818
 
            return self._do_merge(merger, change_reporter, allow_pending,
3819
 
                                  verified)
3820
 
 
3821
 
    def _get_preview(self, merger):
 
3731
                return self._do_merge(merger, change_reporter, allow_pending,
 
3732
                                      verified)
 
3733
        finally:
 
3734
            for cleanup in reversed(cleanups):
 
3735
                cleanup()
 
3736
 
 
3737
    def _get_preview(self, merger, cleanups):
3822
3738
        tree_merger = merger.make_merger()
3823
3739
        tt = tree_merger.make_preview_transform()
3824
 
        self.add_cleanup(tt.finalize)
 
3740
        cleanups.append(tt.finalize)
3825
3741
        result_tree = tt.get_preview_tree()
3826
3742
        return result_tree
3827
3743
 
3828
 
    def _do_preview(self, merger):
 
3744
    def _do_preview(self, merger, cleanups):
3829
3745
        from bzrlib.diff import show_diff_trees
3830
 
        result_tree = self._get_preview(merger)
 
3746
        result_tree = self._get_preview(merger, cleanups)
3831
3747
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3832
3748
                        old_label='', new_label='')
3833
3749
 
3843
3759
        else:
3844
3760
            return 0
3845
3761
 
3846
 
    def _do_interactive(self, merger):
 
3762
    def _do_interactive(self, merger, cleanups):
3847
3763
        """Perform an interactive merge.
3848
3764
 
3849
3765
        This works by generating a preview tree of the merge, then using
3851
3767
        and the preview tree.
3852
3768
        """
3853
3769
        from bzrlib import shelf_ui
3854
 
        result_tree = self._get_preview(merger)
 
3770
        result_tree = self._get_preview(merger, cleanups)
3855
3771
        writer = bzrlib.option.diff_writer_registry.get()
3856
3772
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
3857
3773
                                   reporter=shelf_ui.ApplyReporter(),
3858
3774
                                   diff_writer=writer(sys.stdout))
3859
 
        try:
3860
 
            shelver.run()
3861
 
        finally:
3862
 
            shelver.finalize()
 
3775
        shelver.run()
3863
3776
 
3864
3777
    def sanity_check_merger(self, merger):
3865
3778
        if (merger.show_base and
3925
3838
            allow_pending = True
3926
3839
        return merger, allow_pending
3927
3840
 
3928
 
    def get_merger_from_uncommitted(self, tree, location, pb):
 
3841
    def get_merger_from_uncommitted(self, tree, location, pb, cleanups):
3929
3842
        """Get a merger for uncommitted changes.
3930
3843
 
3931
3844
        :param tree: The tree the merger should apply to.
3932
3845
        :param location: The location containing uncommitted changes.
3933
3846
        :param pb: The progress bar to use for showing progress.
 
3847
        :param cleanups: A list of operations to perform to clean up the
 
3848
            temporary directories, unfinalized objects, etc.
3934
3849
        """
3935
3850
        location = self._select_branch_location(tree, location)[0]
3936
3851
        other_tree, other_path = WorkingTree.open_containing(location)
4023
3938
            merge_type = _mod_merge.Merge3Merger
4024
3939
        tree, file_list = tree_files(file_list)
4025
3940
        tree.lock_write()
4026
 
        self.add_cleanup(tree.unlock)
4027
 
        parents = tree.get_parent_ids()
4028
 
        if len(parents) != 2:
4029
 
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
4030
 
                                         " merges.  Not cherrypicking or"
4031
 
                                         " multi-merges.")
4032
 
        repository = tree.branch.repository
4033
 
        interesting_ids = None
4034
 
        new_conflicts = []
4035
 
        conflicts = tree.conflicts()
4036
 
        if file_list is not None:
4037
 
            interesting_ids = set()
4038
 
            for filename in file_list:
4039
 
                file_id = tree.path2id(filename)
4040
 
                if file_id is None:
4041
 
                    raise errors.NotVersionedError(filename)
4042
 
                interesting_ids.add(file_id)
4043
 
                if tree.kind(file_id) != "directory":
4044
 
                    continue
 
3941
        try:
 
3942
            parents = tree.get_parent_ids()
 
3943
            if len(parents) != 2:
 
3944
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
3945
                                             " merges.  Not cherrypicking or"
 
3946
                                             " multi-merges.")
 
3947
            repository = tree.branch.repository
 
3948
            interesting_ids = None
 
3949
            new_conflicts = []
 
3950
            conflicts = tree.conflicts()
 
3951
            if file_list is not None:
 
3952
                interesting_ids = set()
 
3953
                for filename in file_list:
 
3954
                    file_id = tree.path2id(filename)
 
3955
                    if file_id is None:
 
3956
                        raise errors.NotVersionedError(filename)
 
3957
                    interesting_ids.add(file_id)
 
3958
                    if tree.kind(file_id) != "directory":
 
3959
                        continue
4045
3960
 
4046
 
                for name, ie in tree.inventory.iter_entries(file_id):
4047
 
                    interesting_ids.add(ie.file_id)
4048
 
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4049
 
        else:
4050
 
            # Remerge only supports resolving contents conflicts
4051
 
            allowed_conflicts = ('text conflict', 'contents conflict')
4052
 
            restore_files = [c.path for c in conflicts
4053
 
                             if c.typestring in allowed_conflicts]
4054
 
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
4055
 
        tree.set_conflicts(ConflictList(new_conflicts))
4056
 
        if file_list is not None:
4057
 
            restore_files = file_list
4058
 
        for filename in restore_files:
 
3961
                    for name, ie in tree.inventory.iter_entries(file_id):
 
3962
                        interesting_ids.add(ie.file_id)
 
3963
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
3964
            else:
 
3965
                # Remerge only supports resolving contents conflicts
 
3966
                allowed_conflicts = ('text conflict', 'contents conflict')
 
3967
                restore_files = [c.path for c in conflicts
 
3968
                                 if c.typestring in allowed_conflicts]
 
3969
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
3970
            tree.set_conflicts(ConflictList(new_conflicts))
 
3971
            if file_list is not None:
 
3972
                restore_files = file_list
 
3973
            for filename in restore_files:
 
3974
                try:
 
3975
                    restore(tree.abspath(filename))
 
3976
                except errors.NotConflicted:
 
3977
                    pass
 
3978
            # Disable pending merges, because the file texts we are remerging
 
3979
            # have not had those merges performed.  If we use the wrong parents
 
3980
            # list, we imply that the working tree text has seen and rejected
 
3981
            # all the changes from the other tree, when in fact those changes
 
3982
            # have not yet been seen.
 
3983
            pb = ui.ui_factory.nested_progress_bar()
 
3984
            tree.set_parent_ids(parents[:1])
4059
3985
            try:
4060
 
                restore(tree.abspath(filename))
4061
 
            except errors.NotConflicted:
4062
 
                pass
4063
 
        # Disable pending merges, because the file texts we are remerging
4064
 
        # have not had those merges performed.  If we use the wrong parents
4065
 
        # list, we imply that the working tree text has seen and rejected
4066
 
        # all the changes from the other tree, when in fact those changes
4067
 
        # have not yet been seen.
4068
 
        pb = ui.ui_factory.nested_progress_bar()
4069
 
        tree.set_parent_ids(parents[:1])
4070
 
        try:
4071
 
            merger = _mod_merge.Merger.from_revision_ids(pb,
4072
 
                                                         tree, parents[1])
4073
 
            merger.interesting_ids = interesting_ids
4074
 
            merger.merge_type = merge_type
4075
 
            merger.show_base = show_base
4076
 
            merger.reprocess = reprocess
4077
 
            conflicts = merger.do_merge()
 
3986
                merger = _mod_merge.Merger.from_revision_ids(pb,
 
3987
                                                             tree, parents[1])
 
3988
                merger.interesting_ids = interesting_ids
 
3989
                merger.merge_type = merge_type
 
3990
                merger.show_base = show_base
 
3991
                merger.reprocess = reprocess
 
3992
                conflicts = merger.do_merge()
 
3993
            finally:
 
3994
                tree.set_parent_ids(parents)
 
3995
                pb.finished()
4078
3996
        finally:
4079
 
            tree.set_parent_ids(parents)
4080
 
            pb.finished()
 
3997
            tree.unlock()
4081
3998
        if conflicts > 0:
4082
3999
            return 1
4083
4000
        else:
4105
4022
    name.  If you name a directory, all the contents of that directory will be
4106
4023
    reverted.
4107
4024
 
4108
 
    If you have newly added files since the target revision, they will be
4109
 
    removed.  If the files to be removed have been changed, backups will be
4110
 
    created as above.  Directories containing unknown files will not be
4111
 
    deleted.
 
4025
    Any files that have been newly added since that revision will be deleted,
 
4026
    with a backup kept if appropriate.  Directories containing unknown files
 
4027
    will not be deleted.
4112
4028
 
4113
 
    The working tree contains a list of revisions that have been merged but
4114
 
    not yet committed. These revisions will be included as additional parents
4115
 
    of the next commit.  Normally, using revert clears that list as well as
4116
 
    reverting the files.  If any files are specified, revert leaves the list
4117
 
    of uncommitted merges alone and reverts only the files.  Use ``bzr revert
4118
 
    .`` in the tree root to revert all files but keep the recorded merges,
4119
 
    and ``bzr revert --forget-merges`` to clear the pending merge list without
 
4029
    The working tree contains a list of pending merged revisions, which will
 
4030
    be included as parents in the next commit.  Normally, revert clears that
 
4031
    list as well as reverting the files.  If any files are specified, revert
 
4032
    leaves the pending merge list alone and reverts only the files.  Use "bzr
 
4033
    revert ." in the tree root to revert all files but keep the merge record,
 
4034
    and "bzr revert --forget-merges" to clear the pending merge list without
4120
4035
    reverting any files.
4121
 
 
4122
 
    Using "bzr revert --forget-merges", it is possible to apply all of the
4123
 
    changes from a branch in a single revision.  To do this, perform the merge
4124
 
    as desired.  Then doing revert with the "--forget-merges" option will keep
4125
 
    the content of the tree as it was, but it will clear the list of pending
4126
 
    merges.  The next commit will then contain all of the changes that are
4127
 
    present in the other branch, but without any other parent revisions.
4128
 
    Because this technique forgets where these changes originated, it may
4129
 
    cause additional conflicts on later merges involving the same source and
4130
 
    target branches.
4131
4036
    """
4132
4037
 
4133
4038
    _see_also = ['cat', 'export']
4143
4048
            forget_merges=None):
4144
4049
        tree, file_list = tree_files(file_list)
4145
4050
        tree.lock_write()
4146
 
        self.add_cleanup(tree.unlock)
4147
 
        if forget_merges:
4148
 
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4149
 
        else:
4150
 
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
4051
        try:
 
4052
            if forget_merges:
 
4053
                tree.set_parent_ids(tree.get_parent_ids()[:1])
 
4054
            else:
 
4055
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
4056
        finally:
 
4057
            tree.unlock()
4151
4058
 
4152
4059
    @staticmethod
4153
4060
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4212
4119
    To filter on a range of revisions, you can use the command -r begin..end
4213
4120
    -r revision requests a specific revision, -r ..end or -r begin.. are
4214
4121
    also valid.
4215
 
            
4216
 
    :Exit values:
4217
 
        1 - some missing revisions
4218
 
        0 - no missing revisions
4219
4122
 
4220
4123
    :Examples:
4221
4124
 
4304
4207
        if remote_branch.base == local_branch.base:
4305
4208
            remote_branch = local_branch
4306
4209
 
4307
 
        local_branch.lock_read()
4308
 
        self.add_cleanup(local_branch.unlock)
4309
4210
        local_revid_range = _revision_range_to_revid_range(
4310
4211
            _get_revision_range(my_revision, local_branch,
4311
4212
                self.name()))
4312
4213
 
4313
 
        remote_branch.lock_read()
4314
 
        self.add_cleanup(remote_branch.unlock)
4315
4214
        remote_revid_range = _revision_range_to_revid_range(
4316
4215
            _get_revision_range(revision,
4317
4216
                remote_branch, self.name()))
4318
4217
 
4319
 
        local_extra, remote_extra = find_unmerged(
4320
 
            local_branch, remote_branch, restrict,
4321
 
            backward=not reverse,
4322
 
            include_merges=include_merges,
4323
 
            local_revid_range=local_revid_range,
4324
 
            remote_revid_range=remote_revid_range)
4325
 
 
4326
 
        if log_format is None:
4327
 
            registry = log.log_formatter_registry
4328
 
            log_format = registry.get_default(local_branch)
4329
 
        lf = log_format(to_file=self.outf,
4330
 
                        show_ids=show_ids,
4331
 
                        show_timezone='original')
4332
 
 
4333
 
        status_code = 0
4334
 
        if local_extra and not theirs_only:
4335
 
            message("You have %d extra revision(s):\n" %
4336
 
                len(local_extra))
4337
 
            for revision in iter_log_revisions(local_extra,
4338
 
                                local_branch.repository,
4339
 
                                verbose):
4340
 
                lf.log_revision(revision)
4341
 
            printed_local = True
4342
 
            status_code = 1
4343
 
        else:
4344
 
            printed_local = False
4345
 
 
4346
 
        if remote_extra and not mine_only:
4347
 
            if printed_local is True:
4348
 
                message("\n\n\n")
4349
 
            message("You are missing %d revision(s):\n" %
4350
 
                len(remote_extra))
4351
 
            for revision in iter_log_revisions(remote_extra,
4352
 
                                remote_branch.repository,
4353
 
                                verbose):
4354
 
                lf.log_revision(revision)
4355
 
            status_code = 1
4356
 
 
4357
 
        if mine_only and not local_extra:
4358
 
            # We checked local, and found nothing extra
4359
 
            message('This branch is up to date.\n')
4360
 
        elif theirs_only and not remote_extra:
4361
 
            # We checked remote, and found nothing extra
4362
 
            message('Other branch is up to date.\n')
4363
 
        elif not (mine_only or theirs_only or local_extra or
4364
 
                  remote_extra):
4365
 
            # We checked both branches, and neither one had extra
4366
 
            # revisions
4367
 
            message("Branches are up to date.\n")
4368
 
        self.cleanup_now()
 
4218
        local_branch.lock_read()
 
4219
        try:
 
4220
            remote_branch.lock_read()
 
4221
            try:
 
4222
                local_extra, remote_extra = find_unmerged(
 
4223
                    local_branch, remote_branch, restrict,
 
4224
                    backward=not reverse,
 
4225
                    include_merges=include_merges,
 
4226
                    local_revid_range=local_revid_range,
 
4227
                    remote_revid_range=remote_revid_range)
 
4228
 
 
4229
                if log_format is None:
 
4230
                    registry = log.log_formatter_registry
 
4231
                    log_format = registry.get_default(local_branch)
 
4232
                lf = log_format(to_file=self.outf,
 
4233
                                show_ids=show_ids,
 
4234
                                show_timezone='original')
 
4235
 
 
4236
                status_code = 0
 
4237
                if local_extra and not theirs_only:
 
4238
                    message("You have %d extra revision(s):\n" %
 
4239
                        len(local_extra))
 
4240
                    for revision in iter_log_revisions(local_extra,
 
4241
                                        local_branch.repository,
 
4242
                                        verbose):
 
4243
                        lf.log_revision(revision)
 
4244
                    printed_local = True
 
4245
                    status_code = 1
 
4246
                else:
 
4247
                    printed_local = False
 
4248
 
 
4249
                if remote_extra and not mine_only:
 
4250
                    if printed_local is True:
 
4251
                        message("\n\n\n")
 
4252
                    message("You are missing %d revision(s):\n" %
 
4253
                        len(remote_extra))
 
4254
                    for revision in iter_log_revisions(remote_extra,
 
4255
                                        remote_branch.repository,
 
4256
                                        verbose):
 
4257
                        lf.log_revision(revision)
 
4258
                    status_code = 1
 
4259
 
 
4260
                if mine_only and not local_extra:
 
4261
                    # We checked local, and found nothing extra
 
4262
                    message('This branch is up to date.\n')
 
4263
                elif theirs_only and not remote_extra:
 
4264
                    # We checked remote, and found nothing extra
 
4265
                    message('Other branch is up to date.\n')
 
4266
                elif not (mine_only or theirs_only or local_extra or
 
4267
                          remote_extra):
 
4268
                    # We checked both branches, and neither one had extra
 
4269
                    # revisions
 
4270
                    message("Branches are up to date.\n")
 
4271
            finally:
 
4272
                remote_branch.unlock()
 
4273
        finally:
 
4274
            local_branch.unlock()
4369
4275
        if not status_code and parent is None and other_branch is not None:
4370
4276
            local_branch.lock_write()
4371
 
            self.add_cleanup(local_branch.unlock)
4372
 
            # handle race conditions - a parent might be set while we run.
4373
 
            if local_branch.get_parent() is None:
4374
 
                local_branch.set_parent(remote_branch.base)
 
4277
            try:
 
4278
                # handle race conditions - a parent might be set while we run.
 
4279
                if local_branch.get_parent() is None:
 
4280
                    local_branch.set_parent(remote_branch.base)
 
4281
            finally:
 
4282
                local_branch.unlock()
4375
4283
        return status_code
4376
4284
 
4377
4285
 
4405
4313
    adding new commands, providing additional network transports and
4406
4314
    customizing log output.
4407
4315
 
4408
 
    See the Bazaar Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/>
4409
 
    for further information on plugins including where to find them and how to
4410
 
    install them. Instructions are also provided there on how to write new
4411
 
    plugins using the Python programming language.
 
4316
    See the Bazaar web site, http://bazaar-vcs.org, for further
 
4317
    information on plugins including where to find them and how to
 
4318
    install them. Instructions are also provided there on how to
 
4319
    write new plugins using the Python programming language.
4412
4320
    """
4413
4321
    takes_options = ['verbose']
4414
4322
 
4456
4364
        else:
4457
4365
            b = Branch.open(branch)
4458
4366
        b.lock_read()
4459
 
        self.add_cleanup(b.unlock)
4460
 
        if revision is None:
4461
 
            rev_id = b.last_revision()
4462
 
        else:
4463
 
            rev_id = revision[0].as_revision_id(b)
4464
 
        t = testament_class.from_revision(b.repository, rev_id)
4465
 
        if long:
4466
 
            sys.stdout.writelines(t.as_text_lines())
4467
 
        else:
4468
 
            sys.stdout.write(t.as_short_text())
 
4367
        try:
 
4368
            if revision is None:
 
4369
                rev_id = b.last_revision()
 
4370
            else:
 
4371
                rev_id = revision[0].as_revision_id(b)
 
4372
            t = testament_class.from_revision(b.repository, rev_id)
 
4373
            if long:
 
4374
                sys.stdout.writelines(t.as_text_lines())
 
4375
            else:
 
4376
                sys.stdout.write(t.as_short_text())
 
4377
        finally:
 
4378
            b.unlock()
4469
4379
 
4470
4380
 
4471
4381
class cmd_annotate(Command):
4497
4407
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
4498
4408
        if wt is not None:
4499
4409
            wt.lock_read()
4500
 
            self.add_cleanup(wt.unlock)
4501
4410
        else:
4502
4411
            branch.lock_read()
4503
 
            self.add_cleanup(branch.unlock)
4504
 
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
4505
 
        tree.lock_read()
4506
 
        self.add_cleanup(tree.unlock)
4507
 
        if wt is not None:
4508
 
            file_id = wt.path2id(relpath)
4509
 
        else:
4510
 
            file_id = tree.path2id(relpath)
4511
 
        if file_id is None:
4512
 
            raise errors.NotVersionedError(filename)
4513
 
        file_version = tree.inventory[file_id].revision
4514
 
        if wt is not None and revision is None:
4515
 
            # If there is a tree and we're not annotating historical
4516
 
            # versions, annotate the working tree's content.
4517
 
            annotate_file_tree(wt, file_id, self.outf, long, all,
4518
 
                show_ids=show_ids)
4519
 
        else:
4520
 
            annotate_file(branch, file_version, file_id, long, all, self.outf,
4521
 
                          show_ids=show_ids)
 
4412
        try:
 
4413
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4414
            if wt is not None:
 
4415
                file_id = wt.path2id(relpath)
 
4416
            else:
 
4417
                file_id = tree.path2id(relpath)
 
4418
            if file_id is None:
 
4419
                raise errors.NotVersionedError(filename)
 
4420
            file_version = tree.inventory[file_id].revision
 
4421
            if wt is not None and revision is None:
 
4422
                # If there is a tree and we're not annotating historical
 
4423
                # versions, annotate the working tree's content.
 
4424
                annotate_file_tree(wt, file_id, self.outf, long, all,
 
4425
                    show_ids=show_ids)
 
4426
            else:
 
4427
                annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4428
                              show_ids=show_ids)
 
4429
        finally:
 
4430
            if wt is not None:
 
4431
                wt.unlock()
 
4432
            else:
 
4433
                branch.unlock()
4522
4434
 
4523
4435
 
4524
4436
class cmd_re_sign(Command):
4536
4448
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4537
4449
        b = WorkingTree.open_containing(u'.')[0].branch
4538
4450
        b.lock_write()
4539
 
        self.add_cleanup(b.unlock)
4540
 
        return self._run(b, revision_id_list, revision)
 
4451
        try:
 
4452
            return self._run(b, revision_id_list, revision)
 
4453
        finally:
 
4454
            b.unlock()
4541
4455
 
4542
4456
    def _run(self, b, revision_id_list, revision):
4543
4457
        import bzrlib.gpg as gpg
4594
4508
    before they will be applied to the local branch.
4595
4509
 
4596
4510
    Bound branches use the nickname of its master branch unless it is set
4597
 
    locally, in which case binding will update the local nickname to be
 
4511
    locally, in which case binding will update the the local nickname to be
4598
4512
    that of the master.
4599
4513
    """
4600
4514
 
4689
4603
 
4690
4604
        if tree is not None:
4691
4605
            tree.lock_write()
4692
 
            self.add_cleanup(tree.unlock)
4693
4606
        else:
4694
4607
            b.lock_write()
4695
 
            self.add_cleanup(b.unlock)
4696
 
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
 
4608
        try:
 
4609
            return self._run(b, tree, dry_run, verbose, revision, force,
 
4610
                             local=local)
 
4611
        finally:
 
4612
            if tree is not None:
 
4613
                tree.unlock()
 
4614
            else:
 
4615
                b.unlock()
4697
4616
 
4698
4617
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4699
4618
        from bzrlib.log import log_formatter, show_log
4756
4675
    CAUTION: Locks should only be broken when you are sure that the process
4757
4676
    holding the lock has been stopped.
4758
4677
 
4759
 
    You can get information on what locks are open via the 'bzr info
4760
 
    [location]' command.
 
4678
    You can get information on what locks are open via the 'bzr info' command.
4761
4679
 
4762
4680
    :Examples:
4763
4681
        bzr break-lock
4764
 
        bzr break-lock bzr+ssh://example.com/bzr/foo
4765
4682
    """
4766
4683
    takes_args = ['location?']
4767
4684
 
4797
4714
    takes_options = [
4798
4715
        Option('inet',
4799
4716
               help='Serve on stdin/out for use from inetd or sshd.'),
4800
 
        RegistryOption('protocol',
4801
 
               help="Protocol to serve.",
 
4717
        RegistryOption('protocol', 
 
4718
               help="Protocol to serve.", 
4802
4719
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
4803
4720
               value_switches=True),
4804
4721
        Option('port',
4813
4730
        Option('allow-writes',
4814
4731
               help='By default the server is a readonly server.  Supplying '
4815
4732
                    '--allow-writes enables write access to the contents of '
4816
 
                    'the served directory and below.  Note that ``bzr serve`` '
4817
 
                    'does not perform authentication, so unless some form of '
4818
 
                    'external authentication is arranged supplying this '
4819
 
                    'option leads to global uncontrolled write access to your '
4820
 
                    'file system.'
 
4733
                    'the served directory and below.'
4821
4734
                ),
4822
4735
        ]
4823
4736
 
5039
4952
      directly from the merge directive, without retrieving data from a
5040
4953
      branch.
5041
4954
 
5042
 
    `bzr send` creates a compact data set that, when applied using bzr
5043
 
    merge, has the same effect as merging from the source branch.  
5044
 
    
5045
 
    By default the merge directive is self-contained and can be applied to any
5046
 
    branch containing submit_branch in its ancestory without needing access to
5047
 
    the source branch.
5048
 
    
5049
 
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
5050
 
    revisions, but only a structured request to merge from the
5051
 
    public_location.  In that case the public_branch is needed and it must be
5052
 
    up-to-date and accessible to the recipient.  The public_branch is always
5053
 
    included if known, so that people can check it later.
5054
 
 
5055
 
    The submit branch defaults to the parent of the source branch, but can be
5056
 
    overridden.  Both submit branch and public branch will be remembered in
5057
 
    branch.conf the first time they are used for a particular branch.  The
5058
 
    source branch defaults to that containing the working directory, but can
5059
 
    be changed using --from.
5060
 
 
5061
 
    In order to calculate those changes, bzr must analyse the submit branch.
5062
 
    Therefore it is most efficient for the submit branch to be a local mirror.
5063
 
    If a public location is known for the submit_branch, that location is used
5064
 
    in the merge directive.
5065
 
 
5066
 
    The default behaviour is to send the merge directive by mail, unless -o is
5067
 
    given, in which case it is sent to a file.
 
4955
    If --no-bundle is specified, then public_branch is needed (and must be
 
4956
    up-to-date), so that the receiver can perform the merge using the
 
4957
    public_branch.  The public_branch is always included if known, so that
 
4958
    people can check it later.
 
4959
 
 
4960
    The submit branch defaults to the parent, but can be overridden.  Both
 
4961
    submit branch and public branch will be remembered if supplied.
 
4962
 
 
4963
    If a public_branch is known for the submit_branch, that public submit
 
4964
    branch is used in the merge instructions.  This means that a local mirror
 
4965
    can be used as your actual submit branch, once you have set public_branch
 
4966
    for that mirror.
5068
4967
 
5069
4968
    Mail is sent using your preferred mail program.  This should be transparent
5070
4969
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
5090
4989
 
5091
4990
    The merge directives created by bzr send may be applied using bzr merge or
5092
4991
    bzr pull by specifying a file containing a merge directive as the location.
5093
 
 
5094
 
    bzr send makes extensive use of public locations to map local locations into
5095
 
    URLs that can be used by other people.  See `bzr help configuration` to
5096
 
    set them, and use `bzr info` to display them.
5097
4992
    """
5098
4993
 
5099
4994
    encoding_type = 'exact'
5258
5153
            ):
5259
5154
        branch, relpath = Branch.open_containing(directory)
5260
5155
        branch.lock_write()
5261
 
        self.add_cleanup(branch.unlock)
5262
 
        if delete:
5263
 
            branch.tags.delete_tag(tag_name)
5264
 
            self.outf.write('Deleted tag %s.\n' % tag_name)
5265
 
        else:
5266
 
            if revision:
5267
 
                if len(revision) != 1:
5268
 
                    raise errors.BzrCommandError(
5269
 
                        "Tags can only be placed on a single revision, "
5270
 
                        "not on a range")
5271
 
                revision_id = revision[0].as_revision_id(branch)
 
5156
        try:
 
5157
            if delete:
 
5158
                branch.tags.delete_tag(tag_name)
 
5159
                self.outf.write('Deleted tag %s.\n' % tag_name)
5272
5160
            else:
5273
 
                revision_id = branch.last_revision()
5274
 
            if (not force) and branch.tags.has_tag(tag_name):
5275
 
                raise errors.TagAlreadyExists(tag_name)
5276
 
            branch.tags.set_tag(tag_name, revision_id)
5277
 
            self.outf.write('Created tag %s.\n' % tag_name)
 
5161
                if revision:
 
5162
                    if len(revision) != 1:
 
5163
                        raise errors.BzrCommandError(
 
5164
                            "Tags can only be placed on a single revision, "
 
5165
                            "not on a range")
 
5166
                    revision_id = revision[0].as_revision_id(branch)
 
5167
                else:
 
5168
                    revision_id = branch.last_revision()
 
5169
                if (not force) and branch.tags.has_tag(tag_name):
 
5170
                    raise errors.TagAlreadyExists(tag_name)
 
5171
                branch.tags.set_tag(tag_name, revision_id)
 
5172
                self.outf.write('Created tag %s.\n' % tag_name)
 
5173
        finally:
 
5174
            branch.unlock()
5278
5175
 
5279
5176
 
5280
5177
class cmd_tags(Command):
5313
5210
            return
5314
5211
 
5315
5212
        branch.lock_read()
5316
 
        self.add_cleanup(branch.unlock)
5317
 
        if revision:
5318
 
            graph = branch.repository.get_graph()
5319
 
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
5320
 
            revid1, revid2 = rev1.rev_id, rev2.rev_id
5321
 
            # only show revisions between revid1 and revid2 (inclusive)
5322
 
            tags = [(tag, revid) for tag, revid in tags if
5323
 
                graph.is_between(revid, revid1, revid2)]
5324
 
        if sort == 'alpha':
5325
 
            tags.sort()
5326
 
        elif sort == 'time':
5327
 
            timestamps = {}
5328
 
            for tag, revid in tags:
5329
 
                try:
5330
 
                    revobj = branch.repository.get_revision(revid)
5331
 
                except errors.NoSuchRevision:
5332
 
                    timestamp = sys.maxint # place them at the end
5333
 
                else:
5334
 
                    timestamp = revobj.timestamp
5335
 
                timestamps[revid] = timestamp
5336
 
            tags.sort(key=lambda x: timestamps[x[1]])
5337
 
        if not show_ids:
5338
 
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5339
 
            for index, (tag, revid) in enumerate(tags):
5340
 
                try:
5341
 
                    revno = branch.revision_id_to_dotted_revno(revid)
5342
 
                    if isinstance(revno, tuple):
5343
 
                        revno = '.'.join(map(str, revno))
5344
 
                except errors.NoSuchRevision:
5345
 
                    # Bad tag data/merges can lead to tagged revisions
5346
 
                    # which are not in this branch. Fail gracefully ...
5347
 
                    revno = '?'
5348
 
                tags[index] = (tag, revno)
5349
 
        self.cleanup_now()
 
5213
        try:
 
5214
            if revision:
 
5215
                graph = branch.repository.get_graph()
 
5216
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5217
                revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5218
                # only show revisions between revid1 and revid2 (inclusive)
 
5219
                tags = [(tag, revid) for tag, revid in tags if
 
5220
                    graph.is_between(revid, revid1, revid2)]
 
5221
            if sort == 'alpha':
 
5222
                tags.sort()
 
5223
            elif sort == 'time':
 
5224
                timestamps = {}
 
5225
                for tag, revid in tags:
 
5226
                    try:
 
5227
                        revobj = branch.repository.get_revision(revid)
 
5228
                    except errors.NoSuchRevision:
 
5229
                        timestamp = sys.maxint # place them at the end
 
5230
                    else:
 
5231
                        timestamp = revobj.timestamp
 
5232
                    timestamps[revid] = timestamp
 
5233
                tags.sort(key=lambda x: timestamps[x[1]])
 
5234
            if not show_ids:
 
5235
                # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5236
                for index, (tag, revid) in enumerate(tags):
 
5237
                    try:
 
5238
                        revno = branch.revision_id_to_dotted_revno(revid)
 
5239
                        if isinstance(revno, tuple):
 
5240
                            revno = '.'.join(map(str, revno))
 
5241
                    except errors.NoSuchRevision:
 
5242
                        # Bad tag data/merges can lead to tagged revisions
 
5243
                        # which are not in this branch. Fail gracefully ...
 
5244
                        revno = '?'
 
5245
                    tags[index] = (tag, revno)
 
5246
        finally:
 
5247
            branch.unlock()
5350
5248
        for tag, revspec in tags:
5351
5249
            self.outf.write('%-20s %s\n' % (tag, revspec))
5352
5250
 
5461
5359
    /path/to/newbranch.
5462
5360
 
5463
5361
    Bound branches use the nickname of its master branch unless it is set
5464
 
    locally, in which case switching will update the local nickname to be
 
5362
    locally, in which case switching will update the the local nickname to be
5465
5363
    that of the master.
5466
5364
    """
5467
5365
 
5468
 
    takes_args = ['to_location?']
 
5366
    takes_args = ['to_location']
5469
5367
    takes_options = [Option('force',
5470
5368
                        help='Switch even if local commits will be lost.'),
5471
 
                     'revision',
5472
5369
                     Option('create-branch', short_name='b',
5473
5370
                        help='Create the target branch from this one before'
5474
5371
                             ' switching to it.'),
5475
 
                    ]
 
5372
                     ]
5476
5373
 
5477
 
    def run(self, to_location=None, force=False, create_branch=False,
5478
 
            revision=None):
 
5374
    def run(self, to_location, force=False, create_branch=False):
5479
5375
        from bzrlib import switch
5480
5376
        tree_location = '.'
5481
 
        revision = _get_one_revision('switch', revision)
5482
5377
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5483
 
        if to_location is None:
5484
 
            if revision is None:
5485
 
                raise errors.BzrCommandError('You must supply either a'
5486
 
                                             ' revision or a location')
5487
 
            to_location = '.'
5488
5378
        try:
5489
5379
            branch = control_dir.open_branch()
5490
5380
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5495
5385
            if branch is None:
5496
5386
                raise errors.BzrCommandError('cannot create branch without'
5497
5387
                                             ' source branch')
5498
 
            to_location = directory_service.directories.dereference(
5499
 
                              to_location)
5500
5388
            if '/' not in to_location and '\\' not in to_location:
5501
5389
                # This path is meant to be relative to the existing branch
5502
5390
                this_url = self._get_branch_location(control_dir)
5504
5392
            to_branch = branch.bzrdir.sprout(to_location,
5505
5393
                                 possible_transports=[branch.bzrdir.root_transport],
5506
5394
                                 source_branch=branch).open_branch()
 
5395
            # try:
 
5396
            #     from_branch = control_dir.open_branch()
 
5397
            # except errors.NotBranchError:
 
5398
            #     raise BzrCommandError('Cannot create a branch from this'
 
5399
            #         ' location when we cannot open this branch')
 
5400
            # from_branch.bzrdir.sprout(
 
5401
            pass
5507
5402
        else:
5508
5403
            try:
5509
5404
                to_branch = Branch.open(to_location)
5511
5406
                this_url = self._get_branch_location(control_dir)
5512
5407
                to_branch = Branch.open(
5513
5408
                    urlutils.join(this_url, '..', to_location))
5514
 
        if revision is not None:
5515
 
            revision = revision.as_revision_id(to_branch)
5516
 
        switch.switch(control_dir, to_branch, force, revision_id=revision)
 
5409
        switch.switch(control_dir, to_branch, force)
5517
5410
        if had_explicit_nick:
5518
5411
            branch = control_dir.open_branch() #get the new branch!
5519
5412
            branch.nick = to_branch.nick
5766
5659
            try:
5767
5660
                shelver.run()
5768
5661
            finally:
5769
 
                shelver.finalize()
 
5662
                shelver.work_tree.unlock()
5770
5663
        except errors.UserAbort:
5771
5664
            return 0
5772
5665
 
5773
5666
    def run_for_list(self):
5774
5667
        tree = WorkingTree.open_containing('.')[0]
5775
5668
        tree.lock_read()
5776
 
        self.add_cleanup(tree.unlock)
5777
 
        manager = tree.get_shelf_manager()
5778
 
        shelves = manager.active_shelves()
5779
 
        if len(shelves) == 0:
5780
 
            note('No shelved changes.')
5781
 
            return 0
5782
 
        for shelf_id in reversed(shelves):
5783
 
            message = manager.get_metadata(shelf_id).get('message')
5784
 
            if message is None:
5785
 
                message = '<no message>'
5786
 
            self.outf.write('%3d: %s\n' % (shelf_id, message))
5787
 
        return 1
 
5669
        try:
 
5670
            manager = tree.get_shelf_manager()
 
5671
            shelves = manager.active_shelves()
 
5672
            if len(shelves) == 0:
 
5673
                note('No shelved changes.')
 
5674
                return 0
 
5675
            for shelf_id in reversed(shelves):
 
5676
                message = manager.get_metadata(shelf_id).get('message')
 
5677
                if message is None:
 
5678
                    message = '<no message>'
 
5679
                self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5680
            return 1
 
5681
        finally:
 
5682
            tree.unlock()
5788
5683
 
5789
5684
 
5790
5685
class cmd_unshelve(Command):
5802
5697
            enum_switch=False, value_switches=True,
5803
5698
            apply="Apply changes and remove from the shelf.",
5804
5699
            dry_run="Show changes, but do not apply or remove them.",
5805
 
            preview="Instead of unshelving the changes, show the diff that "
5806
 
                    "would result from unshelving.",
5807
 
            delete_only="Delete changes without applying them.",
5808
 
            keep="Apply changes but don't delete them.",
 
5700
            delete_only="Delete changes without applying them."
5809
5701
        )
5810
5702
    ]
5811
5703
    _see_also = ['shelve']