147 lines
3.9 KiB
Python
147 lines
3.9 KiB
Python
"""The migrate command-line tool.
|
|
"""
|
|
import sys
|
|
from migrate.versioning.base import *
|
|
from optparse import OptionParser,Values
|
|
from migrate.versioning import api,exceptions
|
|
import inspect
|
|
|
|
alias = dict(
|
|
s=api.script,
|
|
vc=api.version_control,
|
|
dbv=api.db_version,
|
|
v=api.version,
|
|
)
|
|
def alias_setup():
|
|
global alias
|
|
for key,val in alias.iteritems():
|
|
setattr(api,key,val)
|
|
alias_setup()
|
|
|
|
class ShellUsageError(Exception):
|
|
def die(self,exitcode=None):
|
|
usage="""%%prog COMMAND ...
|
|
Available commands:
|
|
%s
|
|
|
|
Enter "%%prog help COMMAND" for information on a particular command.
|
|
"""
|
|
usage = usage.replace("\n"+" "*8,"\n")
|
|
commands = list(api.__all__)
|
|
commands.sort()
|
|
commands = '\n'.join(map((lambda x:'\t'+x),commands))
|
|
message = usage%commands
|
|
try:
|
|
message = message.replace('%prog',sys.argv[0])
|
|
except IndexError:
|
|
pass
|
|
|
|
if self.args[0] is not None:
|
|
message += "\nError: %s\n"%str(self.args[0])
|
|
if exitcode is None:
|
|
exitcode = 1
|
|
if exitcode is None:
|
|
exitcode = 0
|
|
die(message,exitcode)
|
|
|
|
def die(message,exitcode=1):
|
|
if message is not None:
|
|
sys.stderr.write(message)
|
|
sys.stderr.write("\n")
|
|
raise SystemExit(int(exitcode))
|
|
|
|
kwmap = dict(
|
|
v='verbose',
|
|
d='debug',
|
|
f='force',
|
|
)
|
|
|
|
def kwparse(arg):
|
|
ret = arg.split('=',1)
|
|
if len(ret) == 1:
|
|
# No value specified (--kw, not --kw=stuff): use True
|
|
ret = [ret[0],True]
|
|
return ret
|
|
|
|
def parse_arg(arg,argnames):
|
|
global kwmap
|
|
if arg.startswith('--'):
|
|
# Keyword-argument; either --keyword or --keyword=value
|
|
kw,val = kwparse(arg[2:])
|
|
elif arg.startswith('-'):
|
|
# Short form of a keyword-argument; map it to a keyword
|
|
try:
|
|
parg = kwmap.get(arg)
|
|
except KeyError:
|
|
raise ShellUsageError("Invalid argument: %s"%arg)
|
|
kw,val = kwparse(parg)
|
|
else:
|
|
# Simple positional parameter
|
|
val = arg
|
|
try:
|
|
kw = argnames.pop(0)
|
|
except IndexError,e:
|
|
raise ShellUsageError("Too many arguments to command")
|
|
return kw,val
|
|
|
|
def parse_args(*args,**kwargs):
|
|
"""Map positional arguments to keyword-args"""
|
|
args=list(args)
|
|
try:
|
|
cmdname = args.pop(0)
|
|
if cmdname == 'downgrade':
|
|
if not args[-1].startswith('--'):
|
|
kwargs['version'] = args[-1]
|
|
|
|
except IndexError:
|
|
# No command specified: no error message; just show usage
|
|
raise ShellUsageError(None)
|
|
|
|
# Special cases: -h and --help should act like 'help'
|
|
if cmdname == '-h' or cmdname == '--help':
|
|
cmdname = 'help'
|
|
|
|
cmdfunc = getattr(api,cmdname,None)
|
|
if cmdfunc is None or cmdname.startswith('_'):
|
|
raise ShellUsageError("Invalid command %s"%cmdname)
|
|
|
|
argnames, p,k, defaults = inspect.getargspec(cmdfunc)
|
|
argnames_orig = list(argnames)
|
|
|
|
for arg in args:
|
|
kw,val = parse_arg(arg,argnames)
|
|
kwargs[kw] = val
|
|
|
|
if defaults is not None:
|
|
num_defaults = len(defaults)
|
|
else:
|
|
num_defaults = 0
|
|
req_argnames = argnames_orig[:len(argnames_orig)-num_defaults]
|
|
for name in req_argnames:
|
|
if name not in kwargs:
|
|
raise ShellUsageError("Too few arguments: %s not specified"%name)
|
|
|
|
return cmdfunc,kwargs
|
|
|
|
def main(argv=None,**kwargs):
|
|
if argv is None:
|
|
argv = list(sys.argv[1:])
|
|
|
|
try:
|
|
command, kwargs = parse_args(*argv,**kwargs)
|
|
except ShellUsageError,e:
|
|
e.die()
|
|
|
|
try:
|
|
ret = command(**kwargs)
|
|
if ret is not None:
|
|
print ret
|
|
except exceptions.UsageError,e:
|
|
e = ShellUsageError(e.args[0])
|
|
e.die()
|
|
except exceptions.KnownError,e:
|
|
die(e.args[0])
|
|
|
|
if __name__=="__main__":
|
|
main()
|