X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=roundup%2Fadmin.py;h=e89f8643df326727cf15b1142a8be69d564fa09b;hb=d53f951d3021166e7f3bebc037708accdecb7ff5;hp=e93bf4f0861122c656826a36fe85776a6addd266;hpb=065f3a3e26709983eed028aed34431f133f2cd33;p=roundup.git diff --git a/roundup/admin.py b/roundup/admin.py index e93bf4f..e89f864 100644 --- a/roundup/admin.py +++ b/roundup/admin.py @@ -16,17 +16,14 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: admin.py,v 1.55 2003-06-23 08:05:30 neaj Exp $ +# $Id: admin.py,v 1.63 2004-03-21 23:39:08 richard Exp $ '''Administration commands for maintaining Roundup trackers. ''' +__docformat__ = 'restructuredtext' import sys, os, getpass, getopt, re, UserDict, shutil, rfc822 -try: - import csv -except ImportError: - csv = None -from roundup import date, hyperdb, roundupdb, init, password, token +from roundup import date, hyperdb, roundupdb, init, password, token, rcsv from roundup import __version__ as roundup_version import roundup.instance from roundup.i18n import _ @@ -281,11 +278,18 @@ Command help: def listTemplates(self): ''' List all the available templates. - Look in three places: - /share/roundup/templates/* - <__file__>/../templates/* - current dir/* - current dir as a template + Look in the following places, where the later rules take precedence: + + 1. /share/roundup/templates/* + this should be the standard place to find them when Roundup is + installed + 2. /../templates/* + this will be used if Roundup's run in the distro (aka. source) + directory + 3. /* + this is for when someone unpacks a 3rd-party template + 4. + this is for someone who "cd"s to the 3rd-party template dir ''' # OK, try /share/roundup/templates # -- this module (roundup.admin) will be installed in something @@ -302,7 +306,7 @@ Command help: path = os.path.dirname(path) tdir = os.path.join(path, 'share', 'roundup', 'templates') if os.path.isdir(tdir): - templates = listTemplates(tdir) + templates = init.listTemplates(tdir) break # OK, now try as if we're in the roundup source distribution @@ -313,13 +317,13 @@ Command help: path = os.path.dirname(path) tdir = os.path.join(path, 'templates') if os.path.isdir(tdir): - templates.update(listTemplates(tdir)) + templates.update(init.listTemplates(tdir)) # Try subdirs of the current dir - templates.update(listTemplates(os.getcwd())) + templates.update(init.listTemplates(os.getcwd())) # Finally, try the current directory as a template - template = loadTemplate(os.getcwd()) + template = init.loadTemplateInfo(os.getcwd()) if template: templates[template['name']] = template @@ -566,42 +570,11 @@ Command help: properties = cl.getprops() for key, value in props.items(): - proptype = properties[key] - if isinstance(proptype, hyperdb.Multilink): - if value is None: - props[key] = [] - else: - props[key] = value.split(',') - elif value is None: - continue - elif isinstance(proptype, hyperdb.String): - continue - elif isinstance(proptype, hyperdb.Password): - 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) - except ValueError, message: - raise UsageError, '"%s": %s'%(value, message) - elif isinstance(proptype, hyperdb.Interval): - try: - props[key] = date.Interval(value) - except ValueError, message: - raise UsageError, '"%s": %s'%(value, message) - elif isinstance(proptype, hyperdb.Link): - props[key] = value - elif isinstance(proptype, hyperdb.Boolean): - props[key] = value.lower() in ('yes', 'true', 'on', '1') - elif isinstance(proptype, hyperdb.Number): - props[key] = float(value) + try: + props[key] = hyperdb.rawToHyperdb(self.db, cl, itemid, + key, value) + except hyperdb.HyperdbValueError, message: + raise UsageError, message # try the set try: @@ -723,7 +696,9 @@ Command help: cl = self.get_class(classname) # display the values - for key in cl.properties.keys(): + keys = cl.properties.keys() + keys.sort() + for key in keys: value = cl.get(nodeid, key) print _('%(key)s: %(value)s')%locals() @@ -772,39 +747,11 @@ Command help: # convert types for propname, value in props.items(): - # get the property try: - proptype = properties[propname] - except KeyError: - raise UsageError, _('%(classname)s has no property ' - '"%(propname)s"')%locals() - - if isinstance(proptype, hyperdb.Date): - try: - props[propname] = date.Date(value) - except ValueError, message: - raise UsageError, _('"%(value)s": %(message)s')%locals() - elif isinstance(proptype, hyperdb.Interval): - try: - props[propname] = date.Interval(value) - except ValueError, message: - raise UsageError, _('"%(value)s": %(message)s')%locals() - elif isinstance(proptype, hyperdb.Password): - 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] = float(value) + props[propname] = hyperdb.rawToHyperdb(self.db, cl, None, + propname, value) + except hyperdb.HyperdbValueError, message: + raise UsageError, message # check for the key property propname = cl.getkey() @@ -880,6 +827,7 @@ Command help: specified, all properties are displayed. By default, the column widths are the width of the largest value. The width may be explicitly defined by defining the property as "name:width". For example:: + roundup> table priority id,name:10 Id Name 1 fatal-bug @@ -888,7 +836,8 @@ Command help: 4 feature Also to make the width of the column the width of the label, - leave a trailing : without a width on the property. E.G. + leave a trailing : without a width on the property. For example:: + roundup> table priority id,name: Id Name 1 fata @@ -1063,15 +1012,12 @@ Command help: colon-separated-value files that are placed in the nominated destination directory. The journals are not exported. ''' - # we need the CSV module - if csv is None: - raise UsageError, \ - _('Sorry, you need the csv module to use this function.\n' - 'Get it from: http://www.object-craft.com.au/projects/csv/') - # grab the directory to export to if len(args) < 1: raise UsageError, _('Not enough arguments supplied') + if rcsv.error: + raise UsageError, _(rcsv.error) + dir = args[-1] # get the list of classes to export @@ -1080,26 +1026,24 @@ Command help: else: classes = self.db.classes.keys() - # use the csv parser if we can - it's faster - p = csv.parser(field_sep=':') - # do all the classes specified for classname in classes: cl = self.get_class(classname) f = open(os.path.join(dir, classname+'.csv'), 'w') + writer = rcsv.writer(f, rcsv.colon_separated) properties = cl.getprops() propnames = properties.keys() propnames.sort() - l = propnames[:] - l.append('is retired') - print >> f, p.join(l) + fields = propnames[:] + fields.append('is retired') + writer.writerow(fields) # all nodes for this class (not using list() 'cos it doesn't # include retired nodes) for nodeid in self.db.getclass(classname).getnodeids(): # get the regular props - print >>f, p.join(cl.export_list(propnames, nodeid)) + writer.writerow (cl.export_list(propnames, nodeid)) # close this file f.close() @@ -1122,11 +1066,8 @@ Command help: ''' if len(args) < 1: raise UsageError, _('Not enough arguments supplied') - if csv is None: - raise UsageError, \ - _('Sorry, you need the csv module to use this function.\n' - 'Get it from: http://www.object-craft.com.au/projects/csv/') - + if rcsv.error: + raise UsageError, _(rcsv.error) from roundup import hyperdb for file in os.listdir(args[0]): @@ -1141,36 +1082,20 @@ Command help: # ensure that the properties and the CSV file headings match cl = self.get_class(classname) - p = csv.parser(field_sep=':') - file_props = p.parse(f.readline()) - -# XXX we don't _really_ need to do this... -# properties = cl.getprops() -# propnames = properties.keys() -# propnames.sort() -# m = file_props[:] -# m.sort() -# if m != propnames: -# raise UsageError, _('Import file doesn\'t define the same ' -# 'properties as "%(arg0)s".')%{'arg0': args[0]} + reader = rcsv.reader(f, rcsv.colon_separated) + file_props = None + maxid = 1 # loop through the file and create a node for each entry - maxid = 1 - while 1: - line = f.readline() - if not line: break - - # parse lines until we get a complete entry - while 1: - l = p.parse(line) - if l: break - line = f.readline() - if not line: - raise ValueError, "Unexpected EOF during CSV parse" + for r in reader: + if file_props is None: + file_props = r + continue # do the import and figure the current highest nodeid - maxid = max(maxid, int(cl.import_list(file_props, l))) + maxid = max(maxid, int(cl.import_list(file_props, r))) + # set the id counter print 'setting', classname, maxid+1 self.db.setid(classname, str(maxid+1)) return 0 @@ -1422,41 +1347,6 @@ Date format is "YYYY-MM-DD" eg: if self.db: self.db.close() - -def listTemplates(dir): - ''' List all the Roundup template directories in a given directory. - - Find all the dirs that contain a TEMPLATE-INFO.txt and parse it. - - Return a list of dicts of info about the templates. - ''' - ret = {} - for idir in os.listdir(dir): - idir = os.path.join(dir, idir) - ti = loadTemplate(idir) - if ti: - ret[ti['name']] = ti - return ret - -def loadTemplate(dir): - ''' Attempt to load a Roundup template from the indicated directory. - - Return None if there's no template, otherwise a template info - dictionary. - ''' - ti = os.path.join(dir, 'TEMPLATE-INFO.txt') - if not os.path.exists(ti): - return None - - # load up the template's information - m = rfc822.Message(open(ti)) - ti = {} - ti['name'] = m['name'] - ti['description'] = m['description'] - ti['intended-for'] = m['intended-for'] - ti['path'] = dir - return ti - if __name__ == '__main__': tool = AdminTool() sys.exit(tool.main())