]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
commands
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 25 Apr 2010 15:26:02 +0000 (11:26 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 25 Apr 2010 15:26:02 +0000 (11:26 -0400)
alembic/__init__.py
alembic/command.py
alembic/options.py
alembic/script.py
scripts/alembic
templates/generic/README [new file with mode: 0644]
templates/multidb/README [new file with mode: 0644]
templates/pylons/README [new file with mode: 0644]

index 304c26b251329a9b130b545edf1d8308bd25f46c..649da28b527bae710368f42035fcf501f4602caa 100644 (file)
@@ -1,4 +1,18 @@
-from command import main
+from alembic import options, command
 
 __version__ = '0.1alpha'
 
+
+
+def main(argv):
+
+    parser = options.get_option_parser()
+
+    opt = options.Options(parser, argv)
+    cmd = opt.get_command().replace('-', '_')
+    if cmd not in dir(command):
+        parser.error("no such command %r" % cmd)
+    getattr(command, cmd)(opt)
+
+
+
index 8fdc9a45d80c6c30f5e37fefa56b1156d6a60846..7334dd76abdbb7f323a31b3acf4243ac340fa9fe 100644 (file)
@@ -1,36 +1,69 @@
 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
index 1749400bfad5d3933af71841941b4bf53a3015b7..715f31391ebe11f652dc580a42dc8886a5da3d39 100644 (file)
@@ -1,49 +1,87 @@
 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:
index 1bdd02f41b29bcfdeabb17756f459518d9ecea91..3085d450c922161ce70b09b14bc40f4b19018b11 100644 (file)
@@ -5,10 +5,6 @@ class ScriptDirectory(object):
         self.dir = dir
         
     @classmethod
-    def from_options(cls, options, file_config):
-        return Script(file_config.get_main_option('script_location'))
+    def from_options(cls, options):
+        return ScriptDirectory(options.get_main_option('script_location'))
 
-    def init(self):
-        if not os.access(self.dir, os.F_OK):
-            os.makedirs(self.dir)
-        # copy files...
index 65d7e02a00f5ecf11b946e1abb69e21527bb1de5..191cc29d92fe97f3280bb53fec048ec086ccfe2a 100755 (executable)
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 
-from alembic import command
+from alembic import main
 import sys
 
 if __name__ == "__main__":
-    command.main(sys.argv)
+    main(sys.argv)
 
diff --git a/templates/generic/README b/templates/generic/README
new file mode 100644 (file)
index 0000000..98e4f9c
--- /dev/null
@@ -0,0 +1 @@
+Generic single-database configuration.
\ No newline at end of file
diff --git a/templates/multidb/README b/templates/multidb/README
new file mode 100644 (file)
index 0000000..5db219f
--- /dev/null
@@ -0,0 +1 @@
+Rudimentary multi-database configuration.
\ No newline at end of file
diff --git a/templates/pylons/README b/templates/pylons/README
new file mode 100644 (file)
index 0000000..ed3c28e
--- /dev/null
@@ -0,0 +1 @@
+Configuration that reads from a Pylons project environment.
\ No newline at end of file