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