Skip to content

Commit 6c82ac8

Browse files
committed
Show XS8 package that introduced a package
Signed-off-by: Gaëtan Lehmann <[email protected]>
1 parent 573885f commit 6c82ac8

File tree

5 files changed

+163
-98
lines changed

5 files changed

+163
-98
lines changed
Lines changed: 10 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,13 @@
11
#!/usr/bin/env python3
22

33
import argparse
4-
import csv
54
import logging
6-
import tempfile
7-
from collections import namedtuple
8-
from typing import Iterable, Iterator
95

10-
import rpm # type: ignore
6+
# from icecream import ic
7+
from tabulate import tabulate
118

129
import repoquery
13-
14-
ARCH = "x86_64"
15-
XCP_VERSION = "8.3"
16-
17-
class EVR:
18-
def __init__(self, e: str, v: str, r: str):
19-
self._evr = (e, v, r)
20-
21-
def __eq__(self, other):
22-
if isinstance(other, EVR):
23-
return self._evr == other._evr
24-
else:
25-
return self._evr == other
26-
27-
def __gt__(self, other):
28-
if isinstance(other, EVR):
29-
return rpm.labelCompare(self._evr, other._evr) > 0 # type: ignore
30-
else:
31-
return self._evr > other
32-
33-
def __lt__(self, other):
34-
return other > self
35-
36-
def __str__(self):
37-
if self._evr[0] != '0':
38-
return f'{self._evr[0]}:{self._evr[1]}.{self._evr[2]}'
39-
else:
40-
return f'{self._evr[1]}.{self._evr[2]}'
41-
42-
# Filters an iterator of (n, e, v, r) for newest evr of each `n`.
43-
# Older versions are allowed to appear before the newer ones.
44-
def filter_best_evr(nevrs: Iterable[tuple[str, str, str, str]]) -> Iterator[tuple[str, str, str, str]]:
45-
best: dict[str, tuple[str, str, str]] = {}
46-
for (n, e, v, r) in nevrs:
47-
if n not in best or rpm.labelCompare(best[n], (e, v, r)) < 0: # type: ignore
48-
best[n] = (e, v, r)
49-
yield (n, e, v, r)
50-
# else (e, v, r) is older than a previously-seen version, drop
51-
52-
def collect_data_xcpng() -> dict[str, EVR]:
53-
with (tempfile.NamedTemporaryFile() as dnfconf,
54-
tempfile.TemporaryDirectory() as yumrepod):
55-
repoquery.setup_xcpng_yum_repos(yum_repo_d=yumrepod,
56-
sections=['base', 'updates'],
57-
bin_arch=None,
58-
version=XCP_VERSION)
59-
repoquery.dnf_setup(dnf_conf=dnfconf.name, yum_repo_d=yumrepod)
60-
61-
xcp_nevr = {
62-
n: EVR(e, v, r)
63-
for (n, e, v, r)
64-
in filter_best_evr(repoquery.rpm_parse_nevr(nevr, f".xcpng{XCP_VERSION}")
65-
for nevr in repoquery.all_srpms())}
66-
67-
return xcp_nevr
68-
69-
def collect_data_xs8():
70-
with (tempfile.NamedTemporaryFile() as dnfconf,
71-
tempfile.TemporaryDirectory() as yumrepod):
72-
73-
repoquery.setup_xs8_yum_repos(yum_repo_d=yumrepod,
74-
sections=['base', 'normal'],
75-
)
76-
repoquery.dnf_setup(dnf_conf=dnfconf.name, yum_repo_d=yumrepod)
77-
logging.debug("fill cache with XS info")
78-
repoquery.fill_srpm_binrpms_cache()
79-
80-
logging.debug("get all XS SRPMs")
81-
xs8_srpms = {nevr for nevr in repoquery.all_srpms()}
82-
xs8_rpms_sources = {nevr for nevr in repoquery.SRPM_BINRPMS_CACHE}
83-
84-
xs8_srpms_set = {n: EVR(e, v, r)
85-
for (n, e, v, r)
86-
in filter_best_evr(repoquery.rpm_parse_nevr(nevr, ".xs8")
87-
for nevr in xs8_srpms)}
88-
xs8_rpms_sources_set = {n: EVR(e, v, r)
89-
for (n, e, v, r)
90-
in filter_best_evr(repoquery.rpm_parse_nevr(nevr, ".xs8")
91-
for nevr in xs8_rpms_sources)}
92-
93-
return (xs8_srpms_set, xs8_rpms_sources_set)
94-
95-
def read_package_status_metadata():
96-
with open('package_status.csv', newline='') as csvfile:
97-
csvreader = csv.reader(csvfile, delimiter=';', quotechar='|')
98-
headers = next(csvreader)
99-
assert headers == ["SRPM_name", "status", "comment"], f"unexpected headers {headers!r}"
100-
PackageStatus = namedtuple("PackageStatus", headers[1:]) # type: ignore[misc]
101-
return {row[0]: PackageStatus(*row[1:])
102-
for row in csvreader}
10+
from lib import collect_data_xcpng, collect_data_xs8, get_xs8_rpm_updates, read_package_status_metadata
10311

10412
parser = argparse.ArgumentParser()
10513
parser.add_argument('-v', '--verbose', action='count', default=0)
@@ -112,7 +20,9 @@ def read_package_status_metadata():
11220

11321
xcp_set = collect_data_xcpng()
11422
(xs8_srpms_set, xs8_rpms_sources_set) = collect_data_xs8()
23+
srpm_updates = get_xs8_rpm_updates()
11524

25+
res = []
11626
for n in sorted(set(xs8_srpms_set.keys()) | xs8_rpms_sources_set.keys()):
11727
if n in PACKAGE_STATUS and PACKAGE_STATUS[n].status == 'ignored':
11828
logging.debug(f"ignoring {n}")
@@ -124,9 +34,12 @@ def read_package_status_metadata():
12434
else:
12535
xs8_evr = xs8_srpms_evr or xs8_rpms_sources_evr
12636
xcp_evr = xcp_set.get(n)
37+
xs8_update = srpm_updates.get(f'{n}-{xs8_evr}.xs8', '?')
12738
# if xcp_evr is not None and xcp_evr < xs8_evr:
12839
if xcp_evr is None:
12940
if not repoquery.is_pristine_upstream(str(xs8_evr)):
130-
print(f'{n} {xcp_evr} -> {xs8_evr}')
41+
res.append((xs8_update, n, xcp_evr, xs8_evr))
13142
elif xcp_evr < xs8_evr:
132-
print(f'{n} {xcp_evr} -> {xs8_evr}')
43+
res.append((xs8_update, n, xcp_evr, xs8_evr))
44+
res.sort()
45+
print(tabulate(res, headers=['xs8 update', 'SRPM', 'XCP-ng version', 'XS8 version']))

scripts/repo_status/lib.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env python3
2+
3+
import csv
4+
import gzip
5+
import logging
6+
import tempfile
7+
import xml.etree.ElementTree as ET
8+
from collections import namedtuple
9+
from typing import Iterable, Iterator
10+
from urllib.request import urlopen
11+
12+
import rpm # type: ignore
13+
14+
import repoquery
15+
16+
ARCH = "x86_64"
17+
XCP_VERSION = "8.3"
18+
19+
class EVR:
20+
def __init__(self, e: str, v: str, r: str):
21+
self._evr = ('0' if e in [None, 'None'] else e, v, r)
22+
23+
def __eq__(self, other):
24+
if isinstance(other, EVR):
25+
return self._evr == other._evr
26+
else:
27+
return self._evr == other
28+
29+
def __gt__(self, other):
30+
if isinstance(other, EVR):
31+
return rpm.labelCompare(self._evr, other._evr) > 0 # type: ignore
32+
else:
33+
return self._evr > other
34+
35+
def __lt__(self, other):
36+
return other > self
37+
38+
def __str__(self):
39+
if self._evr[0] != '0':
40+
return f'{self._evr[0]}:{self._evr[1]}-{self._evr[2]}'
41+
else:
42+
return f'{self._evr[1]}-{self._evr[2]}'
43+
44+
# Filters an iterator of (n, e, v, r) for newest evr of each `n`.
45+
# Older versions are allowed to appear before the newer ones.
46+
def filter_best_evr(nevrs: Iterable[tuple[str, str, str, str]]) -> Iterator[tuple[str, str, str, str]]:
47+
best: dict[str, tuple[str, str, str]] = {}
48+
for (n, e, v, r) in nevrs:
49+
if n not in best or rpm.labelCompare(best[n], (e, v, r)) < 0: # type: ignore
50+
best[n] = (e, v, r)
51+
yield (n, e, v, r)
52+
# else (e, v, r) is older than a previously-seen version, drop
53+
54+
def collect_data_xcpng() -> dict[str, EVR]:
55+
with (tempfile.NamedTemporaryFile() as dnfconf,
56+
tempfile.TemporaryDirectory() as yumrepod):
57+
repoquery.setup_xcpng_yum_repos(yum_repo_d=yumrepod,
58+
sections=['base', 'updates'],
59+
bin_arch=None,
60+
version=XCP_VERSION)
61+
repoquery.dnf_setup(dnf_conf=dnfconf.name, yum_repo_d=yumrepod)
62+
63+
xcp_nevr = {
64+
n: EVR(e, v, r)
65+
for (n, e, v, r)
66+
in filter_best_evr(repoquery.rpm_parse_nevr(nevr, f".xcpng{XCP_VERSION}")
67+
for nevr in repoquery.all_srpms())}
68+
69+
return xcp_nevr
70+
71+
def collect_data_xs8():
72+
with (tempfile.NamedTemporaryFile() as dnfconf,
73+
tempfile.TemporaryDirectory() as yumrepod):
74+
75+
repoquery.setup_xs8_yum_repos(yum_repo_d=yumrepod,
76+
sections=['base', 'normal'],
77+
)
78+
repoquery.dnf_setup(dnf_conf=dnfconf.name, yum_repo_d=yumrepod)
79+
logging.debug("fill cache with XS info")
80+
repoquery.fill_srpm_binrpms_cache()
81+
82+
logging.debug("get all XS SRPMs")
83+
xs8_srpms = {nevr for nevr in repoquery.all_srpms()}
84+
xs8_rpms_sources = {nevr for nevr in repoquery.SRPM_BINRPMS_CACHE}
85+
86+
xs8_srpms_set = {n: EVR(e, v, r)
87+
for (n, e, v, r)
88+
in filter_best_evr(repoquery.rpm_parse_nevr(nevr, ".xs8")
89+
for nevr in xs8_srpms)}
90+
xs8_rpms_sources_set = {n: EVR(e, v, r)
91+
for (n, e, v, r)
92+
in filter_best_evr(repoquery.rpm_parse_nevr(nevr, ".xs8")
93+
for nevr in xs8_rpms_sources)}
94+
95+
return (xs8_srpms_set, xs8_rpms_sources_set)
96+
97+
def read_package_status_metadata():
98+
with open('package_status.csv', newline='') as csvfile:
99+
csvreader = csv.reader(csvfile, delimiter=';', quotechar='|')
100+
headers = next(csvreader)
101+
assert headers == ["SRPM_name", "status", "comment"], f"unexpected headers {headers!r}"
102+
PackageStatus = namedtuple("PackageStatus", headers[1:]) # type: ignore[misc]
103+
return {row[0]: PackageStatus(*row[1:])
104+
for row in csvreader}
105+
106+
def get_xs8_rpm_updates():
107+
NS = {'repo': 'http://linux.duke.edu/metadata/repo'}
108+
BASE_URL = 'http://repos/repos/XS8/normal/xs8p-normal'
109+
110+
# read the update info path from repomd.xml
111+
with urlopen(f'{BASE_URL}/repodata/repomd.xml') as f:
112+
repomd = f.read()
113+
data = ET.fromstring(repomd).find("repo:data[@type='updateinfo']", NS)
114+
assert data is not None
115+
location = data.find('repo:location', NS)
116+
assert location is not None
117+
path = location.attrib['href']
118+
119+
# read the update info file
120+
res = {}
121+
with urlopen(f'{BASE_URL}/{path}') as cf, gzip.open(cf, 'rb') as f:
122+
updateinfo = f.read()
123+
updates = ET.fromstring(updateinfo).findall('update')
124+
for update in updates:
125+
update_id = update.find('id')
126+
assert update_id is not None
127+
update_id = update_id.text
128+
pkglist = update.find('pkglist')
129+
assert pkglist is not None
130+
collection = pkglist.find('collection')
131+
assert collection is not None
132+
packages = collection.findall('package')
133+
for package in packages:
134+
evr = EVR(package.attrib['epoch'], package.attrib['version'], package.attrib['release'])
135+
rpm = f'{package.attrib["name"]}-{evr}'
136+
srpm = repoquery.rpm_source_package(rpm, default=rpm)
137+
res[srpm] = update_id
138+
return res

scripts/repo_status/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ requires-python = "~=3.11"
77
dependencies = [
88
"requests",
99
"rpm",
10+
"tabulate",
1011
]
1112

1213
[dependency-groups]

scripts/repo_status/repoquery.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ def dnf_setup(*, dnf_conf: str, yum_repo_d: str) -> None:
9090
]
9191

9292
BINRPM_SOURCE_CACHE: dict[str, str] = {}
93-
def rpm_source_package(rpmname: str) -> str:
93+
def rpm_source_package(rpmname: str, **kwargs) -> str:
94+
if 'default' in kwargs:
95+
return BINRPM_SOURCE_CACHE.get(rpmname, kwargs['default'])
9496
return BINRPM_SOURCE_CACHE[rpmname]
9597

9698
def run_repoquery(args: list[str], split: bool = True) -> str | Sequence[str]:

scripts/repo_status/uv.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)