1 #! /usr/bin/python
3 # $Id: roundup-admin,v 1.2 2001-07-23 08:20:44 richard Exp $
5 import sys
6 if int(sys.version[0]) < 2:
7 print 'Roundup requires python 2.0 or later.'
8 sys.exit(1)
10 import string, os, getpass
11 from roundup import date, roundupdb, init
13 def determineLogin(instance, argv, n = 2):
14 name = password = ''
15 if argv[2] == '-u':
16 l = argv[3].split(':')
17 name = l[0]
18 if len(l) > 1:
19 password = l[1]
20 n = 4
21 elif os.environ.has_key('ROUNDUP_LOGIN'):
22 l = os.environ['ROUNDUP_LOGIN'].split(':')
23 name = l[0]
24 if len(l) > 1:
25 password = l[1]
26 while not name:
27 name = raw_input('Login name: ')
28 while not password:
29 password = getpass.getpass(' password: ')
30 # TODO use the password...
31 return n, instance.open(name)
33 def usage(message=''):
34 if message: message = 'Problem: '+message+'\n'
35 print '''%sUsage:
37 roundup [-i instance] init template
38 -- initialise the database
39 roundup [-i instance] spec classname
40 -- show the properties for a classname
41 roundup [-i instance] create [-u login] classname propname=value ...
42 -- create a new entry of a given class
43 roundup [-i instance] list [-c] classname
44 -- list the instances of a class
45 roundup [-i instance] history [-c] designator
46 -- show the history entries of a designator
47 roundup [-i instance] get [-c] designator[,designator,...] propname
48 -- get the given property of one or more designator(s)
49 roundup [-i instance] set [-u login] designator[,designator,...] propname=value ...
50 -- set the given property of one or more designator(s)
51 roundup [-i instance] find [-c] classname propname=value ...
52 -- find the class instances with a given property
53 roundup [-i instance] retire designator[,designator,...]
54 -- "retire" a designator
55 roundup help
56 -- this help
57 roundup morehelp
58 -- even more detailed help
59 '''%message
61 def moreusage(message=''):
62 usage(message)
63 print '''
64 All commands (except help) require an instance specifier. This is just the path
65 to the roundup instance you're working with. It may be specified in the environment
66 variable ROUNDUP_INSTANCE or on the command line as "-i instance".
68 A designator is a classname and a nodeid concatenated, eg. bug1, user10, ...
70 Property values are represented as strings in command arguments and in the
71 printed results:
72 . Strings are, well, strings.
73 . Date values are printed in the full date format in the local time zone, and
74 accepted in the full format or any of the partial formats explained below.
75 . Link values are printed as node designators. When given as an argument,
76 node designators and key strings are both accepted.
77 . Multilink values are printed as lists of node designators joined by commas.
78 When given as an argument, node designators and key strings are both
79 accepted; an empty string, a single node, or a list of nodes joined by
80 commas is accepted.
82 When multiple nodes are specified to the roundup get or roundup set
83 commands, the specified properties are retrieved or set on all the listed
84 nodes.
86 When multiple results are returned by the roundup get or roundup find
87 commands, they are printed one per line (default) or joined by commas (with
88 the -c) option.
90 Where the command changes data, a login name/password is required. The
91 login may be specified as either "name" or "name:password".
92 . ROUNDUP_LOGIN environment variable
93 . the -u command-line option
94 If either the name or password is not supplied, they are obtained from the
95 command-line.
97 Date format examples:
98 "2000-04-17.03:45" means <Date 2000-04-17.08:45:00>
99 "2000-04-17" means <Date 2000-04-17.00:00:00>
100 "01-25" means <Date yyyy-01-25.00:00:00>
101 "08-13.22:13" means <Date yyyy-08-14.03:13:00>
102 "11-07.09:32:43" means <Date yyyy-11-07.14:32:43>
103 "14:25" means <Date yyyy-mm-dd.19:25:00>
104 "8:47:11" means <Date yyyy-mm-dd.13:47:11>
105 "." means "right now"
106 '''
108 def main():
109 argv = sys.argv
111 if len(argv) == 1:
112 usage('No command specified')
113 return 1
115 # handle help now
116 if argv[1] == 'help':
117 usage()
118 return 0
119 if argv[1] == 'morehelp':
120 moreusage()
121 return 0
123 # figure the instance home
124 n = 1
125 if argv[1] == '-i':
126 if len(argv) == 2:
127 usage()
128 return 1
129 instance_home = argv[2]
130 n = 3
131 else:
132 instance_home = os.environ.get('ROUNDUP_INSTANCE', '')
133 if not instance_home:
134 usage('No instance home specified')
135 return 1
137 # now figure the command
138 command = argv[n]
139 n = n + 1
141 if command == 'init':
142 adminpw = ''
143 confirm = 'x'
144 while adminpw != confirm:
145 adminpw = getpass.getpass('Admin Password:')
146 confirm = getpass.getpass(' Confirm:')
147 init.init(instance_home, argv[n], adminpw)
148 return 0
150 # get the instance
151 path, instance = os.path.split(instance_home)
152 sys.path.insert(0, path)
153 try:
154 instance = __import__(instance)
155 finally:
156 del sys.path[0]
158 if command == 'get':
159 db = instance.open()
160 designators = string.split(argv[n], ',')
161 propname = argv[n+1]
162 # TODO: handle the -c option
163 for designator in designators:
164 classname, nodeid = roundupdb.splitDesignator(designator)
165 print db.getclass(classname).get(nodeid, propname)
167 elif command == 'set':
168 n, db = determineLogin(instance, argv, n)
169 designators = string.split(argv[n], ',')
170 props = {}
171 for prop in argv[n+1:]:
172 key, value = prop.split('=')
173 props[key] = value
174 for designator in designators:
175 classname, nodeid = roundupdb.splitDesignator(designator)
176 cl = db.getclass(classname)
177 properties = cl.getprops()
178 for key, value in props.items():
179 type = properties[key]
180 if type.isStringType:
181 continue
182 elif type.isDateType:
183 props[key] = date.Date(value)
184 elif type.isIntervalType:
185 props[key] = date.Interval(value)
186 elif type.isLinkType:
187 props[key] = value
188 elif type.isMultilinkType:
189 props[key] = value.split(',')
190 apply(cl.set, (nodeid, ), props)
192 elif command == 'find':
193 db = instance.open()
194 classname = argv[n]
195 cl = db.getclass(classname)
197 # look up the linked-to class and get the nodeid that has the value
198 propname, value = argv[n+1:].split('=')
199 propcl = cl[propname].classname
200 nodeid = propcl.lookup(value)
202 # now do the find
203 # TODO: handle the -c option
204 print cl.find(propname, nodeid)
206 elif command == 'spec':
207 db = instance.open()
208 classname = argv[n]
209 cl = db.getclass(classname)
210 for key, value in cl.properties.items():
211 print '%s: %s'%(key, value)
213 elif command == 'create':
214 n, db = determineLogin(instance, argv, n)
215 classname = argv[n]
216 cl = db.getclass(classname)
217 props = {}
218 properties = cl.getprops()
219 for prop in argv[n+1:]:
220 key, value = prop.split('=')
221 type = properties[key]
222 if type.isStringType:
223 props[key] = value
224 elif type.isDateType:
225 props[key] = date.Date(value)
226 elif type.isIntervalType:
227 props[key] = date.Interval(value)
228 elif type.isLinkType:
229 props[key] = value
230 elif type.isMultilinkType:
231 props[key] = value.split(',')
232 print apply(cl.create, (), props)
234 elif command == 'list':
235 db = instance.open()
236 classname = argv[n]
237 cl = db.getclass(classname)
238 key = cl.getkey() or cl.properties.keys()[0]
239 # TODO: handle the -c option
240 for nodeid in cl.list():
241 value = cl.get(nodeid, key)
242 print "%4s: %s"%(nodeid, value)
244 elif command == 'history':
245 db = instance.open()
246 classname, nodeid = roundupdb.splitDesignator(argv[n])
247 # TODO: handle the -c option
248 print db.getclass(classname).history(nodeid)
250 elif command == 'retire':
251 n, db = determineLogin(instance, argv, n)
252 designators = string.split(argv[n], ',')
253 for designator in designators:
254 classname, nodeid = roundupdb.splitDesignator(designator)
255 db.getclass(classname).retire(nodeid)
257 elif command == 'freshen':
258 n, db = determineLogin(instance, argv, n)
259 for classname, cl in db.classes.items():
260 properties = cl.properties.keys()
261 for nodeid in cl.list():
262 node = {}
263 for name in properties:
264 node[name] = cl.get(nodeid, name)
265 db.setnode(classname, nodeid, node)
267 else:
268 print "Unknown command '%s'"%command
269 usage()
270 return 1
272 db.close()
273 return 0
275 if __name__ == '__main__':
276 sys.exit(main())
278 #
279 # $Log: not supported by cvs2svn $
280 # Revision 1.1 2001/07/23 03:46:48 richard
281 # moving the bin files to facilitate out-of-the-boxness
282 #
283 # Revision 1.1 2001/07/22 11:15:45 richard
284 # More Grande Splite stuff
285 #
286 #