Skip to content

Commit 8a98e04

Browse files
committed
Fetch all different ghc bindist variants
Instead of choosing the oldest debian distribution tarball, which does not work anymore on newer Ubuntu systems as these lack the required libtinfo5 library, we want to be able to choose arbitrary dist and variant.
1 parent f3bc788 commit 8a98e04

File tree

1 file changed

+52
-59
lines changed

1 file changed

+52
-59
lines changed

haskell/gen_ghc_bindist.py

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
import os
88
import json
9+
import re
910
import sys
11+
from collections import OrderedDict
1012
from urllib.request import urlopen
1113
from packaging.version import Version
1214

@@ -16,30 +18,16 @@
1618

1719
# All architectures we generate.
1820
# bazel: bazel name
19-
# upstream: list of download.haskell.org name
21+
# upstream: corresponding os / arch on download.haskell.org
2022
ARCHES = [
21-
{
22-
"bazel": "linux_amd64",
23-
"upstream": ["x86_64-deb8-linux", "x86_64-deb9-linux", "x86_64-deb10-linux"],
24-
},
25-
{
26-
"bazel": "linux_arm64",
27-
"upstream": ["aarch64-deb10-linux"],
28-
},
29-
{"bazel": "darwin_amd64", "upstream": ["x86_64-apple-darwin"]},
30-
{"bazel": "darwin_arm64", "upstream": ["aarch64-apple-darwin"]},
31-
{"bazel": "windows_amd64", "upstream": ["x86_64-unknown-mingw32"]},
23+
{"bazel": "linux_amd64", "upstream": {"os": "linux", "arch": "x86_64"}},
24+
{"bazel": "linux_arm64", "upstream": {"os": "linux", "arch": "aarch64"}},
25+
{"bazel": "darwin_amd64", "upstream": {"os": "darwin", "arch": "x86_64"}},
26+
{"bazel": "darwin_arm64", "upstream": {"os": "darwin", "arch": "aarch64"}},
27+
{"bazel": "windows_amd64", "upstream": {"os": "mingw32", "arch": "x86_64"}},
3228
]
3329

3430

35-
# An url to a bindist tarball.
36-
def link_for_tarball(arch, version):
37-
return "https://downloads.haskell.org/~ghc/{ver}/ghc-{ver}-{arch}.tar.xz".format(
38-
ver=version,
39-
arch=arch,
40-
)
41-
42-
4331
# An url to a version's tarball hashsum file.
4432
# The files contain the hashsums for all arches.
4533
def link_for_sha256_file(version):
@@ -48,23 +36,37 @@ def link_for_sha256_file(version):
4836

4937
# Parses the tarball hashsum file for a distribution version.
5038
def parse_sha256_file(content, version, url):
51-
res = {}
39+
res = []
5240

53-
prefix = "ghc-{ver}-".format(ver=VERSIONS_CORRECTED.get(version, version))
41+
version = VERSIONS_CORRECTED.get(version, version)
5442
suffix = ".tar.xz"
5543

44+
ghc_regex = re.compile(
45+
r"ghc-(?P<version>[^-]+)-(?P<arch>[^-]+)-(?P<dist>[^-]+)-(?P<os>[^-]+)(?:-(?P<variant>[^.]+))?\.tar\.xz"
46+
)
47+
5648
for line in content:
5749
# f5763983a26dedd88b65a0b17267359a3981b83a642569b26334423f684f8b8c ./ghc-8.4.3-i386-deb8-linux.tar.xz
5850
(hash, file_) = line.decode().strip().split(" ./")
5951

60-
if file_.startswith(prefix) and file_.endswith(suffix):
61-
# i386-deb8-linux
62-
name = file_[len(prefix) : -len(suffix)]
63-
res[name] = hash
52+
m = ghc_regex.match(file_)
53+
54+
if m:
55+
v = m.group('version')
56+
arch = m.group('arch')
57+
dist = m.group('dist')
58+
variant = m.group('variant')
59+
os = m.group('os')
60+
61+
if v == version:
62+
spec = {"os": os, "arch": arch, "dist": dist, "sha256": hash, "url": f"https://downloads.haskell.org/~ghc/{version}/{file_}" }
63+
if variant:
64+
spec["variant"] = variant
65+
res.append(spec)
6466

6567
if not res:
6668
eprint(
67-
f"Errors parsing file at {url}. Could not find entries for {prefix}{suffix}"
69+
f"Errors parsing file at {url}. Could not find entries for GHC version {version} with {suffix}"
6870
)
6971
exit(1)
7072

@@ -84,7 +86,7 @@ def select_one(xs, ys):
8486

8587
def fetch_hashsums(versions):
8688
# Fetch all hashsum files
87-
# grab : { version: { arch: sha256 } }
89+
# grab : { version: { arch: "..", sha256: "..", dist: "..", variant = "..", url: "..." } }
8890
grab = {}
8991
for ver in versions:
9092
eprint("fetching " + ver)
@@ -96,44 +98,35 @@ def fetch_hashsums(versions):
9698
else:
9799
grab[ver] = parse_sha256_file(res, ver, url)
98100

99-
# check whether any version is missing arches we need
100-
# errs : { version: set(missing_arches) }
101-
errs = {}
102-
for ver, hashes in grab.items():
103-
real_arches = frozenset(hashes.keys())
104-
upstreams = [select_one(a["upstream"], real_arches) for a in ARCHES]
105-
needed_arches = frozenset(upstreams)
106-
missing_arches = needed_arches.difference(real_arches)
107-
if missing_arches:
108-
errs[ver] = missing_arches
109-
if errs:
110-
for ver, missing in errs.items():
111-
print(
112-
"WARN: version {ver} is missing hashes for architectures {arches}".format(
113-
ver=ver, arches=",".join(missing)
114-
),
115-
file=sys.stderr,
116-
)
117-
118101
return grab
119102

120103

121104
def fetch_bindists(grab):
122105
# fetch the arches we need and create the GHC_BINDISTS dict
123-
# ghc_bindists : { version: { bazel_arch: (tarball_url, sha256_hash) } }
106+
# ghc_bindists : { version: { bazel_arch: [ {url, sha256, dist, variant} ] } }
124107
ghc_bindists = {}
125-
for ver, hashes in grab.items():
108+
for ver, infos in grab.items():
126109
# { bazel_arch: (tarball_url, sha256_hash) }
127110
arch_dists = {}
128111
for arch in ARCHES:
129-
upstream = select_one(arch["upstream"], hashes)
130-
131-
if upstream in hashes:
132-
arch_dists[arch["bazel"]] = (
133-
link_for_tarball(upstream, ver),
134-
hashes[upstream],
112+
spec = arch["upstream"]
113+
upstreams = [
114+
upstream
115+
for upstream in infos if all([spec[k] == upstream.get(k) for k in spec])
116+
]
117+
118+
if not upstreams:
119+
print(
120+
"WARN: version {ver} is missing hashes for {arch} {os}".format(ver=ver, **spec),
121+
file=sys.stderr,
135122
)
136-
ghc_bindists[ver] = arch_dists
123+
124+
else:
125+
arch_dists[arch["bazel"]] = [
126+
{ k: v for k, v in upstream.items() if k not in ["os", "arch"]}
127+
for upstream in sorted(upstreams, key=lambda u: (u["dist"], u.get("variant", "")))
128+
]
129+
ghc_bindists[ver] = OrderedDict(sorted(arch_dists.items()))
137130

138131
return ghc_bindists
139132

@@ -156,10 +149,10 @@ def fetch_bindists(grab):
156149

157150
ghc_bindists = fetch_bindists(grab)
158151

159-
ghc_versions = {
160-
version: ghc_bindists[version]
152+
ghc_versions = OrderedDict(
153+
(version, ghc_bindists[version])
161154
for version in sorted(ghc_bindists.keys(), key=Version)
162-
}
155+
)
163156

164157
json_file.truncate(0)
165158
json_file.seek(0)

0 commit comments

Comments
 (0)