maintainers: remove email for amuckstot30 (#360059)
[NixPkgs.git] / pkgs / os-specific / linux / kernel / update-mainline.py
blob13e89d3df1e1605ac4e693f3c64946933aeff4d2
1 #!/usr/bin/env nix-shell
2 #!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.beautifulsoup4 ps.lxml ps.packaging ])"
3 from functools import cached_property
4 from itertools import groupby
5 import json
6 import os
7 import pathlib
8 import subprocess
9 import sys
10 import urllib.request
11 from dataclasses import dataclass
12 from enum import Enum
14 from bs4 import BeautifulSoup, NavigableString, Tag
15 from packaging.version import parse as parse_version, Version
18 HERE = pathlib.Path(__file__).parent
19 ROOT = HERE.parent.parent.parent.parent
20 VERSIONS_FILE = HERE / "kernels-org.json"
23 class KernelNature(Enum):
24 MAINLINE = 1
25 STABLE = 2
26 LONGTERM = 3
29 @dataclass
30 class KernelRelease:
31 nature: KernelNature
32 version: str
33 date: str
34 link: str
35 eol: bool = False
37 @cached_property
38 def parsed_version(self) -> Version:
39 return parse_version(self.version)
41 @cached_property
42 def branch(self) -> str:
43 version = self.parsed_version
44 # This is a testing kernel.
45 if version.is_prerelease:
46 return "testing"
47 else:
48 return f"{version.major}.{version.minor}"
51 def parse_release(release: Tag) -> KernelRelease | None:
52 columns: list[Tag] = list(release.find_all("td"))
53 try:
54 nature = KernelNature[columns[0].get_text().rstrip(":").upper()]
55 except KeyError:
56 # skip linux-next
57 return None
59 version = columns[1].get_text().rstrip(" [EOL]")
60 date = columns[2].get_text()
61 link = columns[3].find("a")
62 if link is not None and isinstance(link, Tag):
63 link = link.attrs.get("href")
64 assert link is not None, f"link for kernel {version} is non-existent"
65 eol = bool(release.find(class_="eolkernel"))
67 return KernelRelease(
68 nature=nature,
69 version=version,
70 date=date,
71 link=link,
72 eol=eol,
76 def get_hash(kernel: KernelRelease):
77 if kernel.branch == "testing":
78 args = ["--unpack"]
79 else:
80 args = []
82 hash = (
83 subprocess.check_output(["nix-prefetch-url", kernel.link] + args)
84 .decode()
85 .strip()
87 return f"sha256:{hash}"
90 def get_oldest_branch(kernels) -> Version:
91 return min(parse_version(v) for v in kernels.keys() if v != "testing")
94 def predates_oldest_branch(oldest: Version, to_compare: str) -> bool:
95 if to_compare == "testing":
96 return False
98 return parse_version(to_compare) < oldest
101 def commit(message):
102 return subprocess.check_call(["git", "commit", "-m", message, VERSIONS_FILE])
105 def main():
106 kernel_org = urllib.request.urlopen("https://kernel.org/")
107 soup = BeautifulSoup(kernel_org.read().decode(), "lxml")
108 release_table = soup.find(id="releases")
109 if not release_table or isinstance(release_table, NavigableString):
110 print(release_table, file=sys.stderr)
111 print("Failed to find the release table on https://kernel.org", file=sys.stderr)
112 sys.exit(1)
114 releases = release_table.find_all("tr")
115 parsed_releases = [
116 parsed for release in releases
117 if (parsed := parse_release(release)) is not None
119 all_kernels = json.load(VERSIONS_FILE.open())
120 oldest_branch = get_oldest_branch(all_kernels)
122 for (branch, kernels) in groupby(parsed_releases, lambda kernel: kernel.branch):
123 kernel = max(kernels, key=lambda kernel: kernel.parsed_version)
124 nixpkgs_branch = branch.replace(".", "_")
126 old_version = all_kernels.get(branch, {}).get("version")
127 if old_version == kernel.version:
128 print(f"linux_{nixpkgs_branch}: {kernel.version} is latest, skipping...")
129 continue
131 if predates_oldest_branch(oldest_branch, kernel.branch):
132 print(
133 f"{kernel.branch} is too old and not supported anymore, skipping...",
134 file=sys.stderr
136 continue
138 if old_version is None:
139 if kernel.eol:
140 print(
141 f"{kernel.branch} is EOL, not adding...",
142 file=sys.stderr
144 continue
146 message = f"linux_{nixpkgs_branch}: init at {kernel.version}"
147 else:
148 message = f"linux_{nixpkgs_branch}: {old_version} -> {kernel.version}"
150 print(message, file=sys.stderr)
152 all_kernels[branch] = {
153 "version": kernel.version,
154 "hash": get_hash(kernel),
157 with VERSIONS_FILE.open("w") as fd:
158 json.dump(all_kernels, fd, indent=4)
159 fd.write("\n") # makes editorconfig happy
161 if os.environ.get("COMMIT") == "1":
162 commit(message)
165 if __name__ == "__main__":
166 main()