lean-runtime 2.0.0__tar.gz → 2.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/CHANGELOG.md +7 -0
- {lean_runtime-2.0.0/lean_runtime.egg-info → lean_runtime-2.0.1}/PKG-INFO +1 -1
- lean_runtime-2.0.1/lean_runtime/_git.py +13 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/bundles.py +4 -4
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/environments.py +7 -7
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/projects.py +2 -1
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/references.py +4 -3
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/resolver.py +4 -3
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/store.py +10 -8
- {lean_runtime-2.0.0 → lean_runtime-2.0.1/lean_runtime.egg-info}/PKG-INFO +1 -1
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/SOURCES.txt +2 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/pyproject.toml +1 -1
- lean_runtime-2.0.1/tests/test_git.py +12 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_store.py +28 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/LICENSE +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/MANIFEST.in +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/README.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/compatibility/README.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/compatibility/mathlib-4.32.2.json +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/compatibility/mathlib-4.32.2.toml +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/architecture.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/captures.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/case-study-v1.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/cli.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/development.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/environments.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/getting-started.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/index.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/local-projects.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/portable-copies.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/python-api.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/ready-programs.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/standalone-files.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/trust-and-limitations.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/docs/v1-precision.md +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/examples/mathlib.toml +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/__init__.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/__main__.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/backends.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/cli.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/comparison.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/decisions.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/diagnostics.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/errors.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/events.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/facade.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/frontmatter.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/health.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/lake.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/lockfiles.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/locking.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/matrix.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/models.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/oci.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/policies.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/profiling.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/programs.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/publisher_verification.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/py.typed +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/run_cli.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/runtime.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/schema_resources.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/serialization.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/specs.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/timings.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/toolchains.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/verification.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime/wire.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/dependency_links.txt +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/entry_points.txt +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/requires.txt +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/lean_runtime.egg-info/top_level.txt +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/mkdocs.yml +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/cleanup-v1.schema.json +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/comparison-v1.schema.json +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/execution-v1.schema.json +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/inspect-v1.schema.json +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/matrix-v1.schema.json +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/profile-v1.schema.json +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/schemas/verify-v1.schema.json +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/scripts/run_compatibility.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/scripts/run_v1_case_study.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/scripts/smoke_wheel.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/setup.cfg +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/conftest.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_backend.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_bundles.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_cli.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_diagnostics.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_environment_integration.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_events_health.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_facade.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_frontmatter.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_interactive.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_lockfiles.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_multifile.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_prebuilt_policy.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_programs.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_projects.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_references.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_run_cli.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_runtime.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_schema_resources.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_schemas.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_signatures.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_specs.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_toolchains.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_v1_precision.py +0 -0
- {lean_runtime-2.0.0 → lean_runtime-2.0.1}/tests/test_verification_inventory.py +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.1
|
|
4
|
+
|
|
5
|
+
- Enable Git's long-path support for every Runtime-managed source operation so
|
|
6
|
+
Mathlib environments can be prepared and materialized on Windows.
|
|
7
|
+
- Preserve the primary Git diagnostic when cleanup of a failed Windows source
|
|
8
|
+
checkout also encounters locked files.
|
|
9
|
+
|
|
3
10
|
## 2.0.0
|
|
4
11
|
|
|
5
12
|
Version 2 gives the public interface the language used by Lean users rather
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Internal construction of portable Git commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def git_command(*arguments: str) -> list[str]:
|
|
7
|
+
"""Return a Git command that can materialize Lean's deep source trees.
|
|
8
|
+
|
|
9
|
+
``core.longpaths`` is meaningful on Git for Windows and harmless on other
|
|
10
|
+
platforms. Supplying it per invocation avoids mutable global Git settings.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
return ["git", "-c", "core.longpaths=true", *arguments]
|
|
@@ -19,6 +19,7 @@ from datetime import datetime, timezone
|
|
|
19
19
|
from pathlib import Path, PurePosixPath
|
|
20
20
|
from typing import Any
|
|
21
21
|
|
|
22
|
+
from ._git import git_command
|
|
22
23
|
from .backends import Backend
|
|
23
24
|
from .errors import EnvironmentError
|
|
24
25
|
from .events import EventEmitter
|
|
@@ -281,7 +282,7 @@ def _verify_package(root: Path, package: LockedPackage) -> None:
|
|
|
281
282
|
observed: list[str] = []
|
|
282
283
|
for revision in ("HEAD", "HEAD^{tree}"):
|
|
283
284
|
result = subprocess.run(
|
|
284
|
-
|
|
285
|
+
git_command("-C", str(root), "rev-parse", revision),
|
|
285
286
|
text=True,
|
|
286
287
|
capture_output=True,
|
|
287
288
|
check=False,
|
|
@@ -292,15 +293,14 @@ def _verify_package(root: Path, package: LockedPackage) -> None:
|
|
|
292
293
|
if observed != [package.revision.lower(), package.tree_hash.lower()]:
|
|
293
294
|
raise EnvironmentError(f"bundled package source mismatch: {package.name}")
|
|
294
295
|
status = subprocess.run(
|
|
295
|
-
|
|
296
|
-
"git",
|
|
296
|
+
git_command(
|
|
297
297
|
"-C",
|
|
298
298
|
str(root),
|
|
299
299
|
"status",
|
|
300
300
|
"--porcelain=v1",
|
|
301
301
|
"--untracked-files=all",
|
|
302
302
|
"--ignored=no",
|
|
303
|
-
|
|
303
|
+
),
|
|
304
304
|
text=True,
|
|
305
305
|
capture_output=True,
|
|
306
306
|
check=False,
|
|
@@ -20,6 +20,7 @@ from datetime import datetime, timezone
|
|
|
20
20
|
from pathlib import Path, PurePosixPath
|
|
21
21
|
from typing import Any, Generic, TextIO, TypeVar, cast
|
|
22
22
|
|
|
23
|
+
from ._git import git_command
|
|
23
24
|
from .backends import Backend, BackendResult, InteractiveProcess, InteractiveTextReader
|
|
24
25
|
from .diagnostics import error_diagnostic, parse_diagnostics
|
|
25
26
|
from .errors import EnvironmentError, MaterializationError, PolicyError
|
|
@@ -1138,18 +1139,17 @@ class EnvironmentManager:
|
|
|
1138
1139
|
) as raw:
|
|
1139
1140
|
checkout = Path(raw)
|
|
1140
1141
|
commands = [
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
"git",
|
|
1142
|
+
git_command("init", "-q"),
|
|
1143
|
+
git_command("remote", "add", "origin", package.url),
|
|
1144
|
+
git_command(
|
|
1145
1145
|
"fetch",
|
|
1146
1146
|
"--depth",
|
|
1147
1147
|
"1",
|
|
1148
1148
|
"--filter=blob:none",
|
|
1149
1149
|
"origin",
|
|
1150
1150
|
package.revision,
|
|
1151
|
-
|
|
1152
|
-
|
|
1151
|
+
),
|
|
1152
|
+
git_command("checkout", "--detach", "FETCH_HEAD"),
|
|
1153
1153
|
]
|
|
1154
1154
|
for command in commands:
|
|
1155
1155
|
completed = subprocess.run(
|
|
@@ -1168,7 +1168,7 @@ class EnvironmentManager:
|
|
|
1168
1168
|
output=completed.stdout + completed.stderr,
|
|
1169
1169
|
)
|
|
1170
1170
|
tree = subprocess.run(
|
|
1171
|
-
|
|
1171
|
+
git_command("rev-parse", "HEAD^{tree}"),
|
|
1172
1172
|
cwd=checkout,
|
|
1173
1173
|
text=True,
|
|
1174
1174
|
capture_output=True,
|
|
@@ -13,6 +13,7 @@ from dataclasses import dataclass
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import TYPE_CHECKING, Any
|
|
15
15
|
|
|
16
|
+
from ._git import git_command
|
|
16
17
|
from .errors import ProjectError
|
|
17
18
|
from .models import ExecutionResult, ProjectProvenance
|
|
18
19
|
from .policies import ExecutionPolicy
|
|
@@ -31,7 +32,7 @@ def _file_digest(path: Path) -> str | None:
|
|
|
31
32
|
|
|
32
33
|
def _git(root: Path, *arguments: str) -> str | None:
|
|
33
34
|
result = subprocess.run(
|
|
34
|
-
|
|
35
|
+
git_command("-C", str(root), *arguments),
|
|
35
36
|
text=True,
|
|
36
37
|
capture_output=True,
|
|
37
38
|
check=False,
|
|
@@ -17,6 +17,7 @@ if sys.version_info >= (3, 11):
|
|
|
17
17
|
else: # pragma: no cover - exercised by the Python 3.10 CI job
|
|
18
18
|
import tomli as tomllib
|
|
19
19
|
|
|
20
|
+
from ._git import git_command
|
|
20
21
|
from .errors import ResolutionError, SpecificationError
|
|
21
22
|
from .specs import GitPackage
|
|
22
23
|
from .toolchains import ToolchainManager, normalize_toolchain
|
|
@@ -126,7 +127,7 @@ class DiscoveredPackage:
|
|
|
126
127
|
def _run_git(arguments: list[str], *, cwd: Path | None = None, timeout: float = 120) -> str:
|
|
127
128
|
try:
|
|
128
129
|
process = subprocess.run(
|
|
129
|
-
|
|
130
|
+
git_command(*arguments),
|
|
130
131
|
cwd=cwd,
|
|
131
132
|
text=True,
|
|
132
133
|
capture_output=True,
|
|
@@ -137,7 +138,7 @@ def _run_git(arguments: list[str], *, cwd: Path | None = None, timeout: float =
|
|
|
137
138
|
raise ResolutionError(
|
|
138
139
|
"package-reference Git operation timed out",
|
|
139
140
|
phase="package-discovery",
|
|
140
|
-
command=(
|
|
141
|
+
command=tuple(git_command(*arguments)),
|
|
141
142
|
exit_code=124,
|
|
142
143
|
output=str(exc.stdout or "") + str(exc.stderr or ""),
|
|
143
144
|
) from exc
|
|
@@ -145,7 +146,7 @@ def _run_git(arguments: list[str], *, cwd: Path | None = None, timeout: float =
|
|
|
145
146
|
raise ResolutionError(
|
|
146
147
|
"could not acquire package-reference metadata",
|
|
147
148
|
phase="package-discovery",
|
|
148
|
-
command=(
|
|
149
|
+
command=tuple(git_command(*arguments)),
|
|
149
150
|
exit_code=process.returncode,
|
|
150
151
|
output=process.stdout + process.stderr,
|
|
151
152
|
)
|
|
@@ -11,6 +11,7 @@ from dataclasses import replace
|
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
|
+
from ._git import git_command
|
|
14
15
|
from .backends import Backend
|
|
15
16
|
from .errors import ResolutionError
|
|
16
17
|
from .events import EventEmitter
|
|
@@ -27,7 +28,7 @@ _COMMIT = re.compile(r"[0-9a-fA-F]{40}")
|
|
|
27
28
|
|
|
28
29
|
def _git(path: Path, *arguments: str) -> str:
|
|
29
30
|
process = subprocess.run(
|
|
30
|
-
|
|
31
|
+
git_command("-C", str(path), *arguments),
|
|
31
32
|
text=True,
|
|
32
33
|
capture_output=True,
|
|
33
34
|
check=False,
|
|
@@ -36,7 +37,7 @@ def _git(path: Path, *arguments: str) -> str:
|
|
|
36
37
|
raise ResolutionError(
|
|
37
38
|
f"could not inspect resolved Git package at {path}",
|
|
38
39
|
phase="lock-validation",
|
|
39
|
-
command=("
|
|
40
|
+
command=tuple(git_command("-C", str(path), *arguments)),
|
|
40
41
|
exit_code=process.returncode,
|
|
41
42
|
output=process.stdout + process.stderr,
|
|
42
43
|
)
|
|
@@ -144,7 +145,7 @@ class EnvironmentResolver:
|
|
|
144
145
|
pinned.append(package)
|
|
145
146
|
continue
|
|
146
147
|
reference = f"refs/tags/{package.rev}"
|
|
147
|
-
command =
|
|
148
|
+
command = git_command("ls-remote", package.url, reference, f"{reference}^{{}}")
|
|
148
149
|
process = self.backend.execute(
|
|
149
150
|
command,
|
|
150
151
|
cwd=self.store.home,
|
|
@@ -17,6 +17,7 @@ from dataclasses import dataclass
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from typing import Any
|
|
19
19
|
|
|
20
|
+
from ._git import git_command
|
|
20
21
|
from .errors import EnvironmentError
|
|
21
22
|
from .lockfiles import EnvironmentLock
|
|
22
23
|
from .locking import FileLock
|
|
@@ -271,7 +272,7 @@ class EnvironmentStore:
|
|
|
271
272
|
observed = []
|
|
272
273
|
for arguments in commands:
|
|
273
274
|
process = subprocess.run(
|
|
274
|
-
|
|
275
|
+
git_command("-C", str(source), *arguments),
|
|
275
276
|
text=True,
|
|
276
277
|
capture_output=True,
|
|
277
278
|
check=False,
|
|
@@ -298,8 +299,7 @@ class EnvironmentStore:
|
|
|
298
299
|
parent.mkdir(parents=True, exist_ok=True)
|
|
299
300
|
stage = parent / f".staging-{os.getpid()}-{uuid.uuid4().hex}"
|
|
300
301
|
try:
|
|
301
|
-
command =
|
|
302
|
-
"git",
|
|
302
|
+
command = git_command(
|
|
303
303
|
"clone",
|
|
304
304
|
"--quiet",
|
|
305
305
|
"--no-local",
|
|
@@ -308,7 +308,7 @@ class EnvironmentStore:
|
|
|
308
308
|
"--no-tags",
|
|
309
309
|
checkout.resolve().as_uri(),
|
|
310
310
|
str(stage),
|
|
311
|
-
|
|
311
|
+
)
|
|
312
312
|
process = subprocess.run(
|
|
313
313
|
command,
|
|
314
314
|
text=True,
|
|
@@ -322,15 +322,14 @@ class EnvironmentStore:
|
|
|
322
322
|
+ process.stderr
|
|
323
323
|
)
|
|
324
324
|
remote = subprocess.run(
|
|
325
|
-
|
|
326
|
-
"git",
|
|
325
|
+
git_command(
|
|
327
326
|
"-C",
|
|
328
327
|
str(stage),
|
|
329
328
|
"remote",
|
|
330
329
|
"set-url",
|
|
331
330
|
"origin",
|
|
332
331
|
str(metadata["url"]),
|
|
333
|
-
|
|
332
|
+
),
|
|
334
333
|
text=True,
|
|
335
334
|
capture_output=True,
|
|
336
335
|
check=False,
|
|
@@ -346,7 +345,10 @@ class EnvironmentStore:
|
|
|
346
345
|
stage.replace(destination)
|
|
347
346
|
finally:
|
|
348
347
|
if stage.exists():
|
|
349
|
-
|
|
348
|
+
# Failed Git checkouts can leave locked pack files on
|
|
349
|
+
# Windows. Cleanup must not mask the actionable Git error.
|
|
350
|
+
with suppress(OSError):
|
|
351
|
+
shutil.rmtree(stage)
|
|
350
352
|
return destination
|
|
351
353
|
|
|
352
354
|
def environment_path(self, environment_id: str) -> Path:
|
|
@@ -25,6 +25,7 @@ docs/v1-precision.md
|
|
|
25
25
|
examples/mathlib.toml
|
|
26
26
|
lean_runtime/__init__.py
|
|
27
27
|
lean_runtime/__main__.py
|
|
28
|
+
lean_runtime/_git.py
|
|
28
29
|
lean_runtime/backends.py
|
|
29
30
|
lean_runtime/bundles.py
|
|
30
31
|
lean_runtime/cli.py
|
|
@@ -86,6 +87,7 @@ tests/test_environment_integration.py
|
|
|
86
87
|
tests/test_events_health.py
|
|
87
88
|
tests/test_facade.py
|
|
88
89
|
tests/test_frontmatter.py
|
|
90
|
+
tests/test_git.py
|
|
89
91
|
tests/test_interactive.py
|
|
90
92
|
tests/test_lockfiles.py
|
|
91
93
|
tests/test_multifile.py
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from lean_runtime._git import git_command
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_git_commands_enable_windows_long_paths_without_global_configuration() -> None:
|
|
5
|
+
assert git_command("clone", "source", "destination") == [
|
|
6
|
+
"git",
|
|
7
|
+
"-c",
|
|
8
|
+
"core.longpaths=true",
|
|
9
|
+
"clone",
|
|
10
|
+
"source",
|
|
11
|
+
"destination",
|
|
12
|
+
]
|
|
@@ -197,3 +197,31 @@ def test_source_snapshot_is_shallow_and_detects_content_changes(tmp_path: Path)
|
|
|
197
197
|
revision=revision,
|
|
198
198
|
tree_hash=tree_hash,
|
|
199
199
|
)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def test_source_snapshot_preserves_git_error_when_cleanup_also_fails(
|
|
203
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
204
|
+
) -> None:
|
|
205
|
+
checkout = tmp_path / "checkout"
|
|
206
|
+
checkout.mkdir()
|
|
207
|
+
store = EnvironmentStore(tmp_path / "store")
|
|
208
|
+
source_id = "source_" + "2" * 64
|
|
209
|
+
metadata = {
|
|
210
|
+
"source_id": source_id,
|
|
211
|
+
"url": "https://example.test/package",
|
|
212
|
+
"revision": "a" * 40,
|
|
213
|
+
"tree_hash": "b" * 40,
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
def failed_clone(command: list[str], **_kwargs: object) -> subprocess.CompletedProcess[str]:
|
|
217
|
+
Path(command[-1]).mkdir()
|
|
218
|
+
return subprocess.CompletedProcess(command, 1, "", "Filename too long")
|
|
219
|
+
|
|
220
|
+
def failed_cleanup(_path: Path) -> None:
|
|
221
|
+
raise PermissionError("pack file is locked")
|
|
222
|
+
|
|
223
|
+
monkeypatch.setattr("lean_runtime.store.subprocess.run", failed_clone)
|
|
224
|
+
monkeypatch.setattr("lean_runtime.store.shutil.rmtree", failed_cleanup)
|
|
225
|
+
|
|
226
|
+
with pytest.raises(EnvironmentError, match="Filename too long"):
|
|
227
|
+
store.publish_source(checkout, source_id, metadata)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|