Code

Pushed the base code for the extended schema CGI interface back into the
[roundup.git] / roundup-admin
index a1be5c39a190cb073273bc43d2b0ec0092be2edd..85eee36243e2607bbeb6bd644c025b5d231506b0 100755 (executable)
@@ -16,7 +16,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: roundup-admin,v 1.15 2001-08-07 00:24:42 richard Exp $
+# $Id: roundup-admin,v 1.22 2001-10-09 07:25:59 richard Exp $
 
 import sys
 if int(sys.version[0]) < 2:
@@ -24,7 +24,7 @@ if int(sys.version[0]) < 2:
     sys.exit(1)
 
 import string, os, getpass, getopt, re
-from roundup import date, roundupdb, init
+from roundup import date, roundupdb, init, password
 import roundup.instance
 
 def usage(message=''):
@@ -38,24 +38,26 @@ def usage(message=''):
 
 Commands:
  %s
-
 Help:
  roundup-admin -h
- roundup-admin help    
  -- this help
- roundup-admin help <command>
-   -- command-specific help
- roundup-admin morehelp
-   -- even more detailed help
-'''%(message, '\n '.join(commands))
+ roundup-admin help                       -- this help
roundup-admin help <command>             -- command-specific help
+ roundup-admin morehelp                   -- even more detailed help
+Options:
+ -i instance home  -- specify the issue tracker "home directory" to administer
+ -u                -- the user[:password] to use for commands
+ -c                -- when outputting lists of data, just comma-separate them'''%(
+message, '\n '.join(commands))
 
 def moreusage(message=''):
     usage(message)
     print '''
 All commands (except help) require an instance specifier. This is just the path
-to the roundup instance you're working with. It may be specified in the
-environment variable ROUNDUP_INSTANCE or on the command line as "-i instance".
+to the roundup instance you're working with. A roundup instance is where 
+roundup keeps the database and configuration file that defines an issue
+tracker. It may be thought of as the issue tracker's "home directory". It may
+be specified in the environment variable ROUNDUP_INSTANCE or on the command
+line as "-i instance".
 
 A designator is a classname and a nodeid concatenated, eg. bug1, user10, ...
 
@@ -117,9 +119,9 @@ def do_init(instance_home, args):
     if template not in templates:
         print 'Templates:', ', '.join(templates)
     while template not in templates:
-        template = raw_input('Select template [classic]: ').strip()
+        template = raw_input('Select template [extended]: ').strip()
         if not template:
-            template = 'classic'
+            template = 'extended'
 
     import roundup.backends
     backends = roundup.backends.__all__
@@ -148,8 +150,8 @@ def do_get(db, args):
 
     Retrieves the property value of the nodes specified by the designators.
     '''
-    designators = string.split(args[0], ',')
-    propname = args[1]
+    propname = args[0]
+    designators = string.split(args[1], ',')
     # TODO: handle the -c option
     for designator in designators:
         classname, nodeid = roundupdb.splitDesignator(designator)
@@ -163,6 +165,8 @@ def do_set(db, args):
 
     Sets the property to the value for all designators given.
     '''
+    from roundup import hyperdb
+
     designators = string.split(args[0], ',')
     props = {}
     for prop in args[1:]:
@@ -174,15 +178,17 @@ def do_set(db, args):
         properties = cl.getprops()
         for key, value in props.items():
             type =  properties[key]
-            if type.isStringType:
+            if isinstance(type, hyperdb.String):
                 continue
-            elif type.isDateType:
+            elif isinstance(type, hyperdb.Password):
+                props[key] = password.Password(value)
+            elif isinstance(type, hyperdb.Date):
                 props[key] = date.Date(value)
-            elif type.isIntervalType:
+            elif isinstance(type, hyperdb.Interval):
                 props[key] = date.Interval(value)
-            elif type.isLinkType:
+            elif isinstance(type, hyperdb.Link):
                 props[key] = value
-            elif type.isMultilinkType:
+            elif isinstance(type, hyperdb.Multilink):
                 props[key] = value.split(',')
         apply(cl.set, (nodeid, ), props)
     return 0
@@ -220,10 +226,14 @@ def do_spec(db, args):
     '''
     classname = args[0]
     cl = db.getclass(classname)
+    keyprop = cl.getkey()
     for key, value in cl.properties.items():
-        print '%s: %s'%(key, value)
+        if keyprop == key:
+            print '%s: %s (key property)'%(key, value)
+        else:
+            print '%s: %s'%(key, value)
 
-def do_create(db, args):
+def do_create(db, args, pretty_re=re.compile(r'<roundup\.hyperdb\.(.*)>')):
     '''Usage: create classname property=value ...
     Create a new entry of a given class.
 
@@ -231,24 +241,43 @@ def do_create(db, args):
     name=value arguments provided on the command line after the "create"
     command.
     '''
+    from roundup import hyperdb
+
     classname = args[0]
     cl = db.getclass(classname)
     props = {}
-    properties = cl.getprops()
-    for prop in args[1:]:
-        key, value = prop.split('=')
-        type =  properties[key]
-        if type.isStringType:
+    properties = cl.getprops(protected = 0)
+    if len(args) == 1:
+        # ask for the properties
+        for key, value in properties.items():
+            if key == 'id': continue
+            m = pretty_re.match(str(value))
+            if m:
+                value = m.group(1)
+            value = raw_input('%s (%s): '%(key.capitalize(), value))
+            if value:
+                props[key] = value
+    else:
+        # use the args
+        for prop in args[1:]:
+            key, value = prop.split('=')
             props[key] = value 
-        elif type.isDateType:
+
+    # convert types
+    for key in props.keys():
+        type =  properties[key]
+        if isinstance(type, hyperdb.Date):
             props[key] = date.Date(value)
-        elif type.isIntervalType:
+        elif isinstance(type, hyperdb.Interval):
             props[key] = date.Interval(value)
-        elif type.isLinkType:
-            props[key] = value
-        elif type.isMultilinkType:
+        elif isinstance(type, hyperdb.Multilink):
             props[key] = value.split(',')
-    print apply(cl.create, (), props)
+
+    if cl.getkey() and not props.has_key(cl.getkey()):
+        print "You must provide the '%s' property."%cl.getkey()
+    else:
+        print apply(cl.create, (), props)
+
     return 0
 
 def do_list(db, args):
@@ -312,7 +341,7 @@ def do_freshen(db, args):
 #        for nodeid in cl.list():
 #            node = {}
 #            for name, type in properties:
-#                if type.isMultilinkType:
+# isinstance(               if type, hyperdb.Multilink):
 #                    node[name] = cl.get(nodeid, name, [])
 #                else:
 #                    node[name] = cl.get(nodeid, name, None)
@@ -352,11 +381,6 @@ def main():
             return 0
         if opt == '-i':
             instance_home = arg
-        if opt == '-u':
-            l = arg.split(':')
-            name = l[0]
-            if len(l) > 1:
-                password = l[1]
         if opt == '-c':
             comma_sep = 1
 
@@ -391,16 +415,6 @@ def main():
     if command == 'init':
         return do_init(instance_home, args)
 
-    # open the database
-    if command in ('create', 'set', 'retire', 'freshen'):
-        while not name:
-            name = raw_input('Login name: ')
-        while not password:
-            password = getpass.getpass('  password: ')
-
-    # get the instance
-    instance = roundup.instance.open(instance_home)
-
     function = figureCommands().get(command, None)
 
     # not a valid command
@@ -408,7 +422,11 @@ def main():
         usage('Unknown command "%s"'%command)
         return 1
 
-    db = instance.open(name or 'admin')
+    # get the instance
+    instance = roundup.instance.open(instance_home)
+    db = instance.open('admin')
+
+    # do the command
     try:
         return function(db, args[1:])
     finally:
@@ -422,6 +440,50 @@ if __name__ == '__main__':
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.21  2001/10/05 02:23:24  richard
+#  . roundup-admin create now prompts for property info if none is supplied
+#    on the command-line.
+#  . hyperdb Class getprops() method may now return only the mutable
+#    properties.
+#  . Login now uses cookies, which makes it a whole lot more flexible. We can
+#    now support anonymous user access (read-only, unless there's an
+#    "anonymous" user, in which case write access is permitted). Login
+#    handling has been moved into cgi_client.Client.main()
+#  . The "extended" schema is now the default in roundup init.
+#  . The schemas have had their page headings modified to cope with the new
+#    login handling. Existing installations should copy the interfaces.py
+#    file from the roundup lib directory to their instance home.
+#  . Incorrectly had a Bizar Software copyright on the cgitb.py module from
+#    Ping - has been removed.
+#  . Fixed a whole bunch of places in the CGI interface where we should have
+#    been returning Not Found instead of throwing an exception.
+#  . Fixed a deviation from the spec: trying to modify the 'id' property of
+#    an item now throws an exception.
+#
+# Revision 1.20  2001/10/04 02:12:42  richard
+# Added nicer command-line item adding: passing no arguments will enter an
+# interactive more which asks for each property in turn. While I was at it, I
+# fixed an implementation problem WRT the spec - I wasn't raising a
+# ValueError if the key property was missing from a create(). Also added a
+# protected=boolean argument to getprops() so we can list only the mutable
+# properties (defaults to yes, which lists the immutables).
+#
+# Revision 1.19  2001/10/01 06:40:43  richard
+# made do_get have the args in the correct order
+#
+# Revision 1.18  2001/09/18 22:58:37  richard
+#
+# Added some more help to roundu-admin
+#
+# Revision 1.17  2001/08/28 05:58:33  anthonybaxter
+# added missing 'import' statements.
+#
+# Revision 1.16  2001/08/12 06:32:36  richard
+# using isinstance(blah, Foo) now instead of isFooType
+#
+# Revision 1.15  2001/08/07 00:24:42  richard
+# stupid typo
+#
 # Revision 1.14  2001/08/07 00:15:51  richard
 # Added the copyright/license notice to (nearly) all files at request of
 # Bizar Software.