comparison roundup/admin.py @ 2307:f786a1b9dbdf

translatabe strings adjustments, postponed help text translation
author Alexander Smishlajev <a1s@users.sourceforge.net>
date Fri, 14 May 2004 20:01:16 +0000
parents 19d1cd9ab09b
children 8d5c95c33447
comparison
equal deleted inserted replaced
2306:1421b19cd61b 2307:f786a1b9dbdf
13 # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 13 # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
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.68 2004-04-17 01:47:37 richard Exp $ 19 # $Id: admin.py,v 1.69 2004-05-14 20:01:16 a1s Exp $
20 20
21 '''Administration commands for maintaining Roundup trackers. 21 '''Administration commands for maintaining Roundup trackers.
22 ''' 22 '''
23 __docformat__ = 'restructuredtext' 23 __docformat__ = 'restructuredtext'
24 24
129 roundup-admin help all -- all available help 129 roundup-admin help all -- all available help
130 ''')%locals() 130 ''')%locals()
131 self.help_commands() 131 self.help_commands()
132 132
133 def help_commands(self): 133 def help_commands(self):
134 ''' List the commands available with their precis help. 134 ''' List the commands available with their precise help.
135 ''' 135 '''
136 print _('Commands:'), 136 print _('Commands:'),
137 commands = [''] 137 commands = ['']
138 for command in self.commands.values(): 138 for command in self.commands.values():
139 h = command.__doc__.split('\n')[0] 139 h = _(command.__doc__).split('\n')[0]
140 commands.append(' '+h[7:]) 140 commands.append(' '+h[7:])
141 commands.sort() 141 commands.sort()
142 commands.append(_('Commands may be abbreviated as long as the abbreviation matches only one')) 142 commands.append(_(
143 commands.append(_('command, e.g. l == li == lis == list.')) 143 """Commands may be abbreviated as long as the abbreviation
144 matches only one command, e.g. l == li == lis == list."""))
144 print '\n'.join(commands) 145 print '\n'.join(commands)
145 print 146 print
146 147
147 def help_commands_html(self, indent_re=re.compile(r'^(\s+)\S+')): 148 def help_commands_html(self, indent_re=re.compile(r'^(\s+)\S+')):
148 ''' Produce an HTML command list. 149 ''' Produce an HTML command list.
150 commands = self.commands.values() 151 commands = self.commands.values()
151 def sortfun(a, b): 152 def sortfun(a, b):
152 return cmp(a.__name__, b.__name__) 153 return cmp(a.__name__, b.__name__)
153 commands.sort(sortfun) 154 commands.sort(sortfun)
154 for command in commands: 155 for command in commands:
155 h = command.__doc__.split('\n') 156 h = _(command.__doc__).split('\n')
156 name = command.__name__[3:] 157 name = command.__name__[3:]
157 usage = h[0] 158 usage = h[0]
158 print _(''' 159 print _('''
159 <tr><td valign=top><strong>%(name)s</strong></td> 160 <tr><td valign=top><strong>%(name)s</strong></td>
160 <td><tt>%(usage)s</tt><p> 161 <td><tt>%(usage)s</tt><p>
169 print _('</pre></td></tr>\n') 170 print _('</pre></td></tr>\n')
170 171
171 def help_all(self): 172 def help_all(self):
172 print _(''' 173 print _('''
173 All commands (except help) require a tracker specifier. This is just the path 174 All commands (except help) require a tracker specifier. This is just the path
174 to the roundup tracker you're working with. A roundup tracker is where 175 to the roundup tracker you're working with. A roundup tracker is where
175 roundup keeps the database and configuration file that defines an issue 176 roundup keeps the database and configuration file that defines an issue
176 tracker. It may be thought of as the issue tracker's "home directory". It may 177 tracker. It may be thought of as the issue tracker's "home directory". It may
177 be specified in the environment variable TRACKER_HOME or on the command 178 be specified in the environment variable TRACKER_HOME or on the command
178 line as "-i tracker". 179 line as "-i tracker".
179 180
203 \\ (1 token: \) 204 \\ (1 token: \)
204 \n\r\t (1 token: a newline, carriage-return and tab) 205 \n\r\t (1 token: a newline, carriage-return and tab)
205 206
206 When multiple nodes are specified to the roundup get or roundup set 207 When multiple nodes are specified to the roundup get or roundup set
207 commands, the specified properties are retrieved or set on all the listed 208 commands, the specified properties are retrieved or set on all the listed
208 nodes. 209 nodes.
209 210
210 When multiple results are returned by the roundup get or roundup find 211 When multiple results are returned by the roundup get or roundup find
211 commands, they are printed one per line (default) or joined by commas (with 212 commands, they are printed one per line (default) or joined by commas (with
212 the -c) option. 213 the -c) option.
213 214
214 Where the command changes data, a login name/password is required. The 215 Where the command changes data, a login name/password is required. The
215 login may be specified as either "name" or "name:password". 216 login may be specified as either "name" or "name:password".
216 . ROUNDUP_LOGIN environment variable 217 . ROUNDUP_LOGIN environment variable
217 . the -u command-line option 218 . the -u command-line option
218 If either the name or password is not supplied, they are obtained from the 219 If either the name or password is not supplied, they are obtained from the
219 command-line. 220 command-line.
220 221
221 Date format examples: 222 Date format examples:
222 "2000-04-17.03:45" means <Date 2000-04-17.08:45:00> 223 "2000-04-17.03:45" means <Date 2000-04-17.08:45:00>
223 "2000-04-17" means <Date 2000-04-17.00:00:00> 224 "2000-04-17" means <Date 2000-04-17.00:00:00>
224 "01-25" means <Date yyyy-01-25.00:00:00> 225 "01-25" means <Date yyyy-01-25.00:00:00>
230 231
231 Command help: 232 Command help:
232 ''') 233 ''')
233 for name, command in self.commands.items(): 234 for name, command in self.commands.items():
234 print _('%s:')%name 235 print _('%s:')%name
235 print _(' '), command.__doc__ 236 print _(' '), _(command.__doc__)
236 237
237 def do_help(self, args, nl_re=re.compile('[\r\n]'), 238 def do_help(self, args, nl_re=re.compile('[\r\n]'),
238 indent_re=re.compile(r'^(\s+)\S+')): 239 indent_re=re.compile(r'^(\s+)\S+')):
239 '''Usage: help topic 240 ""'''Usage: help topic
240 Give help about topic. 241 Give help about topic.
241 242
242 commands -- list commands 243 commands -- list commands
243 <command> -- help specific to a command 244 <command> -- help specific to a command
244 initopts -- init command options 245 initopts -- init command options
246 ''' 247 '''
247 if len(args)>0: 248 if len(args)>0:
248 topic = args[0] 249 topic = args[0]
249 else: 250 else:
250 topic = 'help' 251 topic = 'help'
251 252
252 253
253 # try help_ methods 254 # try help_ methods
254 if self.help.has_key(topic): 255 if self.help.has_key(topic):
255 self.help[topic]() 256 self.help[topic]()
256 return 0 257 return 0
262 print _('Sorry, no help for "%(topic)s"')%locals() 263 print _('Sorry, no help for "%(topic)s"')%locals()
263 return 1 264 return 1
264 265
265 # display the help for each match, removing the docsring indent 266 # display the help for each match, removing the docsring indent
266 for name, help in l: 267 for name, help in l:
267 lines = nl_re.split(help.__doc__) 268 lines = nl_re.split(_(help.__doc__))
268 print lines[0] 269 print lines[0]
269 indent = indent_re.match(lines[1]) 270 indent = indent_re.match(lines[1])
270 if indent: indent = len(indent.group(1)) 271 if indent: indent = len(indent.group(1))
271 for line in lines[1:]: 272 for line in lines[1:]:
272 if indent: 273 if indent:
335 import roundup.backends 336 import roundup.backends
336 backends = roundup.backends.__all__ 337 backends = roundup.backends.__all__
337 print _('Back ends:'), ', '.join(backends) 338 print _('Back ends:'), ', '.join(backends)
338 339
339 def do_install(self, tracker_home, args): 340 def do_install(self, tracker_home, args):
340 '''Usage: install [template [backend [admin password]]] 341 ""'''Usage: install [template [backend [admin password]]]
341 Install a new Roundup tracker. 342 Install a new Roundup tracker.
342 343
343 The command will prompt for the tracker home directory (if not supplied 344 The command will prompt for the tracker home directory (if not supplied
344 through TRACKER_HOME or the -i option). The template, backend and admin 345 through TRACKER_HOME or the -i option). The template, backend and admin
345 password may be specified on the command-line as arguments, in that 346 password may be specified on the command-line as arguments, in that
361 if not os.path.exists(parent): 362 if not os.path.exists(parent):
362 raise UsageError, _('Instance home parent directory "%(parent)s"' 363 raise UsageError, _('Instance home parent directory "%(parent)s"'
363 ' does not exist')%locals() 364 ' does not exist')%locals()
364 365
365 if os.path.exists(os.path.join(tracker_home, 'config.py')): 366 if os.path.exists(os.path.join(tracker_home, 'config.py')):
366 print _('WARNING: There appears to be a tracker in ' 367 ok = raw_input(_(
367 '"%(tracker_home)s"!')%locals() 368 """WARNING: There appears to be a tracker in "%(tracker_home)s"!
368 print _('If you re-install it, you will lose all the data!') 369 If you re-install it, you will lose all the data!
369 ok = raw_input(_('Erase it? Y/N: ')).strip() 370 Erase it? Y/N: """) % locals())
370 if ok.strip().lower() != 'y': 371 if ok.strip().lower() != 'y':
371 return 0 372 return 0
372 373
373 # clear it out so the install isn't confused 374 # clear it out so the install isn't confused
374 shutil.rmtree(tracker_home) 375 shutil.rmtree(tracker_home)
415 } 416 }
416 return 0 417 return 0
417 418
418 419
419 def do_initialise(self, tracker_home, args): 420 def do_initialise(self, tracker_home, args):
420 '''Usage: initialise [adminpw] 421 ""'''Usage: initialise [adminpw]
421 Initialise a new Roundup tracker. 422 Initialise a new Roundup tracker.
422 423
423 The administrator details will be set at this step. 424 The administrator details will be set at this step.
424 425
425 Execute the tracker's initialisation function dbinit.init() 426 Execute the tracker's initialisation function dbinit.init()
447 db_exists = tracker.select_db.Database.exists(tracker.config) 448 db_exists = tracker.select_db.Database.exists(tracker.config)
448 except AttributeError: 449 except AttributeError:
449 # TODO: move this code to exists() static method in every backend 450 # TODO: move this code to exists() static method in every backend
450 db_exists = os.path.exists(os.path.join(tracker_home, 'db')) 451 db_exists = os.path.exists(os.path.join(tracker_home, 'db'))
451 if db_exists: 452 if db_exists:
452 print _('WARNING: The database is already initialised!') 453 ok = raw_input(_(
453 print _('If you re-initialise it, you will lose all the data!') 454 """WARNING: The database is already initialised!
454 ok = raw_input(_('Erase it? Y/N: ')).strip() 455 If you re-initialise it, you will lose all the data!
456 Erase it? Y/N: """))
455 if ok.strip().lower() != 'y': 457 if ok.strip().lower() != 'y':
456 return 0 458 return 0
457 459
458 # Get a database backend in use by tracker 460 # Get a database backend in use by tracker
459 try: 461 try:
468 470
469 return 0 471 return 0
470 472
471 473
472 def do_get(self, args): 474 def do_get(self, args):
473 '''Usage: get property designator[,designator]* 475 ""'''Usage: get property designator[,designator]*
474 Get the given property of one or more designator(s). 476 Get the given property of one or more designator(s).
475 477
476 Retrieves the property value of the nodes specified by the designators. 478 Retrieves the property value of the nodes specified by the designators.
477 ''' 479 '''
478 if len(args) < 2: 480 if len(args) < 2:
541 543
542 return 0 544 return 0
543 545
544 546
545 def do_set(self, args, pwre = re.compile(r'{(\w+)}(.+)')): 547 def do_set(self, args, pwre = re.compile(r'{(\w+)}(.+)')):
546 '''Usage: set items property=value property=value ... 548 ""'''Usage: set items property=value property=value ...
547 Set the given properties of one or more items(s). 549 Set the given properties of one or more items(s).
548 550
549 The items are specified as a class or as a comma-separated 551 The items are specified as a class or as a comma-separated
550 list of item designators (ie "designator[,designator,...]"). 552 list of item designators (ie "designator[,designator,...]").
551 553
595 import traceback; traceback.print_exc() 597 import traceback; traceback.print_exc()
596 raise UsageError, message 598 raise UsageError, message
597 return 0 599 return 0
598 600
599 def do_find(self, args): 601 def do_find(self, args):
600 '''Usage: find classname propname=value ... 602 ""'''Usage: find classname propname=value ...
601 Find the nodes of the given class with a given link property value. 603 Find the nodes of the given class with a given link property value.
602 604
603 Find the nodes of the given class with a given link property value. The 605 Find the nodes of the given class with a given link property value. The
604 value may be either the nodeid of the linked node, or its key value. 606 value may be either the nodeid of the linked node, or its key value.
605 ''' 607 '''
634 # get the linked-to class and look up the key property 636 # get the linked-to class and look up the key property
635 link_class = self.db.getclass(property.classname) 637 link_class = self.db.getclass(property.classname)
636 try: 638 try:
637 props[propname] = link_class.lookup(value) 639 props[propname] = link_class.lookup(value)
638 except TypeError: 640 except TypeError:
639 raise UsageError, _('%(classname)s has no key property"')%{ 641 raise UsageError, _('%(classname)s has no key property')%{
640 'classname': link_class.classname} 642 'classname': link_class.classname}
641 643
642 # now do the find 644 # now do the find
643 try: 645 try:
644 id = [] 646 id = []
645 designator = [] 647 designator = []
646 if self.separator: 648 if self.separator:
647 if self.print_designator: 649 if self.print_designator:
666 except (ValueError, TypeError), message: 668 except (ValueError, TypeError), message:
667 raise UsageError, message 669 raise UsageError, message
668 return 0 670 return 0
669 671
670 def do_specification(self, args): 672 def do_specification(self, args):
671 '''Usage: specification classname 673 ""'''Usage: specification classname
672 Show the properties for a classname. 674 Show the properties for a classname.
673 675
674 This lists the properties for a given class. 676 This lists the properties for a given class.
675 ''' 677 '''
676 if len(args) < 1: 678 if len(args) < 1:
686 print _('%(key)s: %(value)s (key property)')%locals() 688 print _('%(key)s: %(value)s (key property)')%locals()
687 else: 689 else:
688 print _('%(key)s: %(value)s')%locals() 690 print _('%(key)s: %(value)s')%locals()
689 691
690 def do_display(self, args): 692 def do_display(self, args):
691 '''Usage: display designator[,designator]* 693 ""'''Usage: display designator[,designator]*
692 Show the property values for the given node(s). 694 Show the property values for the given node(s).
693 695
694 This lists the properties and their associated values for the given 696 This lists the properties and their associated values for the given
695 node. 697 node.
696 ''' 698 '''
713 for key in keys: 715 for key in keys:
714 value = cl.get(nodeid, key) 716 value = cl.get(nodeid, key)
715 print _('%(key)s: %(value)s')%locals() 717 print _('%(key)s: %(value)s')%locals()
716 718
717 def do_create(self, args, pwre = re.compile(r'{(\w+)}(.+)')): 719 def do_create(self, args, pwre = re.compile(r'{(\w+)}(.+)')):
718 '''Usage: create classname property=value ... 720 ""'''Usage: create classname property=value ...
719 Create a new entry of a given class. 721 Create a new entry of a given class.
720 722
721 This creates a new entry of the given class using the property 723 This creates a new entry of the given class using the property
722 name=value arguments provided on the command line after the "create" 724 name=value arguments provided on the command line after the "create"
723 command. 725 command.
777 except (TypeError, IndexError, ValueError), message: 779 except (TypeError, IndexError, ValueError), message:
778 raise UsageError, message 780 raise UsageError, message
779 return 0 781 return 0
780 782
781 def do_list(self, args): 783 def do_list(self, args):
782 '''Usage: list classname [property] 784 ""'''Usage: list classname [property]
783 List the instances of a class. 785 List the instances of a class.
784 786
785 Lists all instances of the given class. If the property is not 787 Lists all instances of the given class. If the property is not
786 specified, the "label" property is used. The label property is tried 788 specified, the "label" property is used. The label property is tried
787 in order: the key, "name", "title" and then the first property, 789 in order: the key, "name", "title" and then the first property,
830 '"%(propname)s"')%locals() 832 '"%(propname)s"')%locals()
831 print _('%(nodeid)4s: %(value)s')%locals() 833 print _('%(nodeid)4s: %(value)s')%locals()
832 return 0 834 return 0
833 835
834 def do_table(self, args): 836 def do_table(self, args):
835 '''Usage: table classname [property[,property]*] 837 ""'''Usage: table classname [property[,property]*]
836 List the instances of a class in tabular form. 838 List the instances of a class in tabular form.
837 839
838 Lists all instances of the given class. If the properties are not 840 Lists all instances of the given class. If the properties are not
839 specified, all properties are displayed. By default, the column widths 841 specified, all properties are displayed. By default, the column widths
840 are the width of the largest value. The width may be explicitly defined 842 are the width of the largest value. The width may be explicitly defined
841 by defining the property as "name:width". For example:: 843 by defining the property as "name:width". For example::
842 844
843 roundup> table priority id,name:10 845 roundup> table priority id,name:10
844 Id Name 846 Id Name
845 1 fatal-bug 847 1 fatal-bug
846 2 bug 848 2 bug
847 3 usability 849 3 usability
848 4 feature 850 4 feature
849 851
850 Also to make the width of the column the width of the label, 852 Also to make the width of the column the width of the label,
851 leave a trailing : without a width on the property. For example:: 853 leave a trailing : without a width on the property. For example::
852 854
853 roundup> table priority id,name: 855 roundup> table priority id,name:
854 Id Name 856 Id Name
855 1 fata 857 1 fata
856 2 bug 858 2 bug
857 3 usab 859 3 usab
858 4 feat 860 4 feat
859 861
860 will result in a the 4 character wide "Name" column. 862 will result in a the 4 character wide "Name" column.
861 ''' 863 '''
899 for nodeid in cl.list(): 901 for nodeid in cl.list():
900 curlen = len(str(cl.get(nodeid, spec))) 902 curlen = len(str(cl.get(nodeid, spec)))
901 if curlen > maxlen: 903 if curlen > maxlen:
902 maxlen = curlen 904 maxlen = curlen
903 props.append((spec, maxlen)) 905 props.append((spec, maxlen))
904 906
905 # now display the heading 907 # now display the heading
906 print ' '.join([name.capitalize().ljust(width) for name,width in props]) 908 print ' '.join([name.capitalize().ljust(width) for name,width in props])
907 909
908 # and the table data 910 # and the table data
909 for nodeid in cl.list(): 911 for nodeid in cl.list():
923 l.append(f%value[:width]) 925 l.append(f%value[:width])
924 print ' '.join(l) 926 print ' '.join(l)
925 return 0 927 return 0
926 928
927 def do_history(self, args): 929 def do_history(self, args):
928 '''Usage: history designator 930 ""'''Usage: history designator
929 Show the history entries of a designator. 931 Show the history entries of a designator.
930 932
931 Lists the journal entries for the node identified by the designator. 933 Lists the journal entries for the node identified by the designator.
932 ''' 934 '''
933 if len(args) < 1: 935 if len(args) < 1:
944 except IndexError: 946 except IndexError:
945 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals() 947 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals()
946 return 0 948 return 0
947 949
948 def do_commit(self, args): 950 def do_commit(self, args):
949 '''Usage: commit 951 ""'''Usage: commit
950 Commit changes made to the database during an interactive session. 952 Commit changes made to the database during an interactive session.
951 953
952 The changes made during an interactive session are not 954 The changes made during an interactive session are not
953 automatically written to the database - they must be committed 955 automatically written to the database - they must be committed
954 using this command. 956 using this command.
958 ''' 960 '''
959 self.db.commit() 961 self.db.commit()
960 return 0 962 return 0
961 963
962 def do_rollback(self, args): 964 def do_rollback(self, args):
963 '''Usage: rollback 965 ""'''Usage: rollback
964 Undo all changes that are pending commit to the database. 966 Undo all changes that are pending commit to the database.
965 967
966 The changes made during an interactive session are not 968 The changes made during an interactive session are not
967 automatically written to the database - they must be committed 969 automatically written to the database - they must be committed
968 manually. This command undoes all those changes, so a commit 970 manually. This command undoes all those changes, so a commit
970 ''' 972 '''
971 self.db.rollback() 973 self.db.rollback()
972 return 0 974 return 0
973 975
974 def do_retire(self, args): 976 def do_retire(self, args):
975 '''Usage: retire designator[,designator]* 977 ""'''Usage: retire designator[,designator]*
976 Retire the node specified by designator. 978 Retire the node specified by designator.
977 979
978 This action indicates that a particular node is not to be retrieved by 980 This action indicates that a particular node is not to be retrieved by
979 the list or find commands, and its key value may be re-used. 981 the list or find commands, and its key value may be re-used.
980 ''' 982 '''
993 except IndexError: 995 except IndexError:
994 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals() 996 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals()
995 return 0 997 return 0
996 998
997 def do_restore(self, args): 999 def do_restore(self, args):
998 '''Usage: restore designator[,designator]* 1000 ""'''Usage: restore designator[,designator]*
999 Restore the retired node specified by designator. 1001 Restore the retired node specified by designator.
1000 1002
1001 The given nodes will become available for users again. 1003 The given nodes will become available for users again.
1002 ''' 1004 '''
1003 if len(args) < 1: 1005 if len(args) < 1:
1015 except IndexError: 1017 except IndexError:
1016 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals() 1018 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals()
1017 return 0 1019 return 0
1018 1020
1019 def do_export(self, args): 1021 def do_export(self, args):
1020 '''Usage: export [class[,class]] export_dir 1022 ""'''Usage: export [class[,class]] export_dir
1021 Export the database to colon-separated-value files. 1023 Export the database to colon-separated-value files.
1022 1024
1023 Optionally limit the export to just the names classes. 1025 Optionally limit the export to just the names classes.
1024 1026
1025 This action exports the current data from the database into 1027 This action exports the current data from the database into
1067 map(journals.writerow, cl.export_journals()) 1069 map(journals.writerow, cl.export_journals())
1068 jf.close() 1070 jf.close()
1069 return 0 1071 return 0
1070 1072
1071 def do_import(self, args): 1073 def do_import(self, args):
1072 '''Usage: import import_dir 1074 ""'''Usage: import import_dir
1073 Import a database from the directory containing CSV files, two per 1075 Import a database from the directory containing CSV files, two per
1074 class to import. 1076 class to import.
1075 1077
1076 The files used in the import are: 1078 The files used in the import are:
1077 1079
1127 self.db.setid(classname, str(maxid+1)) 1129 self.db.setid(classname, str(maxid+1))
1128 1130
1129 return 0 1131 return 0
1130 1132
1131 def do_pack(self, args): 1133 def do_pack(self, args):
1132 '''Usage: pack period | date 1134 ""'''Usage: pack period | date
1133 1135
1134 Remove journal entries older than a period of time specified or 1136 Remove journal entries older than a period of time specified or
1135 before a certain date. 1137 before a certain date.
1136 1138
1137 A period is specified using the suffixes "y", "m", and "d". The 1139 A period is specified using the suffixes "y", "m", and "d". The
1138 suffix "w" (for "week") means 7 days. 1140 suffix "w" (for "week") means 7 days.
1139 1141
1140 "3y" means three years 1142 "3y" means three years
1141 "2y 1m" means two years and one month 1143 "2y 1m" means two years and one month
1142 "1m 25d" means one month and 25 days 1144 "1m 25d" means one month and 25 days
1143 "2w 3d" means two weeks and three days 1145 "2w 3d" means two weeks and three days
1144 1146
1145 Date format is "YYYY-MM-DD" eg: 1147 Date format is "YYYY-MM-DD" eg:
1146 2001-01-01 1148 2001-01-01
1147 1149
1148 ''' 1150 '''
1149 if len(args) <> 1: 1151 if len(args) <> 1:
1150 raise UsageError, _('Not enough arguments supplied') 1152 raise UsageError, _('Not enough arguments supplied')
1151 1153
1152 # are we dealing with a period or a date 1154 # are we dealing with a period or a date
1153 value = args[0] 1155 value = args[0]
1154 date_re = re.compile(r''' 1156 date_re = re.compile(r'''
1155 (?P<date>\d\d\d\d-\d\d?-\d\d?)? # yyyy-mm-dd 1157 (?P<date>\d\d\d\d-\d\d?-\d\d?)? # yyyy-mm-dd
1156 (?P<period>(\d+y\s*)?(\d+m\s*)?(\d+d\s*)?)? 1158 (?P<period>(\d+y\s*)?(\d+m\s*)?(\d+d\s*)?)?
1165 pack_before = date.Date(value) 1167 pack_before = date.Date(value)
1166 self.db.pack(pack_before) 1168 self.db.pack(pack_before)
1167 return 0 1169 return 0
1168 1170
1169 def do_reindex(self, args): 1171 def do_reindex(self, args):
1170 '''Usage: reindex 1172 ""'''Usage: reindex
1171 Re-generate a tracker's search indexes. 1173 Re-generate a tracker's search indexes.
1172 1174
1173 This will re-generate the search indexes for a tracker. This will 1175 This will re-generate the search indexes for a tracker. This will
1174 typically happen automatically. 1176 typically happen automatically.
1175 ''' 1177 '''
1176 self.db.indexer.force_reindex() 1178 self.db.indexer.force_reindex()
1177 self.db.reindex() 1179 self.db.reindex()
1178 return 0 1180 return 0
1179 1181
1180 def do_security(self, args): 1182 def do_security(self, args):
1181 '''Usage: security [Role name] 1183 ""'''Usage: security [Role name]
1182 Display the Permissions available to one or all Roles. 1184 Display the Permissions available to one or all Roles.
1183 ''' 1185 '''
1184 if len(args) == 1: 1186 if len(args) == 1:
1185 role = args[0] 1187 role = args[0]
1186 try: 1188 try:
1291 return ret 1293 return ret
1292 1294
1293 def interactive(self): 1295 def interactive(self):
1294 '''Run in an interactive mode 1296 '''Run in an interactive mode
1295 ''' 1297 '''
1296 print _('Roundup %s ready for input.'%roundup_version) 1298 print _('Roundup %s ready for input.\nType "help" for help.'
1297 print _('Type "help" for help.') 1299 % roundup_version)
1298 try: 1300 try:
1299 import readline 1301 import readline
1300 except ImportError: 1302 except ImportError:
1301 print _('Note: command history and editing not available') 1303 print _('Note: command history and editing not available')
1302 1304

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