Skip to content

Commit ff131ff

Browse files
authored
Merge pull request #447 from laraPPr/order_targets
Order the targets in available_software.py
2 parents 9a7e82d + e246c06 commit ff131ff

File tree

7 files changed

+149
-15
lines changed

7 files changed

+149
-15
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import os
2+
import json
3+
from bs4 import BeautifulSoup
4+
5+
path = os.path.dirname(os.path.realpath(__file__))
6+
path_overview = "/../../../docs/available_software/overview.md"
7+
path_data = "/../../../docs/available_software/data/json_data.json"
8+
if os.path.exists(path + path_overview) and os.path.exists(path + path_data):
9+
with open(path + path_data) as json_data:
10+
data = json.load(json_data)
11+
with open(path + path_overview) as f:
12+
soup = BeautifulSoup(f, "html.parser")
13+
else:
14+
os.write(1, b'Error: Could not find overview.md and/or data/json_data.json')
15+
16+
# parse the numbers for the different targets
17+
targets = data["targets"]
18+
ARM_targets = []
19+
x86_targets = []
20+
amd_targets = []
21+
intel_targets = []
22+
nvidia_targets = []
23+
24+
for target in targets:
25+
t = target.split('/')
26+
if t[7] == 'aarch64':
27+
ARM_targets.append(target)
28+
else:
29+
x86_targets.append(target)
30+
if t[8] == "amd":
31+
amd_targets.append(target)
32+
elif t[8] == "intel":
33+
intel_targets.append(target)
34+
elif t[8] == 'nvidia':
35+
nvidia_targets.append(target)
36+
37+
# parse the overview.md page to check the number of colums in rows
38+
table = soup.find("table", {"class": "table"})
39+
for row in table.find_all("tr"):
40+
for column in row.find_all('th'):
41+
if column.text == "x86_64":
42+
print(f'the value for x86_64 is {column.get("colspan")} in the overview page and there are {len(x86_targets)} targets in json_data.json.')
43+
if int(column.get("colspan")) != len(x86_targets):
44+
os.write(2, b'Error: Please make sure the values for x86_64 in json_data.json and overview.md are the same.')
45+
elif column.text == "aarch64":
46+
print(f'the value for aarch64 is {column.get("colspan")} in the overview page and there are {len(ARM_targets)} targets in json_data.json.')
47+
if int(column.get("colspan")) != len(ARM_targets):
48+
os.write(2, b'Error: Please make sure the values for aarch64 in json_data.json and overview.md are the same.')
49+
elif column.text == "amd":
50+
print(f'the value for amd is {column.get("colspan")} in the overview page and there are {len(amd_targets)} targets in json_data.json.')
51+
if int(column.get("colspan")) != len(amd_targets):
52+
os.write(2, b'Error: Please make sure the values for amd in json_data.json and overview.md are the same.')
53+
elif column.text == "intel":
54+
print(f'the value for intel is {column.get("colspan")} in the overview page and there are {len(intel_targets)} targets in json_data.json.')
55+
if int(column.get("colspan")) != len(intel_targets):
56+
os.write(2, b'Error: Please make sure the values for intel in json_data.json and overview.md are the same.')
57+
elif column.text == "nvidia":
58+
print(f'the value for nvidia is {column.get("colspan")} in the overview page and there are {len(nvidia_targets)} targets in json_data.json.')
59+
if int(column.get("colspan")) != len(nvidia_targets):
60+
os.write(2, b'Error: Please make sure the values for nvidia in json_data.json and overview.md are the same.')
61+
last_row = table.find_all("tr")[-1]
62+
print(f'there are {len(last_row.find_all("th"))} columns in the overview page and {len(targets)} targets in json_data.json.')
63+
if len(last_row.find_all("th")) != len(targets):
64+
os.write(2, b'Error: Please make sure there are correct number of <th> elements in the last <tr> element in overview.md for JavaScript to generate the table.')
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Test overview of available software in EESSI
2+
on:
3+
push:
4+
paths:
5+
- ".github/**"
6+
- "docs/available_software/data/**"
7+
jobs:
8+
check_targets:
9+
name: check targets in overview.md and json_data.json
10+
runs-on: ubuntu-22.04
11+
steps:
12+
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
13+
14+
- name: set up Python
15+
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
16+
with:
17+
python-version: '3.10'
18+
architecture: x64
19+
20+
- name: test overview available software
21+
id: test_overview_available_software
22+
run: |
23+
# install required Python packages in virtual environment
24+
python -m venv venv
25+
. venv/bin/activate
26+
pip install -r mkdocs-ldjson-plugin/requirements.txt
27+
28+
python .github/workflows/scripts/test_overview_available_software.py

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
site/
22
venv*
3+
scripts/available_software/__pycache__
4+
scripts/available_software/tests/__pycache__
35

docs/available_software/javascripts/populate_overview.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ function populate_overview(json_data) {
4343
targets: "_all",
4444
className: 'dt-body-center'
4545
}
46-
]
46+
],
47+
scrollX: true,
4748
});
4849
console.log(table)
4950

docs/available_software/overview.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@ This table gives an overview of all the available software in EESSI per specific
1010
<th colspan="3">aarch64</th>
1111
<th colspan="7">x86_64</th>
1212
</tr>
13-
</tr>
13+
<tr>
1414
<th colspan="3"></th>
1515
<th colspan="1"></th>
1616
<th colspan="3">amd</th>
1717
<th colspan="3">intel</th>
1818
</tr>
1919
<tr>
20-
<th colspan="1">generic</th>
21-
<th colspan="1">neoverse_n1</th>
22-
<th colspan="1">neoverse_v1</th>
23-
<th colspan="1">generic</th>
24-
<th colspan="1">zen2</th>
25-
<th colspan="1">zen3</th>
26-
<th colspan="1">zen4</th>
27-
<th colspan="1">haswell</th>
28-
<th colspan="1">skylake_avx512</th>
29-
<th colspan="1">sapphirerapids</th>
20+
<th colspan="1"></th>
21+
<th colspan="1"></th>
22+
<th colspan="1"></th>
23+
<th colspan="1"></th>
24+
<th colspan="1"></th>
25+
<th colspan="1"></th>
26+
<th colspan="1"></th>
27+
<th colspan="1"></th>
28+
<th colspan="1"></th>
29+
<th colspan="1"></th>
3030
</tr>
3131
</thead>
3232
</table>

scripts/available_software/available_software.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import numpy as np
2525
from mdutils.mdutils import MdUtils
2626
from natsort import natsorted
27+
from functools import cmp_to_key
2728

2829
EESSI_TOPDIR = "/cvmfs/software.eessi.io/versions/2023.06"
2930

@@ -220,6 +221,37 @@ def targets_eessi() -> np.ndarray:
220221
return targets
221222

222223

224+
def eessi_target_compare(a, b):
225+
"""
226+
A comparison function to compare the EESSI targets and order them.
227+
First the main architecture is ordered alphabetically, then within them
228+
the CPU targets are again ordered alphabetically, except for the
229+
generic target, which always comes first. Targets that include an extra
230+
vendor subdir always after those without a vendor subdir.
231+
@return: 0, 1, -1
232+
"""
233+
if a == b:
234+
return 0
235+
236+
a_split = a.rsplit('/')
237+
b_split = b.rsplit('/')
238+
239+
# We first compare the main architecture (aarch64, x86_64, ...), which is the 7th field
240+
if a_split[7] == b_split[7]:
241+
# Check if one item is for generic builds (last field), These should always be listed first
242+
if a_split[-1] == 'generic':
243+
return -1
244+
if b_split[-1] == 'generic':
245+
return 1
246+
# If the number of fields are not equal, one has an extra vendor subdirectory (e.g. amd, intel, nvidia).
247+
# These should always come after the ones without this extra level.
248+
if len(a_split) != len(b_split):
249+
return 1 if len(a_split) > len(b_split) else -1
250+
251+
# In all other cases we just do an alphabetical sort of the strings.
252+
return 1 if a > b else -1
253+
254+
223255
def modules_eessi() -> dict:
224256
"""
225257
Returns names of all software module that are installed on EESSI.
@@ -233,7 +265,14 @@ def modules_eessi() -> dict:
233265
if modulepath:
234266
module_unuse(modulepath)
235267

236-
targets = [t for t in targets_eessi() if not any(t.endswith(x) for x in EXCLUDE_CPU_TARGETS)]
268+
targets = targets_eessi()
269+
270+
# Order targets
271+
eessi_target_compare_key = cmp_to_key(eessi_target_compare)
272+
ordered_targets = sorted(targets, key=eessi_target_compare_key)
273+
274+
targets = [t for t in ordered_targets if not any(t.endswith(x) for x in EXCLUDE_CPU_TARGETS)]
275+
237276
for target in targets:
238277
print(f"\t Collecting available modules for {target}... ", end="", flush=True)
239278
module_use(target + "/modules/all/")

scripts/available_software/tests/test_json.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import os
77
import json
88

9-
GENERIC = "/cvmfs/software.eessi.io/versions/2023.06/software/linux/aarch64/generic"
9+
GENERIC_ARM = "/cvmfs/software.eessi.io/versions/2023.06/software/linux/aarch64/generic"
1010
ZEN2 = "/cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen2"
1111

1212

@@ -39,7 +39,7 @@ def test_json_generate_simple(self):
3939
modules = modules_eessi()
4040
json_data = generate_json_overview_data(modules)
4141
assert len(json_data.keys()) == 3
42-
assert list(json_data["targets"]) == [GENERIC, ZEN2]
42+
assert list(json_data["targets"]) == [GENERIC_ARM, ZEN2]
4343
assert json_data["modules"] == {
4444
"Markov": [1, 0],
4545
"cfd": [1, 1],

0 commit comments

Comments
 (0)