root/galaxy-central/eggs/sqlalchemy_migrate-0.5.4-py2.6.egg/migrate/versioning/version.py @ 3

リビジョン 3, 6.5 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import os
5import re
6import shutil
7
8from migrate.versioning import exceptions, pathed, script
9
10
11class VerNum(object):
12    """A version number"""
13
14    _instances = dict()
15
16    def __new__(cls, value):
17        val = str(value)
18        if val not in cls._instances:
19            cls._instances[val] = super(VerNum, cls).__new__(cls)
20        ret = cls._instances[val]
21        return ret
22
23    def __init__(self,value):
24        self.value = str(int(value))
25        if self < 0:
26            raise ValueError("Version number cannot be negative")
27
28    def __add__(self, value):
29        ret = int(self) + int(value)
30        return VerNum(ret)
31
32    def __sub__(self, value):
33        return self + (int(value) * -1)
34
35    def __cmp__(self, value):
36        return int(self) - int(value)
37
38    def __repr__(self):
39        return "<VerNum(%s)>" % self.value
40
41    def __str__(self):
42        return str(self.value)
43
44    def __int__(self):
45        return int(self.value)
46
47
48class Collection(pathed.Pathed):
49    """A collection of versioning scripts in a repository"""
50
51    FILENAME_WITH_VERSION = re.compile(r'^(\d{3,}).*')
52
53    def __init__(self, path):
54        """Collect current version scripts in repository"""
55        super(Collection, self).__init__(path)
56       
57        # Create temporary list of files, allowing skipped version numbers.
58        files = os.listdir(path)
59        if '1' in files:
60            # deprecation
61            raise Exception('It looks like you have a repository in the old '
62                'format (with directories for each version). '
63                'Please convert repository before proceeding.')
64
65        tempVersions = dict()
66        for filename in files:
67            match = self.FILENAME_WITH_VERSION.match(filename)
68            if match:
69                num = int(match.group(1))
70                tempVersions.setdefault(num, []).append(filename)
71            else:
72                pass  # Must be a helper file or something, let's ignore it.
73
74        # Create the versions member where the keys
75        # are VerNum's and the values are Version's.
76        self.versions = dict()
77        for num, files in tempVersions.items():
78            self.versions[VerNum(num)] = Version(num, path, files)
79
80    @property
81    def latest(self):
82        return max([VerNum(0)] + self.versions.keys())
83
84    def create_new_python_version(self, description, **k):
85        """Create Python files for new version"""
86        ver = self.latest + 1
87        extra = str_to_filename(description)
88
89        if extra:
90            if extra == '_':
91                extra = ''
92            elif not extra.startswith('_'):
93                extra = '_%s' % extra
94
95        filename = '%03d%s.py' % (ver, extra)
96        filepath = self._version_path(filename)
97
98        if os.path.exists(filepath):
99            raise Exception('Script already exists: %s' % filepath)
100        else:
101            script.PythonScript.create(filepath)
102
103        self.versions[ver] = Version(ver, self.path, [filename])
104       
105    def create_new_sql_version(self, database, **k):
106        """Create SQL files for new version"""
107        ver = self.latest + 1
108        self.versions[ver] = Version(ver, self.path, [])
109
110        # Create new files.
111        for op in ('upgrade', 'downgrade'):
112            filename = '%03d_%s_%s.sql' % (ver, database, op)
113            filepath = self._version_path(filename)
114            if os.path.exists(filepath):
115                raise Exception('Script already exists: %s' % filepath)
116            else:
117                open(filepath, "w").close()
118            self.versions[ver].add_script(filepath)
119       
120    def version(self, vernum=None):
121        """Returns latest Version if vernum is not given. \
122        Otherwise, returns wanted version"""
123        if vernum is None:
124            vernum = self.latest
125        return self.versions[VerNum(vernum)]
126
127    @classmethod
128    def clear(cls):
129        super(Collection, cls).clear()
130
131    def _version_path(self, ver):
132        """Returns path of file in versions repository"""
133        return os.path.join(self.path, str(ver))
134
135
136class Version(object):
137    """A single version in a collection """
138
139    def __init__(self, vernum, path, filelist):
140        self.version = VerNum(vernum)
141
142        # Collect scripts in this folder
143        self.sql = dict()
144        self.python = None
145
146        for script in filelist:
147            self.add_script(os.path.join(path, script))
148   
149    def script(self, database=None, operation=None):
150        """Returns SQL or Python Script"""
151        for db in (database, 'default'):
152            # Try to return a .sql script first
153            try:
154                return self.sql[db][operation]
155            except KeyError:
156                continue  # No .sql script exists
157
158        # TODO: maybe add force Python parameter?
159        ret = self.python
160
161        assert ret is not None
162        return ret
163
164    # deprecated?
165    @classmethod
166    def create(cls, path):
167        os.mkdir(path)
168        # create the version as a proper Python package
169        initfile = os.path.join(path, "__init__.py")
170        if not os.path.exists(initfile):
171            # just touch the file
172            open(initfile, "w").close()
173        try:
174            ret = cls(path)
175        except:
176            os.rmdir(path)
177            raise
178        return ret
179
180    def add_script(self, path):
181        """Add script to Collection/Version"""
182        if path.endswith(Extensions.py):
183            self._add_script_py(path)
184        elif path.endswith(Extensions.sql):
185            self._add_script_sql(path)
186
187    SQL_FILENAME = re.compile(r'^(\d+)_([^_]+)_([^_]+).sql')
188
189    def _add_script_sql(self, path):
190        match = self.SQL_FILENAME.match(os.path.basename(path))
191
192        if match:
193            version, dbms, op = match.group(1), match.group(2), match.group(3)
194        else:
195            raise exceptions.ScriptError("Invalid SQL script name %s" % path)
196
197        # File the script into a dictionary
198        self.sql.setdefault(dbms, {})[op] = script.SqlScript(path)
199
200    def _add_script_py(self, path):
201        if self.python is not None:
202            raise Exception('You can only have one Python script per version,'
203                ' but you have: %s and %s' % (self.python, path))
204        self.python = script.PythonScript(path)
205
206class Extensions:
207    """A namespace for file extensions"""
208    py = 'py'
209    sql = 'sql'
210
211def str_to_filename(s):
212    """Replaces spaces, (double and single) quotes
213    and double underscores to underscores
214    """
215
216    s = s.replace(' ', '_').replace('"', '_').replace("'", '_')
217    while '__' in s:
218        s = s.replace('__', '_')
219    return s
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。