~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to utilities/script_commands.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-06-25 08:55:37 UTC
  • mfrom: (13287.1.8 bug-800652)
  • Revision ID: launchpad@pqm.canonical.com-20110625085537-moikyoo2pe98zs7r
[r=jcsackett, julian-edwards][bug=800634,
        800652] Enable and display overrides on sync package uploads.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
import inspect
2
 
from optparse import OptionParser
3
 
 
4
 
 
5
 
class UserError(Exception):
6
 
    pass
7
 
 
8
 
 
9
 
def add_dict(name, **kwargs):
10
 
    """Decorator to add a named dictionary to a function's attributes.
11
 
 
12
 
    The kwargs are the contents of the dict.
13
 
    :param name: The name of the dictionary to add.
14
 
    """
15
 
    def decorator(func):
16
 
        setattr(func, name, kwargs)
17
 
        return func
18
 
    return decorator
19
 
 
20
 
 
21
 
def types(**kwargs):
22
 
    """Declare the types require by the arguments of a function.
23
 
 
24
 
    The kwargs are the values to set, as used by OptionParser.add_option::
25
 
      @types(port="int", delay=int)
26
 
    """
27
 
    return add_dict('_types', **kwargs)
28
 
 
29
 
 
30
 
def helps(**kwargs):
31
 
    """Declare the help for the arguments of a function.
32
 
 
33
 
    The kwargs are used to assign help::
34
 
      helps(port="The port to use.", delay="The time to wait.")
35
 
    """
36
 
    return add_dict('_helps', **kwargs)
37
 
 
38
 
 
39
 
def get_function_parser(function):
40
 
    """Generate an OptionParser for a function.
41
 
 
42
 
    Option names are derived from the parameter names.  Defaults come from the
43
 
    parameter defaults.  Types are inferred from the default, or may be
44
 
    specified using the types decorator.  Per-option help may be specified
45
 
    using the helps decorator.
46
 
 
47
 
    :param function: The function to generate a parser for.
48
 
    """
49
 
    parser = OptionParser()
50
 
    args, ignore, ignored, defaults = inspect.getargspec(function)
51
 
    if defaults is None:
52
 
        defaults = [None] * len(args)
53
 
    arg_types = getattr(function, '_types', {})
54
 
    arg_helps = getattr(function, '_helps', {})
55
 
    for arg, default in zip(args, defaults):
56
 
        arg_type = arg_types.get(arg)
57
 
        if arg_type is None:
58
 
            if default is None:
59
 
                continue
60
 
            arg_type = type(default)
61
 
        arg_help = arg_helps.get(arg)
62
 
        if arg_help is not None:
63
 
            arg_help += ' Default: %default.'
64
 
        parser.add_option(
65
 
            '--%s' % arg, type=arg_type, help=arg_help, default=default)
66
 
    return parser
67
 
 
68
 
 
69
 
def parse_args(command, args):
70
 
    """Return the positional arguments as a dict.
71
 
 
72
 
    :param command: A function to treat as a command.
73
 
    :param args: The positional arguments supplied to that function.
74
 
    :return: A dict mapping variable names to arguments.
75
 
    """
76
 
    # TODO: implement!
77
 
    # Basically each argument without a default is treated as a positional
78
 
    # argument.  They must have types defined, since we can't infer it from
79
 
    # the default.
80
 
    #
81
 
    # We may wish to declare optional positional arguments.  These would have
82
 
    # have defaults, but declaring them as positional would prevent them from
83
 
    # being treated as flags.
84
 
    if len(args) != 0:
85
 
        raise UserError('Too many arguments.')
86
 
    return {}
87
 
 
88
 
 
89
 
def run_from_args(command, cmd_args):
90
 
    """Run a command function using the specified commandline arguments.
91
 
 
92
 
    :param command: A function to treat as a command.
93
 
    :param cmd_args: The commandline arguments to use to run the command.
94
 
    """
95
 
    parser = get_function_parser(command)
96
 
    options, args = parser.parse_args(cmd_args)
97
 
    kwargs = parse_args(command, args)
98
 
    kwargs.update(options.__dict__)
99
 
    command(**kwargs)
100
 
 
101
 
 
102
 
def run_subcommand(subcommands, argv):
103
 
    """Run a subcommand as specified by argv.
104
 
 
105
 
    :param subcommands: A dict mapping subcommand names to functions.
106
 
    :param argv: The arguments supplied by the user.  argv[0] should be the
107
 
        subcommand name.
108
 
    """
109
 
    if len(argv) < 1:
110
 
        raise UserError('Must supply a command: %s.' %
111
 
                        ', '.join(subcommands.keys()))
112
 
    try:
113
 
        command = subcommands[argv[0]]
114
 
    except KeyError:
115
 
        raise UserError('%s invalid.  Valid commands: %s.' %
116
 
                        (argv[0], ', '.join(subcommands.keys())))
117
 
    run_from_args(command, argv[1:])