#!/usr/bin/env python # # Creates an schema dump of the tables received as args # # # notes: # # - encoding used only for data that can hold high char values # (can field names hold them?) # # # todo: # # en appserver/src, data.py+geasInstance.py contienen cosas interesantes para # el manejo de datos, incluyendo clase connection, con findRecord() y así; # una vez estabilizado todo eso, puede interesar utilizarlo. # # # estado: # # ... si es posible que los nombres de datos tengan chars altos, hay que pasarlos por encode, tb. # ... y comprobar args con isintance() # # # # copyright notice: # # this code has been built by me, José Esteban, and is just a private # preview, but it follows some code of GNU Enterprise, GPL licensed, so # if any use/copy license is pertinent is this; if not, you must delete # this, and whatever, copy and forget you have seen anyway. # ######### habría que ir metiendo en hacking lo que se pueda sacar de aquí import os, sys from gnue.common.apps import GDebug from gnue.common.apps import i18n from gnue.common.apps.GClientApp import * from gnue.common.datasources.GDataSource import DataSourceWrapper if hasattr(sys, 'frozen'): sys.path.append(os.path.abspath(os.path.dirname(sys.argv[0]))) # ############################################################################# # Geas class definition # ############################################################################# class geasClass: geasModuleName = None geasName = None geasId = None geasModuleId = None geasProp = None geasPropType = None geasProc = None # name, type y comment al menos para cada uno; el code se obtiene de db cuando se necesite # # @param fullName with module prefix # def __init__ (self, fullName): upos = fullName.find('_') if not upos < 0: self.geasModuleName = fullName[0:upos] self.geasName = fullName[upos+1:] self.geasProp = [] self.geasPropType = {} self.geasProc = [] def getName(self): return self.geasName def getFullName(self): return '%s_%s' % (self.geasModuleName,self.geasName) def getId(self): return self.geasId def getModuleName(self): return self.geasModuleName def getModuleId(self): return self.geasModuleId def getPropertyNames(self): return self.geasProp def getPropertyType(self, pname): if self.geasPropType.has_key(pname): return self.geasPropType[pname] return None # ############################################################################# # Geas backend # ############################################################################# class geasBackend: ds = None do = None mndict = {} cndict = {} midict = {} cidict = {} def __init__ (self, ds): self.ds = ds self.do = self.ds.getDataObject() # # performs a query aginst a table throu datasource # def getResultSet(self, tfullname, conditions={}, fields=[]): ####### this couldn't be consistent, but... self.do.table = tfullname ###################### there isn't a method to do this for fkey in self.ds._fieldReferences.keys(): del self.ds._fieldReferences[fkey] self.ds.referenceFields(fields) return self.do.createResultSet(conditions) # # stores module in cache # def setModuleCache(self, name, id): self.mndict[name] = id self.midict[id] = name # # gets module name for a given id # def getModuleName(self, id): if self.midict.has_key(id): return self.midict[id] rs = self.getResultSet('gnue_module', {'gnue_id': id}, ['gnue_name']) if rs == None: raise Exception, 'geas Module not found: %s' % qname rec = rs.nextRecord() if rec == None: raise Exception, 'geas Module not found: %s' % qname self.setModuleCache(rec.getField('gnue_name'),id) return self.midict[id] # # gets module id for a given module/class name # def getModuleId(self, qname): upos = qname.find('_') if not upos < 0: qname = qname[0:upos] if self.mndict.has_key(qname): gDebug(5,'%s: Using cache for module id of %s' % (self.__class__.__name__,qname)) return self.mndict[qname] gDebug(5,'%s: Querying module id for %s' % (self.__class__.__name__,qname)) rs = self.getResultSet('gnue_module', {'gnue_name': qname}, ['gnue_id']) if rs == None: raise Exception, 'geas Module not found: %s' % qname rec = rs.nextRecord() if rec == None: raise Exception, 'geas Module not found: %s' % qname self.setModuleCache(qname,rec.getField('gnue_id')) return self.mndict[qname] # # gets class id for a given full qualified class name # def getClassId(self, qname): gDebug(5,'%s: Querying class id for %s' % (self.__class__.__name__,qname)) upos = qname.find('_') if upos < 0: raise Exception, 'Bad full qualified class name: %s' % qname cname = qname[upos+1:] mid = self.getModuleId(qname) rs = self.getResultSet('gnue_class', {'gnue_module': mid, 'gnue_name': cname}, ['gnue_id']) if rs == None: raise Exception, 'geas Class not found: %s' % qname rec = rs.nextRecord() if rec == None: raise Exception, 'geas Class not found: %s' % qname return rec.getField('gnue_id') # # @return resulset for a given class # def getObjects(self, cfullname, conditions={}, props=[]): if len(props) == 0: cdef = self.getClassDef(cfullname) props = cdef.getPropertyNames() return self.getResultSet(cfullname, conditions, props) # # @return geasClass object # def getClassDef(self, fullname): if self.cndict.has_key(fullname): gDebug(5,'%s: Using cache for class def of %s' % (self.__class__.__name__,fullname)) return self.cndict[fullname] co = geasClass(fullname) if co.getName() == None: return None # module gnue_id co.geasModuleId = self.getModuleId(fullname) # class gnue_id co.geasId = self.getClassId(fullname) # class properties gDebug(5,'%s: Querying column names for %s' % (self.__class__.__name__,co.getFullName())) rs = self.getResultSet('gnue_property', {'gnue_class': co.getId()}, ['gnue_name','gnue_module','gnue_type']) rec = rs.nextRecord() while not rec == None: fname = self.getModuleName(rec.getField('gnue_module')) + '_' + rec.getField('gnue_name') co.geasProp.append(fname) co.geasPropType[fname] = rec.getField('gnue_type') rec = rs.nextRecord() self.cndict[fullname] = co self.cidict[co.getId()] = co return self.cndict[fullname] # ############################################################################# # # Generate GNUe Schema Definition dumps from appservers class repository # # ############################################################################# class appGsdGen (GClientApp): NAME = "geas2gsd" VERSION = "0.0.1" COMMAND = "geas2gsd" USAGE = "%s %s" % (GClientApp.USAGE, " [ OPTIONS ] fqclasname [...]") SUMMARY = u_( """Dumps objects data in gsd format to standard output.""") # # # def __init__ (self, connections = None): self.addCommandOption('connection', 'c', argument = u_('connection name'), help = u_("Set the Connection to use for loading and storing data to ." "gnue-appserver will search for it in connections.conf.")) self.addCommandOption('output', 'o', argument = u_('destination'), help= u_("The destination for the created file.")) self.addCommandOption('encoding', 'e', default='UTF-8', argument = u_('encoding'), help = u_("The generated SQL script will be encoded using . " "Default encoding is UTF-8") ) ConfigOptions = {} GClientApp.__init__ (self, connections, self.COMMAND, ConfigOptions) # if we were to use gnue module related stuff, it could ve useful self.configurationManager.registerAlias ('gConfig', 'appserver') # # Main program # def run (self): # tables args = [unicode (a, i18n.encoding) for a in self.ARGUMENTS] if not len(args): sys.stderr.write("%s: I need table name(s) as argument(s)\n" % self.__class__.__name__) sys.exit (1) # output file self._ofile = self.OPTIONS ['output'] if self._ofile == None: self._ofile = 'data-dump.gsd' # connection dsName = self.OPTIONS['connection'] gDebug(1,u_("Connecting to %s ..." % dsName)) try: ds = DataSourceWrapper(self.connections,attributes={'connection': dsName,'name': 'dtsSource'}) except Exception: sys.stderr.write ("%s: Error when connecting to ds %s: %s: %s\n" % \ ( self.__class__.__name__, dsName, str(sys.exc_info()[0]), str(sys.exc_info()[1]))) sys.exit (1) be = geasBackend(ds) gDebug(1,u_("Generating dump schema ...\n")) try: self.writeSchema(be, args) except Exception: sys.stderr.write ("%s: Error al construir esquema\n" % self.__class__.__name__) sys.exit (1) gDebug(1,u_("Schema generation complete.\n")) # # Actually writes out schema dumps # def writeSchema (self, be, tables = None): # output file try: ofile = open (self._ofile, 'w') except IOError: sys.stderr.write (u_("%s: Unable to create output file %s: %s\n" % \ ( self.__class__.__name__, self._ofile, sys.exc_info()[1]))) raise gDebug(1,'Writing schema ...') # xml head ofile.write('\n' % self.OPTIONS['encoding']) ofile.write('\n' % ( self.NAME, tables )) ofile.write('\n') ofile.write(' \n') for cfullname in tables: try: tclass = be.getClassDef(cfullname) except: sys.stderr.write("%s: Table %s unknown (%s,%s). Stoping with error.\n" % \ ( self.__class__.__name__, cfullname, str(sys.exc_info()[0]), str(sys.exc_info()[1]))) sys.exit(1) gDebug(1,u_('Writing data for table %s' % cfullname)) ofile.write(' \n' % (cfullname, cfullname)) # table definition ofile.write(' \n') for fname in tclass.getPropertyNames(): ptype = tclass.getPropertyType(fname) upos = fullName.find('_') if not upos < 0: ptype = 'string' ofile.write(' \n' % (fname,ptype)) ofile.write(' \n') # table data try: rs = be.getObjects(cfullname) rec = rs.nextRecord() except: sys.stderr.write("%s: Error when retrieving records from table %s (%s,%s). Stoping with error.\n" % \ ( self.__class__.__name__, cfullname, str(sys.exc_info()[0]), str(sys.exc_info()[1]))) sys.exit(1) while not rec == None: ofile.write(' \n') for fname in tclass.getPropertyNames(): ofile.write((' %s\n' % (fname,rec.getField(fname))).encode(self.OPTIONS['encoding'])) ofile.write(' \n') rec = rs.nextRecord() ofile.write(' \n') # xml foot ofile.write(' \n') ofile.write('\n') ofile.close() # running # if __name__ == '__main__': gsdGen = appGsdGen() gsdGen.run ()