436954138f
Update version numbers across Rust, Python, and documentation files to 1.1.0. Enhance the .gitignore to include macOS dSYM files and plans directory. Introduce new dependencies in the Rust core library and update the README to reflect recent performance benchmarks and backtesting engine capabilities. Add new artifacts to the benchmarks manifest and improve documentation for the backtesting engine API.
187 lines
4.9 KiB
Python
187 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Update or verify ferro-ta version strings across release files.
|
|
|
|
Usage
|
|
-----
|
|
python3 scripts/bump_version.py 1.0.3
|
|
python3 scripts/bump_version.py --check
|
|
python3 scripts/bump_version.py --show
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import re
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
SEMVER_RE = re.compile(r"^\d+\.\d+\.\d+$")
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class VersionCarrier:
|
|
label: str
|
|
path: Path
|
|
pattern: str
|
|
replacement: str
|
|
|
|
def read(self) -> str:
|
|
text = self.path.read_text(encoding="utf-8")
|
|
match = re.search(self.pattern, text, flags=re.MULTILINE)
|
|
if not match:
|
|
raise ValueError(f"Could not find version for {self.label} in {self.path}")
|
|
return match.group(2)
|
|
|
|
def write(self, version: str) -> bool:
|
|
text = self.path.read_text(encoding="utf-8")
|
|
updated, count = re.subn(
|
|
self.pattern,
|
|
rf"\g<1>{version}\g<3>",
|
|
text,
|
|
count=1,
|
|
flags=re.MULTILINE,
|
|
)
|
|
if count != 1:
|
|
raise ValueError(f"Could not update {self.label} in {self.path}")
|
|
changed = updated != text
|
|
if changed:
|
|
self.path.write_text(updated, encoding="utf-8")
|
|
return changed
|
|
|
|
|
|
CARRIERS = [
|
|
VersionCarrier(
|
|
"cargo_root",
|
|
ROOT / "Cargo.toml",
|
|
r'(?m)^(version = ")([^"]+)(")$',
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
VersionCarrier(
|
|
"cargo_core_dep",
|
|
ROOT / "Cargo.toml",
|
|
r'(ferro_ta_core = \{ path = "crates/ferro_ta_core", version = ")([^"]+)("[^}]*\})',
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
VersionCarrier(
|
|
"cargo_core_crate",
|
|
ROOT / "crates" / "ferro_ta_core" / "Cargo.toml",
|
|
r'(?m)^(version = ")([^"]+)(")$',
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
VersionCarrier(
|
|
"cargo_core_readme",
|
|
ROOT / "crates" / "ferro_ta_core" / "README.md",
|
|
r'(ferro_ta_core = ")([^"]+)(")',
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
VersionCarrier(
|
|
"pyproject",
|
|
ROOT / "pyproject.toml",
|
|
r'(?m)^(version = ")([^"]+)(")$',
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
VersionCarrier(
|
|
"wasm_cargo",
|
|
ROOT / "wasm" / "Cargo.toml",
|
|
r'(?m)^(version = ")([^"]+)(")$',
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
VersionCarrier(
|
|
"wasm_package",
|
|
ROOT / "wasm" / "package.json",
|
|
r'("version": ")([^"]+)(")',
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
VersionCarrier(
|
|
"conda",
|
|
ROOT / "conda" / "meta.yaml",
|
|
r'({% set version = ")([^"]+)(" %})',
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
VersionCarrier(
|
|
"docs_changelog",
|
|
ROOT / "docs" / "changelog.rst",
|
|
r"(These docs track package version ``)([^`]+)(``\.)",
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
VersionCarrier(
|
|
"docs_support_matrix",
|
|
ROOT / "docs" / "support_matrix.rst",
|
|
r"(These docs track package version ``)([^`]+)(``\.)",
|
|
r"\g<1>{version}\g<3>",
|
|
),
|
|
]
|
|
|
|
|
|
def _read_versions() -> dict[str, str]:
|
|
return {carrier.label: carrier.read() for carrier in CARRIERS}
|
|
|
|
|
|
def _print_versions(versions: dict[str, str]) -> None:
|
|
for label, version in versions.items():
|
|
print(f"{label:20} {version}")
|
|
|
|
|
|
def _check_versions() -> int:
|
|
versions = _read_versions()
|
|
unique = sorted(set(versions.values()))
|
|
_print_versions(versions)
|
|
if len(unique) != 1:
|
|
print()
|
|
print(f"ERROR: version mismatch detected: {', '.join(unique)}")
|
|
return 1
|
|
print()
|
|
print(f"OK: all tracked versions match {unique[0]}")
|
|
return 0
|
|
|
|
|
|
def _set_version(version: str) -> int:
|
|
if not SEMVER_RE.match(version):
|
|
print(f"ERROR: expected MAJOR.MINOR.PATCH, got {version!r}")
|
|
return 1
|
|
|
|
changed_paths: list[Path] = []
|
|
for carrier in CARRIERS:
|
|
if carrier.write(version):
|
|
changed_paths.append(carrier.path)
|
|
|
|
if changed_paths:
|
|
print(f"Updated version to {version}:")
|
|
for path in sorted(set(changed_paths)):
|
|
print(f" - {path.relative_to(ROOT)}")
|
|
else:
|
|
print(f"No changes needed. All tracked files already use {version}.")
|
|
return 0
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("version", nargs="?", help="New version to write")
|
|
parser.add_argument(
|
|
"--check",
|
|
action="store_true",
|
|
help="Fail if tracked version strings do not match",
|
|
)
|
|
parser.add_argument(
|
|
"--show",
|
|
action="store_true",
|
|
help="Print tracked version strings without modifying files",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
if args.check:
|
|
return _check_versions()
|
|
if args.show:
|
|
_print_versions(_read_versions())
|
|
return 0
|
|
if args.version:
|
|
return _set_version(args.version)
|
|
|
|
parser.print_help()
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|