Skip to content

Commit

Permalink
Add support for setting targets from the environment
Browse files Browse the repository at this point in the history
  • Loading branch information
radj307 committed Jan 26, 2022
1 parent 3e01ea1 commit d356eef
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 10 deletions.
55 changes: 53 additions & 2 deletions ARRCON/Help.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct Help {
Help(const std::filesystem::path& program_name) : _program_name{ program_name } {}
friend std::ostream& operator<<(std::ostream& os, const Help& help)
{
os << help._program_name.generic_string() << ' ' << ((help._program_name != std::string_view(DEFAULT_PROGRAM_NAME)) ? "("s + DEFAULT_PROGRAM_NAME + ") "s : "") << "v" << ARRCON_VERSION << '\n'
return os << help._program_name.generic_string() << ' ' << ((help._program_name != std::string_view(DEFAULT_PROGRAM_NAME)) ? "("s + DEFAULT_PROGRAM_NAME + ") "s : "") << "v" << ARRCON_VERSION << '\n'
<< "Another Remote-CONsole Client.\n"
<< '\n'
<< "USAGE:\n"
Expand All @@ -40,6 +40,7 @@ struct Help {
<< "-d <ms> --delay <ms> Time in milliseconds to wait between each command in commandline mode." << '\n'
<< "-n --no-color Disable colorized console output." << '\n'
<< "-Q --no-prompt Disables the prompt in interactive mode, and command echo in commandline mode." << '\n'
<< "--print-env Prints all recognized environment variables, their values, and descriptions." << '\n'
<< "--write-ini (Over)write the configuration file with the default values & exit." << '\n'
<< '\n'
<< "MODES:\n"
Expand All @@ -53,6 +54,56 @@ struct Help {
<< " Each line will be executed as a command in commandline mode after any arguments." << '\n'
<< " Input received from STDIN follows the same rules as script files."
;
return os.flush();
}
};

struct EnvHelp {
std::string program_name;
EnvHelp(const std::string& programName) : program_name{ programName } {}

friend std::ostream& operator<<(std::ostream& os, const EnvHelp& help)
{
std::string var{ help.program_name + "_CONFIG_DIR" };
// ARRCON_CONFIG_DIR
os
<< Global.palette.set(UIElem::ENV_VAR) << var << Global.palette.reset() << '\n'
<< " " << "Current Value: " << env::getvar(var).value_or("") << '\n'
<< " " << "Description:\n"
<< " " << "Overrides the default config location." << '\n'
<< " " << "When this is set, config files in other locations are ignored." << '\n'
<< '\n'
;
// ARRCON_HOST
var = { help.program_name + "_HOST" };
os
<< Global.palette.set(UIElem::ENV_VAR) << var << Global.palette.reset() << '\n'
<< " " << "Current Value: " << env::getvar(var).value_or("") << '\n'
<< " " << "Description:\n"
<< " " << "Overrides the default target hostname." << '\n'
<< " " << "This overrides the " << Global.palette.set(UIElem::INI_KEY_HIGHLIGHT) << "sDefaultHost" << Global.palette.reset() << " key in the INI file." << '\n'
<< '\n'
;
// ARRCON_PORT
var = { help.program_name + "_PORT" };
os
<< Global.palette.set(UIElem::ENV_VAR) << var << Global.palette.reset() << '\n'
<< " " << "Current Value: " << env::getvar(var).value_or("") << '\n'
<< " " << "Description:\n"
<< " " << "Overrides the default target port." << '\n'
<< " " << "This overrides the " << Global.palette.set(UIElem::INI_KEY_HIGHLIGHT) << "sDefaultPort" << Global.palette.reset() << " key in the INI file." << '\n'
<< '\n'
;
// ARRCON_PASS
var = { help.program_name + "_PASS" };
os
<< Global.palette.set(UIElem::ENV_VAR) << var << Global.palette.reset() << '\n'
<< " " << "Current Value: " << env::getvar(var).value_or("") << '\n'
<< " " << "Description:\n"
<< " " << "Overrides the default target password." << '\n'
<< " " << "This overrides the " << Global.palette.set(UIElem::INI_KEY_HIGHLIGHT) << "sDefaultPass" << Global.palette.reset() << " key in the INI file." << '\n'
;
return os;
}
};


9 changes: 8 additions & 1 deletion ARRCON/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace config {
std::filesystem::path home_path;

public:
Locator(const std::filesystem::path& program_dir, const std::filesystem::path& program_name) : program_location{ program_dir }, name_no_ext{ [](auto&& p) -> std::string { const std::string s{ p.generic_string() }; if (const auto pos{ s.find('.') }; pos < s.size()) return s.substr(0ull, pos); return s; }(program_name) }, env_path{ env::getvar(name_no_ext + "_CONFIG_DIR").value_or("") }, home_path{ env::get_home() } {}
Locator(const std::filesystem::path& program_dir, const std::string& program_name_no_extension) : program_location{ program_dir }, name_no_ext{ program_name_no_extension }, env_path{ env::getvar(name_no_ext + "_CONFIG_DIR").value_or("") }, home_path{ env::get_home() } {}

std::string getEnvironmentVariableName(const std::string& suffix = "_CONFIG_DIR") const
{
Expand Down Expand Up @@ -107,6 +107,13 @@ namespace config {
return true;
}

inline void load_environment(const std::string& programNameNoExt)
{
Global.target.hostname = env::getvar(programNameNoExt + "_HOST").value_or(Global.target.hostname);
Global.target.port = env::getvar(programNameNoExt + "_PORT").value_or(Global.target.port);
Global.target.password = env::getvar(programNameNoExt + "_PASS").value_or(Global.target.password);
}

/**
* @brief Save the INI configuration file.
* @param path Location to save config.
Expand Down
10 changes: 8 additions & 2 deletions ARRCON/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
#include <atomic>
#include <unistd.h>

/// @brief The default program name on each platform.
/// @brief The default program name on each platform.
inline constexpr const auto DEFAULT_PROGRAM_NAME{
#ifdef OS_WIN
"ARRCON.exe"
"ARRCON.exe"
#else
"ARRCON"
#endif
Expand All @@ -36,6 +36,8 @@ using SOCKET = unsigned long long;

#define ISSUE_REPORT_URL "https://github.com/radj307/ARRCON/issues"



/**
* @struct HostInfo
* @brief Contains the connection info for a single target.
Expand Down Expand Up @@ -68,6 +70,7 @@ enum class UIElem : unsigned char {
HOST_INFO, // list-hosts command (hostname/port)
INI_KEY_HIGHLIGHT, // used by some exceptions to highlight INI keys.
NO_RESPONSE, // interactive mode no response message
ENV_VAR, // --print-env
};

static struct {
Expand All @@ -82,13 +85,15 @@ static struct {
std::make_pair(UIElem::HOST_INFO, color::light_gray),
std::make_pair(UIElem::INI_KEY_HIGHLIGHT, color::intense_yellow),
std::make_pair(UIElem::NO_RESPONSE, color::orange),
std::make_pair(UIElem::ENV_VAR, color::intense_yellow),
};
const HostInfo DEFAULT_TARGET{ // default target
"localhost",
"27015",
""
};
HostInfo target{ DEFAULT_TARGET }; // active target
HostInfo env_target{};

/// @brief When true, response packets are not printed to the terminal
bool quiet{ false };
Expand Down Expand Up @@ -162,3 +167,4 @@ inline timespec make_timeout(const std::chrono::milliseconds& ms)
}
#define SELECT(nfds, rd, wr, ex, timeout) pselect(nfds, rd, wr, ex, timeout, nullptr)
#endif // #ifdef OS_WIN

38 changes: 33 additions & 5 deletions ARRCON/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
#undef read
#undef write

inline HostInfo get_environment_target(std::string programNameNoExt)
{
programNameNoExt = str::toupper(programNameNoExt);
return{
env::getvar(programNameNoExt + "_HOST").value_or(""),
env::getvar(programNameNoExt + "_PORT").value_or(""),
env::getvar(programNameNoExt + "_PASS").value_or("")
};
}

/**
* @brief Retrieve the user's specified connection target.
* @param args Arguments from main().
Expand All @@ -26,7 +36,7 @@
*/
inline HostInfo get_target_info(const opt::ParamsAPI2& args, const config::HostList& hostlist)
{

const auto
host{ args.typegetv_any<opt::Flag, opt::Option>('H', "host") }, //< Argument: [-H|--host]
port{ args.typegetv_any<opt::Flag, opt::Option>('P', "port") }, //< Argument: [-P|--port]
Expand Down Expand Up @@ -82,7 +92,7 @@ inline void handle_hostfile_arguments(const opt::ParamsAPI2& args, config::HostL
// save-host
else if (const auto save_host{ args.typegetv<opt::Option>("save-host") }; save_host.has_value()) {
std::stringstream message_buffer; // save the messages in a buffer to prevent misleading messages in the event of a file writing error


const auto target_info{ from_hostinfo(target) };
const auto& [existing, added] {
Expand Down Expand Up @@ -249,7 +259,7 @@ int main(const int argc, char** argv)
Global.palette.setDefaultResetSequence(color::reset_f);

std::cout << term::EnableANSI; // enable ANSI escape sequences on windows
const opt::ParamsAPI2 args{ argc, argv, 'H', "host", 'S', "saved", 'P', "port", 'p', "pass", 'd', "delay", 'f', "file", "save-host", "remove-host"}; // parse arguments
const opt::ParamsAPI2 args{ argc, argv, 'H', "host", 'S', "saved", 'P', "port", 'p', "pass", 'd', "delay", 'f', "file", "save-host", "remove-host" }; // parse arguments

// check for disable colors argument:
if (const auto arg{ args.typegetv_any<opt::Option, opt::Flag>('n', "no-color") }; arg.has_value())
Expand All @@ -259,7 +269,15 @@ int main(const int argc, char** argv)
env::PATH PATH{ argv[0] };
const auto& [myDir, myName] { PATH.resolve_split(argv[0]) };

const config::Locator cfg_path(myDir, myName);
const std::string myNameNoExt{
[](auto&& p) -> std::string {
const std::string s{ p.generic_string() };
if (const auto pos{ s.find('.') }; pos < s.size())
return str::toupper(s.substr(0ull, pos));
return str::toupper(s);
}(myName) };

const config::Locator cfg_path(myDir, myNameNoExt);
Global.EnvVar_CONFIG_DIR = cfg_path.getEnvironmentVariableName();

// Argument: [-q|--quiet]
Expand All @@ -276,6 +294,11 @@ int main(const int argc, char** argv)
std::cout << ARRCON_VERSION << std::endl;
return 0;
}
// Argument: [--print-env]
if (args.check<opt::Option>("print-env")) {
std::cout << EnvHelp(myNameNoExt) << std::endl;
return 0;
}

// Get the INI file's path
std::filesystem::path ini_path{ cfg_path.from_extension(".ini") };
Expand All @@ -284,6 +307,9 @@ int main(const int argc, char** argv)
if (file::exists(ini_path))
config::load_ini(ini_path);

// load target-specifier environment variables
config::load_environment(myNameNoExt);

if (args.empty() && !Global.allow_no_args) {
std::cerr << Help(myName) << std::endl << std::endl;
throw make_exception(
Expand All @@ -299,7 +325,7 @@ int main(const int argc, char** argv)
// Initialize the hostlist
config::HostList hosts;

const auto hostfile_path{ cfg_path.from_extension(".hosts")};
const auto hostfile_path{ cfg_path.from_extension(".hosts") };
if (file::exists(hostfile_path)) // load the hostfile if it exists
hosts = config::load_hostfile(hostfile_path);

Expand Down Expand Up @@ -345,9 +371,11 @@ int main(const int argc, char** argv)
return 0;
} catch (const std::exception& ex) { ///< catch exceptions
std::cerr << term::get_error(!Global.no_color) << ex.what() << std::endl;
std::cerr << term::get_info(!Global.no_color) << "You can report bugs here: " << ISSUE_REPORT_URL << std::endl;
return -1;
} catch (...) { ///< catch all other exceptions
std::cerr << term::get_crit(!Global.no_color) << "An unknown exception occurred!" << std::endl;
std::cerr << term::get_info(!Global.no_color) << "Please report this exception here: " << ISSUE_REPORT_URL << std::endl;
return -1;
}
}

0 comments on commit d356eef

Please sign in to comment.