Package Camelot :: Package camelot :: Package bin :: Module camelot_manage
[frames] | no frames]

Source Code for Module Camelot.camelot.bin.camelot_manage

  1  #  ============================================================================
 
  2  #
 
  3  #  Copyright (C) 2007-2008 Conceptive Engineering bvba. All rights reserved.
 
  4  #  www.conceptive.be / project-camelot@conceptive.be
 
  5  #
 
  6  #  This file is part of the Camelot Library.
 
  7  #
 
  8  #  This file may be used under the terms of the GNU General Public
 
  9  #  License version 2.0 as published by the Free Software Foundation
 
 10  #  and appearing in the file LICENSE.GPL included in the packaging of
 
 11  #  this file.  Please review the following information to ensure GNU
 
 12  #  General Public Licensing requirements will be met:
 
 13  #  http://www.trolltech.com/products/qt/opensource.html
 
 14  #
 
 15  #  If you are unsure which license is appropriate for your use, please
 
 16  #  review the following information:
 
 17  #  http://www.trolltech.com/products/qt/licensing.html or contact
 
 18  #  project-camelot@conceptive.be.
 
 19  #
 
 20  #  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
 21  #  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
 22  #
 
 23  #  For use of this library in commercial applications, please contact
 
 24  #  project-camelot@conceptive.be
 
 25  #
 
 26  #  ============================================================================
 
 27  
 
 28  from optparse import OptionParser 
 29  from code import InteractiveConsole 
 30  import sys 
 31  
 
 32  #
 
 33  # Description of the application, out of which the help text as well as the
 
 34  # __doc__ strings can be generated
 
 35  #
 
 36  
 
 37  usage = "usage: %prog [options] command" 
 38  
 
 39  description = """
 
 40  camelot_manage is oriented towards administrators of an installed
 
 41  camelot application. It is used for interacting the database, the model
 
 42  and migration of the database to a certain schema revision.
 
 43  
 
 44  To use this application, PYTHONPATH should contain a valid settings.py file that
 
 45  will be used to resolve the database engine and the model.
 
 46  """ 
 47  
 
 48  command_description = [
 
 49      ('console', """Launches a python console with the model all setup for command line
 
 50  interaction.
 
 51  
 
 52  Within the example movie project one could do
 
 53  the following to print a list of all movie titles to the screen::
 
 54  
 
 55      from model import Movie
 
 56      for movie in Movie.query.all():
 
 57      print movie.title
 
 58  """),
 
 59      ('db_version', """Get the version of the database schema from the current database"""),
 
 60  
 
 61      ('version', """Get the latest available database schema version"""),
 
 62  
 
 63      ('upgrade', """Upgrade or downgrade the database to the specified version, use upgrade version_number."""),
 
 64  
 
 65      ('version_control', """Put the database under version control"""),
 
 66     
 
 67      ('schema_display', """Generate a graph of the database schema.  The result is stored in schema.png.  This
 
 68  option requires pydot to be installed."""),
 
 69  ] 
 70  
 
 71  #
 
 72  # Generate a docstring in restructured text format
 
 73  #
 
 74  
 
 75  __doc__ = description 
 76  
 
 77  for command, desc in command_description: 
 78      __doc__ += "\n.. cmdoption:: %s\n\n"%command 
 79      for line in desc.split('\n'): 
 80          __doc__ += "    %s\n"%line 
 81  
 
 82  __doc__ += """
 
 83     .. image:: ../_static/schema.png
 
 84        :width: 400""" 
 85  
 
 86  #
 
 87  # A custom OptionParser that generates help information on the commands
 
 88  #
 
89 -class CommandOptionParser(OptionParser):
90
91 - def format_help(self, formatter=None):
92 command_help = """ 93 The available commands are : 94 95 """ 96 command_help += '\n\n'.join(['%s\n%s\n%s'%(command,'-'*len(command), desc) for command,desc in command_description]) 97 command_help += """ 98 99 For the creation and development of Camelot projects, see camelot_admin 100 101 """ 102 return OptionParser.format_help(self) + ''.join(command_help)
103
104 -class FileCacher:
105 "Cache the stdout text so we can analyze it before returning it"
106 - def __init__(self): self.reset()
107 - def reset(self): self.out = []
108 - def write(self,line): self.out.append(line)
109 - def flush(self):
110 output = '\n'.join(self.out) 111 self.reset() 112 return output
113
114 -class Shell(InteractiveConsole):
115 "Wrapper around Python that can filter input/output to the shell"
116 - def __init__(self, locals={}):
117 self.stdout = sys.stdout 118 self.cache = FileCacher() 119 InteractiveConsole.__init__(self, locals) 120 return
121 - def get_output(self): sys.stdout = self.cache
122 - def return_output(self): sys.stdout = self.stdout
123 - def push(self,line):
124 line = line.replace('\r','') 125 self.get_output() 126 # you can filter input here by doing something like 127 # line = filter(line) 128 InteractiveConsole.push(self,line) 129 self.return_output() 130 output = self.cache.flush() 131 # you can filter the output here by doing something like 132 # output = filter(output) 133 print output # or do something else with it 134 return
135
136 -def schema_display(image_path='schema.png'):
137 from camelot.core.schema_display import create_uml_graph 138 from sqlalchemy import orm 139 from elixir import entities 140 mappers = [orm.class_mapper(e) for e in entities] 141 graph = create_uml_graph(mappers, 142 show_operations=False, # not necessary in this case 143 show_multiplicity_one=False # some people like to see the ones, some don't 144 ) 145 graph.write_png(image_path)
146
147 -def setup_model():
148 import settings 149 settings.setup_model()
150
151 -def main():
152 import camelot 153 parser = CommandOptionParser(usage=usage, 154 description=description, 155 version=camelot.__version__) 156 (_options, args) = parser.parse_args() 157 if not args: 158 parser.print_help() 159 elif args[0]=='console': 160 setup_model() 161 sh = Shell() 162 sh.interact() 163 elif args[0]=='schema_display': 164 setup_model() 165 schema_display() 166 elif args[0] in ('version_control', 'db_version', 'version', 'upgrade'): 167 import settings 168 from migrate.versioning.repository import Repository 169 from migrate.versioning.schema import ControlledSchema 170 from sqlalchemy.exceptions import NoSuchTableError 171 migrate_engine = settings.ENGINE() 172 repository = Repository(settings.REPOSITORY) 173 schema = None 174 if args[0]=='version_control': 175 migrate_connection = migrate_engine.connect() 176 transaction = migrate_connection.begin() 177 try: 178 schema = ControlledSchema.create(migrate_engine, repository) 179 transaction.commit() 180 except: 181 transaction.rollback() 182 raise 183 finally: 184 migrate_connection.close() 185 print 'database was put under version control' 186 try: 187 schema = ControlledSchema(migrate_engine, repository) 188 except NoSuchTableError: 189 print 'database not yet under version control, use the version_control command first.' 190 if schema: 191 if args[0]=='db_version': 192 print schema.version 193 elif args[0]=='version': 194 print repository.latest 195 elif args[0]=='upgrade': 196 migrate_connection = migrate_engine.connect() 197 if len(args)>=2: 198 version = int(args[1]) 199 else: 200 version = repository.latest 201 # 202 # perform each upgrade step in a separate transaction, since 203 # one upgrade might depend on an other being fully executed 204 # 205 try: 206 if schema.version == version: 207 print 'database is allready at requested version' 208 if schema.version <= version: 209 step = 1 210 else: 211 step = -1 212 for i in range(schema.version+step, version+step, step): 213 transaction = migrate_connection.begin() 214 try: 215 schema.upgrade(i) 216 transaction.commit() 217 if step==1: 218 print 'upgrade %s'%i 219 else: 220 print 'downgrade %s'%i 221 except: 222 transaction.rollback() 223 raise 224 finally: 225 migrate_connection.close() 226 else: 227 parser.print_help()
228 229 if __name__ == '__main__': 230 main() 231