Skip to content

Commit 1614a53

Browse files
committed
distro-clang: Rewrite in Python
We can consolidate the shell scripts into a single Python script. This also allows us to format things nicely, such as using a Markdown table. Signed-off-by: Nathan Chancellor <[email protected]>
1 parent 0035224 commit 1614a53

File tree

6 files changed

+190
-115
lines changed

6 files changed

+190
-115
lines changed

Diff for: .github/workflows/lint.yml

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
name: Lint checks
33
on: [push, pull_request]
44
jobs:
5+
python:
6+
strategy:
7+
fail-fast: false
8+
matrix:
9+
version: ['3.12', '3.11', '3.10', '3.9', '3.8']
10+
uses: ClangBuiltLinux/actions-workflows/.github/workflows/python_lint.yml@main
11+
with:
12+
python_version: ${{ matrix.version }}
513
shellcheck:
614
uses: ClangBuiltLinux/actions-workflows/.github/workflows/shellcheck.yml@main
715
shfmt:

Diff for: distro-clang/get-distro-clang.py

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#!/usr/bin/env python3
2+
# pylint: disable=invalid-name
3+
4+
from argparse import ArgumentParser
5+
import re
6+
import shlex
7+
import shutil
8+
import subprocess
9+
10+
11+
def print_cmd(args, command):
12+
if not args.quiet:
13+
print(f"$ {' '.join([shlex.quote(str(elem)) for elem in command])}",
14+
flush=True)
15+
16+
17+
def chronic(*args, **kwargs):
18+
try:
19+
return subprocess.run(*args,
20+
**kwargs,
21+
capture_output=True,
22+
check=True,
23+
text=True)
24+
except subprocess.CalledProcessError as err:
25+
print(err.stdout)
26+
print(err.stderr)
27+
raise err
28+
29+
30+
PARSER = ArgumentParser(
31+
description=
32+
'Get clang version from various Linux distributions through docker/podman)'
33+
)
34+
PARSER.add_argument('-m',
35+
'--markdown',
36+
action='store_true',
37+
help='Output results as a Markdown table')
38+
PARSER.add_argument('-q',
39+
'--quiet',
40+
action='store_true',
41+
help='Do not print commands being run')
42+
ARGS = PARSER.parse_args()
43+
44+
if ARGS.markdown:
45+
# pylint: disable-next=import-error
46+
from py_markdown_table.markdown_table import markdown_table
47+
48+
for MANAGER in (MANAGERS := ['podman', 'docker']):
49+
if shutil.which(MANAGER):
50+
break
51+
else:
52+
raise RuntimeError(
53+
f"Neither {' nor '.join(MANAGERS)} could be found on your system!")
54+
55+
# This list should only include versions that are actively being supported.
56+
#
57+
# Tags such as "latest", "stable", or "rolling" are preferred so that the list
58+
# does not have to be constantly updated. Old but supported releases like
59+
# Fedora or OpenSUSE are the exception.
60+
IMAGES = [
61+
# Arch Linux is rolling release, it only has one supported version at a time.
62+
('archlinux', 'latest'),
63+
# Debian:
64+
# * https://www.debian.org/releases/
65+
# * https://wiki.debian.org/LTS
66+
# * https://hub.docker.com/_/debian
67+
*[('debian', f"{ver}-slim") for ver in
68+
['oldoldstable', 'oldstable', 'stable', 'testing', 'unstable']],
69+
# Fedora:
70+
# * https://fedoraproject.org/wiki/Releases
71+
# * https://fedoraproject.org/wiki/End_of_life
72+
# * https://hub.docker.com/_/fedora
73+
*[('fedora', ver) for ver in ['38', 'latest', 'rawhide']],
74+
# OpenSUSE:
75+
# * https://en.opensuse.org/openSUSE:Roadmap
76+
# * https://en.opensuse.org/Lifetime
77+
# * https://hub.docker.com/r/opensuse/leap
78+
('opensuse/leap', 'latest'),
79+
('opensuse/tumbleweed', 'latest'),
80+
# Ubuntu:
81+
# * https://wiki.ubuntu.com/Releases
82+
# * https://hub.docker.com/_/ubuntu
83+
*[('ubuntu', ver) for ver in ['focal', 'latest', 'rolling', 'devel']],
84+
]
85+
86+
RESULTS = {}
87+
for ITEM in IMAGES:
88+
DISTRO = ITEM[0]
89+
IMAGE = ':'.join(ITEM)
90+
FULL_IMAGE = f"docker.io/{IMAGE}"
91+
92+
# Make sure image is up to date
93+
PULL_CMD = [MANAGER, 'pull', FULL_IMAGE]
94+
print_cmd(ARGS, PULL_CMD)
95+
chronic(PULL_CMD)
96+
97+
# Build command to update the distribution, install clang, and get its
98+
# version.
99+
ENV_VARS = {}
100+
CMDS = []
101+
if DISTRO == 'archlinux':
102+
CMDS.append('pacman -Syyu --noconfirm')
103+
CMDS.append('pacman -S --noconfirm clang')
104+
elif DISTRO in ('debian', 'ubuntu'):
105+
ENV_VARS['DEBIAN_FRONTEND'] = 'noninteractive'
106+
107+
CMDS.append('apt-get update')
108+
CMDS.append('apt-get upgrade -y')
109+
CMDS.append('apt-get install --no-install-recommends -y clang')
110+
elif DISTRO == 'fedora':
111+
CMDS.append('dnf update -y')
112+
CMDS.append('dnf install -y clang')
113+
elif 'opensuse' in DISTRO:
114+
CMDS.append('zypper -n up')
115+
CMDS.append('zypper -n in clang')
116+
else:
117+
raise RuntimeError(f"Don't know how to install clang on {DISTRO}?")
118+
CMDS.append('clang --version')
119+
120+
# Run container manager with commands generated above.
121+
RUN_CMD = [
122+
MANAGER,
123+
'run',
124+
*[f"--env={key}={value}" for key, value in ENV_VARS.items()],
125+
'--rm',
126+
FULL_IMAGE,
127+
'sh',
128+
'-c',
129+
' && '.join(CMDS),
130+
]
131+
print_cmd(ARGS, RUN_CMD)
132+
RESULT = chronic(RUN_CMD)
133+
134+
# Locate clang version in output and add it to results
135+
if not (match := re.search(
136+
r'^[A-Za-z ]*?clang version [0-9]+\.[0-9]+\.[0-9]+.*$',
137+
RESULT.stdout,
138+
flags=re.M)):
139+
raise RuntimeError('Could not find clang version in output?')
140+
RESULTS[IMAGE] = match[0]
141+
142+
print()
143+
144+
# Pretty print results
145+
if ARGS.markdown:
146+
MD_DATA = [{
147+
"Container image": f"`{key}`",
148+
"Compiler version": f"`{value}`",
149+
} for key, value in RESULTS.items()]
150+
print(
151+
markdown_table(MD_DATA).set_params(padding_weight='right',
152+
quote=False,
153+
row_sep='markdown').get_markdown())
154+
else:
155+
WIDTH = len(max(RESULTS.keys(), key=len))
156+
for IMAGE, VERSION in RESULTS.items():
157+
print(f"{IMAGE:{WIDTH}} {VERSION}")

Diff for: distro-clang/get-distro-clang.sh

-83
This file was deleted.

Diff for: distro-clang/install-check-clang-version.sh

-32
This file was deleted.

Diff for: requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
py-markdown-table

Diff for: ruff.toml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# https://beta.ruff.rs/docs/rules/
2+
select = [
3+
'A', # flake8-builtins
4+
'ARG', # flake8-unused-arguments
5+
'B', # flake8-bugbear
6+
'C4', # flake8-comprehensions
7+
'E', # pycodestyle
8+
'F', # pyflakes
9+
'PIE', # flake8-pie
10+
'PL', # pylint
11+
'PTH', # flake8-use-pathlib
12+
'RET', # flake8-return
13+
'RUF', # ruff
14+
'S', # flake8-bandit
15+
'SIM', # flake8-simplify
16+
'SLF', # flake8-self
17+
'UP', # pyupgrade
18+
'W', # pycodestyle
19+
]
20+
ignore = [
21+
'S603', # subprocess-without-shell-equals-true
22+
'S607', # start-process-with-partial-path
23+
]
24+
target-version = 'py38'

0 commit comments

Comments
 (0)