Skip to content

Commit 4e536ac

Browse files
committed
scripts: Introduce kernel_source.py
`kernel_source.py` contains functions used to check version of desired kernel, download, extract kernel source to specific directory and get the headers out of it. Signed-off-by: Ruoqing He <[email protected]>
1 parent 09aef99 commit 4e536ac

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed

scripts/lib/kernel_source.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Copyright 2025 © Institute of Software, CAS. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
import os
5+
import re
6+
import tarfile
7+
import requests
8+
import subprocess
9+
import tempfile
10+
11+
KERNEL_ORG_CDN = "https://cdn.kernel.org/pub/linux/kernel"
12+
13+
14+
def check_kernel_version(version):
15+
"""
16+
Validate if the input kernel version exists in remote. Supports both X.Y
17+
(namely X.Y.0 and .0 should be omitted) and X.Y.Z formats
18+
"""
19+
# Validate version format
20+
if not re.match(r"^\d+\.\d+(\.\d+)?$", version):
21+
raise ValueError("Invalid version format. Use X.Y or X.Y.Z")
22+
23+
main_ver = version.split(".")[0]
24+
base_url = f"{KERNEL_ORG_CDN}/v{main_ver}.x/"
25+
tarball = f"linux-{version}.tar.xz"
26+
27+
try:
28+
# Fetch content of `base_url`
29+
response = requests.get(base_url, timeout=15)
30+
response.raise_for_status()
31+
32+
# Check for exact filename match
33+
if tarball in response.text:
34+
print(f"Kernel version {version} found in remote")
35+
return
36+
37+
raise RuntimeError(f"Kernel version {version} not found in remote")
38+
39+
except requests.exceptions.HTTPError as e:
40+
if e.response.status_code == 404:
41+
raise RuntimeError(f"Kernel series v{main_ver}.x does not exist")
42+
43+
raise RuntimeError(f"HTTP error ({e.response.status_code}): {str(e)}")
44+
except requests.exceptions.Timeout:
45+
raise RuntimeError("Connection timeout while checking version")
46+
except requests.exceptions.RequestException as e:
47+
raise RuntimeError(f"Network error: {str(e)}")
48+
49+
50+
def create_temp_dir(version):
51+
prefix = f"linux-{version}-source-"
52+
try:
53+
temp_dir = tempfile.TemporaryDirectory(prefix=prefix, dir="/tmp", delete=False)
54+
return temp_dir.name
55+
except OSError as e:
56+
raise RuntimeError(f"Failed to create temp directory: {e}") from e
57+
58+
59+
def download_kernel(version, temp_dir):
60+
version_major = re.match(r"^(\d+)\.\d+(\.\d+)?$", version).group(1)
61+
url = f"{KERNEL_ORG_CDN}/v{version_major}.x/linux-{version}.tar.xz"
62+
tarball_path = os.path.join(temp_dir, f"linux-{version}.tar.xz")
63+
print(f"Downloading {url} to {tarball_path}")
64+
65+
try:
66+
with requests.get(url, stream=True) as response:
67+
response.raise_for_status()
68+
total_size = int(response.headers.get("content-length", 0))
69+
downloaded = 0
70+
71+
with open(tarball_path, "wb") as f:
72+
for chunk in response.iter_content(chunk_size=8192):
73+
f.write(chunk)
74+
downloaded += len(chunk)
75+
if total_size > 0:
76+
progress = downloaded / total_size * 100
77+
print(f"\rDownloading: {progress:.1f}%", end="")
78+
print()
79+
return tarball_path
80+
except Exception as e:
81+
raise RuntimeError(f"Download failed: {e}") from e
82+
83+
84+
def extract_kernel(tarball_path, temp_dir):
85+
print("Extracting...")
86+
try:
87+
with tarfile.open(tarball_path, "r:xz") as tar:
88+
tar.extractall(path=temp_dir)
89+
extract_path = os.path.join(
90+
temp_dir, f"{os.path.basename(tarball_path).split('.tar')[0]}"
91+
)
92+
print(f"Extracted to {extract_path}")
93+
return extract_path
94+
except (tarfile.TarError, IOError) as e:
95+
raise RuntimeError(f"Extraction failed: {e}") from e
96+
97+
98+
def install_headers(src_dir, arch, install_path):
99+
parent_dir = os.path.dirname(src_dir)
100+
if install_path is None:
101+
install_path = os.path.join(parent_dir, f"{arch}_headers")
102+
103+
try:
104+
os.makedirs(install_path, exist_ok=True)
105+
106+
abs_install_path = os.path.abspath(install_path)
107+
print(f"Installing to {abs_install_path}")
108+
result = subprocess.run(
109+
[
110+
"make",
111+
"-C",
112+
f"{src_dir}",
113+
f"ARCH={arch}",
114+
f"INSTALL_HDR_PATH={abs_install_path}",
115+
"headers_install",
116+
],
117+
check=True,
118+
stdout=subprocess.PIPE,
119+
stderr=subprocess.PIPE,
120+
text=True,
121+
)
122+
print(result.stdout)
123+
return install_path
124+
125+
except subprocess.CalledProcessError as e:
126+
raise RuntimeError(
127+
f"Header installation failed:\n{e.output}"
128+
f"Temporary files kept at: {os.path.dirname(src_dir)}"
129+
)

0 commit comments

Comments
 (0)