/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Vincent Ladeuil
  • Date: 2007-07-18 09:43:41 UTC
  • mto: (2778.5.1 vila)
  • mto: This revision was merged to the branch mainline in revision 2789.
  • Revision ID: v.ladeuil+lp@free.fr-20070718094341-edmgsog3el06yqow
Add performance analysis of missing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 by Canonical Ltd
 
1
# Copyright (C) 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
28
28
# TODO: "--profile=cum", to change sort order.  Is there any value in leaving
29
29
# the profile output behind so it can be interactively examined?
30
30
 
 
31
import os
 
32
import sys
 
33
 
 
34
from bzrlib.lazy_import import lazy_import
 
35
lazy_import(globals(), """
31
36
import codecs
32
37
import errno
33
 
import os
34
38
from warnings import warn
35
 
import sys
36
39
 
37
40
import bzrlib
38
 
import bzrlib.errors as errors
39
 
from bzrlib.errors import (BzrError,
40
 
                           BzrCommandError,
41
 
                           BzrCheckError,
42
 
                           NotBranchError)
43
 
from bzrlib import option
 
41
from bzrlib import (
 
42
    debug,
 
43
    errors,
 
44
    option,
 
45
    osutils,
 
46
    trace,
 
47
    win32utils,
 
48
    )
 
49
""")
 
50
 
 
51
from bzrlib.symbol_versioning import (
 
52
    deprecated_function,
 
53
    deprecated_method,
 
54
    zero_eight,
 
55
    zero_eleven,
 
56
    )
 
57
# Compatibility
44
58
from bzrlib.option import Option
45
 
import bzrlib.osutils
46
 
from bzrlib.symbol_versioning import (deprecated_method, zero_eight)
47
 
import bzrlib.trace
48
 
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
 
59
 
49
60
 
50
61
plugin_cmds = {}
51
62
 
66
77
        k_unsquished = k
67
78
    if k_unsquished not in plugin_cmds:
68
79
        plugin_cmds[k_unsquished] = cmd
69
 
        mutter('registered plugin command %s', k_unsquished)
 
80
        ## trace.mutter('registered plugin command %s', k_unsquished)
70
81
        if decorate and k_unsquished in builtin_command_names():
71
82
            return _builtin_commands()[k_unsquished]
72
83
    elif decorate:
74
85
        plugin_cmds[k_unsquished] = cmd
75
86
        return result
76
87
    else:
77
 
        log_error('Two plugins defined the same command: %r' % k)
78
 
        log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
 
88
        trace.log_error('Two plugins defined the same command: %r' % k)
 
89
        trace.log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
79
90
 
80
91
 
81
92
def _squish_command_name(cmd):
127
138
    plugins_override
128
139
        If true, plugin commands can override builtins.
129
140
    """
 
141
    try:
 
142
        return _get_cmd_object(cmd_name, plugins_override)
 
143
    except KeyError:
 
144
        raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
 
145
 
 
146
 
 
147
def _get_cmd_object(cmd_name, plugins_override=True):
 
148
    """Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
130
149
    from bzrlib.externalcommand import ExternalCommand
131
150
 
132
151
    # We want only 'ascii' command names, but the user may have typed
149
168
    cmd_obj = ExternalCommand.find_command(cmd_name)
150
169
    if cmd_obj:
151
170
        return cmd_obj
152
 
 
153
 
    raise BzrCommandError('unknown command "%s"' % cmd_name)
 
171
    raise KeyError
154
172
 
155
173
 
156
174
class Command(object):
204
222
            replace - put in a bogus character (typically '?')
205
223
            exact - do not encode sys.stdout
206
224
 
 
225
            NOTE: by default on Windows, sys.stdout is opened as a text
 
226
            stream, therefore LF line-endings are converted to CRLF.
 
227
            When a command uses encoding_type = 'exact', then
 
228
            sys.stdout is forced to be a binary stream, and line-endings
 
229
            will not mangled.
 
230
 
207
231
    """
208
232
    aliases = []
209
233
    takes_args = []
217
241
        if self.__doc__ == Command.__doc__:
218
242
            warn("No help message set for %r" % self)
219
243
 
 
244
    def _maybe_expand_globs(self, file_list):
 
245
        """Glob expand file_list if the platform does not do that itself.
 
246
        
 
247
        :return: A possibly empty list of unicode paths.
 
248
 
 
249
        Introduced in bzrlib 0.18.
 
250
        """
 
251
        if not file_list:
 
252
            file_list = []
 
253
        if sys.platform == 'win32':
 
254
            file_list = win32utils.glob_expand(file_list)
 
255
        return list(file_list)
 
256
 
 
257
    def _usage(self):
 
258
        """Return single-line grammar for this command.
 
259
 
 
260
        Only describes arguments, not options.
 
261
        """
 
262
        s = 'bzr ' + self.name() + ' '
 
263
        for aname in self.takes_args:
 
264
            aname = aname.upper()
 
265
            if aname[-1] in ['$', '+']:
 
266
                aname = aname[:-1] + '...'
 
267
            elif aname[-1] == '?':
 
268
                aname = '[' + aname[:-1] + ']'
 
269
            elif aname[-1] == '*':
 
270
                aname = '[' + aname[:-1] + '...]'
 
271
            s += aname + ' '
 
272
                
 
273
        assert s[-1] == ' '
 
274
        s = s[:-1]
 
275
        return s
 
276
 
 
277
    def get_help_text(self, additional_see_also=None):
 
278
        """Return a text string with help for this command.
 
279
        
 
280
        :param additional_see_also: Additional help topics to be
 
281
            cross-referenced.
 
282
        """
 
283
        doc = self.help()
 
284
        if doc is None:
 
285
            raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
 
286
 
 
287
        result = ""
 
288
        result += 'usage: %s\n' % self._usage()
 
289
 
 
290
        if self.aliases:
 
291
            result += 'aliases: '
 
292
            result += ', '.join(self.aliases) + '\n'
 
293
 
 
294
        result += '\n'
 
295
 
 
296
        plugin_name = self.plugin_name()
 
297
        if plugin_name is not None:
 
298
            result += '(From plugin "%s")' % plugin_name
 
299
            result += '\n\n'
 
300
 
 
301
        result += doc
 
302
        if result[-1] != '\n':
 
303
            result += '\n'
 
304
        result += '\n'
 
305
        result += option.get_optparser(self.options()).format_option_help()
 
306
        see_also = self.get_see_also(additional_see_also)
 
307
        if see_also:
 
308
            result += '\nSee also: '
 
309
            result += ', '.join(see_also)
 
310
            result += '\n'
 
311
        return result
 
312
 
 
313
    def get_help_topic(self):
 
314
        """Return the commands help topic - its name."""
 
315
        return self.name()
 
316
 
 
317
    def get_see_also(self, additional_terms=None):
 
318
        """Return a list of help topics that are related to this ommand.
 
319
        
 
320
        The list is derived from the content of the _see_also attribute. Any
 
321
        duplicates are removed and the result is in lexical order.
 
322
        :param additional_terms: Additional help topics to cross-reference.
 
323
        :return: A list of help topics.
 
324
        """
 
325
        see_also = set(getattr(self, '_see_also', []))
 
326
        if additional_terms:
 
327
            see_also.update(additional_terms)
 
328
        return sorted(see_also)
 
329
 
220
330
    def options(self):
221
331
        """Return dict of valid options for this command.
222
332
 
223
333
        Maps from long option name to option object."""
224
334
        r = dict()
225
 
        r['help'] = Option.OPTIONS['help']
 
335
        r['help'] = option._help_option
226
336
        for o in self.takes_options:
227
337
            if isinstance(o, basestring):
228
 
                o = Option.OPTIONS[o]
 
338
                o = option.Option.OPTIONS[o]
229
339
            r[o.name] = o
230
340
        return r
231
341
 
236
346
        # Originally I was using self.stdout, but that looks
237
347
        # *way* too much like sys.stdout
238
348
        if self.encoding_type == 'exact':
 
349
            # force sys.stdout to be binary stream on win32
 
350
            if sys.platform == 'win32':
 
351
                fileno = getattr(sys.stdout, 'fileno', None)
 
352
                if fileno:
 
353
                    import msvcrt
 
354
                    msvcrt.setmode(fileno(), os.O_BINARY)
239
355
            self.outf = sys.stdout
240
356
            return
241
357
 
242
 
        output_encoding = bzrlib.osutils.get_terminal_encoding()
 
358
        output_encoding = osutils.get_terminal_encoding()
243
359
 
244
360
        # use 'replace' so that we don't abort if trying to write out
245
361
        # in e.g. the default C locale.
249
365
        # bogus. So set the attribute, so we can find the correct encoding later.
250
366
        self.outf.encoding = output_encoding
251
367
 
252
 
    @deprecated_method(zero_eight)
253
 
    def run_argv(self, argv):
254
 
        """Parse command line and run.
255
 
        
256
 
        See run_argv_aliases for the 0.8 and beyond api.
257
 
        """
258
 
        return self.run_argv_aliases(argv)
259
 
 
260
368
    def run_argv_aliases(self, argv, alias_argv=None):
261
369
        """Parse the command line and run with extra aliases in alias_argv."""
262
370
        if argv is None:
263
 
            warn("Passing None for [] is deprecated from bzrlib 0.10", 
 
371
            warn("Passing None for [] is deprecated from bzrlib 0.10",
264
372
                 DeprecationWarning, stacklevel=2)
265
373
            argv = []
266
374
        args, opts = parse_args(self, argv, alias_argv)
267
375
        if 'help' in opts:  # e.g. bzr add --help
268
 
            from bzrlib.help import help_on_command
269
 
            help_on_command(self.name())
 
376
            sys.stdout.write(self.get_help_text())
270
377
            return 0
271
378
        # mix arguments and options into one dictionary
272
379
        cmdargs = _match_argform(self.name(), self.takes_args, args)
291
398
        shell error code if not.  It's OK for this method to allow
292
399
        an exception to raise up.
293
400
        """
294
 
        raise NotImplementedError('no implementation of command %r' 
 
401
        raise NotImplementedError('no implementation of command %r'
295
402
                                  % self.name())
296
403
 
297
404
    def help(self):
316
423
            return None
317
424
 
318
425
 
 
426
# Technically, this function hasn't been use in a *really* long time
 
427
# but we are only deprecating it now.
 
428
@deprecated_function(zero_eleven)
319
429
def parse_spec(spec):
320
430
    """
321
431
    >>> parse_spec(None)
363
473
        args = argv
364
474
 
365
475
    options, args = parser.parse_args(args)
366
 
    opts = dict([(k, v) for k, v in options.__dict__.iteritems() if 
 
476
    opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
367
477
                 v is not option.OptionParser.DEFAULT_VALUE])
368
478
    return args, opts
369
479
 
385
495
                argdict[argname + '_list'] = None
386
496
        elif ap[-1] == '+':
387
497
            if not args:
388
 
                raise BzrCommandError("command %r needs one or more %s"
389
 
                        % (cmd, argname.upper()))
 
498
                raise errors.BzrCommandError("command %r needs one or more %s"
 
499
                                             % (cmd, argname.upper()))
390
500
            else:
391
501
                argdict[argname + '_list'] = args[:]
392
502
                args = []
393
503
        elif ap[-1] == '$': # all but one
394
504
            if len(args) < 2:
395
 
                raise BzrCommandError("command %r needs one or more %s"
396
 
                        % (cmd, argname.upper()))
 
505
                raise errors.BzrCommandError("command %r needs one or more %s"
 
506
                                             % (cmd, argname.upper()))
397
507
            argdict[argname + '_list'] = args[:-1]
398
508
            args[:-1] = []
399
509
        else:
400
510
            # just a plain arg
401
511
            argname = ap
402
512
            if not args:
403
 
                raise BzrCommandError("command %r requires argument %s"
404
 
                        % (cmd, argname.upper()))
 
513
                raise errors.BzrCommandError("command %r requires argument %s"
 
514
                               % (cmd, argname.upper()))
405
515
            else:
406
516
                argdict[argname] = args.pop(0)
407
517
            
408
518
    if args:
409
 
        raise BzrCommandError("extra argument to command %s: %s"
410
 
                              % (cmd, args[0]))
 
519
        raise errors.BzrCommandError("extra argument to command %s: %s"
 
520
                                     % (cmd, args[0]))
411
521
 
412
522
    return argdict
413
523
 
438
548
 
439
549
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
440
550
    from bzrlib.lsprof import profile
441
 
    import cPickle
442
551
    ret, stats = profile(the_callable, *args, **kwargs)
443
552
    stats.sort()
444
553
    if filename is None:
445
554
        stats.pprint()
446
555
    else:
447
 
        stats.freeze()
448
 
        cPickle.dump(stats, open(filename, 'w'), 2)
449
 
        print 'Profile data written to %r.' % filename
 
556
        stats.save(filename)
 
557
        trace.note('Profile data written to "%s".', filename)
450
558
    return ret
451
559
 
452
560
 
453
 
def get_alias(cmd):
454
 
    """Return an expanded alias, or None if no alias exists"""
455
 
    import bzrlib.config
456
 
    alias = bzrlib.config.GlobalConfig().get_alias(cmd)
 
561
def get_alias(cmd, config=None):
 
562
    """Return an expanded alias, or None if no alias exists.
 
563
 
 
564
    cmd
 
565
        Command to be checked for an alias.
 
566
    config
 
567
        Used to specify an alternative config to use,
 
568
        which is especially useful for testing.
 
569
        If it is unspecified, the global config will be used.
 
570
    """
 
571
    if config is None:
 
572
        import bzrlib.config
 
573
        config = bzrlib.config.GlobalConfig()
 
574
    alias = config.get_alias(cmd)
457
575
    if (alias):
458
 
        return alias.split(' ')
 
576
        import shlex
 
577
        return [a.decode('utf-8') for a in shlex.split(alias.encode('utf-8'))]
459
578
    return None
460
579
 
461
580
 
492
611
        Run under the Python lsprof profiler.
493
612
    """
494
613
    argv = list(argv)
 
614
    trace.mutter("bzr arguments: %r", argv)
495
615
 
496
616
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
497
617
                opt_no_aliases = False
520
640
        elif a == '--builtin':
521
641
            opt_builtin = True
522
642
        elif a in ('--quiet', '-q'):
523
 
            be_quiet()
 
643
            trace.be_quiet()
 
644
        elif a.startswith('-D'):
 
645
            debug.debug_flags.add(a[2:])
524
646
        else:
525
647
            argv_copy.append(a)
526
648
        i += 1
557
679
    # 'command not found' error later.
558
680
 
559
681
    cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
560
 
    if not getattr(cmd_obj.run_argv, 'is_deprecated', False):
561
 
        run = cmd_obj.run_argv
562
 
        run_argv = [argv]
563
 
    else:
564
 
        run = cmd_obj.run_argv_aliases
565
 
        run_argv = [argv, alias_argv]
 
682
    run = cmd_obj.run_argv_aliases
 
683
    run_argv = [argv, alias_argv]
566
684
 
567
685
    try:
568
686
        if opt_lsprof:
574
692
        return ret or 0
575
693
    finally:
576
694
        # reset, in case we may do other commands later within the same process
577
 
        be_quiet(False)
 
695
        trace.be_quiet(False)
578
696
 
579
697
def display_command(func):
580
698
    """Decorator that suppresses pipe/interrupt errors."""
588
706
                raise
589
707
            if e.errno != errno.EPIPE:
590
708
                # Win32 raises IOError with errno=0 on a broken pipe
591
 
                if sys.platform != 'win32' or e.errno != 0:
 
709
                if sys.platform != 'win32' or (e.errno not in (0, errno.EINVAL)):
592
710
                    raise
593
711
            pass
594
712
        except KeyboardInterrupt:
602
720
    bzrlib.ui.ui_factory = TextUIFactory()
603
721
    argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
604
722
    ret = run_bzr_catch_errors(argv)
605
 
    mutter("return code %d", ret)
 
723
    trace.mutter("return code %d", ret)
606
724
    return ret
607
725
 
608
726
 
609
727
def run_bzr_catch_errors(argv):
610
728
    try:
611
729
        return run_bzr(argv)
612
 
        # do this here inside the exception wrappers to catch EPIPE
613
 
        sys.stdout.flush()
614
 
    except Exception, e:
 
730
    except (KeyboardInterrupt, Exception), e:
615
731
        # used to handle AssertionError and KeyboardInterrupt
616
732
        # specially here, but hopefully they're handled ok by the logger now
617
 
        bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
 
733
        trace.report_exception(sys.exc_info(), sys.stderr)
618
734
        if os.environ.get('BZR_PDB'):
619
735
            print '**** entering debugger'
620
736
            import pdb
621
737
            pdb.post_mortem(sys.exc_traceback)
622
738
        return 3
623
739
 
 
740
 
 
741
class HelpCommandIndex(object):
 
742
    """A index for bzr help that returns commands."""
 
743
 
 
744
    def __init__(self):
 
745
        self.prefix = 'commands/'
 
746
 
 
747
    def get_topics(self, topic):
 
748
        """Search for topic amongst commands.
 
749
 
 
750
        :param topic: A topic to search for.
 
751
        :return: A list which is either empty or contains a single
 
752
            Command entry.
 
753
        """
 
754
        if topic and topic.startswith(self.prefix):
 
755
            topic = topic[len(self.prefix):]
 
756
        try:
 
757
            cmd = _get_cmd_object(topic)
 
758
        except KeyError:
 
759
            return []
 
760
        else:
 
761
            return [cmd]
 
762
 
 
763
 
624
764
if __name__ == '__main__':
625
765
    sys.exit(main(sys.argv))