with one click
linglong-fix
根据验证报告自动修复玲珑构建项目中的问题, 包括linglong.yaml格式、desktop文件、图标目录结构、二进制文件权限等。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
根据验证报告自动修复玲珑构建项目中的问题, 包括linglong.yaml格式、desktop文件、图标目录结构、二进制文件权限等。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
| name | linglong-fix |
| description | 根据验证报告自动修复玲珑构建项目中的问题, 包括linglong.yaml格式、desktop文件、图标目录结构、二进制文件权限等。 |
| user-invocable | false |
根据验证报告自动修复玲珑构建项目中的问题,包括linglong.yaml格式、desktop文件、图标目录结构、二进制文件权限等。
使用 scripts/validate_package_id.sh 验证 package_id 格式和一致性:
# 验证工程目录
./scripts/validate_package_id.sh CI_ll_com.visualstudio.code
# 验证工程目录和 deb 文件路径
./scripts/validate_package_id.sh CI_ll_com.visualstudio.code --deb-path com.visualstudio.code/code_1.85.0_amd64.deb
# 详细输出
./scripts/validate_package_id.sh CI_ll_com.visualstudio.code --verbose
验证项:
CI_ll_<package_id>com.example.app)package.id 与目录名一致性<package_id>/xxx.deb输出示例:
{
"status": "passed",
"package_id": "com.visualstudio.code",
"project_dir": "CI_ll_com.visualstudio.code",
"errors": [],
"warnings": []
}
使用 scripts/fix_package_id.sh 修复 package_id 相关问题:
# 模拟执行(查看将要进行的修改)
./scripts/fix_package_id.sh CI_ll_com.visualstudio.code --dry-run
# 修复 linglong.yaml 中的 package.id
./scripts/fix_package_id.sh CI_ll_com.visualstudio.code --new-id com.visualstudio.code
# 修复并重命名工程目录
./scripts/fix_package_id.sh CI_ll_wrong.name --new-id com.visualstudio.code --rename-dir
# 详细输出
./scripts/fix_package_id.sh CI_ll_com.visualstudio.code --verbose
修复项:
package.id--rename-dir)输出示例:
========================================
玲珑包ID修复工具
========================================
工程目录: /path/to/CI_ll_com.visualstudio.code
目标 package_id: com.visualstudio.code
[成功] 已更新 linglong.yaml 中的 package.id 为: com.visualstudio.code
[成功] 已检查 desktop 文件: com.visualstudio.code.desktop
========================================
修复报告
========================================
状态: success
工程目录: /path/to/CI_ll_com.visualstudio.code
已应用的修复:
✓ yaml_package_id: com.visualstudio.code
✓ desktop_file: com.visualstudio.code.desktop
========================================
玲珑包ID必须符合以下规范:
com.example.app)com.visualstudio.codeorg.deepin.musiccn.wps.wps-officeVisualStudio.Code(包含大写)code(缺少域名前缀)com..example(连续的点)⚠️ 这是 LLM 生成工程时最常见的问题之一!
LLM 生成 pak_linyaps.sh 时,经常将 base_id、runtime_id 等变量写为自引用形式(如 base_id="${base_id}"),导致实际值为空,进而使 linglong.yaml 中的 base 和 runtime 字段为空或格式错误。
使用 validate_pak_script.sh 检测脚本中的变量定义问题:
# 检测 pak_linyaps.sh 中的 base/runtime 配置问题
"${skill_root}/../linglong-project-gen/scripts/validate_pak_script.sh" "${project_dir}"
使用 validate_linglong_yaml.py 检测 YAML 中的 base/runtime 格式问题:
# 检测 linglong.yaml 中的 base/runtime 格式问题
"${skill_root}/../compat-testing/scripts/validate_linglong_yaml.py" \
--input "${project_dir}/templates/linglong.yaml" \
--exec-name "${binary_name}"
常见问题模式:
| 问题 | 症状 | 原因 |
|---|---|---|
| 变量自引用 | base_id="${base_id}" → 值为空 | LLM 生成时未定义顶部变量 |
| 空值 | base_id="" → envsubst 输出 base: / | 变量未初始化 |
| 未替换变量 | base: ${base_id}/${base_version} | envsubst 未替换(变量未 export) |
| 格式错误 | base: org.deepin.base (缺少版本) | 生成时遗漏版本号 |
# 自动修复 pak_linyaps.sh 中的变量定义问题
"${skill_root}/../linglong-project-gen/scripts/validate_pak_script.sh" "${project_dir}" --fix
修复内容:
org.deepin.base/25.2.2、org.deepin.runtime.dtk/25.2.2)--base_id 等参数解析如果 linglong.yaml 中的 base/runtime 字段有问题,手动修复:
# 检查当前值
grep -E "^base:|^runtime:" "${project_dir}/templates/linglong.yaml"
# 修复 base 字段(如果为空或格式错误)
sed -i 's|^base:.*|base: org.deepin.base/25.2.2|' "${project_dir}/templates/linglong.yaml"
# 修复 runtime 字段(如果为空或格式错误)
sed -i 's|^runtime:.*|runtime: org.deepin.runtime.dtk/25.2.2|' "${project_dir}/templates/linglong.yaml"
# 重新验证脚本
"${skill_root}/../linglong-project-gen/scripts/validate_pak_script.sh" "${project_dir}"
# 重新验证 YAML
"${skill_root}/../compat-testing/scripts/validate_linglong_yaml.py" \
--input "${project_dir}/templates/linglong.yaml" \
--exec-name "${binary_name}"
import yaml
def fix_yaml_indentation(yaml_path: str):
"""修复YAML缩进问题"""
with open(yaml_path, 'r') as f:
content = f.read()
# description至少4空格缩进
# build至少2空格缩进
lines = content.split('\n')
fixed_lines = []
in_description = False
in_build = False
for i, line in enumerate(lines):
stripped = line.lstrip()
if stripped.startswith('description:'):
in_description = True
fixed_lines.append(line)
elif stripped.startswith('build:'):
in_build = True
fixed_lines.append(line)
elif in_description and stripped and not stripped.startswith('-'):
# 确保description内容至少4空格
if len(line) - len(stripped) < 4:
fixed_lines.append(' ' + stripped)
else:
fixed_lines.append(line)
elif in_build and stripped:
# 确保build内容至少2空格
if len(line) - len(stripped) < 2:
fixed_lines.append(' ' + stripped)
else:
fixed_lines.append(line)
else:
fixed_lines.append(line)
# 检测块结束
if stripped and not stripped.startswith(' ') and not stripped.startswith('\t'):
if in_description and not stripped.startswith('description'):
in_description = False
if in_build and not stripped.startswith('build'):
in_build = False
with open(yaml_path, 'w') as f:
f.write('\n'.join(fixed_lines))
def fix_yaml_required_fields(yaml_path: str, package_info: dict):
"""补全必需字段"""
with open(yaml_path, 'r') as f:
data = yaml.safe_load(f)
# 确保version存在
if 'version' not in data:
data['version'] = package_info.get('ll_version', '1.0.0.0')
# 确保package字段完整
if 'package' not in data:
data['package'] = {}
package_fields = {
'id': package_info.get('package_id'),
'name': package_info.get('app_name'),
'version': package_info.get('ll_version'),
'kind': 'app',
'architecture': package_info.get('ll_architecture'),
'description': package_info.get('description', '')
}
for key, value in package_fields.items():
if key not in data['package'] and value:
data['package'][key] = value
# 确保base存在
if 'base' not in data:
data['base'] = package_info.get('base', 'org.deepin.base/23.1.0')
# 确保command存在
if 'command' not in data:
data['command'] = [f"/opt/apps/{package_info['package_id']}/files/bin/{package_info['binary_name']}"]
# 确保build存在
if 'build' not in data:
data['build'] = "cp -rf /project/binary/* ${prefix}/"
with open(yaml_path, 'w') as f:
yaml.dump(data, f, default_flow_style=False, allow_unicode=True)
def fix_yaml_command(yaml_path: str, desktop_exec: str):
"""修复command与desktop Exec一致"""
# 从desktop Exec提取命令
exec_cmd = desktop_exec.split()[0] # 去除参数如 %U, %F
with open(yaml_path, 'r') as f:
data = yaml.safe_load(f)
# 更新command
data['command'] = [exec_cmd]
with open(yaml_path, 'w') as f:
yaml.dump(data, f, default_flow_style=False)
def fix_desktop_icon(desktop_path: str):
"""修复Icon字段为相对路径"""
with open(desktop_path, 'r') as f:
lines = f.readlines()
fixed_lines = []
for line in lines:
if line.startswith('Icon='):
icon_path = line.split('=', 1)[1].strip()
# 去除绝对路径前缀
if icon_path.startswith('/'):
# 提取图标名(不含扩展名)
icon_name = Path(icon_path).stem
line = f'Icon={icon_name}\n'
fixed_lines.append(line)
with open(desktop_path, 'w') as f:
f.writelines(fixed_lines)
def fix_desktop_exec(desktop_path: str, package_id: str):
"""修复Exec字段"""
with open(desktop_path, 'r') as f:
lines = f.readlines()
fixed_lines = []
for line in lines:
if line.startswith('Exec='):
exec_value = line.split('=', 1)[1].strip()
# 去除绝对路径
parts = exec_value.split()
cmd = parts[0]
args = parts[1:] if len(parts) > 1 else []
if cmd.startswith('/'):
cmd = Path(cmd).name
# 重建Exec行
new_exec = 'Exec=' + cmd
if args:
new_exec += ' ' + ' '.join(args)
line = new_exec + '\n'
fixed_lines.append(line)
with open(desktop_path, 'w') as f:
f.writelines(fixed_lines)
def fix_desktop_required_fields(desktop_path: str, package_info: dict):
"""补全desktop必需字段"""
with open(desktop_path, 'r') as f:
content = f.read()
# 检查并添加必需字段
required = {
'Type': 'Application',
'Name': package_info.get('app_name', ''),
'Comment': package_info.get('description', ''),
'Categories': 'Utility;'
}
for key, value in required.items():
if f'{key}=' not in content and value:
content += f'\n{key}={value}'
with open(desktop_path, 'w') as f:
f.write(content)
def fix_icon_directory_structure(icons_dir: str):
"""修复图标目录结构"""
icons_path = Path(icons_dir)
# 标准尺寸
standard_sizes = ['16x16', '22x22', '24x24', '32x32', '48x48',
'64x64', '128x128', '256x256', '512x512', 'scalable']
# 确保hicolor目录存在
hicolor_dir = icons_path / 'hicolor'
hicolor_dir.mkdir(parents=True, exist_ok=True)
# 整理图标文件
for icon_file in icons_path.rglob('*'):
if icon_file.is_file() and icon_file.suffix in ['.png', '.svg', '.svgz', '.xpm']:
# 确定目标目录
if icon_file.suffix == '.svg':
target_dir = hicolor_dir / 'scalable' / 'apps'
else:
# 根据文件名或尺寸确定目录
size = detect_icon_size(icon_file)
target_dir = hicolor_dir / size / 'apps'
target_dir.mkdir(parents=True, exist_ok=True)
shutil.move(str(icon_file), str(target_dir / icon_file.name))
def fix_binary_permissions(bin_dir: str):
"""修复二进制文件权限"""
import stat
bin_path = Path(bin_dir)
for binary in bin_path.rglob('*'):
if binary.is_file():
# 检查是否为ELF文件
try:
with open(binary, 'rb') as f:
magic = f.read(4)
if magic == b'\x7fELF':
# 添加可执行权限
current_mode = binary.stat().st_mode
binary.chmod(current_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
except:
pass
def fix_project(project_dir: str, validation_report: dict) -> dict:
"""执行完整修复流程"""
fixes_applied = []
# 0. 修复 base/runtime 配置(优先级最高)
# 检测 pak_linyaps.sh 中的变量自引用和空值问题
import subprocess
validate_script = f"{project_dir}/../linglong-project-gen/scripts/validate_pak_script.sh"
if os.path.exists(validate_script):
result = subprocess.run(
[validate_script, project_dir, "--fix"],
capture_output=True, text=True
)
if result.returncode == 2: # 已自动修复
fixes_applied.append('base_runtime_config')
# 0.1 修复 linglong.yaml 中的 base/runtime 字段
yaml_path = f"{project_dir}/templates/linglong.yaml"
if os.path.exists(yaml_path):
with open(yaml_path, 'r') as f:
data = yaml.safe_load(f)
base_fixed = False
runtime_fixed = False
# 修复 base 字段
base_value = data.get('base', '')
if not base_value or '${' in str(base_value) or str(base_value).strip() == '/':
data['base'] = 'org.deepin.base/25.2.2'
base_fixed = True
# 修复 runtime 字段
runtime_value = data.get('runtime', '')
if not runtime_value or '${' in str(runtime_value) or str(runtime_value).strip() == '/':
data['runtime'] = 'org.deepin.runtime.dtk/25.2.2'
runtime_fixed = True
if base_fixed or runtime_fixed:
with open(yaml_path, 'w') as f:
yaml.dump(data, f, default_flow_style=False, allow_unicode=True)
fixes_applied.append('yaml_base_runtime')
# 1. 修复linglong.yaml
if validation_report.get('yaml_validation', {}).get('status') == 'failed':
yaml_path = f"{project_dir}/templates/linglong.yaml"
fix_yaml_indentation(yaml_path)
fix_yaml_required_fields(yaml_path, validation_report['package_info'])
fixes_applied.append('yaml_indentation')
fixes_applied.append('yaml_required_fields')
# 2. 修复desktop文件
if validation_report.get('structure_validation', {}).get('desktop_files', {}).get('status') == 'failed':
desktop_dir = f"{project_dir}/templates/files_res/share/applications"
for desktop in Path(desktop_dir).glob('*.desktop'):
fix_desktop_icon(str(desktop))
fix_desktop_exec(str(desktop), validation_report['package_info']['package_id'])
fixes_applied.append(f'desktop_{desktop.name}')
# 3. 修复图标目录
if validation_report.get('structure_validation', {}).get('icons', {}).get('status') == 'failed':
icons_dir = f"{project_dir}/templates/files_res/share/icons"
fix_icon_directory_structure(icons_dir)
fixes_applied.append('icon_structure')
# 4. 修复二进制权限
if validation_report.get('structure_validation', {}).get('binaries', {}).get('status') == 'failed':
bin_dir = f"{project_dir}/templates/files_res/bin"
fix_binary_permissions(bin_dir)
fixes_applied.append('binary_permissions')
return {
'status': 'success',
'fixes_applied': fixes_applied,
'message': f'Applied {len(fixes_applied)} fixes'
}
{
"status": "success",
"project_dir": "CI_ll_com.example.app",
"fixes_applied": [
"yaml_indentation",
"yaml_required_fields",
"desktop_com.example.app.desktop",
"icon_structure"
],
"details": {
"yaml_indentation": {"before": "2 spaces", "after": "4 spaces"},
"desktop_com.example.app.desktop": {"Icon": "/usr/share/icons/app.png -> app"}
}
}
根据deb包信息和CSV配置,生成完整的玲珑打包工程,包括 linglong.yaml 配置文件和 pak_linyaps.sh 打包脚本。
將 Linux binary release tar 歸檔包轉換為玲瓏(Linglong)應用便捷打包腳本。
从deb包解压后的目录中提取应用资源文件(desktop文件、图标、appdata、补全脚本等), 按照玲珑打包规范整理到 files_res/ 目录结构中。
执行玲珑打包构建测试,验证生成的工程是否可以正常构建, 并运行兼容性检测确保应用能在玲珑环境中正常运行。
解析Debian软件包(.deb)文件,提取元数据信息并解压文件内容, 为后续玲珑打包工程生成提供基础数据。
验证玲珑打包项目目录结构和必要文件的完整性。支持通过JSON配置文件自定义检查规则, 包括目录存在性、文件存在性、通配符匹配数量、脚本可执行权限等。