first commit

This commit is contained in:
linkitapps
2026-09-14 23:22:10 +09:00
commit 9f9c8fb69b
4207 changed files with 1333187 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
from __future__ import annotations
import argparse, shutil, subprocess, tarfile, time
from pathlib import Path
import sys
ROOT=Path(__file__).resolve().parents[1]
sys.path.insert(0,str(ROOT))
from sourcehub.config import Settings
parser=argparse.ArgumentParser()
parser.add_argument("--out",default="backups")
args=parser.parse_args()
settings=Settings.from_env()
out=Path(args.out);out.mkdir(parents=True,exist_ok=True)
stamp=time.strftime("%Y%m%d-%H%M%S")
if settings.database_kind=="sqlite":
db=Path(settings.database_url.replace("sqlite:///","",1))
shutil.copy2(db,out/f"sourcehub-{stamp}.db")
elif settings.database_kind=="postgresql":
target=out/f"sourcehub-{stamp}.dump"
subprocess.run(["pg_dump","--format=custom","--file",str(target),settings.database_url],check=True)
else:
raise SystemExit("지원하지 않는 DB backend")
if settings.storage_backend=="local":
tar_path=out/f"sourcehub-storage-{stamp}.tar.gz"
with tarfile.open(tar_path,"w:gz") as tar:
tar.add(settings.local_storage_dir,arcname="storage")
print(tar_path)
else:
print("MinIO object backup은 bucket versioning/replication 또는 mc mirror 정책으로 운영하세요.")
print("backup complete",stamp)
+40
View File
@@ -0,0 +1,40 @@
from __future__ import annotations
import argparse, shutil, subprocess, tarfile, tempfile
from pathlib import Path
import sys
ROOT=Path(__file__).resolve().parents[1]
sys.path.insert(0,str(ROOT))
from sourcehub.config import Settings
p=argparse.ArgumentParser()
p.add_argument("--db",required=True)
p.add_argument("--storage")
p.add_argument("--yes-really-restore",action="store_true")
a=p.parse_args()
if not a.yes_really_restore:
raise SystemExit("복구는 파괴적 작업입니다. --yes-really-restore를 추가하세요.")
settings=Settings.from_env()
if settings.database_kind=="sqlite":
target=Path(settings.database_url.replace("sqlite:///","",1))
target.parent.mkdir(parents=True,exist_ok=True)
shutil.copy2(a.db,target)
elif settings.database_kind=="postgresql":
subprocess.run(["pg_restore","--clean","--if-exists","--no-owner","--dbname",settings.database_url,a.db],check=True)
else:
raise SystemExit("지원하지 않는 DB backend")
if a.storage:
if settings.storage_backend!="local":
raise SystemExit("MinIO 복구는 mc mirror/versioning 절차를 사용하세요.")
with tempfile.TemporaryDirectory(prefix="sourcehub_restore_") as td:
temp_root=Path(td)
with tarfile.open(a.storage,"r:gz") as tar:
tar.extractall(temp_root,filter="data")
extracted=temp_root/"storage"
if not extracted.exists():
raise SystemExit("백업 파일에 storage 디렉터리가 없습니다.")
shutil.rmtree(settings.local_storage_dir,ignore_errors=True)
settings.local_storage_dir.parent.mkdir(parents=True,exist_ok=True)
shutil.copytree(extracted,settings.local_storage_dir)
print("restore complete")
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
alembic upgrade head
python -m uvicorn app:app --host 0.0.0.0 --port 8000 --reload
+27
View File
@@ -0,0 +1,27 @@
from __future__ import annotations
import os, subprocess, sys, time
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
sys.path.insert(0,str(ROOT))
from sqlalchemy import text
from sourcehub.config import Settings
from sourcehub.db import build_engine
settings=Settings.from_env(ROOT)
engine=build_engine(settings)
last=None
for attempt in range(30):
try:
with engine.connect() as conn:
conn.execute(text("SELECT 1"))
last=None
break
except Exception as exc:
last=exc
print(f"[DB WAIT] {attempt+1}/30 {type(exc).__name__}",flush=True)
time.sleep(2)
if last:
raise SystemExit(f"Database unavailable: {last}")
subprocess.run([sys.executable,"-m","alembic","upgrade","head"],cwd=ROOT,check=True)
os.execvp(sys.executable,[sys.executable,"-m","uvicorn","app:app","--host","0.0.0.0","--port","8000","--proxy-headers","--forwarded-allow-ips=*"])
+4
View File
@@ -0,0 +1,4 @@
@echo off
alembic upgrade head
python -m uvicorn app:app --host 0.0.0.0 --port 8000 --reload
pause