#include "distro_series.h" #include "launchpad.h" #include "utils.h" #include #include 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::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(); }; auto get_str = [&](const std::string& key, std::string& field) { if (data.contains(key) && data[key].is_string()) field = data[key].get(); }; auto get_str_vec = [&](const std::string& key, std::vector& 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()); } } }; 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::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 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 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()); if(!response)break; data=nlohmann::json::parse(response.value()); } } std::generator distro_series::getDerivedSeries() const { if(!lp || self_link.empty()) co_return; std::map 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()); if(!response)break; data=nlohmann::json::parse(response.value()); } } std::generator distro_series::getDifferenceComments(const std::string& since, const std::string& source_package_name) const { if(!lp||self_link.empty()) co_return; std::map 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()); if(!response)break; data=nlohmann::json::parse(response.value()); } } std::generator distro_series::getDifferencesTo(const std::optional& parent_series, const std::optional& difference_type, const std::optional& source_package_name_filter, const std::optional& status, bool child_version_higher) const { if(!lp||self_link.empty()) co_return; std::map 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()); if(!response)break; data=nlohmann::json::parse(response.value()); } } std::optional distro_series::getDistroArchSeries(const std::string& archtag) const { if(!lp||self_link.empty())return std::nullopt; std::map 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 distro_series::getPackageUploads(const std::optional& archive, const std::optional& created_since_date, const std::optional& custom_type, bool exact_match, const std::optional& name, const std::optional& pocket, const std::optional& status, const std::optional& version) const { if(!lp||self_link.empty()) co_return; std::map 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()); if(!response)break; data=nlohmann::json::parse(response.value()); } } std::generator distro_series::getParentSeries() const { if(!lp||self_link.empty()) co_return; std::map 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()); if(!response)break; data=nlohmann::json::parse(response.value()); } } std::optional distro_series::getSourcePackage(const std::string& name_) const { if(!lp||self_link.empty())return std::nullopt; std::map 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 distro_series::getSpecification(const std::string& name_) const { if(!lp||self_link.empty())return std::nullopt; std::map 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 distro_series::getSubscription(const std::string& person) const { if(!lp||self_link.empty())return std::nullopt; std::map 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 distro_series::getSubscriptions() const { if(!lp||self_link.empty()) co_return; std::map 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()); if(!response)break; data=nlohmann::json::parse(response.value()); } } std::generator distro_series::getTranslationImportQueueEntries(const std::optional& import_status, const std::optional& file_extension) const { if(!lp||self_link.empty()) co_return; std::mapparams; 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()); if(!response)break; data=nlohmann::json::parse(response.value()); } } std::optional distro_series::getTranslationTemplateStatistics() const { if(!lp||self_link.empty())return std::nullopt; std::mapparams; 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 distro_series::getTranslationTemplates() const { if(!lp||self_link.empty()) co_return; std::mapparams; 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()); if(!response) break; data=nlohmann::json::parse(response.value()); } } std::generator distro_series::searchTasks(const std::map& params_in) const { if(!lp||self_link.empty()) co_return; std::map 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()); if(!response)break; data=nlohmann::json::parse(response.value()); } } std::optional distro_series::userHasBugSubscriptions() const { if(!lp||self_link.empty())return std::nullopt; std::mapparams; 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& subscriber) const { if(!lp||self_link.empty())return false; std::mapparams; 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& subscriber) const { if(!lp||self_link.empty())return false; std::mapparams; 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& archindep_archtag, const std::vector& architectures, const std::vector& overlay_components, const std::vector& overlay_pockets, const std::vector& overlays, const std::vector& packagesets, const std::vector& parents, bool rebuild) const { if(!lp||self_link.empty())return false; std::mapparams; params["ws.op"]="initDerivedDistroSeries"; if(archindep_archtag.has_value()) params["archindep_archtag"]=archindep_archtag.value(); auto join_list = [](const std::vector& 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 distro_series::newMilestone(const std::string& name, const std::optional& code_name, const std::optional& date_targeted, const std::optional& summary) const { if(!lp||self_link.empty())return std::nullopt; std::mapparams; 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& subscriber) const { if(!lp||self_link.empty())return false; std::mapparams; params["ws.op"]="removeBugSubscription"; if(subscriber.has_value()) params["subscriber"]=subscriber.value(); auto resp=lp->api_post(self_link,params); return resp.has_value(); }