diff --git a/build.sh b/build.sh index 92ee32c..d557dcd 100755 --- a/build.sh +++ b/build.sh @@ -43,6 +43,24 @@ if ! command -v make &> /dev/null; then exit 1 fi +# Check if pkg-config is installed +if ! command -v pkg-config &> /dev/null; then + print_error "pkg-config is not installed. Please install pkg-config first." + print_warning "On Ubuntu/Debian: sudo apt-get install pkg-config" + print_warning "On Fedora: sudo dnf install pkg-config" + print_warning "On Arch: sudo pacman -S pkg-config" + exit 1 +fi + +# Check if ncurses is installed +if ! pkg-config --exists ncurses; then + print_error "ncurses is not installed. Please install ncurses first." + print_warning "On Ubuntu/Debian: sudo apt-get install libncurses-dev" + print_warning "On Fedora: sudo dnf install ncurses-devel" + print_warning "On Arch: sudo pacman -S ncurses" + exit 1 +fi + # Configure with CMake print_status "Configuring with CMake..." cmake .. -DCMAKE_BUILD_TYPE=Release diff --git a/src/autocomplete.cpp b/src/autocomplete.cpp index e3ae70c..3a4c9e7 100644 --- a/src/autocomplete.cpp +++ b/src/autocomplete.cpp @@ -63,17 +63,6 @@ std::vector autocomplete_list_commands() { std::vector commands; std::set unique_commands; // To ensure deduplication - // System templates directory - const std::string system_templates_dir = "/opt/dropshell/templates"; - - // User templates directory - std::string user_templates_dir; - if (!get_user_directory(user_templates_dir)) { - std::cerr << "Error: User directory not set" << std::endl; - return commands; - } - user_templates_dir += "/usertemplates"; - // Helper function to add commands from a directory auto add_commands_from_dir = [&unique_commands](const std::string& dir_path) { if (!fs::exists(dir_path)) { @@ -96,11 +85,17 @@ std::vector autocomplete_list_commands() { } } }; - - // Add commands from both template locations + + // System templates directory + const std::string system_templates_dir = "/opt/dropshell/templates"; add_commands_from_dir(system_templates_dir); - add_commands_from_dir(user_templates_dir); - + + std::string user_templates_dir; + if (get_user_directory(user_templates_dir)) { + // User templates directory + user_templates_dir += "/usertemplates"; + add_commands_from_dir(user_templates_dir); + } // Convert set to vector for return commands.assign(unique_commands.begin(), unique_commands.end()); return commands; diff --git a/src/config.cpp b/src/config.cpp index 1f3f96c..8b79874 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "config.hpp" namespace fs = boost::filesystem; namespace pt = boost::property_tree; @@ -18,18 +19,14 @@ bool is_config_loaded() { return config_loaded; } -bool get_config_path(std::string& path) { +bool get_config_path(std::string &path) +{ // Try ~/.config/dropshell/dropshell.conf const char* home = std::getenv("HOME"); if (home) { fs::path user_path = fs::path(home) / ".config" / "dropshell" / "dropshell.conf"; - if (!fs::exists(user_path)) { - // create path - fs::create_directories(user_path.parent_path()); - } - path = user_path.string(); - return true; + return fs::exists(path); } std::cerr << "Warning: Couldn't determine user directory" << std::endl; path = ""; @@ -39,12 +36,7 @@ bool get_config_path(std::string& path) { bool load_config() { std::string config_path; if (!get_config_path(config_path)) - return true; - - if (config_path.empty()) { - // No config file found, but this is not an error - return true; - } + return false; try { pt::ptree tree; diff --git a/src/dropshell-completion.bash b/src/dropshell-completion.bash index a410224..4fc0981 100755 --- a/src/dropshell-completion.bash +++ b/src/dropshell-completion.bash @@ -7,9 +7,6 @@ _dropshell_completions() { prev="${COMP_WORDS[COMP_CWORD-1]}" root="${COMP_WORDS[1]}" - # List of main commands - opts="help version servers templates install backup" - # add all commands to opts local commands=($(dropshell autocomplete_list_commands)) opts="${opts} ${commands[*]}" diff --git a/src/main.cpp b/src/main.cpp index 0c342a8..46c6296 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,23 +63,28 @@ std::string safearg(int argc, char *argv[], int index) int main(int argc, char* argv[]) { try { - // Load configuration - if (!dropshell::load_config()) { - std::cerr << "Error: Failed to load configuration" << std::endl; - return 1; - } - - // No arguments provided - if (argc < 2) { - dropshell::interactive_mode(); - return 0; - } // Handle commands - std::string cmd = argv[1]; + std::string cmd; + if (argc > 1) { + cmd = argv[1]; + } + + // don't load old config if we're initializing + if (cmd == "init") { + if (argc < 3) { + std::cerr << "Error: init command requires a directory argument" << std::endl; + return 1; + } + try { + dropshell::init_user_directory(argv[2]); + return 0; + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + } - auto commands = dropshell::autocomplete_list_commands(); - if (cmd == "help" || cmd == "-h" || cmd == "--help") { dropshell::print_help(); return 0; @@ -90,6 +95,70 @@ int main(int argc, char* argv[]) { return 0; } + // silently attempt to load the config file. + dropshell::load_config(); + + + // auto compeltion stuff. + auto commands = dropshell::autocomplete_list_commands(); + if (cmd == "autocomplete_list_commands") { + // add in standard commands. + commands.insert(commands.end(), { + "help", + "version", + "init" + }); + if (dropshell::is_config_loaded()) { // these only work if the config is loaded. + commands.insert(commands.end(), { + "servers", + "templates", + "install", + "backup" + }); + } + + for (const auto& command : commands) { + std::cout << command << std::endl; + } + return 0; + } + + if (cmd == "autocomplete_list_servers") { + if (dropshell::is_config_loaded()) + { + auto servers = dropshell::autocomplete_list_servers(); + for (const auto& server : servers) + std::cout << server << std::endl; + } + return 0; + } + + if (cmd == "autocomplete_list_services") { + if (argc < 3) { + std::cerr << "Error: autocomplete_list_services requires a server name" << std::endl; + return 1; + } + if (dropshell::is_config_loaded()) { + auto services = dropshell::autocomplete_list_services(argv[2]); + for (const auto& service : services) + std::cout << service << std::endl; + } + return 0; + } + + // ------------------------------------------------------------ + // from here we require the config file to be loaded. + if (!dropshell::is_config_loaded()) { + std::cerr << "Error: Failed to load configuration." << std::endl << "Please run 'dropshell init ' to initialise the user directory and create a configuration file." << std::endl; + return 1; + } + + // No arguments provided + if (argc < 2) { + dropshell::interactive_mode(); + return 0; + } + if (cmd == "servers") { if (argc > 2) { // Show details for specific server @@ -106,47 +175,6 @@ int main(int argc, char* argv[]) { return 0; } - if (cmd == "init") { - if (argc < 3) { - std::cerr << "Error: init command requires a directory argument" << std::endl; - return 1; - } - try { - dropshell::init_user_directory(argv[2]); - return 0; - } catch (const std::exception& e) { - std::cerr << "Error: " << e.what() << std::endl; - return 1; - } - } - - if (cmd == "autocomplete_list_servers") { - auto servers = dropshell::autocomplete_list_servers(); - for (const auto& server : servers) { - std::cout << server << std::endl; - } - return 0; - } - - if (cmd == "autocomplete_list_services") { - if (argc < 3) { - std::cerr << "Error: autocomplete_list_services requires a server name" << std::endl; - return 1; - } - auto services = dropshell::autocomplete_list_services(argv[2]); - for (const auto& service : services) { - std::cout << service << std::endl; - } - return 0; - } - - if (cmd == "autocomplete_list_commands") { - for (const auto& command : commands) { - std::cout << command << std::endl; - } - return 0; - } - if (cmd == "install") { std::string server_name; std::vector servicelist; @@ -191,6 +219,8 @@ int main(int argc, char* argv[]) { return 0; } + + // handle running a command. for (const auto& command : commands) { if (cmd == command) { std::string server_name; diff --git a/templates/squashkiwi/example.env b/templates/squashkiwi/example/example.env similarity index 100% rename from templates/squashkiwi/example.env rename to templates/squashkiwi/example/example.env