restructured the build module
parent
f750c22faa
commit
368b751a63
|
@ -177,14 +177,13 @@ int main(int argc, char** argv) { \
|
||||||
/* If arguments are provided, use the first as command */ \
|
/* If arguments are provided, use the first as command */ \
|
||||||
if (argc > 1) { \
|
if (argc > 1) { \
|
||||||
command = argv[1]; \
|
command = argv[1]; \
|
||||||
/* Shift the argument array for the command handler */ \
|
/* Shift arguments for the command handler but keep the original argc count */ \
|
||||||
argv++; \
|
argv++; \
|
||||||
argc--; \
|
argc--; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
std::cout << "Executing command: " << command << std::endl; \
|
std::cout << "Executing command: " << command << std::endl; \
|
||||||
return dpm_module_execute(command, argc - 1, argv + 1); \
|
return dpm_module_execute(command, argc, argv); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BUILD_STANDALONE
|
#endif // BUILD_STANDALONE
|
||||||
|
|
|
@ -13,7 +13,9 @@ endif()
|
||||||
# Module version - used by DPM
|
# Module version - used by DPM
|
||||||
add_library(build MODULE
|
add_library(build MODULE
|
||||||
build.cpp
|
build.cpp
|
||||||
src/buildFuncs.cpp
|
src/helpers.cpp
|
||||||
|
src/cli_parsers.cpp
|
||||||
|
src/commands.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set output properties
|
# Set output properties
|
||||||
|
@ -35,7 +37,9 @@ target_link_libraries(build stdc++fs)
|
||||||
# Standalone version - used for debugging
|
# Standalone version - used for debugging
|
||||||
add_executable(build_standalone
|
add_executable(build_standalone
|
||||||
build.cpp
|
build.cpp
|
||||||
src/buildFuncs.cpp
|
src/helpers.cpp
|
||||||
|
src/cli_parsers.cpp
|
||||||
|
src/commands.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Define the BUILD_STANDALONE macro for the standalone build
|
# Define the BUILD_STANDALONE macro for the standalone build
|
||||||
|
|
|
@ -28,11 +28,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstring>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "include/buildFuncs.hpp"
|
#include "include/helpers.hpp"
|
||||||
|
#include "include/commands.hpp"
|
||||||
|
#include "include/cli_parsers.hpp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @def MODULE_VERSION
|
* @def MODULE_VERSION
|
||||||
|
|
|
@ -1,25 +1,14 @@
|
||||||
/**
|
|
||||||
* @file buildFuncs.hpp
|
|
||||||
* @brief Header file for the build module support functions
|
|
||||||
*
|
|
||||||
* Defines functions and enumerations for the build module which creates
|
|
||||||
* DPM packages according to specification.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2025 SILO GROUP LLC
|
|
||||||
* @author Chris Punches <chris.punches@silogroup.org>
|
|
||||||
*
|
|
||||||
* Part of the Dark Horse Linux Package Manager (DPM)
|
|
||||||
*/
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <dpmdk/include/CommonModuleAPI.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <dpmdk/include/CommonModuleAPI.hpp>
|
#include <filesystem>
|
||||||
|
#include "helpers.hpp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @enum Command
|
* @enum Command
|
||||||
* @brief Enumeration of supported commands for the build module
|
* @brief Enumeration of supported commands for the build module
|
||||||
*/
|
*/
|
||||||
enum Command {
|
enum Command {
|
||||||
|
@ -41,6 +30,7 @@ struct BuildOptions {
|
||||||
std::string signature_key; /**< Path to the GPG key for signing the package */
|
std::string signature_key; /**< Path to the GPG key for signing the package */
|
||||||
bool force; /**< Flag to force package creation even if warnings occur */
|
bool force; /**< Flag to force package creation even if warnings occur */
|
||||||
bool verbose; /**< Flag for verbose output */
|
bool verbose; /**< Flag for verbose output */
|
||||||
|
bool show_help; /**< Flag to show help information */
|
||||||
|
|
||||||
// Constructor with default values
|
// Constructor with default values
|
||||||
BuildOptions() :
|
BuildOptions() :
|
||||||
|
@ -51,54 +41,10 @@ struct BuildOptions {
|
||||||
package_name(""),
|
package_name(""),
|
||||||
signature_key(""),
|
signature_key(""),
|
||||||
force(false),
|
force(false),
|
||||||
verbose(false) {}
|
verbose(false),
|
||||||
|
show_help(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handler for the help command
|
|
||||||
*
|
|
||||||
* Displays information about available commands in the build module.
|
|
||||||
*
|
|
||||||
* @param argc Number of arguments
|
|
||||||
* @param argv Array of arguments
|
|
||||||
* @return 0 on success, non-zero on failure
|
|
||||||
*/
|
|
||||||
int cmd_help(int argc, char** argv);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handler for the create command
|
|
||||||
*
|
|
||||||
* Processes arguments and creates a DPM package.
|
|
||||||
*
|
|
||||||
* @param argc Number of arguments
|
|
||||||
* @param argv Array of arguments
|
|
||||||
* @return 0 on success, non-zero on failure
|
|
||||||
*/
|
|
||||||
int cmd_create(int argc, char** argv);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handler for unknown commands
|
|
||||||
*
|
|
||||||
* Displays an error message for unrecognized commands.
|
|
||||||
*
|
|
||||||
* @param command The unrecognized command string
|
|
||||||
* @param argc Number of arguments
|
|
||||||
* @param argv Array of arguments
|
|
||||||
* @return 1 to indicate failure
|
|
||||||
*/
|
|
||||||
int cmd_unknown(const char* command, int argc, char** argv);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Parses a command string into a Command enum value
|
|
||||||
*
|
|
||||||
* Converts a command string to the appropriate Command enum value
|
|
||||||
* for internal routing.
|
|
||||||
*
|
|
||||||
* @param cmd_str The command string to parse
|
|
||||||
* @return The corresponding Command enum value
|
|
||||||
*/
|
|
||||||
Command parse_command(const char* cmd_str);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parses command-line arguments for the create command
|
* @brief Parses command-line arguments for the create command
|
||||||
*
|
*
|
||||||
|
@ -111,6 +57,17 @@ Command parse_command(const char* cmd_str);
|
||||||
*/
|
*/
|
||||||
int parse_create_options(int argc, char** argv, BuildOptions& options);
|
int parse_create_options(int argc, char** argv, BuildOptions& options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parses a command string into a Command enum value
|
||||||
|
*
|
||||||
|
* Converts a command string to the appropriate Command enum value
|
||||||
|
* for internal routing.
|
||||||
|
*
|
||||||
|
* @param cmd_str The command string to parse
|
||||||
|
* @return The corresponding Command enum value
|
||||||
|
*/
|
||||||
|
Command parse_command(const char* cmd_str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Validates the build options
|
* @brief Validates the build options
|
||||||
*
|
*
|
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cli_parsers.hpp"
|
||||||
|
#include <dpmdk/include/CommonModuleAPI.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handler for the create command
|
||||||
|
*
|
||||||
|
* Processes arguments and creates a DPM package.
|
||||||
|
*
|
||||||
|
* @param argc Number of arguments
|
||||||
|
* @param argv Array of arguments
|
||||||
|
* @return 0 on success, non-zero on failure
|
||||||
|
*/
|
||||||
|
int cmd_create(int argc, char** argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handler for the help command
|
||||||
|
*
|
||||||
|
* Displays information about available commands in the build module.
|
||||||
|
*
|
||||||
|
* @param argc Number of arguments
|
||||||
|
* @param argv Array of arguments
|
||||||
|
* @return 0 on success, non-zero on failure
|
||||||
|
*/
|
||||||
|
int cmd_help(int argc, char** argv);
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* @file helpers.hpp
|
||||||
|
* @brief Header file for the build module support functions
|
||||||
|
*
|
||||||
|
* Defines functions and enumerations for the build module which creates
|
||||||
|
* DPM packages according to specification.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2025 SILO GROUP LLC
|
||||||
|
* @author Chris Punches <chris.punches@silogroup.org>
|
||||||
|
*
|
||||||
|
* Part of the Dark Horse Linux Package Manager (DPM)
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <wordexp.h>
|
||||||
|
#include <dpmdk/include/CommonModuleAPI.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Expands environment variables and tildes in a path
|
||||||
|
*
|
||||||
|
* Uses wordexp to handle shell-like expansions in paths,
|
||||||
|
* including environment variables, tildes, and wildcards.
|
||||||
|
*
|
||||||
|
* @param path The path string to expand
|
||||||
|
* @return The expanded path, or the original path if expansion failed
|
||||||
|
*/
|
||||||
|
std::string expand_path(const std::string& path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handler for the help command
|
||||||
|
*
|
||||||
|
* Displays information about available commands in the build module.
|
||||||
|
*
|
||||||
|
* @param argc Number of arguments
|
||||||
|
* @param argv Array of arguments
|
||||||
|
* @return 0 on success, non-zero on failure
|
||||||
|
*/
|
||||||
|
int cmd_help(int argc, char** argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handler for unknown commands
|
||||||
|
*
|
||||||
|
* Displays an error message for unrecognized commands.
|
||||||
|
*
|
||||||
|
* @param command The unrecognized command string
|
||||||
|
* @param argc Number of arguments
|
||||||
|
* @param argv Array of arguments
|
||||||
|
* @return 1 to indicate failure
|
||||||
|
*/
|
||||||
|
int cmd_unknown(const char* command, int argc, char** argv);
|
||||||
|
|
|
@ -1,234 +0,0 @@
|
||||||
/**
|
|
||||||
* @file buildFuncs.cpp
|
|
||||||
* @brief Implementation of the build module support functions
|
|
||||||
*
|
|
||||||
* Implements functions for the build module that create DPM packages
|
|
||||||
* according to the specification.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2025 SILO GROUP LLC
|
|
||||||
* @author Chris Punches <chris.punches@silogroup.org>
|
|
||||||
*
|
|
||||||
* Part of the Dark Horse Linux Package Manager (DPM)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "buildFuncs.hpp"
|
|
||||||
#include <iostream>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handler for the help command
|
|
||||||
*/
|
|
||||||
int cmd_help(int argc, char** argv) {
|
|
||||||
dpm_log(LOG_INFO, "DPM Build Module - Creates DPM packages according to specification");
|
|
||||||
dpm_log(LOG_INFO, "Available commands:");
|
|
||||||
dpm_log(LOG_INFO, " create - Create a new DPM package");
|
|
||||||
dpm_log(LOG_INFO, " help - Display this help message");
|
|
||||||
dpm_log(LOG_INFO, "");
|
|
||||||
dpm_log(LOG_INFO, "Usage: dpm build create [options]");
|
|
||||||
dpm_log(LOG_INFO, "Options:");
|
|
||||||
dpm_log(LOG_INFO, " -o, --output-dir DIR Directory to save the built package (default: current directory)");
|
|
||||||
dpm_log(LOG_INFO, " -c, --contents DIR Directory with package contents (required)");
|
|
||||||
dpm_log(LOG_INFO, " -m, --metadata DIR Directory with package metadata (required)");
|
|
||||||
dpm_log(LOG_INFO, " -H, --hooks DIR Directory with package hooks (optional)");
|
|
||||||
dpm_log(LOG_INFO, " -n, --name NAME Package name (required if not in metadata)");
|
|
||||||
dpm_log(LOG_INFO, " -s, --sign KEY Path to GPG key for signing the package (optional)");
|
|
||||||
dpm_log(LOG_INFO, " -f, --force Force package creation even if warnings occur");
|
|
||||||
dpm_log(LOG_INFO, " -v, --verbose Enable verbose output");
|
|
||||||
dpm_log(LOG_INFO, " -h, --help Display this help message");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handler for unknown commands
|
|
||||||
*/
|
|
||||||
int cmd_unknown(const char* command, int argc, char** argv) {
|
|
||||||
std::string msg = "Unknown command: ";
|
|
||||||
msg += (command ? command : "");
|
|
||||||
dpm_log(LOG_WARN, msg.c_str());
|
|
||||||
dpm_log(LOG_WARN, "Run 'dpm build help' for a list of available commands");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Parses a command string to Command enum
|
|
||||||
*/
|
|
||||||
Command parse_command(const char* cmd_str) {
|
|
||||||
if (cmd_str == nullptr || strlen(cmd_str) == 0) {
|
|
||||||
return CMD_HELP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(cmd_str, "help") == 0) {
|
|
||||||
return CMD_HELP;
|
|
||||||
}
|
|
||||||
else if (strcmp(cmd_str, "create") == 0) {
|
|
||||||
return CMD_CREATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CMD_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handler for the create command
|
|
||||||
*/
|
|
||||||
int cmd_create(int argc, char** argv) {
|
|
||||||
BuildOptions options;
|
|
||||||
|
|
||||||
// Parse command-line options
|
|
||||||
int parse_result = parse_create_options(argc, argv, options);
|
|
||||||
if (parse_result != 0) {
|
|
||||||
return parse_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate options
|
|
||||||
int validate_result = validate_build_options(options);
|
|
||||||
if (validate_result != 0) {
|
|
||||||
return validate_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log the operation
|
|
||||||
if (options.verbose) {
|
|
||||||
dpm_log(LOG_INFO, "Creating DPM package with the following options:");
|
|
||||||
dpm_log(LOG_INFO, (" Output directory: " + options.output_dir).c_str());
|
|
||||||
dpm_log(LOG_INFO, (" Contents directory: " + options.contents_dir).c_str());
|
|
||||||
dpm_log(LOG_INFO, (" Metadata directory: " + options.metadata_dir).c_str());
|
|
||||||
|
|
||||||
if (!options.hooks_dir.empty()) {
|
|
||||||
dpm_log(LOG_INFO, (" Hooks directory: " + options.hooks_dir).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.package_name.empty()) {
|
|
||||||
dpm_log(LOG_INFO, (" Package name: " + options.package_name).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.signature_key.empty()) {
|
|
||||||
dpm_log(LOG_INFO, (" Signature key: " + options.signature_key).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.force) {
|
|
||||||
dpm_log(LOG_INFO, " Force: Yes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, just log that we would create the package
|
|
||||||
dpm_log(LOG_INFO, "Package creation functionality not yet implemented");
|
|
||||||
dpm_log(LOG_INFO, "Would create package using the provided options");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Parses command-line arguments for the create command
|
|
||||||
*/
|
|
||||||
int parse_create_options(int argc, char** argv, BuildOptions& options) {
|
|
||||||
static struct option long_options[] = {
|
|
||||||
{"output-dir", required_argument, 0, 'o'},
|
|
||||||
{"contents", required_argument, 0, 'c'},
|
|
||||||
{"metadata", required_argument, 0, 'm'},
|
|
||||||
{"hooks", required_argument, 0, 'H'},
|
|
||||||
{"name", required_argument, 0, 'n'},
|
|
||||||
{"sign", required_argument, 0, 's'},
|
|
||||||
{"force", no_argument, 0, 'f'},
|
|
||||||
{"verbose", no_argument, 0, 'v'},
|
|
||||||
{"help", no_argument, 0, 'h'},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Skip program name and module name
|
|
||||||
int adjusted_argc = argc;
|
|
||||||
char** adjusted_argv = argv;
|
|
||||||
|
|
||||||
// Reset getopt
|
|
||||||
optind = 0;
|
|
||||||
opterr = 1;
|
|
||||||
|
|
||||||
int opt;
|
|
||||||
int option_index = 0;
|
|
||||||
|
|
||||||
while ((opt = getopt_long(adjusted_argc, adjusted_argv, "o:c:m:H:n:s:fvh", long_options, &option_index)) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
case 'o':
|
|
||||||
options.output_dir = optarg;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
options.contents_dir = optarg;
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
options.metadata_dir = optarg;
|
|
||||||
break;
|
|
||||||
case 'H':
|
|
||||||
options.hooks_dir = optarg;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
options.package_name = optarg;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
options.signature_key = optarg;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
options.force = true;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
options.verbose = true;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
cmd_help(0, nullptr);
|
|
||||||
return 1;
|
|
||||||
case '?':
|
|
||||||
// Error message is printed by getopt
|
|
||||||
dpm_log(LOG_ERROR, "Run 'dpm build create --help' for usage information");
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
dpm_log(LOG_ERROR, "Unknown option");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Validates the build options
|
|
||||||
*/
|
|
||||||
int validate_build_options(const BuildOptions& options) {
|
|
||||||
// Check if contents directory is provided and exists
|
|
||||||
if (options.contents_dir.empty()) {
|
|
||||||
dpm_log(LOG_ERROR, "Contents directory is required (--contents)");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!std::filesystem::exists(options.contents_dir)) {
|
|
||||||
dpm_log(LOG_ERROR, ("Contents directory does not exist: " + options.contents_dir).c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if metadata directory is provided and exists
|
|
||||||
if (options.metadata_dir.empty()) {
|
|
||||||
dpm_log(LOG_ERROR, "Metadata directory is required (--metadata)");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!std::filesystem::exists(options.metadata_dir)) {
|
|
||||||
dpm_log(LOG_ERROR, ("Metadata directory does not exist: " + options.metadata_dir).c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if hooks directory exists if provided
|
|
||||||
if (!options.hooks_dir.empty() && !std::filesystem::exists(options.hooks_dir)) {
|
|
||||||
dpm_log(LOG_ERROR, ("Hooks directory does not exist: " + options.hooks_dir).c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if output directory exists
|
|
||||||
if (!std::filesystem::exists(options.output_dir)) {
|
|
||||||
dpm_log(LOG_ERROR, ("Output directory does not exist: " + options.output_dir).c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if signature key exists if provided
|
|
||||||
if (!options.signature_key.empty() && !std::filesystem::exists(options.signature_key)) {
|
|
||||||
dpm_log(LOG_ERROR, ("Signature key file does not exist: " + options.signature_key).c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
#include "cli_parsers.hpp"
|
||||||
|
|
||||||
|
int parse_create_options(int argc, char** argv, BuildOptions& options) {
|
||||||
|
// For debugging
|
||||||
|
dpm_log(LOG_DEBUG, "Parsing command-line arguments");
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
std::string arg_msg = "Arg " + std::to_string(i) + ": " + (argv[i] ? argv[i] : "(null)");
|
||||||
|
dpm_log(LOG_DEBUG, arg_msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// First process any arguments in --option=value format
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
if (!argv[i] || strlen(argv[i]) == 0) continue;
|
||||||
|
|
||||||
|
std::string arg(argv[i]);
|
||||||
|
size_t equals_pos = arg.find('=');
|
||||||
|
|
||||||
|
if (equals_pos != std::string::npos && arg.length() > 3 && arg[0] == '-' && arg[1] == '-') {
|
||||||
|
// Extract option and value
|
||||||
|
std::string option = arg.substr(0, equals_pos);
|
||||||
|
std::string value = arg.substr(equals_pos + 1);
|
||||||
|
|
||||||
|
if (option == "--output-dir") {
|
||||||
|
options.output_dir = value;
|
||||||
|
} else if (option == "--contents") {
|
||||||
|
options.contents_dir = value;
|
||||||
|
} else if (option == "--metadata") {
|
||||||
|
options.metadata_dir = value;
|
||||||
|
} else if (option == "--hooks") {
|
||||||
|
options.hooks_dir = value;
|
||||||
|
} else if (option == "--name") {
|
||||||
|
options.package_name = value;
|
||||||
|
} else if (option == "--sign") {
|
||||||
|
options.signature_key = value;
|
||||||
|
} else if (option == "--force") {
|
||||||
|
options.force = true;
|
||||||
|
} else if (option == "--verbose") {
|
||||||
|
options.verbose = true;
|
||||||
|
} else if (option == "--help") {
|
||||||
|
options.show_help = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert this argument to a dummy to prevent getopt from processing it
|
||||||
|
argv[i] = strdup("--dummy");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"output-dir", required_argument, 0, 'o'},
|
||||||
|
{"contents", required_argument, 0, 'c'},
|
||||||
|
{"metadata", required_argument, 0, 'm'},
|
||||||
|
{"hooks", required_argument, 0, 'H'},
|
||||||
|
{"name", required_argument, 0, 'n'},
|
||||||
|
{"sign", required_argument, 0, 's'},
|
||||||
|
{"force", no_argument, 0, 'f'},
|
||||||
|
{"verbose", no_argument, 0, 'v'},
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
|
{"dummy", no_argument, 0, 0}, // Add dummy option to prevent getopt errors
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset getopt
|
||||||
|
optind = 0;
|
||||||
|
opterr = 0; // Suppress getopt error messages
|
||||||
|
|
||||||
|
int opt;
|
||||||
|
int option_index = 0;
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv, "o:c:m:H:n:s:fvh", long_options, &option_index)) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'o':
|
||||||
|
options.output_dir = optarg;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
options.contents_dir = optarg;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
options.metadata_dir = optarg;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
options.hooks_dir = optarg;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
options.package_name = optarg;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
options.signature_key = optarg;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
options.force = true;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
options.verbose = true;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
options.show_help = true;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
// Ignore errors as we handle equals-format options separately
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand paths after all arguments have been processed
|
||||||
|
if (!options.output_dir.empty()) {
|
||||||
|
options.output_dir = expand_path(options.output_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.contents_dir.empty()) {
|
||||||
|
options.contents_dir = expand_path(options.contents_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.metadata_dir.empty()) {
|
||||||
|
options.metadata_dir = expand_path(options.metadata_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.hooks_dir.empty()) {
|
||||||
|
options.hooks_dir = expand_path(options.hooks_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.signature_key.empty()) {
|
||||||
|
options.signature_key = expand_path(options.signature_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the parsed options for debugging
|
||||||
|
dpm_log(LOG_DEBUG, ("Parsed options: contents_dir=" + options.contents_dir).c_str());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command parse_command(const char* cmd_str) {
|
||||||
|
if (cmd_str == nullptr || strlen(cmd_str) == 0) {
|
||||||
|
return CMD_HELP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(cmd_str, "help") == 0) {
|
||||||
|
return CMD_HELP;
|
||||||
|
}
|
||||||
|
else if (strcmp(cmd_str, "create") == 0) {
|
||||||
|
return CMD_CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates the build options
|
||||||
|
*/
|
||||||
|
int validate_build_options(const BuildOptions& options) {
|
||||||
|
// Check if contents directory is provided and exists
|
||||||
|
if (options.contents_dir.empty()) {
|
||||||
|
dpm_log(LOG_ERROR, "Contents directory is required (--contents)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(options.contents_dir)) {
|
||||||
|
dpm_log(LOG_ERROR, ("Contents directory does not exist: " + options.contents_dir).c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if metadata directory is provided and exists
|
||||||
|
if (options.metadata_dir.empty()) {
|
||||||
|
dpm_log(LOG_ERROR, "Metadata directory is required (--metadata)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(options.metadata_dir)) {
|
||||||
|
dpm_log(LOG_ERROR, ("Metadata directory does not exist: " + options.metadata_dir).c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if hooks directory exists if provided
|
||||||
|
if (!options.hooks_dir.empty() && !std::filesystem::exists(options.hooks_dir)) {
|
||||||
|
dpm_log(LOG_ERROR, ("Hooks directory does not exist: " + options.hooks_dir).c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if output directory exists
|
||||||
|
if (!std::filesystem::exists(options.output_dir)) {
|
||||||
|
dpm_log(LOG_ERROR, ("Output directory does not exist: " + options.output_dir).c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if signature key exists if provided
|
||||||
|
if (!options.signature_key.empty() && !std::filesystem::exists(options.signature_key)) {
|
||||||
|
dpm_log(LOG_ERROR, ("Signature key file does not exist: " + options.signature_key).c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
#include "commands.hpp"
|
||||||
|
|
||||||
|
int cmd_create(int argc, char** argv) {
|
||||||
|
// create a container for commandline options
|
||||||
|
BuildOptions options;
|
||||||
|
|
||||||
|
// Parse command-line options
|
||||||
|
int parse_result = parse_create_options(argc, argv, options);
|
||||||
|
if (parse_result != 0) {
|
||||||
|
return parse_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If help was requested, show it and return
|
||||||
|
if (options.show_help) {
|
||||||
|
return cmd_help(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate options
|
||||||
|
int validate_result = validate_build_options(options);
|
||||||
|
if (validate_result != 0) {
|
||||||
|
return validate_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the operation
|
||||||
|
if (options.verbose) {
|
||||||
|
dpm_log(LOG_INFO, "Creating DPM package with the following options:");
|
||||||
|
dpm_log(LOG_INFO, (" Output directory: " + options.output_dir).c_str());
|
||||||
|
dpm_log(LOG_INFO, (" Contents directory: " + options.contents_dir).c_str());
|
||||||
|
dpm_log(LOG_INFO, (" Metadata directory: " + options.metadata_dir).c_str());
|
||||||
|
|
||||||
|
if (!options.hooks_dir.empty()) {
|
||||||
|
dpm_log(LOG_INFO, (" Hooks directory: " + options.hooks_dir).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.package_name.empty()) {
|
||||||
|
dpm_log(LOG_INFO, (" Package name: " + options.package_name).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.signature_key.empty()) {
|
||||||
|
dpm_log(LOG_INFO, (" Signature key: " + options.signature_key).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.force) {
|
||||||
|
dpm_log(LOG_INFO, " Force: Yes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, just log that we would create the package
|
||||||
|
dpm_log(LOG_INFO, "Package creation functionality not yet implemented");
|
||||||
|
dpm_log(LOG_INFO, "Would create package using the provided options");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handler for the help command
|
||||||
|
*/
|
||||||
|
int cmd_help(int argc, char** argv) {
|
||||||
|
dpm_log(LOG_INFO, "DPM Build Module - Creates DPM packages according to specification");
|
||||||
|
dpm_log(LOG_INFO, "Available commands:");
|
||||||
|
dpm_log(LOG_INFO, " create - Create a new DPM package");
|
||||||
|
dpm_log(LOG_INFO, " help - Display this help message");
|
||||||
|
dpm_log(LOG_INFO, "");
|
||||||
|
dpm_log(LOG_INFO, "Usage: dpm build create [options]");
|
||||||
|
dpm_log(LOG_INFO, "Options:");
|
||||||
|
dpm_log(LOG_INFO, " -o, --output-dir DIR Directory to save the built package (default: current directory)");
|
||||||
|
dpm_log(LOG_INFO, " -c, --contents DIR Directory with package contents (required)");
|
||||||
|
dpm_log(LOG_INFO, " -m, --metadata DIR Directory with package metadata (required)");
|
||||||
|
dpm_log(LOG_INFO, " -H, --hooks DIR Directory with package hooks (optional)");
|
||||||
|
dpm_log(LOG_INFO, " -n, --name NAME Package name (required if not in metadata)");
|
||||||
|
dpm_log(LOG_INFO, " -s, --sign KEY Path to GPG key for signing the package (optional)");
|
||||||
|
dpm_log(LOG_INFO, " -f, --force Force package creation even if warnings occur");
|
||||||
|
dpm_log(LOG_INFO, " -v, --verbose Enable verbose output");
|
||||||
|
dpm_log(LOG_INFO, " -h, --help Display this help message");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handler for unknown commands
|
||||||
|
*/
|
||||||
|
int cmd_unknown(const char* command, int argc, char** argv) {
|
||||||
|
std::string msg = "Unknown command: ";
|
||||||
|
msg += (command ? command : "");
|
||||||
|
dpm_log(LOG_WARN, msg.c_str());
|
||||||
|
dpm_log(LOG_WARN, "Run 'dpm build help' for a list of available commands");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* @file buildFuncs.cpp
|
||||||
|
* @brief Implementation of the build module support functions
|
||||||
|
*
|
||||||
|
* Implements functions for the build module that create DPM packages
|
||||||
|
* according to the specification.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2025 SILO GROUP LLC
|
||||||
|
* @author Chris Punches <chris.punches@silogroup.org>
|
||||||
|
*
|
||||||
|
* Part of the Dark Horse Linux Package Manager (DPM)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "helpers.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Expands environment variables and tildes in a path
|
||||||
|
*/
|
||||||
|
std::string expand_path(const std::string& path) {
|
||||||
|
wordexp_t exp_result;
|
||||||
|
std::string expanded_path = path;
|
||||||
|
|
||||||
|
// Use wordexp to expand the path
|
||||||
|
if (wordexp(path.c_str(), &exp_result, 0) == 0) {
|
||||||
|
if (exp_result.we_wordc > 0) {
|
||||||
|
expanded_path = exp_result.we_wordv[0];
|
||||||
|
}
|
||||||
|
wordfree(&exp_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return expanded_path;
|
||||||
|
}
|
Loading…
Reference in New Issue