Compare commits

...

31 Commits

Author SHA1 Message Date
wrj97 c451f3dd66
Merge cb5d3d31fa into 4e40696453 2025-11-06 19:18:25 +08:00
reddevillg 4e40696453 fix: fix memory error
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
pointer userAgent is a wild pointer

Signed-off-by: reddevillg <reddevillg@gmail.com>
2025-11-03 10:54:18 +08:00
reddevillg 8748a64e1e refactor: Rework repository client and search logic
Refactors the interaction with remote repositories to clarify the code's
intent.

Key changes include:
- Introduce `ClientAPIWrapper` to encapsulate the generated C-style API
  client.
- The remote package searching function is renamed from `listRemote` to
  `searchRemote` to better reflect its purpose.
- The `pull` method now requires an explicit repo argument.
- add `getPrioritySortedRepos` and `getPriorityGroupedRepos` helpers.

Co-authored-by: reddevillg <reddevillg@gmail.com>
Signed-off-by: reddevillg <reddevillg@gmail.com>
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
2025-10-30 13:30:06 +08:00
deepsource-autofix[bot] 174f40ca2e style: format code with ClangFormat and Prettier
This commit fixes the style issues introduced in f21b273 according to the output
from ClangFormat and Prettier.

Details: None
2025-10-29 10:18:26 +08:00
dengbo f21b273a64 docs: The document contains spelling and typos
Fix spelling and typos in the document.
2025-10-28 20:42:46 +08:00
wrj97 1cb0a541f4 chore: fix uab file name in test script
更新测试脚本中的 UAB 文件名以匹配实际的文件名格式。文
件名从 'org.deepin.demo_x86_64_0.0.0.1_main.uab' 改为
'org.deepin.demo_0.0.0.1_x86_64_main.uab',以符合项目中使用的正确命名
约定。
2025-10-28 10:10:36 +08:00
dengbo 2e83a40c79 fix: There will be multiple versions of the application when an error occurs during the upgrade process
1. Adds rollback mechanism for package installation when install new ref in update.
2. Remove OSTreeRepo redundant transaction.
2025-10-27 16:50:12 +08:00
ComixHe e34f87ec6f refactor: optimizing performance of semver parser
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
2025-10-24 17:13:07 +08:00
deepsource-autofix[bot] b4bcaae25c style: format code with ClangFormat and Prettier
This commit fixes the style issues introduced in 7a8cb94 according to the output
from ClangFormat and Prettier.

Details: None
2025-10-24 10:13:23 +08:00
reddevillg b57cad23b2 fix: clean code
- Replaced Qt logging calls with linyaps log system.
- Centralized log system initialization for tests.
- Remove the unused `isChildProcess` helper function.
- Remove permission notify, it's not used for a while.
- move `ensureDirectory` to file utils.

Signed-off-by: reddevillg <reddevillg@gmail.com>
2025-10-24 10:01:59 +08:00
deepsource-autofix[bot] 841b0b0d9b style: format code with ClangFormat and Prettier
This commit fixes the style issues introduced in 0b7e505 according to the output
from ClangFormat and Prettier.

Details: None
2025-10-24 09:51:11 +08:00
ComixHe 7a8cb94697 feat: support xdg-desktop-portal
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
2025-10-24 09:48:11 +08:00
reddevillg 0b7e505d42 refactor: Extract UAB installation logic into action class
The `PackageManager::installFromUAB` method was overly complex and
handled multiple responsibilities, including validation, user
interaction, and the core installation logic. This made the method
difficult to maintain, test, and understand.

This commit refactors the UAB installation process by extracting the
entire logic into a new `UabInstallationAction` class. This class
encapsulates all steps required for a UAB installation, from preparation
and validation to execution and cleanup.

We will continue refactoring and abstracting the Task and Action related
code in subsequent phases to improve maintainability and testability.

Signed-off-by: reddevillg <reddevillg@gmail.com>
2025-10-24 09:35:57 +08:00
HHR2020 c49e6cfab3 fix: add DBusPrivate to Qt6 find_package
- Updated `find_package(Qt6 COMPONENTS Core DBus)` to include `DBusPrivate` to ensure the availability of the `Qt6::DBusPrivate` target.
- This change aligns with Qt6.10 build system requirements, which mandate explicit inclusion of private modules.

https://doc-snapshots.qt.io/qt6-6.10/whatsnew610.html#build-system-changes
2025-10-23 16:56:07 +08:00
wrj97 8be74385ff fix: fix repo config comparison and add debug logs
Fixed the equality operator for Repo struct to include the newly added
mirrorEnabled field, preventing incorrect comparison results when this
field differs between configurations. Added static assertions to ensure
future structural changes to Repo-related types will trigger compilation
errors if equality operators are not updated accordingly.

Enhanced configuration setting logic with comprehensive debug logging
to improve troubleshooting capabilities. Added logging for configuration
changes, comparison results, and key operations during config updates to
help diagnose issues with repository configuration management.

Log: Improved repository configuration change detection and logging

Influence:
1. Test repository configuration changes with different mirrorEnabled
settings
2. Verify configuration comparison works correctly when only
mirrorEnabled differs
3. Check debug logs appear during configuration updates
4. Test configuration persistence and cache rebuilding after changes
5. Verify no regression in existing configuration management
functionality

fix: 修复仓库配置比较并添加调试日志

修复了 Repo 结构的相等运算符,包含新增的 mirrorEnabled 字段,防止在该字
段不同时产生错误的比较结果。添加了静态断言,确保未来对 Repo 相关类型的结
构更改如果未更新相等运算符实现将触发编译错误。

增强了配置设置逻辑,添加了全面的调试日志以改进故障排除能力。增加了配置变
更、比较结果和配置更新期间关键操作的日志记录,帮助诊断仓库配置管理问题。

Log: 改进仓库配置变更检测和日志记录

Influence:
1. 测试使用不同 mirrorEnabled 设置的仓库配置变更
2. 验证当仅 mirrorEnabled 不同时配置比较正常工作
3. 检查配置更新期间调试日志是否正确出现
4. 测试配置变更后的配置持久化和缓存重建
5. 验证现有配置管理功能无回归问题
2025-10-22 17:02:26 +08:00
wrj97 1adb797f05 feat: add unit tests for utility components
Added comprehensive unit tests for three utility modules:
1. GKeyFileWrapper tests - validate INI file parsing and manipulation
functionality including file loading, value setting/getting, group/key
operations, and file saving
2. PackageInfoHandler tests - test package information conversion
between V1 and V2 formats, JSON parsing from files/GFile objects, and
handling of optional fields
3. XDG directory tests - verify application data directory resolution
based on HOME environment variable with various app ID scenarios

These tests ensure the reliability of core utility functions used
throughout the Linglong system, covering edge cases, error handling, and
proper data conversion between different package information formats.

Influence:
1. Run test suite to verify all new unit tests pass
2. Test GKeyFileWrapper with various INI file formats and invalid inputs
3. Verify PackageInfoHandler handles both V1 and V2 package info formats
correctly
4. Test XDG directory resolution with different HOME environment
settings
5. Confirm error handling works as expected for invalid inputs

feat: 为工具组件添加单元测试

新增了三个工具模块的全面单元测试:
1. GKeyFileWrapper测试 - 验证INI文件解析和操作功能,包括文件加载、值设
置/获取、组/键操作和文件保存
2. PackageInfoHandler测试 - 测试V1和V2格式之间的包信息转换、从文件/GFile
对象解析JSON以及可选字段处理
3. XDG目录测试 - 基于HOME环境变量验证应用程序数据目录解析,涵盖各种应用
ID场景

这些测试确保了Linglong系统中使用的核心工具函数的可靠性,涵盖了边界情况、
错误处理以及不同包信息格式之间的正确数据转换。

Influence:
1. 运行测试套件验证所有新单元测试通过
2. 使用各种INI文件格式和无效输入测试GKeyFileWrapper
3. 验证PackageInfoHandler正确处理V1和V2包信息格式
4. 使用不同的HOME环境设置测试XDG目录解析
5. 确认错误处理对无效输入按预期工作
2025-10-22 17:01:52 +08:00
dengbo d94d9b8b76 feat: enhance inspect command with dir type
1.  Refactored the `inspect` command to support the `dir` subcommand for
displaying application directories.
2.  Added options to specify the directory type (`layer` or `bundle`)
and module type (`binary` or `develop`) when using the `dir` subcommand.
3.  Introduced a version option to retrieve directories for specific
application versions.
4.  Implemented `getLayerDir` and `getBundleDir` methods to fetch and
print the respective directory paths.
5.  The original `inspect` command that used pid is currently removed
because it is not commonly used and requires more discussion if needed.

Log: Added inspect command's dir subcommand to get the layer or bundle
directory of the installed(running) application.

Influence:
1. Test the `ll-cli inspect dir APP` command to verify it displays the
correct layer directory by default.
2. Test the `ll-cli inspect dir APP --type bundle` command to verify it
displays the correct bundle directory.
3. Test the `ll-cli inspect dir APP --type layer --module binary`
command to verify it displays the correct directory for the binary
module.
4. Test the `ll-cli inspect dir APP --version VERSION` command to
verify it displays the correct directory for the specified version of
the application.
5. Test with invalid application IDs and options to ensure proper error
handling and messages.

feat: 增强 inspect 命令,支持目录类型

1.  重构了 `inspect` 命令,以支持 `dir` 子命令来显示应用程序目录。
2.  添加了选项,用于在使用 `dir` 子命令时指定目录类型(`layer` 或
`bundle`)和模块类型(`binary` 或 `develop`)。
3.  引入了版本选项,以检索特定应用程序版本的目录。
4.  实现了 `getLayerDir` 和 `getBundleDir` 方法来获取和打印相应的目录
路径。
5.  原先使用 pid 的 `inspect` 命令已被移除,因为使用场景较少,并且如果需
要可能需要进行更多讨论。

Log: 增加了 inspect 命令的 dir 子命令,用于获取已安装(正在运行)应用程
序的 layer 或 bundle 目录。

Influence:
1. 测试 `ll-cli inspect dir APP` 命令,验证它默认显示正确的 layer 目录。
2. 测试 `ll-cli inspect dir APP --type bundle` 命令,验证它显示正确的
bundle 目录。
3. 测试 `ll-cli inspect dir APP --type layer --module binary` 命令,验证
它显示 binary 模块的正确目录。
4. 测试 `ll-cli inspect dir APP --version VERSION` 命令,验证它显示指定
版本应用程序的正确目录。
5. 使用无效的应用程序 ID 和选项进行测试,以确保正确的错误处理和消息。
2025-10-22 09:42:40 +08:00
reddevillg 9b118c691d fix: fix logging and mergeOutput
- `fmt::println(stderr, message)` could crash if the message contained
  format specifiers like `{}`.
- fix the `mergeOutput` logic and extract it from the `Builder` class
  into a free function within the `detail` namespace. This refactoring
  allows for easier unit testing.
- Unit tests have been added for both `mergeOutput` function and the
  logging format fix.
2025-10-20 09:59:50 +08:00
reddevillg 588fd5c49e feat: Add --mount option and improve loader
Adds a new `--mount` command-line option to the UAB helper. This allows
mounting the UAB's bundle filesystem to a specified directory and
keeping it mounted, which is useful for debugging and inspection.

The UAB loader is enhanced to forward all its command-line arguments
to the application running inside the container.

Signed-off-by: reddevillg <reddevillg@gmail.com>
2025-10-16 10:58:26 +08:00
ComixHe 8b596142cb build: update linyaps-box
Adjust the CMake build for UAB

Signed-off-by: ComixHe <ComixHe1895@outlook.com>
2025-10-15 15:58:24 +08:00
dengbo 74efe1d5e2 fix: base field is empty when use ll-cli search
There is no value assigned to base in PackageInfoV2.
2025-10-15 13:49:11 +08:00
reddevillg 76fcc5b201 feat: Add --privileged and --caps-add options to 'run' command
- The `--privileged` flag allows running a container with an elevated
  set of capabilities and share user namespace with host. This is useful
  for applications that require broader access to host system resources,
  such as network management tools or debugging tools.
- The `--caps-add` option allows for adding specific Linux capabilities
  to the container, offering fine-grained privilege control.

Signed-off-by: reddevillg <reddevillg@gmail.com>
2025-10-15 13:42:41 +08:00
wrj97 cfe7785a80 chore: fix linglong test script package name
测试脚本已更新以修正安装命令中的包文件名格式。原来的文件名
模式'org.deepin.demo_x86_64_0.0.0.1_main.uab'不正确,已更改
为'org.deepin.demo_0.0.0.1_x86_64_main.uab'以匹配后续二进制层安装中使用
的实际包命名约定。这确保了测试过程中UAB包和二进制层包名称的一致性。
2025-10-15 13:16:51 +08:00
ComixHe a74ab84a5f fix: correct formatted message
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
2025-10-15 13:14:12 +08:00
deepsource-autofix[bot] 7551f68448 style: format code with ClangFormat and Prettier
This commit fixes the style issues introduced in 857948b according to the output
from ClangFormat and Prettier.

Details: None
2025-10-15 09:49:43 +08:00
guanzi008 857948b3c3 feat: Support manual extension loading via command line
Introduces the `--extensions` command-line flag for both cli and
builder, enabling users to manually specify and load extensions at
runtime.
2025-10-14 20:25:37 +08:00
ComixHe 01049a68aa refactor: remove unnecessary parameter of errorImpl ctor
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
2025-10-14 18:05:52 +08:00
ComixHe 399d70fd44 chore: update linyaps-box to 2.1.1
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
2025-10-14 17:39:56 +08:00
reddevillg 1035ae54d8 feat: Add tests and enhance string utilities
Add unit tests for the strings utility functions

Key changes include:

- Enhance `trim` to support trimming with a custom set of characters
- `join` function can handle empty vector now
- Rename `hasPrefix` and `hasSuffix` to `starts_with` and `ends_with`
  respectively.

Signed-off-by: reddevillg <reddevillg@gmail.com>
2025-10-14 17:27:46 +08:00
wrj97 75b70e80af refactor: simplify error handling and improve testing
The error handling implementation has been simplified by removing Qt
dependencies from the core error module. The ErrorImpl class now uses
std::string instead of QString for message storage and formatting. This
makes the error module more portable and reduces dependencies on Qt.
The error message output in main.cpp has been updated to directly use
the std::string message without unnecessary conversion to std::string
via toStdString() since the message() method now returns std::string
directly.

Additionally, the test files have been reorganized - the result_test.cpp
has been removed and its content merged into a new error_test.cpp file
with expanded test coverage. The new tests cover more error scenarios
including standard error codes and Qt file errors.

Log: Improved error handling and testing infrastructure

Influence:
1. Test repository operations (add/remove/update/set-default/enable-
mirror/disable-mirror) to verify error messages are displayed correctly
2. Run the updated error tests to ensure all error scenarios are
properly handled
3. Verify error messages contain relevant context information when
operations fail
4. Check that error handling works consistently across different error
types

重构:简化错误处理并改进测试

错误处理实现已通过从核心错误模块中移除 Qt 依赖项得到简化。ErrorImpl 类
现在使用 std::string 而不是 QString 进行消息存储和格式化。这使得错误模
块更具可移植性并减少了对 Qt 的依赖。main.cpp 中的错误消息输出已更新为直
接使用 std::string 消息,无需通过 toStdString() 进行不必要的转换,因为
message() 方法现在直接返回 std::string。

此外,测试文件已重新组织 - result_test.cpp 已被删除,其内容已合并到新的
error_test.cpp 文件中,并扩展了测试覆盖范围。新测试涵盖了更多错误场景,
包括标准错误代码和 Qt 文件错误。

Log: 改进错误处理和测试基础设施

影响:
1. 测试仓库操作(添加/删除/更新/设置默认/启用镜像/禁用镜像)以验证错误消
息是否正确显示
2. 运行更新后的错误测试以确保所有错误场景得到正确处理
3. 验证操作失败时错误消息包含相关上下文信息
4. 检查错误处理在不同错误类型间的一致性
2025-10-14 17:08:52 +08:00
myml cb5d3d31fa
fix: improve process handling in ensureCache method
如果缓存生成时间小于300ms, 则不再显示等待窗口
如果等待窗口显示时间小于1s,则等待1s后再关闭窗口, 避免窗口闪烁
2025-08-06 11:33:28 +08:00
159 changed files with 4947 additions and 2192 deletions

View File

@ -225,6 +225,7 @@ if(BUILD_LINGLONG_BUILDER_UTILS_IN_BOX)
pfl_add_libraries(
LIBS
api
common
ocppi
oci-cfg-generators
APPS
@ -269,6 +270,9 @@ else()
while(true)
find_package(Qt6 COMPONENTS Core DBus)
if(Qt6_FOUND AND Qt6_VERSION VERSION_GREATER_EQUAL "6.10")
find_package(Qt6 COMPONENTS DBusPrivate)
endif()
if(Qt6_FOUND)
set(QT_VERSION_MAJOR "6")
break()

View File

@ -29,6 +29,7 @@ struct RunCommandOptions
std::vector<std::string> execModules;
std::vector<std::string> commands;
bool debugMode = false;
std::vector<std::string> extensions;
};
struct ListCommandOptions

View File

@ -301,7 +301,7 @@ int handleRun(linglong::builder::Builder &builder, const RunCommandOptions &opti
}
}
auto result = builder.run(modules, options.commands, options.debugMode);
auto result = builder.run(modules, options.commands, options.debugMode, options.extensions);
if (!result) {
LogE("Run failed: {}", result.error());
return result.error().code();
@ -471,7 +471,7 @@ int handleRepoAdd(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOptions &
auto ret = repo.setConfig(newCfg);
if (!ret) {
std::cerr << ret.error().message().toStdString() << std::endl;
std::cerr << ret.error().message() << std::endl;
return -1;
}
@ -503,7 +503,7 @@ int handleRepoRemove(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOption
newCfg.repos.erase(existingRepo);
auto ret = repo.setConfig(newCfg);
if (!ret) {
std::cerr << ret.error().message().toStdString() << std::endl;
std::cerr << ret.error().message() << std::endl;
return -1;
}
@ -535,7 +535,7 @@ int handleRepoUpdate(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOption
auto ret = repo.setConfig(newCfg);
if (!ret) {
std::cerr << ret.error().message().toStdString() << std::endl;
std::cerr << ret.error().message() << std::endl;
return -1;
}
@ -562,7 +562,7 @@ int handleRepoSetDefault(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOp
newCfg.defaultRepo = alias;
auto ret = repo.setConfig(newCfg);
if (!ret) {
std::cerr << ret.error().message().toStdString() << std::endl;
std::cerr << ret.error().message() << std::endl;
return -1;
}
qInfo() << "Default repository set to" << QString::fromStdString(alias) << "successfully.";
@ -591,7 +591,7 @@ int handleRepoEnableMirror(linglong::repo::OSTreeRepo &repo, linglong::cli::Repo
existingRepo->mirrorEnabled = true;
auto ret = repo.setConfig(newCfg);
if (!ret) {
std::cerr << ret.error().message().toStdString() << std::endl;
std::cerr << ret.error().message() << std::endl;
return -1;
}
@ -617,7 +617,7 @@ int handleRepoDisableMirror(linglong::repo::OSTreeRepo &repo, linglong::cli::Rep
existingRepo->mirrorEnabled = false;
auto ret = repo.setConfig(newCfg);
if (!ret) {
std::cerr << ret.error().message().toStdString() << std::endl;
std::cerr << ret.error().message() << std::endl;
return -1;
}
std::cerr << "Repository " << alias << " mirror disabled successfully.";
@ -834,6 +834,7 @@ You can report bugs to the linyaps team under this project: https://github.com/O
runOpts.execModules,
_("Run specified module. eg: --modules binary,develop"))
->delimiter(',')
->allow_extra_args(false)
->type_name("modules");
buildRun->add_option(
"COMMAND",
@ -842,6 +843,14 @@ You can report bugs to the linyaps team under this project: https://github.com/O
buildRun->add_flag("--debug",
runOpts.debugMode,
_("Run in debug mode (enable develop module)"));
buildRun
->add_option("--extensions",
runOpts.extensions,
_("Specify extension(s) used by the app to run"))
->type_name("REF")
->delimiter(',')
->allow_extra_args(false)
->check(validatorString);
auto buildList = commandParser.add_subcommand("list", _("List built linyaps app"));
buildList->usage(_("Usage: ll-builder list [OPTIONS]"));
@ -1075,15 +1084,13 @@ You can report bugs to the linyaps team under this project: https://github.com/O
}
}
const auto defaultRepo = linglong::repo::getDefaultRepo(*repoCfg);
linglong::repo::ClientFactory clientFactory(defaultRepo.url);
auto repoRoot = QDir{ QString::fromStdString(builderCfg->repo) };
if (!repoRoot.exists() && !repoRoot.mkpath(".")) {
qCritical() << "failed to create the repository of builder.";
return -1;
}
linglong::repo::OSTreeRepo repo(repoRoot, *repoCfg, clientFactory);
linglong::repo::OSTreeRepo repo(repoRoot, *repoCfg);
if (buildRepo->parsed()) {
return handleRepo(repo,

View File

@ -181,7 +181,8 @@ ll-cli run org.deepin.demo -- bash -x /path/to/bash/script)"));
->expected(0, -1);
cliRun->add_option("--env", runOptions.envs, _("Set environment variables for the application"))
->type_name("ENV")
->expected(0, -1)
// vector parameter allow extra args by default, but we don't want it
->allow_extra_args(false)
->check([](const std::string &env) -> std::string {
if (env.find('=') == std::string::npos) {
return std::string{ _(
@ -200,6 +201,21 @@ ll-cli run org.deepin.demo -- bash -x /path/to/bash/script)"));
_("Specify the runtime used by the application to run"))
->type_name("REF")
->check(validatorString);
cliRun
->add_option("--extensions",
runOptions.extensions,
_("Specify extension(s) used by the application to run"))
->type_name("REF")
->delimiter(',') // 支持以逗号分隔
->allow_extra_args(false) // 避免吞掉后面的参数
->check(validatorString);
cliRun
->add_flag("--privileged", runOptions.privileged, _("Run the application in privileged mode"))
->group("");
cliRun->add_option("--caps-add", runOptions.capsAdd, _("Add capabilities to the application"))
->delimiter(',')
->allow_extra_args(false)
->group("");
cliRun->add_option("COMMAND", runOptions.commands, _("Run commands in a running sandbox"));
}
@ -553,42 +569,35 @@ void addInspectCommand(CLI::App &commandParser,
{
auto *cliInspect =
commandParser
.add_subcommand("inspect", _("Display the information of installed application"))
.add_subcommand("inspect",
_("Display the inspect information of the installed application"))
->group(group)
->usage(_("Usage: ll-cli inspect [OPTIONS]"));
cliInspect->footer("This subcommand is for internal use only currently");
cliInspect->add_option("-p,--pid", inspectOptions.pid, _("Specify the process id"))
->check([](const std::string &input) -> std::string {
if (input.empty()) {
return _("Input parameter is empty, please input valid parameter instead");
}
->usage(_("Usage: ll-cli inspect SUBCOMMAND [OPTIONS]"));
try {
auto pid = std::stoull(input);
if (pid <= 0) {
return _("Invalid process id");
}
} catch (std::exception &e) {
return _("Invalid pid format");
}
cliInspect->require_subcommand(1);
return {};
});
}
// Function to add the dir subcommand
void addDirCommand(CLI::App &commandParser, DirOptions &dirOptions, const std::string &group)
{
auto cliLayerDir =
commandParser.add_subcommand("dir", "Get the layer directory of app(base or runtime)")
->group(group);
cliLayerDir->footer("This subcommand is for internal use only currently");
cliLayerDir
->add_option("APP", dirOptions.appid, _("Specify the installed app(base or runtime)"))
// 创建 inspect dir 子命令
auto *cliInspectDir = cliInspect->add_subcommand(
"dir",
_("Display the data(bundle) directory of the installed(running) application"));
cliInspectDir->usage(_("Usage: ll-cli inspect dir [OPTIONS] APP"));
cliInspectDir
->add_option("APP",
inspectOptions.appid,
_("Specify the application ID, and it can also be reference"))
->required()
->check(validatorString);
cliLayerDir->add_option("--module", dirOptions.module, _("Specify a module"))
->type_name("MODULE")
cliInspectDir
->add_option("-t, --type",
inspectOptions.dirType,
_("Specify the directory type (layer or bundle),the default is layer"))
->type_name("TYPE")
->capture_default_str()
->check(validatorString);
cliInspectDir
->add_option("-m, --module",
inspectOptions.module,
_("Specify the module type (binary or develop). Only works when type is layer"))
->check(validatorString);
}
@ -607,11 +616,6 @@ linglong::utils::error::Result<linglong::repo::OSTreeRepo *> initOSTreeRepo()
return LINGLONG_ERR("load repo config failed", repoConfig);
}
// get default repo
auto defaultRepo = linglong::repo::getDefaultRepo(*repoConfig);
auto clientFactory = new linglong::repo::ClientFactory(std::move(defaultRepo.url));
clientFactory->setParent(QCoreApplication::instance());
// check repo root
auto repoRoot = QDir(LINGLONG_ROOT);
if (!repoRoot.exists()) {
@ -619,7 +623,7 @@ linglong::utils::error::Result<linglong::repo::OSTreeRepo *> initOSTreeRepo()
}
// create repo
auto repo = new linglong::repo::OSTreeRepo(repoRoot, std::move(*repoConfig), *clientFactory);
auto repo = new linglong::repo::OSTreeRepo(repoRoot, std::move(*repoConfig));
repo->setParent(QCoreApplication::instance());
return repo;
}
@ -677,7 +681,6 @@ You can report bugs to the linyaps team under this project: https://github.com/O
ContentOptions contentOptions{};
RepoOptions repoOptions{};
InspectOptions inspectOptions{};
DirOptions dirOptions{};
// groups for subcommands
auto *CliBuildInGroup = _("Managing installed applications and runtimes");
@ -700,7 +703,6 @@ You can report bugs to the linyaps team under this project: https://github.com/O
addContentCommand(commandParser, contentOptions, CliBuildInGroup);
addPruneCommand(commandParser, CliAppManagingGroup);
addInspectCommand(commandParser, inspectOptions, CliHiddenGroup);
addDirCommand(commandParser, dirOptions, CliHiddenGroup);
auto res = transformOldExec(argc, argv);
CLI11_PARSE(commandParser, std::move(res));
@ -906,11 +908,9 @@ You can report bugs to the linyaps team under this project: https://github.com/O
} else if (name == "prune") {
result = cli->prune();
} else if (name == "inspect") {
result = cli->inspect(inspectOptions);
result = cli->inspect(*ret, inspectOptions);
} else if (name == "repo") {
result = cli->repo(*ret, repoOptions);
} else if (name == "dir") {
result = cli->dir(dirOptions);
} else {
// if subcommand name is not found, print help
std::cout << commandParser.help("", CLI::AppFormatMode::All);

View File

@ -32,10 +32,6 @@ void withDBusDaemon(ocppi::cli::CLI &cli)
QCoreApplication::exit(-1);
return;
}
const auto defaultRepo = linglong::repo::getDefaultRepo(*config);
qWarning() << "server" << defaultRepo.url.c_str();
auto *clientFactory = new linglong::repo::ClientFactory(defaultRepo.url);
clientFactory->setParent(QCoreApplication::instance());
auto repoRoot = QDir(LINGLONG_ROOT);
if (!repoRoot.exists() && !repoRoot.mkpath(".")) {
@ -48,7 +44,7 @@ void withDBusDaemon(ocppi::cli::CLI &cli)
qCritical() << "failed to migrate repository";
QCoreApplication::exit(-1);
}
auto *ostreeRepo = new linglong::repo::OSTreeRepo(repoRoot, *config, *clientFactory);
auto *ostreeRepo = new linglong::repo::OSTreeRepo(repoRoot, *config);
ostreeRepo->setParent(QCoreApplication::instance());
auto result = ostreeRepo->fixExportAllEntries();
if (!result.has_value()) {
@ -101,17 +97,13 @@ void withoutDBusDaemon(ocppi::cli::CLI &cli)
return;
}
const auto defaultRepo = linglong::repo::getDefaultRepo(*config);
auto *clientFactory = new linglong::repo::ClientFactory(defaultRepo.url);
clientFactory->setParent(QCoreApplication::instance());
auto repoRoot = QDir(LINGLONG_ROOT);
if (!repoRoot.exists() && !repoRoot.mkpath(".")) {
qCritical() << "failed to create repository directory" << repoRoot.absolutePath();
std::abort();
}
auto *ostreeRepo = new linglong::repo::OSTreeRepo(repoRoot, *config, *clientFactory);
auto *ostreeRepo = new linglong::repo::OSTreeRepo(repoRoot, *config);
ostreeRepo->setParent(QCoreApplication::instance());
auto result = ostreeRepo->fixExportAllEntries();
if (!result.has_value()) {

View File

@ -46,6 +46,7 @@ uabBundle [uabOptions...] [-- loaderOptions...]
Options:
--extract=PATH extract the read-only filesystem image which is in the 'linglong.bundle' segment of uab to PATH. [exclusive]
--mount=PATH mount the read-only filesystem image which is in the 'linglong.bundle' segment of uab to PATH, use ctrl+c to stop. [exclusive]
--print-meta print content of json which from the 'linglong.meta' segment of uab to STDOUT [exclusive]
--help print usage of uab [exclusive]
)";
@ -53,6 +54,7 @@ Options:
enum uabOption : std::uint8_t {
Help = 1,
Extract,
Mount,
Meta,
};
@ -61,6 +63,7 @@ struct argOption
bool help{ false };
bool printMeta{ false };
std::string extractPath;
std::string mountPath;
std::vector<std::string_view> loaderArgs;
};
@ -543,9 +546,10 @@ argOption parseArgs(const std::vector<std::string_view> &args)
opts.loaderArgs.assign(splitter + 1, args.cend());
}
std::array<struct option, 4> long_options{
std::array<struct option, 5> long_options{
{ { "print-meta", no_argument, nullptr, uabOption::Meta },
{ "extract", required_argument, nullptr, uabOption::Extract },
{ "mount", required_argument, nullptr, uabOption::Mount },
{ "help", no_argument, nullptr, uabOption::Help },
{ nullptr, 0, nullptr, 0 } }
};
@ -572,6 +576,10 @@ argOption parseArgs(const std::vector<std::string_view> &args)
opts.extractPath = optarg;
++counter;
} break;
case uabOption::Mount: {
opts.mountPath = optarg;
++counter;
} break;
case uabOption::Help: {
opts.help = true;
++counter;
@ -592,16 +600,31 @@ argOption parseArgs(const std::vector<std::string_view> &args)
}
int mountSelf(const lightElf::native_elf &elf,
const linglong::api::types::v1::UabMetaInfo &metaInfo) noexcept
const linglong::api::types::v1::UabMetaInfo &metaInfo,
const std::filesystem::path &mp = {}) noexcept
{
if (mountFlag.load(std::memory_order_relaxed)) {
std::cout << "bundle already has been mounted" << std::endl;
return 0;
}
const auto &uuid = metaInfo.uuid;
if (auto ret = createMountPoint(uuid); ret != 0) {
return ret;
if (mp.empty()) {
const auto &uuid = metaInfo.uuid;
if (auto ret = createMountPoint(uuid); ret != 0) {
return ret;
}
} else {
std::error_code ec;
auto state = std::filesystem::status(mp, ec);
if (ec) {
std::cerr << "failed to status " + mp.string() + ": " + ec.message() << std::endl;
return -1;
}
if (!std::filesystem::is_directory(state)) {
std::cerr << mp.string() << "is not a directory" << std::endl;
return -1;
}
mountPoint = mp;
}
if (auto ret = mountSelfBundle(elf, metaInfo); ret != 0) {
@ -655,16 +678,19 @@ int main(int argc, char **argv)
std::abort();
});
if (!opts.extractPath.empty()) {
if (auto ret = mountSelf(elf, metaInfo); ret != 0) {
return ret;
}
return extractBundle(opts.extractPath);
if (auto ret = mountSelf(elf, metaInfo, opts.mountPath); ret != 0) {
return ret;
}
if (auto ret = mountSelf(elf, metaInfo); ret != 0) {
return ret;
bool mountOnly = !opts.mountPath.empty();
if (mountOnly) {
while (true) {
pause();
}
}
if (!opts.extractPath.empty()) {
return extractBundle(opts.extractPath);
}
const bool onlyApp = metaInfo.onlyApp.value_or(false);

View File

@ -3,6 +3,7 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "linglong/api/types/v1/Generators.hpp" // IWYU pragma: keep
#include "linglong/common/strings.h"
#include "linglong/oci-cfg-generators/container_cfg_builder.h"
#include "ocppi/runtime/config/types/Generators.hpp" // IWYU pragma: keep
#include "ocppi/runtime/config/types/Hook.hpp"
@ -260,20 +261,9 @@ bool processProfile(const std::filesystem::path &extraDir,
bool generateEntrypoint(linglong::generator::ContainerCfgBuilder &builder,
std::vector<std::string> originalArgs) noexcept
{
// FIXME: use linglong::utils::quoteBashArg
std::for_each(originalArgs.begin(), originalArgs.end(), [](std::string &arg) {
constexpr std::string_view quotePrefix = "'\\";
for (auto it = arg.begin(); it != arg.end(); it++) {
if (*it == '\'') {
it = arg.insert(it, quotePrefix.cbegin(), quotePrefix.cend());
it = arg.insert(it + quotePrefix.size() + 1, 1, '\'');
}
}
});
std::string content = "#!/bin/env bash\nsource /etc/profile\nexec ";
std::string content = "#!/usr/bin/env bash\nsource /etc/profile\nexec ";
for (const auto &arg : originalArgs) {
content.append(arg);
content.append(linglong::common::strings::quoteBashArg(arg));
content.push_back(' ');
}
@ -388,7 +378,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT
}
auto containerID = genRandomString();
auto containerBundleDir = bundleDir.parent_path().parent_path() / containerID;
auto containerBundleDir = bundleDir.parent_path() / containerID;
if (!std::filesystem::create_directories(containerBundleDir, ec) && ec) {
std::cerr << "couldn't create directory " << containerBundleDir << " :" << ec.message()
<< std::endl;
@ -553,8 +543,11 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT
}
// generate entrypoint
if (!generateEntrypoint(builder,
appInfo->command.value_or(std::vector<std::string>{ "/bin/bash" }))) {
auto command = appInfo->command.value_or(std::vector<std::string>{ "/bin/bash" });
for (int i = 1; i < argc; ++i) {
command.push_back(argv[i]);
}
if (!generateEntrypoint(builder, command)) {
std::cerr << "failed to generate entrypoint" << std::endl;
return -1;
}

View File

@ -1,8 +1,8 @@
# Application run conf
# Application Run Configuration
Application run conf is the file how linglong runtime module load the app,
Application run configuration is the file that the Linglong runtime module uses to load the app.
and the conf is machine related, the user can set mount path, permisson control file to the app.
The configuration is machine-related, and the user can set mount paths and permission control files for the app.
## File Format
@ -10,7 +10,7 @@ Should be a yaml file.
## Storage
The config is highly user related, it should store in ~/.linglong/{appid}/app.yaml
The config is highly user related, it should be stored in ~/.linglong/{appid}/app.yaml
If not exist, create it first from info.json.
@ -26,15 +26,15 @@ package:
runtime:
ref: org.deepin.Runtime/20/x86_64
# the section only can set by develop, and only work with debug enable
debug:
# override entrypoint
args:
- /opt/apps/com.qq.weixin.work.deepin/files/run.sh
- --debug
# override the base, casefully set the debug args
mount-bottom:
- /usr:/usr
# This section can only be set by developers and only works with debug enabled
debug:
# Override entrypoint
args:
- /opt/apps/com.qq.weixin.work.deepin/files/run.sh
- --debug
# Override the base, carefully set the debug args
mount-bottom:
- /usr:/usr
permissions:
# mount after all runtime container build
@ -44,7 +44,7 @@ permissions:
- ${HOME}/Documents:${HOME}/Documents
- ${HOME}/Desktop:${HOME}/Desktop
- ${HOME}/Downloads:${HOME}/Downloads
# todo: session and system bus
# TODO: session and system bus
dbus:
owner:
- com.qq.weixin.work.deepin

View File

@ -1,51 +1,50 @@
# Bundle Format
## Introduce
## Introduction
Green software, known as some binary does not install any file to the system.
Green software refers to binaries that do not install any files to the system.
The base constraint of green software is:
The basic constraints of green software are:
- Path unrelated, means has nothing to do with local files.
- Path independence, meaning it has nothing to do with local files
- High compatibility, so the software should contain all dependencies that the system does not have
- highly compatibility, so the software should contain all dependencies that the system does not have.
The well-known technology for building green software on Linux is AppImage.
The famous technology to build green software is AppImage on Linux.
However, there are many problems with that technology. The biggest problem is that the host system ABI cannot stay stable and differs from one system to another. Linglong cannot solve that problem either. We should maintain a baseline of supported systems or ABIs.
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.
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.
A trick on UnionTech OS or Deepin is to only support systems after UnionTech OS 1020, which reduces the testing work for different base systems.
## 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.
The green bundle is not just simple support for running applications independently. It is also designed to be the offline maintainer package format for office system services that support self-running and installation. Therefore, keep the changeability of the bundle format in mind 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.
When a user has internet access, we mostly use online differential updates or install from repositories. We do not use bundles if we can access the repository when distributing applications.
## Specification
The spec of the export bundle:
The specification for the export bundle:
- MUST be an ELF, can be FlatELF
- MUST be an ELF file, which 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
- MUST contain a data segment that can be mounted with FUSE
- MUST contain a loader executable at the root of the FUSE-mounted filesystem
## Implementation
**The implementation change with timeIf you change the implement, update this selection as soon as possible !!!**
**The implementation changes over time. If you change the implementation, update this section as soon as possible!**
### prototype
### 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
- The bundle is a sample ELF loader that joins a read-only filesystem with cat
- The loader simply calls read_elf64 to calculate the offset of the read-only filesystem
- The loader mounts the read-only filesystem with `squashfuse -o ro,offset=xxx`
- The filesystem is now a read-only filesystem
- The root of the filesystem should contain a file named loader (by the way, currently it's .loader)
- The directory structure should be: /{id}/{version}/{arch}/
- The read-only filesystem should support EROFS, and MAY support squashfs
a full example of the filesystem is:
A full example of the filesystem is:
```bash

View File

@ -1,8 +1,8 @@
# 玲珑仓库 mirror 功能设计
# 玲珑仓库 Mirror 功能设计
在ll-cli和ll-builder中添加了enable-mirror和disable-mirror命令用于启用和禁用镜像功能。
ll-cli ll-builder 中添加了 enable-mirror disable-mirror 命令,用于启用和禁用镜像功能。
在对某个仓库启用mirror功能时会更新ostree的config文件添加contenturl配置项
在对某个仓库启用 mirror 功能时,会更新 ostree config 文件,添加 contenturl 配置项:
```diff
url=$repo_url/repos/$repo_name
@ -11,19 +11,19 @@ http2=false
+ contenturl=mirrorlist=$repo_url/api/v2/mirrors/$repo_name
```
当添加contenturl配置项后ostree会优先使用contenturl下载静态文件如files, url仅用于获取元数据如summary, contenturl支持file://、http://、https://三种协议。
当添加 contenturl 配置项后ostree 会优先使用 contenturl 下载静态文件如 filesurl 仅用于获取元数据如 summary。contenturl 支持 file://、http://、https:// 三种协议。
如果在url前面添加mirrorlist=则ostree会先从url获取按行分割的镜像列表然后从镜像列表中选择镜像用于下载文件具体逻辑见 [ostree_pull](#ostree-pull-步骤) 章节。
如果在 url 前面添加 mirrorlist=,则 ostree 会先从 url 获取按行分割的镜像列表,然后从镜像列表中选择镜像用于下载文件,具体逻辑见 [ostree pull 步骤](#ostree-pull-步骤) 章节。
/api/v2/mirrors/$repo_name 是玲珑服务器的一个API接口通过客户端IP获取客户端所在国家从配置文件获取对应国家的镜像列表然后返回给ostree这样就实现了根据用户所在国家自动分流仓库文件下载的功能
/api/v2/mirrors/$repo_name 是玲珑服务器的一个 API 接口,通过客户端 IP 获取客户端所在国家,从配置文件获取对应国家的镜像列表,然后返回给 ostree这样就实现了根据用户所在国家自动分流仓库文件下载的功能。
## 镜像站配置
玲珑的镜像站只提供仓库静态文件的https访问即可玲珑仓库支持rsync和ostree两种同步协议。
玲珑的镜像站只需提供仓库静态文件的 HTTPS 访问即可,玲珑仓库支持 rsync 和 ostree 两种同步协议。
### 使用 rsync 同步配置
优点是同步速度快缺点是需从支持rsync协议的镜像站或官方仓库同步仓库。
优点是同步速度快,缺点是需从支持 rsync 协议的镜像站或官方仓库同步仓库。
```bash
rsync rsync://rsync.linyaps.org.cn/repos/stable $www_root/repos/stable
@ -31,9 +31,9 @@ rsync rsync://rsync.linyaps.org.cn/repos/stable $www_root/repos/stable
### 使用 ostree 同步配置
优点是无协议支持,可从任意镜像站同步仓库,缺点是同步速度较慢。
优点是无协议支持,可从任意镜像站同步仓库,缺点是同步速度较慢。
保存下面脚本,并命名为 sync.sh然后执行`sh sync.sh https://mirror-repo-linglong.deepin.com/repos/stable/ $www_root/repos/stable`
保存下面脚本,并命名为 sync.sh然后执行 `sh sync.sh https://mirror-repo-linglong.deepin.com/repos/stable/ $www_root/repos/stable`
```bash
#!/bin/bash
@ -54,16 +54,16 @@ done
### 判断镜像是否可用
pull时ostree 先从contenturl获取镜像列表然后从每个url获取/config文件如果获取不到/config文件则认为该mirror不可用如果获取到/config文件则认为该mirror可用。如果没有可用mirrorpull失败。
pull 时ostree 先从 contenturl 获取镜像列表,然后从每个 url 获取 /config 文件。如果获取不到 /config 文件,则认为该 mirror 不可用;如果获取到 /config 文件,则认为该 mirror 可用。如果没有可用 mirrorpull 失败。
### 获取summary文件
### 获取 summary 文件
ostree会从url获取summary文件如果获取不到summary文件或者summary文件不存在refpull失败。
ostree 会从 url 获取 summary 文件。如果获取不到 summary 文件,或者 summary 文件中不存在 refpull 失败。
### delta-indexes文件获取
### delta-indexes 文件获取
ostree会在每个可用的mirror中获取delta-indexes如果mirror服务器返回4xx或5xx则在下一个mirror中获取delta-indexes如果最后的mirror返回5xx则pull失败如果最后的mirror返回4xx则跳过dalta步骤直接拉取files。
ostree 会在每个可用的 mirror 中获取 delta-indexes。如果 mirror 服务器返回 4xx 或 5xx则在下一个 mirror 中获取 delta-indexes。如果最后的 mirror 返回 5xx则 pull 失败;如果最后的 mirror 返回 4xx则跳过 delta 步骤直接拉取 files。
### files文件获取
### files 文件获取
ostree会按顺序从可用的mirror中获取files如果mirror服务器返回403, 404 410则认为错误不可恢复pull失败如果mirror服务器返回其他错误码则使用下一个mirror获取files。如果所有mirror都无法获取files则pull失败。
ostree 会按顺序从可用的 mirror 中获取 files。如果 mirror 服务器返回 403、404、410则认为错误不可恢复pull 失败;如果 mirror 服务器返回其他错误码,则使用下一个 mirror 获取 files。如果所有 mirror 都无法获取 files pull 失败。

View File

@ -16,7 +16,7 @@ We can use the `gdbserver` provided by the distribution, using `apt` as an examp
sudo apt install gdbserver gdb -y
```
Next, refer to the tutorial in "Run compiled App", run `bash` in the container through the `ll-build run` command, and run the application to be debugged through `gdbserver`:
Next, refer to the tutorial in "Run compiled App", run `bash` in the container through the `ll-builder run` command, and run the application to be debugged through `gdbserver`:
```bash
ll-build run --exec /bin/bash

View File

@ -36,7 +36,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
8. Why is the Icon displayed as a small black dot?
The desktop file has an 'Icon' field written, but the Icon field name is incorrect or an absolute path is being used."。
The desktop file has an 'Icon' field written, but the Icon field name is incorrect or an absolute path is being used.
9. Why is the Icon field as a gear?
@ -48,7 +48,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
Other formats are stored according to resolution, such as 16x16.
png/xpm → $PREFIX/share/icons/hicolor/16X16/apps/
png/xpm → $PREFIX/share/icons/hicolor/16x16/apps/
11. Why do `xdg-open` and `xdg-email` that come with the application fail?
@ -80,7 +80,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
18. Can the input method of uab offline package format not be used under Debian and Ubuntu?
It is recommended to install the `fictx` input method to experience it.
It is recommended to install the `fcitx` input method to experience it.
19. How can I know which packages are installed in a container environment?

View File

@ -10,7 +10,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
The link library path is not a regular path, the new path is `/runtime/lib`. Add the environment variable `LIBRARY_PATH=<libpath>`, which is included in the build environment by default.
2. `link` static library failed when building, which requires re-build with `fPIC`.
2. `link` static library failed when building, which requires re-building with `-fPIC`.
Use the `-fPIC` parameter when building a static library.
@ -18,12 +18,12 @@ SPDX-License-Identifier: LGPL-3.0-or-later
![ll-box start failed](images/ll-box-start-failed.png)
The kernel does not support `unprivilege namespace`, please open `unprivilege namespace` to solve it.
The kernel does not support `unprivileged namespace`, please open `unprivileged namespace` to solve it.
```bash
sudo sysctl -w kernel.unprivileged_userns_clone=1
```
4. The build of `qtbase` is successful, but the `qt` application cannot be built, which prompts `module,mkspec` related errors.
4. The build of `qtbase` is successful, but the `qt` application cannot be built, which prompts `module`, `mkspec` related errors.
There is a problem in the lower version of `fuse-overlay mount`, which leads to the polluted file content when `qtbase commit`, and cannot be used. Use `fuse-overlayfs >= 1.8.2` version.

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
## Conversion appimage application
convert `appimage` format( `.appimage` or `.AppImage` ) application to linyaps format( `.layer` or `.uab` ) application
convert `appimage` format (`.appimage` or `.AppImage`) application to linyaps format (`.layer` or `.uab`) application
View the help information for the `ll-appimage-convert convert --help` command:
@ -36,20 +36,20 @@ Global Flags:
-V, --verbose verbose output
```
The `ll-appimage-convert convert` command will generate a directory according to specified app name( `--name` option), it will as a root directory of the linyaps project, where the `linglong.yaml` file is located. and it supports two convert methods:
The `ll-appimage-convert convert` command will generate a directory according to the specified app name (`--name` option), which will serve as the root directory of the linyaps project where the `linglong.yaml` file is located. It supports two conversion methods:
1. you can use `--file` option to convert to linyaps application according to specified appimage file;
2. you can use `--url` and `--hash` option to convert to linyaps application according to specified appimage url and hash value;
3. you can use `--layer` option to export `.layer`, or it will export `.uab` default.
1. you can use the `--file` option to convert to linyaps application according to the specified appimage file;
2. you can use the `--url` and `--hash` option to convert to linyaps application according to the specified appimage url and hash value;
3. you can use the `--layer` option to export `.layer`, or it will export `.uab` by default.
`Tips: When the linglong version is greater than 1.5.7, the default convert package format is `.uab`, if you want to export a `.layer` file, you need to add the --layer option.`
`Tips: When the linyaps version is greater than 1.5.7, the default converted package format is `.uab`. If you want to export a `.layer` file, you need to add the --layer option.`
you can use `--output` option to generate config file( `linglong.yaml` ) of linyaps project and a script of build linyaps `.layer`(`.uab`)
then you can execute script file to generate after you modify the `linglong.yaml` file. if you do not specify this option, it will export linyaps `.layer` or `.uab` directly.
you can use the `--output` option to generate the configuration file (`linglong.yaml`) of the linyaps project and a script for building linyaps `.layer` (`.uab`)
then you can execute the script file to generate after you modify the `linglong.yaml` file. If you do not specify this option, it will export linyaps `.layer` or `.uab` directly.
Take converting [BrainWaves](https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage) into linyaps `.layer` through `--url` as an example, the main steps as follows:
Take converting [BrainWaves](https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage) into linyaps `.layer` through `--url` as an example, the main steps are as follows:
Specify the relevant parameters of the linyaps package you want to convert, you can acquire `io.github.brainwaves_0.15.1.0_x86_64_runtime.layer` or `io.github.brainwaves_0.15.1.0_x86_64_runtime.uab` wait a moment.
Specify the relevant parameters of the linyaps package you want to convert, and you will obtain `io.github.brainwaves_0.15.1.0_x86_64_runtime.layer` or `io.github.brainwaves_0.15.1.0_x86_64_runtime.uab` after a short wait.
```bash
ll-appimage-convert convert --url "https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage" --hash "04fcfb9ccf5c0437cd3007922fdd7cd1d0a73883fd28e364b79661dbd25a4093" --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b
@ -85,4 +85,4 @@ The converted directory structure is as follows:
```
`.uab` or `.layer` file verification
The exported `.uab` or `.layer` needs to be installed and verified. install the layer file and run the application, you can refer to: [Install the application](../ll-cli/install.md)
The exported `.uab` or `.layer` files need to be installed and verified. Install the layer files and run the application. You can refer to: [Install the application](../ll-cli/install.md)

View File

@ -1,6 +1,6 @@
# ll-appimage-convert introduction
This tool is provided by the `linglong-pica` package.which provides the ability to convert appimage packages into linyaps packages, generate the linglong.yaml file required to build linyaps applications, and rely on ll-builder to implement application building and export.
This tool is provided by the `linglong-pica` package, which provides the ability to convert appimage packages into linyaps packages, generate the linglong.yaml file required to build linyaps applications, and relies on ll-builder to implement application building and export.
:::tip
@ -21,7 +21,7 @@ ll-appimage-convert --help
Here is the output:
```bash
Convert the appimage to uab. For example:
Convert appimage to uab. For example:
Simple:
ll-appimage-convert convert -f xxx.appimage -i "io.github.demo" -n "io.github.demo" -v "1.0.0.0" -d "this is a appimage convert demo" -b
ll-appimage-convert help

View File

@ -40,10 +40,10 @@ Options:
The `ll-builder build` command can be run in two ways:
1. the root directory of the project, where the `linglong.yaml` file is located.
2. specify the linglong.yaml file path with the `--file` parameter.
1. In the root directory of the project, where the `linglong.yaml` file is located.
2. Specify the linglong.yaml file path with the `--file` parameter.
Taking the linyaps project `org.deepin.demo`, as an example, the main steps to build a linyaps application would be as follows:
Taking the linyaps project `org.deepin.demo` as an example, the main steps to build a linyaps application would be as follows:
Go to the `org.deepin.demo` project directory:
@ -67,4 +67,4 @@ ll-builder build --exec /bin/bash
After entering the container, you can execute `shell` commands, such as `gdb`, `strace`, etc.
For more debugging information of linyaps application `debug` version, please refer to: [Debug App](../debug/debug.md).
For more debugging information about linyaps application `debug` version, please refer to: [Debug App](../debug/debug.md).

View File

@ -28,7 +28,7 @@ Options:
--help-all Expand all help
```
The `ll-builder create` command creates a folder in the current directory according to the project name, and generates the `linglong.yaml` template file required for the build. Here is an example:
The `ll-builder create` command creates a folder in the current directory according to the project name and generates the `linglong.yaml` template file required for the build. Here is an example:
```bash
ll-builder create org.deepin.demo

View File

@ -99,7 +99,7 @@ build: |
make install
```
For more details on configuration file fields, please refer to [Configuration File Description](https://www.google.com/search?q=./manifests.md)
For more details on configuration file fields, please refer to [Configuration File Description](./manifests.md)
## Execute the Build Process
@ -152,4 +152,4 @@ The directory structure after export is as follows:
## More Complete Examples
[Complete Example](https://www.google.com/search?q=../start/how_to_use.md) - a complete example that includes how to build an application, export build content, install, and run.
[Complete Example](../start/how_to_use.md) - a complete example that includes how to build an application, export build content, install, and run.

View File

@ -8,15 +8,15 @@ SPDX-License-Identifier: LGPL-3.0-or-later
## Introduction to ll-builder
`ll-builder` is a tool for developers for building linyaps applications.
`ll-builder` is a tool for developers to build linyaps applications.
The main functions are as follows:
- Supports building in a standalone sandbox.
- Supports building in a standalone sandbox
<!-- - Defined a version management system. -->
<!-- - Defines a version management system. -->
- Provides DTK software development kits.
- Provides DTK software development kits
<!-- - Contains a complete release process. -->
@ -42,7 +42,7 @@ Options:
Subcommands:
create Create linyaps build template project
build Build a linyaps project
run Run builded linyaps app
run Run built linyaps app
export Export to linyaps layer or uab
push Push linyaps app to remote repo
import Import linyaps layer to build repo

View File

@ -39,7 +39,7 @@ In particular, if the organization name and application name of the application
**Note**: In fact, the organization owns the domain name `neovim.io`, so the most reasonable application name **should** be `io.neovim.neovim`.
- **Not recommended** to use application names containing `-`, if the domain name/application name does contain `-`, **recommend** to use `_` instead
- **Not recommended** to use application names containing `-`. If the domain name/application name does contain `-`, **recommend** using `_` instead
- **Not recommended** application names ending with `.desktop`

View File

@ -60,7 +60,7 @@ package:
| kind | Type of the build artifact: `app` (Application), `runtime` (Runtime) | Yes |
| description | Detailed description of the build artifact | Yes |
| architecture | Target architecture of the build artifact (e.g., `x86_64`, `arm64`) | No |
| channel | Channel of the build artifact (e.g., `stable`, `beta`) | No |
| channel | Channel of the build artifact (e.g., `main`) | No |
### Command (`command`)

View File

@ -30,7 +30,7 @@ Options:
--module TEXT Push single module
```
The `ll-builder push` command reads the content of the `bundle` format package according to the file path, and transfers the software data and `bundle` format package to the server.
The `ll-builder push` command reads the content of the `bundle` format package according to the file path and transfers the software data and `bundle` format package to the server.
```bash
ll-builder push <org.deepin.demo-1.0.0_x86_64.uab>

View File

@ -4,7 +4,7 @@ SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
SPDX-License-Identifier: LGPL-3.0-or-later
-->
# Run compiled App
# Run Compiled App
Use `ll-builder run` to run the compiled executable program.
@ -17,7 +17,7 @@ ll-builder run --help
Here is the output:
```text
Run builded linyaps app
Run built linyaps app
Usage: ll-builder run [OPTIONS] [COMMAND...]
Positionals:
@ -51,4 +51,4 @@ To facilitate debugging, use an additional `--exec /bin/bash` parameter to repla
ll-builder run --exec /bin/bash
```
With this option, `ll-builder` will enter the `bash` terminal after creating the container, and can perform other operations inside the container.
With this option, `ll-builder` will enter the `bash` terminal after creating the container, and you can perform other operations inside the container.

View File

@ -27,7 +27,7 @@ Options:
-h,--help Print this help message and exit
--help-all Expand all help
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
# Attach To Container
Use `ll-cli exec` to enter the inside of the running linyaps container.
Use `ll-cli exec` to enter the running linyaps container.
View the help information for the `ll-cli exec` command:
@ -21,7 +21,7 @@ Execute commands in the currently running sandbox
Usage: ll-cli [OPTIONS] [SUBCOMMAND]
Positionals:
INSTANCE TEXT REQUIRED Specify the application running instance(you can get it by ps command)
INSTANCE TEXT REQUIRED Specify the application running instance (you can get it by ps command)
COMMAND TEXT ... Run commands in a running sandbox
Options:
@ -30,7 +30,7 @@ Options:
--working-directory PATH:DIR
Specify working directory
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```
@ -38,14 +38,14 @@ Open a new terminal window and run these commands:
Example of using `ll-cli exec` to get inside org.dde.calendar container:
1. using `ll-cli ps` to get container id:
1. Use `ll-cli ps` to get container ID:
```bash
App ContainerID Pid
main:org.dde.calendar/5.14.5.0/x86_64 c3b5ce363172 539537
```
2. enter the org.dde.calendar container
2. Enter the org.dde.calendar container
```bash
ll-cli exec main:org.dde.calendar/5.14.5.0/x86_64 /bin/bash

View File

@ -27,7 +27,7 @@ Options:
-h,--help Print this help message and exit
--help-all Expand all help
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```

View File

@ -41,15 +41,15 @@ Positionals:
Options:
-h,--help Print this help message and exit
--help-all Expand all help
--module MODULE Install a specify module
--module MODULE Install a specific module
--force Force install the application
-y Automatically answer yes to all questions
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```
Example of the `ll-cli install` command to install a linyaps app:
Example of using the `ll-cli install` command to install a linyaps app:
```bash
ll-cli install <org.deepin.calculator>
@ -57,7 +57,7 @@ ll-cli install <org.deepin.calculator>
Enter the complete `appid` after `ll-cli install`. If the repository has multiple versions, the highest version will be installed by default.
To install a specified version, append the corresponding version number after `appid`:
To install a specific version, append the corresponding version number after `appid`:
```bash
ll-cli install <org.deepin.calculator/5.1.2>
@ -71,7 +71,7 @@ Install main:org.deepin.calculator/5.7.21.4/x86_64 success:100%
After the application is installed, the installation result will be displayed.
The layer or uab files we export using the `ll-builder export` command can be installed using the `ll-cli install` command.
The layer or UAB files exported using the `ll-builder export` command can be installed using the `ll-cli install` command.
`.layer`
@ -80,15 +80,15 @@ ll-cli install ./com.baidu.baidunetdisk_4.17.7.0_x86_64_runtime.layer
```
`.uab`
There are two ways to install uab files
There are two ways to install UAB files:
- use `ll-cli install` to install
- Use `ll-cli install` to install
```bash
ll-cli install com.baidu.baidunetdisk_x86_64_4.17.7.0_main.uab
```
- Execute `uab` on a machine with linyaps environment to install the application.
- Execute the UAB file on a machine with linyaps environment to install the application.
```bash
./com.baidu.baidunetdisk_x86_64_4.17.7.0_main.uab

View File

@ -21,9 +21,9 @@ Run an application
Usage: ll-cli run [OPTIONS] APP [COMMAND...]
Example:
# run application by appid
# Run application by appid
ll-cli run org.deepin.demo
# execute commands in the container rather than running the application
# Execute commands in the container rather than running the application
ll-cli run org.deepin.demo bash
ll-cli run org.deepin.demo -- bash
ll-cli run org.deepin.demo -- bash -x /path/to/bash/script
@ -38,6 +38,6 @@ Options:
--file FILE:FILE Pass file to applications running in a sandbox
--url URL Pass url to applications running in a sandbox
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```

View File

@ -27,11 +27,11 @@ Options:
-h,--help Print this help message and exit
--help-all Expand all help
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```
Example of the `ll-cli kill` command to force quit running linyaps apps:
Example of using the `ll-cli kill` command to force quit running linyaps apps:
```bash
ll-cli kill org.deepin.calculator

View File

@ -31,10 +31,10 @@ ll-cli list --upgradable
Options:
-h,--help Print this help message and exit
--help-all Expand all help
--type TYPE [app] Filter result with specify type. One of "runtime", "app" or "all"
--type TYPE [app] Filter result with specific type. One of "runtime", "app" or "all"
--upgradable Show the list of latest version of the currently installed applications, it only works for app
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```
@ -68,7 +68,7 @@ org.deepin.Runtime deepin runtime 23.0.1.2
org.deepin.foundation deepin-foundation 23.0.0.27 x86_64 main runtime deepin base environment.
```
To view the list of latest version of the currently installed applications, run `ll-cli list --upgradable`:
To view the list of latest versions of the currently installed applications, run `ll-cli list --upgradable`:
Here is the output:

View File

@ -24,11 +24,11 @@ Options:
-h,--help Print this help message and exit
--help-all Expand all help
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```
Use `ll-cli prune` to remove the unused base or runtime
Use `ll-cli prune` to remove the unused base or runtime:
Here is the output:

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
# View Running Apps
Use `ll-cli ps` to view running linyaps Apps.
Use `ll-cli ps` to view running linyaps apps.
View the help information for the `ll-cli ps` command:
@ -24,11 +24,11 @@ Options:
-h,--help Print this help message and exit
--help-all Expand all help
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```
Use `ll-cli ps` to view running linyaps Apps:
Use `ll-cli ps` to view running linyaps apps:
```bash
ll-cli ps

View File

@ -21,12 +21,12 @@ Search the applications/runtimes containing the specified text from the remote r
Usage: ll-cli search [OPTIONS] KEYWORDS
Example:
# find remotely app by name ll-cli search org.deepin.demo
# find remotely runtime by name
# find remote app by name ll-cli search org.deepin.demo
# find remote runtime by name
ll-cli search org.deepin.base --type=runtime
# find all off app of remote
# find all remote apps
ll-cli search .
# find all off runtime of remote
# find all remote runtimes
ll-cli search . --type=runtime
Positionals:
@ -34,10 +34,10 @@ Positionals:
Options:
-h,--help Print this help message and exit --help-all Expand all help
--type TYPE [app] Filter result with specify type. One of "runtime", "app" or "all"
--dev include develop application in result
--type TYPE [app] Filter result with specific type. One of "runtime", "app" or "all"
--dev include development application in result
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```
@ -47,7 +47,7 @@ Use `ll-cli search` to search app meta info from remote repository and local cac
ll-cli search calculator
```
This command returns the info of all apps whose `appid` (appid is the app's unique identifier) contains the keyword "calculator", including the complete `appid`, application name, version, CPU architecture and descriptions.
This command returns the info of all apps whose `appid` (appid is the app's unique identifier) contains the keyword "calculator", including the complete `appid`, application name, version, CPU architecture and description.
Here is the output:

View File

@ -8,13 +8,13 @@ SPDX-License-Identifier: LGPL-3.0-or-later
Use `ll-cli run` command to start a linyaps application.
See help for the `ll-cli run` command:
View help for the `ll-cli run` command:
```bash
ll-cli run --help
```
View the help information for the `ll-cli run` command:
Here is the output:
```text
Run an application
@ -36,7 +36,7 @@ Options:
--help-all Expand all help --file FILE:FILE Pass file to applications running in a sandbox
--url URL Pass url to applications running in a sandbox
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```
@ -52,7 +52,7 @@ Use the `ll-cli run` command to enter the specified program container:
ll-cli run org.deepin.calculator --exec /bin/bash
```
After entering, execute `shell` commands, such as `gdb`, `strace`, `ls`, `find`, etc.
After entering, execute shell commands, such as `gdb`, `strace`, `ls`, `find`, etc.
Since linyaps applications run in the container, they cannot be directly debugged in the conventional way. You need to run debugging tools in the container, such as `gdb`:

View File

@ -26,9 +26,9 @@ Positionals:
Options:
-h,--help Print this help message and exit
--help-all Expand all help
--module MODULE Uninstall a specify module
--module MODULE Uninstall a specific module
If you found any problems during use,
If you find any problems during use,
You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```

View File

@ -21,16 +21,16 @@ Upgrade the application or runtimes
Usage: ll-cli upgrade [OPTIONS] [APP]
Positionals:
APP TEXT Specify the application ID.If it not be specified, all applications will be upgraded
APP TEXT Specify the application ID. If it is not specified, all applications will be upgraded
Options:
-h,--help Print this help message and exit
--help-all Expand all help
If you found any problems during use, You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
If you find any problems during use, You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues
```
Use `ll-cli upgrade ` to upgrade all installed apps to the latest version
Use `ll-cli upgrade` to upgrade all installed apps to the latest version:
Here is the output:

View File

@ -1,4 +1,4 @@
## Conversion Flatpak application
## Convert Flatpak application
The `ll-pica-flatpak convert` command is used to convert Flatpak applications into linyaps applications.
@ -26,7 +26,7 @@ Flags:
-h, --help help for ll-pica-flatpak
```
Convert Flatpak application
Convert Flatpak application:
```bash
ll-pica-flatpak convert org.videolan.VLC --build
@ -36,11 +36,11 @@ ll-pica-flatpak convert org.videolan.VLC --build
The package name for Flatpak is org.videolan.VLC. It can be found by visiting [https://flathub.org/](https://flathub.org/) => clicking on the app => selecting the Install drop-down menu => viewing the package name.
ll-pica-flatpak uses ostree commands to retrieve the application data of org.videolan.VLC, and generates the corresponding linyaps base environment based on the runtime defined in the metadata
ll-pica-flatpak uses ostree commands to retrieve the application data of org.videolan.VLC, and generates the corresponding linyaps base environment based on the runtime defined in the metadata.
:::
The application defaults to generating a uab file. To export a layer file, you need to add the --layer parameter.
The application defaults to generating a UAB file. To export a layer file, you need to add the --layer parameter.
```bash
ll-pica-flatpak convert org.videolan.VLC --build --layer
@ -70,6 +70,6 @@ The constructed products are as follows:
Layer files are divided into two categories: `binary` and `develop`. The `binary` includes the application's execution environment, while the `develop` layer, built upon the `binary`, retains the debugging environment.
The uab file is an offline distribution format used by the linyaps software package, which is not suitable for systems that can normally connect to the linyaps repository. Instead, one should utilize the delta transfer scheme provided by the linyaps software repository to reduce the network transmission size.
The UAB file is an offline distribution format used by the linyaps software package, which is not suitable for systems that can normally connect to the linyaps repository. Instead, one should utilize the delta transfer scheme provided by the linyaps software repository to reduce the network transmission size.
Installing Layer Files and Running the Application Reference[Install linyaps Apps](../ll-cli/install.md)
Installing Layer Files and Running the Application Reference: [Install linyaps Apps](../ll-cli/install.md)

View File

@ -1,6 +1,6 @@
# ll-flatpak-convert introduction
This tool is provided by the `linglong-pica` package.which provides the ability to convert flatpak packages into linyaps packages, generate the linglong.yaml file required to build linyaps applications, and rely on ll-builder to implement application building and export.
This tool is provided by the `linglong-pica` package, which provides the ability to convert flatpak packages into linyaps packages, generate the linglong.yaml file required to build linyaps applications, and rely on ll-builder to implement application building and export.
:::tip
@ -26,7 +26,7 @@ Simple:
ll-pica-flatpak convert [flatpak name] --build
Usage:
ll-pica [command]
ll-pica-flatpak [command]
Available Commands:
convert Convert flatpak to uab

View File

@ -5,7 +5,7 @@ be addressed by adding the corresponding package dependencies in the `linglong.y
The `ll-pica adep` command is used to add package dependencies to the `linglong.yaml` file.
View the help information for the `ll-cli adep` command:
View the help information for the `ll-pica adep` command:
```bash
ll-pica adep --help

View File

@ -1,8 +1,8 @@
## Conversion application
## Convert application
The `ll-pica convert` command is used to generate the `linglong.yaml` file required by linyaps.
View the help information for the `ll-cli convert` command:
View the help information for the `ll-pica convert` command:
```bash
ll-pica convert --help
@ -31,7 +31,7 @@ Global Flags:
-V, --verbose verbose output
```
Translation: After executing the `ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo` command
After executing the `ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo` command
We only need to execute the command `ll-pica convert -w w -b` to convert the linyaps application. Here, we will use the `apt download` command to download the deb package named `com.baidu.baidunetdisk`.
@ -52,10 +52,10 @@ apt download com.baidu.baidunetdisk
ll-pica convert -c com.baidu.baidunetdisk_4.17.7_amd64.deb -w w -b --exportFile layer
```
- -w working directory
- -w working directory.
- -c The configuration method employed here utilizes deb files.
- -b It indicates that a build is required; without adding this parameter, neither building nor exporting the layer file will take place.
- --exportFile layer exports the output as a layer file. If you want to export a uab file, use --exportFile uab.
- --exportFile layer exports the output as a layer file. If you want to export a UAB file, use --exportFile uab.
The constructed products are as follows:
@ -71,6 +71,6 @@ The constructed products are as follows:
Layer files are divided into two categories: `binary` and `develop`. The `binary` includes the application's execution environment, while the `develop` layer, built upon the `binary`, retains the debugging environment.
The uab file is an offline distribution format used by the linyaps software package, which is not suitable for systems that can normally connect to the linyaps repository. Instead, one should utilize the delta transfer scheme provided by the linyaps software repository to reduce the network transmission size.
The UAB file is an offline distribution format used by the linyaps software package, which is not suitable for systems that can normally connect to the linyaps repository. Instead, one should utilize the delta transfer scheme provided by the linyaps software repository to reduce the network transmission size.
Installing Layer Files and Running the Application Reference[Install linyaps Apps](../ll-cli/install.md)
Installing Layer Files and Running the Application Reference: [Install linyaps Apps](../ll-cli/install.md)

View File

@ -2,7 +2,7 @@
The `ll-pica init` command is used to initialize the configuration information for the conversion package.
View the help information for the `ll-cli init` command:
View the help information for the `ll-pica init` command:
```bash
ll-pica init --help
@ -32,7 +32,7 @@ Global Flags:
-V, --verbose verbose output
```
The specific command as follows:
The specific command is as follows:
```bash
ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo

View File

@ -37,7 +37,7 @@ runtime:
| distro_version | The codename of a distribution." |
| arch | The architecture required by a deb package. |
### Deb package informationeb
### Deb package information
```bash
file:
@ -48,9 +48,9 @@ file:
ref: /tmp/com.baidu.baidunetdisk_4.17.7_amd64.deb
```
| name | description |
| ---- | -------------------------------------------------------------------------------------------------------------------------- |
| type | The method of acquisition: 'local' requires specifying a reference, while 'repo' does not require specifying a reference." |
| id | Unique name of the build product |
| name | Specify the correct package name that apt can search for. |
| ref | The path of the deb package on the host machine. |
| name | description |
| ---- | ------------------------------------------------------------------------------------------------------------------------- |
| type | The method of acquisition: 'local' requires specifying a reference, while 'repo' does not require specifying a reference. |
| id | Unique name of the build product |
| name | Specify the correct package name that apt can search for. |
| ref | The path of the deb package on the host machine. |

View File

@ -97,7 +97,7 @@ ll-builder build
ll-builder run
```
the successful output of `ll-builder run` is as follows:
The successful output of `ll-builder run` is as follows:
![org.deepin.calculator.png](./images/org.deepin.calculator.png)
@ -109,7 +109,7 @@ ll-builder run --exec /bin/bash
# Conversion application
Here, we use baidunetdisk as an example. We will introduce the process of converting DEB packages into linyaps packages
Here, we use baidunetdisk as an example. We will introduce the process of converting DEB packages into linyaps packages.
## Obtain software package
@ -133,12 +133,12 @@ Enter the directory
cd work/package/com.baidu.baidunetdisk/amd64
```
Installed using the `ll-cli install` command.
Install using the `ll-cli install` command.
```bash
ll-cli install ./com.baidu.baidunetdisk_4.17.7.0_x86_64_runtime.layer
```
Successful execution output as follows:
Successful execution output is as follows:
![img](images/com.baidu.baidunetdisk.png)

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
# Install linyaps
linyaps is composed of three parts.
linyaps is composed of three parts:
- ll-builder is used to build and debug linyaps applications, provided by linglong-builder.
- ll-box is a sandbox container, provided by linglong-box.
@ -49,7 +49,7 @@ The Linyaps Web Store installation tool needs to be installed through the [AUR r
```bash
# AUR
yay -Syu linyaps-web-store-installer
# 或自建源
# or self-built source
sudo pacman -Syu linyaps-web-store-installer
```

View File

@ -6,21 +6,21 @@ SPDX-License-Identifier: LGPL-3.0-or-later
# Summary
linyaps, an open source package format developed by UnionTech Software, is designed to manage, distribute, create a sandbox for packages, and integrate development tools, instead of using package management tools such as `deb` or `rpm`.
linyaps, an open source package format developed by UnionTech Software, is designed to manage, distribute, create sandboxes for packages, and integrate development tools, instead of using package management tools such as `deb` or `rpm`.
## Problems with current package management
1. Both `deb` and `rpm` are strongly-dependent package management systems and allow complex cross dependencies (or circular dependencies) between components, which makes maintenance a matter of great expertise. A little carelessness will lead to a complete system failure that cannot be repaired.
1. Both `deb` and `rpm` are strongly-dependent package management systems that allow complex cross dependencies (or circular dependencies) between components, which makes maintenance a matter of great expertise. A little carelessness will lead to a complete system failure that cannot be repaired.
2. Installation dependencies and running dependencies are coupled so that multiple versions can hardly coexist. Although `deb` and `rpm` have provided several solutions to solve the multi-version coexistence problem, these solutions require changes in source code and are infeasible.
3. The `Hook` system is complex and has no restrictions, through which many operations can damage the system.
4. They have insufficient reliability, no redundant recovery design, and a lack of verification mechanisms. Once the package management system fails, the system can hardly be repaired.
5. The permissions of `deb` and `rpm` are loosely controlled with big security risks.
5. The permissions of `deb` and `rpm` are loosely controlled with significant security risks.
6. The current package updates do not support incremental updates, which is a great waste of resources.
## linyaps advantages
1. Improve usability and solve the dependency conflict problem of `deb` and `rpm`.
2. Perform the application permission management mechanism to strengthen security.
2. Implement the application permission management mechanism to strengthen security.
3. Support incremental updates of applications.
## Comparison

View File

@ -1,20 +1,20 @@
# 玲珑应用构建工程基础知识
在正式开始构建一个玲珑应用工程前, 我们需要对关于玲珑应用构建的基础知识有一定的认知, 以此协助我们更好地决策我们在启动构建工程前决定要准备哪些材料、进行哪一类型的操作
在正式开始构建一个玲珑应用工程前,我们需要对玲珑应用构建的基础知识有一定的认知,以此协助我们更好地决定在启动构建工程前需要准备哪些材料、进行哪一类型的操作
## 玲珑应用构建基本步骤
在正式开始构建一个玲珑应用工程前, 我们需要了解一个玲珑应用从资源(源代码、二进制文件等)输入到应用安装包导出所经过的基本步骤, 来确定我们需要准备哪些必要文件
在正式开始构建一个玲珑应用工程前,我们需要了解一个玲珑应用从资源(源代码、二进制文件等)输入到应用安装包导出所经过的基本步骤,来确定我们需要准备哪些必要文件。
1. 获取构建目标源文件(开源项目源代码、应用二进制文件等)
2. 根据源文件判断玲珑应用构建类型, 选择合适的构建方案
1. 获取构建目标源文件(开源项目源代码、应用二进制文件等)
2. 根据源文件判断玲珑应用构建类型选择合适的构建方案
3. 准备符合要求的玲珑构建环境
4. 按照构建类型及源代码内容定制构建配置文件 `linglong.yaml`
5. 准备应用所使用的通用类资源, 图标以及其他非二进制资源
5. 准备应用所使用的通用类资源图标以及其他非二进制资源
## 玲珑应用构建工程所需材料
结合上述的知识, 我们可以了解到一个玲珑应用在构建的全过程中, 主要涉及到以下的文件:
结合上述知识,我们可以了解到一个玲珑应用在构建的全过程中,主要涉及到以下文件:
1. 玲珑应用构建工程配置文件 `linglong.yaml`
2. 应用源代码/需要封装的二进制文件等资源
@ -22,32 +22,32 @@
## 玲珑应用遵循的主流规范
每一款Linux桌面软件包管理方案为了能够保障完整的功能和良好的体验, 均需要遵守软件包管理方案提出的各类规范要求以最大限度发挥软件包管理方案的功能并保障应用生态体验.
如意玲珑也并不总是特立独行, 需要满足一定的规范来保障如意玲珑生态得以持续稳步发展.
每一款 Linux 桌面软件包管理方案为了能够保障完整的功能和良好的体验均需要遵守软件包管理方案提出的各类规范要求以最大限度发挥软件包管理方案的功能并保障应用生态体验
如意玲珑也并不总是特立独行,需要满足一定的规范来保障如意玲珑生态得以持续稳步发展。
目前如意玲珑生方案遵守以下主流的规范:
目前如意玲珑方案遵守以下主流的规范:
1. Freedesktop XDG规范
1. Freedesktop XDG 规范
2. 玲珑应用目录结构规范
3. 玲珑应用构建工程配置文件 `linglong.yaml` 规范
### Freedesktop XDG规范
1. 玲珑应用解决方案遵循Freedesktop XDG规范,一款正常的图形化应用应具备图标文件、desktop文件并符合Freedesktop XDG规范
2. 玲珑应用图标文件应该根据不同尺寸归类到`$PREFIX/share/icons/hicolor/目录下
3. 玲珑应用容器中使用 `XDG_DATA_DIRS` 等变量, 支持读写宿主机中的用户目录
1. 玲珑应用解决方案遵循 Freedesktop XDG 规范,一款正常的图形化应用应具备图标文件、desktop 文件并符合 Freedesktop XDG 规范
2. 玲珑应用图标文件应该根据不同尺寸归类到 `$PREFIX/share/icons/hicolor/` 目录下
3. 玲珑应用容器中使用 `XDG_DATA_DIRS` 等变量,支持读写宿主机中的用户目录。
### 玲珑应用目录结构规范
1. 玲珑应用遵循$PREFIX路径规则,该变量自动生成, 应用所有相关文件需存放于此目录下, 该目录层级下存在 `bin` `share` 等目录
1. 玲珑应用遵循 $PREFIX 路径规则,该变量自动生成,应用所有相关文件需存放于此目录下,该目录层级下存在 `bin`、`share` 等目录。
2. 玲珑应用容器中的应用将不被允许读取宿主机中系统目录中的二进制文件、运行库
2. 玲珑应用容器中的应用将不被允许读取宿主机中系统目录中的二进制文件、运行库
3. 在构建工程中, 构建工程目录将会被映射到玲珑容器中, 挂载为 `/project`
3. 在构建工程中,构建工程目录将会被映射到玲珑容器中,挂载为 `/project`
4. 玲珑应用容器中运行库、头文件所在目录将根据运行环境类型而异
foundation类: 在玲珑容器中映射为普通系统路径 `/usr/bin` `/usr/include` 等, 作为基础运行系统环境存在
runtime类: 在玲珑容器中映射为runtime容器路径 `/runtime/usr/bin` `/runtime/usr/include` 等, 作为基础运行系统环境存在
4. 玲珑应用容器中运行库、头文件所在目录将根据运行环境类型而异
foundation 类:在玲珑容器中映射为普通系统路径 `/usr/bin`、`/usr/include` 等,作为基础运行系统环境存在。
runtime 类:在玲珑容器中映射为 runtime 容器路径 `/runtime/usr/bin`、`/runtime/usr/include` 等,作为基础运行系统环境存在。
\*默认情况下, 玲珑容器内部的环境变量已自动处理好路径识别问题, 如:
@ -65,14 +65,14 @@ PATH=szbt@szbt-linyaps23:/project$ echo $PATH
## 玲珑应用构建工程通用资源的规范
在玲珑应用构建工程中, 不同的资源文件均需要遵循相关规范以确保构建、体验能够满足要求
在玲珑应用构建工程中不同的资源文件均需要遵循相关规范以确保构建、体验能够满足要求
### icons 图标目录规范
依据玲珑遵循的 `Freedesktop XDG规范``玲珑应用目录结构规范`, 图标根据不同尺寸放置在对应的目录中
依据玲珑遵循的 `Freedesktop XDG规范``玲珑应用目录结构规范`图标根据不同尺寸放置在对应的目录中
主流的非矢量图标尺寸有: `16x16` `24x24` `32x32` `48x48` `128x128` `256x256` `512x512`
为保障图标在系统中能够获得较佳的体验效果, 因此需要至少一个尺寸不小于 `128x128` 的非矢量图标文件, 矢量图标则不存在该限制
为保障图标在系统中能够获得较佳的体验效果,因此需要至少一个尺寸不小于 `128x128` 的非矢量图标文件,矢量图标则不存在该限制
因此, 一款玲珑应用安装目录中, icons图标目录应为以下示例:
@ -87,7 +87,7 @@ $PREFIX/share/icons/hicolor/512x512/apps
$PREFIX/share/icons/hicolor/scalable/apps
```
\* `scalable` 目录用于放置 `矢量图标` 文件, 一般为 `.svg` 格式
\* `scalable` 目录用于放置 `矢量图标` 文件一般为 `.svg` 格式
假设你的玲珑应用同时提供尺寸为 `128x128` 的非矢量图标文件 `linyaps-app-demo.png``128x128` 的矢量图标文件 `linyaps-app-demo.svg`, 在玲珑容器中应当表现为以下状态
@ -96,18 +96,18 @@ $PREFIX/share/icons/hicolor/128x128/apps/linyaps-app-demo.png
$PREFIX/share/icons/hicolor/scalable/apps/linyaps-app-demo.svg
```
\* 为了避免图标冲突被覆盖, 图标文件名请使用应用 `唯一英文名称``玲珑应用id`
\* 为了避免图标冲突被覆盖图标文件名请使用应用 `唯一英文名称``玲珑应用id`
### desktop 文件规范
玲珑应用兼容大部分符合 `Freedesktop XDG规范``desktop启动文件`, 其中有以下字段需要额外注意:
玲珑应用兼容大部分符合 `Freedesktop XDG规范``desktop启动文件`,其中有以下字段需要额外注意:
| 字段 | 值要求 |
| ---- | ------------------------------------------------------------------------------------------------------------- |
| Exec | 该值用于设置点击此desktop文件时执行的指令, 需要与 `linglong.yaml` 中的 `command` 值保持一致 |
| Icon | 该值用于设置该desktop文件显示的应用图标, 需要与 `icons 图标目录规范` 中的图标文件名一致, 此值不需要文件名后缀 |
| Exec | 该值用于设置点击此desktop文件时执行的指令需要与 `linglong.yaml` 中的 `command` 值保持一致 |
| Icon | 该值用于设置该desktop文件显示的应用图标,需要与 `icons 图标目录规范` 中的图标文件名一致,此值不需要文件名后缀 |
因此, 一个符合玲珑应用规范的desktop文件可以参考:
因此一个符合玲珑应用规范的desktop文件可以参考
```
org.qbittorrent.qBittorrent.desktop
@ -128,13 +128,13 @@ Terminal=false
## 玲珑应用构建工程 `linglong.yaml` 规范
正如其他传统包管理套件一样, 手动创建一个玲珑应用构建工程需要设置构建规则文件 `linglong.yaml`, 在构建规则中, 则根据用途划分为 `全局字段``定制化字段`. \* 案例中 `linglong.yaml` 正文内所有空格符号、占位符均为有效字符, 请勿删除或变更格式
正如其他传统包管理套件一样,手动创建一个玲珑应用构建工程需要设置构建规则文件 `linglong.yaml`,在构建规则中,则根据用途划分为 `全局字段``定制化字段`。\* 案例中 `linglong.yaml` 正文内所有空格符号、占位符均为有效字符,请勿删除或变更格式
### 全局字段规范
`linglong.yaml`, 对于不受构建类型影响的字段我们称为 `全局字段`, 主要有以下参考的规范:
`linglong.yaml`,对于不受构建类型影响的字段我们称为 `全局字段`,主要有以下参考的规范:
1. 一个可以正常开始构建工程的 `linglong.yaml` 应包含以下的关键部分:
1. 一个可以正常开始构建工程的 `linglong.yaml` 应包含以下的关键部分
| 模块 | 解释 |
|-------|-------|
| version | 构建工程版本号 |
@ -154,12 +154,12 @@ Terminal=false
| kind | 玲珑应用类型, 默认为 `app` |
| description | 玲珑应用描述 |
2. 玲珑应用遵循 `$PREFIX` 路径规则,该变量自动生成,应用所有相关文件需存放于此目录下. 构建规则中若有需要涉及安装文件的操作, 均需要安装到 `$PREFIX` 路径下 \* `$PREFIX` 变量名即为填写的实际内容, **请勿使用 `绝对路径` 或任何具有绝对值作用的内容代替 **
2. 玲珑应用遵循 `$PREFIX` 路径规则,该变量自动生成,应用所有相关文件需存放于此目录下。构建规则中若有需要涉及安装文件的操作,均需要安装到 `$PREFIX` 路径下 \* `$PREFIX` 变量名即为填写的实际内容**请勿使用 `绝对路径` 或任何具有绝对值作用的内容代替 **
3. 玲珑应用目前遵循 `四位数字` 的版本号命名规则,不符合规则无法启动构建工程
4. `base`、`runtime` 版本支持自动匹配最新版本 `尾号`,版本号可以仅填写版本号的`前三位数字`.如:
当base `org.deepin.foundation`同时提供 `23.0.0.28` `23.0.0.29`, `linglong.yaml` 中仅填写
4. `base`、`runtime` 版本支持自动匹配最新版本 `尾号`,版本号可以仅填写版本号的`前三位数字`。如:
当base `org.deepin.foundation`同时提供 `23.0.0.28` `23.0.0.29``linglong.yaml` 中仅填写
```
base: org.deepin.foundation/23.0.0
@ -167,18 +167,18 @@ base: org.deepin.foundation/23.0.0
那么在启动玲珑应用构建工程时, 将会默认采用最高版本号的 `23.0.0.29`
5 玲珑应用构建工程配置文件目前不直接兼容其他包构建工具的配置文件,需要根据构建工程配置文件案例来进行适配修改:
https://linglong.dev/guide/ll-builder/manifests.html
5. 玲珑应用构建工程配置文件目前不直接兼容其他包构建工具的配置文件,需要根据构建工程配置文件案例来进行适配修改:
https://linglong.dev/guide/ll-builder/manifests.html
### 定制化字段
根据玲珑应用构建工程源文件类型, 又可将玲珑应用构建工程划分为 `本地文件文件构建` `git 源码仓库拉取构建`, 不同类型则需要填写不同的 `linglong.yaml`
玲珑应用构建工程源文件类型 `sources` 主要支持这几种类型: `git` `local` `file` `archive`
根据玲珑应用构建工程源文件类型又可将玲珑应用构建工程划分为 `本地文件构建` `git 源码仓库拉取构建`不同类型则需要填写不同的 `linglong.yaml`
玲珑应用构建工程源文件类型 `sources` 主要支持这几种类型`git` `local` `file` `archive`
完整说明参考: [构建配置文件简介](https://linyaps.org.cn/guide/ll-builder/manifests.html)
#### git拉取源码编译模式
当玲珑应用构建工程需要通过git拉取开源项目仓库资源到本地进行构建时, 此时 `sources` 应当设置为 `git` 类型, 并根据要求填写 `linglong.yaml`
当玲珑应用构建工程需要通过git拉取开源项目仓库资源到本地进行构建时,此时 `sources` 应当设置为 `git` 类型,并根据要求填写 `linglong.yaml`
此时需要根据规范编写 `sources``build` 模块
1. `sources` 示例:
@ -200,8 +200,8 @@ sources:
| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| kind | 源文件类型 |
| url | 需要通过git拉取的源代码仓库地址, 该仓库需要支持git功能. 当网络状态不佳时, 可采用镜像地址代替 |
| version | 指定源代码仓库的版本号, 即 `tag标签`, 或拉取主线 `master` |
| commit | 根据该仓库 `commit` 变动历史拉取源码, 此处填入commit对应的值, 将会应用该仓库截止本commit的所有变更. \*此字段优先级高于 `version`, 请勿填入 `version` 合并时间之后的任何 `commit` |
| version | 指定源代码仓库的版本号,即 `tag标签`或拉取主线 `master` |
| commit | 根据该仓库 `commit` 变动历史拉取源码此处填入commit对应的值将会应用该仓库截止本commit的所有变更。\*此字段优先级高于 `version`请勿填入 `version` 合并时间之后的任何 `commit` |
\* 支持同时添加多个git仓库作为 `sources` 拉取
@ -215,13 +215,13 @@ build: |
git apply -v /project/patches/linyaps-qBittorrent-4.6.7-szbt2.patch
```
此模块为构建规则正文, 路径遵守 `玲珑应用目录结构规范`
`sources` 拉取到本地后, 仓库文件将会存放在 `/project/linglong/sources` 目录中, 此时不同仓库目录以 `xxx.git` 命名
此模块为构建规则正文路径遵守 `玲珑应用目录结构规范`
`sources` 拉取到本地后,仓库文件将会存放在 `/project/linglong/sources` 目录中,此时不同仓库目录以 `xxx.git` 命名
支持运用 `git patch` 功能对源代码进行便捷维护
#### 本地资源操作模式
当玲珑应用构建工程需要对构建目录中的文件操作时, 此时 `kind` 应当设置为 `local` 类型, 并根据要求填写 `linglong.yaml`
当玲珑应用构建工程需要对构建目录中的文件操作时,此时 `kind` 应当设置为 `local` 类型,并根据要求填写 `linglong.yaml`
此时需要根据规范编写 `sources``build` 模块
1. `sources` 示例:
@ -236,7 +236,7 @@ source:
| 名称 | 描述 |
| ---- | ------------------------------ |
| kind | 源文件类型 |
| name | 源文件名称标识, 不具备实际用途 |
| name | 源文件名称标识不具备实际用途 |
\* 当 `kind` 应当设置为 `local` 类型时, 构建工程将不会对任何源文件进行操作
@ -253,12 +253,12 @@ build: |
make install
```
此模块为构建规则正文, 路径遵守 `玲珑应用目录结构规范`
此时 `build` 规则支持多种写法以模拟人为操作 \* 需要确保此构建规则所有步骤均可以正常被执行, 否则将会中断当次构建任务
此模块为构建规则正文路径遵守 `玲珑应用目录结构规范`
此时 `build` 规则支持多种写法以模拟人为操作 \* 需要确保此构建规则所有步骤均可以正常被执行否则将会中断当次构建任务
#### 容器内部手动操作模式
若计划直接进入玲珑容器手动操作而不是通过构建规则文件 `linglong.yaml`,那么应该参考 `本地资源操作模式` 填写 `linglong.yaml`
若计划直接进入玲珑容器手动操作而不是通过构建规则文件 `linglong.yaml`那么应该参考 `本地资源操作模式` 填写 `linglong.yaml`
1. `sources` 部分写法与 `本地资源操作模式` 一致
2. 由于使用手动操作, 因此不需要完整且可以正常被执行的 `build` 规则, 此时 `linglong.yaml` 用于生成符合描述的玲珑容器而不是执行所有任务, 具体操作可查阅后续课程关于容器内部构建文件的案例
2. 由于使用手动操作,因此不需要完整且可以正常被执行的 `build` 规则,此时 `linglong.yaml` 用于生成符合描述的玲珑容器而不是执行所有任务,具体操作可查阅后续课程关于容器内部构建文件的案例

View File

@ -110,7 +110,7 @@ origin https://ghp.ci/https://github.com/qbittorrent/qBittorrent.git (push)
5. 确认无误后, 将此差异保存到本地中, 形成patch文件
```bash
ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ git diff > ./
ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ git diff > ./qBittorrent.patch
```
6. 在得到patch文件后, 我们将应用patch的内容添加到已有的 `build` 构建规则中:
@ -160,18 +160,18 @@ ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ ll-builder expor
### deepin 23
#![deepin 23](image/4-test-1.png)
![deepin 23](image/4-test-1.png)
### openKylin 2.0
#![openKylin 2.0](image/4-test-2.png)
![openKylin 2.0](image/4-test-2.png)
### Ubuntu 2404
#![Ubuntu 2404](image/4-test-3.png)
![Ubuntu 2404](image/4-test-3.png)
### OpenEuler 2403
#![OpenEuler 2403](image/4-test-4.png)
![OpenEuler 2403](image/4-test-4.png)
至此, 足以证明 `基于Qt5的开源应用--qBittorrent` 在添加定制补丁以及修改构建规则后可以实现一站拉取项目源码并编译成可执行的二进制文件, 并在其他发行版上也可以使用 !

View File

@ -86,8 +86,8 @@ szbt@szbt-linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-git$ tar -xvf qBitt
根据[玲珑应用目录结构规范], 我们将 `DCMAKE_INSTALL_PREFIX` 赋予 `$PREFIX` 的值, 最终我在本地执行了以下操作:
```
cmake -DCMAKE_BUILD_TYPE=Release\
-DCMAKE_INSTALL_PREFIX=$PREFIX ..
cmake -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$PREFIX ..
```
7. 可以从图中看到, 这里出现了一个错误导致无法完成配置. 我们看到 `pkg-config` 出现错误: `libtorrent-rasterbar>=1.2.19` 库不能满足条件:
@ -117,8 +117,8 @@ szbt@szbt-linyaps23:/project/src/qBittorrent-release-4.6.7-szbt2/build$ pkg-conf
根据[玲珑应用目录结构规范], 我们将 `DCMAKE_INSTALL_PREFIX` 赋予 `$PREFIX` 的值, 最终我在本地执行了以下操作:
```
cmake -DCMAKE_BUILD_TYPE=Release\
-DCMAKE_INSTALL_PREFIX=$PREFIX ..
cmake -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$PREFIX ..
make -j$(nproc)
make install
```

View File

@ -78,11 +78,11 @@ wmctrl x11-utils
deepin-screen-recorder imagemagick-6.q16
```
5. 手动启动一次 `deepin-screen-recorder`, 确系统截图保存路径为当前用户的~/Pictures/Screenshots中,且该目录为空
5. 手动启动一次 `deepin-screen-recorder`, 确系统截图保存路径为当前用户的~/Pictures/Screenshots中,且该目录为空
### 启动测试功能
1. 在上节实操课时中, 我们得到了 `qBittorrent--4.6.7` 的玲珑安装包 `org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer`, 为了方便演示套件的批量支持能力, 我这里单独另找一个安装包
1. 在上节实操课时中, 我们得到了 `qBittorrent-4.6.7` 的玲珑安装包 `org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer`, 为了方便演示套件的批量支持能力, 我这里单独另找一个安装包
2. 现在我们有两款玲珑应用的安装包, 首先执行 `linyaps-auto-optimize.sh` 脚本来整理目录
此脚本主要使用两个参数, 用于指向当前存放玲珑应用安装包 `binary.layer` 的目录 `$ll_origin_pool` 及 需要整理的终点目录 `$ll_stored_pool`

View File

@ -4,11 +4,11 @@ SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
SPDX-License-Identifier: LGPL-3.0-or-later
-->
# 转换appimage应用
# 转换AppImage应用
转换 `appimage` 包格式( `.appimage` 或 `.AppImage` ) 到如意玲珑包格式( `.layer``.uab` )
转换 `AppImage` 包格式( `.AppImage` 或 `.AppImage` ) 到如意玲珑包格式( `.layer``.uab` )
查看`ll-appimage-convert convert` 命令的帮助信息:
查看 `ll-appimage-convert convert` 命令的帮助信息:
```bash
ll-appimage-convert convert --help
@ -22,7 +22,7 @@ Usage:
Flags:
-b, --build build linglong
-d, --description string detailed description of the package
-f, --file string app package file, it not required option,
-f, --file string app package file, it is not required option,
you can ignore this option
when you set --url option and --hash option
--hash string pkg hash value, it must be used with --url option
@ -30,7 +30,7 @@ Flags:
-i, --id string the unique name of the package
-l, --layer export layer file
-n, --name string the description the package
-u, --url string pkg url, it not required option,you can ignore this option when you set -f option
-u, --url string pkg url, it is not required option, you can ignore this option when you set -f option
-v, --version string the version of the package
Global Flags:
-V, --verbose verbose output
@ -38,16 +38,16 @@ Global Flags:
`ll-appimage-convert convert` 命令会根据指定的应用名称( `--name` 选项)生成一个目录,该目录会作为如意玲珑项目的根目录,即 `linglong.yaml` 文件所在的位置。它支持两种转换方法:
1. 你可以使用 `--file` 选项将指定的 `appimage` 文件转换为如意玲珑包文件;
2. 你可以使用 `--url``--hash` 选项将指定的 `appimage url` 和 `hash` 值转换为如意玲珑包文件;
1. 你可以使用 `--file` 选项将指定的 `AppImage` 文件转换为如意玲珑包文件;
2. 你可以使用 `--url``--hash` 选项将指定的 `AppImage url` 和 `hash` 值转换为如意玲珑包文件;
3. 你可以使用 `--layer` 选项导出 `.layer` 格式文件,否则将默认导出 `.uab` 格式文件。
`Tips: 在如意玲珑版本大于1.5.7时convert 默认导出 uab 包,如果想要导出 layer 文件,需要加上 --layer 参数`
`Tips: 在如意玲珑版本大于1.5.7时convert 默认导出 uab 包,如果想要导出 layer 文件,需要加上 --layer 参数`
你可以使用 `--output` 选项生成如意玲珑项目的配置文件( `linglong.yaml` )和构建如意玲珑 `.layer` ( `.uab` )的脚本文件
你可以使用 `--output` 选项生成如意玲珑项目的配置文件 (`linglong.yaml`) 和构建如意玲珑 `.layer` (`.uab`) 的脚本文件
然后你可以执行该脚本去生成对应的如意玲珑包当你修改 `linglong.yaml` 配置文件后。如果不指定该选项,将直接导出对应的如意玲珑包。
以通过 `--url` 选项将 [BrainWaves](https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage) `appimage` 文件转换为如意玲珑 `.layer` 文件为例,主要步骤如下:
以通过 `--url` 选项将 [BrainWaves](https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage) `AppImage` 文件转换为如意玲珑 `.layer` 文件为例,主要步骤如下:
指定要转换的如意玲珑包的相关参数,稍等片刻后你就可以得到 `io.github.brainwaves_0.15.1.0_x86_64_runtime.layer` 或者 `io.github.brainwaves_0.15.1.0_x86_64_runtime.uab` 包文件。
@ -55,7 +55,7 @@ Global Flags:
ll-appimage-convert convert --url "https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage" --hash "04fcfb9ccf5c0437cd3007922fdd7cd1d0a73883fd28e364b79661dbd25a4093" --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b
```
以通过 `--file` 选项将 `BrainWaves-0.15.1.AppImage` 转换为如意玲珑 `.uab` 为例,主要步骤如下:
以通过 `--file` 选项将 `BrainWaves-0.15.1.AppImage` 转换为如意玲珑 `.uab` 为例,主要步骤如下:
```bash
ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b
@ -69,7 +69,7 @@ ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io
└── linglong.yaml
```
以通过 `--file` 选项将 `BrainWaves-0.15.1.AppImage` 转换为如意玲珑 `.layer` 为例,主要步骤如下:
以通过 `--file` 选项将 `BrainWaves-0.15.1.AppImage` 转换为如意玲珑 `.layer` 为例,主要步骤如下:
```bash
ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b --layer
@ -84,5 +84,5 @@ ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io
└── linglong.yaml
```
`.uab``.layer` 文件验证
导出的`.uab`或者`.layer`需要安装后进行验证,安装 layer 文件和运行应用参考:[安装应用](../ll-cli/install.md)
`.uab``.layer` 文件验证
导出的 `.uab` 或者 `.layer` 需要安装后进行验证,安装 layer 文件和运行应用参考:[安装应用](../ll-cli/install.md)

View File

@ -1,6 +1,6 @@
# ll-appimage-convert简介
本工具由`linglong-pica`包提供。它提供将appimage包转换为如意玲珑包的能力生成构建如意玲珑应用需要的linglong.yaml文件并依赖 ll-builder 来实现应用构建和导出。
本工具由`linglong-pica`包提供。它提供将AppImage包转换为如意玲珑包的能力生成构建如意玲珑应用需要的linglong.yaml文件并依赖 ll-builder 来实现应用构建和导出。
:::tip

View File

@ -65,6 +65,6 @@ ll-builder build
ll-builder build --exec /bin/bash
```
进入容器后,可执行 `shell`命令,如 `ps`、`ls` 等。
进入容器后,可执行 `shell`命令,如 `ps`、`ls` 等。
如意玲珑应用 `debug`版本更多调试信息请参考:[DEBUG](../debug/debug.md)。

View File

@ -28,7 +28,7 @@ Options:
--help-all 展开所有帮助
```
`ll-builder create`命令根据输入的项目名称在当前目录创建应的文件夹,同时生成构建所需的 `linglong.yaml`模板文件。示例如下:
`ll-builder create`命令根据输入的项目名称在当前目录创建应的文件夹,同时生成构建所需的 `linglong.yaml`模板文件。示例如下:
```bash
ll-builder create org.deepin.demo
@ -41,9 +41,9 @@ org.deepin.demo/
└── linglong.yaml
```
## 编辑 linglong.yaml
## 配置 linglong.yaml
### linglong.yaml 文件语法版本
### linglong.yaml 文件语法版本
```text
version: "1"

View File

@ -6,13 +6,13 @@ SPDX-License-Identifier: LGPL-3.0-or-later
# 构建示例演示
## 初始化玲珑应用项目
## 初始化如意玲珑应用项目
```bash
ll-builder create org.deepin.demo
```
## 编辑 linglong.yaml 配置文件
## 配置 linglong.yaml 配置文件
### 配置软件包元数据信息
@ -100,7 +100,7 @@ build: |
make install
```
更多配置文件字段定义请参考[配置文件说明](./manifests.md)
更多配置文件字段定义请参考[配置文件说明文档](./manifests.md)
## 执行构建流程

View File

@ -81,7 +81,7 @@ bundle 模式在导出时,会尝试自动解析应用的依赖,并导出必
如果应用开发者需要依赖自运行功能,请保证应用带上必要的运行时依赖。
### Bustom Loader 模式
### Custom Loader 模式
custom loader 模式导出的 UAB 文件仅包含应用数据,以及传入的 custom loader。UAB 文件在解压挂载后将控制器交给 custom loader此时 loader 不在容器环境内。环境变量 `LINGLONG_UAB_APPROOT` 保存了应用所在目录custom loader 负责初始化应用程序所需要的运行环境,比如库路径的搜索。

View File

@ -4,11 +4,11 @@ SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
SPDX-License-Identifier: LGPL-3.0-or-later
-->
# 如意玲珑构建工具介
# 如意玲珑构建工具
## ll-builder简介
`ll-builder`是为应用开发者提供的一款构建如意玲珑应用工具。
`ll-builder`是为应用开发者提供的一款用于构建如意玲珑应用工具。
主要功能如下:
@ -61,6 +61,6 @@ Subcommands:
[linglong-tools](https://github.com/myml/linglong-tools) 一个玲珑的命令行辅助工具
[linglong-tools](https://github.com/System233/linglong-tools) 玲珑自动化deb转制工具
[linglong-tools](https://github.com/System233/linglong-tools) 玲珑自动化 deb 转制工具
[linglong-builder-action](https://github.com/myml/linglong-builder-action) github action构建玲珑包
[linglong-builder-action](https://github.com/myml/linglong-builder-action) GitHub Action 构建玲珑包

View File

@ -2,7 +2,7 @@
本文中的关键词**必须**、**禁止**、**必要的**、**应当**、**不应**、**推荐的**、**允许**以及**可选的**[^rfc2119-keywords]的解释见于[RFC 2119][rfc-2119]中的描述。
这些关键词与原文中的英词汇的对应关系如下表所示:
这些关键词与原文中的英词汇的对应关系如下表所示:
| 中文 | 英语 |
| ---------- | ----------- |
@ -17,7 +17,7 @@
[rfc-2119]: https://datatracker.ietf.org/doc/html/rfc2119
本文档旨在帮助应用开发者规范应用程序的构建过程中的行为,以迁移到玲珑包管理系统中。
本文档旨在帮助应用开发者规范应用程序的构建过程中的行为,以便迁移到玲珑包管理系统中。
## 通用
@ -31,17 +31,17 @@
- 开发者**应当**使用自己确实拥有的域名的倒置作为应用名称的前缀,并在之后跟上应用程序名称
**注意**:若开发者无法证明其确实拥有该域名,有可能导致应用包从仓库中移除。
**注意**:如果开发者无法证明其确实拥有该域名,有可能导致应用包从仓库中移除。
- 对于github上开发的第三方应用而言如果该应用程序所在的组织有额外的域名则应当优先使用否则应当采用`io.github.<GITHUB_ID>.`作为前缀。
- 对于GitHub上开发的第三方应用而言如果该应用程序所在的组织有额外的域名则应当优先使用否则应当采用`io.github.<GITHUB_ID>.`作为前缀。
特别的,如果该应用的组织名和应用名称一致,例如<https://github.com/neovim/neovim>,打包者**不应当**省略重复的应用名称组织名这个应用的ID**应当**为`io.github.neovim.neovim`。
特别的,如果该应用的组织名和应用名称一致,例如<https://github.com/neovim/neovim>,打包者**不应当**省略重复的应用名称组织名这个应用的ID**应当**为`io.github.neovim.neovim`。
**注意**:实际上该组织拥有域名`neovim.io`,故最合理的应用名称**应当**为`io.neovim.neovim`。
**注意**:实际上该组织拥有域名`neovim.io`,故最合理的应用名称**应当**为`io.neovim.neovim`。
- **不推荐**使用含`-`的应用名称,如果域名/应用名称确实含`-`**推荐**使用`_`代替
- **不推荐**使用含`-`的应用名称,如果域名/应用名称确实含`-`**推荐**使用`_`代替
- **不推荐**应用名称以`.desktop`结
- **不推荐**应用名称以`.desktop`结
以上规范来自[Desktop Entry Specification][desktop-entry-specification]。
@ -49,7 +49,7 @@
拓展阅读:<https://docs.flatpak.org/en/latest/conventions.html#application-ids>
### `prefix``$DESTDIR`
### `prefix``$DESTDIR`
在编写应用程序的构建过程时,开发者**不应当**假设自己安装的位置是固定的。在Makefile/CMakeLists.txt中将可执行文件安装到硬编码的路径例如`/usr/bin`是不规范的行为。
@ -57,10 +57,10 @@
`prefix`指的是构建/安装时指定给构建系统的、应用最终会被安装到系统中的具体位置。
当开发者没有指定安装位置时,默认值**应当**为`/usr/local`
当开发者没有指定安装位置时,默认值**应当**为`/usr/local`
通过包管理系统打包时包管理系统会配置其值。当使用dpkg相关工具进行打包时其值会被配置为`/usr`。但编写构建/安装过程时,开发者应当考虑`prefix`被配置成任意值的情况。
`$DESTDIR`构建系统进行安装时,为了方便发行版打包等过程,约定的一个环境变量。其大致工作逻辑如下:
`$DESTDIR`是构建系统进行安装时,为了方便发行版打包等过程,约定的一个环境变量。其大致工作逻辑如下:
若构建系统完成了构建工作后,执行安装过程时,被指定了`prefix=/usr`,且`$DESTDIR=./tmp`,则其完成安装后,所有的产物文件都应当出现在`./tmp/usr`目录中。打包工具随后会将`./tmp`视为根目录将其中的文件进行压缩打包等工作。
@ -102,7 +102,7 @@ PKG_CONFIG ?= pkg-config
- 内部可执行文件
指不应当由用户在终端中直接调用的可执行文件,这些可执行文件**不应当**可以通过`$PATH`找到
的是不应当由用户在终端中直接调用的可执行文件,这些可执行文件**不应当**可以通过`$PATH`找到
```makefile
install:
@ -185,7 +185,7 @@ PKG_CONFIG ?= pkg-config
参见:<https://specifications.freedesktop.org/icon-theme-spec/latest/#install_icons>
- 如果安装的图标为固定大小的版本,那么**推荐**使用png格式
至少**需要**安装一个48x48大小的png才能保证桌面环境中图标相关的基础功能正常
至少**需要**安装一个48x48大小的PNG才能保证桌面环境中图标相关的基础功能正常
- 如果安装的图标为矢量版本,那么**推荐**使用svg格式
@ -201,9 +201,9 @@ PKG_CONFIG ?= pkg-config
#### CMake
本节主要参考<https://cmake.org/cmake/help/v3.30/module/GNUInstallDirs.html#module:GNUInstallDirs>以及<https://wiki.debian.org/Multiarch/Implementation>中的相关内容编写。
本节主要参考<https://cmake.org/cmake/help/v3.30/module/GNUInstallDirs.html#module:GNUInstallDirs><https://wiki.debian.org/Multiarch/Implementation>中的相关内容编写。
这里定义一些变量的默认值以及其公共部分以便后文编写示例,这些变量默认值的相关说明可以在上方链接中查找。
这里定义一些变量的默认值以及其公共部分以便后文编写示例,这些变量默认值的相关说明可以在上方链接中查找。
编写逻辑与Makefile一节中的相关内容一致。

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
# 构建配置文件简介
`linglong.yaml` 是如意玲珑项目工程的描述文件,记录构建所需的相关信息。如构建产物的名称、版本、源码地址、构建依赖等。
`linglong.yaml` 是如意玲珑项目的描述文件,记录构建所需信息。如构建产物的名称、版本、源码地址、构建依赖等。
## 工程目录结构
@ -24,7 +24,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
## 字段定义
`linglong.yaml` 文件结构遵循特定的规范。首先,需要在文件顶层声明配置文件的版本:
`linglong.yaml` 文件结构遵循特定规范。首先,需要在文件顶部声明配置文件的版本:
```yaml
version: "1"
@ -60,7 +60,7 @@ package:
| kind | 构建产物的类型:`app` (应用)、`runtime` (运行时) | 是 |
| description | 构建产物的详细描述 | 是 |
| architecture | 构建产物的目标架构 (例如:`x86_64`, `arm64`) | 否 |
| channel | 构建产物的通道 (例如:`stable`, `beta`) | 否 |
| channel | 构建产物的通道 (例如:`main`) | 否 |
### 启动命令 (`command`)

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
# 模块拆分
在如意玲珑构建时,一个应用可以拆分多个模块,每个模块包含部分构建产物,例如调试符号放到 `develop` 模块,翻译文件放到 `lang-*` 模块等。这样用户可以按需安装,缩减应用体积。
在如意玲珑构建时,一个应用可以拆分多个模块,每个模块包含部分构建产物,例如调试符号放到 `develop` 模块,翻译文件放到 `lang-*` 模块等。这样用户可以按需安装,缩减应用体积。
## 模块文件
@ -28,13 +28,13 @@ modules:
files 是一个字符串数组,每列写一个文件路径,支持正则表达式。文件路径会自动添加应用安装路径 `$PREFIX` 作为前缀,所以如果模块要包含 `$PREFIX/bin/demo` 文件,仅需写 /bin/demo如意玲珑会自动转换成 /opt/apps/org.deepin.demo/files/bin/demo 这种路径。
如果同一个文件路径被多个模块包含,仅会移动文件到第一个模块中(按 modules 的顺序),在 files 中写正则表达式需要以^开头,否则会被认为是普通文件路径,正则表达式会自动在^后添加 `$PREFIX` 作为前缀,打包者无需重复添加。
如果同一个文件路径被多个模块包含,仅会移动文件到第一个模块中(按 modules 的顺序),在 files 中写正则表达式需要以^开头,否则会被认为是普通文件路径,正则表达式会自动在^后添加 `$PREFIX` 作为前缀,打包者无需重复添加。
## 保留模块名
### binary 模块
_这是默认模块无需在 modules 中声明_binary 会保存其他模块不使用的构建产物。当 modules 字段不存在时binary 就保存所有构建产物。
_这是默认模块不需要在 modules 中声明_binary 会保存其他模块不使用的构建产物。当 modules 字段不存在时binary 就保存所有构建产物。
用户在使用 ll-cli 安装应用时默认安装该模块,其他模块需要在安装 binary 模块后再能安装,卸载 binary 模块会同时卸载其他模块。

View File

@ -47,7 +47,7 @@ ll-builder -f arm64/linglong.yaml
ll-builder -f loongarch64/linglong.yaml
```
需要注意项目配置文件(即由 -f 指定的 linglong.yaml 文件),需要在项目目录(运行 ll-builder 的当前目录)的目录或者子目录下。
需要注意项目配置文件(即由 -f 指定的 linglong.yaml 文件),需要在项目目录(运行 ll-builder 的当前目录)或其子目录下。
## 龙芯

View File

@ -4,7 +4,7 @@ SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
SPDX-License-Identifier: LGPL-3.0-or-later
-->
# 推送uab到远程仓库
# 推送UAB到远程仓库
`ll-builder push`命令用来将如意玲珑软件包推送至如意玲珑远程仓库。

View File

@ -1,6 +1,6 @@
# base 和 runtime 介绍
在玲珑应用打包体系中base 提供基础运行环境runtime 提供应用框架支持,两者采用层依赖关系。正确选型可确保应用跨发行版的兼容性,建议遵循以下选型原则:
在玲珑应用打包体系中base 提供基础运行环境runtime 提供应用框架支持,两者采用层依赖关系。正确选型可确保应用跨发行版的兼容性,建议遵循以下选型原则:
base 优先原则先选择应用已适配的发行版对应的base
runtime 继承原则runtime必须和base保持兼容
@ -11,7 +11,7 @@ _base 和 runtime 版本号遵循“主版本.次版本.修订版本.打包版
## base 介绍
玲珑的 base 提供最基础的运行环境,包操作系统核心组件(如 glibc、bash 等基础工具链)‌
玲珑的 base 提供最基础的运行环境,包操作系统核心组件(如 glibc、bash 等基础工具链)‌
作为容器化的"最小系统镜像"确保应用能在不同发行版上保持一致的底层依赖。base 通常由玲珑官方维护,开发者可直接引用而无需担心应用运行在不同发行版上的兼容性问题。
推荐使用以下稳定版本,未在文档中列出的 base 一般是实验性质的版本,不建议选用。更详细的信息见 [base 列表](#base-列表)
@ -43,7 +43,7 @@ _base 和 runtime 版本号遵循“主版本.次版本.修订版本.打包版
## runtime 介绍
玲珑的 runtime 提供应用所需的特定运行环境(如 DTK/Wine/GNOME 等框架库),开发者可以根据应用需求选择合适的 runtime ,玲珑官方也提供了多种预编译好的 runtime 镜像供开发者选择。目前应用只能选择一个 runtime 使用,所以 runtime 可能会包含多个环境,例如 DTK 的 runtime 包含 QT 框架Wine 的 runtime 包含 DTK 框架。_应用也可以不使用 runtime_
玲珑的 runtime 提供应用所需的特定运行环境(如 DTK/Wine/GNOME 等框架库),开发者可以根据应用需求选择合适的 runtime ,玲珑官方也提供了多种预编译好的 runtime 镜像供开发者选择。目前应用只能选择一个 runtime 使用,因此 runtime 可能会包含多个环境,例如 DTK 的 runtime 包含 QT 框架Wine 的 runtime 包含 DTK 框架。_应用也可以不使用 runtime_
官方维护的稳定 runtime 如下,未在文档中列出的 runtime 一般是实验性质的版本,不建议选用。更详细的信息见 [runtime 列表](#runtime-列表)

View File

@ -31,9 +31,9 @@ Options:
您可以通过此项目向如意玲珑项目团队报告错误https://github.com/OpenAtom-Linyaps/linyaps/issues
```
使用 `ll-cli content org.dde.calendar` 显示日历应用导出的文件。
使用 `ll-cli content org.dde.calendar` 显示日历应用导出的文件。
`ll-cli content org.dde.calendar`输出如下:
`ll-cli content org.dde.calendar` 输出如下:
```text
/var/lib/linglong/entries/share/applications

View File

@ -45,7 +45,7 @@ App ContainerID Pid
main:org.dde.calendar/5.14.5.0/x86_64 c3b5ce363172 539537
```
2. 进入`the org.dde.calendar`容器内部:
2. 进入 `org.dde.calendar` 容器内部:
```bash
ll-cli exec main:org.dde.calendar/5.14.5.0/x86_64 /bin/bash

View File

@ -33,7 +33,7 @@ Options:
使用 `ll-cli info`显示已安装的应用程序或运行时的信息。
`ll-cli info org.dde.calendar`输出如下:
`ll-cli info org.dde.calendar` 输出如下:
```text
{

View File

@ -25,7 +25,7 @@ ll-cli install --help
ll-cli install org.deepin.demo
# 通过如意玲珑.layer文件安装应用程序
ll-cli install demo_0.0.0.1_x86_64_binary.layer
# 通过通过如意玲珑.uab文件安装应用程序
# 通过如意玲珑.uab文件安装应用程序
ll-cli install demo_x86_64_0.0.0.1_main.uab
# 安装应用的指定模块
ll-cli install org.deepin.demo --module=binary
@ -64,7 +64,7 @@ ll-cli install <org.deepin.calculator>
ll-cli install <org.deepin.calculator/5.1.2>
```
`ll-cli install org.deepin.calculator`输出如下:
`ll-cli install org.deepin.calculator` 输出如下:
```text
Install main:org.deepin.calculator/5.7.21.4/x86_64 success:100%

View File

@ -73,7 +73,7 @@ org.deepin.foundation deepin-foundation 23.0.0.27
显示当前已安装应用程序的最新版本列表,仅适用于应用程序。运行 `ll-cli list --upgradable`:
`ll-cli list --upgradable`输出如下:
`ll-cli list --upgradable` 输出如下:
```text
id installed new

View File

@ -30,7 +30,7 @@ Options:
使用`ll-cli prune`移除未使用的最小系统或运行时。
`ll-cli prune`输出如下:
`ll-cli prune` 输出如下:
```text
Unused base or runtime:

View File

@ -28,7 +28,7 @@ Options:
您可以通过此项目向如意玲珑项目团队报告错误https://github.com/OpenAtom-Linyaps/linyaps/issues
```
查看正在运行的应用,运行`ll-cli ps`命令:
查看正在运行的应用,运行 `ll-cli ps` 命令:
```bash
ll-cli ps

View File

@ -54,7 +54,7 @@ ll-cli run org.deepin.calculator
ll-cli run org.deepin.calculator --exec /bin/bash
```
进入后可执行 `shell` 命令,如 `gdb`、`strace`、`ls`、`find`等。
进入后可执行 `shell` 命令,如 `gdb`、`strace`、`ls`、`find` 等。
由于如意玲珑应用都是在容器内运行,无法通过常规的方式直接调试,需要在容器内运行调试工具,如 `gdb`

View File

@ -25,7 +25,7 @@ ll-cli search --help
ll-cli search org.deepin.demo
# 按名称搜索远程 runtime
ll-cli search org.deepin.base --type=runtime
# 搜索远程所有软件包
# 搜索远程所有软件包
ll-cli search .
# 搜索远程所有的base
ll-cli search . --type=base

View File

@ -33,7 +33,7 @@ Options:
您可以通过此项目向如意玲珑项目团队报告错误https://github.com/OpenAtom-Linyaps/linyaps/issues
```
使用`ll-cli uninstall`命令卸载玲珑应用:
使用 `ll-cli uninstall` 命令卸载玲珑应用:
```bash
ll-cli uninstall <org.deepin.calculator>

View File

@ -31,7 +31,7 @@ Options:
您可以通过此项目向如意玲珑项目团队报告错误https://github.com/OpenAtom-Linyaps/linyaps/issues
```
使用 `ll-cli upgrade`将所有已安装的应用程序升级到最新版本
使用 `ll-cli upgrade` 将所有已安装的应用程序升级到最新版本
`ll-cli upgrade`命令输出如下:

View File

@ -40,7 +40,7 @@ ll-pica-flatpak 使用 ostree 命令拉取 org.videolan.VLC 应用数据,根
:::
转换应用默认生成uab 文件。转换出 layer 文件,需要添加 --layer 参数。
转换应用默认生成 uab 文件。转换出 layer 文件,需要添加 --layer 参数。
```bash
ll-pica-flatpak convert org.videolan.VLC --build --layer
@ -64,8 +64,7 @@ ll-pica-flatpak convert org.videolan.VLC --base "org.deepin.base.flatpak.kde" --
├── org.videolan.VLC
│ ├── org.videolan.VLC_1.0.0.0_x86_64_develop.layer
│ ├── org.videolan.VLC_1.0.0.0_x86_64_binary.layer
or
│ ├── org.videolan.VLC_x86_64_1.0.0.0_main.uab
│ └── org.videolan.VLC_x86_64_1.0.0.0_main.uab
```
玲珑应用的产物

View File

@ -34,7 +34,7 @@ Global Flags:
在执行 `ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo` 命令后,我们仅需要执行 `ll-pica convert -w w -b --exportFile` 命令来转换出玲珑应用,这里会使用 `apt download` 命令去下载包名为 `com.baidu.baidunetdisk` 的 deb 包。
:::tip
这里使用 apt download 命令下载 deb 包,可能由于 deb 包过大而下载或者无法获取链接导致失败推荐使用下面的命令。
这里使用 apt download 命令下载 deb 包,可能由于 deb 包过大而下载失败或者无法获取链接导致失败推荐使用下面的命令。
如果直接使用下面的命令,就不需要执行 `ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo` 命令
:::
@ -50,7 +50,7 @@ ll-pica convert -c com.baidu.baidunetdisk_4.17.7_amd64.deb -w w -b --exportFile
- -w 表示工作目录。
- -c 配置的方式,这里使用 deb 文件。
- -b 表示需要进行构建,不添加该参数不会进行构建和导出 layer 文件。
- --exportFile layer 导出产物为 layer 文件,如果出 uab 文件,使用 --exportFile uab。
- --exportFile layer 导出产物为 layer 文件,如果出 uab 文件,使用 --exportFile uab。
构建产物如下:

View File

@ -64,7 +64,7 @@ file:
详细字段参考:[转换配置文件简介](../manifests.md)。
:::tip
默认使用的 `~/.pica/config.json` 使用的是 deepin v23如果需要指定 UOS 20 版本作为 BASE 和 RUNTIME 使用以下命令修改默认配置。
默认使用的 `~/.pica/config.json`基于 deepin v23如果需要指定 UOS 20 版本作为 BASE 和 RUNTIME使用以下命令修改默认配置。
下面的 <https://professional-packages.chinauos.com/desktop-professional> 请修改成不需要鉴权的地址。
:::

View File

@ -18,7 +18,7 @@ sudo apt install linglong-pica
## Arch Linux
通过 [AUR 仓库](https://aur.archlinux.org/packages/linglong-pica)或[自建源仓库](https://github.com/taotieren/aur-repo)安装。
通过 [AUR 仓库](https://aur.archlinux.org/packages/linglong-pica) [自建源仓库](https://github.com/taotieren/aur-repo) 安装。
```bash
# AUR

View File

@ -1,6 +1,6 @@
# ll-pica 简介
本工具目前提供 deb 包转换为玲珑包的能力,生成构建玲珑应用需要的 linglong.yaml 文件,并依赖 ll-builder 来实现应用构建和导出。目前只支持转换符合[应用商店打包规范](https://doc.chinauos.com/content/M7kCi3QB_uwzIp6HyF5J)的软件包。
本工具目前提供 deb 包转换为玲珑包的能力,生成构建玲珑应用需要的 linglong.yaml 文件,并依赖 ll-builder 来实现应用构建和导出。目前只支持转换符合 [应用商店打包规范](https://doc.chinauos.com/content/M7kCi3QB_uwzIp6HyF5J) 的软件包。
:::tip

View File

@ -1,6 +1,6 @@
# 转换配置文件简介
package.yaml 是 `ll-pica` 转换 deb 包的基础信息。如构建的 base、runtime 的版本,需要被转换的 deb 包。
package.yaml 是 `ll-pica` 转换 deb 包的基础信息,如构建的 base、runtime 的版本,以及需要被转换的 deb 包。
## 工程目录结构
@ -33,7 +33,7 @@ runtime:
| -------------- | ----------------------------------------------- |
| runtime | 运行时runtime |
| version | 运行时runtime版本三位数可以模糊匹配第四位 |
| base_version | base 的版本号, 三位数可以模糊匹配第四位 |
| base_version | base 的版本号三位数可以模糊匹配第四位 |
| source | 获取 deb 包依赖时使用的源 |
| distro_version | 发行版的代号 |
| arch | 获取 deb 包需要的架构 |

View File

@ -42,7 +42,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
sudo pacman -Syu linyaps
```
如意玲珑网页商店安装工具需要通过 [AUR 仓库](https://aur.archlinux.org/packages/linyaps-web-store-installer)或[自建源仓库](https://github.com/taotieren/aur-repo)安装。
如意玲珑网页商店安装工具需要通过 [AUR 仓库](https://aur.archlinux.org/packages/linyaps-web-store-installer) [自建源仓库](https://github.com/taotieren/aur-repo) 安装。
```bash
# AUR

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
# 概述
如意玲珑是统信软件自研的开源软件包格式,用于替代 `deb`、`rpm`等包管理工具,实现了应用包管理、分发、容器、集成开发工具等功能。
如意玲珑是统信软件自研的开源软件包格式,用于替代 `deb`、`rpm` 等包管理工具,实现了应用包管理、分发、容器、集成开发工具等功能。
## 当前包管理器存在的问题

View File

@ -6,9 +6,9 @@
## 格式
ref 是组件在存储仓库中的唯一标识(存储仓库中的索引信息)。一条完整的 ref 信息包括仓库名、渠道、ID、版本号、架构、分支名等信息。
Ref 是组件在存储仓库中的唯一标识(存储仓库中的索引信息)。一条完整的 ref 信息包括仓库名、渠道、ID、版本号、架构、分支名等信息。
ref 格式如下:
Ref 格式如下:
```bash
${repo}/${channel}:${id}/${version}/${arch}
@ -38,9 +38,9 @@ org.deepin.calculator 为 ID1.2.2 为版本x86_64 为架构。
## 使用
Ref 包含两个部分,远程地址标识和本地标识。其中`:`用分割远程标识和本地标识。
Ref 包含两个部分,远程地址标识和本地标识。其中`:`用分割远程标识和本地标识。
程标识主要用于定义这个 layer 是如何获取的。其中 channel 暂时没有用到可以为空。repo 表示远程仓库URL在本地的映射的别名。
程标识主要用于定义这个 layer 是如何获取的。其中 channel 暂时没有用到可以为空。repo 表示远程仓库URL在本地的映射的别名。
在安装过程中,使用完整的 ref 可以唯一标识一个 layer。例如
@ -48,14 +48,14 @@ Ref 包含两个部分,远程地址标识和本地标识。其中`:`前用分
ll-cli install deepin/main:org.deepin.calculator/1.2.2/x86_64
```
一旦 layer 被安装后,所针对 layer 的本地操作都不会改变其远程属性。特别是进行升级的时候。
一旦 layer 被安装后,所针对 layer 的本地操作都不会改变其远程属性。特别是进行升级的时候。
```bash
# 从 deepin/main升级org.deepin.calculator其版本会发生变化但是repo和channel不会变化
# 注意这里install会更新包
# 从 deepin/main 升级 org.deepin.calculator其版本会发生变化但是 repo channel 不会变化
# 注意这里 install 会更新包
ll-cli install org.deepin.calculator/1.2.2/x86_64
# 这里会使用deepin/project这个channel的layer替换本地的org.deepin.calculator/1.2.2/x86_64
# 这里会使用 deepin/project 这个 channel layer 替换本地的 org.deepin.calculator/1.2.2/x86_64
ll-cli install deepin/project:org.deepin.calculator/1.2.2/x86_64
```
@ -69,10 +69,10 @@ Ref 支持进行简写,主要规则如下:
1. 默认 repo 为 deepin
2. 默认 channel 为 main当前未实现 channel 支持,暂时不考虑)
3. 默认版本为远程最新版本或者本地的最新版本,根据场景进行推断,如果有歧义则报错
3. 默认版本为远程最新版本或者本地的最新版本,根据场景进行推断,如果有歧义则报错
4. 默认架构为当前 ll-cli 运行架构
如果有显示指定 ref 中任意一个字段,那么根据这个字段为准。
如果有显式指定 ref 中任意一个字段,那么以这个字段为准。
## 实现

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.
As per the OCI runtime specification, the runtime starts from a rootfs. However, in Linglong, it prepares the rootfs in ll-box. Therefore, we put the information for constructing the rootfs in annotations to ll-box.
The example of annotations is
An 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.
The ll-box supports two methods to build rootfs: using native read-only bind mount or with overlayfs.
`container_root_path` is the work directory of ll-box.
`container_root_path` is the working directory of ll-box.

View File

@ -1,6 +1,6 @@
# System Helper
User with no privilege can mount erofs to dir with:
User with no privileges can mount erofs to directory with:
```bash
busctl --system call org.deepin.linglong.SystemHelper \

View File

@ -1,11 +1,11 @@
# Unit Testing
Linglong use gtest for unit test, just pull test code and testdata in test/ directory of project root.
Linglong uses gtest for unit testing, just pull test code and test data in test/ directory of project root.
Seem some test is hard to run in ci envionment, we disable it by default.
Some tests are hard to run in CI environment, we disable them by default.
Here are some envionment variables to control if test run, all of them are empty by default.
Here are some environment variables to control if tests run, all of them are empty by default.
| name | vaule |
| ----------------- | ---------------------------------- |
| LINGLONG_TEST_ALL | If set, will run all unit testing. |
| name | value |
| ----------------- | -------------------------------- |
| LINGLONG_TEST_ALL | If set, will run all unit tests. |

View File

@ -10,10 +10,16 @@
namespace linglong::api::types::v1 {
// I added this size assertion because these structs overload == operator.
// Adding new fields will make this fail, reminding me to update the == implementation.
static_assert(sizeof(struct Repo) == 120);
static_assert(sizeof(struct RepoConfig) == 88);
static_assert(sizeof(struct RepoConfigV2) == 64);
inline bool operator==(const Repo &cfg1, const Repo &cfg2) noexcept
{
return cfg1.alias == cfg2.alias && cfg1.name == cfg2.name && cfg1.url == cfg2.url
&& cfg1.priority == cfg2.priority;
&& cfg1.priority == cfg2.priority && cfg1.mirrorEnabled == cfg2.mirrorEnabled;
}
inline bool operator!=(const Repo &cfg1, const Repo &cfg2) noexcept

View File

@ -19,11 +19,15 @@ bool stringEqual(std::string_view str1, std::string_view str2, bool caseSensitiv
});
}
std::string trim(const std::string &str) noexcept
std::string trim(std::string_view str, std::string_view chars) noexcept
{
auto first = str.find_first_not_of(' ');
auto last = str.find_last_not_of(' ');
return str.substr(first, last - first + 1);
auto first = str.find_first_not_of(chars);
if (first == std::string_view::npos) {
return "";
}
auto last = str.find_last_not_of(chars);
return std::string(str.substr(first, last - first + 1));
}
std::vector<std::string> split(const std::string &str, char delimiter, splitOption option) noexcept
@ -61,12 +65,27 @@ std::vector<std::string> split(const std::string &str, char delimiter, splitOpti
std::string join(const std::vector<std::string> &strs, char delimiter) noexcept
{
std::string result;
for (size_t i = 0; i < strs.size() - 1; ++i) {
result += strs[i];
result += delimiter;
if (strs.empty()) {
return "";
}
result += strs[strs.size() - 1];
if (strs.size() == 1) {
return strs[0];
}
size_t total_len = strs.size() - 1;
for (const auto &s : strs) {
total_len += s.size();
}
std::string result;
result.reserve(total_len);
result.append(strs[0]);
for (size_t i = 1; i < strs.size(); ++i) {
result.push_back(delimiter);
result.append(strs[i]);
}
return result;
}
@ -97,7 +116,7 @@ std::string replaceSubstring(std::string_view str,
return result;
}
bool hasPrefix(std::string_view str, std::string_view prefix) noexcept
bool starts_with(std::string_view str, std::string_view prefix) noexcept
{
if (str.size() < prefix.size()) {
return false;
@ -106,11 +125,12 @@ bool hasPrefix(std::string_view str, std::string_view prefix) noexcept
return str.substr(0, prefix.size()) == prefix;
}
bool hasSuffix(std::string_view str, std::string_view suffix) noexcept
bool ends_with(std::string_view str, std::string_view suffix) noexcept
{
if (str.size() < suffix.size()) {
return false;
}
return str.substr(str.size() - suffix.size()) == suffix;
}
@ -119,4 +139,20 @@ bool contains(std::string_view str, std::string_view suffix) noexcept
return str.find(suffix) != std::string_view::npos;
}
// Quotes a string for serializing arguments to a bash script.
// Example:
// Input: "let's go"
// Output: "'let'\''s go'"
std::string quoteBashArg(std::string arg) noexcept
{
const std::string quotePrefix = "'\\";
for (auto it = arg.begin(); it != arg.end(); it++) {
if (*it == '\'') {
it = arg.insert(it, quotePrefix.cbegin(), quotePrefix.cend());
it = arg.insert(it + quotePrefix.size() + 1, 1, '\'');
}
}
return "'" + arg + "'";
}
} // namespace linglong::common::strings

View File

@ -31,7 +31,7 @@ inline splitOption operator&(splitOption a, splitOption b)
bool stringEqual(std::string_view str1, std::string_view str2, bool caseSensitive = false) noexcept;
std::string trim(const std::string &str) noexcept;
std::string trim(std::string_view str, std::string_view chars = " ") noexcept;
std::vector<std::string> split(const std::string &str,
char delimiter,
@ -43,10 +43,12 @@ std::string replaceSubstring(std::string_view str,
std::string_view from,
std::string_view to) noexcept;
bool hasPrefix(std::string_view str, std::string_view prefix) noexcept;
bool starts_with(std::string_view str, std::string_view prefix) noexcept;
bool hasSuffix(std::string_view str, std::string_view suffix) noexcept;
bool ends_with(std::string_view str, std::string_view suffix) noexcept;
bool contains(std::string_view str, std::string_view suffix) noexcept;
std::string quoteBashArg(std::string arg) noexcept;
} // namespace linglong::common::strings

View File

@ -53,6 +53,8 @@ pfl_add_library(
src/linglong/package_manager/package_manager.h
src/linglong/package_manager/package_task.cpp
src/linglong/package_manager/package_task.h
src/linglong/package_manager/uab_installation.cpp
src/linglong/package_manager/uab_installation.h
src/linglong/package/reference.cpp
src/linglong/package/reference.h
src/linglong/package/semver.hpp

View File

@ -17,6 +17,7 @@
#include "linglong/package/layer_packager.h"
#include "linglong/package/reference.h"
#include "linglong/package/uab_packager.h"
#include "linglong/repo/config.h"
#include "linglong/repo/ostree_repo.h"
#include "linglong/runtime/container.h"
#include "linglong/utils/command/cmd.h"
@ -131,7 +132,7 @@ utils::error::Result<void> pullDependency(const package::Reference &ref,
printReplacedText(
fmt::format("{:<35}{:<15}{:<15}waiting ...", ref.id, ref.version.toString(), module),
2);
repo.pull(tmpTask, ref, module);
repo.pull(tmpTask, ref, module, repo.getDefaultRepo());
if (tmpTask.state() == linglong::api::types::v1::State::Failed) {
return LINGLONG_ERR(("pull " + ref.toString() + " failed").data(),
std::move(tmpTask).takeError());
@ -142,6 +143,41 @@ utils::error::Result<void> pullDependency(const package::Reference &ref,
} // namespace
namespace detail {
void mergeOutput(const std::vector<std::filesystem::path> &src,
const std::filesystem::path &dest,
const std::vector<std::string> &targets)
{
for (const auto &dir : src) {
LogD("merge {} to {}", dir, dest);
auto matcher = [&dir, &targets](const std::filesystem::path &path) {
if (common::strings::starts_with(path.filename().string(), ".wh.")) {
return false;
}
struct stat st;
if (-1 == lstat((dir / path).c_str(), &st)) {
return false;
}
if (st.st_size == 0 && st.st_rdev == 0 && st.st_mode == S_IFCHR) {
return false;
}
for (const auto &target : targets) {
if (common::strings::starts_with(path.string(), target)) {
return true;
}
}
return false;
};
utils::copyDirectory(dir, dest, matcher);
}
}
} // namespace detail
// install module files by rules
// files will be moved from buildOutput to moduleOutput
utils::error::Result<std::vector<std::filesystem::path>>
@ -227,14 +263,14 @@ utils::error::Result<void> cmdRemoveApp(repo::OSTreeRepo &repo,
for (const auto &ref : refs) {
auto r = package::Reference::parse(QString::fromStdString(ref));
if (!r.has_value()) {
std::cerr << ref << ": " << r.error().message().toStdString() << std::endl;
std::cerr << ref << ": " << r.error().message() << std::endl;
continue;
}
auto modules = repo.getModuleList(*r);
for (const auto &module : modules) {
auto v = repo.remove(*r, module);
if (!v.has_value()) {
std::cerr << ref << ": " << v.error().message().toStdString() << std::endl;
std::cerr << ref << ": " << v.error().message() << std::endl;
continue;
}
}
@ -242,12 +278,12 @@ utils::error::Result<void> cmdRemoveApp(repo::OSTreeRepo &repo,
if (prune) {
auto v = repo.prune();
if (!v.has_value()) {
std::cerr << v.error().message().toStdString();
std::cerr << v.error().message();
}
}
auto v = repo.mergeModules();
if (!v.has_value()) {
std::cerr << v.error().message().toStdString();
std::cerr << v.error().message();
}
return LINGLONG_OK;
}
@ -377,8 +413,11 @@ utils::error::Result<package::Reference> Builder::ensureUtils(const std::string
// always try to get newest version from remote
auto ref = clearDependency(id, true, true);
if (!ref) {
ref = clearDependency(id, false, false);
auto localRef = clearDependency(id, false, false);
if (localRef) {
if (!ref || localRef->version > ref->version) {
ref = std::move(localRef);
}
}
if (ref && pullDependency(*ref, this->repo, "binary")) {
auto appLayerDir = this->repo.getMergedModuleDir(*ref);
@ -901,7 +940,7 @@ utils::error::Result<void> Builder::buildStagePreCommit() noexcept
src.push_back(runtimeOverlay->upperDirPath());
}
}
mergeOutput(src, buildOutput, { "bin/", "sbin/", "lib/" });
detail::mergeOutput(src, buildOutput, { "bin/", "sbin/", "lib/" });
return LINGLONG_OK;
}
@ -1685,7 +1724,8 @@ utils::error::Result<void> Builder::importLayer(repo::OSTreeRepo &ostree, const
utils::error::Result<void> Builder::run(std::vector<std::string> modules,
std::vector<std::string> args,
bool debug)
bool debug,
std::vector<std::string> extensions)
{
LINGLONG_TRACE("run application");
@ -1703,6 +1743,9 @@ utils::error::Result<void> Builder::run(std::vector<std::string> modules,
linglong::runtime::ResolveOptions opts;
opts.depsBinaryOnly = !debug;
opts.appModules = std::move(modules);
if (!extensions.empty()) {
opts.extensionRefs = extensions;
}
auto res = runContext.resolve(*curRef, opts);
if (!res) {
return LINGLONG_ERR(res);
@ -2182,38 +2225,6 @@ void Builder::takeTerminalForeground()
}
}
void Builder::mergeOutput(const std::vector<std::filesystem::path> &src,
const std::filesystem::path &dest,
const std::vector<std::string> &targets)
{
for (const auto &dir : src) {
auto matcher = [&dir, &targets](const std::filesystem::path &path) {
if (path.filename().string().rfind(".wh.", 0) == 0) {
return false;
}
struct stat st;
if (-1 == lstat(path.c_str(), &st)) {
return false;
}
if (st.st_size == 0 && st.st_rdev == 0 && st.st_mode == S_IFCHR) {
return false;
}
for (const auto &target : targets) {
if (path.lexically_relative(dir).string().rfind(target, 0) == 0) {
return true;
}
}
return false;
};
utils::copyDirectory(dir, dest, matcher);
}
}
void Builder::printBasicInfo()
{
printMessage("[Builder info]");

View File

@ -53,6 +53,12 @@ utils::error::Result<void> cmdRemoveApp(repo::OSTreeRepo &repo,
std::vector<std::string> refs,
bool prune);
namespace detail {
void mergeOutput(const std::vector<std::filesystem::path> &src,
const std::filesystem::path &dest,
const std::vector<std::string> &targets);
}
class Builder
{
public:
@ -88,8 +94,10 @@ public:
static auto importLayer(repo::OSTreeRepo &repo, const QString &path)
-> utils::error::Result<void>;
auto run(std::vector<std::string> modules, std::vector<std::string> args, bool debug = false)
-> utils::error::Result<void>;
auto run(std::vector<std::string> modules,
std::vector<std::string> args,
bool debug = false,
std::vector<std::string> extensions = {}) -> utils::error::Result<void>;
auto runtimeCheck() -> utils::error::Result<void>;
auto runFromRepo(const package::Reference &ref, const std::vector<std::string> &args)
-> utils::error::Result<void>;
@ -126,9 +134,6 @@ private:
auto generateBuildDependsScript() noexcept -> utils::error::Result<bool>;
auto generateDependsScript() noexcept -> utils::error::Result<bool>;
void takeTerminalForeground();
void mergeOutput(const std::vector<std::filesystem::path> &src,
const std::filesystem::path &dest,
const std::vector<std::string> &targets);
void printBasicInfo();
void printRepo();
bool checkDeprecatedInstallFile();

View File

@ -10,6 +10,7 @@
#include "linglong/utils/command/cmd.h"
#include "linglong/utils/error/error.h"
#include "linglong/utils/global/initialize.h"
#include "linglong/utils/log/log.h"
#include <QDir>
#include <QTemporaryDir>
@ -51,7 +52,7 @@ auto SourceFetcher::fetch(QDir destination) noexcept -> utils::error::Result<voi
// 便于在执行失败时进行调试
dir->setAutoRemove(false);
scriptFile = dir->filePath(scriptName);
qDebug() << "Dumping " << scriptName << "from qrc to" << scriptFile;
LogD("Dumping {} from qrc to {}", scriptName, scriptFile);
QFile::copy(":/scripts/" + scriptName, scriptFile);
}
auto output =
@ -64,7 +65,7 @@ auto SourceFetcher::fetch(QDir destination) noexcept -> utils::error::Result<voi
this->cacheDir.absolutePath(),
});
if (!output.has_value()) {
qDebug() << "output error:" << output.error();
LogE("output error: {}", output.error());
return LINGLONG_ERR("stderr:", output);
}

View File

@ -27,6 +27,7 @@
#include "linglong/api/types/v1/UpgradeListResult.hpp"
#include "linglong/cli/printer.h"
#include "linglong/common/dir.h"
#include "linglong/common/strings.h"
#include "linglong/oci-cfg-generators/container_cfg_builder.h"
#include "linglong/package/layer_file.h"
#include "linglong/package/reference.h"
@ -34,8 +35,8 @@
#include "linglong/runtime/container_builder.h"
#include "linglong/runtime/run_context.h"
#include "linglong/utils/bash_command_helper.h"
#include "linglong/utils/bash_quote.h"
#include "linglong/utils/error/error.h"
#include "linglong/utils/file.h"
#include "linglong/utils/finally/finally.h"
#include "linglong/utils/gettext.h"
#include "linglong/utils/log/log.h"
@ -48,7 +49,9 @@
#include <linux/un.h>
#include <nlohmann/json.hpp>
#include <QProcess>
#include <QTimer>
#include <QDateTime>
#include <QCryptographicHash>
#include <QEventLoop>
#include <QFileInfo>
@ -72,107 +75,8 @@
using namespace linglong::utils::error;
const auto permissionNotifyMsg =
_("Permission denied, please check whether you are running as root.");
namespace {
linglong::utils::error::Result<bool> isChildProcess(pid_t parent, pid_t pid) noexcept
{
LINGLONG_TRACE(fmt::format("check if {} is child of {}", pid, parent));
auto getppid = [](pid_t pid) -> Result<pid_t> {
LINGLONG_TRACE(fmt::format("get ppid of {}", pid));
std::error_code ec;
auto stat = std::filesystem::path("/proc/" + std::to_string(pid) + "/stat");
auto fd = ::open(stat.c_str(), O_RDONLY);
if (fd == -1) {
return LINGLONG_ERR(
QString{ "failed to open %1: %2" }.arg(stat.c_str(), ::strerror(errno)));
}
auto closeFd = linglong::utils::finally::finally([fd] {
::close(fd);
});
// FIXME: Parsing /proc/pid/stat isn't an good idea, the consistency of file contents
// which in /proc is not guaranteed and the format may change. so we read all the content at
// first and then parse it.
// use read instead of std::ifstream to get more detailed error information the size
// of /proc/pid/stat is zero and we can't get the content size by stat,
// so we use 1024 as the buffer size.
std::array<char, 1024> buf{};
std::string content;
while (true) {
auto readBytes = ::read(fd, buf.data(), buf.size());
if (readBytes == -1) {
return LINGLONG_ERR(
QString{ "failed to read from %1: %2" }.arg(stat.c_str(), ::strerror(errno)));
}
if (readBytes == 0) {
break;
}
content.append(buf.data(), readBytes);
}
auto ppidOffset = 3;
std::string::size_type left = 0;
std::string::size_type right = 0;
for (std::string::size_type i = 0; i < content.size(); i++) {
if (ppidOffset == 0) {
left = i;
right = i;
while (content[right] != ' ') {
right += 1;
}
break;
}
if (content[i] == ' ') {
ppidOffset -= 1;
}
}
pid_t ppid{ -1 };
auto [_, err] = std::from_chars(content.c_str() + left, content.c_str() + right, ppid);
if (err != std::errc()) {
return LINGLONG_ERR(QString{ "failed to parse %1: %2" }.arg(
std::string_view(content.c_str() + left, right - left).data(),
::strerror(static_cast<int>(err))));
}
return ppid;
};
while (pid != parent) {
auto ppid = getppid(pid);
if (!ppid) {
return LINGLONG_ERR(ppid.error());
}
pid = *ppid;
if (pid < parent) {
return false;
}
}
return true;
}
linglong::utils::error::Result<void> ensureDirectory(const std::filesystem::path &dir)
{
LINGLONG_TRACE("ensure runtime directory");
std::error_code ec;
if (!std::filesystem::create_directory(dir, ec) && ec) {
return LINGLONG_ERR("failed to create runtime directory", ec);
}
return LINGLONG_OK;
}
std::vector<std::string> getAutoModuleList() noexcept
{
auto getModuleFromLanguageEnv = [](const std::string &lang) -> std::vector<std::string> {
@ -277,7 +181,7 @@ bool delegateToContainerInit(const std::string &containerID,
std::string bashContent;
for (const auto &command : commands) {
bashContent.append(linglong::utils::quoteBashArg(command));
bashContent.append(linglong::common::strings::quoteBashArg(command));
bashContent.push_back(' ');
}
@ -464,15 +368,6 @@ void Cli::interaction(const QDBusObjectPath &object_path,
this->pkgMan.ReplyInteraction(object_path, utils::serialize::toQVariantMap(reply));
dbusReply.waitForFinished();
if (dbusReply.isError()) {
if (dbusReply.error().type() == QDBusError::AccessDenied) {
auto ret = this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = permissionNotifyMsg });
if (!ret) {
this->printer.printErr(ret.error());
}
return;
}
this->printer.printErr(
LINGLONG_ERRV(dbusReply.error().message(), dbusReply.error().type()));
}
@ -626,14 +521,8 @@ int Cli::run(const RunOptions &options)
auto gid = getgid();
auto pid = getpid();
// NOTE: ll-box is not support running as root for now.
if (uid == 0) {
qInfo() << "'ll-cli run' currently does not support running as root.";
return -1;
}
auto userContainerDir = std::filesystem::path{ "/run/linglong" } / std::to_string(uid);
if (auto ret = ensureDirectory(userContainerDir); !ret) {
if (auto ret = utils::ensureDirectory(userContainerDir); !ret) {
this->printer.printErr(ret.error());
return -1;
}
@ -643,7 +532,8 @@ int Cli::run(const RunOptions &options)
// placeholder file
auto fd = ::open(pidFile.c_str(), O_WRONLY | O_CREAT | O_EXCL, mode);
if (fd == -1) {
qCritical() << QString{ "create file " } % pidFile.c_str() % " error:" % ::strerror(errno);
qCritical()
<< QString{ "create file %1 error: %2" }.arg(pidFile.c_str()).arg(::strerror(errno));
QCoreApplication::exit(-1);
return -1;
}
@ -677,10 +567,18 @@ int Cli::run(const RunOptions &options)
linglong::runtime::ResolveOptions opts;
opts.baseRef = options.base;
opts.runtimeRef = options.runtime;
// 处理多个扩展
if (!options.extensions.empty()) {
opts.extensionRefs = options.extensions;
}
LogD("start resolve run context with base {} and runtime {}",
// 调整日志输出,打印扩展列表(用逗号拼接)
std::string extStr =
opts.extensionRefs ? linglong::common::strings::join(*opts.extensionRefs, ',') : "null";
LogD("start resolve run context with base {}, runtime {}, extensions {}",
opts.baseRef.value_or("null"),
opts.runtimeRef.value_or("null"));
opts.runtimeRef.value_or("null"),
extStr);
auto res = runContext.resolve(*curAppRef, opts);
if (!res) {
@ -786,6 +684,27 @@ int Cli::run(const RunOptions &options)
.forwardDefaultEnv()
.enableSelfAdjustingMount();
std::vector<std::string> capabilities;
// privileged mode shares host's user_namespace and add capabilities
if (options.privileged) {
if (uid != 0) {
this->printer.printMessage(_("privileged mode requires running as root"));
return -1;
}
cfgBuilder.disableUserNamespace();
capabilities = { "CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_FSETID",
"CAP_KILL", "CAP_NET_BIND_SERVICE", "CAP_SETFCAP", "CAP_SETGID",
"CAP_SETPCAP", "CAP_SETUID", "CAP_SYS_CHROOT", "CAP_NET_RAW",
"CAP_NET_ADMIN" };
}
if (!options.capsAdd.empty()) {
capabilities.insert(capabilities.end(), options.capsAdd.begin(), options.capsAdd.end());
}
cfgBuilder.setCapabilities(capabilities);
res = runContext.fillContextCfg(cfgBuilder);
if (!res) {
this->printer.printErr(res.error());
@ -854,32 +773,20 @@ int Cli::run(const RunOptions &options)
int Cli::enter(const EnterOptions &options)
{
LINGLONG_TRACE("ll-cli exec");
auto containers = getCurrentContainers();
if (!containers) {
auto err = LINGLONG_ERRV(containers);
this->printer.printErr(err);
return -1;
}
auto containerIDList = this->getRunningAppContainers(options.instance);
std::string containerID;
for (const auto &container : *containers) {
std::string packageName = container.package;
std::string::size_type colonPos = packageName.find(':');
std::string::size_type slashPos = packageName.find('/');
if (colonPos != std::string::npos && slashPos != std::string::npos) {
packageName = packageName.substr(colonPos + 1, slashPos - colonPos - 1);
}
if (packageName == options.instance) {
containerID = container.id;
break;
}
}
if (containerID.empty()) {
if (containerIDList.empty()) {
this->printer.printErr(LINGLONG_ERRV("no container found"));
return -1;
}
if (containerIDList.size() > 1) {
this->printer.printErr(
LINGLONG_ERRV("multiple running containers found, please specify which one to enter"));
return -1;
}
auto containerID = containerIDList.front();
qInfo() << "select container id" << QString::fromStdString(containerID);
auto commands = options.commands;
if (commands.empty()) {
@ -989,30 +896,37 @@ int Cli::ps()
return 0;
}
std::vector<std::string> Cli::getRunningAppContainers(const std::string &appid)
{
LINGLONG_TRACE("get app running containers");
std::vector<std::string> containerIDList{};
auto containers = getCurrentContainers();
if (!containers) {
this->printer.printErr(containers.error());
return containerIDList;
}
for (const auto &container : *containers) {
auto fuzzyRef = package::FuzzyReference::parse(container.package);
if (!fuzzyRef) {
qWarning() << LINGLONG_ERRV(fuzzyRef).message();
continue;
}
if (fuzzyRef->id == appid || fuzzyRef->toString() == appid) {
containerIDList.emplace_back(container.id);
}
}
return containerIDList;
}
int Cli::kill(const KillOptions &options)
{
LINGLONG_TRACE("command kill");
auto containers = getCurrentContainers();
if (!containers) {
auto err = LINGLONG_ERRV(containers);
this->printer.printErr(err);
return -1;
}
std::vector<std::string> containerIDList;
for (const auto &container : *containers) {
auto fuzzyRef = package::FuzzyReference::parse(container.package);
if (!fuzzyRef) {
this->printer.printErr(fuzzyRef.error());
continue;
}
// support matching container id based on appid or fuzzy ref
if (fuzzyRef->id == options.appid || fuzzyRef->toString() == options.appid) {
containerIDList.emplace_back(container.id);
}
}
auto containerIDList = this->getRunningAppContainers(options.appid);
auto ret = 0;
for (const auto &containerID : containerIDList) {
@ -1065,7 +979,7 @@ int Cli::installFromFile(const QFileInfo &fileInfo,
return -1;
}
qInfo() << "install from file" << filePath;
LogI("install from file {}", filePath);
QFile file{ filePath };
if (!file.open(QIODevice::ReadOnly | QIODevice::ExistingOnly)) {
auto err = LINGLONG_ERR(file);
@ -1093,15 +1007,6 @@ int Cli::installFromFile(const QFileInfo &fileInfo,
utils::serialize::toQVariantMap(commonOptions));
pendingReply.waitForFinished();
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
auto ret = this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = permissionNotifyMsg });
if (!ret) {
this->printer.printErr(ret.error());
}
return -1;
}
auto err = LINGLONG_ERRV(pendingReply.error().message());
this->printer.printErr(err);
return -1;
@ -1221,15 +1126,6 @@ int Cli::install(const InstallOptions &options)
pendingReply.waitForFinished();
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
auto ret = this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = permissionNotifyMsg });
if (!ret) {
this->printer.printErr(ret.error());
}
return -1;
}
this->printer.printErr(
LINGLONG_ERRV(pendingReply.error().message(), pendingReply.error().type()));
return -1;
@ -1397,15 +1293,6 @@ int Cli::upgrade(const UpgradeOptions &options)
pendingReply.waitForFinished();
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
auto ret = this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = permissionNotifyMsg });
if (!ret) {
this->printer.printErr(ret.error());
}
return -1;
}
auto err = LINGLONG_ERRV(pendingReply.error().message());
this->printer.printErr(err);
return -1;
@ -1497,15 +1384,6 @@ int Cli::search(const SearchOptions &options)
pendingReply.waitForFinished();
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
auto ret = this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = permissionNotifyMsg });
if (!ret) {
this->printer.printErr(ret.error());
}
return -1;
}
auto err = LINGLONG_ERRV(pendingReply.error().message());
this->printer.printErr(err);
return -1;
@ -1645,15 +1523,6 @@ int Cli::prune()
pendingReply.waitForFinished();
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
auto ret = this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = permissionNotifyMsg });
if (!ret) {
this->printer.printErr(ret.error());
}
return -1;
}
auto err = LINGLONG_ERRV(pendingReply.error().message());
this->printer.printErr(err);
return -1;
@ -1706,15 +1575,6 @@ int Cli::uninstall(const UninstallOptions &options)
pendingReply.waitForFinished();
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
auto ret = this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = permissionNotifyMsg });
if (!ret) {
this->printer.printErr(ret.error());
}
return -1;
}
auto err = LINGLONG_ERRV(pendingReply.error().message());
this->printer.printErr(err);
return -1;
@ -1923,18 +1783,7 @@ int Cli::repo(CLI::App *app, const RepoOptions &options)
LINGLONG_TRACE("command repo");
auto propCfg = this->pkgMan.configuration();
// check error here, this operation could be failed
if (this->pkgMan.lastError().isValid()) {
if (this->pkgMan.lastError().type() == QDBusError::AccessDenied) {
auto ret = this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = permissionNotifyMsg });
if (!ret) {
this->printer.printErr(ret.error());
}
return -1;
}
auto err = LINGLONG_ERRV(this->pkgMan.lastError().message());
this->printer.printErr(err);
return -1;
@ -2101,15 +1950,6 @@ int Cli::setRepoConfig(const QVariantMap &config)
this->pkgMan.setConfiguration(config);
if (this->pkgMan.lastError().isValid()) {
if (this->pkgMan.lastError().type() == QDBusError::AccessDenied) {
auto ret = this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = permissionNotifyMsg });
if (!ret) {
this->printer.printErr(ret.error());
}
return -1;
}
auto err = LINGLONG_ERRV(this->pkgMan.lastError().message());
this->printer.printErr(err);
return -1;
@ -2769,11 +2609,19 @@ utils::error::Result<std::filesystem::path> Cli::ensureCache(
// Try to generate cache here
QProcess process;
process.setProgram(LINGLONG_LIBEXEC_DIR "/ll-dialog");
process.setArguments(
{ "-m", "startup", "--id", QString::fromStdString(appLayerItem->info.id) });
process.start();
process.setArguments({ "-m", "startup", "--id", QString::fromStdString(appLayerItem->info.id) });
qDebug() << process.program() << process.arguments();
int64_t processStartTime = 0;
// 延迟300ms显示等待提示窗口
QTimer timer(this);
timer.setSingleShot(true);
timer.setInterval(300);
QObject::connect(&timer, &QTimer::timeout, [&process, &processStartTime] {
processStartTime = QDateTime::currentSecsSinceEpoch();
process.start();
});
timer.start();
auto ret = this->generateCache(appRef);
if (ret != 0) {
auto ret = this->notifier->notify(api::types::v1::InteractionRequest{
@ -2783,6 +2631,13 @@ utils::error::Result<std::filesystem::path> Cli::ensureCache(
qWarning() << "failed to notify" << ret.error();
}
}
// 如果缓存生成时间小于300ms, 则不再显示等待窗口
// 如果等待窗口显示时间小于1s则等待1s后再关闭窗口
if (processStartTime == 0) {
timer.stop();
} else if (QDateTime::currentSecsSinceEpoch() - processStartTime < 1000) {
QThread::sleep(1);
}
process.close();
return appCache;
@ -2810,42 +2665,37 @@ void Cli::updateAM() noexcept
}
}
int Cli::inspect(const InspectOptions &options)
int Cli::inspect(CLI::App *app, const InspectOptions &options)
{
auto myContainersRet = getCurrentContainers();
if (!myContainersRet) {
this->printer.printErr(myContainersRet.error());
return -1;
}
const auto &myContainers = *myContainersRet;
LINGLONG_TRACE("command inspect");
api::types::v1::InspectResult result;
auto argsParseFunc = [&app](const std::string &name) -> bool {
return app->get_subcommand(name)->parsed();
};
if (options.pid) {
qDebug() << "inspect by pid:" << options.pid.value();
for (const auto &container : myContainers) {
auto ret = isChildProcess(container.pid, options.pid.value());
if (!ret) {
this->printer.printErr(ret.error());
return -1;
}
if (*ret) {
result.appID = container.package;
break;
}
if (argsParseFunc("dir")) {
if (options.dirType == "layer") {
return this->getLayerDir(options);
} else if (options.dirType == "bundle") {
return this->getBundleDir(options);
} else {
this->printer.printErr(
LINGLONG_ERRV(QString("Invalid type: %1, type must be layer or bundle")
.arg(QString::fromStdString(options.dirType))));
return -1;
}
}
this->printer.printInspect(result);
return 0;
}
int Cli::dir(const DirOptions &options)
int Cli::getLayerDir(const InspectOptions &options)
{
LINGLONG_TRACE("command dir");
LINGLONG_TRACE("Get Layer dir");
auto fuzzyRef = package::FuzzyReference::parse(options.appid);
auto fuzzyString = options.appid;
auto fuzzyRef = package::FuzzyReference::parse(fuzzyString);
if (!fuzzyRef) {
this->printer.printErr(fuzzyRef.error());
return -1;
@ -2871,6 +2721,32 @@ int Cli::dir(const DirOptions &options)
}
std::cout << layerDir->absolutePath().toStdString() << std::endl;
return 0;
}
int Cli::getBundleDir(const InspectOptions &options)
{
LINGLONG_TRACE("Get Bundle dir");
auto containerIDList = getRunningAppContainers(options.appid);
if (containerIDList.empty()) {
this->printer.printErr(LINGLONG_ERRV("Can not find the running application."));
return -1;
}
if (containerIDList.size() > 1) {
this->printer.printErr(
LINGLONG_ERRV("Found multiple running containers for the application, please specify "
"the container ID to inspect."));
return -1;
}
auto bundleDir = linglong::common::dir::getBundleDir(containerIDList.front());
std::cout << bundleDir.string() << std::endl;
return 0;
}

View File

@ -47,6 +47,9 @@ struct RunOptions
std::vector<std::string> commands;
std::optional<std::string> base;
std::optional<std::string> runtime;
std::vector<std::string> extensions;
bool privileged{ false };
std::vector<std::string> capsAdd;
};
struct EnterOptions
@ -116,14 +119,10 @@ struct RepoOptions
};
struct InspectOptions
{
std::optional<pid_t> pid;
};
struct DirOptions
{
std::string appid;
std::string module;
std::string dirType{ "layer" };
};
class Cli : public QObject
@ -156,8 +155,7 @@ public:
int info(const InfoOptions &options);
int content(const ContentOptions &options);
int prune();
int inspect(const InspectOptions &options);
int dir(const DirOptions &options);
int inspect(CLI::App *subcommand, const InspectOptions &options);
void cancelCurrentTask();
@ -196,6 +194,9 @@ private:
runtime::RunContext &runContext, const generator::ContainerCfgBuilder &cfgBuilder) noexcept;
QDBusReply<QString> authorization();
void updateAM() noexcept;
std::vector<std::string> getRunningAppContainers(const std::string &appid);
int getLayerDir(const InspectOptions &options);
int getBundleDir(const InspectOptions &options);
private Q_SLOTS:
// maybe use in the future

View File

@ -33,7 +33,7 @@ std::wstring subwstr(std::wstring wstr, int width)
void CLIPrinter::printErr(const utils::error::Error &err)
{
std::cerr << "Error " << err.code() << ": " << err.message().toStdString() << std::endl;
std::cerr << "Error " << err.code() << ": " << err.message() << std::endl;
}
void CLIPrinter::printPruneResult(const std::vector<api::types::v1::PackageInfoV2> &list)

View File

@ -18,10 +18,8 @@ namespace linglong::cli {
void JSONPrinter::printErr(const utils::error::Error &err)
{
std::cout << nlohmann::json{
{ "code", err.code() },
{ "message", err.message().toStdString() }
}.dump() << std::endl;
std::cout << nlohmann::json{ { "code", err.code() }, { "message", err.message() } }.dump()
<< std::endl;
}
void JSONPrinter::printPackage(const api::types::v1::PackageInfoV2 &info)

View File

@ -10,6 +10,7 @@
#include "linglong/api/types/v1/LayerInfo.hpp"
#include "linglong/utils/command/cmd.h"
#include "linglong/utils/command/env.h"
#include "linglong/utils/log/log.h"
#include <QDataStream>
#include <QSysInfo>
@ -91,7 +92,7 @@ LayerPackager::~LayerPackager()
}
}
if (!std::filesystem::remove_all(this->workDir)) {
qCritical() << "remove" << this->workDir.c_str() << "failed";
LogE("failed to remove {}", this->workDir);
Q_ASSERT(false);
}
}

View File

@ -7,9 +7,12 @@
#include "linglong/package/reference.h"
#include <fmt/format.h>
#include <qregularexpression.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QRegularExpression>
#include <QStringList>
#include <QVariantMap>
namespace linglong::package {

View File

@ -42,6 +42,19 @@ const auto version_pattern =
const auto loose_version_pattern =
(R"(^v?(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$)");
static const QRegularExpression &getRegex(bool strict) noexcept
{
if (strict) {
static const QRegularExpression strictRegExp(version_pattern);
strictRegExp.optimize();
return strictRegExp;
}
static const QRegularExpression looseRegExp(loose_version_pattern);
looseRegExp.optimize();
return looseRegExp;
}
struct semver_exception : public std::runtime_error
{
explicit semver_exception(const std::string &message)
@ -55,25 +68,26 @@ inline uint64_t parse_numeric_part(const std::string &version_part)
return static_cast<uint64_t>(std::stoull(version_part));
}
inline std::vector<std::string> split(const std::string &text, const char &delimiter)
inline std::vector<std::string_view> split(const std::string &text, const char &delimiter)
{
std::size_t pos_start = 0, pos_end, delim_len = 1;
std::string current;
std::vector<std::string> result;
std::vector<std::string_view> result;
size_t start = 0;
size_t end = text.find(delimiter);
while ((pos_end = text.find(delimiter, pos_start)) != std::string::npos) {
current = text.substr(pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
result.push_back(current);
while (end != std::string_view::npos) {
result.emplace_back(text.data() + start, end - start);
start = end + 1;
end = text.find(delimiter, start);
}
result.push_back(text.substr(pos_start));
result.emplace_back(text.data() + start, text.size() - start);
return result;
}
inline bool is_numeric(const std::string &text)
{
return text.find_first_not_of(numbers) == std::string::npos;
return std::all_of(text.cbegin(), text.cend(), [](char c) {
return c >= '0' && c <= '9';
});
}
inline bool is_valid_prerelease(const std::string &text)
@ -90,7 +104,7 @@ private:
uint64_t m_numeric_value;
public:
explicit prerelease_part(const std::string &part)
explicit prerelease_part(std::string part)
{
if (part.empty()) {
throw semver_exception("Pre-release identity contains an empty part.");
@ -104,11 +118,13 @@ public:
m_numeric_value = parse_numeric_part(part);
m_numeric = true;
}
if (!is_valid_prerelease(part)) {
throw semver_exception("Pre-release part '" + part
+ "' contains an invalid character.");
}
m_value = part;
m_value = std::move(part);
}
[[nodiscard]] bool numeric() const { return m_numeric; }
@ -185,16 +201,25 @@ public:
[[nodiscard]] int compare(const prerelease_descriptor &other) const
{
auto this_size = m_parts.size();
auto other_size = other.m_parts.size();
const size_t count = std::min(m_parts.size(), other.m_parts.size());
auto count = std::min(this_size, other_size);
for (size_t i = 0; i < count; ++i) {
int cmp = m_parts[i].compare(other.m_parts[i]);
if (cmp != 0)
const auto &lhs = m_parts[i];
const auto &rhs = other.m_parts[i];
const int cmp = lhs.compare(rhs);
if (cmp != 0) {
return cmp;
}
}
return (this_size < other_size) ? -1 : (this_size > other_size);
if (m_parts.size() < other.m_parts.size()) {
return -1;
}
if (m_parts.size() > other.m_parts.size()) {
return 1;
}
return 0;
}
bool operator<(const prerelease_descriptor &other) const { return compare(other) == -1; }
@ -216,9 +241,11 @@ public:
if (prerelease_part_str.empty())
return empty();
std::vector<prerelease_part> prerelease_parts;
std::vector<std::string> parts = split(prerelease_part_str, '.');
for (auto &part : parts) {
prerelease_parts.emplace_back(part);
const auto parts = split(prerelease_part_str, '.');
prerelease_parts.reserve(parts.size());
for (auto part : parts) {
prerelease_parts.emplace_back(std::string{ part });
}
return prerelease_descriptor(prerelease_parts);
}
@ -410,8 +437,8 @@ public:
static version parse(const std::string &version_str, bool strict = true)
{
QRegularExpression regex(strict ? version_pattern : loose_version_pattern);
QRegularExpressionMatch match = regex.match(QString::fromStdString(version_str));
const auto &regex = getRegex(strict);
const QRegularExpressionMatch match = regex.match(QString::fromStdString(version_str));
if (!match.hasMatch()) {
throw semver_exception("Invalid version: " + version_str);

View File

@ -28,17 +28,7 @@
namespace linglong::package {
/**
* In the package_manager.cpp file, the method installFromUAB attempts to move a lambda to
* QCoreApplication::instance() via QMetaObject::invokeMethod, which has a object of type
* std::unique_ptr<uabFile> that created from this method. However, when compiling this project with
* Qt 5.11, the type of lambda (rvalue reference) is lost during parameter passing to Qt's internal
* method, so the compiler tries to call the copy constructor of this lambda. std::unique_ptr has a
* deleted copy constructor, so it compiles failed. The temporary resolution is that returning a
* std::shared_pointer<UABFile>, if linglong depends on a minimal version of Qt above 5.11, change
* the type of returned value to std::unique_ptr<UABFile>.
**/
utils::error::Result<std::shared_ptr<UABFile>> UABFile::loadFromFile(int fd) noexcept
utils::error::Result<std::unique_ptr<UABFile>> UABFile::loadFromFile(int fd) noexcept
{
LINGLONG_TRACE("load uab file from fd")
@ -47,7 +37,7 @@ utils::error::Result<std::shared_ptr<UABFile>> UABFile::loadFromFile(int fd) noe
using UABFile::UABFile;
};
auto file = std::make_shared<EnableMaker>();
auto file = std::make_unique<EnableMaker>();
if (!file->open(fd, QIODevice::ReadOnly, FileHandleFlag::AutoCloseHandle)) {
return LINGLONG_ERR(QString{ "open uab failed: %1" }.arg(file->errorString()));
@ -56,7 +46,7 @@ utils::error::Result<std::shared_ptr<UABFile>> UABFile::loadFromFile(int fd) noe
elf_version(EV_CURRENT);
auto *elf = elf_begin(fd, ELF_C_READ, nullptr);
if (elf == nullptr) {
return LINGLONG_ERR(QString{ "libelf err:" }.arg(elf_errmsg(errno)));
return LINGLONG_ERR(QString{ "libelf err: %1" }.arg(elf_errmsg(errno)));
}
file->e = elf;
@ -319,7 +309,8 @@ utils::error::Result<std::filesystem::path> UABFile::extractSignData() noexcept
auto tarFile = destination / "sign.tar";
auto tarFd = ::open(tarFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (tarFd == -1) {
return LINGLONG_ERR(QString{ "open" } % tarFile.c_str() % " failed:" % strerror(errno));
return LINGLONG_ERR(
QString{ "open %1 failed: %2" }.arg(tarFile.c_str()).arg(strerror(errno)));
}
auto removeTar = utils::finally::finally([&tarFd, &tarFile] {
@ -350,7 +341,8 @@ utils::error::Result<std::filesystem::path> UABFile::extractSignData() noexcept
errno = 0;
continue;
}
return LINGLONG_ERR(QString{ "read from sign section error:" } % ::strerror(errno));
return LINGLONG_ERR(
QString{ "read from sign section error: %1" }.arg(::strerror(errno)));
}
while (true) {
@ -360,7 +352,8 @@ utils::error::Result<std::filesystem::path> UABFile::extractSignData() noexcept
errno = 0;
continue;
}
return LINGLONG_ERR(QString{ "write to sign.tar error:" } % ::strerror(errno));
return LINGLONG_ERR(
QString{ "write to sign.tar error: %1" }.arg(::strerror(errno)));
}
if (writeBytes != readBytes) {
@ -373,12 +366,12 @@ utils::error::Result<std::filesystem::path> UABFile::extractSignData() noexcept
}
if (::fsync(tarFd) == -1) {
return LINGLONG_ERR(QString{ "fsync sign.tar error: " } % ::strerror(errno));
return LINGLONG_ERR(QString{ "fsync sign.tar error: %1" }.arg(::strerror(errno)));
}
if (::close(tarFd) == -1) {
tarFd = -1; // no need to try twice
return LINGLONG_ERR(QString{ "failed to close tar: " } % ::strerror(errno));
return LINGLONG_ERR(QString{ "failed to close tar: %1" }.arg(::strerror(errno)));
}
tarFd = -1;
@ -422,17 +415,18 @@ utils::error::Result<void> UABFile::saveErofsToFile(const std::string &path)
auto readBytes = bundleLength > buf.size() ? buf.size() : bundleLength;
auto bytesRead = ::read(handle(), buf.data(), readBytes);
if (bytesRead == -1) {
return LINGLONG_ERR(QString{ "read from bundle section error:" } % ::strerror(errno));
return LINGLONG_ERR(
QString{ "read from bundle section error: %1" }.arg(::strerror(errno)));
}
ofs.write(buf.data(), bytesRead);
if (ofs.fail()) {
return LINGLONG_ERR(QString{ "write " } % path.c_str() % " failed");
return LINGLONG_ERR(QString{ "write %1 failed" }.arg(path.c_str()));
}
bundleLength -= bytesRead;
}
ofs.close();
if (ofs.fail()) {
return LINGLONG_ERR(QString{ "close " } % path.c_str() % " failed");
return LINGLONG_ERR(QString{ "close %1 failed" }.arg(path.c_str()));
}
return LINGLONG_OK;
}

Some files were not shown because too many files have changed in this diff Show More