summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 03f68db)
raw | patch | inline | side by side (parent: 03f68db)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Wed, 17 Oct 2001 23:13:19 +0000 (23:13 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Wed, 17 Oct 2001 23:13:19 +0000 (23:13 +0000) |
which displays node information in a tabular format. Also fixed import and
export so they work. Removed freshen.
Fixed quopri usage in mailgw from bug reports.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@309 57a73879-2fb5-44c3-a270-3262357dd7e2
export so they work. Removed freshen.
Fixed quopri usage in mailgw from bug reports.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@309 57a73879-2fb5-44c3-a270-3262357dd7e2
roundup-admin | patch | blob | history | |
roundup/mailgw.py | patch | blob | history |
diff --git a/roundup-admin b/roundup-admin
index be494742298c4a50378bce1d28a01e76bf2f87d5..f7a0ff270e1f988cff590b2e4960d32c54788618 100755 (executable)
--- a/roundup-admin
+++ b/roundup-admin
-#! /usr/bin/python
+#! /Users/builder/bin/python
#
# Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
# This module is free software, and you may redistribute it and/or modify
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: roundup-admin,v 1.32 2001-10-17 06:57:29 richard Exp $
+# $Id: roundup-admin,v 1.33 2001-10-17 23:13:19 richard Exp $
import sys
if int(sys.version[0]) < 2:
import csv
except ImportError:
csv = None
-from roundup import date, roundupdb, init, password
+from roundup import date, hyperdb, roundupdb, init, password
import roundup.instance
def usage(message=''):
'''Usage: list classname [property]
List the instances of a class.
- Lists all instances of the given class along. If the property is not
+ Lists all instances of the given class. If the property is not
specified, the "label" property is used. The label property is tried
in order: the key, "name", "title" and then the first property,
alphabetically.
print "%4s: %s"%(nodeid, value)
return 0
+def do_table(db, args, comma_sep=None):
+ '''Usage: table classname [property[,property]*]
+ List the instances of a class in tabular form.
+
+ Lists all instances of the given class. If the properties are not
+ specified, all properties are displayed. By default, the column widths
+ are the width of the property names. 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
+ 2 bug
+ 3 usability
+ 4 feature
+ '''
+ classname = args[0]
+ cl = db.getclass(classname)
+ if len(args) > 1:
+ prop_names = args[1].split(',')
+ else:
+ prop_names = cl.getprops().keys()
+ props = []
+ for name in prop_names:
+ if ':' in name:
+ name, width = name.split(':')
+ props.append((name, int(width)))
+ else:
+ props.append((name, len(name)))
+
+ print ' '.join([string.capitalize(name) for name, width in props])
+ for nodeid in cl.list():
+ l = []
+ for name, width in props:
+ if name != 'id':
+ value = str(cl.get(nodeid, name))
+ else:
+ value = str(nodeid)
+ f = '%%-%ds'%width
+ l.append(f%value[:width])
+ print ' '.join(l)
+ return 0
+
def do_history(db, args, comma_sep=0):
'''Usage: history designator
Show the history entries of a designator.
def do_export(db, args, comma_sep=0):
'''Usage: export class[,class] destination_dir
- ** EXPERIMENTAL **
- Export the database to CSV files by class in the given directory.
+ Export the database to tab-separated-value files.
This action exports the current data from the database into
- comma-separated files that are placed in the nominated destination
+ tab-separated-value files that are placed in the nominated destination
directory. The journals are not exported.
'''
if len(args) < 2:
# use the csv parser if we can - it's faster
if csv is not None:
- p = csv.parser()
+ p = csv.parser(field_sep=':')
# do all the classes specified
for classname in classes:
cl = db.getclass(classname)
f = open(os.path.join(dir, classname+'.csv'), 'w')
- f.write(string.join(cl.properties.keys(), ',') + '\n')
+ f.write(string.join(cl.properties.keys(), ':') + '\n')
# all nodes for this class
+ properties = cl.properties.items()
for nodeid in cl.list():
+ l = []
+ for prop, type in properties:
+ value = cl.get(nodeid, prop)
+ # convert data where needed
+ if isinstance(type, hyperdb.Date):
+ value = value.get_tuple()
+ elif isinstance(type, hyperdb.Interval):
+ value = value.get_tuple()
+ elif isinstance(type, hyperdb.Password):
+ value = str(value)
+ l.append(repr(value))
+
+ # now write
if csv is not None:
- s = p.join(map(str, cl.getnode(nodeid).values(protected=0)))
- f.write(s + '\n')
+ f.write(p.join(l) + '\n')
else:
- l = []
# escape the individual entries to they're valid CSV
- for entry in map(str, cl.getnode(nodeid).values(protected=0)):
+ m = []
+ for entry in l:
if '"' in entry:
entry = '""'.join(entry.split('"'))
- if ',' in entry:
+ if ':' in entry:
entry = '"%s"'%entry
- l.append(entry)
- f.write(','.join(l) + '\n')
+ m.append(entry)
+ f.write(':'.join(m) + '\n')
return 0
def do_import(db, args, comma_sep=0):
'''Usage: import class file
- ** EXPERIMENTAL **
- Import the contents of the CSV file as new nodes for the given class.
+ Import the contents of the tab-separated-value file.
The file must define the same properties as the class (including having
a "header" line with those property names.) The new nodes are added to
the old data.)
'''
if len(args) < 2:
- print do_export.__doc__
+ print do_import.__doc__
return 1
if csv is None:
print 'Sorry, you need the csv module to use this function.'
# ensure that the properties and the CSV file headings match
cl = db.getclass(args[0])
f = open(args[1])
- p = csv.parser()
+ p = csv.parser(field_sep=':')
file_props = p.parse(f.readline())
props = cl.properties.keys()
m = file_props[:]
m.sort()
props.sort()
if m != props:
- print do_export.__doc__
- print "\n\nFile doesn't define the same properties"
+ print 'Import file doesn\'t define the same properties as "%s".'%args[0]
return 1
# loop through the file and create a node for each entry
# make the new node's property map
d = {}
for i in n:
- value = l[i]
+ # Use eval to reverse the repr() used to output the CSV
+ value = eval(l[i])
+ # Figure the property for this column
key = file_props[i]
type = cl.properties[key]
+ # Convert for property type
if isinstance(type, hyperdb.Date):
value = date.Date(value)
elif isinstance(type, hyperdb.Interval):
pwd = password.Password()
pwd.unpack(value)
value = pwd
- elif isinstance(type, hyperdb.Multilink):
- value = value.split(',')
- d[key] = value
+ if value is not None:
+ d[key] = value
# and create the new node
apply(cl.create, (), d)
return 0
-def do_freshen(db, args, comma_sep=0):
- '''Usage: freshen
- Freshen an existing instance. **DO NOT USE**
-
- This currently kills databases!!!!
-
- This action should generally not be used. It reads in an instance
- database and writes it again. In the future, is may also update
- instance code to account for changes in templates. It's probably wise
- not to use it anyway. Until we're sure it won't break things...
- '''
-# for classname, cl in db.classes.items():
-# properties = cl.properties.items()
-# for nodeid in cl.list():
-# node = {}
-# for name, type in properties:
-# isinstance( if type, hyperdb.Multilink):
-# node[name] = cl.get(nodeid, name, [])
-# else:
-# node[name] = cl.get(nodeid, name, None)
-# db.setnode(classname, nodeid, node)
- return 1
-
def figureCommands():
d = {}
for k, v in globals().items():
return d
class AdminTool:
-
def run_command(self, args):
+ '''Run a single command
+ '''
command = args[0]
# handle help now
# not a valid command
if function is None:
- usage('Unknown command "%s"'%command)
+ print 'Unknown command "%s" ("help commands" for a list)'%command
return 1
# get the instance
#
# $Log: not supported by cvs2svn $
+# Revision 1.32 2001/10/17 06:57:29 richard
+# Interactive startup blurb - need to figure how to get the version in there.
+#
# Revision 1.31 2001/10/17 06:17:26 richard
# Now with readline support :)
#
diff --git a/roundup/mailgw.py b/roundup/mailgw.py
index 702fd559de9ebf610c6ce2eb1bebdb0f7e0ab384..88fe1e73c31c9418b8a9c9067854a2410df29b5e 100644 (file)
--- a/roundup/mailgw.py
+++ b/roundup/mailgw.py
an exception, the original message is bounced back to the sender with the
explanatory message given in the exception.
-$Id: mailgw.py,v 1.19 2001-10-11 23:43:04 richard Exp $
+$Id: mailgw.py,v 1.20 2001-10-17 23:13:19 richard Exp $
'''
# try name on Content-Type
name = part.getparam('name')
# this is just an attachment
- data = part.fp.read()
encoding = part.getencoding()
if encoding == 'base64':
- data = binascii.a2b_base64(data)
+ data = binascii.a2b_base64(part.fp.read())
elif encoding == 'quoted-printable':
- data = quopri.decode(data)
+ # the quopri module wants to work with files
+ decoded = cStringIO.StringIO()
+ quopri.decode(part.fp, decoded)
+ data = decoded.getvalue()
elif encoding == 'uuencoded':
- data = binascii.a2b_uu(data)
+ data = binascii.a2b_uu(part.fp.read())
attachments.append((name, part.gettype(), data))
if content is None:
#
# $Log: not supported by cvs2svn $
+# Revision 1.19 2001/10/11 23:43:04 richard
+# Implemented the comma-separated printing option in the admin tool.
+# Fixed a typo (more of a vim-o actually :) in mailgw.
+#
# Revision 1.18 2001/10/11 06:38:57 richard
# Initial cut at trying to handle people responding to CC'ed messages that
# create an issue.