Source for update/updater.py

2011-06-29 15:17:46 / 5.1 Kt

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# -*- coding: utf-8 -*-
"The database update main procedure."

__copyright__ = """
Database updater script.
Copyright (C) 2010, 2011  Jyrki Launonen

This file is part of slavemaster.

Slavemaster is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Slavemaster is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Slavemaster.  If not, see <http://www.gnu.org/licenses/>.
"""

# Must be run from project root with command:
#  python -m update.updater
from update import uc


def findFromVersion():
   "Try to find current version number."
   try:
      verinfo = __import__("version", globals(), locals(), ['VERSION'])
      return verinfo.VERSION
   except ImportError:
      print "updater: Current db-version information (../version.py) could not be found!"
      print "         Please write following information in mentioned file:"
      print "  VERSION=\"xxx.yyy\""
      print "         xxx.yyy is version number of installed database/software, like \"0.2\"."
      print "         Then run this tool again..."
   return None


def getMod(start, what):
   "Search 'what'-version starting from uc'start'-module."
   while True:
      try:
         module = __import__("update.uc%i" % start, [], [], ['MAP'])
      except ImportError, ex:
         # No module that had this version. Error?
         print ex
         return start, None

      if what in module.MAP:
         return start + 1, module
      start += 1
   #


def findLast(module_index):
   "Find last existing version number or None if it is not in this module."
   module = __import__("update.uc%i" % module_index, [], [], ['MAP'])
   for key, value in module.MAP.iteritems():
      if value is None:
         # Reached end.
         return key
      if value is uc.NEXT:
         # Reached tag "Next module"
         return None
   
   raise KeyError, "Erroneous line of updates - "\
      "could not find latest version number."


def execSQL(sql):
   "Exec given sql statements (separately) and commit them."
   from django.db import connection, transaction
   cursor = connection.cursor() #@UndefinedVariable

   # Data modifying operation - commit required
   for statement in sql.split(";"):
      statement = statement.strip()
      if statement == "":
         continue
      print("## %s;" % statement) #DEBUG :)
      cursor.execute("%s;" % statement)
   transaction.commit_unless_managed()
#


def main():
   "Main entry point."
   import os
   
   # Declare settings module..
   if "DJANGO_SETTINGS_MODULE" not in os.environ:
      os.environ["DJANGO_SETTINGS_MODULE"] = "slavemaster.settings"
   
   # Keep deleted tables so update can do its job
   os.environ["KEEP_DJANGO_TABLES"] = "1"
   
   import sys
   if len(sys.argv) == 2 and sys.argv[1] == "--generate-version":
      module_index = 0
      name = findLast(module_index)
      
      while name is None:
         module_index += 1
         name = findLast(module_index)
      
      print "VERSION=\"%s\"" % name
      exit(0)
   

   fromversion = findFromVersion()
   if fromversion is None:
      exit(1)

   module_index, detmod = getMod(0, fromversion)
   if detmod is None:
      print "updater: No update information found. Probably in latest state..."
      exit(0)

   
   anyUpdate = False
   current = fromversion
   while True:
      tgt = detmod.MAP[current]
      if tgt is None:
         if anyUpdate:
            print " * Reached %s. Updating 'current version'..." % current
            try:
               vdb = open("version.py", "w")
               vdb.write("VERSION=\"%s\"\n" % current)
               vdb.close()
            except IOError:
               print "updater: Failed to write 'version.py'. Please replace its"
               print "         contents with following line:"
               print "VERSION=\"%s\"" % current
            #
         break

      if tgt is not uc.NEXT:
         mod = tgt[0]
         modi = mod()

         if not modi.preCondition():
            print " * Skipping %s.%s" % (mod.__module__, mod.__name__)

         else:
            print " * Updating from %s to %s with %s" % (
               current,
               tgt[1],
               "%s.%s" % (mod.__module__, mod.__name__)
            )

            modi.preCommands()

            for cmdblob in modi.getCommands():
               execSQL(cmdblob)

            modi.postCommands()
            anyUpdate = True

         current = tgt[1]

      else:
         # Import different module.
         module_index, detmod = getMod(module_index, current)
         if detmod is None:
            print "updater: Lost track of versions!"
            exit(1)
         #
      #

   if not anyUpdate:
      print "updater: Already in latest state. No update performed."
   else:
      print "updater: All done."
   #

if __name__ == "__main__":
   main()