[3] | 1 | """The migrate command-line tool.""" |
---|
| 2 | |
---|
| 3 | import sys |
---|
| 4 | import inspect |
---|
| 5 | from optparse import OptionParser, BadOptionError |
---|
| 6 | |
---|
| 7 | from migrate.versioning.base import * |
---|
| 8 | from migrate.versioning import api, exceptions |
---|
| 9 | |
---|
| 10 | |
---|
| 11 | alias = dict( |
---|
| 12 | s=api.script, |
---|
| 13 | vc=api.version_control, |
---|
| 14 | dbv=api.db_version, |
---|
| 15 | v=api.version, |
---|
| 16 | ) |
---|
| 17 | |
---|
| 18 | def alias_setup(): |
---|
| 19 | global alias |
---|
| 20 | for key,val in alias.iteritems(): |
---|
| 21 | setattr(api,key,val) |
---|
| 22 | alias_setup() |
---|
| 23 | |
---|
| 24 | |
---|
| 25 | class PassiveOptionParser(OptionParser): |
---|
| 26 | |
---|
| 27 | def _process_args(self, largs, rargs, values): |
---|
| 28 | """little hack to support all --some_option=value parameters""" |
---|
| 29 | |
---|
| 30 | while rargs: |
---|
| 31 | arg = rargs[0] |
---|
| 32 | if arg == "--": |
---|
| 33 | del rargs[0] |
---|
| 34 | return |
---|
| 35 | elif arg[0:2] == "--": |
---|
| 36 | # if parser does not know about the option, pass it along (make it anonymous) |
---|
| 37 | try: |
---|
| 38 | opt = arg.split('=', 1)[0] |
---|
| 39 | self._match_long_opt(opt) |
---|
| 40 | except BadOptionError: |
---|
| 41 | largs.append(arg) |
---|
| 42 | del rargs[0] |
---|
| 43 | else: |
---|
| 44 | self._process_long_opt(rargs, values) |
---|
| 45 | elif arg[:1] == "-" and len(arg) > 1: |
---|
| 46 | self._process_short_opts(rargs, values) |
---|
| 47 | elif self.allow_interspersed_args: |
---|
| 48 | largs.append(arg) |
---|
| 49 | del rargs[0] |
---|
| 50 | |
---|
| 51 | def main(argv=None, **kwargs): |
---|
| 52 | """kwargs are default options that can be overriden with passing --some_option to cmdline""" |
---|
| 53 | |
---|
| 54 | argv = argv or list(sys.argv[1:]) |
---|
| 55 | commands = list(api.__all__) |
---|
| 56 | commands.sort() |
---|
| 57 | |
---|
| 58 | usage="""%%prog COMMAND ... |
---|
| 59 | |
---|
| 60 | Available commands: |
---|
| 61 | %s |
---|
| 62 | |
---|
| 63 | Enter "%%prog help COMMAND" for information on a particular command. |
---|
| 64 | """ % '\n\t'.join(commands) |
---|
| 65 | |
---|
| 66 | parser = PassiveOptionParser(usage=usage) |
---|
| 67 | parser.add_option("-v", "--verbose", action="store_true", dest="verbose") |
---|
| 68 | parser.add_option("-d", "--debug", action="store_true", dest="debug") |
---|
| 69 | parser.add_option("-f", "--force", action="store_true", dest="force") |
---|
| 70 | help_commands = ['help', '-h', '--help'] |
---|
| 71 | HELP = False |
---|
| 72 | |
---|
| 73 | try: |
---|
| 74 | command = argv.pop(0) |
---|
| 75 | if command in help_commands: |
---|
| 76 | HELP = True |
---|
| 77 | command = argv.pop(0) |
---|
| 78 | except IndexError: |
---|
| 79 | parser.print_help() |
---|
| 80 | return |
---|
| 81 | |
---|
| 82 | command_func = getattr(api, command, None) |
---|
| 83 | if command_func is None or command.startswith('_'): |
---|
| 84 | parser.error("Invalid command %s" % command) |
---|
| 85 | |
---|
| 86 | parser.set_usage(inspect.getdoc(command_func)) |
---|
| 87 | f_args, f_varargs, f_kwargs, f_defaults = inspect.getargspec(command_func) |
---|
| 88 | for arg in f_args: |
---|
| 89 | parser.add_option( |
---|
| 90 | "--%s" % arg, |
---|
| 91 | dest=arg, |
---|
| 92 | action='store', |
---|
| 93 | type="string") |
---|
| 94 | |
---|
| 95 | # display help of the current command |
---|
| 96 | if HELP: |
---|
| 97 | parser.print_help() |
---|
| 98 | return |
---|
| 99 | |
---|
| 100 | options, args = parser.parse_args(argv) |
---|
| 101 | |
---|
| 102 | # override kwargs with anonymous parameters |
---|
| 103 | override_kwargs = dict() |
---|
| 104 | for arg in list(args): |
---|
| 105 | if arg.startswith('--'): |
---|
| 106 | args.remove(arg) |
---|
| 107 | if '=' in arg: |
---|
| 108 | opt, value = arg[2:].split('=', 1) |
---|
| 109 | else: |
---|
| 110 | opt = arg[2:] |
---|
| 111 | value = True |
---|
| 112 | override_kwargs[opt] = value |
---|
| 113 | |
---|
| 114 | # override kwargs with options if user is overwriting |
---|
| 115 | for key, value in options.__dict__.iteritems(): |
---|
| 116 | if value is not None: |
---|
| 117 | override_kwargs[key] = value |
---|
| 118 | |
---|
| 119 | # arguments that function accepts without passed kwargs |
---|
| 120 | f_required = list(f_args) |
---|
| 121 | candidates = dict(kwargs) |
---|
| 122 | candidates.update(override_kwargs) |
---|
| 123 | for key, value in candidates.iteritems(): |
---|
| 124 | if key in f_args: |
---|
| 125 | f_required.remove(key) |
---|
| 126 | |
---|
| 127 | # map function arguments to parsed arguments |
---|
| 128 | for arg in args: |
---|
| 129 | try: |
---|
| 130 | kw = f_required.pop(0) |
---|
| 131 | except IndexError: |
---|
| 132 | parser.error("Too many arguments for command %s: %s" % (command, arg)) |
---|
| 133 | kwargs[kw] = arg |
---|
| 134 | |
---|
| 135 | # apply overrides |
---|
| 136 | kwargs.update(override_kwargs) |
---|
| 137 | |
---|
| 138 | # check if all args are given |
---|
| 139 | try: |
---|
| 140 | num_defaults = len(f_defaults) |
---|
| 141 | except TypeError: |
---|
| 142 | num_defaults = 0 |
---|
| 143 | f_args_default = f_args[len(f_args) - num_defaults:] |
---|
| 144 | required = list(set(f_required) - set(f_args_default)) |
---|
| 145 | if required: |
---|
| 146 | parser.error("Not enough arguments for command %s: %s not specified" % (command, ', '.join(required))) |
---|
| 147 | |
---|
| 148 | # handle command |
---|
| 149 | try: |
---|
| 150 | ret = command_func(**kwargs) |
---|
| 151 | if ret is not None: |
---|
| 152 | print ret |
---|
| 153 | except (exceptions.UsageError, exceptions.KnownError), e: |
---|
| 154 | if e.args[0] is None: |
---|
| 155 | parser.print_help() |
---|
| 156 | parser.error(e.args[0]) |
---|
| 157 | |
---|
| 158 | if __name__ == "__main__": |
---|
| 159 | main() |
---|