Compare commits

..

98 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
shenmo7192 9f761de3fc 准备1.1.3更新 2025-11-10 19:48:47 +08:00
shenmo7192 16c1c819bd 删除无用的ace-run,调整挂载策略 2025-11-10 11:38:26 +08:00
shenmo7192 7f7ba431a8 1.1.3 支持 APM 应用提权 2025-11-10 11:35:35 +08:00
shenmo7192 92d0309713 dos2unix 2025-11-06 12:25:01 +08:00
shenmo7192 b3063e025a update README.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-04 11:45:00 +00:00
shenmo7192 be0974a508 update README.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-04 11:43:42 +00:00
shenmo7192 38c3309d35 1.1.2-1 2025-11-03 14:59:46 +08:00
shenmo7192 211b18a98b 修复-在银河麒麟上安装到 /usr/share
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-03 06:44:53 +00:00
shenmo7192 c34144a1c1 删除无用的dirs
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-02 04:13:24 +00:00
shenmo7192 8838d900f0 清理干净
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-11-01 04:34:20 +00:00
shenmo7192 0f6780e4f4 completion没改过来 2025-11-01 08:57:27 +08:00
shenmo7192 3edefa0243 提交 README 2025-11-01 00:26:58 +08:00
shenmo7192 0f9a4ed76a 初步支持沙箱化运行应用 2025-11-01 00:21:27 +08:00
shenmo7192 7b8ceb8328 忘记改下面了 2025-10-31 23:38:00 +08:00
shenmo7192 c54a9d39c2 update converter 2025-10-31 23:34:15 +08:00
shenmo7192 a2b7bc9826 ensure_dirs 2025-10-31 23:13:14 +08:00
shenmo7192 40809464f2 尝试整个主目录进行沙箱 2025-10-31 23:08:48 +08:00
shenmo7192 31c4ee9c25 update logs 2025-10-31 21:15:58 +08:00
shenmo7192 908f3ab9de 尝试性加入主目录沙箱--Wine 2025-10-31 21:09:16 +08:00
shenmo7192 7b06cf293b 修复 无法转换包的问题,提示需要安装dpkg;修复 apm debug 失效的问题 2025-10-31 13:04:38 +08:00
shenmo7192 137460768f update: APM upgrade notifier 2025-10-31 12:52:22 +08:00
shenmo7192 c3486af9a5 feat: 支持在fedora和arch上直接打包
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-30 07:24:47 +00:00
shenmo7192 9bbcb06c59 Revert "尝试让ace-run也挂载到系统的icon"
This reverts commit 5f55cf19360a891681bd787fafafe946adb5c1df.
2025-10-30 05:58:39 +00:00
shenmo7192 1c7ce04f42 update linyaps.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-30 05:01:43 +00:00
shenmo7192 d13b0b596b update linyaps.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-30 05:00:11 +00:00
shenmo7192 0d41828ece add linyaps.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-30 04:59:56 +00:00
shenmo7192 f8ce04cae3 尝试让ace-run也挂载到系统的icon
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-30 04:23:47 +00:00
shenmo7192 6b4d95b363 apm logo small
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-29 06:32:47 +00:00
shenmo7192 f9fd0020c2 删除部分无用文件;不再修改主机名 2025-10-29 11:12:47 +08:00
shenmo7192 7a0b949bd1 update Packaging-demo/README.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-28 13:21:43 +00:00
shenmo7192 021279310f update README.md.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-28 11:38:15 +00:00
shenmo7192 338a3f5d93 支持 apm show 指令
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-28 11:14:15 +00:00
shenmo7192 48b0b0b5a1 update src/usr/bin/apm.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-28 11:09:33 +00:00
Ving 877bf82f6c !5 更新软件主图标与 README.md
* update README.md.
* update README.md.
* update README.md.
* update README.md.
* 删除文件 src/var/lib/apm/files/.keep
* 更新软件主图标
* 新建 files
* 更新软件主图标
2025-10-28 11:08:40 +00:00
shenmo7192 ac6846a64a update src/usr/bin/apm.
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-28 08:32:24 +00:00
shenmo7192 b2ed2974b9 完成文档 2025-10-28 16:27:15 +08:00
shenmo7192 128944d7d4 修改文档 2025-10-28 16:23:34 +08:00
shenmo7192 910216a457 convert 只输入最表层的依赖
Signed-off-by: shenmo <jifengshenmo@outlook.com>
2025-10-27 06:49:31 +00:00
shenmo7192 48b06ca964 1.0.10 2025-10-27 12:55:53 +08:00
shenmo7192 1cb22d8465 修复convert无法正确写入的问题 2025-10-27 12:54:49 +08:00
shenmo7192 0d368d73d9 写错了变量名称 2025-10-27 12:45:36 +08:00
shenmo7192 f73645a024 去除debug信息 2025-10-27 12:37:36 +08:00
shenmo7192 e46affc340 1.0.10 2025-10-27 12:36:48 +08:00
shenmo7192 c5fd74b513 更改spec以和实际一致 2025-10-27 11:42:05 +08:00
shenmo7192 1c492b165d 支持依赖解析 2025-10-27 11:29:37 +08:00
42 changed files with 1994 additions and 662 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. 修复程序准备就绪后,我们将发布安全更新,并在适当的时候公开致谢。
再次感谢您为保障社区安全所做的负责任的行为!
+380
View File
@@ -0,0 +1,380 @@
# APM 软件包打包流程
本文档为开发者准备,若您只是想从 deb 软件包打包 APM 软件包,您可以通过 `amber-pm-convert` 指令进行全自动一键转换。
通过 `apm search amber-pm-` 即可搜索到所有可用的 base 列表。
---
## APM 软件包结构规范
在阅读前,请确保您对 OverlayFS 有了基本的了解。
OverlayFS 原理解析:
[https://www.cnblogs.com/arnoldlu/p/13055501.html](https://www.cnblogs.com/arnoldlu/p/13055501.html)
---
## OverlayFS 层叠顺序说明
APM 使用 OverlayFS 来管理软件包的文件系统层级,从上到下的层叠顺序为:
1. **Upperdir**
当前包的可写层:`files/core/`
2. **Info Layer Override**
`info_layer_override` 指定的覆盖层,位于所有依赖层之上
3. **依赖层**
`info` 文件递归解析出的所有依赖包
4. **底层 Runtime**
最基础的运行时环境(如 `amber-pm-bookworm`
这种层叠结构允许上层文件覆盖下层文件,实现灵活、高效的依赖管理与环境定制。
---
## APM 软件包目录结构示例
一个典型的 APM 应用或中层依赖包应当包含以下内容:
```
├── DEBIAN
│ ├── control
│ └── postinst
└── var
└── lib
└── apm
└── eom
├── entries
│ ├── applications
│ ├── doc
│ ├── glib-2.0
│ └── man
├── files
│ ├── core
│ └── work
├── info
├── info_layer_override # 可选
└── info_env # 可选(高级功能)
```
---
## DEBIAN 目录说明
包含软件包的基本信息和依赖环境声明。
### control 文件示例
```
Package: eom
Version: 1.26.0-2-apm
Architecture: amd64
Maintainer: APM Converter <apm-convert@spark-app.store>
Depends: amber-pm-bookworm
Installed-Size: 45228
Description: APM converted package from eom
This package was automatically converted from the original deb package.
Based on: amber-pm-bookworm
```
字段说明:
* **Package**
包名,应当唯一。使用转换器时默认与原 deb 包名一致
* **Version**
软件包版本号,转换器会自动追加 `-apm`
* **Architecture**
架构信息,遵循 dpkg 规范
* **Depends**
直接依赖的 base 包名
* **Installed-Size**
安装后大小,转换器自动计算
* **Description**
软件包描述信息
---
### postinst 文件
```
#!/bin/bash
PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE"
if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then
echo "清理卸载残留"
rm -rf "/var/lib/apm/$PACKAGE_NAME"
for username in $(ls /home); do
if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then
rm -rf "/home/$username/.apm/$PACKAGE_NAME"
fi
done
else
echo "非卸载,跳过清理"
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
```
APM 会递归解析该 base 的 `info` 文件,直到找到最底层 runtime(如 `amber-pm-bookworm`)。
> 使用多层依赖并非强制,但合理拆分 base 能显著减小包体积。
> 可用的 base 列表可通过:
>
> ```
> apm search amber-pm-
> ```
>
> 查看。
---
## info_layer_override 文件(覆盖层)
`info_layer_override` 是一个可选文件,用于在**所有依赖层之上**插入额外覆盖层。
### 使用场景
1. 覆盖依赖中的特定库版本(如 mesa)
2. 覆盖默认配置文件
3. 提供特殊运行环境
### 规则说明
* 语法与 `info` 完全一致
* 每行一个包名
* 层级位置:
```
upperdir
info_layer_override
info 递归依赖
```
### 示例
`info`
```
amber-pm-bookworm
```
`info_layer_override`
```
amber-pm-bookworm-mesa
```
最终 lowerdir 顺序:
```
amber-pm-bookworm-mesa:amber-pm-bookworm
```
---
## info_env(环境变量层 · 高级功能)
`info_env` 是一个 **可选的高级特性**,用于为 APM 容器运行时提供**分层的环境变量配置能力**。
### 功能概述
* 为软件包及其依赖提供环境变量
* 支持 **多层叠加**
* **上层自动覆盖下层**
* 与 OverlayFS 层级顺序完全一致
* 不执行 shell 代码,仅解析键值对,安全可靠
---
### info_env 文件位置
```
/var/lib/apm/<包名>/info_env
```
---
### 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` 主要用于 **特殊运行环境、深度定制或调试用途**
View File
+84 -34
View File
@@ -1,50 +1,100 @@
# APM <div align="center">
<img src="https://gitee.com/possibleving/amber-pm/raw/master/amber-pm-logo.png" alt="软件主图标" width="200" height="200"/>
</div>
# <p align="center">APM 琥珀软件包管理器</p>
## 简介
APM 是一款基于 fuse-overlayfsdpkgAmberCE 容器的软件包管理系统,支持在 DebianFedoraArch Linux 等发行版上运行。
APM 目前提供 Debian 12/13 与 deepin 25 基础环境,支持将适配以上环境的应用转换为 APM 应用。
> APM 会自动从主机获取 NVIDIA 驱动文件,因此您无需担心 N 卡加速问题;
>
> 您可在 [src](src/) 目录找到 APM 的源代码;
>
> OverlayFS 原理解析:[https://www.cnblogs.com/arnoldlu/p/13055501.html](https://www.cnblogs.com/arnoldlu/p/13055501.html)。
## 体验
前往右侧的 [发行版](https://gitee.com/amber-ce/amber-pm/releases/) 即可下载体验
完成安装后,根据您的 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
Usage:
apm [COMMAND] [OPTIONS] [PACKAGES...]
Commands:
install 安装软件包
remove 卸载软件包
run <package> 运行指定软件包的可执行文件
sandbox-run <package> 运行指定软件包的可执行文件(主目录沙箱化)
update 更新软件包信息
hold 锁定软件包版本
unhold 解锁软件包版本
full-upgrade 升级全部软件包
list 查看可用软件包信息
search 搜索软件包
download 下载包
show 展示包信息
clean 清除缓存软件包
autoremove 自动移除不需要的包
ssaudit <path> 使用 ssaudit 进行本地软件安装,详情见 spark-store
debug 显示调试系统信息并进入调试环境
amber 彩蛋功能
xmp360 彩蛋功能
bronya 彩蛋功能
-h, --help 显示此帮助信息
-v, --version 展示APM版本号
```
APM 是一款基于 fuse-overlayfs dpkg ACE 的容器软件包管理系统
源码在 src ## APM Deb 包全自动转换器使用方法
原理:https://www.cnblogs.com/arnoldlu/p/13055501.html ```
用法: amber-pm-convert --base <basename> [--base <basename> ...] <deb文件路径> [--pkgname <包名>] [--version <版本号>]
## 体验demo: 查看 https://gitee.com/amber-ce/amber-pm/releases 参数说明:
--basename 必填参数,指定基础环境名称,可多次使用指定多个基础环境
deb文件路径 必填参数,要转换的 Deb 文件路径
--pkgname 可选参数,指定新包的包名(默认使用原 Deb 包名)
--version 可选参数,指定新包的版本号(默认在原版本后追加'-apm'
示例:
amber-pm-convert --base amber-pm-trixie /path/to/package.deb
amber-pm-convert --base amber-pm-bookworm-spark-wine /path/to/package.deb --pkgname new-pkg --version 1.0.0
最下层的 base 在最后,从上到下写 base
制作apm包upperdir的流程 ```
先安装 apm (从release > 注意:APM 软件包为特殊的 Deb 软件包,因此若您在使用 Debian 或其他使用 dpkg 管理软件包的发行版,也可使用 apt 直接将 APM 软件包安装至系统中,同样可供使用。对于此种情况,请使用系统自带的 apt 进行软件包管理。
sudo apm install base包后,在 ## APM 的原理和软件包的介绍
sudo mount -t overlay overlay -o lowerdir='/var/lib/apm/apm/files/ace-env/var/lib/apm/amber-pm-trixie/files/ace-env',upperdir=core/,workdir=work/ ./ace-env 详见 [Packaging-demo](Packaging-demo)。
随后chroot进入进行安装操作,直接进行 apt install 或者其他都可以,完成后 > 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
core: 保存新增文件 ## APM 构建 Tips
work: 保存变更信息
需把这两个目录重新拥有并权限换成755
> 请 `cp -vr src pkg` 来创建一个准备配置的环境,随后 `./build.sh pkg` 即可进行进一步的打包操作
fuse-overlayfs -o lowerdir='/var/lib/apm/apm/files/ace-env/var/lib/apm/amber-pm-trixie/files/ace-env',upperdir=core/,workdir=work/ ./ace-env APM 使用了特殊的精简版 AmberCE 兼容环境,相关的 Tips 见 [Tips](tips.md)。
即可只读挂载。这一步 apm run 包名 会帮你做好。
> apm run 包名: 寻找 /var/lib/apm/包名/是否存在。若存在,根据info文件合成 fuser-overlayfs 参数进行挂载,随后用ACE工具chroot进入进行启动
./ace-run 即可进入,可以尝试启动一下刚刚安装的应用
spec(对于APM内的包):
对于base
/var/lib/apm/包名/files/ace-env 是 lowerdir
对于core
/var/lib/apm/包名/files/core是upperdir
/var/lib/apm/包名/files/work是upperdir的work
/var/lib/apm/包名/files/ace-env是chroot进的目录(需要在打包好的包内加上允许读写这个目录——或者后续换成tmp的挂载点)
/var/lib/apm/包名/info是配置信息,目前只写了依赖的base,后续可以定义默认启动指令等
/var/lib/apm/包名/entries是desktop位置,后续会加到自动展示中
core的依赖需要写base
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

+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
+34
View File
@@ -0,0 +1,34 @@
玲珑官方搞了个这玩意,APM用户这边有人想要那我就写了,其实意义不大
好用就完了,APM又快又简单
| 特性 | 如意玲珑 | 琥珀 APM | Snap | AppImage |
| ------------------------- | ------------------------------- | ------------- | ---------------- | -------------------------------------- |
| 打包桌面应用 | ✔ | ✔ | ✔ | ✔ |
| 打包终端应用 | ✔ | ✔ | ✔ | ✔ |
| 处理服务器应用 | ✔ | ✔ | ✔ | ✘ |
| 打包系统服务(root 权限) | ✘ | ✘ | ✔ | ✘ |
| 主题功能正常 | ✔ | ✔ | ✔ | ✔ |
| 提供库托管服务 | ✔ | ✔ | ✘ | ✘ |
| 库/依赖来源 | 包自身携带 | 包自身携带或使用 APM 中层 Base,用法详见[链接](https://bbs.deepin.org.cn/post/292648) | | |
| SDK | 包自身携带 | 无需专用SDK,复用Debian即可 | | |
| 商业支持 | ✔ | ✘ | ✔ | ✘ |
| 应用商店数量 | 预计 4700+ | 200+常用软件,持续扩充中 | 6600+ | 1300+ |
| 开发工具支持 | linglong-builder | 任意支持部署到debian的工具均支持 | electron-builder | |
| 容器支持 | ✔ | ✔ | ✔ | ◐ (官方不提供,技术上可行) |
| rootless 容器 | ✔ | ✔ | ✘ | ✘ |
| 不安装运行 | ✔ (提供 Bundle 模式) | ◐ (官方不提供,技术上可行) | ✘ | ✔ |
| 不解压运行 | ✔ (提供 Bundle 模式) | ◐ (官方不提供,技术上可行) | ✔ | ✔ |
| 自分发/绿色格式分发 | ✔ | ◐ (官方不提供,技术上可行) | ✘ | ✔ |
| 支持 Wine 应用运行 | ✔ | ✔ | ◐ (理论可行) | ◐ (使用 LD 修改 open 调用,兼容性差) |
| 离线环境支持 | ✔ | ✔ | ✔ | ✔ |
| 权限管理 | ✔ | ✘ | ✔ | ✘ |
| 中心仓库 | mirror-repo-linglong.deepin.com | 星火应用商店 | Snap Store | AppImageHub |
| 多版本共存 | ✔ | ✔ | ✔ | ✔ |
| 点对点分发 | ✔ | ✔ | ✔ | ✔ |
| 多镜像源加速分发 | ✘ | ✔ | ✘ | ◐ (官方不提供,技术上可行) |
| 作为普通安装包直接安装到宿主机 | ✘ | ✔ | ✘ | ✘ |
| 自定义生成 runtime base | ✘ | ✔ | ✘ | ✘ |
| 多级layer自动管理 | ◐ (理论可行) | ✔ | ✘ | ✘ |
| 一键直接转换 Debian 标准软件包 | ✘ | ✔ | ✘ | ✘ |
| 应用升级 | 仓库升级 | 仓库升级 | 仓库升级 | 官方工具升级 |
+4 -3
View File
@@ -1,10 +1,11 @@
Package: apm Package: apm
Source: amber-ce Source: amber-ce
Version: 1.0.9 Version: @VERSION@
Architecture: amd64 Architecture: amd64
Maintainer: shenmo <shenmo@spark-app.store> Maintainer: shenmo <shenmo@spark-app.store>
Installed-Size: 48716 Installed-Size: 49000
Depends: bubblewrap, flatpak, policykit-1 | pkexec | polkit-1 | polkit, systemd, procps,coreutils,fuse-overlayfs,xz-utils 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
Section: misc Section: misc
Conflicts: ace-host-integration Conflicts: ace-host-integration
Priority: optional Priority: optional
+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 &
;; ;;
+10
View File
@@ -10,6 +10,16 @@ if [ "$1" = "remove" ] || [ "$1" = "purge" ];then
echo "清理卸载残留" echo "清理卸载残留"
rm -rf /var/lib/apm/ rm -rf /var/lib/apm/
for username in $(ls /home)
do
echo /home/$username
if [ -d "/home/$username/.apm/" ]
then
rm -fr "/home/$username/.apm/"
fi
done
else else
echo "非卸载,跳过清理" echo "非卸载,跳过清理"
fi fi
+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.
+574 -161
View File
@@ -5,42 +5,53 @@ 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
log.error "若想使用APM软件包转换器,您需先安装dpkg"
exit 1
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 base上 --base base中 --base base下 /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")
shift 2 shift 2
;; ;;
--pkgname) --pkgname)
@@ -51,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
@@ -64,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
# 检查是否已挂载,避免重复挂载 # 检查是否已挂载,避免重复挂载
@@ -112,38 +147,77 @@ cleanup() {
# 设置退出时清理 # 设置退出时清理
trap cleanup EXIT trap cleanup EXIT
# 2. 检查原DEB包信息 # 递归获取info文件中的依赖 (会把新依赖追加到 BASENAMES 数组中)
log.info "检查原DEB包信息..." get_recursive_basenames() {
ORIG_PKGNAME=$(dpkg -f "$DEB_PATH" Package) local basename="$1"
ORIG_VERSION=$(dpkg -f "$DEB_PATH" Version) # 注意:根据之前脚本结构,info 存放在 /var/lib/apm/apm/files/ace-env/var/lib/apm/<basename>/info
ORIG_ARCH=$(dpkg -f "$DEB_PATH" Architecture) local base_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/$basename"
local info_file="$base_dir/info"
log.info "原包名: $ORIG_PKGNAME" if [ -f "$info_file" ]; then
log.info "原版本: $ORIG_VERSION" log.info "读取info文件: $info_file"
log.info "原架构: $ORIG_ARCH" while IFS= read -r base; do
[[ -z "$base" ]] && continue
# 如果依赖的 base 没有被记录过,则递归添加
local found=false
for existing in "${BASENAMES[@]}"; do
if [ "$existing" = "$base" ]; then
found=true
break
fi
done
if [ "$found" = false ]; then
BASENAMES+=("$base")
get_recursive_basenames "$base"
fi
done < "$info_file"
else
log.info "未找到info文件,跳过: $info_file"
fi
}
# 设置新包名和版本 # 递归获取所有基础环境(从用户输入的 base 开始)
NEW_PKGNAME="${PKGNAME:-$ORIG_PKGNAME}" for BASE in "${BASENAMES[@]}"; do
get_recursive_basenames "$BASE"
done
# 如果用户传了 DEB,则读取原包信息(否则跳过)
if [ -n "$DEB_PATH" ]; then
log.info "检查原DEB包信息..."
ORIG_PKGNAME=$(dpkg -f "$DEB_PATH" Package 2>/dev/null || echo "")
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_VERSION:-未知}"
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_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"
# 3. 构建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"
@@ -153,177 +227,502 @@ 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 后脚本将继续。"
# 启动交互 shell,保留环境变量(使用 sudo -E)
sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || {
log.warn "ace-run-pkg shell 退出或出现错误,继续脚本..."
}
log.info "用户已退出手动 shell,脚本将继续。"
# 如果没有 DEB,询问是否要进行后续打包(允许返回 shell)
if [ -z "$DEB_PATH" ]; then
while true; do
echo ""
read -r -p "未提供 DEB 文件。是否现在进行新 APM 包的自动打包? (y = 打包, r = 返回 shell, n = 跳过打包) [y/r/n]: " yn
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
# 到这里:非手动模式或手动模式退出后继续(如果是非手动并且有 DEB,继续原本流程)
# 函数:查找并处理符号链接,返回实际文件路径
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
# 如果不是符号链接或解析失败,返回原文件
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
# 处理.desktop文件
DESKTOP_MODIFIED=false
find "$EXTRACT_DIR" -name "*.desktop" | while read -r desktop_file; do
log.info "处理桌面文件: $desktop_file" log.info "处理桌面文件: $desktop_file"
DESKTOP_MODIFIED=true
# 在Exec和TryExec行前追"apm run $NEW_PKGNAME" # 检查文件是否已经处理过(避免重复添加 apm run
# 处理Exec行 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 if grep -q '^Exec=' "$desktop_file"; then
sed -i 's/^Exec=\(.*\)$/Exec=apm run '"$NEW_PKGNAME"' \1/' "$desktop_file" sed -i "s|^Exec=\(.*\)$|Exec=apm run $pkgname \1|" "$desktop_file"
fi fi
# 处理TryExec行 # 删除 TryExec
if grep -q '^TryExec=' "$desktop_file"; then if grep -q '^TryExec=' "$desktop_file"; then
sed -i 's/^TryExec=\(.*\)$/TryExec=apm run '"$NEW_PKGNAME"' \1/' "$desktop_file" sed -i '/^TryExec=/d' "$desktop_file"
log.info "已删除 TryExec 行"
fi fi
# 处理Icon路径 # 处理 Icon 路径(若以 / 开头)
icon_line=$(grep "^Icon=" "$desktop_file") if grep -q '^Icon=/' "$desktop_file"; then
if [[ "$icon_line" == "Icon=/"* ]]; then sed -i "s|^Icon=/|Icon=/var/lib/apm/apm/files/ace-env/var/lib/apm/$pkgname/files/core/|" "$desktop_file"
sed -i 's|^Icon=/|Icon=/var/lib/apm/apm/files/ace-env/var/lib/apm/'"$NEW_PKGNAME"'/files/core/|' "$desktop_file"
fi fi
# 添加X-APM-APPID # 添加 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 }
if [ "$DESKTOP_MODIFIED" = false ]; then
log.info "未找到需要修改的.desktop文件"
fi
# 重新打包修改后的DEB # 4. 如果有 DEB 文件,进行自动化的检查、解包与修改
MODIFIED_DEB_PATH="$CRAFT_DIR/modified_${ORIG_PKGNAME}.deb" if [ -n "$DEB_PATH" ]; then
log.info "重新打包修改后的DEB: $MODIFIED_DEB_PATH"
# 复制修改后的文件结构到打包目录 # 在融合环境中更新包列表并做 dry-run 检查(如果 ace-run-pkg aptss 可用)
mkdir -p "$MODIFIED_DEB_DIR/data" log.info "在融合环境中测试安装 DEB 包(dry-run..."
cp -r "$EXTRACT_DIR"/* "$MODIFIED_DEB_DIR/" 2>/dev/null || true 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
# 使用fakeroot重新打包 log.error "错误:安装前检查失败,DEB包可能无法在基础环境中安装"
cd "$MODIFIED_DEB_DIR" && fakeroot dpkg-deb --build -Z none . "$MODIFIED_DEB_PATH" log.error "请检查依赖关系或基础环境是否兼容"
cd - > /dev/null
if [ ! -f "$MODIFIED_DEB_PATH" ]; then
log.error "错误:重新打包DEB失败"
exit 1 exit 1
fi fi
log.info "安装前检查通过,准备进行提取与修改..."
sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg mkdir -p /var/cache/apt/archives/partial
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 文件包含原始输入的基础环境)..."
for BASENAME in "${BASENAMES[@]}"; do : > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info" 2>/dev/null || true
echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME/info" for BASENAME in "${BASENAMES_ORIG[@]}"; do
echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info"
log.info " 写入: $BASENAME" log.info " 写入: $BASENAME"
done done
# 创建postinst脚本 log.info "创建 info_debug 文件(包含所有递归依赖的基础环境)..."
cat > "$PKG_BUILD_DIR/DEBIAN/postinst" << 'EOF' : > "$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'
#!/bin/bash #!/bin/bash
PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE" 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
if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then
rm -fr "/home/$username/.apm/$PACKAGE_NAME"
fi
done
else else
echo "非卸载,跳过清理" echo "非卸载,跳过清理"
fi fi
EOF EOF
chmod +x "$PKG_BUILD_DIR/DEBIAN/postinst" 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
@@ -333,27 +732,37 @@ calculate_directory_size() {
fi fi
} }
# 构建依赖字符串 - 包含所有base # 构建依赖字符串 - 包含所有用户原始输入的 base(用于 control
DEPENDS_STR=$(IFS=,; echo "${BASENAMES[*]}") 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@localhost> 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 $DEB_PATH 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[*]} 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 --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"
@@ -361,5 +770,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
+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 &
+39 -2
View File
@@ -4,6 +4,39 @@ if [[ ! -e "/usr/share/gxde-api" ]] && ! grep -q "Kylin" /etc/os-release; then
exit 0 # No needed exit 0 # No needed
fi fi
# 确定目标目录
if grep -q "Kylin" /etc/os-release; then
TARGET_BASE="/usr/share"
echo "检测到麒麟系统,使用目标目录: $TARGET_BASE"
else
TARGET_BASE="/usr/local/share"
echo "检测到GXDE环境,使用目标目录: $TARGET_BASE"
fi
function ensure_dir() {
local dir="$1"
# 检查目录是否为空
if [ -z "$dir" ]; then
echo "错误: 目录路径不能为空"
return 1
fi
# 检查目录是否存在
if [ ! -d "$dir" ]; then
echo "目录 '$dir' 不存在,正在创建..."
if mkdir -p "$dir"; then
echo "成功创建目录 '$dir'"
return 0
else
echo "错误: 无法创建目录 '$dir'"
return 1
fi
else
return 0
fi
}
# 函数:检查目录并创建符号链接 # 函数:检查目录并创建符号链接
process_directory() { process_directory() {
local source_dir="$1" local source_dir="$1"
@@ -18,13 +51,17 @@ process_directory() {
fi fi
} }
# 使用动态确定的目标目录
ensure_dir "$TARGET_BASE/applications/"
ensure_dir "$TARGET_BASE/icons/"
# 处理 applications 目录 # 处理 applications 目录
process_directory "/var/lib/apm/apm/files/ace-env/amber-ce-tools/data-dir/applications/" \ process_directory "/var/lib/apm/apm/files/ace-env/amber-ce-tools/data-dir/applications/" \
"/usr/local/share/applications/" "Applications" "$TARGET_BASE/applications/" "Applications"
# 处理 icons 目录 # 处理 icons 目录
process_directory "/var/lib/apm/apm/files/ace-env/amber-ce-tools/data-dir/icons/" \ process_directory "/var/lib/apm/apm/files/ace-env/amber-ce-tools/data-dir/icons/" \
"/usr/local/share/icons/" "Icons" "$TARGET_BASE/icons/" "Icons"
# 等待所有后台任务完成 # 等待所有后台任务完成
wait wait
+148
View File
@@ -0,0 +1,148 @@
#!/bin/bash
# 发送通知
function get_upgradable_list(){
output=$(env LANGUAGE=en_US amber-pm-debug aptss list --upgradable | awk NR\>1)
IFS_OLD="$IFS"
IFS=$'\n'
for line in $output ; do
PKG_NAME=$(echo $line | awk -F '/' '{print $1}')
PKG_NEW_VER=$(echo $line | awk -F ' ' '{print $2}')
PKG_CUR_VER=$(echo $line | awk -F ' ' '{print $6}' | awk -F ']' '{print $1}')
echo "${PKG_NAME} ${PKG_NEW_VER} ${PKG_CUR_VER}"
done
IFS="$IFS_OLD"
}
function get_current_user() {
# 优先通过 who 命令获取用户
local user
user=$(who | awk '{print $1}' | head -n 1 2>/dev/null)
# 如果 who 无输出,则通过 loginctl 获取
if [[ -z "$user" ]]; then
user=$(loginctl list-sessions --no-legend 2>/dev/null | awk '{print $3}' | head -n 1)
fi
# 返回最终结果(可能为空)
echo "${user}"
}
function notify-send() {
# Detect user using the display
local user=$(get_current_user)
# Detect uid of the user
local uid=$(id -u $user)
sudo -u $user DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${uid}/bus notify-send "$@"
}
# 检测网络链接畅通
function network-check() {
# 超时时间
local timeout=15
# 目标网站
local target=www.baidu.com
# 获取响应状态码
local ret_code=$(curl -I -s --connect-timeout ${timeout} ${target} -w %{http_code} | tail -n1)
if [ "$ret_code" = "200" ]; then
# 网络畅通
return 0
else
# 网络不畅通
return 1
fi
}
# 初始化等待时间和最大等待时间
initial_wait_time=15 # 初始等待时间 15 秒
max_wait_time=$((12 * 3600)) # 最大等待时间 12 小时
# 检测网络,若不通则进行重试,采用指数退避算法
wait_time=$initial_wait_time
while ! network-check; do
echo "$TRANSHELL_CONTENT_NETWORK_FAIL"
echo "Waiting for network to recover... Retrying in ${wait_time} seconds."
sleep $wait_time
wait_time=$((wait_time * 2)) # 等待时间翻倍
if [ $wait_time -gt $max_wait_time ]; then
wait_time=$max_wait_time # 最大等待时间限制为12小时
fi
done
# 每日更新星火源文件
updatetext=$(LANGUAGE=en_US apm update 2>&1)
# 在网络恢复后,继续更新操作
retry_count=0
max_retries=12 # 最大重试次数,防止死循环
until ! echo $updatetext | grep -q "E:"; do
if [ $retry_count -ge $max_retries ]; then
echo "Reached maximum retry limit for apm update."
exit 1
fi
echo "Update failed...Will retry in 15sec"
sleep 15
updatetext=$(LANGUAGE=en_US apm update 2>&1)
retry_count=$((retry_count + 1))
done
update_app_number=$(env LANGUAGE=en_US apm list --upgradable 2>/dev/null | grep -c upgradable)
echo "update_app_number is $update_app_number"
if [ "$update_app_number" -le 0 ]; then
exit 0
fi
# 获取用户选择的要更新的应用
PKG_LIST="$(get_upgradable_list)"
# 指定分隔符为 \n
IFS_OLD="$IFS"
IFS=$'\n'
for line in $PKG_LIST; do
# PKG_NAME=$(echo $line | awk -F ' ' '{print $1}')
# PKG_NEW_VER=$(echo $line | awk -F ' ' '{print $2}')
# PKG_CUR_VER=$(echo $line | awk -F ' ' '{print $3}')
# amber-pm-debug dpkg --compare-versions $PKG_NEW_VER le $PKG_CUR_VER
#
# if [ $? -eq 0 ]; then
# let update_app_number=$update_app_number-1
# continue
# fi
# 检测是否是 hold 状态
PKG_STA=$(amber-pm-debug dpkg-query -W -f='\''\${db:Status-Want}'\' $PKG_NAME)
#PKG_STA=$(dpkg-query -W -f='${db:Status-Want}' $PKG_NAME)
if [ "$PKG_STA" = "hold" ]; then
let update_app_number=$update_app_number-1
fi
done
# 还原分隔符
IFS="$IFS_OLD"
if [ $update_app_number -le 0 ]; then
exit 0
fi
# 如果都是hold或者版本一致的那就直接退出,否则把剩余的给提醒了
# TODO: 除了apt-mark hold之外额外有一个禁止检查列表
notify-send -a apm "APM 琥珀应用包" "有 $update_app_number 个应用可以更新啦,apm list --upgradable 以查看" || true # Some machine don't have bus, or who command just print nothing.
+177 -30
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
VERSION=1.0.9 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/
@@ -17,78 +17,187 @@ APM - Amber Package Manager ${VERSION}
Usage: Usage:
$SCRIPT_NAME [COMMAND] [OPTIONS] [PACKAGES...] $SCRIPT_NAME [COMMAND] [OPTIONS] [PACKAGES...]
Commands: Commands:
install 安装软件包 install 安装软件包
remove 卸载软件包 remove 卸载软件包
run <package> 运行指定软件包的可执行文件
sandbox-run <package> 运行指定软件包的可执行文件(主目录沙箱化)
bwrap-run <package> 运行指定软件包的可执行文件(使用特殊的挂载参数以支持bwrap)
update 更新软件包信息 update 更新软件包信息
hold 锁定软件包版本
unhold 解锁软件包版本
full-upgrade 升级全部软件包
list 查看可用软件包信息
search 搜索软件包
download 下载包 download 下载包
show 展示包信息
clean 清除缓存软件包 clean 清除缓存软件包
autoremove 自动移除不需要的包 autoremove 自动移除不需要的包
full-upgrade 完全升级软件包 ssaudit <path> 使用 ssaudit 进行本地软件安装,详情见 spark-store
run <package> 运行指定软件包的可执行文件
ssaudit <path> 使用 ssaudit 进行软件安装,详情见 spark-store
debug 显示调试系统信息并进入调试环境 debug 显示调试系统信息并进入调试环境
amber 彩蛋功能 amber 彩蛋功能
xmp360 彩蛋功能 xmp360 彩蛋功能
bronya 彩蛋功能 bronya 彩蛋功能
-h, --help 显示此帮助信息 -h, --help 显示此帮助信息
-v, --version 展示APM版本号
本 APM 具有兔兔伯爵,女武神装甲和超级大运之力。
EOF EOF
} }
apm_exec(){ apm_exec(){
# 读取info文件中的所有行,按从下到上的顺序构建lowerdir # ===============================
# 基础变量
# ===============================
local lowerdirs=() local lowerdirs=()
local env_layers=()
local current_dir="${PATH_PREFIX}/var/lib/apm/${coredir}"
local next_info_file=""
local APM_RUN_EXEC=/var/lib/apm/apm/files/ace-run
# 检查info文件是否存在 # ===============================
if [[ ! -f "${PATH_PREFIX}/var/lib/apm/${coredir}/info" ]]; then # 递归读取 info / info_env
log.error "Info file not found for package: $coredir" # ===============================
return 1 while : ; do
next_info_file="${current_dir}/info"
# 记录 info_env(底层优先)
if [[ -f "${current_dir}/info_env" ]]; then
env_layers+=("${current_dir}/info_env")
fi fi
# 读取info文件的每一行 # 没有 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
log.warn "Neither ace-env nor core directory found for base: $basedir" log.warn "Neither ace-env nor core directory found for base: $basedir"
fi fi
done < "${PATH_PREFIX}/var/lib/apm/${coredir}/info" done < "$next_info_file"
# 检查是否找到了有效的lowerdir # 递归到下一个
local next_basedir
next_basedir="$(tail -n 1 "$next_info_file")"
[[ -z "$next_basedir" || ! -d "${PATH_PREFIX}/var/lib/apm/${next_basedir}" ]] && break
current_dir="${PATH_PREFIX}/var/lib/apm/${next_basedir}"
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: $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}" /var/lib/apm/apm/files/ace-run "$@" [[ -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}"
} }
# 调试信息函数 # 调试信息函数
debug_info() { debug_info() {
log.debug "======= APM Debug Information =======" log.debug "======= APM Debug Information ======="
@@ -211,7 +320,7 @@ case "$1" in
apm-nvidia-toggle apm-nvidia-toggle
amber-pm-gxde-desktop-fix amber-pm-gxde-desktop-fix
;; ;;
download|search|policy|list|update|clean) download|search|policy|list|update|clean|show|depends|rdepends|changelog|moo)
command=$1 command=$1
shift shift
amber-pm-debug aptss "$command" "$@" amber-pm-debug aptss "$command" "$@"
@@ -223,6 +332,18 @@ case "$1" in
exit $exit_code exit $exit_code
fi fi
;; ;;
hold|unhold)
command=$1
shift
amber-pm-debug apt-mark "$command" "$@"
exit_code=$?
if [ $exit_code -eq 0 ]; then
log.info "Operation successful"
else
log.error "Error: Operation failed"
exit $exit_code
fi
;;
remove|autoremove|purge|autopurge) remove|autoremove|purge|autopurge)
# 特殊APT命令:移除第一个参数后传递其余参数 # 特殊APT命令:移除第一个参数后传递其余参数
@@ -264,7 +385,7 @@ case "$1" in
fi fi
coredir=$pkg coredir=$pkg
export APM_PKG_NAME=$pkg
# 检测是否有额外命令参数 # 检测是否有额外命令参数
if [ $# -gt 0 ]; then if [ $# -gt 0 ]; then
@@ -277,15 +398,41 @@ case "$1" in
exit 1 exit 1
fi fi
;; ;;
sandbox-run)
# 运行包命令:第二个参数必须是包名
export APM_USE_SANDBOX=1
shift
$0 run "$@"
;;
bwrap-run)
# 运行包命令:使用特殊的挂载参数以支持bwrap
export APM_USE_BWRAP=1
shift
$0 run "$@"
;;
debug) debug)
debug_info shift
debug_info $@
;; ;;
ssaudit) ssaudit)
amber-pm-debug ssaudit "$@" --native amber-pm-debug ssaudit $@ --native
exit_code=$?
if [ $exit_code -eq 0 ]; then
log.info "Operation successful"
else
log.error "Error: Operation failed"
exit $exit_code
fi
amber-pm-debug amber-pm-dstore-patch
amber-pm-gxde-desktop-fix
;; ;;
-h|--help) -h|--help)
show_help show_help
;; ;;
-v|--version)
echo "$VERSION"
;;
amber) amber)
amber_egg amber_egg
;; ;;
@@ -6,7 +6,7 @@ After=apt-daily.service network.target network-online.target systemd-networkd.se
[Service] [Service]
Type=simple Type=simple
RemainAfterExit=yes RemainAfterExit=yes
ExecStart=bash -c "apm clean && apm update" ExecStart=amber-pm-upgrade-notifier
Restart=on-failure Restart=on-failure
RestartSec=10 RestartSec=10
+11
View File
@@ -0,0 +1,11 @@
[Unit]
Description=Timer for APM Daily Update
[Timer]
# 开机后第一次执行
OnBootSec=1min
# 每天执行一次
OnUnitActiveSec=1d
[Install]
WantedBy=timers.target
@@ -44,11 +44,15 @@ _apm()
"update" "update"
"upgrade" "full-upgrade" "dist-upgrade" "upgrade" "full-upgrade" "dist-upgrade"
"run" "run"
"sandbox-run"
"bwrap-run"
"help" "help"
"source" "build-dep" "source" "build-dep"
"clean" "autoclean" "clean" "autoclean"
"download" "changelog" "download" "changelog"
"amber" "amber"
"xmp360"
"bronya"
"debug" "debug"
"depends" "rdepends" "depends" "rdepends"
"policy") "policy")
@@ -66,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
@@ -236,7 +240,7 @@ fi
command grep "^Source: $cur" | sort -u | cut -f2 -d" " ) ) command grep "^Source: $cur" | sort -u | cut -f2 -d" " ) )
return 0 return 0
;; ;;
run) run|sandbox-run|bwrap-run)
COMPREPLY=( $( compgen -W "$(apm_run_compgen)" "$cur" ) ) COMPREPLY=( $( compgen -W "$(apm_run_compgen)" "$cur" ) )
return 0 return 0
;; ;;
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

+91 -30
View File
@@ -1,27 +1,63 @@
#!/bin/bash #!/bin/bash
function bash(){
/usr/bin/bash --rcfile <(cat ~/.bashrc; echo "PS1=\"\[\e[37;40m\][\[\e[32;40m\]\u\[\e[37;40m\]@Amber-PM \[\e[36;40m\]\w\[\e[0m\]]\\\$ \"") $@
}
export -f bash
function ensure_dir() {
local dir="$1"
# 检查目录是否为空
if [ -z "$dir" ]; then
echo "错误: 目录路径不能为空"
return 1
fi
chrootEnvPath="${chrootEnvPath:-$(pwd)/ace-env}" # 检查目录是否存在
if [ ! -d "$dir" ]; then
echo "目录 '$dir' 不存在,正在创建..."
if mkdir -p "$dir"; then
echo "成功创建目录 '$dir'"
return 0
else
echo "错误: 无法创建目录 '$dir'"
return 1
fi
else
return 0
fi
}
chrootEnvPath="${chrootEnvPath:-$(dirname $0)/ace-env}"
APM_PKG_NAME="${APM_PKG_NAME:-apm-general}"
non_root_user=$(who | awk '{print $1}' | head -n 1) non_root_user=$(who | awk '{print $1}' | head -n 1)
uid=$(id -u $non_root_user) uid=$(id -u $non_root_user)
ensure_dir $HOME/.apm/${APM_PKG_NAME}/
# 根据沙盒模式决定是否创建其他目录
#### This part is for args pharm if [ "${APM_USE_SANDBOX:-0}" = "1" ]; then
if [ "$1" = "" ];then ensure_dir $HOME/.apm/${APM_PKG_NAME}/$(basename $(xdg-user-dir DESKTOP))
container_command="bash" ensure_dir $HOME/.apm/${APM_PKG_NAME}/$(basename $(xdg-user-dir DOCUMENTS))
else ensure_dir $HOME/.apm/${APM_PKG_NAME}/$(basename $(xdg-user-dir PICTURES))
container_command="$1" ensure_dir $HOME/.apm/${APM_PKG_NAME}/$(basename $(xdg-user-dir DOWNLOAD))
shift ensure_dir $HOME/.apm/${APM_PKG_NAME}/$(basename $(xdg-user-dir VIDEOS))
for arg in "$@"; do ensure_dir $HOME/.apm/${APM_PKG_NAME}/$(basename $(xdg-user-dir MUSIC))
arg="$(echo "${arg}x" | sed 's|'\''|'\'\\\\\'\''|g')"
arg="${arg%x}"
container_command="${container_command} '${arg}'"
done
fi fi
if [ $# -eq 0 ]; then
container_command="bash"
else
# 正确转义所有参数,处理空格和特殊字符
container_command=""
for arg in "$@"; do
# 使用 printf %q 进行安全的 shell 转义
escaped_arg="$(printf "%q" "$arg")"
container_command="${container_command} ${escaped_arg}"
done
container_command="${container_command# }" # 移除开头的空格
fi
######################################################################################### #########################################################################################
##########合成bwrap 1. 基础函数配置段 ##########合成bwrap 1. 基础函数配置段
# 初始化 EXEC_COMMAND 为 bwrap 基础指令 # 初始化 EXEC_COMMAND 为 bwrap 基础指令
@@ -64,13 +100,6 @@ for directory in "/usr/share/icons"/*; do
fi fi
fi fi
done done
} }
##########合成bwrap 3. 环境变量和目录绑定配置段 ##########合成bwrap 3. 环境变量和目录绑定配置段
# 添加环境变量和其他初始设置 # 添加环境变量和其他初始设置
@@ -83,7 +112,8 @@ ENV_VARS=(
"XDG_DATA_DIRS /amber-ce-tools/additional-data-dir-in-container:\$XDG_DATA_DIRS" "XDG_DATA_DIRS /amber-ce-tools/additional-data-dir-in-container:\$XDG_DATA_DIRS"
) )
BIND_DIRS=( # 基础绑定目录(始终绑定)
BASE_BIND_DIRS=(
"--dev-bind $chrootEnvPath/ /" "--dev-bind $chrootEnvPath/ /"
"--dev-bind-try /media /media" "--dev-bind-try /media /media"
"--dev-bind-try /mnt /mnt" "--dev-bind-try /mnt /mnt"
@@ -100,12 +130,32 @@ BIND_DIRS=(
"--ro-bind-try /usr/share/fonts /usr/local/share/fonts" "--ro-bind-try /usr/share/fonts /usr/local/share/fonts"
"--dev-bind-try /etc/resolv.conf /etc/resolv.conf" "--dev-bind-try /etc/resolv.conf /etc/resolv.conf"
"--dev-bind-try /home /home" "--dev-bind-try /home /home"
"--dev-bind-try $HOME/.apm/${APM_PKG_NAME}/.deepinwine $HOME/.deepinwine"
) )
EXTRA_ARGS=(
"--hostname Amber-PM" # 沙盒模式下的额外绑定目录
"--unshare-uts" SANDBOX_BIND_DIRS=(
"--dev-bind-try $HOME/.apm/${APM_PKG_NAME}/ $HOME/"
"--dev-bind-try $(xdg-user-dir DESKTOP) $(xdg-user-dir DESKTOP)"
"--dev-bind-try $(xdg-user-dir DOCUMENTS) $(xdg-user-dir DOCUMENTS)"
"--dev-bind-try $(xdg-user-dir PICTURES) $(xdg-user-dir PICTURES)"
"--dev-bind-try $(xdg-user-dir DOWNLOAD) $(xdg-user-dir DOWNLOAD)"
"--dev-bind-try $(xdg-user-dir VIDEOS) $(xdg-user-dir VIDEOS)"
"--dev-bind-try $(xdg-user-dir MUSIC) $(xdg-user-dir MUSIC)"
)
# 非沙盒模式下的绑定目录(只绑定.deepinwine
NON_SANDBOX_BIND_DIRS=(
"--dev-bind-try $HOME/.deepinwine $HOME/.deepinwine"
)
# 根据 APM_USE_BWRAP 决定是否添加 CAP_SYS_ADMIN
EXTRA_ARGS=()
if [ "${APM_USE_BWRAP:-0}" != "1" ]; then
EXTRA_ARGS=(
"--cap-add CAP_SYS_ADMIN" "--cap-add CAP_SYS_ADMIN"
) )
fi
EXTRA_SCRIPTS=( EXTRA_SCRIPTS=(
# cursor_theme_dir_integration # cursor_theme_dir_integration
@@ -117,10 +167,23 @@ for var in "${ENV_VARS[@]}"; do
add_env_var $var add_env_var $var
done done
for var in "${BIND_DIRS[@]}"; do # 添加基础绑定目录
for var in "${BASE_BIND_DIRS[@]}"; do
add_command "$var" add_command "$var"
done done
# 根据沙盒模式添加不同的绑定目录
if [ "${APM_USE_SANDBOX:-0}" = "1" ]; then
for var in "${SANDBOX_BIND_DIRS[@]}"; do
add_command "$var"
done
else
for var in "${NON_SANDBOX_BIND_DIRS[@]}"; do
add_command "$var"
done
fi
# 添加额外参数
for var in "${EXTRA_ARGS[@]}"; do for var in "${EXTRA_ARGS[@]}"; do
add_command "$var" add_command "$var"
done done
@@ -136,6 +199,4 @@ add_command "bash -c \"${container_command}\""
# echo "${EXEC_COMMAND}" # echo "${EXEC_COMMAND}"
# 注意: 实际执行时,请确保所有变量(如 $uid, $chrootEnvPath 等)都已正确定义 # 注意: 实际执行时,请确保所有变量(如 $uid, $chrootEnvPath 等)都已正确定义
eval ${EXEC_COMMAND} eval "${EXEC_COMMAND}"
+4 -2
View File
@@ -1,6 +1,9 @@
#!/bin/bash #!/bin/bash
bash(){
/usr/bin/bash --rcfile <(cat ~/.bashrc; echo "PS1=\"\[\e[37;40m\][\[\e[32;40m\]\u\[\e[37;40m\]@Amber-PM \[\e[36;40m\]\w\[\e[0m\]]\\\$ \"") $@
}
export -f bash
chrootEnvPath="${chrootEnvPath:-$(pwd)/ace-env}" chrootEnvPath="${chrootEnvPath:-$(pwd)/ace-env}"
@@ -137,4 +140,3 @@ add_command "bash -c \"${container_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 -2
View File
@@ -104,8 +104,6 @@ sudo -u $(get_current_user) bwrap --dev-bind $chrootEnvPath/ / \
--bind-try /usr/share/themes /usr/local/share/themes \ --bind-try /usr/share/themes /usr/local/share/themes \
--bind-try /usr/share/icons /usr/local/share/icons \ --bind-try /usr/share/icons /usr/local/share/icons \
--bind-try /usr/share/fonts /usr/local/share/fonts \ --bind-try /usr/share/fonts /usr/local/share/fonts \
--hostname Amber-PM \
--unshare-uts \
--dev-bind-try /etc/resolv.conf /etc/resolv.conf \ --dev-bind-try /etc/resolv.conf /etc/resolv.conf \
--dev-bind-try /home /home \ --dev-bind-try /home /home \
locale-gen locale-gen
@@ -114,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
+5 -2
View File
@@ -1,5 +1,10 @@
#!/bin/bash #!/bin/bash
bash(){
/usr/bin/bash --rcfile <(cat ~/.bashrc; echo "PS1=\"\[\e[37;40m\][\[\e[32;40m\]\u\[\e[37;40m\]@Amber-PM \[\e[36;40m\]\w\[\e[0m\]]\\\$ \"") $@
}
export -f bash
curdir=`realpath $0` curdir=`realpath $0`
parent_dir=`dirname $curdir` parent_dir=`dirname $curdir`
pparent_dir=`dirname $parent_dir` pparent_dir=`dirname $parent_dir`
@@ -115,8 +120,6 @@ BIND_DIRS=(
"--dev-bind-try /home /home" "--dev-bind-try /home /home"
) )
EXTRA_ARGS=( EXTRA_ARGS=(
"--hostname Amber-PM"
"--unshare-uts"
"--cap-add CAP_SYS_ADMIN" "--cap-add CAP_SYS_ADMIN"
) )
-155
View File
@@ -1,155 +0,0 @@
#!/bin/bash
curdir=`realpath $0`
parent_dir=`dirname $curdir`
pparent_dir=`dirname $parent_dir`
ppparent_dir=`dirname $pparent_dir`
PKGNAME=`basename $ppparent_dir`
export ACE_PACKAGE_NAME=$PKGNAME
chrootEnvPath=/var/lib/apm/$PKGNAME/files/ace-env
if [ ! -e $chrootEnvPath/finish.flag ];then
if [ "$(id -u)" = "0" ]; then
`dirname $chrootEnvPath`/bin/ace-init
else
pkexec `dirname $chrootEnvPath`/bin/ace-init
fi
fi
non_root_user=$(who | awk '{print $1}' | head -n 1)
uid=$(id -u $non_root_user)
#### This part is for args pharm
if [ "$1" = "" ];then
container_command="bash"
else
container_command="$1"
shift
for arg in "$@"; do
arg="$(echo "${arg}x" | sed 's|'\''|'\'\\\\\'\''|g')"
arg="${arg%x}"
container_command="${container_command} '${arg}'"
done
fi
#########################################################################################
##########合成bwrap 1. 基础函数配置段
# 初始化 EXEC_COMMAND 为 bwrap 基础指令
EXEC_COMMAND="bwrap --dev-bind / / bwrap"
# add_command 函数定义
function add_command() {
# 参数拼接,考虑到转义和空格的处理
for arg in "$@"; do
EXEC_COMMAND="${EXEC_COMMAND} ${arg}"
done
}
function add_env_var() {
local var_name="${1}"
local var_value="${2}"
if [ "$var_value" != "" ]; then
add_command "--setenv $var_name $var_value"
fi
}
##########合成bwrap 2. 特殊需求函数配置段
function cursor_theme_dir_integration() {
local directory=""
if [ "$(id -u)" = "0" ]; then #####We don't want bother root to install themes,but will try to fix the unwriteable issue
mkdir -p $chrootEnvPath/usr/share/icons
chmod 777 -R $chrootEnvPath/usr/share/icons
return
fi
for directory in "/usr/share/icons"/*; do
# 检查是否为目录
if [ -d "$directory" ]; then
# 检查目录中是否存在 cursors 文件
if [ -d "$directory/cursors" ]; then
if [ -w $chrootEnvPath/usr/share/icons ];then
add_command "--ro-bind-try $directory $directory"
fi
fi
fi
done
}
##########合成bwrap 3. 环境变量和目录绑定配置段
# 添加环境变量和其他初始设置
ENV_VARS=(
"FAKEROOTDONTTRYCHOWN 1"
"PULSE_SERVER /run/user/\$uid/pulse/native"
"PATH /amber-ce-tools/bin-override:\$PATH"
"IS_ACE_ENV 1"
"XDG_DATA_DIRS /amber-ce-tools/additional-data-dir-in-container:\$XDG_DATA_DIRS"
)
BIND_DIRS=(
"--dev-bind $chrootEnvPath/ /"
"--dev-bind-try /media /media"
"--dev-bind-try /mnt /mnt"
"--dev-bind-try /tmp /tmp"
"--dev-bind-try /data /data"
"--dev-bind-try /dev /dev"
"--proc /proc"
"--dev-bind /sys /sys"
"--dev-bind /run /run"
"--dev-bind-try /run/user/\$uid/pulse /run/user/\$uid/pulse"
"--dev-bind / /host"
"--ro-bind-try /usr/share/themes /usr/local/share/themes"
"--ro-bind-try /usr/share/icons /usr/local/share/icons"
"--ro-bind-try /usr/share/fonts /usr/local/share/fonts"
"--dev-bind-try /etc/resolv.conf /etc/resolv.conf"
"--dev-bind-try /home /home"
)
EXTRA_ARGS=(
"--hostname Amber-PM"
"--unshare-uts"
# "--cap-add CAP_SYS_ADMIN"
)
EXTRA_SCRIPTS=(
cursor_theme_dir_integration
)
##########合成bwrap 4. 合成并执行指令
# 逐一添加到 EXEC_COMMAND
for var in "${ENV_VARS[@]}"; do
add_env_var $var
done
for var in "${BIND_DIRS[@]}"; do
add_command "$var"
done
for var in "${EXTRA_ARGS[@]}"; do
add_command "$var"
done
for var in "${EXTRA_SCRIPTS[@]}"; do
$var
done
# 添加最终的 bash 命令
add_command "bash -c \"/usr/bin/bwrap ${container_command}\""
# 输出完整的 EXEC_COMMAND 以查看
# echo "${EXEC_COMMAND}"
# 注意: 实际执行时,请确保所有变量(如 $uid, $chrootEnvPath 等)都已正确定义
eval ${EXEC_COMMAND}
@@ -1,91 +0,0 @@
#!/bin/bash
if [ "$UID" != "0" ];then
echo "Need to be run as root."
exit 1
fi
# 清除先前的变量值
unset ABSOLUTE_PATH IN_CONTAINER_PATH PKGNAME_GUESS DPKG_LIST_FILE ACE_ENV_PATH
# 定义环境路径变量
ACE_ENV_PATH="/var/lib/apm/apm/files/ace-env"
# 检查参数个数
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <desktop-file>"
exit 1
fi
# 保存并验证绝对路径
ABSOLUTE_PATH=$1
if [[ $ABSOLUTE_PATH != "$ACE_ENV_PATH"* ]]; then
echo "Error: Invalid path. Must start with $ACE_ENV_PATH"
exit 1
fi
# 验证是否为desktop文件
if [[ ! $ABSOLUTE_PATH == *.desktop ]]; then
if [ ! -e $ABSOLUTE_PATH ];then
echo "$ABSOLUTE_PATH does not exist. May have already been uninstalled. Ignore it."
exit
else
echo "Error: The file is not a desktop file."
exit 1
fi
fi
# 截取路径
IN_CONTAINER_PATH=${ABSOLUTE_PATH#"$ACE_ENV_PATH"}
# 截取并保存包名
PKGNAME_GUESS=$(basename "$ABSOLUTE_PATH" .desktop)
# 检查dpkg列表文件
DPKG_INFO_PATH="$ACE_ENV_PATH/var/lib/dpkg/info"
if [ -f "$DPKG_INFO_PATH/$PKGNAME_GUESS.list" ]; then
DPKG_LIST_FILE="$DPKG_INFO_PATH/$PKGNAME_GUESS.list"
elif ls "$DPKG_INFO_PATH/${PKGNAME_GUESS}:*.list" 1> /dev/null 2>&1; then
DPKG_LIST_FILE=$(ls "$DPKG_INFO_PATH/${PKGNAME_GUESS}:*.list" | head -n 1)
else
echo "Warn:No dpkg list file found for $PKGNAME_GUESS.desktop,try to scan to search for the package"
fi
# 验证文件并执行操作
if [ -f "$DPKG_LIST_FILE" ]; then
if grep -q "$IN_CONTAINER_PATH" "$DPKG_LIST_FILE" || grep -q "/var/lib/apm/$PKGNAME_GUESS/entries/applications/$PKGNAME_GUESS.desktop" "$DPKG_LIST_FILE"; then
apm-debug apt autopurge $PKGNAME_GUESS -y
ret=$?
if [ "$ret" = "0" ];then
echo "Operation succeeded."
exit
else
echo "Operation failed."
exit $ret
fi
else
echo "Warn: Path not found in the dpkg list file,try to scan to search for the package"
fi
fi
# 遍历所有list文件 As fallback
for file in "$DPKG_INFO_PATH"/*.list; do
if grep -q "$IN_CONTAINER_PATH" "$file"; then
PKGNAME_GUESS=$(basename "$file" .list | cut -d':' -f1)
echo "Get pkgname $PKGNAME_GUESS, uninstalling..."
apm-debug apt autopurge $PKGNAME_GUESS -y
ret=$?
if [ "$ret" = "0" ];then
echo "Operation succeeded."
exit 0
else
echo "Operation failed."
exit $ret
fi
fi
done
echo "Error: No matching package found."
exit 1
@@ -1,77 +0,0 @@
#!/bin/bash
if [ "$UID" != "0" ];then
pkexec $0
exit
fi
# 定义应用列表文件路径
ACE_dir="/var/lib/apm/apm/files/ace-env"
HERE="$(dirname $(realpath $0))"
# 读取所有.desktop文件,并构造应用列表
app_list=()
for file in "$ACE_dir"/usr/share/applications/*.desktop; do
if [ ! -e "$file" ];then ##可能是软链接,对主机来说无用
file=$ACE_dir$(readlink $file)
fi
if [ "$(grep -m 1 '^NoDisplay=' "$file" | cut -d '=' -f 2)" = "true" ] || [ "$(grep -m 1 '^NoDisplay=' "$file" | cut -d '=' -f 2)" = "True" ];then
continue
fi
# 读取应用名称和简介
name_orig=$(grep -m 1 '^Name=' "$file" | cut -d '=' -f 2)
name_i18n=$(grep -m 1 "^Name\[${LANGUAGE}\]\=" "$file" | cut -d '=' -f 2)
if [ -z "$name_i18n" ] ;then
name=$name_orig
else
name=$name_i18n
fi
comment_orig=$(grep -m 1 '^Comment=' "$file" | cut -d '=' -f 2)
comment_i18n=$(grep -m 1 "^Comment\[${LANGUAGE}\]\=" "$file" | cut -d '=' -f 2)
if [ -z "$comment_i18n" ] ;then
comment=$comment_orig
else
comment=$comment_i18n
fi
# 如果没有简介,则显示"N/A"
[[ -z "$comment" ]] && comment="N/A"
# 添加到应用列表数组
app_list+=("false" "$name" "$comment" "$file")
done
# 使用 Zenity 显示应用列表,并获取用户选择
selected_apps=$(zenity --list --title "应用列表" --column "是否卸载" --column "应用名称" --column "应用介绍" --column "desktop文件位置" --checklist "${app_list[@]}" --print-column=4 --hide-column=4 --separator=" " --width=800 --height=400)
# 检查用户是否做出了选择
if [ -n "$selected_apps" ]; then
# 卸载选中的应用
(for app_desktop_path in $selected_apps; do
${HERE}/ace-uninstall-helper "$app_desktop_path"
ret=$?
if [ "$ret" != "0" ];then
zenity --error --width 768 --text "$app_desktop_path 卸载失败,中止操作\n请手动执行\nsudo $0 $app_desktop_path \n查看报错!"
exit 1
break
fi
done ) &
cmd_pid=$!
(while kill -0 $cmd_pid 2> /dev/null; do
echo "# 正在执行..."
sleep 1
done)| zenity --progress --text="正在执行卸载操作..." --pulsate --auto-close --no-cancel --width 400
wait $cmd_pid
cmd_status=$?
if [ "$cmd_status" = "1" ];then
zenity --error --width 200 --text "卸载过程出现错误"
exit 1
else
zenity --info --width 200 --text "选定应用已卸载"
fi
else
zenity --info --text "未选择任何应用"
fi
@@ -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
+4 -3
View File
@@ -4,7 +4,7 @@
2. apm 添加了一个钩子(debian only),在安装到 /var/lib/apm 下的应用存在ace-env时,进行configure nvidia操作;若存在entries,则进行链接到/usr/share/applications操作 2. apm 添加了一个钩子(debian only),在安装到 /var/lib/apm 下的应用存在ace-env时,进行configure nvidia操作;若存在entries,则进行链接到/usr/share/applications操作
3. apm 内置 ubuntu rootfs的修改如下 3. apm 内置 rootfs的修改如下
* 安装xz-utils * 安装xz-utils
@@ -26,8 +26,7 @@
* 重要:如何在APM内更新内容——如何覆盖?
* deb全自动转apm
* apm版融合商店 * apm版融合商店
* 类似 Wine 运行器的方式全图形化傻瓜式打包 * 类似 Wine 运行器的方式全图形化傻瓜式打包
* 自动融合 APM 应用到系统主机,并实现右键卸载 * 自动融合 APM 应用到系统主机,并实现右键卸载
@@ -43,3 +42,5 @@
* 完成amd64软件源配置 * 完成amd64软件源配置
* 修改aptss以兼容APM源加速 * 修改aptss以兼容APM源加速
* apm环境变量添加 IS_APM_ENV=1 GTK_USE_PORTAL=1 * apm环境变量添加 IS_APM_ENV=1 GTK_USE_PORTAL=1
* 重要:如何在APM内更新内容——如何覆盖?
* deb全自动转apm