from alembic.script import ScriptDirectory
from alembic import options
+import os
+import sys
-def main(argv=None):
-
- parser = options.get_option_parser()
-
- opts, args = parser.parse_args(argv[1:])
- if len(args) < 1:
- parser.error("no command specified") # Will exit
-
- print opts.config
-
-def list_templates(options):
+def _status(msg, fn, *arg, **kw):
+ sys.stdout.write(" " + msg + "...")
+ try:
+ ret = fn(*arg, **kw)
+ sys.stdout.write("done\n")
+ return ret
+ except:
+ sys.stdout.write("FAILED\n")
+ raise
+
+def list_templates(opts):
"""List available templates"""
-def init(options):
+ print "Available templates:\n"
+ for tempname in os.listdir(opts.get_template_directory()):
+ readme = os.path.join(
+ opts.get_template_directory(),
+ tempname,
+ 'README')
+ synopsis = open(readme).next()
+ print options.format_opt(tempname, synopsis)
+
+ print "\nTemplates are used via the 'init' command, e.g.:"
+ print "\n alembic init --template pylons ./scripts"
+
+def init(opts):
"""Initialize a new scripts directory."""
- script = ScriptDirectory(options)
- script.init()
+ dir_, = opts.get_command_args(1, 'alembic init <directory>')
+ if not _status("Checking for directory %s" % dir_,
+ os.access, dir_, os.F_OK):
+ _status("Creating directory %s" % dir_,
+ os.makedirs, dir_)
+ else:
+ opts.err("Directory %s already exists" % dir_)
+ # copy files...
-def upgrade(options):
+def upgrade(opts):
"""Upgrade to the latest version."""
- script = ScriptDirectory(options)
+ script = ScriptDirectory.from_options(opts)
# ...
-def revert(options, file_config):
+def revert(opts):
"""Revert to a specific previous version."""
- script = ScriptDirectory(options)
+ script = ScriptDirectory.from_options(opts)
# ...
+def history(opts):
+ """List changeset scripts in chronological order."""
+
+ script = ScriptDirectory.from_options(opts)
+
+def splice(opts):
+ """'splice' two branches, creating a new revision file."""
+
+def revision(opts):
+ """Create a new revision file."""
+
+def branches(opts):
+ """Show current un-spliced branch points"""
\ No newline at end of file
from optparse import OptionParser
import ConfigParser
-import textwrap
+import inspect
+import os
+import sys
+def format_opt(opt, hlp, padding=22):
+ return " " + opt + \
+ ((padding - len(opt)) * " ") + hlp
+
def get_option_parser():
+ from alembic import command
+
# TODO:
# OK, what's the super option parser library that
# allows <command> plus command-specfic sub-options ?
+ # we're inventing here a bit.
+
+ commands = [
+ (fn.__name__.replace('_', '-'), fn.__doc__) for fn in
+ [getattr(command, name) for name in sorted(dir(command))]
+ if inspect.isfunction(fn) and
+ fn.__name__[0] != '_' and
+ fn.__module__ == 'alembic.command'
+ ]
- # TODO: pull the commands from command.py directly here
parser = OptionParser(
- "usage: %prog [options] <command>\n\n"
- "Available Commands:\n"
- " list-templates\n"
- " init\n"
- " revision\n"
- " upgrade\n"
- " revert\n"
- " history\n"
- " splice\n"
- " branches"
+ "usage: %prog [options] <command> [command arguments]\n\n"
+ "Available Commands:\n" +
+ "\n".join([
+ format_opt(cmd, hlp)
+ for cmd, hlp in commands
+ ])
)
parser.add_option("-c", "--config",
type="string",
default="alembic.ini",
help="Alternate config file")
parser.add_option("-t", "--template",
+ default='generic',
type="string",
help="Setup template for use with 'init'")
- parser.add_option("-r", "--rev",
+ parser.add_option("-m", "--message",
type="string",
- help="Revsion identifier for usage with 'revert'"
- )
+ help="Message string to use with 'revision'")
return parser
class Options(object):
- def __init__(self, cmd_line_options):
- self.cmd_line_options = cmd_line_options
+ def __init__(self, parser, argv):
+ self.parser = parser
+ self.cmd_line_options, \
+ self.cmd_line_args = parser.parse_args(argv[1:])
+ if len(self.cmd_line_args) < 1:
+ self.err("no command specified")
+ self.config_file_name = self.cmd_line_options.config
self.file_config = ConfigParser.ConfigParser()
- # TODO: cfg file can come from options
- self.file_config.read(['alembic.cfg'])
+ self.file_config.read([self.config_file_name])
+ def get_command(self):
+ return self.cmd_line_args[0]
+
+ def get_command_args(self, count, err):
+ if len(self.cmd_line_args[1:]) != count:
+ self.err(
+ "Command %r syntax: %r" %
+ (self.get_command(), err))
+ return self.cmd_line_args[1:]
+
+ def get_template_directory(self):
+ # TODO: what's the official way to get at
+ # setuptools-installed datafiles ?
+ return os.path.join(os.path.dirname(__file__), '..', 'templates')
+
def get_section(self, name):
return dict(self.file_config.items(name))
+
+ def err(self, msg):
+ sys.stderr.write(msg + "\n")
+ sys.exit(-1)
def get_main_option(self, name, default=None):
+ if not self.file_config.has_section('alembic'):
+ self.err("No config file %r found, or file has no "
+ "'[alembic]' section" % self.config_file_name)
if self.file_config.get('alembic', name):
return self.file_config.get('alembic', name)
else: