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
|
#!/usr/bin/env sh
|
||||||
# uv export > requirements.txt
|
# 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"
|
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 fastapi.middleware.cors import CORSMiddleware
|
||||||
from backend.lib.storage import Storage
|
from backend.lib.storage import Storage
|
||||||
from .objects import JSInterface
|
from .objects import JSInterface
|
||||||
|
from .runtime_paths import ensure_assets
|
||||||
from backend.lib.config import Config
|
from backend.lib.config import Config
|
||||||
|
|
||||||
app = FastAPI()
|
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 = [
|
origins = [
|
||||||
"http://localhost",
|
"http://localhost",
|
||||||
"http://localhost:8081",
|
"http://localhost:8081",
|
||||||
@@ -34,7 +37,6 @@ app.add_middleware(
|
|||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def base64decode(string) -> str:
|
def base64decode(string) -> str:
|
||||||
"""Decode a base64 string."""
|
"""Decode a base64 string."""
|
||||||
try:
|
try:
|
||||||
@@ -134,9 +136,10 @@ class FastAPIServer():
|
|||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
"""Initialize FastAPIServer object parameters."""
|
"""Initialize FastAPIServer object parameters."""
|
||||||
self.config = config
|
self.config = config
|
||||||
app.mount("/static",
|
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
|
||||||
StaticFiles(directory="src/frontend/static"),
|
# app.mount("/static",
|
||||||
name="static")
|
# StaticFiles(directory="src/frontend/static"),
|
||||||
|
# name="static")
|
||||||
self.fe_config = uvicorn.Config(app, host="0.0.0.0", port=8080,
|
self.fe_config = uvicorn.Config(app, host="0.0.0.0", port=8080,
|
||||||
log_level="info", reload=True)
|
log_level="info", reload=True)
|
||||||
self.fe_server = uvicorn.Server(self.fe_config)
|
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."""
|
"""pyShelf's Frontend Objects."""
|
||||||
from subprocess import run
|
from subprocess import run
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from src.backend.lib.config import Config
|
from backend.lib.config import Config
|
||||||
|
|
||||||
|
|
||||||
class JSInterface():
|
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