launchpadlib-cpp/src/archive.cpp

166 lines
7.9 KiB
C++

// Copyright (C) 2024 Simon Quigley <tsimonq2@ubuntu.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "archive.h"
#include "utils.h"
#include "launchpad.h"
#include "source_package_publishing_history.h"
#include <iostream>
#include <nlohmann/json.hpp>
archive::archive()
: authorized_size(0),
build_debug_symbols(false),
description(""),
displayname(""),
distribution_link(""),
external_dependencies(""),
metadata_overrides(nlohmann::json::object()),
name(""),
owner_link(""),
permit_obsolete_series_uploads(false),
is_private(false),
publish(false),
publish_debug_symbols(false),
publishing_method(""),
relative_build_score(0),
repository_format(""),
require_virtualized(false),
signing_key_fingerprint(""),
suppress_subscription_notifications(false),
owner_name(""),
ppa_name(""),
lp(nullptr) {}
archive::~archive() {}
std::optional<archive> archive::parse(const std::string& json_data) {
archive a;
a.parse_json(json_data);
return a;
}
void archive::parse_json(const std::string& json_data) {
if (json_data.empty()) {
std::cerr << "Error: Empty JSON data for archive::parse_json." << std::endl;
return;
}
try {
auto data = nlohmann::json::parse(json_data);
// Map JSON keys to member variable setters
std::map<std::string, std::function<void(const nlohmann::json&)>> json_map = {
{"authorized_size", [this](const nlohmann::json& val) { authorized_size = val.get<int>(); }},
{"build_debug_symbols", [this](const nlohmann::json& val) { build_debug_symbols = val.get<bool>(); }},
{"description", [this](const nlohmann::json& val) { description = val.get<std::string>(); }},
{"displayname", [this](const nlohmann::json& val) { displayname = val.get<std::string>(); }},
{"distribution_link", [this](const nlohmann::json& val) { distribution_link = val.get<std::string>(); }},
{"external_dependencies", [this](const nlohmann::json& val) { external_dependencies = val.get<std::string>(); }},
{"metadata_overrides", [this](const nlohmann::json& val) { metadata_overrides = val; }},
{"name", [this](const nlohmann::json& val) { name = val.get<std::string>(); }},
{"owner_link", [this](const nlohmann::json& val) { owner_link = val.get<std::string>(); }},
{"permit_obsolete_series_uploads", [this](const nlohmann::json& val) { permit_obsolete_series_uploads = val.get<bool>(); }},
{"private", [this](const nlohmann::json& val) { is_private = val.get<bool>(); }},
{"publish", [this](const nlohmann::json& val) { publish = val.get<bool>(); }},
{"publish_debug_symbols", [this](const nlohmann::json& val) { publish_debug_symbols = val.get<bool>(); }},
{"publishing_method", [this](const nlohmann::json& val) { publishing_method = val.get<std::string>(); }},
{"relative_build_score", [this](const nlohmann::json& val) { relative_build_score = val.get<int>(); }},
{"repository_format", [this](const nlohmann::json& val) { repository_format = val.get<std::string>(); }},
{"require_virtualized", [this](const nlohmann::json& val) { require_virtualized = val.get<bool>(); }},
{"signing_key_fingerprint", [this](const nlohmann::json& val) { signing_key_fingerprint = val.get<std::string>(); }},
{"suppress_subscription_notifications", [this](const nlohmann::json& val) { suppress_subscription_notifications = val.get<bool>(); }}
};
// Handle read-only fields separately
std::map<std::string, std::function<void(const nlohmann::json&)>> readonly_map = {
{"dependencies_collection_link", [this](const nlohmann::json& val) { dependencies_collection_link = val.get<std::string>(); }},
{"enabled_restricted_processors_collection_link", [this](const nlohmann::json& val) { enabled_restricted_processors_collection_link = val.get<std::string>(); }},
{"http_etag", [this](const nlohmann::json& val) { http_etag = val.get<std::string>(); }},
{"processors_collection_link", [this](const nlohmann::json& val) { processors_collection_link = val.get<std::string>(); }},
{"reference", [this](const nlohmann::json& val) { reference = val.get<std::string>(); }},
{"resource_type_link", [this](const nlohmann::json& val) { resource_type_link = val.get<std::string>(); }},
{"self_link", [this](const nlohmann::json& val) { self_link = val.get<std::string>(); }},
{"status", [this](const nlohmann::json& val) { status = val.get<std::string>(); }},
{"web_link", [this](const nlohmann::json& val) { web_link = val.get<std::string>(); }}
};
// Process all keys in the JSON object
for (auto& [key, value] : data.items()) {
try {
if (json_map.find(key) != json_map.end()) {
json_map[key](value);
json_map.erase(key);
} else if (readonly_map.find(key) != readonly_map.end()) {
readonly_map[key](value);
readonly_map.erase(key);
}
} catch (const std::exception& e) {
continue;
}
}
// Special handling for owner_name and ppa_name
std::string link = owner_link;
size_t pos = link.find("~");
if (pos != std::string::npos) {
owner_name = link.substr(pos + 1);
if (!owner_name.empty() && owner_name.back() == '/') {
owner_name.pop_back();
}
}
ppa_name = name;
} catch (const nlohmann::json::parse_error& e) {
std::cerr << "JSON parse error in archive::parse_json: " << e.what() << std::endl;
std::cerr << "Input JSON was: " << json_data << std::endl;
} catch (const std::exception& e) {
std::cerr << "Unexpected error during JSON parsing: " << e.what() << std::endl;
}
}
std::string archive::build_archive_endpoint() const {
return "~" + url_encode(owner_name) + "/" + url_encode(ppa_name);
}
std::generator<source_package_publishing_history> archive::getPublishedSources(const std::string& status) const {
std::map<std::string, std::string> params;
params["ws.op"] = "getPublishedSources";
params["status"] = status;
auto response = lp->api_get(this->self_link, params);
auto data = nlohmann::json::parse(response.value());
while (response.has_value() && data.contains("next_collection_link") && data["next_collection_link"] != "") {
try {
if (data.contains("entries") && data["entries"].is_array()) {
for (auto& entry : data["entries"]) {
auto s_opt = source_package_publishing_history::parse(entry.dump());
if (!s_opt) continue;
s_opt->set_lp(lp);
co_yield s_opt.value();
}
}
response = lp->api_get(data["next_collection_link"]);
data = nlohmann::json::parse(response.value());
} catch (const std::exception& e) {
std::cerr << "Error parsing published sources: " << e.what() << std::endl;
}
}
}
void archive::set_lp(launchpad* lp_ptr) {
lp = lp_ptr;
}