refact: new error wrapping macros

Signed-off-by: black-desk <me@black-desk.cn>
This commit is contained in:
black-desk 2024-03-04 17:57:46 +08:00
parent 2c3e586122
commit 3ec42da2f7
No known key found for this signature in database
GPG Key ID: 761EE6143999AE8B
30 changed files with 1000 additions and 1027 deletions

View File

@ -70,7 +70,7 @@ int main(int argc, char **argv)
parser.addOptions({ optVerbose });
parser.addHelpOption();
QStringList subCommandList = { "create", "build", "run", "export", "push", "convert"};
QStringList subCommandList = { "create", "build", "run", "export", "push", "convert" };
parser.addPositionalArgument("subcommand",
subCommandList.join("\n"),
@ -180,31 +180,34 @@ int main(int argc, char **argv)
return -1;
}
linglong::util::Error err;
if (parser.isSet(pkgID) || parser.isSet(pkgName) || parser.isSet(pkgVersion)
|| parser.isSet(pkgDescription) || parser.isSet(scriptOpt)) {
if (appImageFileType) {
err = builder.appimageConvert(
auto ret = builder.appimageConvert(
QStringList()
<< parser.value(pkgFile) << parser.value(pkgUrl) << parser.value(pkgHash)
<< parser.value(pkgID) << parser.value(pkgName) << parser.value(pkgVersion)
<< parser.value(pkgDescription) << parser.value(scriptOpt));
} else if (debFileType) {
// TODO: implement deb convert
if (!ret) {
printer.printErr(ret.error());
return ret.error().code();
}
} else {
printer.printErr(LINGLONG_ERR(-1, "unsupported type").value());
// TODO: implement deb convert
LINGLONG_TRACE("unsupported type");
auto err = LINGLONG_ERR(fileSuffix).value();
printer.printErr(err);
return err.code();
}
}
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
}
return err.code();
return 0;
} },
{ "create",
[&](QCommandLineParser &parser) -> int {
LINGLONG_TRACE("command create");
parser.clearPositionalArguments();
parser.addPositionalArgument("create", "create build template project", "create");
parser.addPositionalArgument("name", "project name", "<org.deepin.demo>");
@ -218,16 +221,19 @@ int main(int argc, char **argv)
parser.showHelp(-1);
}
auto err = builder.create(projectName);
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
auto oldErr = builder.create(projectName);
if (oldErr) {
auto err = LINGLONG_ERR(oldErr.message(), oldErr.code()).value();
printer.printErr(err);
return err.code();
}
return err.code();
return 0;
} },
{ "build",
[&](QCommandLineParser &parser) -> int {
LINGLONG_TRACE("command build");
parser.clearPositionalArguments();
auto execVerbose = QCommandLineOption("exec", "run exec than build script", "exec");
@ -281,12 +287,13 @@ int main(int argc, char **argv)
return -1;
}
auto [project, err] =
auto [project, oldErr] =
linglong::util::fromYAML<QSharedPointer<linglong::builder::Project>>(
projectConfigPath);
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
return -1;
if (oldErr) {
auto err = LINGLONG_ERR(oldErr.message(), oldErr.code()).value();
printer.printErr(err);
return err.code();
}
auto node = YAML::LoadFile(projectConfigPath.toStdString());
@ -317,6 +324,8 @@ int main(int argc, char **argv)
} },
{ "run",
[&](QCommandLineParser &parser) -> int {
LINGLONG_TRACE("command run");
parser.clearPositionalArguments();
auto execVerbose = QCommandLineOption("exec", "run exec than build script", "exec");
@ -331,12 +340,14 @@ int main(int argc, char **argv)
linglong::builder::BuilderConfig::instance()->setExec(exec);
}
auto err = builder.run();
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
auto oldErr = builder.run();
if (oldErr) {
auto err = LINGLONG_ERR(oldErr.message(), oldErr.code()).value();
printer.printErr(err);
return err.code();
}
return err.code();
return 0;
} },
// { "export",
// [&](QCommandLineParser &parser) -> int {
@ -369,6 +380,8 @@ int main(int argc, char **argv)
// } },
{ "export",
[&](QCommandLineParser &parser) -> int {
LINGLONG_TRACE("command export");
parser.clearPositionalArguments();
parser.addPositionalArgument("export", "export build result to layer", "export");
@ -385,14 +398,19 @@ int main(int argc, char **argv)
path = linglong::builder::BuilderConfig::instance()->getProjectRoot();
}
auto err = builder.exportLayer(path);
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
auto oldErr = builder.exportLayer(path);
if (oldErr) {
auto err = LINGLONG_ERR(oldErr.message(), oldErr.code()).value();
printer.printErr(err);
return err.code();
}
return err.code();
return 0;
} },
{ "extract",
[&](QCommandLineParser &parser) -> int {
LINGLONG_TRACE("command extract");
parser.clearPositionalArguments();
parser.addPositionalArgument("extract",
@ -410,14 +428,19 @@ int main(int argc, char **argv)
parser.showHelp(-1);
}
auto err = builder.extractLayer(layerPath, destination);
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
auto oldErr = builder.extractLayer(layerPath, destination);
if (oldErr) {
auto err = LINGLONG_ERR(oldErr.message(), oldErr.code()).value();
printer.printErr(err);
return err.code();
}
return err.code();
return 0;
} },
{ "config",
[&](QCommandLineParser &parser) -> int {
LINGLONG_TRACE("command config");
parser.clearPositionalArguments();
parser.addPositionalArgument("config", "config user info", "config");
@ -428,31 +451,19 @@ int main(int argc, char **argv)
parser.process(app);
auto userName = parser.value(optUserName);
auto userPassword = parser.value(optUserPassword);
auto err = builder.config(userName, userPassword);
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
auto oldErr = builder.config(userName, userPassword);
if (oldErr) {
auto err = LINGLONG_ERR(oldErr.message(), oldErr.code()).value();
printer.printErr(err);
return err.code();
}
return err.code();
return 0;
} },
// { "import",
// [&](QCommandLineParser &parser) -> int {
// parser.clearPositionalArguments();
// parser.addPositionalArgument("import", "import package data to local repo",
// "import");
// parser.process(app);
// auto err = builder.import();
// if (err) {
// qCritical() << err;
// }
// return err.code();
// } },
{ "import",
[&](QCommandLineParser &parser) -> int {
LINGLONG_TRACE("command import");
parser.clearPositionalArguments();
parser.addPositionalArgument("import", "import layer to local repo", "import");
@ -468,14 +479,17 @@ int main(int argc, char **argv)
parser.showHelp(-1);
}
auto err = builder.importLayer(path);
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
auto oldErr = builder.importLayer(path);
if (oldErr) {
auto err = LINGLONG_ERR(oldErr.message(), oldErr.code()).value();
printer.printErr(err);
return err.code();
}
return err.code();
return 0;
} },
{ "track",
[&](QCommandLineParser &parser) -> int {
LINGLONG_TRACE("command track");
parser.clearPositionalArguments();
parser.addPositionalArgument("track",
@ -484,15 +498,18 @@ int main(int argc, char **argv)
parser.process(app);
auto err = builder.track();
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
auto oldErr = builder.track();
if (oldErr) {
auto err = LINGLONG_ERR(oldErr.message(), oldErr.code()).value();
printer.printErr(err);
return err.code();
}
return err.code();
return 0;
} },
{ "push",
[&](QCommandLineParser &parser) -> int {
LINGLONG_TRACE("command push");
parser.clearPositionalArguments();
parser.addPositionalArgument("push", "push build result to repo", "push");
@ -511,13 +528,13 @@ int main(int argc, char **argv)
bool pushWithDevel = parser.isSet(optNoDevel) ? false : true;
auto err = builder.push(repoUrl, repoName, repoChannel, pushWithDevel);
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
auto oldErr = builder.push(repoUrl, repoName, repoChannel, pushWithDevel);
if (oldErr) {
auto err = LINGLONG_ERR(oldErr.message(), oldErr.code()).value();
printer.printErr(err);
return err.code();
}
return err.code();
return 0;
} },
};

View File

@ -66,6 +66,7 @@ void DependFetcher::printProgress(const uint &progress, const QString &speed)
linglong::util::Error DependFetcher::fetch(const QString &subPath, const QString &targetPath)
{
auto handleRef = [&]() -> linglong::utils::error::Result<package::Ref> {
LINGLONG_TRACE("handleRef");
// FIXME(black_desk):
// 1. Offline should not only be an option of builder, but also a work
// mode argument passed to repo, which prevent all network request.
@ -89,8 +90,8 @@ linglong::util::Error DependFetcher::fetch(const QString &subPath, const QString
.arg("..."),
2);
auto ret = ostree.pull(*remoteRef, true);
if (!ret.has_value()) {
return LINGLONG_EWRAP(QString("pull %1 failed.").arg((*remoteRef).toString()), ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
return remoteRef;

View File

@ -68,6 +68,8 @@ LinglongBuilder::LinglongBuilder(repo::OSTreeRepo &ostree,
linglong::utils::error::Result<void> LinglongBuilder::buildStageCommitBuildOutput(
Project *project, const QString &upperdir, const QString &workdir)
{
LINGLONG_TRACE("commit build output");
auto output = project->config().cacheInstallPath("files");
auto lowerDir = project->config().cacheAbsoluteFilePath({ "overlayfs", "lower" });
// if combine runtime, lower is ${PROJECT_CACHE}/runtime/files
@ -87,16 +89,15 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageCommitBuildOutpu
};
qDebug() << "run" << program << arguments.join(" ");
auto execRet = utils::command::Exec(program, arguments);
if (!execRet.has_value()) {
return LINGLONG_EWRAP(QString("exec %1 %2 failed").arg(program).arg(arguments.join(" ")),
execRet.error());
if (!execRet) {
return LINGLONG_ERR(execRet);
}
auto _ = qScopeGuard([=] {
qDebug() << "umount fuse overlayfs";
auto ret = utils::command::Exec("umount", { "--lazy", output });
if (!ret.has_value()) {
qWarning() << "Failed to umount" << ret.error();
if (!ret) {
qCritical() << "Failed to umount" << ret.error();
}
});
@ -152,7 +153,7 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageCommitBuildOutpu
auto desktopFileSavePath = QStringList{ entriesPath, "applications" }.join(QDir::separator());
auto err = modifyConfigFile(desktopFilePath, desktopFileSavePath, "*.desktop", appId);
if (err) {
return LINGLONG_ERR(err.code(), "modify config file: " + err.message());
return LINGLONG_ERR("modify config file: " + err.message(), err.code());
}
// modify context-menus file
@ -161,7 +162,7 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageCommitBuildOutpu
auto contextFileSavePath = contextFilePath;
err = modifyConfigFile(contextFilePath, contextFileSavePath, "*.conf", appId);
if (err) {
return LINGLONG_ERR(err.code(), "modify desktop file: " + err.message());
return LINGLONG_ERR("modify desktop file: " + err.message(), err.code());
}
auto moveDir = [](const QStringList targetList,
@ -193,7 +194,7 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageCommitBuildOutpu
project->config().cacheInstallPath("files"),
project->config().cacheInstallPath("devel-install", "files"));
if (err) {
return LINGLONG_ERR(err.code(), "move debug file: " + err.message());
return LINGLONG_ERR("move debug file: " + err.message(), err.code());
}
auto createInfo = [](Project *project) -> linglong::util::Error {
@ -245,15 +246,15 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageCommitBuildOutpu
err = createInfo(project);
if (err) {
return LINGLONG_ERR(err.code(), "create info " + err.message());
return LINGLONG_ERR("create info " + err.message(), err.code());
}
auto refRuntime = project->refWithModule("runtime");
refRuntime.channel = "main";
qDebug() << "importDirectory " << project->config().cacheInstallPath("");
auto ret = repo.importDirectory(refRuntime, project->config().cacheInstallPath(""));
if (!ret.has_value()) {
return LINGLONG_EWRAP("import runtime", ret.error());
if (!ret) {
return LINGLONG_ERR("import runtime", ret);
}
auto refDevel = project->refWithModule("devel");
@ -261,7 +262,7 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageCommitBuildOutpu
qDebug() << "importDirectory " << project->config().cacheInstallPath("devel-install", "");
ret = repo.importDirectory(refDevel, project->config().cacheInstallPath("devel-install", ""));
if (!ret.has_value()) {
return LINGLONG_EWRAP("import devel", ret.error());
return LINGLONG_ERR("import devel", ret);
}
return LINGLONG_OK;
};
@ -311,15 +312,17 @@ linglong::util::Error LinglongBuilder::config(const QString &userName, const QSt
linglong::utils::error::Result<void> LinglongBuilder::buildStageRunContainer(
QDir workdir, ocppi::cli::CLI &cli, ocppi::runtime::config::types::Config &r)
{
LINGLONG_TRACE("run container");
// 写容器配置文件
auto data = toJSON(r).dump();
QFile f(workdir.filePath("config.json"));
qDebug() << "container config file" << f.fileName();
if (!f.open(QIODevice::WriteOnly)) {
return LINGLONG_ERR(-1, f.errorString());
return LINGLONG_ERR(f);
}
if (!f.write(QByteArray::fromStdString(data))) {
return LINGLONG_ERR(-1, f.errorString());
return LINGLONG_ERR(f);
}
f.close();
@ -327,14 +330,16 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageRunContainer(
auto id = util::genUuid().toStdString();
auto path = std::filesystem::path(workdir.path().toStdString());
auto ret = cli.run(id.c_str(), path);
if (!ret.has_value()) {
return LINGLONG_SERR(ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
return LINGLONG_OK;
}
linglong::util::Error LinglongBuilder::appimageConvert(const QStringList &templateArgs)
utils::error::Result<void> LinglongBuilder::appimageConvert(const QStringList &templateArgs)
{
LINGLONG_TRACE("convert appimage");
const auto file = templateArgs.at(0);
const auto url = templateArgs.at(1);
const auto hash = templateArgs.at(2);
@ -351,13 +356,12 @@ linglong::util::Error LinglongBuilder::appimageConvert(const QStringList &templa
QDir::separator());
if (!QFileInfo::exists(templateFilePath)) {
printer.printMessage("ll-builder should run in the root directory of the linglong project");
return NewError(-1, "appimage.yaml not found");
return LINGLONG_ERR("linglong installation broken: template file appimage.yaml not found");
}
auto ret = QDir().mkpath(projectPath);
if (!ret) {
return NewError(-1, "project already exists");
return LINGLONG_ERR(QString("project path %1 already exists").arg(projectPath));
}
// copy appimage file to project path
@ -367,8 +371,7 @@ linglong::util::Error LinglongBuilder::appimageConvert(const QStringList &templa
const auto &destinationFilePath = QDir(projectPath).filePath(fileInfo.fileName());
if (!QFileInfo::exists(sourcefilePath)) {
printer.printMessage("can not found appimage file");
return NewError(-1, "appimage file not found");
return LINGLONG_ERR(QString("appimage file %1 not found").arg(sourcefilePath));
}
QFile::copy(sourcefilePath, destinationFilePath);
@ -382,15 +385,14 @@ linglong::util::Error LinglongBuilder::appimageConvert(const QStringList &templa
// config linglong.yaml before build if necessary
if (!QFileInfo::exists(configFilePath)) {
printer.printMessage("ll-builder should run in the root directory of the linglong project");
return NewError(-1, "linglong.yaml not found");
return LINGLONG_ERR(
"linglong.yaml not found, ll-builder should run in the root directory of the project.");
}
auto [project, err] =
linglong::util::fromYAML<QSharedPointer<linglong::builder::Project>>(configFilePath);
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
return NewError(-1, "Internal error");
return LINGLONG_ERR(err.message(), err.code());
}
auto node = YAML::LoadFile(configFilePath.toStdString());
@ -421,42 +423,39 @@ linglong::util::Error LinglongBuilder::appimageConvert(const QStringList &templa
linglong::builder::BuilderConfig::instance()->setProjectRoot(projectPath);
auto buildRet = build();
if (!buildRet.has_value()) {
return NewError(buildRet.error().code(), buildRet.error().message());
if (!buildRet) {
return LINGLONG_ERR(buildRet);
}
err = exportLayer(projectPath);
// delete the generated temporary file, only keep .layer(.uab) files
QProcess process;
process.setWorkingDirectory(projectPath);
process.execute("bash",
QStringList()
<< "-c"
<< "find . -maxdepth 1 -not -regex '.*\\.\\|.*\\.layer\\|.*\\.uab' "
"-exec basename {} -print0 \\; | xargs rm -r");
if (err) {
printer.printErr(LINGLONG_ERR(err.code(), err.message()).value());
return err;
auto ret = utils::command::Exec(
"bash",
QStringList() << "-c"
<< "find . -maxdepth 1 -not -regex '.*\\.\\|.*\\.layer\\|.*\\.uab' "
"-exec basename {} -print0 \\; | xargs rm -r");
if (!ret) {
return LINGLONG_ERR(ret);
}
} else {
auto scriptFilePath = QStringList{ projectPath, scriptName }.join(QDir::separator());
// copy convert.sh to project path
QFile::copy(":/convert.sh", scriptFilePath);
if (!QFileInfo::exists(scriptFilePath)) {
printer.printMessage("can not found convert script file");
return NewError(-1, "convert script file not found");
if (!QFile::copy(":/convert.sh", scriptFilePath)) {
return LINGLONG_ERR("create convert.sh failed.");
}
// set execution permissions to convert.sh
QFile(scriptFilePath).setPermissions(QFile::ReadOwner | QFile::ExeOwner);
QFile scriptFile(scriptFilePath);
if (!scriptFile.setPermissions(QFile::ReadOwner | QFile::ExeOwner)) {
return LINGLONG_ERR("set convert.sh permission", scriptFile);
}
}
return Success();
return LINGLONG_OK;
}
linglong::util::Error LinglongBuilder::create(const QString &projectName)
util::Error LinglongBuilder::create(const QString &projectName)
{
auto projectPath = QStringList{ QDir::currentPath(), projectName }.join(QDir::separator());
auto configFilePath = QStringList{ projectPath, "linglong.yaml" }.join(QDir::separator());
@ -478,7 +477,7 @@ linglong::util::Error LinglongBuilder::create(const QString &projectName)
return Success();
}
linglong::util::Error LinglongBuilder::track()
util::Error LinglongBuilder::track()
{
auto projectConfigPath =
QStringList{ BuilderConfig::instance()->getProjectRoot(), "linglong.yaml" }.join(
@ -518,7 +517,7 @@ linglong::util::Error LinglongBuilder::track()
return Success();
}
linglong::utils::error::Result<void> LinglongBuilder::buildStageClean(const Project &project)
utils::error::Result<void> LinglongBuilder::buildStageClean(const Project &project)
{
// initialize some directories
util::removeDir(project.config().cacheRuntimePath({}));
@ -532,8 +531,9 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageClean(const Proj
return LINGLONG_OK;
}
linglong::utils::error::Result<QString> LinglongBuilder::buildStageDepend(Project *project)
utils::error::Result<QString> LinglongBuilder::buildStageDepend(Project *project)
{
LINGLONG_TRACE("handle depends");
printer.printMessage("[Processing Dependency]");
printer.printMessage(
@ -555,13 +555,13 @@ linglong::utils::error::Result<QString> LinglongBuilder::buildStageDepend(Projec
DependFetcher df(runtimeDepend, repo, printer, project);
auto err = df.fetch("", project->config().cacheRuntimePath(""));
if (err) {
return LINGLONG_ERR(err.code(), err.message());
return LINGLONG_ERR(err.message(), err.code());
}
if (!project->base) {
QFile infoFile(project->config().cacheRuntimePath("info.json"));
if (!infoFile.open(QIODevice::ReadOnly)) {
return LINGLONG_ERR(infoFile.error(), infoFile.errorString());
return LINGLONG_ERR("open info.json", infoFile);
}
// FIXME(black_desk): handle error
auto info =
@ -582,7 +582,7 @@ linglong::utils::error::Result<QString> LinglongBuilder::buildStageDepend(Projec
hostBasePath = BuilderConfig::instance()->layerPath({ baseRef.toLocalRefString(), "" });
auto err = baseFetcher.fetch("", hostBasePath);
if (err) {
return LINGLONG_ERR(err.code(), err.message());
return LINGLONG_ERR(err.message(), err.code());
}
// depends fetch
@ -590,7 +590,7 @@ linglong::utils::error::Result<QString> LinglongBuilder::buildStageDepend(Projec
DependFetcher df(depend, repo, printer, project);
err = df.fetch("files", project->config().cacheRuntimePath("files"));
if (err) {
return LINGLONG_ERR(err.code(), err.message());
return LINGLONG_ERR(err.message(), err.code());
}
}
return hostBasePath;
@ -599,6 +599,8 @@ linglong::utils::error::Result<QString> LinglongBuilder::buildStageDepend(Projec
linglong::utils::error::Result<ocppi::runtime::config::types::Config>
LinglongBuilder::buildStageConfigInit()
{
LINGLONG_TRACE("init oci config");
QFile builtinOCIConfigTemplateJSONFile(":/config.json");
if (!builtinOCIConfigTemplateJSONFile.open(QIODevice::ReadOnly)) {
// NOTE(black_desk): Go check qrc if this occurs.
@ -611,11 +613,11 @@ LinglongBuilder::buildStageConfigInit()
ocppi::runtime::config::ConfigLoader loader;
auto r = loader.load(tmpStream);
if (!r.has_value()) {
if (!r) {
printer.printMessage("builtin OCI configuration template is invalid.");
return LINGLONG_SERR(r.error());
return LINGLONG_ERR(r);
}
return r.value();
return *r;
}
linglong::utils::error::Result<void>
@ -626,6 +628,8 @@ LinglongBuilder::buildStageRuntime(ocppi::runtime::config::types::Config &r,
const QString &overlayWorkDir,
const QString &overlayMergeDir)
{
LINGLONG_TRACE("handle runtime");
util::ensureDir(overlayLowerDir);
util::ensureDir(overlayUpperDir);
util::ensureDir(overlayWorkDir);
@ -663,8 +667,8 @@ LinglongBuilder::buildStageRuntime(ocppi::runtime::config::types::Config &r,
};
qDebug() << "run" << program << arguments.join(" ");
auto ret = utils::command::Exec(program, arguments);
if (!ret.has_value()) {
return LINGLONG_EWRAP("mount runtime failed", ret.error());
if (!ret) {
return LINGLONG_ERR("mount runtime", ret);
}
// 使用容器hooks卸载fuse-overlayfs runtime
@ -690,16 +694,17 @@ LinglongBuilder::buildStageRuntime(ocppi::runtime::config::types::Config &r,
return LINGLONG_OK;
}
linglong::utils::error::Result<void>
utils::error::Result<void>
LinglongBuilder::buildStageSource(ocppi::runtime::config::types::Config &r, Project *project)
{
LINGLONG_TRACE("process source");
SourceFetcher sf(project->source, printer, project);
if (project->source) {
printer.printMessage("[Processing Source]");
auto err = sf.fetch();
if (err) {
return LINGLONG_ERR(-1, "fetch source failed");
return LINGLONG_ERR("fetch source failed");
}
}
// 挂载tmp
@ -737,7 +742,7 @@ LinglongBuilder::buildStageSource(ocppi::runtime::config::types::Config &r, Proj
return LINGLONG_OK;
}
linglong::utils::error::Result<void>
utils::error::Result<void>
LinglongBuilder::buildStageEnvrionment(ocppi::runtime::config::types::Config &r,
const Project &project,
const BuilderConfig &buildConfig)
@ -772,6 +777,7 @@ LinglongBuilder::buildStageEnvrionment(ocppi::runtime::config::types::Config &r,
for (auto env : buildConfig.getBuildEnv()) {
r.process->env->push_back(env.toStdString());
}
return LINGLONG_OK;
}
@ -814,6 +820,8 @@ LinglongBuilder::buildStageIDMapping(ocppi::runtime::config::types::Config &r)
linglong::utils::error::Result<void> LinglongBuilder::buildStageRootfs(
ocppi::runtime::config::types::Config &r, const QDir &workdir, const QString &hostBasePath)
{
LINGLONG_TRACE("process rootfs");
// 初始化rootfs目录
workdir.mkdir("rootfs");
workdir.mkdir("upper");
@ -831,8 +839,8 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageRootfs(
};
qDebug() << "run" << program << arguments.join(" ") << r.hooks->poststop.has_value();
auto mountRootRet = utils::command::Exec(program, arguments);
if (!mountRootRet.has_value()) {
return LINGLONG_EWRAP("exec fuse-overlayfs", mountRootRet.error());
if (!mountRootRet) {
return LINGLONG_ERR(mountRootRet);
}
// 使用容器hooks卸载overlayfs rootfs
ocppi::runtime::config::types::Hook umountRootfsHook;
@ -855,20 +863,22 @@ linglong::utils::error::Result<void> LinglongBuilder::buildStageRootfs(
linglong::utils::error::Result<QSharedPointer<Project>> LinglongBuilder::buildStageProjectInit()
{
LINGLONG_TRACE("init project");
linglong::util::Error err;
auto projectConfigPath =
QStringList{ BuilderConfig::instance()->getProjectRoot(), "linglong.yaml" }.join("/");
if (!QFileInfo::exists(projectConfigPath)) {
printer.printMessage("ll-builder should run in the root directory of the linglong project");
return LINGLONG_ERR(-1, "linglong.yaml not found");
return LINGLONG_ERR("linglong.yaml not found");
}
auto [project, err2] = util::fromYAML<QSharedPointer<Project>>(projectConfigPath);
if (err2) {
return LINGLONG_ERR(err2.code(), "cannot load project yaml");
return LINGLONG_ERR("load project yaml: " + err2.message(), err2.code());
}
if (!project->package || project->package->kind.isEmpty()) {
return LINGLONG_ERR(-1, "unknown package kind");
return LINGLONG_ERR("unknown package kind");
}
project->generateBuildScript();
@ -881,13 +891,15 @@ linglong::utils::error::Result<QSharedPointer<Project>> LinglongBuilder::buildSt
linglong::utils::error::Result<void> LinglongBuilder::build()
{
LINGLONG_TRACE("build");
auto projectRet = buildStageProjectInit();
if (!projectRet.has_value()) {
return LINGLONG_EWRAP("project init", projectRet.error());
if (!projectRet) {
return LINGLONG_ERR(projectRet);
}
auto configRet = buildStageConfigInit();
if (!configRet.has_value()) {
return LINGLONG_EWRAP("config init", configRet.error());
if (!configRet) {
return LINGLONG_ERR(configRet);
}
auto project = *projectRet;
printer.printMessage("[Build Target]");
@ -903,12 +915,12 @@ linglong::utils::error::Result<void> LinglongBuilder::build()
printer.printMessage(QString("Url: %1").arg(BuilderConfig::instance()->remoteRepoEndpoint), 2);
auto voidRet = buildStageClean(*project);
if (!voidRet.has_value()) {
return LINGLONG_EWRAP("clean build", voidRet.error());
if (!voidRet) {
return LINGLONG_ERR("clean build", voidRet);
}
auto basePathRet = buildStageDepend(project.get());
if (!basePathRet.has_value()) {
return LINGLONG_EWRAP("processing depend", basePathRet.error());
if (!basePathRet) {
return LINGLONG_ERR("processing depend", basePathRet);
}
auto hostBasePath = *basePathRet;
auto containerConfig = *configRet;
@ -931,34 +943,34 @@ linglong::utils::error::Result<void> LinglongBuilder::build()
overlayUpperDir,
overlayWorkDir,
overlayPointDir);
if (!voidRet.has_value()) {
return LINGLONG_EWRAP("mount runtime", voidRet.error());
if (!voidRet) {
return LINGLONG_ERR(voidRet);
}
// 挂载源码并配置构建脚本
voidRet = buildStageSource(containerConfig, project.get());
if (!voidRet.has_value()) {
return LINGLONG_EWRAP("mount source", voidRet.error());
if (!voidRet) {
return LINGLONG_ERR(voidRet);
}
// 配置环境变量
voidRet = buildStageEnvrionment(containerConfig, *project, *BuilderConfig::instance());
if (!voidRet.has_value()) {
return LINGLONG_EWRAP("config envrionment", voidRet.error());
return LINGLONG_ERR(voidRet);
}
// 配置uid和gid映射
voidRet = buildStageIDMapping(containerConfig);
if (!voidRet.has_value()) {
return LINGLONG_EWRAP("id mapping", voidRet.error());
if (!voidRet) {
return LINGLONG_ERR(voidRet);
}
// 配置容器rootfs
QTemporaryDir tmpDir;
tmpDir.setAutoRemove(false);
voidRet = buildStageRootfs(containerConfig, tmpDir.path(), hostBasePath);
if (!voidRet.has_value()) {
return LINGLONG_EWRAP("mount rootfs", voidRet.error());
if (!voidRet) {
return LINGLONG_ERR(voidRet);
}
// 运行容器
voidRet = buildStageRunContainer(tmpDir.path(), ociCLI, containerConfig);
if (!voidRet.has_value()) {
if (!voidRet) {
// 为避免容器启动失败hook脚本未执行手动再执行一次 umount
if (project->package->kind != PackageKindApp) {
qDebug() << "umount runtime";
@ -967,12 +979,12 @@ linglong::utils::error::Result<void> LinglongBuilder::build()
qDebug() << "umount rootfs";
utils::command::Exec("umount",
{ "--lazy", QString::fromStdString(containerConfig.root->path) });
return LINGLONG_EWRAP("run container", voidRet.error());
return LINGLONG_ERR(voidRet);
}
// 提交构建结果
voidRet = buildStageCommitBuildOutput(project.get(), overlayUpperDir, overlayPointDir);
if (!voidRet.has_value()) {
return LINGLONG_EWRAP("commit build output", voidRet.error());
if (!voidRet) {
return LINGLONG_ERR(voidRet);
}
printer.printMessage(QString("Build %1 success").arg(project->package->id));

View File

@ -31,33 +31,33 @@ public:
cli::Printer &p,
ocppi::cli::CLI &cli,
service::AppManager &appManager);
linglong::util::Error config(const QString &userName, const QString &password) override;
util::Error config(const QString &userName, const QString &password) override;
linglong::util::Error create(const QString &projectName) override;
util::Error create(const QString &projectName) override;
linglong::utils::error::Result<void> build() override;
utils::error::Result<void> build() override;
linglong::util::Error exportLayer(const QString &destination) override;
util::Error exportLayer(const QString &destination) override;
linglong::util::Error extractLayer(const QString &layerPath,
util::Error extractLayer(const QString &layerPath,
const QString &destination) override;
linglong::util::Error exportBundle(const QString &outputFilepath, bool useLocalDir) override;
util::Error exportBundle(const QString &outputFilepath, bool useLocalDir) override;
linglong::util::Error push(const QString &repoUrl,
util::Error push(const QString &repoUrl,
const QString &repoName,
const QString &channel,
bool pushWithDevel) override;
linglong::util::Error import() override;
util::Error import() override;
linglong::util::Error importLayer(const QString &path) override;
util::Error importLayer(const QString &path) override;
linglong::util::Error run() override;
util::Error run() override;
linglong::util::Error track() override;
util::Error track() override;
linglong::util::Error appimageConvert(const QStringList &templateArgs);
utils::error::Result<void> appimageConvert(const QStringList &templateArgs);
private:
repo::OSTreeRepo &repo;

View File

@ -95,22 +95,25 @@ void doIntOperate(int /*sig*/)
auto parseDataFromProxyCfgFile(const QString &dbusProxyCfgPath) -> Result<DBusProxyConfig>
{
LINGLONG_TRACE("parse D-Bus proxy config");
auto dataFile = QFile(dbusProxyCfgPath);
dataFile.open(QIODevice::ReadOnly);
if (dataFile.isOpen()) {
return LINGLONG_ERR(-1, "proxy config data not found");
return LINGLONG_ERR("open proxy config data", dataFile);
}
auto data = dataFile.readAll();
if (data.size() == 0) {
return LINGLONG_ERR(-1, "failed to read config data");
return LINGLONG_ERR("failed to read config data");
}
QJsonParseError jsonError;
auto doc = QJsonDocument::fromJson(data, &jsonError);
if (jsonError.error) {
return LINGLONG_ERR(-1, jsonError.errorString());
return LINGLONG_ERR(jsonError.errorString(), jsonError.error);
}
DBusProxyConfig config;
if (!doc.isNull()) {
QJsonObject jsonObject = doc.object();
@ -280,6 +283,8 @@ Cli::Cli(Printer &printer,
// TODD(wurongjie) 自动将输入转为container id
utils::error::Result<QString> Cli::getContainerID(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("get container id from args");
QString containerId;
if (args["PAGODA"].isString()) {
containerId = QString::fromStdString(args["PAGODA"].asString());
@ -290,18 +295,17 @@ utils::error::Result<QString> Cli::getContainerID(std::map<std::string, docopt::
}
if (containerId.isEmpty()) {
return LINGLONG_ERR(400, "canot get container id");
return LINGLONG_ERR("canot get container id");
}
return containerId;
}
int Cli::run(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command run");
const auto appId = QString::fromStdString(args["APP"].asString());
if (appId.isEmpty()) {
this->printer.printErr(LINGLONG_ERR(-1, "Application ID is required.").value());
return -1;
}
Q_ASSERT(!appId.isEmpty());
linglong::service::RunParamOption paramOption;
@ -329,10 +333,11 @@ int Cli::run(std::map<std::string, docopt::value> &args)
auto dbusProxyCfg = QString::fromStdString(args["--dbus-proxy-cfg"].asString());
if (!dbusProxyCfg.isEmpty()) {
auto data = parseDataFromProxyCfgFile(dbusProxyCfg);
if (!data.has_value()) {
printer.printErr(LINGLONG_ERR(-2, "get empty data from cfg file").value());
return -1;
if (!data) {
printer.printErr(data.error());
return data.error().code();
}
// TODO(linxin): parse dbus filter info from config path
paramOption.busType = "session";
paramOption.filterName = data->name[0];
@ -370,6 +375,8 @@ int Cli::exec(std::map<std::string, docopt::value> &args)
int Cli::enter(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command enter");
QString containerId;
containerId = QString::fromStdString(args["PAGODA"].asString());
@ -382,19 +389,16 @@ int Cli::enter(std::map<std::string, docopt::value> &args)
qWarning() << "COMMAND is not supported yet";
}
if (containerId.isEmpty()) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to get container id").value());
return -1;
}
Q_ASSERT(!containerId.isEmpty());
auto result = this->appMan.ListContainer().result;
QList<QSharedPointer<Container>> containerList;
const auto doc = QJsonDocument::fromJson(result.toUtf8(), nullptr);
if (!doc.isArray()) {
this->printer.printErr(
LINGLONG_ERR(-1, "container list get from server is not a list").value());
return -1;
auto err = LINGLONG_ERR("container list get from server is not a list").value();
this->printer.printErr(err);
return err.code();
}
pid_t pid = 0;
@ -416,14 +420,16 @@ int Cli::enter(std::map<std::string, docopt::value> &args)
}
if (pid == 0) {
this->printer.printErr(LINGLONG_ERR(-1, "no such container").value());
return -1;
auto err = LINGLONG_ERR("no such container").value();
this->printer.printErr(err);
return err.code();
}
int reply = namespaceEnter(pid, id);
if (reply == -1) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to enter namespace").value());
return -1;
auto err = LINGLONG_ERR("failed to enter namespace").value();
this->printer.printErr(err);
return err.code();
}
return 0;
@ -431,15 +437,17 @@ int Cli::enter(std::map<std::string, docopt::value> &args)
int Cli::ps(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command ps");
auto ret = this->appMan.ListContainer();
const auto replyString = ret.result;
QList<QSharedPointer<Container>> containerList;
const auto doc = QJsonDocument::fromJson(replyString.toUtf8(), nullptr);
if (!doc.isArray()) {
this->printer.printErr(
LINGLONG_ERR(-1, "container list get from server is not a list").value());
return -1;
auto err = LINGLONG_ERR("container list get from server is not a list").value();
this->printer.printErr(err);
return err.code();
}
for (const auto container : doc.array()) {
@ -453,6 +461,8 @@ int Cli::ps(std::map<std::string, docopt::value> &args)
int Cli::kill(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command kill");
auto ret = getContainerID(args);
if (!ret.has_value()) {
@ -462,8 +472,9 @@ int Cli::kill(std::map<std::string, docopt::value> &args)
auto reply = this->appMan.Stop(*ret);
if (reply.code != STATUS_CODE(kErrorPkgKillSuccess)) {
this->printer.printErr(LINGLONG_ERR(reply.code, reply.message).value());
return -1;
auto err = LINGLONG_ERR(reply.message, reply.code).value();
this->printer.printErr(err);
return err.code();
}
this->printer.printReply(reply);
@ -472,6 +483,8 @@ int Cli::kill(std::map<std::string, docopt::value> &args)
int Cli::install(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command install");
// 收到中断信号后恢复操作
signal(SIGINT, doIntOperate);
// 设置 24 h超时
@ -480,9 +493,11 @@ int Cli::install(std::map<std::string, docopt::value> &args)
linglong::service::InstallParamOption installParamOption;
auto tiers = args["TIER"].asStringList();
if (tiers.empty()) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to get app id").value());
return -1;
auto err = LINGLONG_ERR("failed to get app id").value();
this->printer.printErr(err);
return err.code();
}
for (auto &tier : tiers) {
linglong::service::Reply reply;
// if specify a layer instead of an appID
@ -548,8 +563,10 @@ int Cli::install(std::map<std::string, docopt::value> &args)
reply.message = "unknown err";
reply.code = -1;
}
this->printer.printErr(LINGLONG_ERR(reply.code, reply.message).value());
return -1;
auto err = LINGLONG_ERR(reply.message, reply.code).value();
this->printer.printErr(err);
return err.code();
}
// Call ReloadApplications() in AM for now. Remove later.
@ -576,11 +593,14 @@ int Cli::install(std::map<std::string, docopt::value> &args)
int Cli::upgrade(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command upgrade");
linglong::service::ParamOption paramOption;
auto tiers = args["TIER"].asStringList();
if (tiers.empty()) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to get app id").value());
auto err = LINGLONG_ERR("failed to get app id").value();
this->printer.printErr(err);
return -1;
}
@ -625,8 +645,9 @@ int Cli::upgrade(std::map<std::string, docopt::value> &args)
}
}
if (reply.code != STATUS_CODE(kErrorPkgUpdateSuccess)) {
this->printer.printErr(LINGLONG_ERR(-1, reply.message).value());
return -1;
auto err = LINGLONG_ERR(reply.message, reply.code).value();
this->printer.printErr(err);
return err.code();
}
this->printer.printReply(reply);
}
@ -636,15 +657,16 @@ int Cli::upgrade(std::map<std::string, docopt::value> &args)
int Cli::search(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command search");
linglong::service::QueryParamOption paramOption;
QString appId;
if (args["TEXT"].isString()) {
appId = QString::fromStdString(args["TEXT"].asString());
}
if (appId.isEmpty()) {
this->printer.printErr(LINGLONG_ERR(-1, "faied to get app id").value());
return -1;
}
Q_ASSERT(!appId.isEmpty());
paramOption.force = true;
paramOption.appId = appId;
this->pkgMan.setTimeout(1000 * 60 * 60 * 24);
@ -652,21 +674,24 @@ int Cli::search(std::map<std::string, docopt::value> &args)
dbusReply.waitForFinished();
linglong::service::QueryReply reply = dbusReply.value();
if (reply.code != STATUS_CODE(kErrorPkgQuerySuccess)) {
this->printer.printErr(LINGLONG_ERR(reply.code, reply.message).value());
return -1;
auto err = LINGLONG_ERR(reply.message, reply.code).value();
this->printer.printErr(err);
return err.code();
}
auto [appMetaInfoList, err] =
auto [appMetaInfoList, oldErr] =
linglong::util::fromJSON<QList<QSharedPointer<linglong::package::AppMetaInfo>>>(
reply.result.toLocal8Bit());
if (err) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to parse json reply").value());
return -1;
if (oldErr) {
auto err = LINGLONG_ERR("failed to parse json reply").value();
this->printer.printErr(err);
return err.code();
}
if (appMetaInfoList.empty()) {
this->printer.printErr(LINGLONG_ERR(-1, "app not found in repo").value());
return -1;
auto err = LINGLONG_ERR("app not found in repo").value();
this->printer.printErr(err);
return err.code();
}
this->printer.printAppMetaInfos(appMetaInfoList);
@ -675,6 +700,8 @@ int Cli::search(std::map<std::string, docopt::value> &args)
int Cli::uninstall(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command uninstall");
this->pkgMan.setTimeout(1000 * 60 * 60 * 24);
QDBusPendingReply<linglong::service::Reply> dbusReply;
linglong::service::UninstallParamOption paramOption;
@ -698,8 +725,9 @@ int Cli::uninstall(std::map<std::string, docopt::value> &args)
reply = dbusReply.value();
if (reply.code != STATUS_CODE(kPkgUninstallSuccess)) {
this->printer.printErr(LINGLONG_ERR(reply.code, reply.message).value());
return -1;
auto err = LINGLONG_ERR(reply.message, reply.code).value();
this->printer.printErr(err);
return err.code();
}
this->printer.printReply(reply);
}
@ -723,6 +751,8 @@ int Cli::list(std::map<std::string, docopt::value> &args)
int Cli::repo(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command repo");
if (!args["modify"].asBool()) {
auto dbusReply = this->pkgMan.getRepoInfo();
dbusReply.waitForFinished();
@ -745,8 +775,9 @@ int Cli::repo(std::map<std::string, docopt::value> &args)
dbusReply.waitForFinished();
reply = dbusReply.value();
if (reply.code != STATUS_CODE(kErrorModifyRepoSuccess)) {
this->printer.printErr(LINGLONG_ERR(reply.code, reply.message).value());
return -1;
auto err = LINGLONG_ERR(reply.message, reply.code).value();
this->printer.printErr(err);
return err.code();
}
this->printer.printReply(reply);
return 0;
@ -754,19 +785,22 @@ int Cli::repo(std::map<std::string, docopt::value> &args)
int Cli::info(std::map<std::string, docopt::value> &args)
{
LINGLONG_TRACE("command info");
QString layerPath;
if (args["LAYER"].isString()) {
layerPath = QString::fromStdString(args["LAYER"].asString());
}
if (layerPath.isEmpty()) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to get layer path").value());
return -1;
auto err = LINGLONG_ERR("failed to get layer path").value();
this->printer.printErr(err);
return err.code();
}
const auto layerFile = package::LayerFile::openLayer(layerPath);
if (!layerFile.has_value()) {
if (!layerFile) {
this->printer.printErr(layerFile.error());
return -1;
}
@ -774,18 +808,19 @@ int Cli::info(std::map<std::string, docopt::value> &args)
(*layerFile)->setCleanStatus(false);
const auto layerInfo = (*layerFile)->layerFileInfo();
if (!layerInfo.has_value()) {
if (!layerInfo) {
this->printer.printErr(layerInfo.error());
return -1;
}
const auto rawData = QByteArray::fromStdString(nlohmann::json((*layerInfo).info).dump());
auto [pkgInfo, err] = util::fromJSON<QSharedPointer<package::Info>>(rawData);
auto [pkgInfo, oldErr] = util::fromJSON<QSharedPointer<package::Info>>(rawData);
if (err) {
this->printer.printErr(
LINGLONG_ERR(err.code(), "failed to parse package::Info. " + err.message()).value());
return -1;
if (oldErr) {
auto err =
LINGLONG_ERR("failed to parse package::Info. " + oldErr.message(), oldErr.code()).value();
this->printer.printErr(err);
return err.code();
}
this->printer.printLayerInfo(pkgInfo);

View File

@ -30,7 +30,8 @@ utils::error::Result<Architecture> Architecture::parse(const QString &raw) noexc
try {
return Architecture(raw);
} catch (const std::exception &e) {
return LINGLONG_ERR(-1, e.what());
LINGLONG_TRACE("parse architecture");
return LINGLONG_ERR(e);
}
Architecture::Architecture(const QString &raw)

View File

@ -12,15 +12,14 @@ namespace linglong::package {
utils::error::Result<FuzzReference> FuzzReference::parse(const QString &raw) noexcept
{
LINGLONG_TRACE_MESSAGE("parse fuzz reference string");
LINGLONG_TRACE("parse fuzz reference string");
static QRegularExpression regexp(
R"(^(?:(?<channel>[^:]*):)?(?<id>[^\/]*)(?:\/(?<version>[^\/]*)(?:\/(?<architecture>[^\/]*))?)?$)");
auto matches = regexp.match(raw);
if (not(matches.isValid() and matches.hasMatch())) {
auto err = LINGLONG_ERR(-1, "regexp mismatched.");
return LINGLONG_EWRAP(err.value());
return LINGLONG_ERR("regexp mismatched.");
}
std::optional<QString> channel;
@ -29,14 +28,14 @@ utils::error::Result<FuzzReference> FuzzReference::parse(const QString &raw) noe
channel = std::nullopt;
}
auto id = matches.captured("id");
auto id = matches.captured("id"); // NOLINT
std::optional<Version> version;
auto versionStr = matches.captured("version");
if ((!versionStr.isEmpty()) && versionStr != "unknown") {
auto tmpVersion = Version::parse(versionStr);
if (!tmpVersion.has_value()) {
return LINGLONG_EWRAP(tmpVersion.error());
if (!tmpVersion) {
return LINGLONG_ERR(tmpVersion);
}
version = *tmpVersion;
}
@ -45,8 +44,8 @@ utils::error::Result<FuzzReference> FuzzReference::parse(const QString &raw) noe
auto architectureStr = matches.captured("architecture");
if ((!architectureStr.isEmpty()) && architectureStr != "unknown") {
auto tmpArchitecture = Architecture::parse(architectureStr);
if (!tmpArchitecture.has_value()) {
return LINGLONG_EWRAP(tmpArchitecture.error());
if (!tmpArchitecture) {
return LINGLONG_ERR(tmpArchitecture);
}
architecture = *tmpArchitecture;
}
@ -56,14 +55,14 @@ utils::error::Result<FuzzReference> FuzzReference::parse(const QString &raw) noe
utils::error::Result<FuzzReference>
FuzzReference::create(const std::optional<QString> &channel,
const QString &id,
const QString &id, // NOLINT
const std::optional<Version> &version,
const std::optional<Architecture> &arch) noexcept
try {
return FuzzReference(channel, id, version, arch);
} catch (const std::exception &e) {
auto err = LINGLONG_ERR(-1, e.what()).value();
return LINGLONG_EWRAP("invalid fuzz reference", err);
LINGLONG_TRACE("create fuzz reference");
return LINGLONG_ERR(e);
}
FuzzReference::FuzzReference(const std::optional<QString> &channel,

View File

@ -5,13 +5,14 @@
*/
#include "linglong/package/layer_dir.h"
#include "linglong/util/qserializer/json.h"
namespace linglong::package {
LayerDir::~LayerDir()
{
if(cleanup) {
if (cleanup) {
this->removeRecursively();
}
}
@ -23,10 +24,12 @@ void LayerDir::setCleanStatus(bool status)
utils::error::Result<QSharedPointer<Info>> LayerDir::info() const
{
const auto infoPath = QStringList { this->absolutePath(), "info.json"}.join(QDir::separator());
LINGLONG_TRACE("get layer info form dir");
const auto infoPath = QStringList{ this->absolutePath(), "info.json" }.join(QDir::separator());
auto [info, err] = util::fromJSON<QSharedPointer<Info>>(infoPath);
if (err) {
return LINGLONG_ERR(err.code(), "failed to parse info.json");
return LINGLONG_ERR(err.message(), err.code());
}
return info;
@ -34,16 +37,17 @@ utils::error::Result<QSharedPointer<Info>> LayerDir::info() const
utils::error::Result<QByteArray> LayerDir::rawInfo() const
{
const auto infoPath = QStringList { this->absolutePath(), "info.json"}.join(QDir::separator());
LINGLONG_TRACE("get raw layer info from dir");
const auto infoPath = QStringList{ this->absolutePath(), "info.json" }.join(QDir::separator());
QFile file(infoPath);
if (!file.open(QIODevice::ReadOnly)) {
return LINGLONG_ERR(-1, "failed to open info.json from layer dir");
return LINGLONG_ERR("open info.json from layer dir", file);
}
QByteArray rawData = file.readAll();
file.close();
return rawData;
}
}
} // namespace linglong::package

View File

@ -5,6 +5,7 @@
*/
#include "linglong/package/layer_file.h"
#include "linglong/package/layer_info.h"
#include <QFileInfo>
@ -33,13 +34,13 @@ LayerFile::~LayerFile()
}
utils::error::Result<QSharedPointer<LayerFile>> LayerFile::openLayer(const QString &path) noexcept
{
try {
QSharedPointer<LayerFile> layerFile(new LayerFile(path));
return layerFile;
} catch (const std::exception &e) {
return LINGLONG_ERR(-1, e.what());
}
try {
QSharedPointer<LayerFile> layerFile(new LayerFile(path));
return layerFile;
} catch (const std::exception &e) {
LINGLONG_TRACE("open layer");
return LINGLONG_ERR(e);
}
void LayerFile::setCleanStatus(bool status) noexcept
@ -49,27 +50,31 @@ void LayerFile::setCleanStatus(bool status) noexcept
utils::error::Result<layer::LayerInfo> LayerFile::layerFileInfo() noexcept
{
LINGLONG_TRACE("get layer file info");
auto ret = layerInfoSize();
if (!ret.has_value()) {
return LINGLONG_EWRAP("failed to get layer file size ", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
auto rawData = this->read(qint64(*ret));
auto layerInfo = fromJson(rawData);
if (!layerInfo.has_value()) {
return LINGLONG_EWRAP("failed to get layer info", layerInfo.error());
if (!layerInfo) {
return LINGLONG_ERR(layerInfo);
}
return layerInfo;
}
utils::error::Result<quint32> LayerFile::layerInfoSize()
{
LINGLONG_TRACE("get layer file info");
// read from position magicNumber.size() everytime
this->seek(magicNumber.size());
quint32 layerInfoSize;
quint32 layerInfoSize = 0;
this->read(reinterpret_cast<char *>(&layerInfoSize), sizeof(quint32));
return layerInfoSize;
@ -77,9 +82,11 @@ utils::error::Result<quint32> LayerFile::layerInfoSize()
utils::error::Result<quint32> LayerFile::layerOffset() noexcept
{
LINGLONG_TRACE("get layer offset");
auto size = layerInfoSize();
if (!size.has_value()) {
return LINGLONG_EWRAP("get LayerInfo size failed", size.error());
if (!size) {
return LINGLONG_ERR(size);
}
return magicNumber.size() + *size + sizeof(quint32);
@ -87,11 +94,12 @@ utils::error::Result<quint32> LayerFile::layerOffset() noexcept
utils::error::Result<void> LayerFile::saveTo(const QString &destination) noexcept
{
LINGLONG_TRACE(QString("save layer file to %1").arg(destination));
if (!this->copy(destination)) {
return LINGLONG_ERR(-1, QString("failed to save layer file to %1").arg(destination));
return LINGLONG_ERR("copy failed: " + this->errorString(), this->error());
}
return LINGLONG_OK;
}
} // namespace linglong::package
} // namespace linglong::package

View File

@ -18,28 +18,25 @@ namespace linglong::package {
using nlohmann::json;
utils::error::Result<layer::LayerInfo> fromJson(const QByteArray &rawData)
{
layer::LayerInfo layerInfo;
try {
layerInfo = json::parse(rawData).get<layer::LayerInfo>();
} catch (std::exception &e) {
return LINGLONG_ERR(-1, "failed to parse json value, invalid data");
}
try {
layer::LayerInfo layerInfo;
layerInfo = json::parse(rawData).get<layer::LayerInfo>();
return layerInfo;
} catch (std::exception &e) {
LINGLONG_TRACE("parse layer info from json");
return LINGLONG_ERR("json::parse", e);
}
utils::error::Result<QByteArray> toJson(layer::LayerInfo &layerInfo)
{
try {
QByteArray rawData;
json jsonValue = layerInfo;
try {
rawData = QByteArray::fromStdString(jsonValue.dump());
} catch (std::exception &e) {
return LINGLONG_ERR(-1, "failed to dump json value, invalid data");
}
rawData = QByteArray::fromStdString(jsonValue.dump());
return rawData;
} catch (std::exception &e) {
LINGLONG_TRACE("dump layer info to json");
return LINGLONG_ERR("dump", e);
}
} // namespace linglong::package
} // namespace linglong::package

View File

@ -15,8 +15,7 @@
namespace linglong::package {
LayerPackager::LayerPackager(const QString &workDir)
: workDir(
QStringList{ workDir, QUuid::createUuid().toString(QUuid::Id128) }.join("-"))
: workDir(QStringList{ workDir, QUuid::createUuid().toString(QUuid::Id128) }.join("-"))
{
util::ensureDir(this->workDir);
}
@ -29,6 +28,8 @@ LayerPackager::~LayerPackager()
utils::error::Result<QSharedPointer<LayerFile>>
LayerPackager::pack(const LayerDir &dir, const QString &layerFilePath) const
{
LINGLONG_TRACE("pack layer");
// compress data with erofs
const auto compressedFilePath =
QStringList{ this->workDir, "tmp.erofs" }.join(QDir::separator());
@ -37,7 +38,7 @@ LayerPackager::pack(const LayerDir &dir, const QString &layerFilePath) const
{ "-zlz4hc,9", compressedFilePath, dir.absolutePath() },
15 * 60 * 1000);
if (ret) {
return LINGLONG_ERR(ret.code(), "call mkfs.erofs failed" + ret.message());
return LINGLONG_ERR("mkfs.erofs: " + ret.message(), ret.code());
}
// generate LayerInfo
@ -45,22 +46,22 @@ LayerPackager::pack(const LayerDir &dir, const QString &layerFilePath) const
layerInfo.version = layerInfoVerison;
auto rawData = dir.rawInfo();
if (!rawData.has_value()) {
return LINGLONG_EWRAP("failed to get raw info data", rawData.error());
if (!rawData) {
return LINGLONG_ERR(rawData);
}
// rawData is not checked format
layerInfo.info = nlohmann::json::parse(*rawData);
auto layerInfoData = toJson(layerInfo);
if (!layerInfoData.has_value()) {
return LINGLONG_EWRAP("failed to convert LayerInfo to Json data", layerInfoData.error());
if (!layerInfoData) {
return LINGLONG_ERR(layerInfoData);
}
// write data, [magic number |LayerInfoSize | LayerInfo | compressed data ]
// open temprary layer file
QFile layer(layerFilePath);
if (!layer.open(QIODevice::WriteOnly | QIODevice::Append)) {
return LINGLONG_ERR(-1, "failed to open temporary file of layer");
return LINGLONG_ERR("open temporary layer file", layer);
}
// write magic number, in 40 bytes
layer.write(magicNumber);
@ -74,7 +75,7 @@ LayerPackager::pack(const LayerDir &dir, const QString &layerFilePath) const
layer.write(*layerInfoData);
QFile compressedFile(compressedFilePath);
if (!compressedFile.open(QIODevice::ReadOnly)) {
return LINGLONG_ERR(-1, "failed to open compressed data file of layer");
return LINGLONG_ERR("open compressed layer file", compressedFile);
}
// write compressedFile
@ -86,58 +87,48 @@ LayerPackager::pack(const LayerDir &dir, const QString &layerFilePath) const
qint64 sizeToRead = qMin(chunkSize, remainingSize);
uchar *compressedData = compressedFile.map(compressedFileOffset, sizeToRead);
if (!compressedData) {
layer.close();
compressedFile.close();
return LINGLONG_ERR(-1, "mapping compressed file error");
return LINGLONG_ERR("mapping compressed file", compressedFile);
}
auto ret = layer.write(reinterpret_cast<char *>(compressedData), sizeToRead);
if (ret < 0) {
compressedFile.unmap(compressedData);
layer.close();
compressedFile.close();
return LINGLONG_ERR(-1, "writing data to temporary layer file failed");
return LINGLONG_ERR("writing data to temporary layer file", layer);
}
compressedFile.unmap(compressedData);
remainingSize -= sizeToRead;
compressedFileOffset += sizeToRead;
}
layer.close();
compressedFile.close();
// it seems no error here, so i didn't check it
return LayerFile::openLayer(layerFilePath);
}
utils::error::Result<QSharedPointer<LayerDir>> LayerPackager::unpack(LayerFile &file,
const QString &destnation)
const QString &destnation)
{
LINGLONG_TRACE("unpack layer file");
auto unpackDir = QStringList{ this->workDir, "unpack" }.join(QDir::separator());
util::ensureDir(unpackDir);
QFileInfo fileInfo(file);
auto offset = file.layerOffset();
if (!offset.has_value()) {
return LINGLONG_EWRAP("failed to get layer offset", offset.error());
if (!offset) {
return LINGLONG_ERR(offset);
}
auto ret =
util::Exec("erofsfuse",
{ QString("--offset=%1").arg(*offset), fileInfo.absoluteFilePath(), unpackDir });
if (ret) {
return LINGLONG_ERR(ret.code(), "call erofsfuse failed: " + ret.message());
return LINGLONG_ERR("call erofsfuse failed: " + ret.message(), ret.code());
}
util::copyDir(unpackDir, destnation);
ret = util::Exec("umount", { unpackDir });
if (ret) {
return LINGLONG_ERR(ret.code(), "call umount failed: " + ret.message());
return LINGLONG_ERR("call umount failed: " + ret.message(), ret.code());
}
QSharedPointer<LayerDir> layerDir(new LayerDir(destnation));

View File

@ -31,7 +31,8 @@ utils::error::Result<Module> Module::parse(const QString &raw) noexcept
try {
return Module(raw);
} catch (const std::exception &e) {
return LINGLONG_ERR(-1, e.what());
LINGLONG_TRACE("parse module");
return LINGLONG_ERR(e);
}
Module::Module(const QString &raw)

View File

@ -14,15 +14,14 @@ namespace linglong::package {
utils::error::Result<Reference> Reference::parse(const QString &raw) noexcept
{
LINGLONG_TRACE_MESSAGE("parse reference string");
LINGLONG_TRACE("parse reference string");
static QRegularExpression referenceRegExp(
R"((?<channel>[^:]+):(?<id>[^\/]+)\/(?<version>[^\/]+)\/(?<architecture>[^\/]+))");
auto matches = referenceRegExp.match(raw);
if (not(matches.isValid() and matches.hasMatch())) {
auto err = LINGLONG_ERR(-1, "regexp mismatched.").value();
return LINGLONG_EWRAP(err);
return LINGLONG_ERR("regexp mismatched.", -1);
}
auto channel = matches.captured("channel");
@ -31,18 +30,18 @@ utils::error::Result<Reference> Reference::parse(const QString &raw) noexcept
auto architectureStr = matches.captured("architecture");
auto version = Version::parse(versionStr);
if (!version.has_value()) {
return LINGLONG_EWRAP(version.error());
if (!version) {
return LINGLONG_ERR(version);
}
auto arch = Architecture::parse(architectureStr);
if (!arch.has_value()) {
return LINGLONG_EWRAP(arch.error());
if (!arch) {
return LINGLONG_ERR(arch);
}
auto reference = create(channel, id, *version, *arch);
if (!reference.has_value()) {
return LINGLONG_EWRAP(reference.error());
if (!reference) {
return LINGLONG_ERR(reference);
}
return *reference;
@ -55,8 +54,8 @@ utils::error::Result<Reference> Reference::create(const QString &channel,
try {
return Reference(channel, id, version, arch);
} catch (const std::exception &e) {
auto err = LINGLONG_ERR(-1, e.what()).value();
return LINGLONG_EWRAP("invalid reference", err);
LINGLONG_TRACE("create reference");
return LINGLONG_ERR("invalid reference", e);
}
Reference::Reference(const QString &channel,

View File

@ -97,7 +97,8 @@ utils::error::Result<Version> Version::parse(const QString &raw) noexcept
try {
return Version(raw);
} catch (const std::exception &e) {
return LINGLONG_ERR(-1, e.what());
LINGLONG_TRACE("parse version");
return LINGLONG_ERR(e);
}
Version::Version(const QString &raw)

View File

@ -12,8 +12,8 @@ utils::error::Result<VersionRange> VersionRange::parse(const QString &raw) noexc
try {
return VersionRange(raw);
} catch (const std::exception &e) {
auto err = LINGLONG_ERR(-1, e.what()).value();
return LINGLONG_EWRAP("invalid version range", err);
LINGLONG_TRACE("parse version range");
return LINGLONG_ERR(e);
}
VersionRange::VersionRange(const QString &raw)

View File

@ -1102,7 +1102,7 @@ auto PackageManager::Uninstall(const UninstallParamOption &paramOption) -> Reply
QString strErr = "";
// 应从安装数据库获取应用所属仓库信息 to do fix
QVector<QString> qrepoList;
auto ret = repoMan.getRemoteRepoList(kLocalRepoPath, qrepoList);
auto ret = repoMan.getRemoteRepoList(qrepoList);
if (!ret.has_value()) {
qCritical() << strErr;
reply.code = STATUS_CODE(kPkgUninstallFailed);

View File

@ -18,28 +18,34 @@ using namespace config;
using namespace utils::error;
Result<ConfigV1> loadConfig(const QString &file) noexcept
try {
auto ifs = std::ifstream(file.toLocal8Bit());
if (!ifs.is_open()) {
return LINGLONG_ERR(-1, QString("open file at path %1 failed").arg(file));
}
{
LINGLONG_TRACE(QString("load config from %1").arg(file));
auto config = ytj::to_json(YAML::Load(ifs)).get<ConfigV1>();
if (config.version != 1) {
return LINGLONG_ERR(-1, QString("wrong configuration file version %1").arg(config.version));
}
try {
auto ifs = std::ifstream(file.toLocal8Bit());
if (!ifs.is_open()) {
return LINGLONG_ERR("open failed");
}
if (config.repos.find(config.defaultRepo) == config.repos.end()) {
return LINGLONG_ERR(-1, QString("default repo not found in repos"));
}
auto config = ytj::to_json(YAML::Load(ifs)).get<ConfigV1>();
if (config.version != 1) {
return LINGLONG_ERR(QString("wrong configuration file version %1").arg(config.version));
}
return config;
} catch (const std::exception &e) {
return LINGLONG_ERR(-1, QString("load config from %1: exception: %2").arg(file).arg(e.what()));
if (config.repos.find(config.defaultRepo) == config.repos.end()) {
return LINGLONG_ERR(QString("default repo not found in repos"));
}
return config;
} catch (const std::exception &e) {
return LINGLONG_ERR(e);
}
}
Result<ConfigV1> loadConfig(const QStringList &files) noexcept
{
LINGLONG_TRACE(QString("load config from %1").arg(files.join(" ")));
for (const auto &file : files) {
auto config = loadConfig(file);
if (!config.has_value()) {
@ -51,26 +57,30 @@ Result<ConfigV1> loadConfig(const QStringList &files) noexcept
return config;
}
return LINGLONG_ERR(-1, "failed to load config file from file list");
return LINGLONG_ERR("all failed");
}
Result<void> saveConfig(const ConfigV1 &cfg, const QString &path) noexcept
try {
if (cfg.repos.find(cfg.defaultRepo) == cfg.repos.end()) {
return LINGLONG_ERR(-1, QString("default repo not found in repos"));
{
LINGLONG_TRACE(QString("save config to %1").arg(path));
try {
if (cfg.repos.find(cfg.defaultRepo) == cfg.repos.end()) {
return LINGLONG_ERR("default repo not found in repos");
}
auto ofs = std::ofstream(path.toLocal8Bit());
if (!ofs.is_open()) {
return LINGLONG_ERR("open failed");
}
auto node = ytj::to_yaml(cfg);
ofs << node;
return LINGLONG_OK;
} catch (const std::exception &e) {
return LINGLONG_ERR(e);
}
auto ofs = std::ofstream(path.toLocal8Bit());
if (!ofs.is_open()) {
return LINGLONG_ERR(-1, QString("open file at path %1 failed").arg(path));
}
auto node = ytj::to_yaml(cfg);
ofs << node;
return LINGLONG_OK;
} catch (const std::exception &e) {
return LINGLONG_ERR(-1, QString("save config to %1: exception: %1").arg(path).arg(e.what()));
}
} // namespace linglong::repo

View File

@ -91,15 +91,15 @@ config::ConfigV1 OSTreeRepo::getConfig() const noexcept
linglong::utils::error::Result<void> OSTreeRepo::setConfig(const config::ConfigV1 &cfg) noexcept
{
LINGLONG_TRACE_MESSAGE("update config");
LINGLONG_TRACE("set config");
if (cfg == this->cfg) {
return LINGLONG_OK;
}
auto res = saveConfig(cfg, this->repoRootPath + "/config.yaml");
if (!res.has_value()) {
return LINGLONG_EWRAP(res.error());
if (!res) {
return LINGLONG_ERR(res);
}
g_autoptr(GKeyFile) cfgGKeyFile = ostree_repo_copy_config(this->repoPtr.get());
@ -125,8 +125,7 @@ linglong::utils::error::Result<void> OSTreeRepo::setConfig(const config::ConfigV
g_autoptr(GError) gErr = nullptr;
if (!ostree_repo_write_config(this->repoPtr.get(), cfgGKeyFile, &gErr)) {
auto err = LINGLONG_GERR(gErr);
return LINGLONG_EWRAP(err.value());
return LINGLONG_ERR("ostree_repo_write_config", gErr);
}
this->repoClient.setEndpoint(QString::fromStdString(cfg.repos.at(cfg.defaultRepo)));
@ -143,9 +142,11 @@ linglong::utils::error::Result<void> OSTreeRepo::setConfig(const config::ConfigV
linglong::utils::error::Result<void> OSTreeRepo::importDirectory(const package::Ref &ref,
const QString &path)
{
LINGLONG_TRACE("import directory");
auto ret = commit(DIR, ref, path, package::Ref(""));
if (!ret.has_value()) {
return LINGLONG_EWRAP("call commit in importDirectory failed.", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
return LINGLONG_OK;
@ -154,9 +155,11 @@ linglong::utils::error::Result<void> OSTreeRepo::importDirectory(const package::
linglong::utils::error::Result<void> OSTreeRepo::importRef(const package::Ref &oldRef,
const package::Ref &newRef)
{
LINGLONG_TRACE("import ref");
auto ret = commit(REF, newRef, "", oldRef);
if (!ret.has_value()) {
return LINGLONG_EWRAP("call commit in importRef failed.", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
return LINGLONG_OK;
@ -167,9 +170,11 @@ linglong::utils::error::Result<void> OSTreeRepo::commit(Tree treeType,
const QString &path,
const package::Ref &oldRef)
{
LINGLONG_TRACE("commit");
g_autoptr(GError) gErr = nullptr;
if (!ostree_repo_prepare_transaction(repoPtr.get(), NULL, NULL, &gErr))
return LINGLONG_ERR(gErr->code, gErr->message);
return LINGLONG_ERR("ostree_repo_prepare_transaction", gErr);
g_autoptr(OstreeMutableTree) mtree = ostree_mutable_tree_new();
@ -191,7 +196,7 @@ linglong::utils::error::Result<void> OSTreeRepo::commit(Tree treeType,
NULL,
nullptr,
&gErr))
return LINGLONG_ERR(gErr->code, gErr->message);
return LINGLONG_ERR("ostree_repo_read_commit", gErr);
break;
case TAR:
qWarning() << "not impelement now.";
@ -203,11 +208,11 @@ linglong::utils::error::Result<void> OSTreeRepo::commit(Tree treeType,
modifier,
nullptr,
&gErr))
return LINGLONG_ERR(gErr->code, gErr->message);
return LINGLONG_ERR("ostree_repo_write_directory_to_mtree", gErr);
g_autoptr(OstreeRepoFile) repo_file = nullptr;
if (!ostree_repo_write_mtree(repoPtr.get(), mtree, (GFile **)&repo_file, nullptr, &gErr))
return LINGLONG_ERR(gErr->code, gErr->message);
return LINGLONG_ERR("ostree_repo_write_mtree", gErr);
g_autofree char *out_commit = nullptr;
if (!ostree_repo_write_commit(repoPtr.get(),
@ -219,7 +224,7 @@ linglong::utils::error::Result<void> OSTreeRepo::commit(Tree treeType,
&out_commit,
NULL,
&gErr)) {
return LINGLONG_ERR(gErr->code, gErr->message);
return LINGLONG_ERR("ostree_repo_write_commit", gErr);
}
ostree_repo_transaction_set_ref(repoPtr.get(),
NULL,
@ -227,17 +232,20 @@ linglong::utils::error::Result<void> OSTreeRepo::commit(Tree treeType,
out_commit);
ostree_repo_commit_transaction(repoPtr.get(), NULL, NULL, &gErr);
if (gErr) {
return LINGLONG_ERR(gErr->code, gErr->message);
return LINGLONG_ERR("ostree_repo_commit_transaction", gErr);
}
return LINGLONG_OK;
}
linglong::utils::error::Result<void> OSTreeRepo::push(const package::Ref &ref)
{
LINGLONG_TRACE("push");
auto ret = getToken();
if (!ret.has_value()) {
return LINGLONG_EWRAP("get token failed", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
remoteToken = *ret;
QSharedPointer<UploadRequest> uploadReq(new UploadRequest);
@ -246,15 +254,15 @@ linglong::utils::error::Result<void> OSTreeRepo::push(const package::Ref &ref)
// FIXME: no need,use /v1/meta/:id
auto repoInfo = getRepoInfo(remoteRepoName);
if (!repoInfo.has_value()) {
return LINGLONG_EWRAP("get repo info", repoInfo.error());
if (!repoInfo) {
return LINGLONG_ERR(repoInfo);
}
QString taskID;
{
auto ret = newUploadTask(uploadReq);
if (!ret.has_value()) {
return LINGLONG_EWRAP("call newUploadTask failed", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
taskID = *ret;
}
@ -263,32 +271,28 @@ linglong::utils::error::Result<void> OSTreeRepo::push(const package::Ref &ref)
QString filePath;
{
auto ret = compressOstreeData(ref);
if (!ret.has_value()) {
return LINGLONG_EWRAP("compress ostree data failed", ret.error());
}
if (ret.has_value()) {
filePath = *ret;
if (!ret) {
return LINGLONG_ERR(ret);
}
filePath = *ret;
}
{
auto ret = doUploadTask(taskID, filePath);
if (!ret.has_value()) {
return LINGLONG_EWRAP("call doUploadTask failed", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
}
{
auto ret = getUploadStatus(taskID);
if (!ret.has_value()) {
if (!ret) {
cleanUploadTask(ref, filePath);
return ret;
}
}
auto cleanRet = cleanUploadTask(ref, filePath);
if (!cleanRet.has_value()) {
return LINGLONG_EWRAP("call cleanUploadTask failed", ret.error());
}
cleanUploadTask(ref, filePath);
return LINGLONG_OK;
}
@ -487,14 +491,9 @@ void OSTreeRepo::progress_changed(OstreeAsyncProgress *progress, gpointer user_d
linglong::utils::error::Result<void> OSTreeRepo::pull(package::Ref &ref, bool /*force*/)
{
// FIXME(black_desk): should implement force
LINGLONG_TRACE(QString("pull %1 from %2").arg(ref.toLocalString(), remoteRepoName));
// FIXME(black_desk): When a error raised from libcurl, libostree will treat
// it like a fail, but not a temporary error, which make the default retry
// (5 times) useless. So we now have to retry some times to overcome this
// problem.
// As we have try the current base will fail so many times during
// transferring. So we decide to retry 30 times.
// FIXME(black_desk): should implement force
g_autoptr(GError) gErr = nullptr;
auto str = ref.toOSTreeRefLocalString().toLocal8Bit();
char *refs_to_fetch[2] = { str.data(), nullptr };
@ -509,10 +508,9 @@ linglong::utils::error::Result<void> OSTreeRepo::pull(package::Ref &ref, bool /*
ostree_async_progress_finish(progress);
if (gErr) {
qWarning() << gErr->code << gErr->message;
return LINGLONG_ERR(
-1,
QString("pull branch %1 from repo %2 failed!").arg(ref.toLocalString(), remoteRepoName));
return LINGLONG_ERR("ostree_repo_pull", gErr);
}
return LINGLONG_OK;
}
@ -537,12 +535,15 @@ linglong::utils::error::Result<void> OSTreeRepo::listRemoteRefs()
linglong::utils::error::Result<QList<package::Ref>> OSTreeRepo::listLocalRefs() noexcept
{
LINGLONG_TRACE("list local refspecs");
g_autoptr(GHashTable) table = NULL;
g_autoptr(GError) gErr = NULL;
ostree_repo_list_refs(repoPtr.get(), NULL, &table, NULL, &gErr);
if (gErr) {
return LINGLONG_GERR(gErr);
return LINGLONG_ERR("ostree_repo_list_refs", gErr);
}
auto ordered_keys = g_hash_table_get_keys(table);
QList<package::Ref> result;
for (auto iter = ordered_keys; iter; iter = iter->next) {
@ -553,12 +554,14 @@ linglong::utils::error::Result<QList<package::Ref>> OSTreeRepo::listLocalRefs()
linglong::utils::error::Result<void> OSTreeRepo::pullAll(const package::Ref &ref, bool /*force*/)
{
LINGLONG_TRACE(QString("pull all %1").arg(ref.toLocalString()));
// FIXME(black-desk): pullAll should not belong to this class.
auto refs = package::Ref(
QStringList{ ref.channel, ref.appId, ref.version, ref.arch, "runtime" }.join("/"));
auto ret = pull(refs, false);
if (!ret.has_value()) {
return LINGLONG_ERR(ret.error().code(), ret.error().message());
if (!ret) {
return LINGLONG_ERR(ret);
}
// FIXME: some old package have no devel, ignore error for now.
@ -566,7 +569,7 @@ linglong::utils::error::Result<void> OSTreeRepo::pullAll(const package::Ref &ref
package::Ref(QStringList{ ref.channel, ref.appId, ref.version, ref.arch, "devel" }.join("/"));
ret = pull(refs, false);
if (!ret.has_value()) {
qWarning() << ret.error().message();
qWarning() << ret.error();
}
return LINGLONG_OK;
@ -576,8 +579,7 @@ linglong::utils::error::Result<void> OSTreeRepo::checkout(const package::Ref &re
const QString &subPath,
const QString &target)
{
LINGLONG_TRACE_MESSAGE(
QString("checkout %1 to %2").arg(ref.toOSTreeRefLocalString()).arg(target));
LINGLONG_TRACE(QString("checkout %1 to %2").arg(ref.toOSTreeRefLocalString()).arg(target));
g_autoptr(GError) gErr = NULL;
OstreeRepoCheckoutAtOptions checkout_options = {};
@ -591,14 +593,13 @@ linglong::utils::error::Result<void> OSTreeRepo::checkout(const package::Ref &re
qInfo() << "print ref string for checkout:" << ref.toOSTreeRefLocalString();
auto rev = resolveRev(ref.toOSTreeRefLocalString());
if (!rev.has_value()) {
return LINGLONG_EWRAP(rev.error());
if (!rev) {
return LINGLONG_ERR(rev);
}
// FIXME: at least the "layers" directory should be ensured when OSTreeRepo is constructed.
if (!util::ensureDir(target)) {
auto err = LINGLONG_ERR(-1, QString("failed to mkdir %1").arg(target));
return LINGLONG_EWRAP(err.value());
return LINGLONG_ERR(QString("mkdir %1").arg(target), -1);
}
ostree_repo_checkout_at(repoPtr.get(),
&checkout_options,
@ -608,9 +609,9 @@ linglong::utils::error::Result<void> OSTreeRepo::checkout(const package::Ref &re
NULL,
&gErr);
if (gErr) {
auto err = LINGLONG_ERR(gErr->code, gErr->message);
return LINGLONG_EWRAP(err.value());
return LINGLONG_ERR("ostree_repo_checkout_at", gErr);
}
return LINGLONG_OK;
}
@ -618,11 +619,13 @@ linglong::utils::error::Result<void> OSTreeRepo::checkoutAll(const package::Ref
const QString &subPath,
const QString &target)
{
LINGLONG_TRACE("checkout all");
package::Ref reference = ref;
reference.module = "runtime";
auto ret = checkout(reference, subPath, target);
if (!ret.has_value()) {
return LINGLONG_EWRAP("checkout all modules", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
reference.module = "devel";
@ -642,17 +645,23 @@ QString OSTreeRepo::rootOfLayer(const package::Ref &ref)
linglong::utils::error::Result<QString> OSTreeRepo::remoteShowUrl(const QString &repoName)
{
LINGLONG_TRACE("show remote url");
g_autofree char *out_url = nullptr;
g_autoptr(GError) gErr = NULL;
ostree_repo_remote_get_url(repoPtr.get(), repoName.toLocal8Bit(), &out_url, &gErr);
if (gErr) {
return LINGLONG_ERR(gErr->code, gErr->message);
return LINGLONG_ERR("ostree_repo_remote_get_url", gErr);
}
return QString::fromUtf8(out_url);
}
linglong::utils::error::Result<package::Ref> OSTreeRepo::localLatestRef(const package::Ref &ref)
{
// FIXME: we should NOT call ostree binary
LINGLONG_TRACE(QString("get local latest %1").arg(ref.toLocalString()));
QString defaultChannel = "main";
QString latestVer = "latest";
QString args = QString("ostree refs --repo=%1 | grep %2 | grep %3 | grep %4")
@ -675,7 +684,7 @@ linglong::utils::error::Result<package::Ref> OSTreeRepo::localLatestRef(const pa
err = util::Exec("sh", { "-c", args }, -1, output);
if (!output || output->isEmpty()) {
return LINGLONG_ERR(-1, QString("%1 is not exist in local repo").arg(ref.appId));
return LINGLONG_ERR("not exist.", -1);
}
}
@ -689,51 +698,28 @@ linglong::utils::error::Result<package::Ref> OSTreeRepo::localLatestRef(const pa
}
return package::Ref("", defaultChannel, ref.appId, latestVer, ref.arch, ref.module);
// void g_hash_table_iter_init(GHashTableIter * iter, GHashTable * hash_table);
// gboolean g_hash_table_iter_next(GHashTableIter * iter, gpointer * key, gpointer * value);
// GHashTable **out_all_refs = nullptr;
// g_autoptr(GError) gErr = nullptr;
// GHashTableIter *iter = nullptr;
// gpointer key, value;
// ostree_repo_list_collection_refs(repoPtr,
// NULL,
// out_all_refs,
// OSTREE_REPO_LIST_REFS_EXT_NONE,
// NULL,
// &gErr);
// if (gErr) {
// return LINGLONG_ERR(gErr->code, gErr->message);
// }
// g_hash_table_iter_init(iter, *out_all_refs);
// while (g_hash_table_iter_next(iter, &key, &value)) {
// }
}
linglong::utils::error::Result<package::Ref> OSTreeRepo::remoteLatestRef(const package::Ref &ref)
{
LINGLONG_TRACE(QString("get remote latest %1").arg(ref.toLocalString()));
QString latestVer = "unknown";
package::Ref queryRef(remoteRepoName, "main", ref.appId, ref.version, ref.arch, "");
auto ret = repoClient.QueryApps(queryRef);
if (!ret.has_value() || (*ret).isEmpty()) {
qWarning() << "query remote app with channel main failed, fallback to channel linglong."
<< queryRef.toSpecString();
if (!ret || (*ret).isEmpty()) {
ret = LINGLONG_ERR("use channel main", ret);
qWarning() << ret.error();
qWarning() << "fallback to channel linglong";
queryRef = package::Ref(remoteRepoName, "linglong", ref.appId, ref.version, ref.arch, "");
ret = repoClient.QueryApps(queryRef);
if (!ret.has_value()) {
qCritical() << "query remote app with channel linglong failed."
<< queryRef.toSpecString();
return LINGLONG_EWRAP(
QString("query remote app with channel linglong failed").arg(queryRef.toSpecString()),
ret.error());
if (!ret) {
return LINGLONG_ERR("use channel linglong", ret);
}
if (ret->isEmpty()) {
return LINGLONG_ERR(
-1,
QString("%1 is not exist in remote repo").arg(queryRef.toSpecString()));
return LINGLONG_ERR("not found", -1);
}
}
@ -758,19 +744,23 @@ linglong::utils::error::Result<package::Ref> OSTreeRepo::remoteLatestRef(const p
utils::error::Result<package::Ref> OSTreeRepo::latestOfRef(const QString &appId,
const QString &appVersion)
{
LINGLONG_TRACE(QString("get local latest %1").arg(appId));
package::Ref ref(appId + "/" + appVersion + "/" + util::hostArch());
QDir appRoot(repoRootPath + "/layers" + "/" + appId);
// TODO(wurongjie) 应该弃用latest
// found latest
// FIXME: DO NOT use "latest"
if (appRoot.exists("latest")) {
ref.version = "latest";
return ref;
}
QString version;
if (!appVersion.isEmpty() && appVersion != "latest") {
version = appVersion;
}
QStringList verDirs;
for (auto dir : appRoot.entryList(QDir::NoDotAndDotDot | QDir::Dirs)) {
if (version.isEmpty()) {
@ -780,8 +770,9 @@ utils::error::Result<package::Ref> OSTreeRepo::latestOfRef(const QString &appId,
}
}
if (verDirs.empty()) {
return LINGLONG_ERR(-1, "no version of ref found");
return LINGLONG_ERR("no version found", -1);
}
version = verDirs.value(0);
for (auto item : verDirs) {
linglong::util::AppVersion versionIter(item);
@ -791,12 +782,14 @@ utils::error::Result<package::Ref> OSTreeRepo::latestOfRef(const QString &appId,
}
}
ref.version = version;
qDebug() << "available version" << version << appRoot << verDirs;
qDebug() << "available versions" << version << appRoot << verDirs;
return ref;
}
utils::error::Result<QString> OSTreeRepo::compressOstreeData(const package::Ref &ref)
{
LINGLONG_TRACE(QString("compress %1").arg(ref.toSpecString()));
// check out ostree data
// Fixme: use /tmp
const auto savePath =
@ -805,9 +798,10 @@ utils::error::Result<QString> OSTreeRepo::compressOstreeData(const package::Ref
qInfo() << "print save path:" << savePath;
auto ret = checkout(ref, "", savePath);
if (!ret.has_value()) {
return LINGLONG_ERR(-1, QString("checkout %1 to %2 failed").arg(ref.appId).arg(savePath));
if (!ret) {
return LINGLONG_ERR(QString("checkout to %2").arg(savePath), ret);
}
// compress data
QStringList args;
const QString fileName = QString("%1.tgz").arg(ref.appId);
@ -825,127 +819,24 @@ utils::error::Result<QString> OSTreeRepo::compressOstreeData(const package::Ref
return { filePath };
}
/*
* ostree
*
* @param repoPath:
* @param vec:
* @param err:
*
* @return bool: true: false:
*/
linglong::utils::error::Result<void> OSTreeRepo::getRemoteRepoList(const QString &repoPath,
QVector<QString> &vec)
linglong::utils::error::Result<void> OSTreeRepo::getRemoteRepoList(QVector<QString> &vec)
{
char info[MAX_ERRINFO_BUFSIZE] = { '\0' };
if (repoPath.isEmpty()) {
snprintf(info, MAX_ERRINFO_BUFSIZE, "%s, function:%s param err", __FILE__, __func__);
// err = info;
return LINGLONG_ERR(-1, QString(QLatin1String(info)));
}
// 校验本地仓库是否创建
if (!repoPtr || repoRootPath != repoPath) {
snprintf(info,
MAX_ERRINFO_BUFSIZE,
"%s, function:%s repo has not been created",
__FILE__,
__func__);
// err = info;
return LINGLONG_ERR(-1, QString(QLatin1String(info)));
}
LINGLONG_TRACE("get remote repos");
g_auto(GStrv) res = nullptr;
if (repoPtr) {
res = ostree_repo_remote_list(repoPtr.get(), nullptr);
res = ostree_repo_remote_list(repoPtr.get(), nullptr);
if (res == nullptr) {
return LINGLONG_ERR("no remote repository found", -1);
}
if (res != nullptr) {
for (int i = 0; res[i] != nullptr; i++) {
// vec.push_back(res[i]);
vec.append(QLatin1String(res[i]));
}
} else {
snprintf(info,
MAX_ERRINFO_BUFSIZE,
"%s, function:%s no remote repo found",
__FILE__,
__func__);
// err = info;
return LINGLONG_ERR(-1, QString(QLatin1String(info)));
for (int i = 0; res[i] != nullptr; i++) {
vec.push_back(QString::fromUtf8(res[i]));
}
return LINGLONG_OK;
}
/*
* refs
*
* @param repoPath:
* @param remoteName:
* @param outRefs: (key:refs, value:commit)
* @param err:
*
* @return bool: true: false:
*/
bool OSTreeRepo::getRemoteRefs(const QString &repoPath,
const QString &remoteName,
QMap<QString, QString> &outRefs,
QString &err)
{
char info[MAX_ERRINFO_BUFSIZE] = { '\0' };
if (remoteName.isEmpty()) {
// fprintf(stdout, "getRemoteRefs param err\n");
qInfo() << "getRemoteRefs param err";
snprintf(info, MAX_ERRINFO_BUFSIZE, "%s, function:%s param err", __FILE__, __func__);
err = info;
return false;
}
if (!repoPtr || repoRootPath != repoPath) {
snprintf(info,
MAX_ERRINFO_BUFSIZE,
"%s, function:%s repo has not been created",
__FILE__,
__func__);
err = info;
return false;
}
const std::string remoteNameTmp = remoteName.toStdString();
g_autoptr(GBytes) summaryBytes = nullptr;
g_autoptr(GBytes) summarySigBytes = nullptr;
g_autoptr(GCancellable) cancellable = nullptr;
g_autoptr(GError) error = nullptr;
bool ret = fetchRemoteSummary(repoPtr.get(),
remoteNameTmp.c_str(),
&summaryBytes,
&summarySigBytes,
cancellable,
&error);
if (!ret) {
if (err != nullptr) {
snprintf(info,
MAX_ERRINFO_BUFSIZE,
"%s, function:%s err:%s",
__FILE__,
__func__,
error->message);
err = info;
} else {
err = "getRemoteRefs remote repo err";
}
return false;
}
g_autoptr(GVariant) summary = g_variant_ref_sink(
g_variant_new_from_bytes(OSTREE_SUMMARY_GVARIANT_FORMAT, summaryBytes, FALSE));
// std::map 转 QMap
std::map<std::string, std::string> outRet;
getPkgRefsBySummary(summary, outRet);
for (auto iter = outRet.begin(); iter != outRet.end(); ++iter) {
outRefs.insert(QString::fromStdString(iter->first), QString::fromStdString(iter->second));
}
return true;
}
/*
* ostree pull
*
@ -960,10 +851,12 @@ linglong::utils::error::Result<void> OSTreeRepo::repoPullbyCmd(const QString &de
const QString &remoteName,
const QString &ref)
{
LINGLONG_TRACE("pull");
// 创建临时仓库
auto tmpPath = createTmpRepo(destPath + "/repo");
if (!tmpPath.has_value()) {
return LINGLONG_ERR(-1, "create tmp repo err");
if (!tmpPath) {
return LINGLONG_ERR(tmpPath);
}
g_autoptr(GError) gErr = nullptr;
@ -980,19 +873,19 @@ linglong::utils::error::Result<void> OSTreeRepo::repoPullbyCmd(const QString &de
g_variant_builder_add(&builder, "{sv}", "http2", g_variant_new_boolean(false));
g_variant_builder_add(&builder, "{sv}", "gpg-verify", g_variant_new_boolean(false));
options = g_variant_ref_sink(g_variant_builder_end(&builder));
if (ostree_repo_open(tmpRepo, NULL, &gErr)) {
ostree_repo_remote_add(tmpRepo,
remoteName.toStdString().c_str(),
(remoteEndpoint + "/repos/" + remoteName).toStdString().c_str(),
options,
NULL,
&gErr);
if (gErr) {
return LINGLONG_ERR(gErr->code, gErr->message);
}
ostree_repo_open(tmpRepo, NULL, &gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("ostree_repo_open", gErr);
}
if (gErr) {
return LINGLONG_ERR(gErr->code, gErr->message);
ostree_repo_remote_add(tmpRepo,
remoteName.toStdString().c_str(),
(remoteEndpoint + "/repos/" + remoteName).toStdString().c_str(),
options,
NULL,
&gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("ostree_repo_remote_add", gErr);
}
ostree_repo_pull(tmpRepo,
@ -1002,17 +895,19 @@ linglong::utils::error::Result<void> OSTreeRepo::repoPullbyCmd(const QString &de
NULL,
NULL,
&gErr);
if (gErr) {
return LINGLONG_ERR(gErr->code, gErr->message);
if (gErr != nullptr) {
return LINGLONG_ERR("ostree_repo_pull", gErr);
}
qInfo() << "repoPullbyCmd pull success";
auto path = destPath + "/repo";
auto dest_repo_path = g_file_new_for_path(path.toStdString().c_str());
g_autoptr(OstreeRepo) repoDest = ostree_repo_new(dest_repo_path);
if (!ostree_repo_open(repoDest, NULL, &gErr)) {
return LINGLONG_ERR(gErr->code, gErr->message);
ostree_repo_open(repoDest, NULL, &gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("ostree_repo_open", gErr);
}
g_autofree auto base_url = g_strconcat("file://", tmpPath->toStdString().c_str(), NULL);
builder = {};
options = NULL;
@ -1025,7 +920,7 @@ linglong::utils::error::Result<void> OSTreeRepo::repoPullbyCmd(const QString &de
g_variant_builder_add(&builder,
"{s@v}",
"disable-static-deltas",
g_variant_new_variant(g_variant_new_boolean(true)));
g_variant_new_variant(g_variant_new_boolean(TRUE)));
g_variant_builder_add(&builder,
"{s@v}",
"disable-sign-verify",
@ -1038,9 +933,10 @@ linglong::utils::error::Result<void> OSTreeRepo::repoPullbyCmd(const QString &de
options = g_variant_ref_sink(g_variant_builder_end(&builder));
ostree_repo_pull_with_options(repoDest, (char *)base_url, options, NULL, NULL, &gErr);
if (gErr) {
return LINGLONG_ERR(gErr->code, gErr->message);
if (gErr != nullptr) {
return LINGLONG_ERR("ostree_repo_pull_with_options", gErr);
}
// 删除临时仓库
QString tmpRepoDir = (*tmpPath).left((*tmpPath).length() - QString("/repoTmp").length());
qInfo() << "delete tmp repo path:" << tmpRepoDir;
@ -1061,8 +957,10 @@ linglong::utils::error::Result<void> OSTreeRepo::repoPullbyCmd(const QString &de
linglong::utils::error::Result<void> OSTreeRepo::repoDeleteDatabyRef(const QString &repoPath,
const QString &ref)
{
LINGLONG_TRACE(QString("delete %1").arg(ref));
if (repoPath.isEmpty() || ref.isEmpty()) {
return LINGLONG_ERR(-1, "repoDeleteDatabyRef param error");
return LINGLONG_ERR("repoDeleteDatabyRef param error");
}
g_autoptr(GError) error = nullptr;
@ -1073,7 +971,7 @@ linglong::utils::error::Result<void> OSTreeRepo::repoDeleteDatabyRef(const QStri
nullptr,
nullptr,
&error)) {
return LINGLONG_ERR(-1, "repoDeleteDatabyRef: " + QString(QLatin1String(error->message)));
return LINGLONG_ERR("repoDeleteDatabyRef: " + QString(QLatin1String(error->message)));
}
qInfo() << "repoDeleteDatabyRef delete " << ref << " success";
@ -1082,17 +980,16 @@ linglong::utils::error::Result<void> OSTreeRepo::repoDeleteDatabyRef(const QStri
gint objectsPruned;
guint64 objsizeTotal;
g_autofree char *formattedFreedSize = NULL;
if (!ostree_repo_prune(repoPtr.get(),
OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY,
0,
&objectsTotal,
&objectsPruned,
&objsizeTotal,
nullptr,
&error)) {
return LINGLONG_ERR(-1,
"repoDeleteDatabyRef pruning repo failed:"
+ QString(QLatin1String(error->message)));
ostree_repo_prune(repoPtr.get(),
OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY,
0,
&objectsTotal,
&objectsPruned,
&objsizeTotal,
nullptr,
&error);
if (error != nullptr) {
return LINGLONG_ERR("ostree_repo_prune", error);
}
formattedFreedSize = g_format_size_full(objsizeTotal, (GFormatSizeFlags)0);
@ -1224,6 +1121,8 @@ void OSTreeRepo::getPkgRefsBySummary(GVariant *summary, std::map<std::string, st
*/
linglong::utils::error::Result<QString> OSTreeRepo::createTmpRepo(const QString &parentRepo)
{
LINGLONG_TRACE(QString("create temporary repo for %1").arg(parentRepo));
QString baseDir = linglong::util::getLinglongRootPath() + "/.cache";
linglong::util::createDir(baseDir);
QTemporaryDir dir(baseDir + "/linglong-cache-XXXXXX");
@ -1241,40 +1140,19 @@ linglong::utils::error::Result<QString> OSTreeRepo::createTmpRepo(const QString
g_autoptr(OstreeRepo) tmpRepo = ostree_repo_new(file);
g_autoptr(GError) gErr = nullptr;
ostree_repo_create(tmpRepo, OSTREE_REPO_MODE_BARE_USER_ONLY, NULL, &gErr);
if (gErr) {
return LINGLONG_ERR(-1, QString("init repoTmp failed: %1").arg(gErr->message));
if (gErr != nullptr) {
return LINGLONG_ERR("ostree_repo_create", gErr);
}
// if (!ostree_repo_open(tmpRepo, nullptr, &gErr))
// return LINGLONG_ERR(gErr->code, gErr->message);
g_autoptr(GKeyFile) config = ostree_repo_copy_config(tmpRepo);
if (config == nullptr) {
return LINGLONG_ERR(-1, "failed to get repo config");
}
g_key_file_set_string(config, "core", "min-free-space-size", "600MB");
Q_ASSERT(config != nullptr);
g_key_file_set_string(config, "core", "min-free-space-size", "600MB");
g_key_file_set_string(config, "core", "parent", parentRepo.toUtf8());
// // 设置最小空间要求
// auto err = util::Exec("ostree",
// { "config",
// "set",
// "--group",
// "core",
// "min-free-space-size",
// "600MB",
// "--repo",
// tmpPath + "/repoTmp" },
// 1000 * 60 * 5);
ostree_repo_write_config(tmpRepo, config, &gErr);
if (gErr) {
return LINGLONG_ERR(
gErr->code,
QString("config set min-free-space-size failed: %1").arg(gErr->message));
}
// 添加父仓库路径
g_key_file_set_string(config, "core", "parent", parentRepo.toStdString().c_str());
ostree_repo_write_config(tmpRepo, config, &gErr);
if (gErr) {
return LINGLONG_ERR(gErr->code, "config set parent failed");
if (gErr != nullptr) {
return LINGLONG_ERR("ostree_repo_write_config", gErr);
}
qInfo() << "create tmp repo path:" << tmpPath << ", ret:" << QDir().exists(tmpPath);
@ -1287,27 +1165,29 @@ linglong::utils::error::Result<QString> OSTreeRepo::createTmpRepo(const QString
linglong::utils::error::Result<void> OSTreeRepo::initCreateRepoIfNotExists()
{
Q_ASSERT(!repoPtr);
Q_ASSERT(!repoRootPath.isEmpty());
LINGLONG_TRACE("create ostree repository if not exists");
QString repoPath = repoRootPath + "/repo";
if (!QDir(repoPath).mkpath(".")) {
return LINGLONG_ERR(-1, "failed create directory " + repoPath);
return LINGLONG_ERR("mkdir " + repoPath, -1);
}
g_autoptr(GFile) repodir = g_file_new_for_path(repoPath.toLocal8Bit());
g_autoptr(OstreeRepo) repo = ostree_repo_new(repodir);
g_autoptr(GError) gErr = nullptr;
if (!ostree_repo_open(repo, nullptr, &gErr)) {
qDebug() << "ostree_repo_open failed:" << gErr->message << "[ code" << gErr->code << "]";
ostree_repo_open(repo, nullptr, &gErr);
if (gErr != nullptr) {
qDebug() << "ostree_repo_open failed:" << gErr->message << "[" << gErr->code << "]";
g_clear_error(&gErr);
g_clear_object(&repo);
repo = ostree_repo_new(repodir);
qInfo() << "Creating linglong ostree repo at" << repoPath;
if (!ostree_repo_create(repo, OSTREE_REPO_MODE_BARE_USER_ONLY, nullptr, &gErr)) {
return LINGLONG_ERR(-1, "ostree_repo_create error:" + QLatin1String(gErr->message));
if (ostree_repo_create(repo, OSTREE_REPO_MODE_BARE_USER_ONLY, nullptr, &gErr) == 0) {
return LINGLONG_ERR("ostree_repo_create error", gErr);
}
}
@ -1315,29 +1195,27 @@ linglong::utils::error::Result<void> OSTreeRepo::initCreateRepoIfNotExists()
url += "/repos/" + this->remoteRepoName;
g_clear_error(&gErr);
g_autoptr(GVariant) options = NULL;
GVariantBuilder builder;
g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
g_variant_builder_add(&builder, "{sv}", "gpg-verify", g_variant_new_boolean(false));
g_variant_builder_add(&builder, "{sv}", "gpg-verify", g_variant_new_boolean(FALSE)); // NOLINT
options = g_variant_ref_sink(g_variant_builder_end(&builder));
if (!ostree_repo_remote_change(repo,
nullptr,
OSTREE_REPO_REMOTE_CHANGE_REPLACE,
this->remoteRepoName.toLocal8Bit(),
url.toLocal8Bit(),
options,
nullptr,
&gErr)) {
return LINGLONG_ERR(-1,
QString("Failed to add remote repo [%1 %2], message: %3")
.arg(this->remoteRepoName, this->remoteEndpoint, gErr->message));
ostree_repo_remote_change(repo,
nullptr,
OSTREE_REPO_REMOTE_CHANGE_REPLACE,
this->remoteRepoName.toLocal8Bit(),
url.toLocal8Bit(),
options,
nullptr,
&gErr);
if (gErr != nullptr) {
return LINGLONG_ERR(
QString("add remote repo [%1 %2]").arg(this->remoteRepoName, this->remoteEndpoint),
gErr);
}
GKeyFile *configKeyFile = ostree_repo_get_config(repo);
if (!configKeyFile) {
return LINGLONG_ERR(-1, QString("Failed to get config of repo"));
}
Q_ASSERT(configKeyFile != nullptr);
g_key_file_set_string(configKeyFile, "core", "min-free-space-size", "600MB");
// NOTE:
@ -1352,9 +1230,9 @@ linglong::utils::error::Result<void> OSTreeRepo::initCreateRepoIfNotExists()
"gpg-verify",
"false");
g_clear_error(&gErr);
if (!ostree_repo_write_config(repo, configKeyFile, &gErr)) {
return LINGLONG_ERR(-1, QString("Failed to write config, message:%1").arg(gErr->message));
ostree_repo_write_config(repo, configKeyFile, &gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("ostree_repo_write_config", gErr);
}
qDebug() << "new OstreeRepo" << repo;

View File

@ -113,6 +113,7 @@ public:
TAR,
REF,
};
explicit OSTreeRepo(const QString &localRepoPath,
const config::ConfigV1 &cfg,
api::client::ClientApi &client);
@ -172,23 +173,7 @@ public:
*
* @return bool: true: false:
*/
linglong::utils::error::Result<void> getRemoteRepoList(const QString &repoPath,
QVector<QString> &vec) override;
/*
* refs
*
* @param repoPath:
* @param remoteName:
* @param outRefs: (key:refs, value:commit值)
* @param err:
*
* @return bool: true: false:
*/
bool getRemoteRefs(const QString &repoPath,
const QString &remoteName,
QMap<QString, QString> &outRefs,
QString &err) override;
linglong::utils::error::Result<void> getRemoteRepoList(QVector<QString> &vec) override;
/*
* ostree命令将软件包数据从远端仓库pull到本地
@ -308,130 +293,6 @@ private:
*/
linglong::utils::error::Result<QString> createTmpRepo(const QString &parentRepo);
linglong::utils::error::Result<void> ostreeRun(const QStringList &args,
QByteArray *stdout = nullptr)
{
QProcess ostree;
ostree.setProgram("ostree");
QStringList ostreeArgs = { "-v", "--repo=" + ostreePath };
ostreeArgs.append(args);
ostree.setArguments(ostreeArgs);
QProcess::connect(&ostree, &QProcess::readyReadStandardOutput, [&]() {
// ostree.readAllStandardOutput() can only be read once.
if (stdout) {
*stdout += ostree.readAllStandardOutput();
qDebug() << QString::fromLocal8Bit(*stdout);
} else {
qDebug() << QString::fromLocal8Bit(ostree.readAllStandardOutput());
}
});
qDebug() << "start" << ostree.arguments().join(" ");
ostree.start();
ostree.waitForFinished(-1);
qDebug() << ostree.exitStatus() << "with exit code:" << ostree.exitCode();
return LINGLONG_ERR(ostree.exitCode(),
QString::fromLocal8Bit(ostree.readAllStandardError()));
}
static QByteArray glibBytesToQByteArray(GBytes *bytes)
{
const void *data;
gsize length;
data = g_bytes_get_data(bytes, &length);
return { reinterpret_cast<const char *>(data), static_cast<int>(length) };
}
static GBytes *glibInputStreamToBytes(GInputStream *inputStream)
{
g_autoptr(GOutputStream) outStream = nullptr;
g_autoptr(GError) gErr = nullptr;
if (inputStream == nullptr)
return g_bytes_new(nullptr, 0);
outStream = g_memory_output_stream_new(nullptr, 0, g_realloc, g_free);
g_output_stream_splice(outStream,
inputStream,
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
nullptr,
&gErr);
g_assert_no_error(gErr);
return g_memory_output_stream_steal_as_bytes(G_MEMORY_OUTPUT_STREAM(outStream));
}
// FIXME: use tmp path for big file.
// FIXME: free the glib pointer.
static linglong::utils::error::Result<QByteArray> compressFile(const QString &filepath)
{
g_autoptr(GError) gErr = nullptr;
g_autoptr(GBytes) inputBytes = nullptr;
g_autoptr(GInputStream) memInput = nullptr;
g_autoptr(GInputStream) zlibStream = nullptr;
g_autoptr(GBytes) zlibBytes = nullptr;
g_autoptr(GFile) file = nullptr;
g_autoptr(GFileInfo) info = nullptr;
g_autoptr(GVariant) xattrs = nullptr;
file = g_file_new_for_path(filepath.toStdString().c_str());
if (file == nullptr) {
return { LINGLONG_EWRAP(QByteArray(),
LINGLONG_ERR(errno, "open file failed: " + filepath).value()) };
}
info = g_file_query_info(file,
G_FILE_ATTRIBUTE_UNIX_MODE,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
nullptr,
nullptr);
guint32 mode = g_file_info_get_attribute_uint32(info, G_FILE_ATTRIBUTE_UNIX_MODE);
info = g_file_query_info(file,
G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
nullptr,
nullptr);
if (g_file_info_get_is_symlink(info)) {
info = g_file_query_info(file,
G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
nullptr,
nullptr);
g_file_info_set_file_type(info, G_FILE_TYPE_SYMBOLIC_LINK);
g_file_info_set_size(info, 0);
} else {
info = g_file_query_info(file,
G_FILE_ATTRIBUTE_STANDARD_SIZE,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
nullptr,
nullptr);
qDebug() << "fize size:" << g_file_info_get_size(info);
// Q_ASSERT(g_file_info_get_size(info) > 0);
g_file_info_set_size(info, g_file_info_get_size(info));
inputBytes = g_file_load_bytes(file, nullptr, nullptr, nullptr);
}
// TODO: set uid/gid with G_FILE_ATTRIBUTE_UNIX_UID/G_FILE_ATTRIBUTE_UNIX_GID
g_file_info_set_attribute_uint32(info, G_FILE_ATTRIBUTE_UNIX_MODE, mode);
if (inputBytes) {
memInput = g_memory_input_stream_new_from_bytes(inputBytes);
}
xattrs = g_variant_ref_sink(g_variant_new_array(G_VARIANT_TYPE("(ayay)"), nullptr, 0));
ostree_raw_file_to_archive_z2_stream(memInput, info, xattrs, &zlibStream, nullptr, &gErr);
zlibBytes = glibInputStreamToBytes(zlibStream);
return glibBytesToQByteArray(zlibBytes);
}
static OstreeRepo *openRepo(const QString &path) { }
QString getObjectPath(const QString &objName)
{
return QDir::cleanPath(
@ -476,38 +337,25 @@ private:
return objects;
}
linglong::utils::error::Result<QList<OstreeRepoObject>>
findObjectsOfCommits(const QStringList &revs)
{
QList<OstreeRepoObject> objects;
for (const auto &rev : revs) {
// FIXME: check error
auto revObjects = traverseCommit(rev, 0);
for (const auto &objName : revObjects) {
auto path = getObjectPath(objName);
objects.push_back(
OstreeRepoObject{ .objectName = objName, .rev = rev, .path = path });
}
}
return objects;
}
linglong::utils::error::Result<QString> resolveRev(const QString &ref)
{
LINGLONG_TRACE(QString("resolve refspec %1").arg(ref));
g_autoptr(GError) gErr = nullptr;
g_autofree char *commitID = nullptr;
std::string refStr = ref.toStdString();
// FIXME: should free commitID?
if (!ostree_repo_resolve_rev(repoPtr.get(), refStr.c_str(), false, &commitID, &gErr)) {
return LINGLONG_EWRAP("ostree_repo_resolve_rev failed: " + ref,
LINGLONG_ERR(gErr->code, gErr->message).value());
if (ostree_repo_resolve_rev(repoPtr.get(), ref.toUtf8(), 0, &commitID, &gErr) == 0) {
return LINGLONG_ERR("ostree_repo_resolve_rev", gErr);
}
return QString::fromLatin1(commitID);
return QString::fromUtf8(commitID);
}
linglong::utils::error::Result<QSharedPointer<api::client::GetRepo_200_response>>
getRepoInfo(const QString &repoName)
{
LINGLONG_TRACE("get repo");
linglong::utils::error::Result<QSharedPointer<api::client::GetRepo_200_response>> ret;
QEventLoop loop;
@ -515,32 +363,37 @@ private:
&apiClient,
&api::client::ClientApi::getRepoSignal,
&loop,
[&loop, &ret](api::client::GetRepo_200_response resp) {
[&](const api::client::GetRepo_200_response &resp) {
loop.exit();
if (resp.getCode() != 200) {
ret = LINGLONG_ERR(resp.getCode(), resp.getMsg());
const qint32 HTTP_OK = 200;
if (resp.getCode() != HTTP_OK) {
ret = LINGLONG_ERR(resp.getMsg(), resp.getCode());
return;
}
auto respPointer = new api::client::GetRepo_200_response(resp);
ret = QSharedPointer<api::client::GetRepo_200_response>(respPointer);
ret = QSharedPointer<api::client::GetRepo_200_response>::create(resp);
},
loop.thread() == apiClient.thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection);
QEventLoop::connect(
&apiClient,
&api::client::ClientApi::getRepoSignalEFull,
&loop,
[&loop, &ret](auto, auto error_type, const QString &error_str) {
[&](auto, auto error_type, const QString &error_str) {
loop.exit();
ret = LINGLONG_ERR(error_type, error_str);
ret = LINGLONG_ERR(error_str, error_type);
},
loop.thread() == apiClient.thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection);
apiClient.getRepo(repoName);
loop.exec();
return ret;
}
linglong::utils::error::Result<QString> getToken()
{
LINGLONG_TRACE("get token");
linglong::utils::error::Result<QString> ret;
QEventLoop loop;
@ -548,10 +401,11 @@ private:
&apiClient,
&api::client::ClientApi::signInSignal,
&loop,
[&loop, &ret](api::client::SignIn_200_response resp) {
[&](api::client::SignIn_200_response resp) {
loop.exit();
if (resp.getCode() != 200) {
ret = LINGLONG_ERR(resp.getCode(), resp.getMsg());
const qint32 HTTP_OK = 200;
if (resp.getCode() != HTTP_OK) {
ret = LINGLONG_ERR(resp.getMsg(), resp.getCode());
return;
}
ret = resp.getData().getToken();
@ -561,9 +415,9 @@ private:
&apiClient,
&api::client::ClientApi::signInSignalEFull,
&loop,
[&loop, &ret](auto, auto error_type, const QString &error_str) {
[&](auto, auto error_type, const QString &error_str) {
loop.exit();
ret = LINGLONG_ERR(error_type, error_str);
ret = LINGLONG_ERR(error_str, error_type);
},
loop.thread() == apiClient.thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection);
@ -580,6 +434,8 @@ private:
linglong::utils::error::Result<QString> newUploadTask(QSharedPointer<UploadRequest> req)
{
LINGLONG_TRACE("new upload task");
linglong::utils::error::Result<QString> ret;
QEventLoop loop;
@ -587,10 +443,11 @@ private:
&apiClient,
&api::client::ClientApi::newUploadTaskIDSignal,
&loop,
[&loop, &ret](api::client::NewUploadTaskID_200_response resp) {
[&](api::client::NewUploadTaskID_200_response resp) {
loop.exit();
if (resp.getCode() != 200) {
ret = LINGLONG_ERR(resp.getCode(), resp.getMsg());
const qint32 HTTP_OK = 200;
if (resp.getCode() != HTTP_OK) {
ret = LINGLONG_ERR(resp.getMsg(), resp.getCode());
return;
}
ret = resp.getData().getId();
@ -600,9 +457,9 @@ private:
&apiClient,
&api::client::ClientApi::newUploadTaskIDSignalEFull,
&loop,
[&loop, &ret](auto, auto error_type, const QString &error_str) {
[&](auto, auto error_type, const QString &error_str) {
loop.exit();
ret = LINGLONG_ERR(error_type, error_str);
ret = LINGLONG_ERR(error_str, error_type);
},
loop.thread() == apiClient.thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection);
api::client::Schema_NewUploadTaskReq taskReq;
@ -616,29 +473,35 @@ private:
linglong::utils::error::Result<void> doUploadTask(const QString &taskID,
const QString &filePath)
{
linglong::utils::error::Result<void> ret = LINGLONG_OK;
LINGLONG_TRACE("do upload task");
linglong::utils::error::Result<void> ret;
QEventLoop loop;
QEventLoop::connect(
&apiClient,
&api::client::ClientApi::uploadTaskFileSignal,
&loop,
[&loop, &ret](api::client::Api_UploadTaskFileResp resp) {
[&](const api::client::Api_UploadTaskFileResp &resp) {
loop.exit();
if (resp.getCode() != 200) {
ret = LINGLONG_ERR(resp.getCode(), resp.getMsg());
const qint32 HTTP_OK = 200;
if (resp.getCode() != HTTP_OK) {
ret = LINGLONG_ERR(resp.getMsg(), resp.getCode());
return;
}
},
loop.thread() == apiClient.thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection);
QEventLoop::connect(
&apiClient,
&api::client::ClientApi::uploadTaskFileSignalEFull,
&loop,
[&loop, &ret](auto, auto error_type, const QString &error_str) {
[&](auto, auto error_type, const QString &error_str) {
loop.exit();
ret = LINGLONG_ERR(error_type, error_str);
ret = LINGLONG_ERR(error_str, error_type);
},
loop.thread() == apiClient.thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection);
api::client::HttpFileElement file;
file.setFileName(filePath);
file.setRequestFileName(filePath);
@ -647,24 +510,28 @@ private:
return ret;
}
linglong::utils::error::Result<void> cleanUploadTask(const package::Ref &ref,
const QString &filePath)
static void cleanUploadTask(const package::Ref &ref, const QString &filePath)
{
const auto savePath =
QStringList{ util::getUserFile(".linglong/builder"), ref.appId }.join(QDir::separator());
util::removeDir(savePath);
if (!util::removeDir(savePath)) {
Q_ASSERT(false);
qCritical() << "Failed to remove" << savePath;
}
QFile file(filePath);
file.remove();
qDebug() << "clean Upload Task";
return LINGLONG_OK;
if (!file.remove()) {
Q_ASSERT(false);
qCritical() << "Failed to remove" << filePath;
}
}
linglong::utils::error::Result<void> getUploadStatus(const QString &taskID)
{
while (1) {
LINGLONG_TRACE("get upload status");
while (true) {
linglong::utils::error::Result<QString> ret = LINGLONG_OK;
qDebug() << "OK have value" << ret.has_value();
QEventLoop loop;
@ -672,10 +539,11 @@ private:
&apiClient,
&api::client::ClientApi::uploadTaskInfoSignal,
&loop,
[&loop, &ret](api::client::UploadTaskInfo_200_response resp) {
[&](const api::client::UploadTaskInfo_200_response &resp) {
loop.exit();
if (resp.getCode() != 200) {
ret = LINGLONG_ERR(resp.getCode(), resp.getMsg());
const qint32 HTTP_OK = 200;
if (resp.getCode() != HTTP_OK) {
ret = LINGLONG_ERR(resp.getMsg(), resp.getCode());
return;
}
ret = resp.getData().getStatus();
@ -687,23 +555,24 @@ private:
&apiClient,
&api::client::ClientApi::uploadTaskInfoSignalEFull,
&loop,
[&loop, &ret](auto, auto error_type, const QString &error_str) {
[&](auto, auto error_type, const QString &error_str) {
loop.exit();
ret = LINGLONG_ERR(error_type, error_str);
ret = LINGLONG_ERR(error_str, error_type);
},
loop.thread() == apiClient.thread() ? Qt::AutoConnection
: Qt::BlockingQueuedConnection);
apiClient.uploadTaskInfo(remoteToken, taskID);
loop.exec();
if (!ret.has_value()) {
return LINGLONG_EWRAP("get upload taks info", ret.error());
if (!ret) {
return LINGLONG_ERR("get upload taks info", ret);
}
auto status = *ret;
if (status == "complete") {
break;
} else if (status == "failed") {
return LINGLONG_ERR(-1, "task status failed");
return LINGLONG_ERR("task status failed", -1);
}
qInfo().noquote() << status;
QThread::sleep(1);
}

View File

@ -62,12 +62,7 @@ public:
virtual utils::error::Result<package::Ref> latestOfRef(const QString &appId,
const QString &appVersion) = 0;
virtual linglong::utils::error::Result<void> getRemoteRepoList(const QString &repoPath,
QVector<QString> &vec) = 0;
virtual bool getRemoteRefs(const QString &repoPath,
const QString &remoteName,
QMap<QString, QString> &outRefs,
QString &err) = 0;
virtual linglong::utils::error::Result<void> getRemoteRepoList(QVector<QString> &vec) = 0;
virtual linglong::utils::error::Result<void> repoPullbyCmd(const QString &destPath,
const QString &remoteName,
const QString &ref) = 0;

View File

@ -27,6 +27,8 @@ QSERIALIZER_IMPL(Response);
linglong::utils::error::Result<QList<QSharedPointer<package::AppMetaInfo>>>
RepoClient::QueryApps(const package::Ref &ref)
{
LINGLONG_TRACE("query apps");
Request_FuzzySearchReq req;
req.setChannel(ref.channel);
req.setAppId(ref.appId);
@ -35,17 +37,17 @@ RepoClient::QueryApps(const package::Ref &ref)
req.setRepoName(ref.repo);
linglong::utils::error::Result<QList<QSharedPointer<package::AppMetaInfo>>> ret =
LINGLONG_ERR(-1, "unknown error");
LINGLONG_ERR("unknown error");
QEventLoop loop;
QEventLoop::connect(
&client,
&ClientApi::fuzzySearchAppSignal,
&loop,
[&loop, &ret](FuzzySearchApp_200_response resp) {
[&](FuzzySearchApp_200_response resp) {
loop.exit();
if (resp.getCode() != 200) {
ret = LINGLONG_ERR(resp.getCode(), resp.getMsg());
ret = LINGLONG_ERR(resp.getMsg(), resp.getCode());
return;
}
QJsonObject obj = resp.asJsonObject();
@ -62,9 +64,9 @@ RepoClient::QueryApps(const package::Ref &ref)
&client,
&ClientApi::fuzzySearchAppSignalEFull,
&loop,
[&loop, &ret](auto, auto error_type, const QString &error_str) {
[&](auto, auto error_type, const QString &error_str) {
loop.exit();
ret = LINGLONG_ERR(error_type, error_str);
ret = LINGLONG_ERR(error_str, error_type);
},
loop.thread() == client.thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection);
client.fuzzySearchApp(req);

View File

@ -109,6 +109,8 @@ auto App::init() -> bool
utils::error::Result<void> App::prepare()
{
LINGLONG_TRACE("prepare app");
// FIXME: get info from module/package
auto runtimeRef = package::Ref(runtime->ref);
QString runtimeRootPath = repo->rootOfLayer(runtimeRef);
@ -123,8 +125,8 @@ utils::error::Result<void> App::prepare()
QString appRootPath = repo->rootOfLayer(appRef);
auto ret = stageRootfs(fixRuntimePath, appRef.appId, appRootPath);
if (!ret.has_value()) {
return LINGLONG_EWRAP("stage rootfs", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
stageSystem();
@ -136,7 +138,7 @@ utils::error::Result<void> App::prepare()
auto envFilepath = container->workingDirectory + QString("/env");
QFile envFile(envFilepath);
if (!envFile.open(QIODevice::WriteOnly)) {
return LINGLONG_ERR(-1, "create env failed" + envFile.errorString());
return LINGLONG_ERR("create env failed" + envFile.errorString());
}
for (const auto &env : *r.process->env) {
envFile.write(env.c_str());
@ -162,20 +164,18 @@ utils::error::Result<void> App::prepare()
QStringList{ appRootPath, "entries", "applications" }.join(QDir::separator()));
auto desktopFilenameList = applicationsDir.entryList({ "*.desktop" }, QDir::Files);
if (desktopFilenameList.length() <= 0) {
return LINGLONG_ERR(-1, "desktop file not found in " + applicationsDir.path());
return LINGLONG_ERR("desktop file not found in " + applicationsDir.path());
}
auto desktopEntry = utils::xdg::DesktopEntry::New(
applicationsDir.absoluteFilePath(desktopFilenameList.value(0)));
if (!desktopEntry.has_value()) {
return LINGLONG_EWRAP("DesktopEntry file path:" + desktopFilenameList.value(0),
desktopEntry.error());
if (!desktopEntry) {
return LINGLONG_ERR(desktopEntry);
}
auto exec = desktopEntry->getValue<QString>("Exec");
if (!exec.has_value()) {
return LINGLONG_EWRAP("Broken desktop file without Exec in main section.",
exec.error());
if (!exec) {
return LINGLONG_ERR(exec);
}
const auto &parsedExec = util::parseExec(*exec);
@ -254,6 +254,8 @@ utils::error::Result<void> App::stageRootfs(QString runtimeRootPath,
const QString &appId,
QString appRootPath)
{
LINGLONG_TRACE("stage rootfs");
// TODO(wurongjie) 先去掉fuse相关功能
// wine应用暂不支持devel 更改为全量包后不需要fusespecialCase 感觉并不需要 fuse
{
@ -273,8 +275,8 @@ utils::error::Result<void> App::stageRootfs(QString runtimeRootPath,
}
// TODO(wurongjie) base体积太大了应该替换成精简的rootfs
auto ret = repo->latestOfRef("org.deepin.base", "23");
if (!ret.has_value()) {
return LINGLONG_EWRAP("latest of ref", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
// 初始化容器workdir目录
@ -298,8 +300,8 @@ utils::error::Result<void> App::stageRootfs(QString runtimeRootPath,
};
qDebug() << "run" << program << arguments.join(" ");
auto mountRootRet = utils::command::Exec(program, arguments);
if (!mountRootRet.has_value()) {
return LINGLONG_EWRAP("Failed to mount rootfs using overlayfs", mountRootRet.error());
if (!mountRootRet) {
return LINGLONG_ERR("mount rootfs by overlayfs", mountRootRet);
}
// 使用容器hook写在 overlayer rootfs
// 由于crun不支持在mount中配置fuse也无法在hooks中挂载 overlayer 为 rootfs
@ -311,10 +313,10 @@ utils::error::Result<void> App::stageRootfs(QString runtimeRootPath,
"--lazy",
containerWorkdir.filePath("rootfs").toStdString() };
umountRootfsHook.path = "/usr/bin/umount";
if (!r.hooks.has_value()) {
if (!r.hooks) {
r.hooks = std::make_optional(ocppi::runtime::config::types::Hooks{});
}
if (r.hooks->poststop.has_value()) {
if (r.hooks->poststop) {
r.hooks->poststop->push_back(umountRootfsHook);
} else {
r.hooks->poststop = { umountRootfsHook };
@ -333,7 +335,7 @@ utils::error::Result<void> App::stageRootfs(QString runtimeRootPath,
{ "LINGLONG_ROOT", linglongRootPath },
};
auto getPath = [&](QString &path) -> QString {
for (auto key : variables.keys()) {
for (const auto &key : variables.keys()) {
path.replace(QString("$%1").arg(key).toLocal8Bit(), variables.value(key).toLocal8Bit());
}
return path;
@ -435,8 +437,8 @@ utils::error::Result<void> App::stageRootfs(QString runtimeRootPath,
.toStdString());
break;
default:
qInfo() << "no supported arch :" << appRef.arch;
return LINGLONG_ERR(-1, "no supported arch :" + appRef.arch);
// FIXME: add other architectures
return LINGLONG_ERR("no supported arch :" + appRef.arch);
}
env.push_back(("LD_LIBRARY_PATH=" + fixLdLibraryPath.join(":")).toStdString());
@ -1112,13 +1114,15 @@ auto App::load(linglong::repo::Repo *repo,
linglong::utils::error::Result<QString> App::start()
{
LINGLONG_TRACE("start app");
package::Ref ref(package->ref);
util::ensureDir(r.root->path.c_str());
auto ret = prepare();
if (!ret.has_value()) {
return LINGLONG_EWRAP("prepare", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
// write pid file
@ -1133,21 +1137,20 @@ linglong::utils::error::Result<QString> App::start()
auto data = runtimeConfigJSON.dump();
QFile f(containerWorkdir.filePath("config.json"));
if (!f.open(QIODevice::WriteOnly)) {
return LINGLONG_ERR(-1, f.errorString());
return LINGLONG_ERR(f.errorString(), f.error());
}
if (!f.write(QByteArray::fromStdString(data))) {
return LINGLONG_ERR(-1, f.errorString());
return LINGLONG_ERR(f.errorString(), f.error());
};
f.close();
// 运行容器
auto qid = util::genUuid();
auto id = qid.toStdString();
auto path = std::filesystem::path(containerWorkdir.path().toStdString());
auto runRet = ociCli->run(id.c_str(), path);
if (!runRet.has_value()) {
auto runRet = ociCli->run(ocppi::runtime::ContainerID(qid.toUtf8()), path);
if (!runRet) {
qDebug() << "umount rootfs";
utils::command::Exec("umount", { "--lazy", QString::fromStdString(r.root->path) });
return LINGLONG_EWRAP("create container", LINGLONG_SERR(runRet.error()).value());
return LINGLONG_ERR(runRet.error());
}
return qid;
}
@ -1184,19 +1187,19 @@ void App::exec(const QStringList &cmd, const QStringList &env, QString cwd)
const auto &desktopEntry = utils::xdg::DesktopEntry::New(
applicationsDir.absoluteFilePath(desktopFilenameList.value(0)));
if (!desktopEntry.has_value()) {
if (!desktopEntry) {
// FIXME(black_desk): return error instead of logging here.
qCritical() << "DesktopEntry file path:"
<< applicationsDir.absoluteFilePath(desktopFilenameList.value(0));
qCritical().noquote() << desktopEntry.error().code() << desktopEntry.error().message();
qCritical() << desktopEntry.error();
return;
}
const auto &exec = desktopEntry->getValue<QString>("Exec");
if (!exec.has_value()) {
if (!exec) {
// FIXME(black_desk): return error instead of logging here.
qCritical() << "Broken desktop file without Exec in main section.";
qCritical().noquote() << exec.error().code() << exec.error().message();
qCritical() << exec.error();
return;
}

View File

@ -33,6 +33,8 @@ AppManager::AppManager(repo::Repo &repo, ocppi::cli::CLI &ociCli)
linglong::utils::error::Result<void> AppManager::Run(const RunParamOption &paramOption)
{
LINGLONG_TRACE(QString("run %1").arg(paramOption.appId));
qDebug() << "run" << paramOption.appId;
QString appID = paramOption.appId;
@ -54,8 +56,8 @@ linglong::utils::error::Result<void> AppManager::Run(const RunParamOption &param
// TODO(wurongjie) 在版本迭代后,可以删除对旧 channel 的支持
if (channel.isEmpty()) {
auto refs = repo.listLocalRefs();
if (!refs.has_value()) {
return LINGLONG_EWRAP("get ref list: ", refs.error());
if (!refs) {
return LINGLONG_ERR(refs);
}
for (auto ref : *refs) {
if (ref.appId == appID && ref.arch == arch && ref.module == module) {
@ -72,7 +74,6 @@ linglong::utils::error::Result<void> AppManager::Run(const RunParamOption &param
}
if (channel.isEmpty()) {
return LINGLONG_ERR(
-1,
QString("Application %1/%2/$latest/%3/%4 cannot be found from the database, "
"maybe you should install it first or pass more parameter")
.arg("main")
@ -84,8 +85,8 @@ linglong::utils::error::Result<void> AppManager::Run(const RunParamOption &param
// 默认选择最新的版本
if (version.isEmpty()) {
auto ret = repo.latestOfRef(appID, "");
if (!ret.has_value()) {
return LINGLONG_EWRAP("found app latest version", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
version = ret->version;
}
@ -93,7 +94,7 @@ linglong::utils::error::Result<void> AppManager::Run(const RunParamOption &param
linglong::package::Ref ref("", channel, appID, version, arch, module);
auto app = linglong::runtime::App::load(&repo, ref, exec, &ociCli);
if (app == nullptr) {
return LINGLONG_ERR(-1, "load app failed");
return LINGLONG_ERR("load app failed");
}
// 设置环境变量
app->saveUserEnvList(env);
@ -103,29 +104,31 @@ linglong::utils::error::Result<void> AppManager::Run(const RunParamOption &param
app->setAppParamMap(paramMap);
// 启动应用
auto ret = app->start();
if (!ret.has_value()) {
return LINGLONG_EWRAP("start app", ret.error());
if (!ret) {
return LINGLONG_ERR(ret);
}
return LINGLONG_OK;
}
Reply AppManager::Exec(const ExecParamOption &paramOption)
{
LINGLONG_TRACE("exec");
Reply reply;
auto const &containerID = paramOption.containerID;
std::string executable = paramOption.cmd[0].toStdString();
std::vector<std::string> command;
for (auto cmd : paramOption.cmd.mid(1)) {
for (const auto &cmd : paramOption.cmd.mid(1)) {
command.push_back(cmd.toStdString());
}
ocppi::runtime::ExecOption opt;
opt.tty = true;
opt.uid = getuid();
opt.gid = getgid();
auto ret = ociCli.exec(containerID.toStdString().c_str(), executable, command, { opt });
if (!ret.has_value()) {
auto err = LINGLONG_SERR(ret.error());
auto ret = ociCli.exec(containerID.toStdString(), executable, command, { opt });
if (!ret) {
auto err = LINGLONG_ERR(ret.error());
reply.code = STATUS_CODE(kFail);
reply.message = "exec container failed: " + err.value().message();
return reply;
@ -136,9 +139,10 @@ Reply AppManager::Exec(const ExecParamOption &paramOption)
Reply AppManager::Stop(const QString &containerId)
{
LINGLONG_TRACE("stop");
Reply reply;
auto id = containerId.toStdString();
auto ret = ociCli.kill(id.c_str(), "SIGTERM");
auto ret = ociCli.kill(containerId.toStdString(), "SIGTERM");
if (!ret.has_value()) {
reply.message = "kill container failed, containerId:" + containerId;
reply.code = STATUS_CODE(kErrorPkgKillFailed);
@ -146,17 +150,19 @@ Reply AppManager::Stop(const QString &containerId)
reply.code = STATUS_CODE(kErrorPkgKillSuccess);
reply.message = "kill container success, containerId:" + containerId;
}
auto err = LINGLONG_SERR(ret.error());
auto err = LINGLONG_ERR(ret.error());
qInfo() << "kill containerId:" << containerId << ", ret:" << err.value().message();
return reply;
}
QueryReply AppManager::ListContainer()
{
LINGLONG_TRACE("list");
QueryReply reply;
auto ret = ociCli.list();
if (!ret.has_value()) {
auto err = LINGLONG_SERR(ret.error());
if (!ret) {
auto err = LINGLONG_ERR(ret.error());
reply.code = err.value().code();
reply.message = err.value().message();
return reply;

View File

@ -17,12 +17,16 @@ namespace linglong {
namespace util {
/*!
* WARNING:
* DO NOT USE THIS CLASS IN NEW CODE
* Use linglong::utils::error::Result
*
* Error is a stack trace error handler when function return
*/
class ErrorPrivate;
class Error : private QSharedPointer<ErrorPrivate>
class Q_DECL_DEPRECATED Error : private QSharedPointer<ErrorPrivate>
{
public:
Error() = default;

View File

@ -59,22 +59,23 @@ QStringList getUserEnv(const QStringList &filters)
return ret.toStringList();
}
// 执行系统命令,返回命令的标准输出
linglong::utils::error::Result<QString> Exec(QString command, QStringList args)
{
LINGLONG_TRACE(QString("exec %1 %2").arg(command).arg(args.join(" ")));
QProcess process;
process.setProgram(command);
process.setArguments(args);
process.start();
// 如果进程启动失败,函数返回错误信息
if (!process.waitForFinished(-1)) {
return LINGLONG_ERR(-1, process.errorString());
return LINGLONG_ERR(process.errorString(), process.error());
}
// 如果进程退出码非0函数返回标准错误输出
if (process.exitCode()) {
return LINGLONG_ERR(process.exitCode(), process.readAllStandardError());
if (process.exitCode() != 0) {
return LINGLONG_ERR(process.readAllStandardError(), process.exitCode());
}
// 如果进程退出码为0,函数返回,标准输出
return process.readAllStandardOutput();
}

View File

@ -19,13 +19,13 @@ namespace linglong::utils::dbus {
const QString &path,
QObject *obj) -> tl::expected<void, error::Error>
{
LINGLONG_TRACE("register D-Bus object");
if (conn.registerObject(path, obj)) {
qCDebug(linglong_utils_dbus) << "register object to dbus on" << path;
return LINGLONG_OK;
}
// FIXME: use real ERROR CODE defined in API.
return LINGLONG_ERR(-1, "register dbus object: object existed.");
return LINGLONG_ERR("object existed.");
}
inline void unregisterDBusObject(QDBusConnection conn, const QString &path)
@ -37,6 +37,8 @@ inline void unregisterDBusObject(QDBusConnection conn, const QString &path)
[[nodiscard]] inline auto registerDBusService(QDBusConnection conn, const QString &serviceName)
-> error::Result<void>
{
LINGLONG_TRACE("register D-Bus service");
if (conn.registerService(serviceName)) {
qCDebug(linglong_utils_dbus) << "register dbus name" << serviceName;
return LINGLONG_OK;
@ -45,20 +47,17 @@ inline void unregisterDBusObject(QDBusConnection conn, const QString &path)
error::Error err;
// FIXME: use real ERROR CODE defined in API.
if (conn.lastError().isValid()) {
err =
LINGLONG_ERR(-1,
QString("%1: %2").arg(conn.lastError().name(), conn.lastError().message()))
.value();
} else {
err = LINGLONG_ERR(-1, "service name existed.").value();
return LINGLONG_ERR(conn.lastError().name() + ": " + conn.lastError().message());
}
return LINGLONG_EWRAP("register dbus service:", err);
return LINGLONG_ERR("service name existed.");
}
[[nodiscard]] inline auto unregisterDBusService(QDBusConnection conn, const QString &serviceName)
-> tl::expected<void, error::Error>
{
LINGLONG_TRACE("unregister D-Bus service");
if (conn.unregisterService(serviceName)) {
qCDebug(linglong_utils_dbus) << "unregister dbus name" << serviceName;
return LINGLONG_OK;
@ -67,15 +66,10 @@ inline void unregisterDBusObject(QDBusConnection conn, const QString &path)
// FIXME: use real ERROR CODE defined in API.
error::Error err;
if (conn.lastError().isValid()) {
err =
LINGLONG_ERR(-1,
QString("%1: %2").arg(conn.lastError().name(), conn.lastError().message()))
.value();
} else {
err = LINGLONG_ERR(-1, "unknown").value();
return LINGLONG_ERR(conn.lastError().name() + ": " + conn.lastError().message());
}
return LINGLONG_EWRAP("unregister dbus service:", err);
return LINGLONG_ERR("unknown");
}
} // namespace linglong::utils::dbus

View File

@ -9,8 +9,10 @@
#include "linglong/utils/error/details/error_impl.h"
#include <glib.h>
#include <tl/expected.hpp>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageLogContext>
@ -37,34 +39,178 @@ public:
[[nodiscard]] auto message() const { return pImpl->message(); }
static auto Wrap(const char *file, int line, const QString &msg, Error cause) -> Error
static auto
Err(const char *file, int line, const QString &trace_msg, const QString &msg, int code = -1)
-> Error
{
return Error(std::make_unique<details::ErrorImpl>(file,
line,
"default",
cause.code(),
msg,
std::move(cause.pImpl)));
code,
trace_msg + ": " + msg,
nullptr));
}
static auto Err(const char *file, int line, int code, const QString &msg) -> Error
static auto Err(const char *file,
int line,
const QString &trace_msg,
const QString &msg,
const QFile &qfile) -> Error
{
return Error(
std::make_unique<details::ErrorImpl>(file, line, "default", code, msg, nullptr));
std::make_unique<details::ErrorImpl>(file,
line,
"default",
qfile.error(),
trace_msg + ": " + msg + ": " + qfile.errorString(),
nullptr));
}
static auto Err(const char *file, int line, std::exception_ptr err) -> Error
static auto Err(const char *file, int line, const QString &trace_msg, const QFile &qfile)
-> Error
{
QString what;
return Error(std::make_unique<details::ErrorImpl>(file,
line,
"default",
qfile.error(),
trace_msg + ": " + qfile.errorString(),
nullptr));
}
static auto
Err(const char *file, int line, const QString &trace_msg, std::exception_ptr err, int code = -1)
-> Error
{
QString what = trace_msg + ": ";
try {
std::rethrow_exception(err);
std::rethrow_exception(std::move(err));
} catch (const std::exception &e) {
what = e.what();
what += e.what();
} catch (...) {
what = "Unknown exception caught";
what += "unknown";
}
return Error(
std::make_unique<details::ErrorImpl>(file, line, "default", -1, what, nullptr));
std::make_unique<details::ErrorImpl>(file, line, "default", code, what, nullptr));
}
static auto Err(const char *file,
int line,
const QString &trace_msg,
const QString &msg,
std::exception_ptr err,
int code = -1) -> Error
{
QString what = trace_msg + ": " + msg + ": ";
try {
std::rethrow_exception(std::move(err));
} catch (const std::exception &e) {
what += e.what();
} catch (...) {
what += "unknown";
}
return Error(
std::make_unique<details::ErrorImpl>(file, line, "default", code, what, nullptr));
}
static auto Err(const char *file, int line, const QString &trace_msg, const std::exception &e)
-> Error
{
return Error(std::make_unique<details::ErrorImpl>(file,
line,
"default",
-1,
trace_msg + ": " + e.what(),
nullptr));
}
static auto Err(const char *file,
int line,
const QString &trace_msg,
const QString &msg,
const std::exception &e,
int code = -1) -> Error
{
QString what = trace_msg + ": " + msg + ": " + e.what();
return Error(
std::make_unique<details::ErrorImpl>(file, line, "default", code, what, nullptr));
}
static auto Err(const char *file,
int line,
const QString &trace_msg,
const QString &msg,
GError const *const e) -> Error
{
return Err(file, line, trace_msg, msg + ": " + e->message, e->code);
}
static auto Err(const char *file,
int line,
const QString &trace_msg,
const QString &msg,
const std::system_error &e) -> Error
{
return Err(file, line, trace_msg, msg, e, e.code().value());
}
template<typename Value>
static auto Err(const char *file,
int line,
const QString &trace_msg,
const QString &msg,
tl::expected<Value, Error> &&cause) -> Error
{
Q_ASSERT(!cause.has_value());
return Error(std::make_unique<details::ErrorImpl>(file,
line,
"default",
cause.error().code(),
trace_msg + ": " + msg,
std::move(cause.error().pImpl)));
}
template<typename Value>
static auto Err(const char *file,
int line,
const QString &trace_msg,
tl::expected<Value, Error> &&cause) -> Error
{
Q_ASSERT(!cause.has_value());
return Error(std::make_unique<details::ErrorImpl>(file,
line,
"default",
cause.error().code(),
trace_msg,
std::move(cause.error().pImpl)));
}
template<typename Value>
static auto Err(const char *file,
int line,
const QString &trace_msg,
tl::expected<Value, std::exception_ptr> &&cause,
int code = -1) -> Error
{
Q_ASSERT(!cause.has_value());
return Err(file, line, trace_msg, cause.error(), code);
}
template<typename Value>
static auto Err(const char *file,
int line,
const QString &trace_msg,
const QString &msg,
tl::expected<Value, std::exception_ptr> &&cause) -> Error
{
Q_ASSERT(!cause.has_value());
return Err(file, line, trace_msg, msg, cause.error());
}
private:
@ -81,36 +227,51 @@ using Result = tl::expected<Value, Error>;
} // namespace linglong::utils::error
#define LINGLONG_TRACE_MESSAGE(message) auto linglong_trace_message = message;
// Use this macro to define trace message at the begining of function
#define LINGLONG_TRACE(message) QString linglong_trace_message = message;
#define LINGLONG_EWRAP_1(cause) /*NOLINT*/ \
tl::unexpected(::linglong::utils::error::Error::Wrap(QT_MESSAGELOG_FILE, \
QT_MESSAGELOG_LINE, \
linglong_trace_message, \
std::move(cause)))
// Use this macro to create new error or wrap an existing error
// LINGLONG_ERR(message, code =-1)
// LINGLONG_ERR(message, /* const QFile& */)
// LINGLONG_ERR(/* const QFile& */)
// LINGLONG_ERR(message, /* std::exception_ptr */, code=-1)
// LINGLONG_ERR(/* std::exception_ptr */)
// LINGLONG_ERR(message, /* const std::exception & */, code=-1)
// LINGLONG_ERR(/* const std::exception & */)
// LINGLONG_ERR(message, /* const std::system_exception & */)
// LINGLONG_ERR(message, /* GError* */)
// LINGLONG_ERR(message, /* Result<Value>&& */)
// LINGLONG_ERR(/* Result<Value>&& */)
// LINGLONG_ERR(message, /* tl::expected<Value,std::exception_ptr>&& */, code=-1)
// LINGLONG_ERR(/* tl::expected<Value,std::exception_ptr>&& */)
#define LINGLONG_EWRAP_2(message, cause) /*NOLINT*/ \
tl::unexpected(::linglong::utils::error::Error::Wrap(QT_MESSAGELOG_FILE, \
QT_MESSAGELOG_LINE, \
message, \
std::move(cause)))
#define LINGLONG_EWRAP_GETMACRO(_1, _2, NAME, ...) NAME
#define LINGLONG_EWRAP(...) \
LINGLONG_EWRAP_GETMACRO(__VA_ARGS__, LINGLONG_EWRAP_2, LINGLONG_EWRAP_1, ...)(__VA_ARGS__)
#define LINGLONG_ERR_GETMACRO(_1, _2, _3, NAME, ...) /*NOLINT*/ NAME
#define LINGLONG_ERR(...) /*NOLINT*/ \
LINGLONG_ERR_GETMACRO(__VA_ARGS__, LINGLONG_ERR_3, LINGLONG_ERR_2, LINGLONG_ERR_1, ...) \
(__VA_ARGS__)
#define LINGLONG_ERR(code, message) /*NOLINT*/ \
tl::unexpected( \
::linglong::utils::error::Error::Err(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, code, message))
// std::move is used for Result<Value>
#define LINGLONG_ERR_1(_1) /*NOLINT*/ \
tl::unexpected(::linglong::utils::error::Error::Err(QT_MESSAGELOG_FILE, \
QT_MESSAGELOG_LINE, \
linglong_trace_message, \
std::move((_1))))
#define LINGLONG_GERR(gErr) /*NOLINT*/ \
tl::unexpected(::linglong::utils::error::Error::Err(QT_MESSAGELOG_FILE, \
QT_MESSAGELOG_LINE, \
gErr->code, \
gErr->message))
// std::move is used for Result<Value>
#define LINGLONG_ERR_2(_1, _2) /*NOLINT*/ \
tl::unexpected(::linglong::utils::error::Error::Err(QT_MESSAGELOG_FILE, \
QT_MESSAGELOG_LINE, \
linglong_trace_message, \
(_1), \
std::move((_2))))
#define LINGLONG_SERR(stdErr) /*NOLINT*/ \
tl::unexpected( \
::linglong::utils::error::Error::Err(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, stdErr))
#define LINGLONG_ERR_3(_1, _2, _3) /*NOLINT*/ \
tl::unexpected(::linglong::utils::error::Error::Err(QT_MESSAGELOG_FILE, \
QT_MESSAGELOG_LINE, \
linglong_trace_message, \
(_1), \
(_2), \
(_3)))
#define LINGLONG_OK \
{ \

View File

@ -32,23 +32,21 @@ public:
static auto New(const QString &filePath) -> error::Result<DesktopEntry>
{
LINGLONG_TRACE(QString("create DesktopEntry for %1").arg(filePath));
auto desktopEntryFile = QFile(filePath);
if (!desktopEntryFile.exists()) {
return LINGLONG_ERR(ENOENT, "no such desktop entry file");
return LINGLONG_ERR("no such desktop entry file");
}
GError *gErr = nullptr;
auto _ = linglong::utils::finally::finally([&gErr]() {
if (gErr != nullptr)
g_error_free(gErr);
});
g_autoptr(GError) gErr = nullptr;
DesktopEntry entry;
if (!g_key_file_load_from_file(entry.gKeyFile.get(),
filePath.toLocal8Bit().constData(),
G_KEY_FILE_KEEP_TRANSLATIONS,
&gErr)) {
return LINGLONG_ERR(gErr->code, gErr->message);
g_key_file_load_from_file(entry.gKeyFile.get(),
filePath.toLocal8Bit().constData(),
G_KEY_FILE_KEEP_TRANSLATIONS,
&gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("g_key_file_load_from_file", gErr);
}
return entry;
@ -63,7 +61,6 @@ private:
public:
using SectionName = QString;
// statics data members
public:
static const SectionName MainSection;
@ -83,10 +80,7 @@ public:
auto groups() -> QStringList
{
gsize length = 0;
auto groups = g_key_file_get_groups(this->gKeyFile.get(), &length);
auto _ = finally::finally([&groups]() {
g_strfreev(groups);
});
g_auto(GStrv) groups = g_key_file_get_groups(this->gKeyFile.get(), &length);
QStringList result;
for (gsize i = 0; i < length; i++) {
@ -99,16 +93,13 @@ public:
auto saveToFile(const QString &filepath) -> error::Result<void>
{
GError *gErr = nullptr;
auto _ = linglong::utils::finally::finally([&gErr]() {
if (gErr != nullptr)
g_error_free(gErr);
});
LINGLONG_TRACE(QString("save to %1").arg(filepath));
if (!g_key_file_save_to_file(this->gKeyFile.get(),
filepath.toLocal8Bit().constData(),
&gErr)) {
return LINGLONG_ERR(gErr->code, gErr->message);
g_autoptr(GError) gErr = nullptr;
g_key_file_save_to_file(this->gKeyFile.get(), filepath.toLocal8Bit().constData(), &gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("g_key_file_save_to_file", gErr);
}
return LINGLONG_OK;
@ -124,7 +115,6 @@ inline void DesktopEntry::setValue(const QString &key,
section.toLocal8Bit().constData(),
key.toLocal8Bit().constData(),
value.toLocal8Bit().constData());
return;
}
template<>
@ -132,22 +122,17 @@ template<>
const SectionName &section) const
-> error::Result<QString>
{
GError *gErr = nullptr;
auto _ = linglong::utils::finally::finally([&gErr]() {
if (gErr != nullptr)
g_error_free(gErr);
});
LINGLONG_TRACE(QString("get %1 from %2").arg(key, section));
auto value = g_key_file_get_string(this->gKeyFile.get(),
section.toLocal8Bit().constData(),
key.toLocal8Bit().constData(),
&gErr);
auto _1 = finally::finally([&value]() {
g_free(value);
});
g_autoptr(GError) gErr = nullptr;
if (gErr) {
return LINGLONG_ERR(gErr->code, gErr->message);
g_autofree gchar *value = g_key_file_get_string(this->gKeyFile.get(),
section.toLocal8Bit().constData(),
key.toLocal8Bit().constData(),
&gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("g_key_file_get_string", gErr);
}
return value;

View File

@ -30,11 +30,12 @@ namespace {
// repository in a bash script to keep our code as unit test.
utils::error::Result<QStringList> executeTestScript(QStringList args)
{
LINGLONG_TRACE("execute test script");
QProcess process;
process.start("src/linglong/repo/ostree_repo_test.sh", args);
if (!process.waitForFinished()) {
return LINGLONG_ERR(
-1,
QString("Run ostree repo test script with %1 failed: %2")
.arg(QString(QJsonDocument(QJsonArray::fromStringList(args)).toJson()))
.arg(process.errorString()));
@ -49,7 +50,6 @@ utils::error::Result<QStringList> executeTestScript(QStringList args)
}
return LINGLONG_ERR(
-1,
QString("Ostree repo test script with %1 failed.\nstdout:\n%2\nstderr:\n%3")
.arg(
QString(QJsonDocument(QJsonArray::fromStringList(args)).toJson(QJsonDocument::Compact)))
@ -192,10 +192,5 @@ TEST_F(RepoTest, getRemoteRepoList)
GTEST_SKIP();
}
TEST_F(RepoTest, getRemoteRefs)
{
GTEST_SKIP();
}
} // namespace
} // namespace linglong::repo::test

View File

@ -13,7 +13,8 @@ using namespace linglong::utils::error;
TEST(Error, New)
{
auto res = []() -> Result<void> {
return LINGLONG_ERR(-1, "message");
LINGLONG_TRACE("test LINGLONG_ERR");
return LINGLONG_ERR("message", -1);
}();
ASSERT_EQ(res.has_value(), false);
@ -24,13 +25,16 @@ TEST(Error, Wrap)
{
auto res = []() -> Result<void> {
auto fn = []() -> Result<void> {
return LINGLONG_ERR(-1, "message1");
LINGLONG_TRACE("test LINGLONG_ERR");
return LINGLONG_ERR("message1", -1);
};
auto res = fn();
if (!res.has_value()) {
return LINGLONG_EWRAP("message2", res.error());
if (!res) {
LINGLONG_TRACE("test LINGLONG_ERR");
return LINGLONG_ERR("message2", res);
}
return LINGLONG_OK;
}();