#! /usr/bin/env python
# -*- coding: iso-8859-1 -*-
#-----------------------------------------------------------------------------
# Modeling Framework: an Object-Relational Bridge for python
#
# Copyright (c) 2001-2004 Sbastien Bigaret <sbigaret@users.sourceforge.net>
# All rights reserved.
#
# This file is part of the Modeling Framework.
#
# This code is distributed under a "3-clause BSD"-style license;
# see the LICENSE file for details.
#-----------------------------------------------------------------------------
"""
TBD docstring
"""
__version__='$Revision: 945 $'[11:-2]
from Modeling.SchemaGeneration import SchemaGeneration,\
DropPrimaryKeySupportKey, DropForeignKeyConstraintsKey, \
DropPrimaryKeyConstraintsKey, DropTablesKey, DropDatabaseKey, \
CreateDatabaseKey, CreateTablesKey, PrimaryKeyConstraintsKey, \
ForeignKeyConstraintsKey, CreatePrimaryKeySupportKey
import getopt, sys, time
def log(msg):
if verbose:
sys.stderr.write(msg+'\n')
err=lambda msg: sys.stderr.write(msg+'\n')
def tracebackInfoFromStack(exc_traceback):
"""
"""
from traceback import extract_tb,format_list
from Modeling.utils import isListOrTuple
tb=None
str='%s\n%s\n'%sys.exc_info()[:2]
try:
tb=sys.exc_info()[-1]
str+=reduce(lambda a,b: a+b, format_list(extract_tb(tb)))
return str
finally:
del tb
def databaseSchemaWithOptions(model,
options={},
administrativeConnectionDictionary={},
onlyStatements=0, continue_on_errors=0,
endStatementWith=';',
createUser=0, dropUser=0):
from traceback import format_list
#print str(options), options.__class__, dir(options)
from Modeling import Adaptor
adaptor=Adaptor.adaptorWithModel(model)
str=''
if options.get(DropDatabaseKey) and not onlyStatements:
log('Drop Database...');
try:
adaptor.dropDatabaseWithAdministrativeConnectionDictionary(administrativeConnectionDictionary, dropUser)
time.sleep(1)
except:
err('Drop Database FAILED\nReason:\n')
err(tracebackInfoFromStack(sys.exc_traceback))
if not continue_on_errors: return
else:
log(' OK')
if options.get(CreateDatabaseKey) and not onlyStatements:
log('Creating Database...')
try:
adaptor.createDatabaseWithAdministrativeConnectionDictionary(administrativeConnectionDictionary, createUser)
except:
err('Create Database FAILED\nReason:')
err(tracebackInfoFromStack(sys.exc_traceback))
if not continue_on_errors: return
else:
log(' OK')
schemaGeneration = adaptor.schemaGenerationFactory()
sqlExprs=schemaGeneration.schemaCreationStatementsForEntities(model.entities(), options)
if onlyStatements:
for sqlExpr in sqlExprs:
str+='%s%s\n'%(sqlExpr.statement(),endStatementWith)
else:
context=adaptor.createAdaptorContext()
channel=context.createAdaptorChannel()
for sqlExpr in sqlExprs:
try:
log(sqlExpr.statement())
channel.evaluateExpression(sqlExpr)
except Exception, exc:
err('FAILED to execute: %s\nReason:'%sqlExpr.statement())
err(tracebackInfoFromStack(sys.exc_traceback))
if not continue_on_errors: break
else:
log(' OK')
if channel.isOpen():
channel.closeChannel()
return str
def usage(prgName):
_usage="""
%s [options] command(s) model.(xml|py)
Generates and/or executes the SQL code from a model, either an xml file or a
PyModel.
General options
---------------
-c --stdout write the SQL statements on stdout, do not execute them
-e --end-with <str> appends <str> to each statement when option -c is
enabled (it has no effect otherwise). Default is ';'
-v --verbose verbose mode
-h --help gives this help
-i --ignore-errors ignore database errors (default is halt on error)
-f --force By default, the script stops if the model has errors.
Setting this flag makes the script ignores the errors:
use at your own risks and expect errors to happen!
Commands for DB-schema generation
---------------------------------
Most commonly used commands:
-A --all-but-database Drops and recreate everything except the database
itself. Equivalent to: -T -t -P -p -S -s -F -f
-C --create-database Create the database from scratch
Equivalent to: -d -T -P -S -F
-R --recreate-database Drop the database and recreate it from scratch
Equivalent to: -D -d -T -P -S -F
Last two options require '--admin-dsn' to be set as well (see below)
Additionally, the following commands are available:
-D drop database (requires --admin-dsn)
-d create database (requires --admin-dsn)
-t drop tables
-T create tables
-p drop primary key constraints
-P create primary key constraints
-s drop primary key supports
-S create primary key supports
-f drop foreign key constraints
-F create foreign key constraints
Note: each of the 3 commands -A -C and -R (and their corresponding long
options) discard any other commands that appear before.
Example: '-D -C' is equivalent to '-C', and '-C -D' is equivalent to '-R'
Connecting to the database
--------------------------
DSNs can be specified on the command-line as well. Valid DSNs are:
<hostname>:<database>:<user>:<password>
or <hostname>:<port>:<database>:<user>:<password>
--dsn overrides the connection dictionary stored in the model
--admin-dsn specifies the administrative DSN. It is required when one of
the following options are used: -C, -R, -D and/or -d
""" % prgName
sys.stderr.write(_usage)
# Global variables
verbose=to_stdout=continue_on_errors=0
_defaultOptions={
DropPrimaryKeySupportKey : 0,
DropForeignKeyConstraintsKey : 0,
DropPrimaryKeyConstraintsKey : 0,
DropTablesKey : 0,
DropDatabaseKey : 0,
CreateDatabaseKey : 0,
CreateTablesKey : 0,
PrimaryKeyConstraintsKey : 0,
ForeignKeyConstraintsKey : 0,
CreatePrimaryKeySupportKey : 0,
}
_all_but_database_options={
DropPrimaryKeySupportKey : 1,
DropForeignKeyConstraintsKey : 1,
DropPrimaryKeyConstraintsKey : 1,
DropTablesKey : 1,
DropDatabaseKey : 0,
CreateDatabaseKey : 0,
CreateTablesKey : 1,
PrimaryKeyConstraintsKey : 1,
ForeignKeyConstraintsKey : 1,
CreatePrimaryKeySupportKey : 1,
}
_create_database_options={
DropPrimaryKeySupportKey : 0,
DropForeignKeyConstraintsKey : 0,
DropPrimaryKeyConstraintsKey : 0,
DropTablesKey : 0,
DropDatabaseKey : 0,
CreateDatabaseKey : 1,
CreateTablesKey : 1,
PrimaryKeyConstraintsKey : 1,
ForeignKeyConstraintsKey : 1,
CreatePrimaryKeySupportKey : 1,
}
_recreate_database_options=_create_database_options.copy()
_recreate_database_options[DropDatabaseKey]=1
_create_options_to_key={
'-T': CreateTablesKey, '-P': PrimaryKeyConstraintsKey,
'-S': CreatePrimaryKeySupportKey, '-F': ForeignKeyConstraintsKey }
_drop_options_to_key={
'-t': DropTablesKey, '-p': DropPrimaryKeyConstraintsKey,
'-s': DropPrimaryKeySupportKey, '-f': DropForeignKeyConstraintsKey }
def main(args):
me=args[0]
generation_options=_defaultOptions
try: options, args = getopt.getopt(sys.argv[1:],
'ce:hivACRDdTtPpSsFf',
["stdout", "end-with=", "help", "verbose",
"ignore-errors",
"all-but-database", "create-database",
"recreate-database", "connection-dict",
"admin-dsn=", "user-dsn="])
except: usage(me); return 1
global verbose, to_stdout, continue_on_errors
admin_connection_dict={}
user_connection_dict={}
should_have_admin_dict=0 # set for options: -A, -C, -R, -D and -d
end_with_str=';'
force_flag=0
for k, v in options:
if k in ('-h', '--help'): usage(me); return 0
if k in ('-v', '--verbose'): verbose=1; continue
if k in ('-c', '--stdout'): to_stdout=1; continue
if k in ('-i', '--ignore-errors'): continue_on_errors=1; continue
if k in ('-e', '--end-with'): end_with_str=v; continue
if k in ('-f', '--force'): force_flag=1; continue
if k in ('-A', '--all-but-database'):
generation_options.update(_all_but_database_options)
continue
if k in ('-C', '--create-database'):
generation_options.update(_create_database_options)
should_have_admin_dict=k
continue
if k in ('-R', '--recreate-database'):
generation_options.update(_recreate_database_options)
should_have_admin_dict=k
continue
if k in _create_options_to_key.keys():
generation_options[_create_options_to_key[k]]=1; continue
if k in _drop_options_to_key.keys():
generation_options[_drop_options_to_key[k]]=1; continue
if k == '-D':
generation_options[DropDatabaseKey]=1
should_have_admin_dict=k
continue
if k == '-d':
generation_options[CreateDatabaseKey]=1
should_have_admin_dict=k
continue
if k in ('--admin-dsn',):
try:
v=v.split(':')
if len(v)==4:
admin_connection_dict={'host': v[0], 'database': v[1],
'user':v[2], 'password':v[3]}
elif len(v)==5:
admin_connection_dict={'host': v[0],'port':int(v[1]),
'database': v[2],
'user':v[3], 'password':v[4]}
else:
sys.stderr.write("Error: invalid admin-dsn")
return 1
except:
sys.stderr.write("Invalid admin-dsn")
return 1
if k in ('--user-dsn',):
try:
v=v.split(':')
if len(v)==4:
user_connection_dict={'host': v[0], 'database': v[1],
'user':v[2], 'password':v[3]}
elif len(v)==5:
user_connection_dict={'host': v[0],'port':int(v[1]),
'database': v[2],
'user':v[3], 'password':v[4]}
else:
sys.stderr.write("Error: invalid user-dsn")
return 1
except:
sys.stderr.write("Invalid user-dsn")
return 1
if should_have_admin_dict and not admin_connection_dict:
sys.stderr.write('Error: option %s requires --admin-connection-dict'%should_have_admin_dict)
return 1
if len(args)!=1: usage(me) ; return 1
import operator
if not reduce(operator.add, generation_options.values()):
sys.stderr.write('Error: no command given, see --help for details\n')
return 1
model_file=args[0]
# load the model
log("Loading the model...")
try:
from Modeling import Model
model=Model.loadModel(model_file)
if not model:
raise RuntimeError, "Abnormal: got no exception but Model is None"
except Exception, exc:
err("Serious: couldn't load the model")
err(tracebackInfoFromStack(exc))
return 3
if user_connection_dict:
model.setConnectionDictionary(user_connection_dict)
# SQLite specifics, bug #785434 / #813297
if model.adaptorName() == 'SQLite' and should_have_admin_dict:
dsn_db_name = model.connectionDictionary()['database']
admin_dsn_db_name = admin_connection_dict['database']
if dsn_db_name != admin_dsn_db_name:
raise ValueError, "Database name in the dsn (%s) and in the admin-dsn (%s) should be the same for SQLite"%(dsn_db_name, admin_dsn_db_name)
from Modeling import ModelValidation
from Modeling.ModelValidation import DEBUG,INFO,WARNING
errors=MV.ModelValidationException(ignore_levels=[DEBUG,INFO,WARNING])
MV.validateModel(model, errors)
if errors.has_errors():
_model_err_log=force_flag and log or err
if verbose:
_model_err_log("Error: model has errors:\n"+str(errors))
else: _model_err_log("Error: model has errors (-v for details)")
if not force_flag:
err("Aborting")
return 4
else:
log("Option --force set, continuing anyway...\n")
result=databaseSchemaWithOptions(model, _defaultOptions,
administrativeConnectionDictionary=admin_connection_dict,
continue_on_errors=continue_on_errors,
onlyStatements=to_stdout,
endStatementWith=end_with_str)
if to_stdout:
print result
if __name__ == "__main__":
status = main(sys.argv)
sys.exit(status or 0)
|