[Checkins] SVN: zc.recipe.zope3instance/branches/dev/ Refactored to not use mkzopeinstance. Need to update doctest.

Jim Fulton jim at zope.com
Mon Oct 30 07:13:58 EST 2006


Log message for revision 70995:
  Refactored to not use mkzopeinstance.  Need to update doctest.
  

Changed:
  U   zc.recipe.zope3instance/branches/dev/buildout.cfg
  U   zc.recipe.zope3instance/branches/dev/setup.py
  U   zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/README.txt
  U   zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/__init__.py
  A   zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/ctl.py
  A   zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/zope3scripts.py

-=-
Modified: zc.recipe.zope3instance/branches/dev/buildout.cfg
===================================================================
--- zc.recipe.zope3instance/branches/dev/buildout.cfg	2006-10-30 12:10:22 UTC (rev 70994)
+++ zc.recipe.zope3instance/branches/dev/buildout.cfg	2006-10-30 12:13:58 UTC (rev 70995)
@@ -1,5 +1,5 @@
 [buildout]
-develop =
+develop = .
 parts = test
 
 [test]

Modified: zc.recipe.zope3instance/branches/dev/setup.py
===================================================================
--- zc.recipe.zope3instance/branches/dev/setup.py	2006-10-30 12:10:22 UTC (rev 70994)
+++ zc.recipe.zope3instance/branches/dev/setup.py	2006-10-30 12:13:58 UTC (rev 70995)
@@ -19,5 +19,9 @@
     install_requires = ['zc.buildout', 'zope.testing', 'setuptools',
                         'zc.recipe.egg'],
     dependency_links = ['http://download.zope.org/distribution/'],
-    entry_points = {'zc.buildout': ['default = %s:Recipe' % name]},
+    entry_points = {
+        'zc.buildout': [
+             'default = %s:Recipe' % name,
+             ]
+        },
     )

Modified: zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/README.txt
===================================================================
--- zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/README.txt	2006-10-30 12:10:22 UTC (rev 70994)
+++ zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/README.txt	2006-10-30 12:13:58 UTC (rev 70995)
@@ -2,9 +2,53 @@
 ======================
 
 The zc.recipe.zope3instance recipe creates a Zope 3 instance.  A Zope
-3 instance is a collection of scripts and configure that define a Zope
-server process.
+3 instance is a collection of scripts and configuration that define a Zope
+server process.  This recipe is likely to evolve quite a bit as our
+knowledge of how to deploy applications with eggs evolves. For
+example, we now need to know the location of a Zope 3 installation,
+however, in the future, we may be able to express our dependence on
+Zope3 soley via eggs.
 
+Note that, currently, this recipe is fairly unix-centric.  Windows
+support will be added in the future.
+
+The zope3 instance recipe takes a number of options:
+
+eggs
+    Specify one or more distribution requirements, on separate lines,
+    for software to be included in the Zope instance.
+
+zope3
+    The name of a section defining a Zope3 installation location (as a
+    location option).  This can be either a checkout or a release
+    installtion. (Unfortunately, we have to do some introspection to
+    determine whether a checkout or release installation is
+    provided.)  Hopefully, this option will be unnecessary in the
+    future and we'll use egg depedencies to define the Zope software
+    used. 
+
+database
+    The names of one or more sections defining databases to be used.
+    These sections must contain zconfig options giving configurations
+    for individual databases.
+
+address
+    One or more addresses to listed for HTTP connections on.  Each
+    address of of the form "host:port" or just "port".
+
+user
+    A global management user of the form:
+    user:encyption:encrypted-password.  
+
+zcml 
+    Specifications for one or more zcml files to be loaded.
+
+options
+    Top-level ZConfig options to be used for the instance.
+
+In addition, the find-links, index, python, interpreter, and
+extra-paths options of the zc.recipe.egg recipe are honored.
+
 Let's start with a minimal example. We have a sample buildout.  Let's
 write a buildout.cfg file that defines a zope instance:
 
@@ -35,9 +79,12 @@
 The Zope3 instance recipe needs to be told the location of a Zope 3
 installation.   This can be done in two ways:
 
-1. Use a zope3checkout recipe to install Zope 3 from subversion, or
+1. Use a zope3checkout recipe to install Zope 3 from subversion, 
 
-2. Create a section with an option that provides the location of a
+2. Use the configure-make-make-install recipe to install a Zope
+   release, or
+
+3. Create a section with an option that provides the location of a
    Zope 3 installation.
 
 
@@ -52,7 +99,7 @@
 Let's run the buildout:
 
     >>> print system(join('bin', 'buildout')),
-xs
+
 We'll get a directory created in the buildout parts directory
 containing configuration files and some directories to contain og
 files, pid files, and so on.

Modified: zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/__init__.py
===================================================================
--- zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/__init__.py	2006-10-30 12:10:22 UTC (rev 70994)
+++ zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/__init__.py	2006-10-30 12:13:58 UTC (rev 70995)
@@ -1,138 +1,311 @@
-import os, re, shutil
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import logging, os, re, shutil
+from xml.sax.saxutils import quoteattr
+
+import pkg_resources
+
 import zc.buildout
 import zc.recipe.egg
 
+logger = logging.getLogger('zc.recipe.zope3instance')
+
 class Recipe:
     # Need to think about the inheritence interface
     # it *is* reasonable to think about instances as an
     # extension of the basic egg/script-generation model.
 
     def __init__(self, buildout, name, options):
-        self.egg = zc.recipe.egg.Egg(buildout, name, options)
         self.options, self.name = options, name
 
-        options['zope3'] = options.get('zope3', 'zope3')
-        options['database-config'] = buildout[options['database']]['zconfig']
-        python = buildout['buildout']['python']
-        options['zope3-directory'] = buildout[options['zope3']]['location']
         options['location'] = os.path.join(
             buildout['buildout']['parts-directory'],
             self.name,
             )
-        options['scripts'] = '' # suppress script generation.
+        
+        z3 = options.get('zope3', 'zope3')
+        z3path = buildout[z3]['location']
+        self.zope3 = z3path
+        if not os.path.exists(z3path):
+            raise zc.buildout.UserError("No directory:", z3path)
 
+        path = os.path.join(z3path, 'lib', 'python')
+        if not os.path.exists(path):
+            path = os.path.join(z3path, 'src')
+            if not os.path.exists(path):
+                logger.error(
+                    "The directory, %r, isn't a valid checkout or release."
+                    % z3)
+                raise zc.buildout.UserError(
+                    "Invalid Zope 3 installation:", z3path)
+
+        skel = os.path.join(z3path, 'zopeskel', 'etc')
+        if not os.path.exists(skel):
+            logger.error("%r does not exists.", skel)
+            raise UserError("Invalid Zope 3 Installation", src)
+
+        if len(options['user'].split(':')) not in (2,3):
+            logger.error(
+                "The user option must specify a login name,"
+                " a password manager and a password.")
+            raise UserError("Invalud user, %r", options['user'])
+
+        extra = options.get('extra-paths')
+        if extra:
+            extra += '\n' + path
+        else:
+            extra = path
+
+        options['database-config'] = '\n'.join([
+            buildout[section]['zconfig']
+            for section in options['database'].split()
+            ])
+
+        options['bin-directory'] = buildout['buildout']['bin-directory']
+
+        zope_options = {}
+        for option in options.get('zope-options', '').split('\n'):
+            option = option.strip()
+            if not option:
+                continue
+            option = option.split(' ', 1)
+            if (len(option) == 1) or not option[1].strip():
+                logger.error('%s: zope-option, %s, has no value',
+                             self.name, option[0]
+                             )
+                raise zc.buildout.UserError("Invalid zope-option", option[0])
+            zope_options[option[0]] = option[1]
+
+        if 'interrupt-check-interval' not in zope_options:
+            zope_options['interrupt-check-interval'] = '200'
+            
+        self.zope_options = zope_options
+
+        # Let the egg recipe do much of the heavy lifting.
+        options['scripts'] = ''
+        options['extra-paths'] = extra
+        options.pop('entry-points', None)
+        self.egg = zc.recipe.egg.Egg(buildout, name, options)
+
     def install(self):
-        
         options = self.options
-        location = options['location']
-
+        dest = options['location']
         requirements, ws = self.egg.working_set()
 
-        if os.path.exists(location):
+        os.mkdir(dest)
+        log_dir = run_dir = subprogram_dir = config_dir = dest
 
-            # See is we can stop.  We need to see if the working set path
-            # has changed.
-            saved_path_path = os.path.join(location, 'etc', '.eggs')
-            if os.path.isfile(saved_path_path):
-                if (open(saved_path_path).read() ==
-                    '\n'.join([d.location for d in ws])
-                    ):
-                    return location
+        site_zcml_path = os.path.join(config_dir, 'site.zcml')
 
-            # The working set has changed.  Blow away the instance.
-            shutil.rmtree(location)
+        zope_options = self.zope_options
+        zope_options['site-definition'] = site_zcml_path
         
-        # What follows is a bit of a hack because the instance-setup mechanism
-        # is a bit monolithic.  We'll run mkzopeinstabce and then we'll
-        # patch the result.  A better approach might be to provide independent
-        # instance-creation logic, but this raises lots of issues that
-        # need to be stored out first.
-        mkzopeinstance = os.path.join(options['zope3-directory'],
-                                      'bin', 'mkzopeinstance')
+        zope_options = '\n  '.join([
+            ' '.join(option)
+            for option in zope_options.iteritems()
+            ])
 
-        assert os.spawnl(
-            os.P_WAIT, options['executable'], options['executable'],
-            mkzopeinstance, '-d', location, '-u', options['user'],
-            '--non-interactive',
-            ) == 0
+        addresses = options.get('address', '8080').split()
+        for address in addresses:
+            zope_options += server_template % address
 
-        try:
-            # Save the working set:
-            open(os.path.join(location, 'etc', '.eggs'), 'w').write(
-                '\n'.join([d.location for d in ws]))
+        # Install zope.conf        
+        zope_conf_path = os.path.join(config_dir, 'zope.conf')
+        open(zope_conf_path, 'w').write(zope_conf_template % dict(
+            options = zope_options,
+            database = options['database-config'],
+            log_dir = log_dir,
+            ))
 
-            # Now, patch the zodb option in zope.conf
-            zope_conf_path = os.path.join(location, 'etc', 'zope.conf')
-            zope_conf = open(zope_conf_path).read()
-            zope_conf = (
-                zope_conf[:zope_conf.find('<zodb>')]
-                +
-                options['database-config']
-                +
-                zope_conf[zope_conf.find('</zodb>')+7:]
+        # Install zdaemon.conf
+        zdaemon_conf_path = os.path.join(config_dir, 'zdaemon.conf')
+        open(zdaemon_conf_path, 'w').write(zdaemon_conf_template % dict(
+            subprogram_dir = subprogram_dir,
+            log_dir = log_dir,
+            run_dir = run_dir,
+            user = ''
+            ))
+
+        # Install zcml files
+        self._zcml(self.zope3, config_dir, options)
+
+        # install subprohrams and ctl scripts
+        zc.buildout.easy_install.scripts(
+            [('runzope', 'zope.app.twisted.main', 'main')],
+            ws, options['executable'], subprogram_dir,
+            extra_paths = options['extra-paths'].split(),
+            arguments = ('\n        ["-C", %r]'
+                         '\n        + sys.argv[1:]'
+                         % zope_conf_path),
+            )
+
+        # Install the scripts defined by this recipe, which adds entry points
+        # missing frm Zope itself.
+        requirements, ws = self.egg.working_set(['zc.recipe.zope3instance'])
+        zc.buildout.easy_install.scripts(
+            [('debugzope', 'zc.recipe.zope3instance.zope3scripts', 'debug'),
+             ('scriptzope', 'zc.recipe.zope3instance.zope3scripts', 'script'),
+             ],
+            ws, options['executable'], subprogram_dir,
+            extra_paths = options['extra-paths'].split(),
+            arguments = ('\n        ["-C", %r]'
+                         '\n        + sys.argv[1:]'
+                         % zope_conf_path),
+            )
+
+        zc.buildout.easy_install.scripts(
+            [(self.name, 'zc.recipe.zope3instance.ctl', 'main')],
+            ws, options['executable'], options['bin-directory'],
+            extra_paths = options['extra-paths'].split(),
+            arguments = ('\n        %r,'
+                         '\n        %r,'
+                         '\n        ["-C", %r]'
+                         '\n        + sys.argv[1:]'
+                         % (os.path.join(subprogram_dir, 'debugzope'),
+                            os.path.join(subprogram_dir, 'scriptzope'),
+                            zdaemon_conf_path)
+                         ),
+            )
+
+        return dest, os.path.join(options['bin-directory'], self.name)
+
+    def _zcml(self, src, dest, options):
+        skel = os.path.join(src, 'zopeskel', 'etc')
+        for name in os.listdir(skel):
+            if name.endswith(".zcml"):
+                shutil.copy(os.path.join(skel, name), dest)
+
+        pzi = os.path.join(skel, 'principals.zcml.in')
+        if os.path.exists(pzi):
+            userdata = options['user'].split(':')
+            if len(userdata) == 2:
+                login, pw = userdata
+                pwmanager = "Plain Text"
+            else:
+                login, pwmanager, pw = userdata
+                
+            open(os.path.join(dest, 'principals.zcml'), 'w').write(
+                open(pzi).read()
+                .replace('<<USERNAME-XMLATTR>>', quoteattr(login))
+                .replace('<<PASSWORD_MANAGER>>', pwmanager)
+                .replace('<<PASSWORD-XMLATTR>>', quoteattr(pw))
                 )
-            open(zope_conf_path, 'w').write(zope_conf)
+            
+        # add zcml files to package-includes
+        zcml = options['zcml'] or '*' # Require zcml but allow it to be empty
+        package_includes = os.path.join(dest, 'package-includes')
+        if zcml:
+            zcml = zcml.split()
+            if '*' in zcml:
+                zcml.remove('*')
+                shutil.copytree(os.path.join(src, 'package-includes'), dest)
+            else:
+                os.mkdir(package_includes)
 
-            # Patch extra paths into binaries
-            path = "\n        '" + "',\n        '".join([
-                dist.location for dist in ws]) + "'\n        "
-            for script_name in 'runzope', 'debugzope', 'scriptzope':
-                script_path = os.path.join(location, 'bin', script_name)
-                script = open(script_path).read()
-                # don't look :/
-                script = script.replace(
-                    'sys.path[:] = [',
-                    'sys.path[:] = ['+path+'] + ['
-                    )
-                open(script_path, 'w').write(script)
+            n = 0
+            package_match = re.compile('\w+([.]\w+)*$').match
+            for package in zcml:
+                n += 1
+                orig = package
+                if ':' in package:
+                    package, filename = package.split(':')
+                else:
+                    filename = None
 
-            # finally, add zcml files to package-includes
-            zcml = options.get('zcml')
-            if zcml:
-                includes_path = os.path.join(
-                    location, 'etc', 'package-includes')
-                zcml = zcml.split()
-                if '*' in zcml:
-                    zcml.remove('*')
+                if '-' in package:
+                    package, suff = package.split('-')
+                    if suff not in ('configure', 'meta', 'overrides'):
+                        raise ValueError('Invalid zcml', orig)
                 else:
-                    shutil.rmtree(includes_path)
-                    os.mkdir(includes_path)
+                    suff = 'configure'
 
-                n = 0
-                package_match = re.compile('\w+([.]\w+)*$').match
-                for package in zcml:
-                    n += 1
-                    orig = package
-                    if ':' in package:
-                        package, filename = package.split(':')
-                    else:
-                        filename = None
+                if filename is None:
+                    filename = suff + '.zcml'
 
-                    if '-' in package:
-                        package, suff = package.split('-')
-                        if suff not in ('configure', 'meta', 'overrides'):
-                            raise ValueError('Invalid zcml', orig)
-                    else:
-                        suff = 'configure'
+                if not package_match(package):
+                    raise ValueError('Invalid zcml', orig)
 
-                    if filename is None:
-                        filename = suff + '.zcml'
+                path = os.path.join(
+                    package_includes,
+                    "%3.3d-%s-%s.zcml" % (n, package, suff),
+                    )
+                open(path, 'w').write(
+                    '<include package="%s" file="%s" />\n'
+                    % (package, filename)
+                    )
+        
+    def update(self):
+        pass
 
-                    if not package_match(package):
-                        raise ValueError('Invalid zcml', orig)
 
-                    path = os.path.join(
-                        includes_path,
-                        "%3.3d-%s-%s.zcml" % (n, package, suff),
-                        )
-                    open(path, 'w').write(
-                        '<include package="%s" file="%s" />\n'
-                        % (package, filename)
-                        )
-                    
-        except:
-            # clean up
-            shutil.rmtree(location)
-            raise
-        
-        return location
+
+zope_conf_template = """\
+# This is the configuration file for the Zope Application Server.
+#
+# This file is generated.  If you edit this file, your edits could
+# easily be lost.
+
+%(options)s
+
+%(database)s
+
+<accesslog>
+  <logfile>
+    path %(log_dir)s/access.log
+  </logfile>
+
+  <logfile>
+    path STDOUT
+  </logfile>
+</accesslog>
+
+<eventlog>
+  <logfile>
+    path %(log_dir)s/z3.log
+    formatter zope.exceptions.log.Formatter
+  </logfile>
+  <logfile>
+    path STDOUT
+    formatter zope.exceptions.log.Formatter
+  </logfile>
+</eventlog>
+"""
+
+zdaemon_conf_template = """\
+# Configuration file for the daemon that manages a Zope 3 process
+#
+# This file is generated.  If you edit this file, your edits could
+# easily be lost.
+<runner>
+  program %(subprogram_dir)s/runzope
+  %(user)sdaemon on
+  transcript %(log_dir)s/transcript.log
+  socket-name %(run_dir)s/zopectlsock
+</runner>
+
+<eventlog>
+  <logfile>
+    path %(log_dir)s/z3.log
+  </logfile>
+</eventlog>
+"""
+
+server_template = """
+<server>
+  type HTTP
+#  type PostmortemDebuggingHTTP
+  address %s
+</server>
+"""

Added: zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/ctl.py
===================================================================
--- zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/ctl.py	2006-10-30 12:10:22 UTC (rev 70994)
+++ zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/ctl.py	2006-10-30 12:13:58 UTC (rev 70995)
@@ -0,0 +1,44 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Top-level controller for 'zopectl'.
+"""
+
+import os
+import zdaemon.zdctl
+
+class ZopectlCmd(zdaemon.zdctl.ZDCmd):
+
+    def do_debug(self, rest):
+        os.system(self._debugzope)
+
+    def help_debug(self):
+        print "debug -- Initialize the Zope application, providing a"
+        print "         debugger object at an interactive Python prompt."
+
+    def do_run(self, arg):
+        os.system(self._scriptzope + ' ' + arg)
+
+    def help_run(self):
+        print "run <script> [args] -- run a Python script with the Zope "
+        print "                       environment set up.  The script has "
+        print "                       'root' exposed as the root container."
+
+
+def main(debugzope, scriptzope, args):
+
+    class Cmd(ZopectlCmd):
+        _debugzope = debugzope
+        _scriptzope = scriptzope
+
+    zdaemon.zdctl.main(args, None, Cmd)


Property changes on: zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/ctl.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/zope3scripts.py
===================================================================
--- zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/zope3scripts.py	2006-10-30 12:10:22 UTC (rev 70994)
+++ zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/zope3scripts.py	2006-10-30 12:13:58 UTC (rev 70995)
@@ -0,0 +1,58 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Zope 3 program entry points
+
+The Zope 3 scripts, scriptzope, and debugzope are distributed
+as templates, rather than as entry points. Here we provide entry-point
+versions.
+
+$Id$
+"""
+
+import os, sys
+import zope.app.debug
+import zope.app.twisted.main
+
+def zglobals(args):
+    db = zope.app.twisted.main.debug(args)
+    if "PYTHONSTARTUP" in os.environ:
+        execfile(os.environ["PYTHONSTARTUP"])
+    
+    app = zope.app.debug.Debugger.fromDatabase(db)
+    return dict(
+        app = app,
+        debugger = app,
+        root = app.root(),
+        __name__ = '__main__',
+        )
+
+
+def script(args):
+    globs = zglobals(args[:2])
+    sys.argv[:] = args[2:]
+    globs['__file__'] = sys.argv[0]
+    execfile(sys.argv[0], globs)
+    sys.exit()
+
+banner = """Welcome to the Zope 3 "debugger".
+The application root object is available as the root variable.
+A Zope debugger instance is available as the debugger (aka app) variable.
+"""
+
+def debug(args):
+    globs = zglobals(args)
+    import code
+    code.interact(banner=banner, local=globs)
+
+    


Property changes on: zc.recipe.zope3instance/branches/dev/src/zc/recipe/zope3instance/zope3scripts.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native



More information about the Checkins mailing list