[Zope-Checkins] CVS: Zope/utilities - copyzopeskel.py:1.1 mkzopeinstance.py:1.5

Chris McDonough chrism@zope.com
Thu, 24 Jul 2003 15:58:22 -0400


Update of /cvs-repository/Zope/utilities
In directory cvs.zope.org:/tmp/cvs-serv18356

Modified Files:
	mkzopeinstance.py 
Added Files:
	copyzopeskel.py 
Log Message:
Split functionality of mkzopeinstance into mkzopeinstance.py and copyzopeskel.py.  copyzopeskel.py can be used by packagers to create custom skeleton directories.


=== Added File Zope/utilities/copyzopeskel.py ===
#! python
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
#
##############################################################################
"""%(program)s:  Create a target directory from a skeleton directory.

usage:  %(program)s [options]

Options:
-h/--help -- print this help text
-s/--sourcedir -- the skeleton source directory
-t/--targetdir -- the directory to which the skeleton files will be copied
-u/--uid       -- the username/uid of the user who will own the target files
-g/--gid       -- the groupname/gid of the group who will own the target files
-r/--replace   -- specify replacement value for .in file

This script may be used to install a custom Zope instance home
skeleton directory.  It is most useful when used to install a skeleton
which does not follow the standard 'one-directory-as-instance-home'
paradigm used by the stock Zope source install.

The value of --targetdir should be the directory where you would like to copy
the skeleton hierarchy.  For many packagers, this will be "/" or "/usr"
or "/usr/local".

The value of --sourcedir should be a directory which contains a custom skeleton
hierarchy.   For many packagers, the skeleton source directory may contain
directories like "usr" and "bin" and these directories will contain files
and other directories, comprising an installation hierarchy suitable for your
platform.

The skeleton source hierarchy may contain any kind of file.  Files
in the skeleton hierarchy that end with a ".in" extension will go through
textual substitution before they are placed in the target directory.  When
they are placed in the target directory, the ".in" extension is removed.

Specify textual replacement values by passing one or more --replace= options
to the script.  The value of each replace option needs to be
in the following format: --replace=key:value.  'key' is the value that
will be replaced (minus the "<<" and ">>" values expected by the
replacement).  'value' is the value that should be used for replacement.

Files which do not have an ".in" extension are copied without substitution.
All file mode bits from files/dirs in the skeleton source directory are copied
along with the file/directory itself.  If the --uid and/or --gid flags are
used, all directories and files created by this script will be provided with
this owner and/or group.  Otherwise, the uid and group owner of the files will
be the executing user's.  Existing directory structures and files are left
unchanged.  If a file already exists in the target directory, it is left
unchanged and the source file is not copied.  If a directory already exists in
the target directory, its ownership information and mode bit settings are left
unchanged.
"""

import os
import shutil
import sys
import getopt

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:],
            "hs:t:u:g:r:",
            ["help", "sourcedir=", "targetdir=", "uid=", "gid=",
             "replace="]
            )
    except getopt.GetoptError, msg:
        usage(sys.stderr, msg)
        sys.exit(2)

    script = os.path.abspath(sys.argv[0])
    sourcedir = None
    targetdir = None
    uid = None
    gid = None
    replacements = {}

    for opt, arg in opts:
        if opt in ("-h", "--help"):
            usage(sys.stdout)
            sys.exit()
        if opt in ("-s", "--sourcedir"):
            sourcedir = os.path.abspath(os.path.expanduser(arg))
            if not sourcedir:
                usage(sys.stderr, "sourcedir must not be empty")
                sys.exit(2)
        if opt in ("-t", "--targetdir"):
            targetdir = os.path.abspath(os.path.expanduser(arg))
            if not targetdir:
                usage(sys.stderr, "targetdir must not be empty")
                sys.exit(2)
        if opt in ("-u", "--uid"):
            if not arg:
                usage(sys.stderr, "uid must not be empty")
                sys.exit(2)
            try:
                if os.getuid() != 0:
                    usage(sys.stderr, "You must be root to specify a uid")
                    sys.exit(2)
                try:
                    uid = int(arg)
                except:
                    try:
                        import pwd
                        uid = pwd.getpwnam(arg)[2]
                        if not gid:
                            gid = pwd.getpwnam(arg)[3]
                    except KeyError:
                        usage(sys.stderr,
                              "The user indicated by uid does not exist on "
                              "your system")
                        sys.exit(2)
            except (ImportError, AttributeError):
                usage(sys.stderr,
                       "Your system does not support the gid or uid options")
                sys.exit(2)
        if opt in ("-g", "--gid"):
            if not arg:
                usage(sys.stderr, "gid must not be empty")
                sys.exit(2)
            try:
                if os.getuid() != 0:
                    usage(sys.stderr, "You must be root to specify a gid")
                    sys.exit(2)
                try:
                    gid = int(arg)
                except:
                    try:
                        import pwd
                        gid = pwd.getpwnam(arg)[3]
                    except KeyError:
                        usage(sys.stderr,
                              "The user indicated by gid does not exist on "
                              "your system")
                        sys.exit(2)
            except (ImportError, AttributeError):
                usage(sys.stderr,
                       "Your system does not support the gid or uid options")
                sys.exit(2)

        if opt in ("-r", "--replace"):
            if not arg:
                continue
            k, v = arg.split(':', 1)
            replacements[k] = v

    if not sourcedir:
        usage(sys.stderr, "Must specify sourcedir")
        sys.exit(2)

    if not targetdir:
        usage(sys.stderr, "Must specify targetdir")
        sys.exit(2)

    copyskel(sourcedir, targetdir, uid, gid, **replacements)

def copyskel(sourcedir, targetdir, uid, gid, **replacements):
    """ This is an independent function because we'd like to
    import and call it from mkzopeinstance """
    # Create the top of the instance:
    if not os.path.exists(targetdir):
        os.makedirs(targetdir)

    # This is fairly ugly.  The chdir() makes path manipulation in the
    # walk() callback a little easier (less magical), so we'll live
    # with it.
    pwd = os.getcwd()
    os.chdir(sourcedir)
    try:
        try:
            os.path.walk(os.curdir, copydir,
                         (targetdir, replacements, uid, gid))
        finally:
            os.chdir(pwd)
    except (IOError, OSError), msg:
        print >>sys.stderr, msg
        sys.exit(1)

CVS = os.path.normcase("CVS")

def copydir((targetdir, replacements, uid, gid), sourcedir, names):
    # Don't recurse into CVS directories:
    for name in names[:]:
        if os.path.normcase(name) == CVS:
            names.remove(name)
        elif os.path.isfile(os.path.join(sourcedir, name)):
            # Copy the file:
            sn, ext = os.path.splitext(name)
            if os.path.normcase(ext) == ".in":
                dst = os.path.join(targetdir, sourcedir, sn)
                if os.path.exists(dst):
                    continue
                copyin(os.path.join(sourcedir, name), dst, replacements, uid,
                       gid)
                if uid is not None:
                    os.chown(dst, uid, gid)
            else:
                src = os.path.join(sourcedir, name)
                dst = os.path.join(targetdir, src)
                if os.path.exists(dst):
                    continue
                shutil.copyfile(src, dst)
                shutil.copymode(src, dst)
                if uid is not None:
                    os.chown(dst, uid, gid)
        else:
            # Directory:
            dn = os.path.join(targetdir, sourcedir, name)
            if not os.path.exists(dn):
                os.mkdir(dn)
                shutil.copymode(os.path.join(sourcedir, name), dn)
                if uid is not None:
                    os.chown(dn, uid, gid)

def copyin(src, dst, replacements, uid, gid):
    ifp = open(src)
    text = ifp.read()
    ifp.close()
    for k in replacements:
        text = text.replace("<<%s>>" % k, replacements[k])
    ofp = open(dst, "w")
    ofp.write(text)
    ofp.close()
    shutil.copymode(src, dst)
    if uid is not None:
        os.chown(dst, uid, gid)

def usage(stream, msg=None):
    if msg:
        print >>stream, msg
        print >>stream
    program = os.path.basename(sys.argv[0])
    print >>stream, __doc__ % {"program": program}

if __name__ == '__main__':
    main()


=== Zope/utilities/mkzopeinstance.py 1.4 => 1.5 ===
--- Zope/utilities/mkzopeinstance.py:1.4	Tue Jul 22 18:11:08 2003
+++ Zope/utilities/mkzopeinstance.py	Thu Jul 24 15:58:16 2003
@@ -17,28 +17,25 @@
 usage:  %(program)s [options]
 
 Options:
--d/--dir --  the directory to which the instance files should be installed
 -h/--help -- print this help text
+-d/--dir  -- the dir in which the instance home should be created
 -u/--user NAME:PASSWORD -- set the user name and password of the initial user
--s/--skel -- the 'skeleton' directory which contains instance files
--z/--home -- the zope home directory (aka ZOPE_HOME) (defaults to ..)
--l/--lib --  the zope lib directory (aka SOFTWARE_HOME) (defaults to
-             ../lib/python)
 
-If no arguments are specified, the installer will ask for dir, username, and
-password and will use ZOPEHOME/skel as the skeleton directory.
+When run without arguments, this script will ask for the information necessary
+to create a Zope instance home.
 """
 
 import getopt
 import os
 import shutil
 import sys
+import copyzopeskel
 
 def main():
     try:
         opts, args = getopt.getopt(sys.argv[1:],
-            "hu:z:d:s:z:l:",
-            ["help", "user=", "dir=", "skel=", "home=", "lib="]
+            "hu:z:d:s:z:l:i:o:g:c:",
+            ["help", "user=", "dir="]
             )
     except getopt.GetoptError, msg:
         usage(sys.stderr, msg)
@@ -47,60 +44,52 @@
     script = os.path.abspath(sys.argv[0])
     user = None
     password = None
-    dirname = None
-    zopehome = None
-    softwarehome = None
-    skel = None
+    skeltarget = None
 
     for opt, arg in opts:
         if opt in ("-d", "--dir"):
-            dirname = os.path.expanduser(os.path.abspath(arg))
-            if not dirname:
-                usage(sys.stderr, "dirname must not be empty")
+            skeltarget = os.path.abspath(os.path.expanduser(arg))
+            if not skeltarget:
+                usage(sys.stderr, "dir must not be empty")
                 sys.exit(2)
         if opt in ("-h", "--help"):
             usage(sys.stdout)
             sys.exit()
         if opt in ("-u", "--user"):
+            if not arg:
+                usage(sys.stderr, "user must not be empty")
+                sys.exit(2)
             if not ":" in arg:
                 usage(sys.stderr, "user must be specified as name:password")
                 sys.exit(2)
             user, password = arg.split(":", 1)
-        if opt in ("-s", "--skel"):
-            skel = os.path.expanduser(os.path.abspath(arg))
-            if not skel:
-                usage(sys.stderr, "skel must not be empty")
-                sys.exit(2)
-        if opt in ("-h", "--home"):
-            zopehome = os.path.expanduser(os.path.abspath(arg))
-            if not zopehome:
-                usage(sys.stderr, "home must not be empty")
-                sys.exit(2)
-        if opt in ("-l", "--lib"):
-            softwarehome = os.path.expanduser(os.path.abspath(arg))
-            if not softwarehome:
-                usage(sys.stderr, "lib must not be empty")
-                sys.exit(2)
 
-    # interactively ask for dirname and initial user name/passwd
-    if not dirname:
-        dirname = get_dirname()
-    dirname = os.path.expanduser(dirname)
-    inituser = os.path.join(dirname, "inituser")
+    if not skeltarget:
+        # interactively ask for skeltarget and initial user name/passwd.
+        # cant set custom instancehome in interactive mode, we default
+        # to skeltarget.
+        skeltarget = instancehome = os.path.abspath(
+            os.path.expanduser(get_skeltarget())
+            )
+
+    instancehome = skeltarget
+    zopehome = os.path.dirname(os.path.dirname(script))
+    softwarehome = os.path.join(zopehome, "lib", "python")
+    configfile = os.path.join(instancehome, 'etc', 'zope.conf')
+    skelsrc = os.path.join(zopehome, "skel")
+
+    inituser = os.path.join(instancehome, "inituser")
     if not (user or os.path.exists(inituser)):
         user, password = get_inituser()
 
-    # use defaults for zopehome, softwarehome, and skel if they're not
-    # given
-    if zopehome is None:
-        zopehome = os.path.dirname(os.path.dirname(script))
-    if softwarehome is None:
-        softwarehome = os.path.join(zopehome, "lib", "python")
-    if skel is None:
-        skel = os.path.join(zopehome, "skel")
-
-    makeinstance(dirname, user, password, inituser, zopehome, softwarehome,
-                 skel)
+    kw = {
+        "PYTHON": sys.executable,
+        "INSTANCE_HOME": instancehome,
+        "SOFTWARE_HOME": softwarehome,
+        "ZOPE_HOME": zopehome,
+        }
+    copyzopeskel.copyskel(skelsrc, skeltarget, None, None, **kw)
+    write_inituser(inituser, user, password)
 
 def usage(stream, msg=None):
     if msg:
@@ -109,19 +98,19 @@
     program = os.path.basename(sys.argv[0])
     print >>stream, __doc__ % {"program": program}
 
-def get_dirname():
+def get_skeltarget():
     print 'Please choose a directory in which you\'d like to install'
     print 'Zope "instance home" files such as database files, configuration'
     print 'files, etc.'
     print
     while 1:
-        dirname = raw_input("Directory: ").strip()
-        if dirname == '':
+        skeltarget = raw_input("Directory: ").strip()
+        if skeltarget == '':
             print 'You must specify a directory'
             continue
         else:
             break
-    return dirname
+    return skeltarget
 
 def get_inituser():
     import getpass
@@ -142,36 +131,6 @@
             print "Password mismatch, please try again..."
     return user, passwd
 
-def makeinstance(dirname, user, password, inituser, zopehome,
-                 softwarehome, skel):
-    # Create the top of the instance:
-    if not os.path.exists(dirname):
-        os.makedirs(dirname)
-
-    replacements = {
-        "PYTHON": sys.executable,
-        "INSTANCE_HOME": dirname,
-        "SOFTWARE_HOME": softwarehome,
-        "ZOPE_HOME": zopehome,
-        }
-
-    # This is fairly ugly.  The chdir() makes path manipulation in the
-    # walk() callback a little easier (less magical), so we'll live
-    # with it.
-    pwd = os.getcwd()
-    os.chdir(skel)
-    try:
-        try:
-            os.path.walk(os.curdir, copyskel, (dirname, replacements))
-        finally:
-            os.chdir(pwd)
-    except (IOError, OSError), msg:
-        print >>sys.stderr, msg
-        sys.exit(1)
-
-    if user:
-        write_inituser(inituser, user, password)
-
 def write_inituser(fn, user, password):
     import binascii
     import sha
@@ -180,45 +139,6 @@
     fp.write('%s:{SHA}%s\n' % (user, pw))
     fp.close()
     os.chmod(fn, 0644)
-
-CVS = os.path.normcase("CVS")
-
-def copyskel((basedir, replacements), dirname, names):
-    # Don't recurse into CVS directories:
-    for name in names[:]:
-        if os.path.normcase(name) == CVS:
-            names.remove(name)
-        elif os.path.isfile(os.path.join(dirname, name)):
-            # Copy the file:
-            sn, ext = os.path.splitext(name)
-            if os.path.normcase(ext) == ".in":
-                dst = os.path.join(basedir, dirname, sn)
-                if os.path.exists(dst):
-                    continue
-                copyin(os.path.join(dirname, name), dst, replacements)
-            else:
-                src = os.path.join(dirname, name)
-                dst = os.path.join(basedir, src)
-                if os.path.exists(dst):
-                    continue
-                shutil.copyfile(src, dst)
-        else:
-            # Directory:
-            dn = os.path.join(basedir, dirname, name)
-            if not os.path.exists(dn):
-                os.mkdir(dn)
-
-def copyin(src, dst, replacements):
-    ifp = open(src)
-    text = ifp.read()
-    ifp.close()
-    for k in replacements:
-        text = text.replace("<<%s>>" % k, replacements[k])
-    ofp = open(dst, "w")
-    ofp.write(text)
-    ofp.close()
-    shutil.copymode(src, dst)
-
 
 if __name__ == "__main__":
     main()