esysrepo-ctl 0.2.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.
- esysrepo_ctl-0.2.0/PKG-INFO +165 -0
- esysrepo_ctl-0.2.0/README.md +152 -0
- esysrepo_ctl-0.2.0/pyproject.toml +46 -0
- esysrepo_ctl-0.2.0/setup.cfg +4 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/__init__.py +3 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/__main__.py +6 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/bootstrap.py +156 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/cli.py +182 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/commands/__init__.py +1 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/commands/doctor.py +28 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/commands/install.py +44 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/commands/preflight.py +67 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/commands/remove.py +44 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/commands/reporting.py +26 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/commands/update.py +38 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/commands/version.py +29 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/compat.py +157 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/conan.py +261 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/diagnostics.py +167 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/discovery.py +182 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/exit_codes.py +17 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/output.py +34 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/paths.py +48 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/process.py +110 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/python_env.py +421 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/remote.py +72 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/toolchain.py +42 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl/wrappers.py +394 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl.egg-info/PKG-INFO +165 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl.egg-info/SOURCES.txt +46 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl.egg-info/dependency_links.txt +1 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl.egg-info/entry_points.txt +3 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl.egg-info/requires.txt +5 -0
- esysrepo_ctl-0.2.0/src/esysrepo_ctl.egg-info/top_level.txt +1 -0
- esysrepo_ctl-0.2.0/tests/test_adr0008_modes.py +139 -0
- esysrepo_ctl-0.2.0/tests/test_bootstrap.py +284 -0
- esysrepo_ctl-0.2.0/tests/test_cli_help.py +29 -0
- esysrepo_ctl-0.2.0/tests/test_commands_lifecycle.py +186 -0
- esysrepo_ctl-0.2.0/tests/test_conan.py +272 -0
- esysrepo_ctl-0.2.0/tests/test_discovery.py +152 -0
- esysrepo_ctl-0.2.0/tests/test_discovery_version.py +23 -0
- esysrepo_ctl-0.2.0/tests/test_doctor.py +114 -0
- esysrepo_ctl-0.2.0/tests/test_exit_codes.py +136 -0
- esysrepo_ctl-0.2.0/tests/test_integration_artifactory.py +220 -0
- esysrepo_ctl-0.2.0/tests/test_process.py +76 -0
- esysrepo_ctl-0.2.0/tests/test_python_env.py +199 -0
- esysrepo_ctl-0.2.0/tests/test_smoke.py +8 -0
- esysrepo_ctl-0.2.0/tests/test_wrappers.py +64 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: esysrepo-ctl
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Control-plane tool for managing the native esysrepo CLI
|
|
5
|
+
Author: Project maintainers
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: typer>=0.12
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
12
|
+
Requires-Dist: ruff>=0.8; extra == "dev"
|
|
13
|
+
|
|
14
|
+
# esysrepo-ctl
|
|
15
|
+
|
|
16
|
+
Control-plane tool for installing, updating, diagnosing, and managing the native
|
|
17
|
+
`esysrepo` CLI (distributed via Conan). Distributed as a Python package on PyPI.
|
|
18
|
+
|
|
19
|
+
Native repository operations use `esysrepo` / `erepo` (from the Conan package).
|
|
20
|
+
This tool only manages the lifecycle of that native CLI.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pipx install esysrepo-ctl
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or from a development checkout:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
python -m pip install -e ".[dev]"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Both `esysrepo-ctl` and `erepo-ctl` are equivalent entry points.
|
|
35
|
+
|
|
36
|
+
Then install the native CLI (first run bootstraps a Python env + Conan 2 per
|
|
37
|
+
[ADR-0008](docs/adr/0008-dual-mode-python-venv-isolation.md)):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Interactive: detect mode, confirm, persist
|
|
41
|
+
esysrepo-ctl install
|
|
42
|
+
|
|
43
|
+
# Non-interactive installer-like (managed home venv + always-on wrappers)
|
|
44
|
+
esysrepo-ctl install --mode managed --yes
|
|
45
|
+
|
|
46
|
+
# Project-private: activate your venv first, then:
|
|
47
|
+
esysrepo-ctl install --mode project --yes
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| Mode | Conan lives in | Native `esysrepo` / `erepo` wrappers |
|
|
51
|
+
|------|----------------|--------------------------------------|
|
|
52
|
+
| `project` | Active project venv | That venv’s `bin` / `Scripts` (while activated) |
|
|
53
|
+
| `pipx` | Managed home venv | Managed `…/esysrepo-ctl/bin` |
|
|
54
|
+
| `managed` | Managed home venv | Managed `…/esysrepo-ctl/bin` |
|
|
55
|
+
|
|
56
|
+
Overrides: `ESYSREPO_CTL_MODE`, `ESYSREPO_CTL_YES=1`, `--reconfigure` (ignore
|
|
57
|
+
persisted mode). Choice is persisted under `ESYSREPO_CTL_HOME` / platform data
|
|
58
|
+
dir (`config.json`).
|
|
59
|
+
|
|
60
|
+
## Commands
|
|
61
|
+
|
|
62
|
+
| Command | Purpose |
|
|
63
|
+
|---------|---------|
|
|
64
|
+
| `install` | Install the native `esysrepo` CLI via Conan |
|
|
65
|
+
| `update` | Update the native CLI (auto-bootstraps when allowed) |
|
|
66
|
+
| `remove` | Remove the native CLI from the Conan cache |
|
|
67
|
+
| `doctor` | Diagnose environment, PATH, and compatibility |
|
|
68
|
+
| `version` | Print control-plane and native CLI versions |
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
esysrepo-ctl --help
|
|
72
|
+
esysrepo-ctl version
|
|
73
|
+
esysrepo-ctl doctor
|
|
74
|
+
esysrepo-ctl install
|
|
75
|
+
esysrepo-ctl install --mode managed --yes
|
|
76
|
+
esysrepo-ctl install --mode project --yes --reconfigure
|
|
77
|
+
esysrepo-ctl install --version 0.2.4
|
|
78
|
+
esysrepo-ctl --channel center install # unnamed Conan Center-style refs
|
|
79
|
+
esysrepo-ctl update
|
|
80
|
+
esysrepo-ctl remove
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Conan channel (ADR-0007)
|
|
84
|
+
|
|
85
|
+
By default, package refs use LibESys Artifactory identity:
|
|
86
|
+
|
|
87
|
+
`esysrepo-cli/<version>@libesys/stable`
|
|
88
|
+
|
|
89
|
+
| Mode | How | Package ref shape |
|
|
90
|
+
|------|-----|-------------------|
|
|
91
|
+
| `libesys` (default) | `--channel libesys` or unset | `…@libesys/stable` |
|
|
92
|
+
| `center` | `--channel center` or `ESYSREPO_CTL_CHANNEL=center` | unnamed (`esysrepo-cli/<ver>`) |
|
|
93
|
+
|
|
94
|
+
Configure the LibESys Conan remote yourself (or via CI vars `CONAN_REMOTE_URL` /
|
|
95
|
+
`CONAN_LOGIN_USERNAME` / `CONAN_PASSWORD`). Install writes VirtualBuildEnv +
|
|
96
|
+
VirtualRunEnv under the managed data dir and places wrappers per mode (above);
|
|
97
|
+
`doctor` / discovery look at PATH, project `Scripts`/`bin`, and the managed bin.
|
|
98
|
+
|
|
99
|
+
## Strict mode / no auto-bootstrap
|
|
100
|
+
|
|
101
|
+
By default, eligible commands (currently `update`) may auto-install the native CLI when
|
|
102
|
+
it is missing (ADR-0005). Disable that with:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
esysrepo-ctl --no-bootstrap update
|
|
106
|
+
# or
|
|
107
|
+
esysrepo-ctl --strict update
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Auto-bootstrap is also disabled when any of these are set:
|
|
111
|
+
|
|
112
|
+
- `CI=true` (typical CI environments)
|
|
113
|
+
- `ESYSREPO_CTL_NO_BOOTSTRAP=1`
|
|
114
|
+
- `ESYSREPO_CTL_STRICT=1`
|
|
115
|
+
|
|
116
|
+
Explicit `install` / `remove` / `doctor` / `version` never trigger implicit install.
|
|
117
|
+
|
|
118
|
+
## Exit codes
|
|
119
|
+
|
|
120
|
+
Stable codes for scripting (ADR-0006):
|
|
121
|
+
|
|
122
|
+
| Code | Meaning |
|
|
123
|
+
|------|---------|
|
|
124
|
+
| 0 | Success |
|
|
125
|
+
| 1 | General error |
|
|
126
|
+
| 2 | Usage error (bad arguments / unknown command) |
|
|
127
|
+
| 3 | Native `esysrepo` / `erepo` missing |
|
|
128
|
+
| 4 | Auto-bootstrap failure |
|
|
129
|
+
| 5 | Conan failure |
|
|
130
|
+
| 6 | Environment / compatibility error |
|
|
131
|
+
|
|
132
|
+
Errors print to stderr as `error: …` with optional `hint: …` remediation lines.
|
|
133
|
+
|
|
134
|
+
## Troubleshooting
|
|
135
|
+
|
|
136
|
+
| Symptom | What to try |
|
|
137
|
+
|---------|-------------|
|
|
138
|
+
| `doctor` reports Conan missing | Install Conan 2 and ensure `conan` is on `PATH` (or re-run `esysrepo-ctl install --mode … --yes` so ctl bootstraps Conan into the chosen venv) |
|
|
139
|
+
| `doctor` reports esysrepo missing | `esysrepo-ctl install` then re-check `doctor` / `version` |
|
|
140
|
+
| Install/update fails talking to remotes | `conan remote list`, fix auth/network, retry |
|
|
141
|
+
| Package installed but CLI not found | Check managed bin (`esysrepo-ctl doctor`) and Conan remotes |
|
|
142
|
+
| Wrong package identity / not found | Use default `--channel libesys` for Artifactory; ensure remote is configured |
|
|
143
|
+
| CI must not mutate the environment | Use `--no-bootstrap` or rely on `CI=true` |
|
|
144
|
+
| `where esysrepo` lists `~/.conan2/…/bin` before the venv wrapper | Shell PATH is polluted (Conan cache bins first), so Windows never runs the `.bat`. **cmd.exe:** `set "PATH=%VIRTUAL_ENV%\\Scripts;%PATH%"` then `where esysrepo` — or `call "%VIRTUAL_ENV%\\Scripts\\_esysrepo_ctl_fix_path.bat"`. **PowerShell:** `$env:PATH = (@("$env:VIRTUAL_ENV\\Scripts") + ($env:PATH -split ';' \| ? { $_ -notmatch '\\.conan2' })) -join ';'`. Or deactivate/reactivate the venv after `esysrepo-ctl install --mode project --yes`. |
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
esysrepo-ctl doctor
|
|
148
|
+
esysrepo-ctl version
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Documentation
|
|
152
|
+
|
|
153
|
+
- [Architecture overview](docs/architecture/overview.md)
|
|
154
|
+
- [CLI specification](docs/architecture/cli-spec.md)
|
|
155
|
+
- [Quality requirements](docs/architecture/quality-requirements.md)
|
|
156
|
+
- [ADRs](docs/adr/README.md)
|
|
157
|
+
- [MVP implementation plan](plans/0001-mvp-implementation.md)
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
python scripts/setup-dev.sh # or scripts/setup-dev.ps1 on Windows
|
|
163
|
+
pytest
|
|
164
|
+
pre-commit run --all-files
|
|
165
|
+
```
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# esysrepo-ctl
|
|
2
|
+
|
|
3
|
+
Control-plane tool for installing, updating, diagnosing, and managing the native
|
|
4
|
+
`esysrepo` CLI (distributed via Conan). Distributed as a Python package on PyPI.
|
|
5
|
+
|
|
6
|
+
Native repository operations use `esysrepo` / `erepo` (from the Conan package).
|
|
7
|
+
This tool only manages the lifecycle of that native CLI.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pipx install esysrepo-ctl
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or from a development checkout:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
python -m pip install -e ".[dev]"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Both `esysrepo-ctl` and `erepo-ctl` are equivalent entry points.
|
|
22
|
+
|
|
23
|
+
Then install the native CLI (first run bootstraps a Python env + Conan 2 per
|
|
24
|
+
[ADR-0008](docs/adr/0008-dual-mode-python-venv-isolation.md)):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Interactive: detect mode, confirm, persist
|
|
28
|
+
esysrepo-ctl install
|
|
29
|
+
|
|
30
|
+
# Non-interactive installer-like (managed home venv + always-on wrappers)
|
|
31
|
+
esysrepo-ctl install --mode managed --yes
|
|
32
|
+
|
|
33
|
+
# Project-private: activate your venv first, then:
|
|
34
|
+
esysrepo-ctl install --mode project --yes
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
| Mode | Conan lives in | Native `esysrepo` / `erepo` wrappers |
|
|
38
|
+
|------|----------------|--------------------------------------|
|
|
39
|
+
| `project` | Active project venv | That venv’s `bin` / `Scripts` (while activated) |
|
|
40
|
+
| `pipx` | Managed home venv | Managed `…/esysrepo-ctl/bin` |
|
|
41
|
+
| `managed` | Managed home venv | Managed `…/esysrepo-ctl/bin` |
|
|
42
|
+
|
|
43
|
+
Overrides: `ESYSREPO_CTL_MODE`, `ESYSREPO_CTL_YES=1`, `--reconfigure` (ignore
|
|
44
|
+
persisted mode). Choice is persisted under `ESYSREPO_CTL_HOME` / platform data
|
|
45
|
+
dir (`config.json`).
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
| Command | Purpose |
|
|
50
|
+
|---------|---------|
|
|
51
|
+
| `install` | Install the native `esysrepo` CLI via Conan |
|
|
52
|
+
| `update` | Update the native CLI (auto-bootstraps when allowed) |
|
|
53
|
+
| `remove` | Remove the native CLI from the Conan cache |
|
|
54
|
+
| `doctor` | Diagnose environment, PATH, and compatibility |
|
|
55
|
+
| `version` | Print control-plane and native CLI versions |
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
esysrepo-ctl --help
|
|
59
|
+
esysrepo-ctl version
|
|
60
|
+
esysrepo-ctl doctor
|
|
61
|
+
esysrepo-ctl install
|
|
62
|
+
esysrepo-ctl install --mode managed --yes
|
|
63
|
+
esysrepo-ctl install --mode project --yes --reconfigure
|
|
64
|
+
esysrepo-ctl install --version 0.2.4
|
|
65
|
+
esysrepo-ctl --channel center install # unnamed Conan Center-style refs
|
|
66
|
+
esysrepo-ctl update
|
|
67
|
+
esysrepo-ctl remove
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Conan channel (ADR-0007)
|
|
71
|
+
|
|
72
|
+
By default, package refs use LibESys Artifactory identity:
|
|
73
|
+
|
|
74
|
+
`esysrepo-cli/<version>@libesys/stable`
|
|
75
|
+
|
|
76
|
+
| Mode | How | Package ref shape |
|
|
77
|
+
|------|-----|-------------------|
|
|
78
|
+
| `libesys` (default) | `--channel libesys` or unset | `…@libesys/stable` |
|
|
79
|
+
| `center` | `--channel center` or `ESYSREPO_CTL_CHANNEL=center` | unnamed (`esysrepo-cli/<ver>`) |
|
|
80
|
+
|
|
81
|
+
Configure the LibESys Conan remote yourself (or via CI vars `CONAN_REMOTE_URL` /
|
|
82
|
+
`CONAN_LOGIN_USERNAME` / `CONAN_PASSWORD`). Install writes VirtualBuildEnv +
|
|
83
|
+
VirtualRunEnv under the managed data dir and places wrappers per mode (above);
|
|
84
|
+
`doctor` / discovery look at PATH, project `Scripts`/`bin`, and the managed bin.
|
|
85
|
+
|
|
86
|
+
## Strict mode / no auto-bootstrap
|
|
87
|
+
|
|
88
|
+
By default, eligible commands (currently `update`) may auto-install the native CLI when
|
|
89
|
+
it is missing (ADR-0005). Disable that with:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
esysrepo-ctl --no-bootstrap update
|
|
93
|
+
# or
|
|
94
|
+
esysrepo-ctl --strict update
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Auto-bootstrap is also disabled when any of these are set:
|
|
98
|
+
|
|
99
|
+
- `CI=true` (typical CI environments)
|
|
100
|
+
- `ESYSREPO_CTL_NO_BOOTSTRAP=1`
|
|
101
|
+
- `ESYSREPO_CTL_STRICT=1`
|
|
102
|
+
|
|
103
|
+
Explicit `install` / `remove` / `doctor` / `version` never trigger implicit install.
|
|
104
|
+
|
|
105
|
+
## Exit codes
|
|
106
|
+
|
|
107
|
+
Stable codes for scripting (ADR-0006):
|
|
108
|
+
|
|
109
|
+
| Code | Meaning |
|
|
110
|
+
|------|---------|
|
|
111
|
+
| 0 | Success |
|
|
112
|
+
| 1 | General error |
|
|
113
|
+
| 2 | Usage error (bad arguments / unknown command) |
|
|
114
|
+
| 3 | Native `esysrepo` / `erepo` missing |
|
|
115
|
+
| 4 | Auto-bootstrap failure |
|
|
116
|
+
| 5 | Conan failure |
|
|
117
|
+
| 6 | Environment / compatibility error |
|
|
118
|
+
|
|
119
|
+
Errors print to stderr as `error: …` with optional `hint: …` remediation lines.
|
|
120
|
+
|
|
121
|
+
## Troubleshooting
|
|
122
|
+
|
|
123
|
+
| Symptom | What to try |
|
|
124
|
+
|---------|-------------|
|
|
125
|
+
| `doctor` reports Conan missing | Install Conan 2 and ensure `conan` is on `PATH` (or re-run `esysrepo-ctl install --mode … --yes` so ctl bootstraps Conan into the chosen venv) |
|
|
126
|
+
| `doctor` reports esysrepo missing | `esysrepo-ctl install` then re-check `doctor` / `version` |
|
|
127
|
+
| Install/update fails talking to remotes | `conan remote list`, fix auth/network, retry |
|
|
128
|
+
| Package installed but CLI not found | Check managed bin (`esysrepo-ctl doctor`) and Conan remotes |
|
|
129
|
+
| Wrong package identity / not found | Use default `--channel libesys` for Artifactory; ensure remote is configured |
|
|
130
|
+
| CI must not mutate the environment | Use `--no-bootstrap` or rely on `CI=true` |
|
|
131
|
+
| `where esysrepo` lists `~/.conan2/…/bin` before the venv wrapper | Shell PATH is polluted (Conan cache bins first), so Windows never runs the `.bat`. **cmd.exe:** `set "PATH=%VIRTUAL_ENV%\\Scripts;%PATH%"` then `where esysrepo` — or `call "%VIRTUAL_ENV%\\Scripts\\_esysrepo_ctl_fix_path.bat"`. **PowerShell:** `$env:PATH = (@("$env:VIRTUAL_ENV\\Scripts") + ($env:PATH -split ';' \| ? { $_ -notmatch '\\.conan2' })) -join ';'`. Or deactivate/reactivate the venv after `esysrepo-ctl install --mode project --yes`. |
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
esysrepo-ctl doctor
|
|
135
|
+
esysrepo-ctl version
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Documentation
|
|
139
|
+
|
|
140
|
+
- [Architecture overview](docs/architecture/overview.md)
|
|
141
|
+
- [CLI specification](docs/architecture/cli-spec.md)
|
|
142
|
+
- [Quality requirements](docs/architecture/quality-requirements.md)
|
|
143
|
+
- [ADRs](docs/adr/README.md)
|
|
144
|
+
- [MVP implementation plan](plans/0001-mvp-implementation.md)
|
|
145
|
+
|
|
146
|
+
## Development
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
python scripts/setup-dev.sh # or scripts/setup-dev.ps1 on Windows
|
|
150
|
+
pytest
|
|
151
|
+
pre-commit run --all-files
|
|
152
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "esysrepo-ctl"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Control-plane tool for managing the native esysrepo CLI"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [{ name = "Project maintainers" }]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"typer>=0.12",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
esysrepo-ctl = "esysrepo_ctl.cli:app"
|
|
19
|
+
erepo-ctl = "esysrepo_ctl.cli:app"
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
dev = [
|
|
23
|
+
"pytest>=8.0",
|
|
24
|
+
"ruff>=0.8",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[tool.setuptools]
|
|
28
|
+
package-dir = { "" = "src" }
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.packages.find]
|
|
31
|
+
where = ["src"]
|
|
32
|
+
|
|
33
|
+
[tool.pytest.ini_options]
|
|
34
|
+
testpaths = ["tests"]
|
|
35
|
+
pythonpath = ["src"]
|
|
36
|
+
markers = [
|
|
37
|
+
"integration: live Conan/Artifactory tests (require ESYSREPO_CTL_INTEGRATION=1)",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[tool.ruff]
|
|
41
|
+
line-length = 100
|
|
42
|
+
target-version = "py311"
|
|
43
|
+
src = ["src", "tests"]
|
|
44
|
+
|
|
45
|
+
[tool.ruff.lint]
|
|
46
|
+
select = ["E", "F", "I", "UP"]
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""Auto-bootstrap of the native esysrepo CLI (ADR-0005, ADR-0008)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
|
|
9
|
+
from esysrepo_ctl import conan as conan_ops
|
|
10
|
+
from esysrepo_ctl.compat import CompatPolicy
|
|
11
|
+
from esysrepo_ctl.conan import ConanOpResult
|
|
12
|
+
from esysrepo_ctl.discovery import ToolInfo, find_native_cli
|
|
13
|
+
from esysrepo_ctl.exit_codes import ExitCode
|
|
14
|
+
from esysrepo_ctl.python_env import wrapper_bin_dir_for_mode
|
|
15
|
+
from esysrepo_ctl.toolchain import bootstrap_for_lifecycle
|
|
16
|
+
|
|
17
|
+
# Subcommands that may auto-bootstrap when the native CLI is missing.
|
|
18
|
+
AUTO_BOOTSTRAP_COMMANDS = frozenset({"update"})
|
|
19
|
+
|
|
20
|
+
# Subcommands that never trigger implicit install.
|
|
21
|
+
EXEMPT_FROM_AUTO_BOOTSTRAP = frozenset({"install", "remove", "version", "doctor"})
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class EnsureResult:
|
|
26
|
+
"""Outcome of ensuring the native CLI is available."""
|
|
27
|
+
|
|
28
|
+
native: ToolInfo | None
|
|
29
|
+
bootstrapped: bool
|
|
30
|
+
exit_code: ExitCode
|
|
31
|
+
message: str | None = None
|
|
32
|
+
remediation: str | None = None
|
|
33
|
+
bootstrap_outcome: ConanOpResult | None = None
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def ok(self) -> bool:
|
|
37
|
+
return self.exit_code is ExitCode.SUCCESS and self.native is not None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def bootstrap_permitted(
|
|
41
|
+
*,
|
|
42
|
+
cli_no_bootstrap: bool = False,
|
|
43
|
+
environ: Mapping[str, str] | None = None,
|
|
44
|
+
) -> bool:
|
|
45
|
+
"""Return whether auto-bootstrap is allowed for this invocation."""
|
|
46
|
+
env = environ if environ is not None else os.environ
|
|
47
|
+
if cli_no_bootstrap:
|
|
48
|
+
return False
|
|
49
|
+
if _truthy(env.get("ESYSREPO_CTL_NO_BOOTSTRAP")):
|
|
50
|
+
return False
|
|
51
|
+
if _truthy(env.get("ESYSREPO_CTL_STRICT")):
|
|
52
|
+
return False
|
|
53
|
+
# CI and similar non-interactive contexts default to strict (no implicit install).
|
|
54
|
+
if _truthy(env.get("CI")):
|
|
55
|
+
return False
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def should_auto_bootstrap(command: str | None) -> bool:
|
|
60
|
+
"""Return whether ``command`` is eligible for first-use auto-bootstrap."""
|
|
61
|
+
if command is None:
|
|
62
|
+
return False
|
|
63
|
+
if command in EXEMPT_FROM_AUTO_BOOTSTRAP:
|
|
64
|
+
return False
|
|
65
|
+
return command in AUTO_BOOTSTRAP_COMMANDS
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def ensure_native_cli(
|
|
69
|
+
*,
|
|
70
|
+
allow_bootstrap: bool,
|
|
71
|
+
policy: CompatPolicy | None = None,
|
|
72
|
+
) -> EnsureResult:
|
|
73
|
+
"""Detect the native CLI and optionally install it when missing.
|
|
74
|
+
|
|
75
|
+
When ``allow_bootstrap`` is false (strict / ``--no-bootstrap`` / CI), a missing
|
|
76
|
+
native CLI yields :attr:`ExitCode.MISSING_NATIVE_CLI` without changing the
|
|
77
|
+
environment.
|
|
78
|
+
"""
|
|
79
|
+
native = find_native_cli()
|
|
80
|
+
if native is not None:
|
|
81
|
+
return EnsureResult(
|
|
82
|
+
native=native,
|
|
83
|
+
bootstrapped=False,
|
|
84
|
+
exit_code=ExitCode.SUCCESS,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if not allow_bootstrap:
|
|
88
|
+
return EnsureResult(
|
|
89
|
+
native=None,
|
|
90
|
+
bootstrapped=False,
|
|
91
|
+
exit_code=ExitCode.MISSING_NATIVE_CLI,
|
|
92
|
+
message="native esysrepo CLI is not installed",
|
|
93
|
+
remediation=(
|
|
94
|
+
"Install explicitly with `esysrepo-ctl install`, or re-run without "
|
|
95
|
+
"`--no-bootstrap` / strict mode to allow auto-bootstrap."
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
# Auto-bootstrap already implies consent; skip interactive mode confirm.
|
|
101
|
+
info, conan = bootstrap_for_lifecycle(yes=True)
|
|
102
|
+
except RuntimeError as exc:
|
|
103
|
+
return EnsureResult(
|
|
104
|
+
native=None,
|
|
105
|
+
bootstrapped=False,
|
|
106
|
+
exit_code=ExitCode.ENVIRONMENT_ERROR,
|
|
107
|
+
message=str(exc),
|
|
108
|
+
remediation=(
|
|
109
|
+
"Set `--mode project|pipx|managed --yes` or ESYSREPO_CTL_MODE / "
|
|
110
|
+
"ESYSREPO_CTL_YES, then re-run."
|
|
111
|
+
),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
wrapper_bin = wrapper_bin_dir_for_mode(info.mode)
|
|
115
|
+
outcome = conan_ops.install(policy=policy, conan=conan, wrapper_bin=wrapper_bin)
|
|
116
|
+
if not outcome.ok:
|
|
117
|
+
return EnsureResult(
|
|
118
|
+
native=None,
|
|
119
|
+
bootstrapped=False,
|
|
120
|
+
exit_code=ExitCode.BOOTSTRAP_FAILURE
|
|
121
|
+
if outcome.exit_code is ExitCode.CONAN_FAILURE
|
|
122
|
+
else outcome.exit_code,
|
|
123
|
+
message=f"auto-bootstrap failed for {outcome.package_ref}",
|
|
124
|
+
remediation=outcome.remediation
|
|
125
|
+
or "Fix the Conan error above, then re-run or use `esysrepo-ctl install`.",
|
|
126
|
+
bootstrap_outcome=outcome,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
native = find_native_cli()
|
|
130
|
+
if native is None:
|
|
131
|
+
return EnsureResult(
|
|
132
|
+
native=None,
|
|
133
|
+
bootstrapped=True,
|
|
134
|
+
exit_code=ExitCode.BOOTSTRAP_FAILURE,
|
|
135
|
+
message=("auto-bootstrap finished but esysrepo/erepo is still not discoverable"),
|
|
136
|
+
remediation=(
|
|
137
|
+
"Conan installed the package, but the native CLI was not found in PATH "
|
|
138
|
+
"or the mode-local wrapper directory. Re-run `esysrepo-ctl install` or "
|
|
139
|
+
"check doctor output."
|
|
140
|
+
),
|
|
141
|
+
bootstrap_outcome=outcome,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
return EnsureResult(
|
|
145
|
+
native=native,
|
|
146
|
+
bootstrapped=True,
|
|
147
|
+
exit_code=ExitCode.SUCCESS,
|
|
148
|
+
message=f"auto-bootstrapped native CLI ({outcome.package_ref})",
|
|
149
|
+
bootstrap_outcome=outcome,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _truthy(value: str | None) -> bool:
|
|
154
|
+
if value is None:
|
|
155
|
+
return False
|
|
156
|
+
return value.strip().lower() in {"1", "true", "yes", "on"}
|