commit-gnue
[Top][All Lists]
Advanced

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

r5925 - in trunk/gnue-common/src: datasources datasources/drivers/Base/S


From: johannes
Subject: r5925 - in trunk/gnue-common/src: datasources datasources/drivers/Base/Schema/Creation datasources/drivers/interbase/Schema/Creation datasources/drivers/postgresql/Schema/Creation schema/scripter
Date: Wed, 7 Jul 2004 17:14:05 -0500 (CDT)

Author: johannes
Date: 2004-06-22 14:21:26 -0500 (Tue, 22 Jun 2004)
New Revision: 5925

Modified:
   trunk/gnue-common/src/datasources/GConnections.py
   trunk/gnue-common/src/datasources/drivers/Base/Schema/Creation/Creation.py
   
trunk/gnue-common/src/datasources/drivers/interbase/Schema/Creation/Creation.py
   
trunk/gnue-common/src/datasources/drivers/postgresql/Schema/Creation/Creation.py
   trunk/gnue-common/src/schema/scripter/Scripter.py
Log:
* The introspector- and creator-instances are now available to connections 
which are not logged in too
* Added a 'createDatabase ()' facility to the schema-creation so a connection 
can be used to create complete databases
* Implemented createDatabase () for PostgreSQL driver; more will follow soon


Modified: trunk/gnue-common/src/datasources/GConnections.py
===================================================================
--- trunk/gnue-common/src/datasources/GConnections.py   2004-06-22 07:57:07 UTC 
(rev 5924)
+++ trunk/gnue-common/src/datasources/GConnections.py   2004-06-22 19:21:26 UTC 
(rev 5925)
@@ -208,53 +208,76 @@
 
 
 
-  def getConnection(self, connection_name, login=0):
+  # ---------------------------------------------------------------------------
+  # get a connection instance on optionally log into it 
+  # ---------------------------------------------------------------------------
 
+  def getConnection (self, connection_name, login = False):
+    """
+    This function returns an instance of the requested connection and
+    optionally logs into it. If there's an already opened connection for the
+    requested connectionname this instance will be returned.
 
-    connection_name = connection_name.lower()
+    @param connection_name: name of the connection to be returned
+    @param login: if TRUE, this function automatically tries to open the
+        connection.
+    @return: connection instance
+    @raise GConnection.NotFoundError: if connection_name does not exist
+    """
+    connection_name = connection_name.lower ()
 
-    try:
-      return self._openConnections[connection_name]
-    except KeyError:
-      pass
+    if self._openConnections.has_key (connection_name):
+      return self._openConnections [connection_name]
 
-    # Support for multiple open connections
-    # to same database.
-    # Specify as 'gnue:1', 'gnue:2', etc, to open
-    # two actual connections to 'gnue', each with
-    # their own transactions, etc.
-    connection_base = connection_name.split(':')[0]
+    # Support for multiple open connections to the same database.
+    # Specify as 'gnue:1', 'gnue:2', etc, to open two actual connections to
+    # 'gnue', each with their own transactions, etc.
+    connection_base = connection_name.split (':') [0]
 
-    # This will throw a GConnections.NotFoundError if an unknown
-    # connection name is specified.  The calling method should
-    # catch this exception and handle it properly (exit w/message)
+    # This will throw a GConnections.NotFoundError if an unknown connection
+    # name is specified. The calling method should catch this exception and
+    # handle it properly (exit w/message)
+    parameters = self.getConnectionParameters (connection_base)
 
-    parameters = self.getConnectionParameters(connection_base)
-
-    driver = parameters['provider'].lower().replace('/','.')
-    behavior = parameters.get('behavior','').lower().replace('/','.')
-
+    driver   = parameters ['provider'].lower ().replace ('/', '.')
+    behavior = parameters.get ('behavior','').lower ().replace ('/', '.')
     dbdriver = plugin.find (driver, 'gnue.common.datasources.drivers',
                             'Connection')
 
     try:
-      conn = dbdriver.Connection(self, connection_name, parameters)
+      conn = dbdriver.Connection (self, connection_name, parameters)
+
     except TypeError:
       # Check for the case that a "Connection" is passed instead of a
-      # "Connection" class. This is the case, when the procedure for deferal
-      # of the loading of the connection object is overwriten by the 
"connection"
-      # module. i.e. there is a Connection.py file
-      # TODO: remove this extra check by cleaning up the whole loading 
procedure
-      conn = dbdriver.Connection.Connection(self, connection_name, parameters)
+      # "Connection" class. This is the case, when the procedure for deferal of
+      # the loading of the connection object is overwriten by the "connection"
+      # module. i.e. there is a Connection.py file 
+      # TODO: remove this extra check by cleaning up the whole loading
+      # procedure
+      conn = dbdriver.Connection.Connection (self, connection_name, parameters)
 
-    self._openConnections[connection_name] = conn
+    self._openConnections [connection_name] = conn
 
+    # Create the introspection instance
+    # TODO: add support of the behavior parameter. Does it describe a path to
+    #       the introspection module or is it the name of a provider whose
+    #       introspector would be used?
+    if hasattr (conn, 'behavior'):
+      behavior = conn.behavior
+    else:
+      behavior = conn.defaultBehavior
+
+    conn.introspector = behavior (conn)
+
+    # Create the schema creator instance
+    if hasattr (conn, 'defaultCreator'):
+      conn.schemaCreator = conn.defaultCreator (conn, conn.introspector)
+    else:
+      conn.schemaCreator = None
+
     if login:
-      self.loginToConnection(conn)
+      self.loginToConnection (conn)
 
-    # TODO: Process the behavior = and
-    # TODO: set conn.behavior= to the
-    # TODO: specific Introspection class
     return conn
 
 
@@ -304,21 +327,27 @@
     dataObject.connect()
 
 
-  def loginToConnection(self, connection):
+  # ---------------------------------------------------------------------------
+  # logon to a connection
+  # ---------------------------------------------------------------------------
 
+  def loginToConnection (self, connection):
+
     connection_name = connection.name
-    connection_base = connection_name.split(':')[0]
+    connection_base = connection_name.split (':') [0]
 
     if not self._loginHandler:
-      self.setLoginHandler(GLoginHandler.BasicLoginHandler())
+      self.setLoginHandler (GLoginHandler.BasicLoginHandler ())
 
     try:
       connected = connection.__connected
+
     except AttributeError:
       connected = 0
 
     if not connected:
       loginData = connection.parameters
+
       try:
         # load the user's netrc file:
         # a sample .netrc could look like:
@@ -330,35 +359,39 @@
         # (Remark: if .netrc should work under Win32 you have to
         #  set the HOME environement variable [SET HOME=...])
 
-        netrcData = netrc.netrc().authenticators(
-              "'gnue://%s/'" % connection_base )
-        if netrcData!=None:
-          GDebug.printMesg(5, 'Read the user\'s .netrc file')
-          loginData['_username'] = netrcData[0][1:-1]
-          loginData['_password'] = netrcData[2][1:-1]
-          GDebug.printMesg(5, 'Found useful stuff for connection %s in the 
user\'s .netrc file' % connection_name)
-      except (IOError,netrc.NetrcParseError,KeyError):
+        netrcData = netrc.netrc ().authenticators ("'gnue://%s/'" \
+                                                   % connection_base)
+        if netrcData is not None:
+          GDebug.printMesg (5, 'Read the user\'s .netrc file')
+          loginData ['_username'] = netrcData [0][1:-1]
+          loginData ['_password'] = netrcData [2][1:-1]
+
+          GDebug.printMesg (5, "Found useful stuff for connection %s in "
+                               "the user\'s .netrc file" % connection_name)
+
+      except (IOError, netrc.NetrcParseError, KeyError):
         pass
 
-      if (loginData.has_key('username')):
-        loginData['_username'] = loginData['username']
-        del loginData['username']
+      if (loginData.has_key ('username')):
+        loginData ['_username'] = loginData ['username']
+        del loginData ['username']
 
-      if (loginData.has_key('password')):
-        loginData['_password'] = loginData['password']
-        del loginData['password']
+      if (loginData.has_key ('password')):
+        loginData ['_password'] = loginData ['password']
+        del loginData ['password']
 
       # Load
-      if loginData.has_key('custom_auth'):
-        authenticator = dyn_import(loginData['custom_auth']).Authenticator()
-        checkFields = authenticator.getLoginFields(connection.getLoginFields())
+      if loginData.has_key ('custom_auth'):
+        authenticator = dyn_import (loginData ['custom_auth']).Authenticator ()
+        checkFields   = authenticator.getLoginFields ( \
+                                             connection.getLoginFields ())
       else:
-        checkFields = connection.getLoginFields()
+        checkFields   = connection.getLoginFields ()
         authenticator = None
 
-      haveAllInformation = 1
+      haveAllInformation = True
       for rf, dummy1, dummy2 in checkFields:
-        if not (loginData.has_key(rf) and loginData[rf] != None):
+        if not (loginData.has_key (rf) and loginData [rf] is not None):
           haveAllInformation = 0
           break
 
@@ -369,9 +402,9 @@
 #          self._authenticatedUsers[base] = None
 
         if authenticator:
-          connection.connect(authenticator.login(loginData))
+          connection.connect (authenticator.login (loginData))
         else:
-          connection.connect(loginData)
+          connection.connect (loginData)
 
       else:
         attempts = 4
@@ -430,22 +463,8 @@
         self._eventHandler.dispatchEvent('Connections:Connect',
               name=connection_name, base=connection_base)
 
-    # Create the introspection instance
-    try:
-      behavior = connection.behavior
-    except AttributeError:
-      behavior = connection.defaultBehavior
-    connection.introspector = behavior(connection)
-
-    # Create the schema creator instance
-    if hasattr (connection, 'defaultCreator'):
-      connection.schemaCreator = connection.defaultCreator (connection,
-                                                       connection.introspector)
-    else:
-      connection.schemaCreator = None
-
     # Done
-    connection.__connected = 1
+    connection.__connected = True
 
 
   def getAuthenticatedUser(self, connection=None):

Modified: 
trunk/gnue-common/src/datasources/drivers/Base/Schema/Creation/Creation.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/Base/Schema/Creation/Creation.py  
2004-06-22 07:57:07 UTC (rev 5924)
+++ trunk/gnue-common/src/datasources/drivers/Base/Schema/Creation/Creation.py  
2004-06-22 19:21:26 UTC (rev 5925)
@@ -29,6 +29,11 @@
 class Error (gException):
   pass
 
+class NoCreationError (Error):
+  def __init__ (self):
+    msg = _("Database creation not implemented by this driver")
+    Error.__init__ (self, msg)
+
 class DefinitionError (Error):
   pass
 
@@ -125,15 +130,27 @@
 
 
   # ---------------------------------------------------------------------------
+  # Create a database
+  # ---------------------------------------------------------------------------
+
+  def createDatabase (self):
+    """
+    Descendants can override this function to create a database. Usually all
+    information needed could be gathered from the connection object.
+    """
+    raise NoCreationError
+
+
+  # ---------------------------------------------------------------------------
   # Create a table from a table definition
   # ---------------------------------------------------------------------------
 
   def createTable (self, tableDefinition, codeOnly = False):
     """
     This function creates a table using the given definition and returns a
-    code-tuple, which can be used to to this. 
+    code-tuple, which can be used to to this.
 
-    @param tableDefinition: a dictionary of the table to be created 
+    @param tableDefinition: a dictionary of the table to be created
     @param codeOnly: if TRUE no operation takes place, but only the code will
         be returned.
     @return: a tuple of sequences (prologue, body, epliogue) containing the

Modified: 
trunk/gnue-common/src/datasources/drivers/interbase/Schema/Creation/Creation.py
===================================================================
--- 
trunk/gnue-common/src/datasources/drivers/interbase/Schema/Creation/Creation.py 
    2004-06-22 07:57:07 UTC (rev 5924)
+++ 
trunk/gnue-common/src/datasources/drivers/interbase/Schema/Creation/Creation.py 
    2004-06-22 19:21:26 UTC (rev 5925)
@@ -20,11 +20,21 @@
 #
 # $Id$
 
+import os
 from gnue.common.datasources.drivers.DBSIG2.Schema.Creation import \
     Creation as Base
 
 
 # =============================================================================
+# Exceptions
+# =============================================================================
+
+class NoBinaryError (gException):
+  def __init__ (self):
+    gException.__init__ (self, u_("No binary for isql(-fb) provided."))
+
+
+# =============================================================================
 # Class implementing schema creation for Interbase (5.x/6.x), Firebird (1.x)
 # =============================================================================
 
@@ -34,6 +44,42 @@
   ALTER_MULTIPLE  = False
 
   # ---------------------------------------------------------------------------
+  # Create a new database
+  # ---------------------------------------------------------------------------
+
+  def __hack__createDatabase (self):
+    """
+    This function is not yet activated, but should somedays create a database
+    as described by the connection.
+    """
+    dbname   = self.connection.parameters.get ('dbname', None)
+    username = self.connection.parameters.get ('username', 'gnue')
+    password = self.connection.parameters.get ('password', None)
+    host     = self.connection.parameters.get ('host', None)
+    isqlbin  = self.connection.parameters.get ('isqlbin', None)
+
+    if not isqlbin:
+      raise NoBinaryError
+
+    if host:
+      dburl = "%s:%s" % (host, dbname)
+    else:
+      dburl = dbname
+
+    code = open ("ib.sql", "w")
+    try:
+      code.write (u"CREATE DATABASE '%s' USER 'sysdba' PASSWORD 'masterkey' "
+                  "DEFAULT CHARACTER SET UTF8;\n" % dburl)
+      code.close ()
+
+      if os.system (u"%s -i ib.sql" % isqlbin):
+        raise gException, ("Cannot create database")
+
+    finally:
+      os.unlink ("ib.sql")
+
+
+  # ---------------------------------------------------------------------------
   # Process a defaultwith attribute
   # ---------------------------------------------------------------------------
 

Modified: 
trunk/gnue-common/src/datasources/drivers/postgresql/Schema/Creation/Creation.py
===================================================================
--- 
trunk/gnue-common/src/datasources/drivers/postgresql/Schema/Creation/Creation.py
    2004-06-22 07:57:07 UTC (rev 5924)
+++ 
trunk/gnue-common/src/datasources/drivers/postgresql/Schema/Creation/Creation.py
    2004-06-22 19:21:26 UTC (rev 5925)
@@ -20,6 +20,7 @@
 #
 # $Id$
 
+import os
 from gnue.common.datasources.drivers.DBSIG2.Schema.Creation import \
     Creation as Base
 
@@ -35,6 +36,55 @@
 
 
   # ---------------------------------------------------------------------------
+  # Create a new database
+  # ---------------------------------------------------------------------------
+
+  def createDatabase (self):
+    """
+    This function creates the requested user and database using the tools
+    'createuser', 'createdb' and 'dropuser'. Of course this function should
+    better make use of the template1 database using a connection object. 
+    """
+    dbname   = self.connection.parameters.get ('dbname', None)
+    username = self.connection.parameters.get ('username', 'gnue')
+    password = self.connection.parameters.get ('password', None)
+    host     = self.connection.parameters.get ('host', None)
+    port     = self.connection.parameters.get ('port', None)
+
+    site = ""
+    if host is not None:
+      site += " --host=%s" % host
+    if port is not None:
+      site += " --port=%s" % port
+
+    # TODO: use a connection object to the template1 database instead of the
+    # shell-scripts. Note: CREATE DATABASE statements must NOT run within a
+    # transaction block, so we cannot use the default connection mechanisms.
+
+    try:
+      os.system (u"dropuser %s%s 2>/dev/null" % (username, site))
+
+    except:
+      pass
+
+    createuser = u"createuser --createdb --adduser %s%s" % (username, site)
+    if os.system (createuser):
+      raise gException, ("User creation failed")
+
+
+    createdb = u"createdb %s --owner=%s%s" % (dbname, username, site)
+    if os.system (createdb):
+      raise gException, ("Database creation failed")
+
+
+    if password is not None and password:
+      self.connection.manager.loginToConnection (self.connection)
+      alterUser = u"ALTER USER %s WITH PASSWORD '%s';" % (username, password)
+      self.connection.makecursor (alterUser)
+      self.connection.commit ()
+
+
+  # ---------------------------------------------------------------------------
   # Handle special defaults
   # ---------------------------------------------------------------------------
 

Modified: trunk/gnue-common/src/schema/scripter/Scripter.py
===================================================================
--- trunk/gnue-common/src/schema/scripter/Scripter.py   2004-06-22 07:57:07 UTC 
(rev 5924)
+++ trunk/gnue-common/src/schema/scripter/Scripter.py   2004-06-22 19:21:26 UTC 
(rev 5925)
@@ -83,6 +83,20 @@
                  "creation is done. If mode is 'data' only data integration "
                  "is done."))
 
+    self.addCommandOption ('username', 'u', argument="user",
+        help = _("Set the username for the database. If the database is to be "
+                 "created, this username will be it's owner."))
+
+    self.addCommandOption ('password', 'p', argument="password",
+        help = _("Set the password for the database."))
+
+    self.addCommandOption ('createdb', 'd', default = False,
+        help = _("If this option is set, the database will be created before "
+                 "any schema creation is done. There must be a username "
+                 "either from the given connection-configuration or from the "
+                 "command line. This user becomes the owner of the database "
+                 "and will be implicitly created."))
+
     ConfigOptions = {}
     GClientApp.__init__ (self, connections, 'schema', ConfigOptions)
 
@@ -119,17 +133,25 @@
       print sys.exc_info () [1]
 
     else:
-      if self.__doData and len (self.tabledata):
-        self.verifyDataKeys ()
+      try:
+        if self.__doData and len (self.tabledata):
+          self.verifyDataKeys ()
 
-      if self.__doSchema:
-        self.executeAndGenerateCode ()
+        if self.OPTIONS ['createdb']:
+          if self.connection.schemaCreator is not None:
+            self.connection.schemaCreator.createDatabase ()
 
-      if self.__doData and len (self.tabledata):
-        self.updateData ()
+        if self.__doSchema:
+          self.executeAndGenerateCode ()
 
+        if self.__doData and len (self.tabledata):
+          self.updateData ()
 
+      except Exception:
+        print sys.exc_info () [1]
 
+
+
   # ---------------------------------------------------------------------------
   # Walk through all command line options
   # ---------------------------------------------------------------------------
@@ -170,7 +192,19 @@
       self.handleStartupError (_("Mode of operation must be one of "
                                  "'both', 'schema' or 'data'."))
 
+    cName = self.OPTIONS ['connection']
+    self.connection = self.connections.getConnection (cName)
 
+    # if a username is given on the command line we pass both username and
+    # password to the connection parameters. If the password is not set, it
+    # defaults to an empty string.
+    username = self.OPTIONS ['username'] or 'gnue'
+
+    self.connection.parameters ['username'] = username
+    self.connection.parameters ['password'] = self.OPTIONS ['password'] or ""
+
+
+
   # ---------------------------------------------------------------------------
   # Get a dictionary with all keys listed in tags and values from sObject
   # ---------------------------------------------------------------------------
@@ -426,12 +460,11 @@
     given output file (if requested by options).
     """
 
-    connection = self.connections.getConnection (self.OPTIONS ['connection'],
-                                                 login = True)
+    self.connections.loginToConnection (self.connection)
 
     print _("Updating schema ...")
-    code = connection.updateSchema (self.tables, self.OPTIONS ['file-only'])
-
+    code = self.connection.updateSchema (self.tables,
+                                         self.OPTIONS ['file-only'])
     if self.outfile is not None:
       dest = open (self.outfile, 'w')
 





reply via email to

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