a7f897a7dd
gates / gates (push) Successful in 6m24s
Read-only. fetch.py + tables.py (stdlib), TABLE.md (45 charts, % of respondents), FELHOM.md (apps, features, reasons, hardware, trends, ten ranked recommendations), METHOD.md (hashes, counts, matching, MIT licence, limits). Survey files are not committed. One register row (R-989) and one STATUS line ask the operator to rule on the recommendations.
43 lines
1.4 KiB
Python
43 lines
1.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Download the selfh.st annual survey results (2023-2025) to a cache outside every repo.
|
|
|
|
Prints bytes and SHA-256 for each file. The files are not committed (spec §9.2).
|
|
"""
|
|
import hashlib
|
|
import os
|
|
import sys
|
|
import urllib.request
|
|
|
|
BASE = "https://raw.githubusercontent.com/selfhst/cdn/main/assets/surveys/annual/{}-results.json"
|
|
CACHE = os.path.expanduser("~/research-cache/selfhst-survey")
|
|
# Prefixes/suffixes of the hashes the reviewer recorded on 2026-10-12.
|
|
EXPECTED = {
|
|
2023: ("714350e5e4b8f3cc", "f03f", 10362),
|
|
2024: ("289c5161e5b6b568", "4832", 14290),
|
|
2025: ("e083094ad7f8cb67", "229e", 20428),
|
|
}
|
|
|
|
|
|
def main():
|
|
os.makedirs(CACHE, exist_ok=True)
|
|
rc = 0
|
|
for year, (pre, suf, size) in EXPECTED.items():
|
|
url = BASE.format(year)
|
|
try:
|
|
with urllib.request.urlopen(url, timeout=30) as r:
|
|
data = r.read()
|
|
except Exception as e: # continue with the years that can be read (spec §13)
|
|
print(f"{year} FETCH FAILED {url}: {e}")
|
|
rc = 1
|
|
continue
|
|
with open(os.path.join(CACHE, f"{year}-results.json"), "wb") as f:
|
|
f.write(data)
|
|
h = hashlib.sha256(data).hexdigest()
|
|
ok = h.startswith(pre) and h.endswith(suf) and len(data) == size
|
|
print(f"{year} bytes={len(data)} sha256={h} {'MATCH' if ok else 'DIFFERS from spec'}")
|
|
return rc
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|