diff --git a/build.sh b/build.sh index d557dcd..278f6fd 100755 --- a/build.sh +++ b/build.sh @@ -9,6 +9,17 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color +# Parse command line arguments +AUTO_INSTALL=false +for arg in "$@"; do + case $arg in + --auto-install) + AUTO_INSTALL=true + ;; + esac +done + + # Function to print status messages print_status() { echo -e "${GREEN}[*] $1${NC}" @@ -79,10 +90,8 @@ else fi # Check if user wants to install -read -p "Do you want to install the program? (y/n) " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - print_status "Installing dropshell..." +if [ $AUTO_INSTALL = true ]; then + print_status "Auto-installing dropshell..." sudo make install if [ $? -eq 0 ]; then print_status "Installation successful!" @@ -90,6 +99,19 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then print_error "Installation failed!" exit 1 fi +else + read -p "Do you want to install the program? (y/n) " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + print_status "Installing dropshell..." + sudo make install + if [ $? -eq 0 ]; then + print_status "Installation successful!" + else + print_error "Installation failed!" + exit 1 + fi + fi fi # Return to original directory diff --git a/src/autocomplete.cpp b/src/autocomplete.cpp new file mode 100644 index 0000000..712c283 --- /dev/null +++ b/src/autocomplete.cpp @@ -0,0 +1,36 @@ +#include "autocomplete.hpp" +#include "servers.hpp" +#include "config.hpp" + +#include + +void dropshell::autocomplete(const std::vector &args) +{ + // std::cerr << "[ "< commands; + dropshell::get_all_used_commands(commands); + +// add in commmands hard-coded and handled in main + commands.merge(std::set{ + "help","init" // these are always available. + }); + if (dropshell::get_global_config()->is_config_set()) + commands.merge(std::set{ + "server","templates","create-service","create-template","create-server","edit","ssh", + "view" // only if we have a config. + }); + for (const auto& command : commands) { + std::cout << command << std::endl; + } +} + diff --git a/src/autocomplete.hpp b/src/autocomplete.hpp new file mode 100644 index 0000000..5bd1f6f --- /dev/null +++ b/src/autocomplete.hpp @@ -0,0 +1,16 @@ +#ifndef AUTOCOMPLETE_HPP +#define AUTOCOMPLETE_HPP + +#include +#include + + +namespace dropshell { + + void autocomplete(const std::vector &args); + + void autocomplete_list_commands(); + +} // namespace dropshell + +#endif \ No newline at end of file diff --git a/src/dropshell-completion.bash b/src/dropshell-completion.bash index 25ec1a8..0bd5a1d 100755 --- a/src/dropshell-completion.bash +++ b/src/dropshell-completion.bash @@ -1,61 +1,14 @@ #!/bin/bash _dropshell_completions() { - local cur prev opts + local cur COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - root="${COMP_WORDS[1]}" - # add all commands to opts - local commands=($(dropshell autocomplete_list_commands)) -# echo "commands: ${commands[*]}" - opts="${opts} ${commands[*]}" - - # If we're completing the first argument, show all commands - if [[ ${COMP_CWORD} -eq 1 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) - return 0 - fi - - # Command-specific completions - case "${root}" in - templates|autocomplete_list_servers|autocomplete_list_services|autocomplete_list_commands) - # No additional completions for these commands - COMPREPLY=() - return 0 - ;; - *) - if [[ ! " ${commands[*]} " =~ " ${root} " ]]; then - COMPREPLY=() - return 0 - fi - # Handle completion for template commands - if [[ ${COMP_CWORD} -eq 2 ]]; then - # Second argument is server name - local servers=($(dropshell autocomplete_list_servers)) - COMPREPLY=( $(compgen -W "${servers[*]}" -- ${cur}) ) - return 0 - elif [[ ${COMP_CWORD} -eq 3 ]]; then - # Third argument is service name - local server_name="${COMP_WORDS[2]}" - local services=($(dropshell autocomplete_list_services "$server_name")) - COMPREPLY=( $(compgen -W "${services[*]}" -- ${cur}) ) - return 0 - elif [[ ${COMP_CWORD} -eq 4 ]]; then - if [[ ${root} == "restore" ]]; then - # Fourth argument is backup file name - local server_name="${COMP_WORDS[2]}" - local service_name="${COMP_WORDS[3]}" - local backup_files=($(dropshell autocomplete_list_backups "$server_name" "$service_name")) - COMPREPLY=( $(compgen -W "${backup_files[*]}" -- ${cur}) ) - return 0 - fi - COMPREPLY=() - return 0 - fi - ;; - esac + # call dropshell to get the list of possiblities for the current argument. Supply all previous arguments. + local completions=($(dropshell autocomplete "${COMP_WORDS[@]:1:${COMP_CWORD}-1}")) + COMPREPLY=( $(compgen -W "${completions[*]}" -- ${cur}) ) + return 0 } # Register the completion function diff --git a/src/main.cpp b/src/main.cpp index 446d325..26ed8b7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,8 @@ #include "templates.hpp" #include "utils/utils.hpp" #include "utils/readmes.hpp" +#include "autocomplete.hpp" +#include "main_commands.hpp" #include #include @@ -74,42 +76,23 @@ int main(int argc, char* argv[]) { // silently attempt to load the config file. cfg->load_config(); - if (argc == 1) { + if (argc < 2) { dropshell::print_help(); return 0; } std::string cmd = argv[1]; + std::vector argvec; + for (int i=0; iadd_local_config_directory(argv[2])) - return 1; // error already reported - cfg->save_config(); - std::cout << "Config directory added: " << cfg->get_local_config_directories().back() << std::endl; - dropshell::create_readme_local_config_dir(cfg->get_local_config_directories().back()); - - if (cfg->get_local_config_directories().size() ==1) - std::cout << "DropShell is now initialised and you can add a server with 'dropshell create-server '" << std::endl; - else - { - std::cout << "DropShell will now use all of the following directories for configuration:" << std::endl; - for (const auto& dir : cfg->get_local_config_directories()) { - std::cout << " " << dir << std::endl; - } - std::cout << "You can edit the config file manually at: " << dropshell::get_local_dropshell_config_path() << std::endl; - } - return 0; - } catch (const std::exception& e) { - std::cerr << "Error in init: " << e.what() << std::endl; - return 1; - } + return dropshell::main_commands::init(argvec); } if (cmd == "help" || cmd == "-h" || cmd == "--help" || cmd== "h" || cmd=="halp") { @@ -117,69 +100,6 @@ int main(int argc, char* argv[]) { return 0; } - // auto completion stuff. - std::set template_shell_commands, full_command_set; - std::vector servers = dropshell::get_configured_servers(); - for (const auto& server : servers) - { - std::vector services = dropshell::get_server_services_info(server.name); - for (const auto& service : services) - template_shell_commands.merge(dropshell::get_used_commands(server.name, service.service_name)); - } - - if (cmd == "autocomplete_list_commands") { // add in commands handled here, not by the template shell scripts. - std::set full_command_set = template_shell_commands; - full_command_set.merge(std::set{ - "help","init" // these are always available. - }); - if (cfg->is_config_set()) - full_command_set.merge(std::set{ - "server","templates","create-service","create-template","create-server","edit","ssh", - "view" // only if we have a config. - }); - - for (const auto& command : full_command_set) { - std::cout << command << std::endl; - } - return 0; - } - - if (cmd == "autocomplete_list_servers") { - if (cfg->is_config_set()) - { - auto servers = dropshell::get_configured_servers(); - for (const auto& server : servers) - std::cout << server.name << 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 (cfg->is_config_set()) { - auto services = dropshell::get_server_services_info(argv[2]); - for (const auto& service : services) - std::cout << service.service_name << std::endl; - } - return 0; - } - - if (cmd == "autocomplete_list_backups") { - if (argc < 4) { - std::cerr << "Error: autocomplete_list_backups requires a server name and service name" << std::endl; - return 1; - } - if (cfg->is_config_set()) { - auto backups = dropshell::list_backups(argv[2], argv[3]); - for (const auto& backup : backups) - std::cout << backup << std::endl; - } - return 0; - } - // ------------------------------------------------------------ // from here we require the config file to be loaded. if (!cfg->is_config_set()) { @@ -187,17 +107,11 @@ int main(int argc, char* argv[]) { return 1; } - std::string lcd; const std::vector & local_config_directories = cfg->get_local_config_directories(); std::cout << "Config directories: "; for (auto & dir : local_config_directories) std::cout << "["<< dir << "] " << std::endl; - std::cout << std::endl;; - // No arguments provided - if (argc < 2) { - dropshell::print_help(); - return 0; - } + std::cout << std::endl; if (cmd == "server" || cmd == "servers" || cmd == "view" || cmd == "views" || cmd == "v") switch (argc) @@ -268,7 +182,8 @@ int main(int argc, char* argv[]) { } // handle running a command. - std::set commands = template_shell_commands; + std::set commands; + dropshell::get_all_used_commands(commands); commands.merge(std::set{"ssh","edit"}); // handled by service_runner, but not in template_shell_commands. for (const auto& command : commands) { if (cmd == command) { diff --git a/src/main_commands.cpp b/src/main_commands.cpp new file mode 100644 index 0000000..fe38bd9 --- /dev/null +++ b/src/main_commands.cpp @@ -0,0 +1,48 @@ +#include "main_commands.hpp" + +#include "utils/directories.hpp" +#include "utils/utils.hpp" +#include "utils/readmes.hpp" +#include "config.hpp" +#include + +namespace dropshell { + +namespace main_commands { + +int init(const std::vector &args) +{ + dropshell::config *cfg = dropshell::get_global_config(); + std::string lcd; + + if (args.size() < 3) { + std::cerr << "Error: init command requires a directory argument" << std::endl; + return 1; + } + try { + if (!cfg->add_local_config_directory(args[2])) + return 1; // error already reported + cfg->save_config(); + std::cout << "Config directory added: " << cfg->get_local_config_directories().back() << std::endl; + dropshell::create_readme_local_config_dir(cfg->get_local_config_directories().back()); + + if (cfg->get_local_config_directories().size() ==1) + std::cout << "DropShell is now initialised and you can add a server with 'dropshell create-server '" << std::endl; + else + { + std::cout << "DropShell will now use all of the following directories for configuration:" << std::endl; + for (const auto& dir : cfg->get_local_config_directories()) { + std::cout << " " << dir << std::endl; + } + std::cout << "You can edit the config file manually at: " << dropshell::get_local_dropshell_config_path() << std::endl; + } + return 0; + } catch (const std::exception& e) { + std::cerr << "Error in init: " << e.what() << std::endl; + return 1; + } +} + +} // namespace main_commands + +} // namespace dropshell diff --git a/src/main_commands.hpp b/src/main_commands.hpp new file mode 100644 index 0000000..4c0cfca --- /dev/null +++ b/src/main_commands.hpp @@ -0,0 +1,17 @@ +#ifndef MAIN_COMMANDS_HPP +#define MAIN_COMMANDS_HPP + +#include +#include + +namespace dropshell { + + namespace main_commands { + + int init(const std::vector &args); + + } // namespace main_commands + +} // namespace dropshell + +#endif \ No newline at end of file diff --git a/src/servers.cpp b/src/servers.cpp index a121c7c..6eb5898 100644 --- a/src/servers.cpp +++ b/src/servers.cpp @@ -186,4 +186,16 @@ void create_server(const std::string &server_name) std::cout << std::endl; } +void get_all_used_commands(std::set &commands) +{ + std::set template_shell_commands; + std::vector servers = get_configured_servers(); + for (const auto& server : servers) + { + std::vector services = dropshell::get_server_services_info(server.name); + for (const auto& service : services) + template_shell_commands.merge(dropshell::get_used_commands(server.name, service.service_name)); + } +} + } // namespace dropshell \ No newline at end of file diff --git a/src/servers.hpp b/src/servers.hpp index 4e7eda3..bd2e72b 100644 --- a/src/servers.hpp +++ b/src/servers.hpp @@ -22,6 +22,8 @@ namespace dropshell { void create_server(const std::string& server_name); + void get_all_used_commands(std::set &commands); + } // namespace dropshell #endif // SERVERS_HPP