python3-openEuler 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python3_openeuler-0.3.2/LICENSE +21 -0
- python3_openeuler-0.3.2/MANIFEST.in +2 -0
- python3_openeuler-0.3.2/PKG-INFO +32 -0
- python3_openeuler-0.3.2/README.md +1 -0
- python3_openeuler-0.3.2/openEuler/__init__.py +74 -0
- python3_openeuler-0.3.2/openEuler/openEuler.py +478 -0
- python3_openeuler-0.3.2/openEuler/openEuler_core_src.txt +224 -0
- python3_openeuler-0.3.2/openEuler/pkg_info/openEuler_24.03-LTS-SP2_x86_64_EPOL.json +4355 -0
- python3_openeuler-0.3.2/openEuler/pkg_info/openEuler_24.03-LTS-SP2_x86_64_Everything.json +18949 -0
- python3_openeuler-0.3.2/openEuler/pkg_info/openEuler_24.03-LTS-SP2_x86_64_OS.json +2534 -0
- python3_openeuler-0.3.2/openEuler/pkg_info/openEuler_24.03-LTS-SP2_x86_64_update.json +1735 -0
- python3_openeuler-0.3.2/python3_openEuler.egg-info/PKG-INFO +32 -0
- python3_openeuler-0.3.2/python3_openEuler.egg-info/SOURCES.txt +16 -0
- python3_openeuler-0.3.2/python3_openEuler.egg-info/dependency_links.txt +1 -0
- python3_openeuler-0.3.2/python3_openEuler.egg-info/requires.txt +2 -0
- python3_openeuler-0.3.2/python3_openEuler.egg-info/top_level.txt +1 -0
- python3_openeuler-0.3.2/setup.cfg +4 -0
- python3_openeuler-0.3.2/setup.py +54 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 redrose2100
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: python3-openEuler
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: used to get and deal information about openEuler os
|
|
5
|
+
Home-page: https://gitee.com/devops_dev/openEuler
|
|
6
|
+
Author: redrose2100
|
|
7
|
+
Author-email: hitredrose@163.com
|
|
8
|
+
Maintainer: redrose2100
|
|
9
|
+
Maintainer-email: hitredrose@163.com
|
|
10
|
+
License: MIT
|
|
11
|
+
Project-URL: Documentation, https://gitee.com/devops_dev/openEuler/README.md
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: System :: Logging
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.4
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.5
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: python3-log
|
|
30
|
+
Requires-Dist: zstandard
|
|
31
|
+
|
|
32
|
+
# python3-openEuler
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# python3-openEuler
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from openEuler.openEuler import OpenEuler
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Optional, Union
|
|
4
|
+
|
|
5
|
+
# 初始化包专属日志器(名称与包绑定,避免冲突)
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
# 核心:设置默认日志级别为 INFO(全局生效)
|
|
9
|
+
DEFAULT_LOG_LEVEL = logging.INFO
|
|
10
|
+
logger.setLevel(DEFAULT_LOG_LEVEL)
|
|
11
|
+
|
|
12
|
+
# 禁止日志向上传播(避免干扰用户根日志器)
|
|
13
|
+
logger.propagate = False
|
|
14
|
+
|
|
15
|
+
# 定义默认日志格式(包含关键上下文信息)
|
|
16
|
+
DEFAULT_FORMATTER = logging.Formatter(
|
|
17
|
+
fmt="[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s",
|
|
18
|
+
datefmt="%Y-%m-%d %H:%M:%S"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def _add_default_handler(level: int = DEFAULT_LOG_LEVEL):
|
|
22
|
+
"""
|
|
23
|
+
为日志器添加默认控制台Handler(仅在无Handler时添加,避免重复输出)
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
level: Handler的日志级别(默认与logger级别一致)
|
|
27
|
+
"""
|
|
28
|
+
if not logger.handlers:
|
|
29
|
+
# 输出到stdout(而非stderr,避免与错误信息混淆)
|
|
30
|
+
console_handler = logging.StreamHandler()
|
|
31
|
+
console_handler.setLevel(level) # Handler级别可独立控制
|
|
32
|
+
console_handler.setFormatter(DEFAULT_FORMATTER)
|
|
33
|
+
logger.addHandler(console_handler)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_logger(
|
|
37
|
+
custom_formatter: Optional[logging.Formatter] = None,
|
|
38
|
+
level: Optional[Union[int, str]] = None
|
|
39
|
+
) -> logging.Logger:
|
|
40
|
+
"""
|
|
41
|
+
获取包的日志器,支持自定义格式和级别
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
custom_formatter: 自定义日志格式(如不指定则使用默认格式)
|
|
45
|
+
level: 日志级别(可选,如 logging.DEBUG 或 "DEBUG",优先级高于默认)
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
配置好的日志器实例
|
|
49
|
+
"""
|
|
50
|
+
# 确保默认Handler存在(首次调用时初始化)
|
|
51
|
+
_add_default_handler()
|
|
52
|
+
|
|
53
|
+
# 动态调整日志级别(支持字符串级别,如 "DEBUG",更友好)
|
|
54
|
+
if level is not None:
|
|
55
|
+
# 若传入字符串级别(如 "DEBUG"),转换为logging常量
|
|
56
|
+
if isinstance(level, str):
|
|
57
|
+
level = logging.getLevelName(level.upper())
|
|
58
|
+
logger.setLevel(level)
|
|
59
|
+
# 同步调整所有Handler的级别(避免Handler级别低于logger导致的日志丢失)
|
|
60
|
+
for handler in logger.handlers:
|
|
61
|
+
handler.setLevel(level)
|
|
62
|
+
|
|
63
|
+
# 应用用户自定义格式
|
|
64
|
+
if custom_formatter:
|
|
65
|
+
for handler in logger.handlers:
|
|
66
|
+
handler.setFormatter(custom_formatter)
|
|
67
|
+
|
|
68
|
+
return logger
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# 初始化时触发一次默认Handler添加(确保用户首次使用日志即有输出)
|
|
72
|
+
_add_default_handler()
|
|
73
|
+
|
|
74
|
+
__all__ = ["OpenEuler", "get_logger"]
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import os
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import gzip
|
|
6
|
+
import bz2
|
|
7
|
+
import zstandard as zstd
|
|
8
|
+
import xml.etree.ElementTree as ET
|
|
9
|
+
from tempfile import TemporaryDirectory
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
import requests
|
|
12
|
+
import traceback
|
|
13
|
+
import functools
|
|
14
|
+
import inspect
|
|
15
|
+
from typing import Callable,List, Any, Generator, Tuple
|
|
16
|
+
import requests.exceptions
|
|
17
|
+
|
|
18
|
+
log=logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
def enter_and_leave_function(func: Callable) -> Callable:
|
|
21
|
+
@functools.wraps(func)
|
|
22
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
23
|
+
func_def_file = inspect.getsourcefile(func) or "unknown_file"
|
|
24
|
+
func_def_file = func_def_file.split("/")[-1]
|
|
25
|
+
func_def_line = inspect.getsourcelines(func)[1] if func_def_file != "unknown_file" else "unknown_line"
|
|
26
|
+
log.info(
|
|
27
|
+
f"[{func_def_file}: {func_def_line}]"
|
|
28
|
+
f"[{func.__name__}()]"
|
|
29
|
+
f"| args={args}, kwargs={kwargs}"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
result = func(*args, **kwargs)
|
|
34
|
+
log.info(
|
|
35
|
+
f"[{func_def_file}: {func_def_line}]"
|
|
36
|
+
f" finish run function {func.__name__}(), return value is: {result} "
|
|
37
|
+
)
|
|
38
|
+
return result
|
|
39
|
+
|
|
40
|
+
except Exception as e:
|
|
41
|
+
error_traceback = traceback.format_exc()
|
|
42
|
+
|
|
43
|
+
log.error(
|
|
44
|
+
f"[{func_def_file}: {func_def_line}]"
|
|
45
|
+
f"failed to run function {func.__name__}() :Failed. "
|
|
46
|
+
f"| error_type:{type(e).__name__} "
|
|
47
|
+
f"| error_message:{str(e)} "
|
|
48
|
+
f"| full_stack_trace:\n{error_traceback}",
|
|
49
|
+
exc_info=False
|
|
50
|
+
)
|
|
51
|
+
raise
|
|
52
|
+
|
|
53
|
+
return wrapper
|
|
54
|
+
|
|
55
|
+
class Gitee():
|
|
56
|
+
def __init__(self):
|
|
57
|
+
self.__base_url= "https://gitee.com/api/v5"
|
|
58
|
+
self.__access_token="aa6cb32539129acf5605793f91a1588c"
|
|
59
|
+
|
|
60
|
+
def get_branches_list_by_repo(self,repo_name,owner_name):
|
|
61
|
+
url = f"{self.__base_url}/repos/{owner_name}/{repo_name}/branches"
|
|
62
|
+
page=1
|
|
63
|
+
parameters={
|
|
64
|
+
"access_token":self.__access_token,
|
|
65
|
+
"repo":repo_name,
|
|
66
|
+
"owner":owner_name,
|
|
67
|
+
"sort":"name",
|
|
68
|
+
"direction":"asc",
|
|
69
|
+
"page":page,
|
|
70
|
+
"per_page":10
|
|
71
|
+
}
|
|
72
|
+
headers={
|
|
73
|
+
"Content-Type":"application/json",
|
|
74
|
+
"Accept":"application/json",
|
|
75
|
+
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36"
|
|
76
|
+
}
|
|
77
|
+
branches=[]
|
|
78
|
+
while True:
|
|
79
|
+
response=requests.get(url,params=parameters,headers=headers)
|
|
80
|
+
if response.status_code==200:
|
|
81
|
+
data=response.json()
|
|
82
|
+
for branch in data:
|
|
83
|
+
branches.append(branch["name"])
|
|
84
|
+
page+=1
|
|
85
|
+
parameters["page"]=page
|
|
86
|
+
if len(data)==0:
|
|
87
|
+
return branches
|
|
88
|
+
else:
|
|
89
|
+
log.error(f"request url is {url}, parameters is {parameters},headers is {headers} failed, response status code is {response.status_code}")
|
|
90
|
+
return branches
|
|
91
|
+
|
|
92
|
+
def get_repo_name_and_repo_html_url_by_org(self,org_name):
|
|
93
|
+
log.info(f"begin to get openEuler repo names and repo html urls by org {org_name}...")
|
|
94
|
+
url = f"{self.__base_url}/orgs/{org_name}/repos"
|
|
95
|
+
page=1
|
|
96
|
+
parameters={
|
|
97
|
+
"access_token":"aa6cb32539129acf5605793f91a1588c",
|
|
98
|
+
"org":org_name,
|
|
99
|
+
"page":page,
|
|
100
|
+
"per_page":10,
|
|
101
|
+
"type":"all"
|
|
102
|
+
}
|
|
103
|
+
headers={
|
|
104
|
+
"Content-Type":"application/json",
|
|
105
|
+
"Accept":"application/json",
|
|
106
|
+
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36"
|
|
107
|
+
}
|
|
108
|
+
page=1
|
|
109
|
+
log.info(f"begin to request url is {url}, parameters is {parameters},headers is {headers}...")
|
|
110
|
+
while True:
|
|
111
|
+
response=requests.get(url,params=parameters,headers=headers)
|
|
112
|
+
if response.status_code==200:
|
|
113
|
+
data=response.json()
|
|
114
|
+
for repo in data:
|
|
115
|
+
yield repo["name"],repo["html_url"]
|
|
116
|
+
page+=1
|
|
117
|
+
parameters["page"]=page
|
|
118
|
+
if len(data)==0:
|
|
119
|
+
break
|
|
120
|
+
else:
|
|
121
|
+
log.error(f"request url is {url}, parameters is {parameters},headers is {headers} failed, response status code is {response.status_code}")
|
|
122
|
+
break
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class RepoRpmParser:
|
|
126
|
+
def __init__(self):
|
|
127
|
+
self.compressed_patterns = {
|
|
128
|
+
"zst": re.compile(r'primary\.xml\.zst', re.I),
|
|
129
|
+
"gz": re.compile(r'primary\.xml\.gz', re.I),
|
|
130
|
+
"bz2": re.compile(r'primary\.xml\.bz2', re.I)
|
|
131
|
+
}
|
|
132
|
+
self.ns_map = {
|
|
133
|
+
"rpm": "http://linux.duke.edu/metadata/rpm",
|
|
134
|
+
"default": "http://linux.duke.edu/metadata/common"
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
def _get_repodata_file_list(self, repodata_url: str) -> List[str]:
|
|
138
|
+
try:
|
|
139
|
+
resp = requests.get(repodata_url, timeout=30)
|
|
140
|
+
resp.raise_for_status()
|
|
141
|
+
file_pattern = re.compile(r'href="([a-f0-9]+-primary\.xml(\.[a-z0-9]+)?)"')
|
|
142
|
+
files = file_pattern.findall(resp.text)
|
|
143
|
+
file_list = list({f[0] for f in files})
|
|
144
|
+
log.debug(f"Found repodata files: {file_list}")
|
|
145
|
+
return file_list
|
|
146
|
+
except Exception as e:
|
|
147
|
+
log.error(f"Failed to get repodata file list from {repodata_url}: {str(e)}")
|
|
148
|
+
return []
|
|
149
|
+
|
|
150
|
+
def _download_file(self, file_url: str, save_path: str) -> bool:
|
|
151
|
+
try:
|
|
152
|
+
resp = requests.get(file_url, stream=True, timeout=60)
|
|
153
|
+
resp.raise_for_status()
|
|
154
|
+
with open(save_path, 'wb') as f:
|
|
155
|
+
for chunk in resp.iter_content(chunk_size=8192):
|
|
156
|
+
if chunk:
|
|
157
|
+
f.write(chunk)
|
|
158
|
+
log.debug(f"Downloaded file: {file_url} -> {save_path}")
|
|
159
|
+
return True
|
|
160
|
+
except Exception as e:
|
|
161
|
+
log.error(f"Failed to download {file_url}: {str(e)}")
|
|
162
|
+
return False
|
|
163
|
+
|
|
164
|
+
def _decompress_file(self, compressed_path: str, output_path: str) -> bool:
|
|
165
|
+
try:
|
|
166
|
+
if compressed_path.endswith('.zst'):
|
|
167
|
+
with open(compressed_path, 'rb') as f_in:
|
|
168
|
+
dctx = zstd.ZstdDecompressor()
|
|
169
|
+
with open(output_path, 'wb') as f_out:
|
|
170
|
+
dctx.copy_stream(f_in, f_out)
|
|
171
|
+
elif compressed_path.endswith('.gz'):
|
|
172
|
+
with gzip.open(compressed_path, 'rb') as f_in:
|
|
173
|
+
with open(output_path, 'wb') as f_out:
|
|
174
|
+
f_out.write(f_in.read())
|
|
175
|
+
elif compressed_path.endswith('.bz2'):
|
|
176
|
+
with bz2.open(compressed_path, 'rb') as f_in:
|
|
177
|
+
with open(output_path, 'wb') as f_out:
|
|
178
|
+
f_out.write(f_in.read())
|
|
179
|
+
else:
|
|
180
|
+
log.error(f"Unsupported compression format: {compressed_path}")
|
|
181
|
+
return False
|
|
182
|
+
log.debug(f"Decompressed file: {compressed_path} -> {output_path}")
|
|
183
|
+
return True
|
|
184
|
+
except Exception as e:
|
|
185
|
+
log.error(f"Failed to decompress {compressed_path}: {str(e)}")
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
def _parse_primary_xml(self, xml_path: str) -> List[str]:
|
|
189
|
+
rpm_names = set()
|
|
190
|
+
try:
|
|
191
|
+
with open(xml_path, 'r', encoding='utf-8') as f:
|
|
192
|
+
xml_content = f.read()
|
|
193
|
+
root = ET.fromstring(xml_content)
|
|
194
|
+
packages = root.findall(".//package[@type='rpm']")
|
|
195
|
+
if not packages:
|
|
196
|
+
packages = root.findall(".//default:package[@type='rpm']",
|
|
197
|
+
namespaces={"default": self.ns_map["default"]})
|
|
198
|
+
|
|
199
|
+
log.debug(f"Found {len(packages)} RPM packages in primary.xml")
|
|
200
|
+
for pkg in packages:
|
|
201
|
+
name_elem = pkg.find("name")
|
|
202
|
+
if name_elem is None:
|
|
203
|
+
name_elem = pkg.find("default:name", namespaces={"default": self.ns_map["default"]})
|
|
204
|
+
if name_elem is not None and name_elem.text:
|
|
205
|
+
pkg_name = name_elem.text.strip()
|
|
206
|
+
if pkg_name:
|
|
207
|
+
rpm_names.add(pkg_name)
|
|
208
|
+
log.debug(f"Extracted package name: {pkg_name}")
|
|
209
|
+
result = sorted(list(rpm_names))
|
|
210
|
+
log.info(f"Extracted {len(result)} unique RPM package names")
|
|
211
|
+
return result
|
|
212
|
+
|
|
213
|
+
except ET.ParseError as e:
|
|
214
|
+
log.error(f"XML parse error in {xml_path}: {str(e)}")
|
|
215
|
+
return []
|
|
216
|
+
except Exception as e:
|
|
217
|
+
log.error(f"Failed to parse primary.xml {xml_path}: {str(e)}")
|
|
218
|
+
return []
|
|
219
|
+
|
|
220
|
+
def get_rpm_list(self, repo_url: str) -> List[str]:
|
|
221
|
+
try:
|
|
222
|
+
repo_url = repo_url.rstrip('/')
|
|
223
|
+
repodata_url = f"{repo_url}/repodata/"
|
|
224
|
+
log.info(f"Start to get RPM list from repo: {repo_url}")
|
|
225
|
+
repodata_files = self._get_repodata_file_list(repodata_url)
|
|
226
|
+
if not repodata_files:
|
|
227
|
+
log.warning(f"No files found in repodata directory: {repodata_url}")
|
|
228
|
+
return []
|
|
229
|
+
primary_file = None
|
|
230
|
+
compressed_type = None
|
|
231
|
+
for f in repodata_files:
|
|
232
|
+
if f.endswith('primary.xml'):
|
|
233
|
+
primary_file = f
|
|
234
|
+
break
|
|
235
|
+
if not primary_file:
|
|
236
|
+
for c_type, pattern in self.compressed_patterns.items():
|
|
237
|
+
for f in repodata_files:
|
|
238
|
+
if pattern.search(f):
|
|
239
|
+
primary_file = f
|
|
240
|
+
compressed_type = c_type
|
|
241
|
+
break
|
|
242
|
+
if primary_file:
|
|
243
|
+
break
|
|
244
|
+
|
|
245
|
+
if not primary_file:
|
|
246
|
+
log.error(f"No primary.xml (or compressed) found in {repodata_url}")
|
|
247
|
+
return []
|
|
248
|
+
log.info(f"Found primary file: {primary_file} (compressed type: {compressed_type or 'none'})")
|
|
249
|
+
|
|
250
|
+
with TemporaryDirectory() as tmp_dir:
|
|
251
|
+
file_url = f"{repodata_url}/{primary_file}"
|
|
252
|
+
local_file = os.path.join(tmp_dir, primary_file)
|
|
253
|
+
|
|
254
|
+
if not self._download_file(file_url, local_file):
|
|
255
|
+
return []
|
|
256
|
+
|
|
257
|
+
xml_path = os.path.join(tmp_dir, 'primary.xml')
|
|
258
|
+
if compressed_type:
|
|
259
|
+
if not self._decompress_file(local_file, xml_path):
|
|
260
|
+
return []
|
|
261
|
+
else:
|
|
262
|
+
xml_path = local_file
|
|
263
|
+
|
|
264
|
+
rpm_names = self._parse_primary_xml(xml_path)
|
|
265
|
+
return rpm_names
|
|
266
|
+
|
|
267
|
+
except Exception as e:
|
|
268
|
+
log.error(f"get rpm list from repo {repo_url} failed, error message is {str(e)}")
|
|
269
|
+
return []
|
|
270
|
+
|
|
271
|
+
class OpenEuler():
|
|
272
|
+
def __init__(self):
|
|
273
|
+
pass
|
|
274
|
+
|
|
275
|
+
def get_rpm_list(self,repo_url):
|
|
276
|
+
try:
|
|
277
|
+
return RepoRpmParser().get_rpm_list(repo_url)
|
|
278
|
+
except Exception as e:
|
|
279
|
+
log.error(f"get rpm list from repo {repo_url} failed, error message is {str(e)}")
|
|
280
|
+
return []
|
|
281
|
+
|
|
282
|
+
def get_openEuler_everything_rpm_list(self, os_version: str, os_arch: str):
|
|
283
|
+
url=f"https://fast-mirror.isrc.ac.cn/openeuler/openEuler-{os_version}/everything/{os_arch}"
|
|
284
|
+
return self.get_rpm_list(url)
|
|
285
|
+
|
|
286
|
+
def get_openEuler_epol_rpm_list(self, os_version: str, os_arch: str):
|
|
287
|
+
url = f"https://fast-mirror.isrc.ac.cn/openeuler/openEuler-{os_version}/EPOL/main/{os_arch}"
|
|
288
|
+
return self.get_rpm_list(url)
|
|
289
|
+
|
|
290
|
+
def get_openEuler_update_rpm_list(self, os_version: str, os_arch: str):
|
|
291
|
+
url = f"https://fast-mirror.isrc.ac.cn/openeuler/openEuler-{os_version}/update/{os_arch}"
|
|
292
|
+
return self.get_rpm_list(url)
|
|
293
|
+
|
|
294
|
+
def get_openEuler_os_rpm_list(self, os_version: str, os_arch: str):
|
|
295
|
+
url = f"https://fast-mirror.isrc.ac.cn/openeuler/openEuler-{os_version}/OS/{os_arch}"
|
|
296
|
+
return self.get_rpm_list(url)
|
|
297
|
+
|
|
298
|
+
def get_openEuler_all_rpm_list(self, os_version: str, os_arch: str):
|
|
299
|
+
all_rpm_list=[]
|
|
300
|
+
rs=self.get_openEuler_os_rpm_list(os_version, os_arch)
|
|
301
|
+
all_rpm_list.extend(rs)
|
|
302
|
+
rs=self.get_openEuler_update_rpm_list(os_version, os_arch)
|
|
303
|
+
all_rpm_list.extend(rs)
|
|
304
|
+
rs=self.get_openEuler_epol_rpm_list(os_version, os_arch)
|
|
305
|
+
all_rpm_list.extend(rs)
|
|
306
|
+
rs=self.get_openEuler_everything_rpm_list(os_version, os_arch)
|
|
307
|
+
all_rpm_list.extend(rs)
|
|
308
|
+
return list(set(all_rpm_list))
|
|
309
|
+
|
|
310
|
+
def get_core_src_list(self):
|
|
311
|
+
core_src_list=[]
|
|
312
|
+
src_path=Path(__file__).resolve().parent / "openEuler_core_src.txt"
|
|
313
|
+
try:
|
|
314
|
+
with open(src_path, "r",encoding="utf-8") as f:
|
|
315
|
+
for line in f.readlines():
|
|
316
|
+
if not line.strip():
|
|
317
|
+
continue
|
|
318
|
+
line_segs = line.strip().split("|")
|
|
319
|
+
if len(line_segs)>=3:
|
|
320
|
+
core_src_list.append(line_segs[2].strip())
|
|
321
|
+
except Exception as e:
|
|
322
|
+
log.error(f"get core src list failed, error is {e}")
|
|
323
|
+
finally:
|
|
324
|
+
return core_src_list
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def get_openEuler_repo_names_and_urls(
|
|
328
|
+
self,
|
|
329
|
+
os_version: str
|
|
330
|
+
) -> Generator[Tuple[str, str], None, None]:
|
|
331
|
+
log.info("正在初始化 Gitee 接口操作实例...")
|
|
332
|
+
gitee = Gitee()
|
|
333
|
+
for repo_name, repo_url in gitee.get_repo_name_and_repo_html_url_by_org("src-openEuler"):
|
|
334
|
+
log.info(f"正在检查仓库: {repo_name},地址: {repo_url}")
|
|
335
|
+
branches = gitee.get_branches_list_by_repo(repo_name, "src-openEuler")
|
|
336
|
+
if not branches:
|
|
337
|
+
log.warning(f"仓库 {repo_name}({repo_url})未发现任何分支,已跳过")
|
|
338
|
+
continue
|
|
339
|
+
branch = f"openEuler-{os_version}"
|
|
340
|
+
if branch in branches:
|
|
341
|
+
log.info(f"仓库 {repo_name}({repo_url})已找到目标版本分支 {branch}")
|
|
342
|
+
yield repo_name, repo_url
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def get_openEuler_core_rpm_list(self,os_version,os_arch):
|
|
347
|
+
core_src_list=self.get_core_src_list()
|
|
348
|
+
core_rpm_list=[]
|
|
349
|
+
os_rpm2src=self.get_openEuler_os_rpm2src(os_version,os_arch)
|
|
350
|
+
for rpm_name,src_name in os_rpm2src.items():
|
|
351
|
+
if src_name in core_src_list and rpm_name not in core_rpm_list:
|
|
352
|
+
core_rpm_list.append(rpm_name)
|
|
353
|
+
return core_rpm_list
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def get_openEuler_os_rpm2src(self,os_version,os_arch):
|
|
357
|
+
rpm2src_file_path=Path(__file__).resolve().parent / "pkg_info" / f"openEuler_{os_version}_{os_arch}_os.json"
|
|
358
|
+
rpm2src_data=dict({})
|
|
359
|
+
try:
|
|
360
|
+
with open(rpm2src_file_path, "r",encoding="utf-8") as f:
|
|
361
|
+
rpm2src_data = json.load(f)
|
|
362
|
+
except FileNotFoundError:
|
|
363
|
+
log.error(f"未找到 {rpm2src_file_path} 文件")
|
|
364
|
+
except json.JSONDecodeError:
|
|
365
|
+
log.error(f"{rpm2src_file_path} 文件格式错误")
|
|
366
|
+
except Exception as e:
|
|
367
|
+
log.error(f"{rpm2src_file_path} 文件读取错误: {str(e)}")
|
|
368
|
+
finally:
|
|
369
|
+
return rpm2src_data
|
|
370
|
+
|
|
371
|
+
def get_openEuler_update_rpm2src(self,os_version,os_arch):
|
|
372
|
+
rpm2src_file_path=Path(__file__).resolve().parent / "pkg_info" / f"openEuler_{os_version}_{os_arch}_update.json"
|
|
373
|
+
rpm2src_data=dict({})
|
|
374
|
+
try:
|
|
375
|
+
with open(rpm2src_file_path, "r",encoding="utf-8") as f:
|
|
376
|
+
rpm2src_data = json.load(f)
|
|
377
|
+
except FileNotFoundError:
|
|
378
|
+
log.error(f"未找到 {rpm2src_file_path} 文件")
|
|
379
|
+
except json.JSONDecodeError:
|
|
380
|
+
log.error(f"{rpm2src_file_path} 文件格式错误")
|
|
381
|
+
except Exception as e:
|
|
382
|
+
log.error(f"{rpm2src_file_path} 文件读取错误: {str(e)}")
|
|
383
|
+
finally:
|
|
384
|
+
return rpm2src_data
|
|
385
|
+
|
|
386
|
+
def get_openEuler_everything_rpm2src(self,os_version,os_arch):
|
|
387
|
+
rpm2src_file_path=Path(__file__).resolve().parent / "pkg_info" / f"openEuler_{os_version}_{os_arch}_everything.json"
|
|
388
|
+
rpm2src_data=dict({})
|
|
389
|
+
try:
|
|
390
|
+
with open(rpm2src_file_path, "r",encoding="utf-8") as f:
|
|
391
|
+
rpm2src_data = json.load(f)
|
|
392
|
+
except FileNotFoundError:
|
|
393
|
+
log.error(f"未找到 {rpm2src_file_path} 文件")
|
|
394
|
+
except json.JSONDecodeError:
|
|
395
|
+
log.error(f"{rpm2src_file_path} 文件格式错误")
|
|
396
|
+
except Exception as e:
|
|
397
|
+
log.error(f"{rpm2src_file_path} 文件读取错误: {str(e)}")
|
|
398
|
+
finally:
|
|
399
|
+
return rpm2src_data
|
|
400
|
+
|
|
401
|
+
def get_openEuler_epol_rpm2src(self,os_version,os_arch):
|
|
402
|
+
rpm2src_file_path=Path(__file__).resolve().parent / "pkg_info" / f"openEuler_{os_version}_{os_arch}_epol.json"
|
|
403
|
+
rpm2src_data=dict({})
|
|
404
|
+
try:
|
|
405
|
+
with open(rpm2src_file_path, "r",encoding="utf-8") as f:
|
|
406
|
+
rpm2src_data = json.load(f)
|
|
407
|
+
except FileNotFoundError:
|
|
408
|
+
log.error(f"未找到 {rpm2src_file_path} 文件")
|
|
409
|
+
except json.JSONDecodeError:
|
|
410
|
+
log.error(f"{rpm2src_file_path} 文件格式错误")
|
|
411
|
+
except Exception as e:
|
|
412
|
+
log.error(f"{rpm2src_file_path} 文件读取错误: {str(e)}")
|
|
413
|
+
finally:
|
|
414
|
+
return rpm2src_data
|
|
415
|
+
|
|
416
|
+
if __name__ == "__main__":
|
|
417
|
+
|
|
418
|
+
# rpm=RepoRpmParser()
|
|
419
|
+
# rs=rpm.get_rpm_list("https://fast-mirror.isrc.ac.cn/openeuler/openEuler-24.03-LTS-SP2/OS/x86_64/")
|
|
420
|
+
# for elem in rs:
|
|
421
|
+
# print(elem)
|
|
422
|
+
# print(f"total {len( rs)} rpms")
|
|
423
|
+
|
|
424
|
+
# oe=OpenEuler()
|
|
425
|
+
# rs=oe.get_rpm_list("https://fast-mirror.isrc.ac.cn/openeuler/openEuler-24.03-LTS-SP2/OS/x86_64/")
|
|
426
|
+
# for elem in rs:
|
|
427
|
+
# print(elem)
|
|
428
|
+
# print(f"total {len( rs)} rpms")
|
|
429
|
+
|
|
430
|
+
# oe = OpenEuler()
|
|
431
|
+
# rs = oe.get_openEuler_os_rpm_list("24.03-LTS-SP2", "x86_64")
|
|
432
|
+
# print(f"os {len(rs)} rpms")
|
|
433
|
+
|
|
434
|
+
# oe=OpenEuler()
|
|
435
|
+
# rs=oe.get_openEuler_update_rpm_list("24.03-LTS-SP2", "x86_64")
|
|
436
|
+
# print(f"os {len( rs)} rpms")
|
|
437
|
+
|
|
438
|
+
# oe = OpenEuler()
|
|
439
|
+
# rs = oe.get_openEuler_everything_rpm_list("24.03-LTS-SP2", "x86_64")
|
|
440
|
+
# print(f"os {len(rs)} rpms")
|
|
441
|
+
|
|
442
|
+
# oe = OpenEuler()
|
|
443
|
+
# rs = oe.get_openEuler_all_rpm_list("24.03-LTS-SP2", "x86_64")
|
|
444
|
+
# print(f"os {len(rs)} rpms")
|
|
445
|
+
|
|
446
|
+
# oe=OpenEuler()
|
|
447
|
+
# repos_generator = oe.get_openEuler_repo_names_and_urls(
|
|
448
|
+
# os_version="24.03-LTS-SP2"
|
|
449
|
+
# )
|
|
450
|
+
# log.info("正在获取 openEuler 24.03-LTS-SP2 x86_64 架构的仓库信息...")
|
|
451
|
+
# count = 0
|
|
452
|
+
# for repo_name, repo_url in repos_generator:
|
|
453
|
+
# log.info(f"正在处理仓库: {repo_name},地址: {repo_url}")
|
|
454
|
+
# count += 1
|
|
455
|
+
# print(f"{repo_name}:{repo_url}")
|
|
456
|
+
# log.info("共获取到 %d 个仓库" % count)
|
|
457
|
+
|
|
458
|
+
# rs=oe.get_core_src_list()
|
|
459
|
+
# print(len(rs))
|
|
460
|
+
|
|
461
|
+
# oe = OpenEuler()
|
|
462
|
+
# rs = oe.get_openEuler_os_rpm2src("24.03-LTS-SP2", "x86_64")
|
|
463
|
+
# print(len(rs.keys()))
|
|
464
|
+
|
|
465
|
+
# oe = OpenEuler()
|
|
466
|
+
# rs = oe.get_openEuler_update_rpm2src("24.03-LTS-SP2", "x86_64")
|
|
467
|
+
# print(len(rs.keys()))
|
|
468
|
+
|
|
469
|
+
# oe = OpenEuler()
|
|
470
|
+
# rs = oe.get_openEuler_everything_rpm2src("24.03-LTS-SP2", "x86_64")
|
|
471
|
+
# print(len(rs.keys()))
|
|
472
|
+
|
|
473
|
+
oe = OpenEuler()
|
|
474
|
+
rs = oe.get_openEuler_epol_rpm2src("24.03-LTS-SP2", "x86_64")
|
|
475
|
+
print(len(rs.keys()))
|
|
476
|
+
|
|
477
|
+
pass
|
|
478
|
+
|