Compare commits

..

53 Commits

Author SHA1 Message Date
shenmo7192 89d17eb5f1 update src/var/lib/apm/apm/files/bin/ace-init.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-12-19 07:03:45 +00:00
shenmo7192 60ff1c1ec8 fix 报错 2025-12-19 08:34:04 +08:00
shenmo7192 3a8a8e2f14 dummy update 2025-12-19 08:32:41 +08:00
shenmo7192 270fa875f8 修正上游链接 2025-12-18 16:00:02 +08:00
shenmo7192 301079a999 add: apm 上游更新源 2025-12-18 15:56:03 +08:00
shenmo7192 705c16937d update doc 2025-12-18 15:27:12 +08:00
shenmo7192 869d11d351 version bump to 1.1.6 2025-12-18 15:22:18 +08:00
shenmo7192 3b25a62a54 支持info_env功能 2025-12-18 15:21:52 +08:00
shenmo7192 e373ae7bde 修复:在btrfs上convert时无法挂载多层layer 2025-12-11 10:12:04 +08:00
shenmo7192 6abdb10a7c update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-12-09 09:16:14 +00:00
shenmo7192 9b1e435f4f Revert "update src/usr/bin/amber-pm-convert."
This reverts commit 61e747ba088d398c4e6401110803146e203f81aa.
2025-12-09 09:10:29 +00:00
shenmo7192 306416d2e4 update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-12-03 08:27:54 +00:00
shenmo7192 1865d994ce update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-12-03 05:36:35 +00:00
shenmo7192 b6bf96817e bump apm dummy version to 1.1.1
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-28 14:01:32 +00:00
shenmo7192 6cfd4a9931 fix: Can't handle space line
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-28 14:00:05 +00:00
shenmo7192 ddcd6ae421 新增 templates 直通
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-27 08:36:01 +00:00
shenmo7192 b1f72c8984 update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-27 07:12:03 +00:00
shenmo7192 891b9b3f52 update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-27 07:04:09 +00:00
shenmo7192 609f2a051d update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-26 02:46:02 +00:00
shenmo7192 08be97227d update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-26 02:41:56 +00:00
shenmo7192 3a0094f2c3 适配 ACE
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-25 12:10:23 +00:00
shenmo7192 d65c89b9e2 fix: 把错误的版本号传上来了 2025-11-23 20:18:54 +08:00
shenmo7192 866f8490bb fix: can not initialize apm 2025-11-21 15:55:04 +08:00
shenmo7192 35083b569f update README.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-21 07:43:39 +00:00
shenmo7192 3aaae488c8 新增功能: info_layer_override 2025-11-21 15:41:05 +08:00
shenmo7192 4d993ea308 AOSC Compatible : xz-utils
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-21 07:12:29 +00:00
shenmo7192 5affba8f59 bump version to 115 2025-11-21 10:57:12 +08:00
shenmo7192 8b06b2a71f 不再频繁提示NVIDIA信息,添加autopurge相关的内容 2025-11-21 10:56:42 +08:00
shenmo7192 22b7728b24 update src/var/lib/apm/apm/files/feedback.sh.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-20 04:05:13 +00:00
shenmo7192 4a666560d6 修复:无法启动带有空格的应用 2025-11-19 23:45:58 +08:00
shenmo7192 8246cb7d53 update src/usr/bin/apm.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-19 11:54:46 +00:00
shenmo7192 76e6c8c467 update src/usr/bin/apm.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-19 11:46:51 +00:00
shenmo7192 9814c2f659 update README.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-19 11:37:50 +00:00
shenmo7192 23051aa433 修复:无法正确启动feedback 2025-11-19 17:05:11 +08:00
shenmo7192 bff2685771 修复 版本号无法反馈的问题 2025-11-19 16:59:26 +08:00
shenmo7192 513652e980 版本号加-apm 确认是apm 2025-11-19 16:57:43 +08:00
shenmo7192 cd868f1a50 开始支持自动构建,加入安装反馈 2025-11-19 16:56:47 +08:00
shenmo7192 c0d47d6cc9 fix: WPS 无法正确添加模板
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-19 08:42:18 +00:00
shenmo7192 c8df48b958 update README.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-18 04:22:55 +00:00
shenmo7192 4ceb3717dd update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-18 04:21:18 +00:00
shenmo7192 e4d084f2a0 ver bump to 1.1.4
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-17 11:21:16 +00:00
shenmo7192 1271bfc88c update: general-feedback 2025-11-17 16:52:14 +08:00
shenmo7192 9913ec67e7 update: issue template 2025-11-17 16:48:21 +08:00
zeqi ef00ee9e5e !8 2个小修改
* !1 update easter egg
* update easter egg
* 新增本 APM具有超级牛力
* 修改版本号
2025-11-16 13:28:18 +00:00
shenmo7192 720c6fd4f1 update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-14 03:42:24 +00:00
shenmo7192 1a3bafc503 update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-14 03:35:39 +00:00
shenmo7192 5b1dd44a21 update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-14 03:33:48 +00:00
shenmo7192 253198d091 update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-14 03:31:19 +00:00
shenmo7192 362bd8cde2 update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-14 03:20:25 +00:00
shenmo7192 118ed4b31e update src/DEBIAN/control.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-12 04:32:22 +00:00
shenmo7192 9d59f30e08 删除.lock 2025-11-12 12:30:53 +08:00
shenmo7192 6d2ed4a177 支持手动打包 2025-11-12 12:29:11 +08:00
shenmo7192 aaed358b70 update src/usr/bin/amber-pm-convert.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-12 02:53:34 +00:00
22 changed files with 1379 additions and 339 deletions
@@ -0,0 +1,90 @@
name: "📢 常规反馈与问题报告"
description: "报告一个 Bug,提出新功能建议,或咨询使用问题。对于安全问题,请使用专门的安全漏洞报告模板。"
title: "请简要描述反馈内容..."
labels: ["needs-triage"] # 会自动添加此标签,便于筛选
body:
- type: markdown
attributes:
value: |
感谢您花时间提交反馈!为了帮助我们更有效地理解和解决问题,请尽可能详细地填写以下信息。
- type: dropdown
id: feedback-type
attributes:
label: "反馈类型"
description: "请选择最符合您需求的类别。"
options:
- "🐛 Bug 报告"
- "💡 功能请求 / 建议"
- "📚 文档改进"
- "❓ 使用求助"
- "其他"
default: 0
validations:
required: true
- type: input
id: apm-version
attributes:
label: "APM 容器版本 / 镜像 Tag"
description: "您使用的是哪个版本?(例如:v1.2.0, latest, 或提交哈希)"
placeholder: "v1.2.0"
validations:
required: true
- type: textarea
id: description
attributes:
label: "问题描述或建议"
description: "清晰而详细地描述您遇到的问题,或者您希望的新功能是什么。"
placeholder: |
**对于 Bug**
- 发生了什么?
- 您期望的行为是什么?
- 实际发生了什么?
**对于功能请求:**
- 您希望实现什么功能?
- 这个功能解决了什么痛点?
- 是否有其他类似的解决方案可供参考?
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: "复现步骤 / 具体场景"
description: "如果是 Bug,请提供详细的复现步骤。如果是功能请求,请描述您的使用场景。"
placeholder: |
复现步骤:
1. 使用配置 '...'
2. 运行命令 '....'
3. 看到错误 '....'
使用场景:
当我在 [某个特定情况] 下,需要实现 [某个目标],但目前无法做到,因为...
validations:
required: false
- type: textarea
id: environment
attributes:
label: "环境信息"
description: "请提供您的运行环境细节。"
placeholder: |
- 操作系统: (例如: Ubuntu 20.04, macOS Monterey
- Docker 版本: (请输入 `docker version` 的输出)
- Kubernetes 版本(如果适用):
- 其他相关配置:
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: "补充信息"
description: "请添加任何其他有助于解决问题的信息,如日志片段、截图、核心配置文件(请脱敏)等。"
validations:
required: false
@@ -0,0 +1,76 @@
name: "🛡️ 安全漏洞报告"
description: "报告 APM 容器项目中可能存在的安全漏洞。请勿公开披露细节。"
title: "[安全]: "
labels: ["security", "needs-triage"]
body:
- type: markdown
attributes:
value: |
**感谢您对 APM 容器项目安全的关注!**
为了保护我们的用户,我们非常重视负责任的漏洞披露。
**请勿在此表格中描述具体的漏洞细节。** 此 Issue 将作为跟踪入口,后续的敏感信息沟通将通过私有渠道进行。
---
**重要提示:**
* 我们承诺遵循负责任的披露原则。
* 在修复之前公开漏洞细节可能会对其他用户造成风险。
* 我们的安全团队将在收到报告后尽快与您联系。
- type: input
id: contact
attributes:
label: "联系方式"
description: "请提供您的可靠联系方式(例如:电子邮件、Gitee ID 或 GitHub ID),以便我们安全团队的成员与您私聊。"
placeholder: "例如:email@example.com 或 @yourusername"
validations:
required: true
- type: textarea
id: vulnerability-overview
attributes:
label: "漏洞类型/概述"
description: "请在不涉及技术细节的前提下,简要描述您发现的漏洞类型和潜在影响。"
placeholder: |
例如:
- 类型:潜在的容器逃逸风险
- 影响:可能允许攻击者访问宿主机资源
- 组件:与数据收集器相关的某个组件
validations:
required: true
- type: dropdown
id: severity
attributes:
label: "初步严重性评估"
description: "根据您的理解,这个漏洞的潜在严重程度如何?"
options:
- "Critical - 远程代码执行、严重权限提升等"
- "High - 信息泄漏、权限绕过等"
- "Medium - 有限的信息泄漏或本地漏洞"
- "Low - 微小的安全策略规避"
- "尚未评估"
validations:
required: true
- type: input
id: affected-versions
attributes:
label: "受影响的版本"
description: "您是在哪个或哪些版本中发现此问题的?(如果已知)"
placeholder: "例如:v1.2.0, v1.3.0-beta1"
- type: textarea
id: next-steps
attributes:
label: "后续步骤确认"
attributes:
value: |
**您提交此报告后,会发生以下事情:**
1. 此 Issue 将被标记为 `security` 和 `needs-triage`。
2. 项目维护人员会通过您提供的联系方式(而非在此公开评论)与您私下联系。
3. 我们将共同协作调查、验证并修复该漏洞。
4. 修复程序准备就绪后,我们将发布安全更新,并在适当的时候公开致谢。
再次感谢您为保障社区安全所做的负责任的行为!
+291 -60
View File
@@ -1,22 +1,45 @@
# APM 软件包打包流程 # APM 软件包打包流程
本文档为开发者准备,若您只是想从 deb 软件包打包 APM 软件包,您可以通过 `amber-pm-convert`指令进行全自动一键转换 本文档为开发者准备,若您只是想从 deb 软件包打包 APM 软件包,您可以通过 `amber-pm-convert` 指令进行全自动一键转换
通过 `apm search amber-pm- ` 即可搜索到所有可用的 base 列表 通过 `apm search amber-pm-` 即可搜索到所有可用的 base 列表
--- ---
## APM 软件包结构规范 ## APM 软件包结构规范
在阅读前,请确保您对overlayfs有了基本的了解 在阅读前,请确保您对 OverlayFS 有了基本的了解
overlayfs 原理解析:https://www.cnblogs.com/arnoldlu/p/13055501.html
OverlayFS 原理解析:
[https://www.cnblogs.com/arnoldlu/p/13055501.html](https://www.cnblogs.com/arnoldlu/p/13055501.html)
--- ---
## OverlayFS 层叠顺序说明
一个典型的 APM 软件/中层依赖包应当包含以下内容 APM 使用 OverlayFS 来管理软件包的文件系统层级,从上到下的层叠顺序为:
1. **Upperdir**
当前包的可写层:`files/core/`
2. **Info Layer Override**
`info_layer_override` 指定的覆盖层,位于所有依赖层之上
3. **依赖层**
`info` 文件递归解析出的所有依赖包
4. **底层 Runtime**
最基础的运行时环境(如 `amber-pm-bookworm`
这种层叠结构允许上层文件覆盖下层文件,实现灵活、高效的依赖管理与环境定制。
---
## APM 软件包目录结构示例
一个典型的 APM 应用或中层依赖包应当包含以下内容:
``` ```
├── DEBIAN ├── DEBIAN
@@ -35,15 +58,17 @@ overlayfs 原理解析:https://www.cnblogs.com/arnoldlu/p/13055501.html
│ ├── core │ ├── core
│ └── work │ └── work
├── info ├── info
── info_debug ── info_layer_override # 可选
└── info_env # 可选(高级功能)
``` ```
* DEBIAN目录包含了软件包的基本信息和依赖的环境信息 ---
1. 以下是 control 文件的内容 ## DEBIAN 目录说明
包含软件包的基本信息和依赖环境声明。
### control 文件示例
``` ```
Package: eom Package: eom
@@ -53,21 +78,33 @@ Maintainer: APM Converter <apm-convert@spark-app.store>
Depends: amber-pm-bookworm Depends: amber-pm-bookworm
Installed-Size: 45228 Installed-Size: 45228
Description: APM converted package from eom Description: APM converted package from eom
This package was automatically converted from the original deb package. This package was automatically converted from the original deb package.
Based on: amber-pm-bookworm Based on: amber-pm-bookworm
``` ```
Package: 包名。应当唯一。若使用转换器进行转换,默认和原包名一致 字段说明:
Version: 版本号。若使用转换器进行转换,默认在原版本号后加`-apm`
Architecture: 软件包架构。同 dpkg 进行填写即可。若使用转换器进行转换,默认和原包架构一致
Depends: 依赖包。填写直接依赖的base即可
Installed-Size: 安装后的大小。若使用转换器进行转换,会自动填写
Description: 包描述。若使用转换器进行转换,会自动填写
* **Package**
包名,应当唯一。使用转换器时默认与原 deb 包名一致
2. 以下是 postinst 文件内容 * **Version**
软件包版本号,转换器会自动追加 `-apm`
* **Architecture**
架构信息,遵循 dpkg 规范
* **Depends**
直接依赖的 base 包名
* **Installed-Size**
安装后大小,转换器自动计算
* **Description**
软件包描述信息
---
### postinst 文件
``` ```
#!/bin/bash #!/bin/bash
@@ -76,74 +113,268 @@ PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE"
if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then
echo "清理卸载残留" echo "清理卸载残留"
rm -rf "/var/lib/apm/$PACKAGE_NAME" rm -rf "/var/lib/apm/$PACKAGE_NAME"
for username in $(ls /home)
do for username in $(ls /home); do
echo /home/$username if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then
if [ -d "/home/$username/.apm/$PACKAGE_NAME" ] rm -rf "/home/$username/.apm/$PACKAGE_NAME"
then
rm -fr "/home/$username/.apm/$PACKAGE_NAME"
fi fi
done done
else else
echo "非卸载,跳过清理" echo "非卸载,跳过清理"
fi fi
```
若无特殊需求,保持该内容即可,用于卸载时清理残留环境。
---
## /var/lib/apm 目录结构说明
该目录包含 APM 软件包的运行环境与元数据。
### 必须目录
* **files/**
* `core/`upperdir,可写层
* `work/`OverlayFS 工作目录
* **info**
* 声明直接依赖的 base 包
* 支持多层递归解析
### 可选目录 / 文件
* **entries/**
* `applications/``.desktop` 文件
* `doc/`:文档
* `glib-2.0/`GLib 相关文件
* `man/`:手册页
> ⚠ `.desktop` 文件中 **必须** 添加:
>
> ```
> X-APM-APPID=包名
> ```
>
> 以允许软件管理器正确识别和管理应用。
---
## info 文件说明(依赖解析)
`info` 文件用于声明当前包直接依赖的 base 包,每行一个包名:
``` ```
若无特殊需求,内容保持一致即可,用于在卸载软件包后清理环境 amber-pm-bookworm-spark-wine10
```
* /var/lib/apm 包含了APM 软件容器的文件和信息 APM 会递归解析该 base 的 `info` 文件,直到找到最底层 runtime(如 `amber-pm-bookworm`)。
> 使用多层依赖并非强制,但合理拆分 base 能显著减小包体积。
> 可用的 base 列表可通过:
>
> ```
> apm search amber-pm-
> ```
>
> 查看。
---
软件应当被放置在 /var/lib/apm/软件包名/ 处 ## info_layer_override 文件(覆盖层)
此处有两个目录,两个文件
entries 可选,包含了软件包需要被放到 /usr/share/ 的文件,如 desktop icon 等 `info_layer_override` 是一个可选文件,用于在**所有依赖层之上**插入额外覆盖层。
files 必须,包含了软件包的 upperdir 和 workdir
info 必须,包含了直接依赖的base信息。若应用使用了多层的依赖,会一层一层寻找info信息,直到找到底层依赖
info_debug 可选,包含了打包时解析的依赖信息
entries下的内容同软件需要放置到 /usr/share/ 下的内容 ### 使用场景
> 注意: .desktop 文件应当新加一行 X-APM-APPID=包名 来允许软件管理器管理 1. 覆盖依赖中的特定库版本(如 mesa)
2. 覆盖默认配置文件
3. 提供特殊运行环境
files的内容请见下一节 ### 规则说明
## APM upperdir 制作流程 * 语法与 `info` 完全一致
* 每行一个包名
* 层级位置:
以下为手动制作 upperdir 的流程 ```
upperdir
info_layer_override
info 递归依赖
```
首先,安装 apm 并使用`sudo apm install` 安装你所需要的 base ### 示例
随后,新建三个文件夹,corework 和 ace-env ,执行 `info`
`sudo mount -t overlay overlay -o lowerdir='/var/lib/apm/apm/files/ace-env/var/lib/apm/base包的包名(如amber-pm-trixie/files/ace-env',upperdir=core/,workdir=work/ ./ace-env` ```
amber-pm-bookworm
```
随后chroot进入进行安装操作,直接进行 apt install 或者其他都可以,完成后解除挂载 ./ace-env `info_layer_override`
你便得到了: ```
amber-pm-bookworm-mesa
```
* core: 保存新增文件 最终 lowerdir 顺序:
* work: 保存变更信息
```
amber-pm-bookworm-mesa:amber-pm-bookworm
```
需把这两个目录重新拥有并权限换成755后放入对应的目录进行 apm 打包 ---
你也可以测试一下刚刚打包的软件 ## info_env(环境变量层 · 高级功能)
fuse-overlayfs -o lowerdir='/var/lib/apm/apm/files/ace-env/var/lib/apm/base包的包名(如amber-pm-trixie/files/ace-env',upperdir=core/,workdir=work/ ./ace-env `info_env` 是一个 **可选的高级特性**,用于为 APM 容器运行时提供**分层的环境变量配置能力**。
即可只读挂载。这一步 apm run 包名 会帮你做好。 ### 功能概述
> apm run 包名: 寻找 /var/lib/apm/包名/是否存在。若存在,根据info文件合成 fuser-overlayfs 参数进行挂载,随后用ACE工具chroot进入进行启动 * 为软件包及其依赖提供环境变量
* 支持 **多层叠加**
* **上层自动覆盖下层**
* 与 OverlayFS 层级顺序完全一致
* 不执行 shell 代码,仅解析键值对,安全可靠
./ace-run 即可进入,可以尝试启动一下刚刚安装的应用 ---
## APM 打包 ### info_env 文件位置
使用 `dpkg-deb --build 软件包目录 输出目录` 即可进行打包 ```
/var/lib/apm/<包名>/info_env
```
## APM 底层 Base Runtime 的构建 ---
### info_env 应用顺序(重要)
环境变量的加载顺序为:
1. 底层 runtime 的 `info_env`
2. 中间依赖包的 `info_env`
3. 当前包的 `info_env`
4. `info_layer_override` 中包的 `info_env`(最高优先级)
**后加载的变量会覆盖之前的同名变量。**
---
### info_env 文件格式
每行一条环境变量定义:
```
KEY=VALUE
```
示例:
```
QT_QPA_PLATFORM=dxcb;xcb
LANG=zh_CN.UTF-8
XMODIFIERS="@im=fcitx"
PATH="/custom/bin:$PATH"
```
#### 规则说明
* 支持分号 `;`
* 支持带引号的值
* 支持引用已有环境变量(如 `$PATH`
* 支持注释行(`#`
* 不允许执行任何 shell 语句
❌ 以下内容将被忽略:
```
export A=1
rm -rf /
$(whoami)
```
---
### 使用场景示例
* 指定 Qt / GTK 平台插件
* 设置输入法变量
* 调整运行时 PATH / LD_LIBRARY_PATH
* 为特定应用注入兼容性环境变量
---
## APM upperdir 制作流程(手动)
1. 安装 APM 并安装所需 base
```bash
sudo apm install amber-pm-xxx
```
2. 创建目录结构:
```bash
mkdir -p core work ace-env
```
3. 挂载 OverlayFS
```bash
sudo mount -t overlay overlay \
-o lowerdir='/var/lib/apm/apm/files/ace-env/var/lib/apm/amber-pm-xxx/files/ace-env',upperdir=core/,workdir=work/ \
./ace-env
```
4. chroot 进入 `ace-env` 进行安装
5. 卸载并打包
---
## APM 软件包测试
```bash
fuse-overlayfs -o lowerdir='...',upperdir=core/,workdir=work/ ./ace-env
```
或直接使用:
```bash
apm run 包名
```
APM 会自动完成:
* 解析 `info` / `info_layer_override`
* 应用 `info_env`
* 构建 OverlayFS
* 进入容器并运行应用
---
## APM 软件包打包
```bash
dpkg-deb --build 软件包目录 输出目录
```
---
## APM 底层 Base Runtime 构建
详见:
[https://gitee.com/amber-ce/amber-pm-common](https://gitee.com/amber-ce/amber-pm-common)
---
### 备注
APM 的打包工具与转换器会自动处理绝大多数复杂操作。
手动打包与 `info_env` 主要用于 **特殊运行环境、深度定制或调试用途**
详见 https://gitee.com/amber-ce/amber-pm-common
+11 -2
View File
@@ -20,11 +20,16 @@ APM 目前提供 Debian 12/13 与 deepin 25 基础环境,支持将适配以上
前往右侧的 [发行版](https://gitee.com/amber-ce/amber-pm/releases/) 即可下载体验 前往右侧的 [发行版](https://gitee.com/amber-ce/amber-pm/releases/) 即可下载体验
目前支持 Debian 10+ , Arch Linux , fedora 42/43, openSUSE(测试) ,deepin/UOS 20+ , Ubuntu 20+ , 银河麒麟v10sp1openkylin 完成安装后,根据您的 CPU 架构选择对应的网页商店使用
[![输入图片说明](https://foruda.gitee.com/images/1762931968047152487/8318e890_4915358.png "apm-webstore-x86-zh-light.png")](https://erotica.spark-app.store/amd64-apm/)
[![输入图片说明](https://foruda.gitee.com/images/1762931903886978407/7ba50cd5_4915358.png "apm-webstore-arm-zh-light.png")](https://erotica.spark-app.store/arm64-apm/)
目前 apm 应用支持 Debian 10+ , Arch Linux , fedora 42/43, openSUSE(测试) ,deepin/UOS 20+ , Ubuntu 20+ , 银河麒麟v10sp1openkylin
## 使用方法 ## 使用方法
``` ```
APM - Amber Package Manager 1.0.10 APM - Amber Package Manager
Usage: Usage:
apm [COMMAND] [OPTIONS] [PACKAGES...] apm [COMMAND] [OPTIONS] [PACKAGES...]
@@ -86,6 +91,10 @@ Commands:
详见 [Packaging-demo](Packaging-demo)。 详见 [Packaging-demo](Packaging-demo)。
> 1.1.5+ 版本支持了覆盖 base 功能,相见 https://gitee.com/amber-ce/amber-pm/blob/master/Packaging-demo/README.md#info_layer_override-%E6%96%87%E4%BB%B6
## APM 构建 Tips ## APM 构建 Tips
> 请 `cp -vr src pkg` 来创建一个准备配置的环境,随后 `./build.sh pkg` 即可进行进一步的打包操作
APM 使用了特殊的精简版 AmberCE 兼容环境,相关的 Tips 见 [Tips](tips.md)。 APM 使用了特殊的精简版 AmberCE 兼容环境,相关的 Tips 见 [Tips](tips.md)。
+1 -1
View File
@@ -1,5 +1,5 @@
Package: apm Package: apm
Version: 1.1 Version: 1.1.2
Maintainer: shenmo <jifengshenmo@outlook.com> Maintainer: shenmo <jifengshenmo@outlook.com>
Priority: optional Priority: optional
Section: utils Section: utils
+2 -2
View File
@@ -30,7 +30,7 @@ linkDir() {
ensureTargetDir "$targetFile" ensureTargetDir "$targetFile"
sourceFile=$(realpath --relative-to="$(dirname $targetFile)" "$sourceFile" ) sourceFile=$(realpath --relative-to="$(dirname $targetFile)" "$sourceFile" )
if [ ! -e ${targetFile} ];then if [ ! -e "${targetFile}" ];then
ln -sv "$sourceFile" "$targetFile" ln -sv "$sourceFile" "$targetFile"
fi fi
done done
@@ -98,7 +98,7 @@ function exec_link_clean(){
find /usr/share/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/share/help -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/help -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/share/locale -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/locale -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/lib/$(gcc -dumpmachine)/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & # find /usr/lib/$(gcc -dumpmachine)/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/lib/mozilla/plugins -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/lib/mozilla/plugins -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/share/polkit-1/actions -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/polkit-1/actions -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/share/fonts -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/fonts -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
+1
View File
@@ -0,0 +1 @@
@VERSION@=1.1.6
Executable
+92
View File
@@ -0,0 +1,92 @@
#!/usr/bin/env bash
########################################
# 配置部分
########################################
config_file="build.config" # 配置文件路径
if [[ -z "$1" ]];then
echo "Need TARGET DIR"
exit
fi
target_dir="${1}" # 要处理的目标目录
########################################
# 读取 ace-base.config 生成替换字典
########################################
declare -A replacements
while IFS= read -r line; do
# 跳过空行
[[ -z "$line" ]] && continue
# 匹配类似 @PKG_NAME@=amber-ce-bookworm 的格式
if [[ "$line" =~ ^@(.*)@=(.*)$ ]]; then
key="${BASH_REMATCH[1]}"
val="${BASH_REMATCH[2]}"
replacements["$key"]="$val"
fi
done < "$config_file"
########################################
# 第一步:文本文件内容替换
########################################
# 定义一个函数来判断文件是否是文本文件(示例仅供参考)
is_text_file() {
local f="$1"
file --mime-type "$f" | grep -q "text/"
}
# 查找所有文件,逐一判断是否文本类型,如果是则进行内容替换
find "$target_dir" -type f -print0 | while IFS= read -r -d '' file; do
if is_text_file "$file"; then
for key in "${!replacements[@]}"; do
# 用 sed 对文件内容进行替换
sed -i "s|@$key@|${replacements[$key]}|g" "$file"
done
fi
done
########################################
# 第二步:先重命名文件
########################################
find "$target_dir" -type f -print0 | while IFS= read -r -d '' file; do
# 拆分目录和文件名
dir_path="$(dirname "$file")"
filename="$(basename "$file")"
newfilename="$filename"
for key in "${!replacements[@]}"; do
newfilename="${newfilename//@$key@/${replacements[$key]}}"
done
# 如果新文件名和原文件名不同,则执行重命名
if [[ "$newfilename" != "$filename" ]]; then
mv -v "$file" "$dir_path/$newfilename"
fi
done
########################################
# 第三步:再重命名目录(由浅到深)
########################################
# 先按目录层级进行排序(层数少的先处理)
# awk -F/ '{print NF, $0}' 会将路径按 / 分割并统计层数,然后 sort -n 升序,层数越小越先处理
find "$target_dir" -type d | awk -F/ '{print NF, $0}' | sort -n | cut -d' ' -f2- | while IFS= read -r dir; do
# 如果要连同最顶层目录一起改名,可以保留;若不需要改最顶层,可以加条件跳过
# [ "$dir" = "$target_dir" ] && continue # 如需跳过顶层可取消注释
parent_path="$(dirname "$dir")"
dirname_only="$(basename "$dir")"
newdirname="$dirname_only"
for key in "${!replacements[@]}"; do
newdirname="${newdirname//@$key@/${replacements[$key]}}"
done
# 需要改名则执行
if [[ "$newdirname" != "$dirname_only" ]]; then
mv -v "$dir" "$parent_path/$newdirname"
fi
done
echo "处理完成!"
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
HERE=$(dirname $(realpath $0))
rm -fr pkg
cp -r src pkg
${HERE}/build.sh pkg
fakeroot dpkg-deb -b -Z xz pkg/ .
rm -fr pkg
+3 -3
View File
@@ -1,10 +1,10 @@
Package: apm Package: apm
Source: amber-ce Source: amber-ce
Version: 1.1.3 Version: @VERSION@
Architecture: amd64 Architecture: amd64
Maintainer: shenmo <shenmo@spark-app.store> Maintainer: shenmo <shenmo@spark-app.store>
Installed-Size: 48992 Installed-Size: 49000
Depends: bubblewrap, flatpak, policykit-1 | pkexec | polkit-1 | polkit, systemd, procps,coreutils,fuse-overlayfs,xz-utils,libnotify-bin,curl,xdg-user-dirs,bash Depends: bubblewrap, flatpak, policykit-1 | pkexec | polkit-1 | polkit, systemd, procps,coreutils,fuse-overlayfs,xz-utils | xz,libnotify-bin,curl,xdg-user-dirs,bash
Recommends: dpkg, fakeroot, busybox Recommends: dpkg, fakeroot, busybox
Section: misc Section: misc
Conflicts: ace-host-integration Conflicts: ace-host-integration
+2
View File
@@ -13,6 +13,8 @@ systemctl restart apparmor.service || true
if [ -f /usr/lib/sysctl.d/apm.conf ];then if [ -f /usr/lib/sysctl.d/apm.conf ];then
sysctl -p /usr/lib/sysctl.d/apm.conf sysctl -p /usr/lib/sysctl.d/apm.conf
fi fi
# Send statistics data
/var/lib/apm/apm/files/feedback.sh &
;; ;;
+2
View File
@@ -0,0 +1,2 @@
deb [signed-by=/etc/apt/trusted.gpg.d/apm.gpg] https://d.spark-app.store/apm-deb-source /
# 上面这行配置可在4.1.2+版本普及后启用,可以做到分不同目录
Binary file not shown.
+563 -198
View File
@@ -1,49 +1,55 @@
#!/bin/bash #!/bin/bash
# APM软件包转换器 - 将DEB包转换为APM格式 # APM软件包转换器 - 将DEB包转换为APM格式
log.warn() { echo -e "[\e[33mWARN\e[0m]: \e[1m$*\e[0m"; } log.warn() { echo -e "[\e[33mWARN\e[0m]: \e[1m$*\e[0m"; }
log.error() { echo -e "[\e[31mERROR\e[0m]: \e[1m$*\e[0m"; } log.error() { echo -e "[\e[31mERROR\e[0m]: \e[1m$*\e[0m"; }
log.info() { echo -e "[\e[96mINFO\e[0m]: \e[1m$*\e[0m"; } log.info() { echo -e "[\e[96mINFO\e[0m]: \e[1m$*\e[0m"; }
log.debug() { echo -e "[\e[32mDEBUG\e[0m]: \e[1m$*\e[0m"; } log.debug() { echo -e "[\e[32mDEBUG\e[0m]: \e[1m$*\e[0m"; }
SCRIPT_NAME=$(basename "$0") SCRIPT_NAME=$(basename "$0")
if ! command -v dpkg > /dev/null ;then if ! command -v dpkg > /dev/null ; then
log.error "若想使用APM软件包转换器,您需先安装dpkg" log.error "若想使用APM软件包转换器,您需先安装dpkg"
exit 1 exit 1
fi fi
# 显示用法信息 # 显示用法信息
usage() { usage() {
echo "用法: $SCRIPT_NAME --base <basename> [--base <basename> ...] <deb文件路径> [--pkgname <包名>] [--version <版本号>]" echo "用法: $SCRIPT_NAME [--manual] --base <basename> [--base <basename> ...] <deb文件路径>"
echo " 或者在手动模式下不传入 DEB 文件: $SCRIPT_NAME --manual --base <basename> [--base <basename> ...]"
echo "" echo ""
echo "参数说明:" echo "参数说明:"
echo " --basename 必填参数,指定基础环境名称,可多次使用指定多个基础环境" echo " --manual 启用手动模式:融合挂载后打开交互 shell,退出 shell 后脚本继续"
echo " deb文件路径 必填参数,要转换的DEB文件路径" echo " --basename 必填参数(非手动模式下),指定基础环境名称,可多次使用"
echo " deb文件路径 要转换的DEB文件路径(非手动且非空模式下必填)"
echo " --pkgname 可选参数,指定新包的包名(默认使用原DEB包名)" echo " --pkgname 可选参数,指定新包的包名(默认使用原DEB包名)"
echo " --version 可选参数,指定新包的版本号(默认在原版本后追加'-apm'" echo " --version 可选参数,指定新包的版本号(默认在原版本后追加'-apm'"
echo "" echo ""
echo "示例:" echo "示例:"
echo " $SCRIPT_NAME --base amber-pm-trixie /path/to/package.deb" echo " $SCRIPT_NAME --base amber-pm-trixie /path/to/package.deb"
echo " $SCRIPT_NAME --base amber-pm-bookworm-spark-wine /path/to/package.deb --pkgname new-pkg --version 1.0.0" echo " $SCRIPT_NAME --manual --base amber-pm-trixie # 只融合挂载并进入手动 shell"
echo "最下层的base在最后面,从上到下写base" echo " $SCRIPT_NAME --manual --base amber-pm-trixie --pkgname newpkg --version 1.2.3 /path/to/package.deb"
echo ""
echo "说明: 最下层的base在最后面,从上到下写base"
} }
# 检查参数数量
if [ $# -lt 3 ]; then
log.error "错误:参数不足"
usage
exit 1
fi
# 解析参数 # 解析参数
BASENAMES=() # 改为数组存储多个base BASENAMES=() # 存放实际用于构建 overlay 的 base(可能会被递归添加)
BASENAMES_ORIG=() # 存放用户原始输入的 base 列表(用于 control 中 Depends 等)
DEB_PATH="" DEB_PATH=""
PKGNAME="" PKGNAME=""
VERSION="" VERSION=""
MANUAL_MODE=false
# 参数解析 # 简单参数解析(顺序敏感)
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
case $1 in case "$1" in
--base) --base)
if [ -z "$2" ]; then
log.error "--base 后需要跟名称"
usage
exit 1
fi
BASENAMES+=("$2") BASENAMES+=("$2")
BASENAMES_ORIG+=("$2") BASENAMES_ORIG+=("$2")
shift 2 shift 2
@@ -56,12 +62,22 @@ while [ $# -gt 0 ]; do
VERSION="$2" VERSION="$2"
shift 2 shift 2
;; ;;
--manual)
MANUAL_MODE=true
shift
;;
-*)
log.error "未知选项: $1"
usage
exit 1
;;
*) *)
if [ -z "$DEB_PATH" ] && [ -f "$1" ]; then # 非选项,视为 DEB 路径(只接受第一个非选项作为 DEB)
if [ -z "$DEB_PATH" ]; then
DEB_PATH="$1" DEB_PATH="$1"
shift shift
else else
log.error "错误:未知参数或无效的DEB文件路径: $1" log.error "未知参数或多余的参数: $1"
usage usage
exit 1 exit 1
fi fi
@@ -69,31 +85,45 @@ while [ $# -gt 0 ]; do
esac esac
done done
# 检查必填参数 # 基本参数验证:
if [ ${#BASENAMES[@]} -eq 0 ] || [ -z "$DEB_PATH" ]; then # 如果不是手动模式,则至少需要一个 --base 和一个 deb 文件
log.error "错误:至少需要一个--basename参数,且DEB文件路径为必填" if [ "$MANUAL_MODE" = false ]; then
usage if [ ${#BASENAMES[@]} -eq 0 ] || [ -z "$DEB_PATH" ]; then
exit 1 log.error "错误:非手动模式下至少需要一个 --base 参数 且 必须提供 DEB 文件路径"
usage
exit 1
fi
else
# 手动模式下允许没有 DEB_FILE,但仍然要有至少一个 base
if [ ${#BASENAMES[@]} -eq 0 ]; then
log.error "错误:手动模式下仍需提供至少一个 --base 参数"
usage
exit 1
fi
fi fi
# 检查DEB文件是否存在 # 如果传入了 DEB_PATH检查文件是否存在
if [ ! -f "$DEB_PATH" ]; then if [ -n "$DEB_PATH" ] && [ ! -f "$DEB_PATH" ]; then
log.error "错误:DEB文件不存在: $DEB_PATH" log.error "错误:DEB文件不存在: $DEB_PATH"
exit 1 exit 1
fi fi
log.info "开始转换DEB包: $DEB_PATH" log.info "开始转换(手动模式: $MANUAL_MODE"
log.info "基础环境数量: ${#BASENAMES[@]}" log.info "基础环境数量: ${#BASENAMES_ORIG[@]}"
for i in "${!BASENAMES[@]}"; do for i in "${!BASENAMES_ORIG[@]}"; do
log.info " 基础环境 $((i+1)): ${BASENAMES[$i]}" log.info " 原始基础环境 $((i+1)): ${BASENAMES_ORIG[$i]}"
done done
if [ -n "$DEB_PATH" ]; then
log.info "目标 DEB: $DEB_PATH"
else
log.info "未提供 DEB 文件,处于纯手动模式(手动修改/安装/打包)"
fi
# 1. 创建临时工作目录 # 1. 创建临时工作目录
CRAFT_DIR="$HOME/apm-craft-$$" CRAFT_DIR="$HOME/apm-craft-$$"
log.info "创建临时工作目录: $CRAFT_DIR" log.info "创建临时工作目录: $CRAFT_DIR"
mkdir -p "$CRAFT_DIR"/{core,work,mergedir,modified_deb} mkdir -p "$CRAFT_DIR"/{core,work,mergedir,modified_deb,extract,new-pkg}
# 设置环境变量
export CRAFT_DIR export CRAFT_DIR
# 检查是否已挂载,避免重复挂载 # 检查是否已挂载,避免重复挂载
@@ -117,21 +147,27 @@ cleanup() {
# 设置退出时清理 # 设置退出时清理
trap cleanup EXIT trap cleanup EXIT
# 递归获取info文件中的依赖 # 递归获取info文件中的依赖 (会把新依赖追加到 BASENAMES 数组中)
get_recursive_basenames() { get_recursive_basenames() {
local basename="$1" local basename="$1"
# 注意:根据之前脚本结构,info 存放在 /var/lib/apm/apm/files/ace-env/var/lib/apm/<basename>/info
local base_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/$basename" local base_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/$basename"
local info_file="$base_dir/info" local info_file="$base_dir/info"
if [ -f "$info_file" ]; then if [ -f "$info_file" ]; then
log.info "读取info文件: $info_file" log.info "读取info文件: $info_file"
while IFS= read -r base; do while IFS= read -r base; do
# 跳过空行
[[ -z "$base" ]] && continue [[ -z "$base" ]] && continue
# 如果依赖的base没有被记录过,则递归添加 # 如果依赖的 base 没有被记录过,则递归添加
if [[ ! " ${BASENAMES[*]} " =~ " $base " ]]; then local found=false
for existing in "${BASENAMES[@]}"; do
if [ "$existing" = "$base" ]; then
found=true
break
fi
done
if [ "$found" = false ]; then
BASENAMES+=("$base") BASENAMES+=("$base")
# 递归获取依赖
get_recursive_basenames "$base" get_recursive_basenames "$base"
fi fi
done < "$info_file" done < "$info_file"
@@ -140,43 +176,48 @@ get_recursive_basenames() {
fi fi
} }
# 递归获取所有基础环境 # 递归获取所有基础环境(从用户输入的 base 开始)
for BASE in "${BASENAMES[@]}"; do for BASE in "${BASENAMES[@]}"; do
get_recursive_basenames "$BASE" get_recursive_basenames "$BASE"
done done
# 检查DEB文件 # 如果用户传了 DEB,则读取原包信息(否则跳过)
log.info "检查原DEB包信息..." if [ -n "$DEB_PATH" ]; then
ORIG_PKGNAME=$(dpkg -f "$DEB_PATH" Package) log.info "检查原DEB包信息..."
ORIG_VERSION=$(dpkg -f "$DEB_PATH" Version) ORIG_PKGNAME=$(dpkg -f "$DEB_PATH" Package 2>/dev/null || echo "")
ORIG_ARCH=$(dpkg -f "$DEB_PATH" Architecture) ORIG_VERSION=$(dpkg -f "$DEB_PATH" Version 2>/dev/null || echo "")
ORIG_ARCH=$(dpkg -f "$DEB_PATH" Architecture 2>/dev/null || echo "")
log.info "原包名: $ORIG_PKGNAME" log.info "原包名: ${ORIG_PKGNAME:-未知}"
log.info "原版本: $ORIG_VERSION" log.info "原版本: ${ORIG_VERSION:-未知}"
log.info "原架构: $ORIG_ARCH" log.info "原架构: ${ORIG_ARCH:-unknown}"
else
ORIG_PKGNAME=""
ORIG_VERSION=""
ORIG_ARCH="$(dpkg --print-architecture 2>/dev/null || echo "unknown")"
fi
# 设置新包名和版本 # 设置新包名和版本(若手动模式且未指定,则稍后询问)
NEW_PKGNAME="${PKGNAME:-$ORIG_PKGNAME}" NEW_PKGNAME="${PKGNAME:-${ORIG_PKGNAME}}"
NEW_VERSION="${VERSION:-${ORIG_VERSION}-apm}" NEW_VERSION="${VERSION:-${ORIG_VERSION}-apm}"
log.info "新包名: $NEW_PKGNAME" log.info "将使用的新包名: ${NEW_PKGNAME:-<未指定>}"
log.info "新版本: $NEW_VERSION" log.info "将使用的新版本: ${NEW_VERSION:-<未指定>}"
log.info "架构: $ORIG_ARCH" log.info "使用的架构: $ORIG_ARCH"
# 2. 构建lowerdir路径(多个base按顺序叠放) # 2. 构建 lowerdir 路径(多个 base 按顺序叠放)
log.info "构建overlay lowerdir路径..." log.info "构建 overlay lowerdir 路径..."
LOWERDIRS=() LOWERDIRS=()
# 按顺序处理每个base(从第一个到最后一个,最后一个在最底层)
for BASENAME in "${BASENAMES[@]}"; do for BASENAME in "${BASENAMES[@]}"; do
ACE_ENV_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/ace-env" ACE_ENV_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/ace-env"
CORE_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/core" CORE_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/core"
if [ -d "$ACE_ENV_PATH" ]; then if [ -d "$ACE_ENV_PATH" ]; then
log.info "使用ace-env路径: $ACE_ENV_PATH" log.info "使用 ace-env 路径: $ACE_ENV_PATH"
LOWERDIRS+=("$ACE_ENV_PATH") LOWERDIRS+=("$ACE_ENV_PATH")
elif [ -d "$CORE_PATH" ]; then elif [ -d "$CORE_PATH" ]; then
log.info "使用core路径: $CORE_PATH" log.info "使用 core 路径: $CORE_PATH"
LOWERDIRS+=("$CORE_PATH") LOWERDIRS+=("$CORE_PATH")
else else
log.error "错误:基础环境路径不存在: $BASENAME" log.error "错误:基础环境路径不存在: $BASENAME"
@@ -186,142 +227,449 @@ for BASENAME in "${BASENAMES[@]}"; do
fi fi
done done
# 将lowerdirs数组用冒号连接 # 将 lowerdirs 数组用冒号连接
LOWERDIR=$(IFS=:; echo "${LOWERDIRS[*]}") LOWERDIR=$(IFS=:; echo "${LOWERDIRS[*]}")
log.debug "最终lowerdir: $LOWERDIR" log.debug "最终 lowerdir: $LOWERDIR"
# 4. 进行融合挂载 # 3. 进行融合挂载
log.info "正在进行融合挂载..." log.info "正在进行融合挂载..."
sudo fuse-overlayfs \
sudo mount -t overlay overlay \
-o "lowerdir=$LOWERDIR,upperdir=$CRAFT_DIR/core/,workdir=$CRAFT_DIR/work/" \ -o "lowerdir=$LOWERDIR,upperdir=$CRAFT_DIR/core/,workdir=$CRAFT_DIR/work/" \
"$CRAFT_DIR/mergedir" "$CRAFT_DIR/mergedir"
log.info "挂载完成" if ! mountpoint -q "$CRAFT_DIR/mergedir"; then
log.error "错误:融合挂载失败"
# 5. 在融合环境中安装修改后的DEB包
log.info "在融合环境中测试安装DEB包..."
# 更新包列表
export chrootEnvPath="$CRAFT_DIR/mergedir"
sudo -E /var/lib/apm/apm/files/ace-run-pkg aptss update
# 首先进行dry-run检查
log.info "进行安装前检查..."
if ! sudo -E /var/lib/apm/apm/files/ace-run-pkg aptss install "$DEB_PATH" --dry-run; then
log.error "错误:安装前检查失败,DEB包可能无法在基础环境中安装"
log.error "请检查依赖关系或基础环境是否兼容"
exit 1 exit 1
fi fi
log.info "安装前检查通过,准备实际安装..." log.info "挂载完成: $CRAFT_DIR/mergedir"
# 6. 提取并修改DEB包 # 导出 chrootEnvPath 以便 ace-run-pkg 使用(并在需要时传递给 sudo -E)
log.info "提取并修改原DEB包..." export chrootEnvPath="$CRAFT_DIR/mergedir"
EXTRACT_DIR="$CRAFT_DIR/extract" log.debug "已导出 chrootEnvPath=$chrootEnvPath"
MODIFIED_DEB_DIR="$CRAFT_DIR/modified_deb"
mkdir -p "$EXTRACT_DIR"
mkdir -p "$MODIFIED_DEB_DIR/DEBIAN"
# 解压DEB包 # 如果在手动模式下,立即打开交互 shell 并在退出后继续脚本
dpkg -x "$DEB_PATH" "$EXTRACT_DIR" if [ "$MANUAL_MODE" = true ]; then
dpkg -e "$DEB_PATH" "$MODIFIED_DEB_DIR/DEBIAN" log.info "进入手动模式:将在融合挂载环境中打开交互 shell(使用 ace-run-pkg)。"
log.info "在 shell 中,您可以手动修改、测试安装或进行其他操作。退出 shell 后脚本将继续。"
# 处理.desktop文件 # 启动交互 shell,保留环境变量(使用 sudo -E)
DESKTOP_MODIFIED=false sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || {
find "$EXTRACT_DIR" -name "*.desktop" | while read -r desktop_file; do log.warn "ace-run-pkg shell 退出或出现错误,继续脚本..."
log.info "处理桌面文件: $desktop_file" }
busybox dos2unix $desktop_file log.info "用户已退出手动 shell,脚本将继续。"
DESKTOP_MODIFIED=true # 如果没有 DEB,询问是否要进行后续打包(允许返回 shell)
if [ -z "$DEB_PATH" ]; then
# 在Exec和TryExec行前追加 "apm run $NEW_PKGNAME" while true; do
# 处理Exec行 echo ""
if grep -q '^Exec=' "$desktop_file"; then read -r -p "未提供 DEB 文件。是否现在进行新 APM 包的自动打包? (y = 打包, r = 返回 shell, n = 跳过打包) [y/r/n]: " yn
sed -i 's/^Exec=\(.*\)$/Exec=apm run '"$NEW_PKGNAME"' \1/' "$desktop_file" case "$yn" in
y|Y)
# 如果缺少包名或版本,交互询问
if [ -z "$NEW_PKGNAME" ]; then
read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME
fi
if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then
read -r -p "请输入要创建的版本 (Version): " NEW_VERSION
fi
break
;;
r|R)
log.info "返回交互 shell(使用 ace-run-pkg)。退出 shell 后再次询问。"
sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || true
;;
n|N)
log.info "跳过自动打包。脚本结束。"
exit 0
;;
*)
echo "请输入 y, r, 或 n。"
;;
esac
done
fi fi
# 处理TryExec行 - 直接删除
if grep -q '^TryExec=' "$desktop_file"; then
sed -i '/^TryExec=/d' "$desktop_file"
log.info "已删除TryExec行"
fi fi
# 处理Icon路径 # 到这里:非手动模式或手动模式退出后继续(如果是非手动并且有 DEB,继续原本流程)
icon_line=$(grep "^Icon=" "$desktop_file")
if [[ "$icon_line" == "Icon=/"* ]]; then # 函数:查找并处理符号链接,返回实际文件路径
sed -i 's|^Icon=/|Icon=/var/lib/apm/apm/files/ace-env/var/lib/apm/'"$NEW_PKGNAME"'/files/core/|' "$desktop_file" resolve_symlink() {
local file="$1"
local target_dir="$2"
if [ -L "$file" ]; then
# 获取符号链接目标
local target=$(readlink "$file")
# 如果目标是绝对路径,则在目标目录中查找
if [[ "$target" == /* ]]; then
local resolved_path="$target_dir${target}"
if [ -f "$resolved_path" ]; then
echo "$resolved_path"
return 0
fi
else
# 相对路径,在符号链接所在目录解析
local link_dir=$(dirname "$file")
local resolved_path="$link_dir/$target"
if [ -f "$resolved_path" ]; then
echo "$resolved_path"
return 0
fi
fi
fi fi
# 添加X-APM-APPID # 如果不是符号链接或解析失败,返回原文件
echo "$file"
}
# 函数:交互式选择文件复制到entries目录(用于手动模式无DEB情况)
# 函数:交互式选择文件复制到entries目录(用于手动模式无DEB情况)
interactive_copy_entries() {
local core_dir="$CRAFT_DIR/core"
local entries_dir="$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries"
log.info "开始交互式选择文件复制到 entries 目录..."
mkdir -p "$entries_dir/applications" "$entries_dir/icons"
# 查找桌面文件(保留完整路径)
local desktop_files=()
while IFS= read -r -d '' file; do
[[ -f "$file" ]] && desktop_files+=("$file")
done < <(find "$core_dir/usr/share" -name "*.desktop" -print0 2>/dev/null || true)
# 查找图标文件(保留完整路径)
local icon_files=()
while IFS= read -r -d '' file; do
[[ -f "$file" ]] && icon_files+=("$file")
done < <(find "$core_dir/usr/share" \( -name "*.png" -o -name "*.svg" -o -name "*.xpm" \) -print0 2>/dev/null || true)
# 处理桌面文件
if [ ${#desktop_files[@]} -gt 0 ]; then
log.info "找到 ${#desktop_files[@]} 个桌面文件:"
for i in "${!desktop_files[@]}"; do
local file="${desktop_files[$i]}"
# 显示完整路径(相对于 core_dir)
local relative_path="${file#$core_dir}"
echo " $((i+1)). $relative_path"
# 检查是否是符号链接
if [ -L "$file" ]; then
local target=$(readlink "$file")
echo " → 符号链接指向: $target"
# 解析符号链接获取实际文件
local resolved_file=$(resolve_symlink "$file" "$core_dir")
if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then
local resolved_relative="${resolved_file#$core_dir}"
echo " → 解析为: $resolved_relative"
desktop_files[$i]="$resolved_file"
fi
fi
done
echo ""
read -r -p "请选择要复制的桌面文件编号(多个用逗号分隔,all=全部,none=跳过): " desktop_choice
if [[ "$desktop_choice" =~ ^[Aa][Ll][Ll]$ ]]; then
# 复制所有桌面文件到 entries/applications,但保持目录结构
for file in "${desktop_files[@]}"; do
local relative_path="${file#$core_dir}"
local dest_filename=$(basename "$file")
# 如果文件在 applications 目录下,直接复制到 entries/applications
if [[ "$relative_path" == /usr/share/applications/* ]]; then
local dest_path="$entries_dir/applications/$dest_filename"
else
# 其他位置的桌面文件,保持相对路径结构
local path_dir=$(dirname "$relative_path")
local dest_dir="$entries_dir/applications$path_dir"
mkdir -p "$dest_dir"
local dest_path="$dest_dir/$dest_filename"
fi
cp -v "$file" "$dest_path"
# 处理桌面文件内容
process_desktop_file "$dest_path" "$NEW_PKGNAME"
done
elif [[ ! "$desktop_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$desktop_choice" ]; then
# 处理选择的文件
IFS=',' read -ra choices <<< "$desktop_choice"
for choice in "${choices[@]}"; do
choice=$(echo "$choice" | tr -d ' ')
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#desktop_files[@]} ]; then
local idx=$((choice-1))
local file="${desktop_files[$idx]}"
local relative_path="${file#$core_dir}"
local dest_filename=$(basename "$file")
# 根据路径决定目标位置
if [[ "$relative_path" == /usr/share/applications/* ]]; then
local dest_path="$entries_dir/applications/$dest_filename"
else
local path_dir=$(dirname "$relative_path")
local dest_dir="$entries_dir/applications$path_dir"
mkdir -p "$dest_dir"
local dest_path="$dest_dir/$dest_filename"
fi
cp -v "$file" "$dest_path"
# 处理桌面文件内容
process_desktop_file "$dest_path" "$NEW_PKGNAME"
else
log.warn "无效的选择: $choice"
fi
done
else
log.info "跳过桌面文件复制"
fi
else
log.info "未找到桌面文件"
fi
# 处理图标文件
if [ ${#icon_files[@]} -gt 0 ]; then
log.info "找到 ${#icon_files[@]} 个图标文件:"
for i in "${!icon_files[@]}"; do
local file="${icon_files[$i]}"
local relative_path="${file#$core_dir}"
echo " $((i+1)). $relative_path"
# 检查是否是符号链接
if [ -L "$file" ]; then
local target=$(readlink "$file")
echo " → 符号链接指向: $target"
# 解析符号链接获取实际文件
local resolved_file=$(resolve_symlink "$file" "$core_dir")
if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then
local resolved_relative="${resolved_file#$core_dir}"
echo " → 解析为: $resolved_relative"
icon_files[$i]="$resolved_file"
fi
fi
done
echo ""
read -r -p "请选择要复制的图标文件编号(多个用逗号分隔,all=全部,none=跳过): " icon_choice
if [[ "$icon_choice" =~ ^[Aa][Ll][Ll]$ ]]; then
# 复制所有图标文件到 entries/icons,保持目录结构
for file in "${icon_files[@]}"; do
local relative_path="${file#$core_dir}"
local dest_filename=$(basename "$file")
# 如果文件在 icons 主题目录下,直接复制到 entries/icons
if [[ "$relative_path" == /usr/share/icons/* ]] ||
[[ "$relative_path" == /usr/share/pixmaps/* ]]; then
local dest_path="$entries_dir/icons/$dest_filename"
else
# 其他位置的图标文件,保持相对路径结构
local path_dir=$(dirname "$relative_path")
local dest_dir="$entries_dir/icons$path_dir"
mkdir -p "$dest_dir"
local dest_path="$dest_dir/$dest_filename"
fi
cp -v "$file" "$dest_path"
done
elif [[ ! "$icon_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$icon_choice" ]; then
# 处理选择的文件
IFS=',' read -ra choices <<< "$icon_choice"
for choice in "${choices[@]}"; do
choice=$(echo "$choice" | tr -d ' ')
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#icon_files[@]} ]; then
local idx=$((choice-1))
local file="${icon_files[$idx]}"
local relative_path="${file#$core_dir}"
local dest_filename=$(basename "$file")
# 根据路径决定目标位置
if [[ "$relative_path" == /usr/share/icons/* ]] ||
[[ "$relative_path" == /usr/share/pixmaps/* ]]; then
local dest_path="$entries_dir/icons/$dest_filename"
else
local path_dir=$(dirname "$relative_path")
local dest_dir="$entries_dir/icons$path_dir"
mkdir -p "$dest_dir"
local dest_path="$dest_dir/$dest_filename"
fi
cp -v "$file" "$dest_path"
else
log.warn "无效的选择: $choice"
fi
done
else
log.info "跳过图标文件复制"
fi
else
log.info "未找到图标文件"
fi
}
# 函数:处理桌面文件内容
# 函数:处理桌面文件内容(安全版本,避免重复处理)
process_desktop_file() {
local desktop_file="$1"
local pkgname="$2"
# 新增:精确路径检查
local apps_path1="/usr/share/applications"
local apps_path2="/opt/apps/${ORIG_PKGNAME}/entries/applications"
local apps_path3="/usr/local/share/applications"
if [[ ! "$desktop_file" =~ ^.*${apps_path1}/.*\.desktop$ ]] &&
[[ ! "$desktop_file" =~ ^.*${apps_path2}/.*\.desktop$ ]] &&
[[ ! "$desktop_file" =~ ^.*${apps_path3}/.*\.desktop$ ]]; then
log.debug "跳过非应用程序 desktop 文件: $desktop_file"
return 0
fi
log.info "处理桌面文件: $desktop_file"
# 检查文件是否已经处理过(避免重复添加 apm run)
if grep -q "^Exec=apm run $pkgname " "$desktop_file"; then
log.info "桌面文件已经处理过,跳过: $desktop_file"
return 0
fi
# 检查是否有其他包的 apm run 前缀(清理旧的)
if grep -q "^Exec=apm run [^ ]* " "$desktop_file"; then
log.info "发现旧的 apm run 前缀,清理后重新添加"
# 移除所有 apm run 前缀
sed -i "s|^Exec=apm run [^ ]* ||" "$desktop_file"
fi
# 尝试用 busybox dos2unix(若不存在则跳过转换)
if command -v busybox >/dev/null 2>&1; then
busybox dos2unix "$desktop_file" 2>/dev/null || true
else
dos2unix "$desktop_file" 2>/dev/null || true
fi
# 处理 Exec 行:在原有命令前追加 apm run $pkgname
if grep -q '^Exec=' "$desktop_file"; then
sed -i "s|^Exec=\(.*\)$|Exec=apm run $pkgname \1|" "$desktop_file"
fi
# 删除 TryExec 行
if grep -q '^TryExec=' "$desktop_file"; then
sed -i '/^TryExec=/d' "$desktop_file"
log.info "已删除 TryExec 行"
fi
# 处理 Icon 路径(若以 / 开头)
if grep -q '^Icon=/' "$desktop_file"; then
sed -i "s|^Icon=/|Icon=/var/lib/apm/apm/files/ace-env/var/lib/apm/$pkgname/files/core/|" "$desktop_file"
fi
# 添加 X-APM-APPID(如果不存在)
if ! grep -q "X-APM-APPID" "$desktop_file"; then if ! grep -q "X-APM-APPID" "$desktop_file"; then
echo "X-APM-APPID=$NEW_PKGNAME" >> "$desktop_file" echo "" >> "$desktop_file"
echo "X-APM-APPID=$pkgname" >> "$desktop_file"
fi fi
# 检查修改结果 # 检查修改结果并打印调试
if grep -q "apm run $NEW_PKGNAME" "$desktop_file"; then if grep -q "apm run $pkgname" "$desktop_file"; then
log.info "桌面文件修改成功" log.info "桌面文件修改成功: $desktop_file"
log.debug "修改后的Exec行: $(grep '^Exec=' "$desktop_file" || echo "未找到")"
log.debug "修改后的TryExec行: $(grep '^TryExec=' "$desktop_file" || echo "未找到")"
else else
log.warn "桌面文件可能未正确修改: $desktop_file" log.warn "桌面文件可能未正确修改: $desktop_file"
fi fi
done }
# 4. 如果有 DEB 文件,进行自动化的检查、解包与修改
if [ -n "$DEB_PATH" ]; then
# 在融合环境中更新包列表并做 dry-run 检查(如果 ace-run-pkg aptss 可用)
log.info "在融合环境中测试安装 DEB 包(dry-run..."
sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss update || log.warn "aptss update 返回非零状态,继续但请注意"
if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss install "$DEB_PATH" --dry-run ; then
log.error "错误:安装前检查失败,DEB包可能无法在基础环境中安装"
log.error "请检查依赖关系或基础环境是否兼容"
exit 1
fi
log.info "安装前检查通过,准备进行提取与修改..."
sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg mkdir -p /var/cache/apt/archives/partial
# 提取 DEB 包内容并准备修改
log.info "提取并修改原DEB包..."
EXTRACT_DIR="$CRAFT_DIR/extract"
MODIFIED_DEB_DIR="$CRAFT_DIR/modified_deb"
mkdir -p "$EXTRACT_DIR"
mkdir -p "$MODIFIED_DEB_DIR/DEBIAN"
dpkg -x "$DEB_PATH" "$EXTRACT_DIR"
dpkg -e "$DEB_PATH" "$MODIFIED_DEB_DIR/DEBIAN"
# 处理 .desktop 文件
DESKTOP_MODIFIED=false
while IFS= read -r desktop_file; do
[ -z "$desktop_file" ] && continue
process_desktop_file "$desktop_file" "${NEW_PKGNAME:-$ORIG_PKGNAME}"
DESKTOP_MODIFIED=true
done < <(find "$EXTRACT_DIR" -name "*.desktop" -print)
if [ "$DESKTOP_MODIFIED" = false ]; then
log.info "未找到需要修改的 .desktop 文件"
fi
# 复制修改后的文件结构到打包目录并重新打包 modified deb(供本地测试/安装使用)
MODIFIED_DEB_PATH="$CRAFT_DIR/modified_${ORIG_PKGNAME:-package}.deb"
log.info "重新打包修改后的 DEB: $MODIFIED_DEB_PATH"
mkdir -p "$MODIFIED_DEB_DIR/data"
cp -r "$EXTRACT_DIR"/* "$MODIFIED_DEB_DIR/" 2>/dev/null || true
(cd "$MODIFIED_DEB_DIR" && fakeroot dpkg-deb --build -Z none . "$MODIFIED_DEB_PATH") || {
log.error "错误:重新打包 DEB 失败"
exit 1
}
if [ ! -f "$MODIFIED_DEB_PATH" ]; then
log.error "错误:重新打包后的 DEB 未生成: $MODIFIED_DEB_PATH"
exit 1
fi
log.info "修改后的 DEB 包已生成: $MODIFIED_DEB_PATH"
# 可选:在融合环境中实际安装修改后的包(默认使用 ssaudit 命令)
if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg ssaudit "$MODIFIED_DEB_PATH" --native --no-create-desktop-entry ; then
log.error "错误:修改后的 DEB 包安装失败(ssaudit"
exit 1
fi
log.info "修改后的 DEB 包安装完成(ssaudit"
if [ "$DESKTOP_MODIFIED" = false ]; then
log.info "未找到需要修改的.desktop文件"
fi fi
# 重新打包修改后的DEB # 清理 apt 缓存
MODIFIED_DEB_PATH="$CRAFT_DIR/modified_${ORIG_PKGNAME}.deb" sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss clean || true
log.info "重新打包修改后的DEB: $MODIFIED_DEB_PATH" sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/apt/lists || true
sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/aptss/lists || true
sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/cache/apt/* || true
# 复制修改后的文件结构到打包目录 # 5. 创建新的 APM 包结构
mkdir -p "$MODIFIED_DEB_DIR/data"
cp -r "$EXTRACT_DIR"/* "$MODIFIED_DEB_DIR/" 2>/dev/null || true
# 使用fakeroot重新打包
cd "$MODIFIED_DEB_DIR" && fakeroot dpkg-deb --build -Z none . "$MODIFIED_DEB_PATH"
cd - > /dev/null
if [ ! -f "$MODIFIED_DEB_PATH" ]; then
log.error "错误:重新打包DEB失败"
exit 1
fi
log.info "DEB包修改完成,新包路径: $MODIFIED_DEB_PATH"
# 实际安装修改后的DEB包
if ! sudo -E /var/lib/apm/apm/files/ace-run-pkg ssaudit "$MODIFIED_DEB_PATH" --native --no-create-desktop-entry; then
log.error "错误:修改后的DEB包安装失败"
exit 1
fi
log.info "修改后的DEB包安装完成"
# 清理一些垃圾
sudo -E /var/lib/apm/apm/files/ace-run-pkg aptss clean
sudo -E /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/apt/lists
sudo -E /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/aptss/lists
# 7. 创建新的APM包结构
log.info "创建新的APM包结构..." log.info "创建新的APM包结构..."
PKG_BUILD_DIR="$CRAFT_DIR/new-pkg" PKG_BUILD_DIR="$CRAFT_DIR/new-pkg"
mkdir -p "$PKG_BUILD_DIR/DEBIAN" mkdir -p "$PKG_BUILD_DIR/DEBIAN"
mkdir -p "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME"/{entries,files} mkdir -p "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME"/{entries,files} 2>/dev/null || true
# 创建info文件 - 写入所有base,每行一个 # info 和 info_debug:写入原始输入的 base 列表 和 递归展开后的 base 列表
log.info "创建info文件包含输入的基础环境:" log.info "创建 info 文件包含原始输入的基础环境..."
: > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info" 2>/dev/null || true
for BASENAME in "${BASENAMES_ORIG[@]}"; do for BASENAME in "${BASENAMES_ORIG[@]}"; do
echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME/info" echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info"
log.info " 写入: $BASENAME"
done
log.info "创建info_debug文件,包含所有基础环境:"
for BASENAME in "${BASENAMES[@]}"; do
echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME/info_debug"
log.info " 写入: $BASENAME" log.info " 写入: $BASENAME"
done done
# 创建postrm脚本 log.info "创建 info_debug 文件(包含所有递归依赖的基础环境)..."
: > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug" 2>/dev/null || true
for BASENAME in "${BASENAMES[@]}"; do
echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug"
log.info " 写入: $BASENAME"
done
# 创建 postrm 脚本
cat > "$PKG_BUILD_DIR/DEBIAN/postrm" << 'EOF' cat > "$PKG_BUILD_DIR/DEBIAN/postrm" << 'EOF'
#!/bin/bash #!/bin/bash
PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE" PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE"
@@ -329,14 +677,11 @@ PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE"
if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then
echo "清理卸载残留" echo "清理卸载残留"
rm -rf "/var/lib/apm/$PACKAGE_NAME" rm -rf "/var/lib/apm/$PACKAGE_NAME"
for username in $(ls /home) for username in $(ls /home); do
do if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then
echo /home/$username
if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]
then
rm -fr "/home/$username/.apm/$PACKAGE_NAME" rm -fr "/home/$username/.apm/$PACKAGE_NAME"
fi fi
done done
else else
echo "非卸载,跳过清理" echo "非卸载,跳过清理"
fi fi
@@ -344,34 +689,40 @@ EOF
chmod +x "$PKG_BUILD_DIR/DEBIAN/postrm" chmod +x "$PKG_BUILD_DIR/DEBIAN/postrm"
# 8. 复制文件到新的APM包 # 6. 复制需要的文件到新的 APM
log.info "复制文件到新的APM包..." log.info "复制文件到新的APM包..."
# 复制/usr/share/内容到entries # 如果是手动模式且没有DEB文件,进行交互式文件选择
if [ -d "$EXTRACT_DIR/usr/share" ]; then if [ "$MANUAL_MODE" = true ] && [ -z "$DEB_PATH" ]; then
log.info "复制/usr/share/内容..." interactive_copy_entries
cp -r "$EXTRACT_DIR/usr/share/"* "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME/entries/"
fi fi
# 复制/opt/apps/内容(如果存在) # 复制 /usr/share 内容到 entries
if [ -d "$EXTRACT_DIR/opt/apps/$ORIG_PKGNAME/entries" ]; then if [ -d "$CRAFT_DIR/extract/usr/share" ]; then
log.info "复制/opt/apps/$ORIG_PKGNAME/entries内容..." log.info "复制 /usr/share 内容..."
cp -r "$EXTRACT_DIR/opt/apps/$ORIG_PKGNAME/entries/"* "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME/entries/" mkdir -p "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries"
cp -r "$CRAFT_DIR/extract/usr/share/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true
fi fi
# 复制融合环境文件 # 复制 /opt/apps/<orig_pkg>/entries(如果存在)
log.info "复制融合环境文件..." if [ -n "$ORIG_PKGNAME" ] && [ -d "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries" ]; then
sudo cp -r "$CRAFT_DIR"/{core,work} "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME/files/" log.info "复制 /opt/apps/$ORIG_PKGNAME/entries 内容..."
cp -r "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true
fi
# 复制融合环境(core, work)到新的包内 files(以便运行时使用)
log.info "复制融合环境文件..."
sudo cp -r "$CRAFT_DIR"/core "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/files/" 2>/dev/null || true
sudo cp -r "$CRAFT_DIR"/work "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/files/" 2>/dev/null || true
# 设置文件权限 # 设置文件权限
sudo chmod -R 755 "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME/files/" sudo chmod -R 755 "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/files/" 2>/dev/null || true
# 9. 解除挂载 # 7. 解除挂载(如果尚未解除)
log.info "解除挂载..." log.info "解除挂载..."
cleanup_mount cleanup_mount
# 10. 打包新的APM包 # 8. 计算目录大小函数
log.info "打包新的APM包..."
calculate_directory_size() { calculate_directory_size() {
local dir="$1" local dir="$1"
if [ -d "$dir" ]; then if [ -d "$dir" ]; then
@@ -381,33 +732,47 @@ calculate_directory_size() {
fi fi
} }
# 构建依赖字符串 - 包含所有base # 构建依赖字符串 - 包含所有用户原始输入的 base(用于 control
DEPENDS_STR=$(IFS=,; echo "${BASENAMES_ORIG[*]}") DEPENDS_STR=$(IFS=,; echo "${BASENAMES_ORIG[*]}")
# 创建control文件 # 若打包前没有 NEW_PKGNAME/NEW_VERSION,交互询问(一般出现在手动无DEB场景)
if [ -z "$NEW_PKGNAME" ]; then
read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME
fi
if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then
read -r -p "请输入要创建的版本 (Version): " NEW_VERSION
fi
# 创建 control 文件
cat > "${PKG_BUILD_DIR}/DEBIAN/control" << EOF cat > "${PKG_BUILD_DIR}/DEBIAN/control" << EOF
Package: $NEW_PKGNAME Package: $NEW_PKGNAME
Version: $NEW_VERSION Version: $NEW_VERSION
Architecture: $ORIG_ARCH Architecture: $ORIG_ARCH
Maintainer: APM Converter <apm-convert@spark-app.store> Maintainer: APM Converter <apm-convert@spark-app.store>
Depends: $DEPENDS_STR Depends: $DEPENDS_STR
Installed-Size: $(calculate_directory_size $PKG_BUILD_DIR) Installed-Size: $(calculate_directory_size "$PKG_BUILD_DIR")
Description: APM converted package from $ORIG_PKGNAME Description: APM converted package from ${ORIG_PKGNAME:-original}
This package was automatically converted from the original deb package. This package was automatically converted from the original deb package.
Based on: ${BASENAMES_ORIG[*]} Based on: ${BASENAMES_ORIG[*]}
EOF EOF
# 生成输出文件名 # 9. 打包并生成输出文件名
OUTPUT_DEB="${NEW_PKGNAME}_${NEW_VERSION}_${ORIG_ARCH}.deb" OUTPUT_DEB="${NEW_PKGNAME}_${NEW_VERSION}_${ORIG_ARCH}.deb"
log.info "开始使用 fakeroot 打包: $OUTPUT_DEB"
fakeroot dpkg-deb -Z xz --build "$PKG_BUILD_DIR" "$OUTPUT_DEB" || {
log.error "错误:打包 APM 包失败"
exit 1
}
# 打包 log.info "转换完成!"
fakeroot dpkg-deb -Z xz --build "$PKG_BUILD_DIR" "$OUTPUT_DEB"
log.info "转换完成!"
log.info "生成的APM包: $OUTPUT_DEB" log.info "生成的APM包: $OUTPUT_DEB"
log.info "包名: $NEW_PKGNAME" log.info "包名: $NEW_PKGNAME"
log.info "版本: $NEW_VERSION" log.info "版本: $NEW_VERSION"
log.info "架构: $ORIG_ARCH" log.info "架构: $ORIG_ARCH"
log.info "依赖: $DEPENDS_STR" log.info "依赖: $DEPENDS_STR"
log.info "基础环境: ${BASENAMES[*]}" log.info "基础环境(原始输入): ${BASENAMES_ORIG[*]}"
log.info "注意:桌面文件已修改,添加了APM运行前缀和APPID" log.info "基础环境(递归展开): ${BASENAMES[*]}"
log.info "注意:桌面文件如存在已被修改,添加了 apm run 前缀和 X-APM-APPID"
# 退出(trap 会触发 cleanup
exit 0
+2 -2
View File
@@ -30,7 +30,7 @@ linkDir() {
ensureTargetDir "$targetFile" ensureTargetDir "$targetFile"
sourceFile=$(realpath --relative-to="$(dirname $targetFile)" "$sourceFile" ) sourceFile=$(realpath --relative-to="$(dirname $targetFile)" "$sourceFile" )
if [ ! -e ${targetFile} ];then if [ ! -e "${targetFile}" ];then
ln -sv "$sourceFile" "$targetFile" ln -sv "$sourceFile" "$targetFile"
fi fi
done done
@@ -98,7 +98,7 @@ function exec_link_clean(){
find /usr/share/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/share/help -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/help -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/share/locale -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/locale -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH`/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & # find /usr/lib/$(gcc -dumpmachine)/fcitx -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/lib/mozilla/plugins -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/lib/mozilla/plugins -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/share/polkit-1/actions -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/polkit-1/actions -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
find /usr/share/fonts -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null & find /usr/share/fonts -xtype l -exec echo '{} is invalid now and going to be cleaned' \; -exec unlink {} \; 2>/dev/null &
+113 -34
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
VERSION=1.1.3 VERSION=@VERSION@
# 获取脚本名称用于帮助信息 # 获取脚本名称用于帮助信息
SCRIPT_NAME=$(basename "$0") SCRIPT_NAME=$(basename "$0")
PATH_PREFIX=/var/lib/apm/apm/files/ace-env/ PATH_PREFIX=/var/lib/apm/apm/files/ace-env/
@@ -46,37 +46,40 @@ Commands:
-h, --help 显示此帮助信息 -h, --help 显示此帮助信息
-v, --version 展示APM版本号 -v, --version 展示APM版本号
本 APM 具有兔兔伯爵,女武神装甲和超级大运之力。
EOF EOF
} }
apm_exec(){ apm_exec(){
# 递归读取info文件并构建lowerdir # ===============================
# 基础变量
# ===============================
local lowerdirs=() local lowerdirs=()
local current_dir="${PATH_PREFIX}/var/lib/apm/${coredir}" # 当前目录开始 local env_layers=()
local current_dir="${PATH_PREFIX}/var/lib/apm/${coredir}"
local next_info_file="" local next_info_file=""
local APM_RUN_EXEC=/var/lib/apm/apm/files/ace-run
# 使用统一的 ace-run 脚本 # ===============================
APM_RUN_EXEC=/var/lib/apm/apm/files/ace-run # 递归读取 info / info_env
# ===============================
while : ; do while : ; do
# 构建info文件的路径
next_info_file="${current_dir}/info" next_info_file="${current_dir}/info"
# echo "${current_dir}/info"
# 检查info文件是否存在 # 记录 info_env(底层优先)
if [[ ! -f "$next_info_file" ]]; then if [[ -f "${current_dir}/info_env" ]]; then
# log.debug "No more info files found, stopping recursion." env_layers+=("${current_dir}/info_env")
break
fi fi
# 读取info文件的每一行并构建lowerdir # 没有 info 就停止
while IFS= read -r basedir; do [[ ! -f "$next_info_file" ]] && break
[[ -z "$basedir" ]] && continue # 跳过空行
# 读取依赖层
while IFS= read -r basedir; do
[[ -z "$basedir" ]] && continue
# 检查ace-env目录是否存在
if [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env" ]]; then if [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env" ]]; then
lowerdirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env") lowerdirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env")
# 如果ace-env不存在,检查core目录
elif [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/core" ]]; then elif [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/core" ]]; then
lowerdirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/core") lowerdirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/core")
else else
@@ -84,35 +87,111 @@ apm_exec(){
fi fi
done < "$next_info_file" done < "$next_info_file"
# 尝试获取下一个依赖信息的路径 # 递归到下一个
local next_basedir=$(tail -n 1 "$next_info_file") local next_basedir
if [[ -z "$next_basedir" || ! -d "${PATH_PREFIX}/var/lib/apm/${next_basedir}" ]]; then next_basedir="$(tail -n 1 "$next_info_file")"
log.debug "No further dependencies found, ending recursion." [[ -z "$next_basedir" || ! -d "${PATH_PREFIX}/var/lib/apm/${next_basedir}" ]] && break
break
fi
# 更新当前目录,递归处理下一个依赖
current_dir="${PATH_PREFIX}/var/lib/apm/${next_basedir}" current_dir="${PATH_PREFIX}/var/lib/apm/${next_basedir}"
done done
# 检查是否找到了有效的lowerdir # ===============================
# info_layer_override(最高优先级)
# ===============================
local override_file="${PATH_PREFIX}/var/lib/apm/${coredir}/info_layer_override"
if [[ -f "$override_file" ]]; then
log.debug "Found info_layer_override: $override_file"
local override_dirs=()
local override_envs=()
while IFS= read -r basedir; do
[[ -z "$basedir" ]] && continue
local base="${PATH_PREFIX}/var/lib/apm/${basedir}"
if [[ -d "${base}/files/ace-env" ]]; then
override_dirs+=("${base}/files/ace-env")
elif [[ -d "${base}/files/core" ]]; then
override_dirs+=("${base}/files/core")
else
log.warn "Override layer not found: $basedir"
fi
if [[ -f "${base}/info_env" ]]; then
override_envs+=("${base}/info_env")
fi
done < "$override_file"
# override 层放最前(最高)
if [[ ${#override_dirs[@]} -gt 0 ]]; then
lowerdirs=("${override_dirs[@]}" "${lowerdirs[@]}")
fi
# override env 最后应用(最高)
if [[ ${#override_envs[@]} -gt 0 ]]; then
env_layers+=("${override_envs[@]}")
fi
fi
# ===============================
# 检查 lowerdir
# ===============================
if [[ ${#lowerdirs[@]} -eq 0 ]]; then if [[ ${#lowerdirs[@]} -eq 0 ]]; then
log.error "No valid lower directories found for package: $coredir" log.error "No valid lower directories found for package: $coredir"
return 1 return 1
fi fi
# 将lowerdirs数组用冒号连接起来 local lowerdir
local lowerdir=$(IFS=:; echo "${lowerdirs[*]}") lowerdir=$(IFS=:; echo "${lowerdirs[*]}")
# 创建挂载点目录
mkdir -p "/tmp/apm/${coredir}" mkdir -p "/tmp/apm/${coredir}"
# 使用fuse-overlayfs挂载 # ===============================
log.debug "Mounting with lowerdir: $lowerdir" # 应用 info_env(从下到上)
fuse-overlayfs -o lowerdir="$lowerdir",upperdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/core/",workdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/work/" "/tmp/apm/${coredir}" # ===============================
for env_file in "${env_layers[@]}"; do
log.debug "Applying env: $env_file"
# 执行命令 while IFS= read -r line || [[ -n "$line" ]]; do
chrootEnvPath="/tmp/apm/${coredir}" ${APM_RUN_EXEC} "$@" [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
if [[ "$line" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then
local key="${line%%=*}"
local val="${line#*=}"
# 去首尾空白
val="${val#"${val%%[![:space:]]*}"}"
val="${val%"${val##*[![:space:]]}"}"
# 去外层引号
if [[ "$val" =~ ^\".*\"$ || "$val" =~ ^\'.*\'$ ]]; then
val="${val:1:-1}"
fi
export "$key=$val"
else
log.warn "Invalid env line ignored: $line"
fi
done < "$env_file"
done
# ===============================
# 挂载 overlay
# ===============================
log.debug "Mounting overlayfs"
log.debug "lowerdir=$lowerdir"
fuse-overlayfs \
-o lowerdir="$lowerdir",upperdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/core/",workdir="${PATH_PREFIX}/var/lib/apm/${coredir}/files/work/" \
"/tmp/apm/${coredir}"
# ===============================
# 执行
# ===============================
chrootEnvPath="/tmp/apm/${coredir}" "${APM_RUN_EXEC}" "$@"
# ===============================
# 卸载 # 卸载
# ===============================
umount "/tmp/apm/${coredir}" umount "/tmp/apm/${coredir}"
} }
@@ -70,7 +70,7 @@ _apm()
# supported options per command # supported options per command
if [[ "$cur" == -* ]]; then if [[ "$cur" == -* ]]; then
case $command in case $command in
install|remove|purge|upgrade|dist-upgrade|full-upgrade|autoremove) install|remove|purge|upgrade|dist-upgrade|full-upgrade|autoremove|autopurge)
COMPREPLY=( $( compgen -W '--show-progress COMPREPLY=( $( compgen -W '--show-progress
--fix-broken --purge --verbose-versions --auto-remove --fix-broken --purge --verbose-versions --auto-remove
-s --simulate --dry-run -s --simulate --dry-run
+13 -12
View File
@@ -27,7 +27,7 @@ function ensure_dir() {
return 0 return 0
fi fi
} }
chrootEnvPath="${chrootEnvPath:-$(pwd)/ace-env}" chrootEnvPath="${chrootEnvPath:-$(dirname $0)/ace-env}"
APM_PKG_NAME="${APM_PKG_NAME:-apm-general}" APM_PKG_NAME="${APM_PKG_NAME:-apm-general}"
@@ -45,18 +45,19 @@ if [ "${APM_USE_SANDBOX:-0}" = "1" ]; then
ensure_dir $HOME/.apm/${APM_PKG_NAME}/$(basename $(xdg-user-dir MUSIC)) ensure_dir $HOME/.apm/${APM_PKG_NAME}/$(basename $(xdg-user-dir MUSIC))
fi fi
#### This part is for args pharm if [ $# -eq 0 ]; then
if [ "$1" = "" ];then container_command="bash"
container_command="bash"
else else
container_command="$1" # 正确转义所有参数,处理空格和特殊字符
shift container_command=""
for arg in "$@"; do for arg in "$@"; do
arg="$(echo "${arg}x" | sed 's|'\''|'\'\\\\\'\''|g')" # 使用 printf %q 进行安全的 shell 转义
arg="${arg%x}" escaped_arg="$(printf "%q" "$arg")"
container_command="${container_command} '${arg}'" container_command="${container_command} ${escaped_arg}"
done done
container_command="${container_command# }" # 移除开头的空格
fi fi
######################################################################################### #########################################################################################
##########合成bwrap 1. 基础函数配置段 ##########合成bwrap 1. 基础函数配置段
# 初始化 EXEC_COMMAND 为 bwrap 基础指令 # 初始化 EXEC_COMMAND 为 bwrap 基础指令
@@ -198,4 +199,4 @@ add_command "bash -c \"${container_command}\""
# echo "${EXEC_COMMAND}" # echo "${EXEC_COMMAND}"
# 注意: 实际执行时,请确保所有变量(如 $uid, $chrootEnvPath 等)都已正确定义 # 注意: 实际执行时,请确保所有变量(如 $uid, $chrootEnvPath 等)都已正确定义
eval ${EXEC_COMMAND} eval "${EXEC_COMMAND}"
@@ -135,8 +135,10 @@ apt install --reinstall /amber-ce-tools/ace-host-integration.deb -y
cd /amber-ce-tools/data-dir/ cd /amber-ce-tools/data-dir/
mkdir -p usr/share/templates
ln -sfv ../../usr/share/applications/ . ln -sfv ../../usr/share/applications/ .
ln -sfv ../../usr/share/icons/ . ln -sfv ../../usr/share/icons/ .
ln -sfv ../../usr/share/templates/ .
#ln -svf ../../usr/share/mime . #ln -svf ../../usr/share/mime .
rm -vf ./mime rm -vf ./mime
update-desktop-database /usr/share/applications || true update-desktop-database /usr/share/applications || true
+4
View File
@@ -112,6 +112,10 @@ chown -R root $chrootEnvPath
mkdir -p $chrootEnvPath/amber-ce-tools/data-dir mkdir -p $chrootEnvPath/amber-ce-tools/data-dir
ln -sv ../../usr/share/applications $chrootEnvPath/amber-ce-tools/data-dir/ ln -sv ../../usr/share/applications $chrootEnvPath/amber-ce-tools/data-dir/
ln -sv ../../usr/share/icons $chrootEnvPath/amber-ce-tools/data-dir/ ln -sv ../../usr/share/icons $chrootEnvPath/amber-ce-tools/data-dir/
mkdir -p $chrootEnvPath/usr/share/templates
ln -sfv ../../usr/share/templates/ $chrootEnvPath/amber-ce-tools/data-dir/
chmod 777 -R $chrootEnvPath/usr/share/icons chmod 777 -R $chrootEnvPath/usr/share/icons
rm -vfr $chrootEnvPath/dev/* rm -vfr $chrootEnvPath/dev/*
true true
@@ -14,29 +14,39 @@ log.error "需要把ace-env所在的路径设置为第一个参数"
exit 1 exit 1
fi fi
# 1\. 获取宿主机 NVIDIA 驱动版本 # 1. 获取宿主机 NVIDIA 驱动版本
nvidia_version=$(cat /sys/module/nvidia/version 2>/dev/null) nvidia_version=$(cat /sys/module/nvidia/version 2>/dev/null)
if [ -z "$nvidia_version" ]; then if [ -z "$nvidia_version" ]; then
log.warn "无法获取 NVIDIA 驱动版本 Can not determine NVIDIA Driver version" # log.warn "无法获取 NVIDIA 驱动版本 Can not determine NVIDIA Driver version"
exit 1 exit 1
fi fi
# 2\. 目标目录准备 # 2. 目标目录准备
ACE_DIR="$1" ACE_DIR="$1"
if [[ ! -e "${ACE_DIR}" ]];then if [[ ! -e "${ACE_DIR}" ]];then
log.error "未检测到 apm安装,请安装后再试 apm is not detected. Please try again after installation" log.error "未检测到 apm安装,请安装后再试 apm is not detected. Please try again after installation"
log.info "请按回车关闭... Press Enter to close..."
read
exit 1 exit 1
fi fi
mkdir -p "$ACE_DIR/usr/lib" "$ACE_DIR/usr/lib32" mkdir -p "$ACE_DIR/usr/lib" "$ACE_DIR/usr/lib32"
# 检查版本是否已存在且匹配
if [ -f "$ACE_DIR/current_version" ]; then
existing_version=$(cat "$ACE_DIR/current_version")
if [ "$existing_version" = "$nvidia_version" ]; then
# log.info "NVIDIA 驱动版本未变化,跳过链接操作 NVIDIA Driver version unchanged, skipping linking."
exit 0
else
log.info "检测到 NVIDIA 驱动版本变化: $existing_version -> $nvidia_version"
log.info "NVIDIA Driver version changed: $existing_version -> $nvidia_version"
fi
fi
log.info "正在链接 NVIDIA 驱动库 Linking NVIDIA Driver Libs" log.info "正在链接 NVIDIA 驱动库 Linking NVIDIA Driver Libs"
# 3\. 收集库文件路径 # 3. 收集库文件路径
lib_list=$(ldconfig -p | grep -Ei "nvidia|libcuda" | cut -d'>' -f2) lib_list=$(ldconfig -p | grep -Ei "nvidia|libcuda" | cut -d'>' -f2)
# 4\. 复制库文件 # 4. 复制库文件
copied=0 copied=0
for lib in $lib_list; do for lib in $lib_list; do
resolved=$(readlink -f "$lib") # 解析符号链接 resolved=$(readlink -f "$lib") # 解析符号链接
@@ -48,7 +58,7 @@ for lib in $lib_list; do
fi fi
done done
# 5\. 复制辅助文件 # 5. 复制辅助文件
additional_files=( additional_files=(
/usr/share/vulkan/icd.d/nvidia_icd.json /usr/share/vulkan/icd.d/nvidia_icd.json
/usr/share/egl/egl_external_platform.d/20_nvidia_xcb.json /usr/share/egl/egl_external_platform.d/20_nvidia_xcb.json
@@ -62,7 +72,7 @@ for file in "${additional_files[@]}"; do
fi fi
done done
# 6\. 标记版本 # 6. 标记版本
if [ $copied -eq 1 ]; then if [ $copied -eq 1 ]; then
echo "$nvidia_version" > "$ACE_DIR/current_version" echo "$nvidia_version" > "$ACE_DIR/current_version"
log.info "NVIDIA 驱动库已成功链接 Nvidia Driver Libs are successfully linked. " log.info "NVIDIA 驱动库已成功链接 Nvidia Driver Libs are successfully linked. "
+69
View File
@@ -0,0 +1,69 @@
#!/bin/bash
# 提取配置信息
VERSION_FEEDBACK=@VERSION@-apm
UUID=$(cat /etc/machine-id 2>/dev/null || echo "unknown")
# 获取系统信息 - 不依赖 lsb_release
if [ -f /etc/os-release ]; then
# 现代 Linux 系统使用 /etc/os-release
source /etc/os-release
DISTRIBUTOR_ID="$NAME"
RELEASE="$VERSION_ID"
elif [ -f /etc/redhat-release ]; then
# RedHat/CentOS 系统
DISTRIBUTOR_ID=$(cat /etc/redhat-release | awk '{print $1}')
RELEASE=$(cat /etc/redhat-release | sed -n 's/.*release \([0-9][0-9.]*\).*/\1/p')
elif [ -f /etc/debian_version ]; then
# Debian 系统
DISTRIBUTOR_ID="Debian"
RELEASE=$(cat /etc/debian_version)
else
# 其他系统
DISTRIBUTOR_ID="Unknown"
RELEASE="Unknown"
fi
ARCHITECTURE=$(uname -m)
# 构建当前时间
CURRENT_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# 构建 JSON 数据
JSON_DATA=$(cat <<EOF
{
"Distributor ID": "$DISTRIBUTOR_ID",
"Release": "$RELEASE",
"Architecture": "$ARCHITECTURE",
"Store_Version": "$VERSION_FEEDBACK",
"UUID": "$UUID",
"TIME": "$CURRENT_TIME"
}
EOF
)
#echo "Spark Store Feedback"
# 调试输出 JSON 数据
#echo "发送的 JSON 数据:"
#echo "$JSON_DATA" | jq .
# 目标 URL
URL="https://status.deepinos.org.cn/upload"
# 使用 curl 发送 POST 请求
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X POST -H "Content-Type: application/json" -d "$JSON_DATA" "$URL")
# 检查 HTTP 响应码
if [ "$RESPONSE" -eq 200 ]; then
#echo "上传成功"
true
elif [ "$RESPONSE" -eq 400 ]; then
echo "错误:客户端请求错误,请检查 JSON 数据或接口逻辑"
elif [ "$RESPONSE" -eq 422 ]; then
echo "错误:请求数据无效,请检查 JSON 字段值"
elif [ "$RESPONSE" -eq 500 ]; then
echo "错误:服务器内部错误,请联系服务器管理员"
else
echo "错误:未处理的响应码 $RESPONSE"
fi