Package gavo :: Package user :: Module upgrade
[frames] | no frames]

Source Code for Module gavo.user.upgrade

  1  """ 
  2  Stuff dealing with the upgrade of the database schema. 
  3   
  4  From software version 0.8.2 on, there is a dc.metastore table with a key 
  5  schemaversion.  Each change in the central schema increases the value 
  6  (interpreted as an integer) by one, and this module will contain a  
  7  corresponding upgrader. 
  8   
  9  An upgrader inherits form the Upgrader class.  See there for more details. 
 10   
 11  This module contains the current schemaversion expected by the software; gavo 
 12  upgrade does everything required to bring the what's in the database in sync 
 13  with the code (or so I hope). 
 14  """ 
 15   
 16  #c Copyright 2008-2019, the GAVO project 
 17  #c 
 18  #c This program is free software, covered by the GNU GPL.  See the 
 19  #c COPYING file in the source distribution. 
 20   
 21   
 22  from __future__ import print_function 
 23   
 24  import sys 
 25   
 26  from psycopg2 import extensions 
 27   
 28  from gavo import base 
 29  from gavo import rsc 
 30  from gavo import rscdesc  #noflake: for cache registration 
 31  from gavo import utils 
32 33 34 -class _COMMIT(object):
35 """A sentinel used by iterStatements. 36 """
37 38 39 CURRENT_SCHEMAVERSION = 20
40 41 42 -def getColumnNamesFor(tableId, connection):
43 """returns (normalised) column names for tableId. 44 45 (tableId is something like //tap#tables) 46 """ 47 t = rsc.TableForDef(base.resolveCrossId(tableId), connection=connection) 48 return set(n for n, t in t.getColumnsFromDB(t.tableDef.getQName()))
49
50 51 -def relationExists(tableName, connection):
52 """returns True if tableName (as schema.name) exists, False otherwise. 53 """ 54 q = base.UnmanagedQuerier(connection) 55 return q.getTableType(tableName) is not None
56
57 58 -def _updateTAP_SCHEMA(connection):
59 """re-ingests TAP_SCHEMA metadata for all RDs already mentioned 60 in TAP_SCHEMA. 61 """ 62 from gavo.protocols import tap 63 64 toDo = [r[0] for r in 65 connection.query( 66 "SELECT DISTINCT sourceRD FROM dc.tablemeta")] 67 68 for rdId in toDo: 69 try: 70 tap.publishToTAP( 71 base.caches.getRD(rdId, doQueries=False), connection) 72 except Exception as msg: 73 base.ui.notifyWarning("RD %s couldn't be loaded or ingested to" 74 " TAP_SCHEMA (%s). Fix and run dachs imp -m on it to have" 75 " up-to-date metadata in TAP_SCHEMA"%(rdId, msg)) 76 continue
77
78 79 -class AnnotatedString(str):
80 """a string with an annotation. 81 82 This is (optionally) used to hold SQL statements here; the annotation 83 is shown to the user instead of the naked statement when present. 84 """
85 - def __new__(cls, content, annotation):
86 res = str.__new__(cls, content) 87 res.annotation = annotation 88 return res
89
90 91 -def showProgress(msg):
92 """outputs msg to stdout without lf "immediately". 93 """ 94 sys.stdout.write(msg) 95 sys.stdout.flush()
96
97 98 -def getDBSchemaVersion():
99 """returns the schemaversion given in the database. 100 101 This will return -1 if no schemaversion is declared. 102 """ 103 try: 104 return int(base.getDBMeta("schemaversion")) 105 except (KeyError, base.DBError): 106 return -1
107
108 109 -def dumpExtensionUpdater(conn):
110 """prints SQL to bring [db]managedExtensions up to date. 111 """ 112 statements = [] 113 114 for extName in base.getConfig("db", "managedextensions"): 115 res = list(conn.query( 116 "SELECT default_version, installed_version" 117 " FROM pg_available_extensions" 118 " WHERE name=%(extName)s", locals())) 119 120 if res: 121 def_version, ins_version = res[0] 122 if ins_version is None: 123 # extra treatment for some magic extensions that may have been 124 # present from before postgres' proper extension mechanism. 125 if extName in ['q3c', 'pg_sphere']: 126 statements.append("CREATE EXTENSION %s FROM unpackaged;"%extName) 127 else: 128 statements.append("CREATE EXTENSION %s;"%extName) 129 130 elif ins_version!=def_version: 131 statements.append("ALTER EXTENSION %s UPDATE TO %s;"%( 132 extName, 133 extensions.adapt(def_version).getquoted())) 134 # else fall through (either the extension is not installed 135 # or it's up to date) 136 137 if statements: 138 print(("\n".join(statements)+"\n")) 139 return 0 140 141 else: 142 return 1
143
144 145 -class Upgrader(object):
146 """A specification to upgrade from some schema version to another schema 147 version. 148 149 Upgraders live as uninstanciated classes. Their version attribute gives the 150 version their instructions update *from*; their destination version 151 therefore is version+1. 152 153 Each upgrader has attributes named u_<seqno>_<something>. These can 154 be either strings, which are then directly executed in the database, 155 or class methods, which will be called with a connection argument. You 156 must not commit this connection. You must not swallow exceptions 157 that have left the connection unready (i.e., require a rollback). 158 159 Note that if you run rsc.makeData, you MUST pass both 160 connection=connection and runCommit=False in order to avoid messing 161 people's lives up. 162 163 The individual upgrader classmethods will be run in the sequence 164 given by the sequence number. 165 166 The updaters should have 1-line docstrings explaining what they do. 167 168 The update of the schemaversion is done automatically, you don't 169 need to worry about it. 170 """ 171 version = None 172 173 @classmethod
174 - def updateSchemaversion(cls, connection):
175 # no docstring, we output our info ourselves 176 showProgress("> update schemaversion to %s..."%(cls.version+1)) 177 base.setDBMeta(connection, "schemaversion", cls.version+1)
178 179 @classmethod
180 - def iterStatements(cls):
181 """returns strings and classmethods that, in all, perform the necessary 182 upgrade. 183 """ 184 for cmdAttr in (s for s in sorted(dir(cls)) if s.startswith("u_")): 185 yield getattr(cls, cmdAttr) 186 yield cls.updateSchemaversion
187
188 189 -class To0Upgrader(Upgrader):
190 """This is executed when there's no schema version defined in the database. 191 192 The assumption is that the database reflects the status of 0.8, so 193 it adds the author column in dc.services if necessary (which it's 194 not if the software has been updated to 0.8.1). 195 """ 196 version = -1 197 198 @classmethod
199 - def u_000_addauthor(cls, connection):
200 """add an author column to dc.services if necessary""" 201 if "authors" in list(connection.queryToDicts( 202 "SELECT * FROM dc.resources LIMIT 1"))[0]: 203 return 204 connection.query("alter table dc.resources add column authors") 205 for sourceRD, resId in connection.query("select sourcrd, resid" 206 " from dc.resources"): 207 try: 208 res = base.getRD(sourceRD).getById(resId) 209 authors = "; ".join(m.getContent("text") #noflake: used through locals 210 for m in res.iterMeta("creator.name", propagate=True)) 211 except: 212 # don't worry if fetching authors fails; people will notice... 213 pass 214 else: 215 connection.query("update dc.resources set authors=%(authors)s" 216 " where resid=%(resId)s and sourcerd=%(sourceRD)s", 217 locals())
218 219 @classmethod
220 - def u_010_makeMetastore(cls, connection):
221 """create the meta store""" 222 td = base.caches.getRD("//dc_tables").getById("metastore") 223 rsc.TableForDef(td, create=True, connection=connection)
224
225 226 -class To1Upgrader(Upgrader):
227 version = 0 228 229 @classmethod
230 - def u_000_update_funcs(cls, connection):
231 """update GAVO server-side functions""" 232 rsc.makeData(base.caches.getRD("//adql").getById("make_udfs"), 233 connection=connection, runCommit=False)
234
235 236 -class To2Upgrader(Upgrader):
237 version = 1 238 239 @classmethod
240 - def _upgradeTable(cls, td, colName, connection):
241 col = td.getColumnByName(colName) 242 if not col.type=='double precision' or not col.xtype=='mjd': 243 # this is not done via the mixin, it appears; give up 244 return 245 246 showProgress(td.getQName()+", ") 247 connection.execute("ALTER TABLE %s ALTER COLUMN %s" 248 " SET DATA TYPE DOUBLE PRECISION USING ts_to_mjd(%s)"% 249 (td.getQName(), colName, colName)) 250 rsc.TableForDef(td, connection=connection, create=False 251 ).updateMeta()
252 253 254 @classmethod
255 - def u_000_siapDateObsToMJD(cls, connection):
256 """change SIAP and SSAP dateObs columns to MJD""" 257 mth = base.caches.getMTH(None) 258 connection.execute("DROP VIEW IF EXISTS ivoa.obscore") 259 260 for tableName, fieldName in connection.query( 261 "SELECT tableName, fieldName FROM dc.columnmeta" 262 " WHERE type='timestamp' AND" 263 " fieldName LIKE '%%dateObs'"): 264 cls._upgradeTable(mth.getTableDefForTable(tableName), fieldName, 265 connection) 266 267 dd = base.caches.getRD("//obscore", doQueries=False 268 ).getById("refreshAfterSchemaUpdate") 269 rsc.makeData(dd, connection=connection)
270
271 272 -class To3Upgrader(Upgrader):
273 version = 2 274 275 @classmethod
276 - def u_000_tapSchema(cls, connection):
277 """add supportedmodels table to tap_schema""" 278 rsc.makeData(base.caches.getRD("//tap").getById("createSchema"), 279 connection=connection, runCommit=False)
280 281 @classmethod
282 - def u_010_declareObscoreModel(cls, connection):
283 """declare obscore data model if the obscore table is present""" 284 if list(connection.query( 285 "select * from dc.tablemeta where tablename='ivoa.ObsCore'")): 286 from gavo.protocols import tap 287 rd = base.caches.getRD("//obscore") 288 tap.publishToTAP(rd, connection) 289 else: 290 showProgress(" (not present)")
291
292 293 -class To4Upgrader(Upgrader):
294 version = 3 295 296 @classmethod
297 - def u_000_adqlfunctions(cls, connection):
298 """update ADQL GAVO-defined functions for the postgres planner's benefit""" 299 rsc.makeData(base.caches.getRD("//adql").getById("make_udfs"), 300 connection=connection, runCommit=False)
301
302 303 -class To5Upgrader(Upgrader):
304 version = 4 305 306 @classmethod
307 - def u_000_updateObscore(cls, connection):
308 """update obscore to work even when the table is empty""" 309 rsc.TableForDef(base.caches.getRD("//obscore").getById("emptyobscore"), 310 connection=connection, create=True) 311 312 dd = base.caches.getRD("//obscore", doQueries=False 313 ).getById("refreshAfterSchemaUpdate") 314 rsc.makeData(dd, connection=connection)
315
316 317 -class To6Upgrader(Upgrader):
318 version = 5 319 320 @classmethod
321 - def u_000_remetaObscore(cls, connection):
322 """update obscore metadata to fix the erroneous id""" 323 rsc.makeData(base.caches.getRD("//obscore").getById("create"), 324 connection=connection, runCommit=False, 325 parseOptions=rsc.getParseOptions(metaOnly=True))
326 327 u_010_addPreviewColumn = ("ALTER TABLE dc.products ADD COLUMN" 328 " preview TEXT DEFAULT 'AUTO'") 329 u_020_dedefaultPreviewColumn = ("ALTER TABLE dc.products ALTER COLUMN" 330 " preview DROP DEFAULT") 331 u_30_addDatalinkColumn = ("ALTER TABLE dc.products ADD COLUMN" 332 " datalink TEXT")
333
334 335 -class To7Upgrader(Upgrader):
336 version = 6 337 338 u_010_addPreviewMIMEColumn = ("ALTER TABLE dc.products ADD COLUMN" 339 " preview_mime TEXT")
340
341 342 -class To8Upgrader(Upgrader):
343 version = 7 344 u_010_removeColumnsMeta = ("DROP TABLE dc.columnmeta")
345
346 347 -class To9Upgrader(Upgrader):
348 version = 8 349 u_010_chuckADQLPrefix = AnnotatedString("UPDATE TAP_SCHEMA.columns" 350 " SET datatype=substring(datatype from 6)" 351 " WHERE datatype LIKE 'adql:%%'", 352 "Remove adql: prefix in TAP_SCHEMA.columns.datatype") 353 u_020_setSize1OnAtoms = AnnotatedString("UPDATE tap_schema.columns" 354 " SET \"size\"=1 WHERE NOT datatype LIKE '%%(*)'", 355 "Set size=1 in TAP_SCHEMA.columns for atomic types") 356 u_030_removeArrayMarkInText = AnnotatedString("UPDATE tap_schema.columns" 357 " SET datatype=replace(datatype, '(*)', '') WHERE datatype LIKE '%%(*)'", 358 "Turn VARCHAR(*) into simple VARCHAR (size=NULL already set for those)")
359
360 361 -class To10Upgrader(Upgrader):
362 version = 9 363 364 @classmethod
365 - def u_000_dropADQLExamples(cls, connection):
366 """drop old TAP examples tables (gone to _examples meta)""" 367 from gavo.user import dropping 368 dropping._do_dropTable("tap_schema.examples", connection)
369 370 @classmethod
371 - def u_010_createDLAsyncTable(cls, connection):
372 """import job table for async datalink""" 373 from gavo import rsc 374 rsc.makeData(base.caches.getRD("//datalink").getById("import"), 375 connection=connection, runCommit=False)
376
377 378 -class To11Upgrader(Upgrader):
379 version = 10 380 381 @classmethod
382 - def u_000_findMixedinTables(cls, connection):
383 """inform about tables with non-trivial mixins.""" 384 # in reality, the mixins that really give us a headache here 385 # are the ones mixin in products. Hence, we simply look 386 # for tables that have both accref and embargo; that's 387 # probably a certain indication. 388 389 print("\n!! Important: column sequences" 390 " of tables with some mixins have changed.") 391 print("!! If this affects you, below commands are shown that will re-import") 392 print("!! the affected tables. Some services on top of these tables may") 393 print("!! be *broken* until these commands have run.") 394 print("!! Sorry for this inconvenience; we hope it won't happen again.\n") 395 396 from gavo import registry 397 for rdId in registry.findAllRDs(): 398 if rdId.startswith("__system"): 399 continue 400 401 try: 402 rd = base.caches.getRD(rdId) 403 except: 404 # ignore broken RDs -- services there are broken anyway 405 continue 406 407 ids = set() 408 409 for td in rd.tables: 410 try: 411 td.getColumnByName("accref") and td.getColumnByName("embargo") 412 except base.NotFoundError: 413 continue # table not affected 414 else: 415 416 if not rsc.TableForDef(td, connection=connection, create=False 417 ).exists(): 418 continue 419 420 # table needs re-importing, see if you can find a correponsing 421 # data element 422 for dd in rd.dds: 423 for make in dd.makes: 424 if make.table==td: 425 ids.add(dd.id) 426 if ids: 427 print("dachs imp '%s' %s"%(rd.sourceId, 428 " ".join("'%s'"%id for id in ids))) 429 430 sys.stderr.write("\nEnd of scan of mixin-affected tables...")
431
432 433 -class To12Upgrader(Upgrader):
434 version = 11 435 436 @classmethod
437 - def u_010_updateTAPRecord(cls, connection):
438 """prettify the TAP record's IVOID""" 439 from gavo.registry import publication 440 publication.updateServiceList([base.caches.getRD("//services")], 441 connection=connection) 442 publication.makeDeletedRecord( 443 "ivo://"+base.getConfig("ivoa", "authority")+"/__system__/tap/run", 444 connection)
445
446 447 -class To13Upgrader(Upgrader):
448 version = 12 449 @classmethod
450 - def u_010_updateObscore(cls, connection):
451 """upgrade ivoa.obscore to obscore 1.1. 452 """ 453 if relationExists("ivoa._obscoresources", connection): 454 dd = base.caches.getRD("//obscore", doQueries=False 455 ).getById("refreshAfterSchemaUpdate") 456 rsc.makeData(dd, connection=connection)
457
458 459 -class To14Upgrader(Upgrader):
460 version = 13 461 462 @classmethod
463 - def u_010_addColIndex(cls, connection):
464 """Adding column_index column to TAP_SCHEMA.columns" 465 """ 466 dbCols = getColumnNamesFor("//tap#columns", connection) 467 if not "column_index" in dbCols: 468 connection.execute("ALTER TABLE TAP_SCHEMA.columns" 469 " ADD COLUMN column_index SMALLINT") 470 if not "arraysize" in dbCols: 471 connection.execute("ALTER TABLE TAP_SCHEMA.columns" 472 " ADD COLUMN arraysize TEXT") 473 if not "xtype" in dbCols: 474 connection.execute("ALTER TABLE TAP_SCHEMA.columns" 475 " ADD COLUMN xtype TEXT")
476
477 478 -class To15Upgrader(Upgrader):
479 version = 14 480 481 @classmethod
482 - def u_10_add_uws_creationTime(cls, connection):
483 """adding creationTime to UWS tables for UWS 1.1 support.""" 484 q = base.UnmanagedQuerier(connection) 485 for tableId, tableName in [ 486 ("//datalink#datalinkjobs", "dc.datalinkjobs"), 487 ("//uws#userjobs", "uws.userjobs"), 488 ("//tap#tapjobs", "tap_schema.tapjobs")]: 489 if q.getTableType(tableName) is not None: 490 if not "creationtime" in getColumnNamesFor(tableId, connection): 491 connection.execute("ALTER TABLE %s" 492 " ADD COLUMN creationTime TIMESTAMP"%tableName)
493
494 495 -class To16Upgrader(Upgrader):
496 version = 15 497 498 u_010_delete_obscore_1_0_model = AnnotatedString( 499 # this purges the old ivoid unconditionally; that's never wrong, 500 # because obscore 1.1 has one of its own. But it's also 501 # fixing spurious publications where old versions of DaCHS 502 # have blindly declared obscore support 503 "DELETE FROM tap_schema.supportedmodels" 504 " WHERE dmivorn='ivo://ivoa.net/std/ObsCore/v1.0'", 505 "Deleting obscore 1.0 model support declaration") 506 507 @classmethod
508 - def u_05_add_schema_index(cls, connection):
509 """adding schema_index to tap_schema.schemas""" 510 # it's really a v19 change, but the following steps would fail without 511 # it 512 if not "schema_index" in getColumnNamesFor("//tap#schemas", connection): 513 connection.execute("ALTER TABLE tap_schema.schemas ADD COLUMN" 514 " schema_index INTEGER")
515 516 @classmethod
517 - def u_10_upgrade_tap_schema_tables(cls, connection):
518 """Adding 1.1 columns to TAP_SCHEMA.tables. 519 """ 520 if not "table_index" in getColumnNamesFor("//tap#tables", connection): 521 connection.execute("ALTER TABLE TAP_SCHEMA.tables" 522 " ADD COLUMN table_index SMALLINT")
523 524 @classmethod
525 - def u_20_upgrade_tap_schema_columns(cls, connection):
526 """Adding 1.1 columns to TAP_SCHEMA.columns. 527 """ 528 dbCols = getColumnNamesFor("//tap#columns", connection) 529 if not "arraysize" in dbCols: 530 connection.execute("ALTER TABLE TAP_SCHEMA.columns" 531 " ADD COLUMN arraysize TEXT") 532 if not "xtype" in dbCols: 533 connection.execute("ALTER TABLE TAP_SCHEMA.columns" 534 " ADD COLUMN xtype TEXT")
535 536 @classmethod
537 - def u_50_update_tap_schema(cls, connection):
538 """Filling new TAP_SCHEMA columns""" 539 _updateTAP_SCHEMA(connection)
540 541 @classmethod
542 - def u_60_update_obscore_spectra(cls, connection):
543 """Updating obscore-published spectral tables.""" 544 try: 545 from gavo.rscdef import scripting 546 script = base.resolveCrossId("//obscore#addTableToObscoreSources") 547 script.notify = False 548 549 with connection.savepoint(): 550 for row in connection.query( 551 "SELECT DISTINCT tablename FROM ivoa._obscoresources" 552 " WHERE sqlfragment LIKE '%%''spectrum'' AS text) AS dataprod%%'"): 553 table = rsc.TableForDef( 554 base.getTableDefForTable(connection, row[0]), 555 connection=connection) 556 showProgress(" "+row[0]) 557 scripting.PythonScriptRunner(script).run(table) 558 559 dd = base.caches.getRD("//obscore", doQueries=False 560 ).getById("create") 561 rsc.makeData(dd, connection=connection, runCommit=False) 562 563 except Exception: 564 # probably there is no obscore table on this installation. 565 showProgress("(skipped)")
566
567 568 -class To17Upgrader(Upgrader):
569 version = 16 570 571 @classmethod
572 - def u_10_import_adql(cls, connection):
573 """loading new ADQL UDFs""" 574 dd = base.caches.getRD("//adql", doQueries=False 575 ).getById("make_udfs") 576 rsc.makeData(dd, connection=connection, runCommit=False)
577 578 @classmethod
579 - def u_20_reload_tap_schema(cls, connection):
580 """updating tap_schema.schemas conflict rule""" 581 dd = base.caches.getRD("//tap", doQueries=False 582 ).getById("createSchema") 583 rsc.makeData(dd, connection=connection, runCommit=False, 584 parseOptions=rsc.getParseOptions(metaOnly=False, systemImport=False))
585 586 @classmethod
587 - def u_30_update_obscore_meta(cls, connection):
588 """updating obscore metadata""" 589 if relationExists("ivoa._obscoresources", connection): 590 dd = base.caches.getRD("//obscore", doQueries=False 591 ).getById("create") 592 rsc.makeData(dd, connection=connection, runCommit=False, 593 parseOptions=rsc.getParseOptions(metaOnly=False, systemImport=True))
594
595 596 -class To18Upgrader(Upgrader):
597 version = 17 598 599 @classmethod
600 - def u_10_restoreTAP_SCHEMA(cls, connection):
601 """recreating a possibly damaged TAP_SCHEMA""" 602 _updateTAP_SCHEMA(connection)
603
604 605 -class To19Upgrader(Upgrader):
606 version = 18 607 608 @classmethod
609 - def u_10_add_schema_index(cls, connection):
610 """adding schema_index to tap_schema.schemas""" 611 if not "schema_index" in getColumnNamesFor("//tap#schemas", connection): 612 connection.execute("ALTER TABLE tap_schema.schemas ADD COLUMN" 613 " schema_index INTEGER")
614 615 @classmethod
616 - def u_20_add_tap_schema_keys(cls, connection):
617 """re-importing TAP_SCHEMA to update foreign key declarations""" 618 _updateTAP_SCHEMA(connection)
619
620 621 -class To20Upgrader(Upgrader):
622 version = 19 623 624 @classmethod
625 - def u_10_update_obscore_meta(cls, connection):
626 """updating obscore metadata""" 627 if relationExists("ivoa._obscoresources", connection): 628 dd = base.caches.getRD("//obscore", doQueries=False 629 ).getById("refreshAfterSchemaUpdate") 630 rsc.makeData(dd, connection=connection)
631 632 @classmethod
633 - def u_20_import_adql(cls, connection):
634 """updating ADQL UDFs""" 635 dd = base.caches.getRD("//adql", doQueries=False 636 ).getById("make_udfs") 637 rsc.makeData(dd, connection=connection, runCommit=False)
638
639 640 -def iterStatements(startVersion, endVersion=CURRENT_SCHEMAVERSION, 641 upgraders=None):
642 """yields all upgraders from startVersion to endVersion in sequence. 643 """ 644 toRun = [] 645 for upgrader in utils.iterDerivedClasses(Upgrader, 646 upgraders or globals().values()): 647 if startVersion<=upgrader.version<endVersion: 648 toRun.append(upgrader) 649 toRun.sort(key=lambda upgrader:upgrader.version) 650 for upgrader in toRun: 651 for statement in upgrader.iterStatements(): 652 yield statement 653 yield _COMMIT
654
655 656 -def upgrade(forceDBVersion=None):
657 """runs all updates necessary to bring a database to the 658 CURRENT_SCHEMAVERSION. 659 660 Unless catastrophic things go on, each upgrade is a transaction 661 of its own; the first failed transaction stops the upgrade at the 662 version last successfully upgraded to. 663 """ 664 if forceDBVersion is None: 665 startVersion = getDBSchemaVersion() 666 else: 667 startVersion = forceDBVersion 668 669 with base.getWritableAdminConn() as conn: 670 for statement in iterStatements(startVersion, CURRENT_SCHEMAVERSION): 671 if statement is _COMMIT: 672 conn.commit() 673 674 elif callable(statement): 675 if statement.__doc__: 676 showProgress("> %s..."%statement.__doc__) 677 # if no docstring is present, we assume the function will output 678 # custom user feedback 679 statement(conn) 680 681 else: 682 showProgress("> "+getattr(statement, "annotation", 683 "executing %s"%utils.makeEllipsis(statement, 60))+"... ") 684 conn.execute(statement) 685 showProgress(" ok\n")
686
687 688 -def parseCommandLine():
689 import argparse 690 parser = argparse.ArgumentParser() 691 parser.add_argument("--force-dbversion", help="assume this as the" 692 " database's schema version. If you don't develop DaCHS, you" 693 " almost certainly should stay clear of this flag", type=int, 694 dest="forceDBVersion", default=None) 695 parser.add_argument("-e", "--get-extension-script", 696 help="Dump a script to update DaCHS-managed extensions (will" 697 " print nothing if no extensions need updating). This will return" 698 " 0 if material was written, 1 otherwise.", 699 dest="dumpExtScript", action="store_true") 700 return parser.parse_args()
701
702 703 -def main():
704 args = parseCommandLine() 705 if args.dumpExtScript: 706 with base.getTableConn() as conn: 707 sys.exit(dumpExtensionUpdater(conn)) 708 else: 709 upgrade(args.forceDBVersion)
710