This commit is contained in:
58
src/commands/command_registry.cpp
Normal file
58
src/commands/command_registry.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#include "command_registry.hpp"
|
||||
|
||||
CommandRegistry& CommandRegistry::instance() {
|
||||
static CommandRegistry reg;
|
||||
return reg;
|
||||
}
|
||||
|
||||
void CommandRegistry::register_command(const CommandInfo& info) {
|
||||
auto ptr = std::make_shared<CommandInfo>(info);
|
||||
for (const auto& name : info.names) {
|
||||
command_map_[name] = ptr;
|
||||
}
|
||||
all_commands_.push_back(ptr);
|
||||
}
|
||||
|
||||
const CommandInfo* CommandRegistry::find_command(const std::string& name) const {
|
||||
auto it = command_map_.find(name);
|
||||
if (it != command_map_.end()) return it->second.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> CommandRegistry::list_commands(bool include_hidden) const {
|
||||
std::set<std::string> out;
|
||||
for (const auto& cmd : all_commands_) {
|
||||
if (!cmd->hidden || include_hidden) {
|
||||
for (const auto& name : cmd->names) out.insert(name);
|
||||
}
|
||||
}
|
||||
return std::vector<std::string>(out.begin(), out.end());
|
||||
}
|
||||
|
||||
std::vector<std::string> CommandRegistry::list_primary_commands(bool include_hidden) const {
|
||||
std::set<std::string> out;
|
||||
for (const auto& cmd : all_commands_) {
|
||||
if (!cmd->hidden || include_hidden) {
|
||||
if (cmd->names.size() > 0)
|
||||
out.insert(cmd->names[0]);
|
||||
}
|
||||
}
|
||||
return std::vector<std::string>(out.begin(), out.end());
|
||||
}
|
||||
|
||||
|
||||
void CommandRegistry::autocomplete(const std::vector<std::string>& args) const {
|
||||
// dropshell autocomplete <command> <arg> <arg> ...
|
||||
if (args.size() < 3) {
|
||||
for (const auto& name : list_primary_commands(false)) {
|
||||
std::cout << name << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
std::string cmd = args[2];
|
||||
auto* info = find_command(cmd);
|
||||
if (info && info->autocomplete) {
|
||||
CommandContext ctx{args[0], cmd, std::vector<std::string>(args.begin() + 2, args.end())};
|
||||
info->autocomplete(ctx);
|
||||
}
|
||||
}
|
51
src/commands/command_registry.hpp
Normal file
51
src/commands/command_registry.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
struct CommandContext {
|
||||
std::string exename;
|
||||
std::string command;
|
||||
std::vector<std::string> args;
|
||||
|
||||
// Add more fields as needed (e.g., config pointer, output stream, etc.)
|
||||
};
|
||||
|
||||
struct CommandInfo {
|
||||
std::vector<std::string> names;
|
||||
std::function<int(const CommandContext&)> handler;
|
||||
std::function<void(const CommandContext&)> autocomplete; // optional
|
||||
bool hidden = false;
|
||||
bool requires_config = false;
|
||||
int min_args = 0;
|
||||
int max_args = -1; // -1 = unlimited
|
||||
std::string help_usage; // install SERVER [SERVICE]
|
||||
std::string help_description; // Install/reinstall/update service(s). Safe/non-destructive.
|
||||
std::string full_help; // detailed help for the command
|
||||
};
|
||||
|
||||
class CommandRegistry {
|
||||
public:
|
||||
static CommandRegistry& instance();
|
||||
|
||||
void register_command(const CommandInfo& info);
|
||||
|
||||
// Returns nullptr if not found
|
||||
const CommandInfo* find_command(const std::string& name) const;
|
||||
|
||||
// List all commands (optionally including hidden)
|
||||
std::vector<std::string> list_commands(bool include_hidden = false) const;
|
||||
std::vector<std::string> list_primary_commands(bool include_hidden = false) const;
|
||||
|
||||
// For autocomplete
|
||||
void autocomplete(const std::vector<std::string>& args) const;
|
||||
|
||||
private:
|
||||
CommandRegistry() = default;
|
||||
std::map<std::string, std::shared_ptr<CommandInfo>> command_map_;
|
||||
std::vector<std::shared_ptr<CommandInfo>> all_commands_;
|
||||
};
|
@ -5,6 +5,8 @@
|
||||
#include "utils/directories.hpp"
|
||||
#include "standard_autocomplete.hpp"
|
||||
#include "templates.hpp"
|
||||
#include "shared_commands.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
@ -46,22 +48,49 @@ struct InstallCommandRegister {
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// install service over ssh
|
||||
// rsync_tree_to_remote : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool rsync_tree_to_remote(
|
||||
const std::string &local_path,
|
||||
const std::string &remote_path,
|
||||
server_env_manager &server_env,
|
||||
bool silent)
|
||||
{
|
||||
ASSERT(!local_path.empty() && !remote_path.empty());
|
||||
|
||||
std::string rsync_cmd = "rsync --delete --mkpath -zrpc -e 'ssh -p " + server_env.get_SSH_PORT() + "' " +
|
||||
quote(local_path + "/") + " "+
|
||||
quote(server_env.get_SSH_USER() + "@" + server_env.get_SSH_HOST() + ":" +
|
||||
remote_path + "/");
|
||||
return execute_local_command(rsync_cmd, nullptr, (silent ? cMode::Silent : cMode::None) + cMode::RawCommand);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// install service over ssh : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool install_service(const std::string& server, const std::string& service, bool silent) {
|
||||
maketitle("Installing " + mService + " (" + mServiceInfo.template_name + ") on " + mServer);
|
||||
LocalServiceInfo service_info = get_service_info(server, service);
|
||||
if (!SIvalid(service_info))
|
||||
return false;
|
||||
|
||||
if (!mServerEnv.is_valid()) return false; // should never hit this.
|
||||
server_env_manager server_env(server);
|
||||
if (!server_env.is_valid())
|
||||
return false;
|
||||
|
||||
|
||||
maketitle("Installing " + service + " (" + service_info.template_name + ") on " + server);
|
||||
|
||||
if (!server_env.is_valid()) return false; // should never hit this.
|
||||
|
||||
// Check if template exists
|
||||
template_info tinfo = gTemplateManager().get_template_info(mServiceInfo.template_name);
|
||||
template_info tinfo = gTemplateManager().get_template_info(service_info.template_name);
|
||||
if (!tinfo.is_set())
|
||||
return false;
|
||||
|
||||
// Create service directory
|
||||
std::string remote_service_path = remotepath::service(mServer, mService);
|
||||
std::string remote_service_path = remotepath::service(server, service);
|
||||
std::string mkdir_cmd = "mkdir -p " + quote(remote_service_path);
|
||||
if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand(mkdir_cmd), cMode::Silent))
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand(mkdir_cmd), cMode::Silent))
|
||||
{
|
||||
std::cerr << "Failed to create service directory " << remote_service_path << std::endl;
|
||||
return false;
|
||||
@ -69,23 +98,25 @@ bool install_service(const std::string& server, const std::string& service, bool
|
||||
|
||||
// Check if rsync is installed on remote host
|
||||
std::string check_rsync_cmd = "which rsync";
|
||||
if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand(check_rsync_cmd), cMode::Silent))
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand(check_rsync_cmd), cMode::Silent))
|
||||
{
|
||||
std::cerr << "rsync is not installed on the remote host" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy template files
|
||||
std::cout << "Copying: [LOCAL] " << tinfo.local_template_path() << std::endl << std::string(8,' ')<<"[REMOTE] " << remotepath::service_template(mServer, mService) << "/" << std::endl;
|
||||
if (!rsync_tree_to_remote(tinfo.local_template_path().string(), remotepath::service_template(mServer, mService), silent))
|
||||
std::cout << "Copying: [LOCAL] " << tinfo.local_template_path() << std::endl << std::string(8,' ')<<"[REMOTE] " << remotepath::service_template(server, service) << "/" << std::endl;
|
||||
if (!rsync_tree_to_remote(tinfo.local_template_path().string(), remotepath::service_template(server, service),
|
||||
server_env, silent))
|
||||
{
|
||||
std::cerr << "Failed to copy template files using rsync" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy service files
|
||||
std::cout << "Copying: [LOCAL] " << localpath::service(mServer,mService) << std::endl << std::string(8,' ')<<"[REMOTE] " << remotepath::service_config(mServer,mService) << std::endl;
|
||||
if (!rsync_tree_to_remote(localpath::service(mServer,mService), remotepath::service_config(mServer,mService), silent))
|
||||
std::cout << "Copying: [LOCAL] " << localpath::service(server,service) << std::endl << std::string(8,' ')<<"[REMOTE] " << remotepath::service_config(server,service) << std::endl;
|
||||
if (!rsync_tree_to_remote(localpath::service(server,service), remotepath::service_config(server,service),
|
||||
server_env, silent))
|
||||
{
|
||||
std::cerr << "Failed to copy service files using rsync" << std::endl;
|
||||
return false;
|
||||
@ -93,7 +124,7 @@ bool install_service(const std::string& server, const std::string& service, bool
|
||||
|
||||
// Run install script
|
||||
{
|
||||
mServerEnv.run_remote_template_command(mService, "install", {}, silent, {});
|
||||
server_env.run_remote_template_command(service, "install", {}, silent, {});
|
||||
}
|
||||
|
||||
// print health tick
|
||||
|
19
src/commands/shared_commands.hpp
Normal file
19
src/commands/shared_commands.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef SHARED_COMMANDS_HPP
|
||||
#define SHARED_COMMANDS_HPP
|
||||
|
||||
#include "servers.hpp"
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
// defined in install.cpp
|
||||
bool rsync_tree_to_remote(
|
||||
const std::string &local_path,
|
||||
const std::string &remote_path,
|
||||
server_env_manager &server_env,
|
||||
bool silent);
|
||||
|
||||
// defined in install.cpp
|
||||
bool install_service(const std::string& server, const std::string& service, bool silent);
|
||||
|
||||
} // namespace dropshell
|
||||
#endif
|
Reference in New Issue
Block a user