Mercurial > p > roundup > code
comparison roundup-admin @ 377:93dc08528ad9
roundup-admin now handles all hyperdb exceptions
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Fri, 09 Nov 2001 10:11:08 +0000 |
| parents | c6d6ea15068b |
| children | c7b5b1aa6b4a |
comparison
equal
deleted
inserted
replaced
| 376:c6d6ea15068b | 377:93dc08528ad9 |
|---|---|
| 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.41 2001-11-09 01:25:40 richard Exp $ | 19 # $Id: roundup-admin,v 1.42 2001-11-09 10:11:08 richard Exp $ |
| 20 | 20 |
| 21 import sys | 21 import sys |
| 22 if int(sys.version[0]) < 2: | 22 if int(sys.version[0]) < 2: |
| 23 print 'Roundup requires python 2.0 or later.' | 23 print 'Roundup requires python 2.0 or later.' |
| 24 sys.exit(1) | 24 sys.exit(1) |
| 48 l.append((ki, self.data[ki])) | 48 l.append((ki, self.data[ki])) |
| 49 if not l and default is self._marker: | 49 if not l and default is self._marker: |
| 50 raise KeyError, key | 50 raise KeyError, key |
| 51 return l | 51 return l |
| 52 | 52 |
| 53 class UsageError(ValueError): | |
| 54 pass | |
| 55 | |
| 53 class AdminTool: | 56 class AdminTool: |
| 54 | 57 |
| 55 def __init__(self): | 58 def __init__(self): |
| 56 self.commands = CommandDict() | 59 self.commands = CommandDict() |
| 57 for k in AdminTool.__dict__.keys(): | 60 for k in AdminTool.__dict__.keys(): |
| 157 topic = args[0] | 160 topic = args[0] |
| 158 | 161 |
| 159 # try help_ methods | 162 # try help_ methods |
| 160 if self.help.has_key(topic): | 163 if self.help.has_key(topic): |
| 161 self.help[topic]() | 164 self.help[topic]() |
| 162 return | 165 return 0 |
| 163 | 166 |
| 164 # try command docstrings | 167 # try command docstrings |
| 165 try: | 168 try: |
| 166 l = self.commands.get(topic) | 169 l = self.commands.get(topic) |
| 167 except KeyError: | 170 except KeyError: |
| 168 print 'Sorry, no help for "%s"'%topic | 171 print 'Sorry, no help for "%s"'%topic |
| 169 return | 172 return 1 |
| 170 | 173 |
| 171 # display the help for each match, removing the docsring indent | 174 # display the help for each match, removing the docsring indent |
| 172 for name, help in l: | 175 for name, help in l: |
| 173 lines = nl_re.split(help.__doc__) | 176 lines = nl_re.split(help.__doc__) |
| 174 print lines[0] | 177 print lines[0] |
| 177 for line in lines[1:]: | 180 for line in lines[1:]: |
| 178 if indent: | 181 if indent: |
| 179 print line[indent:] | 182 print line[indent:] |
| 180 else: | 183 else: |
| 181 print line | 184 print line |
| 185 return 0 | |
| 182 | 186 |
| 183 def help_initopts(self): | 187 def help_initopts(self): |
| 184 import roundup.templates | 188 import roundup.templates |
| 185 templates = roundup.templates.listTemplates() | 189 templates = roundup.templates.listTemplates() |
| 186 print 'Templates:', ', '.join(templates) | 190 print 'Templates:', ', '.join(templates) |
| 240 ''' | 244 ''' |
| 241 propname = args[0] | 245 propname = args[0] |
| 242 designators = string.split(args[1], ',') | 246 designators = string.split(args[1], ',') |
| 243 l = [] | 247 l = [] |
| 244 for designator in designators: | 248 for designator in designators: |
| 249 # decode the node designator | |
| 245 try: | 250 try: |
| 246 classname, nodeid = roundupdb.splitDesignator(designator) | 251 classname, nodeid = roundupdb.splitDesignator(designator) |
| 247 except roundupdb.DesignatorError, message: | 252 except roundupdb.DesignatorError, message: |
| 248 print 'Error: %s'%message | 253 raise UsageError, message |
| 249 return 1 | 254 |
| 250 if self.comma_sep: | 255 # get the class |
| 251 l.append(self.db.getclass(classname).get(nodeid, propname)) | 256 try: |
| 252 else: | 257 cl = self.db.getclass(classname) |
| 253 print self.db.getclass(classname).get(nodeid, propname) | 258 except KeyError: |
| 259 raise UsageError, 'invalid class "%s"'%classname | |
| 260 try: | |
| 261 if self.comma_sep: | |
| 262 l.append(cl.get(nodeid, propname)) | |
| 263 else: | |
| 264 print cl.get(nodeid, propname) | |
| 265 except IndexError: | |
| 266 raise UsageError, 'no such %s node "%s"'%(classname, nodeid) | |
| 267 except KeyError: | |
| 268 raise UsageError, 'no such %s property "%s"'%(classname, | |
| 269 propname) | |
| 254 if self.comma_sep: | 270 if self.comma_sep: |
| 255 print ','.join(l) | 271 print ','.join(l) |
| 256 return 0 | 272 return 0 |
| 257 | 273 |
| 258 | 274 |
| 265 from roundup import hyperdb | 281 from roundup import hyperdb |
| 266 | 282 |
| 267 designators = string.split(args[0], ',') | 283 designators = string.split(args[0], ',') |
| 268 props = {} | 284 props = {} |
| 269 for prop in args[1:]: | 285 for prop in args[1:]: |
| 270 key, value = prop.split('=') | 286 if prop.find('=') == -1: |
| 287 raise UsageError, 'argument "%s" not propname=value'%prop | |
| 288 try: | |
| 289 key, value = prop.split('=') | |
| 290 except (TypeError, ValueError): | |
| 291 raise UsageError, 'argument "%s" not propname=value'%prop | |
| 271 props[key] = value | 292 props[key] = value |
| 272 for designator in designators: | 293 for designator in designators: |
| 294 # decode the node designator | |
| 273 try: | 295 try: |
| 274 classname, nodeid = roundupdb.splitDesignator(designator) | 296 classname, nodeid = roundupdb.splitDesignator(designator) |
| 275 except roundupdb.DesignatorError, message: | 297 except roundupdb.DesignatorError, message: |
| 276 print 'Error: %s'%message | 298 raise UsageError, message |
| 277 return 1 | 299 |
| 278 cl = self.db.getclass(classname) | 300 # get the class |
| 301 try: | |
| 302 cl = self.db.getclass(classname) | |
| 303 except KeyError: | |
| 304 raise UsageError, 'invalid class "%s"'%classname | |
| 305 | |
| 279 properties = cl.getprops() | 306 properties = cl.getprops() |
| 280 for key, value in props.items(): | 307 for key, value in props.items(): |
| 281 type = properties[key] | 308 type = properties[key] |
| 282 if isinstance(type, hyperdb.String): | 309 if isinstance(type, hyperdb.String): |
| 283 continue | 310 continue |
| 284 elif isinstance(type, hyperdb.Password): | 311 elif isinstance(type, hyperdb.Password): |
| 285 props[key] = password.Password(value) | 312 props[key] = password.Password(value) |
| 286 elif isinstance(type, hyperdb.Date): | 313 elif isinstance(type, hyperdb.Date): |
| 287 props[key] = date.Date(value) | 314 try: |
| 315 props[key] = date.Date(value) | |
| 316 except ValueError, message: | |
| 317 raise UsageError, '"%s": %s'%(value, message) | |
| 288 elif isinstance(type, hyperdb.Interval): | 318 elif isinstance(type, hyperdb.Interval): |
| 289 props[key] = date.Interval(value) | 319 try: |
| 320 props[key] = date.Interval(value) | |
| 321 except ValueError, message: | |
| 322 raise UsageError, '"%s": %s'%(value, message) | |
| 290 elif isinstance(type, hyperdb.Link): | 323 elif isinstance(type, hyperdb.Link): |
| 291 props[key] = value | 324 props[key] = value |
| 292 elif isinstance(type, hyperdb.Multilink): | 325 elif isinstance(type, hyperdb.Multilink): |
| 293 props[key] = value.split(',') | 326 props[key] = value.split(',') |
| 294 apply(cl.set, (nodeid, ), props) | 327 |
| 328 # try the set | |
| 329 try: | |
| 330 apply(cl.set, (nodeid, ), props) | |
| 331 except (TypeError, IndexError, ValueError), message: | |
| 332 raise UsageError, message | |
| 295 return 0 | 333 return 0 |
| 296 | 334 |
| 297 def do_find(self, args): | 335 def do_find(self, args): |
| 298 '''Usage: find classname propname=value ... | 336 '''Usage: find classname propname=value ... |
| 299 Find the nodes of the given class with a given link property value. | 337 Find the nodes of the given class with a given link property value. |
| 300 | 338 |
| 301 Find the nodes of the given class with a given link property value. The | 339 Find the nodes of the given class with a given link property value. The |
| 302 value may be either the nodeid of the linked node, or its key value. | 340 value may be either the nodeid of the linked node, or its key value. |
| 303 ''' | 341 ''' |
| 304 classname = args[0] | 342 classname = args[0] |
| 305 cl = self.db.getclass(classname) | 343 # get the class |
| 306 | 344 try: |
| 307 # look up the linked-to class and get the nodeid that has the value | 345 cl = self.db.getclass(classname) |
| 308 propname, value = args[1].split('=') | 346 except KeyError: |
| 347 raise UsageError, 'invalid class "%s"'%classname | |
| 348 | |
| 349 # TODO: handle > 1 argument | |
| 350 # handle the propname=value argument | |
| 351 if prop.find('=') == -1: | |
| 352 raise UsageError, 'argument "%s" not propname=value'%prop | |
| 353 try: | |
| 354 propname, value = args[1].split('=') | |
| 355 except (TypeError, ValueError): | |
| 356 raise UsageError, 'argument "%s" not propname=value'%prop | |
| 357 | |
| 358 # if the value isn't a number, look up the linked class to get the | |
| 359 # number | |
| 309 num_re = re.compile('^\d+$') | 360 num_re = re.compile('^\d+$') |
| 310 if not num_re.match(value): | 361 if not num_re.match(value): |
| 311 propcl = cl.properties[propname] | 362 # get the property |
| 312 if (not isinstance(propcl, hyperdb.Link) and not | 363 try: |
| 364 property = cl.properties[propname] | |
| 365 except KeyError: | |
| 366 raise UsageError, '%s has no property "%s"'%(classname, | |
| 367 propname) | |
| 368 | |
| 369 # make sure it's a link | |
| 370 if (not isinstance(property, hyperdb.Link) and not | |
| 313 isinstance(type, hyperdb.Multilink)): | 371 isinstance(type, hyperdb.Multilink)): |
| 314 print 'You may only "find" link properties' | 372 raise UsageError, 'You may only "find" link properties' |
| 315 return 1 | 373 |
| 316 propcl = self.db.getclass(propcl.classname) | 374 # get the linked-to class and look up the key property |
| 317 value = propcl.lookup(value) | 375 link_class = self.db.getclass(property.classname) |
| 318 | 376 try: |
| 319 # now do the find | 377 value = link_class.lookup(value) |
| 320 if self.comma_sep: | 378 except TypeError: |
| 321 print ','.join(apply(cl.find, (), {propname: value})) | 379 raise UsageError, '%s has no key property"'%link_class.classname |
| 322 else: | 380 except KeyError: |
| 323 print apply(cl.find, (), {propname: value}) | 381 raise UsageError, '%s has no entry "%s"'%(link_class.classname, |
| 382 propname) | |
| 383 | |
| 384 # now do the find | |
| 385 try: | |
| 386 if self.comma_sep: | |
| 387 print ','.join(apply(cl.find, (), {propname: value})) | |
| 388 else: | |
| 389 print apply(cl.find, (), {propname: value}) | |
| 390 except KeyError: | |
| 391 raise UsageError, '%s has no property "%s"'%(classname, | |
| 392 propname) | |
| 393 except (ValueError, TypeError), message: | |
| 394 raise UsageError, message | |
| 324 return 0 | 395 return 0 |
| 325 | 396 |
| 326 def do_specification(self, args): | 397 def do_specification(self, args): |
| 327 '''Usage: specification classname | 398 '''Usage: specification classname |
| 328 Show the properties for a classname. | 399 Show the properties for a classname. |
| 329 | 400 |
| 330 This lists the properties for a given class. | 401 This lists the properties for a given class. |
| 331 ''' | 402 ''' |
| 332 classname = args[0] | 403 classname = args[0] |
| 333 cl = self.db.getclass(classname) | 404 # get the class |
| 405 try: | |
| 406 cl = self.db.getclass(classname) | |
| 407 except KeyError: | |
| 408 raise UsageError, 'invalid class "%s"'%classname | |
| 409 | |
| 410 # get the key property | |
| 334 keyprop = cl.getkey() | 411 keyprop = cl.getkey() |
| 335 for key, value in cl.properties.items(): | 412 for key, value in cl.properties.items(): |
| 336 if keyprop == key: | 413 if keyprop == key: |
| 337 print '%s: %s (key property)'%(key, value) | 414 print '%s: %s (key property)'%(key, value) |
| 338 else: | 415 else: |
| 347 command. | 424 command. |
| 348 ''' | 425 ''' |
| 349 from roundup import hyperdb | 426 from roundup import hyperdb |
| 350 | 427 |
| 351 classname = args[0] | 428 classname = args[0] |
| 352 cl = self.db.getclass(classname) | 429 |
| 430 # get the class | |
| 431 try: | |
| 432 cl = self.db.getclass(classname) | |
| 433 except KeyError: | |
| 434 raise UsageError, 'invalid class "%s"'%classname | |
| 435 | |
| 436 # now do a create | |
| 353 props = {} | 437 props = {} |
| 354 properties = cl.getprops(protected = 0) | 438 properties = cl.getprops(protected = 0) |
| 355 if len(args) == 1: | 439 if len(args) == 1: |
| 356 # ask for the properties | 440 # ask for the properties |
| 357 for key, value in properties.items(): | 441 for key, value in properties.items(): |
| 370 if value: | 454 if value: |
| 371 props[key] = value | 455 props[key] = value |
| 372 else: | 456 else: |
| 373 # use the args | 457 # use the args |
| 374 for prop in args[1:]: | 458 for prop in args[1:]: |
| 375 key, value = prop.split('=') | 459 if prop.find('=') == -1: |
| 460 raise UsageError, 'argument "%s" not propname=value'%prop | |
| 461 try: | |
| 462 key, value = prop.split('=') | |
| 463 except (TypeError, ValueError): | |
| 464 raise UsageError, 'argument "%s" not propname=value'%prop | |
| 376 props[key] = value | 465 props[key] = value |
| 377 | 466 |
| 378 # convert types | 467 # convert types |
| 379 for key in props.keys(): | 468 for key in props.keys(): |
| 380 type = properties[key] | 469 # get the property |
| 470 try: | |
| 471 type = properties[key] | |
| 472 except KeyError: | |
| 473 raise UsageError, '%s has no property "%s"'%(classname, key) | |
| 474 | |
| 381 if isinstance(type, hyperdb.Date): | 475 if isinstance(type, hyperdb.Date): |
| 382 props[key] = date.Date(value) | 476 try: |
| 477 props[key] = date.Date(value) | |
| 478 except ValueError, message: | |
| 479 raise UsageError, '"%s": %s'%(value, message) | |
| 383 elif isinstance(type, hyperdb.Interval): | 480 elif isinstance(type, hyperdb.Interval): |
| 384 props[key] = date.Interval(value) | 481 try: |
| 482 props[key] = date.Interval(value) | |
| 483 except ValueError, message: | |
| 484 raise UsageError, '"%s": %s'%(value, message) | |
| 385 elif isinstance(type, hyperdb.Password): | 485 elif isinstance(type, hyperdb.Password): |
| 386 props[key] = password.Password(value) | 486 props[key] = password.Password(value) |
| 387 elif isinstance(type, hyperdb.Multilink): | 487 elif isinstance(type, hyperdb.Multilink): |
| 388 props[key] = value.split(',') | 488 props[key] = value.split(',') |
| 389 | 489 |
| 490 # check for the key property | |
| 390 if cl.getkey() and not props.has_key(cl.getkey()): | 491 if cl.getkey() and not props.has_key(cl.getkey()): |
| 391 print "You must provide the '%s' property."%cl.getkey() | 492 raise UsageError, "you must provide the '%s' property."%cl.getkey() |
| 392 else: | 493 |
| 494 # do the actual create | |
| 495 try: | |
| 393 print apply(cl.create, (), props) | 496 print apply(cl.create, (), props) |
| 394 | 497 except (TypeError, IndexError, ValueError), message: |
| 498 raise UsageError, message | |
| 395 return 0 | 499 return 0 |
| 396 | 500 |
| 397 def do_list(self, args): | 501 def do_list(self, args): |
| 398 '''Usage: list classname [property] | 502 '''Usage: list classname [property] |
| 399 List the instances of a class. | 503 List the instances of a class. |
| 402 specified, the "label" property is used. The label property is tried | 506 specified, the "label" property is used. The label property is tried |
| 403 in order: the key, "name", "title" and then the first property, | 507 in order: the key, "name", "title" and then the first property, |
| 404 alphabetically. | 508 alphabetically. |
| 405 ''' | 509 ''' |
| 406 classname = args[0] | 510 classname = args[0] |
| 407 cl = self.db.getclass(classname) | 511 |
| 512 # get the class | |
| 513 try: | |
| 514 cl = self.db.getclass(classname) | |
| 515 except KeyError: | |
| 516 raise UsageError, 'invalid class "%s"'%classname | |
| 517 | |
| 518 # figure the property | |
| 408 if len(args) > 1: | 519 if len(args) > 1: |
| 409 key = args[1] | 520 key = args[1] |
| 410 else: | 521 else: |
| 411 key = cl.labelprop() | 522 key = cl.labelprop() |
| 523 | |
| 412 if self.comma_sep: | 524 if self.comma_sep: |
| 413 print ','.join(cl.list()) | 525 print ','.join(cl.list()) |
| 414 else: | 526 else: |
| 415 for nodeid in cl.list(): | 527 for nodeid in cl.list(): |
| 416 value = cl.get(nodeid, key) | 528 try: |
| 529 value = cl.get(nodeid, key) | |
| 530 except KeyError: | |
| 531 raise UsageError, '%s has no property "%s"'%(classname, key) | |
| 417 print "%4s: %s"%(nodeid, value) | 532 print "%4s: %s"%(nodeid, value) |
| 418 return 0 | 533 return 0 |
| 419 | 534 |
| 420 def do_table(self, args): | 535 def do_table(self, args): |
| 421 '''Usage: table classname [property[,property]*] | 536 '''Usage: table classname [property[,property]*] |
| 431 2 bug | 546 2 bug |
| 432 3 usability | 547 3 usability |
| 433 4 feature | 548 4 feature |
| 434 ''' | 549 ''' |
| 435 classname = args[0] | 550 classname = args[0] |
| 436 cl = self.db.getclass(classname) | 551 |
| 552 # get the class | |
| 553 try: | |
| 554 cl = self.db.getclass(classname) | |
| 555 except KeyError: | |
| 556 raise UsageError, 'invalid class "%s"'%classname | |
| 557 | |
| 558 # figure the property names to display | |
| 437 if len(args) > 1: | 559 if len(args) > 1: |
| 438 prop_names = args[1].split(',') | 560 prop_names = args[1].split(',') |
| 439 else: | 561 else: |
| 440 prop_names = cl.getprops().keys() | 562 prop_names = cl.getprops().keys() |
| 563 | |
| 564 # now figure column widths | |
| 441 props = [] | 565 props = [] |
| 442 for name in prop_names: | 566 for spec in prop_names: |
| 443 if ':' in name: | 567 if ':' in spec: |
| 444 name, width = name.split(':') | 568 try: |
| 445 props.append((name, int(width))) | 569 name, width = spec.split(':') |
| 570 except (ValueError, TypeError): | |
| 571 raise UsageError, '"%s" not name:width'%spec | |
| 572 props.append((spec, int(width))) | |
| 446 else: | 573 else: |
| 447 props.append((name, len(name))) | 574 props.append((spec, len(spec))) |
| 448 | 575 |
| 576 # now display the heading | |
| 449 print ' '.join([string.capitalize(name) for name, width in props]) | 577 print ' '.join([string.capitalize(name) for name, width in props]) |
| 578 | |
| 579 # and the table data | |
| 450 for nodeid in cl.list(): | 580 for nodeid in cl.list(): |
| 451 l = [] | 581 l = [] |
| 452 for name, width in props: | 582 for name, width in props: |
| 453 if name != 'id': | 583 if name != 'id': |
| 454 value = str(cl.get(nodeid, name)) | 584 try: |
| 585 value = str(cl.get(nodeid, name)) | |
| 586 except KeyError: | |
| 587 raise UsageError, '%s has no property "%s"'%(classname, | |
| 588 name) | |
| 455 else: | 589 else: |
| 456 value = str(nodeid) | 590 value = str(nodeid) |
| 457 f = '%%-%ds'%width | 591 f = '%%-%ds'%width |
| 458 l.append(f%value[:width]) | 592 l.append(f%value[:width]) |
| 459 print ' '.join(l) | 593 print ' '.join(l) |
| 466 Lists the journal entries for the node identified by the designator. | 600 Lists the journal entries for the node identified by the designator. |
| 467 ''' | 601 ''' |
| 468 try: | 602 try: |
| 469 classname, nodeid = roundupdb.splitDesignator(args[0]) | 603 classname, nodeid = roundupdb.splitDesignator(args[0]) |
| 470 except roundupdb.DesignatorError, message: | 604 except roundupdb.DesignatorError, message: |
| 471 print 'Error: %s'%message | 605 raise UsageError, message |
| 472 return 1 | 606 |
| 473 # TODO: handle the -c option? | 607 # TODO: handle the -c option? |
| 474 print self.db.getclass(classname).history(nodeid) | 608 try: |
| 609 print self.db.getclass(classname).history(nodeid) | |
| 610 except KeyError: | |
| 611 raise UsageError, 'no such class "%s"'%classname | |
| 612 except IndexError: | |
| 613 raise UsageError, 'no such %s node "%s"'%(classname, nodeid) | |
| 475 return 0 | 614 return 0 |
| 476 | 615 |
| 477 def do_retire(self, args): | 616 def do_retire(self, args): |
| 478 '''Usage: retire designator[,designator]* | 617 '''Usage: retire designator[,designator]* |
| 479 Retire the node specified by designator. | 618 Retire the node specified by designator. |
| 484 designators = string.split(args[0], ',') | 623 designators = string.split(args[0], ',') |
| 485 for designator in designators: | 624 for designator in designators: |
| 486 try: | 625 try: |
| 487 classname, nodeid = roundupdb.splitDesignator(designator) | 626 classname, nodeid = roundupdb.splitDesignator(designator) |
| 488 except roundupdb.DesignatorError, message: | 627 except roundupdb.DesignatorError, message: |
| 489 print 'Error: %s'%message | 628 raise UsageError, message |
| 490 return 1 | 629 try: |
| 491 self.db.getclass(classname).retire(nodeid) | 630 self.db.getclass(classname).retire(nodeid) |
| 631 except KeyError: | |
| 632 raise UsageError, 'no such class "%s"'%classname | |
| 633 except IndexError: | |
| 634 raise UsageError, 'no such %s node "%s"'%(classname, nodeid) | |
| 492 return 0 | 635 return 0 |
| 493 | 636 |
| 494 def do_export(self, args): | 637 def do_export(self, args): |
| 495 '''Usage: export class[,class] destination_dir | 638 '''Usage: export class[,class] destination_dir |
| 496 Export the database to tab-separated-value files. | 639 Export the database to tab-separated-value files. |
| 509 if csv is not None: | 652 if csv is not None: |
| 510 p = csv.parser(field_sep=':') | 653 p = csv.parser(field_sep=':') |
| 511 | 654 |
| 512 # do all the classes specified | 655 # do all the classes specified |
| 513 for classname in classes: | 656 for classname in classes: |
| 514 cl = self.db.getclass(classname) | 657 try: |
| 658 cl = self.db.getclass(classname) | |
| 659 except KeyError: | |
| 660 raise UsageError, 'no such class "%s"'%classname | |
| 515 f = open(os.path.join(dir, classname+'.csv'), 'w') | 661 f = open(os.path.join(dir, classname+'.csv'), 'w') |
| 516 f.write(string.join(cl.properties.keys(), ':') + '\n') | 662 f.write(string.join(cl.properties.keys(), ':') + '\n') |
| 517 | 663 |
| 518 # all nodes for this class | 664 # all nodes for this class |
| 519 properties = cl.properties.items() | 665 properties = cl.properties.items() |
| 554 the existing database - if you want to create a new database using the | 700 the existing database - if you want to create a new database using the |
| 555 imported data, then create a new database (or, tediously, retire all | 701 imported data, then create a new database (or, tediously, retire all |
| 556 the old data.) | 702 the old data.) |
| 557 ''' | 703 ''' |
| 558 if len(args) < 2: | 704 if len(args) < 2: |
| 559 print do_import.__doc__ | 705 raise UsageError, 'Not enough arguments supplied' |
| 560 return 1 | |
| 561 if csv is None: | 706 if csv is None: |
| 562 print 'Sorry, you need the csv module to use this function.' | 707 raise UsageError, \ |
| 563 print 'Get it from: http://www.object-craft.com.au/projects/csv/' | 708 'Sorry, you need the csv module to use this function.\n'\ |
| 564 return 1 | 709 'Get it from: http://www.object-craft.com.au/projects/csv/' |
| 565 | 710 |
| 566 from roundup import hyperdb | 711 from roundup import hyperdb |
| 567 | 712 |
| 568 # ensure that the properties and the CSV file headings match | 713 # ensure that the properties and the CSV file headings match |
| 569 cl = self.db.getclass(args[0]) | 714 try: |
| 715 cl = self.db.getclass(classname) | |
| 716 except KeyError: | |
| 717 raise UsageError, 'no such class "%s"'%classname | |
| 570 f = open(args[1]) | 718 f = open(args[1]) |
| 571 p = csv.parser(field_sep=':') | 719 p = csv.parser(field_sep=':') |
| 572 file_props = p.parse(f.readline()) | 720 file_props = p.parse(f.readline()) |
| 573 props = cl.properties.keys() | 721 props = cl.properties.keys() |
| 574 m = file_props[:] | 722 m = file_props[:] |
| 575 m.sort() | 723 m.sort() |
| 576 props.sort() | 724 props.sort() |
| 577 if m != props: | 725 if m != props: |
| 578 print 'Import file doesn\'t define the same properties as "%s".'%args[0] | 726 raise UsageError, 'Import file doesn\'t define the same '\ |
| 579 return 1 | 727 'properties as "%s".'%args[0] |
| 580 | 728 |
| 581 # loop through the file and create a node for each entry | 729 # loop through the file and create a node for each entry |
| 582 n = range(len(props)) | 730 n = range(len(props)) |
| 583 while 1: | 731 while 1: |
| 584 line = f.readline() | 732 line = f.readline() |
| 661 if len(args) < 2: | 809 if len(args) < 2: |
| 662 print function.__doc__ | 810 print function.__doc__ |
| 663 return 1 | 811 return 1 |
| 664 | 812 |
| 665 # do the command | 813 # do the command |
| 666 try: | 814 ret = 0 |
| 667 return function(args[1:]) | 815 try: |
| 668 finally: | 816 ret = function(args[1:]) |
| 669 self.db.close() | 817 except UsageError, message: |
| 670 | 818 print 'Error: %s'%message |
| 671 return 1 | 819 print function.__doc__ |
| 820 ret = 1 | |
| 821 except: | |
| 822 import traceback | |
| 823 traceback.print_exc() | |
| 824 ret = 1 | |
| 825 return ret | |
| 672 | 826 |
| 673 def interactive(self, ws_re=re.compile(r'\s+')): | 827 def interactive(self, ws_re=re.compile(r'\s+')): |
| 674 '''Run in an interactive mode | 828 '''Run in an interactive mode |
| 675 ''' | 829 ''' |
| 676 print 'Roundup {version} ready for input.' | 830 print 'Roundup {version} ready for input.' |
| 711 self.instance_home = arg | 865 self.instance_home = arg |
| 712 if opt == '-c': | 866 if opt == '-c': |
| 713 self.comma_sep = 1 | 867 self.comma_sep = 1 |
| 714 | 868 |
| 715 # if no command - go interactive | 869 # if no command - go interactive |
| 870 ret = 0 | |
| 716 if not args: | 871 if not args: |
| 717 return self.interactive() | 872 self.interactive() |
| 718 | 873 else: |
| 719 self.run_command(args) | 874 ret = self.run_command(args) |
| 875 self.db.close() | |
| 876 return ret | |
| 720 | 877 |
| 721 | 878 |
| 722 if __name__ == '__main__': | 879 if __name__ == '__main__': |
| 723 tool = AdminTool() | 880 tool = AdminTool() |
| 724 sys.exit(tool.main()) | 881 sys.exit(tool.main()) |
| 725 | 882 |
| 726 # | 883 # |
| 727 # $Log: not supported by cvs2svn $ | 884 # $Log: not supported by cvs2svn $ |
| 885 # Revision 1.41 2001/11/09 01:25:40 richard | |
| 886 # Should parse with python 1.5.2 now. | |
| 887 # | |
| 728 # Revision 1.40 2001/11/08 04:42:00 richard | 888 # Revision 1.40 2001/11/08 04:42:00 richard |
| 729 # Expanded the already-abbreviated "initialise" and "specification" commands, | 889 # Expanded the already-abbreviated "initialise" and "specification" commands, |
| 730 # and added a comment to the command help about the abbreviation. | 890 # and added a comment to the command help about the abbreviation. |
| 731 # | 891 # |
| 732 # Revision 1.39 2001/11/08 04:29:59 richard | 892 # Revision 1.39 2001/11/08 04:29:59 richard |
