~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Aaron Bentley
  • Date: 2006-11-17 04:06:03 UTC
  • mfrom: (2139 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2162.
  • Revision ID: aaron.bentley@utoronto.ca-20061117040603-pgebxndswvwk26tt
Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006 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
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
 
26
import tempfile
25
27
 
26
28
import bzrlib
27
29
from bzrlib import (
32
34
    errors,
33
35
    ignores,
34
36
    log,
 
37
    merge as _mod_merge,
35
38
    osutils,
36
39
    repository,
37
40
    transport,
 
41
    tree as _mod_tree,
38
42
    ui,
39
43
    urlutils,
40
44
    )
41
 
from bzrlib.branch import Branch, BranchReferenceFormat
42
 
from bzrlib.bundle import read_bundle_from_url
 
45
from bzrlib.branch import Branch
43
46
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
44
47
from bzrlib.conflicts import ConflictList
 
48
from bzrlib.revision import common_ancestor
 
49
from bzrlib.revisionspec import RevisionSpec
 
50
from bzrlib.workingtree import WorkingTree
 
51
""")
 
52
 
45
53
from bzrlib.commands import Command, display_command
46
 
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
47
 
                           NotBranchError, DivergedBranches, NotConflicted,
48
 
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
49
 
                           NotVersionedError, NotABundle)
50
 
from bzrlib.merge import Merge3Merger
51
54
from bzrlib.option import Option
52
55
from bzrlib.progress import DummyProgress, ProgressPhase
53
 
from bzrlib.revision import common_ancestor
54
 
from bzrlib.revisionspec import RevisionSpec
55
56
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
56
 
from bzrlib.transport.local import LocalTransport
57
 
from bzrlib.workingtree import WorkingTree
58
57
 
59
58
 
60
59
def tree_files(file_list, default_branch=u'.'):
61
60
    try:
62
61
        return internal_tree_files(file_list, default_branch)
63
 
    except FileInWrongBranch, e:
64
 
        raise BzrCommandError("%s is not in the same branch as %s" %
65
 
                             (e.path, file_list[0]))
 
62
    except errors.FileInWrongBranch, e:
 
63
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
 
64
                                     (e.path, file_list[0]))
66
65
 
67
66
 
68
67
# XXX: Bad function name; should possibly also be a class method of
77
76
 
78
77
    :param file_list: Filenames to convert.  
79
78
 
80
 
    :param default_branch: Fallback tree path to use if file_list is empty or None.
 
79
    :param default_branch: Fallback tree path to use if file_list is empty or
 
80
        None.
81
81
 
82
82
    :return: workingtree, [relative_paths]
83
83
    """
84
84
    if file_list is None or len(file_list) == 0:
85
85
        return WorkingTree.open_containing(default_branch)[0], file_list
86
 
    tree = WorkingTree.open_containing(file_list[0])[0]
 
86
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
87
87
    new_list = []
88
88
    for filename in file_list:
89
89
        try:
90
 
            new_list.append(tree.relpath(filename))
 
90
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
91
91
        except errors.PathNotChild:
92
 
            raise FileInWrongBranch(tree.branch, filename)
 
92
            raise errors.FileInWrongBranch(tree.branch, filename)
93
93
    return tree, new_list
94
94
 
95
95
 
113
113
        return format
114
114
    msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
115
115
          "metaweave and weave" % typestring
116
 
    raise BzrCommandError(msg)
 
116
    raise errors.BzrCommandError(msg)
117
117
 
118
118
 
119
119
# TODO: Make sure no commands unconditionally use the working directory as a
194
194
    def run(self, revision_id=None, revision=None):
195
195
 
196
196
        if revision_id is not None and revision is not None:
197
 
            raise BzrCommandError('You can only supply one of revision_id or --revision')
 
197
            raise errors.BzrCommandError('You can only supply one of'
 
198
                                         ' revision_id or --revision')
198
199
        if revision_id is None and revision is None:
199
 
            raise BzrCommandError('You must supply either --revision or a revision_id')
 
200
            raise errors.BzrCommandError('You must supply either'
 
201
                                         ' --revision or a revision_id')
200
202
        b = WorkingTree.open_containing(u'.')[0].branch
201
203
 
202
204
        # TODO: jam 20060112 should cat-revision always output utf-8?
205
207
        elif revision is not None:
206
208
            for rev in revision:
207
209
                if rev is None:
208
 
                    raise BzrCommandError('You cannot specify a NULL revision.')
 
210
                    raise errors.BzrCommandError('You cannot specify a NULL'
 
211
                                                 ' revision.')
209
212
                revno, rev_id = rev.in_history(b)
210
213
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
211
214
    
212
215
 
 
216
class cmd_remove_tree(Command):
 
217
    """Remove the working tree from a given branch/checkout.
 
218
 
 
219
    Since a lightweight checkout is little more than a working tree
 
220
    this will refuse to run against one.
 
221
    """
 
222
 
 
223
    hidden = True
 
224
 
 
225
    takes_args = ['location?']
 
226
 
 
227
    def run(self, location='.'):
 
228
        d = bzrdir.BzrDir.open(location)
 
229
        
 
230
        try:
 
231
            working = d.open_workingtree()
 
232
        except errors.NoWorkingTree:
 
233
            raise errors.BzrCommandError("No working tree to remove")
 
234
        except errors.NotLocalUrl:
 
235
            raise errors.BzrCommandError("You cannot remove the working tree of a "
 
236
                                         "remote path")
 
237
        
 
238
        working_path = working.bzrdir.root_transport.base
 
239
        branch_path = working.branch.bzrdir.root_transport.base
 
240
        if working_path != branch_path:
 
241
            raise errors.BzrCommandError("You cannot remove the working tree from "
 
242
                                         "a lightweight checkout")
 
243
        
 
244
        d.destroy_workingtree()
 
245
        
 
246
 
213
247
class cmd_revno(Command):
214
248
    """Show current revision number.
215
249
 
241
275
            for rev in revision_info_list:
242
276
                revs.append(RevisionSpec.from_string(rev))
243
277
        if len(revs) == 0:
244
 
            raise BzrCommandError('You must supply a revision identifier')
 
278
            raise errors.BzrCommandError('You must supply a revision identifier')
245
279
 
246
280
        b = WorkingTree.open_containing(u'.')[0].branch
247
281
 
298
332
                base_tree, base_path = WorkingTree.open_containing(
299
333
                                            file_ids_from)
300
334
            except errors.NoWorkingTree:
301
 
                base_branch, base_path = branch.Branch.open_containing(
 
335
                base_branch, base_path = Branch.open_containing(
302
336
                                            file_ids_from)
303
337
                base_tree = base_branch.basis_tree()
304
338
 
361
395
    """Show inventory of the current working copy or a revision.
362
396
 
363
397
    It is possible to limit the output to a particular entry
364
 
    type using the --kind option.  For example; --kind file.
 
398
    type using the --kind option.  For example: --kind file.
 
399
 
 
400
    It is also possible to restrict the list of files to a specific
 
401
    set. For example: bzr inventory --show-ids this/file
365
402
    """
366
403
 
367
404
    takes_options = ['revision', 'show-ids', 'kind']
368
 
    
 
405
    takes_args = ['file*']
 
406
 
369
407
    @display_command
370
 
    def run(self, revision=None, show_ids=False, kind=None):
 
408
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
371
409
        if kind and kind not in ['file', 'directory', 'symlink']:
372
 
            raise BzrCommandError('invalid kind specified')
373
 
        tree = WorkingTree.open_containing(u'.')[0]
374
 
        if revision is None:
375
 
            inv = tree.read_working_inventory()
376
 
        else:
 
410
            raise errors.BzrCommandError('invalid kind specified')
 
411
 
 
412
        work_tree, file_list = tree_files(file_list)
 
413
 
 
414
        if revision is not None:
377
415
            if len(revision) > 1:
378
 
                raise BzrCommandError('bzr inventory --revision takes'
379
 
                    ' exactly one revision identifier')
380
 
            inv = tree.branch.repository.get_revision_inventory(
381
 
                revision[0].in_history(tree.branch).rev_id)
382
 
 
383
 
        for path, entry in inv.entries():
 
416
                raise errors.BzrCommandError('bzr inventory --revision takes'
 
417
                                             ' exactly one revision identifier')
 
418
            revision_id = revision[0].in_history(work_tree.branch).rev_id
 
419
            tree = work_tree.branch.repository.revision_tree(revision_id)
 
420
                        
 
421
            # We include work_tree as well as 'tree' here
 
422
            # So that doing '-r 10 path/foo' will lookup whatever file
 
423
            # exists now at 'path/foo' even if it has been renamed, as
 
424
            # well as whatever files existed in revision 10 at path/foo
 
425
            trees = [tree, work_tree]
 
426
        else:
 
427
            tree = work_tree
 
428
            trees = [tree]
 
429
 
 
430
        if file_list is not None:
 
431
            file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
 
432
                                                      require_versioned=True)
 
433
            # find_ids_across_trees may include some paths that don't
 
434
            # exist in 'tree'.
 
435
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
436
                             for file_id in file_ids if file_id in tree)
 
437
        else:
 
438
            entries = tree.inventory.entries()
 
439
 
 
440
        for path, entry in entries:
384
441
            if kind and kind != entry.kind:
385
442
                continue
386
443
            if show_ids:
413
470
            names_list = []
414
471
 
415
472
        if len(names_list) < 2:
416
 
            raise BzrCommandError("missing file argument")
 
473
            raise errors.BzrCommandError("missing file argument")
417
474
        tree, rel_names = tree_files(names_list)
418
475
        
419
476
        if os.path.isdir(names_list[-1]):
422
479
                self.outf.write("%s => %s\n" % pair)
423
480
        else:
424
481
            if len(names_list) != 2:
425
 
                raise BzrCommandError('to mv multiple files the destination '
426
 
                                      'must be a versioned directory')
 
482
                raise errors.BzrCommandError('to mv multiple files the destination '
 
483
                                             'must be a versioned directory')
427
484
            tree.rename_one(rel_names[0], rel_names[1])
428
485
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
429
486
            
457
514
        try:
458
515
            tree_to = WorkingTree.open_containing(u'.')[0]
459
516
            branch_to = tree_to.branch
460
 
        except NoWorkingTree:
 
517
        except errors.NoWorkingTree:
461
518
            tree_to = None
462
519
            branch_to = Branch.open_containing(u'.')[0]
463
520
 
465
522
        if location is not None:
466
523
            try:
467
524
                reader = bundle.read_bundle_from_url(location)
468
 
            except NotABundle:
 
525
            except errors.NotABundle:
469
526
                pass # Continue on considering this url a Branch
470
527
 
471
528
        stored_loc = branch_to.get_parent()
472
529
        if location is None:
473
530
            if stored_loc is None:
474
 
                raise BzrCommandError("No pull location known or specified.")
 
531
                raise errors.BzrCommandError("No pull location known or"
 
532
                                             " specified.")
475
533
            else:
476
534
                display_url = urlutils.unescape_for_display(stored_loc,
477
535
                        self.outf.encoding)
495
553
        elif len(revision) == 1:
496
554
            rev_id = revision[0].in_history(branch_from).rev_id
497
555
        else:
498
 
            raise BzrCommandError('bzr pull --revision takes one value.')
 
556
            raise errors.BzrCommandError('bzr pull --revision takes one value.')
499
557
 
500
558
        old_rh = branch_to.revision_history()
501
559
        if tree_to is not None:
555
613
        stored_loc = br_from.get_push_location()
556
614
        if location is None:
557
615
            if stored_loc is None:
558
 
                raise BzrCommandError("No push location known or specified.")
 
616
                raise errors.BzrCommandError("No push location known or specified.")
559
617
            else:
560
618
                display_url = urlutils.unescape_for_display(stored_loc,
561
619
                        self.outf.encoding)
569
627
        try:
570
628
            dir_to = bzrdir.BzrDir.open(location_url)
571
629
            br_to = dir_to.open_branch()
572
 
        except NotBranchError:
 
630
        except errors.NotBranchError:
573
631
            # create a branch.
574
632
            to_transport = to_transport.clone('..')
575
633
            if not create_prefix:
577
635
                    relurl = to_transport.relpath(location_url)
578
636
                    mutter('creating directory %s => %s', location_url, relurl)
579
637
                    to_transport.mkdir(relurl)
580
 
                except NoSuchFile:
581
 
                    raise BzrCommandError("Parent directory of %s "
582
 
                                          "does not exist." % location)
 
638
                except errors.NoSuchFile:
 
639
                    raise errors.BzrCommandError("Parent directory of %s "
 
640
                                                 "does not exist." % location)
583
641
            else:
584
642
                current = to_transport.base
585
643
                needed = [(to_transport, to_transport.relpath(location_url))]
588
646
                        to_transport, relpath = needed[-1]
589
647
                        to_transport.mkdir(relpath)
590
648
                        needed.pop()
591
 
                    except NoSuchFile:
 
649
                    except errors.NoSuchFile:
592
650
                        new_transport = to_transport.clone('..')
593
651
                        needed.append((new_transport,
594
652
                                       new_transport.relpath(to_transport.base)))
595
653
                        if new_transport.base == to_transport.base:
596
 
                            raise BzrCommandError("Could not create "
597
 
                                                  "path prefix.")
 
654
                            raise errors.BzrCommandError("Could not create "
 
655
                                                         "path prefix.")
598
656
            dir_to = br_from.bzrdir.clone(location_url,
599
657
                revision_id=br_from.last_revision())
600
658
            br_to = dir_to.open_branch()
615
673
                    warning('This transport does not update the working '
616
674
                            'tree of: %s' % (br_to.base,))
617
675
                    count = br_to.pull(br_from, overwrite)
618
 
                except NoWorkingTree:
 
676
                except errors.NoWorkingTree:
619
677
                    count = br_to.pull(br_from, overwrite)
620
678
                else:
621
679
                    count = tree_to.pull(br_from, overwrite)
622
 
            except DivergedBranches:
623
 
                raise BzrCommandError("These branches have diverged."
624
 
                                      "  Try a merge then push with overwrite.")
 
680
            except errors.DivergedBranches:
 
681
                raise errors.BzrCommandError('These branches have diverged.'
 
682
                                        '  Try using "merge" and then "push".')
625
683
        note('%d revision(s) pushed.' % (count,))
626
684
 
627
685
        if verbose:
654
712
        if revision is None:
655
713
            revision = [None]
656
714
        elif len(revision) > 1:
657
 
            raise BzrCommandError(
 
715
            raise errors.BzrCommandError(
658
716
                'bzr branch --revision takes exactly 1 revision value')
659
717
        try:
660
718
            br_from = Branch.open(from_location)
661
719
        except OSError, e:
662
720
            if e.errno == errno.ENOENT:
663
 
                raise BzrCommandError('Source location "%s" does not'
664
 
                                      ' exist.' % to_location)
 
721
                raise errors.BzrCommandError('Source location "%s" does not'
 
722
                                             ' exist.' % to_location)
665
723
            else:
666
724
                raise
667
725
        br_from.lock_read()
687
745
            try:
688
746
                to_transport.mkdir('.')
689
747
            except errors.FileExists:
690
 
                raise BzrCommandError('Target directory "%s" already'
691
 
                                      ' exists.' % to_location)
 
748
                raise errors.BzrCommandError('Target directory "%s" already'
 
749
                                             ' exists.' % to_location)
692
750
            except errors.NoSuchFile:
693
 
                raise BzrCommandError('Parent of "%s" does not exist.' %
694
 
                                      to_location)
 
751
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
752
                                             % to_location)
695
753
            try:
696
754
                # preserve whatever source format we have.
697
755
                dir = br_from.bzrdir.sprout(to_transport.base,
700
758
            except errors.NoSuchRevision:
701
759
                to_transport.delete_tree('.')
702
760
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
703
 
                raise BzrCommandError(msg)
 
761
                raise errors.BzrCommandError(msg)
704
762
            except errors.UnlistableBranch:
705
763
                osutils.rmtree(to_location)
706
764
                msg = "The branch %s cannot be used as a --basis" % (basis,)
707
 
                raise BzrCommandError(msg)
 
765
                raise errors.BzrCommandError(msg)
708
766
            if name:
709
767
                branch.control_files.put_utf8('branch-name', name)
710
768
            note('Branched %d revision(s).' % branch.revno())
749
807
        if revision is None:
750
808
            revision = [None]
751
809
        elif len(revision) > 1:
752
 
            raise BzrCommandError(
 
810
            raise errors.BzrCommandError(
753
811
                'bzr checkout --revision takes exactly 1 revision value')
754
812
        if branch_location is None:
755
813
            branch_location = osutils.getcwd()
775
833
            os.mkdir(to_location)
776
834
        except OSError, e:
777
835
            if e.errno == errno.EEXIST:
778
 
                raise BzrCommandError('Target directory "%s" already'
779
 
                                      ' exists.' % to_location)
 
836
                raise errors.BzrCommandError('Target directory "%s" already'
 
837
                                             ' exists.' % to_location)
780
838
            if e.errno == errno.ENOENT:
781
 
                raise BzrCommandError('Parent of "%s" does not exist.' %
782
 
                                      to_location)
 
839
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
840
                                             % to_location)
783
841
            else:
784
842
                raise
785
843
        old_format = bzrdir.BzrDirFormat.get_default_format()
800
858
 
801
859
    @display_command
802
860
    def run(self, dir=u'.'):
803
 
        from bzrlib.tree import find_renames
804
861
        tree = WorkingTree.open_containing(dir)[0]
805
862
        old_inv = tree.basis_tree().inventory
806
863
        new_inv = tree.read_working_inventory()
807
 
        renames = list(find_renames(old_inv, new_inv))
 
864
        renames = list(_mod_tree.find_renames(old_inv, new_inv))
808
865
        renames.sort()
809
866
        for old_name, new_name in renames:
810
867
            self.outf.write("%s => %s\n" % (old_name, new_name))
825
882
 
826
883
    def run(self, dir='.'):
827
884
        tree = WorkingTree.open_containing(dir)[0]
828
 
        tree.lock_write()
 
885
        master = tree.branch.get_master_branch()
 
886
        if master is not None:
 
887
            tree.lock_write()
 
888
        else:
 
889
            tree.lock_tree_write()
829
890
        try:
830
891
            existing_pending_merges = tree.get_parent_ids()[1:]
831
892
            last_rev = tree.last_revision()
889
950
        tree, file_list = tree_files(file_list)
890
951
        if new is False:
891
952
            if file_list is None:
892
 
                raise BzrCommandError('Specify one or more files to remove, or'
893
 
                                      ' use --new.')
 
953
                raise errors.BzrCommandError('Specify one or more files to'
 
954
                                             ' remove, or use --new.')
894
955
        else:
895
956
            added = tree.changes_from(tree.basis_tree(),
896
957
                specific_files=file_list).added
897
958
            file_list = sorted([f[0] for f in added], reverse=True)
898
959
            if len(file_list) == 0:
899
 
                raise BzrCommandError('No matching files.')
 
960
                raise errors.BzrCommandError('No matching files.')
900
961
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
901
962
 
902
963
 
916
977
        tree, relpath = WorkingTree.open_containing(filename)
917
978
        i = tree.inventory.path2id(relpath)
918
979
        if i is None:
919
 
            raise BzrError("%r is not a versioned file" % filename)
 
980
            raise errors.NotVersionedError(filename)
920
981
        else:
921
982
            self.outf.write(i + '\n')
922
983
 
937
998
        inv = tree.inventory
938
999
        fid = inv.path2id(relpath)
939
1000
        if fid is None:
940
 
            raise BzrError("%r is not a versioned file" % filename)
 
1001
            raise errors.NotVersionedError(filename)
941
1002
        for fip in inv.get_idpath(fid):
942
1003
            self.outf.write(fip + '\n')
943
1004
 
1057
1118
                    
1058
1119
        try:
1059
1120
            existing_bzrdir = bzrdir.BzrDir.open(location)
1060
 
        except NotBranchError:
 
1121
        except errors.NotBranchError:
1061
1122
            # really a NotBzrDir error...
1062
1123
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
1063
1124
        else:
 
1125
            from bzrlib.transport.local import LocalTransport
1064
1126
            if existing_bzrdir.has_branch():
1065
1127
                if (isinstance(to_transport, LocalTransport)
1066
1128
                    and not existing_bzrdir.has_workingtree()):
1167
1229
            new_label = 'new/'
1168
1230
        else:
1169
1231
            if not ':' in prefix:
1170
 
                 raise BzrError("--diff-prefix expects two values separated by a colon")
 
1232
                 raise BzrCommandError(
 
1233
                     "--diff-prefix expects two values separated by a colon")
1171
1234
            old_label, new_label = prefix.split(":")
1172
1235
        
1173
1236
        try:
1175
1238
            tree2 = None
1176
1239
            b = None
1177
1240
            b2 = None
1178
 
        except FileInWrongBranch:
 
1241
        except errors.FileInWrongBranch:
1179
1242
            if len(file_list) != 2:
1180
 
                raise BzrCommandError("Files are in different branches")
 
1243
                raise errors.BzrCommandError("Files are in different branches")
1181
1244
 
1182
1245
            tree1, file1 = WorkingTree.open_containing(file_list[0])
1183
1246
            tree2, file2 = WorkingTree.open_containing(file_list[1])
1184
1247
            if file1 != "" or file2 != "":
1185
1248
                # FIXME diff those two files. rbc 20051123
1186
 
                raise BzrCommandError("Files are in different branches")
 
1249
                raise errors.BzrCommandError("Files are in different branches")
1187
1250
            file_list = None
1188
 
        except NotBranchError:
 
1251
        except errors.NotBranchError:
1189
1252
            if (revision is not None and len(revision) == 2
1190
1253
                and not revision[0].needs_branch()
1191
1254
                and not revision[1].needs_branch()):
1196
1259
                raise
1197
1260
        if revision is not None:
1198
1261
            if tree2 is not None:
1199
 
                raise BzrCommandError("Can't specify -r with two branches")
 
1262
                raise errors.BzrCommandError("Can't specify -r with two branches")
1200
1263
            if (len(revision) == 1) or (revision[1].spec is None):
1201
1264
                return diff_cmd_helper(tree1, file_list, diff_options,
1202
1265
                                       revision[0], 
1206
1269
                                       revision[0], revision[1],
1207
1270
                                       old_label=old_label, new_label=new_label)
1208
1271
            else:
1209
 
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
 
1272
                raise errors.BzrCommandError('bzr diff --revision takes exactly'
 
1273
                                             ' one or two revision identifiers')
1210
1274
        else:
1211
1275
            if tree2 is not None:
1212
1276
                return show_diff_trees(tree1, tree2, sys.stdout, 
1264
1328
        for file_id in inv:
1265
1329
            if file_id in basis_inv:
1266
1330
                continue
 
1331
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
1332
                continue
1267
1333
            path = inv.id2path(file_id)
1268
1334
            if not os.access(osutils.abspath(path), os.F_OK):
1269
1335
                continue
1347
1413
                    # either no tree, or is remote.
1348
1414
                    inv = b.basis_tree().inventory
1349
1415
                file_id = inv.path2id(fp)
 
1416
                if file_id is None:
 
1417
                    raise errors.BzrCommandError(
 
1418
                        "Path does not have any revision history: %s" %
 
1419
                        location)
1350
1420
        else:
1351
1421
            # local dir only
1352
1422
            # FIXME ? log the current subdir only RBC 20060203 
1368
1438
                # b is taken from revision[0].get_branch(), and
1369
1439
                # show_log will use its revision_history. Having
1370
1440
                # different branches will lead to weird behaviors.
1371
 
                raise BzrCommandError(
 
1441
                raise errors.BzrCommandError(
1372
1442
                    "Log doesn't accept two revisions in different branches.")
1373
1443
            if revision[0].spec is None:
1374
1444
                # missing begin-range means first revision
1382
1452
            else:
1383
1453
                rev2 = revision[1].in_history(b).revno
1384
1454
        else:
1385
 
            raise BzrCommandError('bzr log --revision takes one or two values.')
 
1455
            raise errors.BzrCommandError('bzr log --revision takes one or two values.')
1386
1456
 
1387
1457
        # By this point, the revision numbers are converted to the +ve
1388
1458
        # form if they were supplied in the -ve form, so we can do
1462
1532
            null=False):
1463
1533
 
1464
1534
        if verbose and null:
1465
 
            raise BzrCommandError('Cannot set both --verbose and --null')
 
1535
            raise errors.BzrCommandError('Cannot set both --verbose and --null')
1466
1536
        all = not (unknown or versioned or ignored)
1467
1537
 
1468
1538
        selection = {'I':ignored, '?':unknown, 'V':versioned}
1476
1546
            tree = tree.branch.repository.revision_tree(
1477
1547
                revision[0].in_history(tree.branch).rev_id)
1478
1548
 
1479
 
        for fp, fc, kind, fid, entry in tree.list_files():
 
1549
        for fp, fc, kind, fid, entry in tree.list_files(include_root=False):
1480
1550
            if fp.startswith(relpath):
1481
1551
                fp = fp[len(relpath):]
1482
1552
                if non_recursive and '/' in fp:
1502
1572
 
1503
1573
 
1504
1574
class cmd_ignore(Command):
1505
 
    """Ignore a command or pattern.
 
1575
    """Ignore specified files or patterns.
1506
1576
 
1507
1577
    To remove patterns from the ignore list, edit the .bzrignore file.
1508
1578
 
 
1579
    Trailing slashes on patterns are ignored. 
1509
1580
    If the pattern contains a slash, it is compared to the whole path
1510
1581
    from the branch root.  Otherwise, it is compared to only the last
1511
1582
    component of the path.  To match a file only in the root directory,
1512
1583
    prepend './'.
1513
1584
 
 
1585
    Ignore patterns specifying absolute paths are not allowed.
 
1586
 
1514
1587
    Ignore patterns are case-insensitive on case-insensitive systems.
1515
1588
 
1516
1589
    Note: wildcards must be quoted from the shell on Unix.
1519
1592
        bzr ignore ./Makefile
1520
1593
        bzr ignore '*.class'
1521
1594
    """
1522
 
    # TODO: Complain if the filename is absolute
1523
 
    takes_args = ['name_pattern?']
 
1595
    takes_args = ['name_pattern*']
1524
1596
    takes_options = [
1525
1597
                     Option('old-default-rules',
1526
1598
                            help='Out the ignore rules bzr < 0.9 always used.')
1527
1599
                     ]
1528
1600
    
1529
 
    def run(self, name_pattern=None, old_default_rules=None):
 
1601
    def run(self, name_pattern_list=None, old_default_rules=None):
1530
1602
        from bzrlib.atomicfile import AtomicFile
1531
1603
        if old_default_rules is not None:
1532
1604
            # dump the rules and exit
1533
1605
            for pattern in ignores.OLD_DEFAULTS:
1534
1606
                print pattern
1535
1607
            return
1536
 
        if name_pattern is None:
1537
 
            raise BzrCommandError("ignore requires a NAME_PATTERN")
 
1608
        if not name_pattern_list:
 
1609
            raise errors.BzrCommandError("ignore requires at least one "
 
1610
                                  "NAME_PATTERN or --old-default-rules")
 
1611
        for name_pattern in name_pattern_list:
 
1612
            if name_pattern[0] == '/':
 
1613
                raise errors.BzrCommandError(
 
1614
                    "NAME_PATTERN should not be an absolute path")
1538
1615
        tree, relpath = WorkingTree.open_containing(u'.')
1539
1616
        ifn = tree.abspath('.bzrignore')
1540
1617
        if os.path.exists(ifn):
1551
1628
 
1552
1629
        if igns and igns[-1] != '\n':
1553
1630
            igns += '\n'
1554
 
        igns += name_pattern + '\n'
 
1631
        for name_pattern in name_pattern_list:
 
1632
            igns += name_pattern.rstrip('/') + '\n'
1555
1633
 
1556
 
        f = AtomicFile(ifn, 'wt')
 
1634
        f = AtomicFile(ifn, 'wb')
1557
1635
        try:
1558
1636
            f.write(igns.encode('utf-8'))
1559
1637
            f.commit()
1597
1675
        try:
1598
1676
            revno = int(revno)
1599
1677
        except ValueError:
1600
 
            raise BzrCommandError("not a valid revision-number: %r" % revno)
 
1678
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
1601
1679
 
1602
1680
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1603
1681
 
1614
1692
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1615
1693
    is given, the top directory will be the root name of the file.
1616
1694
 
 
1695
    If branch is omitted then the branch containing the CWD will be used.
 
1696
 
1617
1697
    Note: export of tree with non-ascii filenames to zip is not supported.
1618
1698
 
1619
1699
     Supported formats       Autodetected by extension
1624
1704
         tgz                      .tar.gz, .tgz
1625
1705
         zip                          .zip
1626
1706
    """
1627
 
    takes_args = ['dest']
 
1707
    takes_args = ['dest', 'branch?']
1628
1708
    takes_options = ['revision', 'format', 'root']
1629
 
    def run(self, dest, revision=None, format=None, root=None):
 
1709
    def run(self, dest, branch=None, revision=None, format=None, root=None):
1630
1710
        from bzrlib.export import export
1631
 
        tree = WorkingTree.open_containing(u'.')[0]
1632
 
        b = tree.branch
 
1711
 
 
1712
        if branch is None:
 
1713
            tree = WorkingTree.open_containing(u'.')[0]
 
1714
            b = tree.branch
 
1715
        else:
 
1716
            b = Branch.open(branch)
 
1717
            
1633
1718
        if revision is None:
1634
1719
            # should be tree.last_revision  FIXME
1635
1720
            rev_id = b.last_revision()
1636
1721
        else:
1637
1722
            if len(revision) != 1:
1638
 
                raise BzrError('bzr export --revision takes exactly 1 argument')
 
1723
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
1639
1724
            rev_id = revision[0].in_history(b).rev_id
1640
1725
        t = b.repository.revision_tree(rev_id)
1641
1726
        try:
1642
1727
            export(t, dest, format, root)
1643
1728
        except errors.NoSuchExportFormat, e:
1644
 
            raise BzrCommandError('Unsupported export format: %s' % e.format)
 
1729
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
1645
1730
 
1646
1731
 
1647
1732
class cmd_cat(Command):
1648
1733
    """Write a file's text from a previous revision."""
1649
1734
 
1650
 
    takes_options = ['revision']
 
1735
    takes_options = ['revision', 'name-from-revision']
1651
1736
    takes_args = ['filename']
1652
1737
 
1653
1738
    @display_command
1654
 
    def run(self, filename, revision=None):
 
1739
    def run(self, filename, revision=None, name_from_revision=False):
1655
1740
        if revision is not None and len(revision) != 1:
1656
 
            raise BzrCommandError("bzr cat --revision takes exactly one number")
 
1741
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
 
1742
                                        " one number")
 
1743
 
1657
1744
        tree = None
1658
1745
        try:
1659
1746
            tree, relpath = WorkingTree.open_containing(filename)
1660
1747
            b = tree.branch
1661
 
        except NotBranchError:
 
1748
        except errors.NotBranchError:
1662
1749
            pass
1663
1750
 
1664
1751
        if tree is None:
1669
1756
            revision_id = b.last_revision()
1670
1757
        else:
1671
1758
            revision_id = revision[0].in_history(b).rev_id
1672
 
        b.print_file(relpath, revision_id)
 
1759
 
 
1760
        cur_file_id = tree.path2id(relpath)
 
1761
        rev_tree = b.repository.revision_tree(revision_id)
 
1762
        old_file_id = rev_tree.path2id(relpath)
 
1763
        
 
1764
        if name_from_revision:
 
1765
            if old_file_id is None:
 
1766
                raise errors.BzrCommandError("%r is not present in revision %s"
 
1767
                                                % (filename, revision_id))
 
1768
            else:
 
1769
                rev_tree.print_file(old_file_id)
 
1770
        elif cur_file_id is not None:
 
1771
            rev_tree.print_file(cur_file_id)
 
1772
        elif old_file_id is not None:
 
1773
            rev_tree.print_file(old_file_id)
 
1774
        else:
 
1775
            raise errors.BzrCommandError("%r is not present in revision %s" %
 
1776
                                         (filename, revision_id))
1673
1777
 
1674
1778
 
1675
1779
class cmd_local_time_offset(Command):
1729
1833
                StrictCommitFailed)
1730
1834
        from bzrlib.msgeditor import edit_commit_message, \
1731
1835
                make_commit_message_template
1732
 
        from tempfile import TemporaryFile
1733
1836
 
1734
1837
        # TODO: Need a blackbox test for invoking the external editor; may be
1735
1838
        # slightly problematic to run this cross-platform.
1736
1839
 
1737
1840
        # TODO: do more checks that the commit will succeed before 
1738
1841
        # spending the user's valuable time typing a commit message.
1739
 
        #
1740
 
        # TODO: if the commit *does* happen to fail, then save the commit 
1741
 
        # message to a temporary file where it can be recovered
1742
1842
        tree, selected_list = tree_files(selected_list)
1743
1843
        if selected_list == ['']:
1744
1844
            # workaround - commit of root of tree should be exactly the same
1752
1852
            template = make_commit_message_template(tree, selected_list)
1753
1853
            message = edit_commit_message(template)
1754
1854
            if message is None:
1755
 
                raise BzrCommandError("please specify a commit message"
1756
 
                                      " with either --message or --file")
 
1855
                raise errors.BzrCommandError("please specify a commit message"
 
1856
                                             " with either --message or --file")
1757
1857
        elif message and file:
1758
 
            raise BzrCommandError("please specify either --message or --file")
 
1858
            raise errors.BzrCommandError("please specify either --message or --file")
1759
1859
        
1760
1860
        if file:
1761
1861
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1762
1862
 
1763
1863
        if message == "":
1764
 
            raise BzrCommandError("empty commit message specified")
 
1864
            raise errors.BzrCommandError("empty commit message specified")
1765
1865
        
1766
1866
        if verbose:
1767
1867
            reporter = ReportCommitToLog()
1768
1868
        else:
1769
1869
            reporter = NullCommitReporter()
1770
 
        
 
1870
 
 
1871
        msgfilename = self._save_commit_message(message, tree.basedir)
1771
1872
        try:
1772
1873
            tree.commit(message, specific_files=selected_list,
1773
1874
                        allow_pointless=unchanged, strict=strict, local=local,
1774
1875
                        reporter=reporter)
 
1876
            if msgfilename is not None:
 
1877
                try:
 
1878
                    os.unlink(msgfilename)
 
1879
                except IOError, e:
 
1880
                    warning("failed to unlink %s: %s; ignored", msgfilename, e)
1775
1881
        except PointlessCommit:
1776
1882
            # FIXME: This should really happen before the file is read in;
1777
1883
            # perhaps prepare the commit; get the message; then actually commit
1778
 
            raise BzrCommandError("no changes to commit."
 
1884
            if msgfilename is not None:
 
1885
                raise errors.BzrCommandError("no changes to commit."
 
1886
                                  " use --unchanged to commit anyhow\n"
 
1887
                                  "Commit message saved. To reuse the message,"
 
1888
                                  " do\nbzr commit --file " + msgfilename)
 
1889
            else:
 
1890
                raise errors.BzrCommandError("no changes to commit."
1779
1891
                                  " use --unchanged to commit anyhow")
1780
1892
        except ConflictsInTree:
1781
 
            raise BzrCommandError("Conflicts detected in working tree.  "
1782
 
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
 
1893
            if msgfilename is not None:
 
1894
                raise errors.BzrCommandError('Conflicts detected in working '
 
1895
                    'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
 
1896
                    ' resolve.\n'
 
1897
                    'Commit message saved. To reuse the message,'
 
1898
                    ' do\nbzr commit --file ' + msgfilename)
 
1899
            else:
 
1900
                raise errors.BzrCommandError('Conflicts detected in working '
 
1901
                    'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
 
1902
                    ' resolve.')
1783
1903
        except StrictCommitFailed:
1784
 
            raise BzrCommandError("Commit refused because there are unknown "
1785
 
                                  "files in the working tree.")
 
1904
            if msgfilename is not None:
 
1905
                raise errors.BzrCommandError("Commit refused because there are"
 
1906
                                  " unknown files in the working tree.\n"
 
1907
                                  "Commit message saved. To reuse the message,"
 
1908
                                  " do\nbzr commit --file " + msgfilename)
 
1909
            else:
 
1910
                raise errors.BzrCommandError("Commit refused because there are"
 
1911
                                  " unknown files in the working tree.")
1786
1912
        except errors.BoundBranchOutOfDate, e:
1787
 
            raise BzrCommandError(str(e) + "\n"
 
1913
            if msgfilename is not None:
 
1914
                raise errors.BzrCommandError(str(e) + "\n"
 
1915
                'To commit to master branch, run update and then commit.\n'
 
1916
                'You can also pass --local to commit to continue working '
 
1917
                'disconnected.\n'
 
1918
                'Commit message saved. To reuse the message,'
 
1919
                ' do\nbzr commit --file ' + msgfilename)
 
1920
            else:
 
1921
                raise errors.BzrCommandError(str(e) + "\n"
1788
1922
                'To commit to master branch, run update and then commit.\n'
1789
1923
                'You can also pass --local to commit to continue working '
1790
1924
                'disconnected.')
1791
1925
 
 
1926
    def _save_commit_message(self, message, basedir):
 
1927
        # save the commit message and only unlink it if the commit was
 
1928
        # successful
 
1929
        msgfilename = None
 
1930
        try:
 
1931
            tmp_fileno, msgfilename = tempfile.mkstemp(prefix='bzr-commit-',
 
1932
                                                       dir=basedir)
 
1933
        except OSError:
 
1934
            try:
 
1935
                # No access to working dir, try $TMP
 
1936
                tmp_fileno, msgfilename = tempfile.mkstemp(prefix='bzr-commit-')
 
1937
            except OSError:
 
1938
                # We can't create a temp file, try to work without it
 
1939
                return None
 
1940
        try:
 
1941
            os.write(tmp_fileno, message.encode(bzrlib.user_encoding, 'replace'))
 
1942
        finally:
 
1943
            os.close(tmp_fileno)
 
1944
        return msgfilename
 
1945
 
 
1946
 
1792
1947
class cmd_check(Command):
1793
1948
    """Validate consistency of branch history.
1794
1949
 
1808
1963
        check(branch, verbose)
1809
1964
 
1810
1965
 
1811
 
class cmd_scan_cache(Command):
1812
 
    hidden = True
1813
 
    def run(self):
1814
 
        from bzrlib.hashcache import HashCache
1815
 
 
1816
 
        c = HashCache(u'.')
1817
 
        c.read()
1818
 
        c.scan()
1819
 
            
1820
 
        print '%6d stats' % c.stat_count
1821
 
        print '%6d in hashcache' % len(c._cache)
1822
 
        print '%6d files removed from cache' % c.removed_count
1823
 
        print '%6d hashes updated' % c.update_count
1824
 
        print '%6d files changed too recently to cache' % c.danger_count
1825
 
 
1826
 
        if c.needs_write:
1827
 
            c.write()
1828
 
 
1829
 
 
1830
1966
class cmd_upgrade(Command):
1831
1967
    """Upgrade branch storage to current format.
1832
1968
 
1874
2010
            # use branch if we're inside one; otherwise global config
1875
2011
            try:
1876
2012
                c = Branch.open_containing('.')[0].get_config()
1877
 
            except NotBranchError:
 
2013
            except errors.NotBranchError:
1878
2014
                c = config.GlobalConfig()
1879
2015
            if email:
1880
2016
                self.outf.write(c.user_email() + '\n')
1885
2021
        # display a warning if an email address isn't included in the given name.
1886
2022
        try:
1887
2023
            config.extract_email_address(name)
1888
 
        except BzrError, e:
 
2024
        except errors.NoEmailInUsername, e:
1889
2025
            warning('"%s" does not seem to contain an email address.  '
1890
2026
                    'This is allowed, but not recommended.', name)
1891
2027
        
1953
2089
            return FakeNFSServer
1954
2090
        msg = "No known transport type %s. Supported types are: sftp\n" %\
1955
2091
            (typestring)
1956
 
        raise BzrCommandError(msg)
 
2092
        raise errors.BzrCommandError(msg)
1957
2093
 
1958
2094
    hidden = True
1959
2095
    takes_args = ['testspecs*']
1984
2120
 
1985
2121
        if cache_dir is not None:
1986
2122
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
1987
 
        # we don't want progress meters from the tests to go to the
1988
 
        # real output; and we don't want log messages cluttering up
1989
 
        # the real logs.
1990
 
        save_ui = ui.ui_factory
1991
2123
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1992
2124
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1993
2125
        print
1994
 
        info('running tests...')
 
2126
        if testspecs_list is not None:
 
2127
            pattern = '|'.join(testspecs_list)
 
2128
        else:
 
2129
            pattern = ".*"
 
2130
        if benchmark:
 
2131
            test_suite_factory = benchmarks.test_suite
 
2132
            if verbose is None:
 
2133
                verbose = True
 
2134
            # TODO: should possibly lock the history file...
 
2135
            benchfile = open(".perf_history", "at")
 
2136
        else:
 
2137
            test_suite_factory = None
 
2138
            if verbose is None:
 
2139
                verbose = False
 
2140
            benchfile = None
1995
2141
        try:
1996
 
            ui.ui_factory = ui.SilentUIFactory()
1997
 
            if testspecs_list is not None:
1998
 
                pattern = '|'.join(testspecs_list)
1999
 
            else:
2000
 
                pattern = ".*"
2001
 
            if benchmark:
2002
 
                test_suite_factory = benchmarks.test_suite
2003
 
                if verbose is None:
2004
 
                    verbose = True
2005
 
                benchfile = open(".perf_history", "at")
2006
 
            else:
2007
 
                test_suite_factory = None
2008
 
                if verbose is None:
2009
 
                    verbose = False
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()
2023
 
            if result:
2024
 
                info('tests passed')
2025
 
            else:
2026
 
                info('tests failed')
2027
 
            return int(not result)
 
2142
            result = selftest(verbose=verbose, 
 
2143
                              pattern=pattern,
 
2144
                              stop_on_failure=one, 
 
2145
                              keep_output=keep_output,
 
2146
                              transport=transport,
 
2147
                              test_suite_factory=test_suite_factory,
 
2148
                              lsprof_timed=lsprof_timed,
 
2149
                              bench_history=benchfile)
2028
2150
        finally:
2029
 
            ui.ui_factory = save_ui
 
2151
            if benchfile is not None:
 
2152
                benchfile.close()
 
2153
        if result:
 
2154
            info('tests passed')
 
2155
        else:
 
2156
            info('tests failed')
 
2157
        return int(not result)
2030
2158
 
2031
2159
 
2032
2160
class cmd_version(Command):
2057
2185
    
2058
2186
    @display_command
2059
2187
    def run(self, branch, other):
2060
 
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
 
2188
        from bzrlib.revision import MultipleRevisionSources
2061
2189
        
2062
2190
        branch1 = Branch.open_containing(branch)[0]
2063
2191
        branch2 = Branch.open_containing(other)[0]
2125
2253
                            ' from a working copy, instead of branch changes')]
2126
2254
 
2127
2255
    def help(self):
2128
 
        from merge import merge_type_help
2129
2256
        from inspect import getdoc
2130
 
        return getdoc(self) + '\n' + merge_type_help() 
 
2257
        return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2131
2258
 
2132
2259
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2133
2260
            show_base=False, reprocess=False, remember=False, 
2134
2261
            uncommitted=False):
2135
2262
        if merge_type is None:
2136
 
            merge_type = Merge3Merger
 
2263
            merge_type = _mod_merge.Merge3Merger
2137
2264
 
2138
2265
        tree = WorkingTree.open_containing(u'.')[0]
2139
2266
 
2140
2267
        if branch is not None:
2141
2268
            try:
2142
2269
                reader = bundle.read_bundle_from_url(branch)
2143
 
            except NotABundle:
 
2270
            except errors.NotABundle:
2144
2271
                pass # Continue on considering this url a Branch
2145
2272
            else:
2146
2273
                conflicts = merge_bundle(reader, tree, not force, merge_type,
2164
2291
            other_branch, path = Branch.open_containing(branch)
2165
2292
        else:
2166
2293
            if uncommitted:
2167
 
                raise BzrCommandError('Cannot use --uncommitted and --revision'
2168
 
                                      ' at the same time.')
 
2294
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
2295
                                             ' --revision at the same time.')
2169
2296
            branch = revision[0].get_branch() or branch
2170
2297
            if len(revision) == 1:
2171
2298
                base = [None, None]
2175
2302
            else:
2176
2303
                assert len(revision) == 2
2177
2304
                if None in revision:
2178
 
                    raise BzrCommandError(
 
2305
                    raise errors.BzrCommandError(
2179
2306
                        "Merge doesn't permit empty revision specifier.")
2180
2307
                base_branch, path = Branch.open_containing(branch)
2181
2308
                branch1 = revision[1].get_branch() or branch
2197
2324
        pb = ui.ui_factory.nested_progress_bar()
2198
2325
        try:
2199
2326
            try:
2200
 
                conflict_count = merge(other, base, check_clean=(not force),
2201
 
                                       merge_type=merge_type,
2202
 
                                       reprocess=reprocess,
2203
 
                                       show_base=show_base,
2204
 
                                       pb=pb, file_list=interesting_files)
 
2327
                conflict_count = _merge_helper(
 
2328
                    other, base, check_clean=(not force),
 
2329
                    merge_type=merge_type,
 
2330
                    reprocess=reprocess,
 
2331
                    show_base=show_base,
 
2332
                    pb=pb, file_list=interesting_files)
2205
2333
            finally:
2206
2334
                pb.finished()
2207
2335
            if conflict_count != 0:
2228
2356
        stored_location = tree.branch.get_parent()
2229
2357
        mutter("%s", stored_location)
2230
2358
        if stored_location is None:
2231
 
            raise BzrCommandError("No location specified or remembered")
 
2359
            raise errors.BzrCommandError("No location specified or remembered")
2232
2360
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2233
2361
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2234
2362
        return stored_location
2261
2389
                            "conflicts")]
2262
2390
 
2263
2391
    def help(self):
2264
 
        from merge import merge_type_help
2265
2392
        from inspect import getdoc
2266
 
        return getdoc(self) + '\n' + merge_type_help() 
 
2393
        return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2267
2394
 
2268
2395
    def run(self, file_list=None, merge_type=None, show_base=False,
2269
2396
            reprocess=False):
2270
 
        from bzrlib.merge import merge_inner, transform_tree
2271
2397
        if merge_type is None:
2272
 
            merge_type = Merge3Merger
 
2398
            merge_type = _mod_merge.Merge3Merger
2273
2399
        tree, file_list = tree_files(file_list)
2274
2400
        tree.lock_write()
2275
2401
        try:
2276
2402
            parents = tree.get_parent_ids()
2277
2403
            if len(parents) != 2:
2278
 
                raise BzrCommandError("Sorry, remerge only works after normal"
2279
 
                                      " merges.  Not cherrypicking or"
2280
 
                                      " multi-merges.")
 
2404
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
2405
                                             " merges.  Not cherrypicking or"
 
2406
                                             " multi-merges.")
2281
2407
            repository = tree.branch.repository
2282
2408
            base_revision = common_ancestor(parents[0],
2283
2409
                                            parents[1], repository)
2291
2417
                for filename in file_list:
2292
2418
                    file_id = tree.path2id(filename)
2293
2419
                    if file_id is None:
2294
 
                        raise NotVersionedError(filename)
 
2420
                        raise errors.NotVersionedError(filename)
2295
2421
                    interesting_ids.add(file_id)
2296
2422
                    if tree.kind(file_id) != "directory":
2297
2423
                        continue
2299
2425
                    for name, ie in tree.inventory.iter_entries(file_id):
2300
2426
                        interesting_ids.add(ie.file_id)
2301
2427
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2302
 
            transform_tree(tree, tree.basis_tree(), interesting_ids)
 
2428
            else:
 
2429
                # Remerge only supports resolving contents conflicts
 
2430
                allowed_conflicts = ('text conflict', 'contents conflict')
 
2431
                restore_files = [c.path for c in conflicts
 
2432
                                 if c.typestring in allowed_conflicts]
 
2433
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
2303
2434
            tree.set_conflicts(ConflictList(new_conflicts))
2304
 
            if file_list is None:
2305
 
                restore_files = list(tree.iter_conflicts())
2306
 
            else:
 
2435
            if file_list is not None:
2307
2436
                restore_files = file_list
2308
2437
            for filename in restore_files:
2309
2438
                try:
2310
2439
                    restore(tree.abspath(filename))
2311
 
                except NotConflicted:
 
2440
                except errors.NotConflicted:
2312
2441
                    pass
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)
 
2442
            conflicts = _mod_merge.merge_inner(
 
2443
                                      tree.branch, other_tree, base_tree,
 
2444
                                      this_tree=tree,
 
2445
                                      interesting_ids=interesting_ids,
 
2446
                                      other_rev_id=parents[1],
 
2447
                                      merge_type=merge_type,
 
2448
                                      show_base=show_base,
 
2449
                                      reprocess=reprocess)
2320
2450
        finally:
2321
2451
            tree.unlock()
2322
2452
        if conflicts > 0:
2324
2454
        else:
2325
2455
            return 0
2326
2456
 
 
2457
 
2327
2458
class cmd_revert(Command):
2328
 
    """Reverse all changes since the last commit.
2329
 
 
2330
 
    Only versioned files are affected.  Specify filenames to revert only 
2331
 
    those files.  By default, any files that are changed will be backed up
2332
 
    first.  Backup files have a '~' appended to their name.
 
2459
    """Revert files to a previous revision.
 
2460
 
 
2461
    Giving a list of files will revert only those files.  Otherwise, all files
 
2462
    will be reverted.  If the revision is not specified with '--revision', the
 
2463
    last committed revision is used.
 
2464
 
 
2465
    To remove only some changes, without reverting to a prior version, use
 
2466
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
 
2467
    introduced by -2, without affecting the changes introduced by -1.  Or
 
2468
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
2469
    
 
2470
    By default, any files that have been manually changed will be backed up
 
2471
    first.  (Files changed only by merge are not backed up.)  Backup files have
 
2472
    '.~#~' appended to their name, where # is a number.
 
2473
 
 
2474
    When you provide files, you can use their current pathname or the pathname
 
2475
    from the target revision.  So you can use revert to "undelete" a file by
 
2476
    name.  If you name a directory, all the contents of that directory will be
 
2477
    reverted.
2333
2478
    """
2334
2479
    takes_options = ['revision', 'no-backup']
2335
2480
    takes_args = ['file*']
2336
2481
    aliases = ['merge-revert']
2337
2482
 
2338
2483
    def run(self, revision=None, no_backup=False, file_list=None):
2339
 
        from bzrlib.commands import parse_spec
2340
2484
        if file_list is not None:
2341
2485
            if len(file_list) == 0:
2342
 
                raise BzrCommandError("No files specified")
 
2486
                raise errors.BzrCommandError("No files specified")
2343
2487
        else:
2344
2488
            file_list = []
2345
2489
        
2348
2492
            # FIXME should be tree.last_revision
2349
2493
            rev_id = tree.last_revision()
2350
2494
        elif len(revision) != 1:
2351
 
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
 
2495
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
2352
2496
        else:
2353
2497
            rev_id = revision[0].in_history(tree.branch).rev_id
2354
2498
        pb = ui.ui_factory.nested_progress_bar()
2362
2506
 
2363
2507
class cmd_assert_fail(Command):
2364
2508
    """Test reporting of assertion failures"""
 
2509
    # intended just for use in testing
 
2510
 
2365
2511
    hidden = True
 
2512
 
2366
2513
    def run(self):
2367
 
        assert False, "always fails"
 
2514
        raise AssertionError("always fails")
2368
2515
 
2369
2516
 
2370
2517
class cmd_help(Command):
2371
2518
    """Show help on a command or other topic.
2372
2519
 
2373
 
    For a list of all available commands, say 'bzr help commands'."""
 
2520
    For a list of all available commands, say 'bzr help commands'.
 
2521
    """
2374
2522
    takes_options = [Option('long', 'show help on all commands')]
2375
2523
    takes_args = ['topic?']
2376
2524
    aliases = ['?', '--help', '-?', '-h']
2377
2525
    
2378
2526
    @display_command
2379
2527
    def run(self, topic=None, long=False):
2380
 
        import help
 
2528
        import bzrlib.help
2381
2529
        if topic is None and long:
2382
2530
            topic = "commands"
2383
 
        help.help(topic)
 
2531
        bzrlib.help.help(topic)
2384
2532
 
2385
2533
 
2386
2534
class cmd_shell_complete(Command):
2387
2535
    """Show appropriate completions for context.
2388
2536
 
2389
 
    For a list of all available commands, say 'bzr shell-complete'."""
 
2537
    For a list of all available commands, say 'bzr shell-complete'.
 
2538
    """
2390
2539
    takes_args = ['context?']
2391
2540
    aliases = ['s-c']
2392
2541
    hidden = True
2400
2549
class cmd_fetch(Command):
2401
2550
    """Copy in history from another branch but don't merge it.
2402
2551
 
2403
 
    This is an internal method used for pull and merge."""
 
2552
    This is an internal method used for pull and merge.
 
2553
    """
2404
2554
    hidden = True
2405
2555
    takes_args = ['from_branch', 'to_branch']
2406
2556
    def run(self, from_branch, to_branch):
2413
2563
class cmd_missing(Command):
2414
2564
    """Show unmerged/unpulled revisions between two branches.
2415
2565
 
2416
 
    OTHER_BRANCH may be local or remote."""
 
2566
    OTHER_BRANCH may be local or remote.
 
2567
    """
2417
2568
    takes_args = ['other_branch?']
2418
2569
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
2419
2570
                     Option('mine-only', 
2440
2591
        if other_branch is None:
2441
2592
            other_branch = parent
2442
2593
            if other_branch is None:
2443
 
                raise BzrCommandError("No peer location known or specified.")
 
2594
                raise errors.BzrCommandError("No peer location known or specified.")
2444
2595
            print "Using last location: " + local_branch.get_parent()
2445
2596
        remote_branch = Branch.open(other_branch)
2446
2597
        if remote_branch.base == local_branch.base:
2575
2726
            if revision is None:
2576
2727
                revision_id = branch.last_revision()
2577
2728
            elif len(revision) != 1:
2578
 
                raise BzrCommandError('bzr annotate --revision takes exactly 1 argument')
 
2729
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2579
2730
            else:
2580
2731
                revision_id = revision[0].in_history(branch).rev_id
2581
2732
            file_id = tree.inventory.path2id(relpath)
2597
2748
    def run(self, revision_id_list=None, revision=None):
2598
2749
        import bzrlib.gpg as gpg
2599
2750
        if revision_id_list is not None and revision is not None:
2600
 
            raise BzrCommandError('You can only supply one of revision_id or --revision')
 
2751
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
2601
2752
        if revision_id_list is None and revision is None:
2602
 
            raise BzrCommandError('You must supply either --revision or a revision_id')
 
2753
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
2603
2754
        b = WorkingTree.open_containing(u'.')[0].branch
2604
2755
        gpg_strategy = gpg.GPGStrategy(b.get_config())
2605
2756
        if revision_id_list is not None:
2618
2769
                if to_revid is None:
2619
2770
                    to_revno = b.revno()
2620
2771
                if from_revno is None or to_revno is None:
2621
 
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
 
2772
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
2622
2773
                for revno in range(from_revno, to_revno + 1):
2623
2774
                    b.repository.sign_revision(b.get_rev_id(revno), 
2624
2775
                                               gpg_strategy)
2625
2776
            else:
2626
 
                raise BzrCommandError('Please supply either one revision, or a range.')
 
2777
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
2627
2778
 
2628
2779
 
2629
2780
class cmd_bind(Command):
2641
2792
        b_other = Branch.open(location)
2642
2793
        try:
2643
2794
            b.bind(b_other)
2644
 
        except DivergedBranches:
2645
 
            raise BzrCommandError('These branches have diverged.'
2646
 
                                  ' Try merging, and then bind again.')
 
2795
        except errors.DivergedBranches:
 
2796
            raise errors.BzrCommandError('These branches have diverged.'
 
2797
                                         ' Try merging, and then bind again.')
2647
2798
 
2648
2799
 
2649
2800
class cmd_unbind(Command):
2659
2810
    def run(self):
2660
2811
        b, relpath = Branch.open_containing(u'.')
2661
2812
        if not b.unbind():
2662
 
            raise BzrCommandError('Local branch is not bound')
 
2813
            raise errors.BzrCommandError('Local branch is not bound')
2663
2814
 
2664
2815
 
2665
2816
class cmd_uncommit(Command):
2809
2960
        from bzrlib.transport import get_transport
2810
2961
        if directory is None:
2811
2962
            directory = os.getcwd()
2812
 
        url = 'file://' + urlutils.escape(directory)
 
2963
        url = urlutils.local_path_to_url(directory)
2813
2964
        if not allow_writes:
2814
2965
            url = 'readonly+' + url
2815
2966
        t = get_transport(url)
2816
2967
        if inet:
2817
 
            server = smart.SmartStreamServer(sys.stdin, sys.stdout, t)
 
2968
            server = smart.SmartServerPipeStreamMedium(sys.stdin, sys.stdout, t)
2818
2969
        elif port is not None:
2819
2970
            if ':' in port:
2820
2971
                host, port = port.split(':')
2824
2975
            print 'listening on port: ', server.port
2825
2976
            sys.stdout.flush()
2826
2977
        else:
2827
 
            raise BzrCommandError("bzr serve requires one of --inet or --port")
 
2978
            raise errors.BzrCommandError("bzr serve requires one of --inet or --port")
2828
2979
        server.serve()
2829
2980
 
2830
2981
 
2831
2982
# command-line interpretation helper for merge-related commands
2832
 
def merge(other_revision, base_revision,
2833
 
          check_clean=True, ignore_zero=False,
2834
 
          this_dir=None, backup_files=False, merge_type=Merge3Merger,
2835
 
          file_list=None, show_base=False, reprocess=False,
2836
 
          pb=DummyProgress()):
 
2983
def _merge_helper(other_revision, base_revision,
 
2984
                  check_clean=True, ignore_zero=False,
 
2985
                  this_dir=None, backup_files=False,
 
2986
                  merge_type=None,
 
2987
                  file_list=None, show_base=False, reprocess=False,
 
2988
                  pb=DummyProgress()):
2837
2989
    """Merge changes into a tree.
2838
2990
 
2839
2991
    base_revision
2861
3013
    clients might prefer to call merge.merge_inner(), which has less magic 
2862
3014
    behavior.
2863
3015
    """
2864
 
    from bzrlib.merge import Merger
 
3016
    # Loading it late, so that we don't always have to import bzrlib.merge
 
3017
    if merge_type is None:
 
3018
        merge_type = _mod_merge.Merge3Merger
2865
3019
    if this_dir is None:
2866
3020
        this_dir = u'.'
2867
3021
    this_tree = WorkingTree.open_containing(this_dir)[0]
2868
 
    if show_base and not merge_type is Merge3Merger:
2869
 
        raise BzrCommandError("Show-base is not supported for this merge"
2870
 
                              " type. %s" % merge_type)
 
3022
    if show_base and not merge_type is _mod_merge.Merge3Merger:
 
3023
        raise errors.BzrCommandError("Show-base is not supported for this merge"
 
3024
                                     " type. %s" % merge_type)
2871
3025
    if reprocess and not merge_type.supports_reprocess:
2872
 
        raise BzrCommandError("Conflict reduction is not supported for merge"
2873
 
                              " type %s." % merge_type)
 
3026
        raise errors.BzrCommandError("Conflict reduction is not supported for merge"
 
3027
                                     " type %s." % merge_type)
2874
3028
    if reprocess and show_base:
2875
 
        raise BzrCommandError("Cannot do conflict reduction and show base.")
 
3029
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
2876
3030
    try:
2877
 
        merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
 
3031
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
 
3032
                                   pb=pb)
2878
3033
        merger.pp = ProgressPhase("Merge phase", 5, pb)
2879
3034
        merger.pp.next_phase()
2880
3035
        merger.check_basis(check_clean)
2897
3052
    return conflicts
2898
3053
 
2899
3054
 
 
3055
# Compatibility
 
3056
merge = _merge_helper
 
3057
 
 
3058
 
2900
3059
# these get imported and then picked up by the scan for cmd_*
2901
3060
# TODO: Some more consistent way to split command definitions across files;
2902
3061
# we do need to load at least some information about them to know of 
2903
3062
# aliases.  ideally we would avoid loading the implementation until the
2904
3063
# details were needed.
 
3064
from bzrlib.cmd_version_info import cmd_version_info
2905
3065
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2906
3066
from bzrlib.bundle.commands import cmd_bundle_revisions
2907
3067
from bzrlib.sign_my_commits import cmd_sign_my_commits