Show More
@@ -28,7 +28,7 b' class ConstraintChangeset(object):' | |||
|
28 | 28 | def __do_imports(self, visitor_name, *a, **kw): |
|
29 | 29 | engine = kw.pop('engine', self.table.bind) |
|
30 | 30 | from rhodecode.lib.dbmigrate.migrate.changeset.databases.visitor import (get_engine_visitor, |
|
31 | run_single_visitor) | |
|
31 | run_single_visitor) | |
|
32 | 32 | visitorcallable = get_engine_visitor(engine, visitor_name) |
|
33 | 33 | run_single_visitor(engine, visitorcallable, self, *a, **kw) |
|
34 | 34 |
@@ -2,7 +2,7 b'' | |||
|
2 | 2 | Firebird database specific implementations of changeset classes. |
|
3 | 3 | """ |
|
4 | 4 | from sqlalchemy.databases import firebird as sa_base |
|
5 | ||
|
5 | from sqlalchemy.schema import PrimaryKeyConstraint | |
|
6 | 6 | from rhodecode.lib.dbmigrate.migrate import exceptions |
|
7 | 7 | from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06 |
|
8 | 8 | |
@@ -27,13 +27,32 b' class FBColumnDropper(ansisql.ANSIColumn' | |||
|
27 | 27 | if column.table.primary_key.columns.contains_column(column): |
|
28 | 28 | column.table.primary_key.drop() |
|
29 | 29 | # TODO: recreate primary key if it references more than this column |
|
30 | if column.unique or getattr(column, 'unique_name', None): | |
|
31 | for cons in column.table.constraints: | |
|
32 | if cons.contains_column(column): | |
|
33 | cons.drop() | |
|
34 | # TODO: recreate unique constraint if it refenrences more than this column | |
|
35 | 30 | |
|
36 | table = self.start_alter_table(column) | |
|
31 | for index in column.table.indexes: | |
|
32 | # "column in index.columns" causes problems as all | |
|
33 | # column objects compare equal and return a SQL expression | |
|
34 | if column.name in [col.name for col in index.columns]: | |
|
35 | index.drop() | |
|
36 | # TODO: recreate index if it references more than this column | |
|
37 | ||
|
38 | for cons in column.table.constraints: | |
|
39 | if isinstance(cons,PrimaryKeyConstraint): | |
|
40 | # will be deleted only when the column its on | |
|
41 | # is deleted! | |
|
42 | continue | |
|
43 | ||
|
44 | if SQLA_06: | |
|
45 | should_drop = column.name in cons.columns | |
|
46 | else: | |
|
47 | should_drop = cons.contains_column(column) and cons.name | |
|
48 | if should_drop: | |
|
49 | self.start_alter_table(column) | |
|
50 | self.append("DROP CONSTRAINT ") | |
|
51 | self.append(self.preparer.format_constraint(cons)) | |
|
52 | self.execute() | |
|
53 | # TODO: recreate unique constraint if it refenrences more than this column | |
|
54 | ||
|
55 | self.start_alter_table(column) | |
|
37 | 56 | self.append('DROP %s' % self.preparer.format_column(column)) |
|
38 | 57 | self.execute() |
|
39 | 58 |
@@ -80,10 +80,17 b' class SQLiteColumnDropper(SQLiteHelper, ' | |||
|
80 | 80 | """SQLite ColumnDropper""" |
|
81 | 81 | |
|
82 | 82 | def _modify_table(self, table, column, delta): |
|
83 | ||
|
83 | 84 | columns = ' ,'.join(map(self.preparer.format_column, table.columns)) |
|
84 | 85 | return 'INSERT INTO %(table_name)s SELECT ' + columns + \ |
|
85 | 86 | ' from migration_tmp' |
|
86 | 87 | |
|
88 | def visit_column(self,column): | |
|
89 | # For SQLite, we *have* to remove the column here so the table | |
|
90 | # is re-created properly. | |
|
91 | column.remove_from_table(column.table,unset_table=False) | |
|
92 | super(SQLiteColumnDropper,self).visit_column(column) | |
|
93 | ||
|
87 | 94 | |
|
88 | 95 | class SQLiteSchemaChanger(SQLiteHelper, ansisql.ANSISchemaChanger): |
|
89 | 96 | """SQLite SchemaChanger""" |
@@ -29,9 +29,6 b' from rhodecode.lib.dbmigrate.migrate.cha' | |||
|
29 | 29 | 'ColumnDelta', |
|
30 | 30 | ] |
|
31 | 31 | |
|
32 | DEFAULT_ALTER_METADATA = True | |
|
33 | ||
|
34 | ||
|
35 | 32 | def create_column(column, table=None, *p, **kw): |
|
36 | 33 | """Create a column, given the table. |
|
37 | 34 | |
@@ -109,19 +106,11 b' def alter_column(*p, **k):' | |||
|
109 | 106 | The :class:`~sqlalchemy.engine.base.Engine` to use for table |
|
110 | 107 | reflection and schema alterations. |
|
111 | 108 | |
|
112 | :param alter_metadata: | |
|
113 | If `True`, which is the default, the | |
|
114 | :class:`~sqlalchemy.schema.Column` will also modified. | |
|
115 | If `False`, the :class:`~sqlalchemy.schema.Column` will be left | |
|
116 | as it was. | |
|
117 | ||
|
118 | 109 | :returns: A :class:`ColumnDelta` instance representing the change. |
|
119 | 110 | |
|
120 | 111 | |
|
121 | 112 | """ |
|
122 | ||
|
123 | k.setdefault('alter_metadata', DEFAULT_ALTER_METADATA) | |
|
124 | ||
|
113 | ||
|
125 | 114 | if 'table' not in k and isinstance(p[0], sqlalchemy.Column): |
|
126 | 115 | k['table'] = p[0].table |
|
127 | 116 | if 'engine' not in k: |
@@ -135,6 +124,12 b' def alter_column(*p, **k):' | |||
|
135 | 124 | MigrateDeprecationWarning |
|
136 | 125 | ) |
|
137 | 126 | engine = k['engine'] |
|
127 | ||
|
128 | # enough tests seem to break when metadata is always altered | |
|
129 | # that this crutch has to be left in until they can be sorted | |
|
130 | # out | |
|
131 | k['alter_metadata']=True | |
|
132 | ||
|
138 | 133 | delta = ColumnDelta(*p, **k) |
|
139 | 134 | |
|
140 | 135 | visitorcallable = get_engine_visitor(engine, 'schemachanger') |
@@ -188,11 +183,10 b' class ColumnDelta(DictMixin, sqlalchemy.' | |||
|
188 | 183 | :param table: Table at which current Column should be bound to.\ |
|
189 | 184 | If table name is given, reflection will be used. |
|
190 | 185 | :type table: string or Table instance |
|
191 | :param alter_metadata: If True, it will apply changes to metadata. | |
|
192 | :type alter_metadata: bool | |
|
193 | :param metadata: If `alter_metadata` is true, \ | |
|
194 | metadata is used to reflect table names into | |
|
195 | :type metadata: :class:`MetaData` instance | |
|
186 | ||
|
187 | :param metadata: A :class:`MetaData` instance to store | |
|
188 | reflected table names | |
|
189 | ||
|
196 | 190 | :param engine: When reflecting tables, either engine or metadata must \ |
|
197 | 191 | be specified to acquire engine object. |
|
198 | 192 | :type engine: :class:`Engine` instance |
@@ -213,7 +207,11 b' class ColumnDelta(DictMixin, sqlalchemy.' | |||
|
213 | 207 | __visit_name__ = 'column' |
|
214 | 208 | |
|
215 | 209 | def __init__(self, *p, **kw): |
|
210 | # 'alter_metadata' is not a public api. It exists purely | |
|
211 | # as a crutch until the tests that fail when 'alter_metadata' | |
|
212 | # behaviour always happens can be sorted out | |
|
216 | 213 | self.alter_metadata = kw.pop("alter_metadata", False) |
|
214 | ||
|
217 | 215 | self.meta = kw.pop("metadata", None) |
|
218 | 216 | self.engine = kw.pop("engine", None) |
|
219 | 217 | |
@@ -237,17 +235,19 b' class ColumnDelta(DictMixin, sqlalchemy.' | |||
|
237 | 235 | self.apply_diffs(diffs) |
|
238 | 236 | |
|
239 | 237 | def __repr__(self): |
|
240 |
return '<ColumnDelta altermetadata=%r, %s>' % ( |
|
|
241 | super(ColumnDelta, self).__repr__()) | |
|
242 | ||
|
238 | return '<ColumnDelta altermetadata=%r, %s>' % ( | |
|
239 | self.alter_metadata, | |
|
240 | super(ColumnDelta, self).__repr__() | |
|
241 | ) | |
|
242 | ||
|
243 | 243 | def __getitem__(self, key): |
|
244 | 244 | if key not in self.keys(): |
|
245 | raise KeyError("No such diff key, available: %s" % self.diffs) | |
|
245 | raise KeyError("No such diff key, available: %s" % self.diffs ) | |
|
246 | 246 | return getattr(self.result_column, key) |
|
247 | 247 | |
|
248 | 248 | def __setitem__(self, key, value): |
|
249 | 249 | if key not in self.keys(): |
|
250 | raise KeyError("No such diff key, available: %s" % self.diffs) | |
|
250 | raise KeyError("No such diff key, available: %s" % self.diffs ) | |
|
251 | 251 | setattr(self.result_column, key, value) |
|
252 | 252 | |
|
253 | 253 | def __delitem__(self, key): |
@@ -367,7 +367,7 b' class ColumnDelta(DictMixin, sqlalchemy.' | |||
|
367 | 367 | for_update=True)) |
|
368 | 368 | if toinit: |
|
369 | 369 | column._init_items(*toinit) |
|
370 | ||
|
370 | ||
|
371 | 371 | if not SQLA_06: |
|
372 | 372 | column.args = [] |
|
373 | 373 | |
@@ -395,7 +395,6 b' class ColumnDelta(DictMixin, sqlalchemy.' | |||
|
395 | 395 | self._table = table |
|
396 | 396 | if not self.alter_metadata: |
|
397 | 397 | self._table.meta = sqlalchemy.MetaData(bind=self._table.bind) |
|
398 | ||
|
399 | 398 | def _get_result_column(self): |
|
400 | 399 | return getattr(self, '_result_column', None) |
|
401 | 400 | |
@@ -456,22 +455,18 b' class ChangesetTable(object):' | |||
|
456 | 455 | |
|
457 | 456 | :param name: New name of the table. |
|
458 | 457 | :type name: string |
|
459 | :param alter_metadata: If True, table will be removed from metadata | |
|
460 | :type alter_metadata: bool | |
|
461 | 458 | :param connection: reuse connection istead of creating new one. |
|
462 | 459 | :type connection: :class:`sqlalchemy.engine.base.Connection` instance |
|
463 | 460 | """ |
|
464 | self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA) | |
|
465 | 461 | engine = self.bind |
|
466 | 462 | self.new_name = name |
|
467 | 463 | visitorcallable = get_engine_visitor(engine, 'schemachanger') |
|
468 | 464 | run_single_visitor(engine, visitorcallable, self, connection, **kwargs) |
|
469 | 465 | |
|
470 | 466 | # Fix metadata registration |
|
471 |
|
|
|
472 | self.name = name | |
|
473 | self.deregister() | |
|
474 | self._set_parent(self.metadata) | |
|
467 | self.name = name | |
|
468 | self.deregister() | |
|
469 | self._set_parent(self.metadata) | |
|
475 | 470 | |
|
476 | 471 | def _meta_key(self): |
|
477 | 472 | return sqlalchemy.schema._get_table_key(self.name, self.schema) |
@@ -510,7 +505,6 b' class ChangesetColumn(object):' | |||
|
510 | 505 | `~migrate.changeset.constraint.UniqueConstraint` on this column. |
|
511 | 506 | :param primary_key_name: Creates :class:\ |
|
512 | 507 | `~migrate.changeset.constraint.PrimaryKeyConstraint` on this column. |
|
513 | :param alter_metadata: If True, column will be added to table object. | |
|
514 | 508 | :param populate_default: If True, created column will be \ |
|
515 | 509 | populated with defaults |
|
516 | 510 | :param connection: reuse connection istead of creating new one. |
@@ -518,22 +512,19 b' populated with defaults' | |||
|
518 | 512 | :type index_name: string |
|
519 | 513 | :type unique_name: string |
|
520 | 514 | :type primary_key_name: string |
|
521 | :type alter_metadata: bool | |
|
522 | 515 | :type populate_default: bool |
|
523 | 516 | :type connection: :class:`sqlalchemy.engine.base.Connection` instance |
|
524 | 517 | |
|
525 | 518 | :returns: self |
|
526 | 519 | """ |
|
527 | 520 | self.populate_default = populate_default |
|
528 | self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA) | |
|
529 | 521 | self.index_name = index_name |
|
530 | 522 | self.unique_name = unique_name |
|
531 | 523 | self.primary_key_name = primary_key_name |
|
532 | 524 | for cons in ('index_name', 'unique_name', 'primary_key_name'): |
|
533 | 525 | self._check_sanity_constraints(cons) |
|
534 | 526 | |
|
535 |
|
|
|
536 | self.add_to_table(table) | |
|
527 | self.add_to_table(table) | |
|
537 | 528 | engine = self.table.bind |
|
538 | 529 | visitorcallable = get_engine_visitor(engine, 'columngenerator') |
|
539 | 530 | engine._run_visitor(visitorcallable, self, connection, **kwargs) |
@@ -550,59 +541,54 b' populated with defaults' | |||
|
550 | 541 | |
|
551 | 542 | ``ALTER TABLE DROP COLUMN``, for most databases. |
|
552 | 543 | |
|
553 | :param alter_metadata: If True, column will be removed from table object. | |
|
554 | :type alter_metadata: bool | |
|
555 | 544 | :param connection: reuse connection istead of creating new one. |
|
556 | 545 | :type connection: :class:`sqlalchemy.engine.base.Connection` instance |
|
557 | 546 | """ |
|
558 | self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA) | |
|
559 | 547 | if table is not None: |
|
560 | 548 | self.table = table |
|
561 | 549 | engine = self.table.bind |
|
562 | if self.alter_metadata: | |
|
563 | self.remove_from_table(self.table, unset_table=False) | |
|
564 | 550 | visitorcallable = get_engine_visitor(engine, 'columndropper') |
|
565 | 551 | engine._run_visitor(visitorcallable, self, connection, **kwargs) |
|
566 | if self.alter_metadata: | |
|
567 |
|
|
|
552 | self.remove_from_table(self.table, unset_table=False) | |
|
553 | self.table = None | |
|
568 | 554 | return self |
|
569 | 555 | |
|
570 | 556 | def add_to_table(self, table): |
|
571 | 557 | if table is not None and self.table is None: |
|
572 | 558 | self._set_parent(table) |
|
573 | 559 | |
|
574 |
def _col_name_in_constraint(self, |
|
|
560 | def _col_name_in_constraint(self,cons,name): | |
|
575 | 561 | return False |
|
576 | ||
|
562 | ||
|
577 | 563 | def remove_from_table(self, table, unset_table=True): |
|
578 | 564 | # TODO: remove primary keys, constraints, etc |
|
579 | 565 | if unset_table: |
|
580 | 566 | self.table = None |
|
581 | ||
|
567 | ||
|
582 | 568 | to_drop = set() |
|
583 | 569 | for index in table.indexes: |
|
584 | 570 | columns = [] |
|
585 | 571 | for col in index.columns: |
|
586 |
if col.name |
|
|
572 | if col.name!=self.name: | |
|
587 | 573 | columns.append(col) |
|
588 | 574 | if columns: |
|
589 |
index.columns |
|
|
575 | index.columns=columns | |
|
590 | 576 | else: |
|
591 | 577 | to_drop.add(index) |
|
592 | 578 | table.indexes = table.indexes - to_drop |
|
593 | ||
|
579 | ||
|
594 | 580 | to_drop = set() |
|
595 | 581 | for cons in table.constraints: |
|
596 | 582 | # TODO: deal with other types of constraint |
|
597 |
if isinstance(cons, |
|
|
583 | if isinstance(cons,(ForeignKeyConstraint, | |
|
598 | 584 | UniqueConstraint)): |
|
599 | 585 | for col_name in cons.columns: |
|
600 |
if not isinstance(col_name, |
|
|
586 | if not isinstance(col_name,basestring): | |
|
601 | 587 | col_name = col_name.name |
|
602 |
if self.name |
|
|
588 | if self.name==col_name: | |
|
603 | 589 | to_drop.add(cons) |
|
604 | 590 | table.constraints = table.constraints - to_drop |
|
605 | ||
|
591 | ||
|
606 | 592 | if table.c.contains_column(self): |
|
607 | 593 | table.c.remove(self) |
|
608 | 594 | |
@@ -643,18 +629,14 b' class ChangesetIndex(object):' | |||
|
643 | 629 | |
|
644 | 630 | :param name: New name of the Index. |
|
645 | 631 | :type name: string |
|
646 | :param alter_metadata: If True, Index object will be altered. | |
|
647 | :type alter_metadata: bool | |
|
648 | 632 | :param connection: reuse connection istead of creating new one. |
|
649 | 633 | :type connection: :class:`sqlalchemy.engine.base.Connection` instance |
|
650 | 634 | """ |
|
651 | self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA) | |
|
652 | 635 | engine = self.table.bind |
|
653 | 636 | self.new_name = name |
|
654 | 637 | visitorcallable = get_engine_visitor(engine, 'schemachanger') |
|
655 | 638 | engine._run_visitor(visitorcallable, self, connection, **kwargs) |
|
656 |
|
|
|
657 | self.name = name | |
|
639 | self.name = name | |
|
658 | 640 | |
|
659 | 641 | |
|
660 | 642 | class ChangesetDefaultClause(object): |
@@ -111,12 +111,12 b' class ModelGenerator(object):' | |||
|
111 | 111 | out.append(")") |
|
112 | 112 | return out |
|
113 | 113 | |
|
114 |
def _get_tables(self, |
|
|
114 | def _get_tables(self,missingA=False,missingB=False,modified=False): | |
|
115 | 115 | to_process = [] |
|
116 |
for bool_, |
|
|
117 |
(missingA, |
|
|
118 |
(missingB, |
|
|
119 |
(modified, |
|
|
116 | for bool_,names,metadata in ( | |
|
117 | (missingA,self.diff.tables_missing_from_A,self.diff.metadataB), | |
|
118 | (missingB,self.diff.tables_missing_from_B,self.diff.metadataA), | |
|
119 | (modified,self.diff.tables_different,self.diff.metadataA), | |
|
120 | 120 | ): |
|
121 | 121 | if bool_: |
|
122 | 122 | for name in names: |
@@ -140,7 +140,7 b' class ModelGenerator(object):' | |||
|
140 | 140 | decls = ['from rhodecode.lib.dbmigrate.migrate.changeset import schema', |
|
141 | 141 | 'meta = MetaData()'] |
|
142 | 142 | for table in self._get_tables( |
|
143 |
missingA=True, |
|
|
143 | missingA=True,missingB=True,modified=True | |
|
144 | 144 | ): |
|
145 | 145 | decls.extend(self.getTableDefn(table)) |
|
146 | 146 | |
@@ -169,11 +169,11 b' class ModelGenerator(object):' | |||
|
169 | 169 | modelTable, col.name)) |
|
170 | 170 | for modelCol, databaseCol, modelDecl, databaseDecl in diffDecl: |
|
171 | 171 | upgradeCommands.append( |
|
172 |
'assert False, "Can\'t alter columns: %s:%s=>%s"' |
|
|
173 | modelTable, modelCol.name, databaseCol.name) | |
|
172 | 'assert False, "Can\'t alter columns: %s:%s=>%s"' % ( | |
|
173 | modelTable, modelCol.name, databaseCol.name)) | |
|
174 | 174 | downgradeCommands.append( |
|
175 |
'assert False, "Can\'t alter columns: %s:%s=>%s"' |
|
|
176 | modelTable, modelCol.name, databaseCol.name) | |
|
175 | 'assert False, "Can\'t alter columns: %s:%s=>%s"' % ( | |
|
176 | modelTable, modelCol.name, databaseCol.name)) | |
|
177 | 177 | pre_command = ' meta.bind = migrate_engine' |
|
178 | 178 | |
|
179 | 179 | return ( |
@@ -181,7 +181,7 b' class ModelGenerator(object):' | |||
|
181 | 181 | '\n'.join([pre_command] + ['%s%s' % (indent, line) for line in upgradeCommands]), |
|
182 | 182 | '\n'.join([pre_command] + ['%s%s' % (indent, line) for line in downgradeCommands])) |
|
183 | 183 | |
|
184 |
def _db_can_handle_this_change(self, |
|
|
184 | def _db_can_handle_this_change(self,td): | |
|
185 | 185 | if (td.columns_missing_from_B |
|
186 | 186 | and not td.columns_missing_from_A |
|
187 | 187 | and not td.columns_different): |
@@ -207,9 +207,9 b' class ModelGenerator(object):' | |||
|
207 | 207 | dbTable = self.diff.metadataB.tables[tableName] |
|
208 | 208 | |
|
209 | 209 | td = self.diff.tables_different[tableName] |
|
210 | ||
|
210 | ||
|
211 | 211 | if self._db_can_handle_this_change(td): |
|
212 | ||
|
212 | ||
|
213 | 213 | for col in td.columns_missing_from_B: |
|
214 | 214 | modelTable.columns[col].create() |
|
215 | 215 | for col in td.columns_missing_from_A: |
@@ -4,6 +4,7 b'' | |||
|
4 | 4 | import shutil |
|
5 | 5 | import warnings |
|
6 | 6 | import logging |
|
7 | import inspect | |
|
7 | 8 | from StringIO import StringIO |
|
8 | 9 | |
|
9 | 10 | from rhodecode.lib.dbmigrate import migrate |
@@ -49,7 +50,7 b' class PythonScript(base.BaseScript):' | |||
|
49 | 50 | :returns: Upgrade / Downgrade script |
|
50 | 51 | :rtype: string |
|
51 | 52 | """ |
|
52 | ||
|
53 | ||
|
53 | 54 | if isinstance(repository, basestring): |
|
54 | 55 | # oh dear, an import cycle! |
|
55 | 56 | from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository |
@@ -65,7 +66,7 b' class PythonScript(base.BaseScript):' | |||
|
65 | 66 | excludeTables=[repository.version_table]) |
|
66 | 67 | # TODO: diff can be False (there is no difference?) |
|
67 | 68 | decls, upgradeCommands, downgradeCommands = \ |
|
68 |
genmodel.ModelGenerator(diff, |
|
|
69 | genmodel.ModelGenerator(diff,engine).toUpgradeDowngradePython() | |
|
69 | 70 | |
|
70 | 71 | # Store differences into file. |
|
71 | 72 | src = Template(opts.pop('templates_path', None)).get_script(opts.pop('templates_theme', None)) |
@@ -136,12 +137,12 b' class PythonScript(base.BaseScript):' | |||
|
136 | 137 | funcname = base.operations[op] |
|
137 | 138 | script_func = self._func(funcname) |
|
138 | 139 | |
|
139 | try: | |
|
140 | script_func(engine) | |
|
141 | except TypeError: | |
|
142 | warnings.warn("upgrade/downgrade functions must accept engine" | |
|
143 | " parameter (since version > 0.5.4)", MigrateDeprecationWarning) | |
|
144 | raise | |
|
140 | # check for old way of using engine | |
|
141 | if not inspect.getargspec(script_func)[0]: | |
|
142 | raise TypeError("upgrade/downgrade functions must accept engine" | |
|
143 | " parameter (since version 0.5.4)") | |
|
144 | ||
|
145 | script_func(engine) | |
|
145 | 146 | |
|
146 | 147 | @property |
|
147 | 148 | def module(self): |
@@ -18,6 +18,7 b' class SqlScript(base.BaseScript):' | |||
|
18 | 18 | |
|
19 | 19 | :returns: :class:`SqlScript instance <migrate.versioning.script.sql.SqlScript>`""" |
|
20 | 20 | cls.require_notfound(path) |
|
21 | ||
|
21 | 22 | src = Template(opts.pop('templates_path', None)).get_sql_script(theme=opts.pop('templates_theme', None)) |
|
22 | 23 | shutil.copy(src, path) |
|
23 | 24 | return cls(path) |
@@ -77,8 +77,7 b' def main(argv=None, **kwargs):' | |||
|
77 | 77 | %s |
|
78 | 78 | |
|
79 | 79 | Enter "%%prog help COMMAND" for information on a particular command. |
|
80 | """ % '\n\t'.join(["%s - %s" % (command.ljust(28), | |
|
81 | api.command_desc.get(command)) for command in commands]) | |
|
80 | """ % '\n\t'.join(["%s - %s" % (command.ljust(28), api.command_desc.get(command)) for command in commands]) | |
|
82 | 81 | |
|
83 | 82 | parser = PassiveOptionParser(usage=usage) |
|
84 | 83 | parser.add_option("-d", "--debug", |
@@ -80,7 +80,7 b' class Template(pathed.Pathed):' | |||
|
80 | 80 | def get_repository(self, *a, **kw): |
|
81 | 81 | """Calls self._get_item('repository', *a, **kw)""" |
|
82 | 82 | return self._get_item('repository', *a, **kw) |
|
83 | ||
|
83 | ||
|
84 | 84 | def get_script(self, *a, **kw): |
|
85 | 85 | """Calls self._get_item('script', *a, **kw)""" |
|
86 | 86 | return self._get_item('script', *a, **kw) |
General Comments 0
You need to be logged in to leave comments.
Login now