Update source/src/templates.cpp
All checks were successful
Build-Test-Publish / build (linux/amd64) (push) Successful in 42s
Build-Test-Publish / build (linux/arm64) (push) Successful in 1m14s

This commit is contained in:
Your Name
2025-08-24 21:35:45 +12:00
parent e895360871
commit ebc59c40b2

View File

@@ -6,11 +6,13 @@
#include <algorithm> #include <algorithm>
#include <iomanip> #include <iomanip>
#include <map> #include <map>
#include <chrono>
#include <libassert/assert.hpp> #include <libassert/assert.hpp>
#include "utils/envmanager.hpp" #include "utils/envmanager.hpp"
#include "utils/directories.hpp" #include "utils/directories.hpp"
#include "utils/utils.hpp" #include "utils/utils.hpp"
#include "utils/output.hpp"
#include "templates.hpp" #include "templates.hpp"
#include "config.hpp" #include "config.hpp"
#include "utils/hash.hpp" #include "utils/hash.hpp"
@@ -69,32 +71,272 @@
std::set<std::string> template_source_registry::get_template_list() std::set<std::string> template_source_registry::get_template_list()
{ {
#pragma message("TODO: Implement template_source_registry::get_template_list") // Query the registry for available templates
return std::set<std::string>(); // The registry should return a JSON list of available templates
std::string list_url = mRegistry.url + "/dir";
nlohmann::json json_response;
// For HTTPS URLs, use curl to fetch the JSON
if (list_url.substr(0, 8) == "https://") {
std::string temp_file = "/tmp/dropshell_registry_list_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count());
std::string cmd = "curl -fsSL " + quote(list_url) + " -o " + quote(temp_file) + " 2>/dev/null";
int result = system(cmd.c_str());
if (result == 0) {
try {
std::ifstream file(temp_file);
if (file.is_open()) {
file >> json_response;
file.close();
}
} catch (...) {
// Failed to parse JSON
}
std::filesystem::remove(temp_file);
}
} else {
json_response = get_json_from_url(list_url);
}
std::set<std::string> templates;
if (json_response.is_null() || !json_response.contains("entries")) {
warning << "Failed to get template list from registry: " << mRegistry.name << std::endl;
return templates;
}
// Parse the entries array to extract unique template names
for (const auto& entry : json_response["entries"]) {
if (entry.contains("labeltags")) {
for (const auto& label : entry["labeltags"]) {
// Extract template name from label (format: "template:version")
std::string label_str = label.get<std::string>();
size_t colon_pos = label_str.find(':');
if (colon_pos != std::string::npos) {
std::string template_name = label_str.substr(0, colon_pos);
templates.insert(template_name);
}
}
}
}
return templates;
} }
bool template_source_registry::has_template(const std::string& template_name) bool template_source_registry::has_template(const std::string& template_name)
{ {
#pragma message("TODO: Implement template_source_registry::has_template") // Check if template exists in registry
std::string check_url = mRegistry.url + "/exists/" + template_name + ":latest";
// For HTTPS URLs, use curl to fetch the JSON
nlohmann::json json_response;
if (check_url.substr(0, 8) == "https://") {
// Create a temporary file for the response
std::string temp_file = "/tmp/dropshell_registry_check_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count());
std::string cmd = "curl -fsSL " + quote(check_url) + " -o " + quote(temp_file) + " 2>/dev/null";
int result = system(cmd.c_str());
if (result == 0) {
try {
std::ifstream file(temp_file);
if (file.is_open()) {
file >> json_response;
file.close();
}
} catch (...) {
// Failed to parse JSON
}
std::filesystem::remove(temp_file);
}
} else {
json_response = get_json_from_url(check_url);
}
if (!json_response.is_null() && json_response.contains("exists")) {
return json_response["exists"].get<bool>();
}
return false; return false;
} }
template_info template_source_registry::get_template_info(const std::string& template_name) template_info template_source_registry::get_template_info(const std::string& template_name)
{ {
#pragma message("TODO: Implement template_source_registry::get_template_info") // Check if template exists in registry
return template_info(); if (!has_template(template_name)) {
return template_info();
}
// Get cache directory
std::filesystem::path cache_dir = get_cache_dir();
std::filesystem::path template_cache_dir = cache_dir / template_name;
std::filesystem::path template_json_file = cache_dir / (template_name + ".json");
// Create cache directory if it doesn't exist
if (!std::filesystem::exists(cache_dir)) {
std::filesystem::create_directories(cache_dir);
}
// Get metadata from registry to check version
std::string meta_url = mRegistry.url + "/meta/" + template_name + ":latest";
nlohmann::json registry_metadata;
// For HTTPS URLs, use curl to fetch the JSON
if (meta_url.substr(0, 8) == "https://") {
std::string temp_file = "/tmp/dropshell_registry_meta_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count());
std::string cmd = "curl -fsSL " + quote(meta_url) + " -o " + quote(temp_file) + " 2>/dev/null";
int result = system(cmd.c_str());
if (result == 0) {
try {
std::ifstream file(temp_file);
if (file.is_open()) {
file >> registry_metadata;
file.close();
}
} catch (...) {
// Failed to parse JSON
}
std::filesystem::remove(temp_file);
}
} else {
registry_metadata = get_json_from_url(meta_url);
}
if (registry_metadata.is_null()) {
warning << "Failed to get metadata for template: " << template_name << std::endl;
return template_info();
}
// Check if we need to download/update the template
bool need_download = true;
std::string registry_version = "unknown";
std::string registry_hash = "";
// Extract version and hash from registry metadata
if (registry_metadata.contains("metadata")) {
auto& metadata = registry_metadata["metadata"];
if (metadata.contains("version")) {
registry_version = metadata["version"].get<std::string>();
}
}
if (registry_metadata.contains("hash")) {
registry_hash = registry_metadata["hash"].get<std::string>();
}
// Check if we have a cached version
if (std::filesystem::exists(template_json_file)) {
try {
std::ifstream cache_file(template_json_file);
nlohmann::json cache_json;
cache_file >> cache_json;
cache_file.close();
// Compare versions or hashes
if (cache_json.contains("hash") && !registry_hash.empty()) {
if (cache_json["hash"].get<std::string>() == registry_hash) {
need_download = false;
}
} else if (cache_json.contains("version")) {
std::string cached_version = cache_json["version"].get<std::string>();
if (cached_version == registry_version) {
need_download = false;
}
}
} catch (...) {
// If reading cache fails, re-download
need_download = true;
}
}
// Download and extract if needed
if (need_download) {
info << "Downloading template '" << template_name << "' from registry..." << std::endl;
// Download the .tgz file
std::string download_url = mRegistry.url + "/" + template_name + ":latest";
std::filesystem::path temp_tgz = cache_dir / (template_name + ".tgz");
if (!download_file(download_url, temp_tgz.string())) {
error << "Failed to download template: " << template_name << std::endl;
return template_info();
}
// Remove old template directory if it exists
if (std::filesystem::exists(template_cache_dir)) {
std::filesystem::remove_all(template_cache_dir);
}
// Extract the .tgz file
std::string extract_cmd = "tar -xzf " + quote(temp_tgz.string()) + " -C " + quote(cache_dir.string());
int result = system(extract_cmd.c_str());
if (result != 0) {
error << "Failed to extract template: " << template_name << std::endl;
std::filesystem::remove(temp_tgz);
return template_info();
}
// Clean up the .tgz file
std::filesystem::remove(temp_tgz);
// Generate .template_info.env if it doesn't exist
std::filesystem::path template_info_env_path = template_cache_dir / "config" / filenames::template_info_env;
if (!std::filesystem::exists(template_info_env_path)) {
// Create config directory if needed
std::filesystem::create_directories(template_cache_dir / "config");
// Write .template_info.env file
std::ofstream info_file(template_info_env_path);
info_file << "# Template information" << std::endl;
info_file << "TEMPLATE=" << template_name << std::endl;
info_file << "TEMPLATE_SOURCE=registry" << std::endl;
info_file << "TEMPLATE_REGISTRY=" << mRegistry.name << std::endl;
info_file << "TEMPLATE_VERSION=" << registry_version << std::endl;
if (!registry_hash.empty()) {
info_file << "TEMPLATE_HASH=" << registry_hash << std::endl;
}
info_file.close();
}
// Update cache JSON file
nlohmann::json cache_json;
cache_json["template"] = template_name;
cache_json["version"] = registry_version;
cache_json["hash"] = registry_hash;
cache_json["registry"] = mRegistry.name;
cache_json["last_updated"] = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::ofstream cache_file(template_json_file);
cache_file << cache_json.dump(4);
cache_file.close();
info << "Template '" << template_name << "' downloaded and cached successfully" << std::endl;
}
// Return template info pointing to the cached template
return template_info(
template_name,
"Registry: " + mRegistry.name,
template_cache_dir
);
} }
bool template_source_registry::template_command_exists(const std::string& template_name, const std::string& command) bool template_source_registry::template_command_exists(const std::string& template_name, const std::string& command)
{ {
#pragma message("TODO: Implement template_source_registry::template_command_exists") // Get template info to ensure it's downloaded and cached
return false; auto tinfo = get_template_info(template_name);
if (!tinfo.is_set()) {
return false;
}
// Check if the command script exists in the cached template
std::filesystem::path script_path = tinfo.local_template_path() / (command + ".sh");
return std::filesystem::exists(script_path);
} }
std::filesystem::path template_source_registry::get_cache_dir() std::filesystem::path template_source_registry::get_cache_dir()
{ {
#pragma message("TODO: Implement template_source_registry::get_cache_dir") return localpath::template_cache();
return std::filesystem::path();
} }