chore: migrate project into clean repository

This commit is contained in:
yuuux
2026-08-13 16:50:52 +08:00
commit d1d25a09e7
27405 changed files with 9422808 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
import os
import re
import subprocess
from PIL import Image
from datetime import datetime
# 基础配置
ADB_PATH = "adb"
DEVICE_PATH = "/SD:/adb/"
# 生成日期时间作为文件夹名
now = datetime.now()
date_string = now.strftime("%Y%m%d_%H%M%S")
OUTPUT_DIR = f"./build/output/{date_string}"
RAW_FRAMES_DIR = os.path.join(OUTPUT_DIR, "raw_frames")
def run_adb_command(command):
"""执行ADB命令并返回输出"""
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
check=True
)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"ADB命令执行失败: {e}")
return None
def parse_dimensions(filename):
"""从文件名解析宽高"""
match = re.search(r"_(\d+)x(\d+)\.yuv$", filename)
if match:
return int(match.group(1)), int(match.group(2))
return None, None
def process_yuv400_file(filepath, output_dir, is_multi_frame=False):
"""处理YUV400文件"""
# 从文件名获取尺寸
filename = os.path.basename(filepath)
width, height = parse_dimensions(filename)
if not width or not height:
print(f"无法解析尺寸: {filename}")
return
# 读取YUV数据
with open(filepath, "rb") as f:
yuv_data = f.read()
# 计算帧数
frame_size = width * height
total_frames = len(yuv_data) // frame_size
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 处理帧数据
for frame_idx in range(total_frames if is_multi_frame else 1):
start = frame_idx * frame_size
end = start + frame_size
frame_data = yuv_data[start:end]
# 创建灰度图像
img = Image.frombytes("L", (width, height), frame_data)
# 生成输出路径
output_path = os.path.join(
output_dir,
f"{os.path.splitext(filename)[0]}_frame{frame_idx+1:03d}.jpg"
)
img.save(output_path, "JPEG")
def main():
# 创建输出目录
os.makedirs(OUTPUT_DIR, exist_ok=True)
# 获取设备文件列表
ls_output = run_adb_command(f"{ADB_PATH} ls {DEVICE_PATH}")
if not ls_output:
return
device_path = DEVICE_PATH
# 如果该目录下有多个文件,则在显示在控制台
if len(ls_output.split("\n")) > 1:
print("发现多个文件夹:\n")
print(ls_output)
# 控制台输入
folder = input("请输入要拉取的文件夹:")
device_path = f"{DEVICE_PATH}/{folder}"
ls_output = run_adb_command(f"{ADB_PATH} ls {device_path}")
if not ls_output:
print("未找到指定文件夹\n")
return
else:
device_path = DEVICE_PATH + "/" + re.compile('.+ .+ .+ ').sub('', ls_output.split('\n')[0]).strip()
ls_output = run_adb_command(f"{ADB_PATH} ls {device_path}")
if not ls_output:
return
# 筛选目标文件
target_files = []
prefixes = (r".+ .+ .+ raw_img", r".+ .+ .+ stitch_img", r".+ .+ .+ cutline_img")
for line in ls_output.split("\n"):
if any(re.match(prefix, line) for prefix in prefixes) and line.endswith(".yuv"):
target_files.append(re.compile('.+ .+ .+ ').sub('', line).strip())
# 拉取文件到本地
for filename in target_files:
remote_path = os.path.join(device_path, filename).replace("\\", "/")
exit_code = os.system(f"{ADB_PATH} pull {remote_path} {OUTPUT_DIR}")
if exit_code != 0:
print(f"文件拉取失败: {filename}")
continue
local_path = os.path.join(OUTPUT_DIR, filename)
# 根据文件类型处理
if filename.startswith("raw_img"):
process_yuv400_file(local_path, RAW_FRAMES_DIR, is_multi_frame=True)
else:
process_yuv400_file(local_path, OUTPUT_DIR, is_multi_frame=False)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,186 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Clean up git repositories and directories that are not listed in .gitmodules file.
This script will find all git repositories and potential submodule directories in the project
and remove those that are not listed as submodules in the .gitmodules file.
"""
import os
import sys
import shutil
import subprocess
import re
import argparse
from pathlib import Path
def get_submodule_paths(gitmodules_path):
"""
Parse .gitmodules file to extract all submodule paths.
Args:
gitmodules_path: Path to .gitmodules file
Returns:
A set of normalized paths for all submodules
"""
if not os.path.exists(gitmodules_path):
return set()
submodule_paths = set()
with open(gitmodules_path, 'r') as f:
content = f.read()
# Find all path entries in the .gitmodules file
path_matches = re.findall(r'^\s*path\s*=\s*(.+)$', content, re.MULTILINE)
for path in path_matches:
path = path.strip()
# Normalize path to ensure consistent comparison
normalized_path = os.path.normpath(path)
submodule_paths.add(normalized_path)
return submodule_paths
def is_git_repo(path):
"""
Check if a directory is a git repository.
Args:
path: Path to the directory
Returns:
True if the directory is a git repository, False otherwise
"""
# Check if .git directory exists
git_dir = os.path.join(path, '.git')
if os.path.exists(git_dir) and os.path.isdir(git_dir):
return True
# Check if .git file exists (for submodules)
git_file = os.path.join(path, '.git')
if os.path.exists(git_file) and os.path.isfile(git_file):
return True
return False
def load_submodule_whitelist(base_dir):
"""Load whitelist paths from .gitmodules in base_dir. Paths are normalized."""
gm_path = os.path.join(base_dir, '.gitmodules')
return get_submodule_paths(gm_path)
def scan_unexpected_git_repos(root_dir):
"""
Walk the tree from root_dir. For any git repo encountered under a base directory,
compare against that base's .gitmodules whitelist. If a child repo path relative to base
is not listed, mark it as unexpected. When a listed submodule is encountered, treat it
as a new base and use its own .gitmodules for deeper comparisons.
Returns list of paths (relative to root_dir) to remove.
"""
# Maintain mapping of base absolute path -> whitelist set
base_whitelists = {}
root_abs = os.path.abspath(root_dir)
base_whitelists[root_abs] = load_submodule_whitelist(root_abs)
def find_base_for(path_abs):
# choose deepest base that is a prefix of path_abs
candidates = [b for b in base_whitelists.keys() if path_abs == b or path_abs.startswith(b + os.sep)]
if not candidates:
return root_abs
return max(candidates, key=len)
unexpected = []
for dirpath, dirnames, filenames in os.walk(root_abs):
# skip hidden directories at traversal level
dirnames[:] = [d for d in dirnames if not d.startswith('.')]
if not is_git_repo(dirpath):
continue
current_base = find_base_for(dirpath)
rel_to_base = os.path.relpath(dirpath, current_base)
# If this is exactly the base repo directory, allow and ensure its whitelist is loaded
if rel_to_base == '.':
# already loaded for root; for nested bases, load when we encounter them as listed modules below
continue
whitelist = base_whitelists.get(current_base, set())
if rel_to_base in whitelist:
# It's a declared submodule under current_base; treat it as a new base and load its whitelist
sub_base_abs = dirpath
if sub_base_abs not in base_whitelists:
base_whitelists[sub_base_abs] = load_submodule_whitelist(sub_base_abs)
# continue walking inside (allowed)
continue
else:
# Not declared in the nearest base's .gitmodules -> unexpected
rel_to_root = os.path.relpath(dirpath, root_abs)
unexpected.append(rel_to_root)
# no need to descend into this unexpected repo
dirnames[:] = []
return unexpected, base_whitelists[root_abs]
def main():
# Parse command line arguments
parser = argparse.ArgumentParser(description='Clean up git repositories that are not listed in .gitmodules file.')
parser.add_argument('-y', '--yes', action='store_true', help='Automatically confirm removal without prompting')
parser.add_argument('--dry-run', action='store_true', help='Only show what would be removed, but do not actually remove anything')
parser.add_argument('--root-path', type=str, help='Project root path containing .gitmodules', default=os.getcwd())
args = parser.parse_args()
root_dir = args.root_path
# Get the project root directory (where .gitmodules is located)
gitmodules_path = os.path.join(root_dir, '.gitmodules')
# Get all submodule paths from root .gitmodules
root_submodule_paths = get_submodule_paths(gitmodules_path)
print(f"Found {len(root_submodule_paths)} submodules in .gitmodules:")
for path in sorted(root_submodule_paths):
print(f" - {path}")
# Scan with hierarchical .gitmodules
dirs_to_remove, _ = scan_unexpected_git_repos(root_dir)
if not dirs_to_remove:
print("\nNo unexpected module directories found. Nothing to clean up.")
return
print(f"\nFound {len(dirs_to_remove)} git repositories that are not in .gitmodules:")
for dir_path in dirs_to_remove:
print(f" - {dir_path}")
# Check if this is a dry run
if args.dry_run:
print("\nDry run: No repositories will be removed.")
return
# Ask for confirmation before removing (unless --yes flag is provided)
if not args.yes:
confirm = input("\nDo you want to remove these git repositories? [y/N]: ")
if confirm.lower() != 'y':
print("Operation cancelled.")
return
else:
print("\nAutomatic confirmation enabled. Proceeding with removal...")
# Remove the directories
for dir_path in dirs_to_remove:
full_path = os.path.join(root_dir, dir_path)
print(f"Removing {full_path}...")
try:
shutil.rmtree(full_path)
print(f" [OK] Successfully removed {dir_path}")
except Exception as e:
print(f" [FAILED] Failed to remove {dir_path}: {str(e)}")
print("\nCleanup completed.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,87 @@
#!/usr/bin/env python3
import sys
import os
import argparse
def parse_size(size_str):
try:
return int(size_str, 0)
except ValueError:
return int(size_str)
def merge_bins(output_file, bins):
# bins is a list of (address, file_path) tuples
# Sort by address
bins.sort(key=lambda x: x[0])
# Calculate total size
max_addr = 0
bin_data_list = []
for addr, path in bins:
if not os.path.exists(path):
print(f"Error: File not found: {path}")
sys.exit(1)
with open(path, 'rb') as f:
data = f.read()
end_addr = addr + len(data)
if end_addr > max_addr:
max_addr = end_addr
bin_data_list.append({'addr': addr, 'data': data, 'path': path})
print(f"Total merged size: {max_addr} bytes")
# Create buffer filled with 0xFF
merged_data = bytearray([0xFF] * max_addr)
# Fill buffer
for item in bin_data_list:
addr = item['addr']
data = item['data']
size = len(data)
# Check for overlap
# Since we sorted by address, we only need to check if current overlaps with previous filled area?
# Actually, since we write to a bytearray, later writes will overwrite earlier ones.
# But we should probably warn or error on overlap.
# Let's do a simple check against the 'merged_data' if it's not 0xFF?
# No, 0xFF is valid data.
# Let's check ranges.
print(f"Merging {item['path']} at 0x{addr:X} (size: {size} bytes)")
merged_data[addr:addr+size] = data
# Write to output file
output_dir = os.path.dirname(os.path.abspath(output_file))
if not os.path.exists(output_dir):
os.makedirs(output_dir)
with open(output_file, 'wb') as f:
f.write(merged_data)
print(f"Successfully created {output_file}")
def main():
parser = argparse.ArgumentParser(description='Merge multiple binary files into one with padding (0xFF).')
parser.add_argument('-o', '--output', required=True, help='Output merged binary file path')
parser.add_argument('--bin', action='append', nargs=2, metavar=('ADDRESS', 'FILE'),
help='Input binary file and its destination address (hex or decimal). Can be used multiple times.')
args = parser.parse_args()
if not args.bin:
print("Error: No input binaries specified. Use --bin <address> <file>")
sys.exit(1)
parsed_bins = []
for addr_str, file_path in args.bin:
addr = parse_size(addr_str)
parsed_bins.append((addr, file_path))
merge_bins(args.output, parsed_bins)
if __name__ == '__main__':
main()