Multiple directories
This commit is contained in:
parent
4d3523a346
commit
72e757ebd6
@ -30,17 +30,14 @@ bool config::load_config() {
|
|||||||
|
|
||||||
envmanager config_env(config_path);
|
envmanager config_env(config_path);
|
||||||
if (!config_env.load())
|
if (!config_env.load())
|
||||||
{
|
|
||||||
std::cerr << "Warning: Unable to read configuration file: " << config_path << std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
mLocalConfigPath = config_env.get_variable_substituted("local.config.directory");
|
std::string mDirectories = config_env.get_variable_substituted("local.config.directories");
|
||||||
if (mLocalConfigPath.empty())
|
if (mDirectories.empty())
|
||||||
{
|
|
||||||
std::cerr << "Warning: User directory not set in config" << std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
// Split the directories string into a vector of strings
|
||||||
|
mLocalConfigPaths = string2multi(mDirectories);
|
||||||
|
|
||||||
//std::cout << "Local config path: " << mLocalConfigPath << std::endl;
|
//std::cout << "Local config path: " << mLocalConfigPath << std::endl;
|
||||||
return true;
|
return true;
|
||||||
@ -48,7 +45,7 @@ bool config::load_config() {
|
|||||||
|
|
||||||
void config::save_config()
|
void config::save_config()
|
||||||
{
|
{
|
||||||
if (mLocalConfigPath.empty())
|
if (mLocalConfigPaths.empty())
|
||||||
{
|
{
|
||||||
std::cerr << "Warning: Unable to save configuration file, as DropShell has not been initialised."<< std::endl;
|
std::cerr << "Warning: Unable to save configuration file, as DropShell has not been initialised."<< std::endl;
|
||||||
std::cerr << "Please run 'dropshell init <path>' to initialise DropShell." << std::endl;
|
std::cerr << "Please run 'dropshell init <path>' to initialise DropShell." << std::endl;
|
||||||
@ -57,36 +54,46 @@ void config::save_config()
|
|||||||
|
|
||||||
std::string config_path = get_local_dropshell_config_path();
|
std::string config_path = get_local_dropshell_config_path();
|
||||||
envmanager config_env(config_path);
|
envmanager config_env(config_path);
|
||||||
config_env.set_variable("local.config.directory", mLocalConfigPath);
|
|
||||||
|
config_env.set_variable("local.config.directories", multi2string(mLocalConfigPaths));
|
||||||
config_env.save();
|
config_env.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool config::is_config_set() const
|
bool config::is_config_set() const
|
||||||
{
|
{
|
||||||
return !mLocalConfigPath.empty();
|
return !mLocalConfigPaths.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool config::get_local_config_directory(std::string& path) const {
|
|
||||||
path = mLocalConfigPath;
|
const std::vector<std::string> & config::get_local_config_directories() const
|
||||||
return !path.empty();
|
{
|
||||||
|
return mLocalConfigPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
void config::init_local_config_directory(const std::string& path) {
|
bool config::add_local_config_directory(const std::string &path)
|
||||||
|
{
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
throw std::runtime_error("Warning: Unable to initialise local config directory, as the path is empty.");
|
return false;
|
||||||
|
|
||||||
// Convert to canonical path
|
// Convert to canonical path
|
||||||
fs::path abs_path = fs::canonical(path);
|
fs::path abs_path = fs::canonical(path);
|
||||||
|
|
||||||
// The directory must exist
|
// The directory must exist
|
||||||
if (!fs::exists(abs_path)) {
|
if (!fs::exists(abs_path)) {
|
||||||
throw std::runtime_error("The local config directory does not exist: " + abs_path.string());
|
std::cerr << "Error: The local config directory does not exist: " << abs_path.string() << std::endl;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mLocalConfigPath = abs_path.string();
|
// Add to config paths if not already there
|
||||||
save_config();
|
std::string path_str = abs_path.string();
|
||||||
std::cout << "Local config directory initialized to: " << abs_path.string() << std::endl;
|
if (std::find(mLocalConfigPaths.begin(), mLocalConfigPaths.end(), path_str) == mLocalConfigPaths.end()) {
|
||||||
|
mLocalConfigPaths.push_back(path_str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Warning: The local config directory is already registered: " << path_str << std::endl;
|
||||||
|
std::cerr << "No changes made to the DropShell configuration." << std::endl;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace dropshell {
|
namespace dropshell {
|
||||||
|
|
||||||
@ -13,11 +14,11 @@ class config {
|
|||||||
|
|
||||||
bool is_config_set() const;
|
bool is_config_set() const;
|
||||||
|
|
||||||
bool get_local_config_directory(std::string& path) const;
|
const std::vector<std::string> & get_local_config_directories() const;
|
||||||
void init_local_config_directory(const std::string& path);
|
bool add_local_config_directory(const std::string& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mLocalConfigPath;
|
std::vector<std::string> mLocalConfigPaths;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
65
src/main.cpp
65
src/main.cpp
@ -11,7 +11,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iomanip>
|
||||||
namespace dropshell {
|
namespace dropshell {
|
||||||
|
|
||||||
void print_version() {
|
void print_version() {
|
||||||
@ -30,7 +30,7 @@ void print_help() {
|
|||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << " help Show this help message" << std::endl;
|
std::cout << " help Show this help message" << std::endl;
|
||||||
std::cout << " version Show version information" << std::endl;
|
std::cout << " version Show version information" << std::endl;
|
||||||
std::cout << " init DIR Initialise the local dropshell directory (local config, backups, etc)" << std::endl;
|
std::cout << " init DIR Add a local dropshell config directory (you can add several)" << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "Server commands:" << std::endl;
|
std::cout << "Server commands:" << std::endl;
|
||||||
@ -44,6 +44,11 @@ void print_help() {
|
|||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "Standard commands: install, backup, uninstall, start, stop" << std::endl;
|
std::cout << "Standard commands: install, backup, uninstall, start, stop" << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "Creation commands: (apply to the first local config directory)"<<std::endl;
|
||||||
|
std::cout << " create-template TEMPLATE" << std::endl;
|
||||||
|
std::cout << " create-server SERVER" << std::endl;
|
||||||
|
std::cout << " create-service SERVER SERVICE" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
||||||
@ -73,27 +78,38 @@ int main(int argc, char* argv[]) {
|
|||||||
try {
|
try {
|
||||||
dropshell::config *cfg = dropshell::get_global_config();
|
dropshell::config *cfg = dropshell::get_global_config();
|
||||||
|
|
||||||
// Handle commands
|
if (argc == 1) {
|
||||||
std::string cmd;
|
dropshell::print_help();
|
||||||
if (argc > 1) {
|
return 0;
|
||||||
cmd = argv[1];
|
|
||||||
}
|
}
|
||||||
|
std::string cmd = argv[1];
|
||||||
|
|
||||||
|
// silently attempt to load the config file.
|
||||||
|
cfg->load_config();
|
||||||
|
|
||||||
// don't load old config if we're initializing
|
// don't load old config if we're initializing
|
||||||
if (cmd == "init") {
|
if (cmd == "init") {
|
||||||
std::string lcd;
|
std::string lcd;
|
||||||
if (boost::filesystem::exists(dropshell::get_local_dropshell_config_path())) {
|
|
||||||
std::cerr << "DropShell is already initialised in " << dropshell::get_local_dropshell_config_path() << std::endl;
|
|
||||||
std::cerr << "Please manually delete this old config file and re-run the init command." << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
std::cerr << "Error: init command requires a directory argument" << std::endl;
|
std::cerr << "Error: init command requires a directory argument" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cfg->init_local_config_directory(argv[2]);
|
if (!cfg->add_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;
|
||||||
|
if (cfg->get_local_config_directories().size() ==1)
|
||||||
|
std::cout << "DropShell is now initialised and you can add a server with 'dropshell create-server <server-name>'" << 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;
|
return 0;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
std::cerr << "Error in init: " << e.what() << std::endl;
|
std::cerr << "Error in init: " << e.what() << std::endl;
|
||||||
@ -111,9 +127,6 @@ int main(int argc, char* argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// silently attempt to load the config file.
|
|
||||||
cfg->load_config();
|
|
||||||
|
|
||||||
// auto completion stuff.
|
// auto completion stuff.
|
||||||
std::set<std::string> commands;
|
std::set<std::string> commands;
|
||||||
std::vector<dropshell::ServerInfo> servers = dropshell::get_configured_servers();
|
std::vector<dropshell::ServerInfo> servers = dropshell::get_configured_servers();
|
||||||
@ -126,13 +139,11 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
if (cmd == "autocomplete_list_commands") {
|
if (cmd == "autocomplete_list_commands") {
|
||||||
commands.merge(std::set<std::string>{
|
commands.merge(std::set<std::string>{
|
||||||
"help","version"
|
"help","version","init"
|
||||||
});
|
});
|
||||||
if (!boost::filesystem::exists(dropshell::get_local_dropshell_config_path()))
|
|
||||||
commands.insert("init");
|
|
||||||
if (cfg->is_config_set())
|
if (cfg->is_config_set())
|
||||||
commands.merge(std::set<std::string>{
|
commands.merge(std::set<std::string>{
|
||||||
"servers","templates"
|
"servers","templates","create-service","create-template","create-server"
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
@ -172,9 +183,11 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string lcd;
|
std::string lcd;
|
||||||
cfg->get_local_config_directory(lcd);
|
const std::vector<std::string> & local_config_directories = cfg->get_local_config_directories();
|
||||||
std::cout << "Local config path: " << lcd << std::endl;
|
std::cout << "Config directories: ";
|
||||||
|
for (auto & dir : local_config_directories)
|
||||||
|
std::cout << "["<< dir << "] " << std::endl;
|
||||||
|
std::cout << std::endl;;
|
||||||
// No arguments provided
|
// No arguments provided
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
dropshell::print_help();
|
dropshell::print_help();
|
||||||
@ -197,6 +210,14 @@ int main(int argc, char* argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd == "create-template") {
|
||||||
|
if (argc < 3) {
|
||||||
|
std::cerr << "Error: create-template requires a template name" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
dropshell::create_template(argv[2]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
// handle running a command.
|
// handle running a command.
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
if (cmd == command) {
|
if (cmd == command) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "utils/envmanager.hpp"
|
#include "utils/envmanager.hpp"
|
||||||
#include "utils/directories.hpp"
|
#include "utils/directories.hpp"
|
||||||
#include "services.hpp"
|
#include "services.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
@ -18,15 +19,13 @@ namespace dropshell {
|
|||||||
std::vector<ServerInfo> get_configured_servers() {
|
std::vector<ServerInfo> get_configured_servers() {
|
||||||
std::vector<ServerInfo> servers;
|
std::vector<ServerInfo> servers;
|
||||||
|
|
||||||
std::string servers_dir = get_local_config_servers_path();
|
std::vector<std::string> local_config_directories = get_global_config()->get_local_config_directories();
|
||||||
if (servers_dir.empty()) {
|
if (local_config_directories.empty())
|
||||||
return servers;
|
return servers;
|
||||||
}
|
|
||||||
|
|
||||||
if (!fs::exists(servers_dir)) {
|
for (int i = 0; i < local_config_directories.size(); i++) {
|
||||||
std::cerr << "Error: Servers directory not found:" << servers_dir << std::endl;
|
std::string servers_dir = get_local_config_servers_path(i);
|
||||||
return servers;
|
if (!servers_dir.empty() && fs::exists(servers_dir)) {
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& entry : fs::directory_iterator(servers_dir)) {
|
for (const auto& entry : fs::directory_iterator(servers_dir)) {
|
||||||
if (fs::is_directory(entry)) {
|
if (fs::is_directory(entry)) {
|
||||||
@ -34,7 +33,7 @@ std::vector<ServerInfo> get_configured_servers() {
|
|||||||
|
|
||||||
server_env env(server_name);
|
server_env env(server_name);
|
||||||
if (!env.is_valid()) {
|
if (!env.is_valid()) {
|
||||||
std::cerr << "Error: Invalid server environment file: " << server_name << std::endl;
|
std::cerr << "Error: Invalid server environment file: " << entry.path().string() << std::endl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
servers.push_back({
|
servers.push_back({
|
||||||
@ -45,12 +44,12 @@ std::vector<ServerInfo> get_configured_servers() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return servers;
|
return servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void list_servers() {
|
void list_servers() {
|
||||||
auto servers = get_configured_servers();
|
auto servers = get_configured_servers();
|
||||||
|
|
||||||
|
@ -275,7 +275,11 @@ bool service_runner::backup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create backups directory locally if it doesn't exist
|
// Create backups directory locally if it doesn't exist
|
||||||
std::string local_backups_dir = get_local_config_backups_path();
|
std::string local_backups_dir = get_local_config_backups_path(0);
|
||||||
|
if (local_backups_dir.empty()) {
|
||||||
|
std::cerr << "Error: Local backups directory not found - is DropShell initialised?" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!fs::exists(local_backups_dir)) {
|
if (!fs::exists(local_backups_dir)) {
|
||||||
fs::create_directories(local_backups_dir);
|
fs::create_directories(local_backups_dir);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "utils/envmanager.hpp"
|
#include "utils/envmanager.hpp"
|
||||||
#include "utils/directories.hpp"
|
#include "utils/directories.hpp"
|
||||||
#include "templates.hpp"
|
#include "templates.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@ -15,25 +16,32 @@ std::vector<ServiceInfo> get_server_services_info(const std::string& server_name
|
|||||||
if (server_name.empty())
|
if (server_name.empty())
|
||||||
return services;
|
return services;
|
||||||
|
|
||||||
std::string serverpath = get_local_config_servers_path();
|
std::vector<std::string> local_config_directories = get_global_config()->get_local_config_directories();
|
||||||
|
if (local_config_directories.empty()) {
|
||||||
|
std::cerr << "Error: No local config directories found" << std::endl;
|
||||||
|
std::cerr << "Run 'dropshell init' to initialise DropShell" << std::endl;
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < getNumConfigDirectories(); i++) {
|
||||||
|
std::string serverpath = get_local_config_servers_path(i);
|
||||||
if (serverpath.empty()) {
|
if (serverpath.empty()) {
|
||||||
std::cerr << "Error: Server directory not found: " << serverpath << std::endl;
|
std::cerr << "Error: Server directory not found: " << serverpath << std::endl;
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
fs::path server_dir = fs::path(serverpath) / server_name;
|
fs::path server_dir = fs::path(serverpath) / server_name;
|
||||||
if (!fs::exists(server_dir)) {
|
if (fs::exists(server_dir)) {
|
||||||
std::cerr << "Error: Server directory not found:" << server_dir.string() << std::endl;
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
for (const auto& entry : fs::directory_iterator(server_dir)) {
|
for (const auto& entry : fs::directory_iterator(server_dir)) {
|
||||||
if (fs::is_directory(entry)) {
|
if (fs::is_directory(entry)) {
|
||||||
ServiceInfo service = get_service_info(server_name, entry.path().filename().string());
|
ServiceInfo service = get_service_info(server_name, entry.path().filename().string());
|
||||||
if (!service.template_name.empty()) {
|
if (!service.template_name.empty()) {
|
||||||
// std::cout << "Service: " << service.service_name << " found in " << server_dir.string() << ", with template: " << service.template_name << std::endl;
|
|
||||||
services.push_back(service);
|
services.push_back(service);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // end of for (int i = 0; i < getNumConfigDirectories(); i++)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "utils/directories.hpp"
|
#include "utils/directories.hpp"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -40,7 +41,17 @@ bool get_templates(std::vector<template_info>& templates) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
add_templates_from_dir(get_local_config_templates_path());
|
// add templates from the local config directories
|
||||||
|
for (int i = 0; i < getNumConfigDirectories(); i++) {
|
||||||
|
std::string path = get_local_config_templates_path(i);
|
||||||
|
if (path.empty()) {
|
||||||
|
std::cerr << "Error: Templates directory not found: " << path << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
add_templates_from_dir(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add templates from the system templates directory
|
||||||
add_templates_from_dir(get_local_system_templates_path());
|
add_templates_from_dir(get_local_system_templates_path());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -96,4 +107,77 @@ void list_templates() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void create_template(const std::string& template_name) {
|
||||||
|
// 1. Create a new directory in the user templates directory
|
||||||
|
std::vector<std::string> local_config_directories = get_global_config()->get_local_config_directories();
|
||||||
|
|
||||||
|
if (local_config_directories.empty()) {
|
||||||
|
std::cerr << "Error: No local config directories found" << std::endl;
|
||||||
|
std::cerr << "Run 'dropshell init' to initialise DropShell" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template_info info;
|
||||||
|
if (get_template_info(template_name, info)) {
|
||||||
|
std::cerr << "Error: Template '" << template_name << "' already exists at " << info.path << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string user_templates_dir = local_config_directories[0] + "/templates";
|
||||||
|
std::string new_template_path = user_templates_dir + "/" + template_name;
|
||||||
|
|
||||||
|
// Create the new template directory
|
||||||
|
std::filesystem::create_directories(new_template_path);
|
||||||
|
|
||||||
|
// 2. Copy the example template from the system templates directory
|
||||||
|
std::string system_templates_dir = get_local_system_templates_path();
|
||||||
|
std::string example_template_path = system_templates_dir + "/example";
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(example_template_path)) {
|
||||||
|
std::cerr << "Error: Example template not found at " << example_template_path << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all files from example template to new template
|
||||||
|
for (const auto& entry : std::filesystem::recursive_directory_iterator(example_template_path)) {
|
||||||
|
std::string relative_path = entry.path().string().substr(example_template_path.length());
|
||||||
|
std::string target_path = new_template_path + relative_path;
|
||||||
|
|
||||||
|
if (entry.is_directory()) {
|
||||||
|
std::filesystem::create_directory(target_path);
|
||||||
|
} else {
|
||||||
|
std::filesystem::copy_file(entry.path(), target_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// modify the TEMPLATE=example line in the service.env file to TEMPLATE=<template_name>
|
||||||
|
std::string search_string = "TEMPLATE=";
|
||||||
|
std::string replacement_line = "TEMPLATE=" + template_name;
|
||||||
|
// replace the line in the example/service.env file with the replacement line
|
||||||
|
std::string service_env_path = new_template_path + "/example/service.env";
|
||||||
|
|
||||||
|
|
||||||
|
// 3. Print out the README.txt file and the path
|
||||||
|
std::string readme_path = new_template_path + "/README.txt";
|
||||||
|
if (std::filesystem::exists(readme_path)) {
|
||||||
|
std::cout << "\nREADME contents:" << std::endl;
|
||||||
|
std::cout << std::string(60, '-') << std::endl;
|
||||||
|
|
||||||
|
std::ifstream readme_file(readme_path);
|
||||||
|
if (readme_file.is_open()) {
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(readme_file, line)) {
|
||||||
|
std::cout << line << std::endl;
|
||||||
|
}
|
||||||
|
readme_file.close();
|
||||||
|
}
|
||||||
|
std::cout << std::string(60, '-') << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "No README.txt file found in the template." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "Template '" << template_name << "' created at " << new_template_path << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
@ -24,4 +24,11 @@ bool get_template_info(const std::string& name, template_info& info);
|
|||||||
bool template_command_exists(const std::string& template_name,const std::string& command);
|
bool template_command_exists(const std::string& template_name,const std::string& command);
|
||||||
void list_templates();
|
void list_templates();
|
||||||
|
|
||||||
|
|
||||||
|
// create a template
|
||||||
|
// 1. create a new directory in the user templates directory
|
||||||
|
// 2. copy the example template from the system templates directory into the new directory
|
||||||
|
// 3. print out the README.txt file in the new template directory, and the path to the new template
|
||||||
|
void create_template(const std::string& template_name);
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
||||||
|
@ -28,35 +28,41 @@ std::string get_local_system_templates_path()
|
|||||||
return "/opt/dropshell/templates";
|
return "/opt/dropshell/templates";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_local_config_path()
|
int getNumConfigDirectories()
|
||||||
{
|
{
|
||||||
config *cfg = get_global_config();
|
config *cfg = get_global_config();
|
||||||
std::string user_dir;
|
std::vector<std::string> local_config_directories = cfg->get_local_config_directories();
|
||||||
if (!cfg->get_local_config_directory(user_dir)) {
|
return local_config_directories.size();
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
return user_dir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_local_config_templates_path()
|
std::string get_local_config_path(int index)
|
||||||
{
|
{
|
||||||
std::string config_path = get_local_config_path();
|
config *cfg = get_global_config();
|
||||||
|
std::vector<std::string> local_config_directories = cfg->get_local_config_directories();
|
||||||
|
if (index < 0 || index >= local_config_directories.size())
|
||||||
|
return std::string();
|
||||||
|
return local_config_directories[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_local_config_templates_path(int index)
|
||||||
|
{
|
||||||
|
std::string config_path = get_local_config_path(index);
|
||||||
if (config_path.empty())
|
if (config_path.empty())
|
||||||
return std::string();
|
return std::string();
|
||||||
return config_path + "/templates";
|
return config_path + "/templates";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_local_config_servers_path()
|
std::string get_local_config_servers_path(int index)
|
||||||
{
|
{
|
||||||
std::string config_path = get_local_config_path();
|
std::string config_path = get_local_config_path(index);
|
||||||
if (config_path.empty())
|
if (config_path.empty())
|
||||||
return std::string();
|
return std::string();
|
||||||
return config_path + "/servers";
|
return config_path + "/servers";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_local_config_backups_path()
|
std::string get_local_config_backups_path(int index)
|
||||||
{
|
{
|
||||||
std::string config_path = get_local_config_path();
|
std::string config_path = get_local_config_path(index);
|
||||||
if (config_path.empty())
|
if (config_path.empty())
|
||||||
return std::string();
|
return std::string();
|
||||||
return config_path + "/backups";
|
return config_path + "/backups";
|
||||||
@ -64,12 +70,15 @@ std::string get_local_config_backups_path()
|
|||||||
|
|
||||||
std::string get_local_server_path(const std::string &server_name)
|
std::string get_local_server_path(const std::string &server_name)
|
||||||
{
|
{
|
||||||
if (server_name.empty())
|
config *cfg = get_global_config();
|
||||||
|
std::vector<std::string> local_config_directories = cfg->get_local_config_directories();
|
||||||
|
for (auto &dir : local_config_directories) {
|
||||||
|
std::string server_path = dir + "/servers/" + server_name;
|
||||||
|
if (fs::exists(server_path)) {
|
||||||
|
return server_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
return std::string();
|
return std::string();
|
||||||
std::string config_path = get_local_config_path();
|
|
||||||
if (config_path.empty())
|
|
||||||
return std::string();
|
|
||||||
return config_path + "/servers/" + server_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_local_server_env_path(const std::string &server_name)
|
std::string get_local_server_env_path(const std::string &server_name)
|
||||||
|
@ -8,10 +8,12 @@ namespace dropshell {
|
|||||||
// local paths - return empty string on failure
|
// local paths - return empty string on failure
|
||||||
std::string get_local_dropshell_config_path();
|
std::string get_local_dropshell_config_path();
|
||||||
std::string get_local_system_templates_path();
|
std::string get_local_system_templates_path();
|
||||||
std::string get_local_config_path();
|
|
||||||
std::string get_local_config_templates_path();
|
int getNumConfigDirectories();
|
||||||
std::string get_local_config_servers_path();
|
std::string get_local_config_path(int index);
|
||||||
std::string get_local_config_backups_path();
|
std::string get_local_config_templates_path(int index);
|
||||||
|
std::string get_local_config_servers_path(int index);
|
||||||
|
std::string get_local_config_backups_path(int index);
|
||||||
|
|
||||||
std::string get_local_server_path(const std::string &server_name);
|
std::string get_local_server_path(const std::string &server_name);
|
||||||
std::string get_local_server_env_path(const std::string &server_name);
|
std::string get_local_server_env_path(const std::string &server_name);
|
||||||
|
@ -97,7 +97,7 @@ void envmanager::clear_variables() {
|
|||||||
m_variables.clear();
|
m_variables.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string envmanager::trim(std::string str) const {
|
std::string trim(std::string str) {
|
||||||
// Trim leading whitespace
|
// Trim leading whitespace
|
||||||
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](unsigned char ch) {
|
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](unsigned char ch) {
|
||||||
return !std::isspace(ch);
|
return !std::isspace(ch);
|
||||||
@ -132,4 +132,62 @@ std::string envmanager::expand_patterns(std::string str) const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string multi2string(std::vector<std::string> values)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
for (const auto& value : values) {
|
||||||
|
// remove any " contained in the string value, if present
|
||||||
|
std::string quoteless_value = value;
|
||||||
|
quoteless_value.erase(std::remove(quoteless_value.begin(), quoteless_value.end(), '"'), quoteless_value.end());
|
||||||
|
result += "\"" + trim(quoteless_value) + "\",";
|
||||||
|
}
|
||||||
|
if (!result.empty())
|
||||||
|
result.pop_back(); // Remove the last comma
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> string2multi(std::string values)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
// Return values separated by commas, but ignore commas within quotes
|
||||||
|
bool inside_quotes = false;
|
||||||
|
std::string current_item;
|
||||||
|
|
||||||
|
for (char c : values) {
|
||||||
|
if (c == '"') {
|
||||||
|
inside_quotes = !inside_quotes;
|
||||||
|
} else if (c == ',' && !inside_quotes) {
|
||||||
|
if (!current_item.empty()) {
|
||||||
|
// Remove quotes if present
|
||||||
|
if (current_item.front() == '"' && current_item.back() == '"') {
|
||||||
|
current_item = current_item.substr(1, current_item.length() - 2);
|
||||||
|
}
|
||||||
|
std::string final = trim(current_item);
|
||||||
|
if (!final.empty()) {
|
||||||
|
result.push_back(final);
|
||||||
|
}
|
||||||
|
current_item.clear();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current_item += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the last item if not empty
|
||||||
|
if (!current_item.empty()) {
|
||||||
|
// Remove quotes if present
|
||||||
|
if (current_item.front() == '"' && current_item.back() == '"') {
|
||||||
|
current_item = current_item.substr(1, current_item.length() - 2);
|
||||||
|
}
|
||||||
|
std::string final = trim(current_item);
|
||||||
|
if (!final.empty()) {
|
||||||
|
result.push_back(final);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
namespace dropshell {
|
namespace dropshell {
|
||||||
|
|
||||||
// envmanager is a class that manages the environment files for the application.
|
// envmanager is a class that manages the environment files for the application.
|
||||||
@ -36,7 +37,6 @@ class envmanager {
|
|||||||
void clear_variables();
|
void clear_variables();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string trim(std::string str) const;
|
|
||||||
std::string expand_patterns(std::string str) const;
|
std::string expand_patterns(std::string str) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -44,6 +44,11 @@ class envmanager {
|
|||||||
std::map<std::string, std::string> m_variables;
|
std::map<std::string, std::string> m_variables;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// utility functions
|
||||||
|
std::string trim(std::string str);
|
||||||
|
std::string multi2string(std::vector<std::string> values);
|
||||||
|
std::vector<std::string> string2multi(std::string values);
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
DropShell Template Example
|
||||||
|
|
||||||
|
Shell scripts defined in this folder are run as DropShell commands on the remote server (not locally!).
|
||||||
|
All scripts are passed the server-specific service environment (SSSE) file as an argument.
|
||||||
|
|
||||||
|
The default SSSE file used when a new service is created is in example/service.env. This must exist,
|
||||||
|
and must at minimum contain the TEMPLATE=<template_name> variable.
|
||||||
|
|
||||||
|
The backups script gets a second argument, which is the backup file to create (a single tgz file).
|
||||||
|
|
||||||
|
Mandatory scripts are:
|
||||||
|
- install.sh
|
||||||
|
- uninstall.sh
|
||||||
|
- start.sh
|
||||||
|
- stop.sh
|
||||||
|
|
||||||
|
Optional standard scripts are:
|
||||||
|
- backup.sh
|
||||||
|
- status.sh
|
||||||
|
- ports.sh
|
||||||
|
- logs.sh
|
||||||
|
|
@ -63,6 +63,10 @@ grey_end() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
create_and_start_container() {
|
create_and_start_container() {
|
||||||
|
if [ -z "$1" ] || [ -z "$2" ]; then
|
||||||
|
die "Template error: create_and_start_container <run_cmd> <container_name>"
|
||||||
|
fi
|
||||||
|
|
||||||
local run_cmd="$1"
|
local run_cmd="$1"
|
||||||
local container_name="$2"
|
local container_name="$2"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user