• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import argparse
6import optparse
7
8from telemetry.core import camel_case
9
10
11class ArgumentHandlerMixIn(object):
12  """A structured way to handle command-line arguments.
13
14  In AddCommandLineArgs, add command-line arguments.
15  In ProcessCommandLineArgs, validate them and store them in a private class
16  variable. This way, each class encapsulates its own arguments, without needing
17  to pass an arguments object around everywhere.
18  """
19
20  @classmethod
21  def AddCommandLineArgs(cls, parser):
22    """Override to accept custom command-line arguments."""
23
24  @classmethod
25  def ProcessCommandLineArgs(cls, parser, args):
26    """Override to process command-line arguments.
27
28    We pass in parser so we can call parser.error()."""
29
30
31class Command(ArgumentHandlerMixIn):
32  """An abstraction for things that run from the command-line."""
33
34  @classmethod
35  def Name(cls):
36    return camel_case.ToUnderscore(cls.__name__)
37
38  @classmethod
39  def Description(cls):
40    if cls.__doc__:
41      return cls.__doc__.splitlines()[0]
42    else:
43      return ''
44
45  def Run(self, args):
46    raise NotImplementedError()
47
48  @classmethod
49  def main(cls):
50    """Main method to run this command as a standalone script."""
51    parser = argparse.ArgumentParser()
52    cls.AddCommandLineArgs(parser)
53    args = parser.parse_args()
54    cls.ProcessCommandLineArgs(parser, args)
55    return cls().Run(args)
56
57
58# TODO: Convert everything to argparse.
59class OptparseCommand(Command):
60  usage = ''
61
62  @classmethod
63  def CreateParser(cls):
64    return optparse.OptionParser('%%prog %s %s' % (cls.Name(), cls.usage),
65                                 description=cls.Description())
66
67  def Run(self, args):
68    raise NotImplementedError()
69
70  @classmethod
71  def main(cls):
72    """Main method to run this command as a standalone script."""
73    parser = cls.CreateParser()
74    cls.AddCommandLineArgs(parser)
75    options, args = parser.parse_args()
76    options.positional_args = args
77    cls.ProcessCommandLineArgs(parser, options)
78    return cls().Run(options)
79
80
81class SubcommandCommand(Command):
82  """Combines Commands into one big command with sub-commands.
83
84  E.g. "svn checkout", "svn update", and "svn commit" are separate sub-commands.
85
86  Example usage:
87    class MyCommand(command_line.SubcommandCommand):
88      commands = (Help, List, Run)
89
90    if __name__ == '__main__':
91      sys.exit(MyCommand.main())
92  """
93
94  commands = ()
95
96  @classmethod
97  def AddCommandLineArgs(cls, parser):
98    subparsers = parser.add_subparsers()
99
100    for command in cls.commands:
101      subparser = subparsers.add_parser(
102          command.Name(), help=command.Description())
103      subparser.set_defaults(command=command)
104      command.AddCommandLineArgs(subparser)
105
106  @classmethod
107  def ProcessCommandLineArgs(cls, parser, args):
108    args.command.ProcessCommandLineArgs(parser, args)
109
110  def Run(self, args):
111    args.command().Run(args)
112