1 #! /usr/bin/python
3 import sys
4 if int(sys.version[0]) < 2:
5 print 'Roundup requires python 2.0 or later.'
6 sys.exit(1)
8 import string, os, getpass
9 import config, date, roundupdb
11 def determineLogin(argv):
12 n = 2
13 name = password = ''
14 if sys.argv[2] == '-user':
15 l = sys.argv[3].split(':')
16 name = l[0]
17 if len(l) > 1:
18 password = l[1]
19 n = 4
20 elif os.environ.has_key('ROUNDUP_LOGIN'):
21 l = os.environ['ROUNDUP_LOGIN'].split(':')
22 name = l[0]
23 if len(l) > 1:
24 password = l[1]
25 while not name:
26 name = raw_input('Login name: ')
27 while not password:
28 password = getpass.getpass(' password: ')
29 return n, roundupdb.openDB(config.DATABASE, name, password)
31 def usage():
32 print '''Usage:
34 roundup init
35 roundup spec classname
36 roundup create [-user login] classanme propname=value ...
37 roundup list [-list] classname
38 roundup history [-list] designator
39 roundup get [-list] designator[,designator,...] propname
40 roundup set [-user login] designator[,designator,...] propname=value ...
41 roundup find [-list] classname propname=value ...
42 roundup retire designator[,designator,...]
44 A designator is a classname and a nodeid concatenated, eg. bug1, user10, ...
46 Property values are represented as strings in command arguments and in the
47 printed results:
48 . Strings are, well, strings.
49 . Date values are printed in the full date format in the local time zone, and
50 accepted in the full format or any of the partial formats explained below.
51 . Link values are printed as node designators. When given as an argument,
52 node designators and key strings are both accepted.
53 . Multilink values are printed as lists of node designators joined by commas.
54 When given as an argument, node designators and key strings are both
55 accepted; an empty string, a single node, or a list of nodes joined by
56 commas is accepted.
58 When multiple nodes are specified to the roundup get or roundup set
59 commands, the specified properties are retrieved or set on all the listed
60 nodes.
62 When multiple results are returned by the roundup get or roundup find
63 commands, they are printed one per line (default) or joined by commas (with
64 the -list) option.
66 Where the command changes data, a login name/password is required. The
67 login may be specified as either "name" or "name:password".
68 . ROUNDUP_LOGIN environment variable
69 . the -user command-line option
70 If either the name or password is not supplied, they are obtained from the
71 command-line.
73 Date format examples:
74 "2000-04-17.03:45" means <Date 2000-04-17.08:45:00>
75 "2000-04-17" means <Date 2000-04-17.00:00:00>
76 "01-25" means <Date yyyy-01-25.00:00:00>
77 "08-13.22:13" means <Date yyyy-08-14.03:13:00>
78 "11-07.09:32:43" means <Date yyyy-11-07.14:32:43>
79 "14:25" means <Date yyyy-mm-dd.19:25:00>
80 "8:47:11" means <Date yyyy-mm-dd.13:47:11>
81 "." means "right now"
82 '''
84 def main():
86 if len(sys.argv) == 1:
87 usage()
88 return 1
90 command = sys.argv[1]
91 if command == 'init':
92 password = ''
93 confirm = 'x'
94 while password != confirm:
95 password = getpass.getpass('Admin Password:')
96 confirm = getpass.getpass(' Confirm:')
97 roundupdb.initDB(config.DATABASE, password)
98 return 0
100 if command == 'get':
101 db = roundupdb.openDB(config.DATABASE)
102 designators = string.split(sys.argv[2], ',')
103 propname = sys.argv[3]
104 for designator in designators:
105 classname, nodeid = roundupdb.splitDesignator(designator)
106 print db.getclass(classname).get(nodeid, propname)
108 elif command == 'set':
109 n, db = determineLogin(sys.argv)
110 designators = string.split(sys.argv[n], ',')
111 props = {}
112 for prop in sys.argv[n+1:]:
113 key, value = prop.split('=')
114 props[key] = value
115 for designator in designators:
116 classname, nodeid = roundupdb.splitDesignator(designator)
117 cl = db.getclass(classname)
118 properties = cl.getprops()
119 for key, value in props.items():
120 type = properties[key]
121 if type.isStringType:
122 continue
123 elif type.isDateType:
124 props[key] = date.Date(value)
125 elif type.isIntervalType:
126 props[key] = date.Interval(value)
127 elif type.isLinkType:
128 props[key] = value
129 elif type.isMultilinkType:
130 props[key] = value.split(',')
131 apply(cl.set, (nodeid, ), props)
133 elif command == 'find':
134 db = roundupdb.openDB(config.DATABASE)
135 classname = sys.argv[2]
136 cl = db.getclass(classname)
138 # look up the linked-to class and get the nodeid that has the value
139 propname, value = sys.argv[3:].split('=')
140 propcl = cl[propname].classname
141 nodeid = propcl.lookup(value)
143 # now do the find
144 print cl.find(propname, nodeid)
146 elif command == 'spec':
147 db = roundupdb.openDB(config.DATABASE)
148 classname = sys.argv[2]
149 cl = db.getclass(classname)
150 for key, value in cl.properties.items():
151 print '%s: %s'%(key, value)
153 elif command == 'create':
154 n, db = determineLogin(sys.argv)
155 classname = sys.argv[n]
156 cl = db.getclass(classname)
157 props = {}
158 properties = cl.getprops()
159 for prop in sys.argv[n+1:]:
160 key, value = prop.split('=')
161 type = properties[key]
162 if type.isStringType:
163 props[key] = value
164 elif type.isDateType:
165 props[key] = date.Date(value)
166 elif type.isIntervalType:
167 props[key] = date.Interval(value)
168 elif type.isLinkType:
169 props[key] = value
170 elif type.isMultilinkType:
171 props[key] = value.split(',')
172 print apply(cl.create, (), props)
174 elif command == 'list':
175 db = roundupdb.openDB(config.DATABASE)
176 classname = sys.argv[2]
177 cl = db.getclass(classname)
178 key = cl.getkey() or cl.properties.keys()[0]
179 for nodeid in cl.list():
180 value = cl.get(nodeid, key)
181 print "%4s: %s"%(nodeid, value)
183 elif command == 'history':
184 db = roundupdb.openDB(config.DATABASE)
185 classname, nodeid = roundupdb.splitDesignator(sys.argv[2])
186 print db.getclass(classname).history(nodeid)
188 elif command == 'retire':
189 n, db = determineLogin(sys.argv)
190 designators = string.split(sys.argv[2], ',')
191 for designator in designators:
192 classname, nodeid = roundupdb.splitDesignator(designator)
193 db.getclass(classname).retire(nodeid)
195 else:
196 usage()
197 return 1
199 db.close()
200 return 0
202 if __name__ == '__main__':
203 sys.exit(main())