Repository navigation
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·91 lines (87 loc) · 3.68 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·91 lines (87 loc) · 3.68 KB
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
#!/bin/sh
# One-command bootstrap. Local installs use: python3 scripts/install.py
set -eu
main() {
command -v python3 >/dev/null 2>&1 || {
printf '%s\n' 'cpp-tree requires Python 3.10+. Install Python, then retry.' >&2
return 1
}
python3 -c 'import sys; sys.exit(0 if sys.version_info >= (3, 10) else 1)' || {
printf '%s\n' 'cpp-tree requires Python 3.10 or newer.' >&2
return 1
}
# Read, validate, and extract only the application/build files. No tar extraction
# to arbitrary paths, symlinks, privileged writes, or changes to shell profiles.
python3 - "$@" <<'PY'
import io
import os
from pathlib import Path, PurePosixPath
import re
import subprocess
import sys
import tarfile
import tempfile
from urllib.parse import quote
from urllib.request import urlopen
repo = os.environ.get("CPP_TREE_REPO", "RidaCode/cpp-tree")
ref = os.environ.get("CPP_TREE_REF", "main")
limit = 10 * 1024 * 1024
def bootstrap():
if not re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", repo) or not ref:
raise ValueError("Invalid CPP_TREE_REPO or CPP_TREE_REF.")
# A supplied archive makes the same bootstrap testable without network access.
local = os.environ.get("CPP_TREE_ARCHIVE")
if local:
with open(local, "rb") as response:
payload = response.read(limit + 1)
else:
url = "https://codeload.github.com/" + repo + "/tar.gz/" + quote(ref, safe="")
print("Downloading " + repo + " (" + ref + ")...", flush=True)
with urlopen(url, timeout=30) as response:
payload = response.read(limit + 1)
if len(payload) > limit:
raise ValueError("Source archive exceeds 10 MiB.")
with tempfile.TemporaryDirectory(prefix="cpp-tree-source-") as work:
root = Path(work)
seen = set()
total = 0
with tarfile.open(fileobj=io.BytesIO(payload), mode="r:gz") as archive:
for member in archive:
name = PurePosixPath(member.name)
if name.is_absolute() or ".." in name.parts:
raise ValueError("Unsafe source archive path.")
if member.isdir():
continue
if not member.isfile():
raise ValueError("Source archive contains a link or special file.")
if len(name.parts) < 2:
continue
relative = PurePosixPath(*name.parts[1:])
selected = (
relative.parts[0] == "cpp_tree" and relative.suffix in (".py", ".json")
or str(relative) in ("scripts/build.py", "scripts/install.py", "LICENSE", "NOTICE.md")
)
if not selected:
continue
total += member.size
if relative in seen or total > limit:
raise ValueError("Duplicate files or oversized source contents.")
seen.add(relative)
destination = root.joinpath(*relative.parts)
destination.parent.mkdir(parents=True, exist_ok=True)
stream = archive.extractfile(member)
if stream is None:
raise ValueError("Could not read source file.")
with stream:
destination.write_bytes(stream.read())
result = subprocess.run([sys.executable, str(root / "scripts/install.py"), *sys.argv[1:]])
return result.returncode
try:
raise SystemExit(bootstrap())
except (OSError, ValueError, tarfile.TarError) as exc:
print("cpp-tree install failed: " + str(exc), file=sys.stderr)
raise SystemExit(1)
PY
}
# Defining the entire function before invocation avoids running a truncated download.
main "$@"