From 299b8dd989079d18544dfbaa6c71d9aeed97f1d1 Mon Sep 17 00:00:00 2001 From: Chris Punches Date: Sun, 2 Mar 2025 00:29:26 -0500 Subject: [PATCH] modules now can access config entries in a new conf.d dir pulled by DPM core (ini file format) --- CMakeLists.txt | 5 +- include/ConfigManager.hpp | 88 +++++++++ include/ModuleLoader.hpp | 57 +++--- include/dpm_interface.hpp | 6 +- include/dpm_interface_helpers.hpp | 3 +- include/error.hpp | 4 +- include/handlers.hpp | 4 +- include/module_interface.hpp | 64 ++++--- modules/info.cpp | 63 ++++-- src/ConfigManager.cpp | 307 ++++++++++++++++++++++++++++++ src/ModuleLoader.cpp | 30 +++ src/dpm.cpp | 52 +++-- src/dpm_interface.cpp | 32 +++- src/dpm_interface_helpers.cpp | 41 +++- src/error.cpp | 30 +++ src/handlers.cpp | 32 +++- src/module_interface.cpp | 95 ++++++--- 17 files changed, 775 insertions(+), 138 deletions(-) create mode 100644 include/ConfigManager.hpp create mode 100644 src/ConfigManager.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 04b44c5..f78ca60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,16 +6,15 @@ set(CMAKE_CXX_STANDARD 20) # Create modules directory file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/modules) -add_executable( - dpm +add_executable(dpm src/dpm.cpp src/ModuleLoader.cpp src/dpm_interface.cpp src/error.cpp - include/dpm_interface_helpers.hpp src/dpm_interface_helpers.cpp src/handlers.cpp src/module_interface.cpp + src/ConfigManager.cpp ) target_include_directories(dpm PRIVATE include) diff --git a/include/ConfigManager.hpp b/include/ConfigManager.hpp new file mode 100644 index 0000000..90e7554 --- /dev/null +++ b/include/ConfigManager.hpp @@ -0,0 +1,88 @@ +/** + * @file ConfigManager.hpp + * @brief Configuration management system for the DPM utility + * + * Defines the ConfigManager class which is responsible for loading, parsing, + * and providing access to configuration values from INI-style files in the + * /etc/dpm/conf.d/ directory. Supports the configuration needs of both the + * DPM core and its modules. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ConfigManager { + public: + // Constructor + ConfigManager(const std::string& config_dir = "/etc/dpm/conf.d/"); + + // Load all configuration files from the config directory + bool loadConfigurations(); + + // Get configuration values with type conversion + const char* getConfigValue(const char* section, const char* key) const; + std::string getConfigString(const char* section, const char* key, const std::string& defaultValue = "") const; + int getConfigInt(const char* section, const char* key, int defaultValue = 0) const; + double getConfigDouble(const char* section, const char* key, double defaultValue = 0.0) const; + bool getConfigBool(const char* section, const char* key, bool defaultValue = false) const; + + // Check if configuration directory exists + bool configDirExists() const; + + // Check if a configuration key exists + bool hasConfigKey(const char* section, const char* key) const; + + private: + // Default section name to use when none is specified + static constexpr const char* DEFAULT_SECTION = "MAIN"; + + // Parse a single configuration file + bool parseConfigFile(const std::filesystem::path& config_file); + + // Trim whitespace from a string + std::string trimWhitespace(const std::string& str) const; + + // Find a key in the given section or in the default section + std::optional> findConfigValue(const std::string& section, const std::string& key) const; + + // Configuration directory path + std::string _config_dir; + + // Configuration data structure: section -> key -> value + std::map> _config_data; +}; + +// Global configuration manager instance +extern ConfigManager g_config_manager; diff --git a/include/ModuleLoader.hpp b/include/ModuleLoader.hpp index 7c5141c..4a48b43 100644 --- a/include/ModuleLoader.hpp +++ b/include/ModuleLoader.hpp @@ -1,31 +1,31 @@ /** -* @file ModuleLoader.hpp -* @brief Dynamic module loading and management for DPM -* -* Defines the ModuleLoader class which is responsible for finding, loading, -* validating, and executing DPM modules. It handles the dynamic loading of -* shared objects and ensures they conform to the expected module interface. -* -* @copyright Copyright (c) 2025 SILO GROUP LLC -* @author Chris Punches -* -* Part of the Dark Horse Linux Package Manager (DPM) -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see . -* -* For bug reports or contributions, please contact the dhlp-contributors -* mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + * @file ModuleLoader.hpp + * @brief Dynamic module loading and management for DPM + * + * Defines the ModuleLoader class which is responsible for finding, loading, + * validating, and executing DPM modules. It handles the dynamic loading of + * shared objects and ensures they conform to the expected module interface. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors */ #pragma once @@ -33,16 +33,15 @@ #include #include #include -#include #include #include +#include #include #include #include "error.hpp" #include "module_interface.hpp" - class ModuleLoader { public: // initializer diff --git a/include/dpm_interface.hpp b/include/dpm_interface.hpp index 17ca9c3..eece612 100644 --- a/include/dpm_interface.hpp +++ b/include/dpm_interface.hpp @@ -1,5 +1,5 @@ /** -* @file dpm_interface.hpp + * @file dpm_interface.hpp * @brief Interface declarations for the DPM command-line functionality * * Defines the public interface methods that provide human-readable interaction @@ -30,11 +30,11 @@ #pragma once #include -#include #include -#include #include #include +#include +#include #include "error.hpp" #include "ModuleLoader.hpp" diff --git a/include/dpm_interface_helpers.hpp b/include/dpm_interface_helpers.hpp index d1ef0e1..8c947e9 100644 --- a/include/dpm_interface_helpers.hpp +++ b/include/dpm_interface_helpers.hpp @@ -1,5 +1,5 @@ /** -* @file dpm_interface_helpers.hpp + * @file dpm_interface_helpers.hpp * @brief Helper functions for DPM command-line interface * * Provides utility functions for command-line argument parsing and @@ -29,6 +29,7 @@ */ #pragma once + #include #include #include diff --git a/include/error.hpp b/include/error.hpp index b779b0a..bafb5c2 100644 --- a/include/error.hpp +++ b/include/error.hpp @@ -1,5 +1,5 @@ /** -* @file error.hpp + * @file error.hpp * @brief Error handling system for the DPM utility * * Defines the error categories, error context structure, and utility @@ -29,6 +29,7 @@ */ #pragma once + #include // global errors for the core DPM routing/execution component @@ -59,4 +60,3 @@ typedef struct { // shorthand for creating a FlexDPMError instance FlexDPMError make_error( DPMErrorCategory error_category ); - diff --git a/include/handlers.hpp b/include/handlers.hpp index 00f0df5..d49dffc 100644 --- a/include/handlers.hpp +++ b/include/handlers.hpp @@ -1,5 +1,5 @@ /** -* @file handlers.hpp + * @file handlers.hpp * @brief Error handling functions for the DPM system * * Defines specialized handler functions for each error category in the DPM @@ -29,8 +29,8 @@ */ #pragma once -#include +#include #include "error.hpp" // fatal error routing method diff --git a/include/module_interface.hpp b/include/module_interface.hpp index 2905d9b..df674e1 100644 --- a/include/module_interface.hpp +++ b/include/module_interface.hpp @@ -1,36 +1,41 @@ /** -* @file module_interface.hpp -* @brief Defines the interface for DPM modules -* -* Establishes the required symbols and common interface that all DPM modules -* must implement to be loadable and executable by the core DPM system. -* This forms the contract between the main DPM application and its modules. -* -* @copyright Copyright (c) 2025 SILO GROUP LLC -* @author Chris Punches -* -* Part of the Dark Horse Linux Package Manager (DPM) -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see . -* -* For bug reports or contributions, please contact the dhlp-contributors -* mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + * @file module_interface.hpp + * @brief Defines the interface for DPM modules + * + * Establishes the required symbols and common interface that all DPM modules + * must implement to be loadable and executable by the core DPM system. + * This forms the contract between the main DPM application and its modules. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors */ #pragma once + #include #include +#include + +#include "ConfigManager.hpp" + /* * Provides reserved symbol names we look for in modules. @@ -59,4 +64,7 @@ extern "C" { // Callback function exposed by DPM core for modules to use int dpm_core_callback(const char* action, const char* data); -} \ No newline at end of file + + // Direct configuration access function + const char* dpm_get_config(const char* section, const char* key); +} diff --git a/modules/info.cpp b/modules/info.cpp index 72bd5fc..73794f1 100644 --- a/modules/info.cpp +++ b/modules/info.cpp @@ -1,11 +1,40 @@ -// info.cpp +/** + * @file info.cpp + * @brief Example DPM info module implementation + * + * Implements a simple DPM module that provides information about the DPM system. + * This module demonstrates how to implement the required module interface and + * interact with the DPM core through configuration functions. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + */ + #include #include #include #include -// Declaration of the DPM core function we want to call -extern "C" int dpm_core_callback(const char* action, const char* data); +// Declaration of the DPM config function we want to call +extern "C" const char* dpm_get_config(const char* section, const char* key); // Implementation of the info module // This module provides information about the DPM system @@ -29,9 +58,8 @@ extern "C" int dpm_module_execute(const char* command, int argc, char** argv) { std::cout << "Available commands:\n"; std::cout << " version - Display DPM version information\n"; std::cout << " system - Display system information\n"; + std::cout << " config - Display configuration information\n"; std::cout << " help - Display this help message\n"; - - dpm_core_callback("log", "No command specified, displayed help"); return 0; } @@ -39,18 +67,14 @@ extern "C" int dpm_module_execute(const char* command, int argc, char** argv) { std::string cmd(command); if (cmd == "version") { - dpm_core_callback("log", "Executing 'version' command"); - std::cout << "DPM Version: 0.1.0\n"; std::cout << "Build Date: " << __DATE__ << "\n"; std::cout << "Build Time: " << __TIME__ << "\n"; return 0; } else if (cmd == "system") { - dpm_core_callback("log", "Executing 'system' command"); - - // Request config information - dpm_core_callback("get_config", "system.arch"); + // Request config information using the direct method + const char* module_path = dpm_get_config("modules", "module_path"); std::cout << "System Information:\n"; std::cout << " OS: " @@ -77,24 +101,29 @@ extern "C" int dpm_module_execute(const char* command, int argc, char** argv) { "Unknown" #endif << "\n"; + std::cout << " Module Path: " << (module_path ? module_path : "Not configured") << "\n"; + return 0; + } + else if (cmd == "config") { + // Retrieve module path configuration + const char* module_path = dpm_get_config("modules", "module_path"); + + std::cout << "Configuration Information:\n"; + std::cout << " Module Path: " << (module_path ? module_path : "Not configured") << "\n"; return 0; } else if (cmd == "help") { - dpm_core_callback("log", "Executing 'help' command"); - std::cout << "DPM Info Module - Provides information about the DPM system\n"; std::cout << "Available commands:\n"; std::cout << " version - Display DPM version information\n"; std::cout << " system - Display system information\n"; + std::cout << " config - Display configuration information\n"; std::cout << " help - Display this help message\n"; return 0; } else { - std::string error_msg = "Unknown command: " + cmd; - dpm_core_callback("log", error_msg.c_str()); - std::cerr << "Unknown command: " << cmd << "\n"; std::cerr << "Run 'dpm info help' for a list of available commands\n"; return 1; } -} \ No newline at end of file +} diff --git a/src/ConfigManager.cpp b/src/ConfigManager.cpp new file mode 100644 index 0000000..836c81a --- /dev/null +++ b/src/ConfigManager.cpp @@ -0,0 +1,307 @@ +/** + * @file ConfigManager.cpp + * @brief Implementation of the configuration management system + * + * Implements the ConfigManager class methods for loading and parsing configuration + * files from the /etc/dpm/conf.d/ directory, and providing access to configuration + * values through a consistent interface. Handles INI-style files with sections + * and key-value pairs. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + */ + +#include "ConfigManager.hpp" + +// Global configuration manager instance +ConfigManager g_config_manager; + +ConfigManager::ConfigManager(const std::string& config_dir) + : _config_dir(config_dir) +{ + // Ensure the config directory ends with a slash + if (!_config_dir.empty() && _config_dir.back() != '/') { + _config_dir += '/'; + } +} + +std::string ConfigManager::trimWhitespace(const std::string& str) const +{ + const std::string whitespace = " \t\n\r\f\v"; + size_t start = str.find_first_not_of(whitespace); + + // Return empty string if there are only whitespace characters + if (start == std::string::npos) { + return ""; + } + + size_t end = str.find_last_not_of(whitespace); + return str.substr(start, end - start + 1); +} + +bool ConfigManager::configDirExists() const +{ + DIR* dir = opendir(_config_dir.c_str()); + if (dir) { + closedir(dir); + return true; + } + return false; +} + +bool ConfigManager::loadConfigurations() +{ + // Clear existing configuration data + _config_data.clear(); + + // Ensure DEFAULT_SECTION exists in the configuration data + _config_data[DEFAULT_SECTION] = std::map(); + + // Check if the configuration directory exists + if (!configDirExists()) { + std::cerr << "Warning: Configuration directory does not exist: " << _config_dir << std::endl; + return false; + } + + // Open the directory + DIR* dir = opendir(_config_dir.c_str()); + if (!dir) { + std::cerr << "Error: Failed to open configuration directory: " << _config_dir << std::endl; + return false; + } + + bool success = true; + struct dirent* entry; + + // Iterate through directory entries + while ((entry = readdir(dir)) != NULL) { + std::string filename = entry->d_name; + + // Skip . and .. directories + if (filename == "." || filename == "..") { + continue; + } + + // Check if file ends with .conf + if (filename.length() >= 5 && + filename.substr(filename.length() - 5) == ".conf") { + + std::string filepath = _config_dir + filename; + if (!parseConfigFile(filepath)) { + std::cerr << "Warning: Failed to parse config file: " << filepath << std::endl; + success = false; + } + } + } + + closedir(dir); + return success; +} + +bool ConfigManager::parseConfigFile(const std::filesystem::path& config_file) +{ + std::ifstream file(config_file); + if (!file.is_open()) { + std::cerr << "Error: Could not open config file: " << config_file << std::endl; + return false; + } + + std::string line; + std::string current_section = DEFAULT_SECTION; + + // Process each line in the file + while (std::getline(file, line)) { + // Trim whitespace + line = trimWhitespace(line); + + // Skip empty lines and comments + if (line.empty() || line[0] == '#' || line[0] == ';') { + continue; + } + + // Check for section header + if (line[0] == '[' && line.back() == ']') { + current_section = line.substr(1, line.length() - 2); + + // Trim whitespace from section name + current_section = trimWhitespace(current_section); + + // Skip empty section names, use default instead + if (current_section.empty()) { + current_section = DEFAULT_SECTION; + } + + // Ensure section exists in the map + if (_config_data.find(current_section) == _config_data.end()) { + _config_data[current_section] = std::map(); + } + + continue; + } + + // Parse key-value pair + size_t delimiter_pos = line.find('='); + if (delimiter_pos != std::string::npos) { + std::string key = trimWhitespace(line.substr(0, delimiter_pos)); + std::string value = trimWhitespace(line.substr(delimiter_pos + 1)); + + // Skip empty keys + if (key.empty()) { + continue; + } + + // Store in configuration map + _config_data[current_section][key] = value; + } + } + + file.close(); + return true; +} + +std::optional> ConfigManager::findConfigValue( + const std::string& section, const std::string& key) const +{ + // Check if section exists + auto section_it = _config_data.find(section); + if (section_it != _config_data.end()) { + // Check if key exists in section + auto key_it = section_it->second.find(key); + if (key_it != section_it->second.end()) { + return key_it->second; + } + } + + // If section is not DEFAULT_SECTION and key was not found, + // try looking in the DEFAULT_SECTION + if (section != DEFAULT_SECTION) { + auto default_section_it = _config_data.find(DEFAULT_SECTION); + if (default_section_it != _config_data.end()) { + auto default_key_it = default_section_it->second.find(key); + if (default_key_it != default_section_it->second.end()) { + return default_key_it->second; + } + } + } + + // Key not found in specified section or DEFAULT_SECTION + return std::nullopt; +} + +bool ConfigManager::hasConfigKey(const char* section, const char* key) const +{ + if (!key) { + return false; + } + + // Use the default section if none is provided + std::string section_str = section ? section : DEFAULT_SECTION; + std::string key_str(key); + + return findConfigValue(section_str, key_str).has_value(); +} + +const char* ConfigManager::getConfigValue(const char* section, const char* key) const +{ + if (!key) { + return nullptr; + } + + // Use the default section if none is provided + std::string section_str = section ? section : DEFAULT_SECTION; + std::string key_str(key); + + auto value_opt = findConfigValue(section_str, key_str); + if (value_opt.has_value()) { + return value_opt.value().get().c_str(); + } + + return nullptr; +} + +std::string ConfigManager::getConfigString(const char* section, const char* key, const std::string& defaultValue) const +{ + const char* value = getConfigValue(section, key); + return value ? value : defaultValue; +} + +int ConfigManager::getConfigInt(const char* section, const char* key, int defaultValue) const +{ + const char* value = getConfigValue(section, key); + if (!value) { + return defaultValue; + } + + char* endptr; + int result = strtol(value, &endptr, 10); + + // If conversion failed or didn't consume the entire string, return default + if (*endptr != '\0') { + return defaultValue; + } + + return result; +} + +double ConfigManager::getConfigDouble(const char* section, const char* key, double defaultValue) const +{ + const char* value = getConfigValue(section, key); + if (!value) { + return defaultValue; + } + + char* endptr; + double result = strtod(value, &endptr); + + // If conversion failed or didn't consume the entire string, return default + if (*endptr != '\0') { + return defaultValue; + } + + return result; +} + +bool ConfigManager::getConfigBool(const char* section, const char* key, bool defaultValue) const +{ + const char* value = getConfigValue(section, key); + if (!value) { + return defaultValue; + } + + std::string value_lower = value; + std::transform(value_lower.begin(), value_lower.end(), value_lower.begin(), + [](unsigned char c) { return std::tolower(c); }); + + // Check for common true values + if (value_lower == "true" || value_lower == "yes" || value_lower == "1" || + value_lower == "on" || value_lower == "enabled") { + return true; + } + + // Check for common false values + if (value_lower == "false" || value_lower == "no" || value_lower == "0" || + value_lower == "off" || value_lower == "disabled") { + return false; + } + + // If not recognized, return default + return defaultValue; +} diff --git a/src/ModuleLoader.cpp b/src/ModuleLoader.cpp index d9539bc..a3c110c 100644 --- a/src/ModuleLoader.cpp +++ b/src/ModuleLoader.cpp @@ -1,3 +1,33 @@ +/** + * @file ModuleLoader.cpp + * @brief Implementation of dynamic module loading and management for DPM + * + * Implements the ModuleLoader class methods for finding, loading, validating, + * and executing DPM modules. It handles the dynamic loading of shared objects + * and ensures they conform to the expected module interface. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + */ + #include "ModuleLoader.hpp" namespace fs = std::filesystem; diff --git a/src/dpm.cpp b/src/dpm.cpp index 0d3e257..fd232fb 100644 --- a/src/dpm.cpp +++ b/src/dpm.cpp @@ -1,5 +1,5 @@ /** -* @file dpm.cpp + * @file dpm.cpp * @brief Main entry point for the Dark Horse Package Manager (DPM) * * Implements the core command-line interface and module routing functionality @@ -28,13 +28,14 @@ */ #include -#include #include +#include #include "ModuleLoader.hpp" #include "dpm_interface.hpp" #include "dpm_interface_helpers.hpp" #include "error.hpp" +#include "ConfigManager.hpp" /* * DPM serves three functions: @@ -59,19 +60,44 @@ int default_behavior(const ModuleLoader& loader) * @param argv Array of C-style strings containing the arguments * @return Exit code indicating success (0) or failure (non-zero) */ -int main( int argc, char* argv[] ) +int main(int argc, char* argv[]) { + // Load configuration files + if (!g_config_manager.loadConfigurations()) { + std::cerr << "Warning: Some configuration files could not be loaded." << std::endl; + // Continue execution, as we might be able to use default values + } + // process the arguments suppplied to DPM and provide // an object that contains them for command and routing - // processing - auto args = parse_args( argc, argv ); + // processing - this will include any module_path from CLI + auto args = parse_args(argc, argv); - // create a module loader object at the supplied or default path - ModuleLoader loader( args.module_path ); + // Determine the module path (CLI arg > config > default) + std::string module_path; + + // If CLI argument was provided, use it + if (!args.module_path.empty()) { + module_path = args.module_path; + } + // Otherwise, check configuration file + else { + const char* config_module_path = g_config_manager.getConfigValue("modules", "module_path"); + if (config_module_path) { + module_path = config_module_path; + } + // Finally, use default if nothing else is available + else { + module_path = "/usr/lib/dpm/modules/"; + } + } + + // create a module loader object with the determined path + ModuleLoader loader(module_path); // check the module path for the loader object - int path_check_result = main_check_module_path( loader ); - if ( path_check_result != 0 ) { + int path_check_result = main_check_module_path(loader); + if (path_check_result != 0) { // exit if there's an error and ensure // it has an appropriate return code return 1; @@ -79,8 +105,8 @@ int main( int argc, char* argv[] ) // if no module is provided to execute, then trigger the default // dpm behaviour - if ( args.module_name.empty() ) { - return default_behavior( loader ); + if (args.module_name.empty()) { + return default_behavior(loader); } // execute the module @@ -94,5 +120,5 @@ int main( int argc, char* argv[] ) result.module_path = extracted_path.c_str(); // pair result with a message and exit with the appropriate error code - return handle_error( result ); -} \ No newline at end of file + return handle_error(result); +} diff --git a/src/dpm_interface.cpp b/src/dpm_interface.cpp index 4a2cfd1..f81cfc8 100644 --- a/src/dpm_interface.cpp +++ b/src/dpm_interface.cpp @@ -1,3 +1,33 @@ +/** + * @file dpm_interface.cpp + * @brief Implementation of DPM command-line interface functions + * + * Implements the functions that provide human-readable interaction with the + * DPM core functionality, including module path validation and module listing + * capabilities. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + */ + #include "dpm_interface.hpp" /* @@ -177,5 +207,3 @@ int main_list_modules(const ModuleLoader& loader) return 0; } - - diff --git a/src/dpm_interface_helpers.cpp b/src/dpm_interface_helpers.cpp index 35867ca..35c4d40 100644 --- a/src/dpm_interface_helpers.cpp +++ b/src/dpm_interface_helpers.cpp @@ -1,3 +1,33 @@ +/** + * @file dpm_interface_helpers.cpp + * @brief Implementation of helper functions for DPM command-line interface + * + * Implements utility functions for command-line argument parsing and provides + * data structures for representing command arguments in a structured format. + * These helpers are used by the main DPM interface to process user input. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + */ + #include "dpm_interface_helpers.hpp" /** @@ -26,7 +56,7 @@ CommandArgs parse_args(int argc, char* argv[]) { CommandArgs args; - args.module_path = "/usr/lib/dpm/modules/"; // Set to same default as ModuleLoader + args.module_path = ""; // Start with empty path to allow for config fallback static struct option long_options[] = { {"module-path", required_argument, 0, 'm'}, @@ -42,11 +72,10 @@ CommandArgs parse_args(int argc, char* argv[]) args.module_path = optarg; break; case 'h': - std::cout << "Usage: dpm [options] [module-name] [module args...]\n\n" + std::cout << "Usage: dpm [options] [module-name] [module args...] [module-command] [command-args]\n\n" << "Options:\n\n" - << " -m, --module-path PATH Path to DPM modules\n" - << " -h, --help Show this help message\n\n" - << "If no module is specified, available modules will be listed.\n\n"; + << " -m, --module-path PATH Path to DPM modules (overrides config)\n" + << " -h, --help Show this help message\n\n"; exit(0); case '?': exit(1); @@ -71,4 +100,4 @@ CommandArgs parse_args(int argc, char* argv[]) } return args; -} \ No newline at end of file +} diff --git a/src/error.cpp b/src/error.cpp index b9fe8a9..22669a4 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -1,3 +1,33 @@ +/** +* @file error.cpp + * @brief Implementation of error handling system for the DPM utility + * + * Implements the utility functions for error handling defined in error.hpp. + * Provides functionality for creating error context structures to ensure + * consistent error reporting throughout the DPM system. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + */ + #include "error.hpp" // Simple helper function that takes only the required error category diff --git a/src/handlers.cpp b/src/handlers.cpp index 6399ac5..a0116b6 100644 --- a/src/handlers.cpp +++ b/src/handlers.cpp @@ -1,3 +1,33 @@ +/** + * @file handlers.cpp + * @brief Implementation of error handling functions for the DPM system + * + * Implements specialized handler functions for each error category in the DPM + * error system. These handlers translate error codes into user-friendly + * messages and provide appropriate exit behavior for different error conditions. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + */ + #include "handlers.hpp" // Helper function for validating required fields in a FlexDPMError @@ -134,4 +164,4 @@ int handle_undefined_error(FlexDPMError context) { } std::cerr << std::endl; return 1; -} \ No newline at end of file +} diff --git a/src/module_interface.cpp b/src/module_interface.cpp index 12a3f0a..c6548e2 100644 --- a/src/module_interface.cpp +++ b/src/module_interface.cpp @@ -1,35 +1,33 @@ /** -* @file module_interface.cpp -* @brief Implementation of the module interface functions -* -* Provides the implementation of functions declared in the module interface -* that are part of the DPM core, such as callback functions available to modules. -* -* @copyright Copyright (c) 2025 SILO GROUP LLC -* @author Chris Punches -* -* Part of the Dark Horse Linux Package Manager (DPM) -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see . -* -* For bug reports or contributions, please contact the dhlp-contributors -* mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors + * @file module_interface.cpp + * @brief Implementation of the module interface functions + * + * Provides the implementation of functions declared in the module interface + * that are part of the DPM core, such as callback functions available to modules. + * + * @copyright Copyright (c) 2025 SILO GROUP LLC + * @author Chris Punches + * + * Part of the Dark Horse Linux Package Manager (DPM) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * For bug reports or contributions, please contact the dhlp-contributors + * mailing list at: https://lists.darkhorselinux.org/mailman/listinfo/dhlp-contributors */ #include "module_interface.hpp" -#include -#include /** * @brief Function that modules can call to access DPM core functionality @@ -62,12 +60,47 @@ extern "C" int dpm_core_callback(const char* action, const char* data) { return 0; } else if (action_str == "get_config") { - if (data) { - std::cout << "Module requested config: " << data << std::endl; + if (!data) { + std::cerr << "Error: get_config requires section.key format" << std::endl; + return 1; } + + // Parse the section.key format + std::string data_str(data); + size_t dot_pos = data_str.find('.'); + + if (dot_pos == std::string::npos) { + std::cerr << "Error: Invalid config format. Use section.key" << std::endl; + return 1; + } + + std::string section = data_str.substr(0, dot_pos); + std::string key = data_str.substr(dot_pos + 1); + + // Get the configuration value + const char* value = g_config_manager.getConfigValue(section.c_str(), key.c_str()); + + // Log the request for debugging purposes + std::cout << "Module requested config: " << data << " = " + << (value ? value : "not found") << std::endl; + return 0; } std::cerr << "Error: Unknown module callback action: " << action_str << std::endl; return 1; -} \ No newline at end of file +} + +/** + * @brief Function that provides direct access to configuration values + * + * This function allows modules to get configuration values directly. + * It returns the string value from the configuration or nullptr if not found. + * + * @param section The configuration section name + * @param key The configuration key within the section + * @return The configuration value or nullptr if not found + */ +extern "C" const char* dpm_get_config(const char* section, const char* key) { + return g_config_manager.getConfigValue(section, key); +}