stargate-cli 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
stargate/source.py ADDED
@@ -0,0 +1,66 @@
1
+ """Read a task through the configured commands for its URL's host."""
2
+ from __future__ import annotations
3
+
4
+ import re
5
+ import shlex
6
+ import subprocess
7
+ from pathlib import Path
8
+ from typing import Any
9
+ from urllib.parse import urlsplit
10
+
11
+ from .config import agent_env, task_sources
12
+ from .core import StargateError
13
+
14
+ # ponytail: fixed timeout; make configurable if sources need longer fetches.
15
+ FETCH_TIMEOUT_SECONDS = 120
16
+
17
+
18
+ def fetch_task(config: dict[str, Any], url: str, cwd: Path) -> str:
19
+ sources = task_sources(config)
20
+ try:
21
+ parsed = urlsplit(url)
22
+ host = parsed.hostname
23
+ except ValueError as exc:
24
+ raise StargateError(f"--from needs an absolute URL with a host; got {url!r}.") from exc
25
+ if not parsed.scheme or not host:
26
+ raise StargateError(f"--from needs an absolute URL with a host; got {url!r}.")
27
+ source = next((source for source in sources if host.lower() in source["hosts"]), None)
28
+ if source is None:
29
+ raise StargateError(
30
+ f"No task source is configured for host {host!r}; add it to task_sources "
31
+ "in your config. Stargate does not fetch URLs by itself."
32
+ )
33
+ values = {"url": url, "host": host, "path": parsed.path}
34
+ env = agent_env(source)
35
+ failures = []
36
+ for command in source["commands"]:
37
+ # One pass keeps placeholder-looking text in the URL literal.
38
+ cmd = [re.sub(r"\{(url|host|path)\}", lambda m: values[m[1]], part) for part in command]
39
+ try:
40
+ proc = subprocess.run(
41
+ cmd, cwd=cwd, text=True, capture_output=True,
42
+ stdin=subprocess.DEVNULL, timeout=FETCH_TIMEOUT_SECONDS, env=env,
43
+ )
44
+ except subprocess.TimeoutExpired as exc:
45
+ stderr = exc.stderr or b""
46
+ if isinstance(stderr, bytes):
47
+ stderr = stderr.decode(errors="replace")
48
+ reason = f"timed out after {FETCH_TIMEOUT_SECONDS}s: {stderr.strip() or '(no stderr)'}"
49
+ except (OSError, ValueError) as exc:
50
+ reason = str(exc)
51
+ else:
52
+ if proc.returncode == 0 and proc.stdout.strip():
53
+ return proc.stdout
54
+ reason = (
55
+ "exited 0 but produced no text (empty or whitespace-only output is a failed fetch)"
56
+ if proc.returncode == 0 else f"exit {proc.returncode}"
57
+ )
58
+ reason += f": {proc.stderr.strip() or '(no stderr)'}"
59
+ failures.append(f" $ {shlex.join(cmd)}\n {reason}")
60
+ raise StargateError(f"Could not read task from {url!r}:\n" + "\n".join(failures))
61
+
62
+
63
+ def branch_hint(url: str) -> str:
64
+ """Use only the last non-empty path segment, without interpreting the ref."""
65
+ segments = [part for part in urlsplit(url).path.split("/") if part]
66
+ return segments[-1] if segments else ""