refact: new error wrapping macros
Signed-off-by: black-desk <me@black-desk.cn>
This commit is contained in:
parent
2c3e586122
commit
3ec42da2f7
|
|
@ -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;
|
||||
} },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1102,7 +1102,7 @@ auto PackageManager::Uninstall(const UninstallParamOption ¶mOption) -> 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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 更改为全量包后不需要fuse,specialCase 感觉并不需要 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ AppManager::AppManager(repo::Repo &repo, ocppi::cli::CLI &ociCli)
|
|||
|
||||
linglong::utils::error::Result<void> AppManager::Run(const RunParamOption ¶mOption)
|
||||
{
|
||||
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 ¶m
|
|||
// 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 ¶m
|
|||
}
|
||||
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 ¶m
|
|||
// 默认选择最新的版本
|
||||
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 ¶m
|
|||
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 ¶m
|
|||
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 ¶mOption)
|
||||
{
|
||||
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 ¶mOption)
|
|||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
{ \
|
||||
|
|
|
|||
|
|
@ -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 §ion) 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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue