Skip to content

Commit cacd4d9

Browse files
author
yan hu
committed
tools: fix CI git diff path parsing
1 parent ece7b4f commit cacd4d9

5 files changed

Lines changed: 348 additions & 32 deletions

File tree

tools/ci/compile_bsp_with_drivers.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88
# 2023-06-27 dejavudwh the first version
99
#
1010

11-
import subprocess
1211
import logging
1312
import os
1413
import sys
1514

15+
try:
16+
from git_utils import get_changed_files
17+
except ImportError:
18+
from tools.ci.git_utils import get_changed_files
19+
1620
CONFIG_BSP_USING_X = ["CONFIG_BSP_USING_UART", "CONFIG_BSP_USING_I2C", "CONFIG_BSP_USING_SPI", "CONFIG_BSP_USING_ADC", "CONFIG_BSP_USING_DAC"]
1721

1822
def init_logger():
@@ -24,25 +28,35 @@ def init_logger():
2428
)
2529

2630
def diff():
27-
result = subprocess.run(['git', 'diff', '--name-only', 'HEAD', 'origin/master', '--diff-filter=ACMR', '--no-renames', '--full-index'], stdout = subprocess.PIPE)
28-
file_list = result.stdout.decode().strip().split('\n')
31+
try:
32+
file_list = get_changed_files(
33+
"HEAD",
34+
"origin/master",
35+
diff_filter="ACMR",
36+
no_renames=True,
37+
full_index=True,
38+
)
39+
except RuntimeError as e:
40+
logging.error(e)
41+
return set()
42+
2943
logging.info(file_list)
3044
bsp_paths = set()
3145
for file in file_list:
3246
if "bsp/" in file:
3347
logging.info("Modifed file: {}".format(file))
3448
bsp_paths.add(file)
35-
49+
3650
dirs = set()
3751
for dir in bsp_paths:
38-
dir = os.path.dirname(dir)
52+
dir = os.path.dirname(dir)
3953
while "bsp/" in dir:
4054
files = os.listdir(dir)
4155
if ".config" in files and "rt-thread.elf" not in files and not dir.endswith("bsp"):
4256
logging.info("Found bsp path: {}".format(dir))
4357
dirs.add(dir)
4458
break
45-
new_dir = os.path.dirname(dir)
59+
new_dir = os.path.dirname(dir)
4660
dir = new_dir
4761

4862
return dirs

tools/ci/format_ignore.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
import yaml
1212
import logging
1313
import os
14-
import subprocess
14+
15+
try:
16+
from git_utils import get_changed_files
17+
except ImportError:
18+
from tools.ci.git_utils import get_changed_files
1519

1620
def init_logger():
1721
log_format = "[%(filename)s %(lineno)d %(levelname)s] %(message)s "
@@ -72,13 +76,23 @@ def __exclude_file(self, file_path):
7276
return 1
7377

7478
def get_new_file(self):
75-
result = subprocess.run(['git', 'diff', '--name-only', 'HEAD', 'origin/master', '--diff-filter=ACMR', '--no-renames', '--full-index'], stdout = subprocess.PIPE)
76-
file_list = result.stdout.decode().strip().split('\n')
79+
try:
80+
file_list = get_changed_files(
81+
"HEAD",
82+
"origin/master",
83+
diff_filter="ACMR",
84+
no_renames=True,
85+
full_index=True,
86+
)
87+
except RuntimeError as e:
88+
logging.error(e)
89+
return []
90+
7791
new_files = []
7892
for line in file_list:
7993
logging.info("modified file -> {}".format(line))
8094
result = self.__exclude_file(line)
8195
if result != 0:
8296
new_files.append(line)
83-
84-
return new_files
97+
98+
return new_files

tools/ci/git_diff_show.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@
1717

1818
import json
1919
from typing import List
20+
21+
try:
22+
from git_utils import get_blob_size
23+
from git_utils import get_merge_base as git_get_merge_base
24+
from git_utils import get_name_status_lines
25+
except ImportError:
26+
from tools.ci.git_utils import get_blob_size
27+
from tools.ci.git_utils import get_merge_base as git_get_merge_base
28+
from tools.ci.git_utils import get_name_status_lines
29+
2030
class FileDiff:
2131
def __init__(self, path: str, status: str, size_change: int = 0, old_size: int = 0, new_size: int = 0):
2232
self.path = path
@@ -49,14 +59,13 @@ def get_diff_files(self) -> List[FileDiff]:
4959
sys.exit(1)
5060

5161
# 获取差异文件列表
52-
diff_cmd = f"git diff --name-status {merge_base} HEAD"
53-
print(diff_cmd)
62+
print("git diff --name-status {} HEAD".format(merge_base))
5463
try:
55-
output = subprocess.check_output(diff_cmd.split(), stderr=subprocess.STDOUT)
56-
output = output.decode(self.encoding).strip()
64+
lines = get_name_status_lines(merge_base, "HEAD", self.encoding)
65+
output = "\n".join(lines)
5766
print(output)
58-
except subprocess.CalledProcessError as e:
59-
print(f"Error executing git diff: {e.output.decode(self.encoding)}")
67+
except RuntimeError as e:
68+
print("Error executing git diff: {}".format(e))
6069
sys.exit(1)
6170

6271
if not output:
@@ -110,24 +119,15 @@ def get_diff_files(self) -> List[FileDiff]:
110119
def get_merge_base(self) -> str:
111120
"""获取当前分支和目标分支的最近共同祖先"""
112121
try:
113-
cmd = f"git merge-base {self.target_branch} HEAD"
114-
print(cmd)
115-
output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
116-
return output.decode(self.encoding).strip()
117-
except subprocess.CalledProcessError as e:
118-
print(f"Error executing git merge-base: {e.output.decode(self.encoding)}")
122+
print("git merge-base {} HEAD".format(self.target_branch))
123+
return git_get_merge_base(self.target_branch, "HEAD", self.encoding)
124+
except RuntimeError as e:
125+
print("Error executing git merge-base: {}".format(e))
119126
return None
120127

121128
def get_file_size(self, path: str, ref: str) -> int:
122-
"""获取指定分支上文件的大小"""
123-
try:
124-
# 使用 git cat-file 来获取文件内容,然后计算其大小
125-
cmd = f"git cat-file blob {ref}:{path}"
126-
output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
127-
return len(output)
128-
except subprocess.CalledProcessError:
129-
# 如果文件不存在或无法获取,返回0
130-
return 0
129+
"""Get the size of a file at the specified git ref."""
130+
return get_blob_size(ref, path, self.encoding)
131131

132132
def format_size(size: int) -> str:
133133
"""将字节大小转换为人类可读的格式"""

tools/ci/git_utils.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#
2+
# Copyright (c) 2006-2026, RT-Thread Development Team
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
import locale
8+
import subprocess
9+
10+
11+
def _default_encoding():
12+
return locale.getpreferredencoding()
13+
14+
15+
def _decode_output(data, encoding=None):
16+
if data is None:
17+
return ""
18+
19+
if encoding is None:
20+
encoding = _default_encoding()
21+
22+
return data.decode(encoding, errors="replace")
23+
24+
25+
def _run_git(args, encoding=None):
26+
result = subprocess.run(
27+
["git"] + args,
28+
stdout=subprocess.PIPE,
29+
stderr=subprocess.PIPE,
30+
check=False,
31+
)
32+
stdout = _decode_output(getattr(result, "stdout", b""), encoding)
33+
stderr = _decode_output(getattr(result, "stderr", b""), encoding)
34+
returncode = getattr(result, "returncode", 0)
35+
36+
if returncode != 0:
37+
raise RuntimeError(
38+
"git {} failed with code {}: {}".format(
39+
" ".join(args),
40+
returncode,
41+
stderr.strip(),
42+
)
43+
)
44+
45+
return stdout
46+
47+
48+
def split_nonempty_lines(output):
49+
return [line.strip() for line in output.splitlines() if line.strip()]
50+
51+
52+
def get_changed_files(base, head, diff_filter="ACMR", no_renames=True, full_index=True, encoding=None):
53+
args = [
54+
"diff",
55+
"--name-only",
56+
base,
57+
head,
58+
"--diff-filter={}".format(diff_filter),
59+
]
60+
61+
if no_renames:
62+
args.append("--no-renames")
63+
if full_index:
64+
args.append("--full-index")
65+
66+
output = _run_git(args, encoding=encoding)
67+
return split_nonempty_lines(output)
68+
69+
70+
def get_name_status_lines(base, head="HEAD", encoding=None):
71+
output = _run_git(
72+
["diff", "--name-status", base, head],
73+
encoding=encoding,
74+
)
75+
return split_nonempty_lines(output)
76+
77+
78+
def get_merge_base(target_branch, head="HEAD", encoding=None):
79+
output = _run_git(
80+
["merge-base", target_branch, head],
81+
encoding=encoding,
82+
)
83+
return output.strip()
84+
85+
86+
def _parse_ls_tree_size(output, encoding=None):
87+
text = _decode_output(output, encoding).strip()
88+
if not text:
89+
return 0
90+
91+
fields = text.split(None, 4)
92+
if len(fields) < 4:
93+
return 0
94+
95+
try:
96+
return int(fields[3])
97+
except ValueError:
98+
return 0
99+
100+
101+
def get_blob_size(ref, path, encoding=None):
102+
result = subprocess.run(
103+
["git", "ls-tree", "-l", ref, "--", path],
104+
stdout=subprocess.PIPE,
105+
stderr=subprocess.PIPE,
106+
check=False,
107+
)
108+
109+
if result.returncode != 0:
110+
return 0
111+
112+
return _parse_ls_tree_size(result.stdout, encoding)

0 commit comments

Comments
 (0)