mirror of https://github.com/linuxdeepin/linglong
Compare commits
31 Commits
6891cb6653
...
c451f3dd66
| Author | SHA1 | Date |
|---|---|---|
|
|
c451f3dd66 | |
|
|
4e40696453 | |
|
|
8748a64e1e | |
|
|
174f40ca2e | |
|
|
f21b273a64 | |
|
|
1cb0a541f4 | |
|
|
2e83a40c79 | |
|
|
e34f87ec6f | |
|
|
b4bcaae25c | |
|
|
b57cad23b2 | |
|
|
841b0b0d9b | |
|
|
7a8cb94697 | |
|
|
0b7e505d42 | |
|
|
c49e6cfab3 | |
|
|
8be74385ff | |
|
|
1adb797f05 | |
|
|
d94d9b8b76 | |
|
|
9b118c691d | |
|
|
588fd5c49e | |
|
|
8b596142cb | |
|
|
74efe1d5e2 | |
|
|
76fcc5b201 | |
|
|
cfe7785a80 | |
|
|
a74ab84a5f | |
|
|
7551f68448 | |
|
|
857948b3c3 | |
|
|
01049a68aa | |
|
|
399d70fd44 | |
|
|
1035ae54d8 | |
|
|
75b70e80af | |
|
|
cb5d3d31fa |
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 time,If 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 下载静态文件如 files,url 仅用于获取元数据如 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可用。如果没有可用mirror,pull失败。
|
||||
在 pull 时,ostree 先从 contenturl 获取镜像列表,然后从每个 url 获取 /config 文件。如果获取不到 /config 文件,则认为该 mirror 不可用;如果获取到 /config 文件,则认为该 mirror 可用。如果没有可用 mirror,pull 失败。
|
||||
|
||||
### 获取summary文件
|
||||
### 获取 summary 文件
|
||||
|
||||
ostree会从url获取summary文件,如果获取不到summary文件,或者summary文件不存在ref,pull失败。
|
||||
ostree 会从 url 获取 summary 文件。如果获取不到 summary 文件,或者 summary 文件中不存在 ref,pull 失败。
|
||||
|
||||
### 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 失败。
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|||
|
||||

|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
||||
|
|
|
|||
|
|
@ -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`)
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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`:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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. |
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||

|
||||
|
||||
|
|
@ -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:
|
||||
|
||||

|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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` 用于生成符合描述的玲珑容器而不是执行所有任务,具体操作可查阅后续课程关于容器内部构建文件的案例
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
#
|
||||

|
||||
|
||||
### openKylin 2.0
|
||||
|
||||
#
|
||||

|
||||
|
||||
### Ubuntu 2404
|
||||
|
||||
#
|
||||

|
||||
|
||||
### OpenEuler 2403
|
||||
|
||||
#
|
||||

|
||||
|
||||
至此, 足以证明 `基于Qt5的开源应用--qBittorrent` 在添加定制补丁以及修改构建规则后可以实现一站拉取项目源码并编译成可执行的二进制文件, 并在其他发行版上也可以使用 !
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# ll-appimage-convert简介
|
||||
|
||||
本工具由`linglong-pica`包提供。它提供将appimage包转换为如意玲珑包的能力,生成构建如意玲珑应用需要的linglong.yaml文件,并依赖 ll-builder 来实现应用构建和导出。
|
||||
本工具由`linglong-pica`包提供。它提供将AppImage包转换为如意玲珑包的能力,生成构建如意玲珑应用需要的linglong.yaml文件,并依赖 ll-builder 来实现应用构建和导出。
|
||||
|
||||
:::tip
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,6 @@ ll-builder build
|
|||
ll-builder build --exec /bin/bash
|
||||
```
|
||||
|
||||
进入容器后,可执行 `shell`命令,如 `ps`、`ls` 等。
|
||||
进入容器后,可以执行 `shell`命令,如 `ps`、`ls` 等。
|
||||
|
||||
如意玲珑应用 `debug`版本更多调试信息请参考:[DEBUG](../debug/debug.md)。
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
## 执行构建流程
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ bundle 模式在导出时,会尝试自动解析应用的依赖,并导出必
|
|||
|
||||
如果应用开发者需要依赖自运行功能,请保证应用带上必要的运行时依赖。
|
||||
|
||||
### Bustom Loader 模式
|
||||
### Custom Loader 模式
|
||||
|
||||
custom loader 模式导出的 UAB 文件仅包含应用数据,以及传入的 custom loader。UAB 文件在解压挂载后将控制器交给 custom loader,此时 loader 不在容器环境内。环境变量 `LINGLONG_UAB_APPROOT` 保存了应用所在目录,custom loader 负责初始化应用程序所需要的运行环境,比如库路径的搜索。
|
||||
|
||||
|
|
|
|||
|
|
@ -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 构建玲珑包
|
||||
|
|
|
|||
|
|
@ -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一节中的相关内容一致。
|
||||
|
||||
|
|
|
|||
|
|
@ -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`)
|
||||
|
||||
|
|
|
|||
|
|
@ -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 模块会同时卸载其他模块。
|
||||
|
||||
|
|
|
|||
|
|
@ -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 的当前目录)或其子目录下。
|
||||
|
||||
## 龙芯
|
||||
|
||||
|
|
|
|||
|
|
@ -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`命令用来将如意玲珑软件包推送至如意玲珑远程仓库。
|
||||
|
||||
|
|
|
|||
|
|
@ -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-列表)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ Options:
|
|||
|
||||
使用 `ll-cli info`显示已安装的应用程序或运行时的信息。
|
||||
|
||||
`ll-cli info org.dde.calendar`输出如下:
|
||||
`ll-cli info org.dde.calendar` 输出如下:
|
||||
|
||||
```text
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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%
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Options:
|
|||
|
||||
使用`ll-cli prune`移除未使用的最小系统或运行时。
|
||||
|
||||
`ll-cli prune`输出如下:
|
||||
`ll-cli prune` 输出如下:
|
||||
|
||||
```text
|
||||
Unused base or runtime:
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ Options:
|
|||
您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues
|
||||
```
|
||||
|
||||
查看正在运行的应用,运行`ll-cli ps`命令:
|
||||
查看正在运行的应用,运行 `ll-cli ps` 命令:
|
||||
|
||||
```bash
|
||||
ll-cli ps
|
||||
|
|
|
|||
|
|
@ -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`:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Options:
|
|||
您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues
|
||||
```
|
||||
|
||||
使用 `ll-cli upgrade`将所有已安装的应用程序升级到最新版本
|
||||
使用 `ll-cli upgrade` 将所有已安装的应用程序升级到最新版本
|
||||
|
||||
`ll-cli upgrade`命令输出如下:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
||||
玲珑应用的产物 :
|
||||
|
|
|
|||
|
|
@ -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。
|
||||
|
||||
构建产物如下:
|
||||
|
||||
|
|
|
|||
|
|
@ -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> 请修改成不需要鉴权的地址。
|
||||
:::
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 包需要的架构 |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later
|
|||
|
||||
# 概述
|
||||
|
||||
如意玲珑是统信软件自研的开源软件包格式,用于替代 `deb`、`rpm`等包管理工具,实现了应用包管理、分发、容器、集成开发工具等功能。
|
||||
如意玲珑是统信软件自研的开源软件包格式,用于替代 `deb`、`rpm` 等包管理工具,实现了应用包管理、分发、容器、集成开发工具等功能。
|
||||
|
||||
## 当前包管理器存在的问题
|
||||
|
||||
|
|
|
|||
20
docs/ref.md
20
docs/ref.md
|
|
@ -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 为 ID,1.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 中任意一个字段,那么以这个字段为准。
|
||||
|
||||
## 实现
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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. |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]");
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ®ex = getRegex(strict);
|
||||
const QRegularExpressionMatch match = regex.match(QString::fromStdString(version_str));
|
||||
|
||||
if (!match.hasMatch()) {
|
||||
throw semver_exception("Invalid version: " + version_str);
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue