exclude docs from wheel; harden bundle item handling; single-source version
This commit is contained in:
+8
-7
@@ -48,16 +48,17 @@ Local only: never publishes, and makes no network call unless `--check-pypi` is
|
||||
passed. See `docs/publishing.md` for the full flow.
|
||||
|
||||
```bash
|
||||
python build/run.py release preflight --version 0.5.2
|
||||
python build/run.py release preflight --version <version>
|
||||
python build/run.py release preflight --all-wheel-pythons --check-pypi
|
||||
python build/run.py release audit SDK\0.5.2\orisys-0.5.2-cp312-cp312-win_amd64.whl
|
||||
python build/run.py release audit SDK\<version>\orisys-<version>-cp312-cp312-win_amd64.whl
|
||||
```
|
||||
|
||||
`preflight` runs: repo state → version consistency → duplicate guard (fails only
|
||||
when the version is already released: a local git tag, or PyPI with
|
||||
`--check-pypi`) → pytest → bundle precheck → per-wheel static content/metadata
|
||||
assertions → isolated runtime verification (bundled assets + real frames, no
|
||||
camera). A populated `SDK/<version>/` is the expected input, so build first:
|
||||
`preflight` runs: repo state → version consistency → version-string scan →
|
||||
duplicate guard (fails only when the version is already released: a local git
|
||||
tag, or PyPI with `--check-pypi`) → pytest → bundle precheck → per-wheel static
|
||||
content/metadata assertions → isolated runtime verification in one venv per wheel
|
||||
(imports + bundled assets + real frames, no camera). A populated `SDK/<version>/`
|
||||
is the expected input, so build first:
|
||||
|
||||
```bash
|
||||
python build/run.py wheel-win
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from common.verify.gui import GUI_PRODUCTS, verify_gui_dist
|
||||
from common.verify.wheel import (
|
||||
verify_built_wheel,
|
||||
verify_wheel,
|
||||
verify_wheel_assets,
|
||||
verify_wheel_runtime,
|
||||
)
|
||||
@@ -14,6 +15,7 @@ __all__ = [
|
||||
"inspect_wheel",
|
||||
"verify_built_wheel",
|
||||
"verify_gui_dist",
|
||||
"verify_wheel",
|
||||
"verify_wheel_assets",
|
||||
"verify_wheel_runtime",
|
||||
]
|
||||
|
||||
@@ -16,6 +16,7 @@ from common.verify import ( # noqa: E402
|
||||
inspect_wheel,
|
||||
verify_built_wheel,
|
||||
verify_gui_dist,
|
||||
verify_wheel,
|
||||
verify_wheel_assets,
|
||||
verify_wheel_runtime,
|
||||
)
|
||||
@@ -79,7 +80,28 @@ def main(argv: list[str] | None = None) -> int:
|
||||
if not result.ok:
|
||||
exit_code = 1
|
||||
|
||||
if args.assets or args.runtime:
|
||||
if args.assets and args.runtime:
|
||||
video = args.video or default_verification_video(REPO_ROOT)
|
||||
if video is None:
|
||||
print("[FAIL] runtime: no clip found; pass --video or set ORISYS_VERIFY_VIDEO")
|
||||
return 1
|
||||
try:
|
||||
record = verify_wheel(
|
||||
args.wheel,
|
||||
video=video,
|
||||
config_name=args.config,
|
||||
frames=args.frames,
|
||||
offline=args.offline,
|
||||
)
|
||||
print(f"[ok ] {record['imports']}")
|
||||
print(f"[ok ] {record['assets']}")
|
||||
print(f"[ok ] runtime: frames={record['frames']} flow={record['flow_shape']}")
|
||||
except Exception as exc:
|
||||
print(f"[FAIL] isolated verification: {type(exc).__name__}: {exc}")
|
||||
exit_code = 1
|
||||
return exit_code
|
||||
|
||||
if args.assets:
|
||||
try:
|
||||
print(verify_wheel_assets(args.wheel))
|
||||
except Exception as exc:
|
||||
|
||||
@@ -20,6 +20,7 @@ import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import venv
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
|
||||
# Public SDK surface that must import from a released wheel.
|
||||
@@ -302,60 +303,75 @@ class WheelVerificationError(RuntimeError):
|
||||
"""
|
||||
|
||||
|
||||
def _run_in_fresh_venv(
|
||||
def _run_script(
|
||||
python: Path, script: str, args: list[str] | None = None, *, env: dict
|
||||
) -> str:
|
||||
"""Run a verification script in an already-prepared venv."""
|
||||
completed = subprocess.run(
|
||||
[str(python), "-c", script, *(args or [])],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=env,
|
||||
check=False,
|
||||
)
|
||||
if completed.returncode != 0:
|
||||
command = " ".join(str(part) for part in (args or []))
|
||||
raise WheelVerificationError(
|
||||
f"verification script failed in the venv (exit {completed.returncode}"
|
||||
+ (f", args: {command}" if command else "")
|
||||
+ ").\n--- stdout ---\n"
|
||||
+ (completed.stdout.strip() or "<empty>")
|
||||
+ "\n--- stderr ---\n"
|
||||
+ (completed.stderr.strip() or "<empty>")
|
||||
)
|
||||
return completed.stdout.strip()
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _installed_venv(
|
||||
wheel_path: Path,
|
||||
script: str,
|
||||
args: list[str] | None = None,
|
||||
*,
|
||||
python_executable: Path | None = None,
|
||||
offline: bool = False,
|
||||
prefix: str = "orisys-wheel-verify-",
|
||||
) -> str:
|
||||
):
|
||||
"""Create a venv with the wheel installed, for one or more checks.
|
||||
|
||||
Creating a venv and installing the runtime dependencies is by far the most
|
||||
expensive part of verification (tens of seconds plus a large download when
|
||||
not using ``--offline``), so callers that run several checks must share one
|
||||
venv instead of building one per check.
|
||||
"""
|
||||
wheel_path = wheel_path.resolve()
|
||||
env = _hermetic_env()
|
||||
with tempfile.TemporaryDirectory(prefix=prefix) as tmp:
|
||||
venv_dir = Path(tmp) / "venv"
|
||||
interpreter = python_executable or Path(sys.executable)
|
||||
print(
|
||||
f" [{wheel_path.name}] creating venv from {interpreter.name}"
|
||||
+ ("" if offline else " and installing dependencies (first run downloads packages)")
|
||||
+ " ...",
|
||||
flush=True,
|
||||
)
|
||||
python = _create_venv(
|
||||
venv_dir,
|
||||
python_executable=python_executable,
|
||||
system_site_packages=offline,
|
||||
)
|
||||
_install_wheel(python, wheel_path, offline=offline, env=env)
|
||||
completed = subprocess.run(
|
||||
[str(python), "-c", script, *(args or [])],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=env,
|
||||
check=False,
|
||||
)
|
||||
if completed.returncode != 0:
|
||||
command = " ".join(str(part) for part in (args or []))
|
||||
raise WheelVerificationError(
|
||||
f"verification script failed in the venv (exit {completed.returncode}"
|
||||
+ (f", args: {command}" if command else "")
|
||||
+ ").\n--- stdout ---\n"
|
||||
+ (completed.stdout.strip() or "<empty>")
|
||||
+ "\n--- stderr ---\n"
|
||||
+ (completed.stderr.strip() or "<empty>")
|
||||
)
|
||||
return completed.stdout.strip()
|
||||
yield python, env
|
||||
|
||||
|
||||
def verify_built_wheel(wheel_path: Path, *, python_executable: Path | None = None) -> None:
|
||||
"""Install the wheel in a temporary venv and smoke-test public imports."""
|
||||
_run_in_fresh_venv(
|
||||
wheel_path, _SMOKE_IMPORT_SCRIPT, python_executable=python_executable
|
||||
)
|
||||
with _installed_venv(wheel_path, python_executable=python_executable) as (python, env):
|
||||
_run_script(python, _SMOKE_IMPORT_SCRIPT, env=env)
|
||||
|
||||
|
||||
def verify_wheel_assets(wheel_path: Path, *, python_executable: Path | None = None) -> str:
|
||||
"""Assert the wheel carries loadable bundled configs and sensor assets."""
|
||||
return _run_in_fresh_venv(
|
||||
wheel_path,
|
||||
_ASSET_SCRIPT,
|
||||
python_executable=python_executable,
|
||||
prefix="orisys-wheel-assets-",
|
||||
)
|
||||
with _installed_venv(wheel_path, python_executable=python_executable) as (python, env):
|
||||
return _run_script(python, _ASSET_SCRIPT, env=env)
|
||||
|
||||
|
||||
def verify_wheel_runtime(
|
||||
@@ -372,20 +388,59 @@ def verify_wheel_runtime(
|
||||
This is the only check that proves the compiled extension plus the bundled
|
||||
sensor assets actually produce finite flow/force output end to end.
|
||||
"""
|
||||
with _installed_venv(
|
||||
wheel_path, python_executable=python_executable, offline=offline
|
||||
) as (python, env):
|
||||
return _runtime_check(python, env, video=video, config_name=config_name, frames=frames)
|
||||
|
||||
|
||||
def _runtime_check(
|
||||
python: Path, env: dict, *, video: Path, config_name: str, frames: int
|
||||
) -> dict:
|
||||
video = Path(video).resolve()
|
||||
if not video.is_file():
|
||||
raise FileNotFoundError(f"verification video not found: {video}")
|
||||
if frames < 1:
|
||||
raise ValueError("frames must be >= 1")
|
||||
|
||||
output = _run_in_fresh_venv(
|
||||
wheel_path,
|
||||
_RUNTIME_SCRIPT,
|
||||
[str(video), config_name, str(frames)],
|
||||
python_executable=python_executable,
|
||||
offline=offline,
|
||||
prefix="orisys-wheel-runtime-",
|
||||
print(f" processing {frames} frame(s) with config {config_name!r} ...", flush=True)
|
||||
output = _run_script(
|
||||
python, _RUNTIME_SCRIPT, [str(video), config_name, str(frames)], env=env
|
||||
)
|
||||
import json
|
||||
|
||||
return json.loads(output.splitlines()[-1])
|
||||
|
||||
|
||||
def verify_wheel(
|
||||
wheel_path: Path,
|
||||
*,
|
||||
video: Path | None = None,
|
||||
config_name: str = DEFAULT_RUNTIME_CONFIG,
|
||||
frames: int = 40,
|
||||
python_executable: Path | None = None,
|
||||
offline: bool = False,
|
||||
check_assets: bool = True,
|
||||
) -> dict:
|
||||
"""Run every isolated-check level for one wheel inside a single venv.
|
||||
|
||||
Use this instead of calling the individual ``verify_wheel_*`` helpers: it
|
||||
pays the venv/dependency cost once and returns the runtime record plus the
|
||||
asset and import summaries.
|
||||
"""
|
||||
with _installed_venv(
|
||||
wheel_path, python_executable=python_executable, offline=offline
|
||||
) as (python, env):
|
||||
imports = _run_script(python, _SMOKE_IMPORT_SCRIPT, env=env)
|
||||
record: dict = {"wheel": Path(wheel_path).name, "imports": imports}
|
||||
if check_assets:
|
||||
record["assets"] = _run_script(python, _ASSET_SCRIPT, env=env)
|
||||
else:
|
||||
record["assets"] = "asset check skipped (--no-assets)"
|
||||
if video is not None:
|
||||
record.update(
|
||||
_runtime_check(
|
||||
python, env, video=video, config_name=config_name, frames=frames
|
||||
)
|
||||
)
|
||||
return record
|
||||
|
||||
+26
-1
@@ -14,6 +14,7 @@ from common.paths import REPO_ROOT # noqa: E402
|
||||
from common.verify.wheel import ( # noqa: E402
|
||||
DEFAULT_RUNTIME_CONFIG,
|
||||
default_verification_video,
|
||||
verify_wheel,
|
||||
verify_wheel_assets,
|
||||
verify_wheel_runtime,
|
||||
)
|
||||
@@ -116,7 +117,31 @@ def _cmd_audit(argv: list[str]) -> int:
|
||||
if not result.ok:
|
||||
exit_code = 1
|
||||
|
||||
if args.assets or args.runtime:
|
||||
if args.assets and args.runtime:
|
||||
# One venv for both checks: building it (and downloading dependencies in
|
||||
# online mode) is the expensive part.
|
||||
video = args.video or default_verification_video(REPO_ROOT)
|
||||
if video is None:
|
||||
print("[FAIL] runtime: no verification clip; pass --video or set ORISYS_VERIFY_VIDEO")
|
||||
return 1
|
||||
try:
|
||||
record = verify_wheel(
|
||||
wheel,
|
||||
video=video,
|
||||
config_name=args.config,
|
||||
frames=args.frames,
|
||||
python_executable=args.python,
|
||||
offline=args.offline,
|
||||
)
|
||||
print(f"[ok ] {record['imports']}")
|
||||
print(f"[ok ] {record['assets']}")
|
||||
print(f"[ok ] runtime: frames={record['frames']} flow={record['flow_shape']}")
|
||||
except Exception as exc:
|
||||
print(f"[FAIL] isolated verification: {type(exc).__name__}: {exc}")
|
||||
exit_code = 1
|
||||
return exit_code
|
||||
|
||||
if args.assets:
|
||||
try:
|
||||
print(verify_wheel_assets(wheel, python_executable=args.python))
|
||||
except Exception as exc:
|
||||
|
||||
+49
-16
@@ -8,12 +8,13 @@ Steps, in order:
|
||||
|
||||
1. ``repo-state`` - git repository, clean working tree, recorded commit
|
||||
2. ``version-consistency`` - __version__ == pyproject dynamic attr == wheel names
|
||||
3. ``duplicate-guard`` - SDK/<version>/ already populated; optionally PyPI
|
||||
4. ``tests`` - pytest (slow/hardware markers excluded)
|
||||
5. ``bundle-precheck`` - every bundle item resolves; required assets present
|
||||
6. ``wheel-inspection`` - static metadata/content assertions per wheel
|
||||
7. ``wheel-runtime`` - isolated venv: bundled assets load and real frames
|
||||
flow through the public pipeline
|
||||
3. ``version-strings`` - no stale version literal left in tracked prose
|
||||
4. ``duplicate-guard`` - already-released version (git tag, optionally PyPI)
|
||||
5. ``tests`` - pytest (slow/hardware markers excluded)
|
||||
6. ``bundle-precheck`` - every bundle item resolves; required assets present
|
||||
7. ``wheel-inspection`` - static metadata/content assertions per wheel
|
||||
8. ``wheel-runtime`` - one isolated venv per wheel: bundled assets load and
|
||||
real frames flow through the public pipeline
|
||||
|
||||
Output lands in ``build/release/reports/<version>/preflight.{json,txt}``.
|
||||
"""
|
||||
@@ -39,8 +40,7 @@ from common.pyproject_utils import bundle_items, get_version # noqa: E402
|
||||
from common.verify.wheel import ( # noqa: E402
|
||||
DEFAULT_RUNTIME_CONFIG,
|
||||
default_verification_video,
|
||||
verify_wheel_assets,
|
||||
verify_wheel_runtime,
|
||||
verify_wheel,
|
||||
)
|
||||
from common.verify.wheel_contents import inspect_wheel # noqa: E402
|
||||
from release import report as report_mod # noqa: E402
|
||||
@@ -108,7 +108,9 @@ class Preflight:
|
||||
self.version = get_version(self.repo_root)
|
||||
self.version_source = "pyproject.toml dynamic attr"
|
||||
else:
|
||||
self.version = "0.0.0"
|
||||
# Not version-shaped on purpose: this is a sentinel for "unresolved",
|
||||
# and it must not look like a release version to the version-string scan.
|
||||
self.version = "unknown"
|
||||
self.version_source = "unresolved"
|
||||
|
||||
self.report_dir = report_mod.reports_root(self.repo_root, options.report_dir) / self.version
|
||||
@@ -270,6 +272,34 @@ class Preflight:
|
||||
detail += "\n" + "\n".join(problems)
|
||||
return Step("duplicate-guard", not problems, detail)
|
||||
|
||||
def _version_strings(self) -> Step:
|
||||
"""Keep the version out of prose: one source, everything else derived.
|
||||
|
||||
Scans tracked text for version-looking literals that disagree with the
|
||||
release version. Dependency constraints are ignored by design; deliberate
|
||||
exceptions live in ``version.VERSION_STRING_ALLOWLIST``.
|
||||
"""
|
||||
findings = version_mod.find_version_literals(self.repo_root, self.version)
|
||||
if not findings:
|
||||
scanned = len(version_mod.tracked_text_files(self.repo_root))
|
||||
return Step(
|
||||
"version-strings",
|
||||
True,
|
||||
f"no stale version literal in {scanned} scanned file(s); "
|
||||
f"version {self.version} lives only where it is derived from",
|
||||
)
|
||||
|
||||
by_file: dict[str, list[str]] = {}
|
||||
for path, lineno, literal in findings:
|
||||
by_file.setdefault(path, []).append(f"{path}:{lineno} -> {literal}")
|
||||
detail = (
|
||||
f"{len(findings)} version literal(s) disagree with {self.version}. "
|
||||
"Update them, or make the file version-agnostic, or add a documented "
|
||||
"entry to build/release/version.py::VERSION_STRING_ALLOWLIST:\n"
|
||||
+ "\n".join(line for lines in by_file.values() for line in lines)
|
||||
)
|
||||
return Step("version-strings", False, detail, data={"count": len(findings)})
|
||||
|
||||
def _tests(self) -> Step:
|
||||
if self.options.skip_tests:
|
||||
return Step(
|
||||
@@ -439,17 +469,16 @@ class Preflight:
|
||||
for tag, wheel, executable in targets:
|
||||
label = f"{tag} {wheel.name}"
|
||||
try:
|
||||
if self.options.no_assets:
|
||||
assets_out = "asset check skipped (--no-assets)"
|
||||
else:
|
||||
assets_out = verify_wheel_assets(wheel, python_executable=executable)
|
||||
runtime_out = verify_wheel_runtime(
|
||||
# One venv per wheel: it runs the import smoke test, the bundled
|
||||
# asset check and the frame pipeline together.
|
||||
record = verify_wheel(
|
||||
wheel,
|
||||
video=video,
|
||||
config_name=self.options.config_name,
|
||||
frames=self.options.frames,
|
||||
python_executable=executable,
|
||||
offline=self.options.offline,
|
||||
check_assets=not self.options.no_assets,
|
||||
)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
problems.append(f"{label}: command failed ({exc})")
|
||||
@@ -458,8 +487,11 @@ class Preflight:
|
||||
problems.append(f"{label}: {type(exc).__name__}: {exc}")
|
||||
continue
|
||||
|
||||
lines.append(f"{label}: {assets_out} | frames={runtime_out['frames']} flow={runtime_out['flow_shape']}")
|
||||
self.runtime_records.append({"tag": tag, "wheel": wheel.name, **runtime_out})
|
||||
lines.append(
|
||||
f"{label}: {record['assets']} | frames={record['frames']} "
|
||||
f"flow={record['flow_shape']}"
|
||||
)
|
||||
self.runtime_records.append({"tag": tag, **record})
|
||||
|
||||
detail = "\n".join(lines)
|
||||
if problems:
|
||||
@@ -480,6 +512,7 @@ class Preflight:
|
||||
for step_fn in (
|
||||
self._repo_state,
|
||||
self._version_consistency,
|
||||
self._version_strings,
|
||||
self._duplicate_guard,
|
||||
self._tests,
|
||||
self._bundle_precheck,
|
||||
|
||||
@@ -143,6 +143,97 @@ def released_tags_for(version: str, tags: list[str]) -> list[str]:
|
||||
return sorted({version, f"v{version}"} & set(tags))
|
||||
|
||||
|
||||
# Version literals that are deliberately not the package version. Keyed by
|
||||
# repo-relative path; each entry documents *why* the literal may stay.
|
||||
VERSION_STRING_ALLOWLIST: dict[str, frozenset[str]] = {
|
||||
# Historical release records: rewriting these would destroy the audit trail.
|
||||
"docs/publishing.md": frozenset({"0.4.2", "0.4.3", "0.4.4", "0.5.0", "0.5.1", "0.5.2"}),
|
||||
# Unrelated third-party/CUDA versions quoted in prose.
|
||||
"docs/get_started.md": frozenset({"12.9.0"}),
|
||||
}
|
||||
|
||||
# Paths never scanned: tests deliberately use synthetic versions, reports are
|
||||
# generated output, and this module's own allowlist/sentinel literals would
|
||||
# otherwise flag themselves.
|
||||
VERSION_SCAN_EXCLUDED_PREFIXES = (
|
||||
"tests/",
|
||||
"build/release/reports/",
|
||||
"build/nuitka/",
|
||||
"build/lib/",
|
||||
"dist/",
|
||||
"SDK/",
|
||||
"data/",
|
||||
)
|
||||
VERSION_SCAN_EXCLUDED_FILES = ("build/release/version.py",)
|
||||
|
||||
_VERSION_LITERAL_RE = re.compile(
|
||||
r"(?<![<>=!~\w.])v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.]+)?)(?![0-9A-Za-z.])"
|
||||
)
|
||||
_SCANNED_SUFFIXES = (".md", ".py", ".txt", ".toml", ".cfg", ".ini", ".rst")
|
||||
|
||||
|
||||
def tracked_text_files(repo_root: Path) -> list[Path]:
|
||||
"""Tracked files worth scanning for version literals."""
|
||||
repo_root = Path(repo_root)
|
||||
try:
|
||||
completed = subprocess.run(
|
||||
["git", "-C", str(repo_root), "ls-files", "-z"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
names = [n for n in (completed.stdout or "").split("\0") if n]
|
||||
except OSError:
|
||||
names = []
|
||||
|
||||
if not names:
|
||||
names = [
|
||||
str(path.relative_to(repo_root)).replace("\\", "/")
|
||||
for path in repo_root.rglob("*")
|
||||
if path.is_file()
|
||||
]
|
||||
|
||||
selected = []
|
||||
for name in names:
|
||||
if name.startswith(VERSION_SCAN_EXCLUDED_PREFIXES):
|
||||
continue
|
||||
if name in VERSION_SCAN_EXCLUDED_FILES:
|
||||
continue
|
||||
if not name.endswith(_SCANNED_SUFFIXES):
|
||||
continue
|
||||
selected.append(Path(name))
|
||||
return selected
|
||||
|
||||
|
||||
def find_version_literals(
|
||||
repo_root: Path, version: str
|
||||
) -> list[tuple[str, int, str]]:
|
||||
"""``(path, lineno, literal)`` for every version-looking string != ``version``.
|
||||
|
||||
Dependency constraints are skipped by the regex lookbehind (``numpy>=1.24.4``
|
||||
is not a version reference), and historical/third-party literals require an
|
||||
explicit entry in :data:`VERSION_STRING_ALLOWLIST`.
|
||||
"""
|
||||
repo_root = Path(repo_root)
|
||||
findings: list[tuple[str, int, str]] = []
|
||||
for relative in tracked_text_files(repo_root):
|
||||
absolute = repo_root / relative
|
||||
try:
|
||||
text = absolute.read_text(encoding="utf-8", errors="ignore")
|
||||
except OSError:
|
||||
continue
|
||||
if "\0" in text:
|
||||
continue
|
||||
allowed = VERSION_STRING_ALLOWLIST.get(relative.as_posix(), frozenset())
|
||||
for lineno, line in enumerate(text.splitlines(), start=1):
|
||||
for match in _VERSION_LITERAL_RE.finditer(line):
|
||||
literal = match.group(1)
|
||||
if literal == version or literal in allowed:
|
||||
continue
|
||||
findings.append((relative.as_posix(), lineno, literal))
|
||||
return findings
|
||||
|
||||
|
||||
def conda_envs_root() -> Path | None:
|
||||
"""Locate the conda envs directory the same way build/wheel/win.bat does."""
|
||||
override = os.getenv("CONDA_ENVS_ROOT")
|
||||
|
||||
+2
-2
@@ -91,8 +91,8 @@ def main(argv: list[str] | None = None) -> int:
|
||||
print(" python build/run.py wheel --help")
|
||||
print(" python build/run.py gui finger")
|
||||
print(" python build/run.py manylinux -PythonVersions 3.10")
|
||||
print(" python build/run.py release preflight --version 0.5.2")
|
||||
print(" python build/run.py release audit SDK\\0.5.2\\orisys-0.5.2-cp312-cp312-win_amd64.whl")
|
||||
print(" python build/run.py release preflight --version <version>")
|
||||
print(" python build/run.py release audit SDK\\<version>\\orisys-<version>-cp312-cp312-win_amd64.whl")
|
||||
return 0
|
||||
|
||||
command, rest = argv[0], argv[1:]
|
||||
|
||||
@@ -118,10 +118,12 @@ def build(*, target: str = "internal", verify: bool | None = None) -> Path:
|
||||
# Bundle rules live in pyproject.toml → [[tool.orisys.bundle.items]]
|
||||
bundle = bundle_items(REPO_ROOT)
|
||||
copied_counts = copy_bundle_items(REPO_ROOT, pkg_dir, bundle)
|
||||
print(f"Copied {copied_counts['configs']} JSON config files")
|
||||
print(f"Copied {copied_counts['examples']} example files to orisys/examples/")
|
||||
print(f"Copied {copied_counts['docs']} doc files to orisys/docs/")
|
||||
print(f"Copied {copied_counts['sensors']} sensor bundle files to orisys/sensors/")
|
||||
for item in bundle:
|
||||
destination = f"orisys/{item['target']}/"
|
||||
print(
|
||||
f"Copied {copied_counts.get(item['name'], 0)} file(s) "
|
||||
f"for bundle item {item['name']!r} to {destination}"
|
||||
)
|
||||
|
||||
write_wheel_setup(
|
||||
NUITKA_WHEEL_DIR,
|
||||
|
||||
@@ -55,8 +55,8 @@ def metadata_kwargs(project: dict) -> dict:
|
||||
|
||||
The Nuitka wheel is built by a generated ``setup.py`` outside the normal
|
||||
setuptools pipeline, so every PyPI-visible field has to be passed through
|
||||
explicitly. Omitting them is what left the 0.5.2 release with no
|
||||
``Requires-Python``, classifiers, project URLs or license on PyPI.
|
||||
explicitly. Omitting them is what left the early PyPI releases with no
|
||||
``Requires-Python``, classifiers, project URLs or license on the project page.
|
||||
"""
|
||||
authors = _person_strings(project.get("authors"))
|
||||
maintainers = _person_strings(project.get("maintainers"))
|
||||
|
||||
Reference in New Issue
Block a user