| 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() | 
|---|