commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

r5863 - in trunk: gnue-appserver gnue-appserver/doc gnue-appserver/sampl


From: johannes
Subject: r5863 - in trunk: gnue-appserver gnue-appserver/doc gnue-appserver/samples gnue-appserver/scripts gnue-appserver/src gnue-appserver/src/gcd gnue-common/scripts
Date: Mon, 7 Jun 2004 10:12:32 -0500 (CDT)

Author: johannes
Date: 2004-06-07 10:12:31 -0500 (Mon, 07 Jun 2004)
New Revision: 5863

Added:
   trunk/gnue-appserver/doc/gcd.dtd
   trunk/gnue-appserver/scripts/gnue-gcd2sql
   trunk/gnue-appserver/src/gcd/
   trunk/gnue-appserver/src/gcd/GCParser.py
   trunk/gnue-appserver/src/gcd/__init__.py
   trunk/gnue-appserver/src/gcd/gcd2sql.py
Modified:
   trunk/gnue-appserver/BUGS
   trunk/gnue-appserver/samples/sample.gfd
   trunk/gnue-appserver/setup.cvs
   trunk/gnue-common/scripts/gnuedtd
Log:
Implemented gcd2sql, a tool to transform GNUe Class Definitions into sql files


Modified: trunk/gnue-appserver/BUGS
===================================================================
--- trunk/gnue-appserver/BUGS   2004-06-07 14:08:55 UTC (rev 5862)
+++ trunk/gnue-appserver/BUGS   2004-06-07 15:12:31 UTC (rev 5863)
@@ -3,3 +3,7 @@
 * Time fields are broken in some dbdrivers. Depending on the driver, it's
   possible that the "Meeting Time" field in the sample doesn't work.
 
+* gcd2sql: extending classes of other modules won't work because the gnue_id of
+  the foreign module (module of the class to be extended) is not known. This
+  will change as soon as all stuff runs into a connection directly, without
+  creating a intermediate sql file.

Added: trunk/gnue-appserver/doc/gcd.dtd
===================================================================
--- trunk/gnue-appserver/doc/gcd.dtd    2004-06-07 14:08:55 UTC (rev 5862)
+++ trunk/gnue-appserver/doc/gcd.dtd    2004-06-07 15:12:31 UTC (rev 5863)
@@ -0,0 +1,99 @@
+<!-- GNUe Class Definitions DTD (Version 0.0.7.99) -->
+
+<!--
+     Copyright 2001-2004 Free Software Foundation
+
+     This file is part of GNU Enterprise.
+
+     GNU Enterprise is free software; you can redistribute it
+     and/or modify it under the terms of the GNU General Public
+     License as published by the Free Software Foundation; either
+     version 2, or (at your option) any later version.
+
+     GNU Enterprise 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 General Public License for more details.
+
+     You should have received a copy of the GNU General Public
+     License along with program; see the file COPYING. If not,
+     write to the Free Software Foundation, Inc., 59 Temple Place
+     - Suite 330, Boston, MA 02111-1307, USA.
+-->
+
+<!-- Entities for characters/symbols -->
+<!ENTITY % lt "&#38;#60;">
+<!ENTITY % gt "&#62;">
+<!ENTITY % amp "&#38;#38;">
+
+<!--  =================================================  -->
+<!--  Datatype entities to make DTD more human readable  -->
+<!--  =================================================  -->
+
+<!ENTITY % text "CDATA">
+
+<!ENTITY % true "Y">
+<!ENTITY % false "N">
+<!ENTITY % boolean "(%true;|%false;) #IMPLIED">
+
+<!ENTITY % integer "NMTOKEN">
+<!-- [-]?[0-9]+ -->
+
+<!ENTITY % name "NMTOKEN">
+<!-- [A-Za-z]([A-Z][a-z][0-9][#$_-])* -->
+
+
+
+<!-- ================= -->
+<!-- Top level element -->
+<!-- ================= -->
+<!ELEMENT module (class*)>
+<!ATTLIST module name ID #REQUIRED>
+<!ATTLIST module comment %text; #IMPLIED>
+
+
+<!-- ======================== -->
+<!-- Child elements of module -->
+<!-- ======================== -->
+<!ELEMENT class (procedure*, property*)>
+<!ATTLIST class name ID #REQUIRED>
+<!ATTLIST class comment %text; #IMPLIED>
+<!ATTLIST class module %name; #IMPLIED>
+
+
+<!-- ======================= -->
+<!-- Child elements of class -->
+<!-- ======================= -->
+<!ELEMENT procedure (parameter*, #PCDATA)>
+<!ATTLIST procedure name ID #REQUIRED>
+<!ATTLIST procedure comment %text; #IMPLIED>
+<!ATTLIST procedure language %name; "python">
+<!ATTLIST procedure length %integer; #IMPLIED>
+<!ATTLIST procedure nullable %boolean;>
+<!ATTLIST procedure scale %integer; #IMPLIED>
+<!ATTLIST procedure type %text; #IMPLIED>
+
+<!ELEMENT property EMPTY>
+<!ATTLIST property name ID #REQUIRED>
+<!ATTLIST property type %text; #REQUIRED>
+<!ATTLIST property comment %text; #IMPLIED>
+<!ATTLIST property language %name; "python">
+<!ATTLIST property length %integer; #IMPLIED>
+<!ATTLIST property nullable %boolean;>
+<!ATTLIST property scale %integer; #IMPLIED>
+
+
+<!-- =========================== -->
+<!-- Child elements of procedure -->
+<!-- =========================== -->
+<!ELEMENT parameter EMPTY>
+<!ATTLIST parameter name ID #REQUIRED>
+<!ATTLIST parameter type %text; #REQUIRED>
+<!ATTLIST parameter comment %text; #IMPLIED>
+<!ATTLIST parameter length %integer; #IMPLIED>
+<!ATTLIST parameter scale %integer; #IMPLIED>
+
+
+<!-- This DTD was created by gnuedtd
+     Updated: 2004-06-07 16:57:35   -->
+

Modified: trunk/gnue-appserver/samples/sample.gfd
===================================================================
--- trunk/gnue-appserver/samples/sample.gfd     2004-06-07 14:08:55 UTC (rev 
5862)
+++ trunk/gnue-appserver/samples/sample.gfd     2004-06-07 15:12:31 UTC (rev 
5863)
@@ -49,11 +49,9 @@
   <datasource name="dtsMCountry" connection="appserver"
     table="address_country"/>
   <trigger name="showRecord" type="NAMED"><![CDATA[
-    setParameter('next', blkPerson.inpHuman.get ())
-    dtsPerson.createResultSet ()
-    # retval = dtsPerson.call("address_show", {})
-    # if retval is not None:
-      # print "retval =", retval
+    retval = dtsPerson.call("address_show", {})
+    if retval is not None:
+      print "retval =", retval
   ]]></trigger>
   <logic>
     <block name="blkPerson" datasource="dtsPerson">

Added: trunk/gnue-appserver/scripts/gnue-gcd2sql
===================================================================
--- trunk/gnue-appserver/scripts/gnue-gcd2sql   2004-06-07 14:08:55 UTC (rev 
5862)
+++ trunk/gnue-appserver/scripts/gnue-gcd2sql   2004-06-07 15:12:31 UTC (rev 
5863)
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# This file is part of GNU Enterprise.
+#
+# GNU Enterprise is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2001-2004 Free Software Foundation
+#
+# $Id: $
+
+import os, sys
+
+if hasattr(sys, 'frozen'):
+  sys.path.append(os.path.abspath(os.path.dirname(sys.argv[0])))
+
+from gnue.appserver.gcd import gcd2sql
+
+if __name__ == '__main__':
+  gcd2sql = gcd2sql.gcdConverter ()
+  gcd2sql.run ();


Property changes on: trunk/gnue-appserver/scripts/gnue-gcd2sql
___________________________________________________________________
Name: svn:executable
   + *

Modified: trunk/gnue-appserver/setup.cvs
===================================================================
--- trunk/gnue-appserver/setup.cvs      2004-06-07 14:08:55 UTC (rev 5862)
+++ trunk/gnue-appserver/setup.cvs      2004-06-07 15:12:31 UTC (rev 5863)
@@ -33,6 +33,7 @@
 # Create our shell script..
 createShell ('gacvs', 'gnue-appserver')
 createShell ('ggcvs', 'gnue-gsdgen')
+createShell ('gcdcvs', 'gnue-gcd2sql')
 
 # Add our GNUe RPC resource files to the config directory...
 createLink ('grpc/appserver.grpc','%s/share/gnue/grpc/appserver.grpc' % 
CONFDIR, overwrite=1)


Property changes on: trunk/gnue-appserver/src/gcd
___________________________________________________________________
Name: ignore
   + *.pyc


Added: trunk/gnue-appserver/src/gcd/GCParser.py
===================================================================
--- trunk/gnue-appserver/src/gcd/GCParser.py    2004-06-07 14:08:55 UTC (rev 
5862)
+++ trunk/gnue-appserver/src/gcd/GCParser.py    2004-06-07 15:12:31 UTC (rev 
5863)
@@ -0,0 +1,424 @@
+#
+# This file is part of GNU Enterprise.
+#
+# GNU Enterprise is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2001-2004 Free Software Foundation
+#
+# $Id: $
+
+import re
+
+from gnue.common.definitions import GParser, GObjects, GRootObj
+from gnue.common.definitions.GParserHelpers import GContent
+from gnue.common.formatting import GTypecast
+from gnue.appserver.classrep import helpers, Namespace
+
+
+xmlElements   = None
+_LENGTH_SCALE = re.compile ('^\w+\s*\(\s*(\d*)\s*[\,]{0,1}\s*(\d*)\s*\)\s*')
+
+
+# =============================================================================
+# Exceptions
+# =============================================================================
+
+class Error (gException):
+  pass
+
+class NoModuleError (Error):
+  def __init__ (self, classname):
+    msg = u_("Class '%s' has no module") % classname
+    Error.__init__ (self, msg)
+
+class DuplicateDefinitionError (Error):
+  def __init__ (self, name, asLength):
+    if asLength:
+      msg = u_("'%s' has a length in type and an extra length attribute") % 
name
+    else:
+      msg = u_("'%s' has a scale in type and an extra scale attribute") % name
+    Error.__init__ (self, msg)
+
+class ModuleMismatchError (Error):
+  def __init__ (self, classname, module):
+    msg = u_("The class '%(class)s' mismatches the given module attribute "
+             "'%(module)s'") % {'class': classname, 'module': module}
+    Error.__init__ (self, msg)
+
+class InvalidCalculatedError (Error):
+  def __init__ (self, classname, propName):
+    msg = u_("Calculated property '%(class)s.%(property)s' has parameters") \
+          % {'class': classname, 'property': propName}
+    Error.__init__ (self, msg)
+
+# =============================================================================
+# load an XML object tree from a given stream and return it's root object
+# =============================================================================
+
+def loadFile (stream, initialize = True):
+  return GParser.loadXMLObject (stream, xmlSchemaHandler, 'GCModule',
+      'module', initialize)
+
+
+# =============================================================================
+# Build a dictionary tree with all available XML elements
+# =============================================================================
+
+def getXMLelements ():
+  global xmlElements
+
+  if xmlElements is None:
+    xmlElements = {
+      'module': {
+        'BaseClass' : GCModule,
+        'Required'  : True,
+        'Attributes': {
+          'name': {
+            'Required': True,
+            'Unique'  : True,
+            'Typecast': GTypecast.name},
+          'comment': {
+            'Typecast': GTypecast.text}
+        },
+        'ParentTags': (None)
+      },
+
+      'class': {
+        'BaseClass': GCClass,
+        'Attributes': {
+          'name': {
+            'Required': True,
+            'Unique'  : True,
+            'Typecast': GTypecast.name},
+          'module': {
+            'Typecast': GTypecast.name},
+          'comment': {
+            'Typecast': GTypecast.text}
+        },
+        'ParentTags': ('module',)
+      },
+
+      'property': {
+        'BaseClass': GCProperty,
+        'Attributes': {
+          'name': {
+            'Required': True,
+            'Unique'  : True,
+            'Typecast': GTypecast.name},
+          'type': {
+            'Required': True,
+            'Typecast': GTypecast.text},
+          'nullable': {
+            'Default' : True,
+            'Typecast': GTypecast.boolean},
+          'comment': {
+            'Typecast': GTypecast.text},
+          'length': {
+            'Typecast': GTypecast.integer},
+          'scale': {
+            'Typecast': GTypecast.integer},
+          'language': {
+            'Default' : 'python',
+            'Typecast': GTypecast.name}
+        },
+        'MixedContent'  : True,
+        'KeepWhitespace': True,
+        'ParentTags'    : ('class',)
+      },
+
+      'procedure': {
+        'BaseClass'     : GCProcedure,
+        'Attributes'    : {
+          'name': {
+            'Required': True,
+            'Unique'  : True,
+            'Typecast': GTypecast.name},
+          'type': {
+            'Typecast': GTypecast.text},
+          'nullable': {
+            'Default' : True,
+            'Typecast': GTypecast.boolean},
+          'comment': {
+            'Typecast': GTypecast.text},
+          'length': {
+            'Typecast': GTypecast.integer},
+          'scale': {
+            'Typecast': GTypecast.integer},
+          'language': {
+            'Default' : 'python',
+            'Typecast': GTypecast.name}
+        },
+        'MixedContent'  : True,
+        'KeepWhitespace': True,
+        'ParentTags'    : ('class',)
+      },
+
+      'parameter': {
+        'BaseClass': GCParameter,
+        'Attributes': {
+          'name': {
+            'Required': True,
+            'Unique'  : True,
+            'Typecast': GTypecast.name},
+          'type': {
+            'Required': True,
+            'Typecast': GTypecast.text},
+          'comment': {
+            'Typecast': GTypecast.text},
+          'length': {
+            'Typecast': GTypecast.integer},
+          'scale': {
+            'Typecast': GTypecast.integer}
+        },
+        'ParentTags': ('procedure',)
+      }
+    }
+
+  return GParser.buildImportableTags ('module', xmlElements)
+
+
+# =============================================================================
+# Class called by the XML parser to process the XML file
+# =============================================================================
+
+class xmlSchemaHandler (GParser.xmlHandler):
+  def __init__ (self):
+    GParser.xmlHandler.__init__ (self)
+    self.xmlElements = getXMLelements ()
+
+
+# =============================================================================
+# Base class for all GNUe Class Definition classes
+# =============================================================================
+
+class GCObject (GObjects.GObj):
+  pass
+
+
+# =============================================================================
+# Base class for all objects with a type-attribute
+# =============================================================================
+
+class GCTypeDefinition (GCObject):
+  def __init__ (self, parent = None, objType = None):
+    GCObject.__init__ (self, parent, type = objType)
+
+    self.datatype    = None
+    self.length      = None
+    self.scale       = None
+    self.isReference = False
+
+    self._inits.extend ([None, self._validate])
+
+
+  # ---------------------------------------------------------------------------
+  # If an instance has a type attribute, verify it
+  # ---------------------------------------------------------------------------
+
+  def _validate (self):
+
+    if hasattr (self, 'type'):
+      fieldType = self.type.lower ().strip ()
+      tpMatch   = re.compile ('^(\w+)').match (fieldType)
+      if tpMatch is None:
+        raise helpers.TypeNameError, (fieldType)
+
+      typename = tpMatch.groups () [0]
+      if not typename in helpers.BASE_TYPES and len (typename.split ('_')) != 
2:
+        raise helpers.TypeNameError, (fieldType)
+
+      flength = 0
+      fscale  = 0
+
+      # try to extract length and scale from fieldType
+      lsMatch = _LENGTH_SCALE.match (fieldType)
+      if lsMatch is not None:
+        (lstr, sstr) = lsMatch.groups ()
+
+        if len (lstr):
+          if self.length is not None:
+            raise DuplicateDefinitionError, (self.name, True)
+          self.length = int (lstr)
+
+        if len (sstr):
+          if self.scale is not None:
+            raise DuplicateDefinitionError, (self.name, False)
+          self.scale = int (sstr)
+
+      if typename in helpers.BASE_TYPES:
+        helpers.verifyBasetype (typename, self.length, self.scale)
+      else:
+        self.isReference = True
+
+        if self.length:
+          raise helpers.TypeFormatError, \
+              u_("Reference type '%s' must not have a length") % typename
+        if self.scale:
+          raise helpers.TypeFormatError, \
+              u_("Reference type '%s' must not have a scale") % typename
+
+        typename = 'string'
+        self.length = 32
+
+      self.datatype = typename
+
+
+# =============================================================================
+# The module object, root object of a GCD tree
+# =============================================================================
+
+class GCModule (GRootObj.GRootObj, GCObject):
+  def __init__ (self, parent = None):
+    GRootObj.GRootObj.__init__ (self, 'module', getXMLelements, 
self.__module__)
+    GCObject.__init__ (self, parent, type = 'GCModule')
+
+
+# =============================================================================
+# The class object
+# =============================================================================
+
+class GCClass (GCObject):
+  def __init__ (self, parent):
+    GCObject.__init__ (self, parent, type = 'GCClass')
+    self.fullName = None
+    self.action   = 'create'
+    self._inits.extend ([None, self._validate, self._complete])
+
+  # ---------------------------------------------------------------------------
+  # Validate a class definition
+  # ---------------------------------------------------------------------------
+
+  def _validate (self):
+    if not isinstance (self._parent, GCModule):
+      raise NoModuleError, self.name
+
+    nameParts = self.name.split ('_')
+    if len (nameParts) > 1:
+      if hasattr (self, 'module') and self.module != nameParts [0]:
+        raise ModuleMismatchError, (self.name, self.module)
+
+      (self.module, self.name) = nameParts [:2]
+
+    if not hasattr (self, 'module'):
+      self.module = self._parent.name
+
+    # if this class is not defined by the top level module, this is just a
+    # definition for a class extension
+    if self.module != self._parent.name:
+      self.action = 'extend'
+
+    self.fullName = Namespace.createName (self.module, self.name)
+
+
+  # ---------------------------------------------------------------------------
+  # Complete a class definition if neccessary
+  # ---------------------------------------------------------------------------
+
+  def _complete (self):
+    # check if there's a gnue_id in new classes
+    if self.action == 'create':
+      items = [c.fullName for c in self.findChildrenOfType ('GCProperty')]
+      if not 'gnue_id' in items:
+        gnueId = GCProperty (self)
+        gnueId.name     = 'id'
+        gnueId.type     = 'string'
+        gnueId.length   = 32
+        gnueId.comment  = 'Object ID'
+        gnueId.nullable = False
+
+        gnueId._validate ()
+        gnueId.module  = 'gnue'
+        gnueId.fullName= 'gnue_id'
+
+    # transform all 'calculated properties' into procedures
+    for prop in self.findChildrenOfType ('GCProperty') [:]:
+      if True in [isinstance (c, GContent) for c in prop._children]:
+        if prop.findChildOfType ('GCParameter'):
+          raise InvalidCalculatedError, (self.fullName, prop.fullName)
+
+        proc = GCProcedure (self)
+        proc.name      = 'get%s' % prop.name
+        proc.type      = prop.type
+        proc.length    = prop.length
+        proc.scale     = prop.scale
+        proc.nullable  = prop.nullable
+        proc.language  = prop.language
+        if hasattr (prop, 'comment'):
+          proc.comment = prop.comment
+
+        proc._children = prop._children
+
+        for child in proc._children:
+          child._parent = proc
+
+        proc._validate ()
+
+        self._children.remove (prop)
+
+      
+
+
+
+# =============================================================================
+# The property object
+# =============================================================================
+
+class GCProperty (GCTypeDefinition):
+  def __init__ (self, parent):
+    GCTypeDefinition.__init__ (self, parent, objType = 'GCProperty')
+    self.module   = None
+    self.fullName = None
+
+
+  # ---------------------------------------------------------------------------
+  # Validate a property definition
+  # ---------------------------------------------------------------------------
+
+  def _validate (self):
+    GCTypeDefinition._validate (self)
+    self.module   = self.findParentOfType ('GCModule').name
+    self.fullName = Namespace.createName (self.module, self.name)
+
+
+# =============================================================================
+# The procedure object
+# =============================================================================
+
+class GCProcedure (GCTypeDefinition):
+  def __init__ (self, parent):
+    GCTypeDefinition.__init__ (self, parent, objType = 'GCProcedure')
+    self.module   = None
+    self.fullName = None
+
+
+  # ---------------------------------------------------------------------------
+  # Validate a procedure definition
+  # ---------------------------------------------------------------------------
+
+  def _validate (self):
+    GCTypeDefinition._validate (self)
+    self.module   = self.findParentOfType ('GCModule').name
+    self.fullName = Namespace.createName (self.module, self.name)
+
+
+# =============================================================================
+# The parameter object
+# =============================================================================
+
+class GCParameter (GCTypeDefinition):
+  def __init__ (self, parent):
+    GCTypeDefinition.__init__ (self, parent, objType = 'GCParameter')
+


Property changes on: trunk/gnue-appserver/src/gcd/GCParser.py
___________________________________________________________________
Name: svn:keywords
   + +Id

Added: trunk/gnue-appserver/src/gcd/__init__.py
===================================================================

Added: trunk/gnue-appserver/src/gcd/gcd2sql.py
===================================================================
--- trunk/gnue-appserver/src/gcd/gcd2sql.py     2004-06-07 14:08:55 UTC (rev 
5862)
+++ trunk/gnue-appserver/src/gcd/gcd2sql.py     2004-06-07 15:12:31 UTC (rev 
5863)
@@ -0,0 +1,397 @@
+# GNU Enterprise Application Server - Gnue Schema Definition Generator
+#
+# Copyright 2001-2004 Free Software Foundation
+#
+# This file is part of GNU Enterprise.
+#
+# GNU Enterprise is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id: $
+
+import sys
+import os
+import whrandom
+
+from gnue.common.apps import i18n
+from gnue.common.apps.GClientApp import *
+from gnue.common.utils.FileUtils import openResource, dyn_import
+
+from gnue.appserver import VERSION
+from gnue.appserver.gcd import GCParser
+
+from gnue.common.schema.scripter.processors import vendors as VENDORS
+from gnue.common.schema.scripter import Definition
+from gnue.common.schema import Objects
+from gnue.common.definitions.GParserHelpers import GContent
+
+
+# =============================================================================
+# Generate SQL from GNUe Class Definition files 
+# =============================================================================
+
+class gcdConverter (GClientApp):
+
+  NAME    = "gcd2sql"
+  VERSION = VERSION
+  COMMAND = "gcd2sql"
+  USAGE   = "%s %s" % (GClientApp.USAGE, " [OPTIONS] file")
+  SUMMARY = _(
+"""A tool to create a SQL script from a GNUe Class Definition (gcd) file""")
+
+  _PROC_PATH = "gnue.common.schema.scripter.processors.%s"
+  _GNUE_MODULE_ID = '0' * 32
+
+
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, connections = None):
+
+    self.addCommandOption ('vendor', 'v', default = 'all', argument = 'vendor',
+        help = _("The vendor to create a script for. If <vendor> is 'all', 
then"
+                 " scripts for all supported vendors will be created. <vendor> 
"
+                 "can also be a comma-separated list."))
+
+    self.addCommandOption('encoding', 'e', default='UTF-8', \
+        argument = _('encoding'),
+        help = _("The generated SQL script will be encoded using <encoding>. "
+                 "Default encoding is UTF-8") )
+
+    self.addCommandOption ('output', 'o', argument = 'dest',
+        help = _("to be added later"))
+
+    ConfigOptions = {}
+
+    GClientApp.__init__ (self, connections, 'gcd2sql', ConfigOptions)
+
+
+  # ---------------------------------------------------------------------------
+  # Print a message to stdout, if output is sent to a file
+  # ---------------------------------------------------------------------------
+  def __message (self, text):
+    if self.__filename:
+      print text
+
+
+  # ---------------------------------------------------------------------------
+  # Verify the given commandline options
+  # ---------------------------------------------------------------------------
+
+  def __check_options (self):
+    self._args = [unicode (a, i18n.encoding) for a in self.ARGUMENTS]
+
+    # do we have an accessible input file
+    if not len (self._args):
+      self.handleStartupError (_("No input file specified."))
+
+    if len (self._args) > 1:
+      self.handleStartupError (_("Too much input files specified."))
+
+    try:
+      self._input = openResource (self._args [0])
+
+    except IOError:
+      self.handleStartupError (u_("Unable to open input file %s") % \
+                                  self._args [0])
+
+    # check the specified vendors
+    self._vendors = []
+    if self.OPTIONS ['vendor'].lower () == 'all':
+      self._vendors.extend (VENDORS)
+    else:
+      self._vendors.extend (self.OPTIONS ['vendor'].split (','))
+
+    self._output = self.OPTIONS ['output']
+    if len (self._vendors) > 1 and self._output is not None:
+      if not os.path.isdir (self._output):
+        self.handleStartupError (_("If multiple vendors are specified "
+          "--output must be a directory or\n left empty."))
+
+  # ---------------------------------------------------------------------------
+  # Main program
+  # ---------------------------------------------------------------------------
+
+  def run (self):
+    self.__check_options ()
+
+    try:
+      self.schema = GCParser.loadFile (self._input)
+
+    except:
+      print sys.exc_info () [1]
+      sys.exit (1)
+
+    for vendor in self._vendors:
+      self._transform (vendor)
+
+
+  # ---------------------------------------------------------------------------
+  # Transform the GCD tree to a given vendors' SQL
+  # ---------------------------------------------------------------------------
+  
+  def _transform (self, vendor):
+    aModule = dyn_import (self._PROC_PATH % vendor)
+
+    if not self._output:
+      filename = "%s.sql" % aModule.name
+
+    elif os.path.isdir (self._output):
+      filename = os.path.join (self._output, "%s.sql" % aModule.name)
+
+    else:
+      filename = self._output
+
+    try:
+      self.destination = open (filename, 'w')
+
+    except IOError:
+      sys.stderr.write (u_("Unable to create output file %s" % filename))
+      sys.stderr.write (sys.exc_info () [1])
+      sys.exit (1)
+
+    self.processor = aModule.Processor (self.destination, self._args [0])
+
+    print u_("Writing schema to %s ...") % filename
+
+    try:
+      self.tables = {}
+      self.data   = {}
+      self.module = None
+
+      self.processor.startDump ()
+      self.processor.client_encoding (self.OPTIONS ['encoding'])
+
+      self.schema.walk (self.__iterateObjects)
+
+      maxPhase = 0
+      for table in self.tables.values ():
+        maxPhase = max (maxPhase, max (table.phases.keys ()))
+
+      for phase in range (0, maxPhase + 1):
+        for table in self.tables.values ():
+          self.processor.writePhase (table, phase)
+  
+      for table in ['gnue_module', 'gnue_class', 'gnue_property', \
+                    'gnue_procedure', 'gnue_parameter']:
+        if self.data.has_key (table):
+          self.processor.writeData (self.data [table])
+
+      self.processor.finishDump ()
+
+      self.destination.close ()
+
+    except:
+      os.unlink (filename)
+      raise
+
+
+  # ---------------------------------------------------------------------------
+  # Iterate over all top level elements
+  # ---------------------------------------------------------------------------
+
+  def __iterateObjects (self, sObject):
+    if sObject._type == 'GCModule':
+      self.__translateModule (sObject)
+
+    elif sObject._type == 'GCClass':
+      self.__translateClass (sObject)
+
+  
+
+  # ---------------------------------------------------------------------------
+  # A module translates to a gnue_module data entry only
+  # ---------------------------------------------------------------------------
+
+  def __translateModule (self, aModule):
+    self.module     = aModule
+    aModule.gnue_id = self.__generateId ()
+
+    data = [('gnue_id', 'string', aModule.gnue_id),
+            ('gnue_name', 'string', aModule.name)]
+
+    if hasattr (aModule, 'comment'):
+      data.append (('gnue_comment', 'string', aModule.comment))
+
+    self.__addData ('gnue_module', data)
+
+
+  # ---------------------------------------------------------------------------
+  # A class translation needs a table creation/modification and a data entry
+  # ---------------------------------------------------------------------------
+
+  def __translateClass (self, aClass):
+    aTable = Definition.TableDefinition (aClass.fullName, aClass.action)
+    self.tables [aTable.name] = aTable
+
+    if aClass.action == 'create':
+      # New classes get a primary key for the gnue_id column
+      primaryKey   = aTable.addPrimaryKey ('gnue_id_pk_%s' % aClass.fullName)
+      pkField      = Objects.GSPKField (None)
+      pkField.name = 'gnue_id'
+      primaryKey.fields.append (pkField)
+
+      # Add this new class to the data dictionary
+      aClass.gnue_id = self.__generateId ()
+
+      data = [('gnue_id'    , 'string', aClass.gnue_id),
+              ('gnue_module', 'string', self.module.gnue_id),
+              ('gnue_name'  , 'string', aClass.name)]
+
+      if hasattr (aClass, 'comment'):
+        data.append (('gnue_comment', 'string', aClass.comment))
+
+      self.__addData ('gnue_class', data)
+    else:
+      aClass.gnue_id = '---unknown---'
+
+    # After processing the class definition, iterate over all it's items
+    aClass.walk (self.__iterateClassObjects, cClass = aClass, tableDef = 
aTable)
+
+    self.processor.translateTableDefinition (aTable)
+
+
+  # ---------------------------------------------------------------------------
+  # Iterate over all elements of a class definition
+  # ---------------------------------------------------------------------------
+
+  def __iterateClassObjects (self, sObject, cClass, tableDef):
+    if sObject._type == 'GCProperty':
+      # Add a field to the table definition
+      item = Objects.GSField (None)
+      item.name        = sObject.fullName
+      item.type        = sObject.datatype
+      item.length      = sObject.length or 0
+      item.precision   = sObject.scale or 0
+      item.nullable    = sObject.nullable
+      item.defaultwith = 'constant'
+      if hasattr (sObject, 'comment'):
+        item.description = sObject.comment
+
+      tableDef.fields.append (item)
+
+      # Create a foreign key constraint for class references
+      if sObject.isReference:
+        cName = "%s_%s_fk" % (cClass.fullName, sObject.type)
+        constraint = tableDef.newConstraint (cName, 'foreignkey')
+        constraint.reftable = sObject.type
+        constraint.fields.append (item)
+        ref = Objects.GSField (None)
+        ref.name = 'gnue_id'
+        constraint.reffields.append (ref)
+
+      # Create an entry for the gnue_property table
+      if sObject.fullName == 'gnue_id':
+        moduleId = self._GNUE_MODULE_ID
+      else:
+        moduleId = self.module.gnue_id
+
+      data = [('gnue_id'      , 'string' , self.__generateId ()),
+              ('gnue_module'  , 'string' , moduleId),
+              ('gnue_class'   , 'string' , cClass.gnue_id),
+              ('gnue_name'    , 'string' , sObject.name),
+              ('gnue_type'    , 'string' , sObject.datatype),
+              ('gnue_nullable', 'boolean', sObject.nullable)]
+
+      if hasattr (sObject, 'comment'):
+        data.append (('gnue_comment', 'string', sObject.comment))
+      if sObject.length:
+        data.append (('gnue_length', 'number', sObject.length))
+      if sObject.scale:
+        data.append (('gnue_scale', 'number', sObject.scale))
+
+      self.__addData ('gnue_property', data)
+
+
+    elif sObject._type == 'GCProcedure':
+      # Create an entry for the gnue_procedure table
+      sObject.gnue_id = self.__generateId ()
+      data = [('gnue_id'      , 'string' , sObject.gnue_id),
+              ('gnue_module'  , 'string' , self.module.gnue_id),
+              ('gnue_class'   , 'string' , cClass.gnue_id),
+              ('gnue_name'    , 'string' , sObject.name),
+              ('gnue_nullable', 'boolean', sObject.nullable),
+              ('gnue_code'    , 'string' , sObject.getChildrenAsContent ()),
+              ('gnue_language', 'string' , sObject.language)]
+                  
+
+      if sObject.datatype is not None:
+        data.append (('gnue_type'    , 'string' , sObject.datatype))
+
+      if hasattr (sObject, 'comment'):
+        data.append (('gnue_comment', 'string', sObject.comment))
+
+      if sObject.length:
+        data.append (('gnue_length', 'number', sObject.length))
+      if sObject.scale:
+        data.append (('gnue_scale', 'number', sObject.scale))
+
+      self.__addData ('gnue_procedure', data)
+
+      sObject.walk (self.__iterateProcObjects, cProc = sObject)
+
+  def __iterateProcObjects (self, sObject, cProc):
+    if sObject._type == 'GCParameter':
+      sObject.gnue_id = self.__generateId ()
+
+      data = [('gnue_id'       , 'string', sObject.gnue_id),
+              ('gnue_procedure', 'string', cProc.gnue_id),
+              ('gnue_name'     , 'string', sObject.name)]
+
+      if hasattr (sObject, 'comment'):
+        data.append (('gnue_comment', 'string', sObject.comment))
+      if sObject.datatype:
+        data.append (('gnue_type', 'string', sObject.datatype))
+      if sObject.length:
+        data.append (('gnue_length', 'number', sObject.length))
+      if sObject.scale:
+        data.append (('gnue_scale', 'number', sObject.scale))
+
+      self.__addData ('gnue_parameter', data)
+
+  # ---------------------------------------------------------------------------
+  # Add a fields-tuple to the data-dictionary
+  # ---------------------------------------------------------------------------
+
+  def __addData (self, table, fields):
+    if not self.data.has_key (table):
+      self.data [table] = Definition.DataDefinition (table)
+
+    row = self.data [table].addRow ()
+    for (name, datatype, value) in fields:
+      item = Objects.GSValue (None)
+      item.dataType = datatype
+      item.value    = value
+
+      row.columns.append (name)
+      row.values.append (item)
+
+
+  # ---------------------------------------------------------------------------
+  # Generate a new object id
+  # ---------------------------------------------------------------------------
+
+  def __generateId (self):
+
+    # TODO: need a better algorithm here
+    result = u''
+    for i in range (0, 32):
+      result = result + str (int (whrandom.random () * 10))
+    return result
+
+
+if __name__ == "__main__":
+  gcdConverter ().run ()


Property changes on: trunk/gnue-appserver/src/gcd/gcd2sql.py
___________________________________________________________________
Name: svn:keywords
   + +Id

Modified: trunk/gnue-common/scripts/gnuedtd
===================================================================
--- trunk/gnue-common/scripts/gnuedtd   2004-06-07 14:08:55 UTC (rev 5862)
+++ trunk/gnue-common/scripts/gnuedtd   2004-06-07 15:12:31 UTC (rev 5863)
@@ -77,8 +77,17 @@
       name = 'GNURPC'
       from gnue.common import VERSION as version
 
+    elif tool == 'gcd':
+      from gnue.appserver.gcd import GCParser
+      from gnue.appserver import VERSION
+      xmlElements = GCParser.getXMLelements ()
+      topLevelElement = 'module'
+      name = 'GNUe Class Definitions'
+      version = VERSION
+
     else:
-      print "\nSyntax: gnuedtd <forms|reports|schema|navigator|gnurpc> 
[outfile.dtd]\n"
+      print "\nSyntax: gnuedtd <forms|reports|schema|navigator|gnurpc|gcd>" +\
+            "[outfile.dtd]\n"
       sys.exit()
 
     self.parentMappings = {}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]