dblift 2.1.1__tar.gz → 2.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dblift-2.1.1 → dblift-2.2.1}/PKG-INFO +1 -1
- dblift-2.2.1/api/__init__.py +16 -0
- {dblift-2.1.1 → dblift-2.2.1}/api/_client_operations.py +6 -2
- {dblift-2.1.1 → dblift-2.2.1}/api/client.py +9 -5
- {dblift-2.1.1 → dblift-2.2.1}/cli/_command_handlers.py +3 -1
- {dblift-2.1.1 → dblift-2.2.1}/cli/_config_helpers.py +40 -11
- {dblift-2.1.1 → dblift-2.2.1}/cli/_output.py +2 -1
- {dblift-2.1.1 → dblift-2.2.1}/cli/_parser_setup.py +89 -5
- dblift-2.2.1/cli/commands/__init__.py +1 -0
- dblift-2.2.1/cli/commands/config_command.py +48 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/_shared.py +20 -10
- {dblift-2.1.1 → dblift-2.2.1}/cli/main.py +51 -8
- {dblift-2.1.1 → dblift-2.2.1}/config/database_config.py +3 -3
- {dblift-2.1.1 → dblift-2.2.1}/config/dblift_config.py +124 -55
- dblift-2.2.1/config/property_registry.py +135 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/secrets/_registry.py +3 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/dialect_boundary.py +9 -4
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/formatters/_formatter_impl.py +1 -3
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/formatters/htmlformatter.py +26 -14
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/base_command.py +2 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/migrate_command.py +3 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/undo_command.py +28 -258
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executor/execution_engine.py +3 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executor/migration_executor.py +1 -1
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/ui/data_collector.py +9 -15
- dblift-2.2.1/core/seams/capabilities.py +20 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/seams/event_listeners.py +3 -2
- dblift-2.2.1/core/seams/feature_loading.py +66 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/seams/introspection.py +1 -1
- dblift-2.2.1/core/seams/license_info.py +42 -0
- dblift-2.2.1/core/seams/runtime_checks.py +35 -0
- dblift-2.2.1/core/seams/sql_generators.py +42 -0
- dblift-2.2.1/core/seams/tier_resolver.py +59 -0
- dblift-2.2.1/core/sql_generator/__init__.py +42 -0
- dblift-2.2.1/core/sql_generator/alter/__init__.py +17 -0
- dblift-2.2.1/core/sql_generator/alter/alter_generator_factory.py +123 -0
- dblift-2.2.1/core/sql_generator/alter/base_alter_generator.py +169 -0
- dblift-2.2.1/core/sql_generator/alter_generator.py +64 -0
- dblift-2.2.1/core/sql_generator/base_generator.py +607 -0
- dblift-2.2.1/core/sql_generator/basic_table_ddl_generator.py +1034 -0
- dblift-2.2.1/core/sql_generator/dependency_analyzer.py +602 -0
- dblift-2.2.1/core/sql_generator/diff_converters/__init__.py +5 -0
- dblift-2.2.1/core/sql_generator/diff_converters/base_converter.py +36 -0
- dblift-2.2.1/core/sql_generator/formatter.py +112 -0
- dblift-2.2.1/core/sql_generator/generator_factory.py +188 -0
- dblift-2.2.1/core/sql_generator/options.py +59 -0
- dblift-2.2.1/core/sql_generator/script_organizer.py +307 -0
- dblift-2.2.1/core/sql_generator/sql_generator.py +50 -0
- dblift-2.2.1/core/sql_generator/sql_statement.py +5 -0
- dblift-2.2.1/core/sql_generator/table_ddl_render.py +61 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/event.py +14 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/extension.py +14 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/foreign_data_wrapper.py +12 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/foreign_server.py +14 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/index.py +14 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/package.py +14 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/procedure.py +14 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/sequence.py +21 -1
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/synonym.py +14 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/table.py +32 -61
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/trigger.py +12 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/user_defined_type.py +12 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/view.py +14 -2
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_validator/__init__.py +1 -1
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_validator/migration_validator.py +2 -2
- {dblift-2.1.1 → dblift-2.2.1}/db/base_quirks.py +22 -7
- {dblift-2.1.1 → dblift-2.2.1}/db/dml_analysis.py +1 -1
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/cosmosdb/query_executor.py +1 -1
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/quirks.py +13 -6
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/db2/schema_operations.py +10 -8
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/provider.py +14 -8
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/quirks.py +10 -5
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/quirks.py +11 -6
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/quirks.py +47 -38
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/quirks.py +13 -9
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/quirks.py +9 -5
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/quirks.py +11 -7
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/sqlalchemy_url.py +12 -1
- {dblift-2.1.1 → dblift-2.2.1}/dblift.egg-info/PKG-INFO +1 -1
- {dblift-2.1.1 → dblift-2.2.1}/dblift.egg-info/SOURCES.txt +26 -3
- {dblift-2.1.1 → dblift-2.2.1}/pyproject.toml +3 -1
- dblift-2.1.1/api/__init__.py +0 -12
- dblift-2.1.1/core/features.py +0 -123
- dblift-2.1.1/core/logger/formatters/diff_utils.py +0 -414
- dblift-2.1.1/core/normalization/data_type_normalizer.py +0 -5
- {dblift-2.1.1 → dblift-2.2.1}/LICENSE +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/README.md +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/api/_cli_support.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/api/_client_factory.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/api/_engine_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/api/async_client.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/api/events.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/api/migrations.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/api/py.typed +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/_constants.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/db_utils.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/extensions.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/baseline.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/clean.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/import_flyway.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/info.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/migrate.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/repair.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/undo.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/cli/handlers/validate.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/_credential_masking.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/_subclasses/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/_subclasses/dummy_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/_url_builder_mixin.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/config_builder.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/errors.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/secrets/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/secrets/_cache.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/secrets/_provider_base.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/secrets/_resolver.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/config/secrets/_secrets_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/constants.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/exceptions.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/_column_enricher.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/_partition_enricher.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/_schema_orchestrator.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/_utils.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/_vendor_property_applier.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/base_introspector.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/base_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/column_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/constraint_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/index_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/misc_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/procedure_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/sequence_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/table_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/trigger_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/extractors/view_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/introspector_factory.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/result.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/schema_introspector.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/vendor_queries_base.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/vendor_queries_factory.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/vendor_queries_protocols.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/introspection/version_detector.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/_base.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/_factory.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/_formatters.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/_levels.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/_multi.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/_null.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/console.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/formatters/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/formatters/factory.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/formatters/formatter.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/formatters/jsonformatter.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/log.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/logger/results.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/_type_match.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/clean_summary.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/_script_events.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/baseline_command.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/clean_command.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/import_flyway_command.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/info_command.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/repair_command.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/commands/validate_command.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/encoding.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executor/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executor/migration_helpers.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executor/placeholder_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executor/transaction_policy.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executors/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executors/base_executor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executors/executor_factory.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executors/python_executor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/executors/sql_executor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/formats/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/formats/format_detector.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/formats/migration_format.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/history/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/history/migration_history_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/journals/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/journals/migration_journal.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/migration.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/placeholders/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/placeholders/placeholder_service.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/rules/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/rules/migration_rules.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/migration_script_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/undo_script_generator/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/undo_script_generator/_ddl_reversers.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/undo_script_generator/_dml_reversers.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/undo_script_generator/_extractors.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/undo_script_generator/_generator.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/undo_script_generator/_helpers.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/undo_script_generator/_models.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/scripting/undo_script_generator/_reversers.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/sql/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/sql/execution_statement.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/sql/sql_analyzer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/sql/sql_execution_service.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/sql/statement_splitter.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/state/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/state/migration_data_service.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/state/migration_display_state.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/state/migration_formatter.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/state/migration_state.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/state/migration_state_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/state/migration_state_service.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/ui/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/ui/display_formatters.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/ui/migration_analyzer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/ui/migration_ui.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/ui/table_renderer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/migration/version_utils.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/normalization/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/normalization/dependency_resolver.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/normalization/identifier_normalizer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/normalization/object_orderer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/normalization/type_constants.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/normalization/type_mapper.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/normalization/type_mappings.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/normalization/type_normalizer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/seams/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/_base_parse_result.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/_base_sql_column.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/_base_sql_constraint.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/_base_sql_object.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/_base_sql_statement.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/base.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/constraint_validator.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/database_link.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/dialect.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/linked_server.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/module.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/partition.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/table_canonicalizer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/table_options.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_model/view_options.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/_partition_handler.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/_sqlglot_builders.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/base_statement_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/base_tokenizer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/common/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/common/base_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/dialects/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/dialects/base_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/enhanced_regex_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/hybrid_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/parser_context.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/parser_factory.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/parser_interface.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/sqlglot_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/tokens.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_parser/unified_regex_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_validator/_checksum_validator.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_validator/_flyway_compatibility.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_validator/_migration_filter.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_validator/_sql_syntax_validator.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/sql_validator/_strict_mode_validator.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/state/sql_script_formatter.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/state/sql_statement.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/utils/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/utils/database_url_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/utils/metadata_helpers.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/utils/row_access.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/utils/string_utils.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/core/utils/url_masking.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/base_provider.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/constants.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/error.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/error_handler.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/exceptions.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/native_connection_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/object_naming.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/base_history_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/base_locking_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/base_query_executor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/base_schema_operations.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/base_snapshot_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/base_undo_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/cosmosdb/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/cosmosdb/_sdk.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/cosmosdb/connection_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/cosmosdb/history_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/cosmosdb/locking_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/cosmosdb/schema_operations.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/introspection/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/parser/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/parser/cosmosdb_regex_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/plugin.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/provider.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/sdk_translator/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/sdk_translator/_executor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/sdk_translator/_executors.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/sdk_translator/_parsing.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/sdk_translator/_script_generation.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/sdk_translator/_translator.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/cosmosdb/sdk_translator/_translators.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/db2/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/db2/history_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/db2/locking_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/introspection/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/parser/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/parser/db2_regex_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/parser/parser_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/plugin.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/db2/sqlalchemy_url.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mariadb/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mariadb/plugin.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mariadb/provider.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mariadb/quirks.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/introspection/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/mysql/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/mysql/history_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/mysql/locking_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/mysql/schema_operations.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/parser/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/parser/mysql_regex_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/parser/mysql_statement_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/parser/mysql_tokenizer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/parser/parser_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/plugin.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/provider.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/mysql/sqlalchemy_url.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/introspection/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/introspection/oracle_utils.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/oracle/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/oracle/dbms_output.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/oracle/history_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/oracle/locking_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/oracle/schema_operations.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/_comments.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/_object_extractor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/_plsql_block.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/_sqlplus.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/_statement_splitter.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/oracle_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/oracle_statement_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/oracle_tokenizer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/parser_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/parser/sqlplus_context.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/plugin.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/provider.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/oracle/sqlalchemy_url.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/_provider_query_executor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/introspection/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/parser/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/parser/parser_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/parser/postgresql_regex_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/parser/postgresql_statement_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/parser/postgresql_tokenizer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/plugin.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/postgresql/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/postgresql/history_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/postgresql/locking_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/postgresql/schema_operations.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/provider.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/postgresql/sqlalchemy_url.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/introspection/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/parser/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/parser/parser_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/parser/sqlite_regex_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/plugin.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/provider.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/sqlalchemy_url.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/sqlite/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/sqlite/connection_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/sqlite/history_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/sqlite/locking_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/sqlite/query_executor.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlite/sqlite/schema_operations.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/introspection/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/parser/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/parser/parser_config.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/parser/sqlserver_regex_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/parser/sqlserver_statement_parser.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/parser/sqlserver_tokenizer.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/parser/tsql_batch_separator.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/plugin.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/provider.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/sqlserver/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/sqlserver/history_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/sqlserver/locking_manager.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/plugins/sqlserver/sqlserver/schema_operations.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/provider_capabilities.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/provider_interfaces.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/provider_registry.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/sqlalchemy_provider.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/db/value_utils.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/dblift.egg-info/dependency_links.txt +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/dblift.egg-info/entry_points.txt +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/dblift.egg-info/requires.txt +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/dblift.egg-info/top_level.txt +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/_client.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/_engine.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/apps.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/checks.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/management/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/management/commands/__init__.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/management/commands/dblift_info.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/management/commands/dblift_migrate.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/django/management/commands/dblift_validate.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/fastapi.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/flask.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/integrations/opentelemetry.py +0 -0
- {dblift-2.1.1 → dblift-2.2.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dblift
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Summary: A database migration tool that supports multiple databases with native Python drivers
|
|
5
5
|
Classifier: Development Status :: 5 - Production/Stable
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Public API for DBLift library integration.
|
|
2
|
+
|
|
3
|
+
This module provides a clean Python API for using DBLift programmatically,
|
|
4
|
+
enabling integration with IDEs, CI/CD pipelines, and other development tools.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from api.client import DBLiftClient
|
|
8
|
+
from api.events import EventEmitter, EventType
|
|
9
|
+
from api.migrations import MigrationContext
|
|
10
|
+
|
|
11
|
+
__all__ = [ # noqa: F822
|
|
12
|
+
"DBLiftClient",
|
|
13
|
+
"EventEmitter",
|
|
14
|
+
"EventType",
|
|
15
|
+
"MigrationContext",
|
|
16
|
+
]
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
"""Private operation helpers for
|
|
1
|
+
"""Private operation helpers for :mod:`api.client`.
|
|
2
|
+
|
|
3
|
+
Keep large operation bodies out of ``DBLiftClient`` so the public client class
|
|
4
|
+
stays readable while preserving the same public methods and behavior.
|
|
5
|
+
"""
|
|
2
6
|
|
|
3
7
|
from __future__ import annotations
|
|
4
8
|
|
|
@@ -19,7 +23,7 @@ def _heuristic_statement_count_from_sql(sql_text: str) -> int:
|
|
|
19
23
|
|
|
20
24
|
|
|
21
25
|
def _apply_sql_script_warning_scan(
|
|
22
|
-
result: GenerateUndoScriptResult,
|
|
26
|
+
result: Union[Any, GenerateUndoScriptResult],
|
|
23
27
|
sql_text: str,
|
|
24
28
|
) -> None:
|
|
25
29
|
"""Set manual-review flag and collect per-line warnings from generated SQL text."""
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Main client for programmatic access to DBLift."""
|
|
2
2
|
|
|
3
3
|
from functools import wraps
|
|
4
|
-
from importlib import import_module
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
from types import TracebackType
|
|
7
6
|
from typing import (
|
|
@@ -25,10 +24,7 @@ from api._client_factory import (
|
|
|
25
24
|
normalize_migrations_dirs,
|
|
26
25
|
resolve_config_or_raise,
|
|
27
26
|
)
|
|
28
|
-
from api._client_operations import
|
|
29
|
-
generate_undo_script_operation,
|
|
30
|
-
generate_undo_scripts_operation,
|
|
31
|
-
)
|
|
27
|
+
from api._client_operations import generate_undo_script_operation, generate_undo_scripts_operation
|
|
32
28
|
from api.events import EventEmitter, EventType, use_client_emitter
|
|
33
29
|
from config import DbliftConfig
|
|
34
30
|
from core.logger.results import (
|
|
@@ -44,6 +40,7 @@ from core.logger.results import (
|
|
|
44
40
|
)
|
|
45
41
|
from core.migration.executor.migration_executor import MigrationExecutor
|
|
46
42
|
from core.seams.event_listeners import attach_registered_listeners
|
|
43
|
+
from core.seams.feature_loading import load_feature_extensions
|
|
47
44
|
from db.base_provider import BaseProvider
|
|
48
45
|
from db.provider_interfaces import ConnectionProvider, TransactionalProvider
|
|
49
46
|
|
|
@@ -119,6 +116,13 @@ class DBLiftClient:
|
|
|
119
116
|
log_file: Optional log file path; omit to keep ``config`` values
|
|
120
117
|
**kwargs: Additional configuration options
|
|
121
118
|
"""
|
|
119
|
+
# Feature registrations from installed add-on packages must load for
|
|
120
|
+
# every client construction path, not just CLI startup — otherwise the
|
|
121
|
+
# runtime-check and tier-resolver seams would silently no-op for
|
|
122
|
+
# API-only usage. Idempotent (module-level once-flag), so double-loading
|
|
123
|
+
# with the CLI's own call is harmless.
|
|
124
|
+
load_feature_extensions()
|
|
125
|
+
|
|
122
126
|
# Resolve config before logger so defaults come from merged config (e.g. from file).
|
|
123
127
|
config = resolve_config_or_raise(provider, config)
|
|
124
128
|
|
|
@@ -43,7 +43,9 @@ if _builtin_conflicts:
|
|
|
43
43
|
_COMMAND_HANDLERS.update(_extension_handlers)
|
|
44
44
|
del _extension_handlers, _builtin_conflicts
|
|
45
45
|
|
|
46
|
-
_AVAILABLE_COMMANDS =
|
|
46
|
+
_AVAILABLE_COMMANDS = (
|
|
47
|
+
list(_COMMAND_HANDLERS.keys()) + ["db", "config"] + list(load_terminal_commands())
|
|
48
|
+
)
|
|
47
49
|
|
|
48
50
|
|
|
49
51
|
def execute_single_command(
|
|
@@ -35,15 +35,37 @@ _SUBCOMMAND_BOOLEAN_FLAGS = frozenset(
|
|
|
35
35
|
"--clean-disabled",
|
|
36
36
|
"--clean-enabled",
|
|
37
37
|
"--dry-run",
|
|
38
|
+
"--generate-sql",
|
|
39
|
+
"--ignore-unmanaged",
|
|
40
|
+
"--include-drops",
|
|
41
|
+
"--keep-container",
|
|
42
|
+
"--managed-only",
|
|
38
43
|
"--mark-as-executed",
|
|
44
|
+
"--no-performance",
|
|
39
45
|
"--show-sql",
|
|
46
|
+
"--rehearse-rollback",
|
|
47
|
+
"--skip-replay",
|
|
40
48
|
"--skip-validation",
|
|
49
|
+
"--skip-validate-sql",
|
|
50
|
+
"--split-by-type",
|
|
41
51
|
"--strict",
|
|
52
|
+
"--unmanaged-only",
|
|
42
53
|
"--validate-only",
|
|
43
54
|
}
|
|
44
55
|
)
|
|
45
56
|
|
|
46
57
|
|
|
58
|
+
def _command_handler_attr(command: Optional[str], attr_name: str, default: Any = None) -> Any:
|
|
59
|
+
if not command:
|
|
60
|
+
return default
|
|
61
|
+
from cli._command_handlers import _COMMAND_HANDLERS
|
|
62
|
+
|
|
63
|
+
handler = _COMMAND_HANDLERS.get(command)
|
|
64
|
+
if handler is None:
|
|
65
|
+
return default
|
|
66
|
+
return getattr(handler, attr_name, default)
|
|
67
|
+
|
|
68
|
+
|
|
47
69
|
def _extract_commands_from_argv(
|
|
48
70
|
argv_list: List[str],
|
|
49
71
|
available_commands: List[str],
|
|
@@ -257,16 +279,21 @@ def _load_and_merge_config(args: argparse.Namespace, log: Any) -> Any:
|
|
|
257
279
|
db_overrides["schema"] = args.database_schema
|
|
258
280
|
|
|
259
281
|
if db_overrides:
|
|
260
|
-
|
|
261
|
-
|
|
282
|
+
command = getattr(args, "command", None)
|
|
283
|
+
commands_list = getattr(args, "commands_list", None) or ([command] if command else [])
|
|
284
|
+
is_offline = len(commands_list) == 1 and bool(
|
|
285
|
+
_command_handler_attr(command, "_dblift_skip_secret_resolution", False)
|
|
286
|
+
)
|
|
287
|
+
if not is_offline:
|
|
288
|
+
from config.secrets._resolver import resolve_secret_refs
|
|
262
289
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
290
|
+
try:
|
|
291
|
+
db_overrides = resolve_secret_refs({"database": db_overrides}, config.secrets).get(
|
|
292
|
+
"database", db_overrides
|
|
293
|
+
)
|
|
294
|
+
except SecretsResolutionError as e:
|
|
295
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
296
|
+
sys.exit(1)
|
|
270
297
|
config.database = ConfigBuilder.merge_database_overrides(config.database, db_overrides)
|
|
271
298
|
|
|
272
299
|
if log:
|
|
@@ -321,7 +348,7 @@ def _validate_db_config(
|
|
|
321
348
|
if commands and commands[0] == "db":
|
|
322
349
|
return
|
|
323
350
|
|
|
324
|
-
migration_commands =
|
|
351
|
+
migration_commands = {
|
|
325
352
|
"migrate",
|
|
326
353
|
"undo",
|
|
327
354
|
"clean",
|
|
@@ -330,7 +357,9 @@ def _validate_db_config(
|
|
|
330
357
|
"repair",
|
|
331
358
|
"import-flyway",
|
|
332
359
|
"baseline",
|
|
333
|
-
|
|
360
|
+
}
|
|
361
|
+
if _command_handler_attr(args.command, "_dblift_validate_db_config", False):
|
|
362
|
+
migration_commands.add(args.command)
|
|
334
363
|
if args.command not in migration_commands:
|
|
335
364
|
return
|
|
336
365
|
|
|
@@ -13,7 +13,8 @@ dispatch in ``cli/main.py`` re-derive the same predicate:
|
|
|
13
13
|
else:
|
|
14
14
|
ctx.log.info(payload) # routed through ConsoleLog
|
|
15
15
|
|
|
16
|
-
That duplication has already caused
|
|
16
|
+
That duplication has already caused two regressions (PR 158 banner fix
|
|
17
|
+
+ PR-01 machine-format scope). ADR-0005 added the
|
|
17
18
|
`MACHINE_READABLE_FORMATS` set as a single source of truth; this
|
|
18
19
|
module does the same for the *routing* decision itself.
|
|
19
20
|
|
|
@@ -106,6 +106,57 @@ def _make_history_table_parent() -> argparse.ArgumentParser:
|
|
|
106
106
|
return p
|
|
107
107
|
|
|
108
108
|
|
|
109
|
+
def _add_registry_flags(parser: argparse.ArgumentParser) -> None:
|
|
110
|
+
"""Emit a --flag for every registry property that lacks one.
|
|
111
|
+
|
|
112
|
+
Skips properties that are cli_only, cli_exempt, nested (database.*), or
|
|
113
|
+
already covered by a legacy flag recorded in cli_aliases. Ensures any NEW
|
|
114
|
+
persistent property added to the registry automatically gets a CLI flag,
|
|
115
|
+
so the CLI surface can never silently drift from config/env again.
|
|
116
|
+
"""
|
|
117
|
+
from config.property_registry import PROPERTY_REGISTRY
|
|
118
|
+
|
|
119
|
+
deferred_specs = {"max_snapshots", "snapshot_table"}
|
|
120
|
+
|
|
121
|
+
# Collect option strings across the WHOLE tree (root + every subparser), not
|
|
122
|
+
# just the root parser. Many registry properties (e.g. --tags,
|
|
123
|
+
# --target-version, --snapshot-table) intentionally live only on specific
|
|
124
|
+
# subcommands; a root-only ``existing`` set would treat them as missing and
|
|
125
|
+
# emit a duplicate root flag, colliding with the subparser dest. This helper
|
|
126
|
+
# therefore runs AFTER subparsers are registered so the tree walk sees them.
|
|
127
|
+
existing: set[str] = set()
|
|
128
|
+
|
|
129
|
+
def _collect(p: argparse.ArgumentParser) -> None:
|
|
130
|
+
for action in p._actions:
|
|
131
|
+
existing.update(action.option_strings)
|
|
132
|
+
choices = getattr(action, "choices", None)
|
|
133
|
+
if isinstance(choices, dict):
|
|
134
|
+
for sub in choices.values():
|
|
135
|
+
if isinstance(sub, argparse.ArgumentParser):
|
|
136
|
+
_collect(sub)
|
|
137
|
+
|
|
138
|
+
_collect(parser)
|
|
139
|
+
for spec in PROPERTY_REGISTRY:
|
|
140
|
+
if spec.cli_only or spec.cli_exempt or "." in spec.name:
|
|
141
|
+
continue
|
|
142
|
+
if spec.name in deferred_specs:
|
|
143
|
+
continue
|
|
144
|
+
if spec.cli_aliases:
|
|
145
|
+
continue # legacy flag (e.g. --table, --strict) already provides the surface
|
|
146
|
+
if spec.cli in existing:
|
|
147
|
+
continue
|
|
148
|
+
if spec.type == "bool":
|
|
149
|
+
parser.add_argument(
|
|
150
|
+
spec.cli, dest=spec.name, action="store_true", default=None, help=spec.help
|
|
151
|
+
)
|
|
152
|
+
elif spec.type == "int":
|
|
153
|
+
parser.add_argument(spec.cli, dest=spec.name, type=int, default=None, help=spec.help)
|
|
154
|
+
elif spec.type == "float":
|
|
155
|
+
parser.add_argument(spec.cli, dest=spec.name, type=float, default=None, help=spec.help)
|
|
156
|
+
else:
|
|
157
|
+
parser.add_argument(spec.cli, dest=spec.name, default=None, help=spec.help)
|
|
158
|
+
|
|
159
|
+
|
|
109
160
|
def _make_snapshot_table_parent() -> argparse.ArgumentParser:
|
|
110
161
|
"""Parent parser for explicit snapshot storage commands."""
|
|
111
162
|
p = argparse.ArgumentParser(add_help=False)
|
|
@@ -155,7 +206,7 @@ def _make_filter_parent() -> argparse.ArgumentParser:
|
|
|
155
206
|
|
|
156
207
|
# NOTE: ``--target-version`` is intentionally NOT extracted into a parent
|
|
157
208
|
# parser. Its help text is genuinely command-specific (migrate / undo /
|
|
158
|
-
#
|
|
209
|
+
# validate each describe a different intent) and unifying it would degrade
|
|
159
210
|
# `--help` output. Each subparser adds it explicitly in
|
|
160
211
|
# ``_add_diff_and_target_options`` so the user-facing string stays
|
|
161
212
|
# accurate. See Bugbot review on PR-09.
|
|
@@ -185,13 +236,12 @@ def _add_baseline_options(baseline_parser: argparse.ArgumentParser) -> None:
|
|
|
185
236
|
|
|
186
237
|
|
|
187
238
|
def _add_diff_and_target_options(
|
|
188
|
-
diff_parser: argparse.ArgumentParser | None,
|
|
189
239
|
migrate_parser: argparse.ArgumentParser,
|
|
190
240
|
undo_parser: argparse.ArgumentParser,
|
|
191
241
|
validate_parser: argparse.ArgumentParser,
|
|
192
242
|
clean_parser: argparse.ArgumentParser,
|
|
193
243
|
) -> None:
|
|
194
|
-
"""Configure
|
|
244
|
+
"""Configure migrate/undo/validate/clean subcommand-specific options.
|
|
195
245
|
|
|
196
246
|
``--target-version`` is added per-command (rather than via a shared
|
|
197
247
|
parent parser) because each command has a meaningfully different
|
|
@@ -243,6 +293,21 @@ def _add_diff_and_target_options(
|
|
|
243
293
|
)
|
|
244
294
|
|
|
245
295
|
|
|
296
|
+
def _register_builtin_command_parsers(
|
|
297
|
+
parser: argparse.ArgumentParser,
|
|
298
|
+
) -> list[argparse.ArgumentParser]:
|
|
299
|
+
"""Register first-party command parsers that remain in the OSS CLI."""
|
|
300
|
+
subparser_actions = [
|
|
301
|
+
action for action in parser._actions if isinstance(action, argparse._SubParsersAction)
|
|
302
|
+
]
|
|
303
|
+
if not subparser_actions:
|
|
304
|
+
return []
|
|
305
|
+
|
|
306
|
+
registered: list[argparse.ArgumentParser] = []
|
|
307
|
+
|
|
308
|
+
return registered
|
|
309
|
+
|
|
310
|
+
|
|
246
311
|
def create_parser(
|
|
247
312
|
exit_on_error: bool = True, suppress_errors: bool = False
|
|
248
313
|
) -> argparse.ArgumentParser:
|
|
@@ -307,6 +372,11 @@ def create_parser(
|
|
|
307
372
|
),
|
|
308
373
|
)
|
|
309
374
|
parser.add_argument("--dry-run", action="store_true", help="Dry run mode")
|
|
375
|
+
parser.add_argument(
|
|
376
|
+
"--installed-by",
|
|
377
|
+
dest="installed_by",
|
|
378
|
+
help="Value recorded in the installed_by column (default: database username)",
|
|
379
|
+
)
|
|
310
380
|
parser.add_argument("--log-dir", default="logs", help="Log directory")
|
|
311
381
|
parser.add_argument("--log-format", default="text", help="Log format (text, json, html)")
|
|
312
382
|
parser.add_argument(
|
|
@@ -389,10 +459,10 @@ def create_parser(
|
|
|
389
459
|
default="flyway_schema_history",
|
|
390
460
|
help="Source Flyway schema history table name (default: flyway_schema_history)",
|
|
391
461
|
)
|
|
392
|
-
builtin_extension_parsers
|
|
462
|
+
builtin_extension_parsers = _register_builtin_command_parsers(parser)
|
|
393
463
|
# Configure arguments via extracted functions
|
|
394
464
|
_add_baseline_options(baseline_parser)
|
|
395
|
-
_add_diff_and_target_options(
|
|
465
|
+
_add_diff_and_target_options(migrate_parser, undo_parser, validate_parser, clean_parser)
|
|
396
466
|
# info --format option (JSON output for scripting)
|
|
397
467
|
info_parser.add_argument(
|
|
398
468
|
"--format",
|
|
@@ -404,7 +474,21 @@ def create_parser(
|
|
|
404
474
|
db_parser = subparsers.add_parser("db", help="Database utility commands")
|
|
405
475
|
db_subparsers = db_parser.add_subparsers(dest="db_command", required=True)
|
|
406
476
|
setup_db_utils_parser(db_subparsers)
|
|
477
|
+
# Configuration introspection: `dblift config --list` prints every persistent
|
|
478
|
+
# property and its three surfaces (config key / env var / CLI flag). Distinct
|
|
479
|
+
# from the global `--config <path>` option — a subcommand named ``config`` and
|
|
480
|
+
# an optional ``--config`` flag do not collide in argparse.
|
|
481
|
+
config_parser = subparsers.add_parser("config", help="Inspect dblift configuration")
|
|
482
|
+
config_parser.add_argument(
|
|
483
|
+
"--list",
|
|
484
|
+
action="store_true",
|
|
485
|
+
help="List all properties and how to set them (config key / env var / CLI flag)",
|
|
486
|
+
)
|
|
407
487
|
import_module("cli.extensions").load_command_extensions(parser)
|
|
488
|
+
# Emit registry-derived flags LAST, after every subparser (built-in and
|
|
489
|
+
# extension) is registered, so the tree walk in _add_registry_flags can see
|
|
490
|
+
# subcommand-only flags and skip them instead of shadowing them on the root.
|
|
491
|
+
_add_registry_flags(parser)
|
|
408
492
|
if suppress_errors:
|
|
409
493
|
all_subparsers = [
|
|
410
494
|
migrate_parser,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""First-party CLI command handlers that own their own dispatch."""
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""``dblift config --list`` — print every persistent property and its surfaces."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List
|
|
6
|
+
|
|
7
|
+
from config.property_registry import PROPERTY_REGISTRY, PropertySpec
|
|
8
|
+
from core.logger.console import render_records_table
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _cli_display(spec: PropertySpec) -> str:
|
|
12
|
+
"""The real CLI flag for a property: '(none)' if cli-exempt, the legacy
|
|
13
|
+
alias if one is registered, else the derived flag."""
|
|
14
|
+
if spec.cli_exempt:
|
|
15
|
+
return "(none)"
|
|
16
|
+
if spec.cli_aliases:
|
|
17
|
+
return str(spec.cli_aliases[0])
|
|
18
|
+
return spec.cli
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def build_property_table() -> List[Dict[str, str]]:
|
|
22
|
+
"""Return one row per registry property with its config key, env var, CLI flag, and default."""
|
|
23
|
+
rows: List[Dict[str, str]] = []
|
|
24
|
+
for spec in PROPERTY_REGISTRY:
|
|
25
|
+
rows.append(
|
|
26
|
+
{
|
|
27
|
+
"name": spec.name,
|
|
28
|
+
"config": spec.name,
|
|
29
|
+
"env": spec.env,
|
|
30
|
+
"cli": _cli_display(spec),
|
|
31
|
+
"default": "" if spec.default is None else str(spec.default),
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
return rows
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def run_config_command(args: Any) -> int:
|
|
38
|
+
"""Print the property/env/CLI surface table for ``dblift config --list``; return 0."""
|
|
39
|
+
rows = build_property_table()
|
|
40
|
+
table = render_records_table(
|
|
41
|
+
[("PROPERTY", "left"), ("ENV VAR", "left"), ("CLI FLAG", "left")],
|
|
42
|
+
[[r["name"], r["env"], r["cli"]] for r in rows],
|
|
43
|
+
title="dblift configuration properties",
|
|
44
|
+
)
|
|
45
|
+
print(
|
|
46
|
+
table
|
|
47
|
+
) # lint: allow-print config --list self-documentation (pre-CommandOutput short-circuit)
|
|
48
|
+
return 0
|
|
@@ -12,11 +12,9 @@ from dataclasses import dataclass, field
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import Any, Dict, List, Optional
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
# SQL files when scanning a directory (e.g. leftover temp files, schema
|
|
19
|
-
# dumps) so only intentional migration scripts are
|
|
15
|
+
# Flyway-compatible migration filename patterns — used by SQL-file validation to
|
|
16
|
+
# skip non-migration SQL files when scanning a directory (e.g. leftover
|
|
17
|
+
# temp files, schema dumps) so only intentional migration scripts are
|
|
20
18
|
# checked. Explicitly-listed files are always validated regardless of name.
|
|
21
19
|
_MIGRATION_FILENAME_RE = re.compile(
|
|
22
20
|
r"^[VRUBvrub][\d_.]*__.*\.sql$",
|
|
@@ -61,9 +59,21 @@ class CliCommandContext:
|
|
|
61
59
|
# Migration configuration
|
|
62
60
|
placeholders: Dict[str, Any] = field(default_factory=dict)
|
|
63
61
|
dir_recursive_map: Dict[Path, bool] = field(default_factory=dict)
|
|
64
|
-
# License tier for feature-level gates.
|
|
65
|
-
#
|
|
66
|
-
|
|
62
|
+
# License tier for feature-level gates. Opaque to OSS (see
|
|
63
|
+
# core.seams.tier_resolver) — execute_single_command supplies the real
|
|
64
|
+
# CLI-resolved tier; paid-tier handler tests must pass their own tier
|
|
65
|
+
# explicitly since OSS no longer has a permissive default to fall back on.
|
|
66
|
+
license_tier: Any = None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class ConfigOnlyClient:
|
|
71
|
+
"""Config-only stand-in for commands that do not need a live provider."""
|
|
72
|
+
|
|
73
|
+
config: Any
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
ValidateSqlConfigClient = ConfigOnlyClient
|
|
67
77
|
|
|
68
78
|
|
|
69
79
|
def _set_command_completed(log: Any, result: Any, command_type: str) -> None:
|
|
@@ -92,7 +102,7 @@ def emit_rendered_output(
|
|
|
92
102
|
) -> None:
|
|
93
103
|
"""Dispatch a rendered command output to machine channel, logger, and/or file.
|
|
94
104
|
|
|
95
|
-
|
|
105
|
+
Shared by extension report handlers that follow the same machine/human/file
|
|
96
106
|
dispatch pattern once the command-specific rendering is done.
|
|
97
107
|
"""
|
|
98
108
|
if command_output.is_machine_format:
|
|
@@ -111,7 +121,7 @@ def emit_rendered_output(
|
|
|
111
121
|
|
|
112
122
|
|
|
113
123
|
def _extract_version_filters(args: Any) -> tuple[Any, Any, Any, Any, Any]:
|
|
114
|
-
"""Extract version/tag filter arguments common to
|
|
124
|
+
"""Extract version/tag filter arguments common to filtered migration handlers.
|
|
115
125
|
|
|
116
126
|
Returns:
|
|
117
127
|
Tuple (target_version, versions, exclude_versions, tags, exclude_tags),
|
|
@@ -50,13 +50,9 @@ from cli._config_helpers import ( # noqa: F401
|
|
|
50
50
|
_validate_log_format_for_cli,
|
|
51
51
|
)
|
|
52
52
|
from cli._output import CommandOutput, from_args
|
|
53
|
-
from cli._parser_setup import
|
|
54
|
-
_add_baseline_options,
|
|
55
|
-
_add_diff_and_target_options,
|
|
56
|
-
create_parser,
|
|
57
|
-
parse_with_selective_errors,
|
|
58
|
-
)
|
|
53
|
+
from cli._parser_setup import create_parser, parse_with_selective_errors
|
|
59
54
|
from cli.extensions import load_terminal_commands
|
|
55
|
+
from core.seams.feature_loading import load_feature_extensions
|
|
60
56
|
|
|
61
57
|
# Module-level placeholder; main() uses a local 'log' variable (no global declaration)
|
|
62
58
|
log = None
|
|
@@ -102,6 +98,13 @@ _GLOBAL_ONLY_ARGS: List[str] = [
|
|
|
102
98
|
"--quiet",
|
|
103
99
|
"-q",
|
|
104
100
|
"--no-progress",
|
|
101
|
+
# Root-only value flags. They live only on the root parser, so — like the
|
|
102
|
+
# other root-only value flags above — they must be classified global or the
|
|
103
|
+
# argv preprocessor relocates them past the subcommand token and the
|
|
104
|
+
# subparser rejects them as "unrecognized arguments". Covered by
|
|
105
|
+
# tests/unit/cli/test_global_only_args_completeness.py.
|
|
106
|
+
"--installed-by",
|
|
107
|
+
"--max-snapshots",
|
|
105
108
|
]
|
|
106
109
|
|
|
107
110
|
# Tool-level flag aliases for subcommands that take their own version-like
|
|
@@ -154,6 +157,7 @@ def main() -> None:
|
|
|
154
157
|
from core.logger.console import install_rich_traceback
|
|
155
158
|
|
|
156
159
|
install_rich_traceback()
|
|
160
|
+
load_feature_extensions()
|
|
157
161
|
|
|
158
162
|
ctx = _parse_argv_and_load_config(sys.argv[1:])
|
|
159
163
|
command_output = _setup_logging_and_output(ctx)
|
|
@@ -227,12 +231,22 @@ def _parse_argv_and_load_config(argv: List[str]) -> _CliContext:
|
|
|
227
231
|
if not commands and hasattr(args, "command"):
|
|
228
232
|
commands = [args.command]
|
|
229
233
|
|
|
234
|
+
# `dblift config --list` is offline self-documentation: it reads only the
|
|
235
|
+
# property registry, so it short-circuits here — before any config/db load —
|
|
236
|
+
# exactly like the `db` subcommand path below. Listing is the command's only
|
|
237
|
+
# behaviour today, so it runs whether or not --list was passed.
|
|
238
|
+
if commands and commands[0] == "config":
|
|
239
|
+
from cli.commands.config_command import run_config_command
|
|
240
|
+
|
|
241
|
+
sys.exit(run_config_command(args))
|
|
242
|
+
|
|
230
243
|
log = LogFactory.get_log("Dblift")
|
|
231
244
|
parser = create_parser()
|
|
232
245
|
# Validate log format before any config load so bogus --log-format fails with argparse
|
|
233
246
|
# UX (and so db/* commands are covered — _validate_db_config skips early for "db").
|
|
234
247
|
_validate_log_format_for_cli(args, parser)
|
|
235
|
-
# Attach the full command list so
|
|
248
|
+
# Attach the full command list so config loading can distinguish
|
|
249
|
+
# single-command config-only flows from chained invocations.
|
|
236
250
|
args.commands_list = commands
|
|
237
251
|
config = None if commands[0] == "db" else _load_and_merge_config(args, log)
|
|
238
252
|
_validate_db_config(args, config, parser, commands)
|
|
@@ -258,6 +272,15 @@ def _build_terminal_args(
|
|
|
258
272
|
return args
|
|
259
273
|
|
|
260
274
|
|
|
275
|
+
def _command_handler_attr(command: Optional[str], attr_name: str, default: Any = None) -> Any:
|
|
276
|
+
if not command:
|
|
277
|
+
return default
|
|
278
|
+
handler = _COMMAND_HANDLERS.get(command)
|
|
279
|
+
if handler is None:
|
|
280
|
+
return default
|
|
281
|
+
return getattr(handler, attr_name, default)
|
|
282
|
+
|
|
283
|
+
|
|
261
284
|
def _setup_logging_and_output(ctx: _CliContext) -> CommandOutput:
|
|
262
285
|
"""Phase 3: configure logging, build :class:`CommandOutput`.
|
|
263
286
|
|
|
@@ -287,12 +310,26 @@ def _setup_logging_and_output(ctx: _CliContext) -> CommandOutput:
|
|
|
287
310
|
assert ctx.config is not None
|
|
288
311
|
ctx.log = _configure_logging(ctx.args, ctx.config, ctx.parser)
|
|
289
312
|
|
|
313
|
+
_apply_configured_output_format(ctx)
|
|
314
|
+
|
|
290
315
|
# Banner routing is centralised in :class:`cli._output.CommandOutput`
|
|
291
316
|
# (ADR-0008 supersedes ADR-0005's suppression approach). Machine
|
|
292
317
|
# mode routes the banner to stderr; human mode keeps it on stdout.
|
|
293
318
|
return from_args(ctx.args)
|
|
294
319
|
|
|
295
320
|
|
|
321
|
+
def _apply_configured_output_format(ctx: _CliContext) -> None:
|
|
322
|
+
"""Use handler-provided config defaults before top-level banner routing."""
|
|
323
|
+
if len(ctx.commands) != 1 or getattr(ctx.args, "format", None):
|
|
324
|
+
return
|
|
325
|
+
resolver = _command_handler_attr(ctx.commands[0], "_dblift_configured_output_format")
|
|
326
|
+
if not callable(resolver):
|
|
327
|
+
return
|
|
328
|
+
output_format = resolver(ctx.args, ctx.config)
|
|
329
|
+
if output_format:
|
|
330
|
+
ctx.args.format = output_format
|
|
331
|
+
|
|
332
|
+
|
|
296
333
|
def _dispatch_command(ctx: _CliContext, command_output: CommandOutput) -> int:
|
|
297
334
|
"""Phase 4: build full workflow context and run the command loop.
|
|
298
335
|
|
|
@@ -316,7 +353,6 @@ def _dispatch_command(ctx: _CliContext, command_output: CommandOutput) -> int:
|
|
|
316
353
|
ctx.log.debug(f"Using placeholders: {placeholders}")
|
|
317
354
|
|
|
318
355
|
ctx.config.journal_enabled = True
|
|
319
|
-
ctx.config.journal_dir = None
|
|
320
356
|
if getattr(ctx.args, "strict", False):
|
|
321
357
|
ctx.config.strict_mode = True
|
|
322
358
|
ctx.log.info(
|
|
@@ -344,6 +380,13 @@ def _dispatch_command(ctx: _CliContext, command_output: CommandOutput) -> int:
|
|
|
344
380
|
# in base_command does not re-emit it (it also has no format awareness).
|
|
345
381
|
if main_header:
|
|
346
382
|
base_command._console_main_header_printed = True # type: ignore[attr-defined]
|
|
383
|
+
for command in ctx.commands:
|
|
384
|
+
handler = _COMMAND_HANDLERS.get(command)
|
|
385
|
+
if handler is None:
|
|
386
|
+
continue
|
|
387
|
+
command_module = sys.modules.get(handler.__module__)
|
|
388
|
+
if command_module is not None:
|
|
389
|
+
command_module._console_main_header_printed = True # type: ignore[attr-defined]
|
|
347
390
|
|
|
348
391
|
for cmd_index, command in enumerate(ctx.commands):
|
|
349
392
|
if len(ctx.commands) > 1 and cmd_index > 0:
|
|
@@ -199,9 +199,9 @@ def _apply_url_overrides(cls: Type["BaseDatabaseConfig"], data: Dict[str, Any])
|
|
|
199
199
|
if url_lower.startswith("jdbc:"):
|
|
200
200
|
raise ValueError("Legacy database URLs are no longer supported; use a SQLAlchemy URL")
|
|
201
201
|
# _allow_incomplete is set when the URL could not be parsed (e.g. an
|
|
202
|
-
# unresolved secret URI in offline mode). Skip hydration/inference so
|
|
203
|
-
#
|
|
204
|
-
# is opened.
|
|
202
|
+
# unresolved secret URI in offline mode). Skip hydration/inference so that
|
|
203
|
+
# `dblift plan` with `database.url: vault://...` doesn't mutate fields from
|
|
204
|
+
# the secret URI before a connection is opened.
|
|
205
205
|
if data.get("_allow_incomplete"):
|
|
206
206
|
return
|
|
207
207
|
if ProviderRegistry.is_native_dialect(db_type):
|