Mercurial > p > roundup > code
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: |
