Compare commits

...

4 Commits

Author SHA1 Message Date
reddevillg bb4ed7b3e8 feat: Add --force option to uninstall command
build / ubuntu_24.04 (push) Has been cancelled Details
build / ubuntu_22.04 (push) Has been cancelled Details
coverage / codecov (push) Has been cancelled Details
Introduces a `--force` flag to the `ll-cli uninstall` command, allowing
users to forcefully uninstall packages that are typically protected,
such as base and runtime dependencies.

This commit also includes significant refactoring:
- The dependency pulling logic in `PackageManager::pullDependency` has
  been refactored to prioritize newer remote packages over existing local
  ones, ensuring dependencies are kept up-to-date.

Signed-off-by: reddevillg <reddevillg@gmail.com>
2025-11-11 16:28:50 +08:00
dengbo b13e95c9b7 docs: Localizes documentation content to Chinese
Translates various user documentation pages from English to Chinese, including guides on unit testing, bundle format, rootfs, and system helper.

Additionally, updates the release notes to include both English and Chinese versions, ensuring accessibility for Chinese-speaking users while maintaining original content for English speakers.
2025-11-11 10:33:30 +08:00
ComixHe 2c0c17fc96 chore: add pre-commit-config
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
2025-11-10 11:55:56 +08:00
reddevillg 5b165d88f9 refactor: improve cli command handling
Repetitive code for D-Bus calls, task state management, and error
handling was extracted into helper functions.

Signed-off-by: reddevillg <reddevillg@gmail.com>
2025-11-10 11:54:29 +08:00
25 changed files with 731 additions and 817 deletions

35
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,35 @@
# SPDX-FileCopyrightText: None
#
# SPDX-License-Identifier: CC0-1.0
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-toml
- id: check-added-large-files
- id: check-xml
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v21.1.5
hooks:
- id: clang-format
name: clang-format (C/C++)
files: \.(c|cc|cpp|cxx|h|hpp)$
args: ['-i', '--sort-includes', '--style=file']
exclude: |
(?x)^(
build/|
external/|
libs/api/src/linglong/api/types/v1/
)
- repo: https://github.com/scop/pre-commit-shfmt
rev: v3.12.0-2
hooks:
- id: shfmt
args: ['-i', '4', '-ci', '-sr']

View File

@ -1025,11 +1025,15 @@
"type": "object",
"description": "package manager uninstall parameters",
"required": [
"package"
"package",
"options"
],
"properties": {
"package": {
"$ref": "#/$defs/PackageManager1Package"
},
"options": {
"$ref": "#/$defs/CommonOptions"
}
}
},

View File

@ -790,9 +790,12 @@ $defs:
description: package manager uninstall parameters
required:
- package
- options
properties:
package:
$ref: '#/$defs/PackageManager1Package'
options:
$ref: '#/$defs/CommonOptions'
PackageManager1UpdateParameters:
type: object
description: package manager update result

View File

@ -326,6 +326,9 @@ void addUninstallCommand(CLI::App &commandParser,
cliUninstall->add_option("--module", uninstallOptions.module, _("Uninstall a specify module"))
->type_name("MODULE")
->check(validatorString);
cliUninstall->add_flag("--force",
uninstallOptions.forceOpt,
_("Force uninstall base or runtime"));
// below options are used for compatibility with old ll-cli
const auto &pruneDescription = std::string{ _("Remove all unused modules") };

View File

@ -1,11 +1,11 @@
# Unit Testing
Linyaps uses GoogleTest (gtest) for unit testing. Simply include test code and test data in the `test/` directory of the project root.
Linyaps utilizes GoogleTest (gtest) as its unit testing framework. Simply include your test code and test data in the `test/` directory at the project root.
Since some tests are difficult to run in CI environments, they are disabled by default.
Since certain tests are challenging to execute in CI environments, they are disabled by default.
Here are some environment variables to control test execution. All of them are empty by default.
The following environment variables control test execution. All are empty by default:
| Variable Name | Value | Description |
| ----------------- | ------------------------------- | ------------------------------- |
| LINGLONG_TEST_ALL | If set, will run all unit tests | Enables all unit test execution |
| LINGLONG_TEST_ALL | If set, enables all unit tests | Executes complete unit test suite |

View File

@ -2,79 +2,103 @@
---
## Version 1.10
### 🚀 **New Features**
* **GPU Support:** The application runtime now supports graphics processing unit (GPU) capabilities to improve computing performance and rendering efficiency.
* **Container Process Management:** Containerized runtimes have been enhanced to support waiting for child processes to terminate, ensuring resource management and system stability.
* **Repository Mirror Control:** Repository configuration now includes the ability to enable and disable mirroring, allowing users to flexibly control and optimize dependency pull speed.
* **Startup Environment Variables:** The application startup command now supports using the `--env` parameter to set runtime environment variables, facilitating dynamic configuration and debugging.
* **Build Tool Export:** The build tool now includes a `--ref` option, supporting the export of UAB packages by specific references, optimizing the distribution and deployment process.
### 🐞 **Bug Fixes**
* **Desktop Integration:** Fixed a logical error that could cause application icons to disappear from the taskbar after updating the Linglong component.
* **File I/O:** Resolved encoding and parsing issues that caused operations to fail when opening file paths containing special characters.
* **Build File Inclusion:** Fixed an issue where the build tools failed to correctly include and export hidden files when exporting packages.
---
## Version 1.9
### **New Features**
### 🚀 **New Features**
- **Container Process Management Optimization:** Introduced **`dumb-init`** as the container `init` process, responsible for signal forwarding and zombie process cleanup, significantly optimizing container internal process management efficiency.
- **UAB File Generation Refactoring:** Completely refactored the UAB file generation logic, encapsulating all related dependencies into the **`ll-builder-utils`** toolchain, resolving compatibility issues during export on some distributions.
- **Qt Version Compatibility:** The project now supports both **Qt5 and Qt6**, automatically selecting the appropriate Qt version when compiling applications, improving flexibility.
- **Command Line Tool Multi-language Support:** Command line tools now support more languages from different countries and regions, enhancing internationalization capabilities.
- **Architecture-specific Configuration Loading:** Supports loading architecture-specific configuration files (e.g., `linglong.arm64.yaml`) through **`ll-builder`**, enabling automatic adaptation for different hardware architectures.
- **Build Product Compression Algorithm Selection:** Linyaps build tools now allow users to specify compression algorithms when exporting target products.
- **Local Multi-repository Support:** Added support for local multi-repository management, which can be used for installing and searching applications.
* **Container Process Management Optimization:** Introduced **`dumb-init`** as the container `init` process, responsible for signal forwarding and zombie process cleanup, significantly optimizing container internal process management efficiency.
* **UAB File Generation Refactoring:** Completely refactored the UAB file generation logic, encapsulating all related dependencies into the **`ll-builder-utils`** toolchain, resolving compatibility issues during export on some distributions.
* **Qt Version Compatibility:** The project now supports both **Qt5 and Qt6**, automatically selecting the appropriate Qt version when compiling applications, improving flexibility.
* **Command Line Tool Multi-language Support:** Command line tools now support more languages from different countries and regions, enhancing internationalization capabilities.
* **Architecture-specific Configuration Loading:** Supports loading architecture-specific configuration files (e.g., `linglong.arm64.yaml`) through **`ll-builder`**, enabling automatic adaptation for different hardware architectures.
* **Build Product Compression Algorithm Selection:** Linyaps build tools now allow users to specify compression algorithms when exporting target products.
* **Local Multi-repository Support:** Added support for local multi-repository management, which can be used for installing and searching applications.
### **Bug Fixes**
### 🐞 **Bug Fixes**
- Fixed the issue where error messages were too vague, now the prompts are clearer and more explicit.
- Fixed anomalies in application cache loading and update logic.
- Fixed defects where update tasks would abnormally terminate during application runtime.
- Fixed potential abnormal error reporting issues when uninstalling applications.
* Fixed the issue where error messages were too vague, now the prompts are clearer and more explicit.
* Fixed anomalies in application cache loading and update logic.
* Fixed defects where update tasks would abnormally terminate during application runtime.
* Fixed potential abnormal error reporting issues when uninstalling applications.
---
## Version 1.8
### **New Features**
### 🚀 **New Features**
- **Enhanced Build Capabilities:**
- **Dependency Management Optimization:** Improved dependency management mechanism, supporting installation of build toolchain dependencies through **APT package manager**.
- **Compression Algorithm Extension:** When exporting applications, now supports more compression algorithms, including **LZ4, LZMA, and ZSTD**.
- **Build Environment Upgrade:** Linyaps client now supports building in **Qt6 environment**.
- **Internationalization Support:** Command line tools added support for multiple languages, including English (en_US/en_GB), Spanish (es), Simplified Chinese (zh_CN), Catalan (ca), Finnish (fi), Polish (pl), Brazilian Portuguese (pt_BR), Albanian (sq), and Ukrainian (uk).
* **Enhanced Build Capabilities:**
* **Dependency Management Optimization:** Improved dependency management mechanism, supporting installation of build toolchain dependencies through **APT package manager**.
* **Compression Algorithm Extension:** When exporting applications, now supports more compression algorithms, including **LZ4, LZMA, and ZSTD**.
* **Build Environment Upgrade:** Linyaps client now supports building in **Qt6 environment**.
* **Internationalization Support:** Command line tools added support for multiple languages, including English (en_US/en_GB), Spanish (es), Simplified Chinese (zh_CN), Catalan (ca), Finnish (fi), Polish (pl), Brazilian Portuguese (pt_BR), Albanian (sq), and Ukrainian (uk).
### **Bug Fixes**
### 🐞 **Bug Fixes**
- **Stability Improvements:**
- Fixed the issue where mounted directories were not completely cleaned up after installing layers.
- Resolved defects in upgrading base environment and runtime components.
- Optimized application uninstall logic to ensure residual directories can be thoroughly cleaned.
- **Symbolic Link Processing Mechanism Improvement:** Fixed the anomaly where relative path symbolic links were incorrectly converted to empty directories; also corrected the issue where invalid symbolic links were not properly copied.
* **Stability Improvements:**
* Fixed the issue where mounted directories were not completely cleaned up after installing layers.
* Resolved defects in upgrading base environment and runtime components.
* Optimized application uninstall logic to ensure residual directories can be thoroughly cleaned.
* **Symbolic Link Processing Mechanism Improvement:** Fixed the anomaly where relative path symbolic links were incorrectly converted to empty directories; also corrected the issue where invalid symbolic links were not properly copied.
---
## Version 1.7
### **New Features**
### 🚀 **New Features**
- **Repository Storage Layer Structure Optimization:** Optimized the repository's storage layer structure, making application management no longer forcibly dependent on the file system, improving flexibility.
- **Linyaps Data File Export Optimization:** Linyaps data file export function no longer exports all files under the `share` directory, reducing export volume.
- **Loongson New World Architecture Support:** Linyaps now supports application packaging and running on **Loongson New World architecture**.
- **Installation, Uninstallation, and Update Behavior Adjustment and Optimization:**
- The new version no longer supports installing multiple versions of the same application locally. For multiple old versions retained after client upgrade, all package management operations will only take effect on the highest version except for uninstall operations.
- When upgrading or downgrading while the application is running, the uninstall action of the old version will be delayed to ensure smooth transition.
- **Linyaps Command Line Tool Help Information Internationalization:** Command line tool help information has begun internationalization, currently supporting Chinese, English, and Spanish, with professional internationalization translation platforms to be integrated later.
- **Linyaps Command Line Parameter Parsing Optimization:** Adopted a new command line parameter parsing framework, making parameter information display clearer and more readable.
- **Linyaps Application Packaging Build Optimization:** When using the new build tool to package applications, application debug symbols will be stripped to effectively reduce the final application package size.
- **`runtime/base` Management Command Adjustment:** `runtime/base` no longer supports uninstallation using the `uninstall` command, instead providing the `prune` command for cleaning up unused `runtime` and `base` components.
- **New `ll-cli list --upgradable` Command:** This command is used to display all upgradeable version lists of currently installed applications.
* **Repository Storage Layer Structure Optimization:** Optimized the repository's storage layer structure, making application management no longer forcibly dependent on the file system, improving flexibility.
* **Linyaps Data File Export Optimization:** Linyaps data file export function no longer exports all files under the `share` directory, reducing export volume.
* **Loongson New World Architecture Support:** Linyaps now supports application packaging and running on **Loongson New World architecture**.
* **Installation, Uninstallation, and Update Behavior Adjustment and Optimization:**
* The new version no longer supports installing multiple versions of the same application locally. For multiple old versions retained after client upgrade, all package management operations will only take effect on the highest version except for uninstall operations.
* When upgrading or downgrading while the application is running, the uninstall action of the old version will be delayed to ensure smooth transition.
* **Linyaps Command Line Tool Help Information Internationalization:** Command line tool help information has begun internationalization, currently supporting Chinese, English, and Spanish, with professional internationalization translation platforms to be integrated later.
* **Linyaps Command Line Parameter Parsing Optimization:** Adopted a new command line parameter parsing framework, making parameter information display clearer and more readable.
* **Linyaps Application Packaging Build Optimization:** When using the new build tool to package applications, application debug symbols will be stripped to effectively reduce the final application package size.
* **`runtime/base` Management Command Adjustment:** `runtime/base` no longer supports uninstallation using the `uninstall` command, instead providing the `prune` command for cleaning up unused `runtime` and `base` components.
* **New `ll-cli list --upgradable` Command:** This command is used to display all upgradeable version lists of currently installed applications.
### **Bug Fixes**
### 🐞 **Bug Fixes**
- Solved the problem of Linyaps application debugging failure.
- Fixed the defect that could cause application crashes when using the `ll-cli search` command to find applications after enabling system proxy.
* Solved the problem of Linyaps application debugging failure.
* Fixed the defect that could cause application crashes when using the `ll-cli search` command to find applications after enabling system proxy.
---
## Version 1.6
### **New Features**
### 🚀 **New Features**
- **USB Drive Directory File Reading:** Linyaps applications now support direct reading of directories and files in USB drives.
- **New `ll-pica-flatpak` Tool:** Added the **`ll-pica-flatpak`** tool, supporting conversion of `Flatpak` format applications to Linyaps format.
* **USB Drive Directory File Reading:** Linyaps applications now support direct reading of directories and files in USB drives.
* **New `ll-pica-flatpak` Tool:** Added the **`ll-pica-flatpak`** tool, supporting conversion of `Flatpak` format applications to Linyaps format.
### **Bug Fixes**
### 🐞 **Bug Fixes**
- Fixed the issue where script execution failed when upgrading Linyaps packages.
- Fixed the defect where executing other commands might be blocked when installing Linyaps applications.
- Fixed the problem where application names were too long and displayed incompletely when viewing the application list.
* Fixed the issue where script execution failed when upgrading Linyaps packages.
* Fixed the defect where executing other commands might be blocked when installing Linyaps applications.
* Fixed the problem where application names were too long and displayed incompletely when viewing the application list.

View File

@ -1,52 +1,50 @@
# Bundle Format
# 捆绑包格式
## Introduce
## 介绍
Green software, known as some binary does not install any file to the system.
绿色软件,指的是一些不向系统安装任何文件的二进制程序。
The base constraint of green software is:
绿色软件的基本约束是:
- Path unrelated, means has nothing to do with local files.
- 路径无关,意味着与本地文件无关。
- highly compatibility, so the software should contain all dependencies that the system does not have.
- 高度兼容性,因此软件应包含系统所没有的所有依赖项。
The famous technology to build green software is AppImage on Linux.
在 Linux 上构建绿色软件的著名技术是 AppImage。
However, there are many problems with that technology, the biggest problem is that the host system ABI can not stay stable and differ from one another. The linglong can not solve that problem either. We should keep a baseline of support system or ABI.
然而,该技术存在许多问题,最大的问题是主机系统 ABI 无法保持稳定,并且彼此不同。玲珑也无法解决这个问题。我们应该保持对支持系统或 ABI 的基线。
A trick on uniontech os or deepin is just support system after uniontech os 1020, which reduces the testing work for the different base systems.
在统信操作系统或深度操作系统上的一个技巧是仅支持统信操作系统 1020 之后的系统,这减少了针对不同基础系统的测试工作。
## Target
## 目标
The green bundle is not just simple support for application run path independently. It is also designed to be the offline maintainer package format on office system service package support self-run and install. so keep the changeability of the bundle format when designing.
绿色捆绑包不仅仅是简单支持应用程序运行路径独立。它还被设计为办公系统服务包支持的离线维护包格式,支持自运行和安装。因此在设计时保持捆绑包格式的可变性。
When a user has internet, we mostly use online diff update or install by repo. we do not use bundle if we can access the repo when distributing applications.
当用户有互联网时,我们主要使用在线差异更新或通过仓库安装。如果我们可以在分发应用程序时访问仓库,则不会使用捆绑包。
## Specification
## 规范
The spec of the export bundle:
导出捆绑包的规范:
- MUST be an ELF, can be FlatELF
- MUST be statically-linked
- MUST contain a data segment that can mount with fuse
- MUST contain a loader executable on the root of fuse mount filesystem
- 必须是 ELF可以是 FlatELF
- 必须是静态链接的
- 必须包含一个可以使用 fuse 挂载的数据段
- 必须包含一个在 fuse 挂载文件系统根目录下的加载器可执行文件
## Implementation
## 实现
**The implementation change with timeIf you change the implement, update this selection as soon as possible !!!**
**实现会随时间变化,如果您更改了实现,请尽快更新此部分!!!**
### prototype
### 原型
- The bundle is a sample elf loader that joins a readonly filesystem with cat.
- The loader simply calls read_elf64 to calc the offset of readonly filesystem.
- The loader mount readonly filesystem with `squashfuse -o ro,offset=xxx`
- The filesystem now is readonly filesystem
- The root of the filesystem should contain a file name loader(by the way, now is .loader)
- the directory structure should be: /{id}/{version}/{arch}/
- The readonly filesystem should support erofs, and MAY support suqashfs
- 捆绑包是一个简单的 ELF 加载器,通过 cat 连接只读文件系统。
- 加载器简单地调用 read_elf64 来计算只读文件系统的偏移量。
- 加载器使用 `squashfuse -o ro,offset=xxx` 挂载只读文件系统
- 文件系统现在是只读文件系统
- 文件系统的根目录应该包含一个名为 loader 的文件(顺便说一下,现在是 .loader
- 目录结构应该是:/{id}/{version}/{arch}/
- 只读文件系统应该支持 erofs并且可能支持 squashfs
a full example of the filesystem is:
文件系统的完整示例是:
```bash
```

View File

@ -1,8 +1,8 @@
# Ref
# 引用(Ref
## 定义
组件:组件一般等价于其他系统中的 artifacts/component/module/package 等,在玲珑中,我们使用 layer 来表示一个组件。
组件:组件通常等同于其他系统中的 artifacts/component/module/package 等,在玲珑中,我们使用 layer 来表示一个组件。
## 格式
@ -40,7 +40,7 @@ org.deepin.calculator 为 ID1.2.2 为版本x86_64 为架构。
Ref 包含两个部分,远程地址标识和本地标识。其中`:`前用分割远程标识和本地标识。
程标识主要用于定义这个 layer 是如何获取的。其中 channel 暂时没有用到可以为空。repo 表示远程仓库URL在本地的映射的别名。
程标识主要用于定义这个 layer 是如何获取的。其中 channel 暂时没有用到可以为空。repo 表示远程仓库URL在本地的映射的别名。
在安装过程中,使用完整的 ref 可以唯一标识一个 layer。例如

View File

@ -1,8 +1,8 @@
# Rootfs
As oci runtime specification, the runtime start from an rootfs, but in linglong, it prepare rootfs in ll-box. so we put the information of construction rootfs in annotations to ll-box.
根据 OCI 运行时规范,运行时从 rootfs 开始,但在玲珑中,它在 ll-box 中准备 rootfs。因此我们将构建 rootfs 的信息放在 ll-box 的注释中。
The example of annotations is
注释的示例是
```json
"annotations": {
@ -77,6 +77,6 @@ The example of annotations is
}
```
The ll-box support two method to build rootfs, use native ro bind mount or with overlayfs.
ll-box 支持两种构建 rootfs 的方法,使用原生只读绑定挂载或使用 overlayfs。
`container_root_path` is the work directory of ll-box.
`container_root_path` 是 ll-box 的工作目录。

View File

@ -1,6 +1,6 @@
# System Helper
# 系统助手
User with no privilege can mount erofs to dir with:
无特权的用户可以通过以下方式将 erofs 挂载到目录:
```bash
busctl --system call org.deepin.linglong.SystemHelper \
@ -12,4 +12,3 @@ busctl --system call org.deepin.linglong.SystemHelper \
'/run/user/1000/linglong/vfs/layers/com.qq.music/1.1.3/x86_64/' \
'erofs' \
0
```

View File

@ -2,79 +2,97 @@
---
## 1.10 版本
### 🚀 **新功能**
* **GPU 支持:** 应用运行时现在实现了对图形处理器 (GPU) 功能的支持,以提升计算性能和渲染效率。
* **容器进程管理:** 容器化运行时已增强,能够支持等待其子进程结束,确保资源管理和系统稳定性。
* **仓库镜像控制:** 仓库配置新增启用和禁用镜像功能,允许用户灵活控制和优化依赖拉取速度。
* **启动环境变量:** 应用启动命令现在支持使用 `--env` 参数来设置运行时环境变量,方便动态配置和调试。
* **构建工具导出:** 构建工具已新增 `--ref` 选项,支持按特定引用导出 uab 包,优化了分发和部署流程。
### 🐞 **问题修复**
* **桌面集成:** 修复了更新玲珑组件后,任务栏应用图标可能丢失的逻辑错误。
* **文件 I/O** 解决了打开包含特殊字符的文件路径时,导致操作失败的编码和解析问题。
* **构建文件包含:** 修复了构建工具在导出包时,无法正确包含和导出隐藏文件的问题。
---
## 1.9 版本
### **新功能**
### 🚀 **新功能**
- **容器进程管理优化:** 引入 **`dumb-init`** 作为容器 `init` 进程,负责转发信号并清理僵尸进程,显著优化了容器内部的进程管理效率。
- **UAB 文件生成重构:** 彻底重构了 UAB 文件的生成逻辑,将所有相关依赖封装到 **`ll-builder-utils`** 工具链中,解决了在部分发行版中导出时的兼容性问题。
- **Qt 版本兼容:** 项目现已同时支持 **Qt5 和 Qt6**,编译应用时将自动选择合适的 Qt 版本,提升了灵活性。
- **命令行工具多语言支持:** 命令行工具已支持更多国家和地区的语言,增强了国际化能力。
- **架构特定配置加载:** 支持通过 **`ll-builder`** 加载架构特定的配置文件(例如 `linglong.arm64.yaml`),实现不同硬件架构的自动适配。
- **构建产物压缩算法选择:** 玲珑构建工具在导出目标产物时,现在允许用户指定压缩算法。
- **本地多仓库支持:** 新增支持本地多仓库管理功能,可用于安装和搜索应用。
* **容器进程管理优化:** 引入 **`dumb-init`** 作为容器 `init` 进程,负责转发信号并清理僵尸进程,显著优化了容器内部的进程管理效率。
* **UAB 文件生成重构:** 彻底重构了 UAB 文件的生成逻辑,将所有相关依赖封装到 **`ll-builder-utils`** 工具链中,解决了在部分发行版中导出时的兼容性问题。
* **Qt 版本兼容:** 项目现已同时支持 **Qt5 和 Qt6**,编译应用时将自动选择合适的 Qt 版本,提升了灵活性。
* **命令行工具多语言支持:** 命令行工具已支持更多国家和地区的语言,增强了国际化能力。
* **架构特定配置加载:** 支持通过 **`ll-builder`** 加载架构特定的配置文件(例如 `linglong.arm64.yaml`),实现不同硬件架构的自动适配。
* **构建产物压缩算法选择:** 玲珑构建工具在导出目标产物时,现在允许用户指定压缩算法。
* **本地多仓库支持:** 新增支持本地多仓库管理功能,可用于安装和搜索应用。
### **问题修复**
### 🐞 **问题修复**
- 修复了错误信息提示过于模糊的问题,现在提示更加清晰明了。
- 修复了应用缓存加载和更新逻辑中的异常问题。
- 修复了应用运行时,更新任务异常终止的缺陷。
- 修复了卸载应用时可能发生的异常报错问题。
* 修复了错误信息提示过于模糊的问题,现在提示更加清晰明了。
* 修复了应用缓存加载和更新逻辑中的异常问题。
* 修复了应用运行时,更新任务异常终止的缺陷。
* 修复了卸载应用时可能发生的异常报错问题。
---
## 1.8 版本
### **新功能**
### 🚀 **新功能**
- **构建能力增强:**
- **依赖管理优化:** 改进了依赖管理机制,支持通过 **APT 包管理器**安装构建工具链的依赖项。
- **压缩算法扩展:** 应用导出时,现在支持选择更多压缩算法,包括 **LZ4、LZMA 和 ZSTD**
- **编译环境升级:** 玲珑客户端现已支持在 **Qt6 环境**下进行构建。
- **国际化支持:** 命令行工具新增对多种语言的支持包括英语en_US/en_GB、西班牙语es、简体中文zh_CN、加泰罗尼亚语ca、芬兰语fi、波兰语pl、巴西葡萄牙语pt_BR、阿尔巴尼亚语sq和乌克兰语uk
* **构建能力增强:**
* **依赖管理优化:** 改进了依赖管理机制,支持通过 **APT 包管理器**安装构建工具链的依赖项。
* **压缩算法扩展:** 应用导出时,现在支持选择更多压缩算法,包括 **LZ4、LZMA 和 ZSTD**
* **编译环境升级:** 玲珑客户端现已支持在 **Qt6 环境**下进行构建。
* **国际化支持:** 命令行工具新增对多种语言的支持包括英语en_US/en_GB、西班牙语es、简体中文zh_CN、加泰罗尼亚语ca、芬兰语fi、波兰语pl、巴西葡萄牙语pt_BR、阿尔巴尼亚语sq和乌克兰语uk
### **问题修复**
### 🐞 **问题修复**
- **稳定性改进:**
- 修复了安装层layer后挂载目录未能完全清理的问题。
- 解决了基础环境base与运行时runtime组件升级失败的缺陷。
- 优化了应用卸载逻辑,确保残留目录能够被彻底清除。
- **符号链接处理机制完善:** 修复了相对路径符号链接被错误地转换为空目录的异常;同时修正了无效符号链接未能被正确复制的问题。
* **稳定性改进:**
* 修复了安装层layer后挂载目录未能完全清理的问题。
* 解决了基础环境base与运行时runtime组件升级失败的缺陷。
* 优化了应用卸载逻辑,确保残留目录能够被彻底清除。
* **符号链接处理机制完善:** 修复了相对路径符号链接被错误地转换为空目录的异常;同时修正了无效符号链接未能被正确复制的问题。
---
## 1.7 版本
### **新功能**
### 🚀 **新功能**
- **仓库存储层结构优化:** 优化了仓库的存储层结构,使得应用管理不再强制依赖文件系统,提升了灵活性。
- **玲珑数据文件导出优化:** 玲珑数据文件导出功能不再导出 `share` 目录下所有文件,减少了导出体积。
- **龙芯新世界架构支持:** 如意玲珑现已支持**龙芯新世界架构**下的应用打包和运行。
- **安装、卸载、更新行为调整优化:**
- 新版本不再支持在本地同时安装同一应用的多个版本。对于客户端升级后仍保留的多个旧版本,除卸载操作外,所有软件包管理操作将仅对最高版本生效。
- 当应用处于运行状态时进行升级或降级,旧版本的卸载动作将延迟执行,以确保平滑过渡。
- **如意玲珑命令行工具帮助信息国际化:** 命令行工具的帮助信息已开始国际化,目前支持中文、英文和西班牙语,后续将接入专业的国际化翻译平台。
- **玲珑命令行参数解析优化:** 采用全新的命令行参数解析框架,使参数信息展示更清晰、易读。
- **玲珑应用打包构建优化:** 使用新构建工具打包应用时,将剥离应用调试符号,以有效减小最终应用包的体积。
- **`runtime/base` 管理命令调整:** `runtime/base` 不再支持使用 `uninstall` 命令卸载,转而提供 `prune` 命令用于清理未使用的 `runtime``base` 组件。
- **新增 `ll-cli list --upgradable` 命令:** 该命令用于显示当前已安装应用程序的所有可更新版本列表。
* **仓库存储层结构优化:** 优化了仓库的存储层结构,使得应用管理不再强制依赖文件系统,提升了灵活性。
* **玲珑数据文件导出优化:** 玲珑数据文件导出功能不再导出 `share` 目录下所有文件,减少了导出体积。
* **龙芯新世界架构支持:** 如意玲珑现已支持**龙芯新世界架构**下的应用打包和运行。
* **安装、卸载、更新行为调整优化:**
* 新版本不再支持在本地同时安装同一应用的多个版本。对于客户端升级后仍保留的多个旧版本,除卸载操作外,所有软件包管理操作将仅对最高版本生效。
* 当应用处于运行状态时进行升级或降级,旧版本的卸载动作将延迟执行,以确保平滑过渡。
* **如意玲珑命令行工具帮助信息国际化:** 命令行工具的帮助信息已开始国际化,目前支持中文、英文和西班牙语,后续将接入专业的国际化翻译平台。
* **玲珑命令行参数解析优化:** 采用全新的命令行参数解析框架,使参数信息展示更清晰、易读。
* **玲珑应用打包构建优化:** 使用新构建工具打包应用时,将剥离应用调试符号,以有效减小最终应用包的体积。
* **`runtime/base` 管理命令调整:** `runtime/base` 不再支持使用 `uninstall` 命令卸载,转而提供 `prune` 命令用于清理未使用的 `runtime``base` 组件。
* **新增 `ll-cli list --upgradable` 命令:** 该命令用于显示当前已安装应用程序的所有可更新版本列表。
### **问题修复**
### 🐞 **问题修复**
- 解决了玲珑应用调试失败的问题。
- 修复了在开启系统代理后,使用 `ll-cli search` 命令查找应用时可能导致应用崩溃的缺陷。
* 解决了玲珑应用调试失败的问题。
* 修复了在开启系统代理后,使用 `ll-cli search` 命令查找应用时可能导致应用崩溃的缺陷。
---
## 1.6 版本
### **新功能**
### 🚀 **新功能**
- **U 盘目录文件读取:** 玲珑应用现已支持直接读取 U 盘中的目录和文件。
- **`ll-pica-flatpak` 工具新增:** 新增了 **`ll-pica-flatpak`** 工具,支持将 `Flatpak` 格式的应用程序转换为玲珑格式。
* **U 盘目录文件读取:** 玲珑应用现已支持直接读取 U 盘中的目录和文件。
* **`ll-pica-flatpak` 工具新增:** 新增了 **`ll-pica-flatpak`** 工具,支持将 `Flatpak` 格式的应用程序转换为玲珑格式。
### **问题修复**
### 🐞 **问题修复**
- 修复了升级玲珑包时脚本执行失败的问题。
- 修复了在安装玲珑应用时执行其他命令可能被阻塞的缺陷。
- 修复了应用名称过长时,在查看应用列表时显示不完整的问题。
* 修复了升级玲珑包时脚本执行失败的问题。
* 修复了在安装玲珑应用时执行其他命令可能被阻塞的缺陷。
* 修复了应用名称过长时,在查看应用列表时显示不完整的问题。

View File

@ -1047,11 +1047,13 @@ j["type"] = x.type;
}
inline void from_json(const json & j, PackageManager1UninstallParameters& x) {
x.options = j.at("options").get<CommonOptions>();
x.package = j.at("package").get<PackageManager1Package>();
}
inline void to_json(json & j, const PackageManager1UninstallParameters & x) {
j = json::object();
j["options"] = x.options;
j["package"] = x.package;
}

View File

@ -17,6 +17,7 @@
#include <nlohmann/json.hpp>
#include "linglong/api/types/v1/helper.hpp"
#include "linglong/api/types/v1/CommonOptions.hpp"
#include "linglong/api/types/v1/PackageManager1Package.hpp"
namespace linglong {
@ -33,6 +34,7 @@ using nlohmann::json;
* package manager uninstall parameters
*/
struct PackageManager1UninstallParameters {
CommonOptions options;
PackageManager1Package package;
};
}

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,8 @@
#include "linglong/repo/ostree_repo.h"
#include "linglong/runtime/container_builder.h"
#include "linglong/utils/error/error.h"
#include "linglong/utils/log/log.h"
#include "linglong/utils/serialize/json.h"
#include <CLI/CLI.hpp>
@ -27,6 +29,10 @@ namespace linglong::generator {
class ContainerCfgBuilder;
}
namespace linglong::api::types::v1 {
struct PackageManager1InstallParameters;
}
namespace linglong::cli {
class Printer;
@ -92,6 +98,7 @@ struct UninstallOptions
{
std::string appid;
std::string module;
bool forceOpt{ false };
};
struct ListOptions
@ -125,6 +132,18 @@ struct InspectOptions
std::string dirType{ "layer" };
};
struct PMTaskState
{
linglong::api::types::v1::State state{ linglong::api::types::v1::State::Unknown };
linglong::api::types::v1::SubState subState{ linglong::api::types::v1::SubState::Unknown };
QString message;
double percentage{ 0 };
linglong::utils::error::ErrorCode errorCode;
};
bool operator!=(const PMTaskState &lhs, const PMTaskState &rhs);
bool operator==(const PMTaskState &lhs, const PMTaskState &rhs);
class Cli : public QObject
{
Q_OBJECT
@ -176,13 +195,14 @@ private:
const std::string &type);
static void filterPackageInfosByVersion(
std::map<std::string, std::vector<api::types::v1::PackageInfoV2>> &list) noexcept;
void printProgress() noexcept;
void printProgress(const PMTaskState &state) noexcept;
[[nodiscard]] utils::error::Result<std::vector<api::types::v1::CliContainer>>
getCurrentContainers() const noexcept;
int installFromFile(const QFileInfo &fileInfo,
const api::types::v1::CommonOptions &commonOptions,
const std::string &appid);
int setRepoConfig(const QVariantMap &config);
utils::error::Result<void> ensureAuthorized();
utils::error::Result<void> runningAsRoot();
utils::error::Result<void> runningAsRoot(const QList<QString> &args);
utils::error::Result<std::vector<api::types::v1::UpgradeListResult>>
@ -197,6 +217,34 @@ private:
std::vector<std::string> getRunningAppContainers(const std::string &appid);
int getLayerDir(const InspectOptions &options);
int getBundleDir(const InspectOptions &options);
utils::error::Result<void> initInteraction();
template <typename T>
utils::error::Result<T> waitDBusReply(QDBusPendingReply<QVariantMap> &reply)
{
LINGLONG_TRACE("waitDBusReply");
reply.waitForFinished();
if (reply.isError()) {
return LINGLONG_ERR(reply.error().message(), reply.error().type());
}
auto result = utils::serialize::fromQVariantMap<T>(reply.value());
if (!result) {
LogF("bug detected: {}", result.error());
std::abort();
}
return result;
}
utils::error::Result<void> waitTaskCreated(QDBusPendingReply<QVariantMap> &reply);
void waitTaskDone();
void handleInstallError(const utils::error::Error &error,
const api::types::v1::PackageManager1InstallParameters &params);
void handleUninstallError(const utils::error::Error &error);
bool handleCommonError(const utils::error::Error &error);
private Q_SLOTS:
// maybe use in the future
@ -226,11 +274,7 @@ private:
api::dbus::v1::PackageManager &pkgMan;
QString taskObjectPath;
api::dbus::v1::Task1 *task{ nullptr };
linglong::api::types::v1::State lastState{ linglong::api::types::v1::State::Unknown };
linglong::api::types::v1::SubState lastSubState{ linglong::api::types::v1::SubState::Unknown };
QString lastMessage;
double lastPercentage{ 0 };
linglong::utils::error::ErrorCode lastErrorCode;
PMTaskState taskState;
GlobalOptions globalOptions;
};

View File

@ -226,12 +226,6 @@ void CLIPrinter::printContainers(const std::vector<api::types::v1::CliContainer>
}
}
void CLIPrinter::printReply(const api::types::v1::CommonResult &reply)
{
std::cout << "code: " << reply.code << std::endl;
std::cout << "message:" << std::endl << reply.message << std::endl;
}
void CLIPrinter::printRepoConfig(const api::types::v1::RepoConfigV2 &repoInfo)
{
std::cout << "Default: " << repoInfo.defaultRepo << std::endl;
@ -342,9 +336,9 @@ void CLIPrinter::printInspect(const api::types::v1::InspectResult &result)
<< std::endl;
}
void CLIPrinter::printMessage(const QString &message)
void CLIPrinter::printMessage(const std::string &message)
{
std::cout << message.toStdString() << std::endl;
std::cout << message << std::endl;
}
} // namespace linglong::cli

View File

@ -40,7 +40,6 @@ public:
printSearchResult(std::map<std::string, std::vector<api::types::v1::PackageInfoV2>>) override;
void printPruneResult(const std::vector<api::types::v1::PackageInfoV2> &list) override;
void printContainers(const std::vector<api::types::v1::CliContainer> &) override;
void printReply(const api::types::v1::CommonResult &) override;
void printRepoConfig(const api::types::v1::RepoConfigV2 &) override;
void printLayerInfo(const api::types::v1::LayerInfo &) override;
void printTaskState(double percentage,
@ -50,7 +49,7 @@ public:
void printContent(const QStringList &filePaths) override;
void printUpgradeList(std::vector<api::types::v1::UpgradeListResult> &) override;
void printInspect(const api::types::v1::InspectResult &result) override;
void printMessage(const QString &message) override;
void printMessage(const std::string &message) override;
};
} // namespace linglong::cli

View File

@ -76,11 +76,6 @@ void JSONPrinter::printContainers(const std::vector<api::types::v1::CliContainer
std::cout << nlohmann::json(list).dump() << std::endl;
}
void JSONPrinter::printReply(const api::types::v1::CommonResult &reply)
{
std::cout << nlohmann::json(reply).dump() << std::endl;
}
void JSONPrinter::printRepoConfig(const api::types::v1::RepoConfigV2 &config)
{
std::cout << nlohmann::json(config).dump() << std::endl;
@ -122,9 +117,9 @@ void JSONPrinter::printInspect(const api::types::v1::InspectResult &result)
std::cout << nlohmann::json(result).dump(4) << std::endl;
}
void JSONPrinter::printMessage(const QString &message)
void JSONPrinter::printMessage(const std::string &message)
{
std::cout << nlohmann::json{ { "message", message.toStdString() } }.dump() << std::endl;
std::cout << nlohmann::json{ { "message", message } }.dump() << std::endl;
}
} // namespace linglong::cli

View File

@ -25,7 +25,6 @@ public:
printSearchResult(std::map<std::string, std::vector<api::types::v1::PackageInfoV2>>) override;
void printPruneResult(const std::vector<api::types::v1::PackageInfoV2> &) override;
void printContainers(const std::vector<api::types::v1::CliContainer> &) override;
void printReply(const api::types::v1::CommonResult &) override;
void printRepoConfig(const api::types::v1::RepoConfigV2 &) override;
void printLayerInfo(const api::types::v1::LayerInfo &) override;
void printTaskState(double percentage,
@ -35,7 +34,7 @@ public:
void printContent(const QStringList &desktopPaths) override;
void printUpgradeList(std::vector<api::types::v1::UpgradeListResult> &) override;
void printInspect(const api::types::v1::InspectResult &) override;
void printMessage(const QString &message) override;
void printMessage(const std::string &message) override;
};
} // namespace linglong::cli

View File

@ -82,7 +82,6 @@ public:
printSearchResult(std::map<std::string, std::vector<api::types::v1::PackageInfoV2>>) = 0;
virtual void printPruneResult(const std::vector<api::types::v1::PackageInfoV2> &) = 0;
virtual void printContainers(const std::vector<api::types::v1::CliContainer> &) = 0;
virtual void printReply(const api::types::v1::CommonResult &) = 0;
virtual void printRepoConfig(const api::types::v1::RepoConfigV2 &) = 0;
virtual void printLayerInfo(const api::types::v1::LayerInfo &) = 0;
virtual void printTaskState(double percentage,
@ -92,7 +91,7 @@ public:
virtual void printContent(const QStringList &filePaths) = 0;
virtual void printUpgradeList(std::vector<api::types::v1::UpgradeListResult> &) = 0;
virtual void printInspect(const api::types::v1::InspectResult &) = 0;
virtual void printMessage(const QString &message) = 0;
virtual void printMessage(const std::string &message) = 0;
};
} // namespace linglong::cli

View File

@ -792,8 +792,7 @@ QVariantMap PackageManager::installFromUAB(const QDBusUnixFileDescriptor &fd,
auto res = action->doAction(task);
if (!res) {
LogE("uab installation failed: {}", res.error());
task.reportError(LINGLONG_ERRV(std::move(res).error().message(),
utils::error::ErrorCode::AppInstallFailed));
task.reportError(std::move(res).error());
}
},
connection());
@ -893,8 +892,7 @@ auto PackageManager::Install(const QVariantMap &parameters) noexcept -> QVariant
auto res = action->doAction(task);
if (!res) {
LogE("ref installation failed: {}", res.error());
task.reportError(LINGLONG_ERRV(std::move(res).error().message(),
utils::error::ErrorCode::AppInstallFailed));
task.reportError(std::move(res).error());
}
};
@ -1074,7 +1072,7 @@ auto PackageManager::Uninstall(const QVariantMap &parameters) noexcept -> QVaria
}
}
if (mainKind == "base" || mainKind == "runtime") {
if ((mainKind == "base" || mainKind == "runtime") && !paras->options.force) {
return toDBusReply(utils::error::ErrorCode::AppUninstallBaseOrRuntime,
"base or runtime package cannot be uninstalled");
}
@ -1470,145 +1468,88 @@ void PackageManager::pullDependency(PackageTask &taskContext,
LINGLONG_TRACE("pull dependencies of " + info.id);
utils::Transaction transaction;
if (info.runtime) {
auto fuzzyRuntime = package::FuzzyReference::parse(*info.runtime);
if (!fuzzyRuntime) {
auto tryPull = [this, &transaction, &taskContext](const std::string &refStr,
const std::string &module) {
LINGLONG_TRACE("try pull dependency");
auto fuzzyRef = package::FuzzyReference::parse(refStr);
if (!fuzzyRef) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
LINGLONG_ERRV(fuzzyRuntime).message());
LINGLONG_ERRV(fuzzyRef).message());
return false;
}
auto remote = this->repo.latestRemoteReference(*fuzzyRef);
auto local = this->repo.clearReference(*fuzzyRef,
{
.forceRemote = false,
.fallbackToRemote = false,
.semanticMatching = true,
});
bool remotePulled = false;
// if remote is newer than local , pull remote
if (remote && (!local || remote->reference.version > local->version)) {
this->repo.pull(taskContext, remote->reference, module, remote->repo);
remotePulled = !isTaskDone(taskContext.subState());
if (remotePulled) {
auto ret = executePostInstallHooks(remote->reference);
if (!ret) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
LINGLONG_ERRV(ret).message());
return false;
}
transaction.addRollBack([this, remoteRef = *remote, module]() noexcept {
auto result = this->repo.remove(remoteRef.reference, module);
if (!result) {
qCritical() << result.error();
Q_ASSERT(false);
}
result = executePostUninstallHooks(remoteRef.reference);
if (!result) {
qCritical() << result.error();
Q_ASSERT(false);
}
});
}
}
if (!local) {
if (!remote) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
fmt::format("dependency {} not found", refStr));
return false;
}
if (!remotePulled) {
return false;
}
}
return true;
};
if (info.runtime) {
taskContext.updateSubState(linglong::api::types::v1::SubState::InstallRuntime,
"Installing runtime " + *info.runtime);
if (!tryPull(*info.runtime, "binary")) {
return;
}
auto runtime = this->repo.getRemoteReferenceByPriority(*fuzzyRuntime,
{
.semanticMatching = true,
});
// 如果远程没有获取到runtime(可能是网络原因或者离线场景) 应该再从本地查找,
// 如果本地也找不到再返回
if (!runtime) {
auto localRuntime = this->repo.clearReference(*fuzzyRuntime,
{
.forceRemote = false,
.fallbackToRemote = false,
.semanticMatching = true,
});
if (!localRuntime) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
runtime.error().message());
return;
}
runtime =
linglong::package::ReferenceWithRepo{ .repo =
this->repo.getHighestPriorityRepos().front(),
.reference = *localRuntime };
}
// 如果runtime已存在则直接使用, 否则从远程拉取
auto runtimeLayerDir = repo.getLayerDir(runtime->reference);
if (!runtimeLayerDir) {
if (isTaskDone(taskContext.subState())) {
return;
}
taskContext.updateSubState(linglong::api::types::v1::SubState::InstallRuntime,
"Installing runtime " + runtime->reference.toString());
this->repo.pull(taskContext, runtime->reference, module, runtime->repo);
if (isTaskDone(taskContext.subState())) {
return;
}
auto ret = executePostInstallHooks(runtime->reference);
if (!ret) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
LINGLONG_ERRV(ret).message());
return;
}
transaction.addRollBack([this, runtimeRef = *runtime, module]() noexcept {
auto result = this->repo.remove(runtimeRef.reference, module);
if (!result) {
qCritical() << result.error();
Q_ASSERT(false);
}
result = executePostUninstallHooks(runtimeRef.reference);
if (!result) {
qCritical() << result.error();
Q_ASSERT(false);
}
});
}
}
auto fuzzyBase = package::FuzzyReference::parse(info.base);
if (!fuzzyBase) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
LINGLONG_ERRV(fuzzyBase).message());
taskContext.updateSubState(linglong::api::types::v1::SubState::InstallBase,
"Installing base " + info.base);
if (!tryPull(info.base, "binary")) {
return;
}
auto base = this->repo.getRemoteReferenceByPriority(*fuzzyBase,
{
.semanticMatching = true,
});
// 如果远程没有获取到base(可能是网络原因或者离线场景) 应该再从本地查找,
// 如果本地也找不到再返回
if (!base) {
auto localBase = this->repo.clearReference(*fuzzyBase,
{
.forceRemote = false,
.fallbackToRemote = false,
.semanticMatching = true,
});
if (!localBase) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
LINGLONG_ERRV(base).message());
return;
}
base = linglong::package::ReferenceWithRepo{ .repo =
this->repo.getHighestPriorityRepos().front(),
.reference = *localBase };
}
// 如果base已存在则直接使用, 否则从远程拉取
auto baseLayerDir = repo.getLayerDir(base->reference, module);
if (!baseLayerDir) {
if (isTaskDone(taskContext.subState())) {
return;
}
taskContext.updateSubState(linglong::api::types::v1::SubState::InstallBase,
"Installing base " + base->reference.toString());
this->repo.pull(taskContext, base->reference, module, base->repo);
if (isTaskDone(taskContext.subState())) {
return;
}
auto ret = executePostInstallHooks(base->reference);
if (!ret) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
LINGLONG_ERRV(ret).message());
return;
}
transaction.addRollBack([this, baseRef = *base, module]() noexcept {
auto result = this->repo.remove(baseRef.reference, module);
if (!result) {
qCritical() << result.error();
Q_ASSERT(false);
}
result = executePostUninstallHooks(baseRef.reference);
if (!result) {
qCritical() << result.error();
Q_ASSERT(false);
}
});
}
transaction.commit();
// state may be error in pull, update state to processing
taskContext.updateState(linglong::api::types::v1::State::Processing, "Dependency installed");
}
auto PackageManager::Prune() noexcept -> QVariantMap

View File

@ -135,6 +135,9 @@ void PackageTask::updateState(linglong::api::types::v1::State newState,
if (curState == linglong::api::types::v1::State::Canceled
|| curState == linglong::api::types::v1::State::Failed
|| curState == linglong::api::types::v1::State::Succeed) {
if (curState == linglong::api::types::v1::State::Succeed) {
this->setProperty("Code", static_cast<int>(utils::error::ErrorCode::Success));
}
auto subState = optDone.value_or(linglong::api::types::v1::SubState::AllDone);
updateSubState(subState, message);
return;

View File

@ -1590,68 +1590,6 @@ OSTreeRepo::clearReference(const package::FuzzyReference &fuzzy,
return reference;
}
utils::error::Result<linglong::package::ReferenceWithRepo>
OSTreeRepo::getRemoteReferenceByPriority(const package::FuzzyReference &fuzzy,
const getRemoteReferenceByPriorityOption &opts,
const std::string &module) noexcept
{
LINGLONG_TRACE("get remote reference by priority")
auto repos = this->getHighestPriorityRepos();
// 指定了repo则不需要按照优先级来查找
if (opts.onlyClearHighestPriority) {
if (repos.empty()) {
return LINGLONG_ERR("No repositories available",
utils::error::ErrorCode::AppInstallNotFoundFromRemote);
}
// 找到优先级最高的第一个仓库
const auto &highestPriorityRepo = repos.front();
auto refRet =
this->clearReference(fuzzy,
{ .forceRemote = true, .semanticMatching = opts.semanticMatching },
module,
highestPriorityRepo.alias.value_or(highestPriorityRepo.name));
if (!refRet) {
return LINGLONG_ERR(refRet);
}
return linglong::package::ReferenceWithRepo{ .repo = highestPriorityRepo,
.reference = *refRet };
}
// 未指定repo则只找优先级最高的仓库可以有多个
std::vector<linglong::package::ReferenceWithRepo> results;
for (const auto &repo : repos) {
auto refRet =
this->clearReference(fuzzy,
{ .forceRemote = true, .semanticMatching = opts.semanticMatching },
module,
repo.alias.value_or(repo.name));
if (!refRet) {
if (static_cast<utils::error::ErrorCode>(refRet.error().code())
== utils::error::ErrorCode::AppNotFoundFromRemote) {
continue;
}
return LINGLONG_ERR(refRet);
}
results.emplace_back(
linglong::package::ReferenceWithRepo{ .repo = repo, .reference = *refRet });
}
// 寻找最新的版本
auto it = std::max_element(results.begin(), results.end(), [](const auto &a, const auto &b) {
return a.reference.version < b.reference.version;
});
if (it != results.end()) {
return *it;
}
return LINGLONG_ERR(fmt::format("not found {} in all repos", fuzzy.toString()),
utils::error::ErrorCode::AppInstallNotFoundFromRemote);
}
utils::error::Result<std::vector<api::types::v1::PackageInfoV2>>
OSTreeRepo::listLocal() const noexcept
{
@ -1871,27 +1809,31 @@ utils::error::Result<repo::RemotePackages>
OSTreeRepo::matchRemoteByPriority(const package::FuzzyReference &fuzzyRef,
const std::optional<api::types::v1::Repo> &repo) const noexcept
{
LINGLONG_TRACE("match remote packages by priority");
repo::RemotePackages remotePackages;
if (repo) {
auto list = this->searchRemote(fuzzyRef, *repo, true);
if (!list) {
LogW("failed to list remote packages from {}: {}", repo->name, list.error());
return remotePackages;
return LINGLONG_ERR(fmt::format("failed to search remote packages from {}", repo->name),
utils::error::ErrorCode::NetworkError);
}
if (!list->empty()) {
remotePackages.addPackages(*repo, std::move(list).value());
}
} else {
bool allError = true;
auto repos = this->getPriorityGroupedRepos();
for (const auto &repoGroup : repos) {
for (const auto &repo : repoGroup) {
auto list = this->searchRemote(fuzzyRef, repo, true);
if (!list) {
LogW("failed to list remote packages from {}: {}", repo.name, list.error());
LogW("failed to search remote packages from {}: {}", repo.name, list.error());
continue;
}
allError = false;
if (list->empty()) {
continue;
@ -1905,6 +1847,11 @@ OSTreeRepo::matchRemoteByPriority(const package::FuzzyReference &fuzzyRef,
break;
}
}
if (allError) {
return LINGLONG_ERR("failed to search remote packages",
utils::error::ErrorCode::NetworkError);
}
}
return remotePackages;
@ -3280,12 +3227,25 @@ OSTreeRepo::latestRemoteReference(package::FuzzyReference &fuzzyRef) noexcept
{
LINGLONG_TRACE("get latest reference");
fuzzyRef.version.reset();
auto ref = this->getRemoteReferenceByPriority(fuzzyRef, { .semanticMatching = false });
auto candidates = this->matchRemoteByPriority(fuzzyRef);
if (!candidates) {
return LINGLONG_ERR(candidates);
}
auto latestPackage = candidates->getLatestPackage();
if (!latestPackage) {
return LINGLONG_ERR(latestPackage);
}
auto ref = package::Reference::fromPackageInfo(latestPackage->second);
if (!ref) {
return LINGLONG_ERR(ref);
}
return ref;
return package::ReferenceWithRepo{
.repo = latestPackage->first,
.reference = std::move(ref).value(),
};
}
utils::error::Result<package::Reference>

View File

@ -94,10 +94,6 @@ public:
const clearReferenceOption &opts,
const std::string &module = "binary",
const std::optional<std::string> &repo = std::nullopt) const noexcept;
[[nodiscard]] utils::error::Result<linglong::package::ReferenceWithRepo>
getRemoteReferenceByPriority(const package::FuzzyReference &fuzzy,
const getRemoteReferenceByPriorityOption &opts,
const std::string &module = "binary") noexcept;
utils::error::Result<std::vector<api::types::v1::PackageInfoV2>> listLocal() const noexcept;
utils::error::Result<std::vector<api::types::v1::PackageInfoV2>>

View File

@ -605,8 +605,7 @@ TEST(OSTreeRepoTest, matchRemoteByPriority_AllReposError)
auto result = repo.matchRemoteByPriority(*fuzzyRef);
EXPECT_TRUE(result.has_value());
EXPECT_TRUE(result->empty());
EXPECT_FALSE(result.has_value());
}
TEST(OSTreeRepoTest, matchRemoteByPriority_NoReposConfigured)
@ -622,8 +621,7 @@ TEST(OSTreeRepoTest, matchRemoteByPriority_NoReposConfigured)
auto result = repo.matchRemoteByPriority(*fuzzyRef);
EXPECT_TRUE(result.has_value());
EXPECT_TRUE(result->empty());
EXPECT_FALSE(result.has_value());
}
TEST(OSTreeRepoTest, matchRemoteByPriority_UseHighestPriority)