16 |
# write to the Free Software Foundation, Inc., 59 Temple Place |
# write to the Free Software Foundation, Inc., 59 Temple Place |
17 |
# - Suite 330, Boston, MA 02111-1307, USA. |
# - Suite 330, Boston, MA 02111-1307, USA. |
18 |
# |
# |
19 |
# Copyright 2002 Free Software Foundation |
# Copyright 2002-2003 Free Software Foundation |
20 |
# |
# |
21 |
# FILE: |
# FILE: |
22 |
# Objects.py |
# Scripter.py |
23 |
# |
# |
24 |
# DESCRIPTION: |
# DESCRIPTION: |
25 |
# GObjects for the Schema definitions |
# Schema definition scripter |
26 |
# |
# |
27 |
# NOTES: |
# NOTES: |
28 |
|
# Beware the Scriptor() class -- it smells like a billy goat. |
29 |
# |
# |
30 |
|
|
31 |
|
from gnue.common import VERSION |
32 |
from gnue.common.schema import GSParser |
from gnue.common.schema import GSParser |
33 |
from gnue.common.FileUtils import openResource, dyn_import |
from gnue.common.FileUtils import openResource, dyn_import |
34 |
from gnue.common.GClientApp import GClientApp |
from gnue.common.GClientApp import GClientApp |
35 |
|
from processors import vendors |
36 |
|
|
37 |
import sys |
import sys |
38 |
import os |
import os |
39 |
|
|
40 |
|
class ScripterRunner(GClientApp): |
41 |
|
# |
42 |
|
# GClientApp() overrides |
43 |
|
# |
44 |
|
VERSION = VERSION |
45 |
|
COMMAND = "gnue-schema-scripter" |
46 |
|
NAME = "GNUe Schema Scripter" |
47 |
|
USAGE = "[options] file [old-schema]" |
48 |
|
COMMAND_OPTIONS = [ |
49 |
|
[ 'drop_tables',None,'drop-tables', 0, None, None, |
50 |
|
'Generate commands to drop relevant tables.'], |
51 |
|
[ 'ignore_schema','S','no-create', 0, None, None, |
52 |
|
'Do not generate schema creation code.'], |
53 |
|
[ 'ignore_data','D','no-data', 0, None, None, |
54 |
|
'Do not generate data insertion code.'], |
55 |
|
[ 'upgrade_schema','u','upgrade-schema', 0, None, None, |
56 |
|
'Generate code to upgrade an older version of a schema to ' |
57 |
|
'the recent version. You must specify a previous schema with on the ' |
58 |
|
'command line.'], |
59 |
|
[ 'upgrade_data','U','upgrade-data', 0, None, None, |
60 |
|
'Generate code to upgrade an older version of schema data to ' |
61 |
|
'the recent version. You must specify a previous schema with on the ' |
62 |
|
'command line.'], |
63 |
|
[ 'list_vendors','l','list-vendors', 0, None, None, |
64 |
|
'List all supported vendors.'], |
65 |
|
[ 'output','o','output', 1, None, 'dest', |
66 |
|
'The destination for the created schemas. This can be in several ' |
67 |
|
'formats. If <dest> is a file name, then output is written to this ' |
68 |
|
'file. If <dest> is a directory, then <dest>/<Vendor>.sql is created. ' |
69 |
|
'The default is to create <Vendor>.sql in the current directory. ' |
70 |
|
'NOTE: the first form (<dest> as a filename) is not supported for ' |
71 |
|
'--vendors all.' ], |
72 |
|
[ 'vendor','v','vendor', 1, 'all', 'vendor', |
73 |
|
'The vendor to create a script for. If <vendor> is "all", then ' |
74 |
|
'scripts for all supported vendors will be created. <vendor> can ' |
75 |
|
'also be a comma-separated list.'], |
76 |
|
] |
77 |
|
SUMMARY = \ |
78 |
|
"GNUe Schema Scripter creates SQL files based on GNUe Schema Definitions." |
79 |
|
|
80 |
|
# |
81 |
|
# Run |
82 |
|
# |
83 |
|
def run(self): |
84 |
|
|
85 |
|
globals().update(self.OPTIONS) |
86 |
|
|
87 |
|
# List vendors, if requested |
88 |
|
if list_vendors: |
89 |
|
self.listVendors() |
90 |
|
sys.exit() |
91 |
|
|
92 |
|
upgrading = 0 |
93 |
|
|
94 |
|
# Do some sanity checks on the options |
95 |
|
if upgrade_schema or upgrade_data: |
96 |
|
upgrading = 1 |
97 |
|
|
98 |
|
if drop_tables: |
99 |
|
self.handleStartupError('--drop-tables is not compatable with the ' |
100 |
|
'--upgrade-?? options. Unable to create an upgrade schema.') |
101 |
|
try: |
102 |
|
old_schema = self.ARGUMENTS[1] |
103 |
|
except IndexError: |
104 |
|
self.handleStartupError('An --upgrade-?? option was selected, but ' |
105 |
|
'only one source file was specified. Unable to create ' |
106 |
|
'an upgrade schema.') |
107 |
|
|
108 |
|
elif drop_tables and ignore_schema: |
109 |
|
# If we are dropping tables and ignoring schema, |
110 |
|
# then we can't possibly want the data. |
111 |
|
ignore_data = 1 |
112 |
|
|
113 |
|
|
114 |
|
if vendor.lower() == 'all': |
115 |
|
vens = vendors |
116 |
|
|
117 |
|
else: |
118 |
|
vens = vendor.split(',') |
119 |
|
|
120 |
|
if len(vens) > 1 and (output and not os.path.isdir(output)): |
121 |
|
self.handleStartupError('--output cannot reference a file ' |
122 |
|
'if multiple vendors are specified.') |
123 |
|
|
124 |
|
# Assign input file |
125 |
|
try: |
126 |
|
schema = self.ARGUMENTS[0] |
127 |
|
input = openResource(schema) |
128 |
|
except IndexError: |
129 |
|
self.handleStartupError('No source file was specified.') |
130 |
|
except IOError: |
131 |
|
self.handleStartupError('Unable to open requested file: %s' % schema) |
132 |
|
|
133 |
|
print |
134 |
|
scripter = Scripter(schema) |
135 |
|
for ven in vens: |
136 |
|
if not output: |
137 |
|
outfile = self.getVendorName(ven) + '.sql' |
138 |
|
elif os.path.isdir(output): |
139 |
|
outfile = os.path.join(output, self.getVendorName(ven) + '.sql') |
140 |
|
else: |
141 |
|
outfile = output |
142 |
|
|
143 |
|
try: |
144 |
|
out = open(outfile,'w') |
145 |
|
except IOError, mesg: |
146 |
|
self.handleStartupError('Unable to open destination file: %s\n\n%s' % (outfile,mesg)) |
147 |
|
|
148 |
|
print "Writing schema to %s ..." % outfile |
149 |
|
|
150 |
|
try: |
151 |
|
scripter.writeSql(ven, out) |
152 |
|
except: |
153 |
|
print "WARNING: Unable to create a schema for %s" % ven |
154 |
|
raise |
155 |
|
|
156 |
|
out.close() |
157 |
|
|
158 |
|
# |
159 |
|
# Get a vendor name |
160 |
|
# |
161 |
|
def getVendorName(self, vendor): |
162 |
|
return dyn_import('processors.%s' % vendor).name |
163 |
|
|
164 |
|
# |
165 |
|
# List Vendors |
166 |
|
# |
167 |
|
def listVendors(self): |
168 |
|
header = "%s\nVersion %s" % (self.NAME, self.VERSION) |
169 |
|
print |
170 |
|
print header |
171 |
|
print |
172 |
|
print "Supported Database Vendors" |
173 |
|
print "--------------------------" |
174 |
|
|
175 |
|
modules = {} |
176 |
|
maxsize = 0 |
177 |
|
for vendor in vendors: |
178 |
|
maxsize = max(maxsize, len(vendor)) |
179 |
|
try: |
180 |
|
modules[vendor] = dyn_import('processors.%s' % vendor) |
181 |
|
except ImportError: |
182 |
|
pass |
183 |
|
|
184 |
|
srt = modules.keys() |
185 |
|
srt.sort() |
186 |
|
for vendor in srt: |
187 |
|
print vendor.ljust(maxsize+4), modules[vendor].description |
188 |
|
|
189 |
|
print |
190 |
|
|
191 |
|
|
192 |
|
|
193 |
|
|
194 |
|
|
195 |
|
|
196 |
|
############################################################ |
197 |
|
# |
198 |
|
# The actual worker class |
199 |
|
# |
200 |
class Scripter: |
class Scripter: |
201 |
def __init__(self, source, oldsource=None): |
def __init__(self, source, oldsource=None): |
202 |
|
|
222 |
self._postfields = [] |
self._postfields = [] |
223 |
self._pretable = [] |
self._pretable = [] |
224 |
self._posttable = [] |
self._posttable = [] |
225 |
|
self._pkfields = [] |
226 |
|
self._pkname = "" |
227 |
object.walk(self._walkTable, tablename=object.name) |
object.walk(self._walkTable, tablename=object.name) |
228 |
|
if len(self._pkfields): |
229 |
|
self._handlePK(object.name) |
230 |
self.destination.write(self.processor.createTable(object.name, self._fields + self._postfields, self._pretable, self._posttable)) |
self.destination.write(self.processor.createTable(object.name, self._fields + self._postfields, self._pretable, self._posttable)) |
231 |
self.destination.write('\n\n') |
self.destination.write('\n\n') |
232 |
|
|
233 |
def _walkTable(self, object, tablename): |
def _walkTable(self, object, tablename): |
234 |
if object._type == 'GSField': |
if object._type == 'GSField': |
235 |
exec "field, extra, pretable,posttable = self.processor.createField(object.name,tablename,self.processor.%s(object), object)" % object.type in locals() |
exec "self._handlePrePost(self.processor.createField(object.name,tablename,self.processor.%s(object), object))" % object.type in locals() |
236 |
if field: |
elif object._type == 'GSPKField': |
237 |
self._fields.append(field) |
self._pkfields.append(object.name) |
238 |
if extra: |
elif object._type == 'GSIndex': |
239 |
self._postfields += extra |
self._indexfields = [] |
240 |
if pretable: |
object.walk(self._walkIndex, tablename) |
241 |
self._pretable += pretable |
self._handlePrePost(self.processor.createIndex(object.name,tablename,self._indexfields, object.unique)) |
242 |
if posttable: |
|
243 |
self._posttable += posttable |
|
244 |
|
def _walkIndex(self, object, tablename): |
245 |
|
if object._type == 'GSIndexField': |
246 |
|
self._indexfields.append(object.name) |
247 |
|
|
248 |
|
|
249 |
|
def _handlePK(self, tablename): |
250 |
|
self._handlePrePost(self.processor.createPrimaryKey(self._pkname,tablename, self._pkfields)) |
251 |
|
|
252 |
|
|
253 |
|
# Butt-ugly stuff |
254 |
|
def _handlePrePost(self, results): |
255 |
|
field, extra, pretable, posttable = results |
256 |
|
if field: |
257 |
|
self._fields.append(field) |
258 |
|
if extra: |
259 |
|
self._postfields += extra |
260 |
|
if pretable: |
261 |
|
self._pretable += pretable |
262 |
|
if posttable: |
263 |
|
self._posttable += posttable |
264 |
|
|
265 |
|
|
266 |
if __name__ == '__main__': |
if __name__ == '__main__': |
267 |
Scripter(sys.argv[1]).writeSql(sys.argv[2]) |
ScripterRunner().run() |