splent-cli 1.25.1__tar.gz → 1.26.0__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.
- {splent_cli-1.25.1/src/splent_cli.egg-info → splent_cli-1.26.0}/PKG-INFO +1 -1
- {splent_cli-1.25.1 → splent_cli-1.26.0}/pyproject.toml +1 -1
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/export/export_puml.py +1 -1
- splent_cli-1.26.0/src/splent_cli/commands/feature/feature_discard.py +105 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_pull.py +18 -21
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_remove.py +33 -24
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_unlock.py +17 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_upgrade.py +42 -40
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/marketplace/marketplace_index.py +27 -8
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_configure.py +1 -1
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_validate.py +0 -17
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_create.py +2 -2
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_info.py +0 -8
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_list.py +0 -13
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_utils.py +2 -3
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/marketplace.py +84 -34
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/spl_store.py +8 -82
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/feature_utils.py +41 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/lifecycle.py +1 -1
- {splent_cli-1.25.1 → splent_cli-1.26.0/src/splent_cli.egg-info}/PKG-INFO +1 -1
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli.egg-info/SOURCES.txt +0 -1
- splent_cli-1.25.1/src/splent_cli/commands/feature/feature_discard.py +0 -105
- splent_cli-1.25.1/src/splent_cli/commands/spl/spl_migrate_catalog.py +0 -180
- {splent_cli-1.25.1 → splent_cli-1.26.0}/LICENSE +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/README.md +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/setup.cfg +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/__main__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/cli.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/cache/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/cache/cache_clear.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/cache/cache_prune.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/cache/cache_size.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/cache/cache_status.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/cache/cache_usage.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/cache/cache_versions.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_contracts.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_deps.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_docker.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_env.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_features.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_github.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_infra.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_product.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_pypi.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_pyproject.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/check/check_releases.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/clear/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/clear/clear_build.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/clear/clear_log.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/clear/clear_uploads.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/command/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/command/command_create.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/coverage.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/database/db_console.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/database/db_dump.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/database/db_migrate.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/database/db_reset.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/database/db_restore.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/database/db_rollback.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/database/db_seed.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/database/db_status.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/database/db_upgrade.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/doctor.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/env/env_list.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/env/env_set.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/env/env_show.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/export/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_add.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_attach.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_clean.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_clone.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_compat.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_compile.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_contract.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_create.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_delete.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_detach.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_drift.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_env.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_fork.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_git.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_impact.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_info.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_install.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_list.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_order.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_outdated.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_pin.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_pip_install.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_refine.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_release.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_rename.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_search.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_status.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_test.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_translate.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_versions.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/feature/feature_xray.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/lint.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/locust.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/marketplace/login.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/marketplace/logout.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/marketplace/marketplace_auth_utils.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/marketplace/whoami.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_auto_require.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_build.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_clean.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_commands.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_config.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_console.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_containers.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_create.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_deploy.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_derive.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_deselect.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_down.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_drift.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_env.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_list.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_logs.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_missing.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_port.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_release.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_resolve.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_restart.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_routes.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_run.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_select.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_shell.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_signals.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_sync_template.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_test.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_up.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/release/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/release/release_core.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/release/release_resume.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/selenium.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_add_constraints.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_add_feature.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_compare.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_configurations.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_deps.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_features.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_outdated.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_pin.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_publish.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/spl/spl_remove_feature.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/tokens_setup.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/uvl/uvl_utils.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/version.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/compose.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/context.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/credentials.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/index_refresh.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/marketplace_api.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/marketplace_url.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/preflight.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/pypi_quota.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/registry.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/release.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/release_dry_run.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/services/release_gate.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/__init__.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/archetype.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/cache_utils.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/command_loader.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/contract_freshness.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/db_utils.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/decorators.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/dynamic_imports.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/feature_installer.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/forge.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/git_url.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/integrity.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/io_utils.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/manifest.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/path_utils.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/proc.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/utils/template_drift.py +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli.egg-info/dependency_links.txt +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli.egg-info/entry_points.txt +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli.egg-info/requires.txt +0 -0
- {splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: splent_cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.26.0
|
|
4
4
|
Summary: SPLENT-CLI is a CLI to be able to work on your development more easily.
|
|
5
5
|
Author-email: DiversoLab <diversolab@us.es>
|
|
6
6
|
Project-URL: Homepage, https://github.com/diverso-lab/splent_cli
|
|
@@ -788,7 +788,7 @@ def export_puml(
|
|
|
788
788
|
product = context.require_app()
|
|
789
789
|
product_dir = os.path.join(workspace, product)
|
|
790
790
|
|
|
791
|
-
# Read UVL —
|
|
791
|
+
# Read UVL — the model the product's SPL pin names first, then legacy [tool.splent.uvl]
|
|
792
792
|
import tomllib
|
|
793
793
|
|
|
794
794
|
uvl_path = None
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import click
|
|
3
|
+
import tomllib
|
|
4
|
+
from splent_cli.services import context
|
|
5
|
+
from splent_cli.utils.cache_utils import rmtree_force
|
|
6
|
+
from splent_cli.utils.feature_utils import (
|
|
7
|
+
editable_feature_dir,
|
|
8
|
+
find_feature_entries,
|
|
9
|
+
get_normalize_feature_name_in_splent_format,
|
|
10
|
+
normalize_namespace,
|
|
11
|
+
parse_feature_entry,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
DEFAULT_NAMESPACE = os.getenv("SPLENT_DEFAULT_NAMESPACE", "splent_io")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _products_declaring_editable(workspace, feature_name, ns_safe) -> list[str]:
|
|
19
|
+
"""The products in the workspace that declare the feature without a version.
|
|
20
|
+
|
|
21
|
+
Those are the ones running the editable copy, and the ones that break when
|
|
22
|
+
it goes. The match ignores how the namespace is spelled.
|
|
23
|
+
"""
|
|
24
|
+
used_in = []
|
|
25
|
+
for item in sorted(os.listdir(workspace)):
|
|
26
|
+
pyproject_path = os.path.join(workspace, item, "pyproject.toml")
|
|
27
|
+
if not os.path.isfile(pyproject_path):
|
|
28
|
+
continue
|
|
29
|
+
try:
|
|
30
|
+
with open(pyproject_path, "rb") as f:
|
|
31
|
+
data = tomllib.load(f)
|
|
32
|
+
except (OSError, tomllib.TOMLDecodeError):
|
|
33
|
+
continue
|
|
34
|
+
for _, entry in find_feature_entries(data, feature_name, namespace=ns_safe):
|
|
35
|
+
if parse_feature_entry(entry)[2] is None:
|
|
36
|
+
used_in.append(item)
|
|
37
|
+
break
|
|
38
|
+
return used_in
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@click.command(
|
|
42
|
+
"feature:discard",
|
|
43
|
+
short_help="Delete the editable copy of a feature from the workspace root (snapshots kept).",
|
|
44
|
+
)
|
|
45
|
+
@click.argument("feature_name", required=True)
|
|
46
|
+
@click.option("--namespace", default=DEFAULT_NAMESPACE, help="Feature namespace.")
|
|
47
|
+
@context.requires_product
|
|
48
|
+
def feature_discard(feature_name, namespace):
|
|
49
|
+
"""
|
|
50
|
+
Delete the editable copy of a feature, the checkout at the workspace root:
|
|
51
|
+
|
|
52
|
+
- Warns when a product in the workspace declares it without a version.
|
|
53
|
+
- Removes ONLY that checkout, never the versioned snapshots in the cache.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
workspace = str(context.workspace())
|
|
57
|
+
ns_safe = normalize_namespace(namespace)
|
|
58
|
+
feature_name = get_normalize_feature_name_in_splent_format(feature_name)
|
|
59
|
+
|
|
60
|
+
# Editable copies live at the workspace root, next to splent_cli and
|
|
61
|
+
# splent_framework. This used to look under .splent_cache/features/, where
|
|
62
|
+
# they were kept before, and so never found one.
|
|
63
|
+
editable_path = editable_feature_dir(workspace, feature_name, ns_safe)
|
|
64
|
+
|
|
65
|
+
# 1) Check if editable exists
|
|
66
|
+
if editable_path is None:
|
|
67
|
+
click.echo(
|
|
68
|
+
f"ℹ️ No editable copy of {feature_name} at the workspace root. "
|
|
69
|
+
"Nothing to discard."
|
|
70
|
+
)
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
click.echo(f"🧩 Editable feature detected at:\n {editable_path}")
|
|
74
|
+
|
|
75
|
+
# 2) Detect products using this editable feature
|
|
76
|
+
used_in = _products_declaring_editable(workspace, feature_name, ns_safe)
|
|
77
|
+
|
|
78
|
+
if used_in:
|
|
79
|
+
click.echo("⚠️ This editable feature is currently being used in:")
|
|
80
|
+
for product in used_in:
|
|
81
|
+
click.echo(f" - {product}")
|
|
82
|
+
|
|
83
|
+
if not click.confirm(
|
|
84
|
+
"Do you want to continue and break these products?", default=False
|
|
85
|
+
):
|
|
86
|
+
click.echo("🚫 Aborted. Nothing removed.")
|
|
87
|
+
raise SystemExit(1)
|
|
88
|
+
|
|
89
|
+
# 3) Delete the checkout. A copy that came out of the cache through
|
|
90
|
+
# feature:unlock may still carry read-only files, so a plain rmtree would
|
|
91
|
+
# raise PermissionError and leave a partial delete.
|
|
92
|
+
click.echo("🗑️ Removing editable feature folder...")
|
|
93
|
+
try:
|
|
94
|
+
rmtree_force(editable_path)
|
|
95
|
+
except OSError as e:
|
|
96
|
+
raise click.ClickException(
|
|
97
|
+
f"Failed to remove editable feature at {editable_path}: {e}\n"
|
|
98
|
+
"Check filesystem permissions and that no process is using the folder."
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
click.echo("✅ Editable feature removed.")
|
|
102
|
+
click.echo("🎯 All versioned snapshots preserved.")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
cli_command = feature_discard
|
|
@@ -2,21 +2,11 @@ import subprocess
|
|
|
2
2
|
import click
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from splent_cli.services import context
|
|
5
|
-
from splent_cli.utils.feature_utils import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
result = []
|
|
11
|
-
if not cache_root.exists():
|
|
12
|
-
return result
|
|
13
|
-
for ns_dir in sorted(cache_root.iterdir()):
|
|
14
|
-
if not ns_dir.is_dir():
|
|
15
|
-
continue
|
|
16
|
-
for feat_dir in sorted(ns_dir.iterdir()):
|
|
17
|
-
if feat_dir.is_dir() and "@" not in feat_dir.name:
|
|
18
|
-
result.append((ns_dir.name, feat_dir.name, feat_dir))
|
|
19
|
-
return result
|
|
5
|
+
from splent_cli.utils.feature_utils import (
|
|
6
|
+
editable_feature_dirs,
|
|
7
|
+
get_normalize_feature_name_in_splent_format,
|
|
8
|
+
normalize_namespace,
|
|
9
|
+
)
|
|
20
10
|
|
|
21
11
|
|
|
22
12
|
def _git_pull(path: Path) -> tuple:
|
|
@@ -40,25 +30,30 @@ def _git_pull(path: Path) -> tuple:
|
|
|
40
30
|
|
|
41
31
|
|
|
42
32
|
@click.command(
|
|
43
|
-
"feature:pull",
|
|
33
|
+
"feature:pull",
|
|
34
|
+
short_help="Git pull on one or all editable features at the workspace root.",
|
|
44
35
|
)
|
|
45
36
|
@click.argument("feature_ref", required=False)
|
|
46
37
|
@context.requires_product
|
|
47
38
|
def feature_pull(feature_ref):
|
|
48
39
|
"""
|
|
49
|
-
Run git pull on editable
|
|
40
|
+
Run git pull on the editable features, the checkouts at the workspace root.
|
|
50
41
|
|
|
51
42
|
\b
|
|
52
43
|
With no arguments, pulls all editable features.
|
|
53
44
|
With FEATURE_REF (e.g. splent_io/splent_feature_auth), pulls only that one.
|
|
54
45
|
"""
|
|
55
46
|
workspace = context.workspace()
|
|
56
|
-
cache_root = workspace / ".splent_cache" / "features"
|
|
57
47
|
|
|
58
|
-
|
|
48
|
+
# Editable copies live at the workspace root. This used to walk
|
|
49
|
+
# .splent_cache/features/ for directories without a version, where they
|
|
50
|
+
# were kept before, and so always found nothing.
|
|
51
|
+
all_features = [
|
|
52
|
+
(ns, name, Path(path)) for ns, name, path in editable_feature_dirs(workspace)
|
|
53
|
+
]
|
|
59
54
|
|
|
60
55
|
if not all_features:
|
|
61
|
-
click.secho("ℹ️ No editable features
|
|
56
|
+
click.secho("ℹ️ No editable features at the workspace root.", fg="yellow")
|
|
62
57
|
return
|
|
63
58
|
|
|
64
59
|
if feature_ref:
|
|
@@ -67,6 +62,7 @@ def feature_pull(feature_ref):
|
|
|
67
62
|
if "/" in feature_ref:
|
|
68
63
|
ns_filter, name_filter = feature_ref.split("/", 1)
|
|
69
64
|
ns_filter = normalize_namespace(ns_filter)
|
|
65
|
+
name_filter = get_normalize_feature_name_in_splent_format(name_filter)
|
|
70
66
|
|
|
71
67
|
targets = [
|
|
72
68
|
f
|
|
@@ -75,7 +71,8 @@ def feature_pull(feature_ref):
|
|
|
75
71
|
]
|
|
76
72
|
if not targets:
|
|
77
73
|
click.secho(
|
|
78
|
-
f"⚠️ No editable
|
|
74
|
+
f"⚠️ No editable copy of '{feature_ref}' at the workspace root.",
|
|
75
|
+
fg="yellow",
|
|
79
76
|
)
|
|
80
77
|
return
|
|
81
78
|
else:
|
|
@@ -68,30 +68,6 @@ def feature_remove(feature_name, namespace, env_scope, force):
|
|
|
68
68
|
product_path = os.path.join(workspace, product)
|
|
69
69
|
short = feature_name.replace("splent_feature_", "")
|
|
70
70
|
|
|
71
|
-
if not force:
|
|
72
|
-
# Guard: dependency check
|
|
73
|
-
dependents = get_dependents(product_path, feature_name)
|
|
74
|
-
if dependents:
|
|
75
|
-
click.secho(
|
|
76
|
-
f" Cannot remove '{short}': the following features depend on it:\n"
|
|
77
|
-
+ "".join(f" - {d}\n" for d in dependents)
|
|
78
|
-
+ " Remove those first, or use --force.",
|
|
79
|
-
fg="red",
|
|
80
|
-
)
|
|
81
|
-
raise SystemExit(1)
|
|
82
|
-
|
|
83
|
-
# Guard: migration state
|
|
84
|
-
key = feature_key(org_safe, feature_name)
|
|
85
|
-
state = get_feature_state(product_path, key)
|
|
86
|
-
if state == "migrated":
|
|
87
|
-
click.secho(
|
|
88
|
-
f" {short} has migrations applied (state: {state}).\n"
|
|
89
|
-
f" Roll them back first: splent db:rollback {feature_name} --steps 999\n"
|
|
90
|
-
f" Or use --force.",
|
|
91
|
-
fg="red",
|
|
92
|
-
)
|
|
93
|
-
raise SystemExit(1)
|
|
94
|
-
|
|
95
71
|
# ── Update pyproject.toml ─────────────────────────────────────────
|
|
96
72
|
pyproject_path = os.path.join(product_path, "pyproject.toml")
|
|
97
73
|
if not os.path.exists(pyproject_path):
|
|
@@ -105,6 +81,39 @@ def feature_remove(feature_name, namespace, env_scope, force):
|
|
|
105
81
|
# normalizes the namespace spelling (splent-io == splent_io) and ignores any
|
|
106
82
|
# pinned version, so every spelling of the entry is caught.
|
|
107
83
|
keys = (f"features_{env_scope}",) if env_scope else FEATURE_LIST_KEYS
|
|
84
|
+
declared = find_feature_entries(data, feature_name, namespace=org_safe, keys=keys)
|
|
85
|
+
|
|
86
|
+
if not force:
|
|
87
|
+
# Guard: dependency check
|
|
88
|
+
dependents = get_dependents(product_path, feature_name)
|
|
89
|
+
if dependents:
|
|
90
|
+
click.secho(
|
|
91
|
+
f" Cannot remove '{short}': the following features depend on it:\n"
|
|
92
|
+
+ "".join(f" - {d}\n" for d in dependents)
|
|
93
|
+
+ " Remove those first, or use --force.",
|
|
94
|
+
fg="red",
|
|
95
|
+
)
|
|
96
|
+
raise SystemExit(1)
|
|
97
|
+
|
|
98
|
+
# Guard: migration state. The manifest is keyed on the version, so
|
|
99
|
+
# the state is looked up under the key of each declaration about to
|
|
100
|
+
# go, plus the bare key, which is what a pinned feature removed by
|
|
101
|
+
# name alone used to be checked against, and never matched.
|
|
102
|
+
candidates = {feature_key(org_safe, feature_name)}
|
|
103
|
+
for _, entry in declared:
|
|
104
|
+
_, entry_name, entry_version = parse_feature_entry(entry)
|
|
105
|
+
candidates.add(feature_key(org_safe, entry_name, entry_version))
|
|
106
|
+
for key in sorted(candidates):
|
|
107
|
+
state = get_feature_state(product_path, key)
|
|
108
|
+
if state in ("migrated", "active"):
|
|
109
|
+
click.secho(
|
|
110
|
+
f" {short} has migrations applied (state: {state}).\n"
|
|
111
|
+
f" Roll them back first: splent db:rollback {feature_name} --steps 999\n"
|
|
112
|
+
f" Or use --force.",
|
|
113
|
+
fg="red",
|
|
114
|
+
)
|
|
115
|
+
raise SystemExit(1)
|
|
116
|
+
|
|
108
117
|
removed = drop_feature_entries(data, feature_name, namespace=org_safe, keys=keys)
|
|
109
118
|
# What survives the removal, e.g. a features entry when --dev was used.
|
|
110
119
|
remaining = find_feature_entries(data, feature_name, namespace=org_safe)
|
|
@@ -8,6 +8,7 @@ from splent_cli.utils import forge
|
|
|
8
8
|
from splent_cli.utils.cache_utils import make_feature_writable
|
|
9
9
|
from splent_cli.utils.proc import run
|
|
10
10
|
from splent_cli.utils.io_utils import load_toml, atomic_write
|
|
11
|
+
from splent_cli.utils.manifest import feature_key, remove_feature, set_feature_state
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
# =====================================================================
|
|
@@ -307,6 +308,22 @@ def _edit_one(
|
|
|
307
308
|
os.unlink(new)
|
|
308
309
|
os.symlink(rel_target, new)
|
|
309
310
|
|
|
311
|
+
# The manifest is keyed on the version. Without this the product kept
|
|
312
|
+
# reporting the feature as pinned at a version it no longer declared,
|
|
313
|
+
# and the editable copy it now runs had no record at all.
|
|
314
|
+
product = os.path.basename(product_path)
|
|
315
|
+
remove_feature(product_path, product, feature_key(ns_fs, name, version))
|
|
316
|
+
set_feature_state(
|
|
317
|
+
product_path,
|
|
318
|
+
product,
|
|
319
|
+
feature_key(ns_fs, name),
|
|
320
|
+
"declared",
|
|
321
|
+
namespace=ns_fs,
|
|
322
|
+
name=name,
|
|
323
|
+
version=None,
|
|
324
|
+
mode="editable",
|
|
325
|
+
)
|
|
326
|
+
|
|
310
327
|
# Reinstall via pip in the product's web container so the running
|
|
311
328
|
# Flask process picks up the new location without a manual restart.
|
|
312
329
|
_hot_reinstall(workspace, product_path, editable_path, name)
|
|
@@ -3,13 +3,19 @@ import tomllib
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
import click
|
|
6
|
+
import tomli_w
|
|
6
7
|
from packaging.version import Version, InvalidVersion
|
|
7
8
|
|
|
8
9
|
from splent_cli.services import context, registry
|
|
9
10
|
from splent_cli.utils.feature_utils import (
|
|
11
|
+
find_feature_entries,
|
|
10
12
|
normalize_namespace,
|
|
13
|
+
prune_feature_links,
|
|
14
|
+
read_feature_list,
|
|
11
15
|
read_features_from_data,
|
|
16
|
+
write_features_to_data,
|
|
12
17
|
)
|
|
18
|
+
from splent_cli.utils.io_utils import atomic_write, load_toml
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
# ── GitHub helpers ────────────────────────────────────────────────────────────
|
|
@@ -76,22 +82,22 @@ def _read_features(pyproject_path: Path) -> list[dict]:
|
|
|
76
82
|
return result
|
|
77
83
|
|
|
78
84
|
|
|
79
|
-
def _update_pyproject(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
):
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
)
|
|
94
|
-
pyproject_path.
|
|
85
|
+
def _update_pyproject(pyproject_path: Path, ns_fs: str, name: str, new_ver: str):
|
|
86
|
+
"""Move every declaration of the feature to *new_ver*, in place.
|
|
87
|
+
|
|
88
|
+
The entry is rewritten where it is declared, with the namespace spelled
|
|
89
|
+
the way it already is. This used to be a text replace that spelled the
|
|
90
|
+
namespace as the forge does (splent-io), while products spell it as the
|
|
91
|
+
package does (splent_io), so an editable entry never matched: the
|
|
92
|
+
symlink moved to the new version and the declaration stayed editable.
|
|
93
|
+
"""
|
|
94
|
+
data = load_toml(pyproject_path, what="pyproject.toml")
|
|
95
|
+
for key, entry in find_feature_entries(data, name, namespace=ns_fs):
|
|
96
|
+
base = entry.partition("@")[0]
|
|
97
|
+
entries = read_feature_list(data, key)
|
|
98
|
+
entries[entries.index(entry)] = f"{base}@{new_ver}"
|
|
99
|
+
write_features_to_data(data, entries, key=key)
|
|
100
|
+
atomic_write(pyproject_path, tomli_w.dumps(data))
|
|
95
101
|
|
|
96
102
|
|
|
97
103
|
# ── Cache / clone helpers ─────────────────────────────────────────────────────
|
|
@@ -118,25 +124,19 @@ def _clone_if_missing(ns_fs: str, name: str, version: str, cache_root: Path):
|
|
|
118
124
|
|
|
119
125
|
|
|
120
126
|
def _update_symlink(
|
|
121
|
-
product_path: Path,
|
|
122
|
-
ns_fs: str,
|
|
123
|
-
name: str,
|
|
124
|
-
old_ver: str | None,
|
|
125
|
-
new_ver: str,
|
|
126
|
-
cache_root: Path,
|
|
127
|
+
product_path: Path, ns_fs: str, name: str, new_ver: str, cache_root: Path
|
|
127
128
|
):
|
|
128
129
|
features_dir = product_path / "features" / ns_fs
|
|
129
130
|
features_dir.mkdir(parents=True, exist_ok=True)
|
|
130
|
-
if old_ver:
|
|
131
|
-
old_link = features_dir / f"{name}@{old_ver}"
|
|
132
|
-
if old_link.is_symlink():
|
|
133
|
-
old_link.unlink()
|
|
134
131
|
new_link = features_dir / f"{name}@{new_ver}"
|
|
135
132
|
target = cache_root / ns_fs / f"{name}@{new_ver}"
|
|
136
133
|
if new_link.is_symlink():
|
|
137
134
|
new_link.unlink()
|
|
138
135
|
rel_target = os.path.relpath(str(target), str(features_dir))
|
|
139
136
|
new_link.symlink_to(rel_target)
|
|
137
|
+
# The link the previous declaration created, name@old for a pinned
|
|
138
|
+
# feature or plain name for an editable one, and any other leftover.
|
|
139
|
+
prune_feature_links(str(product_path), ns_fs, name, keep=new_link.name)
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
# ── Command ───────────────────────────────────────────────────────────────────
|
|
@@ -244,7 +244,7 @@ def feature_upgrade(feature_ref, yes):
|
|
|
244
244
|
|
|
245
245
|
click.echo()
|
|
246
246
|
from splent_cli.utils.lifecycle import require_state
|
|
247
|
-
from splent_cli.utils.manifest import feature_key
|
|
247
|
+
from splent_cli.utils.manifest import feature_key, remove_feature, set_feature_state
|
|
248
248
|
|
|
249
249
|
for u in upgrades:
|
|
250
250
|
# Guard: cannot upgrade a feature with applied migrations
|
|
@@ -256,20 +256,22 @@ def feature_upgrade(feature_ref, yes):
|
|
|
256
256
|
|
|
257
257
|
try:
|
|
258
258
|
_clone_if_missing(u["ns_fs"], u["name"], u["latest"], cache_root)
|
|
259
|
-
_update_pyproject(
|
|
260
|
-
pyproject_path,
|
|
261
|
-
u["ns_github"],
|
|
262
|
-
u["name"],
|
|
263
|
-
u["version"],
|
|
264
|
-
u["latest"],
|
|
265
|
-
)
|
|
259
|
+
_update_pyproject(pyproject_path, u["ns_fs"], u["name"], u["latest"])
|
|
266
260
|
_update_symlink(
|
|
267
|
-
product_path,
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
261
|
+
product_path, u["ns_fs"], u["name"], u["latest"], cache_root
|
|
262
|
+
)
|
|
263
|
+
# The manifest is keyed on the version, so the old record goes
|
|
264
|
+
# and the new version starts over as declared and pinned.
|
|
265
|
+
remove_feature(str(product_path), product, key)
|
|
266
|
+
set_feature_state(
|
|
267
|
+
str(product_path),
|
|
268
|
+
product,
|
|
269
|
+
feature_key(u["ns_fs"], u["name"], u["latest"]),
|
|
270
|
+
"declared",
|
|
271
|
+
namespace=u["ns_fs"],
|
|
272
|
+
name=u["name"],
|
|
273
|
+
version=u["latest"],
|
|
274
|
+
mode="pinned",
|
|
273
275
|
)
|
|
274
276
|
click.secho(f" ✔ {u['ns_fs']}/{u['name']} → {u['latest']}", fg="green")
|
|
275
277
|
except Exception as e:
|
{splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/marketplace/marketplace_index.py
RENAMED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
marketplace:index — Build the marketplace index from the real sources.
|
|
3
3
|
|
|
4
4
|
The index is a regenerable cache: every entry derives from a feature's
|
|
5
|
-
[tool.splent.contract] (read at its latest released tag on
|
|
6
|
-
the workspace in --local mode) plus the SPL
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
hand: when in
|
|
5
|
+
[tool.splent.contract] (read at its latest released tag on the forge, or from
|
|
6
|
+
the workspace in --local mode) plus the SPL lines the marketplace publishes
|
|
7
|
+
(or the models the workspace knows, in --local mode). Publishing a feature
|
|
8
|
+
is `splent feature:release`, and publishing an SPL is `splent spl:publish`;
|
|
9
|
+
this command just picks both up. Nothing is kept in sync by hand: when in
|
|
10
|
+
doubt, rebuild.
|
|
10
11
|
"""
|
|
11
12
|
|
|
12
13
|
import os
|
|
@@ -14,7 +15,8 @@ from pathlib import Path
|
|
|
14
15
|
|
|
15
16
|
import click
|
|
16
17
|
|
|
17
|
-
from splent_cli.services import context, marketplace, registry
|
|
18
|
+
from splent_cli.services import context, marketplace, marketplace_api, registry
|
|
19
|
+
from splent_cli.services.marketplace_url import InvalidRegistryURL, resolve_registry
|
|
18
20
|
from splent_cli.utils.io_utils import load_toml
|
|
19
21
|
|
|
20
22
|
|
|
@@ -78,7 +80,9 @@ def marketplace_index(orgs, repos, registry_file, local, output, no_pypi):
|
|
|
78
80
|
The index is derived from:
|
|
79
81
|
- [tool.splent.contract] of each feature at its latest released tag
|
|
80
82
|
(or the workspace pyprojects with --local)
|
|
81
|
-
- every SPL
|
|
83
|
+
- every SPL line the marketplace publishes, at the DOI it publishes
|
|
84
|
+
(or every SPL model the workspace knows, with --local): UVL
|
|
85
|
+
structure and constraints
|
|
82
86
|
- computed relations: used_by (reverse deps) and provides collisions
|
|
83
87
|
|
|
84
88
|
\b
|
|
@@ -147,7 +151,21 @@ def marketplace_index(orgs, repos, registry_file, local, output, no_pypi):
|
|
|
147
151
|
click.secho(" Index NOT written.", fg="red")
|
|
148
152
|
raise SystemExit(1)
|
|
149
153
|
|
|
150
|
-
|
|
154
|
+
if local:
|
|
155
|
+
spls = marketplace.build_spls(workspace)
|
|
156
|
+
marketplace_url = None
|
|
157
|
+
else:
|
|
158
|
+
try:
|
|
159
|
+
marketplace_url = resolve_registry(None).url
|
|
160
|
+
click.echo(f" spls marketplace: {marketplace_url}")
|
|
161
|
+
lines = marketplace_api.MarketplaceClient(marketplace_url).list_spls()
|
|
162
|
+
except (InvalidRegistryURL, marketplace_api.MarketplaceError) as e:
|
|
163
|
+
# Same rule as the features: an index without the product lines
|
|
164
|
+
# must never overwrite a good one.
|
|
165
|
+
click.secho(f" ❌ Could not read the SPL lines. {e}", fg="red")
|
|
166
|
+
click.secho(" Index NOT written.", fg="red")
|
|
167
|
+
raise SystemExit(1)
|
|
168
|
+
spls = marketplace.build_published_spls(workspace, lines)
|
|
151
169
|
|
|
152
170
|
index = marketplace.assemble_index(
|
|
153
171
|
features,
|
|
@@ -156,6 +174,7 @@ def marketplace_index(orgs, repos, registry_file, local, output, no_pypi):
|
|
|
156
174
|
"orgs": org_list if not local else [],
|
|
157
175
|
"repos": repo_list if not local else [],
|
|
158
176
|
"workspace": local,
|
|
177
|
+
"marketplace": marketplace_url,
|
|
159
178
|
},
|
|
160
179
|
)
|
|
161
180
|
|
{splent_cli-1.25.1 → splent_cli-1.26.0}/src/splent_cli/commands/product/product_configure.py
RENAMED
|
@@ -887,7 +887,7 @@ def product_configure():
|
|
|
887
887
|
Interactive SPL feature configurator.
|
|
888
888
|
|
|
889
889
|
\b
|
|
890
|
-
Reads the
|
|
890
|
+
Reads the product's SPL model (UVL), walks the full feature tree
|
|
891
891
|
recursively, respects mandatory/optional/alternative/or/cardinality
|
|
892
892
|
group semantics, propagates constraints (including parent-chain,
|
|
893
893
|
excludes, and contrapositive), validates with Flamapy,
|
|
@@ -62,20 +62,6 @@ def _infer_parents(uvl_path: str, selected: set[str]) -> set[str]:
|
|
|
62
62
|
return extra
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
def _catalog_migration_hint(workspace):
|
|
66
|
-
"""Name the migration when the workspace still depends on splent_catalog.
|
|
67
|
-
|
|
68
|
-
Before the pin existed the catalog held every DOI, so an unmigrated
|
|
69
|
-
workspace cannot resolve any model and every phase that needs one fails
|
|
70
|
-
for the same single reason.
|
|
71
|
-
"""
|
|
72
|
-
from splent_cli.services import spl_store
|
|
73
|
-
|
|
74
|
-
if spl_store.catalog_migration_pending(workspace):
|
|
75
|
-
return spl_store.MIGRATE_HINT
|
|
76
|
-
return None
|
|
77
|
-
|
|
78
|
-
|
|
79
65
|
def _run_sat_check(workspace, app_name, data, feature_list, print_config):
|
|
80
66
|
"""Run UVL SAT check. Returns (ok, selected, universe, uvl_path)."""
|
|
81
67
|
local_uvl = _resolve_uvl_path(workspace, app_name, data)
|
|
@@ -296,9 +282,6 @@ def product_validate(feature_list, pyproject, print_config, only):
|
|
|
296
282
|
"proved either way",
|
|
297
283
|
fg="red",
|
|
298
284
|
)
|
|
299
|
-
hint = _catalog_migration_hint(workspace)
|
|
300
|
-
if hint:
|
|
301
|
-
click.secho(f" {hint}", fg="yellow")
|
|
302
285
|
failed = True
|
|
303
286
|
elif sat_ok:
|
|
304
287
|
click.secho(
|
|
@@ -40,8 +40,8 @@ def spl_create(name):
|
|
|
40
40
|
uvl_path = spl_dir / spl_store.uvl_filename(name)
|
|
41
41
|
uvl_path.write_text(f"features\n\t{name}\n", encoding="utf-8")
|
|
42
42
|
|
|
43
|
-
#
|
|
44
|
-
#
|
|
43
|
+
# The model itself is tracked here. Only the backups spl:add-feature
|
|
44
|
+
# leaves behind are noise.
|
|
45
45
|
(spl_dir / ".gitignore").write_text("*.uvl.bak\n", encoding="utf-8")
|
|
46
46
|
|
|
47
47
|
click.secho(f" SPL '{name}' created at {spl_dir}", fg="green")
|
|
@@ -78,14 +78,6 @@ def spl_info(spl_name):
|
|
|
78
78
|
)
|
|
79
79
|
else:
|
|
80
80
|
click.echo(click.style("Status : no model and no DOI", fg="red"))
|
|
81
|
-
# The DOI is very likely sitting in splent_catalog, unmigrated. Saying
|
|
82
|
-
# so here saves the reader from concluding the model is simply lost.
|
|
83
|
-
if spl_store.catalog_entry(workspace, spl_name) is not None:
|
|
84
|
-
click.secho(
|
|
85
|
-
" splent_catalog still describes it. "
|
|
86
|
-
f"{spl_store.MIGRATE_HINT}",
|
|
87
|
-
fg="yellow",
|
|
88
|
-
)
|
|
89
81
|
|
|
90
82
|
click.echo()
|
|
91
83
|
|
|
@@ -51,18 +51,5 @@ def spl_list():
|
|
|
51
51
|
click.secho(f" {' ' * width} {pin.description}", dim=True)
|
|
52
52
|
click.echo()
|
|
53
53
|
|
|
54
|
-
# A workspace that predates the pin has a splent_catalog holding every DOI
|
|
55
|
-
# and no product carrying one, so every row above reads "no model". Naming
|
|
56
|
-
# the fix here is the whole point: this is the command someone runs to find
|
|
57
|
-
# out what is wrong, and the hint used to live only behind a hard failure.
|
|
58
|
-
pending = spl_store.catalog_migration_pending(workspace)
|
|
59
|
-
if pending:
|
|
60
|
-
click.secho(
|
|
61
|
-
f" {len(pending)} of these are still described only by splent_catalog.",
|
|
62
|
-
fg="yellow",
|
|
63
|
-
)
|
|
64
|
-
click.echo(f" {spl_store.MIGRATE_HINT}")
|
|
65
|
-
click.echo()
|
|
66
|
-
|
|
67
54
|
|
|
68
55
|
cli_command = spl_list
|
|
@@ -15,9 +15,8 @@ def _resolve_spl_metadata(spl_name: str) -> dict:
|
|
|
15
15
|
"""Everything known about an SPL, in the shape metadata.toml used to have.
|
|
16
16
|
|
|
17
17
|
Kept in the old shape because callers pass it straight to
|
|
18
|
-
:func:`_fetch_uvl`. The values
|
|
19
|
-
|
|
20
|
-
and the cache, in that order.
|
|
18
|
+
:func:`_fetch_uvl`. The values are merged from the product that pins the
|
|
19
|
+
model, the working copy, and the cache, in that order.
|
|
21
20
|
"""
|
|
22
21
|
workspace = str(context.workspace())
|
|
23
22
|
pin = spl_store.read_pin(workspace, spl_name)
|