]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
we're making revision files....
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 27 Apr 2010 23:13:55 +0000 (19:13 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 27 Apr 2010 23:13:55 +0000 (19:13 -0400)
alembic/command.py
alembic/op.py
alembic/script.py
alembic/util.py
templates/generic/script.py.mako
templates/multidb/script.py.mako
templates/pylons/script.py.mako

index 8278d6e3914965ecf6ea97da06817c57d901e96d..de3f27e244a18368fc89ddb4d6c069836141267a 100644 (file)
@@ -28,6 +28,10 @@ def init(opts):
 
     util.status("Creating directory %s" % os.path.abspath(dir_),
                 os.makedirs, dir_)
+    
+    versions = os.path.join(dir_, 'versions')
+    util.status("Creating directory %s" % os.path.abspath(versions),
+                os.makedirs, versions)
 
     script = ScriptDirectory(dir_, opts)
 
@@ -61,7 +65,7 @@ def revision(opts):
     """Create a new revision file."""
 
     script = ScriptDirectory.from_options(opts)
-    script.generate_rev(uuid.uuid4())
+    script.generate_rev(uuid.uuid4(), opts.cmd_line_options.message)
     
 def upgrade(opts):
     """Upgrade to the latest version."""
index 16fc1ab71b0c7648144503416f6e2427d33a3492..ebd4b56f49982a1b1e95b8b10b1cf93787fa36c5 100644 (file)
@@ -2,7 +2,7 @@ from alembic import util
 from sqlalchemy.types import NULLTYPE
 from sqlalchemy import schema
 
-__all__ = ['alter_column', 'add_foreign_key']
+__all__ = ['alter_column', 'create_foreign_key', 'create_unique_constraint']
 
 def alter_column(table_name, column_name, 
                     nullable=util.NO_VALUE,
index 8cac6917cbfe83447d1e908571be09565e75d43a..ddd8ea5f23322a78daf6c8e9c2f8821178b0a9a6 100644 (file)
@@ -4,13 +4,19 @@ import shutil
 import re
 import inspect
 
-_uuid_re = re.compile(r'[a-z0-9]{16}')
-_mod_def_re = re.compile(r'(upgrade|downgrade)_([a-z0-9]{16})')
+_uuid_re = re.compile(r'[a-z0-9]{32}\.py$')
+_mod_def_re = re.compile(r'(upgrade|downgrade)_([a-z0-9]{32})')
 
 class ScriptDirectory(object):
     def __init__(self, dir, options):
         self.dir = dir
-        self.options = otions
+        self.versions = os.path.join(self.dir, 'versions')
+        
+        if not os.access(dir, os.F_OK):
+            options.err("Path doesn't exist: %r.  Please use "
+                        "the 'init' command to create a new "
+                        "scripts folder." % dir)
+        self.options = options
         
     @classmethod
     def from_options(cls, options):
@@ -20,22 +26,32 @@ class ScriptDirectory(object):
 
     @util.memoized_property
     def _revision_map(self):
-        for file_ in os.listdir(self.dir):
-            script = Script.from_file(self.dir, file_)
+        map_ = {}
+        for file_ in os.listdir(self.versions):
+            script = Script.from_path(self.versions, file_)
             if script is None:
                 continue
+            if script.upgrade in map_:
+                util.warn("Revision %s is present more than once" % script.upgrade)
             map_[script.upgrade] = script
+        for rev in map_.values():
+            if rev.downgrade is None:
+                continue
+            if rev.downgrade not in map_:
+                util.warn("Revision %s referenced from %s is not present"
+                            % (rev.downgrade, rev))
+                rev.downgrade = None
+            else:
+                map_[rev.downgrade].nextrev = rev.upgrade
         return map_
     
-    def _get_head(self):
+    def _get_heads(self):
         # TODO: keep map sorted chronologically
-        
+        heads = []
         for script in self._revision_map.values():
-            if script.upgrade is None \
-                and script.downgrade in self._revision_map:
-                return script
-        else:
-            return None
+            if script.nextrev is None:
+                heads.append(script)
+        return heads
     
     def _get_origin(self):
         # TODO: keep map sorted chronologically
@@ -48,7 +64,7 @@ class ScriptDirectory(object):
             return None
         
     def generate_template(self, src, dest, **kw):
-        util.status("Generating %s" % os.path.abspath(src),
+        util.status("Generating %s" % os.path.abspath(dest),
             util.template_to_file,
             src, 
             dest,
@@ -59,18 +75,26 @@ class ScriptDirectory(object):
         util.status("Generating %s" % os.path.abspath(dest), 
                     shutil.copy, 
                     src, dest)
-        
     
-    def generate_rev(self, revid):
-        current_head = self._get_head()
+    def generate_rev(self, revid, message):
+        current_heads = self._get_heads()
+        if len(current_heads) > 1:
+            raise Exception("Only a single head supported so far...")
+        if current_heads:
+            current_head = current_heads[0]
+        else:
+            current_head = None
         self.generate_template(
-            os.path.join(self.dir, "script.py.mako", 
-                up_revision=revid,
-                down_revision=current_head.upgrade if current_head else None
-            )
+            os.path.join(self.dir, "script.py.mako"),
+            os.path.join(self.versions, "%s.py" % revid.hex), 
+            up_revision=str(revid.hex),
+            down_revision=current_head.upgrade if current_head else None,
+            message=message if message is not None else ("Alembic revision %s" % revid.hex)
         )
         
 class Script(object):
+    nextrev = None
+    
     def __init__(self, module):
         self.module = module
         self.upgrade = self.downgrade = None
@@ -87,12 +111,16 @@ class Script(object):
                 self.downgrade = m.group(2)
         if not self.downgrade and not self.upgrade:
             raise Exception("Script %s has no upgrade or downgrade path" % module)
-            
+    
+    def __str__(self):
+        return "revision %s" % self.upgrade
+        
     @classmethod
     def from_path(cls, dir_, filename):
         if not _uuid_re.match(filename):
             return None
-
+        
+        print "LOAD PYTHON FILE", filename
         module = util.load_python_file(dir_, filename)
         return Script(module)
         
\ No newline at end of file
index df5bfd895a6550ab142189ae93a13d182d0406cf..b065ef92f872a7bced858bad20cbb928fc7c3e19 100644 (file)
@@ -4,6 +4,8 @@ import os
 import textwrap
 from sqlalchemy import util
 import imp
+import warnings
+import re
 
 NO_VALUE = util.symbol("NO_VALUE")
 
@@ -24,8 +26,8 @@ def format_opt(opt, hlp, padding=22):
     return "  " + opt + \
         ((padding - len(opt)) * " ") + hlp
 
-def status(message, fn, *arg, **kw):
-    msg(message + "...", False)
+def status(_statmsg, fn, *arg, **kw):
+    msg(_statmsg + "...", False)
     try:
         ret = fn(*arg, **kw)
         sys.stdout.write("done\n")
@@ -34,7 +36,9 @@ def status(message, fn, *arg, **kw):
         sys.stdout.write("FAILED\n")
         raise
 
-
+def warn(msg):
+    warnings.warn(msg)
+    
 def msg(msg, newline=True):
     lines = textwrap.wrap(msg, width)
     if len(lines) > 1:
index 596027f30102835e1993e6746187b65ed608dd02..509194640589f1504706a73c42d5fb6b516710b1 100644 (file)
@@ -1,3 +1,5 @@
+"""${message}"""
+
 from alembic.op import *
 
 def upgrade_${up_revision}():
index 112b0269457fcb5f8cbad0277b386671b5f3a7c0..2aebeb6007a90ae1178012301bfdf73c8399a10f 100644 (file)
@@ -1,3 +1,5 @@
+"""${message}"""
+
 from alembic.op import *
 
 def upgrade_${up_revision}(engine):
index 596027f30102835e1993e6746187b65ed608dd02..509194640589f1504706a73c42d5fb6b516710b1 100644 (file)
@@ -1,3 +1,5 @@
+"""${message}"""
+
 from alembic.op import *
 
 def upgrade_${up_revision}():