6
6
7
7
import os
8
8
import json
9
+ import re
9
10
import sys
11
+ from collections import OrderedDict
10
12
from urllib .request import urlopen
11
13
from packaging .version import Version
12
14
16
18
17
19
# All architectures we generate.
18
20
# bazel: bazel name
19
- # upstream: list of download.haskell.org name
21
+ # upstream: corresponding os / arch on download.haskell.org
20
22
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" }},
32
28
]
33
29
34
30
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
-
43
31
# An url to a version's tarball hashsum file.
44
32
# The files contain the hashsums for all arches.
45
33
def link_for_sha256_file (version ):
@@ -48,23 +36,37 @@ def link_for_sha256_file(version):
48
36
49
37
# Parses the tarball hashsum file for a distribution version.
50
38
def parse_sha256_file (content , version , url ):
51
- res = {}
39
+ res = []
52
40
53
- prefix = "ghc-{ver}-" . format ( ver = VERSIONS_CORRECTED .get (version , version ) )
41
+ version = VERSIONS_CORRECTED .get (version , version )
54
42
suffix = ".tar.xz"
55
43
44
+ ghc_regex = re .compile (
45
+ r"ghc-(?P<version>[^-]+)-(?P<arch>[^-]+)-(?P<dist>[^-]+)-(?P<os>[^-]+)(?:-(?P<variant>[^.]+))?\.tar\.xz"
46
+ )
47
+
56
48
for line in content :
57
49
# f5763983a26dedd88b65a0b17267359a3981b83a642569b26334423f684f8b8c ./ghc-8.4.3-i386-deb8-linux.tar.xz
58
50
(hash , file_ ) = line .decode ().strip ().split (" ./" )
59
51
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 )
64
66
65
67
if not res :
66
68
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 } "
68
70
)
69
71
exit (1 )
70
72
@@ -84,7 +86,7 @@ def select_one(xs, ys):
84
86
85
87
def fetch_hashsums (versions ):
86
88
# Fetch all hashsum files
87
- # grab : { version: { arch: sha256 } }
89
+ # grab : { version: { arch: "..", sha256: "..", dist: "..", variant = "..", url: "..." } }
88
90
grab = {}
89
91
for ver in versions :
90
92
eprint ("fetching " + ver )
@@ -96,44 +98,35 @@ def fetch_hashsums(versions):
96
98
else :
97
99
grab [ver ] = parse_sha256_file (res , ver , url )
98
100
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
-
118
101
return grab
119
102
120
103
121
104
def fetch_bindists (grab ):
122
105
# 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} ] } }
124
107
ghc_bindists = {}
125
- for ver , hashes in grab .items ():
108
+ for ver , infos in grab .items ():
126
109
# { bazel_arch: (tarball_url, sha256_hash) }
127
110
arch_dists = {}
128
111
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 ,
135
122
)
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 ()))
137
130
138
131
return ghc_bindists
139
132
@@ -156,10 +149,10 @@ def fetch_bindists(grab):
156
149
157
150
ghc_bindists = fetch_bindists (grab )
158
151
159
- ghc_versions = {
160
- version : ghc_bindists [version ]
152
+ ghc_versions = OrderedDict (
153
+ ( version , ghc_bindists [version ])
161
154
for version in sorted (ghc_bindists .keys (), key = Version )
162
- }
155
+ )
163
156
164
157
json_file .truncate (0 )
165
158
json_file .seek (0 )
0 commit comments