comparison roundup/admin.py @ 1566:053065585406

added command-line functionality for roundup-adming (feature [SF#687664])
author Richard Jones <richard@users.sourceforge.net>
date Wed, 26 Mar 2003 11:02:28 +0000
parents e2a8ce4d2317
children 93e0a565cee5
comparison
equal deleted inserted replaced
1565:1e617a4a663d 1566:053065585406
14 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 14 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
15 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" 15 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
16 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, 16 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
17 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 17 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
18 # 18 #
19 # $Id: admin.py,v 1.48 2003-03-26 10:43:58 richard Exp $ 19 # $Id: admin.py,v 1.49 2003-03-26 11:02:28 richard Exp $
20 20
21 '''Administration commands for maintaining Roundup trackers. 21 '''Administration commands for maintaining Roundup trackers.
22 ''' 22 '''
23 23
24 import sys, os, getpass, getopt, re, UserDict, shlex, shutil 24 import sys, os, getpass, getopt, re, UserDict, shlex, shutil
108 108
109 def usage(self, message=''): 109 def usage(self, message=''):
110 ''' Display a simple usage message. 110 ''' Display a simple usage message.
111 ''' 111 '''
112 if message: 112 if message:
113 message = _('Problem: %(message)s)\n\n')%locals() 113 message = _('Problem: %(message)s\n\n')%locals()
114 print _('''%(message)sUsage: roundup-admin [options] <command> <arguments> 114 print _('''%(message)sUsage: roundup-admin [options] [<command> <arguments>]
115 115
116 Options: 116 Options:
117 -i instance home -- specify the issue tracker "home directory" to administer 117 -i instance home -- specify the issue tracker "home directory" to administer
118 -u -- the user[:password] to use for commands 118 -u -- the user[:password] to use for commands
119 -c -- when outputting lists of data, just comma-separate them 119 -d -- print full designators not just class id numbers
120 -c -- when outputting lists of data, comma-separate them.
121 Same as '-S ","'.
122 -S <string> -- when outputting lists of data, string-separate them
123 -s -- when outputting lists of data, space-separate them.
124 Same as '-S " "'.
125
126 Only one of -s, -c or -S can be specified.
120 127
121 Help: 128 Help:
122 roundup-admin -h 129 roundup-admin -h
123 roundup-admin help -- this help 130 roundup-admin help -- this help
124 roundup-admin help <command> -- command-specific help 131 roundup-admin help <command> -- command-specific help
420 raise UsageError, message 427 raise UsageError, message
421 428
422 # get the class 429 # get the class
423 cl = self.get_class(classname) 430 cl = self.get_class(classname)
424 try: 431 try:
425 if self.comma_sep: 432 id=[]
426 l.append(cl.get(nodeid, propname)) 433 if self.separator:
434 if self.print_designator:
435 # see if property is a link or multilink for
436 # which getting a desginator make sense.
437 # Algorithm: Get the properties of the
438 # current designator's class. (cl.getprops)
439 # get the property object for the property the
440 # user requested (properties[propname])
441 # verify its type (isinstance...)
442 # raise error if not link/multilink
443 # get class name for link/multilink property
444 # do the get on the designators
445 # append the new designators
446 # print
447 properties = cl.getprops()
448 property = properties[propname]
449 if not (isinstance(property, hyperdb.Multilink) or
450 isinstance(property, hyperdb.Link)):
451 raise UsageError, _('property %s is not of type Multilink or Link so -d flag does not apply.')%propname
452 propclassname = self.db.getclass(property.classname).classname
453 id = cl.get(nodeid, propname)
454 for i in id:
455 l.append(propclassname + i)
456 else:
457 id = cl.get(nodeid, propname)
458 for i in id:
459 l.append(i)
427 else: 460 else:
428 print cl.get(nodeid, propname) 461 if self.print_designator:
462 properties = cl.getprops()
463 property = properties[propname]
464 if not (isinstance(property, hyperdb.Multilink) or
465 isinstance(property, hyperdb.Link)):
466 raise UsageError, _('property %s is not of type Multilink or Link so -d flag does not apply.')%propname
467 propclassname = self.db.getclass(property.classname).classname
468 id = cl.get(nodeid, propname)
469 for i in id:
470 print propclassname + i
471 else:
472 print cl.get(nodeid, propname)
429 except IndexError: 473 except IndexError:
430 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals() 474 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals()
431 except KeyError: 475 except KeyError:
432 raise UsageError, _('no such %(classname)s property ' 476 raise UsageError, _('no such %(classname)s property '
433 '"%(propname)s"')%locals() 477 '"%(propname)s"')%locals()
434 if self.comma_sep: 478 if self.separator:
435 print ','.join(l) 479 print self.separator.join(l)
480
436 return 0 481 return 0
437 482
438 483
439 def do_set(self, args, pwre = re.compile(r'{(\w+)}(.+)')): 484 def do_set(self, args, pwre = re.compile(r'{(\w+)}(.+)')):
440 '''Usage: set [items] property=value property=value ... 485 '''Usage: set [items] property=value property=value ...
441 Set the given properties of one or more items(s). 486 Set the given properties of one or more items(s).
442 487
443 The items may be specified as a class or as a comma-separeted 488 The items may be specified as a class or as a comma-separated
444 list of item designators (ie "designator[,designator,...]"). 489 list of item designators (ie "designator[,designator,...]").
445 490
446 This command sets the properties to the values for all designators 491 This command sets the properties to the values for all designators
447 given. If the value is missing (ie. "property=") then the property is 492 given. If the value is missing (ie. "property=") then the property is
448 un-set. If the property is a multilink, you specify the linked ids 493 un-set. If the property is a multilink, you specify the linked ids
564 raise UsageError, _('%(classname)s has no key property"')%{ 609 raise UsageError, _('%(classname)s has no key property"')%{
565 'classname': link_class.classname} 610 'classname': link_class.classname}
566 611
567 # now do the find 612 # now do the find
568 try: 613 try:
569 if self.comma_sep: 614 id = []
570 print ','.join(apply(cl.find, (), props)) 615 designator = []
616 if self.separator:
617 if self.print_designator:
618 id=apply(cl.find, (), props)
619 for i in id:
620 designator.append(classname + i)
621 print self.separator.join(designator)
622 else:
623 print self.separator.join(apply(cl.find, (), props))
624
571 else: 625 else:
572 print apply(cl.find, (), props) 626 if self.print_designator:
627 id=apply(cl.find, (), props)
628 for i in id:
629 designator.append(classname + i)
630 print designator
631 else:
632 print apply(cl.find, (), props)
573 except KeyError: 633 except KeyError:
574 raise UsageError, _('%(classname)s has no property ' 634 raise UsageError, _('%(classname)s has no property '
575 '"%(propname)s"')%locals() 635 '"%(propname)s"')%locals()
576 except (ValueError, TypeError), message: 636 except (ValueError, TypeError), message:
577 raise UsageError, message 637 raise UsageError, message
596 print _('%(key)s: %(value)s (key property)')%locals() 656 print _('%(key)s: %(value)s (key property)')%locals()
597 else: 657 else:
598 print _('%(key)s: %(value)s')%locals() 658 print _('%(key)s: %(value)s')%locals()
599 659
600 def do_display(self, args): 660 def do_display(self, args):
601 '''Usage: display designator 661 '''Usage: display designator[,designator]*
602 Show the property values for the given node. 662 Show the property values for the given node(s).
603 663
604 This lists the properties and their associated values for the given 664 This lists the properties and their associated values for the given
605 node. 665 node.
606 ''' 666 '''
607 if len(args) < 1: 667 if len(args) < 1:
608 raise UsageError, _('Not enough arguments supplied') 668 raise UsageError, _('Not enough arguments supplied')
609 669
610 # decode the node designator 670 # decode the node designator
611 try: 671 for designator in args[0].split(','):
612 classname, nodeid = hyperdb.splitDesignator(args[0]) 672 try:
613 except hyperdb.DesignatorError, message: 673 classname, nodeid = hyperdb.splitDesignator(designator)
614 raise UsageError, message 674 except hyperdb.DesignatorError, message:
615 675 raise UsageError, message
616 # get the class 676
617 cl = self.get_class(classname) 677 # get the class
618 678 cl = self.get_class(classname)
619 # display the values 679
620 for key in cl.properties.keys(): 680 # display the values
621 value = cl.get(nodeid, key) 681 for key in cl.properties.keys():
622 print _('%(key)s: %(value)s')%locals() 682 value = cl.get(nodeid, key)
683 print _('%(key)s: %(value)s')%locals()
623 684
624 def do_create(self, args, pwre = re.compile(r'{(\w+)}(.+)')): 685 def do_create(self, args, pwre = re.compile(r'{(\w+)}(.+)')):
625 '''Usage: create classname property=value ... 686 '''Usage: create classname property=value ...
626 Create a new entry of a given class. 687 Create a new entry of a given class.
627 688
719 780
720 Lists all instances of the given class. If the property is not 781 Lists all instances of the given class. If the property is not
721 specified, the "label" property is used. The label property is tried 782 specified, the "label" property is used. The label property is tried
722 in order: the key, "name", "title" and then the first property, 783 in order: the key, "name", "title" and then the first property,
723 alphabetically. 784 alphabetically.
724 ''' 785
786 With -c, -S or -s print a list of item id's if no property specified.
787 If property specified, print list of that property for every class
788 instance.
789 '''
790 if len(args) > 2:
791 raise UsageError, _('Too many arguments supplied')
725 if len(args) < 1: 792 if len(args) < 1:
726 raise UsageError, _('Not enough arguments supplied') 793 raise UsageError, _('Not enough arguments supplied')
727 classname = args[0] 794 classname = args[0]
728 795
729 # get the class 796 # get the class
733 if len(args) > 1: 800 if len(args) > 1:
734 propname = args[1] 801 propname = args[1]
735 else: 802 else:
736 propname = cl.labelprop() 803 propname = cl.labelprop()
737 804
738 if self.comma_sep: 805 if self.separator:
739 print ','.join(cl.list()) 806 if len(args) == 2:
807 # create a list of propnames since user specified propname
808 proplist=[]
809 for nodeid in cl.list():
810 try:
811 proplist.append(cl.get(nodeid, propname))
812 except KeyError:
813 raise UsageError, _('%(classname)s has no property '
814 '"%(propname)s"')%locals()
815 print self.separator.join(proplist)
816 else:
817 # create a list of index id's since user didn't specify
818 # otherwise
819 print self.separator.join(cl.list())
740 else: 820 else:
741 for nodeid in cl.list(): 821 for nodeid in cl.list():
742 try: 822 try:
743 value = cl.get(nodeid, propname) 823 value = cl.get(nodeid, propname)
744 except KeyError: 824 except KeyError:
1241 self.db.commit() 1321 self.db.commit()
1242 return 0 1322 return 0
1243 1323
1244 def main(self): 1324 def main(self):
1245 try: 1325 try:
1246 opts, args = getopt.getopt(sys.argv[1:], 'i:u:hc') 1326 opts, args = getopt.getopt(sys.argv[1:], 'i:u:hcdsS:')
1247 except getopt.GetoptError, e: 1327 except getopt.GetoptError, e:
1248 self.usage(str(e)) 1328 self.usage(str(e))
1249 return 1 1329 return 1
1250 1330
1251 # handle command-line args 1331 # handle command-line args
1255 if os.environ.has_key('ROUNDUP_LOGIN'): 1335 if os.environ.has_key('ROUNDUP_LOGIN'):
1256 l = os.environ['ROUNDUP_LOGIN'].split(':') 1336 l = os.environ['ROUNDUP_LOGIN'].split(':')
1257 name = l[0] 1337 name = l[0]
1258 if len(l) > 1: 1338 if len(l) > 1:
1259 password = l[1] 1339 password = l[1]
1260 self.comma_sep = 0 1340 self.separator = None
1341 self.print_designator = 0
1261 for opt, arg in opts: 1342 for opt, arg in opts:
1262 if opt == '-h': 1343 if opt == '-h':
1263 self.usage() 1344 self.usage()
1264 return 0 1345 return 0
1265 if opt == '-i': 1346 if opt == '-i':
1266 self.tracker_home = arg 1347 self.tracker_home = arg
1267 if opt == '-c': 1348 if opt == '-c':
1268 self.comma_sep = 1 1349 if self.separator != None:
1350 self.usage('Only one of -c, -S and -s may be specified')
1351 return 1
1352 self.separator = ','
1353 if opt == '-S':
1354 if self.separator != None:
1355 self.usage('Only one of -c, -S and -s may be specified')
1356 return 1
1357 self.separator = arg
1358 if opt == '-s':
1359 if self.separator != None:
1360 self.usage('Only one of -c, -S and -s may be specified')
1361 return 1
1362 self.separator = ' '
1363 if opt == '-d':
1364 self.print_designator = 1
1269 1365
1270 # if no command - go interactive 1366 # if no command - go interactive
1271 # wrap in a try/finally so we always close off the db 1367 # wrap in a try/finally so we always close off the db
1272 ret = 0 1368 ret = 0
1273 try: 1369 try:

Roundup Issue Tracker: http://roundup-tracker.org/