comparison rhodecode/lib/dbmigrate/migrate/versioning/shell.py @ 833:9753e0907827 beta

added dbmigrate package, added model changes moved out upgrade db command to that package
author Marcin Kuzminski <marcin@python-works.com>
date Sat, 11 Dec 2010 01:54:12 +0100
parents
children 08d2dcd71666
comparison
equal deleted inserted replaced
832:634596f81cfd 833:9753e0907827
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """The migrate command-line tool."""
5
6 import sys
7 import inspect
8 import logging
9 from optparse import OptionParser, BadOptionError
10
11 from migrate import exceptions
12 from migrate.versioning import api
13 from migrate.versioning.config import *
14 from migrate.versioning.util import asbool
15
16
17 alias = dict(
18 s=api.script,
19 vc=api.version_control,
20 dbv=api.db_version,
21 v=api.version,
22 )
23
24 def alias_setup():
25 global alias
26 for key, val in alias.iteritems():
27 setattr(api, key, val)
28 alias_setup()
29
30
31 class PassiveOptionParser(OptionParser):
32
33 def _process_args(self, largs, rargs, values):
34 """little hack to support all --some_option=value parameters"""
35
36 while rargs:
37 arg = rargs[0]
38 if arg == "--":
39 del rargs[0]
40 return
41 elif arg[0:2] == "--":
42 # if parser does not know about the option
43 # pass it along (make it anonymous)
44 try:
45 opt = arg.split('=', 1)[0]
46 self._match_long_opt(opt)
47 except BadOptionError:
48 largs.append(arg)
49 del rargs[0]
50 else:
51 self._process_long_opt(rargs, values)
52 elif arg[:1] == "-" and len(arg) > 1:
53 self._process_short_opts(rargs, values)
54 elif self.allow_interspersed_args:
55 largs.append(arg)
56 del rargs[0]
57
58 def main(argv=None, **kwargs):
59 """Shell interface to :mod:`migrate.versioning.api`.
60
61 kwargs are default options that can be overriden with passing
62 --some_option as command line option
63
64 :param disable_logging: Let migrate configure logging
65 :type disable_logging: bool
66 """
67 if argv is not None:
68 argv = argv
69 else:
70 argv = list(sys.argv[1:])
71 commands = list(api.__all__)
72 commands.sort()
73
74 usage = """%%prog COMMAND ...
75
76 Available commands:
77 %s
78
79 Enter "%%prog help COMMAND" for information on a particular command.
80 """ % '\n\t'.join(["%s - %s" % (command.ljust(28),
81 api.command_desc.get(command)) for command in commands])
82
83 parser = PassiveOptionParser(usage=usage)
84 parser.add_option("-d", "--debug",
85 action="store_true",
86 dest="debug",
87 default=False,
88 help="Shortcut to turn on DEBUG mode for logging")
89 parser.add_option("-q", "--disable_logging",
90 action="store_true",
91 dest="disable_logging",
92 default=False,
93 help="Use this option to disable logging configuration")
94 help_commands = ['help', '-h', '--help']
95 HELP = False
96
97 try:
98 command = argv.pop(0)
99 if command in help_commands:
100 HELP = True
101 command = argv.pop(0)
102 except IndexError:
103 parser.print_help()
104 return
105
106 command_func = getattr(api, command, None)
107 if command_func is None or command.startswith('_'):
108 parser.error("Invalid command %s" % command)
109
110 parser.set_usage(inspect.getdoc(command_func))
111 f_args, f_varargs, f_kwargs, f_defaults = inspect.getargspec(command_func)
112 for arg in f_args:
113 parser.add_option(
114 "--%s" % arg,
115 dest=arg,
116 action='store',
117 type="string")
118
119 # display help of the current command
120 if HELP:
121 parser.print_help()
122 return
123
124 options, args = parser.parse_args(argv)
125
126 # override kwargs with anonymous parameters
127 override_kwargs = dict()
128 for arg in list(args):
129 if arg.startswith('--'):
130 args.remove(arg)
131 if '=' in arg:
132 opt, value = arg[2:].split('=', 1)
133 else:
134 opt = arg[2:]
135 value = True
136 override_kwargs[opt] = value
137
138 # override kwargs with options if user is overwriting
139 for key, value in options.__dict__.iteritems():
140 if value is not None:
141 override_kwargs[key] = value
142
143 # arguments that function accepts without passed kwargs
144 f_required = list(f_args)
145 candidates = dict(kwargs)
146 candidates.update(override_kwargs)
147 for key, value in candidates.iteritems():
148 if key in f_args:
149 f_required.remove(key)
150
151 # map function arguments to parsed arguments
152 for arg in args:
153 try:
154 kw = f_required.pop(0)
155 except IndexError:
156 parser.error("Too many arguments for command %s: %s" % (command,
157 arg))
158 kwargs[kw] = arg
159
160 # apply overrides
161 kwargs.update(override_kwargs)
162
163 # configure options
164 for key, value in options.__dict__.iteritems():
165 kwargs.setdefault(key, value)
166
167 # configure logging
168 if not asbool(kwargs.pop('disable_logging', False)):
169 # filter to log =< INFO into stdout and rest to stderr
170 class SingleLevelFilter(logging.Filter):
171 def __init__(self, min=None, max=None):
172 self.min = min or 0
173 self.max = max or 100
174
175 def filter(self, record):
176 return self.min <= record.levelno <= self.max
177
178 logger = logging.getLogger()
179 h1 = logging.StreamHandler(sys.stdout)
180 f1 = SingleLevelFilter(max=logging.INFO)
181 h1.addFilter(f1)
182 h2 = logging.StreamHandler(sys.stderr)
183 f2 = SingleLevelFilter(min=logging.WARN)
184 h2.addFilter(f2)
185 logger.addHandler(h1)
186 logger.addHandler(h2)
187
188 if options.debug:
189 logger.setLevel(logging.DEBUG)
190 else:
191 logger.setLevel(logging.INFO)
192
193 log = logging.getLogger(__name__)
194
195 # check if all args are given
196 try:
197 num_defaults = len(f_defaults)
198 except TypeError:
199 num_defaults = 0
200 f_args_default = f_args[len(f_args) - num_defaults:]
201 required = list(set(f_required) - set(f_args_default))
202 if required:
203 parser.error("Not enough arguments for command %s: %s not specified" \
204 % (command, ', '.join(required)))
205
206 # handle command
207 try:
208 ret = command_func(**kwargs)
209 if ret is not None:
210 log.info(ret)
211 except (exceptions.UsageError, exceptions.KnownError), e:
212 parser.error(e.args[0])
213
214 if __name__ == "__main__":
215 main()