mirror of
https://github.com/th3r00t/pyShelf.git
synced 2026-04-28 01:59:35 -04:00
Created install.sh and build.sh
Also refactored methods to work as a zipapp
This commit is contained in:
2
build.sh
vendored
2
build.sh
vendored
@@ -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
8
instal.sh
vendored
Executable 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
|
||||
13
src/frontend/lib/FastAPIServer.py
vendored
13
src/frontend/lib/FastAPIServer.py
vendored
@@ -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)
|
||||
|
||||
2
src/frontend/lib/objects.py
vendored
2
src/frontend/lib/objects.py
vendored
@@ -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
69
src/frontend/lib/runtime_paths.py
vendored
Normal 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
|
||||
|
||||
Reference in New Issue
Block a user