command_line.py revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson# Copyright 2014 The Chromium Authors. All rights reserved. 29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson# Use of this source code is governed by a BSD-style license that can be 39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson# found in the LICENSE file. 49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport argparse 69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport optparse 79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonfrom telemetry.core import camel_case 99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonclass ArgumentHandlerMixIn(object): 129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson """A structured way to handle command-line arguments. 139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson In AddCommandLineArgs, add command-line arguments. 159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson In ProcessCommandLineArgs, validate them and store them in a private class 169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson variable. This way, each class encapsulates its own arguments, without needing 179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson to pass an arguments object around everywhere. 189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson """ 199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson @classmethod 219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson def AddCommandLineArgs(cls, parser): 229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson """Override to accept custom command-line arguments.""" 239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson @classmethod 259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson def ProcessCommandLineArgs(cls, parser, args): 269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson """Override to process command-line arguments. 279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson We pass in parser so we can call parser.error().""" 299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonclass Command(ArgumentHandlerMixIn): 329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson """Represents a command-line sub-command for use with an argparse sub-parser. 339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson E.g. "svn checkout", "svn update", and "svn commit" are separate sub-commands. 359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Example usage, to set up argparse to use these commands: 379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parser = argparse.ArgumentParser() 389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson subparsers = parser.add_subparsers() 399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for command in COMMANDS: 419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson subparser = subparsers.add_parser( 429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson command.Name(), help=command.Description()) 439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson subparser.set_defaults(command=command) 449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson command.AddCommandLineArgs(subparser) 459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson args = parser.parse_args() 479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson args.command.ProcessCommandLineArgs(parser, args) 489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson args.command().Run(args) 499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson """ 509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson @classmethod 529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson def Name(cls): 539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return camel_case.ToUnderscore(cls.__name__) 549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson @classmethod 569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson def Description(cls): 579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if cls.__doc__: 589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return cls.__doc__.splitlines()[0] 599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else: 609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return '' 619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson def Run(self, args): 639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson raise NotImplementedError() 649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson @classmethod 669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson def main(cls): 679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parser = argparse.ArgumentParser() 689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson cls.AddCommandLineArgs(parser) 699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson args = parser.parse_args() 709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson cls.ProcessCommandLineArgs(parser, args) 719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson cls().Run(args) 729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson# TODO: Convert everything to argparse. 759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonclass OptparseCommand(Command): 769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson usage = '' 779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson @classmethod 799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson def CreateParser(cls): 809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return optparse.OptionParser('%%prog %s %s' % (cls.Name(), cls.usage)) 819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson def Run(self, args): 839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson raise NotImplementedError() 849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson @classmethod 869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson def main(cls): 879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parser = optparse.OptionParser() 889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson cls.AddCommandLineArgs(parser) 899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson options, args = parser.parse_args() 909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson options.positional_args = args 919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson cls.ProcessCommandLineArgs(parser, options) 929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson cls().Run(options) 939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson