tlaplus-cli 0.3.4__tar.gz → 0.4.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.
- {tlaplus_cli-0.3.4/src/tlaplus_cli.egg-info → tlaplus_cli-0.4.1}/PKG-INFO +38 -2
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/README.md +37 -1
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/pyproject.toml +7 -2
- tlaplus_cli-0.4.1/src/tlaplus_cli/cache/github.py +28 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/src/tlaplus_cli/cli.py +10 -24
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/__init__.py +0 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/check_java.py +19 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/config/__init__.py +6 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/config/edit.py +34 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/config/list.py +16 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/fetch_cache/__init__.py +5 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/fetch_cache/clear.py +11 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/modules/__init__.py +5 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/modules/build.py +30 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/modules/lib.py +46 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/modules/path.py +39 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tlc.py +51 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/__init__.py +8 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/dir.py +16 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/install.py +79 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/list.py +80 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/meta/__init__.py +5 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/meta/sync.py +33 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/path.py +33 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/pin.py +31 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/uninstall.py +103 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/cmd/tools/upgrade.py +76 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/config/__init__.py +0 -0
- tlaplus_cli-0.3.4/src/tlaplus_cli/config.py → tlaplus_cli-0.4.1/src/tlaplus_cli/config/loader.py +24 -4
- tlaplus_cli-0.3.4/src/tlaplus_cli/settings.py → tlaplus_cli-0.4.1/src/tlaplus_cli/config/schema.py +2 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/java/__init__.py +7 -0
- tlaplus_cli-0.3.4/src/tlaplus_cli/check_java.py → tlaplus_cli-0.4.1/src/tlaplus_cli/java/inspector.py +15 -11
- tlaplus_cli-0.4.1/src/tlaplus_cli/project/__init__.py +3 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/py.typed +0 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/tlc/__init__.py +0 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/tlc/compiler.py +58 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/tlc/runner.py +102 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/ui.py +6 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/versioning/__init__.py +53 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/versioning/api.py +110 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/versioning/downloader.py +93 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/versioning/metadata.py +92 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/versioning/paths.py +83 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/versioning/resolver.py +92 -0
- tlaplus_cli-0.4.1/src/tlaplus_cli/versioning/schema.py +27 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1/src/tlaplus_cli.egg-info}/PKG-INFO +38 -2
- tlaplus_cli-0.4.1/src/tlaplus_cli.egg-info/SOURCES.txt +66 -0
- tlaplus_cli-0.4.1/tests/test_build_modules_path.py +50 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/tests/test_cli.py +1 -4
- tlaplus_cli-0.4.1/tests/test_config.py +59 -0
- tlaplus_cli-0.4.1/tests/test_config_suite.py +74 -0
- tlaplus_cli-0.4.1/tests/test_modules_build_lib.py +88 -0
- tlaplus_cli-0.4.1/tests/test_modules_lib.py +106 -0
- tlaplus_cli-0.4.1/tests/test_modules_path.py +101 -0
- tlaplus_cli-0.4.1/tests/test_settings.py +38 -0
- tlaplus_cli-0.4.1/tests/test_tlc_modules_path.py +43 -0
- tlaplus_cli-0.3.4/src/tlaplus_cli/build_tlc_module.py +0 -73
- tlaplus_cli-0.3.4/src/tlaplus_cli/run_tlc.py +0 -111
- tlaplus_cli-0.3.4/src/tlaplus_cli/tools_manager.py +0 -385
- tlaplus_cli-0.3.4/src/tlaplus_cli/version_manager.py +0 -504
- tlaplus_cli-0.3.4/src/tlaplus_cli.egg-info/SOURCES.txt +0 -32
- tlaplus_cli-0.3.4/tests/test_build_tlc_module.py +0 -161
- tlaplus_cli-0.3.4/tests/test_check_java.py +0 -69
- tlaplus_cli-0.3.4/tests/test_java_module_naming.py +0 -86
- tlaplus_cli-0.3.4/tests/test_project.py +0 -50
- tlaplus_cli-0.3.4/tests/test_run_tlc.py +0 -96
- tlaplus_cli-0.3.4/tests/test_spec_resolution.py +0 -200
- tlaplus_cli-0.3.4/tests/test_tools_manager.py +0 -830
- tlaplus_cli-0.3.4/tests/test_version_manager.py +0 -322
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/LICENSE +0 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/MANIFEST.in +0 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/setup.cfg +0 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/src/tlaplus_cli/__init__.py +0 -0
- /tlaplus_cli-0.3.4/src/tlaplus_cli/py.typed → /tlaplus_cli-0.4.1/src/tlaplus_cli/cache/__init__.py +0 -0
- /tlaplus_cli-0.3.4/src/tlaplus_cli/project.py → /tlaplus_cli-0.4.1/src/tlaplus_cli/project/core.py +0 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/src/tlaplus_cli/resources/__init__.py +0 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/src/tlaplus_cli/resources/default_config.yaml +0 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/src/tlaplus_cli.egg-info/dependency_links.txt +0 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/src/tlaplus_cli.egg-info/entry_points.txt +0 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/src/tlaplus_cli.egg-info/requires.txt +0 -0
- {tlaplus_cli-0.3.4 → tlaplus_cli-0.4.1}/src/tlaplus_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tlaplus-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: TLA+ tools: download TLC, compile custom modules, run model checker
|
|
5
5
|
Author-email: Denis Nikolskiy <codeomatics@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -170,6 +170,31 @@ Compile modules in a specific project path:
|
|
|
170
170
|
tla modules build path/to/project
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
+
Configure a persistent custom modules path:
|
|
174
|
+
```bash
|
|
175
|
+
tla modules path /path/to/custom/modules
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
View or reset the custom modules path:
|
|
179
|
+
```bash
|
|
180
|
+
tla modules path # View current path
|
|
181
|
+
tla modules path none # Reset to default
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Configure a persistent custom modules dependencies (lib) path:
|
|
185
|
+
```bash
|
|
186
|
+
tla modules lib /path/to/custom/libs
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
View or reset the custom lib path:
|
|
190
|
+
```bash
|
|
191
|
+
tla modules lib # View current path
|
|
192
|
+
tla modules lib none # Reset to default
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
> [!TIP]
|
|
196
|
+
> Setting a persistent `module_path` (and optionally `module_lib_path`) allows `tla modules build` and `tla tlc` to resolve your Java overrides regardless of where the commands are executed.
|
|
197
|
+
|
|
173
198
|
Verbose output:
|
|
174
199
|
```bash
|
|
175
200
|
tla modules build --verbose
|
|
@@ -203,7 +228,15 @@ On first run, a default config is created at:
|
|
|
203
228
|
~/.config/tla/config.yaml
|
|
204
229
|
```
|
|
205
230
|
|
|
206
|
-
|
|
231
|
+
You can manage the configuration using the `tla config` command:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
tla config list # Display current configuration
|
|
235
|
+
tla config edit # Open config in default editor ($EDITOR or vim)
|
|
236
|
+
tla config edit nano # Open config in a specific editor
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Example configuration (`config.yaml`):
|
|
207
240
|
|
|
208
241
|
```yaml
|
|
209
242
|
tla:
|
|
@@ -221,6 +254,9 @@ tlc:
|
|
|
221
254
|
java_class: tlc2.TLC
|
|
222
255
|
overrides_class: tlc2.overrides.TLCOverrides
|
|
223
256
|
|
|
257
|
+
module_path: null # (Optional) Persistent custom modules path
|
|
258
|
+
module_lib_path: null # (Optional) Persistent custom modules lib path
|
|
259
|
+
|
|
224
260
|
java:
|
|
225
261
|
min_version: 11
|
|
226
262
|
opts:
|
|
@@ -141,6 +141,31 @@ Compile modules in a specific project path:
|
|
|
141
141
|
tla modules build path/to/project
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
Configure a persistent custom modules path:
|
|
145
|
+
```bash
|
|
146
|
+
tla modules path /path/to/custom/modules
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
View or reset the custom modules path:
|
|
150
|
+
```bash
|
|
151
|
+
tla modules path # View current path
|
|
152
|
+
tla modules path none # Reset to default
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Configure a persistent custom modules dependencies (lib) path:
|
|
156
|
+
```bash
|
|
157
|
+
tla modules lib /path/to/custom/libs
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
View or reset the custom lib path:
|
|
161
|
+
```bash
|
|
162
|
+
tla modules lib # View current path
|
|
163
|
+
tla modules lib none # Reset to default
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
> [!TIP]
|
|
167
|
+
> Setting a persistent `module_path` (and optionally `module_lib_path`) allows `tla modules build` and `tla tlc` to resolve your Java overrides regardless of where the commands are executed.
|
|
168
|
+
|
|
144
169
|
Verbose output:
|
|
145
170
|
```bash
|
|
146
171
|
tla modules build --verbose
|
|
@@ -174,7 +199,15 @@ On first run, a default config is created at:
|
|
|
174
199
|
~/.config/tla/config.yaml
|
|
175
200
|
```
|
|
176
201
|
|
|
177
|
-
|
|
202
|
+
You can manage the configuration using the `tla config` command:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
tla config list # Display current configuration
|
|
206
|
+
tla config edit # Open config in default editor ($EDITOR or vim)
|
|
207
|
+
tla config edit nano # Open config in a specific editor
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Example configuration (`config.yaml`):
|
|
178
211
|
|
|
179
212
|
```yaml
|
|
180
213
|
tla:
|
|
@@ -192,6 +225,9 @@ tlc:
|
|
|
192
225
|
java_class: tlc2.TLC
|
|
193
226
|
overrides_class: tlc2.overrides.TLCOverrides
|
|
194
227
|
|
|
228
|
+
module_path: null # (Optional) Persistent custom modules path
|
|
229
|
+
module_lib_path: null # (Optional) Persistent custom modules lib path
|
|
230
|
+
|
|
195
231
|
java:
|
|
196
232
|
min_version: 11
|
|
197
233
|
opts:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tlaplus-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.1"
|
|
8
8
|
description = "TLA+ tools: download TLC, compile custom modules, run model checker"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -62,6 +62,7 @@ dev = [
|
|
|
62
62
|
"pre-commit>=3.5.0,<4.0.0",
|
|
63
63
|
"pre-commit-hooks>=6.0.0,<7.0.0",
|
|
64
64
|
"twine>=6.0.0,<7.0.0",
|
|
65
|
+
"bandit>=1.9.4",
|
|
65
66
|
]
|
|
66
67
|
|
|
67
68
|
[tool.pytest.ini_options]
|
|
@@ -105,10 +106,14 @@ ignore = [
|
|
|
105
106
|
"PLR0913", # Many arguments are common in tests (fixtures)
|
|
106
107
|
]
|
|
107
108
|
|
|
109
|
+
[tool.bandit]
|
|
110
|
+
skips = ["B404", "B603", "B607"]
|
|
111
|
+
|
|
108
112
|
[tool.poe.tasks]
|
|
109
113
|
check = "pre-commit run --all-files"
|
|
110
|
-
lint = ["lint-ruff", "type-check"]
|
|
114
|
+
lint = ["lint-ruff", "lint-bandit", "type-check"]
|
|
111
115
|
lint-ruff = "ruff check ."
|
|
116
|
+
lint-bandit = "bandit -c pyproject.toml -r src/tlaplus_cli"
|
|
112
117
|
type-check = "mypy ."
|
|
113
118
|
fix = ["format", "lint-fix"]
|
|
114
119
|
format = "ruff format ."
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from dataclasses import asdict
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from tlaplus_cli.ui import warn
|
|
6
|
+
from tlaplus_cli.versioning.schema import RemoteVersion
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def load_github_cache(cache_file: Path) -> list[RemoteVersion] | None:
|
|
10
|
+
"""Load the remote versions cache from disk."""
|
|
11
|
+
if cache_file.exists():
|
|
12
|
+
try:
|
|
13
|
+
with cache_file.open("r", encoding="utf-8") as f:
|
|
14
|
+
data = json.load(f)
|
|
15
|
+
return [RemoteVersion(**item) for item in data]
|
|
16
|
+
except (json.JSONDecodeError, OSError, KeyError, TypeError) as e:
|
|
17
|
+
warn(f"Failed to read cache: {e}")
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def save_github_cache(cache_file: Path, versions: list[RemoteVersion]) -> None:
|
|
22
|
+
"""Save the remote versions cache to disk."""
|
|
23
|
+
try:
|
|
24
|
+
cache_file.parent.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
with cache_file.open("w", encoding="utf-8") as f:
|
|
26
|
+
json.dump([asdict(v) for v in versions], f)
|
|
27
|
+
except OSError as e:
|
|
28
|
+
warn(f"Failed to save cache: {e}")
|
|
@@ -4,11 +4,13 @@ import importlib.metadata
|
|
|
4
4
|
|
|
5
5
|
import typer
|
|
6
6
|
|
|
7
|
-
from tlaplus_cli.
|
|
8
|
-
from tlaplus_cli.
|
|
9
|
-
from tlaplus_cli.
|
|
10
|
-
from tlaplus_cli.
|
|
11
|
-
from tlaplus_cli.
|
|
7
|
+
from tlaplus_cli.cmd.check_java import check_java
|
|
8
|
+
from tlaplus_cli.cmd.config import app as config_app
|
|
9
|
+
from tlaplus_cli.cmd.fetch_cache import app as fetch_cache_app
|
|
10
|
+
from tlaplus_cli.cmd.modules import app as modules_app
|
|
11
|
+
from tlaplus_cli.cmd.tlc import tlc as run_tlc_cmd
|
|
12
|
+
from tlaplus_cli.cmd.tools import app as tools_app
|
|
13
|
+
from tlaplus_cli.config.loader import load_config
|
|
12
14
|
|
|
13
15
|
app = typer.Typer(
|
|
14
16
|
name="tla",
|
|
@@ -28,7 +30,7 @@ def version_callback(value: bool) -> None:
|
|
|
28
30
|
|
|
29
31
|
@app.callback()
|
|
30
32
|
def root(
|
|
31
|
-
version: bool = typer.Option(
|
|
33
|
+
version: bool = typer.Option( # noqa: ARG001
|
|
32
34
|
None,
|
|
33
35
|
"--version",
|
|
34
36
|
"-v",
|
|
@@ -40,33 +42,17 @@ def root(
|
|
|
40
42
|
"""TLA+ CLI tool."""
|
|
41
43
|
# Load config early to trigger first-run copy
|
|
42
44
|
load_config()
|
|
43
|
-
if version:
|
|
44
|
-
# This branch is effectively redundant due to callback, but keeps type checker happy
|
|
45
|
-
pass
|
|
46
45
|
|
|
47
46
|
|
|
48
47
|
# --- Subcommands ---
|
|
49
48
|
|
|
50
|
-
# Attach typer subgroups
|
|
51
|
-
modules_app = typer.Typer(name="modules", help="Manage TLA+ Java modules.", no_args_is_help=True)
|
|
52
|
-
modules_app.command(name="build")(build_tlc_cmd)
|
|
53
|
-
|
|
54
49
|
app.add_typer(modules_app, name="modules")
|
|
55
50
|
app.add_typer(tools_app, name="tools")
|
|
56
51
|
app.add_typer(fetch_cache_app, name="fetch-cache")
|
|
52
|
+
app.add_typer(config_app, name="config")
|
|
57
53
|
|
|
58
54
|
app.command(name="tlc")(run_tlc_cmd)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
@app.command(name="check-java")
|
|
62
|
-
def check_java() -> None:
|
|
63
|
-
"""Check if Java is installed and meets the minimum version requirement."""
|
|
64
|
-
config = load_config()
|
|
65
|
-
version = get_java_version()
|
|
66
|
-
if version:
|
|
67
|
-
typer.echo(f"Detected Java version: {version}")
|
|
68
|
-
check_java_version(config.java.min_version)
|
|
69
|
-
typer.echo(f"Java version is compatible (>= {config.java.min_version}).")
|
|
55
|
+
app.command(name="check-java")(check_java)
|
|
70
56
|
|
|
71
57
|
|
|
72
58
|
def main() -> None:
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from tlaplus_cli.config.loader import load_config
|
|
4
|
+
from tlaplus_cli.java import get_java_version, validate_java_version
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def check_java() -> None:
|
|
8
|
+
"""Check if Java is installed and meets the minimum version requirement."""
|
|
9
|
+
config = load_config()
|
|
10
|
+
version = get_java_version()
|
|
11
|
+
if version:
|
|
12
|
+
typer.echo(f"Detected Java version: {version}")
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
validate_java_version(config.java.min_version)
|
|
16
|
+
typer.echo(f"Java version is compatible (>= {config.java.min_version}).")
|
|
17
|
+
except RuntimeError as e:
|
|
18
|
+
typer.echo(f"Error: {e}", err=True)
|
|
19
|
+
raise typer.Exit(1) from None
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from tlaplus_cli.cmd.config import app
|
|
8
|
+
from tlaplus_cli.config.loader import config_path, load_config
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.command(name="edit")
|
|
12
|
+
def edit_config(
|
|
13
|
+
editor: str | None = typer.Argument(None, help="The editor to use (defaults to $EDITOR or 'vim')."),
|
|
14
|
+
) -> None:
|
|
15
|
+
"""Open the configuration file in an editor."""
|
|
16
|
+
cp = config_path()
|
|
17
|
+
|
|
18
|
+
# Ensure config exists by loading it
|
|
19
|
+
load_config()
|
|
20
|
+
|
|
21
|
+
if not editor:
|
|
22
|
+
editor = os.environ.get("EDITOR", "vim")
|
|
23
|
+
|
|
24
|
+
editor_path = shutil.which(editor)
|
|
25
|
+
if not editor_path:
|
|
26
|
+
typer.echo(f"Error: Editor '{editor}' not found in PATH.", err=True)
|
|
27
|
+
raise typer.Exit(1)
|
|
28
|
+
|
|
29
|
+
typer.echo(f"Opening {cp} with {editor} ...")
|
|
30
|
+
try:
|
|
31
|
+
subprocess.run([editor_path, str(cp)], check=True)
|
|
32
|
+
except subprocess.CalledProcessError as e:
|
|
33
|
+
typer.echo(f"Editor exited with error: {e}", err=True)
|
|
34
|
+
raise typer.Exit(1) from None
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from tlaplus_cli.cmd.config import app
|
|
4
|
+
from tlaplus_cli.config.loader import config_path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@app.command(name="list")
|
|
8
|
+
def list_config() -> None:
|
|
9
|
+
"""Display the current configuration file content."""
|
|
10
|
+
cp = config_path()
|
|
11
|
+
if not cp.exists():
|
|
12
|
+
typer.echo("Configuration file not found.", err=True)
|
|
13
|
+
raise typer.Exit(1)
|
|
14
|
+
|
|
15
|
+
with cp.open(encoding="utf-8") as f:
|
|
16
|
+
typer.echo(f.read())
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from tlaplus_cli.cmd.fetch_cache import app
|
|
4
|
+
from tlaplus_cli.versioning import clear_cache
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@app.command(name="clear")
|
|
8
|
+
def cmd_clear_cache() -> None:
|
|
9
|
+
"""Clear the local cache of remote GitHub versions."""
|
|
10
|
+
clear_cache()
|
|
11
|
+
typer.echo("GitHub versions cache cleared.")
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from tlaplus_cli.cmd.modules import app
|
|
7
|
+
from tlaplus_cli.tlc.compiler import compile_modules
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@app.command(name="build")
|
|
11
|
+
def build(
|
|
12
|
+
path: str | None = typer.Argument(None, help="Project root directory (defaults to workspace root)."),
|
|
13
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show compilation output."),
|
|
14
|
+
) -> None:
|
|
15
|
+
"""Compile custom Java modules."""
|
|
16
|
+
base_dir = Path(path).resolve() if path is not None else None
|
|
17
|
+
|
|
18
|
+
typer.echo("Compiling Java files ...")
|
|
19
|
+
try:
|
|
20
|
+
classes_dir = compile_modules(base_dir, verbose)
|
|
21
|
+
except FileNotFoundError as e:
|
|
22
|
+
typer.echo(f"Error: {e}", err=True)
|
|
23
|
+
raise typer.Exit(1) from None
|
|
24
|
+
except subprocess.CalledProcessError:
|
|
25
|
+
typer.echo("Compilation failed!", err=True)
|
|
26
|
+
raise typer.Exit(1) from None
|
|
27
|
+
|
|
28
|
+
typer.echo(f"Successfully compiled to {classes_dir}")
|
|
29
|
+
service_file = classes_dir / "META-INF" / "services" / "tlc2.overrides.ITLCOverrides"
|
|
30
|
+
typer.echo(f"Created service file at {service_file}")
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from tlaplus_cli.cmd.modules import app
|
|
6
|
+
from tlaplus_cli.config.loader import load_config, save_config, workspace_root
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@app.command(name="lib")
|
|
10
|
+
def set_modules_lib_path(
|
|
11
|
+
path: str | None = typer.Argument(
|
|
12
|
+
None, help="Path to the custom Java modules dependencies directory, or 'none' to reset."
|
|
13
|
+
),
|
|
14
|
+
) -> None:
|
|
15
|
+
"""Configure or view a persistent custom Java modules dependencies (lib) path."""
|
|
16
|
+
config_obj = load_config()
|
|
17
|
+
|
|
18
|
+
if path is None:
|
|
19
|
+
if config_obj.module_lib_path:
|
|
20
|
+
typer.echo(f"Current modules lib path: {config_obj.module_lib_path}")
|
|
21
|
+
else:
|
|
22
|
+
modules_dir = (
|
|
23
|
+
Path(config_obj.module_path)
|
|
24
|
+
if config_obj.module_path
|
|
25
|
+
else workspace_root() / config_obj.workspace.modules_dir
|
|
26
|
+
)
|
|
27
|
+
default_path = modules_dir / "lib"
|
|
28
|
+
typer.echo("Custom modules lib path is not set.")
|
|
29
|
+
typer.echo(f"Defaulting to: {default_path}")
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
if path.lower() == "none":
|
|
33
|
+
config_obj.module_lib_path = None
|
|
34
|
+
save_config(config_obj)
|
|
35
|
+
typer.echo("Custom modules lib path reset to default.")
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
p = Path(path).resolve()
|
|
39
|
+
|
|
40
|
+
if not p.is_dir():
|
|
41
|
+
typer.echo(f"Error: Path does not exist or is not a directory: {p}", err=True)
|
|
42
|
+
raise typer.Exit(1)
|
|
43
|
+
|
|
44
|
+
config_obj.module_lib_path = str(p)
|
|
45
|
+
save_config(config_obj)
|
|
46
|
+
typer.echo(f"Modules lib path updated to: {p}")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from tlaplus_cli.cmd.modules import app
|
|
6
|
+
from tlaplus_cli.config.loader import load_config, save_config, workspace_root
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@app.command(name="path")
|
|
10
|
+
def set_modules_path(
|
|
11
|
+
path: str | None = typer.Argument(None, help="Path to the custom Java modules directory, or 'none' to reset."),
|
|
12
|
+
) -> None:
|
|
13
|
+
"""Configure or view a persistent custom Java modules source path."""
|
|
14
|
+
config_obj = load_config()
|
|
15
|
+
|
|
16
|
+
if path is None:
|
|
17
|
+
if config_obj.module_path:
|
|
18
|
+
typer.echo(f"Current modules path: {config_obj.module_path}")
|
|
19
|
+
else:
|
|
20
|
+
default_path = workspace_root() / config_obj.workspace.modules_dir
|
|
21
|
+
typer.echo("Custom modules path is not set.")
|
|
22
|
+
typer.echo(f"Defaulting to: {default_path}")
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
if path.lower() == "none":
|
|
26
|
+
config_obj.module_path = None
|
|
27
|
+
save_config(config_obj)
|
|
28
|
+
typer.echo("Custom modules path reset to default.")
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
p = Path(path).resolve()
|
|
32
|
+
|
|
33
|
+
if not p.is_dir():
|
|
34
|
+
typer.echo(f"Error: Path does not exist or is not a directory: {p}", err=True)
|
|
35
|
+
raise typer.Exit(1)
|
|
36
|
+
|
|
37
|
+
config_obj.module_path = str(p)
|
|
38
|
+
save_config(config_obj)
|
|
39
|
+
typer.echo(f"Modules path updated to: {p}")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from tlaplus_cli.tlc.compiler import get_tlc_jar_path
|
|
4
|
+
from tlaplus_cli.tlc.runner import get_tlc_version, resolve_spec_file, run_tlc
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def version_callback(value: bool) -> None:
|
|
8
|
+
if value:
|
|
9
|
+
jar_path = get_tlc_jar_path()
|
|
10
|
+
typer.echo(f"tla2tools.jar path: {jar_path}")
|
|
11
|
+
|
|
12
|
+
if not jar_path.exists():
|
|
13
|
+
typer.echo(f"Error: tla2tools.jar not found at {jar_path}", err=True)
|
|
14
|
+
typer.echo("Run 'tla tools install' first.", err=True)
|
|
15
|
+
raise typer.Exit(1)
|
|
16
|
+
|
|
17
|
+
version_str = get_tlc_version()
|
|
18
|
+
if version_str:
|
|
19
|
+
typer.echo(version_str)
|
|
20
|
+
|
|
21
|
+
raise typer.Exit(0)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def tlc(
|
|
25
|
+
spec: str = typer.Argument(help="Name of the TLA+ specification (without .tla extension)."),
|
|
26
|
+
version: bool | None = typer.Option(
|
|
27
|
+
None,
|
|
28
|
+
"--version",
|
|
29
|
+
help="Print the path to tla2tools.jar and its version.",
|
|
30
|
+
callback=version_callback,
|
|
31
|
+
is_eager=True,
|
|
32
|
+
),
|
|
33
|
+
) -> None:
|
|
34
|
+
"""Run TLC model checker on a TLA+ specification."""
|
|
35
|
+
if version:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
_, spec_name = resolve_spec_file(spec)
|
|
40
|
+
except FileNotFoundError as e:
|
|
41
|
+
typer.echo(f"Error: {e}", err=True)
|
|
42
|
+
raise typer.Exit(1) from None
|
|
43
|
+
|
|
44
|
+
typer.echo(f"Running TLC on {spec_name} ...")
|
|
45
|
+
try:
|
|
46
|
+
exit_code = run_tlc(spec)
|
|
47
|
+
except FileNotFoundError as e:
|
|
48
|
+
typer.echo(f"Error: {e}", err=True)
|
|
49
|
+
raise typer.Exit(1) from None
|
|
50
|
+
|
|
51
|
+
raise typer.Exit(exit_code)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from tlaplus_cli.cmd.tools.meta import app as meta_app
|
|
4
|
+
|
|
5
|
+
app = typer.Typer(name="tools", help="Manage TLC tools (tla2tools.jar).", no_args_is_help=True)
|
|
6
|
+
app.add_typer(meta_app, name="meta")
|
|
7
|
+
|
|
8
|
+
from . import dir, install, list, path, pin, uninstall, upgrade # noqa: F401, E402
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from tlaplus_cli.cmd.tools import app
|
|
4
|
+
from tlaplus_cli.versioning import get_tools_dir
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@app.command(name="dir")
|
|
8
|
+
def show_dir() -> None:
|
|
9
|
+
"""Show the absolute path to the local TLC tools cache directory."""
|
|
10
|
+
tools_dir = get_tools_dir()
|
|
11
|
+
typer.echo(str(tools_dir))
|
|
12
|
+
|
|
13
|
+
if tools_dir.is_dir():
|
|
14
|
+
versions = sorted([d.name for d in tools_dir.iterdir() if d.is_dir()])
|
|
15
|
+
for v in versions:
|
|
16
|
+
typer.echo(f" {v}")
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from tlaplus_cli.cmd.tools import app
|
|
7
|
+
from tlaplus_cli.config.loader import load_config
|
|
8
|
+
from tlaplus_cli.versioning import (
|
|
9
|
+
download_version,
|
|
10
|
+
download_version_from_url,
|
|
11
|
+
fetch_remote_versions,
|
|
12
|
+
get_pinned_version_dir,
|
|
13
|
+
get_tools_dir,
|
|
14
|
+
is_url,
|
|
15
|
+
set_pin,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _auto_pin_if_needed(version_dir: Path) -> None:
|
|
20
|
+
"""Pin the version if no version is currently pinned."""
|
|
21
|
+
pinned_dir = get_pinned_version_dir()
|
|
22
|
+
if pinned_dir is None:
|
|
23
|
+
typer.echo(f"Auto-pinning newly installed version {version_dir.name}")
|
|
24
|
+
set_pin(version_dir)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@app.command()
|
|
28
|
+
def install(
|
|
29
|
+
version: str = typer.Argument(None, help="Version tag (e.g. 'v1.8.0') or a direct URL to tla2tools.jar."),
|
|
30
|
+
force: bool = typer.Option(False, "--force", "-f", help="Re-download if already installed."),
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Download and install a specific TLC version."""
|
|
33
|
+
if version and is_url(version):
|
|
34
|
+
try:
|
|
35
|
+
version_dir = download_version_from_url(version)
|
|
36
|
+
except (requests.RequestException, OSError, ValueError) as e:
|
|
37
|
+
typer.echo(f"Error: Failed to download: {e}", err=True)
|
|
38
|
+
raise typer.Exit(1) from e
|
|
39
|
+
else:
|
|
40
|
+
typer.echo("Download complete.")
|
|
41
|
+
typer.echo(f"Successfully installed from URL to {version_dir}")
|
|
42
|
+
_auto_pin_if_needed(version_dir)
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
config = load_config()
|
|
46
|
+
versions, status = fetch_remote_versions(config.tla.urls.tags, config.tla.urls.releases, config.tla.urls.per_page)
|
|
47
|
+
|
|
48
|
+
if not versions:
|
|
49
|
+
typer.echo(f"Error: Could not fetch remote versions (status: {status.value})", err=True)
|
|
50
|
+
raise typer.Exit(1)
|
|
51
|
+
|
|
52
|
+
target = None
|
|
53
|
+
if version:
|
|
54
|
+
target = next((v for v in versions if v.name == version), None)
|
|
55
|
+
if not target:
|
|
56
|
+
typer.echo(f"Error: Version {version} not found.", err=True)
|
|
57
|
+
raise typer.Exit(1)
|
|
58
|
+
else:
|
|
59
|
+
typer.echo("No version specified, selecting latest stable release.")
|
|
60
|
+
# Default to latest non-prerelease
|
|
61
|
+
target = next((v for v in versions if not v.prerelease), versions[0])
|
|
62
|
+
|
|
63
|
+
# Check if already installed
|
|
64
|
+
target_dir = get_tools_dir() / f"{target.name}-{target.short_sha}"
|
|
65
|
+
if target_dir.exists() and not force:
|
|
66
|
+
typer.echo(f"Version {target.name} is already installed.")
|
|
67
|
+
typer.echo(f"Successfully installed {target.name} to {target_dir}")
|
|
68
|
+
_auto_pin_if_needed(target_dir)
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
version_dir = download_version(target, force=force)
|
|
73
|
+
typer.echo("Download complete.")
|
|
74
|
+
typer.echo(f"Successfully installed {target.name} to {version_dir}")
|
|
75
|
+
except (requests.RequestException, OSError) as e:
|
|
76
|
+
typer.echo(f"Error: Failed to download: {e}", err=True)
|
|
77
|
+
raise typer.Exit(1) from e
|
|
78
|
+
|
|
79
|
+
_auto_pin_if_needed(version_dir)
|