Created install.sh and build.sh

Also refactored methods to work as a zipapp
This commit is contained in:
2025-08-08 18:27:28 +00:00
parent d334ec4ada
commit f108bab2f9
5 changed files with 88 additions and 6 deletions

2
build.sh vendored
View File

@@ -1,3 +1,5 @@
#!/usr/bin/env sh
# uv export > requirements.txt
# mkdir if not exists release
mkdir -p release
python -m zipapp src --compress --output=release/pyshelf --python="/usr/bin/env python"

8
instal.sh vendored Executable file
View File

@@ -0,0 +1,8 @@
cd /tmp/
git clone https://github.com/th3r00t/pyShelf.git
cd pyshelf
git checkout 0.8.0--dev-zipapp
./build.sh
sudo cp ./src/frontend/static /var/lib/pyshelf/assets -r
sudo cp ./src/frontend/templates /var/lib/pyshelf/assets -r
sudo cp ./release/pyshelf /usr/local/bin/pyshelf

View File

@@ -16,10 +16,13 @@ from fastapi.templating import Jinja2Templates
from fastapi.middleware.cors import CORSMiddleware
from backend.lib.storage import Storage
from .objects import JSInterface
from .runtime_paths import ensure_assets
from backend.lib.config import Config
app = FastAPI()
templates = Jinja2Templates(directory="src/frontend/templates")
STATIC_DIR, TEMPLATES_DIR = ensure_assets()
templates = Jinja2Templates(directory=str(TEMPLATES_DIR))
# templates = Jinja2Templates(directory="src/frontend/templates")
origins = [
"http://localhost",
"http://localhost:8081",
@@ -34,7 +37,6 @@ app.add_middleware(
allow_headers=["*"],
)
def base64decode(string) -> str:
"""Decode a base64 string."""
try:
@@ -134,9 +136,10 @@ class FastAPIServer():
def __init__(self, config):
"""Initialize FastAPIServer object parameters."""
self.config = config
app.mount("/static",
StaticFiles(directory="src/frontend/static"),
name="static")
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
# app.mount("/static",
# StaticFiles(directory="src/frontend/static"),
# name="static")
self.fe_config = uvicorn.Config(app, host="0.0.0.0", port=8080,
log_level="info", reload=True)
self.fe_server = uvicorn.Server(self.fe_config)

View File

@@ -1,7 +1,7 @@
"""pyShelf's Frontend Objects."""
from subprocess import run
from pathlib import Path
from src.backend.lib.config import Config
from backend.lib.config import Config
class JSInterface():

69
src/frontend/lib/runtime_paths.py vendored Normal file
View File

@@ -0,0 +1,69 @@
# src/frontend/lib/runtime_paths.py
from __future__ import annotations
import os, sys, shutil
from pathlib import Path
from importlib import resources
ASSET_TOPS = ("static", "templates")
def _inside_zipapp() -> bool:
# zipapps can be a single file (…/pyshelf.pyz) or an executable file without .pyz
# When invoked, sys.argv[0] is the archive path; treat non-directory as zipapp
return not Path(sys.argv[0]).is_dir()
def assets_root() -> Path:
"""
Directory that *contains* static/ and templates/.
Priority:
1) PYSHELF_ASSETS
2) ./pyshelf (sibling dir next to the archive) when running as zipapp
3) frontend/ (package dir) when running from source/unpacked tree
"""
env = os.environ.get("PYSHELF_ASSETS")
if env:
return Path(env)
if _inside_zipapp():
# e.g. /opt/pyshelf/pyshelf -> use /opt/pyshelf/pyshelf{,/static,/templates}
base = Path(sys.argv[0]).resolve()
# strip suffix like ".pyz" if present to get a nice folder name
return base.with_suffix("")
# Dev/regular run: __file__ = …/frontend/lib/runtime_paths.py => parents[1] == …/frontend
return Path(__file__).resolve().parents[1]
def _copy_traversable_tree(src_trav, dst_dir: Path) -> None:
"""Recursively copy a Traversable (importlib.resources) tree to dst_dir."""
for child in src_trav.iterdir():
target = dst_dir / child.name
if child.is_dir():
target.mkdir(parents=True, exist_ok=True)
_copy_traversable_tree(child, target)
else:
target.parent.mkdir(parents=True, exist_ok=True)
with child.open("rb") as r, open(target, "wb") as w:
shutil.copyfileobj(r, w)
def ensure_assets() -> tuple[Path, Path]:
"""
Ensure static/ and templates/ exist on disk and return their paths.
If running from zipapp and they don't exist yet, extract packaged copies.
"""
root = assets_root()
static_dir = root / "static"
tmpl_dir = root / "templates"
# If both already exist, use them (works in repo tree and next to .pyz)
if static_dir.exists() and tmpl_dir.exists():
return static_dir, tmpl_dir
# Extract from package data into root/{static,templates}
pkg = "frontend" # package that contains 'static' and 'templates'
for top in ASSET_TOPS:
src = resources.files(pkg) / top # Traversable
dst = root / top
dst.mkdir(parents=True, exist_ok=True)
_copy_traversable_tree(src, dst)
return static_dir, tmpl_dir