Spaces:
Sleeping
Sleeping
File size: 6,035 Bytes
16b3f85 8d29022 16b3f85 8d29022 16b3f85 8d29022 16b3f85 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | #!/usr/bin/env python3
"""
prevalidation.py — CiteGuardian Submission Pre-Validator
Replicates the 3 checks from validate-submission.sh:
Step 1: Ping HF Space /reset endpoint
Step 2: Docker build
Step 3: openenv validate
Usage:
python prevalidation.py <ping_url> [repo_dir]
Example:
python prevalidation.py https://my-team.hf.space .
"""
import json
import os
import subprocess
import sys
import urllib.request
import urllib.error
from datetime import datetime, timezone
from pathlib import Path
DOCKER_BUILD_TIMEOUT = 600 # seconds
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
PASS_COUNT = 0
def ts() -> str:
return datetime.now(timezone.utc).strftime("%H:%M:%S")
def log(msg: str):
print(f"[{ts()}] {msg}")
def passed(msg: str):
global PASS_COUNT
PASS_COUNT += 1
print(f"[{ts()}] PASSED -- {msg}")
def failed(msg: str):
print(f"[{ts()}] FAILED -- {msg}")
def hint(msg: str):
print(f" Hint: {msg}")
def stop_at(step: str):
print(f"\nValidation stopped at {step}. Fix the above before continuing.")
sys.exit(1)
# ---------------------------------------------------------------------------
# Step 1: Ping HF Space
# ---------------------------------------------------------------------------
def check_hf_space(ping_url: str):
log(f"Step 1/3: Pinging HF Space ({ping_url}/reset) ...")
url = f"{ping_url.rstrip('/')}/reset"
req = urllib.request.Request(
url,
data=b"{}",
headers={"Content-Type": "application/json"},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
code = resp.status
except urllib.error.HTTPError as e:
code = e.code
except Exception as e:
failed(f"HF Space not reachable: {e} — skipping, continuing to local checks")
hint("Check your network and that the Space is running.")
if code == 200:
passed("HF Space is live and responds to /reset")
else:
failed(f"HF Space /reset returned HTTP {code} (expected 200) — skipping, continuing to local checks")
hint("Deploy your HF Space and re-run to fully validate.")
# ---------------------------------------------------------------------------
# Step 2: Docker build
# ---------------------------------------------------------------------------
def check_docker_build(repo_dir: Path):
log("Step 2/3: Running docker build ...")
# Check docker is available
if subprocess.run(["docker", "--version"], capture_output=True).returncode != 0:
failed("docker command not found")
hint("Install Docker: https://docs.docker.com/get-docker/")
stop_at("Step 2")
# Find Dockerfile
if (repo_dir / "Dockerfile").exists():
context = repo_dir
elif (repo_dir / "server" / "Dockerfile").exists():
context = repo_dir / "server"
else:
failed("No Dockerfile found in repo root or server/ directory")
stop_at("Step 2")
return
log(f" Found Dockerfile in {context}")
try:
result = subprocess.run(
["docker", "build", str(context)],
capture_output=True,
text=True,
timeout=DOCKER_BUILD_TIMEOUT,
)
except subprocess.TimeoutExpired:
failed(f"Docker build timed out after {DOCKER_BUILD_TIMEOUT}s")
stop_at("Step 2")
return
if result.returncode == 0:
passed("Docker build succeeded")
else:
failed("Docker build failed")
# Print last 20 lines of output
lines = (result.stdout + result.stderr).strip().splitlines()
for line in lines[-20:]:
print(f" {line}")
stop_at("Step 2")
# ---------------------------------------------------------------------------
# Step 3: openenv validate
# ---------------------------------------------------------------------------
def check_openenv_validate(repo_dir: Path):
log("Step 3/3: Running openenv validate ...")
# Try uv run openenv first (works in uv-managed projects)
result = subprocess.run(
["uv", "run", "openenv", "validate"],
capture_output=True,
text=True,
cwd=str(repo_dir),
)
# If uv fails, try direct openenv
if result.returncode != 0 and "uv" in result.stderr.lower():
result = subprocess.run(
["openenv", "validate"],
capture_output=True,
text=True,
cwd=str(repo_dir),
)
output = (result.stdout + result.stderr).strip()
if result.returncode == 0:
passed("openenv validate passed")
if output:
log(f" {output}")
else:
failed("openenv validate failed")
print(output)
stop_at("Step 3")
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main():
args = sys.argv[1:]
if not args:
print(__doc__)
sys.exit(1)
ping_url = args[0]
repo_dir = Path(args[1]).resolve() if len(args) > 1 else Path(".").resolve()
if not repo_dir.is_dir():
print(f"Error: directory '{repo_dir}' not found")
sys.exit(1)
print()
print("=" * 40)
print(" OpenEnv Submission Validator")
print("=" * 40)
log(f"Repo: {repo_dir}")
log(f"Ping URL: {ping_url}")
print()
check_hf_space(ping_url)
check_docker_build(repo_dir)
check_openenv_validate(repo_dir)
print()
print("=" * 40)
print(f" All 3/3 checks passed!")
print(f" Your submission is ready to submit.")
print("=" * 40)
print()
if __name__ == "__main__":
main()
|