# Part of the A-A-P recipe executive: process the command line arguments. # Copyright (C) 2002 Stichting NLnet Labs # Permission to copy and use this file is specified in the file COPYING. # If this file is missing you can find it here: http://www.a-a-p.org/COPYING # The arguments come in three catogeries # - options # start with a dash: in the form "-v", "--version", "-f foo". # - variable assignments # contain an equal sign: "foo=asdf" # - targets # the rest # The code for handing options originally comes from SCons. import sys import string import getopt from Args import Args from Error import * from Version import * # # function called for -v and --version # def opt_version(opt, arg): print _("A-A-P recipe executive version %s; released %s %s GMT") \ % (version_string, version_date, version_time) sys.exit(0) # # function called for -h and --help # def opt_help(opt, arg): global option_list help_opts = filter(lambda x: x.helpline, option_list) print _("Usage: aap [OPTION] [VAR=VALUE] [TARGET] ...\n") \ + _("Options:\n") \ + string.join(map(lambda x: x.helpline, help_opts), "\n") + "\n" sys.exit(0) # # The following variables are filled with all the possible options. # option_list = [] # list of all Option objects short_opts = "" # string of short (single-character) options long_opts = [] # array of long (--) options option_dict = {} # mapping of each option string to its Option object def options_init(): """Initialize command-line arguments processing. This is in a function mainly so we can easily single-step over it in the debugger. """ class Option: """Class for command-line option information. This exists to provide a central location for everything describing a command-line option, so that we can change options without having to update the code to handle the option in one place, the -h help message in another place, etc. There are no methods here, only attributes. You can initialize an Option with the following: func The function that will be called when this option is processed on the command line. Calling sequence is: func(opt, arg) If there is no func, then this Option probably stores an optstring to be printed. name The generic option name. Usually either func or name is used. When a name is specified, the option is stored for later use. helpline The string to be printed in -h output. If no helpline is specified but a help string is specified (the usual case), a helpline will be constructed automatically from the short, long, arg, and help attributes. (In practice, then, setting helpline without setting func allows you to print arbitrary lines of text in the -h output.) short The string for short, single-hyphen command-line options. Do not include the hyphen: 'a' for -a, 'xy' for -x and -y, etc. long An array of strings for long, double-hyphen command-line options. Do not include the hyphens: ['my-option', 'verbose'] arg If this option takes an argument, this string specifies how you want it to appear in the -h output ('DIRECTORY', 'FILE', etc.). help The help string that will be printed for this option in the -h output. Must be 49 characters or fewer. future If non-zero, this indicates that this feature will be supported in a future release, not the currently planned one. SCons will recognize the option, but it won't show up in the -h output. The following attribute is derived from the supplied attributes: optstring A string, with hyphens, describing the flags for this option, as constructed from the specified short, long and arg attributes. All Option objects are stored in the global option_list list, in the order in which they're created. This is the list that's used to generate -h output, so the order in which the objects are created is the order in which they're printed. """ def __init__(self, func = None, name = None, helpline = None, short = None, long = None, arg = None, append = 0, help = None, future = None): self.func = func self.name = name self.short = short self.long = long self.arg = arg self.append = append self.help = help # process the short and long option names to create a help line. opts = [] if self.short: for c in self.short: if arg: c = c + " " + arg opts = opts + ['-' + c] if self.long: l = self.long if arg: l = map(lambda x,a=arg: x + "=" + a, self.long) opts = opts + map(lambda x: '--' + x, l) self.optstring = string.join(opts, ', ') if helpline: self.helpline = helpline elif help and not future: if len(self.optstring) <= 26: sep = " " * (28 - len(self.optstring)) else: sep = self.helpstring = "\n" + " " * 30 self.helpline = " " + self.optstring + sep + self.help else: self.helpline = None # Add the newly created Option object to the list of objects. global option_list option_list.append(self) # In the following instantiations, the help string should be no # longer than 49 characters. Use the following as a guide: # help = _("1234567890123456789012345678901234567890123456789") Option(func = opt_version, short = 'V', long = ['version'], help = _("Print version information and exit")) Option(func = opt_help, short = 'h', long = ['help'], help = _("Print help message (this one) and exit")) Option(name = "verbose", short = 'v', long = ['verbose'], help = _("Print more information")) Option(name = "silent", short = 's', long = ['silent'], help = _("Print less information")) Option(name = "debug", short = 'd', long = ['debug'], arg = 'FLAGS', help = _("Debug the specified items")) Option(name = "nobuild", short = 'n', long = ['nobuild'], help = _("Print the build commands but do not execute them")) Option(name = "command", short = 'c', long = ['command'], arg = 'CMD', append = 1, help = _("Execute a command after reading the recipe")) Option(name = "continue", short = 'k', long = ['continue'], help = _("Continue building after encountering an error")) Option(name = "stop", short = 'S', long = ['stop'], help = _("Stop building after encountering an error")) Option(name = "refresh-recipe", short = 'R', long = ['refresh-recipe'], help = _("Refresh recipe file and child recipes")) Option(name = "nocache", short = 'a', long = ['nocache'], help = _("Always download files, don't use the cache")) Option(name = "jobs", short = 'j', long = ['jobs'], arg = 'N', help = _("Maximum number of parallel jobs")) Option(name = "search-up", short = 'u', long = ['search-up', 'up'], help = _("Search directory tree upwards for main.aap recipe")) Option(name = "include", short = 'I', long = ['include'], arg = 'DIR', append = 1, help = _("Directory to search for included recipes")) Option(name = "recipe", short = 'f', long = ['recipe'], arg = 'FILE', help = _("Recipe file to be executed")) # Now that all Option objects are created, make the list of short and long # option names for use with getopt(). # This also makes a dictonary to be able to find each Option object by the # option name. global short_opts global long_opts global option_dict for o in option_list: if o.short: for c in o.short: option_dict['-' + c] = o short_opts = short_opts + o.short if o.arg: short_opts = short_opts + ":" if o.long: for l in o.long: option_dict['--' + l] = o if o.arg: long_opts = long_opts + map(lambda a: a + "=", o.long) else: long_opts = long_opts + o.long # # The main function to process the command line arguments. # def doargs(): """ Process the command line arguments. Returns an Args object with the resuting args and targets. """ global short_opts global long_opts global option_dict options_init() # # Start with an empty Args object. # args = Args() # # First extract the options. # # It looks like Python 2.0 changed the name of the exception class raised # by getopt. try: getopt_err = getopt.GetoptError except: getopt_err = getopt.error try: cmd_opts, argv = getopt.getopt(sys.argv[1:], short_opts, long_opts) except getopt_err, x: raise UserError, _("Invalid argument: ") + x else: # For the recognized options call a function and/or add the argument to # the argument dictionary for later use. # Note that a function may cause us to exit! for opt, arg in cmd_opts: o = option_dict[opt] if o.func: o.func(opt, arg) if o.name: if o.append: if args.options.has_key(o.name): args.options[o.name].append(arg) else: args.options[o.name] = [ arg ] else: args.options[o.name] = arg # # The remaining arguments are either variable assignments or targets. # for a in argv: if '=' in a: name, value = string.split(a, '=', 2) args.values[name] = value else: args.targets.append(a) # Using a "refresh" or "update" target implies the # --refresh-recipe option. if a == "refresh" or a == "update": args.options["refresh-recipe"] = 1 return args # vim: set sw=4 sts=4 tw=79 fo+=l: .