Update source/src/templates.cpp
This commit is contained in:
@@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user