Keep workers online during long-running downloads
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
"""Construye un ZIP reproducible y limpio del Bot de Descarga."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DEFAULT_OUTPUT = ROOT.parent / "bot_descarga.zip"
|
||||
TOP_LEVEL_FILES = (
|
||||
".env.example",
|
||||
".gitignore",
|
||||
"README.md",
|
||||
"requirements.txt",
|
||||
"run_gui.py",
|
||||
"main.py",
|
||||
)
|
||||
EXCLUDED_PARTS = {"__pycache__", ".pytest_cache", ".venv", "data", "logs", "out"}
|
||||
EXCLUDED_SUFFIXES = {".pyc", ".pyo", ".log"}
|
||||
|
||||
|
||||
def package_files(root: Path) -> list[Path]:
|
||||
files: list[Path] = []
|
||||
for name in TOP_LEVEL_FILES:
|
||||
path = root / name
|
||||
if path.is_file():
|
||||
files.append(path)
|
||||
package_root = root / "bot_descarga"
|
||||
for path in package_root.rglob("*"):
|
||||
relative = path.relative_to(root)
|
||||
if not path.is_file() or any(part in EXCLUDED_PARTS for part in relative.parts):
|
||||
continue
|
||||
if path.suffix.lower() in EXCLUDED_SUFFIXES:
|
||||
continue
|
||||
files.append(path)
|
||||
return sorted(files, key=lambda path: path.relative_to(root).as_posix())
|
||||
|
||||
|
||||
def build_package(root: Path = ROOT, output: Path = DEFAULT_OUTPUT) -> Path:
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with ZipFile(output, "w", compression=ZIP_DEFLATED, compresslevel=9) as archive:
|
||||
for source in package_files(root):
|
||||
relative = source.relative_to(root).as_posix()
|
||||
info = ZipInfo(f"bot_descarga/{relative}", date_time=(2020, 1, 1, 0, 0, 0))
|
||||
info.compress_type = ZIP_DEFLATED
|
||||
info.external_attr = 0o644 << 16
|
||||
archive.writestr(info, source.read_bytes())
|
||||
return output
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as source:
|
||||
for chunk in iter(lambda: source.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT)
|
||||
args = parser.parse_args()
|
||||
target = build_package(output=args.output.resolve())
|
||||
print(f"Paquete: {target}")
|
||||
print(f"SHA256: {sha256(target)}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,66 @@
|
||||
"""Construye y publica el Bot de Descarga en el prefijo latest de MinIO."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import boto3
|
||||
from botocore.config import Config
|
||||
|
||||
from package_bot import DEFAULT_OUTPUT, build_package, sha256
|
||||
|
||||
|
||||
DEFAULT_ENDPOINT = "https://s3.builker.xyz"
|
||||
DEFAULT_BUCKET = "apps-versions"
|
||||
DEFAULT_KEY = "BotDescargaPYSCuentasMedicas/latest/bot_descarga.zip"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT)
|
||||
parser.add_argument("--build-only", action="store_true")
|
||||
args = parser.parse_args()
|
||||
artifact = build_package(output=args.output.resolve())
|
||||
print(f"Paquete validado: {artifact} ({sha256(artifact)})")
|
||||
if args.build_only:
|
||||
return 0
|
||||
|
||||
access = os.getenv("MINIO_ACCESS_KEY") or os.getenv("AWS_ACCESS_KEY_ID")
|
||||
secret = os.getenv("MINIO_SECRET_KEY") or os.getenv("AWS_SECRET_ACCESS_KEY")
|
||||
if not access or not secret:
|
||||
print("Faltan MINIO_ACCESS_KEY/MINIO_SECRET_KEY para publicar.", file=sys.stderr)
|
||||
return 2
|
||||
endpoint = os.getenv("MINIO_ENDPOINT", DEFAULT_ENDPOINT).rstrip("/")
|
||||
bucket = os.getenv("MINIO_APPS_BUCKET", DEFAULT_BUCKET)
|
||||
key = os.getenv("DOWNLOAD_PACKAGE_KEY", DEFAULT_KEY).strip("/")
|
||||
client = boto3.client(
|
||||
"s3",
|
||||
endpoint_url=endpoint,
|
||||
aws_access_key_id=access,
|
||||
aws_secret_access_key=secret,
|
||||
region_name=os.getenv("MINIO_REGION", "us-east-1"),
|
||||
config=Config(s3={"addressing_style": "path"}),
|
||||
)
|
||||
client.upload_file(
|
||||
str(artifact),
|
||||
bucket,
|
||||
key,
|
||||
ExtraArgs={"ContentType": "application/zip"},
|
||||
)
|
||||
remote = client.head_object(Bucket=bucket, Key=key)
|
||||
remote_size = int(remote.get("ContentLength") or 0)
|
||||
if remote_size != artifact.stat().st_size:
|
||||
print(
|
||||
f"La verificación remota falló: local={artifact.stat().st_size}, remoto={remote_size}.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 3
|
||||
print(f"Publicado: {endpoint}/{bucket}/{key}")
|
||||
print(f"Verificado: {remote_size} bytes")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user