Add single-command installation: install.sh, Makefile, frontend build hook
- hatch_build.py: custom hatchling build hook that compiles the React frontend (npm ci + build) when frontend/dist is missing or stale, so 'uv tool install git+https://gitea.zephyre.one/Pakobbix/nvcurve.git' works as a single command - install.sh: curl|bash installer (checks prerequisites, auto-installs uv, clones and installs) - Makefile: dev targets (frontend, install, dev, test, clean) - README/docs: document the one-liner, clone, and direct-git installs
This commit is contained in:
1 parent
d810c44478
commit
a8462e696c
7 files changed
+287
-30
No files matched your search
@@ -0,0 +1,68 @@
|
||||
"""Custom hatchling build hook: build the React frontend if it is missing or stale.
|
||||
|
||||
This makes NVCurve installable with a single command, e.g.::
|
||||
|
||||
uv tool install "git+https://gitea.zephyre.one/Pakobbix/nvcurve.git"
|
||||
|
||||
The hook runs inside the isolated build environment right before the wheel
|
||||
(or sdist) is assembled. If ``frontend/dist`` does not exist yet — or is older
|
||||
than the frontend sources — it compiles the frontend using the host's ``npm``
|
||||
(PATH is inherited from the environment).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
||||
|
||||
# Frontend inputs that must be newer than dist/index.html to trigger a rebuild.
|
||||
_FRONTEND_INPUTS = ("src", "index.html", "vite.config.ts", "package.json", "tsconfig.json")
|
||||
|
||||
|
||||
class FrontendBuildHook(BuildHookInterface):
|
||||
"""Build ``frontend/dist`` with npm when it is missing or stale."""
|
||||
|
||||
PLUGIN_NAME = "custom"
|
||||
|
||||
def initialize(self, version: str, build_data: dict) -> None:
|
||||
frontend = os.path.join(self.root, "frontend")
|
||||
dist_index = os.path.join(frontend, "dist", "index.html")
|
||||
|
||||
if not self._needs_build(frontend, dist_index):
|
||||
return
|
||||
|
||||
npm = shutil.which("npm")
|
||||
if npm is None:
|
||||
raise RuntimeError(
|
||||
"npm not found on PATH. Node.js 18+ and npm are required to build "
|
||||
"the NVCurve frontend. Install them and retry, or use install.sh "
|
||||
"which checks prerequisites for you."
|
||||
)
|
||||
|
||||
print(
|
||||
"[nvcurve] frontend/dist missing or stale — building frontend with npm ...",
|
||||
file=sys.stderr,
|
||||
)
|
||||
subprocess.run([npm, "ci", "--no-audit", "--no-fund"], cwd=frontend, check=True)
|
||||
subprocess.run([npm, "run", "build"], cwd=frontend, check=True)
|
||||
|
||||
@staticmethod
|
||||
def _needs_build(frontend: str, dist_index: str) -> bool:
|
||||
if not os.path.isfile(dist_index):
|
||||
return True
|
||||
dist_mtime = os.path.getmtime(dist_index)
|
||||
for name in _FRONTEND_INPUTS:
|
||||
path = os.path.join(frontend, name)
|
||||
if os.path.isfile(path):
|
||||
if os.path.getmtime(path) > dist_mtime:
|
||||
return True
|
||||
elif os.path.isdir(path):
|
||||
for root, _dirs, files in os.walk(path):
|
||||
for file in files:
|
||||
if os.path.getmtime(os.path.join(root, file)) > dist_mtime:
|
||||
return True
|
||||
return False
|
||||
Reference in new issue
Block a user