Compare commits

...

32 Commits

Author SHA1 Message Date
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
16 changed files with 1003 additions and 282 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. 修复程序准备就绪后,我们将发布安全更新,并在适当的时候公开致谢。
再次感谢您为保障社区安全所做的负责任的行为!
+102 -49
View File
@@ -12,9 +12,20 @@
overlayfs 原理解析:https://www.cnblogs.com/arnoldlu/p/13055501.html overlayfs 原理解析:https://www.cnblogs.com/arnoldlu/p/13055501.html
--- ---
## OverlayFS 层叠顺序说明
APM 使用 OverlayFS 来管理软件包的文件系统层级,从上到下的层叠顺序为:
1. **Upperdir** - 当前包的可写层 `files/core/`
2. **Info Layer Override** - 覆盖层指定的目录(位于所有依赖层之上)
3. **依赖层** - 从 `info` 文件递归解析出的所有依赖包
3. **底层** - 最基础的运行时环境
这种层叠结构允许上层文件覆盖下层文件,实现依赖管理和自定义覆盖。
---
一个典型的 APM 软件/中层依赖包应当包含以下内容 一个典型的 APM 软件/中层依赖包应当包含以下内容
@@ -30,21 +41,20 @@ overlayfs 原理解析:https://www.cnblogs.com/arnoldlu/p/13055501.html
│ ├── applications │ ├── applications
│ ├── doc │ ├── doc
│ ├── glib-2.0 │ ├── glib-2.0
│ └── man │ └── man
├── files ├── files
│ ├── core │ ├── core
│ └── work │ └── work
├── info ├── info
└── info_debug └── info_layer_override # 可选,用于自定义覆盖层
``` ```
* DEBIAN目录包含了软件包的基本信息和依赖的环境信息 ### DEBIAN 目录
1. 以下是 control 文件的内容 包含软件包的基本信息和依赖的环境信息
**control 文件示例:**
``` ```
Package: eom Package: eom
Version: 1.26.0-2-apm Version: 1.26.0-2-apm
@@ -55,20 +65,16 @@ 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: 包名应当唯一。若使用转换器进行转换,默认和原包名一致 - **Package**: 包名应当唯一。若使用转换器进行转换,默认和原包名一致
Version: 版本号。若使用转换器进行转换,默认在原版本号后加`-apm` - **Version**: 版本号。若使用转换器进行转换,默认在原版本号后加 `-apm`
Architecture: 软件包架构同 dpkg 进行填写即可。若使用转换器进行转换,默认和原包架构一致 - **Architecture**: 软件包架构同 dpkg 规范填写
Depends: 依赖包。填写直接依赖的base即可 - **Depends**: 直接依赖的 base 包名
Installed-Size: 安装后的大小。若使用转换器进行转换,会自动填写 - **Installed-Size**: 安装后的大小,转换器会自动计算
Description: 包描述。若使用转换器进行转换,会自动填写 - **Description**: 包描述,转换器会自动填写
2. 以下是 postinst 文件内容
**postinst 文件内容:**
``` ```
#!/bin/bash #!/bin/bash
PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE" PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE"
@@ -87,63 +93,110 @@ done
else else
echo "非卸载,跳过清理" echo "非卸载,跳过清理"
fi fi
``` ```
若无特殊需求,内容保持一致即可,用于在卸载软件包后清理环境
* /var/lib/apm 包含了APM 软件容器的文件和信息 若无特殊需求,内容保持一致即可,用于在卸载软件包后清理环境。
### /var/lib/apm 目录结构
包含 APM 软件容器的文件和信息:
- **entries** (可选):包含需要放置到 `/usr/share/` 的文件,如 desktop、icon 等
- **files** (必须):包含软件包的 upperdir 和 workdir
- **info** (必须):包含直接依赖的 base 信息。若应用使用了多层的依赖,会一层一层寻找 info 信息,直到找到底层依赖。如填写 amber-pm-bookworm-spark-wine10 会自动解析出 amber-pm-bookworm
- **info_layer_override** (可选):用于指定自定义覆盖层的目录
> 关于 Info: 使用多层的依赖并不是必须的,即使不使用也可以正常打包,但恰当地使用多层依赖可大大降低包体积。 可用的多层依赖见 `apm search amber-pm-[base名称]- ` 。若有必要,可申请新增 base
**entries 目录说明:**
- `entries/applications`:存放 `.desktop` 文件
- `entries/doc`:存放文档
- `entries/glib-2.0`:存放 GLib 相关文件
- `entries/man`:存放帮助文档
软件应当被放置在 /var/lib/apm/软件包名/ 处 > **重要提示**`.desktop` 文件应当添加一行 `X-APM-APPID=包名` 来允许软件管理器管理应用
此处有两个目录,两个文件
entries 可选,包含了软件包需要被放到 /usr/share/ 的文件,如 desktop icon 等 ### info_layer_override 文件
files 必须,包含了软件包的 upperdir 和 workdir
info 必须,包含了直接依赖的base信息。若应用使用了多层的依赖,会一层一层寻找info信息,直到找到底层依赖
info_debug 可选,包含了打包时解析的依赖信息
entries下的内容同软件需要放置到 /usr/share/ 下的内容 `info_layer_override` 是一个可选文件,用于在当前包的依赖层之上插入额外的覆盖层。这个功能在以下场景特别有用:
> 注意: .desktop 文件应当新加一行 X-APM-APPID=包名 来允许软件管理器管理 1. **自定义库版本**:覆盖依赖包中的特定库文件,如你想要用更新版本的 mesa 覆盖 debian 默认提供的版本作为运行环境
2. **配置文件自定义**:使用自定义配置覆盖默认配置
- **语法**:与 `info` 文件一致,每行一个包名
- **层叠位置**:位于所有依赖层之上、当前包的 upperdir 之下
- **文件位置**`${PATH_PREFIX}/var/lib/apm/${coredir}/info_layer_override`
files的内容请见下一节 **示例:**
假设您想用自定义的 `override-layer` 包来覆盖 `base-package` 中的某些文件:
`my-package/info` 内容:
```
amber-pm-bookworm
```
`my-package/info_layer_override` 内容:
```
amber-pm-bookworm-mesa
```
最终的挂载 lowerdir 为:`amber-pm-bookworm-mesa:amber-pm-bookworm`
这样,`override-layer` 中的文件会覆盖 `base-package` 中的同名文件(除非当前包的 upperdir 中也有该文件)。
## APM upperdir 制作流程 ## APM upperdir 制作流程
以下为手动制作 upperdir 的流程 以下为手动制作 upperdir 的流程
首先安装 apm 并使用`sudo apm install` 安装所需的 base 1. **安装依赖**首先安装 apm 并使用 `sudo apm install` 安装所需的 base
随后,新建三个文件夹,corework 和 ace-env ,执行 2. **创建目录结构**
```bash
mkdir -p core work ace-env
```
`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` 3. **挂载 overlay**
```bash
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
```
随后chroot进入进行安装操作,直接进行 apt install 或其他都可以,完成后解除挂载 ./ace-env 4. **chroot 安装**chroot 进入 `./ace-env` 进行安装操作,可以使用 `apt install` 或其他方式
你便得到了: 5. **卸载并打包**:完成后解除挂载 `./ace-env`
* core: 保存新增文件 您将得到:
* work: 保存变更信息 - **core**:保存新增文件
- **work**:保存变更信息
将这两个目录权限设置为 755 后放入对应的目录进行 apm 打包。
需把这两个目录重新拥有并权限换成755后放入对应的目录进行 apm 打包 ## APM 软件包测试
你也可以测试一下刚刚打包的软件 可以测试刚刚打包的软件
```bash
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 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
```
即可只读挂载。这一步 apm run 包名 会帮你做好。 即可只读挂载。`apm run 包名` 会自动完成:
- 寻找 `/var/lib/apm/包名/` 是否存在
- 根据 `info` 文件(和可选的 `info_layer_override`)合成 fuse-overlayfs 参数进行挂载
- 使用 ACE 工具 chroot 进入并启动应用
> apm run 包名: 寻找 /var/lib/apm/包名/是否存在。若存在,根据info文件合成 fuser-overlayfs 参数进行挂载,随后用ACE工具chroot进入进行启动 使用 `./ace-run` 即可进入容器环境,测试您安装的应用。
./ace-run 即可进入,可以尝试启动一下刚刚安装的应用
## APM 打包 ## APM 打包
使用 `dpkg-deb --build 软件包目录 输出目录` 即可进行打包 使用以下命令进行打包
```bash
dpkg-deb --build 软件包目录 输出目录
```
## APM 底层 Base Runtime 的构建 ## APM 底层 Base Runtime 的构建
详见 https://gitee.com/amber-ce/amber-pm-common 详见 https://gitee.com/amber-ce/amber-pm-common
---
**备注**:APM 打包工具和转换器会为您自动处理大部分复杂操作,手动打包主要用于特殊情况或自定义需求。
+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
View File
@@ -0,0 +1 @@
@VERSION@=1.1.5
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 &
;; ;;
+467 -183
View File
@@ -5,45 +5,51 @@ 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
if [ ${#BASENAMES[@]} -eq 0 ] || [ -z "$DEB_PATH" ]; then
log.error "错误:非手动模式下至少需要一个 --base 参数 且 必须提供 DEB 文件路径"
usage usage
exit 1 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,368 @@ 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 mount -t overlay overlay \ 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情况)
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]}"
local filename=$(basename "$file")
echo " $((i+1)). $filename"
# 检查是否是符号链接
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
echo " → 解析为: $(basename "$resolved_file")"
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 filename=$(basename "$file")
local dest_path="$entries_dir/applications/$filename"
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 filename=$(basename "$file")
local dest_path="$entries_dir/applications/$filename"
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 filename=$(basename "$file")
echo " $((i+1)). $filename"
# 检查是否是符号链接
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
echo " → 解析为: $(basename "$resolved_file")"
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 filename=$(basename "$file")
local dest_path="$entries_dir/icons/$filename"
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 filename=$(basename "$file")
local dest_path="$entries_dir/icons/$filename"
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"
log.info "处理桌面文件: $desktop_file"
# 尝试用 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 "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 }
if [ "$DESKTOP_MODIFIED" = false ]; then # 4. 如果有 DEB 文件,进行自动化的检查、解包与修改
log.info "未找到需要修改的.desktop文件" if [ -n "$DEB_PATH" ]; then
fi
# 重新打包修改后的DEB # 在融合环境中更新包列表并做 dry-run 检查(如果 ace-run-pkg aptss 可用)
MODIFIED_DEB_PATH="$CRAFT_DIR/modified_${ORIG_PKGNAME}.deb" log.info "在融合环境中测试安装 DEB 包(dry-run..."
log.info "重新打包修改后的DEB: $MODIFIED_DEB_PATH" 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包可能无法在基础环境中安装"
mkdir -p "$MODIFIED_DEB_DIR/data" log.error "请检查依赖关系或基础环境是否兼容"
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 exit 1
fi fi
log.info "安装前检查通过,准备进行提取与修改..."
log.info "DEB包修改完成,新包路径: $MODIFIED_DEB_PATH" # 提取 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"
# 实际安装修改后的DEB包 dpkg -x "$DEB_PATH" "$EXTRACT_DIR"
if ! sudo -E /var/lib/apm/apm/files/ace-run-pkg ssaudit "$MODIFIED_DEB_PATH" --native --no-create-desktop-entry; then dpkg -e "$DEB_PATH" "$MODIFIED_DEB_DIR/DEBIAN"
log.error "错误:修改后的DEB包安装失败"
# 处理 .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 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"
fi fi
log.info "修改后的DEB包安装完成" # 清理 apt 缓存
sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss clean || true
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 包结构
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 +596,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 +608,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(如果存在)
if [ -n "$ORIG_PKGNAME" ] && [ -d "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries" ]; then
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 "复制融合环境文件..." log.info "复制融合环境文件..."
sudo cp -r "$CRAFT_DIR"/{core,work} "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME/files/" 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,27 +651,37 @@ 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" || {
fakeroot dpkg-deb -Z xz --build "$PKG_BUILD_DIR" "$OUTPUT_DEB" log.error "错误:打包 APM 包失败"
exit 1
}
log.info "转换完成!" log.info "转换完成!"
log.info "生成的APM包: $OUTPUT_DEB" log.info "生成的APM包: $OUTPUT_DEB"
@@ -409,5 +689,9 @@ 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
+30 -5
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,6 +46,7 @@ Commands:
-h, --help 显示此帮助信息 -h, --help 显示此帮助信息
-v, --version 展示APM版本号 -v, --version 展示APM版本号
本 APM 具有兔兔伯爵,女武神装甲和超级大运之力。
EOF EOF
} }
@@ -62,10 +63,8 @@ apm_exec(){
while : ; do while : ; do
# 构建info文件的路径 # 构建info文件的路径
next_info_file="${current_dir}/info" next_info_file="${current_dir}/info"
# echo "${current_dir}/info"
# 检查info文件是否存在 # 检查info文件是否存在
if [[ ! -f "$next_info_file" ]]; then if [[ ! -f "$next_info_file" ]]; then
# log.debug "No more info files found, stopping recursion."
break break
fi fi
@@ -87,13 +86,39 @@ apm_exec(){
# 尝试获取下一个依赖信息的路径 # 尝试获取下一个依赖信息的路径
local next_basedir=$(tail -n 1 "$next_info_file") local next_basedir=$(tail -n 1 "$next_info_file")
if [[ -z "$next_basedir" || ! -d "${PATH_PREFIX}/var/lib/apm/${next_basedir}" ]]; then if [[ -z "$next_basedir" || ! -d "${PATH_PREFIX}/var/lib/apm/${next_basedir}" ]]; then
log.debug "No further dependencies found, ending recursion."
break break
fi fi
# 更新当前目录,递归处理下一个依赖 # 更新当前目录,递归处理下一个依赖
current_dir="${PATH_PREFIX}/var/lib/apm/${next_basedir}" current_dir="${PATH_PREFIX}/var/lib/apm/${next_basedir}"
done done
# 添加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 file: $override_file"
local override_dirs=()
# 读取override文件并构建override目录数组
while IFS= read -r basedir; do
[[ -z "$basedir" ]] && continue
# 检查override目录是否存在
if [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env" ]]; then
override_dirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/ace-env")
elif [[ -d "${PATH_PREFIX}/var/lib/apm/${basedir}/files/core" ]]; then
override_dirs+=("${PATH_PREFIX}/var/lib/apm/${basedir}/files/core")
else
log.warn "Neither ace-env nor core directory found for override base: $basedir"
fi
done < "$override_file"
# 将override目录插入到现有lowerdirs数组的最前面(最左侧/最顶层)
if [[ ${#override_dirs[@]} -gt 0 ]]; then
log.debug "Adding override directories to the top layer"
lowerdirs=("${override_dirs[@]}" "${lowerdirs[@]}")
fi
fi
# 检查是否找到了有效的lowerdir # 检查是否找到了有效的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"
@@ -110,7 +135,7 @@ apm_exec(){
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}" 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} "$@" 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
+12 -11
View File
@@ -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
@@ -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