~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Martin Pool
  • Date: 2005-07-06 00:38:13 UTC
  • Revision ID: mbp@sourcefrog.net-20050706003813-3994f3d9e806a259
- better error when failing to run selftest on python2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
import bzrlib
22
22
from bzrlib.trace import mutter, note, log_error
23
23
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
24
 
from bzrlib.osutils import quotefn
25
 
from bzrlib import Branch, Inventory, InventoryEntry, BZRDIR, \
26
 
     format_date
 
24
from bzrlib.branch import find_branch
 
25
from bzrlib import BZRDIR
 
26
 
 
27
 
 
28
plugin_cmds = {}
 
29
 
 
30
 
 
31
def register_command(cmd):
 
32
    "Utility function to help register a command"
 
33
    global plugin_cmds
 
34
    k = cmd.__name__
 
35
    if k.startswith("cmd_"):
 
36
        k_unsquished = _unsquish_command_name(k)
 
37
    else:
 
38
        k_unsquished = k
 
39
    if not plugin_cmds.has_key(k_unsquished):
 
40
        plugin_cmds[k_unsquished] = cmd
 
41
    else:
 
42
        log_error('Two plugins defined the same command: %r' % k)
 
43
        log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
27
44
 
28
45
 
29
46
def _squish_command_name(cmd):
68
85
        revs = int(revstr)
69
86
    return revs
70
87
 
71
 
def _find_plugins():
72
 
    """Find all python files which are plugins, and load their commands
73
 
    to add to the list of "all commands"
74
 
 
75
 
    The environment variable BZRPATH is considered a delimited set of
76
 
    paths to look through. Each entry is searched for *.py files.
77
 
    If a directory is found, it is also searched, but they are 
78
 
    not searched recursively. This allows you to revctl the plugins.
79
 
    
80
 
    Inside the plugin should be a series of cmd_* function, which inherit from
81
 
    the bzrlib.commands.Command class.
82
 
    """
83
 
    bzrpath = os.environ.get('BZRPLUGINPATH', '')
84
 
 
85
 
    plugin_cmds = {} 
86
 
    if not bzrpath:
87
 
        return plugin_cmds
88
 
    _platform_extensions = {
89
 
        'win32':'.pyd',
90
 
        'cygwin':'.dll',
91
 
        'darwin':'.dylib',
92
 
        'linux2':'.so'
93
 
        }
94
 
    if _platform_extensions.has_key(sys.platform):
95
 
        platform_extension = _platform_extensions[sys.platform]
96
 
    else:
97
 
        platform_extension = None
98
 
    for d in bzrpath.split(os.pathsep):
99
 
        plugin_names = {} # This should really be a set rather than a dict
100
 
        for f in os.listdir(d):
101
 
            if f.endswith('.py'):
102
 
                f = f[:-3]
103
 
            elif f.endswith('.pyc') or f.endswith('.pyo'):
104
 
                f = f[:-4]
105
 
            elif platform_extension and f.endswith(platform_extension):
106
 
                f = f[:-len(platform_extension)]
107
 
                if f.endswidth('module'):
108
 
                    f = f[:-len('module')]
109
 
            else:
110
 
                continue
111
 
            if not plugin_names.has_key(f):
112
 
                plugin_names[f] = True
113
 
 
114
 
        plugin_names = plugin_names.keys()
115
 
        plugin_names.sort()
116
 
        try:
117
 
            sys.path.insert(0, d)
118
 
            for name in plugin_names:
119
 
                try:
120
 
                    old_module = None
121
 
                    try:
122
 
                        if sys.modules.has_key(name):
123
 
                            old_module = sys.modules[name]
124
 
                            del sys.modules[name]
125
 
                        plugin = __import__(name, locals())
126
 
                        for k in dir(plugin):
127
 
                            if k.startswith('cmd_'):
128
 
                                k_unsquished = _unsquish_command_name(k)
129
 
                                if not plugin_cmds.has_key(k_unsquished):
130
 
                                    plugin_cmds[k_unsquished] = getattr(plugin, k)
131
 
                                else:
132
 
                                    log_error('Two plugins defined the same command: %r' % k)
133
 
                                    log_error('Not loading the one in %r in dir %r' % (name, d))
134
 
                    finally:
135
 
                        if old_module:
136
 
                            sys.modules[name] = old_module
137
 
                except ImportError, e:
138
 
                    log_error('Unable to load plugin: %r from %r\n%s' % (name, d, e))
139
 
        finally:
140
 
            sys.path.pop(0)
141
 
    return plugin_cmds
142
 
 
143
 
def _get_cmd_dict(include_plugins=True):
 
88
 
 
89
 
 
90
def _get_cmd_dict(plugins_override=True):
144
91
    d = {}
145
92
    for k, v in globals().iteritems():
146
93
        if k.startswith("cmd_"):
147
94
            d[_unsquish_command_name(k)] = v
148
 
    if include_plugins:
149
 
        d.update(_find_plugins())
 
95
    # If we didn't load plugins, the plugin_cmds dict will be empty
 
96
    if plugins_override:
 
97
        d.update(plugin_cmds)
 
98
    else:
 
99
        d2 = plugin_cmds.copy()
 
100
        d2.update(d)
 
101
        d = d2
150
102
    return d
 
103
 
151
104
    
152
 
def get_all_cmds(include_plugins=True):
 
105
def get_all_cmds(plugins_override=True):
153
106
    """Return canonical name and class for all registered commands."""
154
 
    for k, v in _get_cmd_dict(include_plugins=include_plugins).iteritems():
 
107
    for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
155
108
        yield k,v
156
109
 
157
110
 
158
 
def get_cmd_class(cmd,include_plugins=True):
 
111
def get_cmd_class(cmd, plugins_override=True):
159
112
    """Return the canonical name and command class for a command.
160
113
    """
161
114
    cmd = str(cmd)                      # not unicode
162
115
 
163
116
    # first look up this command under the specified name
164
 
    cmds = _get_cmd_dict(include_plugins=include_plugins)
 
117
    cmds = _get_cmd_dict(plugins_override=plugins_override)
165
118
    try:
166
119
        return cmd, cmds[cmd]
167
120
    except KeyError:
350
303
    
351
304
    def run(self, all=False, show_ids=False, file_list=None):
352
305
        if file_list:
353
 
            b = Branch(file_list[0])
 
306
            b = find_branch(file_list[0])
354
307
            file_list = [b.relpath(x) for x in file_list]
355
308
            # special case: only one path was given and it's the root
356
309
            # of the branch
357
310
            if file_list == ['']:
358
311
                file_list = None
359
312
        else:
360
 
            b = Branch('.')
 
313
            b = find_branch('.')
361
314
        import status
362
315
        status.show_status(b, show_unchanged=all, show_ids=show_ids,
363
316
                           specific_files=file_list)
370
323
    takes_args = ['revision_id']
371
324
    
372
325
    def run(self, revision_id):
373
 
        Branch('.').get_revision(revision_id).write_xml(sys.stdout)
 
326
        from bzrlib.xml import pack_xml
 
327
        pack_xml(find_branch('.').get_revision(revision_id), sys.stdout)
374
328
 
375
329
 
376
330
class cmd_revno(Command):
378
332
 
379
333
    This is equal to the number of revisions on this branch."""
380
334
    def run(self):
381
 
        print Branch('.').revno()
 
335
        print find_branch('.').revno()
382
336
 
383
337
    
384
338
class cmd_add(Command):
406
360
    takes_options = ['verbose', 'no-recurse']
407
361
    
408
362
    def run(self, file_list, verbose=False, no_recurse=False):
409
 
        bzrlib.add.smart_add(file_list, verbose, not no_recurse)
 
363
        from bzrlib.add import smart_add
 
364
        smart_add(file_list, verbose, not no_recurse)
 
365
 
 
366
 
 
367
 
 
368
class cmd_mkdir(Command):
 
369
    """Create a new versioned directory.
 
370
 
 
371
    This is equivalent to creating the directory and then adding it.
 
372
    """
 
373
    takes_args = ['dir+']
 
374
 
 
375
    def run(self, dir_list):
 
376
        b = None
 
377
        
 
378
        for d in dir_list:
 
379
            os.mkdir(d)
 
380
            if not b:
 
381
                b = find_branch(d)
 
382
            b.add([d], verbose=True)
410
383
 
411
384
 
412
385
class cmd_relpath(Command):
415
388
    hidden = True
416
389
    
417
390
    def run(self, filename):
418
 
        print Branch(filename).relpath(filename)
 
391
        print find_branch(filename).relpath(filename)
419
392
 
420
393
 
421
394
 
424
397
    takes_options = ['revision', 'show-ids']
425
398
    
426
399
    def run(self, revision=None, show_ids=False):
427
 
        b = Branch('.')
 
400
        b = find_branch('.')
428
401
        if revision == None:
429
402
            inv = b.read_working_inventory()
430
403
        else:
447
420
    """
448
421
    takes_args = ['source$', 'dest']
449
422
    def run(self, source_list, dest):
450
 
        b = Branch('.')
 
423
        b = find_branch('.')
451
424
 
452
425
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
453
426
 
469
442
    takes_args = ['from_name', 'to_name']
470
443
    
471
444
    def run(self, from_name, to_name):
472
 
        b = Branch('.')
 
445
        b = find_branch('.')
473
446
        b.rename_one(b.relpath(from_name), b.relpath(to_name))
474
447
 
475
448
 
494
467
 
495
468
    def run(self, location=None):
496
469
        from bzrlib.merge import merge
 
470
        import tempfile
 
471
        from shutil import rmtree
497
472
        import errno
498
473
        
499
 
        br_to = Branch('.')
 
474
        br_to = find_branch('.')
500
475
        stored_loc = None
501
476
        try:
502
477
            stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
503
478
        except IOError, e:
504
 
            if errno == errno.ENOENT:
 
479
            if e.errno != errno.ENOENT:
505
480
                raise
506
481
        if location is None:
507
 
            location = stored_loc
508
 
        if location is None:
509
 
            raise BzrCommandError("No pull location known or specified.")
510
 
        from branch import find_branch, DivergedBranches
 
482
            if stored_loc is None:
 
483
                raise BzrCommandError("No pull location known or specified.")
 
484
            else:
 
485
                print "Using last location: %s" % stored_loc
 
486
                location = stored_loc
 
487
        cache_root = tempfile.mkdtemp()
 
488
        from bzrlib.branch import DivergedBranches
511
489
        br_from = find_branch(location)
512
490
        location = pull_loc(br_from)
513
491
        old_revno = br_to.revno()
514
492
        try:
515
 
            br_to.update_revisions(br_from)
516
 
        except DivergedBranches:
517
 
            raise BzrCommandError("These branches have diverged.  Try merge.")
518
 
            
519
 
        merge(('.', -1), ('.', old_revno), check_clean=False)
520
 
        if location != stored_loc:
521
 
            br_to.controlfile("x-pull", "wb").write(location + "\n")
 
493
            from branch import find_cached_branch, DivergedBranches
 
494
            br_from = find_cached_branch(location, cache_root)
 
495
            location = pull_loc(br_from)
 
496
            old_revno = br_to.revno()
 
497
            try:
 
498
                br_to.update_revisions(br_from)
 
499
            except DivergedBranches:
 
500
                raise BzrCommandError("These branches have diverged."
 
501
                    "  Try merge.")
 
502
                
 
503
            merge(('.', -1), ('.', old_revno), check_clean=False)
 
504
            if location != stored_loc:
 
505
                br_to.controlfile("x-pull", "wb").write(location + "\n")
 
506
        finally:
 
507
            rmtree(cache_root)
522
508
 
523
509
 
524
510
 
537
523
    def run(self, from_location, to_location=None, revision=None):
538
524
        import errno
539
525
        from bzrlib.merge import merge
540
 
        from branch import find_branch, DivergedBranches, NoSuchRevision
 
526
        from bzrlib.branch import DivergedBranches, NoSuchRevision, \
 
527
             find_cached_branch, Branch
541
528
        from shutil import rmtree
542
 
        try:
543
 
            br_from = find_branch(from_location)
544
 
        except OSError, e:
545
 
            if e.errno == errno.ENOENT:
546
 
                raise BzrCommandError('Source location "%s" does not exist.' %
547
 
                                      to_location)
548
 
            else:
549
 
                raise
550
 
 
551
 
        if to_location is None:
552
 
            to_location = os.path.basename(from_location.rstrip("/\\"))
553
 
 
554
 
        try:
555
 
            os.mkdir(to_location)
556
 
        except OSError, e:
557
 
            if e.errno == errno.EEXIST:
558
 
                raise BzrCommandError('Target directory "%s" already exists.' %
559
 
                                      to_location)
560
 
            if e.errno == errno.ENOENT:
561
 
                raise BzrCommandError('Parent of "%s" does not exist.' %
562
 
                                      to_location)
563
 
            else:
564
 
                raise
565
 
        br_to = Branch(to_location, init=True)
566
 
 
567
 
        try:
568
 
            br_to.update_revisions(br_from, stop_revision=revision)
569
 
        except NoSuchRevision:
570
 
            rmtree(to_location)
571
 
            msg = "The branch %s has no revision %d." % (from_location,
572
 
                                                         revision)
573
 
            raise BzrCommandError(msg)
574
 
        merge((to_location, -1), (to_location, 0), this_dir=to_location,
575
 
              check_clean=False, ignore_zero=True)
576
 
        from_location = pull_loc(br_from)
577
 
        br_to.controlfile("x-pull", "wb").write(from_location + "\n")
 
529
        from meta_store import CachedStore
 
530
        import tempfile
 
531
        cache_root = tempfile.mkdtemp()
 
532
        try:
 
533
            try:
 
534
                br_from = find_cached_branch(from_location, cache_root)
 
535
            except OSError, e:
 
536
                if e.errno == errno.ENOENT:
 
537
                    raise BzrCommandError('Source location "%s" does not'
 
538
                                          ' exist.' % to_location)
 
539
                else:
 
540
                    raise
 
541
 
 
542
            if to_location is None:
 
543
                to_location = os.path.basename(from_location.rstrip("/\\"))
 
544
 
 
545
            try:
 
546
                os.mkdir(to_location)
 
547
            except OSError, e:
 
548
                if e.errno == errno.EEXIST:
 
549
                    raise BzrCommandError('Target directory "%s" already'
 
550
                                          ' exists.' % to_location)
 
551
                if e.errno == errno.ENOENT:
 
552
                    raise BzrCommandError('Parent of "%s" does not exist.' %
 
553
                                          to_location)
 
554
                else:
 
555
                    raise
 
556
            br_to = Branch(to_location, init=True)
 
557
 
 
558
            try:
 
559
                br_to.update_revisions(br_from, stop_revision=revision)
 
560
            except NoSuchRevision:
 
561
                rmtree(to_location)
 
562
                msg = "The branch %s has no revision %d." % (from_location,
 
563
                                                             revision)
 
564
                raise BzrCommandError(msg)
 
565
            merge((to_location, -1), (to_location, 0), this_dir=to_location,
 
566
                  check_clean=False, ignore_zero=True)
 
567
            from_location = pull_loc(br_from)
 
568
            br_to.controlfile("x-pull", "wb").write(from_location + "\n")
 
569
        finally:
 
570
            rmtree(cache_root)
578
571
 
579
572
 
580
573
def pull_loc(branch):
597
590
    takes_args = ['dir?']
598
591
 
599
592
    def run(self, dir='.'):
600
 
        b = Branch(dir)
 
593
        b = find_branch(dir)
601
594
        old_inv = b.basis_tree().inventory
602
595
        new_inv = b.read_working_inventory()
603
596
 
614
607
    def run(self, branch=None):
615
608
        import info
616
609
 
617
 
        from branch import find_branch
618
610
        b = find_branch(branch)
619
611
        info.show_info(b)
620
612
 
629
621
    takes_options = ['verbose']
630
622
    
631
623
    def run(self, file_list, verbose=False):
632
 
        b = Branch(file_list[0])
 
624
        b = find_branch(file_list[0])
633
625
        b.remove([b.relpath(f) for f in file_list], verbose=verbose)
634
626
 
635
627
 
643
635
    hidden = True
644
636
    takes_args = ['filename']
645
637
    def run(self, filename):
646
 
        b = Branch(filename)
 
638
        b = find_branch(filename)
647
639
        i = b.inventory.path2id(b.relpath(filename))
648
640
        if i == None:
649
641
            raise BzrError("%r is not a versioned file" % filename)
659
651
    hidden = True
660
652
    takes_args = ['filename']
661
653
    def run(self, filename):
662
 
        b = Branch(filename)
 
654
        b = find_branch(filename)
663
655
        inv = b.inventory
664
656
        fid = inv.path2id(b.relpath(filename))
665
657
        if fid == None:
672
664
    """Display list of revision ids on this branch."""
673
665
    hidden = True
674
666
    def run(self):
675
 
        for patchid in Branch('.').revision_history():
 
667
        for patchid in find_branch('.').revision_history():
676
668
            print patchid
677
669
 
678
670
 
679
671
class cmd_directories(Command):
680
672
    """Display list of versioned directories in this branch."""
681
673
    def run(self):
682
 
        for name, ie in Branch('.').read_working_inventory().directories():
 
674
        for name, ie in find_branch('.').read_working_inventory().directories():
683
675
            if name == '':
684
676
                print '.'
685
677
            else:
700
692
        bzr commit -m 'imported project'
701
693
    """
702
694
    def run(self):
 
695
        from bzrlib.branch import Branch
703
696
        Branch('.', init=True)
704
697
 
705
698
 
733
726
 
734
727
    def run(self, revision=None, file_list=None, diff_options=None):
735
728
        from bzrlib.diff import show_diff
736
 
        from bzrlib import find_branch
737
729
 
738
730
        if file_list:
739
731
            b = find_branch(file_list[0])
742
734
                # just pointing to top-of-tree
743
735
                file_list = None
744
736
        else:
745
 
            b = Branch('.')
 
737
            b = find_branch('.')
746
738
    
747
739
        show_diff(b, revision, specific_files=file_list,
748
740
                  external_diff_options=diff_options)
757
749
    TODO: Show files deleted since a previous revision, or between two revisions.
758
750
    """
759
751
    def run(self, show_ids=False):
760
 
        b = Branch('.')
 
752
        b = find_branch('.')
761
753
        old = b.basis_tree()
762
754
        new = b.working_tree()
763
755
 
779
771
    hidden = True
780
772
    def run(self):
781
773
        import statcache
782
 
        b = Branch('.')
 
774
        b = find_branch('.')
783
775
        inv = b.read_working_inventory()
784
776
        sc = statcache.update_cache(b, inv)
785
777
        basis = b.basis_tree()
805
797
    """List files added in working tree."""
806
798
    hidden = True
807
799
    def run(self):
808
 
        b = Branch('.')
 
800
        b = find_branch('.')
809
801
        wt = b.working_tree()
810
802
        basis_inv = b.basis_tree().inventory
811
803
        inv = wt.inventory
827
819
    takes_args = ['filename?']
828
820
    def run(self, filename=None):
829
821
        """Print the branch root."""
830
 
        from branch import find_branch
831
822
        b = find_branch(filename)
832
823
        print getattr(b, 'base', None) or getattr(b, 'baseurl')
833
824
 
844
835
    """
845
836
 
846
837
    takes_args = ['filename?']
847
 
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision']
 
838
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long']
848
839
    
849
840
    def run(self, filename=None, timezone='original',
850
841
            verbose=False,
851
842
            show_ids=False,
852
843
            forward=False,
853
 
            revision=None):
854
 
        from bzrlib import show_log, find_branch
 
844
            revision=None,
 
845
            long=False):
 
846
        from bzrlib.branch import find_branch
 
847
        from bzrlib.log import log_formatter, show_log
855
848
        import codecs
856
849
 
857
850
        direction = (forward and 'forward') or 'reverse'
883
876
        # in e.g. the default C locale.
884
877
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
885
878
 
886
 
        show_log(b, file_id,
887
 
                 show_timezone=timezone,
 
879
        if long:
 
880
            log_format = 'long'
 
881
        else:
 
882
            log_format = 'short'
 
883
        lf = log_formatter(log_format,
 
884
                           show_ids=show_ids,
 
885
                           to_file=outf,
 
886
                           show_timezone=timezone)
 
887
 
 
888
        show_log(b,
 
889
                 lf,
 
890
                 file_id,
888
891
                 verbose=verbose,
889
 
                 show_ids=show_ids,
890
 
                 to_file=outf,
891
892
                 direction=direction,
892
893
                 start_revision=revision[0],
893
894
                 end_revision=revision[1])
901
902
    hidden = True
902
903
    takes_args = ["filename"]
903
904
    def run(self, filename):
904
 
        b = Branch(filename)
 
905
        b = find_branch(filename)
905
906
        inv = b.read_working_inventory()
906
907
        file_id = inv.path2id(b.relpath(filename))
907
908
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
915
916
    """
916
917
    hidden = True
917
918
    def run(self, revision=None, verbose=False):
918
 
        b = Branch('.')
 
919
        b = find_branch('.')
919
920
        if revision == None:
920
921
            tree = b.working_tree()
921
922
        else:
939
940
class cmd_unknowns(Command):
940
941
    """List unknown files."""
941
942
    def run(self):
942
 
        for f in Branch('.').unknowns():
 
943
        from bzrlib.osutils import quotefn
 
944
        for f in find_branch('.').unknowns():
943
945
            print quotefn(f)
944
946
 
945
947
 
967
969
        from bzrlib.atomicfile import AtomicFile
968
970
        import os.path
969
971
 
970
 
        b = Branch('.')
 
972
        b = find_branch('.')
971
973
        ifn = b.abspath('.bzrignore')
972
974
 
973
975
        if os.path.exists(ifn):
1007
1009
 
1008
1010
    See also: bzr ignore"""
1009
1011
    def run(self):
1010
 
        tree = Branch('.').working_tree()
 
1012
        tree = find_branch('.').working_tree()
1011
1013
        for path, file_class, kind, file_id in tree.list_files():
1012
1014
            if file_class != 'I':
1013
1015
                continue
1031
1033
        except ValueError:
1032
1034
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1033
1035
 
1034
 
        print Branch('.').lookup_revision(revno)
 
1036
        print find_branch('.').lookup_revision(revno)
1035
1037
 
1036
1038
 
1037
1039
class cmd_export(Command):
1045
1047
    takes_args = ['dest']
1046
1048
    takes_options = ['revision', 'format']
1047
1049
    def run(self, dest, revision=None, format='dir'):
1048
 
        b = Branch('.')
 
1050
        b = find_branch('.')
1049
1051
        if revision == None:
1050
1052
            rh = b.revision_history()[-1]
1051
1053
        else:
1063
1065
    def run(self, filename, revision=None):
1064
1066
        if revision == None:
1065
1067
            raise BzrCommandError("bzr cat requires a revision number")
1066
 
        b = Branch('.')
 
1068
        b = find_branch('.')
1067
1069
        b.print_file(b.relpath(filename), int(revision))
1068
1070
 
1069
1071
 
1096
1098
 
1097
1099
    def run(self, message=None, file=None, verbose=True, selected_list=None):
1098
1100
        from bzrlib.commit import commit
 
1101
        from bzrlib.osutils import get_text_message
1099
1102
 
1100
1103
        ## Warning: shadows builtin file()
1101
1104
        if not message and not file:
1102
 
            raise BzrCommandError("please specify a commit message",
1103
 
                                  ["use either --message or --file"])
 
1105
            import cStringIO
 
1106
            stdout = sys.stdout
 
1107
            catcher = cStringIO.StringIO()
 
1108
            sys.stdout = catcher
 
1109
            cmd_status({"file_list":selected_list}, {})
 
1110
            info = catcher.getvalue()
 
1111
            sys.stdout = stdout
 
1112
            message = get_text_message(info)
 
1113
            
 
1114
            if message is None:
 
1115
                raise BzrCommandError("please specify a commit message",
 
1116
                                      ["use either --message or --file"])
1104
1117
        elif message and file:
1105
1118
            raise BzrCommandError("please specify either --message or --file")
1106
1119
        
1108
1121
            import codecs
1109
1122
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1110
1123
 
1111
 
        b = Branch('.')
 
1124
        b = find_branch('.')
1112
1125
        commit(b, message, verbose=verbose, specific_files=selected_list)
1113
1126
 
1114
1127
 
1124
1137
    takes_args = ['dir?']
1125
1138
 
1126
1139
    def run(self, dir='.'):
1127
 
        import bzrlib.check
1128
 
        bzrlib.check.check(Branch(dir))
 
1140
        from bzrlib.check import check
 
1141
        check(find_branch(dir))
1129
1142
 
1130
1143
 
1131
1144
 
1139
1152
 
1140
1153
    def run(self, dir='.'):
1141
1154
        from bzrlib.upgrade import upgrade
1142
 
        upgrade(Branch(dir))
 
1155
        upgrade(find_branch(dir))
1143
1156
 
1144
1157
 
1145
1158
 
1245
1258
              check_clean=(not force))
1246
1259
 
1247
1260
 
 
1261
 
1248
1262
class cmd_revert(Command):
 
1263
    """Restore selected files from a previous revision.
 
1264
    """
 
1265
    takes_args = ['file+']
 
1266
    def run(self, file_list):
 
1267
        from bzrlib.branch import find_branch
 
1268
        
 
1269
        if not file_list:
 
1270
            file_list = ['.']
 
1271
            
 
1272
        b = find_branch(file_list[0])
 
1273
 
 
1274
        b.revert([b.relpath(f) for f in file_list])
 
1275
 
 
1276
 
 
1277
class cmd_merge_revert(Command):
1249
1278
    """Reverse all changes since the last commit.
1250
1279
 
1251
1280
    Only versioned files are affected.
1288
1317
    hidden = True
1289
1318
    def run(self):
1290
1319
        import statcache
1291
 
        b = Branch('.')
 
1320
        b = find_branch('.')
1292
1321
        statcache.update_cache(b.base, b.read_working_inventory())
1293
1322
 
1294
1323
 
1295
1324
 
 
1325
class cmd_plugins(Command):
 
1326
    """List plugins"""
 
1327
    hidden = True
 
1328
    def run(self):
 
1329
        import bzrlib.plugin
 
1330
        from pprint import pprint
 
1331
        pprint(bzrlib.plugin.all_plugins)
 
1332
 
 
1333
 
 
1334
 
1296
1335
# list of all available options; the rhs can be either None for an
1297
1336
# option that takes no argument, or a constructor function that checks
1298
1337
# the type.
1314
1353
    'version':                None,
1315
1354
    'email':                  None,
1316
1355
    'update':                 None,
 
1356
    'long':                   None,
1317
1357
    }
1318
1358
 
1319
1359
SHORT_OPTIONS = {
1322
1362
    'm':                      'message',
1323
1363
    'r':                      'revision',
1324
1364
    'v':                      'verbose',
 
1365
    'l':                      'long',
1325
1366
}
1326
1367
 
1327
1368
 
1470
1511
    return argdict
1471
1512
 
1472
1513
 
 
1514
def _parse_master_args(argv):
 
1515
    """Parse the arguments that always go with the original command.
 
1516
    These are things like bzr --no-plugins, etc.
 
1517
 
 
1518
    There are now 2 types of option flags. Ones that come *before* the command,
 
1519
    and ones that come *after* the command.
 
1520
    Ones coming *before* the command are applied against all possible commands.
 
1521
    And are generally applied before plugins are loaded.
 
1522
 
 
1523
    The current list are:
 
1524
        --builtin   Allow plugins to load, but don't let them override builtin commands,
 
1525
                    they will still be allowed if they do not override a builtin.
 
1526
        --no-plugins    Don't load any plugins. This lets you get back to official source
 
1527
                        behavior.
 
1528
        --profile   Enable the hotspot profile before running the command.
 
1529
                    For backwards compatibility, this is also a non-master option.
 
1530
        --version   Spit out the version of bzr that is running and exit.
 
1531
                    This is also a non-master option.
 
1532
        --help      Run help and exit, also a non-master option (I think that should stay, though)
 
1533
 
 
1534
    >>> argv, opts = _parse_master_args(['bzr', '--test'])
 
1535
    Traceback (most recent call last):
 
1536
    ...
 
1537
    BzrCommandError: Invalid master option: 'test'
 
1538
    >>> argv, opts = _parse_master_args(['bzr', '--version', 'command'])
 
1539
    >>> print argv
 
1540
    ['command']
 
1541
    >>> print opts['version']
 
1542
    True
 
1543
    >>> argv, opts = _parse_master_args(['bzr', '--profile', 'command', '--more-options'])
 
1544
    >>> print argv
 
1545
    ['command', '--more-options']
 
1546
    >>> print opts['profile']
 
1547
    True
 
1548
    >>> argv, opts = _parse_master_args(['bzr', '--no-plugins', 'command'])
 
1549
    >>> print argv
 
1550
    ['command']
 
1551
    >>> print opts['no-plugins']
 
1552
    True
 
1553
    >>> print opts['profile']
 
1554
    False
 
1555
    >>> argv, opts = _parse_master_args(['bzr', 'command', '--profile'])
 
1556
    >>> print argv
 
1557
    ['command', '--profile']
 
1558
    >>> print opts['profile']
 
1559
    False
 
1560
    """
 
1561
    master_opts = {'builtin':False,
 
1562
        'no-plugins':False,
 
1563
        'version':False,
 
1564
        'profile':False,
 
1565
        'help':False
 
1566
    }
 
1567
 
 
1568
    # This is the point where we could hook into argv[0] to determine
 
1569
    # what front-end is supposed to be run
 
1570
    # For now, we are just ignoring it.
 
1571
    cmd_name = argv.pop(0)
 
1572
    for arg in argv[:]:
 
1573
        if arg[:2] != '--': # at the first non-option, we return the rest
 
1574
            break
 
1575
        arg = arg[2:] # Remove '--'
 
1576
        if arg not in master_opts:
 
1577
            # We could say that this is not an error, that we should
 
1578
            # just let it be handled by the main section instead
 
1579
            raise BzrCommandError('Invalid master option: %r' % arg)
 
1580
        argv.pop(0) # We are consuming this entry
 
1581
        master_opts[arg] = True
 
1582
    return argv, master_opts
 
1583
 
 
1584
 
1473
1585
 
1474
1586
def run_bzr(argv):
1475
1587
    """Execute a command.
1479
1591
    """
1480
1592
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
1481
1593
    
1482
 
    include_plugins=True
1483
1594
    try:
1484
 
        args, opts = parse_args(argv[1:])
 
1595
        # some options like --builtin and --no-plugins have special effects
 
1596
        argv, master_opts = _parse_master_args(argv)
 
1597
        if not master_opts['no-plugins']:
 
1598
            from bzrlib.plugin import load_plugins
 
1599
            load_plugins()
 
1600
 
 
1601
        args, opts = parse_args(argv)
 
1602
 
 
1603
        if master_opts['help']:
 
1604
            from bzrlib.help import help
 
1605
            if argv:
 
1606
                help(argv[0])
 
1607
            else:
 
1608
                help()
 
1609
            return 0            
 
1610
            
1485
1611
        if 'help' in opts:
1486
 
            import help
 
1612
            from bzrlib.help import help
1487
1613
            if args:
1488
 
                help.help(args[0])
 
1614
                help(args[0])
1489
1615
            else:
1490
 
                help.help()
 
1616
                help()
1491
1617
            return 0
1492
1618
        elif 'version' in opts:
1493
1619
            show_version()
1502
1628
        return 1
1503
1629
          
1504
1630
 
1505
 
    canonical_cmd, cmd_class = get_cmd_class(cmd,include_plugins=include_plugins)
 
1631
    plugins_override = not (master_opts['builtin'])
 
1632
    canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
1506
1633
 
1507
 
    # global option
 
1634
    profile = master_opts['profile']
 
1635
    # For backwards compatibility, I would rather stick with --profile being a
 
1636
    # master/global option
1508
1637
    if 'profile' in opts:
1509
1638
        profile = True
1510
1639
        del opts['profile']
1511
 
    else:
1512
 
        profile = False
1513
1640
 
1514
1641
    # check options are reasonable
1515
1642
    allowed = cmd_class.takes_options
1564
1691
 
1565
1692
 
1566
1693
def main(argv):
1567
 
    import errno
1568
1694
    
1569
 
    bzrlib.open_tracefile(argv)
 
1695
    bzrlib.trace.open_tracefile(argv)
1570
1696
 
1571
1697
    try:
1572
1698
        try:
1593
1719
            _report_exception('interrupted', quiet=True)
1594
1720
            return 2
1595
1721
        except Exception, e:
 
1722
            import errno
1596
1723
            quiet = False
1597
1724
            if (isinstance(e, IOError) 
1598
1725
                and hasattr(e, 'errno')