~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: John Arbash Meinel
  • Date: 2006-10-06 07:36:16 UTC
  • mto: This revision was merged to the branch mainline in revision 2071.
  • Revision ID: john@arbash-meinel.com-20061006073616-c9a36866b39fce47
make bzrlib/conflicts.py lazy

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
16
16
 
17
17
"""builtin bzr commands"""
18
18
 
 
19
import os
19
20
 
 
21
from bzrlib.lazy_import import lazy_import
 
22
lazy_import(globals(), """
20
23
import codecs
21
24
import errno
22
 
import os
23
 
import os.path
24
25
import sys
25
26
 
26
27
import bzrlib
27
 
from bzrlib.branch import Branch, BranchReferenceFormat
28
 
from bzrlib import (bundle, branch, bzrdir, errors, osutils, ui, config,
29
 
    repository, log)
30
 
from bzrlib.bundle import read_bundle_from_url
 
28
from bzrlib import (
 
29
    branch,
 
30
    bundle,
 
31
    bzrdir,
 
32
    config,
 
33
    errors,
 
34
    ignores,
 
35
    log,
 
36
    merge as _mod_merge,
 
37
    osutils,
 
38
    repository,
 
39
    transport,
 
40
    tree as _mod_tree,
 
41
    ui,
 
42
    urlutils,
 
43
    )
 
44
from bzrlib.branch import Branch
31
45
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
32
46
from bzrlib.conflicts import ConflictList
 
47
from bzrlib.revision import common_ancestor
 
48
from bzrlib.revisionspec import RevisionSpec
 
49
from bzrlib.workingtree import WorkingTree
 
50
""")
 
51
 
33
52
from bzrlib.commands import Command, display_command
34
 
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
 
53
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
35
54
                           NotBranchError, DivergedBranches, NotConflicted,
36
55
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
37
56
                           NotVersionedError, NotABundle)
38
 
from bzrlib.merge import Merge3Merger
39
57
from bzrlib.option import Option
40
58
from bzrlib.progress import DummyProgress, ProgressPhase
41
 
from bzrlib.revision import common_ancestor
42
 
from bzrlib.revisionspec import RevisionSpec
43
59
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
44
60
from bzrlib.transport.local import LocalTransport
45
 
import bzrlib.urlutils as urlutils
46
 
from bzrlib.workingtree import WorkingTree
47
61
 
48
62
 
49
63
def tree_files(file_list, default_branch=u'.'):
96
110
        format = bzrdir.BzrDirMetaFormat1()
97
111
        format.repository_format = repository.RepositoryFormatKnit1()
98
112
        return format
 
113
    if typestring == "experimental-knit2":
 
114
        format = bzrdir.BzrDirMetaFormat1()
 
115
        format.repository_format = repository.RepositoryFormatKnit2()
 
116
        return format
99
117
    msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
100
118
          "metaweave and weave" % typestring
101
119
    raise BzrCommandError(msg)
224
242
            revs.extend(revision)
225
243
        if revision_info_list is not None:
226
244
            for rev in revision_info_list:
227
 
                revs.append(RevisionSpec(rev))
 
245
                revs.append(RevisionSpec.from_string(rev))
228
246
        if len(revs) == 0:
229
247
            raise BzrCommandError('You must supply a revision identifier')
230
248
 
263
281
 
264
282
    --dry-run will show which files would be added, but not actually 
265
283
    add them.
 
284
 
 
285
    --file-ids-from will try to use the file ids from the supplied path.
 
286
    It looks up ids trying to find a matching parent directory with the
 
287
    same filename, and then by pure path.
266
288
    """
267
289
    takes_args = ['file*']
268
 
    takes_options = ['no-recurse', 'dry-run', 'verbose']
 
290
    takes_options = ['no-recurse', 'dry-run', 'verbose',
 
291
                     Option('file-ids-from', type=unicode,
 
292
                            help='Lookup file ids from here')]
269
293
    encoding_type = 'replace'
270
294
 
271
 
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
 
295
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
 
296
            file_ids_from=None):
272
297
        import bzrlib.add
273
298
 
274
 
        action = bzrlib.add.AddAction(to_file=self.outf,
275
 
            should_print=(not is_quiet()))
276
 
 
277
 
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
 
299
        if file_ids_from is not None:
 
300
            try:
 
301
                base_tree, base_path = WorkingTree.open_containing(
 
302
                                            file_ids_from)
 
303
            except errors.NoWorkingTree:
 
304
                base_branch, base_path = Branch.open_containing(
 
305
                                            file_ids_from)
 
306
                base_tree = base_branch.basis_tree()
 
307
 
 
308
            action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
 
309
                          to_file=self.outf, should_print=(not is_quiet()))
 
310
        else:
 
311
            action = bzrlib.add.AddAction(to_file=self.outf,
 
312
                should_print=(not is_quiet()))
 
313
 
 
314
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
278
315
                                              action=action, save=not dry_run)
279
316
        if len(ignored) > 0:
280
317
            if verbose:
327
364
    """Show inventory of the current working copy or a revision.
328
365
 
329
366
    It is possible to limit the output to a particular entry
330
 
    type using the --kind option.  For example; --kind file.
 
367
    type using the --kind option.  For example: --kind file.
 
368
 
 
369
    It is also possible to restrict the list of files to a specific
 
370
    set. For example: bzr inventory --show-ids this/file
331
371
    """
332
372
 
333
373
    takes_options = ['revision', 'show-ids', 'kind']
334
 
    
 
374
    takes_args = ['file*']
 
375
 
335
376
    @display_command
336
 
    def run(self, revision=None, show_ids=False, kind=None):
 
377
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
337
378
        if kind and kind not in ['file', 'directory', 'symlink']:
338
379
            raise BzrCommandError('invalid kind specified')
339
 
        tree = WorkingTree.open_containing(u'.')[0]
340
 
        if revision is None:
341
 
            inv = tree.read_working_inventory()
342
 
        else:
 
380
 
 
381
        work_tree, file_list = tree_files(file_list)
 
382
 
 
383
        if revision is not None:
343
384
            if len(revision) > 1:
344
385
                raise BzrCommandError('bzr inventory --revision takes'
345
 
                    ' exactly one revision identifier')
346
 
            inv = tree.branch.repository.get_revision_inventory(
347
 
                revision[0].in_history(tree.branch).rev_id)
348
 
 
349
 
        for path, entry in inv.entries():
 
386
                                      ' exactly one revision identifier')
 
387
            revision_id = revision[0].in_history(work_tree.branch).rev_id
 
388
            tree = work_tree.branch.repository.revision_tree(revision_id)
 
389
                        
 
390
            # We include work_tree as well as 'tree' here
 
391
            # So that doing '-r 10 path/foo' will lookup whatever file
 
392
            # exists now at 'path/foo' even if it has been renamed, as
 
393
            # well as whatever files existed in revision 10 at path/foo
 
394
            trees = [tree, work_tree]
 
395
        else:
 
396
            tree = work_tree
 
397
            trees = [tree]
 
398
 
 
399
        if file_list is not None:
 
400
            file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
 
401
                                                      require_versioned=True)
 
402
            # find_ids_across_trees may include some paths that don't
 
403
            # exist in 'tree'.
 
404
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
405
                             for file_id in file_ids if file_id in tree)
 
406
        else:
 
407
            entries = tree.inventory.entries()
 
408
 
 
409
        for path, entry in entries:
350
410
            if kind and kind != entry.kind:
351
411
                continue
352
412
            if show_ids:
516
576
            create_prefix=False, verbose=False):
517
577
        # FIXME: Way too big!  Put this into a function called from the
518
578
        # command.
519
 
        from bzrlib.transport import get_transport
520
579
        
521
580
        br_from = Branch.open_containing('.')[0]
522
581
        stored_loc = br_from.get_push_location()
529
588
                self.outf.write("Using saved location: %s\n" % display_url)
530
589
                location = stored_loc
531
590
 
532
 
        transport = get_transport(location)
533
 
        location_url = transport.base
 
591
        to_transport = transport.get_transport(location)
 
592
        location_url = to_transport.base
534
593
 
535
594
        old_rh = []
536
595
        try:
538
597
            br_to = dir_to.open_branch()
539
598
        except NotBranchError:
540
599
            # create a branch.
541
 
            transport = transport.clone('..')
 
600
            to_transport = to_transport.clone('..')
542
601
            if not create_prefix:
543
602
                try:
544
 
                    relurl = transport.relpath(location_url)
 
603
                    relurl = to_transport.relpath(location_url)
545
604
                    mutter('creating directory %s => %s', location_url, relurl)
546
 
                    transport.mkdir(relurl)
 
605
                    to_transport.mkdir(relurl)
547
606
                except NoSuchFile:
548
607
                    raise BzrCommandError("Parent directory of %s "
549
608
                                          "does not exist." % location)
550
609
            else:
551
 
                current = transport.base
552
 
                needed = [(transport, transport.relpath(location_url))]
 
610
                current = to_transport.base
 
611
                needed = [(to_transport, to_transport.relpath(location_url))]
553
612
                while needed:
554
613
                    try:
555
 
                        transport, relpath = needed[-1]
556
 
                        transport.mkdir(relpath)
 
614
                        to_transport, relpath = needed[-1]
 
615
                        to_transport.mkdir(relpath)
557
616
                        needed.pop()
558
617
                    except NoSuchFile:
559
 
                        new_transport = transport.clone('..')
 
618
                        new_transport = to_transport.clone('..')
560
619
                        needed.append((new_transport,
561
 
                                       new_transport.relpath(transport.base)))
562
 
                        if new_transport.base == transport.base:
 
620
                                       new_transport.relpath(to_transport.base)))
 
621
                        if new_transport.base == to_transport.base:
563
622
                            raise BzrCommandError("Could not create "
564
623
                                                  "path prefix.")
565
624
            dir_to = br_from.bzrdir.clone(location_url,
618
677
    aliases = ['get', 'clone']
619
678
 
620
679
    def run(self, from_location, to_location=None, revision=None, basis=None):
621
 
        from bzrlib.transport import get_transport
622
680
        if revision is None:
623
681
            revision = [None]
624
682
        elif len(revision) > 1:
651
709
            else:
652
710
                name = os.path.basename(to_location) + '\n'
653
711
 
654
 
            to_transport = get_transport(to_location)
 
712
            to_transport = transport.get_transport(to_location)
655
713
            try:
656
714
                to_transport.mkdir('.')
657
715
            except errors.FileExists:
732
790
        # if the source and to_location are the same, 
733
791
        # and there is no working tree,
734
792
        # then reconstitute a branch
735
 
        if (osutils.abspath(to_location) == 
 
793
        if (osutils.abspath(to_location) ==
736
794
            osutils.abspath(branch_location)):
737
795
            try:
738
796
                source.bzrdir.open_workingtree()
753
811
        old_format = bzrdir.BzrDirFormat.get_default_format()
754
812
        bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
755
813
        try:
756
 
            if lightweight:
757
 
                checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
758
 
                branch.BranchReferenceFormat().initialize(checkout, source)
759
 
            else:
760
 
                checkout_branch =  bzrdir.BzrDir.create_branch_convenience(
761
 
                    to_location, force_new_tree=False)
762
 
                checkout = checkout_branch.bzrdir
763
 
                checkout_branch.bind(source)
764
 
                if revision_id is not None:
765
 
                    rh = checkout_branch.revision_history()
766
 
                    checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
767
 
            checkout.create_workingtree(revision_id)
 
814
            source.create_checkout(to_location, revision_id, lightweight)
768
815
        finally:
769
816
            bzrdir.BzrDirFormat.set_default_format(old_format)
770
817
 
779
826
 
780
827
    @display_command
781
828
    def run(self, dir=u'.'):
782
 
        from bzrlib.tree import find_renames
783
829
        tree = WorkingTree.open_containing(dir)[0]
784
830
        old_inv = tree.basis_tree().inventory
785
831
        new_inv = tree.read_working_inventory()
786
 
        renames = list(find_renames(old_inv, new_inv))
 
832
        renames = list(_mod_tree.find_renames(old_inv, new_inv))
787
833
        renames.sort()
788
834
        for old_name, new_name in renames:
789
835
            self.outf.write("%s => %s\n" % (old_name, new_name))
800
846
    'bzr revert' instead of 'bzr commit' after the update.
801
847
    """
802
848
    takes_args = ['dir?']
 
849
    aliases = ['up']
803
850
 
804
851
    def run(self, dir='.'):
805
852
        tree = WorkingTree.open_containing(dir)[0]
806
853
        tree.lock_write()
807
854
        try:
808
 
            last_rev = tree.last_revision() 
 
855
            existing_pending_merges = tree.get_parent_ids()[1:]
 
856
            last_rev = tree.last_revision()
809
857
            if last_rev == tree.branch.last_revision():
810
858
                # may be up to date, check master too.
811
859
                master = tree.branch.get_master_branch()
816
864
            conflicts = tree.update()
817
865
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
818
866
            note('Updated to revision %d.' % (revno,))
 
867
            if tree.get_parent_ids()[1:] != existing_pending_merges:
 
868
                note('Your local commits will now show as pending merges with '
 
869
                     "'bzr status', and can be committed with 'bzr commit'.")
819
870
            if conflicts != 0:
820
871
                return 1
821
872
            else:
866
917
                raise BzrCommandError('Specify one or more files to remove, or'
867
918
                                      ' use --new.')
868
919
        else:
869
 
            from bzrlib.delta import compare_trees
870
 
            added = [compare_trees(tree.basis_tree(), tree,
871
 
                                   specific_files=file_list).added]
872
 
            file_list = sorted([f[0] for f in added[0]], reverse=True)
 
920
            added = tree.changes_from(tree.basis_tree(),
 
921
                specific_files=file_list).added
 
922
            file_list = sorted([f[0] for f in added], reverse=True)
873
923
            if len(file_list) == 0:
874
924
                raise BzrCommandError('No matching files.')
875
925
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
890
940
    def run(self, filename):
891
941
        tree, relpath = WorkingTree.open_containing(filename)
892
942
        i = tree.inventory.path2id(relpath)
893
 
        if i == None:
 
943
        if i is None:
894
944
            raise BzrError("%r is not a versioned file" % filename)
895
945
        else:
896
946
            self.outf.write(i + '\n')
911
961
        tree, relpath = WorkingTree.open_containing(filename)
912
962
        inv = tree.inventory
913
963
        fid = inv.path2id(relpath)
914
 
        if fid == None:
 
964
        if fid is None:
915
965
            raise BzrError("%r is not a versioned file" % filename)
916
966
        for fip in inv.get_idpath(fid):
917
967
            self.outf.write(fip + '\n')
975
1025
            last_revision = wt.last_revision()
976
1026
 
977
1027
        revision_ids = b.repository.get_ancestry(last_revision)
978
 
        assert revision_ids[0] == None
 
1028
        assert revision_ids[0] is None
979
1029
        revision_ids.pop(0)
980
1030
        for revision_id in revision_ids:
981
1031
            self.outf.write(revision_id + '\n')
1016
1066
            format = get_format_type('default')
1017
1067
        if location is None:
1018
1068
            location = u'.'
1019
 
        else:
1020
 
            # The path has to exist to initialize a
1021
 
            # branch inside of it.
1022
 
            # Just using os.mkdir, since I don't
1023
 
            # believe that we want to create a bunch of
1024
 
            # locations if the user supplies an extended path
1025
 
            if not os.path.exists(location):
1026
 
                os.mkdir(location)
 
1069
 
 
1070
        to_transport = transport.get_transport(location)
 
1071
 
 
1072
        # The path has to exist to initialize a
 
1073
        # branch inside of it.
 
1074
        # Just using os.mkdir, since I don't
 
1075
        # believe that we want to create a bunch of
 
1076
        # locations if the user supplies an extended path
 
1077
        # TODO: create-prefix
 
1078
        try:
 
1079
            to_transport.mkdir('.')
 
1080
        except errors.FileExists:
 
1081
            pass
 
1082
                    
1027
1083
        try:
1028
1084
            existing_bzrdir = bzrdir.BzrDir.open(location)
1029
1085
        except NotBranchError:
1031
1087
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
1032
1088
        else:
1033
1089
            if existing_bzrdir.has_branch():
1034
 
                if existing_bzrdir.has_workingtree():
1035
 
                    raise errors.AlreadyBranchError(location)
1036
 
                else:
1037
 
                    raise errors.BranchExistsWithoutWorkingTree(location)
 
1090
                if (isinstance(to_transport, LocalTransport)
 
1091
                    and not existing_bzrdir.has_workingtree()):
 
1092
                        raise errors.BranchExistsWithoutWorkingTree(location)
 
1093
                raise errors.AlreadyBranchError(location)
1038
1094
            else:
1039
1095
                existing_bzrdir.create_branch()
1040
1096
                existing_bzrdir.create_workingtree()
1066
1122
                             ' a working tree')]
1067
1123
    aliases = ["init-repo"]
1068
1124
    def run(self, location, format=None, trees=False):
1069
 
        from bzrlib.transport import get_transport
1070
1125
        if format is None:
1071
1126
            format = get_format_type('default')
1072
 
        transport = get_transport(location)
1073
 
        if not transport.has('.'):
1074
 
            transport.mkdir('')
1075
 
        newdir = format.initialize_on_transport(transport)
 
1127
 
 
1128
        if location is None:
 
1129
            location = '.'
 
1130
 
 
1131
        to_transport = transport.get_transport(location)
 
1132
        try:
 
1133
            to_transport.mkdir('.')
 
1134
        except errors.FileExists:
 
1135
            pass
 
1136
 
 
1137
        newdir = format.initialize_on_transport(to_transport)
1076
1138
        repo = newdir.create_repository(shared=True)
1077
1139
        repo.set_make_working_trees(trees)
1078
1140
 
1149
1211
                raise BzrCommandError("Files are in different branches")
1150
1212
            file_list = None
1151
1213
        except NotBranchError:
1152
 
            # Don't raise an error when bzr diff is called from
1153
 
            # outside a working tree.
1154
 
            tree1, tree2 = None, None
 
1214
            if (revision is not None and len(revision) == 2
 
1215
                and not revision[0].needs_branch()
 
1216
                and not revision[1].needs_branch()):
 
1217
                # If both revision specs include a branch, we can
 
1218
                # diff them without needing a local working tree
 
1219
                tree1, tree2 = None, None
 
1220
            else:
 
1221
                raise
1155
1222
        if revision is not None:
1156
1223
            if tree2 is not None:
1157
1224
                raise BzrCommandError("Can't specify -r with two branches")
1205
1272
    hidden = True
1206
1273
    @display_command
1207
1274
    def run(self):
1208
 
        from bzrlib.delta import compare_trees
1209
 
 
1210
1275
        tree = WorkingTree.open_containing(u'.')[0]
1211
 
        td = compare_trees(tree.basis_tree(), tree)
1212
 
 
 
1276
        td = tree.changes_from(tree.basis_tree())
1213
1277
        for path, id, kind, text_modified, meta_modified in td.modified:
1214
1278
            self.outf.write(path + '\n')
1215
1279
 
1311
1375
        else:
1312
1376
            # local dir only
1313
1377
            # FIXME ? log the current subdir only RBC 20060203 
1314
 
            dir, relpath = bzrdir.BzrDir.open_containing('.')
 
1378
            if revision is not None \
 
1379
                    and len(revision) > 0 and revision[0].get_branch():
 
1380
                location = revision[0].get_branch()
 
1381
            else:
 
1382
                location = '.'
 
1383
            dir, relpath = bzrdir.BzrDir.open_containing(location)
1315
1384
            b = dir.open_branch()
1316
1385
 
1317
1386
        if revision is None:
1320
1389
        elif len(revision) == 1:
1321
1390
            rev1 = rev2 = revision[0].in_history(b).revno
1322
1391
        elif len(revision) == 2:
 
1392
            if revision[1].get_branch() != revision[0].get_branch():
 
1393
                # b is taken from revision[0].get_branch(), and
 
1394
                # show_log will use its revision_history. Having
 
1395
                # different branches will lead to weird behaviors.
 
1396
                raise BzrCommandError(
 
1397
                    "Log doesn't accept two revisions in different branches.")
1323
1398
            if revision[0].spec is None:
1324
1399
                # missing begin-range means first revision
1325
1400
                rev1 = 1
1340
1415
        if rev1 > rev2:
1341
1416
            (rev2, rev1) = (rev1, rev2)
1342
1417
 
1343
 
        if (log_format == None):
 
1418
        if (log_format is None):
1344
1419
            default = b.get_config().log_format()
1345
1420
            log_format = get_log_format(long=long, short=short, line=line, 
1346
1421
                                        default=default)
1480
1555
        from bzrlib.atomicfile import AtomicFile
1481
1556
        if old_default_rules is not None:
1482
1557
            # dump the rules and exit
1483
 
            for pattern in bzrlib.DEFAULT_IGNORE:
 
1558
            for pattern in ignores.OLD_DEFAULTS:
1484
1559
                print pattern
1485
1560
            return
1486
1561
        if name_pattern is None:
1613
1688
 
1614
1689
        if tree is None:
1615
1690
            b, relpath = Branch.open_containing(filename)
 
1691
        if revision is not None and revision[0].get_branch() is not None:
 
1692
            b = Branch.open(revision[0].get_branch())
1616
1693
        if revision is None:
1617
1694
            revision_id = b.last_revision()
1618
1695
        else:
1732
1809
            raise BzrCommandError("Commit refused because there are unknown "
1733
1810
                                  "files in the working tree.")
1734
1811
        except errors.BoundBranchOutOfDate, e:
1735
 
            raise BzrCommandError(str(e)
1736
 
                                  + ' Either unbind, update, or'
1737
 
                                    ' pass --local to commit.')
1738
 
 
 
1812
            raise BzrCommandError(str(e) + "\n"
 
1813
                'To commit to master branch, run update and then commit.\n'
 
1814
                'You can also pass --local to commit to continue working '
 
1815
                'disconnected.')
1739
1816
 
1740
1817
class cmd_check(Command):
1741
1818
    """Validate consistency of branch history.
1833
1910
        # display a warning if an email address isn't included in the given name.
1834
1911
        try:
1835
1912
            config.extract_email_address(name)
1836
 
        except BzrError, e:
 
1913
        except errors.NoEmailInUsername, e:
1837
1914
            warning('"%s" does not seem to contain an email address.  '
1838
1915
                    'This is allowed, but not recommended.', name)
1839
1916
        
1917
1994
                     Option('lsprof-timed',
1918
1995
                            help='generate lsprof output for benchmarked'
1919
1996
                                 ' sections of code.'),
 
1997
                     Option('cache-dir', type=str,
 
1998
                            help='a directory to cache intermediate'
 
1999
                                 ' benchmark steps'),
1920
2000
                     ]
1921
2001
 
1922
2002
    def run(self, testspecs_list=None, verbose=None, one=False,
1923
2003
            keep_output=False, transport=None, benchmark=None,
1924
 
            lsprof_timed=None):
 
2004
            lsprof_timed=None, cache_dir=None):
1925
2005
        import bzrlib.ui
1926
2006
        from bzrlib.tests import selftest
1927
2007
        import bzrlib.benchmarks as benchmarks
 
2008
        from bzrlib.benchmarks import tree_creator
 
2009
 
 
2010
        if cache_dir is not None:
 
2011
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
1928
2012
        # we don't want progress meters from the tests to go to the
1929
2013
        # real output; and we don't want log messages cluttering up
1930
2014
        # the real logs.
1943
2027
                test_suite_factory = benchmarks.test_suite
1944
2028
                if verbose is None:
1945
2029
                    verbose = True
 
2030
                # TODO: should possibly lock the history file...
 
2031
                benchfile = open(".perf_history", "at")
1946
2032
            else:
1947
2033
                test_suite_factory = None
1948
2034
                if verbose is None:
1949
2035
                    verbose = False
1950
 
            result = selftest(verbose=verbose, 
1951
 
                              pattern=pattern,
1952
 
                              stop_on_failure=one, 
1953
 
                              keep_output=keep_output,
1954
 
                              transport=transport,
1955
 
                              test_suite_factory=test_suite_factory,
1956
 
                              lsprof_timed=lsprof_timed)
 
2036
                benchfile = None
 
2037
            try:
 
2038
                result = selftest(verbose=verbose, 
 
2039
                                  pattern=pattern,
 
2040
                                  stop_on_failure=one, 
 
2041
                                  keep_output=keep_output,
 
2042
                                  transport=transport,
 
2043
                                  test_suite_factory=test_suite_factory,
 
2044
                                  lsprof_timed=lsprof_timed,
 
2045
                                  bench_history=benchfile)
 
2046
            finally:
 
2047
                if benchfile is not None:
 
2048
                    benchfile.close()
1957
2049
            if result:
1958
2050
                info('tests passed')
1959
2051
            else:
1963
2055
            ui.ui_factory = save_ui
1964
2056
 
1965
2057
 
1966
 
def _get_bzr_branch():
1967
 
    """If bzr is run from a branch, return Branch or None"""
1968
 
    from os.path import dirname
1969
 
    
1970
 
    try:
1971
 
        branch = Branch.open(dirname(osutils.abspath(dirname(__file__))))
1972
 
        return branch
1973
 
    except errors.BzrError:
1974
 
        return None
1975
 
    
1976
 
 
1977
 
def show_version():
1978
 
    import bzrlib
1979
 
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
1980
 
    # is bzrlib itself in a branch?
1981
 
    branch = _get_bzr_branch()
1982
 
    if branch:
1983
 
        rh = branch.revision_history()
1984
 
        revno = len(rh)
1985
 
        print "  bzr checkout, revision %d" % (revno,)
1986
 
        print "  nick: %s" % (branch.nick,)
1987
 
        if rh:
1988
 
            print "  revid: %s" % (rh[-1],)
1989
 
    print "Using python interpreter:", sys.executable
1990
 
    import site
1991
 
    print "Using python standard library:", os.path.dirname(site.__file__)
1992
 
    print "Using bzrlib:",
1993
 
    if len(bzrlib.__path__) > 1:
1994
 
        # print repr, which is a good enough way of making it clear it's
1995
 
        # more than one element (eg ['/foo/bar', '/foo/bzr'])
1996
 
        print repr(bzrlib.__path__)
1997
 
    else:
1998
 
        print bzrlib.__path__[0]
1999
 
 
2000
 
    print
2001
 
    print bzrlib.__copyright__
2002
 
    print "http://bazaar-vcs.org/"
2003
 
    print
2004
 
    print "bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and"
2005
 
    print "you may use, modify and redistribute it under the terms of the GNU"
2006
 
    print "General Public License version 2 or later."
2007
 
 
2008
 
 
2009
2058
class cmd_version(Command):
2010
2059
    """Show version of bzr."""
 
2060
 
2011
2061
    @display_command
2012
2062
    def run(self):
 
2063
        from bzrlib.version import show_version
2013
2064
        show_version()
2014
2065
 
 
2066
 
2015
2067
class cmd_rocks(Command):
2016
2068
    """Statement of optimism."""
 
2069
 
2017
2070
    hidden = True
 
2071
 
2018
2072
    @display_command
2019
2073
    def run(self):
2020
2074
        print "it sure does!"
2021
2075
 
2022
2076
 
2023
2077
class cmd_find_merge_base(Command):
2024
 
    """Find and print a base revision for merging two branches.
2025
 
    """
 
2078
    """Find and print a base revision for merging two branches."""
2026
2079
    # TODO: Options to specify revisions on either side, as if
2027
2080
    #       merging only part of the history.
2028
2081
    takes_args = ['branch', 'other']
2030
2083
    
2031
2084
    @display_command
2032
2085
    def run(self, branch, other):
2033
 
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
 
2086
        from bzrlib.revision import MultipleRevisionSources
2034
2087
        
2035
2088
        branch1 = Branch.open_containing(branch)[0]
2036
2089
        branch2 = Branch.open_containing(other)[0]
2093
2146
    takes_args = ['branch?']
2094
2147
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2095
2148
                     Option('show-base', help="Show base revision text in "
2096
 
                            "conflicts")]
 
2149
                            "conflicts"), 
 
2150
                     Option('uncommitted', help='Apply uncommitted changes'
 
2151
                            ' from a working copy, instead of branch changes')]
2097
2152
 
2098
2153
    def help(self):
2099
 
        from merge import merge_type_help
2100
2154
        from inspect import getdoc
2101
 
        return getdoc(self) + '\n' + merge_type_help() 
 
2155
        return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2102
2156
 
2103
2157
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2104
 
            show_base=False, reprocess=False, remember=False):
 
2158
            show_base=False, reprocess=False, remember=False, 
 
2159
            uncommitted=False):
2105
2160
        if merge_type is None:
2106
 
            merge_type = Merge3Merger
 
2161
            merge_type = _mod_merge.Merge3Merger
2107
2162
 
2108
2163
        tree = WorkingTree.open_containing(u'.')[0]
2109
2164
 
2120
2175
                else:
2121
2176
                    return 1
2122
2177
 
2123
 
        branch = self._get_remembered_parent(tree, branch, 'Merging from')
 
2178
        if revision is None \
 
2179
                or len(revision) < 1 or revision[0].needs_branch():
 
2180
            branch = self._get_remembered_parent(tree, branch, 'Merging from')
2124
2181
 
2125
2182
        if revision is None or len(revision) < 1:
2126
 
            base = [None, None]
2127
 
            other = [branch, -1]
 
2183
            if uncommitted:
 
2184
                base = [branch, -1]
 
2185
                other = [branch, None]
 
2186
            else:
 
2187
                base = [None, None]
 
2188
                other = [branch, -1]
2128
2189
            other_branch, path = Branch.open_containing(branch)
2129
2190
        else:
 
2191
            if uncommitted:
 
2192
                raise BzrCommandError('Cannot use --uncommitted and --revision'
 
2193
                                      ' at the same time.')
 
2194
            branch = revision[0].get_branch() or branch
2130
2195
            if len(revision) == 1:
2131
2196
                base = [None, None]
2132
2197
                other_branch, path = Branch.open_containing(branch)
2136
2201
                assert len(revision) == 2
2137
2202
                if None in revision:
2138
2203
                    raise BzrCommandError(
2139
 
                        "Merge doesn't permit that revision specifier.")
2140
 
                other_branch, path = Branch.open_containing(branch)
 
2204
                        "Merge doesn't permit empty revision specifier.")
 
2205
                base_branch, path = Branch.open_containing(branch)
 
2206
                branch1 = revision[1].get_branch() or branch
 
2207
                other_branch, path1 = Branch.open_containing(branch1)
 
2208
                if revision[0].get_branch() is not None:
 
2209
                    # then path was obtained from it, and is None.
 
2210
                    path = path1
2141
2211
 
2142
 
                base = [branch, revision[0].in_history(other_branch).revno]
2143
 
                other = [branch, revision[1].in_history(other_branch).revno]
 
2212
                base = [branch, revision[0].in_history(base_branch).revno]
 
2213
                other = [branch1, revision[1].in_history(other_branch).revno]
2144
2214
 
2145
2215
        if tree.branch.get_parent() is None or remember:
2146
2216
            tree.branch.set_parent(other_branch.base)
2152
2222
        pb = ui.ui_factory.nested_progress_bar()
2153
2223
        try:
2154
2224
            try:
2155
 
                conflict_count = merge(other, base, check_clean=(not force),
2156
 
                                       merge_type=merge_type,
2157
 
                                       reprocess=reprocess,
2158
 
                                       show_base=show_base,
2159
 
                                       pb=pb, file_list=interesting_files)
 
2225
                conflict_count = _merge_helper(
 
2226
                    other, base, check_clean=(not force),
 
2227
                    merge_type=merge_type,
 
2228
                    reprocess=reprocess,
 
2229
                    show_base=show_base,
 
2230
                    pb=pb, file_list=interesting_files)
2160
2231
            finally:
2161
2232
                pb.finished()
2162
2233
            if conflict_count != 0:
2216
2287
                            "conflicts")]
2217
2288
 
2218
2289
    def help(self):
2219
 
        from merge import merge_type_help
2220
2290
        from inspect import getdoc
2221
 
        return getdoc(self) + '\n' + merge_type_help() 
 
2291
        return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2222
2292
 
2223
2293
    def run(self, file_list=None, merge_type=None, show_base=False,
2224
2294
            reprocess=False):
2225
 
        from bzrlib.merge import merge_inner, transform_tree
2226
2295
        if merge_type is None:
2227
 
            merge_type = Merge3Merger
 
2296
            merge_type = _mod_merge.Merge3Merger
2228
2297
        tree, file_list = tree_files(file_list)
2229
2298
        tree.lock_write()
2230
2299
        try:
2231
 
            pending_merges = tree.pending_merges() 
2232
 
            if len(pending_merges) != 1:
 
2300
            parents = tree.get_parent_ids()
 
2301
            if len(parents) != 2:
2233
2302
                raise BzrCommandError("Sorry, remerge only works after normal"
2234
2303
                                      " merges.  Not cherrypicking or"
2235
2304
                                      " multi-merges.")
2236
2305
            repository = tree.branch.repository
2237
 
            base_revision = common_ancestor(tree.branch.last_revision(), 
2238
 
                                            pending_merges[0], repository)
 
2306
            base_revision = common_ancestor(parents[0],
 
2307
                                            parents[1], repository)
2239
2308
            base_tree = repository.revision_tree(base_revision)
2240
 
            other_tree = repository.revision_tree(pending_merges[0])
 
2309
            other_tree = repository.revision_tree(parents[1])
2241
2310
            interesting_ids = None
2242
2311
            new_conflicts = []
2243
2312
            conflicts = tree.conflicts()
2254
2323
                    for name, ie in tree.inventory.iter_entries(file_id):
2255
2324
                        interesting_ids.add(ie.file_id)
2256
2325
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2257
 
            transform_tree(tree, tree.basis_tree(), interesting_ids)
 
2326
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
2258
2327
            tree.set_conflicts(ConflictList(new_conflicts))
2259
2328
            if file_list is None:
2260
2329
                restore_files = list(tree.iter_conflicts())
2265
2334
                    restore(tree.abspath(filename))
2266
2335
                except NotConflicted:
2267
2336
                    pass
2268
 
            conflicts = merge_inner(tree.branch, other_tree, base_tree,
2269
 
                                    this_tree=tree,
2270
 
                                    interesting_ids=interesting_ids, 
2271
 
                                    other_rev_id=pending_merges[0], 
2272
 
                                    merge_type=merge_type, 
2273
 
                                    show_base=show_base,
2274
 
                                    reprocess=reprocess)
 
2337
            conflicts = _mod_merge.merge_inner(
 
2338
                                      tree.branch, other_tree, base_tree,
 
2339
                                      this_tree=tree,
 
2340
                                      interesting_ids=interesting_ids,
 
2341
                                      other_rev_id=parents[1],
 
2342
                                      merge_type=merge_type,
 
2343
                                      show_base=show_base,
 
2344
                                      reprocess=reprocess)
2275
2345
        finally:
2276
2346
            tree.unlock()
2277
2347
        if conflicts > 0:
2280
2350
            return 0
2281
2351
 
2282
2352
class cmd_revert(Command):
2283
 
    """Reverse all changes since the last commit.
2284
 
 
2285
 
    Only versioned files are affected.  Specify filenames to revert only 
2286
 
    those files.  By default, any files that are changed will be backed up
2287
 
    first.  Backup files have a '~' appended to their name.
 
2353
    """Revert files to a previous revision.
 
2354
 
 
2355
    Giving a list of files will revert only those files.  Otherwise, all files
 
2356
    will be reverted.  If the revision is not specified with '--revision', the
 
2357
    last committed revision is used.
 
2358
 
 
2359
    To remove only some changes, without reverting to a prior version, use
 
2360
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
 
2361
    introduced by -2, without affecting the changes introduced by -1.  Or
 
2362
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
2363
    
 
2364
    By default, any files that have been manually changed will be backed up
 
2365
    first.  (Files changed only by merge are not backed up.)  Backup files have
 
2366
    '.~#~' appended to their name, where # is a number.
 
2367
 
 
2368
    When you provide files, you can use their current pathname or the pathname
 
2369
    from the target revision.  So you can use revert to "undelete" a file by
 
2370
    name.  If you name a directory, all the contents of that directory will be
 
2371
    reverted.
2288
2372
    """
2289
2373
    takes_options = ['revision', 'no-backup']
2290
2374
    takes_args = ['file*']
2291
2375
    aliases = ['merge-revert']
2292
2376
 
2293
2377
    def run(self, revision=None, no_backup=False, file_list=None):
2294
 
        from bzrlib.commands import parse_spec
2295
2378
        if file_list is not None:
2296
2379
            if len(file_list) == 0:
2297
2380
                raise BzrCommandError("No files specified")
2395
2478
        if other_branch is None:
2396
2479
            other_branch = parent
2397
2480
            if other_branch is None:
2398
 
                raise BzrCommandError("No missing location known or specified.")
 
2481
                raise BzrCommandError("No peer location known or specified.")
2399
2482
            print "Using last location: " + local_branch.get_parent()
2400
2483
        remote_branch = Branch.open(other_branch)
2401
2484
        if remote_branch.base == local_branch.base:
2405
2488
            remote_branch.lock_read()
2406
2489
            try:
2407
2490
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2408
 
                if (log_format == None):
 
2491
                if (log_format is None):
2409
2492
                    default = local_branch.get_config().log_format()
2410
2493
                    log_format = get_log_format(long=long, short=short, 
2411
2494
                                                line=line, default=default)
2459
2542
        import bzrlib.plugin
2460
2543
        from inspect import getdoc
2461
2544
        for name, plugin in bzrlib.plugin.all_plugins().items():
2462
 
            if hasattr(plugin, '__path__'):
 
2545
            if getattr(plugin, '__path__', None) is not None:
2463
2546
                print plugin.__path__[0]
2464
 
            elif hasattr(plugin, '__file__'):
 
2547
            elif getattr(plugin, '__file__', None) is not None:
2465
2548
                print plugin.__file__
2466
2549
            else:
2467
 
                print `plugin`
 
2550
                print repr(plugin)
2468
2551
                
2469
2552
            d = getdoc(plugin)
2470
2553
            if d:
2473
2556
 
2474
2557
class cmd_testament(Command):
2475
2558
    """Show testament (signing-form) of a revision."""
2476
 
    takes_options = ['revision', 'long', 
 
2559
    takes_options = ['revision', 
 
2560
                     Option('long', help='Produce long-format testament'), 
2477
2561
                     Option('strict', help='Produce a strict-format'
2478
2562
                            ' testament')]
2479
2563
    takes_args = ['branch?']
2721
2805
            pass
2722
2806
        
2723
2807
 
 
2808
class cmd_wait_until_signalled(Command):
 
2809
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
2810
 
 
2811
    This just prints a line to signal when it is ready, then blocks on stdin.
 
2812
    """
 
2813
 
 
2814
    hidden = True
 
2815
 
 
2816
    def run(self):
 
2817
        sys.stdout.write("running\n")
 
2818
        sys.stdout.flush()
 
2819
        sys.stdin.readline()
 
2820
 
 
2821
 
 
2822
class cmd_serve(Command):
 
2823
    """Run the bzr server."""
 
2824
 
 
2825
    aliases = ['server']
 
2826
 
 
2827
    takes_options = [
 
2828
        Option('inet',
 
2829
               help='serve on stdin/out for use from inetd or sshd'),
 
2830
        Option('port',
 
2831
               help='listen for connections on nominated port of the form '
 
2832
                    '[hostname:]portnumber. Passing 0 as the port number will '
 
2833
                    'result in a dynamically allocated port.',
 
2834
               type=str),
 
2835
        Option('directory',
 
2836
               help='serve contents of directory',
 
2837
               type=unicode),
 
2838
        Option('allow-writes',
 
2839
               help='By default the server is a readonly server. Supplying '
 
2840
                    '--allow-writes enables write access to the contents of '
 
2841
                    'the served directory and below. '
 
2842
                ),
 
2843
        ]
 
2844
 
 
2845
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
 
2846
        from bzrlib.transport import smart
 
2847
        from bzrlib.transport import get_transport
 
2848
        if directory is None:
 
2849
            directory = os.getcwd()
 
2850
        url = urlutils.local_path_to_url(directory)
 
2851
        if not allow_writes:
 
2852
            url = 'readonly+' + url
 
2853
        t = get_transport(url)
 
2854
        if inet:
 
2855
            server = smart.SmartStreamServer(sys.stdin, sys.stdout, t)
 
2856
        elif port is not None:
 
2857
            if ':' in port:
 
2858
                host, port = port.split(':')
 
2859
            else:
 
2860
                host = '127.0.0.1'
 
2861
            server = smart.SmartTCPServer(t, host=host, port=int(port))
 
2862
            print 'listening on port: ', server.port
 
2863
            sys.stdout.flush()
 
2864
        else:
 
2865
            raise BzrCommandError("bzr serve requires one of --inet or --port")
 
2866
        server.serve()
 
2867
 
2724
2868
 
2725
2869
# command-line interpretation helper for merge-related commands
2726
 
def merge(other_revision, base_revision,
2727
 
          check_clean=True, ignore_zero=False,
2728
 
          this_dir=None, backup_files=False, merge_type=Merge3Merger,
2729
 
          file_list=None, show_base=False, reprocess=False,
2730
 
          pb=DummyProgress()):
 
2870
def _merge_helper(other_revision, base_revision,
 
2871
                  check_clean=True, ignore_zero=False,
 
2872
                  this_dir=None, backup_files=False,
 
2873
                  merge_type=None,
 
2874
                  file_list=None, show_base=False, reprocess=False,
 
2875
                  pb=DummyProgress()):
2731
2876
    """Merge changes into a tree.
2732
2877
 
2733
2878
    base_revision
2755
2900
    clients might prefer to call merge.merge_inner(), which has less magic 
2756
2901
    behavior.
2757
2902
    """
2758
 
    from bzrlib.merge import Merger
 
2903
    # Loading it late, so that we don't always have to import bzrlib.merge
 
2904
    if merge_type is None:
 
2905
        merge_type = _mod_merge.Merge3Merger
2759
2906
    if this_dir is None:
2760
2907
        this_dir = u'.'
2761
2908
    this_tree = WorkingTree.open_containing(this_dir)[0]
2762
 
    if show_base and not merge_type is Merge3Merger:
 
2909
    if show_base and not merge_type is _mod_merge.Merge3Merger:
2763
2910
        raise BzrCommandError("Show-base is not supported for this merge"
2764
2911
                              " type. %s" % merge_type)
2765
2912
    if reprocess and not merge_type.supports_reprocess:
2768
2915
    if reprocess and show_base:
2769
2916
        raise BzrCommandError("Cannot do conflict reduction and show base.")
2770
2917
    try:
2771
 
        merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
 
2918
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
 
2919
                                   pb=pb)
2772
2920
        merger.pp = ProgressPhase("Merge phase", 5, pb)
2773
2921
        merger.pp.next_phase()
2774
2922
        merger.check_basis(check_clean)
2791
2939
    return conflicts
2792
2940
 
2793
2941
 
 
2942
# Compatibility
 
2943
merge = _merge_helper
 
2944
 
 
2945
 
2794
2946
# these get imported and then picked up by the scan for cmd_*
2795
2947
# TODO: Some more consistent way to split command definitions across files;
2796
2948
# we do need to load at least some information about them to know of 
2797
2949
# aliases.  ideally we would avoid loading the implementation until the
2798
2950
# details were needed.
 
2951
from bzrlib.cmd_version_info import cmd_version_info
2799
2952
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2800
2953
from bzrlib.bundle.commands import cmd_bundle_revisions
2801
2954
from bzrlib.sign_my_commits import cmd_sign_my_commits