Mercurial > p > roundup > code
comparison roundup-admin @ 438:9d97c1a4ddad
Notes from changes.
>From CHANGES:
. Added the "display" command to the admin tool - displays a node's values
. [SF#489760] [issue] only subject
. fixed the doc/index.html to include the quoting in the mail alias.
Also:
. fixed roundup-admin so it works with transactions
. disabled the back_anydbm module if anydbm tries to use dumbdbm
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Mon, 10 Dec 2001 00:57:38 +0000 |
| parents | a28a80b714f9 |
| children | 208697858c8b |
comparison
equal
deleted
inserted
replaced
| 437:a1e778940f92 | 438:9d97c1a4ddad |
|---|---|
| 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: roundup-admin,v 1.50 2001-12-02 05:06:16 richard Exp $ | 19 # $Id: roundup-admin,v 1.51 2001-12-10 00:57:38 richard Exp $ |
| 20 | 20 |
| 21 import sys | 21 import sys |
| 22 if not hasattr(sys, 'version_info') or sys.version_info[:2] < (2,1): | 22 if not hasattr(sys, 'version_info') or sys.version_info[:2] < (2,1): |
| 23 print 'Roundup requires python 2.1 or later.' | 23 print 'Roundup requires python 2.1 or later.' |
| 24 sys.exit(1) | 24 sys.exit(1) |
| 62 self.commands[k[3:]] = getattr(self, k) | 62 self.commands[k[3:]] = getattr(self, k) |
| 63 self.help = {} | 63 self.help = {} |
| 64 for k in AdminTool.__dict__.keys(): | 64 for k in AdminTool.__dict__.keys(): |
| 65 if k[:5] == 'help_': | 65 if k[:5] == 'help_': |
| 66 self.help[k[5:]] = getattr(self, k) | 66 self.help[k[5:]] = getattr(self, k) |
| 67 self.instance_home = '' | |
| 67 self.db = None | 68 self.db = None |
| 68 | 69 |
| 69 def usage(self, message=''): | 70 def usage(self, message=''): |
| 70 if message: message = 'Problem: '+message+'\n\n' | 71 if message: message = 'Problem: '+message+'\n\n' |
| 71 print '''%sUsage: roundup-admin [-i instance home] [-u login] [-c] <command> <arguments> | 72 print '''%sUsage: roundup-admin [-i instance home] [-u login] [-c] <command> <arguments> |
| 203 password may be specified on the command-line as arguments, in that | 204 password may be specified on the command-line as arguments, in that |
| 204 order. | 205 order. |
| 205 | 206 |
| 206 See also initopts help. | 207 See also initopts help. |
| 207 ''' | 208 ''' |
| 209 if len(args) < 1: | |
| 210 raise UsageError, 'Not enough arguments supplied' | |
| 208 # select template | 211 # select template |
| 209 import roundup.templates | 212 import roundup.templates |
| 210 templates = roundup.templates.listTemplates() | 213 templates = roundup.templates.listTemplates() |
| 211 template = len(args) > 1 and args[1] or '' | 214 template = len(args) > 1 and args[1] or '' |
| 212 if template not in templates: | 215 if template not in templates: |
| 241 '''Usage: get property designator[,designator]* | 244 '''Usage: get property designator[,designator]* |
| 242 Get the given property of one or more designator(s). | 245 Get the given property of one or more designator(s). |
| 243 | 246 |
| 244 Retrieves the property value of the nodes specified by the designators. | 247 Retrieves the property value of the nodes specified by the designators. |
| 245 ''' | 248 ''' |
| 249 if len(args) < 2: | |
| 250 raise UsageError, 'Not enough arguments supplied' | |
| 246 propname = args[0] | 251 propname = args[0] |
| 247 designators = string.split(args[1], ',') | 252 designators = string.split(args[1], ',') |
| 248 l = [] | 253 l = [] |
| 249 for designator in designators: | 254 for designator in designators: |
| 250 # decode the node designator | 255 # decode the node designator |
| 277 '''Usage: set designator[,designator]* propname=value ... | 282 '''Usage: set designator[,designator]* propname=value ... |
| 278 Set the given property of one or more designator(s). | 283 Set the given property of one or more designator(s). |
| 279 | 284 |
| 280 Sets the property to the value for all designators given. | 285 Sets the property to the value for all designators given. |
| 281 ''' | 286 ''' |
| 287 if len(args) < 2: | |
| 288 raise UsageError, 'Not enough arguments supplied' | |
| 282 from roundup import hyperdb | 289 from roundup import hyperdb |
| 283 | 290 |
| 284 designators = string.split(args[0], ',') | 291 designators = string.split(args[0], ',') |
| 285 props = {} | 292 props = {} |
| 286 for prop in args[1:]: | 293 for prop in args[1:]: |
| 338 Find the nodes of the given class with a given link property value. | 345 Find the nodes of the given class with a given link property value. |
| 339 | 346 |
| 340 Find the nodes of the given class with a given link property value. The | 347 Find the nodes of the given class with a given link property value. The |
| 341 value may be either the nodeid of the linked node, or its key value. | 348 value may be either the nodeid of the linked node, or its key value. |
| 342 ''' | 349 ''' |
| 350 if len(args) < 1: | |
| 351 raise UsageError, 'Not enough arguments supplied' | |
| 343 classname = args[0] | 352 classname = args[0] |
| 344 # get the class | 353 # get the class |
| 345 try: | 354 try: |
| 346 cl = self.db.getclass(classname) | 355 cl = self.db.getclass(classname) |
| 347 except KeyError: | 356 except KeyError: |
| 399 '''Usage: specification classname | 408 '''Usage: specification classname |
| 400 Show the properties for a classname. | 409 Show the properties for a classname. |
| 401 | 410 |
| 402 This lists the properties for a given class. | 411 This lists the properties for a given class. |
| 403 ''' | 412 ''' |
| 413 if len(args) < 1: | |
| 414 raise UsageError, 'Not enough arguments supplied' | |
| 404 classname = args[0] | 415 classname = args[0] |
| 405 # get the class | 416 # get the class |
| 406 try: | 417 try: |
| 407 cl = self.db.getclass(classname) | 418 cl = self.db.getclass(classname) |
| 408 except KeyError: | 419 except KeyError: |
| 414 if keyprop == key: | 425 if keyprop == key: |
| 415 print '%s: %s (key property)'%(key, value) | 426 print '%s: %s (key property)'%(key, value) |
| 416 else: | 427 else: |
| 417 print '%s: %s'%(key, value) | 428 print '%s: %s'%(key, value) |
| 418 | 429 |
| 430 def do_display(self, args): | |
| 431 '''Usage: display designator | |
| 432 Show the property values for the given node. | |
| 433 | |
| 434 This lists the properties and their associated values for the given | |
| 435 node. | |
| 436 ''' | |
| 437 if len(args) < 1: | |
| 438 raise UsageError, 'Not enough arguments supplied' | |
| 439 | |
| 440 # decode the node designator | |
| 441 try: | |
| 442 classname, nodeid = roundupdb.splitDesignator(args[0]) | |
| 443 except roundupdb.DesignatorError, message: | |
| 444 raise UsageError, message | |
| 445 | |
| 446 # get the class | |
| 447 try: | |
| 448 cl = self.db.getclass(classname) | |
| 449 except KeyError: | |
| 450 raise UsageError, 'invalid class "%s"'%classname | |
| 451 | |
| 452 # display the values | |
| 453 for key in cl.properties.keys(): | |
| 454 value = cl.get(nodeid, key) | |
| 455 print '%s: %s'%(key, value) | |
| 456 | |
| 419 def do_create(self, args): | 457 def do_create(self, args): |
| 420 '''Usage: create classname property=value ... | 458 '''Usage: create classname property=value ... |
| 421 Create a new entry of a given class. | 459 Create a new entry of a given class. |
| 422 | 460 |
| 423 This creates a new entry of the given class using the property | 461 This creates a new entry of the given class using the property |
| 424 name=value arguments provided on the command line after the "create" | 462 name=value arguments provided on the command line after the "create" |
| 425 command. | 463 command. |
| 426 ''' | 464 ''' |
| 465 if len(args) < 1: | |
| 466 raise UsageError, 'Not enough arguments supplied' | |
| 427 from roundup import hyperdb | 467 from roundup import hyperdb |
| 428 | 468 |
| 429 classname = args[0] | 469 classname = args[0] |
| 430 | 470 |
| 431 # get the class | 471 # get the class |
| 506 Lists all instances of the given class. If the property is not | 546 Lists all instances of the given class. If the property is not |
| 507 specified, the "label" property is used. The label property is tried | 547 specified, the "label" property is used. The label property is tried |
| 508 in order: the key, "name", "title" and then the first property, | 548 in order: the key, "name", "title" and then the first property, |
| 509 alphabetically. | 549 alphabetically. |
| 510 ''' | 550 ''' |
| 551 if len(args) < 1: | |
| 552 raise UsageError, 'Not enough arguments supplied' | |
| 511 classname = args[0] | 553 classname = args[0] |
| 512 | 554 |
| 513 # get the class | 555 # get the class |
| 514 try: | 556 try: |
| 515 cl = self.db.getclass(classname) | 557 cl = self.db.getclass(classname) |
| 546 1 fatal-bug | 588 1 fatal-bug |
| 547 2 bug | 589 2 bug |
| 548 3 usability | 590 3 usability |
| 549 4 feature | 591 4 feature |
| 550 ''' | 592 ''' |
| 593 if len(args) < 1: | |
| 594 raise UsageError, 'Not enough arguments supplied' | |
| 551 classname = args[0] | 595 classname = args[0] |
| 552 | 596 |
| 553 # get the class | 597 # get the class |
| 554 try: | 598 try: |
| 555 cl = self.db.getclass(classname) | 599 cl = self.db.getclass(classname) |
| 598 '''Usage: history designator | 642 '''Usage: history designator |
| 599 Show the history entries of a designator. | 643 Show the history entries of a designator. |
| 600 | 644 |
| 601 Lists the journal entries for the node identified by the designator. | 645 Lists the journal entries for the node identified by the designator. |
| 602 ''' | 646 ''' |
| 647 if len(args) < 1: | |
| 648 raise UsageError, 'Not enough arguments supplied' | |
| 603 try: | 649 try: |
| 604 classname, nodeid = roundupdb.splitDesignator(args[0]) | 650 classname, nodeid = roundupdb.splitDesignator(args[0]) |
| 605 except roundupdb.DesignatorError, message: | 651 except roundupdb.DesignatorError, message: |
| 606 raise UsageError, message | 652 raise UsageError, message |
| 607 | 653 |
| 635 The changes made during an interactive session are not | 681 The changes made during an interactive session are not |
| 636 automatically written to the database - they must be committed | 682 automatically written to the database - they must be committed |
| 637 manually. This command undoes all those changes, so a commit | 683 manually. This command undoes all those changes, so a commit |
| 638 immediately after would make no changes to the database. | 684 immediately after would make no changes to the database. |
| 639 ''' | 685 ''' |
| 640 self.db.commit() | 686 self.db.rollback() |
| 641 return 0 | 687 return 0 |
| 642 | 688 |
| 643 def do_retire(self, args): | 689 def do_retire(self, args): |
| 644 '''Usage: retire designator[,designator]* | 690 '''Usage: retire designator[,designator]* |
| 645 Retire the node specified by designator. | 691 Retire the node specified by designator. |
| 646 | 692 |
| 647 This action indicates that a particular node is not to be retrieved by | 693 This action indicates that a particular node is not to be retrieved by |
| 648 the list or find commands, and its key value may be re-used. | 694 the list or find commands, and its key value may be re-used. |
| 649 ''' | 695 ''' |
| 696 if len(args) < 1: | |
| 697 raise UsageError, 'Not enough arguments supplied' | |
| 650 designators = string.split(args[0], ',') | 698 designators = string.split(args[0], ',') |
| 651 for designator in designators: | 699 for designator in designators: |
| 652 try: | 700 try: |
| 653 classname, nodeid = roundupdb.splitDesignator(designator) | 701 classname, nodeid = roundupdb.splitDesignator(designator) |
| 654 except roundupdb.DesignatorError, message: | 702 except roundupdb.DesignatorError, message: |
| 668 This action exports the current data from the database into | 716 This action exports the current data from the database into |
| 669 tab-separated-value files that are placed in the nominated destination | 717 tab-separated-value files that are placed in the nominated destination |
| 670 directory. The journals are not exported. | 718 directory. The journals are not exported. |
| 671 ''' | 719 ''' |
| 672 if len(args) < 2: | 720 if len(args) < 2: |
| 673 print do_export.__doc__ | 721 raise UsageError, 'Not enough arguments supplied' |
| 674 return 1 | |
| 675 classes = string.split(args[0], ',') | 722 classes = string.split(args[0], ',') |
| 676 dir = args[1] | 723 dir = args[1] |
| 677 | 724 |
| 678 # use the csv parser if we can - it's faster | 725 # use the csv parser if we can - it's faster |
| 679 if csv is not None: | 726 if csv is not None: |
| 832 | 879 |
| 833 # get the instance | 880 # get the instance |
| 834 try: | 881 try: |
| 835 instance = roundup.instance.open(self.instance_home) | 882 instance = roundup.instance.open(self.instance_home) |
| 836 except ValueError, message: | 883 except ValueError, message: |
| 884 self.instance_home = '' | |
| 837 print "Couldn't open instance: %s"%message | 885 print "Couldn't open instance: %s"%message |
| 838 return 1 | 886 return 1 |
| 839 self.db = instance.open('admin') | 887 |
| 840 | 888 # only open the database once! |
| 841 if len(args) < 2: | 889 if not self.db: |
| 842 print function.__doc__ | 890 self.db = instance.open('admin') |
| 843 return 1 | |
| 844 | 891 |
| 845 # do the command | 892 # do the command |
| 846 ret = 0 | 893 ret = 0 |
| 847 try: | 894 try: |
| 848 ret = function(args[1:]) | 895 ret = function(args[1:]) |
| 868 | 915 |
| 869 while 1: | 916 while 1: |
| 870 try: | 917 try: |
| 871 command = raw_input('roundup> ') | 918 command = raw_input('roundup> ') |
| 872 except EOFError: | 919 except EOFError: |
| 873 print '.. exit' | 920 print 'exit...' |
| 874 return 0 | 921 break |
| 922 if not command: continue | |
| 875 args = ws_re.split(command) | 923 args = ws_re.split(command) |
| 876 if not args: continue | 924 if not args: continue |
| 877 if args[0] in ('quit', 'exit'): return 0 | 925 if args[0] in ('quit', 'exit'): break |
| 878 self.run_command(args) | 926 self.run_command(args) |
| 927 | |
| 928 # exit.. check for transactions | |
| 929 if self.db and self.db.transactions: | |
| 930 commit = raw_input("There are unsaved changes. Commit them (y/N)? ") | |
| 931 if commit[0].lower() == 'y': | |
| 932 self.db.commit() | |
| 933 return 0 | |
| 879 | 934 |
| 880 def main(self): | 935 def main(self): |
| 881 try: | 936 try: |
| 882 opts, args = getopt.getopt(sys.argv[1:], 'i:u:hc') | 937 opts, args = getopt.getopt(sys.argv[1:], 'i:u:hc') |
| 883 except getopt.GetoptError, e: | 938 except getopt.GetoptError, e: |
| 916 tool = AdminTool() | 971 tool = AdminTool() |
| 917 sys.exit(tool.main()) | 972 sys.exit(tool.main()) |
| 918 | 973 |
| 919 # | 974 # |
| 920 # $Log: not supported by cvs2svn $ | 975 # $Log: not supported by cvs2svn $ |
| 976 # Revision 1.50 2001/12/02 05:06:16 richard | |
| 977 # . We now use weakrefs in the Classes to keep the database reference, so | |
| 978 # the close() method on the database is no longer needed. | |
| 979 # I bumped the minimum python requirement up to 2.1 accordingly. | |
| 980 # . #487480 ] roundup-server | |
| 981 # . #487476 ] INSTALL.txt | |
| 982 # | |
| 983 # I also cleaned up the change message / post-edit stuff in the cgi client. | |
| 984 # There's now a clearly marked "TODO: append the change note" where I believe | |
| 985 # the change note should be added there. The "changes" list will obviously | |
| 986 # have to be modified to be a dict of the changes, or somesuch. | |
| 987 # | |
| 988 # More testing needed. | |
| 989 # | |
| 921 # Revision 1.49 2001/12/01 07:17:50 richard | 990 # Revision 1.49 2001/12/01 07:17:50 richard |
| 922 # . We now have basic transaction support! Information is only written to | 991 # . We now have basic transaction support! Information is only written to |
| 923 # the database when the commit() method is called. Only the anydbm | 992 # the database when the commit() method is called. Only the anydbm |
| 924 # backend is modified in this way - neither of the bsddb backends have been. | 993 # backend is modified in this way - neither of the bsddb backends have been. |
| 925 # The mail, admin and cgi interfaces all use commit (except the admin tool | 994 # The mail, admin and cgi interfaces all use commit (except the admin tool |
