66
77"""
88
9- import functools
109import itertools
10+ import json
1111import operator
1212import re
1313import sys
14+ from collections import defaultdict
15+ from typing import NamedTuple
1416from urllib .parse import quote_plus
1517
1618import humanize
2022PREFIX = "https://s3.amazonaws.com/ifcopenshell-builds/"
2123
2224
23- def _ ():
24- import json
25+ class Asset (NamedTuple ):
26+ version : str
27+ commit : str
28+ last_modified : str
29+ product : str
30+ os : str
31+ size : int
32+ key : str
2533
26- d = json .load (open (sys .argv [1 ]))
27- for c in d ["Contents" ]:
28- k = c ["Key" ]
29- if k .endswith (".zip" ):
30- parts = k [:- 4 ].rsplit ("-" , 3 )
34+
35+ def get_bucket_data ():
36+ bucket = json .load (open (sys .argv [1 ]))
37+ for zip_data in bucket ["Contents" ]:
38+ key : str = zip_data ["Key" ]
39+ if key .endswith (".zip" ):
40+ parts = key .removesuffix (".zip" ).rsplit ("-" , 3 )
3141 if len (parts ) == 4 :
32- product , version , hash , os = parts
42+ product , version , commit , os = parts
3343
3444 if product in {"IfcConvert" , "IfcGeomServer" , "svgfill" }:
3545 pass
@@ -38,24 +48,21 @@ def _():
3848 else :
3949 continue
4050
41- if len (hash ) == 7 :
42- pass
43- else :
51+ if len (commit ) != 7 :
4452 continue
4553
46- if re .match (r"^v\d\.\d\.\d+$" , version ):
47- pass
48- else :
54+ # E.g. searching for 'v0.8.5'.
55+ if not re .match (r"^v\d\.\d\.\d+$" , version ):
4956 continue
5057
5158 if os in {"macosm164" , "macos64" , "linux64" , "linuxarm64" , "win32" , "win64" , "linux32" }:
5259 pass
5360 else :
5461 continue
5562
56- yield version , hash , c ["LastModified" ], product , os , c ["Size" ], k
57- elif k .endswith (".whl" ):
58- fixed = k .replace ("ifcopenshell-python" , "ifcopenshell_python" )
63+ yield Asset ( version , commit , zip_data ["LastModified" ], product , os , zip_data ["Size" ], key )
64+ elif key .endswith (".whl" ):
65+ fixed = key .replace ("ifcopenshell-python" , "ifcopenshell_python" )
5966 fixed = re .sub (r"(v\d\.\d\.\d)(\-|\+)(\w{7})" , "v0.8.1+\\ 3" , fixed )
6067 try :
6168 module_name , version , _ , tags = parse_wheel_filename (fixed )
@@ -75,7 +82,16 @@ def _():
7582
7683 abi = re .sub ("c|p|y" , "" , tag .abi )
7784
78- yield f"v{ version .public } " , version .local , c ["LastModified" ], f"{ module_name } -{ abi } " , "WASM" , c ["Size" ], k
85+ assert version .local is not None
86+ yield Asset (
87+ f"v{ version .public } " ,
88+ version .local ,
89+ zip_data ["LastModified" ],
90+ f"{ module_name } -{ abi } " ,
91+ "WASM" ,
92+ zip_data ["Size" ],
93+ key ,
94+ )
7995
8096
8197if len (sys .argv ) != 2 :
@@ -86,35 +102,55 @@ def _():
86102print ("Source code - [IfcOpenShell/build-listing](https://github.com/IfcOpenShell/build-listing)" )
87103print ()
88104
89- hashtodate = dict (
90- (hash , functools .reduce (min , (t [1 ] for t in hash_dates )))
91- for hash , hash_dates in itertools .groupby (sorted ((a [1 ], a [2 ]) for a in _ ()), key = operator .itemgetter (0 ))
92- )
93- data = natsort .natsorted (_ (), reverse = True )
94- for section , subsections in itertools .groupby (data , key = operator .itemgetter (0 )):
105+ commit_dates : defaultdict [str , list [str ]] = defaultdict (list )
106+ for asset in get_bucket_data ():
107+ commit_dates [asset .commit ].append (asset .last_modified )
108+ hash_to_date = {commit : min (dates ) for commit , dates in commit_dates .items ()}
109+
110+ data = natsort .natsorted (get_bucket_data (), reverse = True )
111+
112+ for section , subsections in itertools .groupby (data , key = operator .attrgetter ("version" )):
95113 print ("##" , section )
96114
97- for hash , rows in itertools .groupby (
98- sorted (subsections , key = lambda t : hashtodate [t [1 ]], reverse = True ), key = operator .itemgetter (1 )
115+ for commit , rows in itertools .groupby (
116+ sorted (subsections , key = lambda t : hash_to_date [t .commit ], reverse = True ),
117+ key = operator .attrgetter ("commit" ),
99118 ):
100- print ("###" , hash , "(%s)" % hashtodate [ hash ] )
119+ print (f "### { commit } ( { hash_to_date [ commit ] } )" )
101120 rows = list (rows )
102- product , os , size = map (lambda vs : natsort .natsorted (set (vs )), zip (* (r [3 :6 ] for r in rows )))
103- osh = list (
104- map (
105- lambda s : s [0 ].upper () + s [1 :],
106- map (
107- lambda s : re .sub (r"(32|64)" , " \\ 1bit" , s .replace ("m1" , " M1" ).replace ("arm" , " ARM" )).replace (
108- "os" , "OS"
109- ),
110- os ,
111- ),
112- )
113- )
114- d = dict ((r [3 :5 ], (humanize .naturalsize (r [5 ]), quote_plus (r [6 ]))) for r in rows )
121+
122+ def unique_sorted (vs : list [str ]) -> list [str ]:
123+ return natsort .natsorted (set (vs ))
124+
125+ product = unique_sorted ([r .product for r in rows ])
126+ os = unique_sorted ([r .os for r in rows ])
127+
128+ def format_os (os : str ) -> str :
129+ os = os .replace ("m1" , " M1" )
130+ os = os .replace ("arm" , " ARM" )
131+ os = os .replace ("os" , "OS" )
132+ os = re .sub (r"(32|64)" , r" \1bit" , os )
133+ os = f"{ os [0 ].upper ()} { os [1 :]} "
134+ return os
135+
136+ # Header.
137+ osh = list (map (format_os , os ))
138+ existing_products = {(r .product , r .os ): (humanize .naturalsize (r .size ), quote_plus (r .key )) for r in rows }
115139 print ()
116140 print ("item|" , "|" .join (osh ))
117- print ("|" .join (["---" ] * (len (osh ) + 1 )))
118- for p in product :
119- print (p , "|" , "|" .join (map (lambda t : "[%%s](%s%%s)" % PREFIX % t , (d .get ((p , o ), ("-" , "" )) for o in os ))))
141+ print ("|" .join (["---" ] + [":---:" ] * len (osh )))
142+
143+ # Rows.
144+ for product_ in product :
145+ links : list [str ] = []
146+ for os_ in os :
147+ size , filename = existing_products .get ((product_ , os_ ), ("-" , "" ))
148+ if filename :
149+ url = f"{ PREFIX } { filename } "
150+ link = f"[{ size } ]({ url } )"
151+ else :
152+ link = "-"
153+ links .append (link )
154+
155+ print (product_ , "|" , "|" .join (links ))
120156 print ()
0 commit comments