Mercurial > p > roundup > code
comparison roundup/admin.py @ 4357:13b3155869e0
Beginnings of a big code cleanup / modernisation to make 2to3 happy
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Mon, 22 Feb 2010 05:26:57 +0000 |
| parents | e16a1131ba67 |
| children | a0be2bc223f5 |
comparison
equal
deleted
inserted
replaced
| 4356:05a65559d873 | 4357:13b3155869e0 |
|---|---|
| 19 | 19 |
| 20 """Administration commands for maintaining Roundup trackers. | 20 """Administration commands for maintaining Roundup trackers. |
| 21 """ | 21 """ |
| 22 __docformat__ = 'restructuredtext' | 22 __docformat__ = 'restructuredtext' |
| 23 | 23 |
| 24 import csv, getopt, getpass, os, re, shutil, sys, UserDict | 24 import csv, getopt, getpass, os, re, shutil, sys, UserDict, operator |
| 25 | 25 |
| 26 from roundup import date, hyperdb, roundupdb, init, password, token | 26 from roundup import date, hyperdb, roundupdb, init, password, token |
| 27 from roundup import __version__ as roundup_version | 27 from roundup import __version__ as roundup_version |
| 28 import roundup.instance | 28 import roundup.instance |
| 29 from roundup.configuration import CoreConfig | 29 from roundup.configuration import CoreConfig |
| 35 | 35 |
| 36 Original code submitted by Engelbert Gruber. | 36 Original code submitted by Engelbert Gruber. |
| 37 """ | 37 """ |
| 38 _marker = [] | 38 _marker = [] |
| 39 def get(self, key, default=_marker): | 39 def get(self, key, default=_marker): |
| 40 if self.data.has_key(key): | 40 if key in self.data: |
| 41 return [(key, self.data[key])] | 41 return [(key, self.data[key])] |
| 42 keylist = self.data.keys() | 42 keylist = sorted(self.data) |
| 43 keylist.sort() | |
| 44 l = [] | 43 l = [] |
| 45 for ki in keylist: | 44 for ki in keylist: |
| 46 if ki.startswith(key): | 45 if ki.startswith(key): |
| 47 l.append((ki, self.data[ki])) | 46 l.append((ki, self.data[ki])) |
| 48 if not l and default is self._marker: | 47 if not l and default is self._marker: |
| 49 raise KeyError, key | 48 raise KeyError(key) |
| 50 return l | 49 return l |
| 51 | 50 |
| 52 class AdminTool: | 51 class AdminTool: |
| 53 """ A collection of methods used in maintaining Roundup trackers. | 52 """ A collection of methods used in maintaining Roundup trackers. |
| 54 | 53 |
| 61 | 60 |
| 62 Additional help may be supplied by help_*() methods. | 61 Additional help may be supplied by help_*() methods. |
| 63 """ | 62 """ |
| 64 def __init__(self): | 63 def __init__(self): |
| 65 self.commands = CommandDict() | 64 self.commands = CommandDict() |
| 66 for k in AdminTool.__dict__.keys(): | 65 for k in AdminTool.__dict__: |
| 67 if k[:3] == 'do_': | 66 if k[:3] == 'do_': |
| 68 self.commands[k[3:]] = getattr(self, k) | 67 self.commands[k[3:]] = getattr(self, k) |
| 69 self.help = {} | 68 self.help = {} |
| 70 for k in AdminTool.__dict__.keys(): | 69 for k in AdminTool.__dict__: |
| 71 if k[:5] == 'help_': | 70 if k[:5] == 'help_': |
| 72 self.help[k[5:]] = getattr(self, k) | 71 self.help[k[5:]] = getattr(self, k) |
| 73 self.tracker_home = '' | 72 self.tracker_home = '' |
| 74 self.db = None | 73 self.db = None |
| 75 self.db_uncommitted = False | 74 self.db_uncommitted = False |
| 78 """Get the class - raise an exception if it doesn't exist. | 77 """Get the class - raise an exception if it doesn't exist. |
| 79 """ | 78 """ |
| 80 try: | 79 try: |
| 81 return self.db.getclass(classname) | 80 return self.db.getclass(classname) |
| 82 except KeyError: | 81 except KeyError: |
| 83 raise UsageError, _('no such class "%(classname)s"')%locals() | 82 raise UsageError(_('no such class "%(classname)s"')%locals()) |
| 84 | 83 |
| 85 def props_from_args(self, args): | 84 def props_from_args(self, args): |
| 86 """ Produce a dictionary of prop: value from the args list. | 85 """ Produce a dictionary of prop: value from the args list. |
| 87 | 86 |
| 88 The args list is specified as ``prop=value prop=value ...``. | 87 The args list is specified as ``prop=value prop=value ...``. |
| 89 """ | 88 """ |
| 90 props = {} | 89 props = {} |
| 91 for arg in args: | 90 for arg in args: |
| 92 if arg.find('=') == -1: | 91 if arg.find('=') == -1: |
| 93 raise UsageError, _('argument "%(arg)s" not propname=value' | 92 raise UsageError(_('argument "%(arg)s" not propname=value' |
| 94 )%locals() | 93 )%locals()) |
| 95 l = arg.split('=') | 94 l = arg.split('=') |
| 96 if len(l) < 2: | 95 if len(l) < 2: |
| 97 raise UsageError, _('argument "%(arg)s" not propname=value' | 96 raise UsageError(_('argument "%(arg)s" not propname=value' |
| 98 )%locals() | 97 )%locals()) |
| 99 key, value = l[0], '='.join(l[1:]) | 98 key, value = l[0], '='.join(l[1:]) |
| 100 if value: | 99 if value: |
| 101 props[key] = value | 100 props[key] = value |
| 102 else: | 101 else: |
| 103 props[key] = None | 102 props[key] = None |
| 135 def help_commands(self): | 134 def help_commands(self): |
| 136 """List the commands available with their help summary. | 135 """List the commands available with their help summary. |
| 137 """ | 136 """ |
| 138 print _('Commands:'), | 137 print _('Commands:'), |
| 139 commands = [''] | 138 commands = [''] |
| 140 for command in self.commands.values(): | 139 for command in self.commands.itervalues(): |
| 141 h = _(command.__doc__).split('\n')[0] | 140 h = _(command.__doc__).split('\n')[0] |
| 142 commands.append(' '+h[7:]) | 141 commands.append(' '+h[7:]) |
| 143 commands.sort() | 142 commands.sort() |
| 144 commands.append(_( | 143 commands.append(_( |
| 145 """Commands may be abbreviated as long as the abbreviation | 144 """Commands may be abbreviated as long as the abbreviation |
| 148 print | 147 print |
| 149 | 148 |
| 150 def help_commands_html(self, indent_re=re.compile(r'^(\s+)\S+')): | 149 def help_commands_html(self, indent_re=re.compile(r'^(\s+)\S+')): |
| 151 """ Produce an HTML command list. | 150 """ Produce an HTML command list. |
| 152 """ | 151 """ |
| 153 commands = self.commands.values() | 152 commands = sorted(self.commands.itervalues(), |
| 154 def sortfun(a, b): | 153 operator.attrgetter('__name__')) |
| 155 return cmp(a.__name__, b.__name__) | |
| 156 commands.sort(sortfun) | |
| 157 for command in commands: | 154 for command in commands: |
| 158 h = _(command.__doc__).split('\n') | 155 h = _(command.__doc__).split('\n') |
| 159 name = command.__name__[3:] | 156 name = command.__name__[3:] |
| 160 usage = h[0] | 157 usage = h[0] |
| 161 print """ | 158 print """ |
| 253 else: | 250 else: |
| 254 topic = 'help' | 251 topic = 'help' |
| 255 | 252 |
| 256 | 253 |
| 257 # try help_ methods | 254 # try help_ methods |
| 258 if self.help.has_key(topic): | 255 if topic in self.help: |
| 259 self.help[topic]() | 256 self.help[topic]() |
| 260 return 0 | 257 return 0 |
| 261 | 258 |
| 262 # try command docstrings | 259 # try command docstrings |
| 263 try: | 260 try: |
| 338 | 335 |
| 339 return templates | 336 return templates |
| 340 | 337 |
| 341 def help_initopts(self): | 338 def help_initopts(self): |
| 342 templates = self.listTemplates() | 339 templates = self.listTemplates() |
| 343 print _('Templates:'), ', '.join(templates.keys()) | 340 print _('Templates:'), ', '.join(templates) |
| 344 import roundup.backends | 341 import roundup.backends |
| 345 backends = roundup.backends.list_backends() | 342 backends = roundup.backends.list_backends() |
| 346 print _('Back ends:'), ', '.join(backends) | 343 print _('Back ends:'), ', '.join(backends) |
| 347 | 344 |
| 348 def do_install(self, tracker_home, args): | 345 def do_install(self, tracker_home, args): |
| 367 the tracker's dbinit.py module init() function. | 364 the tracker's dbinit.py module init() function. |
| 368 | 365 |
| 369 See also initopts help. | 366 See also initopts help. |
| 370 """ | 367 """ |
| 371 if len(args) < 1: | 368 if len(args) < 1: |
| 372 raise UsageError, _('Not enough arguments supplied') | 369 raise UsageError(_('Not enough arguments supplied')) |
| 373 | 370 |
| 374 # make sure the tracker home can be created | 371 # make sure the tracker home can be created |
| 375 tracker_home = os.path.abspath(tracker_home) | 372 tracker_home = os.path.abspath(tracker_home) |
| 376 parent = os.path.split(tracker_home)[0] | 373 parent = os.path.split(tracker_home)[0] |
| 377 if not os.path.exists(parent): | 374 if not os.path.exists(parent): |
| 378 raise UsageError, _('Instance home parent directory "%(parent)s"' | 375 raise UsageError(_('Instance home parent directory "%(parent)s"' |
| 379 ' does not exist')%locals() | 376 ' does not exist')%locals()) |
| 380 | 377 |
| 381 config_ini_file = os.path.join(tracker_home, CoreConfig.INI_FILE) | 378 config_ini_file = os.path.join(tracker_home, CoreConfig.INI_FILE) |
| 382 # check for both old- and new-style configs | 379 # check for both old- and new-style configs |
| 383 if filter(os.path.exists, [config_ini_file, | 380 if list(filter(os.path.exists, [config_ini_file, |
| 384 os.path.join(tracker_home, 'config.py')]): | 381 os.path.join(tracker_home, 'config.py')])): |
| 385 ok = raw_input(_( | 382 ok = raw_input(_( |
| 386 """WARNING: There appears to be a tracker in "%(tracker_home)s"! | 383 """WARNING: There appears to be a tracker in "%(tracker_home)s"! |
| 387 If you re-install it, you will lose all the data! | 384 If you re-install it, you will lose all the data! |
| 388 Erase it? Y/N: """) % locals()) | 385 Erase it? Y/N: """) % locals()) |
| 389 if ok.strip().lower() != 'y': | 386 if ok.strip().lower() != 'y': |
| 393 shutil.rmtree(tracker_home) | 390 shutil.rmtree(tracker_home) |
| 394 | 391 |
| 395 # select template | 392 # select template |
| 396 templates = self.listTemplates() | 393 templates = self.listTemplates() |
| 397 template = len(args) > 1 and args[1] or '' | 394 template = len(args) > 1 and args[1] or '' |
| 398 if not templates.has_key(template): | 395 if template not in templates: |
| 399 print _('Templates:'), ', '.join(templates.keys()) | 396 print _('Templates:'), ', '.join(templates) |
| 400 while not templates.has_key(template): | 397 while template not in templates: |
| 401 template = raw_input(_('Select template [classic]: ')).strip() | 398 template = raw_input(_('Select template [classic]: ')).strip() |
| 402 if not template: | 399 if not template: |
| 403 template = 'classic' | 400 template = 'classic' |
| 404 | 401 |
| 405 # select hyperdb backend | 402 # select hyperdb backend |
| 437 # XXX config._get_unset_options() is marked as private | 434 # XXX config._get_unset_options() is marked as private |
| 438 # (leading underscore). make it public or don't care? | 435 # (leading underscore). make it public or don't care? |
| 439 need_set = CoreConfig(tracker_home)._get_unset_options() | 436 need_set = CoreConfig(tracker_home)._get_unset_options() |
| 440 if need_set: | 437 if need_set: |
| 441 print _(" ... at a minimum, you must set following options:") | 438 print _(" ... at a minimum, you must set following options:") |
| 442 for section, options in need_set.items(): | 439 for section in need_set: |
| 443 print " [%s]: %s" % (section, ", ".join(options)) | 440 print " [%s]: %s" % (section, ", ".join(need_set[section])) |
| 444 | 441 |
| 445 # note about schema modifications | 442 # note about schema modifications |
| 446 print _(""" | 443 print _(""" |
| 447 If you wish to modify the database schema, | 444 If you wish to modify the database schema, |
| 448 you should also edit the schema file: | 445 you should also edit the schema file: |
| 464 ''"""Usage: genconfig <filename> | 461 ''"""Usage: genconfig <filename> |
| 465 Generate a new tracker config file (ini style) with default values | 462 Generate a new tracker config file (ini style) with default values |
| 466 in <filename>. | 463 in <filename>. |
| 467 """ | 464 """ |
| 468 if len(args) < 1: | 465 if len(args) < 1: |
| 469 raise UsageError, _('Not enough arguments supplied') | 466 raise UsageError(_('Not enough arguments supplied')) |
| 470 config = CoreConfig() | 467 config = CoreConfig() |
| 471 config.save(args[0]) | 468 config.save(args[0]) |
| 472 | 469 |
| 473 def do_initialise(self, tracker_home, args): | 470 def do_initialise(self, tracker_home, args): |
| 474 ''"""Usage: initialise [adminpw] | 471 ''"""Usage: initialise [adminpw] |
| 488 adminpw = getpass.getpass(_('Admin Password: ')) | 485 adminpw = getpass.getpass(_('Admin Password: ')) |
| 489 confirm = getpass.getpass(_(' Confirm: ')) | 486 confirm = getpass.getpass(_(' Confirm: ')) |
| 490 | 487 |
| 491 # make sure the tracker home is installed | 488 # make sure the tracker home is installed |
| 492 if not os.path.exists(tracker_home): | 489 if not os.path.exists(tracker_home): |
| 493 raise UsageError, _('Instance home does not exist')%locals() | 490 raise UsageError(_('Instance home does not exist')%locals()) |
| 494 try: | 491 try: |
| 495 tracker = roundup.instance.open(tracker_home) | 492 tracker = roundup.instance.open(tracker_home) |
| 496 except roundup.instance.TrackerError: | 493 except roundup.instance.TrackerError: |
| 497 raise UsageError, _('Instance has not been installed')%locals() | 494 raise UsageError(_('Instance has not been installed')%locals()) |
| 498 | 495 |
| 499 # is there already a database? | 496 # is there already a database? |
| 500 if tracker.exists(): | 497 if tracker.exists(): |
| 501 ok = raw_input(_( | 498 ok = raw_input(_( |
| 502 """WARNING: The database is already initialised! | 499 """WARNING: The database is already initialised! |
| 528 | 525 |
| 529 Retrieves the property value of the nodes specified | 526 Retrieves the property value of the nodes specified |
| 530 by the designators. | 527 by the designators. |
| 531 """ | 528 """ |
| 532 if len(args) < 2: | 529 if len(args) < 2: |
| 533 raise UsageError, _('Not enough arguments supplied') | 530 raise UsageError(_('Not enough arguments supplied')) |
| 534 propname = args[0] | 531 propname = args[0] |
| 535 designators = args[1].split(',') | 532 designators = args[1].split(',') |
| 536 l = [] | 533 l = [] |
| 537 for designator in designators: | 534 for designator in designators: |
| 538 # decode the node designator | 535 # decode the node designator |
| 539 try: | 536 try: |
| 540 classname, nodeid = hyperdb.splitDesignator(designator) | 537 classname, nodeid = hyperdb.splitDesignator(designator) |
| 541 except hyperdb.DesignatorError, message: | 538 except hyperdb.DesignatorError, message: |
| 542 raise UsageError, message | 539 raise UsageError(message) |
| 543 | 540 |
| 544 # get the class | 541 # get the class |
| 545 cl = self.get_class(classname) | 542 cl = self.get_class(classname) |
| 546 try: | 543 try: |
| 547 id=[] | 544 id=[] |
| 561 # print | 558 # print |
| 562 properties = cl.getprops() | 559 properties = cl.getprops() |
| 563 property = properties[propname] | 560 property = properties[propname] |
| 564 if not (isinstance(property, hyperdb.Multilink) or | 561 if not (isinstance(property, hyperdb.Multilink) or |
| 565 isinstance(property, hyperdb.Link)): | 562 isinstance(property, hyperdb.Link)): |
| 566 raise UsageError, _('property %s is not of type Multilink or Link so -d flag does not apply.')%propname | 563 raise UsageError(_('property %s is not of type' |
| 564 ' Multilink or Link so -d flag does not ' | |
| 565 'apply.')%propname) | |
| 567 propclassname = self.db.getclass(property.classname).classname | 566 propclassname = self.db.getclass(property.classname).classname |
| 568 id = cl.get(nodeid, propname) | 567 id = cl.get(nodeid, propname) |
| 569 for i in id: | 568 for i in id: |
| 570 l.append(propclassname + i) | 569 l.append(propclassname + i) |
| 571 else: | 570 else: |
| 576 if self.print_designator: | 575 if self.print_designator: |
| 577 properties = cl.getprops() | 576 properties = cl.getprops() |
| 578 property = properties[propname] | 577 property = properties[propname] |
| 579 if not (isinstance(property, hyperdb.Multilink) or | 578 if not (isinstance(property, hyperdb.Multilink) or |
| 580 isinstance(property, hyperdb.Link)): | 579 isinstance(property, hyperdb.Link)): |
| 581 raise UsageError, _('property %s is not of type Multilink or Link so -d flag does not apply.')%propname | 580 raise UsageError(_('property %s is not of type' |
| 581 ' Multilink or Link so -d flag does not ' | |
| 582 'apply.')%propname) | |
| 582 propclassname = self.db.getclass(property.classname).classname | 583 propclassname = self.db.getclass(property.classname).classname |
| 583 id = cl.get(nodeid, propname) | 584 id = cl.get(nodeid, propname) |
| 584 for i in id: | 585 for i in id: |
| 585 print propclassname + i | 586 print propclassname + i |
| 586 else: | 587 else: |
| 587 print cl.get(nodeid, propname) | 588 print cl.get(nodeid, propname) |
| 588 except IndexError: | 589 except IndexError: |
| 589 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals() | 590 raise UsageError(_('no such %(classname)s node ' |
| 591 '"%(nodeid)s"')%locals()) | |
| 590 except KeyError: | 592 except KeyError: |
| 591 raise UsageError, _('no such %(classname)s property ' | 593 raise UsageError(_('no such %(classname)s property ' |
| 592 '"%(propname)s"')%locals() | 594 '"%(propname)s"')%locals()) |
| 593 if self.separator: | 595 if self.separator: |
| 594 print self.separator.join(l) | 596 print self.separator.join(l) |
| 595 | 597 |
| 596 return 0 | 598 return 0 |
| 597 | 599 |
| 610 given. If the value is missing (ie. "property=") then the property | 612 given. If the value is missing (ie. "property=") then the property |
| 611 is un-set. If the property is a multilink, you specify the linked | 613 is un-set. If the property is a multilink, you specify the linked |
| 612 ids for the multilink as comma-separated numbers (ie "1,2,3"). | 614 ids for the multilink as comma-separated numbers (ie "1,2,3"). |
| 613 """ | 615 """ |
| 614 if len(args) < 2: | 616 if len(args) < 2: |
| 615 raise UsageError, _('Not enough arguments supplied') | 617 raise UsageError(_('Not enough arguments supplied')) |
| 616 from roundup import hyperdb | 618 from roundup import hyperdb |
| 617 | 619 |
| 618 designators = args[0].split(',') | 620 designators = args[0].split(',') |
| 619 if len(designators) == 1: | 621 if len(designators) == 1: |
| 620 designator = designators[0] | 622 designator = designators[0] |
| 626 designators = [(designator, x) for x in cl.list()] | 628 designators = [(designator, x) for x in cl.list()] |
| 627 else: | 629 else: |
| 628 try: | 630 try: |
| 629 designators = [hyperdb.splitDesignator(x) for x in designators] | 631 designators = [hyperdb.splitDesignator(x) for x in designators] |
| 630 except hyperdb.DesignatorError, message: | 632 except hyperdb.DesignatorError, message: |
| 631 raise UsageError, message | 633 raise UsageError(message) |
| 632 | 634 |
| 633 # get the props from the args | 635 # get the props from the args |
| 634 props = self.props_from_args(args[1:]) | 636 props = self.props_from_args(args[1:]) |
| 635 | 637 |
| 636 # now do the set for all the nodes | 638 # now do the set for all the nodes |
| 641 for key, value in props.items(): | 643 for key, value in props.items(): |
| 642 try: | 644 try: |
| 643 props[key] = hyperdb.rawToHyperdb(self.db, cl, itemid, | 645 props[key] = hyperdb.rawToHyperdb(self.db, cl, itemid, |
| 644 key, value) | 646 key, value) |
| 645 except hyperdb.HyperdbValueError, message: | 647 except hyperdb.HyperdbValueError, message: |
| 646 raise UsageError, message | 648 raise UsageError(message) |
| 647 | 649 |
| 648 # try the set | 650 # try the set |
| 649 try: | 651 try: |
| 650 apply(cl.set, (itemid, ), props) | 652 cl.set(itemid, **props) |
| 651 except (TypeError, IndexError, ValueError), message: | 653 except (TypeError, IndexError, ValueError), message: |
| 652 import traceback; traceback.print_exc() | 654 import traceback; traceback.print_exc() |
| 653 raise UsageError, message | 655 raise UsageError(message) |
| 654 self.db_uncommitted = True | 656 self.db_uncommitted = True |
| 655 return 0 | 657 return 0 |
| 656 | 658 |
| 657 def do_find(self, args): | 659 def do_find(self, args): |
| 658 ''"""Usage: find classname propname=value ... | 660 ''"""Usage: find classname propname=value ... |
| 661 Find the nodes of the given class with a given link property value. | 663 Find the nodes of the given class with a given link property value. |
| 662 The value may be either the nodeid of the linked node, or its key | 664 The value may be either the nodeid of the linked node, or its key |
| 663 value. | 665 value. |
| 664 """ | 666 """ |
| 665 if len(args) < 1: | 667 if len(args) < 1: |
| 666 raise UsageError, _('Not enough arguments supplied') | 668 raise UsageError(_('Not enough arguments supplied')) |
| 667 classname = args[0] | 669 classname = args[0] |
| 668 # get the class | 670 # get the class |
| 669 cl = self.get_class(classname) | 671 cl = self.get_class(classname) |
| 670 | 672 |
| 671 # handle the propname=value argument | 673 # handle the propname=value argument |
| 672 props = self.props_from_args(args[1:]) | 674 props = self.props_from_args(args[1:]) |
| 673 | 675 |
| 674 # convert the user-input value to a value used for find() | 676 # convert the user-input value to a value used for find() |
| 675 for propname, value in props.items(): | 677 for propname, value in props.iteritems(): |
| 676 if ',' in value: | 678 if ',' in value: |
| 677 values = value.split(',') | 679 values = value.split(',') |
| 678 else: | 680 else: |
| 679 values = [value] | 681 values = [value] |
| 680 d = props[propname] = {} | 682 d = props[propname] = {} |
| 690 try: | 692 try: |
| 691 id = [] | 693 id = [] |
| 692 designator = [] | 694 designator = [] |
| 693 if self.separator: | 695 if self.separator: |
| 694 if self.print_designator: | 696 if self.print_designator: |
| 695 id=apply(cl.find, (), props) | 697 id = cl.find(**props) |
| 696 for i in id: | 698 for i in id: |
| 697 designator.append(classname + i) | 699 designator.append(classname + i) |
| 698 print self.separator.join(designator) | 700 print self.separator.join(designator) |
| 699 else: | 701 else: |
| 700 print self.separator.join(apply(cl.find, (), props)) | 702 print self.separator.join(cl.find(**props)) |
| 701 | 703 |
| 702 else: | 704 else: |
| 703 if self.print_designator: | 705 if self.print_designator: |
| 704 id=apply(cl.find, (), props) | 706 id = cl.find(**props) |
| 705 for i in id: | 707 for i in id: |
| 706 designator.append(classname + i) | 708 designator.append(classname + i) |
| 707 print designator | 709 print designator |
| 708 else: | 710 else: |
| 709 print apply(cl.find, (), props) | 711 print cl.find(**props) |
| 710 except KeyError: | 712 except KeyError: |
| 711 raise UsageError, _('%(classname)s has no property ' | 713 raise UsageError(_('%(classname)s has no property ' |
| 712 '"%(propname)s"')%locals() | 714 '"%(propname)s"')%locals()) |
| 713 except (ValueError, TypeError), message: | 715 except (ValueError, TypeError), message: |
| 714 raise UsageError, message | 716 raise UsageError(message) |
| 715 return 0 | 717 return 0 |
| 716 | 718 |
| 717 def do_specification(self, args): | 719 def do_specification(self, args): |
| 718 ''"""Usage: specification classname | 720 ''"""Usage: specification classname |
| 719 Show the properties for a classname. | 721 Show the properties for a classname. |
| 720 | 722 |
| 721 This lists the properties for a given class. | 723 This lists the properties for a given class. |
| 722 """ | 724 """ |
| 723 if len(args) < 1: | 725 if len(args) < 1: |
| 724 raise UsageError, _('Not enough arguments supplied') | 726 raise UsageError(_('Not enough arguments supplied')) |
| 725 classname = args[0] | 727 classname = args[0] |
| 726 # get the class | 728 # get the class |
| 727 cl = self.get_class(classname) | 729 cl = self.get_class(classname) |
| 728 | 730 |
| 729 # get the key property | 731 # get the key property |
| 730 keyprop = cl.getkey() | 732 keyprop = cl.getkey() |
| 731 for key, value in cl.properties.items(): | 733 for key in cl.properties: |
| 734 value = cl.properties[key] | |
| 732 if keyprop == key: | 735 if keyprop == key: |
| 733 print _('%(key)s: %(value)s (key property)')%locals() | 736 print _('%(key)s: %(value)s (key property)')%locals() |
| 734 else: | 737 else: |
| 735 print _('%(key)s: %(value)s')%locals() | 738 print _('%(key)s: %(value)s')%locals() |
| 736 | 739 |
| 743 | 746 |
| 744 This lists the properties and their associated values for the given | 747 This lists the properties and their associated values for the given |
| 745 node. | 748 node. |
| 746 """ | 749 """ |
| 747 if len(args) < 1: | 750 if len(args) < 1: |
| 748 raise UsageError, _('Not enough arguments supplied') | 751 raise UsageError(_('Not enough arguments supplied')) |
| 749 | 752 |
| 750 # decode the node designator | 753 # decode the node designator |
| 751 for designator in args[0].split(','): | 754 for designator in args[0].split(','): |
| 752 try: | 755 try: |
| 753 classname, nodeid = hyperdb.splitDesignator(designator) | 756 classname, nodeid = hyperdb.splitDesignator(designator) |
| 754 except hyperdb.DesignatorError, message: | 757 except hyperdb.DesignatorError, message: |
| 755 raise UsageError, message | 758 raise UsageError(message) |
| 756 | 759 |
| 757 # get the class | 760 # get the class |
| 758 cl = self.get_class(classname) | 761 cl = self.get_class(classname) |
| 759 | 762 |
| 760 # display the values | 763 # display the values |
| 761 keys = cl.properties.keys() | 764 keys = sorted(cl.properties) |
| 762 keys.sort() | |
| 763 for key in keys: | 765 for key in keys: |
| 764 value = cl.get(nodeid, key) | 766 value = cl.get(nodeid, key) |
| 765 print _('%(key)s: %(value)s')%locals() | 767 print _('%(key)s: %(value)s')%locals() |
| 766 | 768 |
| 767 def do_create(self, args): | 769 def do_create(self, args): |
| 771 This creates a new entry of the given class using the property | 773 This creates a new entry of the given class using the property |
| 772 name=value arguments provided on the command line after the "create" | 774 name=value arguments provided on the command line after the "create" |
| 773 command. | 775 command. |
| 774 """ | 776 """ |
| 775 if len(args) < 1: | 777 if len(args) < 1: |
| 776 raise UsageError, _('Not enough arguments supplied') | 778 raise UsageError(_('Not enough arguments supplied')) |
| 777 from roundup import hyperdb | 779 from roundup import hyperdb |
| 778 | 780 |
| 779 classname = args[0] | 781 classname = args[0] |
| 780 | 782 |
| 781 # get the class | 783 # get the class |
| 784 # now do a create | 786 # now do a create |
| 785 props = {} | 787 props = {} |
| 786 properties = cl.getprops(protected = 0) | 788 properties = cl.getprops(protected = 0) |
| 787 if len(args) == 1: | 789 if len(args) == 1: |
| 788 # ask for the properties | 790 # ask for the properties |
| 789 for key, value in properties.items(): | 791 for key in properties: |
| 790 if key == 'id': continue | 792 if key == 'id': continue |
| 793 value = properties[key] | |
| 791 name = value.__class__.__name__ | 794 name = value.__class__.__name__ |
| 792 if isinstance(value , hyperdb.Password): | 795 if isinstance(value , hyperdb.Password): |
| 793 again = None | 796 again = None |
| 794 while value != again: | 797 while value != again: |
| 795 value = getpass.getpass(_('%(propname)s (Password): ')%{ | 798 value = getpass.getpass(_('%(propname)s (Password): ')%{ |
| 806 props[key] = value | 809 props[key] = value |
| 807 else: | 810 else: |
| 808 props = self.props_from_args(args[1:]) | 811 props = self.props_from_args(args[1:]) |
| 809 | 812 |
| 810 # convert types | 813 # convert types |
| 811 for propname, value in props.items(): | 814 for propname in props: |
| 812 try: | 815 try: |
| 813 props[propname] = hyperdb.rawToHyperdb(self.db, cl, None, | 816 props[propname] = hyperdb.rawToHyperdb(self.db, cl, None, |
| 814 propname, value) | 817 propname, props[propname]) |
| 815 except hyperdb.HyperdbValueError, message: | 818 except hyperdb.HyperdbValueError, message: |
| 816 raise UsageError, message | 819 raise UsageError(message) |
| 817 | 820 |
| 818 # check for the key property | 821 # check for the key property |
| 819 propname = cl.getkey() | 822 propname = cl.getkey() |
| 820 if propname and not props.has_key(propname): | 823 if propname and propname not in props: |
| 821 raise UsageError, _('you must provide the "%(propname)s" ' | 824 raise UsageError(_('you must provide the "%(propname)s" ' |
| 822 'property.')%locals() | 825 'property.')%locals()) |
| 823 | 826 |
| 824 # do the actual create | 827 # do the actual create |
| 825 try: | 828 try: |
| 826 print apply(cl.create, (), props) | 829 print cl.create(**props) |
| 827 except (TypeError, IndexError, ValueError), message: | 830 except (TypeError, IndexError, ValueError), message: |
| 828 raise UsageError, message | 831 raise UsageError(message) |
| 829 self.db_uncommitted = True | 832 self.db_uncommitted = True |
| 830 return 0 | 833 return 0 |
| 831 | 834 |
| 832 def do_list(self, args): | 835 def do_list(self, args): |
| 833 ''"""Usage: list classname [property] | 836 ''"""Usage: list classname [property] |
| 841 With -c, -S or -s print a list of item id's if no property | 844 With -c, -S or -s print a list of item id's if no property |
| 842 specified. If property specified, print list of that property | 845 specified. If property specified, print list of that property |
| 843 for every class instance. | 846 for every class instance. |
| 844 """ | 847 """ |
| 845 if len(args) > 2: | 848 if len(args) > 2: |
| 846 raise UsageError, _('Too many arguments supplied') | 849 raise UsageError(_('Too many arguments supplied')) |
| 847 if len(args) < 1: | 850 if len(args) < 1: |
| 848 raise UsageError, _('Not enough arguments supplied') | 851 raise UsageError(_('Not enough arguments supplied')) |
| 849 classname = args[0] | 852 classname = args[0] |
| 850 | 853 |
| 851 # get the class | 854 # get the class |
| 852 cl = self.get_class(classname) | 855 cl = self.get_class(classname) |
| 853 | 856 |
| 863 proplist=[] | 866 proplist=[] |
| 864 for nodeid in cl.list(): | 867 for nodeid in cl.list(): |
| 865 try: | 868 try: |
| 866 proplist.append(cl.get(nodeid, propname)) | 869 proplist.append(cl.get(nodeid, propname)) |
| 867 except KeyError: | 870 except KeyError: |
| 868 raise UsageError, _('%(classname)s has no property ' | 871 raise UsageError(_('%(classname)s has no property ' |
| 869 '"%(propname)s"')%locals() | 872 '"%(propname)s"')%locals()) |
| 870 print self.separator.join(proplist) | 873 print self.separator.join(proplist) |
| 871 else: | 874 else: |
| 872 # create a list of index id's since user didn't specify | 875 # create a list of index id's since user didn't specify |
| 873 # otherwise | 876 # otherwise |
| 874 print self.separator.join(cl.list()) | 877 print self.separator.join(cl.list()) |
| 875 else: | 878 else: |
| 876 for nodeid in cl.list(): | 879 for nodeid in cl.list(): |
| 877 try: | 880 try: |
| 878 value = cl.get(nodeid, propname) | 881 value = cl.get(nodeid, propname) |
| 879 except KeyError: | 882 except KeyError: |
| 880 raise UsageError, _('%(classname)s has no property ' | 883 raise UsageError(_('%(classname)s has no property ' |
| 881 '"%(propname)s"')%locals() | 884 '"%(propname)s"')%locals()) |
| 882 print _('%(nodeid)4s: %(value)s')%locals() | 885 print _('%(nodeid)4s: %(value)s')%locals() |
| 883 return 0 | 886 return 0 |
| 884 | 887 |
| 885 def do_table(self, args): | 888 def do_table(self, args): |
| 886 ''"""Usage: table classname [property[,property]*] | 889 ''"""Usage: table classname [property[,property]*] |
| 910 4 feat | 913 4 feat |
| 911 | 914 |
| 912 will result in a the 4 character wide "Name" column. | 915 will result in a the 4 character wide "Name" column. |
| 913 """ | 916 """ |
| 914 if len(args) < 1: | 917 if len(args) < 1: |
| 915 raise UsageError, _('Not enough arguments supplied') | 918 raise UsageError(_('Not enough arguments supplied')) |
| 916 classname = args[0] | 919 classname = args[0] |
| 917 | 920 |
| 918 # get the class | 921 # get the class |
| 919 cl = self.get_class(classname) | 922 cl = self.get_class(classname) |
| 920 | 923 |
| 925 for spec in prop_names: | 928 for spec in prop_names: |
| 926 if ':' in spec: | 929 if ':' in spec: |
| 927 try: | 930 try: |
| 928 propname, width = spec.split(':') | 931 propname, width = spec.split(':') |
| 929 except (ValueError, TypeError): | 932 except (ValueError, TypeError): |
| 930 raise UsageError, _('"%(spec)s" not name:width')%locals() | 933 raise UsageError(_('"%(spec)s" not ' |
| 934 'name:width')%locals()) | |
| 931 else: | 935 else: |
| 932 propname = spec | 936 propname = spec |
| 933 if not all_props.has_key(propname): | 937 if propname not in all_props: |
| 934 raise UsageError, _('%(classname)s has no property ' | 938 raise UsageError(_('%(classname)s has no property ' |
| 935 '"%(propname)s"')%locals() | 939 '"%(propname)s"')%locals()) |
| 936 else: | 940 else: |
| 937 prop_names = cl.getprops().keys() | 941 prop_names = cl.getprops() |
| 938 | 942 |
| 939 # now figure column widths | 943 # now figure column widths |
| 940 props = [] | 944 props = [] |
| 941 for spec in prop_names: | 945 for spec in prop_names: |
| 942 if ':' in spec: | 946 if ':' in spec: |
| 984 eg. bug1, user10, ... | 988 eg. bug1, user10, ... |
| 985 | 989 |
| 986 Lists the journal entries for the node identified by the designator. | 990 Lists the journal entries for the node identified by the designator. |
| 987 """ | 991 """ |
| 988 if len(args) < 1: | 992 if len(args) < 1: |
| 989 raise UsageError, _('Not enough arguments supplied') | 993 raise UsageError(_('Not enough arguments supplied')) |
| 990 try: | 994 try: |
| 991 classname, nodeid = hyperdb.splitDesignator(args[0]) | 995 classname, nodeid = hyperdb.splitDesignator(args[0]) |
| 992 except hyperdb.DesignatorError, message: | 996 except hyperdb.DesignatorError, message: |
| 993 raise UsageError, message | 997 raise UsageError(message) |
| 994 | 998 |
| 995 try: | 999 try: |
| 996 print self.db.getclass(classname).history(nodeid) | 1000 print self.db.getclass(classname).history(nodeid) |
| 997 except KeyError: | 1001 except KeyError: |
| 998 raise UsageError, _('no such class "%(classname)s"')%locals() | 1002 raise UsageError(_('no such class "%(classname)s"')%locals()) |
| 999 except IndexError: | 1003 except IndexError: |
| 1000 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals() | 1004 raise UsageError(_('no such %(classname)s node ' |
| 1005 '"%(nodeid)s"')%locals()) | |
| 1001 return 0 | 1006 return 0 |
| 1002 | 1007 |
| 1003 def do_commit(self, args): | 1008 def do_commit(self, args): |
| 1004 ''"""Usage: commit | 1009 ''"""Usage: commit |
| 1005 Commit changes made to the database during an interactive session. | 1010 Commit changes made to the database during an interactive session. |
| 1037 | 1042 |
| 1038 This action indicates that a particular node is not to be retrieved | 1043 This action indicates that a particular node is not to be retrieved |
| 1039 by the list or find commands, and its key value may be re-used. | 1044 by the list or find commands, and its key value may be re-used. |
| 1040 """ | 1045 """ |
| 1041 if len(args) < 1: | 1046 if len(args) < 1: |
| 1042 raise UsageError, _('Not enough arguments supplied') | 1047 raise UsageError(_('Not enough arguments supplied')) |
| 1043 designators = args[0].split(',') | 1048 designators = args[0].split(',') |
| 1044 for designator in designators: | 1049 for designator in designators: |
| 1045 try: | 1050 try: |
| 1046 classname, nodeid = hyperdb.splitDesignator(designator) | 1051 classname, nodeid = hyperdb.splitDesignator(designator) |
| 1047 except hyperdb.DesignatorError, message: | 1052 except hyperdb.DesignatorError, message: |
| 1048 raise UsageError, message | 1053 raise UsageError(message) |
| 1049 try: | 1054 try: |
| 1050 self.db.getclass(classname).retire(nodeid) | 1055 self.db.getclass(classname).retire(nodeid) |
| 1051 except KeyError: | 1056 except KeyError: |
| 1052 raise UsageError, _('no such class "%(classname)s"')%locals() | 1057 raise UsageError(_('no such class "%(classname)s"')%locals()) |
| 1053 except IndexError: | 1058 except IndexError: |
| 1054 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals() | 1059 raise UsageError(_('no such %(classname)s node ' |
| 1060 '"%(nodeid)s"')%locals()) | |
| 1055 self.db_uncommitted = True | 1061 self.db_uncommitted = True |
| 1056 return 0 | 1062 return 0 |
| 1057 | 1063 |
| 1058 def do_restore(self, args): | 1064 def do_restore(self, args): |
| 1059 ''"""Usage: restore designator[,designator]* | 1065 ''"""Usage: restore designator[,designator]* |
| 1063 eg. bug1, user10, ... | 1069 eg. bug1, user10, ... |
| 1064 | 1070 |
| 1065 The given nodes will become available for users again. | 1071 The given nodes will become available for users again. |
| 1066 """ | 1072 """ |
| 1067 if len(args) < 1: | 1073 if len(args) < 1: |
| 1068 raise UsageError, _('Not enough arguments supplied') | 1074 raise UsageError(_('Not enough arguments supplied')) |
| 1069 designators = args[0].split(',') | 1075 designators = args[0].split(',') |
| 1070 for designator in designators: | 1076 for designator in designators: |
| 1071 try: | 1077 try: |
| 1072 classname, nodeid = hyperdb.splitDesignator(designator) | 1078 classname, nodeid = hyperdb.splitDesignator(designator) |
| 1073 except hyperdb.DesignatorError, message: | 1079 except hyperdb.DesignatorError, message: |
| 1074 raise UsageError, message | 1080 raise UsageError(message) |
| 1075 try: | 1081 try: |
| 1076 self.db.getclass(classname).restore(nodeid) | 1082 self.db.getclass(classname).restore(nodeid) |
| 1077 except KeyError: | 1083 except KeyError: |
| 1078 raise UsageError, _('no such class "%(classname)s"')%locals() | 1084 raise UsageError(_('no such class "%(classname)s"')%locals()) |
| 1079 except IndexError: | 1085 except IndexError: |
| 1080 raise UsageError, _('no such %(classname)s node "%(nodeid)s"')%locals() | 1086 raise UsageError(_('no such %(classname)s node ' |
| 1087 '"%(nodeid)s"')%locals()) | |
| 1081 self.db_uncommitted = True | 1088 self.db_uncommitted = True |
| 1082 return 0 | 1089 return 0 |
| 1083 | 1090 |
| 1084 def do_export(self, args, export_files=True): | 1091 def do_export(self, args, export_files=True): |
| 1085 ''"""Usage: export [[-]class[,class]] export_dir | 1092 ''"""Usage: export [[-]class[,class]] export_dir |
| 1094 colon-separated-value files that are placed in the nominated | 1101 colon-separated-value files that are placed in the nominated |
| 1095 destination directory. | 1102 destination directory. |
| 1096 """ | 1103 """ |
| 1097 # grab the directory to export to | 1104 # grab the directory to export to |
| 1098 if len(args) < 1: | 1105 if len(args) < 1: |
| 1099 raise UsageError, _('Not enough arguments supplied') | 1106 raise UsageError(_('Not enough arguments supplied')) |
| 1100 | 1107 |
| 1101 dir = args[-1] | 1108 dir = args[-1] |
| 1102 | 1109 |
| 1103 # get the list of classes to export | 1110 # get the list of classes to export |
| 1104 if len(args) == 2: | 1111 if len(args) == 2: |
| 1105 if args[0].startswith('-'): | 1112 if args[0].startswith('-'): |
| 1106 classes = [ c for c in self.db.classes.keys() | 1113 classes = [ c for c in self.db.classes |
| 1107 if not c in args[0][1:].split(',') ] | 1114 if not c in args[0][1:].split(',') ] |
| 1108 else: | 1115 else: |
| 1109 classes = args[0].split(',') | 1116 classes = args[0].split(',') |
| 1110 else: | 1117 else: |
| 1111 classes = self.db.classes.keys() | 1118 classes = self.db.classes |
| 1112 | 1119 |
| 1113 class colon_separated(csv.excel): | 1120 class colon_separated(csv.excel): |
| 1114 delimiter = ':' | 1121 delimiter = ':' |
| 1115 | 1122 |
| 1116 # make sure target dir exists | 1123 # make sure target dir exists |
| 1164 jf = open(os.path.join(dir, classname+'-journals.csv'), 'wb') | 1171 jf = open(os.path.join(dir, classname+'-journals.csv'), 'wb') |
| 1165 if self.verbose: | 1172 if self.verbose: |
| 1166 sys.stdout.write("\nExporting Journal for %s\n" % classname) | 1173 sys.stdout.write("\nExporting Journal for %s\n" % classname) |
| 1167 sys.stdout.flush() | 1174 sys.stdout.flush() |
| 1168 journals = csv.writer(jf, colon_separated) | 1175 journals = csv.writer(jf, colon_separated) |
| 1169 map(journals.writerow, cl.export_journals()) | 1176 for row in cl.export_journals(): |
| 1177 journals.writerow(row) | |
| 1170 jf.close() | 1178 jf.close() |
| 1171 if max_len > self.db.config.CSV_FIELD_SIZE: | 1179 if max_len > self.db.config.CSV_FIELD_SIZE: |
| 1172 print >> sys.stderr, \ | 1180 print >> sys.stderr, \ |
| 1173 "Warning: config csv_field_size should be at least %s"%max_len | 1181 "Warning: config csv_field_size should be at least %s"%max_len |
| 1174 return 0 | 1182 return 0 |
| 1207 The new nodes are added to the existing database - if you want to | 1215 The new nodes are added to the existing database - if you want to |
| 1208 create a new database using the imported data, then create a new | 1216 create a new database using the imported data, then create a new |
| 1209 database (or, tediously, retire all the old data.) | 1217 database (or, tediously, retire all the old data.) |
| 1210 """ | 1218 """ |
| 1211 if len(args) < 1: | 1219 if len(args) < 1: |
| 1212 raise UsageError, _('Not enough arguments supplied') | 1220 raise UsageError(_('Not enough arguments supplied')) |
| 1213 from roundup import hyperdb | 1221 from roundup import hyperdb |
| 1214 | 1222 |
| 1215 if hasattr (csv, 'field_size_limit'): | 1223 if hasattr (csv, 'field_size_limit'): |
| 1216 csv.field_size_limit(self.db.config.CSV_FIELD_SIZE) | 1224 csv.field_size_limit(self.db.config.CSV_FIELD_SIZE) |
| 1217 | 1225 |
| 1248 # do the import and figure the current highest nodeid | 1256 # do the import and figure the current highest nodeid |
| 1249 nodeid = cl.import_list(file_props, r) | 1257 nodeid = cl.import_list(file_props, r) |
| 1250 if hasattr(cl, 'import_files'): | 1258 if hasattr(cl, 'import_files'): |
| 1251 cl.import_files(dir, nodeid) | 1259 cl.import_files(dir, nodeid) |
| 1252 maxid = max(maxid, int(nodeid)) | 1260 maxid = max(maxid, int(nodeid)) |
| 1261 | |
| 1262 # (print to sys.stdout here to allow tests to squash it .. ugh) | |
| 1253 print >> sys.stdout | 1263 print >> sys.stdout |
| 1264 | |
| 1254 f.close() | 1265 f.close() |
| 1255 | 1266 |
| 1256 # import the journals | 1267 # import the journals |
| 1257 f = open(os.path.join(args[0], classname + '-journals.csv'), 'r') | 1268 f = open(os.path.join(args[0], classname + '-journals.csv'), 'r') |
| 1258 reader = csv.reader(f, colon_separated) | 1269 reader = csv.reader(f, colon_separated) |
| 1259 cl.import_journals(reader) | 1270 cl.import_journals(reader) |
| 1260 f.close() | 1271 f.close() |
| 1261 | 1272 |
| 1273 # (print to sys.stdout here to allow tests to squash it .. ugh) | |
| 1274 print >> sys.stdout, 'setting', classname, maxid+1 | |
| 1275 | |
| 1262 # set the id counter | 1276 # set the id counter |
| 1263 print >> sys.stdout, 'setting', classname, maxid+1 | |
| 1264 self.db.setid(classname, str(maxid+1)) | 1277 self.db.setid(classname, str(maxid+1)) |
| 1265 | 1278 |
| 1266 self.db_uncommitted = True | 1279 self.db_uncommitted = True |
| 1267 return 0 | 1280 return 0 |
| 1268 | 1281 |
| 1282 | 1295 |
| 1283 Date format is "YYYY-MM-DD" eg: | 1296 Date format is "YYYY-MM-DD" eg: |
| 1284 2001-01-01 | 1297 2001-01-01 |
| 1285 | 1298 |
| 1286 """ | 1299 """ |
| 1287 if len(args) <> 1: | 1300 if len(args) != 1: |
| 1288 raise UsageError, _('Not enough arguments supplied') | 1301 raise UsageError(_('Not enough arguments supplied')) |
| 1289 | 1302 |
| 1290 # are we dealing with a period or a date | 1303 # are we dealing with a period or a date |
| 1291 value = args[0] | 1304 value = args[0] |
| 1292 date_re = re.compile(r""" | 1305 date_re = re.compile(r""" |
| 1293 (?P<date>\d\d\d\d-\d\d?-\d\d?)? # yyyy-mm-dd | 1306 (?P<date>\d\d\d\d-\d\d?-\d\d?)? # yyyy-mm-dd |
| 1294 (?P<period>(\d+y\s*)?(\d+m\s*)?(\d+d\s*)?)? | 1307 (?P<period>(\d+y\s*)?(\d+m\s*)?(\d+d\s*)?)? |
| 1295 """, re.VERBOSE) | 1308 """, re.VERBOSE) |
| 1296 m = date_re.match(value) | 1309 m = date_re.match(value) |
| 1297 if not m: | 1310 if not m: |
| 1298 raise ValueError, _('Invalid format') | 1311 raise ValueError(_('Invalid format')) |
| 1299 m = m.groupdict() | 1312 m = m.groupdict() |
| 1300 if m['period']: | 1313 if m['period']: |
| 1301 pack_before = date.Date(". - %s"%value) | 1314 pack_before = date.Date(". - %s"%value) |
| 1302 elif m['date']: | 1315 elif m['date']: |
| 1303 pack_before = date.Date(value) | 1316 pack_before = date.Date(value) |
| 1318 if m: | 1331 if m: |
| 1319 cl = self.get_class(m.group(1)) | 1332 cl = self.get_class(m.group(1)) |
| 1320 try: | 1333 try: |
| 1321 cl.index(m.group(2)) | 1334 cl.index(m.group(2)) |
| 1322 except IndexError: | 1335 except IndexError: |
| 1323 raise UsageError, _('no such item "%(designator)s"')%{ | 1336 raise UsageError(_('no such item "%(designator)s"')%{ |
| 1324 'designator': arg} | 1337 'designator': arg}) |
| 1325 else: | 1338 else: |
| 1326 cl = self.get_class(arg) | 1339 cl = self.get_class(arg) |
| 1327 self.db.reindex(arg) | 1340 self.db.reindex(arg) |
| 1328 else: | 1341 else: |
| 1329 self.db.reindex(show_progress=True) | 1342 self.db.reindex(show_progress=True) |
| 1339 roles = [(args[0], self.db.security.role[args[0]])] | 1352 roles = [(args[0], self.db.security.role[args[0]])] |
| 1340 except KeyError: | 1353 except KeyError: |
| 1341 print _('No such Role "%(role)s"')%locals() | 1354 print _('No such Role "%(role)s"')%locals() |
| 1342 return 1 | 1355 return 1 |
| 1343 else: | 1356 else: |
| 1344 roles = self.db.security.role.items() | 1357 roles = list(self.db.security.role.items()) |
| 1345 role = self.db.config.NEW_WEB_USER_ROLES | 1358 role = self.db.config.NEW_WEB_USER_ROLES |
| 1346 if ',' in role: | 1359 if ',' in role: |
| 1347 print _('New Web users get the Roles "%(role)s"')%locals() | 1360 print _('New Web users get the Roles "%(role)s"')%locals() |
| 1348 else: | 1361 else: |
| 1349 print _('New Web users get the Role "%(role)s"')%locals() | 1362 print _('New Web users get the Role "%(role)s"')%locals() |
| 1515 | 1528 |
| 1516 # handle command-line args | 1529 # handle command-line args |
| 1517 self.tracker_home = os.environ.get('TRACKER_HOME', '') | 1530 self.tracker_home = os.environ.get('TRACKER_HOME', '') |
| 1518 # TODO: reinstate the user/password stuff (-u arg too) | 1531 # TODO: reinstate the user/password stuff (-u arg too) |
| 1519 name = password = '' | 1532 name = password = '' |
| 1520 if os.environ.has_key('ROUNDUP_LOGIN'): | 1533 if 'ROUNDUP_LOGIN' in os.environ: |
| 1521 l = os.environ['ROUNDUP_LOGIN'].split(':') | 1534 l = os.environ['ROUNDUP_LOGIN'].split(':') |
| 1522 name = l[0] | 1535 name = l[0] |
| 1523 if len(l) > 1: | 1536 if len(l) > 1: |
| 1524 password = l[1] | 1537 password = l[1] |
| 1525 self.separator = None | 1538 self.separator = None |
