~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-11-17 03:20:35 UTC
  • mfrom: (4792.4.3 456036)
  • Revision ID: pqm@pqm.ubuntu.com-20091117032035-s3sgtlixj1lrminn
(Gordon Tyler) Fix IndexError during 'bzr ignore /' (#456036)

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])
 
434
            refs_as_tuples = tuple([tuple([tuple(ref) for ref in ref_list])
 
435
                                   for ref_list in node[3]])
442
436
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
443
437
            self.outf.write('%s\n' % (as_tuple,))
444
438
 
502
496
                wt.lock_read()
503
497
            except (errors.NoWorkingTree, errors.NotLocalUrl):
504
498
                raise errors.NoWorkingTree(location)
505
 
            self.add_cleanup(wt.unlock)
506
 
            revid = wt.last_revision()
507
499
            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)
 
500
                revid = wt.last_revision()
 
501
                try:
 
502
                    revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
503
                except errors.NoSuchRevision:
 
504
                    revno_t = ('???',)
 
505
                revno = ".".join(str(n) for n in revno_t)
 
506
            finally:
 
507
                wt.unlock()
512
508
        else:
513
509
            b = Branch.open_containing(location)[0]
514
510
            b.lock_read()
515
 
            self.add_cleanup(b.unlock)
516
 
            revno = b.revno()
517
 
        self.cleanup_now()
 
511
            try:
 
512
                revno = b.revno()
 
513
            finally:
 
514
                b.unlock()
 
515
 
518
516
        self.outf.write(str(revno) + '\n')
519
517
 
520
518
 
542
540
            wt = WorkingTree.open_containing(directory)[0]
543
541
            b = wt.branch
544
542
            wt.lock_read()
545
 
            self.add_cleanup(wt.unlock)
546
543
        except (errors.NoWorkingTree, errors.NotLocalUrl):
547
544
            wt = None
548
545
            b = Branch.open_containing(directory)[0]
549
546
            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())
 
547
        try:
 
548
            revision_ids = []
 
549
            if revision is not None:
 
550
                revision_ids.extend(rev.as_revision_id(b) for rev in revision)
 
551
            if revision_info_list is not None:
 
552
                for rev_str in revision_info_list:
 
553
                    rev_spec = RevisionSpec.from_string(rev_str)
 
554
                    revision_ids.append(rev_spec.as_revision_id(b))
 
555
            # No arguments supplied, default to the last revision
 
556
            if len(revision_ids) == 0:
 
557
                if tree:
 
558
                    if wt is None:
 
559
                        raise errors.NoWorkingTree(directory)
 
560
                    revision_ids.append(wt.last_revision())
 
561
                else:
 
562
                    revision_ids.append(b.last_revision())
 
563
 
 
564
            revinfos = []
 
565
            maxlen = 0
 
566
            for revision_id in revision_ids:
 
567
                try:
 
568
                    dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
569
                    revno = '.'.join(str(i) for i in dotted_revno)
 
570
                except errors.NoSuchRevision:
 
571
                    revno = '???'
 
572
                maxlen = max(maxlen, len(revno))
 
573
                revinfos.append([revno, revision_id])
 
574
        finally:
 
575
            if wt is None:
 
576
                b.unlock()
564
577
            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()
 
578
                wt.unlock()
 
579
 
579
580
        for ri in revinfos:
580
581
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
581
582
 
653
654
 
654
655
        if base_tree:
655
656
            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()
 
657
        try:
 
658
            tree, file_list = tree_files_for_add(file_list)
 
659
            added, ignored = tree.smart_add(file_list, not
 
660
                no_recurse, action=action, save=not dry_run)
 
661
        finally:
 
662
            if base_tree is not None:
 
663
                base_tree.unlock()
661
664
        if len(ignored) > 0:
662
665
            if verbose:
663
666
                for glob in sorted(ignored.keys()):
727
730
        revision = _get_one_revision('inventory', revision)
728
731
        work_tree, file_list = tree_files(file_list)
729
732
        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()
 
733
        try:
 
734
            if revision is not None:
 
735
                tree = revision.as_tree(work_tree.branch)
 
736
 
 
737
                extra_trees = [work_tree]
 
738
                tree.lock_read()
 
739
            else:
 
740
                tree = work_tree
 
741
                extra_trees = []
 
742
 
 
743
            if file_list is not None:
 
744
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
745
                                          require_versioned=True)
 
746
                # find_ids_across_trees may include some paths that don't
 
747
                # exist in 'tree'.
 
748
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
749
                                 for file_id in file_ids if file_id in tree)
 
750
            else:
 
751
                entries = tree.inventory.entries()
 
752
        finally:
 
753
            tree.unlock()
 
754
            if tree is not work_tree:
 
755
                work_tree.unlock()
 
756
 
752
757
        for path, entry in entries:
753
758
            if kind and kind != entry.kind:
754
759
                continue
800
805
            raise errors.BzrCommandError("missing file argument")
801
806
        tree, rel_names = tree_files(names_list, canonicalize=False)
802
807
        tree.lock_tree_write()
803
 
        self.add_cleanup(tree.unlock)
804
 
        self._run(tree, names_list, rel_names, after)
 
808
        try:
 
809
            self._run(tree, names_list, rel_names, after)
 
810
        finally:
 
811
            tree.unlock()
805
812
 
806
813
    def run_auto(self, names_list, after, dry_run):
807
814
        if names_list is not None and len(names_list) > 1:
812
819
                                         ' --auto.')
813
820
        work_tree, file_list = tree_files(names_list, default_branch='.')
814
821
        work_tree.lock_tree_write()
815
 
        self.add_cleanup(work_tree.unlock)
816
 
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
 
822
        try:
 
823
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
 
824
        finally:
 
825
            work_tree.unlock()
817
826
 
818
827
    def _run(self, tree, names_list, rel_names, after):
819
828
        into_existing = osutils.isdir(names_list[-1])
840
849
            # All entries reference existing inventory items, so fix them up
841
850
            # for cicp file-systems.
842
851
            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))
 
852
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
853
                self.outf.write("%s => %s\n" % pair)
846
854
        else:
847
855
            if len(names_list) != 2:
848
856
                raise errors.BzrCommandError('to mv multiple files the'
892
900
            dest = osutils.pathjoin(dest_parent, dest_tail)
893
901
            mutter("attempting to move %s => %s", src, dest)
894
902
            tree.rename_one(src, dest, after=after)
895
 
            if not is_quiet():
896
 
                self.outf.write("%s => %s\n" % (src, dest))
 
903
            self.outf.write("%s => %s\n" % (src, dest))
897
904
 
898
905
 
899
906
class cmd_pull(Command):
900
907
    """Turn this branch into a mirror of another branch.
901
908
 
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.
 
909
    This command only works on branches that have not diverged.  Branches are
 
910
    considered diverged if the destination branch's most recent commit is one
 
911
    that has not been merged (directly or indirectly) into the parent.
906
912
 
907
913
    If branches have diverged, you can use 'bzr merge' to integrate the changes
908
914
    from one into the other.  Once one branch has merged, the other should
909
915
    be able to pull it again.
910
916
 
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.
 
917
    If you want to forget your local changes and just update your branch to
 
918
    match the remote one, use pull --overwrite.
914
919
 
915
920
    If there is no default location set, the first pull will set it.  After
916
921
    that, you can omit the location to use the default.  To change the
997
1002
 
998
1003
        if branch_from is not branch_to:
999
1004
            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)
 
1005
        try:
 
1006
            if revision is not None:
 
1007
                revision_id = revision.as_revision_id(branch_from)
 
1008
 
 
1009
            branch_to.lock_write()
 
1010
            try:
 
1011
                if tree_to is not None:
 
1012
                    view_info = _get_view_info_for_change_reporter(tree_to)
 
1013
                    change_reporter = delta._ChangeReporter(
 
1014
                        unversioned_filter=tree_to.is_ignored,
 
1015
                        view_info=view_info)
 
1016
                    result = tree_to.pull(
 
1017
                        branch_from, overwrite, revision_id, change_reporter,
 
1018
                        possible_transports=possible_transports, local=local)
 
1019
                else:
 
1020
                    result = branch_to.pull(
 
1021
                        branch_from, overwrite, revision_id, local=local)
 
1022
 
 
1023
                result.report(self.outf)
 
1024
                if verbose and result.old_revid != result.new_revid:
 
1025
                    log.show_branch_change(
 
1026
                        branch_to, self.outf, result.old_revno,
 
1027
                        result.old_revid)
 
1028
            finally:
 
1029
                branch_to.unlock()
 
1030
        finally:
 
1031
            if branch_from is not branch_to:
 
1032
                branch_from.unlock()
1023
1033
 
1024
1034
 
1025
1035
class cmd_push(Command):
1180
1190
                    ' directory exists, but does not already'
1181
1191
                    ' have a control directory.  This flag will'
1182
1192
                    ' allow branch to proceed.'),
1183
 
        Option('bind',
1184
 
            help="Bind new branch to from location."),
1185
1193
        ]
1186
1194
    aliases = ['get', 'clone']
1187
1195
 
1188
1196
    def run(self, from_location, to_location=None, revision=None,
1189
1197
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1190
 
            use_existing_dir=False, switch=False, bind=False):
 
1198
            use_existing_dir=False, switch=False):
1191
1199
        from bzrlib import switch as _mod_switch
1192
1200
        from bzrlib.tag import _merge_tags_if_possible
1193
1201
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1194
1202
            from_location)
 
1203
        if (accelerator_tree is not None and
 
1204
            accelerator_tree.supports_content_filtering()):
 
1205
            accelerator_tree = None
1195
1206
        revision = _get_one_revision('branch', revision)
1196
1207
        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
1208
        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)
 
1209
            if revision is not None:
 
1210
                revision_id = revision.as_revision_id(br_from)
1214
1211
            else:
1215
 
                try:
1216
 
                    bzrdir.BzrDir.open_from_transport(to_transport)
1217
 
                except errors.NotBranchError:
1218
 
                    pass
 
1212
                # FIXME - wt.last_revision, fallback to branch, fall back to
 
1213
                # None or perhaps NULL_REVISION to mean copy nothing
 
1214
                # RBC 20060209
 
1215
                revision_id = br_from.last_revision()
 
1216
            if to_location is None:
 
1217
                to_location = urlutils.derive_to_location(from_location)
 
1218
            to_transport = transport.get_transport(to_location)
 
1219
            try:
 
1220
                to_transport.mkdir('.')
 
1221
            except errors.FileExists:
 
1222
                if not use_existing_dir:
 
1223
                    raise errors.BzrCommandError('Target directory "%s" '
 
1224
                        'already exists.' % to_location)
1219
1225
                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'))
 
1226
                    try:
 
1227
                        bzrdir.BzrDir.open_from_transport(to_transport)
 
1228
                    except errors.NotBranchError:
 
1229
                        pass
 
1230
                    else:
 
1231
                        raise errors.AlreadyBranchError(to_location)
 
1232
            except errors.NoSuchFile:
 
1233
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1234
                                             % to_location)
 
1235
            try:
 
1236
                # preserve whatever source format we have.
 
1237
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1238
                                            possible_transports=[to_transport],
 
1239
                                            accelerator_tree=accelerator_tree,
 
1240
                                            hardlink=hardlink, stacked=stacked,
 
1241
                                            force_new_repo=standalone,
 
1242
                                            create_tree_if_local=not no_tree,
 
1243
                                            source_branch=br_from)
 
1244
                branch = dir.open_branch()
 
1245
            except errors.NoSuchRevision:
 
1246
                to_transport.delete_tree('.')
 
1247
                msg = "The branch %s has no revision %s." % (from_location,
 
1248
                    revision)
 
1249
                raise errors.BzrCommandError(msg)
 
1250
            _merge_tags_if_possible(br_from, branch)
 
1251
            # If the source branch is stacked, the new branch may
 
1252
            # be stacked whether we asked for that explicitly or not.
 
1253
            # We therefore need a try/except here and not just 'if stacked:'
 
1254
            try:
 
1255
                note('Created new stacked branch referring to %s.' %
 
1256
                    branch.get_stacked_on_url())
 
1257
            except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1258
                errors.UnstackableRepositoryFormat), e:
 
1259
                note('Branched %d revision(s).' % branch.revno())
 
1260
            if switch:
 
1261
                # Switch to the new branch
 
1262
                wt, _ = WorkingTree.open_containing('.')
 
1263
                _mod_switch.switch(wt.bzrdir, branch)
 
1264
                note('Switched to branch: %s',
 
1265
                    urlutils.unescape_for_display(branch.base, 'utf-8'))
 
1266
        finally:
 
1267
            br_from.unlock()
1260
1268
 
1261
1269
 
1262
1270
class cmd_checkout(Command):
1341
1349
    def run(self, dir=u'.'):
1342
1350
        tree = WorkingTree.open_containing(dir)[0]
1343
1351
        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))
 
1352
        try:
 
1353
            new_inv = tree.inventory
 
1354
            old_tree = tree.basis_tree()
 
1355
            old_tree.lock_read()
 
1356
            try:
 
1357
                old_inv = old_tree.inventory
 
1358
                renames = []
 
1359
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1360
                for f, paths, c, v, p, n, k, e in iterator:
 
1361
                    if paths[0] == paths[1]:
 
1362
                        continue
 
1363
                    if None in (paths):
 
1364
                        continue
 
1365
                    renames.append(paths)
 
1366
                renames.sort()
 
1367
                for old_name, new_name in renames:
 
1368
                    self.outf.write("%s => %s\n" % (old_name, new_name))
 
1369
            finally:
 
1370
                old_tree.unlock()
 
1371
        finally:
 
1372
            tree.unlock()
1361
1373
 
1362
1374
 
1363
1375
class cmd_update(Command):
1369
1381
 
1370
1382
    If you want to discard your local changes, you can just do a
1371
1383
    '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
1384
    """
1376
1385
 
1377
1386
    _see_also = ['pull', 'working-trees', 'status-flags']
1378
1387
    takes_args = ['dir?']
1379
 
    takes_options = ['revision']
1380
1388
    aliases = ['up']
1381
1389
 
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")
 
1390
    def run(self, dir='.'):
1386
1391
        tree = WorkingTree.open_containing(dir)[0]
1387
 
        branch = tree.branch
1388
1392
        possible_transports = []
1389
 
        master = branch.get_master_branch(
 
1393
        master = tree.branch.get_master_branch(
1390
1394
            possible_transports=possible_transports)
1391
1395
        if master is not None:
1392
1396
            tree.lock_write()
1393
 
            branch_location = master.base
1394
1397
        else:
1395
1398
            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
1399
        try:
 
1400
            existing_pending_merges = tree.get_parent_ids()[1:]
 
1401
            last_rev = _mod_revision.ensure_null(tree.last_revision())
 
1402
            if last_rev == _mod_revision.ensure_null(
 
1403
                tree.branch.last_revision()):
 
1404
                # may be up to date, check master too.
 
1405
                if master is None or last_rev == _mod_revision.ensure_null(
 
1406
                    master.last_revision()):
 
1407
                    revno = tree.branch.revision_id_to_revno(last_rev)
 
1408
                    note("Tree is up to date at revision %d." % (revno,))
 
1409
                    return 0
 
1410
            view_info = _get_view_info_for_change_reporter(tree)
1423
1411
            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
 
1412
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
 
1413
                view_info=view_info), possible_transports=possible_transports)
 
1414
            revno = tree.branch.revision_id_to_revno(
 
1415
                _mod_revision.ensure_null(tree.last_revision()))
 
1416
            note('Updated to revision %d.' % (revno,))
 
1417
            if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1418
                note('Your local commits will now show as pending merges with '
 
1419
                     "'bzr status', and can be committed with 'bzr commit'.")
 
1420
            if conflicts != 0:
 
1421
                return 1
 
1422
            else:
 
1423
                return 0
 
1424
        finally:
 
1425
            tree.unlock()
1445
1426
 
1446
1427
 
1447
1428
class cmd_info(Command):
1518
1499
            file_list = [f for f in file_list]
1519
1500
 
1520
1501
        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')
 
1502
        try:
 
1503
            # Heuristics should probably all move into tree.remove_smart or
 
1504
            # some such?
 
1505
            if new:
 
1506
                added = tree.changes_from(tree.basis_tree(),
 
1507
                    specific_files=file_list).added
 
1508
                file_list = sorted([f[0] for f in added], reverse=True)
 
1509
                if len(file_list) == 0:
 
1510
                    raise errors.BzrCommandError('No matching files.')
 
1511
            elif file_list is None:
 
1512
                # missing files show up in iter_changes(basis) as
 
1513
                # versioned-with-no-kind.
 
1514
                missing = []
 
1515
                for change in tree.iter_changes(tree.basis_tree()):
 
1516
                    # Find paths in the working tree that have no kind:
 
1517
                    if change[1][1] is not None and change[6][1] is None:
 
1518
                        missing.append(change[1][1])
 
1519
                file_list = sorted(missing, reverse=True)
 
1520
                file_deletion_strategy = 'keep'
 
1521
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1522
                keep_files=file_deletion_strategy=='keep',
 
1523
                force=file_deletion_strategy=='force')
 
1524
        finally:
 
1525
            tree.unlock()
1543
1526
 
1544
1527
 
1545
1528
class cmd_file_id(Command):
1765
1748
 
1766
1749
 
1767
1750
class cmd_init_repository(Command):
1768
 
    """Create a shared repository for branches to share storage space.
 
1751
    """Create a shared repository to hold branches.
1769
1752
 
1770
1753
    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.
 
1754
    revisions in the repository, not in the branch directory.
1774
1755
 
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.
 
1756
    If the --no-trees option is used then the branches in the repository
 
1757
    will not have working trees by default.
1781
1758
 
1782
1759
    :Examples:
1783
 
        Create a shared repository holding just branches::
 
1760
        Create a shared repositories holding just branches::
1784
1761
 
1785
1762
            bzr init-repo --no-trees repo
1786
1763
            bzr init repo/trunk
1852
1829
 
1853
1830
            bzr diff -r1
1854
1831
 
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
 
1832
        Difference between revision 2 and revision 1::
 
1833
 
 
1834
            bzr diff -r1..2
 
1835
 
 
1836
        Difference between revision 2 and revision 1 for branch xxx::
 
1837
 
 
1838
            bzr diff -r1..2 xxx
1876
1839
 
1877
1840
        Show just the differences for file NEWS::
1878
1841
 
1971
1934
    def run(self, show_ids=False):
1972
1935
        tree = WorkingTree.open_containing(u'.')[0]
1973
1936
        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')
 
1937
        try:
 
1938
            old = tree.basis_tree()
 
1939
            old.lock_read()
 
1940
            try:
 
1941
                for path, ie in old.inventory.iter_entries():
 
1942
                    if not tree.has_id(ie.file_id):
 
1943
                        self.outf.write(path)
 
1944
                        if show_ids:
 
1945
                            self.outf.write(' ')
 
1946
                            self.outf.write(ie.file_id)
 
1947
                        self.outf.write('\n')
 
1948
            finally:
 
1949
                old.unlock()
 
1950
        finally:
 
1951
            tree.unlock()
1985
1952
 
1986
1953
 
1987
1954
class cmd_modified(Command):
2023
1990
    def run(self, null=False):
2024
1991
        wt = WorkingTree.open_containing(u'.')[0]
2025
1992
        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')
 
1993
        try:
 
1994
            basis = wt.basis_tree()
 
1995
            basis.lock_read()
 
1996
            try:
 
1997
                basis_inv = basis.inventory
 
1998
                inv = wt.inventory
 
1999
                for file_id in inv:
 
2000
                    if file_id in basis_inv:
 
2001
                        continue
 
2002
                    if inv.is_root(file_id) and len(basis_inv) == 0:
 
2003
                        continue
 
2004
                    path = inv.id2path(file_id)
 
2005
                    if not os.access(osutils.abspath(path), os.F_OK):
 
2006
                        continue
 
2007
                    if null:
 
2008
                        self.outf.write(path + '\0')
 
2009
                    else:
 
2010
                        self.outf.write(osutils.quotefn(path) + '\n')
 
2011
            finally:
 
2012
                basis.unlock()
 
2013
        finally:
 
2014
            wt.unlock()
2044
2015
 
2045
2016
 
2046
2017
class cmd_root(Command):
2304
2275
 
2305
2276
        file_ids = []
2306
2277
        filter_by_dir = False
2307
 
        if file_list:
2308
 
            # find the file ids to log and check for directory filtering
2309
 
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2310
 
                revision, file_list)
2311
 
            self.add_cleanup(b.unlock)
2312
 
            for relpath, file_id, kind in file_info_list:
2313
 
                if file_id is None:
2314
 
                    raise errors.BzrCommandError(
2315
 
                        "Path unknown at end or start of revision range: %s" %
2316
 
                        relpath)
2317
 
                # If the relpath is the top of the tree, we log everything
2318
 
                if relpath == '':
2319
 
                    file_ids = []
2320
 
                    break
 
2278
        b = None
 
2279
        try:
 
2280
            if file_list:
 
2281
                # find the file ids to log and check for directory filtering
 
2282
                b, file_info_list, rev1, rev2 = _get_info_for_log_files(
 
2283
                    revision, file_list)
 
2284
                for relpath, file_id, kind in file_info_list:
 
2285
                    if file_id is None:
 
2286
                        raise errors.BzrCommandError(
 
2287
                            "Path unknown at end or start of revision range: %s" %
 
2288
                            relpath)
 
2289
                    # If the relpath is the top of the tree, we log everything
 
2290
                    if relpath == '':
 
2291
                        file_ids = []
 
2292
                        break
 
2293
                    else:
 
2294
                        file_ids.append(file_id)
 
2295
                    filter_by_dir = filter_by_dir or (
 
2296
                        kind in ['directory', 'tree-reference'])
 
2297
            else:
 
2298
                # log everything
 
2299
                # FIXME ? log the current subdir only RBC 20060203
 
2300
                if revision is not None \
 
2301
                        and len(revision) > 0 and revision[0].get_branch():
 
2302
                    location = revision[0].get_branch()
2321
2303
                else:
2322
 
                    file_ids.append(file_id)
2323
 
                filter_by_dir = filter_by_dir or (
2324
 
                    kind in ['directory', 'tree-reference'])
2325
 
        else:
2326
 
            # log everything
2327
 
            # FIXME ? log the current subdir only RBC 20060203
2328
 
            if revision is not None \
2329
 
                    and len(revision) > 0 and revision[0].get_branch():
2330
 
                location = revision[0].get_branch()
2331
 
            else:
2332
 
                location = '.'
2333
 
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2334
 
            b = dir.open_branch()
2335
 
            b.lock_read()
2336
 
            self.add_cleanup(b.unlock)
2337
 
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2338
 
 
2339
 
        # Decide on the type of delta & diff filtering to use
2340
 
        # TODO: add an --all-files option to make this configurable & consistent
2341
 
        if not verbose:
2342
 
            delta_type = None
2343
 
        else:
2344
 
            delta_type = 'full'
2345
 
        if not show_diff:
2346
 
            diff_type = None
2347
 
        elif file_ids:
2348
 
            diff_type = 'partial'
2349
 
        else:
2350
 
            diff_type = 'full'
2351
 
 
2352
 
        # Build the log formatter
2353
 
        if log_format is None:
2354
 
            log_format = log.log_formatter_registry.get_default(b)
2355
 
        # Make a non-encoding output to include the diffs - bug 328007
2356
 
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
2357
 
        lf = log_format(show_ids=show_ids, to_file=self.outf,
2358
 
                        to_exact_file=unencoded_output,
2359
 
                        show_timezone=timezone,
2360
 
                        delta_format=get_verbosity_level(),
2361
 
                        levels=levels,
2362
 
                        show_advice=levels is None)
2363
 
 
2364
 
        # Choose the algorithm for doing the logging. It's annoying
2365
 
        # having multiple code paths like this but necessary until
2366
 
        # the underlying repository format is faster at generating
2367
 
        # deltas or can provide everything we need from the indices.
2368
 
        # The default algorithm - match-using-deltas - works for
2369
 
        # multiple files and directories and is faster for small
2370
 
        # amounts of history (200 revisions say). However, it's too
2371
 
        # slow for logging a single file in a repository with deep
2372
 
        # history, i.e. > 10K revisions. In the spirit of "do no
2373
 
        # evil when adding features", we continue to use the
2374
 
        # original algorithm - per-file-graph - for the "single
2375
 
        # file that isn't a directory without showing a delta" case.
2376
 
        partial_history = revision and b.repository._format.supports_chks
2377
 
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2378
 
            or delta_type or partial_history)
2379
 
 
2380
 
        # Build the LogRequest and execute it
2381
 
        if len(file_ids) == 0:
2382
 
            file_ids = None
2383
 
        rqst = make_log_request_dict(
2384
 
            direction=direction, specific_fileids=file_ids,
2385
 
            start_revision=rev1, end_revision=rev2, limit=limit,
2386
 
            message_search=message, delta_type=delta_type,
2387
 
            diff_type=diff_type, _match_using_deltas=match_using_deltas)
2388
 
        Logger(b, rqst).show(lf)
 
2304
                    location = '.'
 
2305
                dir, relpath = bzrdir.BzrDir.open_containing(location)
 
2306
                b = dir.open_branch()
 
2307
                b.lock_read()
 
2308
                rev1, rev2 = _get_revision_range(revision, b, self.name())
 
2309
 
 
2310
            # Decide on the type of delta & diff filtering to use
 
2311
            # TODO: add an --all-files option to make this configurable & consistent
 
2312
            if not verbose:
 
2313
                delta_type = None
 
2314
            else:
 
2315
                delta_type = 'full'
 
2316
            if not show_diff:
 
2317
                diff_type = None
 
2318
            elif file_ids:
 
2319
                diff_type = 'partial'
 
2320
            else:
 
2321
                diff_type = 'full'
 
2322
 
 
2323
            # Build the log formatter
 
2324
            if log_format is None:
 
2325
                log_format = log.log_formatter_registry.get_default(b)
 
2326
            lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2327
                            show_timezone=timezone,
 
2328
                            delta_format=get_verbosity_level(),
 
2329
                            levels=levels,
 
2330
                            show_advice=levels is None)
 
2331
 
 
2332
            # Choose the algorithm for doing the logging. It's annoying
 
2333
            # having multiple code paths like this but necessary until
 
2334
            # the underlying repository format is faster at generating
 
2335
            # deltas or can provide everything we need from the indices.
 
2336
            # The default algorithm - match-using-deltas - works for
 
2337
            # multiple files and directories and is faster for small
 
2338
            # amounts of history (200 revisions say). However, it's too
 
2339
            # slow for logging a single file in a repository with deep
 
2340
            # history, i.e. > 10K revisions. In the spirit of "do no
 
2341
            # evil when adding features", we continue to use the
 
2342
            # original algorithm - per-file-graph - for the "single
 
2343
            # file that isn't a directory without showing a delta" case.
 
2344
            partial_history = revision and b.repository._format.supports_chks
 
2345
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2346
                or delta_type or partial_history)
 
2347
 
 
2348
            # Build the LogRequest and execute it
 
2349
            if len(file_ids) == 0:
 
2350
                file_ids = None
 
2351
            rqst = make_log_request_dict(
 
2352
                direction=direction, specific_fileids=file_ids,
 
2353
                start_revision=rev1, end_revision=rev2, limit=limit,
 
2354
                message_search=message, delta_type=delta_type,
 
2355
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2356
            Logger(b, rqst).show(lf)
 
2357
        finally:
 
2358
            if b is not None:
 
2359
                b.unlock()
2389
2360
 
2390
2361
 
2391
2362
def _get_revision_range(revisionspec_list, branch, command_name):
2458
2429
        file_id = tree.path2id(relpath)
2459
2430
        b = tree.branch
2460
2431
        b.lock_read()
2461
 
        self.add_cleanup(b.unlock)
2462
 
        touching_revs = log.find_touching_revisions(b, file_id)
2463
 
        for revno, revision_id, what in touching_revs:
2464
 
            self.outf.write("%6d %s\n" % (revno, what))
 
2432
        try:
 
2433
            touching_revs = log.find_touching_revisions(b, file_id)
 
2434
            for revno, revision_id, what in touching_revs:
 
2435
                self.outf.write("%6d %s\n" % (revno, what))
 
2436
        finally:
 
2437
            b.unlock()
2465
2438
 
2466
2439
 
2467
2440
class cmd_ls(Command):
2519
2492
        if from_root:
2520
2493
            if relpath:
2521
2494
                prefix = relpath + '/'
2522
 
        elif fs_path != '.' and not fs_path.endswith('/'):
 
2495
        elif fs_path != '.':
2523
2496
            prefix = fs_path + '/'
2524
2497
 
2525
2498
        if revision is not None or tree is None:
2534
2507
                note("Ignoring files outside view. View is %s" % view_str)
2535
2508
 
2536
2509
        tree.lock_read()
2537
 
        self.add_cleanup(tree.unlock)
2538
 
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2539
 
            from_dir=relpath, recursive=recursive):
2540
 
            # Apply additional masking
2541
 
            if not all and not selection[fc]:
2542
 
                continue
2543
 
            if kind is not None and fkind != kind:
2544
 
                continue
2545
 
            if apply_view:
2546
 
                try:
2547
 
                    if relpath:
2548
 
                        fullpath = osutils.pathjoin(relpath, fp)
2549
 
                    else:
2550
 
                        fullpath = fp
2551
 
                    views.check_path_in_view(tree, fullpath)
2552
 
                except errors.FileOutsideView:
2553
 
                    continue
 
2510
        try:
 
2511
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2512
                from_dir=relpath, recursive=recursive):
 
2513
                # Apply additional masking
 
2514
                if not all and not selection[fc]:
 
2515
                    continue
 
2516
                if kind is not None and fkind != kind:
 
2517
                    continue
 
2518
                if apply_view:
 
2519
                    try:
 
2520
                        if relpath:
 
2521
                            fullpath = osutils.pathjoin(relpath, fp)
 
2522
                        else:
 
2523
                            fullpath = fp
 
2524
                        views.check_path_in_view(tree, fullpath)
 
2525
                    except errors.FileOutsideView:
 
2526
                        continue
2554
2527
 
2555
 
            # Output the entry
2556
 
            if prefix:
2557
 
                fp = osutils.pathjoin(prefix, fp)
2558
 
            kindch = entry.kind_character()
2559
 
            outstring = fp + kindch
2560
 
            ui.ui_factory.clear_term()
2561
 
            if verbose:
2562
 
                outstring = '%-8s %s' % (fc, outstring)
2563
 
                if show_ids and fid is not None:
2564
 
                    outstring = "%-50s %s" % (outstring, fid)
2565
 
                self.outf.write(outstring + '\n')
2566
 
            elif null:
2567
 
                self.outf.write(fp + '\0')
2568
 
                if show_ids:
2569
 
                    if fid is not None:
2570
 
                        self.outf.write(fid)
2571
 
                    self.outf.write('\0')
2572
 
                self.outf.flush()
2573
 
            else:
2574
 
                if show_ids:
2575
 
                    if fid is not None:
2576
 
                        my_id = fid
2577
 
                    else:
2578
 
                        my_id = ''
2579
 
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
2580
 
                else:
 
2528
                # Output the entry
 
2529
                if prefix:
 
2530
                    fp = osutils.pathjoin(prefix, fp)
 
2531
                kindch = entry.kind_character()
 
2532
                outstring = fp + kindch
 
2533
                ui.ui_factory.clear_term()
 
2534
                if verbose:
 
2535
                    outstring = '%-8s %s' % (fc, outstring)
 
2536
                    if show_ids and fid is not None:
 
2537
                        outstring = "%-50s %s" % (outstring, fid)
2581
2538
                    self.outf.write(outstring + '\n')
 
2539
                elif null:
 
2540
                    self.outf.write(fp + '\0')
 
2541
                    if show_ids:
 
2542
                        if fid is not None:
 
2543
                            self.outf.write(fid)
 
2544
                        self.outf.write('\0')
 
2545
                    self.outf.flush()
 
2546
                else:
 
2547
                    if show_ids:
 
2548
                        if fid is not None:
 
2549
                            my_id = fid
 
2550
                        else:
 
2551
                            my_id = ''
 
2552
                        self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2553
                    else:
 
2554
                        self.outf.write(outstring + '\n')
 
2555
        finally:
 
2556
            tree.unlock()
2582
2557
 
2583
2558
 
2584
2559
class cmd_unknowns(Command):
2599
2574
 
2600
2575
    See ``bzr help patterns`` for details on the syntax of patterns.
2601
2576
 
2602
 
    If a .bzrignore file does not exist, the ignore command
2603
 
    will create one and add the specified files or patterns to the newly
2604
 
    created file. The ignore command will also automatically add the 
2605
 
    .bzrignore file to be versioned. Creating a .bzrignore file without
2606
 
    the use of the ignore command will require an explicit add command.
2607
 
 
2608
2577
    To remove patterns from the ignore list, edit the .bzrignore file.
2609
2578
    After adding, editing or deleting that file either indirectly by
2610
2579
    using this command or directly by using an editor, be sure to commit
2696
2665
    def run(self):
2697
2666
        tree = WorkingTree.open_containing(u'.')[0]
2698
2667
        tree.lock_read()
2699
 
        self.add_cleanup(tree.unlock)
2700
 
        for path, file_class, kind, file_id, entry in tree.list_files():
2701
 
            if file_class != 'I':
2702
 
                continue
2703
 
            ## XXX: Slightly inefficient since this was already calculated
2704
 
            pat = tree.is_ignored(path)
2705
 
            self.outf.write('%-50s %s\n' % (path, pat))
 
2668
        try:
 
2669
            for path, file_class, kind, file_id, entry in tree.list_files():
 
2670
                if file_class != 'I':
 
2671
                    continue
 
2672
                ## XXX: Slightly inefficient since this was already calculated
 
2673
                pat = tree.is_ignored(path)
 
2674
                self.outf.write('%-50s %s\n' % (path, pat))
 
2675
        finally:
 
2676
            tree.unlock()
2706
2677
 
2707
2678
 
2708
2679
class cmd_lookup_revision(Command):
2811
2782
        tree, branch, relpath = \
2812
2783
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2813
2784
        branch.lock_read()
2814
 
        self.add_cleanup(branch.unlock)
2815
 
        return self._run(tree, branch, relpath, filename, revision,
2816
 
                         name_from_revision, filters)
 
2785
        try:
 
2786
            return self._run(tree, branch, relpath, filename, revision,
 
2787
                             name_from_revision, filters)
 
2788
        finally:
 
2789
            branch.unlock()
2817
2790
 
2818
2791
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
2819
2792
        filtered):
2820
2793
        if tree is None:
2821
2794
            tree = b.basis_tree()
2822
2795
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2823
 
        rev_tree.lock_read()
2824
 
        self.add_cleanup(rev_tree.unlock)
2825
2796
 
2826
2797
        old_file_id = rev_tree.path2id(relpath)
2827
2798
 
2862
2833
            chunks = content.splitlines(True)
2863
2834
            content = filtered_output_bytes(chunks, filters,
2864
2835
                ContentFilterContext(relpath, rev_tree))
2865
 
            self.cleanup_now()
2866
2836
            self.outf.writelines(content)
2867
2837
        else:
2868
 
            self.cleanup_now()
2869
2838
            self.outf.write(content)
2870
2839
 
2871
2840
 
2978
2947
             Option('strict',
2979
2948
                    help="Refuse to commit if there are unknown "
2980
2949
                    "files in the working tree."),
2981
 
             Option('commit-time', type=str,
2982
 
                    help="Manually set a commit time using commit date "
2983
 
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2984
2950
             ListOption('fixes', type=str,
2985
2951
                    help="Mark a bug as being fixed by this revision "
2986
2952
                         "(see \"bzr help bugs\")."),
2993
2959
                         "the master branch until a normal commit "
2994
2960
                         "is performed."
2995
2961
                    ),
2996
 
             Option('show-diff',
2997
 
                    help='When no message is supplied, show the diff along'
2998
 
                    ' with the status summary in the message editor.'),
 
2962
              Option('show-diff',
 
2963
                     help='When no message is supplied, show the diff along'
 
2964
                     ' with the status summary in the message editor.'),
2999
2965
             ]
3000
2966
    aliases = ['ci', 'checkin']
3001
2967
 
3020
2986
 
3021
2987
    def run(self, message=None, file=None, verbose=False, selected_list=None,
3022
2988
            unchanged=False, strict=False, local=False, fixes=None,
3023
 
            author=None, show_diff=False, exclude=None, commit_time=None):
 
2989
            author=None, show_diff=False, exclude=None):
3024
2990
        from bzrlib.errors import (
3025
2991
            PointlessCommit,
3026
2992
            ConflictsInTree,
3032
2998
            make_commit_message_template_encoded
3033
2999
        )
3034
3000
 
3035
 
        commit_stamp = offset = None
3036
 
        if commit_time is not None:
3037
 
            try:
3038
 
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
3039
 
            except ValueError, e:
3040
 
                raise errors.BzrCommandError(
3041
 
                    "Could not parse --commit-time: " + str(e))
3042
 
 
3043
3001
        # TODO: Need a blackbox test for invoking the external editor; may be
3044
3002
        # slightly problematic to run this cross-platform.
3045
3003
 
3065
3023
        if local and not tree.branch.get_bound_location():
3066
3024
            raise errors.LocalRequiresBoundBranch()
3067
3025
 
3068
 
        if message is not None:
3069
 
            try:
3070
 
                file_exists = osutils.lexists(message)
3071
 
            except UnicodeError:
3072
 
                # The commit message contains unicode characters that can't be
3073
 
                # represented in the filesystem encoding, so that can't be a
3074
 
                # file.
3075
 
                file_exists = False
3076
 
            if file_exists:
3077
 
                warning_msg = (
3078
 
                    'The commit message is a file name: "%(f)s".\n'
3079
 
                    '(use --file "%(f)s" to take commit message from that file)'
3080
 
                    % { 'f': message })
3081
 
                ui.ui_factory.show_warning(warning_msg)
3082
 
 
3083
3026
        def get_message(commit_obj):
3084
3027
            """Callback to get commit message"""
3085
3028
            my_message = message
3115
3058
                        specific_files=selected_list,
3116
3059
                        allow_pointless=unchanged, strict=strict, local=local,
3117
3060
                        reporter=None, verbose=verbose, revprops=properties,
3118
 
                        authors=author, timestamp=commit_stamp,
3119
 
                        timezone=offset,
 
3061
                        authors=author,
3120
3062
                        exclude=safe_relpath_files(tree, exclude))
3121
3063
        except PointlessCommit:
3122
3064
            # FIXME: This should really happen before the file is read in;
3532
3474
            verbose = not is_quiet()
3533
3475
            # TODO: should possibly lock the history file...
3534
3476
            benchfile = open(".perf_history", "at", buffering=1)
3535
 
            self.add_cleanup(benchfile.close)
3536
3477
        else:
3537
3478
            test_suite_factory = None
3538
3479
            benchfile = None
3539
 
        selftest_kwargs = {"verbose": verbose,
3540
 
                          "pattern": pattern,
3541
 
                          "stop_on_failure": one,
3542
 
                          "transport": transport,
3543
 
                          "test_suite_factory": test_suite_factory,
3544
 
                          "lsprof_timed": lsprof_timed,
3545
 
                          "lsprof_tests": lsprof_tests,
3546
 
                          "bench_history": benchfile,
3547
 
                          "matching_tests_first": first,
3548
 
                          "list_only": list_only,
3549
 
                          "random_seed": randomize,
3550
 
                          "exclude_pattern": exclude,
3551
 
                          "strict": strict,
3552
 
                          "load_list": load_list,
3553
 
                          "debug_flags": debugflag,
3554
 
                          "starting_with": starting_with
3555
 
                          }
3556
 
        selftest_kwargs.update(self.additional_selftest_args)
3557
 
        result = selftest(**selftest_kwargs)
 
3480
        try:
 
3481
            selftest_kwargs = {"verbose": verbose,
 
3482
                              "pattern": pattern,
 
3483
                              "stop_on_failure": one,
 
3484
                              "transport": transport,
 
3485
                              "test_suite_factory": test_suite_factory,
 
3486
                              "lsprof_timed": lsprof_timed,
 
3487
                              "lsprof_tests": lsprof_tests,
 
3488
                              "bench_history": benchfile,
 
3489
                              "matching_tests_first": first,
 
3490
                              "list_only": list_only,
 
3491
                              "random_seed": randomize,
 
3492
                              "exclude_pattern": exclude,
 
3493
                              "strict": strict,
 
3494
                              "load_list": load_list,
 
3495
                              "debug_flags": debugflag,
 
3496
                              "starting_with": starting_with
 
3497
                              }
 
3498
            selftest_kwargs.update(self.additional_selftest_args)
 
3499
            result = selftest(**selftest_kwargs)
 
3500
        finally:
 
3501
            if benchfile is not None:
 
3502
                benchfile.close()
3558
3503
        return int(not result)
3559
3504
 
3560
3505
 
3599
3544
        branch1 = Branch.open_containing(branch)[0]
3600
3545
        branch2 = Branch.open_containing(other)[0]
3601
3546
        branch1.lock_read()
3602
 
        self.add_cleanup(branch1.unlock)
3603
 
        branch2.lock_read()
3604
 
        self.add_cleanup(branch2.unlock)
3605
 
        last1 = ensure_null(branch1.last_revision())
3606
 
        last2 = ensure_null(branch2.last_revision())
3607
 
 
3608
 
        graph = branch1.repository.get_graph(branch2.repository)
3609
 
        base_rev_id = graph.find_unique_lca(last1, last2)
3610
 
 
3611
 
        print 'merge base is revision %s' % base_rev_id
 
3547
        try:
 
3548
            branch2.lock_read()
 
3549
            try:
 
3550
                last1 = ensure_null(branch1.last_revision())
 
3551
                last2 = ensure_null(branch2.last_revision())
 
3552
 
 
3553
                graph = branch1.repository.get_graph(branch2.repository)
 
3554
                base_rev_id = graph.find_unique_lca(last1, last2)
 
3555
 
 
3556
                print 'merge base is revision %s' % base_rev_id
 
3557
            finally:
 
3558
                branch2.unlock()
 
3559
        finally:
 
3560
            branch1.unlock()
3612
3561
 
3613
3562
 
3614
3563
class cmd_merge(Command):
3665
3614
 
3666
3615
            bzr merge -r 81..82 ../bzr.dev
3667
3616
 
3668
 
        To apply a merge directive contained in /tmp/merge::
 
3617
        To apply a merge directive contained in /tmp/merge:
3669
3618
 
3670
3619
            bzr merge /tmp/merge
3671
3620
    """
3731
3680
        view_info = _get_view_info_for_change_reporter(tree)
3732
3681
        change_reporter = delta._ChangeReporter(
3733
3682
            unversioned_filter=tree.is_ignored, view_info=view_info)
3734
 
        pb = ui.ui_factory.nested_progress_bar()
3735
 
        self.add_cleanup(pb.finished)
3736
 
        tree.lock_write()
3737
 
        self.add_cleanup(tree.unlock)
3738
 
        if location is not None:
3739
 
            try:
3740
 
                mergeable = bundle.read_mergeable_from_url(location,
3741
 
                    possible_transports=possible_transports)
3742
 
            except errors.NotABundle:
3743
 
                mergeable = None
 
3683
        cleanups = []
 
3684
        try:
 
3685
            pb = ui.ui_factory.nested_progress_bar()
 
3686
            cleanups.append(pb.finished)
 
3687
            tree.lock_write()
 
3688
            cleanups.append(tree.unlock)
 
3689
            if location is not None:
 
3690
                try:
 
3691
                    mergeable = bundle.read_mergeable_from_url(location,
 
3692
                        possible_transports=possible_transports)
 
3693
                except errors.NotABundle:
 
3694
                    mergeable = None
 
3695
                else:
 
3696
                    if uncommitted:
 
3697
                        raise errors.BzrCommandError('Cannot use --uncommitted'
 
3698
                            ' with bundles or merge directives.')
 
3699
 
 
3700
                    if revision is not None:
 
3701
                        raise errors.BzrCommandError(
 
3702
                            'Cannot use -r with merge directives or bundles')
 
3703
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3704
                       mergeable, pb)
 
3705
 
 
3706
            if merger is None and uncommitted:
 
3707
                if revision is not None and len(revision) > 0:
 
3708
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3709
                        ' --revision at the same time.')
 
3710
                merger = self.get_merger_from_uncommitted(tree, location, pb,
 
3711
                                                          cleanups)
 
3712
                allow_pending = False
 
3713
 
 
3714
            if merger is None:
 
3715
                merger, allow_pending = self._get_merger_from_branch(tree,
 
3716
                    location, revision, remember, possible_transports, pb)
 
3717
 
 
3718
            merger.merge_type = merge_type
 
3719
            merger.reprocess = reprocess
 
3720
            merger.show_base = show_base
 
3721
            self.sanity_check_merger(merger)
 
3722
            if (merger.base_rev_id == merger.other_rev_id and
 
3723
                merger.other_rev_id is not None):
 
3724
                note('Nothing to do.')
 
3725
                return 0
 
3726
            if pull:
 
3727
                if merger.interesting_files is not None:
 
3728
                    raise errors.BzrCommandError('Cannot pull individual files')
 
3729
                if (merger.base_rev_id == tree.last_revision()):
 
3730
                    result = tree.pull(merger.other_branch, False,
 
3731
                                       merger.other_rev_id)
 
3732
                    result.report(self.outf)
 
3733
                    return 0
 
3734
            if merger.this_basis is None:
 
3735
                raise errors.BzrCommandError(
 
3736
                    "This branch has no commits."
 
3737
                    " (perhaps you would prefer 'bzr pull')")
 
3738
            if preview:
 
3739
                return self._do_preview(merger, cleanups)
 
3740
            elif interactive:
 
3741
                return self._do_interactive(merger, cleanups)
3744
3742
            else:
3745
 
                if uncommitted:
3746
 
                    raise errors.BzrCommandError('Cannot use --uncommitted'
3747
 
                        ' with bundles or merge directives.')
3748
 
 
3749
 
                if revision is not None:
3750
 
                    raise errors.BzrCommandError(
3751
 
                        'Cannot use -r with merge directives or bundles')
3752
 
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
3753
 
                   mergeable, pb)
3754
 
 
3755
 
        if merger is None and uncommitted:
3756
 
            if revision is not None and len(revision) > 0:
3757
 
                raise errors.BzrCommandError('Cannot use --uncommitted and'
3758
 
                    ' --revision at the same time.')
3759
 
            merger = self.get_merger_from_uncommitted(tree, location, pb)
3760
 
            allow_pending = False
3761
 
 
3762
 
        if merger is None:
3763
 
            merger, allow_pending = self._get_merger_from_branch(tree,
3764
 
                location, revision, remember, possible_transports, pb)
3765
 
 
3766
 
        merger.merge_type = merge_type
3767
 
        merger.reprocess = reprocess
3768
 
        merger.show_base = show_base
3769
 
        self.sanity_check_merger(merger)
3770
 
        if (merger.base_rev_id == merger.other_rev_id and
3771
 
            merger.other_rev_id is not None):
3772
 
            note('Nothing to do.')
3773
 
            return 0
3774
 
        if pull:
3775
 
            if merger.interesting_files is not None:
3776
 
                raise errors.BzrCommandError('Cannot pull individual files')
3777
 
            if (merger.base_rev_id == tree.last_revision()):
3778
 
                result = tree.pull(merger.other_branch, False,
3779
 
                                   merger.other_rev_id)
3780
 
                result.report(self.outf)
3781
 
                return 0
3782
 
        if merger.this_basis is None:
3783
 
            raise errors.BzrCommandError(
3784
 
                "This branch has no commits."
3785
 
                " (perhaps you would prefer 'bzr pull')")
3786
 
        if preview:
3787
 
            return self._do_preview(merger)
3788
 
        elif interactive:
3789
 
            return self._do_interactive(merger)
3790
 
        else:
3791
 
            return self._do_merge(merger, change_reporter, allow_pending,
3792
 
                                  verified)
3793
 
 
3794
 
    def _get_preview(self, merger):
 
3743
                return self._do_merge(merger, change_reporter, allow_pending,
 
3744
                                      verified)
 
3745
        finally:
 
3746
            for cleanup in reversed(cleanups):
 
3747
                cleanup()
 
3748
 
 
3749
    def _get_preview(self, merger, cleanups):
3795
3750
        tree_merger = merger.make_merger()
3796
3751
        tt = tree_merger.make_preview_transform()
3797
 
        self.add_cleanup(tt.finalize)
 
3752
        cleanups.append(tt.finalize)
3798
3753
        result_tree = tt.get_preview_tree()
3799
3754
        return result_tree
3800
3755
 
3801
 
    def _do_preview(self, merger):
 
3756
    def _do_preview(self, merger, cleanups):
3802
3757
        from bzrlib.diff import show_diff_trees
3803
 
        result_tree = self._get_preview(merger)
 
3758
        result_tree = self._get_preview(merger, cleanups)
3804
3759
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3805
3760
                        old_label='', new_label='')
3806
3761
 
3816
3771
        else:
3817
3772
            return 0
3818
3773
 
3819
 
    def _do_interactive(self, merger):
 
3774
    def _do_interactive(self, merger, cleanups):
3820
3775
        """Perform an interactive merge.
3821
3776
 
3822
3777
        This works by generating a preview tree of the merge, then using
3824
3779
        and the preview tree.
3825
3780
        """
3826
3781
        from bzrlib import shelf_ui
3827
 
        result_tree = self._get_preview(merger)
 
3782
        result_tree = self._get_preview(merger, cleanups)
3828
3783
        writer = bzrlib.option.diff_writer_registry.get()
3829
3784
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
3830
3785
                                   reporter=shelf_ui.ApplyReporter(),
3831
3786
                                   diff_writer=writer(sys.stdout))
3832
 
        try:
3833
 
            shelver.run()
3834
 
        finally:
3835
 
            shelver.finalize()
 
3787
        shelver.run()
3836
3788
 
3837
3789
    def sanity_check_merger(self, merger):
3838
3790
        if (merger.show_base and
3898
3850
            allow_pending = True
3899
3851
        return merger, allow_pending
3900
3852
 
3901
 
    def get_merger_from_uncommitted(self, tree, location, pb):
 
3853
    def get_merger_from_uncommitted(self, tree, location, pb, cleanups):
3902
3854
        """Get a merger for uncommitted changes.
3903
3855
 
3904
3856
        :param tree: The tree the merger should apply to.
3905
3857
        :param location: The location containing uncommitted changes.
3906
3858
        :param pb: The progress bar to use for showing progress.
 
3859
        :param cleanups: A list of operations to perform to clean up the
 
3860
            temporary directories, unfinalized objects, etc.
3907
3861
        """
3908
3862
        location = self._select_branch_location(tree, location)[0]
3909
3863
        other_tree, other_path = WorkingTree.open_containing(location)
3996
3950
            merge_type = _mod_merge.Merge3Merger
3997
3951
        tree, file_list = tree_files(file_list)
3998
3952
        tree.lock_write()
3999
 
        self.add_cleanup(tree.unlock)
4000
 
        parents = tree.get_parent_ids()
4001
 
        if len(parents) != 2:
4002
 
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
4003
 
                                         " merges.  Not cherrypicking or"
4004
 
                                         " multi-merges.")
4005
 
        repository = tree.branch.repository
4006
 
        interesting_ids = None
4007
 
        new_conflicts = []
4008
 
        conflicts = tree.conflicts()
4009
 
        if file_list is not None:
4010
 
            interesting_ids = set()
4011
 
            for filename in file_list:
4012
 
                file_id = tree.path2id(filename)
4013
 
                if file_id is None:
4014
 
                    raise errors.NotVersionedError(filename)
4015
 
                interesting_ids.add(file_id)
4016
 
                if tree.kind(file_id) != "directory":
4017
 
                    continue
 
3953
        try:
 
3954
            parents = tree.get_parent_ids()
 
3955
            if len(parents) != 2:
 
3956
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
3957
                                             " merges.  Not cherrypicking or"
 
3958
                                             " multi-merges.")
 
3959
            repository = tree.branch.repository
 
3960
            interesting_ids = None
 
3961
            new_conflicts = []
 
3962
            conflicts = tree.conflicts()
 
3963
            if file_list is not None:
 
3964
                interesting_ids = set()
 
3965
                for filename in file_list:
 
3966
                    file_id = tree.path2id(filename)
 
3967
                    if file_id is None:
 
3968
                        raise errors.NotVersionedError(filename)
 
3969
                    interesting_ids.add(file_id)
 
3970
                    if tree.kind(file_id) != "directory":
 
3971
                        continue
4018
3972
 
4019
 
                for name, ie in tree.inventory.iter_entries(file_id):
4020
 
                    interesting_ids.add(ie.file_id)
4021
 
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4022
 
        else:
4023
 
            # Remerge only supports resolving contents conflicts
4024
 
            allowed_conflicts = ('text conflict', 'contents conflict')
4025
 
            restore_files = [c.path for c in conflicts
4026
 
                             if c.typestring in allowed_conflicts]
4027
 
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
4028
 
        tree.set_conflicts(ConflictList(new_conflicts))
4029
 
        if file_list is not None:
4030
 
            restore_files = file_list
4031
 
        for filename in restore_files:
 
3973
                    for name, ie in tree.inventory.iter_entries(file_id):
 
3974
                        interesting_ids.add(ie.file_id)
 
3975
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
3976
            else:
 
3977
                # Remerge only supports resolving contents conflicts
 
3978
                allowed_conflicts = ('text conflict', 'contents conflict')
 
3979
                restore_files = [c.path for c in conflicts
 
3980
                                 if c.typestring in allowed_conflicts]
 
3981
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
3982
            tree.set_conflicts(ConflictList(new_conflicts))
 
3983
            if file_list is not None:
 
3984
                restore_files = file_list
 
3985
            for filename in restore_files:
 
3986
                try:
 
3987
                    restore(tree.abspath(filename))
 
3988
                except errors.NotConflicted:
 
3989
                    pass
 
3990
            # Disable pending merges, because the file texts we are remerging
 
3991
            # have not had those merges performed.  If we use the wrong parents
 
3992
            # list, we imply that the working tree text has seen and rejected
 
3993
            # all the changes from the other tree, when in fact those changes
 
3994
            # have not yet been seen.
 
3995
            pb = ui.ui_factory.nested_progress_bar()
 
3996
            tree.set_parent_ids(parents[:1])
4032
3997
            try:
4033
 
                restore(tree.abspath(filename))
4034
 
            except errors.NotConflicted:
4035
 
                pass
4036
 
        # Disable pending merges, because the file texts we are remerging
4037
 
        # have not had those merges performed.  If we use the wrong parents
4038
 
        # list, we imply that the working tree text has seen and rejected
4039
 
        # all the changes from the other tree, when in fact those changes
4040
 
        # have not yet been seen.
4041
 
        pb = ui.ui_factory.nested_progress_bar()
4042
 
        tree.set_parent_ids(parents[:1])
4043
 
        try:
4044
 
            merger = _mod_merge.Merger.from_revision_ids(pb,
4045
 
                                                         tree, parents[1])
4046
 
            merger.interesting_ids = interesting_ids
4047
 
            merger.merge_type = merge_type
4048
 
            merger.show_base = show_base
4049
 
            merger.reprocess = reprocess
4050
 
            conflicts = merger.do_merge()
 
3998
                merger = _mod_merge.Merger.from_revision_ids(pb,
 
3999
                                                             tree, parents[1])
 
4000
                merger.interesting_ids = interesting_ids
 
4001
                merger.merge_type = merge_type
 
4002
                merger.show_base = show_base
 
4003
                merger.reprocess = reprocess
 
4004
                conflicts = merger.do_merge()
 
4005
            finally:
 
4006
                tree.set_parent_ids(parents)
 
4007
                pb.finished()
4051
4008
        finally:
4052
 
            tree.set_parent_ids(parents)
4053
 
            pb.finished()
 
4009
            tree.unlock()
4054
4010
        if conflicts > 0:
4055
4011
            return 1
4056
4012
        else:
4078
4034
    name.  If you name a directory, all the contents of that directory will be
4079
4035
    reverted.
4080
4036
 
4081
 
    If you have newly added files since the target revision, they will be
4082
 
    removed.  If the files to be removed have been changed, backups will be
4083
 
    created as above.  Directories containing unknown files will not be
4084
 
    deleted.
 
4037
    Any files that have been newly added since that revision will be deleted,
 
4038
    with a backup kept if appropriate.  Directories containing unknown files
 
4039
    will not be deleted.
4085
4040
 
4086
4041
    The working tree contains a list of pending merged revisions, which will
4087
4042
    be included as parents in the next commit.  Normally, revert clears that
4090
4045
    revert ." in the tree root to revert all files but keep the merge record,
4091
4046
    and "bzr revert --forget-merges" to clear the pending merge list without
4092
4047
    reverting any files.
4093
 
 
4094
 
    Using "bzr revert --forget-merges", it is possible to apply the changes
4095
 
    from an arbitrary merge as a single revision.  To do this, perform the
4096
 
    merge as desired.  Then doing revert with the "--forget-merges" option will
4097
 
    keep the content of the tree as it was, but it will clear the list of
4098
 
    pending merges.  The next commit will then contain all of the changes that
4099
 
    would have been in the merge, but without any mention of the other parent
4100
 
    revisions.  Because this technique forgets where these changes originated,
4101
 
    it may cause additional conflicts on later merges involving the source and
4102
 
    target branches.
4103
4048
    """
4104
4049
 
4105
4050
    _see_also = ['cat', 'export']
4115
4060
            forget_merges=None):
4116
4061
        tree, file_list = tree_files(file_list)
4117
4062
        tree.lock_write()
4118
 
        self.add_cleanup(tree.unlock)
4119
 
        if forget_merges:
4120
 
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4121
 
        else:
4122
 
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
4063
        try:
 
4064
            if forget_merges:
 
4065
                tree.set_parent_ids(tree.get_parent_ids()[:1])
 
4066
            else:
 
4067
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
4068
        finally:
 
4069
            tree.unlock()
4123
4070
 
4124
4071
    @staticmethod
4125
4072
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4184
4131
    To filter on a range of revisions, you can use the command -r begin..end
4185
4132
    -r revision requests a specific revision, -r ..end or -r begin.. are
4186
4133
    also valid.
4187
 
            
4188
 
    :Exit values:
4189
 
        1 - some missing revisions
4190
 
        0 - no missing revisions
4191
4134
 
4192
4135
    :Examples:
4193
4136
 
4276
4219
        if remote_branch.base == local_branch.base:
4277
4220
            remote_branch = local_branch
4278
4221
 
4279
 
        local_branch.lock_read()
4280
 
        self.add_cleanup(local_branch.unlock)
4281
4222
        local_revid_range = _revision_range_to_revid_range(
4282
4223
            _get_revision_range(my_revision, local_branch,
4283
4224
                self.name()))
4284
4225
 
4285
 
        remote_branch.lock_read()
4286
 
        self.add_cleanup(remote_branch.unlock)
4287
4226
        remote_revid_range = _revision_range_to_revid_range(
4288
4227
            _get_revision_range(revision,
4289
4228
                remote_branch, self.name()))
4290
4229
 
4291
 
        local_extra, remote_extra = find_unmerged(
4292
 
            local_branch, remote_branch, restrict,
4293
 
            backward=not reverse,
4294
 
            include_merges=include_merges,
4295
 
            local_revid_range=local_revid_range,
4296
 
            remote_revid_range=remote_revid_range)
4297
 
 
4298
 
        if log_format is None:
4299
 
            registry = log.log_formatter_registry
4300
 
            log_format = registry.get_default(local_branch)
4301
 
        lf = log_format(to_file=self.outf,
4302
 
                        show_ids=show_ids,
4303
 
                        show_timezone='original')
4304
 
 
4305
 
        status_code = 0
4306
 
        if local_extra and not theirs_only:
4307
 
            message("You have %d extra revision(s):\n" %
4308
 
                len(local_extra))
4309
 
            for revision in iter_log_revisions(local_extra,
4310
 
                                local_branch.repository,
4311
 
                                verbose):
4312
 
                lf.log_revision(revision)
4313
 
            printed_local = True
4314
 
            status_code = 1
4315
 
        else:
4316
 
            printed_local = False
4317
 
 
4318
 
        if remote_extra and not mine_only:
4319
 
            if printed_local is True:
4320
 
                message("\n\n\n")
4321
 
            message("You are missing %d revision(s):\n" %
4322
 
                len(remote_extra))
4323
 
            for revision in iter_log_revisions(remote_extra,
4324
 
                                remote_branch.repository,
4325
 
                                verbose):
4326
 
                lf.log_revision(revision)
4327
 
            status_code = 1
4328
 
 
4329
 
        if mine_only and not local_extra:
4330
 
            # We checked local, and found nothing extra
4331
 
            message('This branch is up to date.\n')
4332
 
        elif theirs_only and not remote_extra:
4333
 
            # We checked remote, and found nothing extra
4334
 
            message('Other branch is up to date.\n')
4335
 
        elif not (mine_only or theirs_only or local_extra or
4336
 
                  remote_extra):
4337
 
            # We checked both branches, and neither one had extra
4338
 
            # revisions
4339
 
            message("Branches are up to date.\n")
4340
 
        self.cleanup_now()
 
4230
        local_branch.lock_read()
 
4231
        try:
 
4232
            remote_branch.lock_read()
 
4233
            try:
 
4234
                local_extra, remote_extra = find_unmerged(
 
4235
                    local_branch, remote_branch, restrict,
 
4236
                    backward=not reverse,
 
4237
                    include_merges=include_merges,
 
4238
                    local_revid_range=local_revid_range,
 
4239
                    remote_revid_range=remote_revid_range)
 
4240
 
 
4241
                if log_format is None:
 
4242
                    registry = log.log_formatter_registry
 
4243
                    log_format = registry.get_default(local_branch)
 
4244
                lf = log_format(to_file=self.outf,
 
4245
                                show_ids=show_ids,
 
4246
                                show_timezone='original')
 
4247
 
 
4248
                status_code = 0
 
4249
                if local_extra and not theirs_only:
 
4250
                    message("You have %d extra revision(s):\n" %
 
4251
                        len(local_extra))
 
4252
                    for revision in iter_log_revisions(local_extra,
 
4253
                                        local_branch.repository,
 
4254
                                        verbose):
 
4255
                        lf.log_revision(revision)
 
4256
                    printed_local = True
 
4257
                    status_code = 1
 
4258
                else:
 
4259
                    printed_local = False
 
4260
 
 
4261
                if remote_extra and not mine_only:
 
4262
                    if printed_local is True:
 
4263
                        message("\n\n\n")
 
4264
                    message("You are missing %d revision(s):\n" %
 
4265
                        len(remote_extra))
 
4266
                    for revision in iter_log_revisions(remote_extra,
 
4267
                                        remote_branch.repository,
 
4268
                                        verbose):
 
4269
                        lf.log_revision(revision)
 
4270
                    status_code = 1
 
4271
 
 
4272
                if mine_only and not local_extra:
 
4273
                    # We checked local, and found nothing extra
 
4274
                    message('This branch is up to date.\n')
 
4275
                elif theirs_only and not remote_extra:
 
4276
                    # We checked remote, and found nothing extra
 
4277
                    message('Other branch is up to date.\n')
 
4278
                elif not (mine_only or theirs_only or local_extra or
 
4279
                          remote_extra):
 
4280
                    # We checked both branches, and neither one had extra
 
4281
                    # revisions
 
4282
                    message("Branches are up to date.\n")
 
4283
            finally:
 
4284
                remote_branch.unlock()
 
4285
        finally:
 
4286
            local_branch.unlock()
4341
4287
        if not status_code and parent is None and other_branch is not None:
4342
4288
            local_branch.lock_write()
4343
 
            self.add_cleanup(local_branch.unlock)
4344
 
            # handle race conditions - a parent might be set while we run.
4345
 
            if local_branch.get_parent() is None:
4346
 
                local_branch.set_parent(remote_branch.base)
 
4289
            try:
 
4290
                # handle race conditions - a parent might be set while we run.
 
4291
                if local_branch.get_parent() is None:
 
4292
                    local_branch.set_parent(remote_branch.base)
 
4293
            finally:
 
4294
                local_branch.unlock()
4347
4295
        return status_code
4348
4296
 
4349
4297
 
4428
4376
        else:
4429
4377
            b = Branch.open(branch)
4430
4378
        b.lock_read()
4431
 
        self.add_cleanup(b.unlock)
4432
 
        if revision is None:
4433
 
            rev_id = b.last_revision()
4434
 
        else:
4435
 
            rev_id = revision[0].as_revision_id(b)
4436
 
        t = testament_class.from_revision(b.repository, rev_id)
4437
 
        if long:
4438
 
            sys.stdout.writelines(t.as_text_lines())
4439
 
        else:
4440
 
            sys.stdout.write(t.as_short_text())
 
4379
        try:
 
4380
            if revision is None:
 
4381
                rev_id = b.last_revision()
 
4382
            else:
 
4383
                rev_id = revision[0].as_revision_id(b)
 
4384
            t = testament_class.from_revision(b.repository, rev_id)
 
4385
            if long:
 
4386
                sys.stdout.writelines(t.as_text_lines())
 
4387
            else:
 
4388
                sys.stdout.write(t.as_short_text())
 
4389
        finally:
 
4390
            b.unlock()
4441
4391
 
4442
4392
 
4443
4393
class cmd_annotate(Command):
4469
4419
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
4470
4420
        if wt is not None:
4471
4421
            wt.lock_read()
4472
 
            self.add_cleanup(wt.unlock)
4473
4422
        else:
4474
4423
            branch.lock_read()
4475
 
            self.add_cleanup(branch.unlock)
4476
 
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
4477
 
        tree.lock_read()
4478
 
        self.add_cleanup(tree.unlock)
4479
 
        if wt is not None:
4480
 
            file_id = wt.path2id(relpath)
4481
 
        else:
4482
 
            file_id = tree.path2id(relpath)
4483
 
        if file_id is None:
4484
 
            raise errors.NotVersionedError(filename)
4485
 
        file_version = tree.inventory[file_id].revision
4486
 
        if wt is not None and revision is None:
4487
 
            # If there is a tree and we're not annotating historical
4488
 
            # versions, annotate the working tree's content.
4489
 
            annotate_file_tree(wt, file_id, self.outf, long, all,
4490
 
                show_ids=show_ids)
4491
 
        else:
4492
 
            annotate_file(branch, file_version, file_id, long, all, self.outf,
4493
 
                          show_ids=show_ids)
 
4424
        try:
 
4425
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4426
            if wt is not None:
 
4427
                file_id = wt.path2id(relpath)
 
4428
            else:
 
4429
                file_id = tree.path2id(relpath)
 
4430
            if file_id is None:
 
4431
                raise errors.NotVersionedError(filename)
 
4432
            file_version = tree.inventory[file_id].revision
 
4433
            if wt is not None and revision is None:
 
4434
                # If there is a tree and we're not annotating historical
 
4435
                # versions, annotate the working tree's content.
 
4436
                annotate_file_tree(wt, file_id, self.outf, long, all,
 
4437
                    show_ids=show_ids)
 
4438
            else:
 
4439
                annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4440
                              show_ids=show_ids)
 
4441
        finally:
 
4442
            if wt is not None:
 
4443
                wt.unlock()
 
4444
            else:
 
4445
                branch.unlock()
4494
4446
 
4495
4447
 
4496
4448
class cmd_re_sign(Command):
4508
4460
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4509
4461
        b = WorkingTree.open_containing(u'.')[0].branch
4510
4462
        b.lock_write()
4511
 
        self.add_cleanup(b.unlock)
4512
 
        return self._run(b, revision_id_list, revision)
 
4463
        try:
 
4464
            return self._run(b, revision_id_list, revision)
 
4465
        finally:
 
4466
            b.unlock()
4513
4467
 
4514
4468
    def _run(self, b, revision_id_list, revision):
4515
4469
        import bzrlib.gpg as gpg
4661
4615
 
4662
4616
        if tree is not None:
4663
4617
            tree.lock_write()
4664
 
            self.add_cleanup(tree.unlock)
4665
4618
        else:
4666
4619
            b.lock_write()
4667
 
            self.add_cleanup(b.unlock)
4668
 
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
 
4620
        try:
 
4621
            return self._run(b, tree, dry_run, verbose, revision, force,
 
4622
                             local=local)
 
4623
        finally:
 
4624
            if tree is not None:
 
4625
                tree.unlock()
 
4626
            else:
 
4627
                b.unlock()
4669
4628
 
4670
4629
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4671
4630
        from bzrlib.log import log_formatter, show_log
4728
4687
    CAUTION: Locks should only be broken when you are sure that the process
4729
4688
    holding the lock has been stopped.
4730
4689
 
4731
 
    You can get information on what locks are open via the 'bzr info
4732
 
    [location]' command.
 
4690
    You can get information on what locks are open via the 'bzr info' command.
4733
4691
 
4734
4692
    :Examples:
4735
4693
        bzr break-lock
4736
 
        bzr break-lock bzr+ssh://example.com/bzr/foo
4737
4694
    """
4738
4695
    takes_args = ['location?']
4739
4696
 
4769
4726
    takes_options = [
4770
4727
        Option('inet',
4771
4728
               help='Serve on stdin/out for use from inetd or sshd.'),
4772
 
        RegistryOption('protocol',
4773
 
               help="Protocol to serve.",
 
4729
        RegistryOption('protocol', 
 
4730
               help="Protocol to serve.", 
4774
4731
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
4775
4732
               value_switches=True),
4776
4733
        Option('port',
4785
4742
        Option('allow-writes',
4786
4743
               help='By default the server is a readonly server.  Supplying '
4787
4744
                    '--allow-writes enables write access to the contents of '
4788
 
                    'the served directory and below.  Note that ``bzr serve`` '
4789
 
                    'does not perform authentication, so unless some form of '
4790
 
                    'external authentication is arranged supplying this '
4791
 
                    'option leads to global uncontrolled write access to your '
4792
 
                    'file system.'
 
4745
                    'the served directory and below.'
4793
4746
                ),
4794
4747
        ]
4795
4748
 
5011
4964
      directly from the merge directive, without retrieving data from a
5012
4965
      branch.
5013
4966
 
5014
 
    `bzr send` creates a compact data set that, when applied using bzr
5015
 
    merge, has the same effect as merging from the source branch.  
5016
 
    
5017
 
    By default the merge directive is self-contained and can be applied to any
5018
 
    branch containing submit_branch in its ancestory without needing access to
5019
 
    the source branch.
5020
 
    
5021
 
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
5022
 
    revisions, but only a structured request to merge from the
5023
 
    public_location.  In that case the public_branch is needed and it must be
5024
 
    up-to-date and accessible to the recipient.  The public_branch is always
5025
 
    included if known, so that people can check it later.
5026
 
 
5027
 
    The submit branch defaults to the parent of the source branch, but can be
5028
 
    overridden.  Both submit branch and public branch will be remembered in
5029
 
    branch.conf the first time they are used for a particular branch.  The
5030
 
    source branch defaults to that containing the working directory, but can
5031
 
    be changed using --from.
5032
 
 
5033
 
    In order to calculate those changes, bzr must analyse the submit branch.
5034
 
    Therefore it is most efficient for the submit branch to be a local mirror.
5035
 
    If a public location is known for the submit_branch, that location is used
5036
 
    in the merge directive.
5037
 
 
5038
 
    The default behaviour is to send the merge directive by mail, unless -o is
5039
 
    given, in which case it is sent to a file.
 
4967
    If --no-bundle is specified, then public_branch is needed (and must be
 
4968
    up-to-date), so that the receiver can perform the merge using the
 
4969
    public_branch.  The public_branch is always included if known, so that
 
4970
    people can check it later.
 
4971
 
 
4972
    The submit branch defaults to the parent, but can be overridden.  Both
 
4973
    submit branch and public branch will be remembered if supplied.
 
4974
 
 
4975
    If a public_branch is known for the submit_branch, that public submit
 
4976
    branch is used in the merge instructions.  This means that a local mirror
 
4977
    can be used as your actual submit branch, once you have set public_branch
 
4978
    for that mirror.
5040
4979
 
5041
4980
    Mail is sent using your preferred mail program.  This should be transparent
5042
4981
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
5062
5001
 
5063
5002
    The merge directives created by bzr send may be applied using bzr merge or
5064
5003
    bzr pull by specifying a file containing a merge directive as the location.
5065
 
 
5066
 
    bzr send makes extensive use of public locations to map local locations into
5067
 
    URLs that can be used by other people.  See `bzr help configuration` to
5068
 
    set them, and use `bzr info` to display them.
5069
5004
    """
5070
5005
 
5071
5006
    encoding_type = 'exact'
5230
5165
            ):
5231
5166
        branch, relpath = Branch.open_containing(directory)
5232
5167
        branch.lock_write()
5233
 
        self.add_cleanup(branch.unlock)
5234
 
        if delete:
5235
 
            branch.tags.delete_tag(tag_name)
5236
 
            self.outf.write('Deleted tag %s.\n' % tag_name)
5237
 
        else:
5238
 
            if revision:
5239
 
                if len(revision) != 1:
5240
 
                    raise errors.BzrCommandError(
5241
 
                        "Tags can only be placed on a single revision, "
5242
 
                        "not on a range")
5243
 
                revision_id = revision[0].as_revision_id(branch)
 
5168
        try:
 
5169
            if delete:
 
5170
                branch.tags.delete_tag(tag_name)
 
5171
                self.outf.write('Deleted tag %s.\n' % tag_name)
5244
5172
            else:
5245
 
                revision_id = branch.last_revision()
5246
 
            if (not force) and branch.tags.has_tag(tag_name):
5247
 
                raise errors.TagAlreadyExists(tag_name)
5248
 
            branch.tags.set_tag(tag_name, revision_id)
5249
 
            self.outf.write('Created tag %s.\n' % tag_name)
 
5173
                if revision:
 
5174
                    if len(revision) != 1:
 
5175
                        raise errors.BzrCommandError(
 
5176
                            "Tags can only be placed on a single revision, "
 
5177
                            "not on a range")
 
5178
                    revision_id = revision[0].as_revision_id(branch)
 
5179
                else:
 
5180
                    revision_id = branch.last_revision()
 
5181
                if (not force) and branch.tags.has_tag(tag_name):
 
5182
                    raise errors.TagAlreadyExists(tag_name)
 
5183
                branch.tags.set_tag(tag_name, revision_id)
 
5184
                self.outf.write('Created tag %s.\n' % tag_name)
 
5185
        finally:
 
5186
            branch.unlock()
5250
5187
 
5251
5188
 
5252
5189
class cmd_tags(Command):
5285
5222
            return
5286
5223
 
5287
5224
        branch.lock_read()
5288
 
        self.add_cleanup(branch.unlock)
5289
 
        if revision:
5290
 
            graph = branch.repository.get_graph()
5291
 
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
5292
 
            revid1, revid2 = rev1.rev_id, rev2.rev_id
5293
 
            # only show revisions between revid1 and revid2 (inclusive)
5294
 
            tags = [(tag, revid) for tag, revid in tags if
5295
 
                graph.is_between(revid, revid1, revid2)]
5296
 
        if sort == 'alpha':
5297
 
            tags.sort()
5298
 
        elif sort == 'time':
5299
 
            timestamps = {}
5300
 
            for tag, revid in tags:
5301
 
                try:
5302
 
                    revobj = branch.repository.get_revision(revid)
5303
 
                except errors.NoSuchRevision:
5304
 
                    timestamp = sys.maxint # place them at the end
5305
 
                else:
5306
 
                    timestamp = revobj.timestamp
5307
 
                timestamps[revid] = timestamp
5308
 
            tags.sort(key=lambda x: timestamps[x[1]])
5309
 
        if not show_ids:
5310
 
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5311
 
            for index, (tag, revid) in enumerate(tags):
5312
 
                try:
5313
 
                    revno = branch.revision_id_to_dotted_revno(revid)
5314
 
                    if isinstance(revno, tuple):
5315
 
                        revno = '.'.join(map(str, revno))
5316
 
                except errors.NoSuchRevision:
5317
 
                    # Bad tag data/merges can lead to tagged revisions
5318
 
                    # which are not in this branch. Fail gracefully ...
5319
 
                    revno = '?'
5320
 
                tags[index] = (tag, revno)
5321
 
        self.cleanup_now()
 
5225
        try:
 
5226
            if revision:
 
5227
                graph = branch.repository.get_graph()
 
5228
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5229
                revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5230
                # only show revisions between revid1 and revid2 (inclusive)
 
5231
                tags = [(tag, revid) for tag, revid in tags if
 
5232
                    graph.is_between(revid, revid1, revid2)]
 
5233
            if sort == 'alpha':
 
5234
                tags.sort()
 
5235
            elif sort == 'time':
 
5236
                timestamps = {}
 
5237
                for tag, revid in tags:
 
5238
                    try:
 
5239
                        revobj = branch.repository.get_revision(revid)
 
5240
                    except errors.NoSuchRevision:
 
5241
                        timestamp = sys.maxint # place them at the end
 
5242
                    else:
 
5243
                        timestamp = revobj.timestamp
 
5244
                    timestamps[revid] = timestamp
 
5245
                tags.sort(key=lambda x: timestamps[x[1]])
 
5246
            if not show_ids:
 
5247
                # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5248
                for index, (tag, revid) in enumerate(tags):
 
5249
                    try:
 
5250
                        revno = branch.revision_id_to_dotted_revno(revid)
 
5251
                        if isinstance(revno, tuple):
 
5252
                            revno = '.'.join(map(str, revno))
 
5253
                    except errors.NoSuchRevision:
 
5254
                        # Bad tag data/merges can lead to tagged revisions
 
5255
                        # which are not in this branch. Fail gracefully ...
 
5256
                        revno = '?'
 
5257
                    tags[index] = (tag, revno)
 
5258
        finally:
 
5259
            branch.unlock()
5322
5260
        for tag, revspec in tags:
5323
5261
            self.outf.write('%-20s %s\n' % (tag, revspec))
5324
5262
 
5437
5375
    that of the master.
5438
5376
    """
5439
5377
 
5440
 
    takes_args = ['to_location?']
 
5378
    takes_args = ['to_location']
5441
5379
    takes_options = [Option('force',
5442
5380
                        help='Switch even if local commits will be lost.'),
5443
 
                     'revision',
5444
5381
                     Option('create-branch', short_name='b',
5445
5382
                        help='Create the target branch from this one before'
5446
5383
                             ' switching to it.'),
5447
 
                    ]
 
5384
                     ]
5448
5385
 
5449
 
    def run(self, to_location=None, force=False, create_branch=False,
5450
 
            revision=None):
 
5386
    def run(self, to_location, force=False, create_branch=False):
5451
5387
        from bzrlib import switch
5452
5388
        tree_location = '.'
5453
 
        revision = _get_one_revision('switch', revision)
5454
5389
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5455
 
        if to_location is None:
5456
 
            if revision is None:
5457
 
                raise errors.BzrCommandError('You must supply either a'
5458
 
                                             ' revision or a location')
5459
 
            to_location = '.'
5460
5390
        try:
5461
5391
            branch = control_dir.open_branch()
5462
5392
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5467
5397
            if branch is None:
5468
5398
                raise errors.BzrCommandError('cannot create branch without'
5469
5399
                                             ' source branch')
5470
 
            to_location = directory_service.directories.dereference(
5471
 
                              to_location)
5472
5400
            if '/' not in to_location and '\\' not in to_location:
5473
5401
                # This path is meant to be relative to the existing branch
5474
5402
                this_url = self._get_branch_location(control_dir)
5476
5404
            to_branch = branch.bzrdir.sprout(to_location,
5477
5405
                                 possible_transports=[branch.bzrdir.root_transport],
5478
5406
                                 source_branch=branch).open_branch()
 
5407
            # try:
 
5408
            #     from_branch = control_dir.open_branch()
 
5409
            # except errors.NotBranchError:
 
5410
            #     raise BzrCommandError('Cannot create a branch from this'
 
5411
            #         ' location when we cannot open this branch')
 
5412
            # from_branch.bzrdir.sprout(
 
5413
            pass
5479
5414
        else:
5480
5415
            try:
5481
5416
                to_branch = Branch.open(to_location)
5483
5418
                this_url = self._get_branch_location(control_dir)
5484
5419
                to_branch = Branch.open(
5485
5420
                    urlutils.join(this_url, '..', to_location))
5486
 
        if revision is not None:
5487
 
            revision = revision.as_revision_id(to_branch)
5488
 
        switch.switch(control_dir, to_branch, force, revision_id=revision)
 
5421
        switch.switch(control_dir, to_branch, force)
5489
5422
        if had_explicit_nick:
5490
5423
            branch = control_dir.open_branch() #get the new branch!
5491
5424
            branch.nick = to_branch.nick
5745
5678
    def run_for_list(self):
5746
5679
        tree = WorkingTree.open_containing('.')[0]
5747
5680
        tree.lock_read()
5748
 
        self.add_cleanup(tree.unlock)
5749
 
        manager = tree.get_shelf_manager()
5750
 
        shelves = manager.active_shelves()
5751
 
        if len(shelves) == 0:
5752
 
            note('No shelved changes.')
5753
 
            return 0
5754
 
        for shelf_id in reversed(shelves):
5755
 
            message = manager.get_metadata(shelf_id).get('message')
5756
 
            if message is None:
5757
 
                message = '<no message>'
5758
 
            self.outf.write('%3d: %s\n' % (shelf_id, message))
5759
 
        return 1
 
5681
        try:
 
5682
            manager = tree.get_shelf_manager()
 
5683
            shelves = manager.active_shelves()
 
5684
            if len(shelves) == 0:
 
5685
                note('No shelved changes.')
 
5686
                return 0
 
5687
            for shelf_id in reversed(shelves):
 
5688
                message = manager.get_metadata(shelf_id).get('message')
 
5689
                if message is None:
 
5690
                    message = '<no message>'
 
5691
                self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5692
            return 1
 
5693
        finally:
 
5694
            tree.unlock()
5760
5695
 
5761
5696
 
5762
5697
class cmd_unshelve(Command):
5774
5709
            enum_switch=False, value_switches=True,
5775
5710
            apply="Apply changes and remove from the shelf.",
5776
5711
            dry_run="Show changes, but do not apply or remove them.",
5777
 
            preview="Instead of unshelving the changes, show the diff that "
5778
 
                    "would result from unshelving.",
5779
 
            delete_only="Delete changes without applying them.",
5780
 
            keep="Apply changes but don't delete them.",
 
5712
            delete_only="Delete changes without applying them."
5781
5713
        )
5782
5714
    ]
5783
5715
    _see_also = ['shelve']