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