Skip to content
Yaml_Conf.cpp 5.96 KiB
Newer Older
Valerio Pastore's avatar
Valerio Pastore committed
#include <Yaml_Conf.h>
#include <fstream>
#include <filesystem>
#include <algorithm>
#include <iterator>
#include <cctype>
Valerio Pastore's avatar
Valerio Pastore committed
#include <boost/algorithm/string.hpp>
Valerio Pastore's avatar
Valerio Pastore committed
#include <iostream>
Valerio Pastore's avatar
Valerio Pastore committed
#include <ctime>
#include <iomanip>
Valerio Pastore's avatar
Valerio Pastore committed

using namespace inaf::oasbo::Configurators;

YamlConfigurator::YamlConfigurator(std::string path) {
	this->path = path;
	load(path);
}

void YamlConfigurator::load(std::string path) {
	if (!std::filesystem::exists(path)) {
Valerio Pastore's avatar
Valerio Pastore committed
		time_t now = time(nullptr);
		std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
				<< "]\t[YAML Configurator]\t" << "file: " << path
Valerio Pastore's avatar
Valerio Pastore committed
				<< " does not exits." << std::endl;
		return;
	}
	file = YAML::LoadFile(path);
	if (file.IsNull()) {
Valerio Pastore's avatar
Valerio Pastore committed
		time_t now = time(nullptr);
		std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
				<< "]\t[YAML Configurator]\t" << "file." << std::endl;
Valerio Pastore's avatar
Valerio Pastore committed
	}
	if (!file.IsSequence()) {
Valerio Pastore's avatar
Valerio Pastore committed
		time_t now = time(nullptr);
		std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
				<< "]\t[YAML Configurator]\t"
				<< "file does not contains a yaml sequence." << std::endl;
Valerio Pastore's avatar
Valerio Pastore committed
	}
}

/**
Valerio Pastore's avatar
Valerio Pastore committed
 @brief Updates the YAML configuration file by adding new configuration entries for the target key.
Valerio Pastore's avatar
Valerio Pastore committed
 It also removes old configurations corresponding to the target key.
 @param target The target key for which to add and remove configuration entries.
 */
Valerio Pastore's avatar
Valerio Pastore committed
int YamlConfigurator::pushConfigToSource(std::string target) {
	boost::to_lower(target);
	// Extracrs only target entries
	std::map<std::string, std::string> filteredMap;
	for (const auto &pair : this->config) {
Valerio Pastore's avatar
Valerio Pastore committed
		if (pair.first.compare(0, target.length(), target) == 0) {
Valerio Pastore's avatar
Valerio Pastore committed
			std::string key = pair.first.substr(target.length() + 1);
			boost::to_lower(key);
			filteredMap[key] = pair.second;
		}
	}

	// save the file content in a vector
	std::fstream ifile(path);
	std::vector<std::string> file_content;
	std::string line;
	while (std::getline(ifile, line)) {
		file_content.push_back(line);
	}
	ifile.close();
	// update the file content into the vector
	size_t pos = 0;
	for (; pos < file_content.size(); pos++) {
		if (file_content[pos].find(std::string("- ").append(target))
				!= std::string::npos) {
			for (auto pair : filteredMap) {
				pos += 1;
				std::string new_line("    " + pair.first + ": " + pair.second);
				auto insertionPoint = file_content.begin() + pos;
				file_content.insert(insertionPoint, new_line);
			}
			pos += 1;
			break;
		}
	}

	// remove the old configuration
	for (; pos < file_content.size(); pos++) {
		if (file_content[pos][0] != '-') {
			line = file_content[pos];
Valerio Pastore's avatar
Valerio Pastore committed
			// Remove leading whitespace from the string and stop analysis at the ":" character (excluding it)
Valerio Pastore's avatar
Valerio Pastore committed
			line = line.erase(0, line.find_first_not_of(' ')).substr(0,
					line.find(':'));
			boost::to_lower(line);
Valerio Pastore's avatar
Valerio Pastore committed
			bool found = false; // Checks if the line has been replaced by the new configuration
Valerio Pastore's avatar
Valerio Pastore committed
			for (auto key : filteredMap) {
				if (key.first.compare(line) == 0) {
					found = true;
					break;
				}
			}
			if (found) {
				file_content.erase(file_content.begin() + pos);
				pos--;
			}

		} else
			break;
	}

	// update the file with the content of the vector
	std::ofstream ofile(path, std::ofstream::trunc); // Open the file in truncation mode
	for (const auto &line : file_content) {
		ofile << line << std::endl;
	}
	ofile.close();

	load(path);
	return 1;
}

int YamlConfigurator::pushConfigToSource() {
Valerio Pastore's avatar
Valerio Pastore committed
	// extract targets
Valerio Pastore's avatar
Valerio Pastore committed
	std::vector<std::string> tagets;
	for (const auto &pair : config) {
		std::string key = pair.first;
		size_t pos = key.find('_');

		if (pos != std::string::npos) {
			std::string prefix = key.substr(0, pos);
			if (std::find(tagets.begin(), tagets.end(), prefix)
					== tagets.end()) {
				tagets.push_back(prefix);
			}
		}
	}
Valerio Pastore's avatar
Valerio Pastore committed
	// call push for each target
Valerio Pastore's avatar
Valerio Pastore committed
	for (auto target : tagets)
		pushConfigToSource(target);
	return 1;
}

int YamlConfigurator::readConfigFromSource(std::string target) {
	boost::to_lower(target);
	if (file.IsNull())
		return -1;
	try {
		for (auto element : file) {
			if (element[target]) {
				YAML::Node node = element[target];
				for (const auto &kvp : node) {
					config[target + "_" + kvp.first.as<std::string>()] =
							kvp.second.as<std::string>();
				}
			}
		}
	} catch (const YAML::Exception &e) {
Valerio Pastore's avatar
Valerio Pastore committed
		time_t now = time(nullptr);
		std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
				<< "]\t[YAML Configurator]\t" << "reading error: " << e.what()
Valerio Pastore's avatar
Valerio Pastore committed
				<< std::endl;
		return -1;
	}
	return 1;
}

int YamlConfigurator::readConfigFromSource() {
	if (file.IsNull())
		return -1;
	try {
Valerio Pastore's avatar
Valerio Pastore committed
		// Iterate over the elements of the YAML document
		for (const auto &element : file) {
			for (const auto &pair : element) {
				std::string elementName = element.first.as<std::string>();
				boost::to_lower(elementName);
				// If the element is a map, extract the keys and values
				if (pair.second.IsMap()) {
					for (const auto &subPair : pair.second) {
						std::string key = elementName + "_"
								+ subPair.first.as<std::string>();
						std::string value = subPair.second.as<std::string>();
						config[key] = value;
					}
				}
			}
		}
Valerio Pastore's avatar
Valerio Pastore committed
		for (const auto &element : file) {
			for (const auto &pair : element) {
				std::string elementName = element.first.as<std::string>();
				boost::to_lower(elementName);
Valerio Pastore's avatar
Valerio Pastore committed
				// If the element is a map, extract the keys and values
Valerio Pastore's avatar
Valerio Pastore committed
				if (pair.second.IsMap()) {
					for (const auto &subPair : pair.second) {
						std::string key = elementName + "_"
								+ subPair.first.as<std::string>();
						std::string value = subPair.second.as<std::string>();
						config[key] = value;
					}
				}
			}
		}
	} catch (const YAML::Exception &e) {
Valerio Pastore's avatar
Valerio Pastore committed
		time_t now = time(nullptr);
		std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
				<< "]\t[YAML Configurator]\t" << " reading error: " << e.what()
Valerio Pastore's avatar
Valerio Pastore committed
				<< std::endl;
		return -1;
	}
	return 1;
}

int YamlConfigurator::insert(std::map<std::string, std::string> conf,
		std::string target) {
	boost::to_lower(target);
	for (const auto &kvp : conf) {
		this->config[target + "_" + kvp.first] = kvp.second;
	}
	return 1;
}