did latest stuff

This commit is contained in:
alexander
2026-01-22 22:04:22 +01:00
parent 2c5ae03d3f
commit efc2116de4
8 changed files with 114 additions and 45 deletions

3
.gitignore vendored
View File

@@ -1,9 +1,8 @@
.venv .venv
out out
prod
node_modules node_modules
__pycache__/ __pycache__/
package-lock.json package-lock.json
package.json package.json
cheatsheet_inventory.json

View File

@@ -1,13 +1,10 @@
FROM python:3.11 AS build FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
WORKDIR /workdir
COPY . . COPY . .
RUN pip install --no-cache-dir -r ./requirements.txt CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
RUN python3 src/build.py
FROM caddy:latest AS serve
COPY --from=build /workdir/out/ /www/
COPY --from=build /workdir/Caddyfile /etc/caddy/Caddyfile

View File

@@ -18,3 +18,5 @@ typing-inspection==0.4.2
typing_extensions==4.15.0 typing_extensions==4.15.0
urllib3==2.6.3 urllib3==2.6.3
Werkzeug==3.1.5 Werkzeug==3.1.5
fastapi==0.115.0
uvicorn[standard]==0.30.1

View File

@@ -1,3 +1,4 @@
import asyncio
from jinja2 import Environment, FileSystemLoader, select_autoescape from jinja2 import Environment, FileSystemLoader, select_autoescape
import shutil import shutil
@@ -11,15 +12,19 @@ INVENTORY_FILE = "cheatsheet_inventory.json"
STATIC_DIR = "static" STATIC_DIR = "static"
TEMPLATES_DIR = "templates" TEMPLATES_DIR = "templates"
OUTPUT_DIR = "out" OUTPUT_DIR = "out"
PROD_DIR = "prod"
async def build(trigger_list: list[str] | None = None):
inv_raw = load_cheatsheet_inventory(INVENTORY_FILE) inv_raw = load_cheatsheet_inventory(INVENTORY_FILE)
# Clear output directory # Clear output directory
shutil.rmtree(OUTPUT_DIR, ignore_errors=True) shutil.rmtree(OUTPUT_DIR, ignore_errors=True)
shutil.copytree(STATIC_DIR, OUTPUT_DIR) shutil.copytree(STATIC_DIR, OUTPUT_DIR)
inv: list[CSItem] = prepare_cheatsheets(inv_raw, OUTPUT_DIR) inv: list[CSItem] = await prepare_cheatsheets(inv_raw, OUTPUT_DIR)
if not os.path.exists(PROD_DIR):
os.mkdir(PROD_DIR)
env = Environment( env = Environment(
loader=FileSystemLoader(TEMPLATES_DIR), loader=FileSystemLoader(TEMPLATES_DIR),
@@ -43,3 +48,10 @@ with open(f"{OUTPUT_DIR}/impressum.html", "w", encoding="utf-8") as f:
with open(f"{OUTPUT_DIR}/license.html", "w", encoding="utf-8") as f: with open(f"{OUTPUT_DIR}/license.html", "w", encoding="utf-8") as f:
f.write(env.get_template("license.html.j2").render(thisYear=thisYear)) f.write(env.get_template("license.html.j2").render(thisYear=thisYear))
# Copy to prod
print("Copying to prod directory...")
shutil.copytree(OUTPUT_DIR, PROD_DIR, dirs_exist_ok=True)
if __name__ == "__main__":
asyncio.run(build())

View File

@@ -20,7 +20,7 @@ def load_cheatsheet_inventory(file: str) -> CSInventoryConfig:
return res return res
def prepare_cheatsheets(config: CSInventoryConfig, outdir: str) -> list[CSItem]: async def prepare_cheatsheets(config: CSInventoryConfig, outdir: str) -> list[CSItem]:
res: list[CSItem] = [] res: list[CSItem] = []
for item in config.items: for item in config.items:
@@ -29,10 +29,10 @@ def prepare_cheatsheets(config: CSInventoryConfig, outdir: str) -> list[CSItem]:
try: try:
match item.source.type: match item.source.type:
case CheatsheetSourceType.GITEA_SOURCE: case CheatsheetSourceType.GITEA_SOURCE:
new_items += process_gitea(item, outdir) new_items += await process_gitea(item, outdir)
case CheatsheetSourceType.PLAIN_URL: case CheatsheetSourceType.PLAIN_URL:
new_items.append(process_plain_url(item, outdir)) new_items.append(await process_plain_url(item, outdir))
case _: case _:
print("Unknow Source Type:", item.source.type) print("Unknow Source Type:", item.source.type)

59
src/main.py Normal file
View File

@@ -0,0 +1,59 @@
from fastapi import FastAPI, HTTPException, Depends
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from pydantic import BaseModel
import queue
import asyncio
from contextlib import asynccontextmanager
import os
from build import build as run_build
class TriggerRequest(BaseModel):
items: list[str]
build_queue: asyncio.Queue = None
async def worker():
print("Build queue thread started")
while True:
selected = await build_queue.get()
print("Processing build request for:", selected)
await run_build(trigger_list=selected)
@asynccontextmanager
async def lifespan(app: FastAPI):
global build_queue
build_queue = asyncio.Queue()
task = asyncio.create_task(worker())
try:
yield
finally:
task.cancel()
try:
await task
except asyncio.CancelledError:
pass
app = FastAPI(title="FSSquared Trigger API", lifespan=lifespan)
@app.post("/trigger")
async def trigger(payload: TriggerRequest):
build_queue.put(payload.items)
return {"status": "ok", "requested": payload.items}
@app.post("/trigger/all")
async def trigger_all():
await build_queue.put(None)
return {"status": "ok", "requested": "all"}
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000)

View File

@@ -5,7 +5,7 @@ import requests
from pathlib import Path from pathlib import Path
def process_gitea(item: CSInventoryItem, outdir: str) -> list[CSItem] | None: async def process_gitea(item: CSInventoryItem, outdir: str) -> list[CSItem] | None:
source: CSSourceGitea = item.source source: CSSourceGitea = item.source
commit_hash = get_release_commit_sha(source.base_url, source.owner, source.repo, source.tag) commit_hash = get_release_commit_sha(source.base_url, source.owner, source.repo, source.tag)
asserts = list_release_assets(source.base_url, source.owner, source.repo, source.tag) asserts = list_release_assets(source.base_url, source.owner, source.repo, source.tag)

View File

@@ -1,7 +1,7 @@
from sources import CSInventoryItem, CSSourcePlainURL, CSItem from sources import CSInventoryItem, CSSourcePlainURL, CSItem
from sources.util import cache_cheatsheet, get_datestring from sources.util import cache_cheatsheet, get_datestring
def process_plain_url(item: CSInventoryItem, outdir: str) -> CSItem | None: async def process_plain_url(item: CSInventoryItem, outdir: str) -> CSItem | None:
source: CSSourcePlainURL = item.source source: CSSourcePlainURL = item.source
res_url = source.url res_url = source.url