Code

applied patch 688595
[roundup.git] / roundup / admin.py
index ff961b77eb63c50084f049ff32a7d8835e20ba46..94e38462d4eb60dda9283f68ecf66d4893fdef73 100644 (file)
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: admin.py,v 1.32 2002-09-24 01:36:04 richard Exp $
+# $Id: admin.py,v 1.38 2003-02-25 10:19:31 richard Exp $
+
+'''Administration commands for maintaining Roundup trackers.
+'''
 
 import sys, os, getpass, getopt, re, UserDict, shlex, shutil
 try:
@@ -51,7 +54,17 @@ class UsageError(ValueError):
     pass
 
 class AdminTool:
+    ''' A collection of methods used in maintaining Roundup trackers.
+
+        Typically these methods are accessed through the roundup-admin
+        script. The main() method provided on this class gives the main
+        loop for the roundup-admin script.
 
+        Actions are defined by do_*() methods, with help for the action
+        given in the method docstring.
+
+        Additional help may be supplied by help_*() methods.
+    '''
     def __init__(self):
         self.commands = CommandDict()
         for k in AdminTool.__dict__.keys():
@@ -73,14 +86,20 @@ class AdminTool:
             raise UsageError, _('no such class "%(classname)s"')%locals()
 
     def props_from_args(self, args):
+        ''' Produce a dictionary of prop: value from the args list.
+
+            The args list is specified as ``prop=value prop=value ...``.
+        '''
         props = {}
         for arg in args:
             if arg.find('=') == -1:
-                raise UsageError, _('argument "%(arg)s" not propname=value')%locals()
+                raise UsageError, _('argument "%(arg)s" not propname=value'
+                    )%locals()
             try:
                 key, value = arg.split('=')
             except ValueError:
-                raise UsageError, _('argument "%(arg)s" not propname=value')%locals()
+                raise UsageError, _('argument "%(arg)s" not propname=value'
+                    )%locals()
             if value:
                 props[key] = value
             else:
@@ -88,6 +107,8 @@ class AdminTool:
         return props
 
     def usage(self, message=''):
+        ''' Display a simple usage message.
+        '''
         if message:
             message = _('Problem: %(message)s)\n\n')%locals()
         print _('''%(message)sUsage: roundup-admin [options] <command> <arguments>
@@ -106,6 +127,8 @@ Help:
         self.help_commands()
 
     def help_commands(self):
+        ''' List the commands available with their precis help.
+        '''
         print _('Commands:'),
         commands = ['']
         for command in self.commands.values():
@@ -118,11 +141,13 @@ Help:
         print
 
     def help_commands_html(self, indent_re=re.compile(r'^(\s+)\S+')):
-       commands = self.commands.values()
+        ''' Produce an HTML command list.
+        '''
+        commands = self.commands.values()
         def sortfun(a, b):
             return cmp(a.__name__, b.__name__)
         commands.sort(sortfun)
-       for command in commands:
+        for command in commands:
             h = command.__doc__.split('\n')
             name = command.__name__[3:]
             usage = h[0]
@@ -303,12 +328,14 @@ Command help:
         # XXX perform a unit test based on the user's selections
 
         # install!
-        init.install(tracker_home, template, backend)
+        init.install(tracker_home, template)
+        init.write_select_db(tracker_home, backend)
 
         print _('''
  You should now edit the tracker configuration file:
    %(config_file)s
- ... at a minimum, you must set MAILHOST, MAIL_DOMAIN and ADMIN_EMAIL.
+ ... at a minimum, you must set MAILHOST, TRACKER_WEB, MAIL_DOMAIN and
+ ADMIN_EMAIL.
 
  If you wish to modify the default schema, you should also edit the database
  initialisation file:
@@ -342,19 +369,31 @@ Command help:
         # make sure the tracker home is installed
         if not os.path.exists(tracker_home):
             raise UsageError, _('Instance home does not exist')%locals()
-        if not os.path.exists(os.path.join(tracker_home, 'html')):
+        try:
+            tracker = roundup.instance.open(tracker_home)
+        except roundup.instance.TrackerError:
             raise UsageError, _('Instance has not been installed')%locals()
 
         # is there already a database?
-        if os.path.exists(os.path.join(tracker_home, 'db')):
+        try:
+            db_exists = tracker.select_db.Database.exists(tracker.config)
+        except AttributeError:
+            # TODO: move this code to exists() static method in every backend
+            db_exists = os.path.exists(os.path.join(tracker_home, 'db'))
+        if db_exists:
             print _('WARNING: The database is already initialised!')
             print _('If you re-initialise it, you will lose all the data!')
             ok = raw_input(_('Erase it? Y/[N]: ')).strip()
             if ok.lower() != 'y':
                 return 0
 
-            # nuke it
-            shutil.rmtree(os.path.join(tracker_home, 'db'))
+            # Get a database backend in use by tracker
+            try:
+                # nuke it
+                tracker.select_db.Database.nuke(tracker.config)
+            except AttributeError:
+                # TODO: move this code to nuke() static method in every backend
+                shutil.rmtree(os.path.join(tracker_home, 'db'))
 
         # GO
         init.initialise(tracker_home, adminpw)
@@ -397,7 +436,7 @@ Command help:
         return 0
 
 
-    def do_set(self, args):
+    def do_set(self, args, pwre = re.compile(r'{(\w+)}(.+)')):
         '''Usage: set [items] property=value property=value ...
         Set the given properties of one or more items(s).
 
@@ -447,7 +486,15 @@ Command help:
                 elif isinstance(proptype, hyperdb.String):
                     continue
                 elif isinstance(proptype, hyperdb.Password):
-                    props[key] = password.Password(value)
+                    m = pwre.match(value)
+                    if m:
+                        # password is being given to us encrypted
+                        p = password.Password()
+                        p.scheme = m.group(1)
+                        p.password = m.group(2)
+                        props[key] = p
+                    else:
+                        props[key] = password.Password(value)
                 elif isinstance(proptype, hyperdb.Date):
                     try:
                         props[key] = date.Date(value)
@@ -463,12 +510,13 @@ Command help:
                 elif isinstance(proptype, hyperdb.Boolean):
                     props[key] = value.lower() in ('yes', 'true', 'on', '1')
                 elif isinstance(proptype, hyperdb.Number):
-                    props[key] = int(value)
+                    props[key] = float(value)
 
             # try the set
             try:
                 apply(cl.set, (itemid, ), props)
             except (TypeError, IndexError, ValueError), message:
+                import traceback; traceback.print_exc()
                 raise UsageError, message
         return 0
 
@@ -570,7 +618,7 @@ Command help:
             value = cl.get(nodeid, key)
             print _('%(key)s: %(value)s')%locals()
 
-    def do_create(self, args):
+    def do_create(self, args, pwre = re.compile(r'{(\w+)}(.+)')):
         '''Usage: create classname property=value ...
         Create a new entry of a given class.
 
@@ -633,13 +681,21 @@ Command help:
                 except ValueError, message:
                     raise UsageError, _('"%(value)s": %(message)s')%locals()
             elif isinstance(proptype, hyperdb.Password):
-                props[propname] = password.Password(value)
+                m = pwre.match(value)
+                if m:
+                    # password is being given to us encrypted
+                    p = password.Password()
+                    p.scheme = m.group(1)
+                    p.password = m.group(2)
+                    props[propname] = p
+                else:
+                    props[propname] = password.Password(value)
             elif isinstance(proptype, hyperdb.Multilink):
                 props[propname] = value.split(',')
             elif isinstance(proptype, hyperdb.Boolean):
                 props[propname] = value.lower() in ('yes', 'true', 'on', '1')
             elif isinstance(proptype, hyperdb.Number):
-                props[propname] = int(value)
+                props[propname] = float(value)
 
         # check for the key property
         propname = cl.getkey()