tlaplus-cli 0.4.2__tar.gz → 0.6.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.
- {tlaplus_cli-0.4.2/src/tlaplus_cli.egg-info → tlaplus_cli-0.6.0}/PKG-INFO +16 -3
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/README.md +14 -2
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/pyproject.toml +2 -1
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cli.py +1 -1
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/modules/__init__.py +1 -1
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/modules/build.py +12 -1
- tlaplus_cli-0.6.0/src/tlaplus_cli/cmd/modules/install.py +75 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/cmd/modules/path.py +72 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/cmd/tlc.py +159 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/meta/sync.py +2 -1
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/uninstall.py +3 -2
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/config/schema.py +2 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/java/classpath.py +174 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/resources/default_config.yaml +5 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/tlc/codes.py +314 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/tlc/compiler.py +18 -25
- tlaplus_cli-0.6.0/src/tlaplus_cli/tlc/formatter.py +409 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/tlc/models.py +132 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/tlc/parser.py +258 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/tlc/runner.py +151 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/tlc/sany.py +94 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/tlc/values.py +186 -0
- tlaplus_cli-0.6.0/src/tlaplus_cli/ui.py +21 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/versioning/api.py +9 -6
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/versioning/downloader.py +15 -18
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/versioning/paths.py +10 -4
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0/src/tlaplus_cli.egg-info}/PKG-INFO +16 -3
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli.egg-info/SOURCES.txt +13 -1
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli.egg-info/requires.txt +1 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_build_both.py +4 -3
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_modules_build_lib.py +4 -4
- tlaplus_cli-0.6.0/tests/test_modules_build_show_command.py +27 -0
- tlaplus_cli-0.6.0/tests/test_modules_install_community.py +86 -0
- tlaplus_cli-0.6.0/tests/test_modules_path_resolved.py +33 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_tlc_modules_path.py +11 -4
- tlaplus_cli-0.6.0/tests/test_tlc_show_command.py +25 -0
- tlaplus_cli-0.4.2/src/tlaplus_cli/cmd/modules/path.py +0 -39
- tlaplus_cli-0.4.2/src/tlaplus_cli/cmd/tlc.py +0 -51
- tlaplus_cli-0.4.2/src/tlaplus_cli/tlc/runner.py +0 -102
- tlaplus_cli-0.4.2/src/tlaplus_cli/ui.py +0 -6
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/LICENSE +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/MANIFEST.in +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/setup.cfg +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cache/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cache/github.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/check_java.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/config/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/config/edit.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/config/list.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/fetch_cache/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/fetch_cache/clear.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/modules/lib.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/dir.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/install.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/list.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/meta/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/path.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/pin.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/cmd/tools/upgrade.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/config/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/config/loader.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/java/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/java/inspector.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/project/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/project/core.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/py.typed +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/resources/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/tlc/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/versioning/__init__.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/versioning/metadata.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/versioning/resolver.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli/versioning/schema.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli.egg-info/dependency_links.txt +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli.egg-info/entry_points.txt +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/src/tlaplus_cli.egg-info/top_level.txt +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_build_modules_path.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_cli.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_config.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_config_suite.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_modules_lib.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_modules_path.py +0 -0
- {tlaplus_cli-0.4.2 → tlaplus_cli-0.6.0}/tests/test_settings.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tlaplus-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
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
|
|
@@ -25,6 +25,7 @@ Requires-Dist: pyyaml<7.0,>=6.0
|
|
|
25
25
|
Requires-Dist: platformdirs<5.0,>=4.0
|
|
26
26
|
Requires-Dist: pydantic<3.0.0,>=2.12.5
|
|
27
27
|
Requires-Dist: truststore<1.0.0,>=0.9.0
|
|
28
|
+
Requires-Dist: rich<14.0.0,>=13.7.0
|
|
28
29
|
Dynamic: license-file
|
|
29
30
|
|
|
30
31
|
# TLA+ CLI
|
|
@@ -156,6 +157,12 @@ To check the currently pinned `tla2tools.jar` path and its TLC version:
|
|
|
156
157
|
tla tlc --version
|
|
157
158
|
```
|
|
158
159
|
|
|
160
|
+
To inspect the exact Java command that will be executed without running it:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
tla tlc <spec_name> --show-command
|
|
164
|
+
```
|
|
165
|
+
|
|
159
166
|
### Compile Custom Java Modules
|
|
160
167
|
|
|
161
168
|
Java modules (overrides) are compiled using the pinned version of the toolset.
|
|
@@ -177,8 +184,9 @@ tla modules path /path/to/custom/modules
|
|
|
177
184
|
|
|
178
185
|
View or reset the custom modules path:
|
|
179
186
|
```bash
|
|
180
|
-
tla modules path
|
|
181
|
-
tla modules path none
|
|
187
|
+
tla modules path # View current path
|
|
188
|
+
tla modules path none # Reset to default
|
|
189
|
+
tla modules path --resolved # Show fully resolved paths for current context
|
|
182
190
|
```
|
|
183
191
|
|
|
184
192
|
Configure a persistent custom modules dependencies (lib) path:
|
|
@@ -200,6 +208,11 @@ Verbose output:
|
|
|
200
208
|
tla modules build --verbose
|
|
201
209
|
```
|
|
202
210
|
|
|
211
|
+
Show compilation command:
|
|
212
|
+
```bash
|
|
213
|
+
tla modules build --show-command
|
|
214
|
+
```
|
|
215
|
+
|
|
203
216
|
The build command:
|
|
204
217
|
1. Resolves the project root (defaults to `workspace.root` from config).
|
|
205
218
|
2. Includes `lib/*.jar` files from the project root in the `javac` classpath.
|
|
@@ -127,6 +127,12 @@ To check the currently pinned `tla2tools.jar` path and its TLC version:
|
|
|
127
127
|
tla tlc --version
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
To inspect the exact Java command that will be executed without running it:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
tla tlc <spec_name> --show-command
|
|
134
|
+
```
|
|
135
|
+
|
|
130
136
|
### Compile Custom Java Modules
|
|
131
137
|
|
|
132
138
|
Java modules (overrides) are compiled using the pinned version of the toolset.
|
|
@@ -148,8 +154,9 @@ tla modules path /path/to/custom/modules
|
|
|
148
154
|
|
|
149
155
|
View or reset the custom modules path:
|
|
150
156
|
```bash
|
|
151
|
-
tla modules path
|
|
152
|
-
tla modules path none
|
|
157
|
+
tla modules path # View current path
|
|
158
|
+
tla modules path none # Reset to default
|
|
159
|
+
tla modules path --resolved # Show fully resolved paths for current context
|
|
153
160
|
```
|
|
154
161
|
|
|
155
162
|
Configure a persistent custom modules dependencies (lib) path:
|
|
@@ -171,6 +178,11 @@ Verbose output:
|
|
|
171
178
|
tla modules build --verbose
|
|
172
179
|
```
|
|
173
180
|
|
|
181
|
+
Show compilation command:
|
|
182
|
+
```bash
|
|
183
|
+
tla modules build --show-command
|
|
184
|
+
```
|
|
185
|
+
|
|
174
186
|
The build command:
|
|
175
187
|
1. Resolves the project root (defaults to `workspace.root` from config).
|
|
176
188
|
2. Includes `lib/*.jar` files from the project root in the `javac` classpath.
|
|
@@ -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.6.0"
|
|
8
8
|
description = "TLA+ tools: download TLC, compile custom modules, run model checker"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -15,6 +15,7 @@ dependencies = [
|
|
|
15
15
|
"platformdirs>=4.0,<5.0",
|
|
16
16
|
"pydantic>=2.12.5,<3.0.0",
|
|
17
17
|
"truststore>=0.9.0,<1.0.0",
|
|
18
|
+
"rich>=13.7.0,<14.0.0",
|
|
18
19
|
]
|
|
19
20
|
authors = [
|
|
20
21
|
{name = "Denis Nikolskiy", email = "codeomatics@gmail.com"}
|
|
@@ -4,17 +4,28 @@ from pathlib import Path
|
|
|
4
4
|
import typer
|
|
5
5
|
|
|
6
6
|
from tlaplus_cli.cmd.modules import app
|
|
7
|
-
from tlaplus_cli.tlc.compiler import compile_modules
|
|
7
|
+
from tlaplus_cli.tlc.compiler import build_compile_command, compile_modules
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
@app.command(name="build")
|
|
11
11
|
def build(
|
|
12
12
|
path: str | None = typer.Argument(None, help="Project root directory (defaults to workspace root)."),
|
|
13
13
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show compilation output."),
|
|
14
|
+
show_command: bool = typer.Option(False, "--show-command", help="Print the command instead of executing it."),
|
|
14
15
|
) -> None:
|
|
15
16
|
"""Compile custom Java modules."""
|
|
16
17
|
base_dir = Path(path).resolve() if path is not None else None
|
|
17
18
|
|
|
19
|
+
if show_command:
|
|
20
|
+
try:
|
|
21
|
+
cmd = build_compile_command(base_dir)
|
|
22
|
+
except FileNotFoundError as e:
|
|
23
|
+
typer.echo(f"Error: {e}", err=True)
|
|
24
|
+
raise typer.Exit(1) from None
|
|
25
|
+
if cmd:
|
|
26
|
+
typer.echo(" ".join(cmd))
|
|
27
|
+
return
|
|
28
|
+
|
|
18
29
|
typer.echo("Compiling Java files ...")
|
|
19
30
|
try:
|
|
20
31
|
classes_dir = compile_modules(base_dir, verbose)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import typer
|
|
3
|
+
|
|
4
|
+
from tlaplus_cli import ui
|
|
5
|
+
from tlaplus_cli.cmd.modules import app
|
|
6
|
+
from tlaplus_cli.config.loader import load_config
|
|
7
|
+
from tlaplus_cli.versioning import (
|
|
8
|
+
download_version,
|
|
9
|
+
download_version_from_url,
|
|
10
|
+
fetch_remote_versions,
|
|
11
|
+
is_url,
|
|
12
|
+
)
|
|
13
|
+
from tlaplus_cli.versioning.paths import get_modules_dir
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.command(name="install-community")
|
|
17
|
+
def install_community(
|
|
18
|
+
version: str = typer.Argument(
|
|
19
|
+
None, help="Version tag (e.g. 'v202412171801') or a direct URL to CommunityModules.jar."
|
|
20
|
+
),
|
|
21
|
+
force: bool = typer.Option(False, "--force", "-f", help="Re-download if already installed."),
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Download and install a specific version of CommunityModules."""
|
|
24
|
+
base_dir = get_modules_dir()
|
|
25
|
+
jar_name = "CommunityModules.jar"
|
|
26
|
+
|
|
27
|
+
if version and is_url(version):
|
|
28
|
+
try:
|
|
29
|
+
version_dir = download_version_from_url(version, base_dir=base_dir, jar_name=jar_name)
|
|
30
|
+
except (requests.RequestException, OSError, ValueError) as e:
|
|
31
|
+
ui.error(f"Failed to download: {e}")
|
|
32
|
+
raise typer.Exit(1) from e
|
|
33
|
+
else:
|
|
34
|
+
ui.success(f"Successfully installed from URL to {version_dir}")
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
config = load_config()
|
|
38
|
+
if not config.tla.community_modules:
|
|
39
|
+
ui.error("Community modules URLs not configured in settings.")
|
|
40
|
+
raise typer.Exit(1)
|
|
41
|
+
|
|
42
|
+
versions, status = fetch_remote_versions(
|
|
43
|
+
config.tla.community_modules.tags,
|
|
44
|
+
config.tla.community_modules.releases,
|
|
45
|
+
config.tla.community_modules.per_page,
|
|
46
|
+
asset_name=jar_name,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if not versions:
|
|
50
|
+
ui.error(f"Could not fetch remote versions (status: {status.value})")
|
|
51
|
+
raise typer.Exit(1)
|
|
52
|
+
|
|
53
|
+
target = None
|
|
54
|
+
if version:
|
|
55
|
+
target = next((v for v in versions if v.name == version), None)
|
|
56
|
+
if not target:
|
|
57
|
+
ui.error(f"Version {version} not found.")
|
|
58
|
+
raise typer.Exit(1)
|
|
59
|
+
else:
|
|
60
|
+
# Default to latest non-prerelease
|
|
61
|
+
target = next((v for v in versions if not v.prerelease), versions[0])
|
|
62
|
+
ui.info(f"No version specified, selecting latest stable release: {target.name}")
|
|
63
|
+
|
|
64
|
+
# Check if already installed
|
|
65
|
+
target_dir = base_dir / f"{target.name}-{target.short_sha}"
|
|
66
|
+
if target_dir.exists() and not force:
|
|
67
|
+
ui.info(f"Version {target.name} is already installed at {target_dir}")
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
version_dir = download_version(target, force=force, base_dir=base_dir, jar_name=jar_name)
|
|
72
|
+
ui.success(f"Successfully installed {target.name} to {version_dir}")
|
|
73
|
+
except (requests.RequestException, OSError) as e:
|
|
74
|
+
ui.error(f"Failed to download: {e}")
|
|
75
|
+
raise typer.Exit(1) from e
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
from tlaplus_cli.java.classpath import ClasspathResolver, ResolveMode, SubdirType
|
|
8
|
+
from tlaplus_cli.tlc.compiler import get_tlc_jar_path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.command(name="path")
|
|
12
|
+
def set_modules_path(
|
|
13
|
+
path: str | None = typer.Argument(None, help="Path to the custom Java modules directory, or 'none' to reset."),
|
|
14
|
+
resolved: bool = typer.Option(False, "--resolved", help="Show the actual resolved paths for the current context."),
|
|
15
|
+
) -> None:
|
|
16
|
+
"""Configure or view custom Java modules source path."""
|
|
17
|
+
config_obj = load_config()
|
|
18
|
+
|
|
19
|
+
if resolved:
|
|
20
|
+
resolver = ClasspathResolver(config_obj, project_root=workspace_root(), tool_jar=get_tlc_jar_path())
|
|
21
|
+
|
|
22
|
+
# Source path (modules)
|
|
23
|
+
tla_library = resolver.get_tla_library_property()
|
|
24
|
+
typer.echo(f"Source Path: {tla_library or 'None'}")
|
|
25
|
+
|
|
26
|
+
# Classes path
|
|
27
|
+
classes_dir = resolver.get_project_path(SubdirType.CLASSES)
|
|
28
|
+
typer.echo(f"Classes Path: {classes_dir or 'None'}")
|
|
29
|
+
|
|
30
|
+
# Library path (JARs)
|
|
31
|
+
libs = resolver.resolve(ResolveMode.RUNTIME)
|
|
32
|
+
# Filter out classes_dir and tool_jar to show only libs
|
|
33
|
+
tool_jar = get_tlc_jar_path()
|
|
34
|
+
only_libs = [p for p in libs if p != str(classes_dir) and p != str(tool_jar)]
|
|
35
|
+
|
|
36
|
+
lib_str = "None"
|
|
37
|
+
if only_libs:
|
|
38
|
+
lib_str = f"{len(only_libs)} JARs"
|
|
39
|
+
|
|
40
|
+
typer.echo(f"Library Path: {lib_str}")
|
|
41
|
+
if only_libs:
|
|
42
|
+
for lib in only_libs:
|
|
43
|
+
typer.echo(f" - {lib}")
|
|
44
|
+
|
|
45
|
+
# Tool Jar
|
|
46
|
+
typer.echo(f"Tool Jar: {tool_jar}")
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
if path is None:
|
|
50
|
+
if config_obj.module_path:
|
|
51
|
+
typer.echo(f"Current modules path: {config_obj.module_path}")
|
|
52
|
+
else:
|
|
53
|
+
default_path = workspace_root() / config_obj.workspace.modules_dir
|
|
54
|
+
typer.echo("Custom modules path is not set.")
|
|
55
|
+
typer.echo(f"Defaulting to: {default_path}")
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
if path.lower() == "none":
|
|
59
|
+
config_obj.module_path = None
|
|
60
|
+
save_config(config_obj)
|
|
61
|
+
typer.echo("Custom modules path reset to default.")
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
p = Path(path).resolve()
|
|
65
|
+
|
|
66
|
+
if not p.is_dir():
|
|
67
|
+
typer.echo(f"Error: Path does not exist or is not a directory: {p}", err=True)
|
|
68
|
+
raise typer.Exit(1)
|
|
69
|
+
|
|
70
|
+
config_obj.module_path = str(p)
|
|
71
|
+
save_config(config_obj)
|
|
72
|
+
typer.echo(f"Modules path updated to: {p}")
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from rich.console import Console
|
|
3
|
+
from rich.live import Live
|
|
4
|
+
|
|
5
|
+
from tlaplus_cli import ui
|
|
6
|
+
from tlaplus_cli.config.loader import load_config
|
|
7
|
+
from tlaplus_cli.java.classpath import ClasspathResolver
|
|
8
|
+
from tlaplus_cli.project import find_project_root
|
|
9
|
+
from tlaplus_cli.tlc.compiler import get_tlc_jar_path
|
|
10
|
+
from tlaplus_cli.tlc.formatter import TlcFormatter
|
|
11
|
+
from tlaplus_cli.tlc.models import CheckState, ModelCheckResult
|
|
12
|
+
from tlaplus_cli.tlc.runner import (
|
|
13
|
+
build_tlc_command,
|
|
14
|
+
get_tlc_version,
|
|
15
|
+
resolve_spec_file,
|
|
16
|
+
run_tlc,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def version_callback(value: bool) -> None:
|
|
21
|
+
if value:
|
|
22
|
+
jar_path = get_tlc_jar_path()
|
|
23
|
+
typer.echo(f"tla2tools.jar path: {jar_path}")
|
|
24
|
+
|
|
25
|
+
if not jar_path.exists():
|
|
26
|
+
ui.error(f"tla2tools.jar not found at {jar_path}")
|
|
27
|
+
typer.echo("Run 'tla tools install' first.", err=True)
|
|
28
|
+
raise typer.Exit(1)
|
|
29
|
+
|
|
30
|
+
version_str = get_tlc_version()
|
|
31
|
+
if version_str:
|
|
32
|
+
typer.echo(version_str)
|
|
33
|
+
|
|
34
|
+
raise typer.Exit(0)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _show_diagnostic_info(spec: str, spec_name: str) -> None:
|
|
38
|
+
"""Show diagnostic info before running TLC."""
|
|
39
|
+
version_str = get_tlc_version() or "unknown"
|
|
40
|
+
typer.echo(f"Running TLC ({version_str}) on {spec_name} ...")
|
|
41
|
+
|
|
42
|
+
# Check if we have TLA-Library
|
|
43
|
+
try:
|
|
44
|
+
config = load_config()
|
|
45
|
+
spec_file, _ = resolve_spec_file(spec)
|
|
46
|
+
project_root = find_project_root(
|
|
47
|
+
spec_file,
|
|
48
|
+
modules_dir=config.workspace.modules_dir,
|
|
49
|
+
classes_dir=config.workspace.classes_dir,
|
|
50
|
+
)
|
|
51
|
+
jar_path = get_tlc_jar_path()
|
|
52
|
+
resolver = ClasspathResolver(config, project_root=project_root, tool_jar=jar_path)
|
|
53
|
+
tla_library = resolver.get_tla_library_property()
|
|
54
|
+
if tla_library:
|
|
55
|
+
ui.info(f"TLA-Library: {tla_library}")
|
|
56
|
+
except Exception:
|
|
57
|
+
pass # nosec
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# PLR0912: This command handler orchestrates multiple output types (errors, warnings, results, progress);
|
|
61
|
+
# splitting it would fragment the CLI's primary user-facing logic.
|
|
62
|
+
# PLR0915: Too many statements.
|
|
63
|
+
def tlc( # noqa: PLR0912, PLR0915
|
|
64
|
+
spec: str = typer.Argument(help="Name of the TLA+ specification (without .tla extension)."),
|
|
65
|
+
# Typer requires the parameter in the signature to register the CLI option;
|
|
66
|
+
# since the logic is in the eager callback, the value is not used here.
|
|
67
|
+
version: bool | None = typer.Option( # noqa: ARG001
|
|
68
|
+
None,
|
|
69
|
+
"--version",
|
|
70
|
+
help="Print the path to tla2tools.jar and its version.",
|
|
71
|
+
callback=version_callback,
|
|
72
|
+
is_eager=True,
|
|
73
|
+
),
|
|
74
|
+
show_command: bool = typer.Option(False, "--show-command", help="Print the command instead of executing it."),
|
|
75
|
+
_refresh_interval: float | None = typer.Option(
|
|
76
|
+
None,
|
|
77
|
+
"--refresh-interval",
|
|
78
|
+
help="Refresh interval for the output (seconds).",
|
|
79
|
+
),
|
|
80
|
+
coverage: bool = typer.Option(False, "--coverage", help="Enable code coverage visualization."),
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Run TLC model checker on a TLA+ specification."""
|
|
83
|
+
# version argument is handled by version_callback (is_eager=True)
|
|
84
|
+
try:
|
|
85
|
+
_, _spec_name = resolve_spec_file(spec)
|
|
86
|
+
except FileNotFoundError as e:
|
|
87
|
+
ui.error(str(e))
|
|
88
|
+
raise typer.Exit(1) from None
|
|
89
|
+
|
|
90
|
+
if show_command:
|
|
91
|
+
cmd = build_tlc_command(spec)
|
|
92
|
+
if coverage:
|
|
93
|
+
cmd.extend(["-coverage", "1"])
|
|
94
|
+
if not cmd:
|
|
95
|
+
raise typer.Exit(1) from None
|
|
96
|
+
typer.echo(" ".join(cmd))
|
|
97
|
+
raise typer.Exit(0)
|
|
98
|
+
|
|
99
|
+
tlc_version = get_tlc_version() or "unknown"
|
|
100
|
+
formatter = TlcFormatter(tlc_version=tlc_version)
|
|
101
|
+
layout = formatter.create_layout()
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
final_result: list[ModelCheckResult] = []
|
|
105
|
+
|
|
106
|
+
with Live(layout, refresh_per_second=4, screen=False):
|
|
107
|
+
|
|
108
|
+
def wrapped_callback(res: ModelCheckResult) -> None:
|
|
109
|
+
formatter.update(layout, res)
|
|
110
|
+
|
|
111
|
+
if not final_result:
|
|
112
|
+
final_result.append(res)
|
|
113
|
+
else:
|
|
114
|
+
final_result[0] = res
|
|
115
|
+
|
|
116
|
+
exit_code = run_tlc(spec, callback=wrapped_callback, coverage=coverage)
|
|
117
|
+
|
|
118
|
+
if final_result:
|
|
119
|
+
res = final_result[0]
|
|
120
|
+
|
|
121
|
+
if res.sany_errors:
|
|
122
|
+
console = Console()
|
|
123
|
+
spec_file, _ = resolve_spec_file(spec)
|
|
124
|
+
for sany_err in res.sany_errors:
|
|
125
|
+
console.print(formatter.render_sany_error(sany_err, spec_file))
|
|
126
|
+
|
|
127
|
+
if res.state == CheckState.Success:
|
|
128
|
+
ui.success("Model checking completed successfully.")
|
|
129
|
+
elif res.state == CheckState.Error:
|
|
130
|
+
ui.error(f"Model checking failed with {len(res.errors)} error(s).")
|
|
131
|
+
for err in res.errors:
|
|
132
|
+
if err.error_trace:
|
|
133
|
+
console = Console()
|
|
134
|
+
console.print(formatter.render_error_trace(err.error_trace))
|
|
135
|
+
else:
|
|
136
|
+
for line in err.lines:
|
|
137
|
+
typer.echo(f" {line}", err=True)
|
|
138
|
+
|
|
139
|
+
if res.warnings:
|
|
140
|
+
ui.warn(f"Found {len(res.warnings)} warning(s).")
|
|
141
|
+
for warn_info in res.warnings:
|
|
142
|
+
for line in warn_info.lines:
|
|
143
|
+
typer.echo(f" {line}", err=True)
|
|
144
|
+
|
|
145
|
+
if res.coverage_stat:
|
|
146
|
+
console = Console()
|
|
147
|
+
console.print(formatter.render_coverage_table(res.coverage_stat))
|
|
148
|
+
|
|
149
|
+
# Show inline coverage for the main spec
|
|
150
|
+
spec_file, _ = resolve_spec_file(spec)
|
|
151
|
+
console.print(formatter.render_inline_coverage(res.coverage_stat, spec_file))
|
|
152
|
+
|
|
153
|
+
if res.duration:
|
|
154
|
+
ui.info(f"Duration: {res.duration}ms")
|
|
155
|
+
except FileNotFoundError as e:
|
|
156
|
+
ui.error(str(e))
|
|
157
|
+
raise typer.Exit(1) from None
|
|
158
|
+
|
|
159
|
+
raise typer.Exit(exit_code)
|
|
@@ -2,6 +2,7 @@ import typer
|
|
|
2
2
|
|
|
3
3
|
from tlaplus_cli.cmd.tools.meta import app
|
|
4
4
|
from tlaplus_cli.config.loader import load_config
|
|
5
|
+
from tlaplus_cli.ui import warn
|
|
5
6
|
from tlaplus_cli.versioning import (
|
|
6
7
|
fetch_remote_versions,
|
|
7
8
|
list_local_versions,
|
|
@@ -28,6 +29,6 @@ def meta_sync() -> None:
|
|
|
28
29
|
write_version_metadata(lv.path, target)
|
|
29
30
|
typer.echo(f"Synced metadata for {lv.path.name}")
|
|
30
31
|
else:
|
|
31
|
-
|
|
32
|
+
warn(f"Could not find remote data for {lv.name}")
|
|
32
33
|
|
|
33
34
|
typer.echo("Metadata sync complete.")
|
|
@@ -5,6 +5,7 @@ import typer
|
|
|
5
5
|
|
|
6
6
|
from tlaplus_cli.cmd.tools import app
|
|
7
7
|
from tlaplus_cli.config.loader import cache_dir
|
|
8
|
+
from tlaplus_cli.ui import warn
|
|
8
9
|
from tlaplus_cli.versioning import (
|
|
9
10
|
clear_pin,
|
|
10
11
|
get_pinned_version_dir,
|
|
@@ -24,12 +25,12 @@ def _resolve_uninstall_targets(versions: list[str]) -> list[Path]:
|
|
|
24
25
|
if legacy.exists():
|
|
25
26
|
targets.append(legacy)
|
|
26
27
|
else:
|
|
27
|
-
|
|
28
|
+
warn("Default (legacy) tla2tools.jar not found.")
|
|
28
29
|
continue
|
|
29
30
|
|
|
30
31
|
matching = sorted([lv for lv in local_versions if lv.name == v], key=lambda x: x.path.name)
|
|
31
32
|
if not matching:
|
|
32
|
-
|
|
33
|
+
warn(f"Version {v} not found locally.")
|
|
33
34
|
continue
|
|
34
35
|
|
|
35
36
|
if len(matching) > 1:
|
|
@@ -13,6 +13,7 @@ class TlaUrls(BaseModel):
|
|
|
13
13
|
|
|
14
14
|
class TlaConfig(BaseModel):
|
|
15
15
|
urls: TlaUrls
|
|
16
|
+
community_modules: TlaUrls | None = None
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class WorkspaceConfig(BaseModel):
|
|
@@ -25,6 +26,7 @@ class WorkspaceConfig(BaseModel):
|
|
|
25
26
|
class TlcConfig(BaseModel):
|
|
26
27
|
java_class: str = "tlc2.TLC"
|
|
27
28
|
overrides_class: str = "tlc2.overrides.TLCOverrides"
|
|
29
|
+
refresh_interval: float = 1.0
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class JavaConfig(BaseModel):
|