lean-runtime 2.9.1__tar.gz → 2.10.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-2.9.1 → lean_runtime-2.10.0}/CHANGELOG.md +28 -0
- {lean_runtime-2.9.1/lean_runtime.egg-info → lean_runtime-2.10.0}/PKG-INFO +1 -1
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/cli.md +3 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/environments.md +6 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/local-projects.md +13 -4
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/portable-copies.md +6 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/cli.py +254 -35
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/console.py +19 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/environments.py +4 -10
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/errors.py +25 -0
- lean_runtime-2.10.0/lean_runtime/header_cache.py +214 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/health.py +13 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/locking.py +50 -1
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/models.py +6 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/oci.py +96 -13
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/programs.py +2 -6
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/project_execution.py +99 -30
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/project_sharing.py +3 -1
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/resolver.py +5 -2
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/runtime.py +39 -12
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/shared_projects.py +38 -4
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/store.py +122 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/toolchains.py +30 -1
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/wire.py +18 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0/lean_runtime.egg-info}/PKG-INFO +1 -1
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime.egg-info/SOURCES.txt +2 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/pyproject.toml +1 -1
- lean_runtime-2.10.0/schemas/check-batch-v1.schema.json +36 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/schemas/cleanup-v1.schema.json +7 -3
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/schemas/execution-v1.schema.json +1 -1
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/schemas/publication-v1.schema.json +2 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_bundles.py +81 -5
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_cli.py +196 -6
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_console.py +12 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_events_health.py +1 -0
- lean_runtime-2.10.0/tests/test_header_cache.py +329 -0
- lean_runtime-2.10.0/tests/test_locking.py +59 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_projects.py +7 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_schemas.py +6 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_store.py +35 -0
- lean_runtime-2.9.1/lean_runtime/header_cache.py +0 -126
- lean_runtime-2.9.1/tests/test_header_cache.py +0 -44
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/LICENSE +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/MANIFEST.in +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/README.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/environments.toml +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/locks/core-v4.32.2.lock.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/locks/leancert-v4.30.0.5.lock.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/locks/leancert-v4.31.0.lock.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/locks/leancert-v4.32.2.4.lock.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/locks/leancert-v4.33.0.lock.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/locks/mathlib-v4.30.0.lock.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/locks/mathlib-v4.31.0.lock.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/locks/mathlib-v4.32.2.lock.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/catalog/locks/mathlib-v4.33.0.lock.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/compatibility/README.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/compatibility/lake-artifact-cache-4.33.0.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/compatibility/mathlib-4.32.2.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/compatibility/mathlib-4.32.2.toml +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/compatibility/mathlib-4.33.0.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/compatibility/mathlib-4.33.0.toml +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/architecture.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/captures.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/case-study-v1.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/development.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/getting-started.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/index.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/lake-artifact-cache-design.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/project-publishing.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/python-api.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/ready-programs.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/standalone-files.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/trust-and-limitations.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/docs/v1-precision.md +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/examples/mathlib.toml +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/__init__.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/__main__.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/_git.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/_paths.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/backends.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/bundles.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/capsules.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/comparison.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/decisions.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/diagnostics.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/__init__.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/analyzer.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/api.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/candidate.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/catalog.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/catalog_build.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/catalog_cli.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/catalog_manifest.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/data/catalog.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/defaults.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/engine.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/errors.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/module_inventory.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/planner.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/policy.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/probe.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/py.typed +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/result.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/schema_resources.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/schemas/catalog-v1.schema.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/schemas/plan-v1.schema.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/discovery/schemas/result-v1.schema.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/events.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/facade.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/frontmatter.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/identifier_resolver.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/lake.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/lake_cache.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/lockfiles.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/matrix.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/oci_protocol.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/packs.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/policies.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/profiling.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/projects.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/publisher_verification.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/py.typed +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/references.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/run_cli.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/schema_resources.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/serialization.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/specs.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/timings.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/toolchain_oci.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/toolchain_slim.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime/verification.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime.egg-info/dependency_links.txt +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime.egg-info/entry_points.txt +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime.egg-info/requires.txt +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/lean_runtime.egg-info/top_level.txt +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/mkdocs.yml +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/schemas/comparison-v1.schema.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/schemas/inspect-v1.schema.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/schemas/matrix-v1.schema.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/schemas/profile-v1.schema.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/schemas/verify-v1.schema.json +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/scripts/announcement_gate.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/scripts/lake_cache_gate.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/scripts/registry_preflight.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/scripts/run_compatibility.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/scripts/run_v1_case_study.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/scripts/smoke_wheel.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/setup.cfg +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/conftest.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/discovery/e2e/test_real_discovery.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/discovery/test_analyzer.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/discovery/test_catalog.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/discovery/test_catalog_build.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/discovery/test_discovery_schema_resources.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/discovery/test_engine.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/discovery/test_planner.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/discovery/test_policy.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_backend.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_capsules.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_diagnostics.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_environment_integration.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_facade.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_frontmatter.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_git.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_identifier_resolver.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_interactive.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_lake_cache.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_lockfiles.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_models.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_multifile.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_oci_protocol.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_packs.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_paths.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_prebuilt_policy.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_programs.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_project_publish.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_references.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_run_cli.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_runtime.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_schema_resources.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_signatures.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_specs.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_toolchain_oci.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_toolchain_slim.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_toolchains.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_v1_precision.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_verification_inventory.py +0 -0
- {lean_runtime-2.9.1 → lean_runtime-2.10.0}/tests/test_verification_probe.py +0 -0
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 2.10.0 - 2026-08-16
|
|
6
|
+
|
|
7
|
+
- Make header snapshots opt-in (`LEAN_RUNTIME_HEADER_SNAPSHOTS=1`; `--watch` and
|
|
8
|
+
`--repeat` enable them automatically), key them by module identity, load
|
|
9
|
+
existing snapshots without holding the creation lock, cancel lock waits
|
|
10
|
+
promptly, and retry once without a snapshot—quarantining it—when a snapshot
|
|
11
|
+
check times out or reports snapshot errors.
|
|
12
|
+
- Support `check FILE...` and `check DIRECTORY...` with independent per-file
|
|
13
|
+
results, `--concurrency`, a `lean-runtime.check-batch/v1` JSON envelope, and
|
|
14
|
+
an explicit `--environment NAME`; the legacy positional `ENVIRONMENT FILE`
|
|
15
|
+
form now applies only when the first argument is not an existing path.
|
|
16
|
+
- Attribute shared workspace lock waits to their holder (PID and operation),
|
|
17
|
+
announce header snapshot waits, and record `workspace_lock` and
|
|
18
|
+
`header_snapshot` phase timings so coordination cost is visible next to the
|
|
19
|
+
actual Lean check time.
|
|
20
|
+
|
|
21
|
+
## 2.9.2 - 2026-08-16
|
|
22
|
+
|
|
23
|
+
- Keep one fail-closed publication authentication session from push preflight through
|
|
24
|
+
upload, propagate explicit publication timeouts to credential and registry I/O,
|
|
25
|
+
and report credential-provider failures without labeling them anonymous.
|
|
26
|
+
- Use logical project names during atomic initialization, show compact TTY-only check
|
|
27
|
+
progress, cache Lean executable identities across invocations, and report check
|
|
28
|
+
command-preparation timing.
|
|
29
|
+
- Track disposable execution and resolution workspaces with process-held leases;
|
|
30
|
+
include their footprint in storage reporting and reclaim abandoned workspaces with
|
|
31
|
+
`clean` while protecting active work.
|
|
32
|
+
|
|
5
33
|
## 2.9.1 - 2026-08-15
|
|
6
34
|
|
|
7
35
|
- Make GHCR credential discovery a single bounded GitHub CLI status read so a
|
|
@@ -215,6 +215,9 @@ lean-runtime check research-stack Main.lean --include Support/Defs.lean
|
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
Resolution and materialization print structured lifecycle progress to stderr.
|
|
218
|
+
One-shot checks show a compact in-place status on interactive terminals while Lean
|
|
219
|
+
is working. Redirected output, `--json`, and `--quiet` remain free of human progress;
|
|
220
|
+
`--timings` separates command preparation from Lean execution.
|
|
218
221
|
Pass global `--quiet` before the subcommand to suppress it.
|
|
219
222
|
|
|
220
223
|
Pass global `--timings` before the subcommand for stable phase timing output. Machine-readable
|
|
@@ -93,6 +93,12 @@ Short-lived execution leases prevent deletion during cloning without
|
|
|
93
93
|
serializing concurrent checks. Locks and source snapshots remain retained in
|
|
94
94
|
the current store schema.
|
|
95
95
|
|
|
96
|
+
Disposable execution and dependency-resolution workspaces carry their own
|
|
97
|
+
process-held ownership leases. `storage` includes them under `Scratch`, and
|
|
98
|
+
`clean` previews and reclaims abandoned workspaces while retaining every
|
|
99
|
+
workspace with a live owner. Legacy scratch directories created before ownership
|
|
100
|
+
metadata are removed only by an explicit `clean --execute` after the safety grace.
|
|
101
|
+
|
|
96
102
|
Sparse downloads are stored once by artifact digest under the shared module
|
|
97
103
|
CAS and hardlinked into environment projections when the filesystem permits.
|
|
98
104
|
`lean-runtime storage` reports this category separately. Because it is shared,
|
|
@@ -68,10 +68,19 @@ stays silent. Only root-project outputs enter this cache: locked dependencies
|
|
|
68
68
|
continue to use the verified shared workspace, avoiding a second multi-gigabyte
|
|
69
69
|
copy. `build` retains Lake's complete target semantics.
|
|
70
70
|
|
|
71
|
-
Repeated file
|
|
72
|
-
toolchain, project identity, and import block. Body-only
|
|
73
|
-
reloading the unchanged import environment.
|
|
74
|
-
|
|
71
|
+
Repeated checks of one file can reuse Lean's native header snapshots, keyed by
|
|
72
|
+
the exact toolchain, project identity, module, and import block. Body-only
|
|
73
|
+
edits therefore avoid reloading the unchanged import environment. Snapshots are
|
|
74
|
+
used automatically by `--watch` and `--repeat`; set
|
|
75
|
+
`LEAN_RUNTIME_HEADER_SNAPSHOTS=1` to enable them for one-shot checks (or `=0`
|
|
76
|
+
to disable them everywhere). A check that fails or times out under a snapshot
|
|
77
|
+
is retried once without it, and the snapshot is discarded. `--watch` is a thin
|
|
78
|
+
save loop over the same ordinary check/result contract. `check` also accepts
|
|
79
|
+
several files or directories and checks each independently, in parallel with
|
|
80
|
+
`--concurrency`. When one invocation must wait on another, the console names
|
|
81
|
+
the holder (for example `Waiting for shared workspace lock held by PID 512
|
|
82
|
+
(shared build of mathlib)`), and `--timings` reports `workspace_lock` and
|
|
83
|
+
`header_snapshot` phases alongside the actual Lean execution time. Failed checks may add exact-graph
|
|
75
84
|
identifier hints derived from pinned `.ilean` indexes; raw Lean streams remain
|
|
76
85
|
unchanged.
|
|
77
86
|
|
|
@@ -135,6 +135,12 @@ run:
|
|
|
135
135
|
gh auth refresh -s write:packages,read:packages
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
+
Credential discovery is fail-closed: a configured provider that times out or
|
|
139
|
+
returns an unusable token stops publication before any registry request. The same
|
|
140
|
+
verified credential is retained from preflight through upload; it is not rediscovered
|
|
141
|
+
after a long environment build. An explicitly supplied publication `--timeout`
|
|
142
|
+
also applies to credential discovery and registry network operations.
|
|
143
|
+
|
|
138
144
|
Publish the current platform after ensuring the lock:
|
|
139
145
|
|
|
140
146
|
```bash
|
|
@@ -8,12 +8,14 @@ import os
|
|
|
8
8
|
import re
|
|
9
9
|
import sys
|
|
10
10
|
import time
|
|
11
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
12
|
+
from dataclasses import replace
|
|
11
13
|
from datetime import datetime
|
|
12
14
|
from importlib.metadata import version as distribution_version
|
|
13
15
|
from pathlib import Path
|
|
14
16
|
from typing import Any, cast
|
|
15
17
|
|
|
16
|
-
from .console import styler_for
|
|
18
|
+
from .console import ConsoleRenderer, styler_for
|
|
17
19
|
from .environments import ExecutionCapture
|
|
18
20
|
from .errors import (
|
|
19
21
|
LeanRuntimeError,
|
|
@@ -23,6 +25,7 @@ from .errors import (
|
|
|
23
25
|
ResolutionError,
|
|
24
26
|
)
|
|
25
27
|
from .events import RuntimeEvent
|
|
28
|
+
from .header_cache import ENABLE_VARIABLE as _HEADER_SNAPSHOTS_VARIABLE
|
|
26
29
|
from .health import DoctorReport
|
|
27
30
|
from .lake import ROOT_MODULE
|
|
28
31
|
from .lockfiles import EnvironmentLock
|
|
@@ -39,6 +42,7 @@ from .timings import render_timings
|
|
|
39
42
|
from .wire import (
|
|
40
43
|
envelope,
|
|
41
44
|
error,
|
|
45
|
+
serialize_check_batch_v1,
|
|
42
46
|
serialize_comparison_v1,
|
|
43
47
|
serialize_execution_v1,
|
|
44
48
|
serialize_matrix_v1,
|
|
@@ -89,6 +93,7 @@ def _render_storage(status: StoreStatus) -> None:
|
|
|
89
93
|
("Project packages", status.project_packages, status.project_packages_bytes),
|
|
90
94
|
("Toolchains", None, status.toolchains_bytes),
|
|
91
95
|
("Executions", status.executions, status.executions_bytes),
|
|
96
|
+
("Scratch", status.scratch_workspaces, status.scratch_bytes),
|
|
92
97
|
)
|
|
93
98
|
for label, count, bytes_used in rows:
|
|
94
99
|
counted = f"{count:>5}" if count is not None else " "
|
|
@@ -139,7 +144,11 @@ def _render_doctor(report: DoctorReport) -> None:
|
|
|
139
144
|
print(f"{symbols[check.status]} {check.name}: {check.message}")
|
|
140
145
|
|
|
141
146
|
|
|
142
|
-
def _render_cleanup(
|
|
147
|
+
def _render_cleanup(
|
|
148
|
+
environments: CleanupReport,
|
|
149
|
+
downloads: DownloadCleanupReport | None,
|
|
150
|
+
scratch: CleanupReport | None = None,
|
|
151
|
+
) -> None:
|
|
143
152
|
style = styler_for(sys.stdout)
|
|
144
153
|
retained_note = style.dim(
|
|
145
154
|
f"Retained {len(environments.retained)} environment(s) (named, recent, or in use)."
|
|
@@ -169,17 +178,36 @@ def _render_cleanup(environments: CleanupReport, downloads: DownloadCleanupRepor
|
|
|
169
178
|
)
|
|
170
179
|
else:
|
|
171
180
|
print("No unreferenced cached downloads to remove.")
|
|
181
|
+
if scratch is not None:
|
|
182
|
+
if scratch.candidates:
|
|
183
|
+
anything = True
|
|
184
|
+
print(
|
|
185
|
+
style.bold(
|
|
186
|
+
f"Would remove {len(scratch.candidates)} abandoned workspace(s) · "
|
|
187
|
+
f"{format_byte_size(scratch.candidate_bytes)}"
|
|
188
|
+
)
|
|
189
|
+
)
|
|
190
|
+
else:
|
|
191
|
+
print("No abandoned workspaces to remove.")
|
|
172
192
|
print(retained_note)
|
|
173
193
|
if anything:
|
|
174
194
|
print()
|
|
175
195
|
print("This was a preview. Re-run with --execute to delete.")
|
|
176
196
|
return
|
|
177
197
|
reclaimed = environments.reclaimed_bytes + (downloads.reclaimed_bytes if downloads else 0)
|
|
178
|
-
|
|
198
|
+
if scratch is not None:
|
|
199
|
+
reclaimed += scratch.reclaimed_bytes
|
|
200
|
+
removed = (
|
|
201
|
+
len(environments.removed)
|
|
202
|
+
+ (len(downloads.removed) if downloads else 0)
|
|
203
|
+
+ (len(scratch.removed) if scratch else 0)
|
|
204
|
+
)
|
|
179
205
|
if removed:
|
|
180
206
|
parts = [f"{len(environments.removed)} environment(s)"]
|
|
181
207
|
if downloads is not None:
|
|
182
208
|
parts.append(f"{len(downloads.removed)} cached download(s)")
|
|
209
|
+
if scratch is not None:
|
|
210
|
+
parts.append(f"{len(scratch.removed)} abandoned workspace(s)")
|
|
183
211
|
print(
|
|
184
212
|
style.green(f"Removed {' and '.join(parts)} · reclaimed {format_byte_size(reclaimed)}")
|
|
185
213
|
)
|
|
@@ -290,11 +318,15 @@ def _print_publication_failure(exc: PublicationError) -> None:
|
|
|
290
318
|
file=sys.stderr,
|
|
291
319
|
)
|
|
292
320
|
print(f" {exc}", file=sys.stderr)
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
f"
|
|
296
|
-
|
|
297
|
-
|
|
321
|
+
if exc.attempted_provider is not None:
|
|
322
|
+
print(" Authentication: unavailable (source: none)", file=sys.stderr)
|
|
323
|
+
print(f" Attempted provider: {exc.attempted_provider}", file=sys.stderr)
|
|
324
|
+
else:
|
|
325
|
+
identity = exc.username or "anonymous"
|
|
326
|
+
print(
|
|
327
|
+
f" Authentication: {identity} (source: {exc.credential_source})",
|
|
328
|
+
file=sys.stderr,
|
|
329
|
+
)
|
|
298
330
|
if exc.partial:
|
|
299
331
|
print(
|
|
300
332
|
" No verified final release was produced; immutable platform content may exist.",
|
|
@@ -314,6 +346,82 @@ def _cli_source_name(path: Path) -> str:
|
|
|
314
346
|
return path.as_posix()
|
|
315
347
|
|
|
316
348
|
|
|
349
|
+
def _expand_check_inputs(inputs: list[str]) -> list[Path]:
|
|
350
|
+
"""Expand FILE and DIRECTORY inputs into an ordered, deduplicated file list."""
|
|
351
|
+
files: list[Path] = []
|
|
352
|
+
for raw in inputs:
|
|
353
|
+
path = Path(raw)
|
|
354
|
+
if path.is_dir():
|
|
355
|
+
found: list[Path] = []
|
|
356
|
+
for current, directories, filenames in os.walk(path):
|
|
357
|
+
directories[:] = sorted(name for name in directories if not name.startswith("."))
|
|
358
|
+
found.extend(
|
|
359
|
+
Path(current) / name for name in sorted(filenames) if name.endswith(".lean")
|
|
360
|
+
)
|
|
361
|
+
if not found:
|
|
362
|
+
raise ValueError(f"no Lean files found under directory: {path}")
|
|
363
|
+
files.extend(found)
|
|
364
|
+
elif path.is_file():
|
|
365
|
+
files.append(path)
|
|
366
|
+
else:
|
|
367
|
+
raise ValueError(f"check input does not exist: {path}")
|
|
368
|
+
return list(dict.fromkeys(files))
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _run_check_batch(runtime: Runtime, files: list[Path], args: argparse.Namespace) -> int:
|
|
372
|
+
"""Check each file independently, optionally in parallel, and report per file."""
|
|
373
|
+
if args.concurrency < 1 or args.concurrency > 32:
|
|
374
|
+
raise ValueError("check concurrency must be between 1 and 32")
|
|
375
|
+
environment = runtime.environment(args.environment) if args.environment else None
|
|
376
|
+
|
|
377
|
+
def execute(path: Path) -> ExecutionResult:
|
|
378
|
+
if environment is not None:
|
|
379
|
+
name = _cli_source_name(path)
|
|
380
|
+
return environment.check_files(
|
|
381
|
+
{name: path.read_text(encoding="utf-8")}, entrypoint=name, policy=_policy(args)
|
|
382
|
+
)
|
|
383
|
+
return runtime.check_file(
|
|
384
|
+
path, toolchain=args.toolchain, project=args.project, policy=_policy(args)
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
started = time.monotonic()
|
|
388
|
+
results: dict[Path, ExecutionResult] = {}
|
|
389
|
+
if args.concurrency == 1:
|
|
390
|
+
for path in files:
|
|
391
|
+
results[path] = execute(path)
|
|
392
|
+
else:
|
|
393
|
+
with ThreadPoolExecutor(
|
|
394
|
+
max_workers=args.concurrency, thread_name_prefix="lean-check"
|
|
395
|
+
) as pool:
|
|
396
|
+
futures = {pool.submit(execute, path): path for path in files}
|
|
397
|
+
try:
|
|
398
|
+
for future in as_completed(futures):
|
|
399
|
+
results[futures[future]] = future.result()
|
|
400
|
+
except BaseException:
|
|
401
|
+
for future in futures:
|
|
402
|
+
future.cancel()
|
|
403
|
+
raise
|
|
404
|
+
entries = [(str(path), results[path]) for path in files]
|
|
405
|
+
runtime.events.emit(
|
|
406
|
+
"check.completed",
|
|
407
|
+
"Lean check completed",
|
|
408
|
+
ok=all(result.ok for _, result in entries),
|
|
409
|
+
)
|
|
410
|
+
if args.json:
|
|
411
|
+
_json(serialize_check_batch_v1(entries, time.monotonic() - started))
|
|
412
|
+
else:
|
|
413
|
+
for display, result in entries:
|
|
414
|
+
status = "accepted" if result.ok else "rejected"
|
|
415
|
+
print(f"{display}\t{status}\t{result.elapsed_seconds:.2f}s")
|
|
416
|
+
if not result.ok:
|
|
417
|
+
output = "\n".join(part for part in (result.stdout, result.stderr) if part).strip()
|
|
418
|
+
if output:
|
|
419
|
+
print(output, file=sys.stderr)
|
|
420
|
+
accepted = sum(1 for _, result in entries if result.ok)
|
|
421
|
+
print(f"{accepted}/{len(entries)} accepted")
|
|
422
|
+
return 0 if all(result.ok for _, result in entries) else 1
|
|
423
|
+
|
|
424
|
+
|
|
317
425
|
def _display_result_text(text: str, result: ExecutionResult, display_path: str | None) -> str:
|
|
318
426
|
"""Rewrite only the staged entrypoint when the CLI has a logical input name."""
|
|
319
427
|
if display_path is None or not result.command:
|
|
@@ -436,7 +544,12 @@ Run `lean-runtime COMMAND --help` for examples and options.""",
|
|
|
436
544
|
publish_environment.add_argument("--publish-to", required=True)
|
|
437
545
|
publish_environment.add_argument("--tag", action="append", default=[])
|
|
438
546
|
publish_environment.add_argument("--name")
|
|
439
|
-
publish_environment.add_argument(
|
|
547
|
+
publish_environment.add_argument(
|
|
548
|
+
"--timeout",
|
|
549
|
+
type=float,
|
|
550
|
+
default=None,
|
|
551
|
+
help="override timeouts for credential, registry, hydration, and build operations",
|
|
552
|
+
)
|
|
440
553
|
publish_environment.add_argument("--platform-only", action="store_true")
|
|
441
554
|
publish_environment.add_argument("--accelerate", action="store_true")
|
|
442
555
|
publish_environment.add_argument("--sign", action="store_true")
|
|
@@ -511,8 +624,8 @@ Run `lean-runtime COMMAND --help` for examples and options.""",
|
|
|
511
624
|
push.add_argument(
|
|
512
625
|
"--timeout",
|
|
513
626
|
type=float,
|
|
514
|
-
default=
|
|
515
|
-
help="
|
|
627
|
+
default=None,
|
|
628
|
+
help="override timeouts for credential, registry, hydration, and build operations",
|
|
516
629
|
)
|
|
517
630
|
push.add_argument(
|
|
518
631
|
"--platform-only",
|
|
@@ -623,11 +736,36 @@ Run `lean-runtime COMMAND --help` for examples and options.""",
|
|
|
623
736
|
program_index.add_argument("--tag", action="append", default=[])
|
|
624
737
|
program_index.add_argument("--sign", action="store_true")
|
|
625
738
|
|
|
626
|
-
check = commands.add_parser(
|
|
739
|
+
check = commands.add_parser(
|
|
740
|
+
"check",
|
|
741
|
+
help="check Lean files or all local libraries",
|
|
742
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
743
|
+
epilog="""examples:
|
|
744
|
+
lean-runtime check check every local library of this project
|
|
745
|
+
lean-runtime check Foo.lean check one file in its discovered project
|
|
746
|
+
lean-runtime check Foo.lean Bar.lean check several files, one result per file
|
|
747
|
+
lean-runtime check src --concurrency 4 check every *.lean under src in parallel
|
|
748
|
+
lean-runtime check Foo.lean --project ~/p check a file against an explicit Lake project
|
|
749
|
+
lean-runtime check --environment NAME Foo.lean
|
|
750
|
+
check inside a published environment
|
|
751
|
+
lean-runtime check Foo.lean --with github:owner/repo@v1.0
|
|
752
|
+
check against exact package references
|
|
753
|
+
lean-runtime check Foo.lean --timeout 60 bound one Lean invocation to 60 seconds
|
|
754
|
+
lean-runtime --timings check Foo.lean append stable phase timings to the result
|
|
755
|
+
|
|
756
|
+
Multi-file checks exit nonzero if any file is rejected. Header snapshots for
|
|
757
|
+
warm re-checks are used by --watch and --repeat automatically; set
|
|
758
|
+
LEAN_RUNTIME_HEADER_SNAPSHOTS=1 to enable them for one-shot checks.""",
|
|
759
|
+
)
|
|
627
760
|
check.add_argument(
|
|
628
761
|
"inputs",
|
|
629
762
|
nargs="*",
|
|
630
|
-
help="FILE
|
|
763
|
+
help="FILE..., DIRECTORY..., legacy ENVIRONMENT FILE, or omit inside a Lake "
|
|
764
|
+
"project; FILE may be -",
|
|
765
|
+
)
|
|
766
|
+
check.add_argument(
|
|
767
|
+
"--environment",
|
|
768
|
+
help="check the given FILEs inside this published environment",
|
|
631
769
|
)
|
|
632
770
|
check.add_argument(
|
|
633
771
|
"--with",
|
|
@@ -652,7 +790,9 @@ Run `lean-runtime COMMAND --help` for examples and options.""",
|
|
|
652
790
|
check.add_argument("--repeat", type=int, help="measure N repeated checks of one project file")
|
|
653
791
|
check.add_argument("--warmup", type=int, default=1, help="warmups before --repeat samples")
|
|
654
792
|
check.add_argument("--across", type=Path, help="check FILE across contexts in CONFIGURATION")
|
|
655
|
-
check.add_argument(
|
|
793
|
+
check.add_argument(
|
|
794
|
+
"--concurrency", type=int, default=1, help="workers for --across and multi-file checks"
|
|
795
|
+
)
|
|
656
796
|
_add_policy(check)
|
|
657
797
|
|
|
658
798
|
inspect = commands.add_parser("inspect", help="inspect a published environment")
|
|
@@ -933,6 +1073,10 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
933
1073
|
args.mathlib = None if args.core else args.mathlib_version
|
|
934
1074
|
operation_started = time.monotonic()
|
|
935
1075
|
display_path: str | None = None
|
|
1076
|
+
renderer = ConsoleRenderer(
|
|
1077
|
+
mode="quiet" if args.quiet or getattr(args, "json", False) else None,
|
|
1078
|
+
verbose=args.verbose,
|
|
1079
|
+
)
|
|
936
1080
|
try:
|
|
937
1081
|
if args.command == "completion":
|
|
938
1082
|
print(_completion_script(args.shell), end="")
|
|
@@ -947,7 +1091,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
947
1091
|
)
|
|
948
1092
|
runtime = Runtime(
|
|
949
1093
|
home=args.home,
|
|
950
|
-
on_event=
|
|
1094
|
+
on_event=renderer,
|
|
951
1095
|
availability=selected_availability,
|
|
952
1096
|
libraries=args.libraries,
|
|
953
1097
|
max_download_bytes=selected_download_limit,
|
|
@@ -1190,7 +1334,13 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1190
1334
|
_json(environment.inspect().to_dict())
|
|
1191
1335
|
return 0
|
|
1192
1336
|
if args.command == "build-and-publish":
|
|
1193
|
-
|
|
1337
|
+
timeout_override = args.timeout
|
|
1338
|
+
publisher = runtime.begin_publication(
|
|
1339
|
+
args.publish_to,
|
|
1340
|
+
auth_timeout=timeout_override if timeout_override is not None else 10,
|
|
1341
|
+
registry_timeout=timeout_override if timeout_override is not None else 30,
|
|
1342
|
+
)
|
|
1343
|
+
access = publisher.check_access()
|
|
1194
1344
|
if args.check_access:
|
|
1195
1345
|
_json(
|
|
1196
1346
|
envelope(_schema_for(args.command), ok=True, data=access.to_dict())
|
|
@@ -1203,7 +1353,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1203
1353
|
environment = runtime.open_exact(
|
|
1204
1354
|
EnvironmentLock.load(args.lock),
|
|
1205
1355
|
name=args.name,
|
|
1206
|
-
build_timeout=
|
|
1356
|
+
build_timeout=timeout_override if timeout_override is not None else 1800,
|
|
1207
1357
|
accelerate=args.accelerate,
|
|
1208
1358
|
)
|
|
1209
1359
|
publication = runtime.publish_environment(
|
|
@@ -1213,6 +1363,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1213
1363
|
finalize=not args.platform_only,
|
|
1214
1364
|
sign=args.sign,
|
|
1215
1365
|
attest=args.attest,
|
|
1366
|
+
publisher=publisher,
|
|
1216
1367
|
).to_dict()
|
|
1217
1368
|
publication["consumer_command"] = (
|
|
1218
1369
|
f"lean-runtime --library {args.publish_to} download {args.lock}"
|
|
@@ -1487,10 +1638,15 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1487
1638
|
if args.include_downloads
|
|
1488
1639
|
else None
|
|
1489
1640
|
)
|
|
1641
|
+
gc_scratch = runtime.clean_scratch(
|
|
1642
|
+
dry_run=not args.execute,
|
|
1643
|
+
minimum_age_seconds=min(args.minimum_age_hours * 3600, 3600),
|
|
1644
|
+
)
|
|
1490
1645
|
if args.json:
|
|
1491
1646
|
gc_payload: dict[str, Any] = {
|
|
1492
1647
|
"environments": gc_report.to_dict(),
|
|
1493
1648
|
"downloaded_files": gc_downloads.to_dict() if gc_downloads else None,
|
|
1649
|
+
"scratch": gc_scratch.to_dict(),
|
|
1494
1650
|
}
|
|
1495
1651
|
_json(
|
|
1496
1652
|
envelope(
|
|
@@ -1500,11 +1656,17 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1500
1656
|
)
|
|
1501
1657
|
)
|
|
1502
1658
|
else:
|
|
1503
|
-
_render_cleanup(gc_report, gc_downloads)
|
|
1659
|
+
_render_cleanup(gc_report, gc_downloads, gc_scratch)
|
|
1504
1660
|
return 0
|
|
1505
1661
|
if args.command == "check":
|
|
1506
1662
|
if args.across is not None:
|
|
1507
|
-
if
|
|
1663
|
+
if (
|
|
1664
|
+
len(args.inputs) != 1
|
|
1665
|
+
or args.package_refs
|
|
1666
|
+
or args.include
|
|
1667
|
+
or args.project
|
|
1668
|
+
or args.environment
|
|
1669
|
+
):
|
|
1508
1670
|
raise ValueError("check --across requires exactly one FILE")
|
|
1509
1671
|
across_file = Path(args.inputs[0])
|
|
1510
1672
|
contexts = load_matrix(args.across)
|
|
@@ -1539,6 +1701,8 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1539
1701
|
"check --repeat requires positive samples and nonnegative warmups"
|
|
1540
1702
|
)
|
|
1541
1703
|
repeated_file = Path(args.inputs[0])
|
|
1704
|
+
if os.environ.get(_HEADER_SNAPSHOTS_VARIABLE) is None:
|
|
1705
|
+
runtime.header_cache.enabled = True
|
|
1542
1706
|
for _ in range(args.warmup):
|
|
1543
1707
|
warm = runtime.check_file(
|
|
1544
1708
|
repeated_file, project=args.project, policy=_policy(args)
|
|
@@ -1576,6 +1740,8 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1576
1740
|
if not watched.is_file():
|
|
1577
1741
|
raise ValueError(f"watched Lean file does not exist: {watched}")
|
|
1578
1742
|
print(f"Watching {watched} · Ctrl-C to stop")
|
|
1743
|
+
if os.environ.get(_HEADER_SNAPSHOTS_VARIABLE) is None:
|
|
1744
|
+
runtime.header_cache.enabled = True
|
|
1579
1745
|
previous: tuple[int, int] | None = None
|
|
1580
1746
|
while True:
|
|
1581
1747
|
stat = watched.stat()
|
|
@@ -1590,11 +1756,34 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1590
1756
|
)
|
|
1591
1757
|
_emit_result(watched_result, False)
|
|
1592
1758
|
time.sleep(args.watch_interval)
|
|
1759
|
+
check_subject = (
|
|
1760
|
+
Path(args.inputs[-1]).name
|
|
1761
|
+
if args.inputs and args.inputs[-1] != "-"
|
|
1762
|
+
else "stdin"
|
|
1763
|
+
if args.inputs
|
|
1764
|
+
else Path(args.project or ".").resolve().name
|
|
1765
|
+
)
|
|
1766
|
+
runtime.events.emit("check.started", "Checking Lean input", subject=check_subject)
|
|
1593
1767
|
if args.project is not None and args.package_refs:
|
|
1594
1768
|
raise ValueError("check cannot combine --project with --with")
|
|
1769
|
+
if args.environment is not None and (
|
|
1770
|
+
args.package_refs or args.project or args.toolchain
|
|
1771
|
+
):
|
|
1772
|
+
raise ValueError(
|
|
1773
|
+
"check --environment cannot be combined with --with, --project, or --toolchain"
|
|
1774
|
+
)
|
|
1775
|
+
legacy_environment = (
|
|
1776
|
+
args.environment is None
|
|
1777
|
+
and not args.package_refs
|
|
1778
|
+
and len(args.inputs) == 2
|
|
1779
|
+
and args.inputs[0] != "-"
|
|
1780
|
+
and not Path(args.inputs[0]).exists()
|
|
1781
|
+
)
|
|
1595
1782
|
if not args.inputs:
|
|
1596
1783
|
if args.package_refs or args.include:
|
|
1597
1784
|
raise ValueError("project-wide check does not accept --with or --include")
|
|
1785
|
+
if args.environment is not None:
|
|
1786
|
+
raise ValueError("check --environment requires at least one FILE")
|
|
1598
1787
|
result = runtime.check_project(
|
|
1599
1788
|
args.project or Path("."), toolchain=args.toolchain, policy=_policy(args)
|
|
1600
1789
|
)
|
|
@@ -1604,11 +1793,22 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1604
1793
|
raise ValueError("check with --with expects exactly one FILE")
|
|
1605
1794
|
environment = runtime.open_references(args.package_refs, toolchain=args.toolchain)
|
|
1606
1795
|
source_file = Path(args.inputs[0])
|
|
1607
|
-
elif
|
|
1608
|
-
if args.
|
|
1609
|
-
raise ValueError("
|
|
1610
|
-
|
|
1611
|
-
|
|
1796
|
+
elif legacy_environment:
|
|
1797
|
+
if args.toolchain:
|
|
1798
|
+
raise ValueError("check --toolchain is only valid with --with")
|
|
1799
|
+
if args.project:
|
|
1800
|
+
raise ValueError("check --project is only valid with a single FILE")
|
|
1801
|
+
environment = runtime.environment(args.inputs[0])
|
|
1802
|
+
source_file = Path(args.inputs[1])
|
|
1803
|
+
elif "-" in args.inputs:
|
|
1804
|
+
if len(args.inputs) != 1:
|
|
1805
|
+
raise ValueError("stdin (-) must be the only check input")
|
|
1806
|
+
if args.environment is not None:
|
|
1807
|
+
environment = runtime.environment(args.environment)
|
|
1808
|
+
source_file = Path("-")
|
|
1809
|
+
else:
|
|
1810
|
+
if args.include:
|
|
1811
|
+
raise ValueError("local project checks do not accept --include")
|
|
1612
1812
|
display_path = "<stdin>"
|
|
1613
1813
|
result = runtime.check(
|
|
1614
1814
|
sys.stdin.read(),
|
|
@@ -1616,23 +1816,26 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1616
1816
|
project=args.project,
|
|
1617
1817
|
policy=_policy(args),
|
|
1618
1818
|
)
|
|
1819
|
+
source_file = None
|
|
1820
|
+
else:
|
|
1821
|
+
selected_files = _expand_check_inputs(args.inputs)
|
|
1822
|
+
if len(selected_files) > 1:
|
|
1823
|
+
if args.include:
|
|
1824
|
+
raise ValueError("multi-file checks do not accept --include")
|
|
1825
|
+
return _run_check_batch(runtime, selected_files, args)
|
|
1826
|
+
if args.environment is not None:
|
|
1827
|
+
environment = runtime.environment(args.environment)
|
|
1828
|
+
source_file = selected_files[0]
|
|
1619
1829
|
else:
|
|
1830
|
+
if args.include:
|
|
1831
|
+
raise ValueError("local project checks do not accept --include")
|
|
1620
1832
|
result = runtime.check_file(
|
|
1621
|
-
|
|
1833
|
+
selected_files[0],
|
|
1622
1834
|
toolchain=args.toolchain,
|
|
1623
1835
|
project=args.project,
|
|
1624
1836
|
policy=_policy(args),
|
|
1625
1837
|
)
|
|
1626
|
-
|
|
1627
|
-
else:
|
|
1628
|
-
if len(args.inputs) != 2:
|
|
1629
|
-
raise ValueError("check expects FILE, ENVIRONMENT FILE, or FILE with --with")
|
|
1630
|
-
if args.toolchain:
|
|
1631
|
-
raise ValueError("check --toolchain is only valid with --with")
|
|
1632
|
-
if args.project:
|
|
1633
|
-
raise ValueError("check --project is only valid with a single FILE")
|
|
1634
|
-
environment = runtime.environment(args.inputs[0])
|
|
1635
|
-
source_file = Path(args.inputs[1])
|
|
1838
|
+
source_file = None
|
|
1636
1839
|
if source_file is None:
|
|
1637
1840
|
pass
|
|
1638
1841
|
elif str(source_file) == "-":
|
|
@@ -1672,9 +1875,11 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1672
1875
|
shared=args.shared,
|
|
1673
1876
|
)
|
|
1674
1877
|
except KeyboardInterrupt:
|
|
1878
|
+
renderer.close()
|
|
1675
1879
|
print("lean-runtime: interrupted", file=sys.stderr)
|
|
1676
1880
|
return 130
|
|
1677
1881
|
except (ResolutionError, MaterializationError) as exc:
|
|
1882
|
+
renderer.close()
|
|
1678
1883
|
details = {
|
|
1679
1884
|
"phase": exc.phase,
|
|
1680
1885
|
"command": list(exc.command),
|
|
@@ -1694,6 +1899,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1694
1899
|
_print_operation_failure(exc, verbose=args.verbose)
|
|
1695
1900
|
return 2
|
|
1696
1901
|
except PublicationError as exc:
|
|
1902
|
+
renderer.close()
|
|
1697
1903
|
if getattr(args, "json", False):
|
|
1698
1904
|
_json(
|
|
1699
1905
|
envelope(
|
|
@@ -1707,6 +1913,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1707
1913
|
_print_publication_failure(exc)
|
|
1708
1914
|
return exc.exit_code
|
|
1709
1915
|
except (LeanRuntimeError, OSError, UnicodeError, ValueError, json.JSONDecodeError) as exc:
|
|
1916
|
+
renderer.close()
|
|
1710
1917
|
if getattr(args, "json", False):
|
|
1711
1918
|
_json(
|
|
1712
1919
|
envelope(
|
|
@@ -1719,6 +1926,18 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1719
1926
|
else:
|
|
1720
1927
|
print(f"lean-runtime: {exc}", file=sys.stderr)
|
|
1721
1928
|
return 2
|
|
1929
|
+
if args.command in {"check", "check-file"}:
|
|
1930
|
+
runtime.events.emit("check.completed", "Lean check completed", ok=result.ok)
|
|
1931
|
+
total_ms = round((time.monotonic() - operation_started) * 1000)
|
|
1932
|
+
accounted_ms = sum(timing.duration_ms for timing in result.timings)
|
|
1933
|
+
result = replace(
|
|
1934
|
+
result,
|
|
1935
|
+
timings=(
|
|
1936
|
+
PhaseTiming("command_preparation", max(0, total_ms - accounted_ms)),
|
|
1937
|
+
*result.timings,
|
|
1938
|
+
),
|
|
1939
|
+
)
|
|
1940
|
+
renderer.close()
|
|
1722
1941
|
_emit_result(result, args.json, display_path=display_path)
|
|
1723
1942
|
if args.timings:
|
|
1724
1943
|
print(render_timings(result.timings), file=sys.stderr)
|
|
@@ -215,6 +215,25 @@ class ConsoleRenderer:
|
|
|
215
215
|
def _render_capability_required(self, event: RuntimeEvent) -> None:
|
|
216
216
|
self._print(event.message)
|
|
217
217
|
|
|
218
|
+
def _render_check_started(self, event: RuntimeEvent) -> None:
|
|
219
|
+
if self.mode != "tty":
|
|
220
|
+
return
|
|
221
|
+
subject = str(event.data.get("subject") or "Lean input")
|
|
222
|
+
message = f"Checking {subject}…"
|
|
223
|
+
self.stream.write("\r" + self.style.cyan(message))
|
|
224
|
+
self.stream.flush()
|
|
225
|
+
self._line_length = len(message)
|
|
226
|
+
|
|
227
|
+
def _render_check_completed(self, _event: RuntimeEvent) -> None:
|
|
228
|
+
self._end_progress_line()
|
|
229
|
+
|
|
230
|
+
def _render_check_header_wait(self, event: RuntimeEvent) -> None:
|
|
231
|
+
module = str(event.data.get("module") or "Lean input")
|
|
232
|
+
self._print(f"Waiting for header snapshot initialization: {module}")
|
|
233
|
+
|
|
234
|
+
def _render_project_workspace_lock_wait(self, event: RuntimeEvent) -> None:
|
|
235
|
+
self._print(event.message)
|
|
236
|
+
|
|
218
237
|
# -- low-level output -----------------------------------------------
|
|
219
238
|
|
|
220
239
|
def _verbose_line(self, event: RuntimeEvent) -> None:
|