launchpadlib-cpp/src/distro_series.cpp

522 lines
23 KiB
C++

#include "distro_series.h"
#include "launchpad.h"
#include "utils.h"
#include <iostream>
#include <nlohmann/json.hpp>
distro_series::distro_series()
: active(false),
advertise_by_hash(false),
backports_not_automatic(false),
include_long_descriptions(false),
language_pack_full_export_requested(false),
proposed_not_automatic(false),
publish_by_hash(false),
publish_i18n_index(false),
strict_supported_component_dependencies(false),
supported(false),
lp(nullptr) {}
distro_series::~distro_series() {}
std::optional<distro_series> distro_series::parse(const std::string& json_data) {
distro_series ds;
ds.parse_json(json_data);
return ds;
}
void distro_series::parse_json(const std::string& json_data) {
if (json_data.empty()) {
std::cerr << "Error: Empty JSON data for distro_series::parse_json." << std::endl;
return;
}
try {
auto data = nlohmann::json::parse(json_data);
auto get_bool = [&](const std::string& key, bool& field) {
if (data.contains(key) && data[key].is_boolean()) field = data[key].get<bool>();
};
auto get_str = [&](const std::string& key, std::string& field) {
if (data.contains(key) && data[key].is_string()) field = data[key].get<std::string>();
};
auto get_str_vec = [&](const std::string& key, std::vector<std::string>& field) {
if (data.contains(key) && data[key].is_array()) {
field.clear();
for (auto& e : data[key]) {
if (e.is_string()) field.push_back(e.get<std::string>());
}
}
};
get_bool("active", active);
get_bool("advertise_by_hash", advertise_by_hash);
get_str("all_milestones_collection_link", all_milestones_collection_link);
get_str("all_specifications_collection_link", all_specifications_collection_link);
get_str("architectures_collection_link", architectures_collection_link);
get_bool("backports_not_automatic", backports_not_automatic);
get_str("bug_reported_acknowledgement", bug_reported_acknowledgement);
get_str("bug_reporting_guidelines", bug_reporting_guidelines);
get_str("changeslist", changeslist);
get_str_vec("component_names", component_names);
get_str("date_created", date_created);
get_str("datereleased", datereleased);
get_str("description", description);
get_str("displayname", displayname);
get_str("distribution_link", distribution_link);
get_str("driver_link", driver_link);
get_str("drivers_collection_link", drivers_collection_link);
get_str("fullseriesname", fullseriesname);
get_str("http_etag", http_etag);
get_bool("include_long_descriptions", include_long_descriptions);
get_str_vec("index_compressors", index_compressors);
get_bool("language_pack_full_export_requested", language_pack_full_export_requested);
get_str("main_archive_link", main_archive_link);
get_str("name", name);
get_str("nominatedarchindep_link", nominatedarchindep_link);
get_str_vec("official_bug_tags", official_bug_tags);
get_str("owner_link", owner_link);
get_str("previous_series_link", previous_series_link);
get_bool("proposed_not_automatic", proposed_not_automatic);
get_bool("publish_by_hash", publish_by_hash);
get_bool("publish_i18n_index", publish_i18n_index);
get_str("registrant_link", registrant_link);
get_str("resource_type_link", resource_type_link);
get_str("self_link", self_link);
get_str("status", status);
get_bool("strict_supported_component_dependencies", strict_supported_component_dependencies);
get_str_vec("suite_names", suite_names);
get_str("summary", summary);
get_bool("supported", supported);
get_str("title", title);
get_str("translations_usage", translations_usage);
get_str("valid_specifications_collection_link", valid_specifications_collection_link);
get_str("version", version);
get_str("web_link", web_link);
// These additional fields might not be present in the JSON, but we define them if they exist
// They are listed as additional read-only fields in the header, but were not found in the JSON keys above
// We'll just attempt to parse them similarly if they exist
get_str("active_milestones_collection_link", active_milestones_collection_link);
get_str("archive_mirrors_collection_link", archive_mirrors_collection_link);
get_str("archives_collection_link", archives_collection_link);
get_str("series_collection_link", series_collection_link);
get_str("vulnerabilities_collection_link", vulnerabilities_collection_link);
get_str("webhooks_collection_link", webhooks_collection_link);
} catch (const nlohmann::json::parse_error& e) {
std::cerr << "JSON parse error in distro_series::parse_json: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Unexpected error during JSON parsing: " << e.what() << std::endl;
}
}
void distro_series::set_lp(launchpad* lp_ptr) {
lp = lp_ptr;
}
std::optional<distro_series> distro_series::get() const {
if (self_link.empty()) return std::nullopt;
auto resp = lp->api_get(self_link);
if(!resp)return std::nullopt;
return parse(resp.value());
}
bool distro_series::patch(const nlohmann::json& data) const {
if (self_link.empty()) return false;
auto resp = lp->api_patch(self_link, data);
return resp.has_value();
}
bool distro_series::put(const nlohmann::json& data) const {
if (self_link.empty()) return false;
std::string endpoint = self_link + "?ws.op=replace";
auto resp = lp->api_patch(endpoint, data);
return resp.has_value();
}
std::generator<nlohmann::json> distro_series::getBuildRecords(const std::string& build_state, const std::string& pocket, const std::string& source_name) const {
if (!lp) co_return;
if (self_link.empty()) co_return;
std::map<std::string,std::string> params;
params["ws.op"] = "getBuildRecords";
if(!build_state.empty()) params["build_state"]=build_state;
if(!pocket.empty()) params["pocket"]=pocket;
if(!source_name.empty()) params["source_name"]=source_name;
auto response=lp->api_get(self_link, params);
if(!response) co_return;
auto data=nlohmann::json::parse(response.value());
while(true) {
if(data.contains("entries") && data["entries"].is_array()) {
for(auto&e:data["entries"]){
co_yield e;
}
}
if(!data.contains("next_collection_link") || data["next_collection_link"].is_null() || data["next_collection_link"]=="") break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response)break;
data=nlohmann::json::parse(response.value());
}
}
std::generator<distro_series> distro_series::getDerivedSeries() const {
if(!lp || self_link.empty()) co_return;
std::map<std::string,std::string> params;
params["ws.op"]="getDerivedSeries";
auto response=lp->api_get(self_link,params);
if(!response) co_return;
auto data=nlohmann::json::parse(response.value());
while(true){
if(data.contains("entries") && data["entries"].is_array()){
for(auto&e:data["entries"]){
auto ds_opt = parse(e.dump());
if(ds_opt){
ds_opt->set_lp(lp);
co_yield ds_opt.value();
}
}
}
if(!data.contains("next_collection_link")||data["next_collection_link"].is_null()||data["next_collection_link"]=="")break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response)break;
data=nlohmann::json::parse(response.value());
}
}
std::generator<nlohmann::json> distro_series::getDifferenceComments(const std::string& since, const std::string& source_package_name) const {
if(!lp||self_link.empty()) co_return;
std::map<std::string,std::string> params;
params["ws.op"]="getDifferenceComments";
if(!since.empty()) params["since"]=since;
if(!source_package_name.empty()) params["source_package_name"]=source_package_name;
auto response=lp->api_get(self_link,params);
if(!response) co_return;
auto data=nlohmann::json::parse(response.value());
while(true){
if(data.contains("entries") && data["entries"].is_array()){
for(auto&e:data["entries"]){
co_yield e;
}
}
if(!data.contains("next_collection_link")||data["next_collection_link"].is_null()||data["next_collection_link"]=="")break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response)break;
data=nlohmann::json::parse(response.value());
}
}
std::generator<nlohmann::json> distro_series::getDifferencesTo(const std::optional<std::string>& parent_series,
const std::optional<std::string>& difference_type,
const std::optional<std::string>& source_package_name_filter,
const std::optional<std::string>& status,
bool child_version_higher) const {
if(!lp||self_link.empty()) co_return;
std::map<std::string,std::string> params;
params["ws.op"]="getDifferencesTo";
if(parent_series.has_value()) params["parent_series"]=parent_series.value();
if(difference_type.has_value()) params["difference_type"]=difference_type.value();
if(source_package_name_filter.has_value()) params["source_package_name_filter"]=source_package_name_filter.value();
if(status.has_value()) params["status"]=status.value();
if(child_version_higher) params["child_version_higher"]="true";
auto response=lp->api_get(self_link,params);
if(!response) co_return;
auto data=nlohmann::json::parse(response.value());
// Usually differences might have entries too
while(true){
if(data.contains("entries")&&data["entries"].is_array()){
for(auto&e:data["entries"]){
co_yield e;
}
}
if(!data.contains("next_collection_link")||data["next_collection_link"].is_null()||data["next_collection_link"]=="")break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response)break;
data=nlohmann::json::parse(response.value());
}
}
std::optional<nlohmann::json> distro_series::getDistroArchSeries(const std::string& archtag) const {
if(!lp||self_link.empty())return std::nullopt;
std::map<std::string,std::string> params;
params["ws.op"]="getDistroArchSeries";
params["archtag"]=archtag;
auto response=lp->api_get(self_link,params);
if(!response)return std::nullopt;
return nlohmann::json::parse(response.value());
}
std::generator<nlohmann::json> distro_series::getPackageUploads(const std::optional<std::string>& archive,
const std::optional<std::string>& created_since_date,
const std::optional<std::string>& custom_type,
bool exact_match,
const std::optional<std::string>& name,
const std::optional<std::string>& pocket,
const std::optional<std::string>& status,
const std::optional<std::string>& version) const {
if(!lp||self_link.empty()) co_return;
std::map<std::string,std::string> params;
params["ws.op"]="getPackageUploads";
if(archive.has_value()) params["archive"]=archive.value();
if(created_since_date.has_value()) params["created_since_date"]=created_since_date.value();
if(custom_type.has_value()) params["custom_type"]=custom_type.value();
if(exact_match) params["exact_match"]="true";
if(name.has_value()) params["name"]=name.value();
if(pocket.has_value()) params["pocket"]=pocket.value();
if(status.has_value()) params["status"]=status.value();
if(version.has_value()) params["version"]=version.value();
auto response=lp->api_get(self_link,params);
if(!response) co_return;
auto data=nlohmann::json::parse(response.value());
while(true){
if(data.contains("entries") && data["entries"].is_array()){
for(auto&e:data["entries"]) {
co_yield e;
}
}
if(!data.contains("next_collection_link")||data["next_collection_link"].is_null()||data["next_collection_link"]=="") break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response)break;
data=nlohmann::json::parse(response.value());
}
}
std::generator<distro_series> distro_series::getParentSeries() const {
if(!lp||self_link.empty()) co_return;
std::map<std::string,std::string> params;
params["ws.op"]="getParentSeries";
auto response=lp->api_get(self_link,params);
if(!response) co_return;
auto data=nlohmann::json::parse(response.value());
while(true) {
if(data.contains("entries")&&data["entries"].is_array()){
for(auto&e:data["entries"]){
auto ds_opt=parse(e.dump());
if(ds_opt){
ds_opt->set_lp(lp);
co_yield ds_opt.value();
}
}
}
if(!data.contains("next_collection_link")||data["next_collection_link"].is_null()||data["next_collection_link"]=="")break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response)break;
data=nlohmann::json::parse(response.value());
}
}
std::optional<nlohmann::json> distro_series::getSourcePackage(const std::string& name_) const {
if(!lp||self_link.empty())return std::nullopt;
std::map<std::string,std::string> params;
params["ws.op"]="getSourcePackage";
params["name"]=name_;
auto resp=lp->api_get(self_link,params);
if(!resp)return std::nullopt;
return nlohmann::json::parse(resp.value());
}
std::optional<nlohmann::json> distro_series::getSpecification(const std::string& name_) const {
if(!lp||self_link.empty())return std::nullopt;
std::map<std::string,std::string> params;
params["ws.op"]="getSpecification";
params["name"]=name_;
auto resp=lp->api_get(self_link,params);
if(!resp)return std::nullopt;
return nlohmann::json::parse(resp.value());
}
std::optional<nlohmann::json> distro_series::getSubscription(const std::string& person) const {
if(!lp||self_link.empty())return std::nullopt;
std::map<std::string,std::string> params;
params["ws.op"]="getSubscription";
params["person"]=person;
auto resp=lp->api_get(self_link,params);
if(!resp)return std::nullopt;
return nlohmann::json::parse(resp.value());
}
std::generator<nlohmann::json> distro_series::getSubscriptions() const {
if(!lp||self_link.empty()) co_return;
std::map<std::string,std::string> params;
params["ws.op"]="getSubscriptions";
auto response=lp->api_get(self_link,params);
if(!response) co_return;
auto data=nlohmann::json::parse(response.value());
while(true) {
if(data.contains("entries")&&data["entries"].is_array()){
for(auto&e:data["entries"]){
co_yield e;
}
}
if(!data.contains("next_collection_link")||data["next_collection_link"].is_null()||data["next_collection_link"]=="")break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response)break;
data=nlohmann::json::parse(response.value());
}
}
std::generator<nlohmann::json> distro_series::getTranslationImportQueueEntries(const std::optional<std::string>& import_status,
const std::optional<std::string>& file_extension) const {
if(!lp||self_link.empty()) co_return;
std::map<std::string,std::string>params;
params["ws.op"]="getTranslationImportQueueEntries";
if(import_status.has_value()) params["import_status"]=import_status.value();
if(file_extension.has_value()) params["file_extension"]=file_extension.value();
auto response=lp->api_get(self_link,params);
if(!response)co_return;
auto data=nlohmann::json::parse(response.value());
while(true){
if(data.contains("entries")&&data["entries"].is_array()){
for(auto&e:data["entries"]){
co_yield e;
}
}
if(!data.contains("next_collection_link")||data["next_collection_link"].is_null()||data["next_collection_link"]=="")break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response)break;
data=nlohmann::json::parse(response.value());
}
}
std::optional<nlohmann::json> distro_series::getTranslationTemplateStatistics() const {
if(!lp||self_link.empty())return std::nullopt;
std::map<std::string,std::string>params;
params["ws.op"]="getTranslationTemplateStatistics";
auto resp=lp->api_get(self_link,params);
if(!resp)return std::nullopt;
return nlohmann::json::parse(resp.value());
}
std::generator<nlohmann::json> distro_series::getTranslationTemplates() const {
if(!lp||self_link.empty()) co_return;
std::map<std::string,std::string>params;
params["ws.op"]="getTranslationTemplates";
auto response=lp->api_get(self_link,params);
if(!response)co_return;
auto data=nlohmann::json::parse(response.value());
while(true){
if(data.contains("entries")&&data["entries"].is_array()){
for(auto&e:data["entries"]){
co_yield e;
}
}
if(!data.contains("next_collection_link")||data["next_collection_link"].is_null()||data["next_collection_link"]=="") break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response) break;
data=nlohmann::json::parse(response.value());
}
}
std::generator<nlohmann::json> distro_series::searchTasks(const std::map<std::string,std::string>& params_in) const {
if(!lp||self_link.empty()) co_return;
std::map<std::string,std::string> params = params_in;
params["ws.op"]="searchTasks";
auto response=lp->api_get(self_link,params);
if(!response) co_return;
auto data=nlohmann::json::parse(response.value());
while(true){
if(data.contains("entries")&&data["entries"].is_array()){
for(auto&e:data["entries"]){
co_yield e;
}
}
if(!data.contains("next_collection_link")||data["next_collection_link"].is_null()||data["next_collection_link"]=="")break;
response=lp->api_get(data["next_collection_link"].get<std::string>());
if(!response)break;
data=nlohmann::json::parse(response.value());
}
}
std::optional<nlohmann::json> distro_series::userHasBugSubscriptions() const {
if(!lp||self_link.empty())return std::nullopt;
std::map<std::string,std::string>params;
params["ws.op"]="userHasBugSubscriptions";
auto resp=lp->api_get(self_link,params);
if(!resp)return std::nullopt;
return nlohmann::json::parse(resp.value());
}
bool distro_series::addBugSubscription(const std::optional<std::string>& subscriber) const {
if(!lp||self_link.empty())return false;
std::map<std::string,std::string>params;
params["ws.op"]="addBugSubscription";
if(subscriber.has_value()) params["subscriber"]=subscriber.value();
auto resp=lp->api_post(self_link,params);
return resp.has_value();
}
bool distro_series::addBugSubscriptionFilter(const std::optional<std::string>& subscriber) const {
if(!lp||self_link.empty())return false;
std::map<std::string,std::string>params;
params["ws.op"]="addBugSubscriptionFilter";
if(subscriber.has_value())params["subscriber"]=subscriber.value();
auto resp=lp->api_post(self_link,params);
return resp.has_value();
}
bool distro_series::initDerivedDistroSeries(const std::optional<std::string>& archindep_archtag,
const std::vector<std::string>& architectures,
const std::vector<std::string>& overlay_components,
const std::vector<std::string>& overlay_pockets,
const std::vector<std::string>& overlays,
const std::vector<std::string>& packagesets,
const std::vector<std::string>& parents,
bool rebuild) const {
if(!lp||self_link.empty())return false;
std::map<std::string,std::string>params;
params["ws.op"]="initDerivedDistroSeries";
if(archindep_archtag.has_value()) params["archindep_archtag"]=archindep_archtag.value();
auto join_list = [](const std::vector<std::string>& vec){
std::string joined;
for (auto& v:vec) {
joined+=v+",";
}
if(!joined.empty()) joined.pop_back();
return joined;
};
if(!architectures.empty()) params["architectures"]=join_list(architectures);
if(!overlay_components.empty()) params["overlay_components"]=join_list(overlay_components);
if(!overlay_pockets.empty()) params["overlay_pockets"]=join_list(overlay_pockets);
if(!overlays.empty()) params["overlays"]=join_list(overlays);
if(!packagesets.empty()) params["packagesets"]=join_list(packagesets);
if(!parents.empty()) params["parents"]=join_list(parents);
if(rebuild) params["rebuild"]="true";
auto resp=lp->api_post(self_link,params);
return resp.has_value();
}
std::optional<nlohmann::json> distro_series::newMilestone(const std::string& name,
const std::optional<std::string>& code_name,
const std::optional<std::string>& date_targeted,
const std::optional<std::string>& summary) const {
if(!lp||self_link.empty())return std::nullopt;
std::map<std::string,std::string>params;
params["ws.op"]="newMilestone";
params["name"]=name;
if(code_name.has_value()) params["code_name"]=code_name.value();
if(date_targeted.has_value()) params["date_targeted"]=date_targeted.value();
if(summary.has_value()) params["summary"]=summary.value();
auto resp=lp->api_post(self_link,params);
if(!resp)return std::nullopt;
return nlohmann::json::parse(resp.value());
}
bool distro_series::removeBugSubscription(const std::optional<std::string>& subscriber) const {
if(!lp||self_link.empty())return false;
std::map<std::string,std::string>params;
params["ws.op"]="removeBugSubscription";
if(subscriber.has_value()) params["subscriber"]=subscriber.value();
auto resp=lp->api_post(self_link,params);
return resp.has_value();
}