lean-runtime 4.30.0__tar.gz → 4.33.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.
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/CHANGELOG.md +25 -2
- {lean_runtime-4.30.0/lean_runtime.egg-info → lean_runtime-4.33.0}/PKG-INFO +1 -1
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/bundles.py +127 -9
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/capsules.py +50 -9
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/cli.py +3 -3
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/console.py +37 -6
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/declaration_index_build.py +32 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/declaration_index_oci.py +38 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/events.py +22 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/packs.py +57 -42
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/programs.py +33 -3
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/progress.py +70 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/project_execution.py +6 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/projects.py +8 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/runtime.py +77 -42
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/store.py +139 -26
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/toolchain_oci.py +28 -2
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/toolchain_slim.py +49 -20
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/toolchains.py +18 -9
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/verification.py +67 -37
- {lean_runtime-4.30.0 → lean_runtime-4.33.0/lean_runtime.egg-info}/PKG-INFO +1 -1
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime.egg-info/SOURCES.txt +1 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/pyproject.toml +1 -1
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_progress.py +7 -1
- lean_runtime-4.33.0/tests/test_progress_counted.py +155 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/LICENSE +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/MANIFEST.in +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/README.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/environments.toml +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/core-v4.32.2.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/leancert-v4.30.0.5.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/leancert-v4.31.0.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/leancert-v4.32.2.4.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/leancert-v4.33.0.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/mathlib-v4.30.0.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/mathlib-v4.31.0.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/mathlib-v4.32.2.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/mathlib-v4.33.0.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/catalog/locks/mathlib-v4.33.1.lock.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/compatibility/README.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/compatibility/lake-artifact-cache-4.33.0.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/compatibility/mathlib-4.32.2.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/compatibility/mathlib-4.32.2.toml +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/compatibility/mathlib-4.33.0.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/compatibility/mathlib-4.33.0.toml +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/concepts/context-selection.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/index.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/reference/commands.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/reference/python-advanced.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/reference/python-api.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/reference/storage.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/trust.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/tutorial.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/workflows/check-files.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/docs/workflows/lake-projects.md +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/examples/mathlib.toml +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/__init__.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/__main__.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/_git.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/_paths.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/backends.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/comparison.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/context_resolution.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/decisions.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/declaration_index.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/diagnostics.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/__init__.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/analyzer.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/api.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/candidate.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/catalog.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/catalog_build.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/catalog_cli.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/catalog_manifest.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/data/catalog.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/defaults.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/engine.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/errors.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/history.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/memo.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/module_inventory.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/planner.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/policy.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/probe.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/py.typed +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/result.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/schema_resources.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/schemas/catalog-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/schemas/plan-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/discovery/schemas/result-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/environments.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/errors.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/facade.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/frontmatter.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/header_cache.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/health.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/identifier_resolver.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/import_syntax.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/lake.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/lake_cache.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/lockfiles.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/locking.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/matrix.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/models.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/oci.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/oci_protocol.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/package_ids.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/policies.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/profiling.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/project_sharing.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/publisher_verification.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/py.typed +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/references.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/resolver.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/run_cli.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/schema_resources.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/serialization.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/shared_projects.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/specs.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/timings.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime/wire.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime.egg-info/dependency_links.txt +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime.egg-info/entry_points.txt +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime.egg-info/requires.txt +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/lean_runtime.egg-info/top_level.txt +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/mkdocs.yml +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/attestation-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/check-batch-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/cleanup-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/comparison-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/execution-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/inspect-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/matrix-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/plan-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/profile-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/publication-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/status-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/schemas/verify-v1.schema.json +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/scripts/announcement_gate.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/scripts/catalog_update.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/scripts/lake_cache_gate.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/scripts/prepare_declaration_index.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/scripts/publish_declaration_index.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/scripts/registry_preflight.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/scripts/run_compatibility.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/scripts/run_v1_case_study.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/scripts/smoke_wheel.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/setup.cfg +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/conftest.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/discovery/e2e/test_real_discovery.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/discovery/test_analyzer.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/discovery/test_catalog.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/discovery/test_catalog_build.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/discovery/test_discovery_schema_resources.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/discovery/test_engine.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/discovery/test_memo.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/discovery/test_planner.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/discovery/test_policy.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_announcement_gate.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_backend.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_bundles.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_capsules.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_cli.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_console.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_context_resolution.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_declaration_index.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_diagnostics.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_environment_integration.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_events_health.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_facade.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_frontmatter.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_git.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_header_cache.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_identifier_resolver.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_interactive.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_lake_cache.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_lockfiles.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_locking.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_models.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_multifile.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_oci_protocol.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_package_ids.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_packs.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_paths.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_prebuilt_policy.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_programs.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_project_bootstrap.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_project_publish.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_projects.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_references.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_run_cli.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_runtime.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_schema_resources.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_schemas.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_signatures.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_specs.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_store.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_toolchain_oci.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_toolchain_slim.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_toolchains.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_v1_precision.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_verification_inventory.py +0 -0
- {lean_runtime-4.30.0 → lean_runtime-4.33.0}/tests/test_verification_probe.py +0 -0
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 4.33.0 - 2026-08-27
|
|
6
|
+
|
|
7
|
+
- Cover the remaining silent phases with progress. Elan bootstrap and
|
|
8
|
+
`elan toolchain install`, and the `lake init`/`lake update` behind `new`, now
|
|
9
|
+
stream their output as `process.progress`/`process.output` like every other
|
|
10
|
+
subprocess. Long pure-Python loops report counted progress that renders as a
|
|
11
|
+
bar: `verification.inventory` (hashing build artifacts in `verify`),
|
|
12
|
+
`bundle.tree_inventory` (`env export`/`import`), `source.snapshot_digest`
|
|
13
|
+
(source fingerprints, including path dependencies during `adopt`), and
|
|
14
|
+
`capsule.import_parse`. The publish preflight fetch
|
|
15
|
+
(`publish.remote_probe_started`) and the Lake configuration read behind
|
|
16
|
+
project-wide `check` (`project.config_translate_started`) announce
|
|
17
|
+
themselves. Any event carrying `current`/`total` and a `label` now renders as
|
|
18
|
+
a counted bar without a dedicated console handler, and deep helpers reach
|
|
19
|
+
the active runtime's emitter through `lean_runtime.events.current()`.
|
|
20
|
+
- Re-running `adopt` over a tree no longer re-probes every already attached
|
|
21
|
+
project (a Lake graph load each, up to two minutes for Mathlib); the plan
|
|
22
|
+
already reports them as attached and `verify` re-checks links. Attachment
|
|
23
|
+
now announces `adopt.attach_started` per project, rendered as
|
|
24
|
+
`Attaching projects [bar] i/n`, and the pre-swap Lake graph probe streams its
|
|
25
|
+
output like every other Lake invocation instead of running silently.
|
|
26
|
+
|
|
5
27
|
## 4.30.0 - 2026-08-26
|
|
6
28
|
|
|
7
29
|
- Attach shared dependencies on Windows without administrator rights. Creating
|
|
@@ -29,8 +51,9 @@
|
|
|
29
51
|
`project.detach.package_started` for each package `unshare` materializes; all
|
|
30
52
|
carry `current`/`total` and render as the same counted bar.
|
|
31
53
|
- Keep the terminal alive during any silent stretch: when no event has arrived
|
|
32
|
-
for two seconds the console shows `⋯
|
|
33
|
-
logs print `Still working
|
|
54
|
+
for two seconds the console shows `⋯ no new events for Ns · last: <activity>`
|
|
55
|
+
in place; plain logs print `Still working (…)` after ten seconds and then
|
|
56
|
+
every thirty.
|
|
34
57
|
- Name new shared package directories `pkg_<32 hex>` instead of
|
|
35
58
|
`project_package_<64 hex>`. The 80-character name pushed Mathlib's deepest
|
|
36
59
|
build outputs past Windows' 260-character path limit, so an adopted Mathlib
|
|
@@ -13,10 +13,11 @@ import tarfile
|
|
|
13
13
|
import tempfile
|
|
14
14
|
import uuid
|
|
15
15
|
from collections.abc import Iterable, Mapping, Sequence
|
|
16
|
+
from contextlib import nullcontext
|
|
16
17
|
from dataclasses import dataclass
|
|
17
18
|
from datetime import datetime, timezone
|
|
18
19
|
from pathlib import Path, PurePosixPath
|
|
19
|
-
from typing import Any
|
|
20
|
+
from typing import Any, Protocol
|
|
20
21
|
|
|
21
22
|
import zstandard
|
|
22
23
|
|
|
@@ -33,7 +34,7 @@ from .capsules import (
|
|
|
33
34
|
setup_artifact_groups,
|
|
34
35
|
)
|
|
35
36
|
from .errors import EnvironmentError
|
|
36
|
-
from .events import EventEmitter
|
|
37
|
+
from .events import EventEmitter, current
|
|
37
38
|
from .lake import ROOT_MODULE
|
|
38
39
|
from .lockfiles import EnvironmentLock, LockedPackage
|
|
39
40
|
from .locking import FileLock
|
|
@@ -61,6 +62,7 @@ from .packs import (
|
|
|
61
62
|
unpack_frame,
|
|
62
63
|
)
|
|
63
64
|
from .policies import ExecutionPolicy
|
|
65
|
+
from .progress import CountedProgress
|
|
64
66
|
from .serialization import canonical_json_bytes, write_json_atomic
|
|
65
67
|
from .store import (
|
|
66
68
|
EnvironmentStore,
|
|
@@ -81,6 +83,53 @@ SOURCE_TREE_INVENTORY = ".lean-runtime-source-tree.json"
|
|
|
81
83
|
MAX_CAPSULE_CONFIG_BYTES = 64 * 1024**2
|
|
82
84
|
|
|
83
85
|
|
|
86
|
+
class _BinaryReader(Protocol):
|
|
87
|
+
def read(self, size: int = -1) -> bytes: ...
|
|
88
|
+
|
|
89
|
+
def readinto(self, buffer: Any) -> int | None: ...
|
|
90
|
+
|
|
91
|
+
def seek(self, offset: int, whence: int = 0) -> int: ...
|
|
92
|
+
|
|
93
|
+
def tell(self) -> int: ...
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class _ProgressReader:
|
|
97
|
+
"""Report bytes after a consumer has actually read them."""
|
|
98
|
+
|
|
99
|
+
def __init__(
|
|
100
|
+
self, handle: _BinaryReader, progress: CountedProgress, *, offset: int = 0
|
|
101
|
+
) -> None:
|
|
102
|
+
self._handle = handle
|
|
103
|
+
self._progress = progress
|
|
104
|
+
self._offset = offset
|
|
105
|
+
self._furthest = offset
|
|
106
|
+
|
|
107
|
+
def _report(self) -> None:
|
|
108
|
+
position = self._offset + self._handle.tell()
|
|
109
|
+
if position > self._furthest:
|
|
110
|
+
self._furthest = position
|
|
111
|
+
self._progress.advance(to=position)
|
|
112
|
+
|
|
113
|
+
def read(self, size: int = -1) -> bytes:
|
|
114
|
+
data = self._handle.read(size)
|
|
115
|
+
self._report()
|
|
116
|
+
return data
|
|
117
|
+
|
|
118
|
+
def readinto(self, buffer: Any) -> int:
|
|
119
|
+
count = self._handle.readinto(buffer)
|
|
120
|
+
self._report()
|
|
121
|
+
return count if count is not None else 0
|
|
122
|
+
|
|
123
|
+
def seek(self, offset: int, whence: int = 0) -> int:
|
|
124
|
+
return self._handle.seek(offset, whence)
|
|
125
|
+
|
|
126
|
+
def tell(self) -> int:
|
|
127
|
+
return self._handle.tell()
|
|
128
|
+
|
|
129
|
+
def __getattr__(self, name: str) -> Any:
|
|
130
|
+
return getattr(self._handle, name)
|
|
131
|
+
|
|
132
|
+
|
|
84
133
|
@dataclass(frozen=True, slots=True)
|
|
85
134
|
class PortableCopyInfo:
|
|
86
135
|
environment_id: str
|
|
@@ -130,8 +179,27 @@ def _tree_entries(
|
|
|
130
179
|
excluded_names: frozenset[str] = frozenset(),
|
|
131
180
|
omit_volatile_build_metadata: bool = False,
|
|
132
181
|
) -> Iterable[tuple[Path, str]]:
|
|
133
|
-
|
|
182
|
+
scan = CountedProgress(
|
|
183
|
+
current().emit,
|
|
184
|
+
"bundle.tree_scan",
|
|
185
|
+
f"Scanning {root.name}",
|
|
186
|
+
1,
|
|
187
|
+
phase="bundle",
|
|
188
|
+
)
|
|
189
|
+
scan.start()
|
|
190
|
+
paths = sorted(root.rglob("*"), key=lambda value: value.relative_to(root).as_posix())
|
|
191
|
+
scan.advance(f"{len(paths)} entries")
|
|
192
|
+
progress = CountedProgress(
|
|
193
|
+
current().emit,
|
|
194
|
+
"bundle.tree_inventory",
|
|
195
|
+
f"Inventorying {root.name}",
|
|
196
|
+
len(paths),
|
|
197
|
+
phase="bundle",
|
|
198
|
+
)
|
|
199
|
+
progress.start()
|
|
200
|
+
for path in paths:
|
|
134
201
|
if excluded is not None and (path == excluded or excluded in path.parents):
|
|
202
|
+
progress.advance(path.relative_to(root).as_posix())
|
|
135
203
|
continue
|
|
136
204
|
relative = path.relative_to(root)
|
|
137
205
|
if relative.parts and relative.parts[0] in excluded_names:
|
|
@@ -145,8 +213,10 @@ def _tree_entries(
|
|
|
145
213
|
or relative.name.endswith(".rsp")
|
|
146
214
|
)
|
|
147
215
|
):
|
|
216
|
+
progress.advance(relative.as_posix())
|
|
148
217
|
continue
|
|
149
218
|
yield path, relative.as_posix()
|
|
219
|
+
progress.advance(relative.as_posix())
|
|
150
220
|
|
|
151
221
|
|
|
152
222
|
def _write_tar_gzip(
|
|
@@ -219,6 +289,18 @@ def _oci_archive(entries: dict[str, bytes]) -> bytes:
|
|
|
219
289
|
|
|
220
290
|
|
|
221
291
|
def _write_oci_archive(entries: dict[str, Path], output: Path) -> None:
|
|
292
|
+
ordered = sorted(entries.items())
|
|
293
|
+
total = sum(path.stat().st_size for _name, path in ordered)
|
|
294
|
+
progress = CountedProgress(
|
|
295
|
+
current().emit,
|
|
296
|
+
"bundle.archive_write",
|
|
297
|
+
"Writing portable archive",
|
|
298
|
+
total,
|
|
299
|
+
phase="bundle",
|
|
300
|
+
unit="bytes",
|
|
301
|
+
)
|
|
302
|
+
progress.start()
|
|
303
|
+
written = 0
|
|
222
304
|
with (
|
|
223
305
|
output.open("wb") as raw_output,
|
|
224
306
|
gzip.GzipFile(
|
|
@@ -226,11 +308,13 @@ def _write_oci_archive(entries: dict[str, Path], output: Path) -> None:
|
|
|
226
308
|
) as compressed,
|
|
227
309
|
tarfile.open(fileobj=compressed, mode="w|", format=tarfile.PAX_FORMAT) as archive,
|
|
228
310
|
):
|
|
229
|
-
for name, path in
|
|
311
|
+
for name, path in ordered:
|
|
230
312
|
info = _normalized_info(name, mode=0o644)
|
|
231
313
|
info.size = path.stat().st_size
|
|
232
314
|
with path.open("rb") as handle:
|
|
233
|
-
archive.addfile(info, handle)
|
|
315
|
+
archive.addfile(info, _ProgressReader(handle, progress, offset=written))
|
|
316
|
+
written += info.size
|
|
317
|
+
progress.advance(name, to=written)
|
|
234
318
|
|
|
235
319
|
|
|
236
320
|
def _safe_name(name: str) -> PurePosixPath:
|
|
@@ -315,16 +399,32 @@ def _extract_layer(data: bytes | Path, destination: Path) -> None:
|
|
|
315
399
|
if destination.is_symlink():
|
|
316
400
|
raise EnvironmentError("bundle extraction destination must not be a symlink")
|
|
317
401
|
destination.mkdir(parents=True, exist_ok=True)
|
|
402
|
+
progress: CountedProgress | None = None
|
|
403
|
+
raw_handle: Any = None
|
|
318
404
|
try:
|
|
319
405
|
if isinstance(data, Path):
|
|
320
|
-
|
|
406
|
+
raw_handle = data.open("rb")
|
|
407
|
+
progress = CountedProgress(
|
|
408
|
+
current().emit,
|
|
409
|
+
"bundle.layer_extract",
|
|
410
|
+
f"Extracting {destination.name}",
|
|
411
|
+
data.stat().st_size,
|
|
412
|
+
phase="bundle",
|
|
413
|
+
unit="bytes",
|
|
414
|
+
)
|
|
415
|
+
progress.start()
|
|
416
|
+
archive = tarfile.open( # noqa: SIM115
|
|
417
|
+
fileobj=_ProgressReader(raw_handle, progress), mode="r:gz"
|
|
418
|
+
)
|
|
321
419
|
else:
|
|
322
420
|
archive = tarfile.open( # noqa: SIM115
|
|
323
421
|
fileobj=io.BytesIO(data), mode="r:gz"
|
|
324
422
|
)
|
|
325
423
|
except (tarfile.TarError, OSError) as exc:
|
|
424
|
+
if raw_handle is not None:
|
|
425
|
+
raw_handle.close()
|
|
326
426
|
raise EnvironmentError("bundle layer is not a valid gzip tar archive") from exc
|
|
327
|
-
with archive:
|
|
427
|
+
with archive, raw_handle if raw_handle is not None else nullcontext():
|
|
328
428
|
for member in archive:
|
|
329
429
|
count += 1
|
|
330
430
|
total += member.size
|
|
@@ -353,6 +453,8 @@ def _extract_layer(data: bytes | Path, destination: Path) -> None:
|
|
|
353
453
|
target.symlink_to(member.linkname)
|
|
354
454
|
else:
|
|
355
455
|
raise EnvironmentError(f"unsupported bundle member: {member.name!r}")
|
|
456
|
+
if progress is not None:
|
|
457
|
+
progress.advance(to=progress.total)
|
|
356
458
|
|
|
357
459
|
|
|
358
460
|
def _git_object_id(kind: str, data: bytes) -> str:
|
|
@@ -1112,11 +1214,26 @@ class EnvironmentBundles:
|
|
|
1112
1214
|
entries: dict[str, Path] = {}
|
|
1113
1215
|
total = 0
|
|
1114
1216
|
count = 0
|
|
1217
|
+
byte_progress = CountedProgress(
|
|
1218
|
+
current().emit,
|
|
1219
|
+
"bundle.archive_extract",
|
|
1220
|
+
f"Reading {bundle.name}",
|
|
1221
|
+
bundle.stat().st_size,
|
|
1222
|
+
phase="bundle",
|
|
1223
|
+
unit="bytes",
|
|
1224
|
+
)
|
|
1225
|
+
byte_progress.start()
|
|
1226
|
+
raw_handle: Any = None
|
|
1115
1227
|
try:
|
|
1116
|
-
|
|
1228
|
+
raw_handle = bundle.open("rb")
|
|
1229
|
+
archive = tarfile.open( # noqa: SIM115
|
|
1230
|
+
fileobj=_ProgressReader(raw_handle, byte_progress), mode="r:gz"
|
|
1231
|
+
)
|
|
1117
1232
|
except (tarfile.TarError, OSError) as exc:
|
|
1233
|
+
if raw_handle is not None:
|
|
1234
|
+
raw_handle.close()
|
|
1118
1235
|
raise EnvironmentError(f"could not read OCI bundle: {bundle}") from exc
|
|
1119
|
-
with archive:
|
|
1236
|
+
with archive, raw_handle:
|
|
1120
1237
|
for member in archive:
|
|
1121
1238
|
count += 1
|
|
1122
1239
|
if count > MAX_FILES:
|
|
@@ -1136,6 +1253,7 @@ class EnvironmentBundles:
|
|
|
1136
1253
|
with path.open("wb") as output:
|
|
1137
1254
|
shutil.copyfileobj(source, output)
|
|
1138
1255
|
entries[member.name] = path
|
|
1256
|
+
byte_progress.advance(to=byte_progress.total)
|
|
1139
1257
|
return entries
|
|
1140
1258
|
|
|
1141
1259
|
def _import_capsule_layout(
|
|
@@ -21,8 +21,10 @@ from pathlib import Path, PurePosixPath
|
|
|
21
21
|
from typing import Any, Literal
|
|
22
22
|
|
|
23
23
|
from .errors import EnvironmentError
|
|
24
|
+
from .events import current
|
|
24
25
|
from .import_syntax import IMPORT_STATEMENT
|
|
25
26
|
from .lockfiles import EnvironmentLock
|
|
27
|
+
from .progress import CountedProgress
|
|
26
28
|
from .serialization import canonical_json_bytes, write_json_atomic
|
|
27
29
|
|
|
28
30
|
CAPSULE_SCHEMA = "lean-runtime-check-capsule/1"
|
|
@@ -253,6 +255,14 @@ def parse_import_headers(
|
|
|
253
255
|
with tempfile.TemporaryDirectory(prefix="lean-runtime-imports-") as raw:
|
|
254
256
|
helper = Path(raw) / "ParseImports.lean"
|
|
255
257
|
helper.write_text(IMPORT_PARSER_SOURCE, encoding="utf-8")
|
|
258
|
+
progress = CountedProgress(
|
|
259
|
+
current().emit,
|
|
260
|
+
"capsule.import_parse",
|
|
261
|
+
"Parsing imports",
|
|
262
|
+
len(source_paths),
|
|
263
|
+
phase="capsule",
|
|
264
|
+
)
|
|
265
|
+
progress.start()
|
|
256
266
|
for offset in range(0, len(source_paths), batch_size):
|
|
257
267
|
batch = list(source_paths[offset : offset + batch_size])
|
|
258
268
|
process = subprocess.run(
|
|
@@ -286,6 +296,7 @@ def parse_import_headers(
|
|
|
286
296
|
if isinstance(item, dict) and isinstance(item.get("module"), str)
|
|
287
297
|
}
|
|
288
298
|
result[path] = tuple(sorted(names))
|
|
299
|
+
progress.advance(to=min(offset + len(batch), len(source_paths)))
|
|
289
300
|
return result
|
|
290
301
|
|
|
291
302
|
|
|
@@ -369,16 +380,34 @@ def build_manifest(
|
|
|
369
380
|
complete_modules: frozenset[str] | None = None,
|
|
370
381
|
) -> CapsuleManifest:
|
|
371
382
|
"""Inventory retained module artifacts beneath package build roots."""
|
|
383
|
+
scan = CountedProgress(
|
|
384
|
+
current().emit,
|
|
385
|
+
"capsule.artifact_scan",
|
|
386
|
+
"Scanning capsule artifacts",
|
|
387
|
+
1,
|
|
388
|
+
phase="capsule",
|
|
389
|
+
)
|
|
390
|
+
scan.start()
|
|
391
|
+
paths = [
|
|
392
|
+
(package, root, path)
|
|
393
|
+
for package, root in sorted(build_roots.items())
|
|
394
|
+
if root.is_dir()
|
|
395
|
+
for path in sorted(root.rglob("*"))
|
|
396
|
+
if path.is_file()
|
|
397
|
+
]
|
|
398
|
+
scan.advance(f"{len(paths)} files")
|
|
399
|
+
progress = CountedProgress(
|
|
400
|
+
current().emit,
|
|
401
|
+
"capsule.artifact_inventory",
|
|
402
|
+
"Hashing capsule artifacts",
|
|
403
|
+
len(paths),
|
|
404
|
+
phase="capsule",
|
|
405
|
+
)
|
|
406
|
+
progress.start()
|
|
372
407
|
modules: dict[str, tuple[str, list[CapsuleArtifact]]] = {}
|
|
373
|
-
for package, root in
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
for path in sorted(root.rglob("*")):
|
|
377
|
-
if not path.is_file():
|
|
378
|
-
continue
|
|
379
|
-
module = module_from_artifact(path.relative_to(root))
|
|
380
|
-
if module is None:
|
|
381
|
-
continue
|
|
408
|
+
for package, root, path in paths:
|
|
409
|
+
module = module_from_artifact(path.relative_to(root))
|
|
410
|
+
if module is not None:
|
|
382
411
|
relative = path.relative_to(workspace).as_posix()
|
|
383
412
|
capability = artifact_capability(path)
|
|
384
413
|
artifact = CapsuleArtifact(
|
|
@@ -390,6 +419,7 @@ def build_manifest(
|
|
|
390
419
|
f"capsule module {module} is provided by both {existing[0]} and {package}"
|
|
391
420
|
)
|
|
392
421
|
modules.setdefault(module, (package, []))[1].append(artifact)
|
|
422
|
+
progress.advance(path.relative_to(workspace).as_posix())
|
|
393
423
|
known_complete = frozenset(imports) if complete_modules is None else complete_modules
|
|
394
424
|
records = tuple(
|
|
395
425
|
CapsuleModule(
|
|
@@ -436,6 +466,14 @@ def inventory_workspace(
|
|
|
436
466
|
) -> CapsuleManifest:
|
|
437
467
|
"""Build an exact capsule inventory from a verified full workspace."""
|
|
438
468
|
source_roots, build_roots = _package_directories(workspace, lock)
|
|
469
|
+
discovery = CountedProgress(
|
|
470
|
+
current().emit,
|
|
471
|
+
"capsule.module_discovery",
|
|
472
|
+
"Discovering capsule modules",
|
|
473
|
+
len(build_roots) + len(source_roots),
|
|
474
|
+
phase="capsule",
|
|
475
|
+
)
|
|
476
|
+
discovery.start()
|
|
439
477
|
modules_by_package: dict[str, set[str]] = {}
|
|
440
478
|
for package, root in build_roots.items():
|
|
441
479
|
modules_by_package[package] = {
|
|
@@ -443,11 +481,13 @@ def inventory_workspace(
|
|
|
443
481
|
for path in root.rglob("*.olean")
|
|
444
482
|
if (module := module_from_artifact(path.relative_to(root))) is not None
|
|
445
483
|
}
|
|
484
|
+
discovery.advance(package)
|
|
446
485
|
|
|
447
486
|
source_modules: dict[Path, str] = {}
|
|
448
487
|
claimed: dict[str, tuple[int, Path]] = {}
|
|
449
488
|
for package, root in source_roots.items():
|
|
450
489
|
if not root.is_dir():
|
|
490
|
+
discovery.advance(package)
|
|
451
491
|
continue
|
|
452
492
|
available = modules_by_package[package]
|
|
453
493
|
for path in sorted(root.rglob("*.lean")):
|
|
@@ -473,6 +513,7 @@ def inventory_workspace(
|
|
|
473
513
|
source_modules.pop(previous[1], None)
|
|
474
514
|
claimed[module] = (stripped, path)
|
|
475
515
|
source_modules[path] = module
|
|
516
|
+
discovery.advance(package)
|
|
476
517
|
|
|
477
518
|
parsed = parse_import_headers(lean_command, tuple(source_modules))
|
|
478
519
|
imports = {source_modules[path]: names for path, names in parsed.items()}
|
|
@@ -1970,9 +1970,9 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1970
1970
|
)
|
|
1971
1971
|
if declined is not None:
|
|
1972
1972
|
return declined
|
|
1973
|
-
di_publication = OCIDeclarationIndexPublisher(
|
|
1974
|
-
|
|
1975
|
-
)
|
|
1973
|
+
di_publication = OCIDeclarationIndexPublisher(
|
|
1974
|
+
di_repository, events=runtime.events
|
|
1975
|
+
).publish(tuple(di_item.source for di_item in built.shards), lock_id=lock.lock_id)
|
|
1976
1976
|
if args.sign:
|
|
1977
1977
|
CosignVerifier(executable=runtime.verification_executable).sign(
|
|
1978
1978
|
di_repository, di_publication.manifest_digest
|
|
@@ -141,6 +141,19 @@ class ConsoleRenderer:
|
|
|
141
141
|
handler = getattr(self, "_render_" + event.kind.replace(".", "_"), None)
|
|
142
142
|
if handler is not None:
|
|
143
143
|
handler(event)
|
|
144
|
+
elif (
|
|
145
|
+
isinstance(event.data.get("current"), int)
|
|
146
|
+
and isinstance(event.data.get("total"), int)
|
|
147
|
+
and event.data.get("label")
|
|
148
|
+
):
|
|
149
|
+
# Any counted event renders as a bar without a dedicated handler.
|
|
150
|
+
self._render_count_progress(
|
|
151
|
+
str(event.data["label"]),
|
|
152
|
+
event.data["current"],
|
|
153
|
+
event.data["total"],
|
|
154
|
+
str(event.data.get("detail") or ""),
|
|
155
|
+
bytes_unit=event.data.get("unit") == "bytes",
|
|
156
|
+
)
|
|
144
157
|
|
|
145
158
|
def note(self, message: str) -> None:
|
|
146
159
|
"""Print one renderer-owned status line."""
|
|
@@ -183,11 +196,12 @@ class ConsoleRenderer:
|
|
|
183
196
|
idle = self._clock() - self._last_event_at
|
|
184
197
|
if idle < self._heartbeat_seconds:
|
|
185
198
|
continue
|
|
199
|
+
last = _truncate(self._last_message, _OUTPUT_WIDTH)
|
|
186
200
|
if self.mode == "tty":
|
|
187
|
-
text = f"⋯
|
|
201
|
+
text = f"⋯ no new events for {int(idle)}s · last: {last}"
|
|
188
202
|
self._draw_line(text, self.style.dim(text))
|
|
189
203
|
elif idle >= self._next_plain_heartbeat:
|
|
190
|
-
self._print(f"Still working
|
|
204
|
+
self._print(f"Still working ({int(idle)}s without events; last: {last})")
|
|
191
205
|
self._next_plain_heartbeat = idle + _PLAIN_HEARTBEAT_REPEAT_SECONDS
|
|
192
206
|
|
|
193
207
|
# -- individual event renderings ------------------------------------
|
|
@@ -366,6 +380,9 @@ class ConsoleRenderer:
|
|
|
366
380
|
def _render_adopt_identity_started(self, event: RuntimeEvent) -> None:
|
|
367
381
|
self._count_from(event, "Resolving dependency identities", "name")
|
|
368
382
|
|
|
383
|
+
def _render_adopt_attach_started(self, event: RuntimeEvent) -> None:
|
|
384
|
+
self._count_from(event, "Attaching projects", "name")
|
|
385
|
+
|
|
369
386
|
def _render_project_detach_package_started(self, event: RuntimeEvent) -> None:
|
|
370
387
|
self._count_from(event, "Materializing packages", "package")
|
|
371
388
|
|
|
@@ -376,7 +393,11 @@ class ConsoleRenderer:
|
|
|
376
393
|
return
|
|
377
394
|
self._render_count_progress(label, current, total, str(event.data.get(detail_key) or ""))
|
|
378
395
|
|
|
379
|
-
def _render_count_progress(
|
|
396
|
+
def _render_count_progress(
|
|
397
|
+
self, label: str, current: int, total: int, detail: str, *, bytes_unit: bool = False
|
|
398
|
+
) -> None:
|
|
399
|
+
if total <= 0:
|
|
400
|
+
return
|
|
380
401
|
current = min(current, total)
|
|
381
402
|
if self.mode == "tty":
|
|
382
403
|
now = self._clock()
|
|
@@ -390,10 +411,15 @@ class ConsoleRenderer:
|
|
|
390
411
|
filled = _BAR_WIDTH * current // total
|
|
391
412
|
bar = "█" * filled + "░" * (_BAR_WIDTH - filled)
|
|
392
413
|
suffix = f" · {_truncate(detail, _DETAIL_WIDTH)}" if detail else ""
|
|
393
|
-
|
|
414
|
+
amount = (
|
|
415
|
+
f"{format_byte_size(current)}/{format_byte_size(total)}"
|
|
416
|
+
if bytes_unit
|
|
417
|
+
else f"{current}/{total}"
|
|
418
|
+
)
|
|
419
|
+
plain = f"{label} [{bar}] {amount}{suffix}"
|
|
394
420
|
styled = (
|
|
395
421
|
f"{label} [{self.style.cyan(bar)}] "
|
|
396
|
-
f"{self.style.bold(
|
|
422
|
+
f"{self.style.bold(amount)}{self.style.dim(suffix)}"
|
|
397
423
|
)
|
|
398
424
|
self._draw_line(plain, styled)
|
|
399
425
|
if current >= total:
|
|
@@ -405,7 +431,12 @@ class ConsoleRenderer:
|
|
|
405
431
|
self._count_checkpoint = _PLAIN_CHECKPOINT_PERCENT
|
|
406
432
|
percent = current * 100 // total
|
|
407
433
|
while self._count_checkpoint <= percent:
|
|
408
|
-
|
|
434
|
+
amount = (
|
|
435
|
+
f"{format_byte_size(current)}/{format_byte_size(total)}"
|
|
436
|
+
if bytes_unit
|
|
437
|
+
else f"{current}/{total}"
|
|
438
|
+
)
|
|
439
|
+
self._print(f"{label}: {self._count_checkpoint}% ({amount})")
|
|
409
440
|
self._count_checkpoint += _PLAIN_CHECKPOINT_PERCENT
|
|
410
441
|
|
|
411
442
|
# -- low-level output -----------------------------------------------
|
|
@@ -19,7 +19,9 @@ from .declaration_index import (
|
|
|
19
19
|
)
|
|
20
20
|
from .declaration_index_oci import DeclarationShardSource
|
|
21
21
|
from .errors import EnvironmentError
|
|
22
|
+
from .events import current
|
|
22
23
|
from .lockfiles import EnvironmentLock, LockedPackage
|
|
24
|
+
from .progress import CountedProgress
|
|
23
25
|
from .runtime import Runtime
|
|
24
26
|
from .serialization import canonical_json_bytes
|
|
25
27
|
|
|
@@ -101,9 +103,26 @@ def _declarations(root: Path) -> tuple[dict[str, str], tuple[str, ...], tuple[st
|
|
|
101
103
|
declarations: dict[str, str] = {}
|
|
102
104
|
ambiguous: set[str] = set()
|
|
103
105
|
modules: set[str] = set()
|
|
106
|
+
scan = CountedProgress(
|
|
107
|
+
current().emit,
|
|
108
|
+
"declaration_index.scan",
|
|
109
|
+
f"Scanning declarations in {root.name}",
|
|
110
|
+
1,
|
|
111
|
+
phase="declaration-index",
|
|
112
|
+
)
|
|
113
|
+
scan.start()
|
|
104
114
|
ileans = tuple(sorted(root.rglob("*.ilean"), key=lambda item: item.as_posix()))
|
|
115
|
+
scan.advance(f"{len(ileans)} files")
|
|
105
116
|
if not ileans:
|
|
106
117
|
raise EnvironmentError(f"compiled declaration root contains no .ilean files: {root}")
|
|
118
|
+
progress = CountedProgress(
|
|
119
|
+
current().emit,
|
|
120
|
+
"declaration_index.parse",
|
|
121
|
+
f"Reading declarations in {root.name}",
|
|
122
|
+
len(ileans),
|
|
123
|
+
phase="declaration-index",
|
|
124
|
+
)
|
|
125
|
+
progress.start()
|
|
107
126
|
for path in ileans:
|
|
108
127
|
if path.stat().st_size > MAX_ILEAN_BYTES:
|
|
109
128
|
raise EnvironmentError(f"Lean index exceeds its supported size: {path}")
|
|
@@ -129,6 +148,7 @@ def _declarations(root: Path) -> tuple[dict[str, str], tuple[str, ...], tuple[st
|
|
|
129
148
|
ambiguous.add(name)
|
|
130
149
|
continue
|
|
131
150
|
declarations[name] = module
|
|
151
|
+
progress.advance(path.name)
|
|
132
152
|
if not declarations:
|
|
133
153
|
raise EnvironmentError(f"compiled declaration root produced no public names: {root}")
|
|
134
154
|
namespace_roots = {name.split(".", 1)[0] for name in declarations}
|
|
@@ -147,6 +167,14 @@ def _write_shard(
|
|
|
147
167
|
) -> None:
|
|
148
168
|
if output.exists():
|
|
149
169
|
raise EnvironmentError(f"refusing to overwrite declaration shard: {output}")
|
|
170
|
+
progress = CountedProgress(
|
|
171
|
+
current().emit,
|
|
172
|
+
"declaration_index.sqlite",
|
|
173
|
+
f"Writing declaration shard {output.stem[:20]}",
|
|
174
|
+
4,
|
|
175
|
+
phase="declaration-index",
|
|
176
|
+
)
|
|
177
|
+
progress.start()
|
|
150
178
|
with sqlite3.connect(output) as connection:
|
|
151
179
|
connection.executescript(
|
|
152
180
|
f"""
|
|
@@ -171,6 +199,7 @@ def _write_shard(
|
|
|
171
199
|
) WITHOUT ROWID;
|
|
172
200
|
"""
|
|
173
201
|
)
|
|
202
|
+
progress.advance("schema")
|
|
174
203
|
metadata = {
|
|
175
204
|
"schema": DECLARATION_SHARD_SCHEMA,
|
|
176
205
|
"shard_id": shard_id,
|
|
@@ -184,12 +213,15 @@ def _write_shard(
|
|
|
184
213
|
for name in sorted(declarations)
|
|
185
214
|
]
|
|
186
215
|
connection.executemany("INSERT INTO decl VALUES (?, ?, ?, ?)", rows)
|
|
216
|
+
progress.advance("declarations")
|
|
187
217
|
connection.executemany(
|
|
188
218
|
"INSERT INTO suffix VALUES (?, ?)",
|
|
189
219
|
sorted((name.rsplit(".", 1)[-1], name) for name in declarations),
|
|
190
220
|
)
|
|
191
221
|
connection.commit()
|
|
222
|
+
progress.advance("suffix index")
|
|
192
223
|
connection.execute("VACUUM")
|
|
224
|
+
progress.advance("vacuum")
|
|
193
225
|
DeclarationIndex(output, expected_shard_id=shard_id)
|
|
194
226
|
|
|
195
227
|
|