~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: 2006-09-17 21:19:56 UTC
  • mfrom: (1997.1.6 bind-does-not-push-or-pull)
  • Revision ID: pqm@pqm.ubuntu.com-20060917211956-6e30d07da410fd1a
(Robert Collins) Change the Branch bind method to just bind rather than binding and pushing (fixes #43744 and #39542)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2004, 2005, 2006 by 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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
20
import codecs
21
21
import errno
22
22
import os
23
 
from shutil import rmtree
 
23
import os.path
24
24
import sys
25
25
 
26
26
import bzrlib
27
 
import bzrlib.branch
28
 
from bzrlib.branch import Branch
29
 
import bzrlib.bzrdir as bzrdir
30
 
from bzrlib.bundle.read_bundle import BundleReader
31
 
from bzrlib.bundle.apply_bundle import merge_bundle
 
27
from bzrlib import (
 
28
    branch,
 
29
    bundle,
 
30
    bzrdir,
 
31
    config,
 
32
    errors,
 
33
    ignores,
 
34
    log,
 
35
    osutils,
 
36
    repository,
 
37
    transport,
 
38
    ui,
 
39
    urlutils,
 
40
    )
 
41
from bzrlib.branch import Branch, BranchReferenceFormat
 
42
from bzrlib.bundle import read_bundle_from_url
 
43
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
 
44
from bzrlib.conflicts import ConflictList
32
45
from bzrlib.commands import Command, display_command
33
 
import bzrlib.errors as errors
34
46
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
35
47
                           NotBranchError, DivergedBranches, NotConflicted,
36
48
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
37
49
                           NotVersionedError, NotABundle)
38
 
from bzrlib.log import show_one_log
39
50
from bzrlib.merge import Merge3Merger
40
51
from bzrlib.option import Option
41
 
import bzrlib.osutils
42
52
from bzrlib.progress import DummyProgress, ProgressPhase
43
53
from bzrlib.revision import common_ancestor
44
54
from bzrlib.revisionspec import RevisionSpec
45
 
import bzrlib.trace
46
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
 
55
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
47
56
from bzrlib.transport.local import LocalTransport
48
 
import bzrlib.ui
49
 
import bzrlib.urlutils as urlutils
50
57
from bzrlib.workingtree import WorkingTree
51
58
 
52
59
 
94
101
        return bzrdir.BzrDirMetaFormat1()
95
102
    if typestring == "metaweave":
96
103
        format = bzrdir.BzrDirMetaFormat1()
97
 
        format.repository_format = bzrlib.repository.RepositoryFormat7()
 
104
        format.repository_format = repository.RepositoryFormat7()
98
105
        return format
99
106
    if typestring == "knit":
100
107
        format = bzrdir.BzrDirMetaFormat1()
101
 
        format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
 
108
        format.repository_format = repository.RepositoryFormatKnit1()
 
109
        return format
 
110
    if typestring == "experimental-knit2":
 
111
        format = bzrdir.BzrDirMetaFormat1()
 
112
        format.repository_format = repository.RepositoryFormatKnit2()
102
113
        return format
103
114
    msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
104
115
          "metaweave and weave" % typestring
132
143
    modified
133
144
        Text has changed since the previous revision.
134
145
 
135
 
    unchanged
136
 
        Nothing about this file has changed since the previous revision.
137
 
        Only shown with --all.
138
 
 
139
146
    unknown
140
147
        Not versioned and not matching an ignore pattern.
141
148
 
154
161
    # TODO: --no-recurse, --recurse options
155
162
    
156
163
    takes_args = ['file*']
157
 
    takes_options = ['all', 'show-ids', 'revision']
 
164
    takes_options = ['show-ids', 'revision']
158
165
    aliases = ['st', 'stat']
159
166
 
160
167
    encoding_type = 'replace'
161
168
    
162
169
    @display_command
163
 
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
 
170
    def run(self, show_ids=False, file_list=None, revision=None):
164
171
        from bzrlib.status import show_tree_status
165
172
 
166
173
        tree, file_list = tree_files(file_list)
167
174
            
168
 
        show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
 
175
        show_tree_status(tree, show_ids=show_ids,
169
176
                         specific_files=file_list, revision=revision,
170
177
                         to_file=self.outf)
171
178
 
232
239
            revs.extend(revision)
233
240
        if revision_info_list is not None:
234
241
            for rev in revision_info_list:
235
 
                revs.append(RevisionSpec(rev))
 
242
                revs.append(RevisionSpec.from_string(rev))
236
243
        if len(revs) == 0:
237
244
            raise BzrCommandError('You must supply a revision identifier')
238
245
 
271
278
 
272
279
    --dry-run will show which files would be added, but not actually 
273
280
    add them.
 
281
 
 
282
    --file-ids-from will try to use the file ids from the supplied path.
 
283
    It looks up ids trying to find a matching parent directory with the
 
284
    same filename, and then by pure path.
274
285
    """
275
286
    takes_args = ['file*']
276
 
    takes_options = ['no-recurse', 'dry-run', 'verbose']
 
287
    takes_options = ['no-recurse', 'dry-run', 'verbose',
 
288
                     Option('file-ids-from', type=unicode,
 
289
                            help='Lookup file ids from here')]
277
290
    encoding_type = 'replace'
278
291
 
279
 
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
 
292
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
 
293
            file_ids_from=None):
280
294
        import bzrlib.add
281
295
 
282
 
        action = bzrlib.add.AddAction(to_file=self.outf,
283
 
            should_print=(not is_quiet()))
284
 
 
285
 
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
 
296
        if file_ids_from is not None:
 
297
            try:
 
298
                base_tree, base_path = WorkingTree.open_containing(
 
299
                                            file_ids_from)
 
300
            except errors.NoWorkingTree:
 
301
                base_branch, base_path = branch.Branch.open_containing(
 
302
                                            file_ids_from)
 
303
                base_tree = base_branch.basis_tree()
 
304
 
 
305
            action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
 
306
                          to_file=self.outf, should_print=(not is_quiet()))
 
307
        else:
 
308
            action = bzrlib.add.AddAction(to_file=self.outf,
 
309
                should_print=(not is_quiet()))
 
310
 
 
311
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
286
312
                                              action=action, save=not dry_run)
287
313
        if len(ignored) > 0:
288
314
            if verbose:
383
409
    encoding_type = 'replace'
384
410
 
385
411
    def run(self, names_list):
 
412
        if names_list is None:
 
413
            names_list = []
 
414
 
386
415
        if len(names_list) < 2:
387
416
            raise BzrCommandError("missing file argument")
388
417
        tree, rel_names = tree_files(names_list)
410
439
    from one into the other.  Once one branch has merged, the other should
411
440
    be able to pull it again.
412
441
 
413
 
    If branches have diverged, you can use 'bzr merge' to pull the text changes
414
 
    from one into the other.  Once one branch has merged, the other should
415
 
    be able to pull it again.
416
 
 
417
442
    If you want to forget your local changes and just update your branch to
418
443
    match the remote one, use pull --overwrite.
419
444
 
420
445
    If there is no default location set, the first pull will set it.  After
421
446
    that, you can omit the location to use the default.  To change the
422
 
    default, use --remember.
 
447
    default, use --remember. The value will only be saved if the remote
 
448
    location can be accessed.
423
449
    """
424
450
 
425
451
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
434
460
        except NoWorkingTree:
435
461
            tree_to = None
436
462
            branch_to = Branch.open_containing(u'.')[0]
 
463
 
 
464
        reader = None
 
465
        if location is not None:
 
466
            try:
 
467
                reader = bundle.read_bundle_from_url(location)
 
468
            except NotABundle:
 
469
                pass # Continue on considering this url a Branch
 
470
 
437
471
        stored_loc = branch_to.get_parent()
438
472
        if location is None:
439
473
            if stored_loc is None:
444
478
                self.outf.write("Using saved location: %s\n" % display_url)
445
479
                location = stored_loc
446
480
 
447
 
        branch_from = Branch.open(location)
448
 
 
449
 
        if branch_to.get_parent() is None or remember:
450
 
            branch_to.set_parent(branch_from.base)
451
 
 
 
481
 
 
482
        if reader is not None:
 
483
            install_bundle(branch_to.repository, reader)
 
484
            branch_from = branch_to
 
485
        else:
 
486
            branch_from = Branch.open(location)
 
487
 
 
488
            if branch_to.get_parent() is None or remember:
 
489
                branch_to.set_parent(branch_from.base)
 
490
 
 
491
        rev_id = None
452
492
        if revision is None:
453
 
            rev_id = None
 
493
            if reader is not None:
 
494
                rev_id = reader.target
454
495
        elif len(revision) == 1:
455
496
            rev_id = revision[0].in_history(branch_from).rev_id
456
497
        else:
494
535
 
495
536
    If there is no default push location set, the first push will set it.
496
537
    After that, you can omit the location to use the default.  To change the
497
 
    default, use --remember.
 
538
    default, use --remember. The value will only be saved if the remote
 
539
    location can be accessed.
498
540
    """
499
541
 
500
542
    takes_options = ['remember', 'overwrite', 'verbose',
508
550
            create_prefix=False, verbose=False):
509
551
        # FIXME: Way too big!  Put this into a function called from the
510
552
        # command.
511
 
        from bzrlib.transport import get_transport
512
553
        
513
554
        br_from = Branch.open_containing('.')[0]
514
555
        stored_loc = br_from.get_push_location()
518
559
            else:
519
560
                display_url = urlutils.unescape_for_display(stored_loc,
520
561
                        self.outf.encoding)
521
 
                self.outf.write("Using saved location: %s" % display_url)
 
562
                self.outf.write("Using saved location: %s\n" % display_url)
522
563
                location = stored_loc
523
564
 
524
 
        transport = get_transport(location)
525
 
        location_url = transport.base
526
 
        if br_from.get_push_location() is None or remember:
527
 
            br_from.set_push_location(location_url)
 
565
        to_transport = transport.get_transport(location)
 
566
        location_url = to_transport.base
528
567
 
529
568
        old_rh = []
530
569
        try:
531
 
            dir_to = bzrlib.bzrdir.BzrDir.open(location_url)
 
570
            dir_to = bzrdir.BzrDir.open(location_url)
532
571
            br_to = dir_to.open_branch()
533
572
        except NotBranchError:
534
573
            # create a branch.
535
 
            transport = transport.clone('..')
 
574
            to_transport = to_transport.clone('..')
536
575
            if not create_prefix:
537
576
                try:
538
 
                    relurl = transport.relpath(location_url)
 
577
                    relurl = to_transport.relpath(location_url)
539
578
                    mutter('creating directory %s => %s', location_url, relurl)
540
 
                    transport.mkdir(relurl)
 
579
                    to_transport.mkdir(relurl)
541
580
                except NoSuchFile:
542
581
                    raise BzrCommandError("Parent directory of %s "
543
582
                                          "does not exist." % location)
544
583
            else:
545
 
                current = transport.base
546
 
                needed = [(transport, transport.relpath(location_url))]
 
584
                current = to_transport.base
 
585
                needed = [(to_transport, to_transport.relpath(location_url))]
547
586
                while needed:
548
587
                    try:
549
 
                        transport, relpath = needed[-1]
550
 
                        transport.mkdir(relpath)
 
588
                        to_transport, relpath = needed[-1]
 
589
                        to_transport.mkdir(relpath)
551
590
                        needed.pop()
552
591
                    except NoSuchFile:
553
 
                        new_transport = transport.clone('..')
 
592
                        new_transport = to_transport.clone('..')
554
593
                        needed.append((new_transport,
555
 
                                       new_transport.relpath(transport.base)))
556
 
                        if new_transport.base == transport.base:
 
594
                                       new_transport.relpath(to_transport.base)))
 
595
                        if new_transport.base == to_transport.base:
557
596
                            raise BzrCommandError("Could not create "
558
597
                                                  "path prefix.")
559
598
            dir_to = br_from.bzrdir.clone(location_url,
560
599
                revision_id=br_from.last_revision())
561
600
            br_to = dir_to.open_branch()
562
601
            count = len(br_to.revision_history())
 
602
            # We successfully created the target, remember it
 
603
            if br_from.get_push_location() is None or remember:
 
604
                br_from.set_push_location(br_to.base)
563
605
        else:
 
606
            # We were able to connect to the remote location, so remember it
 
607
            # we don't need to successfully push because of possible divergence.
 
608
            if br_from.get_push_location() is None or remember:
 
609
                br_from.set_push_location(br_to.base)
564
610
            old_rh = br_to.revision_history()
565
611
            try:
566
612
                try:
605
651
    aliases = ['get', 'clone']
606
652
 
607
653
    def run(self, from_location, to_location=None, revision=None, basis=None):
608
 
        from bzrlib.transport import get_transport
609
 
        from bzrlib.osutils import rmtree
610
654
        if revision is None:
611
655
            revision = [None]
612
656
        elif len(revision) > 1:
639
683
            else:
640
684
                name = os.path.basename(to_location) + '\n'
641
685
 
642
 
            to_transport = get_transport(to_location)
 
686
            to_transport = transport.get_transport(to_location)
643
687
            try:
644
688
                to_transport.mkdir('.')
645
 
            except bzrlib.errors.FileExists:
 
689
            except errors.FileExists:
646
690
                raise BzrCommandError('Target directory "%s" already'
647
691
                                      ' exists.' % to_location)
648
 
            except bzrlib.errors.NoSuchFile:
 
692
            except errors.NoSuchFile:
649
693
                raise BzrCommandError('Parent of "%s" does not exist.' %
650
694
                                      to_location)
651
695
            try:
653
697
                dir = br_from.bzrdir.sprout(to_transport.base,
654
698
                        revision_id, basis_dir)
655
699
                branch = dir.open_branch()
656
 
            except bzrlib.errors.NoSuchRevision:
 
700
            except errors.NoSuchRevision:
657
701
                to_transport.delete_tree('.')
658
702
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
659
703
                raise BzrCommandError(msg)
660
 
            except bzrlib.errors.UnlistableBranch:
661
 
                rmtree(to_location)
 
704
            except errors.UnlistableBranch:
 
705
                osutils.rmtree(to_location)
662
706
                msg = "The branch %s cannot be used as a --basis" % (basis,)
663
707
                raise BzrCommandError(msg)
664
708
            if name:
698
742
                                 "such access, and also support local commits."
699
743
                            ),
700
744
                     ]
 
745
    aliases = ['co']
701
746
 
702
747
    def run(self, branch_location=None, to_location=None, revision=None, basis=None,
703
748
            lightweight=False):
707
752
            raise BzrCommandError(
708
753
                'bzr checkout --revision takes exactly 1 revision value')
709
754
        if branch_location is None:
710
 
            branch_location = bzrlib.osutils.getcwd()
 
755
            branch_location = osutils.getcwd()
711
756
            to_location = branch_location
712
757
        source = Branch.open(branch_location)
713
758
        if len(revision) == 1 and revision[0] is not None:
719
764
        # if the source and to_location are the same, 
720
765
        # and there is no working tree,
721
766
        # then reconstitute a branch
722
 
        if (bzrlib.osutils.abspath(to_location) == 
723
 
            bzrlib.osutils.abspath(branch_location)):
 
767
        if (osutils.abspath(to_location) ==
 
768
            osutils.abspath(branch_location)):
724
769
            try:
725
770
                source.bzrdir.open_workingtree()
726
771
            except errors.NoWorkingTree:
737
782
                                      to_location)
738
783
            else:
739
784
                raise
740
 
        old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
741
 
        bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
 
785
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
786
        bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
742
787
        try:
743
 
            if lightweight:
744
 
                checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
745
 
                bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
746
 
            else:
747
 
                checkout_branch =  bzrlib.bzrdir.BzrDir.create_branch_convenience(
748
 
                    to_location, force_new_tree=False)
749
 
                checkout = checkout_branch.bzrdir
750
 
                checkout_branch.bind(source)
751
 
                if revision_id is not None:
752
 
                    rh = checkout_branch.revision_history()
753
 
                    checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
754
 
            checkout.create_workingtree(revision_id)
 
788
            source.create_checkout(to_location, revision_id, lightweight)
755
789
        finally:
756
 
            bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
 
790
            bzrdir.BzrDirFormat.set_default_format(old_format)
757
791
 
758
792
 
759
793
class cmd_renames(Command):
766
800
 
767
801
    @display_command
768
802
    def run(self, dir=u'.'):
 
803
        from bzrlib.tree import find_renames
769
804
        tree = WorkingTree.open_containing(dir)[0]
770
805
        old_inv = tree.basis_tree().inventory
771
806
        new_inv = tree.read_working_inventory()
772
 
 
773
 
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
 
807
        renames = list(find_renames(old_inv, new_inv))
774
808
        renames.sort()
775
809
        for old_name, new_name in renames:
776
810
            self.outf.write("%s => %s\n" % (old_name, new_name))
787
821
    'bzr revert' instead of 'bzr commit' after the update.
788
822
    """
789
823
    takes_args = ['dir?']
 
824
    aliases = ['up']
790
825
 
791
826
    def run(self, dir='.'):
792
827
        tree = WorkingTree.open_containing(dir)[0]
793
828
        tree.lock_write()
794
829
        try:
795
 
            if tree.last_revision() == tree.branch.last_revision():
 
830
            existing_pending_merges = tree.get_parent_ids()[1:]
 
831
            last_rev = tree.last_revision()
 
832
            if last_rev == tree.branch.last_revision():
796
833
                # may be up to date, check master too.
797
834
                master = tree.branch.get_master_branch()
798
 
                if master is None or master.last_revision == tree.last_revision():
799
 
                    note("Tree is up to date.")
800
 
                    return
 
835
                if master is None or last_rev == master.last_revision():
 
836
                    revno = tree.branch.revision_id_to_revno(last_rev)
 
837
                    note("Tree is up to date at revision %d." % (revno,))
 
838
                    return 0
801
839
            conflicts = tree.update()
802
 
            note('Updated to revision %d.' %
803
 
                 (tree.branch.revision_id_to_revno(tree.last_revision()),))
 
840
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
 
841
            note('Updated to revision %d.' % (revno,))
 
842
            if tree.get_parent_ids()[1:] != existing_pending_merges:
 
843
                note('Your local commits will now show as pending merges with '
 
844
                     "'bzr status', and can be committed with 'bzr commit'.")
804
845
            if conflicts != 0:
805
846
                return 1
806
847
            else:
851
892
                raise BzrCommandError('Specify one or more files to remove, or'
852
893
                                      ' use --new.')
853
894
        else:
854
 
            from bzrlib.delta import compare_trees
855
 
            added = [compare_trees(tree.basis_tree(), tree,
856
 
                                   specific_files=file_list).added]
857
 
            file_list = sorted([f[0] for f in added[0]], reverse=True)
 
895
            added = tree.changes_from(tree.basis_tree(),
 
896
                specific_files=file_list).added
 
897
            file_list = sorted([f[0] for f in added], reverse=True)
858
898
            if len(file_list) == 0:
859
899
                raise BzrCommandError('No matching files.')
860
900
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
875
915
    def run(self, filename):
876
916
        tree, relpath = WorkingTree.open_containing(filename)
877
917
        i = tree.inventory.path2id(relpath)
878
 
        if i == None:
 
918
        if i is None:
879
919
            raise BzrError("%r is not a versioned file" % filename)
880
920
        else:
881
921
            self.outf.write(i + '\n')
896
936
        tree, relpath = WorkingTree.open_containing(filename)
897
937
        inv = tree.inventory
898
938
        fid = inv.path2id(relpath)
899
 
        if fid == None:
 
939
        if fid is None:
900
940
            raise BzrError("%r is not a versioned file" % filename)
901
941
        for fip in inv.get_idpath(fid):
902
942
            self.outf.write(fip + '\n')
924
964
 
925
965
    def run(self, branch="."):
926
966
        from bzrlib.reconcile import reconcile
927
 
        dir = bzrlib.bzrdir.BzrDir.open(branch)
 
967
        dir = bzrdir.BzrDir.open(branch)
928
968
        reconcile(dir)
929
969
 
930
970
 
931
971
class cmd_revision_history(Command):
932
 
    """Display list of revision ids on this branch."""
 
972
    """Display the list of revision ids on a branch."""
 
973
    takes_args = ['location?']
 
974
 
933
975
    hidden = True
934
976
 
935
977
    @display_command
936
 
    def run(self):
937
 
        branch = WorkingTree.open_containing(u'.')[0].branch
938
 
        for patchid in branch.revision_history():
939
 
            self.outf.write(patchid)
 
978
    def run(self, location="."):
 
979
        branch = Branch.open_containing(location)[0]
 
980
        for revid in branch.revision_history():
 
981
            self.outf.write(revid)
940
982
            self.outf.write('\n')
941
983
 
942
984
 
943
985
class cmd_ancestry(Command):
944
986
    """List all revisions merged into this branch."""
 
987
    takes_args = ['location?']
 
988
 
945
989
    hidden = True
946
990
 
947
991
    @display_command
948
 
    def run(self):
949
 
        tree = WorkingTree.open_containing(u'.')[0]
950
 
        b = tree.branch
951
 
        # FIXME. should be tree.last_revision
952
 
        revision_ids = b.repository.get_ancestry(b.last_revision())
953
 
        assert revision_ids[0] == None
 
992
    def run(self, location="."):
 
993
        try:
 
994
            wt = WorkingTree.open_containing(location)[0]
 
995
        except errors.NoWorkingTree:
 
996
            b = Branch.open(location)
 
997
            last_revision = b.last_revision()
 
998
        else:
 
999
            b = wt.branch
 
1000
            last_revision = wt.last_revision()
 
1001
 
 
1002
        revision_ids = b.repository.get_ancestry(last_revision)
 
1003
        assert revision_ids[0] is None
954
1004
        revision_ids.pop(0)
955
1005
        for revision_id in revision_ids:
956
1006
            self.outf.write(revision_id + '\n')
987
1037
                            type=get_format_type),
988
1038
                     ]
989
1039
    def run(self, location=None, format=None):
990
 
        from bzrlib.branch import Branch
991
1040
        if format is None:
992
1041
            format = get_format_type('default')
993
1042
        if location is None:
994
1043
            location = u'.'
995
 
        else:
996
 
            # The path has to exist to initialize a
997
 
            # branch inside of it.
998
 
            # Just using os.mkdir, since I don't
999
 
            # believe that we want to create a bunch of
1000
 
            # locations if the user supplies an extended path
1001
 
            if not os.path.exists(location):
1002
 
                os.mkdir(location)
 
1044
 
 
1045
        to_transport = transport.get_transport(location)
 
1046
 
 
1047
        # The path has to exist to initialize a
 
1048
        # branch inside of it.
 
1049
        # Just using os.mkdir, since I don't
 
1050
        # believe that we want to create a bunch of
 
1051
        # locations if the user supplies an extended path
 
1052
        # TODO: create-prefix
 
1053
        try:
 
1054
            to_transport.mkdir('.')
 
1055
        except errors.FileExists:
 
1056
            pass
 
1057
                    
1003
1058
        try:
1004
1059
            existing_bzrdir = bzrdir.BzrDir.open(location)
1005
1060
        except NotBranchError:
1007
1062
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
1008
1063
        else:
1009
1064
            if existing_bzrdir.has_branch():
1010
 
                if existing_bzrdir.has_workingtree():
1011
 
                    raise errors.AlreadyBranchError(location)
1012
 
                else:
1013
 
                    raise errors.BranchExistsWithoutWorkingTree(location)
 
1065
                if (isinstance(to_transport, LocalTransport)
 
1066
                    and not existing_bzrdir.has_workingtree()):
 
1067
                        raise errors.BranchExistsWithoutWorkingTree(location)
 
1068
                raise errors.AlreadyBranchError(location)
1014
1069
            else:
1015
1070
                existing_bzrdir.create_branch()
1016
1071
                existing_bzrdir.create_workingtree()
1042
1097
                             ' a working tree')]
1043
1098
    aliases = ["init-repo"]
1044
1099
    def run(self, location, format=None, trees=False):
1045
 
        from bzrlib.transport import get_transport
1046
1100
        if format is None:
1047
1101
            format = get_format_type('default')
1048
 
        transport = get_transport(location)
1049
 
        if not transport.has('.'):
1050
 
            transport.mkdir('')
1051
 
        newdir = format.initialize_on_transport(transport)
 
1102
 
 
1103
        if location is None:
 
1104
            location = '.'
 
1105
 
 
1106
        to_transport = transport.get_transport(location)
 
1107
        try:
 
1108
            to_transport.mkdir('.')
 
1109
        except errors.FileExists:
 
1110
            pass
 
1111
 
 
1112
        newdir = format.initialize_on_transport(to_transport)
1052
1113
        repo = newdir.create_repository(shared=True)
1053
1114
        repo.set_make_working_trees(trees)
1054
1115
 
1055
1116
 
1056
1117
class cmd_diff(Command):
1057
 
    """Show differences in working tree.
 
1118
    """Show differences in the working tree or between revisions.
1058
1119
    
1059
1120
    If files are listed, only the changes in those files are listed.
1060
1121
    Otherwise, all changes for the tree are listed.
1064
1125
 
1065
1126
    examples:
1066
1127
        bzr diff
 
1128
            Shows the difference in the working tree versus the last commit
1067
1129
        bzr diff -r1
 
1130
            Difference between the working tree and revision 1
1068
1131
        bzr diff -r1..2
 
1132
            Difference between revision 2 and revision 1
1069
1133
        bzr diff --diff-prefix old/:new/
 
1134
            Same as 'bzr diff' but prefix paths with old/ and new/
1070
1135
        bzr diff bzr.mine bzr.dev
 
1136
            Show the differences between the two working trees
1071
1137
        bzr diff foo.c
 
1138
            Show just the differences for 'foo.c'
1072
1139
    """
1073
1140
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
1074
1141
    #       or a graphical diff.
1118
1185
                # FIXME diff those two files. rbc 20051123
1119
1186
                raise BzrCommandError("Files are in different branches")
1120
1187
            file_list = None
 
1188
        except NotBranchError:
 
1189
            if (revision is not None and len(revision) == 2
 
1190
                and not revision[0].needs_branch()
 
1191
                and not revision[1].needs_branch()):
 
1192
                # If both revision specs include a branch, we can
 
1193
                # diff them without needing a local working tree
 
1194
                tree1, tree2 = None, None
 
1195
            else:
 
1196
                raise
1121
1197
        if revision is not None:
1122
1198
            if tree2 is not None:
1123
1199
                raise BzrCommandError("Can't specify -r with two branches")
1171
1247
    hidden = True
1172
1248
    @display_command
1173
1249
    def run(self):
1174
 
        from bzrlib.delta import compare_trees
1175
 
 
1176
1250
        tree = WorkingTree.open_containing(u'.')[0]
1177
 
        td = compare_trees(tree.basis_tree(), tree)
1178
 
 
 
1251
        td = tree.changes_from(tree.basis_tree())
1179
1252
        for path, id, kind, text_modified, meta_modified in td.modified:
1180
1253
            self.outf.write(path + '\n')
1181
1254
 
1192
1265
            if file_id in basis_inv:
1193
1266
                continue
1194
1267
            path = inv.id2path(file_id)
1195
 
            if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
 
1268
            if not os.access(osutils.abspath(path), os.F_OK):
1196
1269
                continue
1197
1270
            self.outf.write(path + '\n')
1198
1271
 
1277
1350
        else:
1278
1351
            # local dir only
1279
1352
            # FIXME ? log the current subdir only RBC 20060203 
1280
 
            dir, relpath = bzrdir.BzrDir.open_containing('.')
 
1353
            if revision is not None \
 
1354
                    and len(revision) > 0 and revision[0].get_branch():
 
1355
                location = revision[0].get_branch()
 
1356
            else:
 
1357
                location = '.'
 
1358
            dir, relpath = bzrdir.BzrDir.open_containing(location)
1281
1359
            b = dir.open_branch()
1282
1360
 
1283
1361
        if revision is None:
1286
1364
        elif len(revision) == 1:
1287
1365
            rev1 = rev2 = revision[0].in_history(b).revno
1288
1366
        elif len(revision) == 2:
 
1367
            if revision[1].get_branch() != revision[0].get_branch():
 
1368
                # b is taken from revision[0].get_branch(), and
 
1369
                # show_log will use its revision_history. Having
 
1370
                # different branches will lead to weird behaviors.
 
1371
                raise BzrCommandError(
 
1372
                    "Log doesn't accept two revisions in different branches.")
1289
1373
            if revision[0].spec is None:
1290
1374
                # missing begin-range means first revision
1291
1375
                rev1 = 1
1306
1390
        if rev1 > rev2:
1307
1391
            (rev2, rev1) = (rev1, rev2)
1308
1392
 
1309
 
        if (log_format == None):
1310
 
            default = bzrlib.config.BranchConfig(b).log_format()
1311
 
            log_format = get_log_format(long=long, short=short, line=line, default=default)
 
1393
        if (log_format is None):
 
1394
            default = b.get_config().log_format()
 
1395
            log_format = get_log_format(long=long, short=short, line=line, 
 
1396
                                        default=default)
1312
1397
        lf = log_formatter(log_format,
1313
1398
                           show_ids=show_ids,
1314
1399
                           to_file=self.outf,
1350
1435
        b = tree.branch
1351
1436
        inv = tree.read_working_inventory()
1352
1437
        file_id = inv.path2id(relpath)
1353
 
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
 
1438
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1354
1439
            self.outf.write("%6d %s\n" % (revno, what))
1355
1440
 
1356
1441
 
1412
1497
    """List unknown files."""
1413
1498
    @display_command
1414
1499
    def run(self):
1415
 
        from bzrlib.osutils import quotefn
1416
1500
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1417
 
            self.outf.write(quotefn(f) + '\n')
 
1501
            self.outf.write(osutils.quotefn(f) + '\n')
1418
1502
 
1419
1503
 
1420
1504
class cmd_ignore(Command):
1436
1520
        bzr ignore '*.class'
1437
1521
    """
1438
1522
    # TODO: Complain if the filename is absolute
1439
 
    takes_args = ['name_pattern']
 
1523
    takes_args = ['name_pattern?']
 
1524
    takes_options = [
 
1525
                     Option('old-default-rules',
 
1526
                            help='Out the ignore rules bzr < 0.9 always used.')
 
1527
                     ]
1440
1528
    
1441
 
    def run(self, name_pattern):
 
1529
    def run(self, name_pattern=None, old_default_rules=None):
1442
1530
        from bzrlib.atomicfile import AtomicFile
1443
 
        import os.path
1444
 
 
 
1531
        if old_default_rules is not None:
 
1532
            # dump the rules and exit
 
1533
            for pattern in ignores.OLD_DEFAULTS:
 
1534
                print pattern
 
1535
            return
 
1536
        if name_pattern is None:
 
1537
            raise BzrCommandError("ignore requires a NAME_PATTERN")
1445
1538
        tree, relpath = WorkingTree.open_containing(u'.')
1446
1539
        ifn = tree.abspath('.bzrignore')
1447
 
 
1448
1540
        if os.path.exists(ifn):
1449
1541
            f = open(ifn, 'rt')
1450
1542
            try:
1535
1627
    takes_args = ['dest']
1536
1628
    takes_options = ['revision', 'format', 'root']
1537
1629
    def run(self, dest, revision=None, format=None, root=None):
1538
 
        import os.path
1539
1630
        from bzrlib.export import export
1540
1631
        tree = WorkingTree.open_containing(u'.')[0]
1541
1632
        b = tree.branch
1572
1663
 
1573
1664
        if tree is None:
1574
1665
            b, relpath = Branch.open_containing(filename)
 
1666
        if revision is not None and revision[0].get_branch() is not None:
 
1667
            b = Branch.open(revision[0].get_branch())
1575
1668
        if revision is None:
1576
1669
            revision_id = b.last_revision()
1577
1670
        else:
1584
1677
    hidden = True    
1585
1678
    @display_command
1586
1679
    def run(self):
1587
 
        print bzrlib.osutils.local_time_offset()
 
1680
        print osutils.local_time_offset()
1588
1681
 
1589
1682
 
1590
1683
 
1668
1761
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1669
1762
 
1670
1763
        if message == "":
1671
 
                raise BzrCommandError("empty commit message specified")
 
1764
            raise BzrCommandError("empty commit message specified")
1672
1765
        
1673
1766
        if verbose:
1674
1767
            reporter = ReportCommitToLog()
1682
1775
        except PointlessCommit:
1683
1776
            # FIXME: This should really happen before the file is read in;
1684
1777
            # perhaps prepare the commit; get the message; then actually commit
1685
 
            raise BzrCommandError("no changes to commit",
1686
 
                                  ["use --unchanged to commit anyhow"])
 
1778
            raise BzrCommandError("no changes to commit."
 
1779
                                  " use --unchanged to commit anyhow")
1687
1780
        except ConflictsInTree:
1688
1781
            raise BzrCommandError("Conflicts detected in working tree.  "
1689
1782
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1691
1784
            raise BzrCommandError("Commit refused because there are unknown "
1692
1785
                                  "files in the working tree.")
1693
1786
        except errors.BoundBranchOutOfDate, e:
1694
 
            raise BzrCommandError(str(e)
1695
 
                                  + ' Either unbind, update, or'
1696
 
                                    ' pass --local to commit.')
1697
 
 
 
1787
            raise BzrCommandError(str(e) + "\n"
 
1788
                'To commit to master branch, run update and then commit.\n'
 
1789
                'You can also pass --local to commit to continue working '
 
1790
                'disconnected.')
1698
1791
 
1699
1792
class cmd_check(Command):
1700
1793
    """Validate consistency of branch history.
1760
1853
 
1761
1854
 
1762
1855
class cmd_whoami(Command):
1763
 
    """Show bzr user id."""
1764
 
    takes_options = ['email']
 
1856
    """Show or set bzr user id.
 
1857
    
 
1858
    examples:
 
1859
        bzr whoami --email
 
1860
        bzr whoami 'Frank Chu <fchu@example.com>'
 
1861
    """
 
1862
    takes_options = [ Option('email',
 
1863
                             help='display email address only'),
 
1864
                      Option('branch',
 
1865
                             help='set identity for the current branch instead of '
 
1866
                                  'globally'),
 
1867
                    ]
 
1868
    takes_args = ['name?']
 
1869
    encoding_type = 'replace'
1765
1870
    
1766
1871
    @display_command
1767
 
    def run(self, email=False):
 
1872
    def run(self, email=False, branch=False, name=None):
 
1873
        if name is None:
 
1874
            # use branch if we're inside one; otherwise global config
 
1875
            try:
 
1876
                c = Branch.open_containing('.')[0].get_config()
 
1877
            except NotBranchError:
 
1878
                c = config.GlobalConfig()
 
1879
            if email:
 
1880
                self.outf.write(c.user_email() + '\n')
 
1881
            else:
 
1882
                self.outf.write(c.username() + '\n')
 
1883
            return
 
1884
 
 
1885
        # display a warning if an email address isn't included in the given name.
1768
1886
        try:
1769
 
            b = WorkingTree.open_containing(u'.')[0].branch
1770
 
            config = bzrlib.config.BranchConfig(b)
1771
 
        except NotBranchError:
1772
 
            config = bzrlib.config.GlobalConfig()
 
1887
            config.extract_email_address(name)
 
1888
        except BzrError, e:
 
1889
            warning('"%s" does not seem to contain an email address.  '
 
1890
                    'This is allowed, but not recommended.', name)
1773
1891
        
1774
 
        if email:
1775
 
            print config.user_email()
 
1892
        # use global config unless --branch given
 
1893
        if branch:
 
1894
            c = Branch.open_containing('.')[0].get_config()
1776
1895
        else:
1777
 
            print config.username()
 
1896
            c = config.GlobalConfig()
 
1897
        c.set_user_option('email', name)
1778
1898
 
1779
1899
 
1780
1900
class cmd_nick(Command):
1849
1969
                     Option('lsprof-timed',
1850
1970
                            help='generate lsprof output for benchmarked'
1851
1971
                                 ' sections of code.'),
 
1972
                     Option('cache-dir', type=str,
 
1973
                            help='a directory to cache intermediate'
 
1974
                                 ' benchmark steps'),
1852
1975
                     ]
1853
1976
 
1854
1977
    def run(self, testspecs_list=None, verbose=None, one=False,
1855
1978
            keep_output=False, transport=None, benchmark=None,
1856
 
            lsprof_timed=None):
 
1979
            lsprof_timed=None, cache_dir=None):
1857
1980
        import bzrlib.ui
1858
1981
        from bzrlib.tests import selftest
1859
1982
        import bzrlib.benchmarks as benchmarks
 
1983
        from bzrlib.benchmarks import tree_creator
 
1984
 
 
1985
        if cache_dir is not None:
 
1986
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
1860
1987
        # we don't want progress meters from the tests to go to the
1861
1988
        # real output; and we don't want log messages cluttering up
1862
1989
        # the real logs.
1863
 
        save_ui = bzrlib.ui.ui_factory
1864
 
        print '%10s: %s' % ('bzr', bzrlib.osutils.realpath(sys.argv[0]))
 
1990
        save_ui = ui.ui_factory
 
1991
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1865
1992
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1866
1993
        print
1867
 
        bzrlib.trace.info('running tests...')
 
1994
        info('running tests...')
1868
1995
        try:
1869
 
            bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
 
1996
            ui.ui_factory = ui.SilentUIFactory()
1870
1997
            if testspecs_list is not None:
1871
1998
                pattern = '|'.join(testspecs_list)
1872
1999
            else:
1875
2002
                test_suite_factory = benchmarks.test_suite
1876
2003
                if verbose is None:
1877
2004
                    verbose = True
 
2005
                benchfile = open(".perf_history", "at")
1878
2006
            else:
1879
2007
                test_suite_factory = None
1880
2008
                if verbose is None:
1881
2009
                    verbose = False
1882
 
            result = selftest(verbose=verbose, 
1883
 
                              pattern=pattern,
1884
 
                              stop_on_failure=one, 
1885
 
                              keep_output=keep_output,
1886
 
                              transport=transport,
1887
 
                              test_suite_factory=test_suite_factory,
1888
 
                              lsprof_timed=lsprof_timed)
 
2010
                benchfile = None
 
2011
            try:
 
2012
                result = selftest(verbose=verbose, 
 
2013
                                  pattern=pattern,
 
2014
                                  stop_on_failure=one, 
 
2015
                                  keep_output=keep_output,
 
2016
                                  transport=transport,
 
2017
                                  test_suite_factory=test_suite_factory,
 
2018
                                  lsprof_timed=lsprof_timed,
 
2019
                                  bench_history=benchfile)
 
2020
            finally:
 
2021
                if benchfile is not None:
 
2022
                    benchfile.close()
1889
2023
            if result:
1890
 
                bzrlib.trace.info('tests passed')
 
2024
                info('tests passed')
1891
2025
            else:
1892
 
                bzrlib.trace.info('tests failed')
 
2026
                info('tests failed')
1893
2027
            return int(not result)
1894
2028
        finally:
1895
 
            bzrlib.ui.ui_factory = save_ui
1896
 
 
1897
 
 
1898
 
def _get_bzr_branch():
1899
 
    """If bzr is run from a branch, return Branch or None"""
1900
 
    import bzrlib.errors
1901
 
    from bzrlib.branch import Branch
1902
 
    from bzrlib.osutils import abspath
1903
 
    from os.path import dirname
1904
 
    
1905
 
    try:
1906
 
        branch = Branch.open(dirname(abspath(dirname(__file__))))
1907
 
        return branch
1908
 
    except bzrlib.errors.BzrError:
1909
 
        return None
1910
 
    
1911
 
 
1912
 
def show_version():
1913
 
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
1914
 
    # is bzrlib itself in a branch?
1915
 
    branch = _get_bzr_branch()
1916
 
    if branch:
1917
 
        rh = branch.revision_history()
1918
 
        revno = len(rh)
1919
 
        print "  bzr checkout, revision %d" % (revno,)
1920
 
        print "  nick: %s" % (branch.nick,)
1921
 
        if rh:
1922
 
            print "  revid: %s" % (rh[-1],)
1923
 
    print "Using python interpreter:", sys.executable
1924
 
    import site
1925
 
    print "Using python standard library:", os.path.dirname(site.__file__)
1926
 
    print "Using bzrlib:",
1927
 
    if len(bzrlib.__path__) > 1:
1928
 
        # print repr, which is a good enough way of making it clear it's
1929
 
        # more than one element (eg ['/foo/bar', '/foo/bzr'])
1930
 
        print repr(bzrlib.__path__)
1931
 
    else:
1932
 
        print bzrlib.__path__[0]
1933
 
 
1934
 
    print
1935
 
    print bzrlib.__copyright__
1936
 
    print "http://bazaar-vcs.org/"
1937
 
    print
1938
 
    print "bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and"
1939
 
    print "you may use, modify and redistribute it under the terms of the GNU"
1940
 
    print "General Public License version 2 or later."
 
2029
            ui.ui_factory = save_ui
1941
2030
 
1942
2031
 
1943
2032
class cmd_version(Command):
1944
2033
    """Show version of bzr."""
 
2034
 
1945
2035
    @display_command
1946
2036
    def run(self):
 
2037
        from bzrlib.version import show_version
1947
2038
        show_version()
1948
2039
 
 
2040
 
1949
2041
class cmd_rocks(Command):
1950
2042
    """Statement of optimism."""
 
2043
 
1951
2044
    hidden = True
 
2045
 
1952
2046
    @display_command
1953
2047
    def run(self):
1954
2048
        print "it sure does!"
1955
2049
 
1956
2050
 
1957
2051
class cmd_find_merge_base(Command):
1958
 
    """Find and print a base revision for merging two branches.
1959
 
    """
 
2052
    """Find and print a base revision for merging two branches."""
1960
2053
    # TODO: Options to specify revisions on either side, as if
1961
2054
    #       merging only part of the history.
1962
2055
    takes_args = ['branch', 'other']
1981
2074
        base_rev_id = common_ancestor(last1, last2, source)
1982
2075
 
1983
2076
        print 'merge base is revision %s' % base_rev_id
1984
 
        
1985
 
        return
1986
 
 
1987
 
        if base_revno is None:
1988
 
            raise bzrlib.errors.UnrelatedBranches()
1989
 
 
1990
 
        print ' r%-6d in %s' % (base_revno, branch)
1991
 
 
1992
 
        other_revno = branch2.revision_id_to_revno(base_revid)
1993
 
        
1994
 
        print ' r%-6d in %s' % (other_revno, other)
1995
 
 
1996
2077
 
1997
2078
 
1998
2079
class cmd_merge(Command):
1999
2080
    """Perform a three-way merge.
2000
2081
    
2001
 
    The branch is the branch you will merge from.  By default, it will
2002
 
    merge the latest revision.  If you specify a revision, that
2003
 
    revision will be merged.  If you specify two revisions, the first
2004
 
    will be used as a BASE, and the second one as OTHER.  Revision
2005
 
    numbers are always relative to the specified branch.
 
2082
    The branch is the branch you will merge from.  By default, it will merge
 
2083
    the latest revision.  If you specify a revision, that revision will be
 
2084
    merged.  If you specify two revisions, the first will be used as a BASE,
 
2085
    and the second one as OTHER.  Revision numbers are always relative to the
 
2086
    specified branch.
2006
2087
 
2007
2088
    By default, bzr will try to merge in all new work from the other
2008
2089
    branch, automatically determining an appropriate base.  If this
2017
2098
 
2018
2099
    If there is no default branch set, the first merge will set it. After
2019
2100
    that, you can omit the branch to use the default.  To change the
2020
 
    default, use --remember.
 
2101
    default, use --remember. The value will only be saved if the remote
 
2102
    location can be accessed.
2021
2103
 
2022
2104
    Examples:
2023
2105
 
2038
2120
    takes_args = ['branch?']
2039
2121
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2040
2122
                     Option('show-base', help="Show base revision text in "
2041
 
                            "conflicts")]
 
2123
                            "conflicts"), 
 
2124
                     Option('uncommitted', help='Apply uncommitted changes'
 
2125
                            ' from a working copy, instead of branch changes')]
2042
2126
 
2043
2127
    def help(self):
2044
2128
        from merge import merge_type_help
2046
2130
        return getdoc(self) + '\n' + merge_type_help() 
2047
2131
 
2048
2132
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2049
 
            show_base=False, reprocess=False, remember=False):
 
2133
            show_base=False, reprocess=False, remember=False, 
 
2134
            uncommitted=False):
2050
2135
        if merge_type is None:
2051
2136
            merge_type = Merge3Merger
2052
2137
 
2053
2138
        tree = WorkingTree.open_containing(u'.')[0]
2054
2139
 
2055
 
        try:
2056
 
            if branch is not None:
2057
 
                reader = BundleReader(file(branch, 'rb'))
2058
 
            else:
2059
 
                reader = None
2060
 
        except IOError, e:
2061
 
            if e.errno not in (errno.ENOENT, errno.EISDIR):
2062
 
                raise
2063
 
            reader = None
2064
 
        except NotABundle:
2065
 
            reader = None
2066
 
        if reader is not None:
2067
 
            conflicts = merge_bundle(reader, tree, not force, merge_type,
2068
 
                                        reprocess, show_base)
2069
 
            if conflicts == 0:
2070
 
                return 0
2071
 
            else:
2072
 
                return 1
 
2140
        if branch is not None:
 
2141
            try:
 
2142
                reader = bundle.read_bundle_from_url(branch)
 
2143
            except NotABundle:
 
2144
                pass # Continue on considering this url a Branch
 
2145
            else:
 
2146
                conflicts = merge_bundle(reader, tree, not force, merge_type,
 
2147
                                            reprocess, show_base)
 
2148
                if conflicts == 0:
 
2149
                    return 0
 
2150
                else:
 
2151
                    return 1
2073
2152
 
2074
 
        branch = self._get_remembered_parent(tree, branch, 'Merging from')
 
2153
        if revision is None \
 
2154
                or len(revision) < 1 or revision[0].needs_branch():
 
2155
            branch = self._get_remembered_parent(tree, branch, 'Merging from')
2075
2156
 
2076
2157
        if revision is None or len(revision) < 1:
2077
 
            base = [None, None]
2078
 
            other = [branch, -1]
 
2158
            if uncommitted:
 
2159
                base = [branch, -1]
 
2160
                other = [branch, None]
 
2161
            else:
 
2162
                base = [None, None]
 
2163
                other = [branch, -1]
2079
2164
            other_branch, path = Branch.open_containing(branch)
2080
2165
        else:
 
2166
            if uncommitted:
 
2167
                raise BzrCommandError('Cannot use --uncommitted and --revision'
 
2168
                                      ' at the same time.')
 
2169
            branch = revision[0].get_branch() or branch
2081
2170
            if len(revision) == 1:
2082
2171
                base = [None, None]
2083
2172
                other_branch, path = Branch.open_containing(branch)
2087
2176
                assert len(revision) == 2
2088
2177
                if None in revision:
2089
2178
                    raise BzrCommandError(
2090
 
                        "Merge doesn't permit that revision specifier.")
2091
 
                other_branch, path = Branch.open_containing(branch)
 
2179
                        "Merge doesn't permit empty revision specifier.")
 
2180
                base_branch, path = Branch.open_containing(branch)
 
2181
                branch1 = revision[1].get_branch() or branch
 
2182
                other_branch, path1 = Branch.open_containing(branch1)
 
2183
                if revision[0].get_branch() is not None:
 
2184
                    # then path was obtained from it, and is None.
 
2185
                    path = path1
2092
2186
 
2093
 
                base = [branch, revision[0].in_history(other_branch).revno]
2094
 
                other = [branch, revision[1].in_history(other_branch).revno]
 
2187
                base = [branch, revision[0].in_history(base_branch).revno]
 
2188
                other = [branch1, revision[1].in_history(other_branch).revno]
2095
2189
 
2096
2190
        if tree.branch.get_parent() is None or remember:
2097
2191
            tree.branch.set_parent(other_branch.base)
2100
2194
            interesting_files = [path]
2101
2195
        else:
2102
2196
            interesting_files = None
2103
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
2197
        pb = ui.ui_factory.nested_progress_bar()
2104
2198
        try:
2105
2199
            try:
2106
2200
                conflict_count = merge(other, base, check_clean=(not force),
2114
2208
                return 1
2115
2209
            else:
2116
2210
                return 0
2117
 
        except bzrlib.errors.AmbiguousBase, e:
 
2211
        except errors.AmbiguousBase, e:
2118
2212
            m = ("sorry, bzr can't determine the right merge base yet\n"
2119
2213
                 "candidates are:\n  "
2120
2214
                 + "\n  ".join(e.bases)
2179
2273
        tree, file_list = tree_files(file_list)
2180
2274
        tree.lock_write()
2181
2275
        try:
2182
 
            pending_merges = tree.pending_merges() 
2183
 
            if len(pending_merges) != 1:
 
2276
            parents = tree.get_parent_ids()
 
2277
            if len(parents) != 2:
2184
2278
                raise BzrCommandError("Sorry, remerge only works after normal"
2185
 
                                      + " merges.  Not cherrypicking or"
2186
 
                                      + "multi-merges.")
 
2279
                                      " merges.  Not cherrypicking or"
 
2280
                                      " multi-merges.")
2187
2281
            repository = tree.branch.repository
2188
 
            base_revision = common_ancestor(tree.branch.last_revision(), 
2189
 
                                            pending_merges[0], repository)
 
2282
            base_revision = common_ancestor(parents[0],
 
2283
                                            parents[1], repository)
2190
2284
            base_tree = repository.revision_tree(base_revision)
2191
 
            other_tree = repository.revision_tree(pending_merges[0])
 
2285
            other_tree = repository.revision_tree(parents[1])
2192
2286
            interesting_ids = None
 
2287
            new_conflicts = []
 
2288
            conflicts = tree.conflicts()
2193
2289
            if file_list is not None:
2194
2290
                interesting_ids = set()
2195
2291
                for filename in file_list:
2202
2298
                    
2203
2299
                    for name, ie in tree.inventory.iter_entries(file_id):
2204
2300
                        interesting_ids.add(ie.file_id)
 
2301
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2205
2302
            transform_tree(tree, tree.basis_tree(), interesting_ids)
 
2303
            tree.set_conflicts(ConflictList(new_conflicts))
2206
2304
            if file_list is None:
2207
2305
                restore_files = list(tree.iter_conflicts())
2208
2306
            else:
2212
2310
                    restore(tree.abspath(filename))
2213
2311
                except NotConflicted:
2214
2312
                    pass
2215
 
            conflicts =  merge_inner(tree.branch, other_tree, base_tree,
2216
 
                                     this_tree=tree,
2217
 
                                     interesting_ids = interesting_ids, 
2218
 
                                     other_rev_id=pending_merges[0], 
2219
 
                                     merge_type=merge_type, 
2220
 
                                     show_base=show_base,
2221
 
                                     reprocess=reprocess)
 
2313
            conflicts = merge_inner(tree.branch, other_tree, base_tree,
 
2314
                                    this_tree=tree,
 
2315
                                    interesting_ids=interesting_ids,
 
2316
                                    other_rev_id=parents[1],
 
2317
                                    merge_type=merge_type,
 
2318
                                    show_base=show_base,
 
2319
                                    reprocess=reprocess)
2222
2320
        finally:
2223
2321
            tree.unlock()
2224
2322
        if conflicts > 0:
2253
2351
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2254
2352
        else:
2255
2353
            rev_id = revision[0].in_history(tree.branch).rev_id
2256
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
2354
        pb = ui.ui_factory.nested_progress_bar()
2257
2355
        try:
2258
2356
            tree.revert(file_list, 
2259
2357
                        tree.branch.repository.revision_tree(rev_id),
2307
2405
    takes_args = ['from_branch', 'to_branch']
2308
2406
    def run(self, from_branch, to_branch):
2309
2407
        from bzrlib.fetch import Fetcher
2310
 
        from bzrlib.branch import Branch
2311
2408
        from_b = Branch.open(from_branch)
2312
2409
        to_b = Branch.open(to_branch)
2313
2410
        Fetcher(to_b, from_b)
2330
2427
                     'show-ids',
2331
2428
                     'verbose'
2332
2429
                     ]
 
2430
    encoding_type = 'replace'
2333
2431
 
 
2432
    @display_command
2334
2433
    def run(self, other_branch=None, reverse=False, mine_only=False,
2335
2434
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
2336
2435
            show_ids=False, verbose=False):
2337
2436
        from bzrlib.missing import find_unmerged, iter_log_data
2338
2437
        from bzrlib.log import log_formatter
2339
 
        local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
 
2438
        local_branch = Branch.open_containing(u".")[0]
2340
2439
        parent = local_branch.get_parent()
2341
2440
        if other_branch is None:
2342
2441
            other_branch = parent
2343
2442
            if other_branch is None:
2344
 
                raise BzrCommandError("No missing location known or specified.")
 
2443
                raise BzrCommandError("No peer location known or specified.")
2345
2444
            print "Using last location: " + local_branch.get_parent()
2346
 
        remote_branch = bzrlib.branch.Branch.open(other_branch)
 
2445
        remote_branch = Branch.open(other_branch)
2347
2446
        if remote_branch.base == local_branch.base:
2348
2447
            remote_branch = local_branch
2349
2448
        local_branch.lock_read()
2351
2450
            remote_branch.lock_read()
2352
2451
            try:
2353
2452
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2354
 
                if (log_format == None):
2355
 
                    default = bzrlib.config.BranchConfig(local_branch).log_format()
2356
 
                    log_format = get_log_format(long=long, short=short, line=line, default=default)
2357
 
                lf = log_formatter(log_format, sys.stdout,
 
2453
                if (log_format is None):
 
2454
                    default = local_branch.get_config().log_format()
 
2455
                    log_format = get_log_format(long=long, short=short, 
 
2456
                                                line=line, default=default)
 
2457
                lf = log_formatter(log_format,
 
2458
                                   to_file=self.outf,
2358
2459
                                   show_ids=show_ids,
2359
2460
                                   show_timezone='original')
2360
2461
                if reverse is False:
2403
2504
        import bzrlib.plugin
2404
2505
        from inspect import getdoc
2405
2506
        for name, plugin in bzrlib.plugin.all_plugins().items():
2406
 
            if hasattr(plugin, '__path__'):
 
2507
            if getattr(plugin, '__path__', None) is not None:
2407
2508
                print plugin.__path__[0]
2408
 
            elif hasattr(plugin, '__file__'):
 
2509
            elif getattr(plugin, '__file__', None) is not None:
2409
2510
                print plugin.__file__
2410
2511
            else:
2411
 
                print `plugin`
 
2512
                print repr(plugin)
2412
2513
                
2413
2514
            d = getdoc(plugin)
2414
2515
            if d:
2417
2518
 
2418
2519
class cmd_testament(Command):
2419
2520
    """Show testament (signing-form) of a revision."""
2420
 
    takes_options = ['revision', 'long']
 
2521
    takes_options = ['revision', 
 
2522
                     Option('long', help='Produce long-format testament'), 
 
2523
                     Option('strict', help='Produce a strict-format'
 
2524
                            ' testament')]
2421
2525
    takes_args = ['branch?']
2422
2526
    @display_command
2423
 
    def run(self, branch=u'.', revision=None, long=False):
2424
 
        from bzrlib.testament import Testament
 
2527
    def run(self, branch=u'.', revision=None, long=False, strict=False):
 
2528
        from bzrlib.testament import Testament, StrictTestament
 
2529
        if strict is True:
 
2530
            testament_class = StrictTestament
 
2531
        else:
 
2532
            testament_class = Testament
2425
2533
        b = WorkingTree.open_containing(branch)[0].branch
2426
2534
        b.lock_read()
2427
2535
        try:
2429
2537
                rev_id = b.last_revision()
2430
2538
            else:
2431
2539
                rev_id = revision[0].in_history(b).rev_id
2432
 
            t = Testament.from_revision(b.repository, rev_id)
 
2540
            t = testament_class.from_revision(b.repository, rev_id)
2433
2541
            if long:
2434
2542
                sys.stdout.writelines(t.as_text_lines())
2435
2543
            else:
2450
2558
    # TODO: annotate directories; showing when each file was last changed
2451
2559
    # TODO: if the working copy is modified, show annotations on that 
2452
2560
    #       with new uncommitted lines marked
2453
 
    aliases = ['blame', 'praise']
 
2561
    aliases = ['ann', 'blame', 'praise']
2454
2562
    takes_args = ['filename']
2455
2563
    takes_options = [Option('all', help='show annotations on all lines'),
2456
2564
                     Option('long', help='show date in annotations'),
2487
2595
    takes_options = ['revision']
2488
2596
    
2489
2597
    def run(self, revision_id_list=None, revision=None):
2490
 
        import bzrlib.config as config
2491
2598
        import bzrlib.gpg as gpg
2492
2599
        if revision_id_list is not None and revision is not None:
2493
2600
            raise BzrCommandError('You can only supply one of revision_id or --revision')
2494
2601
        if revision_id_list is None and revision is None:
2495
2602
            raise BzrCommandError('You must supply either --revision or a revision_id')
2496
2603
        b = WorkingTree.open_containing(u'.')[0].branch
2497
 
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
 
2604
        gpg_strategy = gpg.GPGStrategy(b.get_config())
2498
2605
        if revision_id_list is not None:
2499
2606
            for revision_id in revision_id_list:
2500
2607
                b.repository.sign_revision(revision_id, gpg_strategy)
2555
2662
            raise BzrCommandError('Local branch is not bound')
2556
2663
 
2557
2664
 
2558
 
class cmd_uncommit(bzrlib.commands.Command):
 
2665
class cmd_uncommit(Command):
2559
2666
    """Remove the last committed revision.
2560
2667
 
2561
2668
    --verbose will print out what is being removed.
2576
2683
    takes_args = ['location?']
2577
2684
    aliases = []
2578
2685
 
2579
 
    def run(self, location=None, 
 
2686
    def run(self, location=None,
2580
2687
            dry_run=False, verbose=False,
2581
2688
            revision=None, force=False):
2582
 
        from bzrlib.branch import Branch
2583
 
        from bzrlib.log import log_formatter
 
2689
        from bzrlib.log import log_formatter, show_log
2584
2690
        import sys
2585
2691
        from bzrlib.uncommit import uncommit
2586
2692
 
2594
2700
            tree = None
2595
2701
            b = control.open_branch()
2596
2702
 
 
2703
        rev_id = None
2597
2704
        if revision is None:
2598
2705
            revno = b.revno()
2599
 
            rev_id = b.last_revision()
2600
2706
        else:
2601
 
            revno, rev_id = revision[0].in_history(b)
 
2707
            # 'bzr uncommit -r 10' actually means uncommit
 
2708
            # so that the final tree is at revno 10.
 
2709
            # but bzrlib.uncommit.uncommit() actually uncommits
 
2710
            # the revisions that are supplied.
 
2711
            # So we need to offset it by one
 
2712
            revno = revision[0].in_history(b).revno+1
 
2713
 
 
2714
        if revno <= b.revno():
 
2715
            rev_id = b.get_rev_id(revno)
2602
2716
        if rev_id is None:
2603
 
            print 'No revisions to uncommit.'
2604
 
 
2605
 
        for r in range(revno, b.revno()+1):
2606
 
            rev_id = b.get_rev_id(r)
2607
 
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2608
 
            lf.show(r, b.repository.get_revision(rev_id), None)
 
2717
            self.outf.write('No revisions to uncommit.\n')
 
2718
            return 1
 
2719
 
 
2720
        lf = log_formatter('short',
 
2721
                           to_file=self.outf,
 
2722
                           show_timezone='original')
 
2723
 
 
2724
        show_log(b,
 
2725
                 lf,
 
2726
                 verbose=False,
 
2727
                 direction='forward',
 
2728
                 start_revision=revno,
 
2729
                 end_revision=b.revno())
2609
2730
 
2610
2731
        if dry_run:
2611
2732
            print 'Dry-run, pretending to remove the above revisions.'
2646
2767
            pass
2647
2768
        
2648
2769
 
 
2770
class cmd_wait_until_signalled(Command):
 
2771
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
2772
 
 
2773
    This just prints a line to signal when it is ready, then blocks on stdin.
 
2774
    """
 
2775
 
 
2776
    hidden = True
 
2777
 
 
2778
    def run(self):
 
2779
        sys.stdout.write("running\n")
 
2780
        sys.stdout.flush()
 
2781
        sys.stdin.readline()
 
2782
 
 
2783
 
 
2784
class cmd_serve(Command):
 
2785
    """Run the bzr server.
 
2786
    """
 
2787
    takes_options = [
 
2788
        Option('inet',
 
2789
               help='serve on stdin/out for use from inetd or sshd'),
 
2790
        Option('port',
 
2791
               help='listen for connections on nominated port of the form '
 
2792
                    '[hostname:]portnumber. Passing 0 as the port number will '
 
2793
                    'result in a dynamically allocated port.',
 
2794
               type=str),
 
2795
        Option('directory',
 
2796
               help='serve contents of directory',
 
2797
               type=unicode),
 
2798
        ]
 
2799
 
 
2800
    def run(self, port=None, inet=False, directory=None):
 
2801
        from bzrlib.transport import smart
 
2802
        from bzrlib.transport import get_transport
 
2803
        if directory is None:
 
2804
            directory = os.getcwd()
 
2805
        t = get_transport(directory)
 
2806
        if inet:
 
2807
            server = smart.SmartStreamServer(sys.stdin, sys.stdout, t)
 
2808
        elif port is not None:
 
2809
            if ':' in port:
 
2810
                host, port = port.split(':')
 
2811
            else:
 
2812
                host = '127.0.0.1'
 
2813
            server = smart.SmartTCPServer(t, host=host, port=int(port))
 
2814
            print 'listening on port: ', server.port
 
2815
            sys.stdout.flush()
 
2816
        else:
 
2817
            raise BzrCommandError("bzr serve requires one of --inet or --port")
 
2818
        server.serve()
 
2819
 
2649
2820
 
2650
2821
# command-line interpretation helper for merge-related commands
2651
2822
def merge(other_revision, base_revision,