[Zope-Checkins] CVS: Zope/lib/python/Zope/Startup/misc - TextBlockFormatter.py:1.2 __init__.py:1.2 factory.py:1.2 lock_file.py:1.2 zpasswd.py:1.2

Fred L. Drake, Jr. fred@zope.com
Wed, 29 Jan 2003 15:25:51 -0500


Update of /cvs-repository/Zope/lib/python/Zope/Startup/misc
In directory cvs.zope.org:/tmp/cvs-serv21529/misc

Added Files:
	TextBlockFormatter.py __init__.py factory.py lock_file.py 
	zpasswd.py 
Log Message:
Update from chrism-install-branch.

=== Zope/lib/python/Zope/Startup/misc/TextBlockFormatter.py 1.1 => 1.2 ===
--- /dev/null	Wed Jan 29 15:25:51 2003
+++ Zope/lib/python/Zope/Startup/misc/TextBlockFormatter.py	Wed Jan 29 15:25:17 2003
@@ -0,0 +1,128 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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
+# 
+##############################################################################
+"""
+Revision information:
+$Id$
+"""
+import string, math
+
+def format(text, max_width=80, indent=0, trailing_lines_indent_more=0):
+    text = string.expandtabs(string.replace(text, '\r', ''))
+    lines = string.split(text, '\n')
+    aggregate = []
+    for line in lines:
+        if len(line) <= max_width-1:
+            # this line is short enough to output
+            aggregate.append(line)
+        else:
+            lines = splitlongline(line, max_width)
+            aggregate.extend(lines)
+    out = []
+    i = 0
+    for line in aggregate:
+        spaces = ' ' * indent
+        if i != 0 and trailing_lines_indent_more:
+            spaces = spaces + (' ' * trailing_lines_indent_more)
+        out.append('%s%s' % (spaces, line))
+        i = i + 1
+    return string.join(out, '\n')
+
+def splitword(word, max_width=80, linepos=0):
+    # some lines may have single words that exceed the max_width
+    # We want to break apart long words into as many chunks as necessary
+    if len(word) <= max_width:
+        return [word]
+    first_chunk_len = max_width-1-linepos
+    firstchunk = word[:first_chunk_len]
+    word = word[first_chunk_len:]
+    numchunks = int(math.ceil(len(word) / float(max_width-1)))
+    index = 0
+    tmp = [firstchunk]
+    for chunknum in range(numchunks):
+        chunk = word[index:index+max_width-1]
+        tmp.append(chunk)
+        index = index + max_width-1
+    return tmp
+    
+def splitlongline(line, max_width=80):
+    # split a "long" line defined by max_width into a list of lines
+    line = string.strip(line)
+    words = string.split(line, ' ')
+    wordnum = 0
+    # iterate over all the words in the line, extending the word list
+    # necessary for too-long words
+                
+    aggregate = []
+    linelen = 0
+    wordnum = 0
+    while words:
+        word = words.pop(0)
+        if not word: continue
+        if len(word) > max_width:
+            new_words = splitword(word, max_width, linelen)
+            word = new_words[0]
+            for new_word in new_words[1:]:
+                words.insert(wordnum, new_word)
+                wordnum = wordnum + 1
+        if words:
+            next_word = words[0]
+        else:
+            next_word = None
+        if next_word is None:
+            aggregate.append(word)
+            wordnum = wordnum + 1
+            continue
+        maybe_len = linelen + len(word) + len(next_word)
+        if maybe_len >= max_width-1:
+            aggregate.append(word)
+            aggregate.append(None)
+            linelen = 0
+        else:
+            aggregate.append(word)
+            linelen = linelen + len(word) + 1
+        wordnum = wordnum + 1
+
+    s = ""
+    last = None
+    for item in aggregate:
+        if item is None:
+            s = '%s\n' % s
+        elif last is None:
+            s = '%s%s' % (s, item)
+        else:
+            s = '%s %s' % (s, item)
+        last = item
+    return string.split(s, '\n')
+
+long = """
+To turn a component into a product you must fulfill many contracts. For the most part these contracts are not yet defined in terms of interfaces. Instead you must subclass from base classes that implement the contracts. This makes building products confusing, and this is an area that we are actively working on improving.  Hereisalonglinethatshouldbecaughtandbrokenupbytheformatter,hopefullyitllgetsplitupwhenirunitthroughthere."""
+long2 = """
+Hereisalonglinethatshouldbecaughtandbrokenupbytheformatter,hopefullyitllgetsplitupwhenirunitthroughthere."""
+long3 = """
+To turn a component into a product you must fulfill many contracts. For the most part these contracts are not yet defined in terms of interfaces.
+
+Instead you must subclass from base classes that implement the contracts. This makes building products confusing, and this is an area that we are
+
+actively working on improving.  Hereisalonglinethatshouldbecaughtandbrokenupbytheformatter,hopefullyitllgetsplitupwhenirunitthroughthere."""
+
+if __name__ == '__main__':
+    print format(long, 60, 10)
+    print format(long)
+    print format(long2, 60, 10)
+    print format(long2)
+    print format(long3, 60, 10)
+    print format(long3)
+
+
+


=== Zope/lib/python/Zope/Startup/misc/__init__.py 1.1 => 1.2 ===
--- /dev/null	Wed Jan 29 15:25:51 2003
+++ Zope/lib/python/Zope/Startup/misc/__init__.py	Wed Jan 29 15:25:17 2003
@@ -0,0 +1 @@
+""" Placeholder module file """


=== Zope/lib/python/Zope/Startup/misc/factory.py 1.1 => 1.2 ===
--- /dev/null	Wed Jan 29 15:25:51 2003
+++ Zope/lib/python/Zope/Startup/misc/factory.py	Wed Jan 29 15:25:17 2003
@@ -0,0 +1,53 @@
+_marker = []
+
+def importer(name):
+    components = name.split('.')
+    start = components[0]
+    g = globals()
+    package = __import__(start, g, g)
+    modulenames = [start]
+    for component in components[1:]:
+        modulenames.append(component)
+        try:
+            package = getattr(package, component)
+        except AttributeError:
+            name = '.'.join(modulenames)
+            package = __import__(name, g, g, component)
+    return package
+
+class Factory:
+    """
+    A generic wrapper for instance construction and function calling used
+    to delay construction/call until necessary.  The class path is the dotted
+    name to the class or function, args are the positional args, kw are the
+    keyword args. If it is specified, 'callback' is a function which will be
+    called back after constructing an instance or calling a function.  It must
+    take the instance (or the result of the function) as a single argument.
+    """
+    def __init__(self, class_path, callback, *args, **kw):
+        self.class_path = class_path
+        self.callback = callback
+        self.setArgs(list(args), kw)
+        self.resolved = _marker
+
+    def __repr__(self):
+        return ('<Factory instance for class "%s" with positional args "%s" '
+                'and keword args "%s"' % (self.class_path, self.args, self.kw))
+
+    __str__ = __repr__
+
+    def __call__(self):
+        if self.resolved is _marker:
+            package = importer(self.class_path)
+            inst = package(*self.args, **self.kw)
+            if self.callback:
+                self.callback(inst)
+            self.resolved = inst
+        return self.resolved
+
+    def setArgs(self, args, kw):
+        self.args = args
+        self.kw = kw
+
+    def getArgs(self):
+        return (self.args, self.kw)


=== Zope/lib/python/Zope/Startup/misc/lock_file.py 1.1 => 1.2 ===
--- /dev/null	Wed Jan 29 15:25:51 2003
+++ Zope/lib/python/Zope/Startup/misc/lock_file.py	Wed Jan 29 15:25:17 2003
@@ -0,0 +1,30 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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
+#
+##############################################################################
+""" Utilities for file locking """
+try:
+    import fcntl
+    def lock_file(file):
+        un=file.fileno()
+        fcntl.flock(un, fcntl.LOCK_EX | fcntl.LOCK_NB)
+except:
+    # Try windows-specific code:
+    try:
+        from ZODB.winlock import LockFile
+        def lock_file(file):
+            un=file.fileno()
+            LockFile(un,0,0,1,0) # just lock the first byte, who cares
+    except:
+        # we don't understand any kind of locking, forget it
+        def lock_file(file):
+            pass


=== Zope/lib/python/Zope/Startup/misc/zpasswd.py 1.1 => 1.2 ===
--- /dev/null	Wed Jan 29 15:25:51 2003
+++ Zope/lib/python/Zope/Startup/misc/zpasswd.py	Wed Jan 29 15:25:17 2003
@@ -0,0 +1,200 @@
+#!/usr/bin/env 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
+#
+##############################################################################
+"""Zope user bootstrap system"""
+
+__version__='$Revision$ '[11:-2]
+
+import sys,  sha, binascii, random, getopt, getpass, os
+
+try:
+    from crypt import crypt
+except ImportError:
+    crypt = None
+
+def generate_salt():
+    """Generate a salt value for the crypt function."""
+    salt_choices = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                    "abcdefghijklmnopqrstuvwxyz"
+                    "0123456789./")
+    return random.choice(salt_choices)+random.choice(salt_choices)
+
+def generate_passwd(password, encoding):
+    encoding=encoding.upper()
+    if encoding == 'SHA':
+        pw = '{SHA}' + binascii.b2a_base64(sha.new(password).digest())[:-1]
+    elif encoding == 'CRYPT':
+        pw = '{CRYPT}' + crypt(password, generate_salt())
+    elif encoding == 'CLEARTEXT':
+        pw = password
+
+    return pw
+
+def write_generated_password(home, ac_path, username):
+    pw_choices = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                  "abcdefghijklmnopqrstuvwxyz"
+                  "0123456789!")
+    acfile=open(ac_path, 'w')
+    pw = ''
+    for i in range(8):
+        pw = pw + random.choice(pw_choices)
+    acfile.write('%s:%s' % (username, generate_passwd(pw, 'SHA')))
+    acfile.close()
+    os.system('chmod 644 %s' % ac_path)
+    return pw
+
+def write_access(home, user='', group=''):
+    ac_path=os.path.join(home, 'access')
+    if not os.path.exists(ac_path):
+        print '-'*78
+        print 'creating default access file'
+        pw = write_generated_password(home, ac_path, 'emergency')
+        print """Note:
+        The emergency user name and password are 'emergency'
+        and '%s'.
+
+        You can change the emergency name and password with the
+        zpasswd script.  To find out more, type:
+
+        %s zpasswd.py
+        """ % (pw, sys.executable)
+
+        import do; do.ch(ac_path, user, group)
+
+def write_inituser(home, user='', group=''):
+    ac_path=os.path.join(home, 'inituser')
+    if not os.path.exists(ac_path):
+        print '-'*78
+        print 'creating default inituser file'
+        pw = write_generated_password(home, ac_path, 'admin')
+        print """Note:
+        The initial user name and password are 'admin'
+        and '%s'.
+
+        You can change the name and password through the web
+        interface or using the 'zpasswd.py' script.
+        """ % pw
+
+        import do; do.ch(ac_path, user, group)
+
+
+def main(argv):
+    short_options = ':u:p:e:d:'
+    long_options = ['username=',
+                    'password=',
+                    'encoding=',
+                    'domains=']
+
+    usage = """Usage: %s [options] filename
+If this program is called without command-line options, it will prompt
+for all necessary information.  The available options are:
+
+    -u / --username=
+    Set the username to be used for the initial user or the emergency user
+
+    -p / --password=
+    Set the password
+
+    -e / --encoding=
+    Set the encryption/encoding rules.  Defaults to SHA-1. OPTIONAL
+
+    -d / --domains=
+    Set the domain names that the user user can log in from.  Defaults to
+    any. OPTIONAL.
+
+    Filename is required and should be the name of the file to store the
+    information in (usually "inituser" or "access").
+
+Copyright (C) 1999, 2000 Digital Creations, Inc.
+""" % argv[0]
+
+    try:
+        if len(argv) < 2:
+            raise "CommandLineError"
+
+        optlist, args = getopt.getopt(sys.argv[1:], short_options, long_options)
+
+        if len(args) != 1:
+            raise "CommandLineError"
+
+        access_file = open(args[0], 'w')
+
+        if len(optlist) > 0:
+            # Set the sane defaults
+            username = ''
+            encoding = 'SHA'
+            domains = ''
+
+            for opt in optlist:
+                if (opt[0] == '-u') or (opt[0] == '--username'):
+                    username = opt[1]
+                elif (opt[0] == '-p') or (opt[0] == '--password'):
+                    password = opt[1]
+                elif (opt[0] == '-e') or (opt[0] == '--encoding'):
+                    encoding = opt[1]
+                elif (opt[0] == '-d') or (opt[0] == '--domains'):
+                    domains = ":" + opt[1]
+
+            # Verify that we got what we need
+            if not username or not password:
+                raise "CommandLineError"
+
+            access_file.write(username + ':' +
+                              generate_passwd(password, encoding) +
+                              domains)
+
+        else:
+            # Run through the prompts
+            while 1:
+                username = raw_input("Username: ")
+                if username != '':
+                    break
+
+            while 1:
+                password = getpass.getpass("Password: ")
+                verify = getpass.getpass("Verify password: ")
+                if verify == password:
+                    break
+                else:
+                    password = verify = ''
+                    print "Password mismatch, please try again..."
+
+            while 1:
+                print """
+Please choose a format from:
+
+SHA - SHA-1 hashed password (default)
+CRYPT - UNIX-style crypt password
+CLEARTEXT - no protection
+"""
+                encoding = raw_input("Encoding: ")
+                if encoding == '':
+                    encoding = 'SHA'
+                    break
+                if encoding.upper() in ['SHA', 'CRYPT', 'CLEARTEXT']:
+                    break
+
+            domains = raw_input("Domain restrictions: ")
+            if domains: domains = ":" + domains
+
+            access_file.write(username + ":" +
+                              generate_passwd(password, encoding) +
+                              domains)
+
+    except "CommandLineError":
+        sys.stderr.write(usage)
+        sys.exit(1)
+
+
+# If called from the command line
+if __name__=='__main__': main(sys.argv)