From 6f2c6cabc2da2d6aba99326cb8f67dc68036abdd Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 27 Mar 2021 21:37:28 +0100 Subject: [PATCH] cli: Add more build action operations --- cli/main.cpp | 112 +++++++++++++++++++- librepomgr/buildactions/buildactionmeta.cpp | 4 - 2 files changed, 108 insertions(+), 8 deletions(-) diff --git a/cli/main.cpp b/cli/main.cpp index 51401b7..0362312 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include using namespace CppUtilities; @@ -253,6 +254,69 @@ static void printListOfBuildActions(const LibRepoMgr::WebClient::Response::body_ std::cout << t << std::endl; } +static std::string printTimeStamp(const DateTime timeStamp) +{ + static const auto now = DateTime::gmtNow(); + return (now - timeStamp).toString(TimeSpanOutputFormat::WithMeasures, true) % ' ' % '(' + % timeStamp.toString(DateTimeOutputFormat::DateAndTime, true) + + ')'; +} + +static void printBuildActions(const LibRepoMgr::WebClient::Response::body_type::value_type &jsonData) +{ + const auto buildActions = ReflectiveRapidJSON::JsonReflector::fromJson>(jsonData.data(), jsonData.size()); + const auto meta = LibRepoMgr::BuildActionMetaInfo(); + const auto unknown = std::string_view("?"); + for (const auto &a : buildActions) { + const auto typeInfo = meta.isTypeIdValid(a.type) ? &meta.typeInfoForId(a.type) : nullptr; + const auto status = static_cast(a.status) < meta.states.size() ? meta.states[static_cast(a.status)].name : unknown; + const auto result + = static_cast(a.result) < meta.results.size() ? meta.results[static_cast(a.result)].name : unknown; + const auto flags = typeInfo ? &typeInfo->flags : nullptr; + const auto startAfter = a.startAfter | std::views::transform([](auto id) { return numberToString(id); }); + + std::cout << TextAttribute::Bold << "Build action " << a.id << TextAttribute::Reset << '\n'; + tabulate::Table t; + t.format().hide_border(); + t.add_row({ "Task", a.taskName }); + t.add_row({ "Type", (typeInfo ? typeInfo->name : unknown).data() }); + t.add_row({ "Status", status.data() }); + t.add_row({ "Result", result.data() }); + if (std::holds_alternative(a.resultData)) { + t.add_row({ "Result data", std::get(a.resultData) }); + } else { + t.add_row({ "Result data", "(no output formatter for result output type implemented yet)" }); + } + t.add_row({ "Created", printTimeStamp(a.created) }); + t.add_row({ "Started", printTimeStamp(a.started) }); + t.add_row({ "Finished", printTimeStamp(a.finished) }); + t.add_row({ "Start after", joinStrings(startAfter, ", ") }); + t.add_row({ "Directory", a.directory }); + t.add_row({ "Source repo", joinStrings(a.sourceDbs, "\n") }); + t.add_row({ "Destination repo", joinStrings(a.destinationDbs, "\n") }); + t.add_row({ "Packages", joinStrings(a.packageNames, "\n") }); + if (flags) { + auto presentFlags = std::string(); + presentFlags.reserve(32); + for (const auto &flag : *flags) { + if (a.flags & flag.id) { + if (!presentFlags.empty()) { + presentFlags += ", "; + } + presentFlags += flag.name; + } + } + t.add_row({ "Flags", std::move(presentFlags) }); + } else { + t.add_row({ "Flags", numberToString(a.flags) }); + } + t.add_row({ "Output", a.output }); + t.column(0).format().font_align(tabulate::FontAlign::right); + std::cout << t << '\n'; + } + std::cout.flush(); +} + static void printRawDataForErrorHandling(const LibRepoMgr::WebClient::Response::body_type::value_type &rawData) { if (!rawData.empty()) { @@ -308,6 +372,7 @@ int main(int argc, const char *argv[]) ConfigValueArgument configFileArg("config-file", 'c', "specifies the path of the config file", { "path" }); configFileArg.setEnvironmentVariable(PROJECT_VARNAME_UPPER "_CONFIG_FILE"); ConfigValueArgument instanceArg("instance", 'i', "specifies the instance to connect to", { "instance" }); + ConfigValueArgument rawArg("raw", 'r', "print the raw output from the server"); OperationArgument packageArg("package", 'p', "Package-related operations:"); OperationArgument searchArg("search", 's', "searches for packages"); ConfigValueArgument searchTermArg("term", 't', "specifies the search term", { "term" }); @@ -337,10 +402,48 @@ int main(int argc, const char *argv[]) path = "/api/v0/build-action"; printer = printListOfBuildActions; }); - actionArg.setSubArguments({ &listActionsArg }); + ConfigValueArgument buildActionIdArg("id", '\0', "specifies the build action ID", { "ID" }); + buildActionIdArg.setImplicit(true); + buildActionIdArg.setRequired(true); + OperationArgument showBuildActionArg("show", 'd', "show details about a build action"); + showBuildActionArg.setCallback([&path, &printer, &buildActionIdArg](const ArgumentOccurrence &) { + path = "/api/v0/build-action/details?id=" + LibRepoMgr::WebAPI::Url::encodeValue(buildActionIdArg.firstValueOr("0")); + printer = printBuildActions; + }); + showBuildActionArg.setSubArguments({ &buildActionIdArg }); + OperationArgument deleteBuildActionArg("delete", '\0', "deletes a build action"); + deleteBuildActionArg.setCallback([&verb, &path, &printer, &buildActionIdArg](const ArgumentOccurrence &) { + verb = boost::beast::http::verb::delete_; + path = "/api/v0/build-action?id=" + LibRepoMgr::WebAPI::Url::encodeValue(buildActionIdArg.firstValueOr("0")); + printer = printRawData; + }); + deleteBuildActionArg.setSubArguments({ &buildActionIdArg }); + OperationArgument cloneBuildActionArg("clone", '\0', "clones a build action"); + cloneBuildActionArg.setCallback([&verb, &path, &printer, &buildActionIdArg](const ArgumentOccurrence &) { + verb = boost::beast::http::verb::post; + path = "/api/v0/build-action/clone?id=" + LibRepoMgr::WebAPI::Url::encodeValue(buildActionIdArg.firstValueOr("0")); + printer = printRawData; + }); + cloneBuildActionArg.setSubArguments({ &buildActionIdArg }); + OperationArgument startBuildActionArg("start", '\0', "starts a build action"); + startBuildActionArg.setCallback([&verb, &path, &printer, &buildActionIdArg](const ArgumentOccurrence &) { + verb = boost::beast::http::verb::post; + path = "/api/v0/build-action/start?id=" + LibRepoMgr::WebAPI::Url::encodeValue(buildActionIdArg.firstValueOr("0")); + printer = printRawData; + }); + startBuildActionArg.setSubArguments({ &buildActionIdArg }); + OperationArgument stopBuildActionArg("stop", '\0', "stops a build action"); + stopBuildActionArg.setCallback([&verb, &path, &printer, &buildActionIdArg](const ArgumentOccurrence &) { + verb = boost::beast::http::verb::post; + path = "/api/v0/build-action/stop?id=" + LibRepoMgr::WebAPI::Url::encodeValue(buildActionIdArg.firstValueOr("0")); + printer = printRawData; + }); + stopBuildActionArg.setSubArguments({ &buildActionIdArg }); + actionArg.setSubArguments( + { &listActionsArg, &showBuildActionArg, &deleteBuildActionArg, &cloneBuildActionArg, &startBuildActionArg, &stopBuildActionArg }); HelpArgument helpArg(parser); NoColorArgument noColorArg; - parser.setMainArguments({ &packageArg, &actionArg, &instanceArg, &configFileArg, &noColorArg, &helpArg }); + parser.setMainArguments({ &packageArg, &actionArg, &instanceArg, &configFileArg, &rawArg, &noColorArg, &helpArg }); parser.parseArgs(argc, argv); // return early if no operation specified @@ -369,8 +472,9 @@ int main(int argc, const char *argv[]) sslContext.set_verify_mode(boost::asio::ssl::verify_peer); sslContext.set_default_verify_paths(); LibRepoMgr::WebClient::runSessionFromUrl(ioContext, sslContext, url, - std::bind(&handleResponse, std::ref(url), std::placeholders::_1, std::placeholders::_2, printer, std::ref(returnCode)), std::string(), - config.userName, config.password, verb); + std::bind(&handleResponse, std::ref(url), std::placeholders::_1, std::placeholders::_2, rawArg.isPresent() ? printRawData : printer, + std::ref(returnCode)), + std::string(), config.userName, config.password, verb); ioContext.run(); return 0; diff --git a/librepomgr/buildactions/buildactionmeta.cpp b/librepomgr/buildactions/buildactionmeta.cpp index c28850e..d748395 100644 --- a/librepomgr/buildactions/buildactionmeta.cpp +++ b/librepomgr/buildactions/buildactionmeta.cpp @@ -344,10 +344,6 @@ BuildActionMetaInfo::BuildActionMetaInfo() .id = BuildActionStatus::Enqueued, .name = "Enqueued", }, - BuildActionStatusMetaInfo{ - .id = BuildActionStatus::AwaitingConfirmation, - .name = "Enqueued", - }, BuildActionStatusMetaInfo{ .id = BuildActionStatus::AwaitingConfirmation, .name = "Awaiting confirmation",