jrl-cmakemodules-scripts 2.2.4__tar.gz → 2.4.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.
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/PKG-INFO +6 -3
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/README.md +5 -2
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/jrl_cmakemodules_scripts.egg-info/PKG-INFO +6 -3
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/jrl_release.py +172 -61
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/pyproject.toml +1 -1
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/jrl_cmakemodules_scripts.egg-info/SOURCES.txt +0 -0
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/jrl_cmakemodules_scripts.egg-info/dependency_links.txt +0 -0
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/jrl_cmakemodules_scripts.egg-info/entry_points.txt +0 -0
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/jrl_cmakemodules_scripts.egg-info/requires.txt +0 -0
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/jrl_cmakemodules_scripts.egg-info/top_level.txt +0 -0
- {jrl_cmakemodules_scripts-2.2.4 → jrl_cmakemodules_scripts-2.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jrl-cmakemodules-scripts
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Release scripting tools for JRL CMake modules
|
|
5
5
|
License: BSD-3-Clause
|
|
6
6
|
Project-URL: homepage, https://github.com/jrl-umi3218/jrl-cmakemodules
|
|
@@ -79,12 +79,15 @@ jrl-release --bump patch --git-commit --git-tag
|
|
|
79
79
|
| `package.xml` | `<version>` tag |
|
|
80
80
|
| `pyproject.toml` | `project.version` |
|
|
81
81
|
| `CHANGELOG.md` | First `## [X.Y.Z]` section (not Unreleased) |
|
|
82
|
-
| `pixi.toml` | `[workspace] version` |
|
|
82
|
+
| `pixi.toml` | `[workspace] version` and `[package] version` (pixi-build) |
|
|
83
83
|
| `pixi.lock` | Regenerated via `pixi list` |
|
|
84
|
+
| `Cargo.toml` | `[package] version` and `[workspace.package] version` |
|
|
85
|
+
| `Cargo.lock` | Regenerated via `cargo update --workspace` |
|
|
84
86
|
| `CITATION.cff` | `version` key |
|
|
85
87
|
| `CMakeLists.txt` | `project(... VERSION X.Y.Z ...)` |
|
|
86
88
|
|
|
87
|
-
> Requires `pixi` CLI if `pixi.lock` exists in the project root
|
|
89
|
+
> Requires `pixi` CLI if `pixi.lock` exists in the project root, and `cargo`
|
|
90
|
+
> if `Cargo.lock` does.
|
|
88
91
|
|
|
89
92
|
## Testing
|
|
90
93
|
|
|
@@ -61,12 +61,15 @@ jrl-release --bump patch --git-commit --git-tag
|
|
|
61
61
|
| `package.xml` | `<version>` tag |
|
|
62
62
|
| `pyproject.toml` | `project.version` |
|
|
63
63
|
| `CHANGELOG.md` | First `## [X.Y.Z]` section (not Unreleased) |
|
|
64
|
-
| `pixi.toml` | `[workspace] version` |
|
|
64
|
+
| `pixi.toml` | `[workspace] version` and `[package] version` (pixi-build) |
|
|
65
65
|
| `pixi.lock` | Regenerated via `pixi list` |
|
|
66
|
+
| `Cargo.toml` | `[package] version` and `[workspace.package] version` |
|
|
67
|
+
| `Cargo.lock` | Regenerated via `cargo update --workspace` |
|
|
66
68
|
| `CITATION.cff` | `version` key |
|
|
67
69
|
| `CMakeLists.txt` | `project(... VERSION X.Y.Z ...)` |
|
|
68
70
|
|
|
69
|
-
> Requires `pixi` CLI if `pixi.lock` exists in the project root
|
|
71
|
+
> Requires `pixi` CLI if `pixi.lock` exists in the project root, and `cargo`
|
|
72
|
+
> if `Cargo.lock` does.
|
|
70
73
|
|
|
71
74
|
## Testing
|
|
72
75
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jrl-cmakemodules-scripts
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Release scripting tools for JRL CMake modules
|
|
5
5
|
License: BSD-3-Clause
|
|
6
6
|
Project-URL: homepage, https://github.com/jrl-umi3218/jrl-cmakemodules
|
|
@@ -79,12 +79,15 @@ jrl-release --bump patch --git-commit --git-tag
|
|
|
79
79
|
| `package.xml` | `<version>` tag |
|
|
80
80
|
| `pyproject.toml` | `project.version` |
|
|
81
81
|
| `CHANGELOG.md` | First `## [X.Y.Z]` section (not Unreleased) |
|
|
82
|
-
| `pixi.toml` | `[workspace] version` |
|
|
82
|
+
| `pixi.toml` | `[workspace] version` and `[package] version` (pixi-build) |
|
|
83
83
|
| `pixi.lock` | Regenerated via `pixi list` |
|
|
84
|
+
| `Cargo.toml` | `[package] version` and `[workspace.package] version` |
|
|
85
|
+
| `Cargo.lock` | Regenerated via `cargo update --workspace` |
|
|
84
86
|
| `CITATION.cff` | `version` key |
|
|
85
87
|
| `CMakeLists.txt` | `project(... VERSION X.Y.Z ...)` |
|
|
86
88
|
|
|
87
|
-
> Requires `pixi` CLI if `pixi.lock` exists in the project root
|
|
89
|
+
> Requires `pixi` CLI if `pixi.lock` exists in the project root, and `cargo`
|
|
90
|
+
> if `Cargo.lock` does.
|
|
88
91
|
|
|
89
92
|
## Testing
|
|
90
93
|
|
|
@@ -46,11 +46,11 @@ uv run --no-project jrl_release.py --bump patch --git-commit --git-tag
|
|
|
46
46
|
| Option | Description |
|
|
47
47
|
| :--- | :--- |
|
|
48
48
|
| `--root <PATH>` | Project root (default: cwd). |
|
|
49
|
-
| `--bump
|
|
49
|
+
| `--bump {major,minor,patch}` | Bump version component. |
|
|
50
50
|
| `--update-version <X.Y.Z>` | Set a specific version. |
|
|
51
51
|
| `--dry-run` | Show changes without writing files. |
|
|
52
52
|
| `--short` | Print only the version string. |
|
|
53
|
-
| `--output-format
|
|
53
|
+
| `--output-format {text,json}` | Output format (default: text). |
|
|
54
54
|
| `--confirm` | Skip interactive prompts. |
|
|
55
55
|
| `--list-files` | List tracked files. |
|
|
56
56
|
| `--git-commit [MSG]` | Commit changes. Optional message (`{version}` placeholder). |
|
|
@@ -71,21 +71,24 @@ uv run --no-project jrl_release.py --bump patch --git-commit --git-tag
|
|
|
71
71
|
| `package.xml` | `<version> and <url>` tag |
|
|
72
72
|
| `pyproject.toml` | `project.version` and `project.urls` |
|
|
73
73
|
| `CHANGELOG.md` | First `## [X.Y.Z]` section (not Unreleased) |
|
|
74
|
-
| `pixi.toml` | `[workspace] version` |
|
|
74
|
+
| `pixi.toml` | `[workspace] version` and `[package] version` (pixi-build) |
|
|
75
75
|
| `pixi.lock` | Regenerated via `pixi list` |
|
|
76
|
+
| `Cargo.toml` | `[package] version` and `[workspace.package] version` |
|
|
77
|
+
| `Cargo.lock` | Regenerated via `cargo update --workspace` |
|
|
76
78
|
| `CITATION.cff` | `version` key |
|
|
77
79
|
| `CMakeLists.txt` | `project(... VERSION X.Y.Z ... HOMEPAGE_URL ...)` |
|
|
78
80
|
| `debian/changelog` | `version = ...` |
|
|
79
81
|
| `conanfile.py` | `version = ...` |
|
|
80
82
|
|
|
81
|
-
> Requires `pixi` CLI if `pixi.lock` exists in the project root
|
|
83
|
+
> Requires `pixi` CLI if `pixi.lock` exists in the project root, and `cargo`
|
|
84
|
+
> if `Cargo.lock` does.
|
|
82
85
|
|
|
83
86
|
## Meta-packages
|
|
84
87
|
|
|
85
88
|
ROS meta-packages are handled automatically: every nested directory with a
|
|
86
89
|
`package.xml` is treated like the repository root — the full set of
|
|
87
90
|
supported files (`package.xml`, `pyproject.toml`, `CHANGELOG.md`, `pixi.toml`,
|
|
88
|
-
`CITATION.cff`, `CMakeLists.txt`, `debian/changelog`) is checked there too,
|
|
91
|
+
`Cargo.toml`, `CITATION.cff`, `CMakeLists.txt`, `debian/changelog`) is checked there too,
|
|
89
92
|
skipping any that don't exist in that nested directory.
|
|
90
93
|
Discovery skips hidden directories (`.git`, `.pixi`, `.venv`, …), git submodules,
|
|
91
94
|
and — honoring your `.gitignore` via `git check-ignore` — ignored dirs like
|
|
@@ -98,10 +101,12 @@ import re
|
|
|
98
101
|
import os
|
|
99
102
|
import argparse
|
|
100
103
|
import datetime
|
|
104
|
+
import importlib.metadata
|
|
101
105
|
import json
|
|
102
106
|
import subprocess
|
|
103
107
|
import shutil
|
|
104
108
|
import tempfile
|
|
109
|
+
from collections import Counter
|
|
105
110
|
from pathlib import Path
|
|
106
111
|
from abc import ABC, abstractmethod
|
|
107
112
|
from typing import List, Optional, Tuple, Dict
|
|
@@ -167,6 +172,11 @@ class VersionExtractor(ABC):
|
|
|
167
172
|
def check_file_exists(self) -> bool:
|
|
168
173
|
return self.file_path.exists()
|
|
169
174
|
|
|
175
|
+
@property
|
|
176
|
+
def id(self) -> tuple:
|
|
177
|
+
"""Unique identity of the tracked version field."""
|
|
178
|
+
return (self.file_path,)
|
|
179
|
+
|
|
170
180
|
@property
|
|
171
181
|
def name(self) -> str:
|
|
172
182
|
return self.file_path.name
|
|
@@ -213,6 +223,8 @@ class XmlVersionExtractor(VersionExtractor):
|
|
|
213
223
|
f.write(new_content)
|
|
214
224
|
|
|
215
225
|
def get_url(self) -> str | None:
|
|
226
|
+
if not self.file_path.exists():
|
|
227
|
+
return None
|
|
216
228
|
with open(self.file_path, "r", encoding="utf-8") as f:
|
|
217
229
|
content = f.read()
|
|
218
230
|
for url in re.findall(r"<url[^>]*>(.*?)</url>", content, re.I):
|
|
@@ -226,6 +238,11 @@ class TomlVersionExtractor(VersionExtractor):
|
|
|
226
238
|
super().__init__(file_path)
|
|
227
239
|
self.keys = keys
|
|
228
240
|
|
|
241
|
+
@property
|
|
242
|
+
def id(self) -> tuple:
|
|
243
|
+
# Several keys can be tracked in the same file (e.g. pixi.toml, Cargo.toml).
|
|
244
|
+
return (self.file_path, tuple(self.keys))
|
|
245
|
+
|
|
229
246
|
def get_version(self) -> str:
|
|
230
247
|
with open(self.file_path, "r", encoding="utf-8") as f:
|
|
231
248
|
data = tomlkit.load(f)
|
|
@@ -239,6 +256,13 @@ class TomlVersionExtractor(VersionExtractor):
|
|
|
239
256
|
f"Key '{'.'.join(self.keys)}' not found in {self.name}"
|
|
240
257
|
)
|
|
241
258
|
|
|
259
|
+
# e.g. pixi-build `[package] version = { workspace = true }`,
|
|
260
|
+
# or Cargo `version.workspace = true`
|
|
261
|
+
if isinstance(value, dict):
|
|
262
|
+
raise VersionNotPresent(
|
|
263
|
+
f"Key '{'.'.join(self.keys)}' in {self.name} is not a version string"
|
|
264
|
+
)
|
|
265
|
+
|
|
242
266
|
return str(value)
|
|
243
267
|
|
|
244
268
|
def update_version(self, new_version: str) -> None:
|
|
@@ -259,6 +283,8 @@ class TomlVersionExtractor(VersionExtractor):
|
|
|
259
283
|
tomlkit.dump(data, f)
|
|
260
284
|
|
|
261
285
|
def get_url(self) -> str | None:
|
|
286
|
+
if not self.file_path.exists():
|
|
287
|
+
return None
|
|
262
288
|
with open(self.file_path, "r", encoding="utf-8") as f:
|
|
263
289
|
data = tomlkit.load(f)
|
|
264
290
|
if "project" in data and "urls" in data["project"]:
|
|
@@ -375,6 +401,8 @@ class CMakeListsVersionExtractor(VersionExtractor):
|
|
|
375
401
|
return self._get_version_regex(content)
|
|
376
402
|
|
|
377
403
|
def get_url(self) -> str | None:
|
|
404
|
+
if not self.file_path.exists():
|
|
405
|
+
return None
|
|
378
406
|
with open(self.file_path, "r", encoding="utf-8") as f:
|
|
379
407
|
content = f.read()
|
|
380
408
|
if match := re.search(r'HOMEPAGE_URL\s+"([^"]+)"', content):
|
|
@@ -775,6 +803,11 @@ def build_root_checks(root_dir: Path) -> List[VersionExtractor]:
|
|
|
775
803
|
TomlVersionExtractor(root_dir / "pyproject.toml", ["project", "version"]),
|
|
776
804
|
ChangelogVersionExtractor(root_dir / "CHANGELOG.md", r""),
|
|
777
805
|
TomlVersionExtractor(root_dir / "pixi.toml", ["workspace", "version"]),
|
|
806
|
+
TomlVersionExtractor(root_dir / "pixi.toml", ["package", "version"]),
|
|
807
|
+
TomlVersionExtractor(root_dir / "Cargo.toml", ["package", "version"]),
|
|
808
|
+
TomlVersionExtractor(
|
|
809
|
+
root_dir / "Cargo.toml", ["workspace", "package", "version"]
|
|
810
|
+
),
|
|
778
811
|
YamlVersionExtractor(root_dir / "CITATION.cff", ["version"]),
|
|
779
812
|
CMakeListsVersionExtractor(root_dir / "CMakeLists.txt"),
|
|
780
813
|
DebianChangelogVersionExtractor(root_dir / "debian/changelog"),
|
|
@@ -790,21 +823,26 @@ def collect_version_checks(root_dir: Path) -> List[VersionExtractor]:
|
|
|
790
823
|
package directory are simply skipped (VersionExtractor.check_file_exists()).
|
|
791
824
|
"""
|
|
792
825
|
checks = list(build_root_checks(root_dir))
|
|
793
|
-
|
|
826
|
+
seen_ids = {check.id for check in checks}
|
|
794
827
|
|
|
795
828
|
for package_root in discover_package_roots(root_dir):
|
|
796
829
|
for check in build_root_checks(package_root):
|
|
797
|
-
if check.
|
|
830
|
+
if check.id in seen_ids:
|
|
798
831
|
continue
|
|
799
832
|
checks.append(check)
|
|
800
|
-
|
|
833
|
+
seen_ids.add(check.id)
|
|
801
834
|
|
|
802
835
|
# Label nested files by their relative path so identical basenames stay distinct.
|
|
836
|
+
checks_per_file = Counter(check.file_path for check in checks)
|
|
803
837
|
for check in checks:
|
|
804
838
|
try:
|
|
805
839
|
check.label = str(check.file_path.relative_to(root_dir))
|
|
806
840
|
except ValueError:
|
|
807
841
|
check.label = check.file_path.name
|
|
842
|
+
# A file tracking several version fields (e.g. pixi.toml, Cargo.toml)
|
|
843
|
+
# gets its table appended so each field stays distinct.
|
|
844
|
+
if checks_per_file[check.file_path] > 1:
|
|
845
|
+
check.label += f" [{'.'.join(check.keys[:-1])}]"
|
|
808
846
|
|
|
809
847
|
return checks
|
|
810
848
|
|
|
@@ -1235,63 +1273,113 @@ def gh_release(
|
|
|
1235
1273
|
return False, e.stderr or ""
|
|
1236
1274
|
|
|
1237
1275
|
|
|
1238
|
-
def
|
|
1239
|
-
|
|
1276
|
+
def update_lock_file(
|
|
1277
|
+
root_dir: Path,
|
|
1278
|
+
lock_name: str,
|
|
1279
|
+
command: List[str],
|
|
1280
|
+
install_url: str,
|
|
1281
|
+
dry_run: bool = False,
|
|
1282
|
+
backups: Optional[Dict[Path, Path]] = None,
|
|
1283
|
+
) -> Optional[str]:
|
|
1284
|
+
"""Regenerate a lock file by running `command` in root_dir.
|
|
1240
1285
|
|
|
1241
|
-
|
|
1286
|
+
The lock file is added to `backups` before being rewritten, so a later
|
|
1287
|
+
failure restores it. Returns the path to the lock file if it exists (and
|
|
1288
|
+
so is, or in dry run would be, regenerated), None otherwise.
|
|
1242
1289
|
"""
|
|
1243
|
-
|
|
1290
|
+
lock_path = root_dir / lock_name
|
|
1291
|
+
tool = command[0]
|
|
1292
|
+
cmd_str = " ".join(command)
|
|
1244
1293
|
|
|
1245
|
-
if not
|
|
1294
|
+
if not lock_path.exists():
|
|
1246
1295
|
return None
|
|
1247
1296
|
|
|
1248
1297
|
if dry_run:
|
|
1249
|
-
return
|
|
1298
|
+
return str(lock_path)
|
|
1299
|
+
|
|
1300
|
+
if backups is not None:
|
|
1301
|
+
backup_file(backups, lock_path)
|
|
1250
1302
|
|
|
1251
1303
|
console.print(
|
|
1252
|
-
f"[{STYLE_INFO}]Running '
|
|
1304
|
+
f"[{STYLE_INFO}]Running '{cmd_str}' to update {lock_name}...[/{STYLE_INFO}]"
|
|
1253
1305
|
)
|
|
1254
1306
|
try:
|
|
1255
1307
|
result = subprocess.run(
|
|
1256
|
-
|
|
1308
|
+
command,
|
|
1257
1309
|
cwd=root_dir,
|
|
1258
1310
|
timeout=60,
|
|
1259
1311
|
)
|
|
1260
1312
|
|
|
1261
1313
|
if result.returncode != 0:
|
|
1262
1314
|
console.print(
|
|
1263
|
-
f"[{STYLE_ERROR}]Error: '
|
|
1315
|
+
f"[{STYLE_ERROR}]Error: '{cmd_str}' returned non-zero exit code: {result.returncode}[/{STYLE_ERROR}]"
|
|
1264
1316
|
)
|
|
1265
1317
|
console.print(
|
|
1266
|
-
f"[{STYLE_ERROR}]Failed to update
|
|
1318
|
+
f"[{STYLE_ERROR}]Failed to update {lock_name}. Please ensure '{tool}' is installed.[/{STYLE_ERROR}]"
|
|
1267
1319
|
)
|
|
1268
|
-
raise RuntimeError(f"'
|
|
1320
|
+
raise RuntimeError(f"'{cmd_str}' failed with exit code {result.returncode}")
|
|
1269
1321
|
|
|
1270
1322
|
except subprocess.TimeoutExpired:
|
|
1271
1323
|
console.print(
|
|
1272
|
-
f"[{STYLE_ERROR}]Error: '
|
|
1324
|
+
f"[{STYLE_ERROR}]Error: '{cmd_str}' command timed out[/{STYLE_ERROR}]"
|
|
1273
1325
|
)
|
|
1274
|
-
raise RuntimeError("'
|
|
1326
|
+
raise RuntimeError(f"'{cmd_str}' command timed out after 60 seconds")
|
|
1275
1327
|
except FileNotFoundError:
|
|
1276
|
-
console.print(f"[{STYLE_ERROR}]Error: 'pixi' command not found[/{STYLE_ERROR}]")
|
|
1277
1328
|
console.print(
|
|
1278
|
-
f"[{STYLE_ERROR}]
|
|
1329
|
+
f"[{STYLE_ERROR}]Error: '{tool}' command not found[/{STYLE_ERROR}]"
|
|
1330
|
+
)
|
|
1331
|
+
console.print(
|
|
1332
|
+
f"[{STYLE_ERROR}]{lock_name} exists but '{tool}' executable is not available.[/{STYLE_ERROR}]"
|
|
1279
1333
|
)
|
|
1280
1334
|
console.print(
|
|
1281
|
-
f"[{STYLE_INFO}]Please install
|
|
1335
|
+
f"[{STYLE_INFO}]Please install {tool}: {install_url}[/{STYLE_INFO}]"
|
|
1282
1336
|
)
|
|
1283
|
-
raise RuntimeError("'
|
|
1337
|
+
raise RuntimeError(f"'{tool}' executable not found. Install from {install_url}")
|
|
1284
1338
|
except Exception as e:
|
|
1285
1339
|
console.print(
|
|
1286
|
-
f"[{STYLE_ERROR}]Error: Failed to run '
|
|
1340
|
+
f"[{STYLE_ERROR}]Error: Failed to run '{cmd_str}': {e}[/{STYLE_ERROR}]"
|
|
1287
1341
|
)
|
|
1288
|
-
raise RuntimeError(f"Failed to run '
|
|
1342
|
+
raise RuntimeError(f"Failed to run '{cmd_str}': {e}") from e
|
|
1289
1343
|
|
|
1290
1344
|
console.print(
|
|
1291
|
-
f"[{STYLE_SUCCESS}]✓ Updated
|
|
1345
|
+
f"[{STYLE_SUCCESS}]✓ Updated {lock_name} via '{cmd_str}'[/{STYLE_SUCCESS}]"
|
|
1292
1346
|
)
|
|
1293
1347
|
|
|
1294
|
-
return str(
|
|
1348
|
+
return str(lock_path)
|
|
1349
|
+
|
|
1350
|
+
|
|
1351
|
+
def update_pixi_lock(
|
|
1352
|
+
root_dir: Path,
|
|
1353
|
+
dry_run: bool = False,
|
|
1354
|
+
backups: Optional[Dict[Path, Path]] = None,
|
|
1355
|
+
) -> Optional[str]:
|
|
1356
|
+
"""Update pixi.lock file by running 'pixi list'.
|
|
1357
|
+
|
|
1358
|
+
Returns the path to pixi.lock if it exists, None otherwise.
|
|
1359
|
+
"""
|
|
1360
|
+
return update_lock_file(
|
|
1361
|
+
root_dir, "pixi.lock", ["pixi", "list"], "https://pixi.sh", dry_run, backups
|
|
1362
|
+
)
|
|
1363
|
+
|
|
1364
|
+
|
|
1365
|
+
def update_cargo_lock(
|
|
1366
|
+
root_dir: Path,
|
|
1367
|
+
dry_run: bool = False,
|
|
1368
|
+
backups: Optional[Dict[Path, Path]] = None,
|
|
1369
|
+
) -> Optional[str]:
|
|
1370
|
+
"""Update Cargo.lock file by running 'cargo update --workspace'.
|
|
1371
|
+
|
|
1372
|
+
Only the workspace crates' own versions are refreshed, not dependencies.
|
|
1373
|
+
Returns the path to Cargo.lock if it exists, None otherwise.
|
|
1374
|
+
"""
|
|
1375
|
+
return update_lock_file(
|
|
1376
|
+
root_dir,
|
|
1377
|
+
"Cargo.lock",
|
|
1378
|
+
["cargo", "update", "--workspace"],
|
|
1379
|
+
"https://rustup.rs",
|
|
1380
|
+
dry_run,
|
|
1381
|
+
backups,
|
|
1382
|
+
)
|
|
1295
1383
|
|
|
1296
1384
|
|
|
1297
1385
|
def create_backups(file_paths: List[Path]) -> Dict[Path, Path]:
|
|
@@ -1299,17 +1387,27 @@ def create_backups(file_paths: List[Path]) -> Dict[Path, Path]:
|
|
|
1299
1387
|
|
|
1300
1388
|
Returns a mapping of original paths to backup paths.
|
|
1301
1389
|
"""
|
|
1302
|
-
backups = {}
|
|
1303
|
-
|
|
1390
|
+
backups: Dict[Path, Path] = {}
|
|
1391
|
+
for file_path in file_paths:
|
|
1392
|
+
backup_file(backups, file_path)
|
|
1393
|
+
return backups
|
|
1304
1394
|
|
|
1305
|
-
# Index-prefix the name so files sharing a basename don't collide.
|
|
1306
|
-
for index, file_path in enumerate(file_paths):
|
|
1307
|
-
if file_path.exists():
|
|
1308
|
-
backup_path = temp_dir / f"{index:04d}_{file_path.name}"
|
|
1309
|
-
shutil.copy2(file_path, backup_path)
|
|
1310
|
-
backups[file_path] = backup_path
|
|
1311
1395
|
|
|
1312
|
-
|
|
1396
|
+
def backup_file(backups: Dict[Path, Path], file_path: Path) -> None:
|
|
1397
|
+
"""Add a backup copy of file_path to backups (no-op if missing or already there)."""
|
|
1398
|
+
# Deduplicate: a file may carry several tracked version fields.
|
|
1399
|
+
if file_path in backups or not file_path.exists():
|
|
1400
|
+
return
|
|
1401
|
+
|
|
1402
|
+
if backups:
|
|
1403
|
+
temp_dir = next(iter(backups.values())).parent
|
|
1404
|
+
else:
|
|
1405
|
+
temp_dir = Path(tempfile.mkdtemp(prefix="release_backup_"))
|
|
1406
|
+
|
|
1407
|
+
# Index-prefix the name so files sharing a basename don't collide.
|
|
1408
|
+
backup_path = temp_dir / f"{len(backups):04d}_{file_path.name}"
|
|
1409
|
+
shutil.copy2(file_path, backup_path)
|
|
1410
|
+
backups[file_path] = backup_path
|
|
1313
1411
|
|
|
1314
1412
|
|
|
1315
1413
|
def restore_backups(backups: Dict[Path, Path]) -> None:
|
|
@@ -1541,13 +1639,14 @@ def perform_version_updates(
|
|
|
1541
1639
|
check.update_version(target_version)
|
|
1542
1640
|
dry_run_rows.append((check.label, old_version, target_version))
|
|
1543
1641
|
line = Text()
|
|
1544
|
-
line.append(f" {check.label:<28}", style="cyan")
|
|
1642
|
+
line.append(f" {check.label:<28} ", style="cyan")
|
|
1545
1643
|
line.append(old_version, style=STYLE_OLD_VALUE)
|
|
1546
1644
|
line.append(" → ", style="dim")
|
|
1547
1645
|
line.append(target_version, style=STYLE_NEW_VALUE)
|
|
1548
1646
|
console.print(line)
|
|
1549
1647
|
updated_files.append(check.label)
|
|
1550
|
-
|
|
1648
|
+
if str(check.file_path) not in updated_file_paths:
|
|
1649
|
+
updated_file_paths.append(str(check.file_path))
|
|
1551
1650
|
except VersionNotPresent:
|
|
1552
1651
|
pass # file exists but has no version configured; skip
|
|
1553
1652
|
except Exception as e:
|
|
@@ -1560,9 +1659,17 @@ def perform_version_updates(
|
|
|
1560
1659
|
return updated_files, updated_file_paths, failed, dry_run_rows
|
|
1561
1660
|
|
|
1562
1661
|
|
|
1662
|
+
def print_lock_rows(lock_paths: List[str]) -> None:
|
|
1663
|
+
for lock_path in lock_paths:
|
|
1664
|
+
line = Text()
|
|
1665
|
+
line.append(f" {Path(lock_path).name:<28}", style="cyan")
|
|
1666
|
+
line.append("regenerated", style="dim")
|
|
1667
|
+
console.print(line)
|
|
1668
|
+
|
|
1669
|
+
|
|
1563
1670
|
def show_dry_run_panel(
|
|
1564
1671
|
dry_run_rows: List[Tuple[str, str, str]],
|
|
1565
|
-
|
|
1672
|
+
lock_paths: List[str],
|
|
1566
1673
|
git_lines: List[str],
|
|
1567
1674
|
) -> None:
|
|
1568
1675
|
"""Display a unified dry-run preview."""
|
|
@@ -1580,11 +1687,7 @@ def show_dry_run_panel(
|
|
|
1580
1687
|
line.append(" → ", style="dim")
|
|
1581
1688
|
line.append(new, style=STYLE_NEW_VALUE)
|
|
1582
1689
|
console.print(line)
|
|
1583
|
-
|
|
1584
|
-
line = Text()
|
|
1585
|
-
line.append(f" {'pixi.lock':<28}", style="cyan")
|
|
1586
|
-
line.append("regenerated via pixi list", style="dim")
|
|
1587
|
-
console.print(line)
|
|
1690
|
+
print_lock_rows(lock_paths)
|
|
1588
1691
|
|
|
1589
1692
|
if git_lines:
|
|
1590
1693
|
console.print()
|
|
@@ -1596,14 +1699,10 @@ def show_dry_run_panel(
|
|
|
1596
1699
|
|
|
1597
1700
|
|
|
1598
1701
|
def show_result_panel(
|
|
1599
|
-
|
|
1702
|
+
lock_paths: List[str],
|
|
1600
1703
|
) -> None:
|
|
1601
1704
|
"""Display a polished summary of completed version updates."""
|
|
1602
|
-
|
|
1603
|
-
line = Text()
|
|
1604
|
-
line.append(f" {'pixi.lock':<28}", style="cyan")
|
|
1605
|
-
line.append("regenerated via pixi list", style="dim")
|
|
1606
|
-
console.print(line)
|
|
1705
|
+
print_lock_rows(lock_paths)
|
|
1607
1706
|
console.print()
|
|
1608
1707
|
console.print(
|
|
1609
1708
|
f"[{STYLE_SUCCESS_STRONG}]✓ Version updated successfully[/{STYLE_SUCCESS_STRONG}]"
|
|
@@ -1730,6 +1829,11 @@ def main():
|
|
|
1730
1829
|
)
|
|
1731
1830
|
|
|
1732
1831
|
group = parser.add_mutually_exclusive_group(required=True)
|
|
1832
|
+
group.add_argument(
|
|
1833
|
+
"--version",
|
|
1834
|
+
action="store_true",
|
|
1835
|
+
help="Show jrl-cmakemodules-scripts version and exit",
|
|
1836
|
+
)
|
|
1733
1837
|
group.add_argument(
|
|
1734
1838
|
"--check-version", action="store_true", help="Check versions across files."
|
|
1735
1839
|
)
|
|
@@ -1756,6 +1860,11 @@ def main():
|
|
|
1756
1860
|
)
|
|
1757
1861
|
|
|
1758
1862
|
args = parser.parse_args()
|
|
1863
|
+
|
|
1864
|
+
if args.version:
|
|
1865
|
+
print(importlib.metadata.version("jrl_cmakemodules_scripts"))
|
|
1866
|
+
sys.exit(0)
|
|
1867
|
+
|
|
1759
1868
|
root_dir = args.root
|
|
1760
1869
|
|
|
1761
1870
|
# Redirect console output to stderr for clean stdout with json/short
|
|
@@ -1882,13 +1991,17 @@ def main():
|
|
|
1882
1991
|
sys.exit(1)
|
|
1883
1992
|
|
|
1884
1993
|
try:
|
|
1885
|
-
|
|
1886
|
-
if
|
|
1887
|
-
|
|
1888
|
-
|
|
1994
|
+
lock_paths: List[str] = []
|
|
1995
|
+
if lock_path := update_pixi_lock(root_dir, args.dry_run, backups):
|
|
1996
|
+
lock_paths.append(lock_path)
|
|
1997
|
+
if lock_path := update_cargo_lock(root_dir, args.dry_run, backups):
|
|
1998
|
+
lock_paths.append(lock_path)
|
|
1999
|
+
for lock_path in lock_paths:
|
|
2000
|
+
updated_files.append(Path(lock_path).name)
|
|
2001
|
+
updated_file_paths.append(lock_path)
|
|
1889
2002
|
except RuntimeError as e:
|
|
1890
2003
|
console.print(
|
|
1891
|
-
f"[{STYLE_ERROR}]
|
|
2004
|
+
f"[{STYLE_ERROR}]Lock file update failed: {e}[/{STYLE_ERROR}]"
|
|
1892
2005
|
)
|
|
1893
2006
|
if backups:
|
|
1894
2007
|
console.print(
|
|
@@ -1943,8 +2056,6 @@ def main():
|
|
|
1943
2056
|
archive_name = f"{project_url.split('/')[-1]}-{target_version}.tar.gz"
|
|
1944
2057
|
|
|
1945
2058
|
if args.dry_run:
|
|
1946
|
-
pixi_lock_would_update = (root_dir / "pixi.lock").exists()
|
|
1947
|
-
|
|
1948
2059
|
git_lines: List[str] = []
|
|
1949
2060
|
if args.git_commit is not None:
|
|
1950
2061
|
custom_message = None if args.git_commit is True else args.git_commit
|
|
@@ -2000,11 +2111,11 @@ def main():
|
|
|
2000
2111
|
)
|
|
2001
2112
|
git_lines.append(call)
|
|
2002
2113
|
|
|
2003
|
-
show_dry_run_panel(dry_run_rows,
|
|
2114
|
+
show_dry_run_panel(dry_run_rows, lock_paths, git_lines)
|
|
2004
2115
|
sys.exit(0)
|
|
2005
2116
|
else:
|
|
2006
2117
|
if not args.short and args.output_format == "text":
|
|
2007
|
-
show_result_panel(
|
|
2118
|
+
show_result_panel(lock_paths)
|
|
2008
2119
|
|
|
2009
2120
|
# Git operations - only perform if explicitly requested
|
|
2010
2121
|
if args.git_tag is not None and args.git_commit is None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|