This commit is contained in:
parent
8fc3384c03
commit
d946c18d7c
@ -102,14 +102,6 @@ if [ "$ARCH" != "aarch64" ] && [ "$ARCH" != "x86_64" ]; then
|
||||
fi
|
||||
|
||||
|
||||
#-----------------------------------------
|
||||
# install bb64
|
||||
curl -fsSL https://gitea.jde.nz/j/bb64/raw/branch/main/install.sh -o ./install-bb64.sh && bash ./install-bb64.sh && rm ./install-bb64.sh
|
||||
|
||||
#-----------------------------------------
|
||||
|
||||
|
||||
|
||||
echo "Installation complete."
|
||||
|
||||
#--------------------------------
|
||||
|
@ -88,7 +88,7 @@ bool install_service(const std::string& server, const std::string& service, bool
|
||||
// Create service directory
|
||||
std::string remote_service_path = remotepath::service(server, service);
|
||||
std::string mkdir_cmd = "mkdir -p " + quote(remote_service_path);
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand(mkdir_cmd), cMode::Silent))
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("",remotepath::executables(server), mkdir_cmd, {}), cMode::Silent))
|
||||
{
|
||||
std::cerr << "Failed to create service directory " << remote_service_path << std::endl;
|
||||
return false;
|
||||
@ -96,7 +96,7 @@ 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(server_env.get_SSH_INFO(), sCommand(check_rsync_cmd), cMode::Silent))
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("",remotepath::executables(server), check_rsync_cmd, {}), cMode::Silent))
|
||||
{
|
||||
std::cerr << "rsync is not installed on the remote host" << std::endl;
|
||||
return false;
|
||||
|
@ -61,6 +61,8 @@ bool config::save_config(bool create_aux_directories)
|
||||
std::string dropshell_base = homedir + "/.dropshell";
|
||||
mConfig["tempfiles"] = dropshell_base + "/tmp";
|
||||
mConfig["backups"] = dropshell_base + "/backups";
|
||||
mConfig["executables"] = dropshell_base + "/executables";
|
||||
|
||||
mConfig["template_cache"] = dropshell_base + "/template_cache";
|
||||
mConfig["template_registry_URLs"] = {
|
||||
"https://templates.dropshell.app"
|
||||
@ -68,6 +70,7 @@ bool config::save_config(bool create_aux_directories)
|
||||
mConfig["template_local_paths"] = {
|
||||
dropshell_base + "/local_templates"
|
||||
};
|
||||
|
||||
mConfig["server_definition_paths"] = {
|
||||
dropshell_base + "/servers"
|
||||
};
|
||||
@ -116,6 +119,11 @@ std::string config::get_local_template_cache_path() {
|
||||
return mConfig["template_cache"];
|
||||
}
|
||||
|
||||
std::string config::get_local_executables_path()
|
||||
{
|
||||
return mConfig["executables"];
|
||||
}
|
||||
|
||||
std::vector<std::string> config::get_template_registry_urls() {
|
||||
nlohmann::json template_registry_urls = mConfig["template_registry_URLs"];
|
||||
std::vector<std::string> urls;
|
||||
|
@ -20,7 +20,7 @@ class config {
|
||||
std::string get_local_tempfiles_path();
|
||||
std::string get_local_backup_path();
|
||||
std::string get_local_template_cache_path();
|
||||
|
||||
std::string get_local_executables_path();
|
||||
std::vector<std::string> get_template_registry_urls();
|
||||
std::vector<std::string> get_template_local_paths();
|
||||
std::vector<std::string> get_local_server_definition_paths();
|
||||
|
@ -145,7 +145,6 @@ auto command_match = [](const std::string& cmd_list, int argc, char* argv[]) ->
|
||||
|
||||
int old_main(int argc, char* argv[]) {
|
||||
HAPPYEXIT("hash", hash_demo_raw(safearg(argc,argv,2)))
|
||||
HAPPYEXIT("makesafecmd", std::cout<<makesafecmd(safearg(argc,argv,2))<<std::endl)
|
||||
HAPPYEXIT("version", printversion())
|
||||
BOOLEXIT("test-template", gTemplateManager().test_template(safearg(argc,argv,2)))
|
||||
ASSERT(safearg(argc,argv,1) != "assert", "Hello! Here is an assert.");
|
||||
|
@ -101,11 +101,10 @@ std::string server_env_manager::get_variable(const std::string& name) const {
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
sCommand server_env_manager::construct_standard_template_run_cmd(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent) const
|
||||
std::optional<sCommand> server_env_manager::construct_standard_template_run_cmd(const std::string &service_name, const std::string &command, const std::vector<std::string> args, const bool silent) const
|
||||
{
|
||||
if (command.empty())
|
||||
return sCommand();
|
||||
return std::nullopt;
|
||||
|
||||
std::string remote_service_template_path = remotepath::service_template(mServerName,service_name);
|
||||
std::string script_path = remote_service_template_path + "/" + command + ".sh";
|
||||
@ -113,7 +112,7 @@ sCommand server_env_manager::construct_standard_template_run_cmd(const std::stri
|
||||
std::map<std::string, std::string> env_vars;
|
||||
if (!get_all_service_env_vars(mServerName, service_name, env_vars)) {
|
||||
std::cerr << "Error: Failed to get all service env vars for " << service_name << std::endl;
|
||||
return sCommand();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string argstr = "";
|
||||
@ -121,23 +120,29 @@ sCommand server_env_manager::construct_standard_template_run_cmd(const std::stri
|
||||
argstr += " " + quote(dequote(trim(arg)));
|
||||
}
|
||||
|
||||
sCommand scommand(remote_service_template_path, quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""), env_vars);
|
||||
sCommand sc(
|
||||
remote_service_template_path,
|
||||
remotepath::executables(mServerName),
|
||||
quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""),
|
||||
env_vars
|
||||
);
|
||||
|
||||
if (scommand.empty())
|
||||
if (sc.empty()) {
|
||||
std::cerr << "Error: Failed to construct command for " << service_name << " " << command << std::endl;
|
||||
|
||||
return scommand;
|
||||
return std::nullopt;
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
|
||||
bool server_env_manager::check_remote_dir_exists(const std::string &dir_path) const
|
||||
{
|
||||
sCommand scommand("test -d " + quote(dir_path));
|
||||
sCommand scommand("",remotepath::executables(mServerName),"test -d " + quote(dir_path),{});
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent);
|
||||
}
|
||||
|
||||
bool server_env_manager::check_remote_file_exists(const std::string& file_path) const {
|
||||
sCommand scommand("test -f " + quote(file_path));
|
||||
sCommand scommand("",remotepath::executables(mServerName),"test -f " + quote(file_path),{});
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent);
|
||||
}
|
||||
|
||||
@ -151,7 +156,7 @@ bool server_env_manager::check_remote_items_exist(const std::vector<std::string>
|
||||
file_names_str += std::filesystem::path(file_path).filename().string() + " ";
|
||||
}
|
||||
// check if all items in the vector exist on the remote server, in a single command.
|
||||
sCommand scommand("for item in " + file_paths_str + "; do test -f $item; done");
|
||||
sCommand scommand("",remotepath::executables(mServerName),"for item in " + file_paths_str + "; do test -f $item; done",{});
|
||||
|
||||
bool okay = execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent);
|
||||
if (!okay) {
|
||||
@ -182,7 +187,7 @@ bool server_env_manager::remove_remote_dir(const std::string &dir_path, bool sil
|
||||
if (!silent)
|
||||
std::cout << "Running command: " << remote_cmd << std::endl;
|
||||
|
||||
sCommand scommand(remote_cmd);
|
||||
sCommand scommand("",remotepath::executables(mServerName),remote_cmd,{});
|
||||
cMode mode = (silent ? cMode::Silent : cMode::None);
|
||||
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand, mode);
|
||||
@ -190,33 +195,36 @@ bool server_env_manager::remove_remote_dir(const std::string &dir_path, bool sil
|
||||
|
||||
bool server_env_manager::run_remote_template_command(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent, std::map<std::string, std::string> extra_env_vars) const
|
||||
{
|
||||
sCommand scommand = construct_standard_template_run_cmd(service_name, command, args, silent);
|
||||
auto scommand = construct_standard_template_run_cmd(service_name, command, args, silent);
|
||||
if (!scommand.has_value())
|
||||
return false;
|
||||
|
||||
// add the extra env vars to the command
|
||||
for (const auto& [key, value] : extra_env_vars)
|
||||
scommand.add_env_var(key, value);
|
||||
scommand->add_env_var(key, value);
|
||||
|
||||
if (scommand.get_command_to_run().empty())
|
||||
if (scommand->get_command_to_run().empty())
|
||||
return false;
|
||||
cMode mode = (command=="ssh") ? (cMode::Interactive) : cMode::Silent;
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand, mode);
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand.value(), mode);
|
||||
}
|
||||
|
||||
bool server_env_manager::run_remote_template_command_and_capture_output(const std::string &service_name, const std::string &command, std::vector<std::string> args, std::string &output, bool silent, std::map<std::string, std::string> extra_env_vars) const
|
||||
{
|
||||
sCommand scommand = construct_standard_template_run_cmd(service_name, command, args, false);
|
||||
if (scommand.get_command_to_run().empty())
|
||||
auto scommand = construct_standard_template_run_cmd(service_name, command, args, false);
|
||||
if (!scommand.has_value())
|
||||
return false;
|
||||
|
||||
// add the extra env vars to the command
|
||||
for (const auto& [key, value] : extra_env_vars)
|
||||
scommand.add_env_var(key, value);
|
||||
scommand->add_env_var(key, value);
|
||||
|
||||
cMode mode = cMode::CaptureOutput;
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand, mode, &output);
|
||||
return execute_ssh_command(get_SSH_INFO(), scommand.value(), mode, &output);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// base64 <<< "FOO=BAR WHEE=YAY bash ./test.sh"
|
||||
// echo YmFzaCAtYyAnRk9PPUJBUiBXSEVFPVlBWSBiYXNoIC4vdGVzdC5zaCcK | base64 -d | bash
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "utils/execute.hpp"
|
||||
|
||||
#include <optional>
|
||||
namespace dropshell {
|
||||
|
||||
class server_env_manager;
|
||||
@ -61,7 +61,7 @@ class server_env_manager {
|
||||
std::vector<std::string> args, std::string & output, bool silent, std::map<std::string, std::string> extra_env_vars) const;
|
||||
|
||||
private:
|
||||
sCommand construct_standard_template_run_cmd(const std::string& service_name, const std::string& command, std::vector<std::string> args, bool silent) const;
|
||||
std::optional<sCommand> construct_standard_template_run_cmd(const std::string& service_name, const std::string& command, const std::vector<std::string> args, const bool silent) const;
|
||||
|
||||
private:
|
||||
std::string mServerName;
|
||||
|
@ -236,12 +236,12 @@ bool service_runner::interactive_ssh(const std::string & server_name, const std:
|
||||
return false;
|
||||
}
|
||||
|
||||
sCommand scommand("bash");
|
||||
server_env_manager env(server_name);
|
||||
if (!env.is_valid()) {
|
||||
std::cerr << "Error: Invalid server environment file: " << server_name << std::endl;
|
||||
return false;
|
||||
}
|
||||
sCommand scommand("",remotepath::executables(server_name), "bash",{});
|
||||
return execute_ssh_command(env.get_SSH_INFO(), scommand, cMode::Interactive);
|
||||
}
|
||||
|
||||
@ -426,7 +426,7 @@ bool service_runner::backup(bool silent) {
|
||||
std::string remote_backups_dir = remotepath::backups(mServer);
|
||||
if (!silent) std::cout << "Remote backups directory on "<< mServer <<": " << remote_backups_dir << std::endl;
|
||||
std::string mkdir_cmd = "mkdir -p " + quote(remote_backups_dir);
|
||||
if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand(mkdir_cmd), cMode::Silent)) {
|
||||
if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand("",remotepath::executables(mServer), mkdir_cmd, {}), cMode::Silent)) {
|
||||
std::cerr << "Failed to create backups directory on server" << std::endl;
|
||||
return false;
|
||||
}
|
||||
@ -484,7 +484,7 @@ cRemoteTempFolder::cRemoteTempFolder(const server_env_manager &server_env) : mSe
|
||||
{
|
||||
std::string p = remotepath::temp_files(server_env.get_server_name()) + "/" + random_alphanumeric_string(10);
|
||||
std::string mkdir_cmd = "mkdir -p " + quote(p);
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand(mkdir_cmd), cMode::Silent))
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("",remotepath::executables(server_env.get_server_name()), mkdir_cmd, {}), cMode::Silent))
|
||||
std::cerr << "Failed to create temp directory on server" << std::endl;
|
||||
else
|
||||
mPath = p;
|
||||
@ -493,7 +493,7 @@ cRemoteTempFolder::cRemoteTempFolder(const server_env_manager &server_env) : mSe
|
||||
cRemoteTempFolder::~cRemoteTempFolder()
|
||||
{
|
||||
std::string rm_cmd = "rm -rf " + quote(mPath);
|
||||
execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand(rm_cmd), cMode::Silent);
|
||||
execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand("",remotepath::executables(mServerEnv.get_server_name()), rm_cmd, {}), cMode::Silent);
|
||||
}
|
||||
|
||||
std::string cRemoteTempFolder::path() const
|
||||
|
@ -230,6 +230,7 @@ bool get_all_service_env_vars(const std::string &server_name, const std::string
|
||||
all_env_vars["SERVER"] = server_name;
|
||||
all_env_vars["SERVICE"] = service_name;
|
||||
all_env_vars["AGENT_PATH"] = remotepath::service_template(server_name, "dropshell-agent") + "/shared";
|
||||
all_env_vars["EXECUTABLES"] = remotepath::executables(server_name);
|
||||
|
||||
ServerInfo server_info = get_server_info(server_name);
|
||||
if (server_info.ssh_host.empty())
|
||||
|
@ -142,6 +142,12 @@ namespace remotepath {
|
||||
return (dsp.empty() ? "" : (dsp + "/temp_files"));
|
||||
}
|
||||
|
||||
std::string executables(const std::string &server_name)
|
||||
{
|
||||
std::string dsp = DROPSHELL_DIR(server_name);
|
||||
return (dsp.empty() ? "" : (dsp + "/executables"));
|
||||
}
|
||||
|
||||
std::string service_env(const std::string &server_name, const std::string &service_name)
|
||||
{
|
||||
std::string service_path = service_config(server_name, service_name);
|
||||
|
@ -27,6 +27,8 @@ namespace dropshell {
|
||||
|
||||
// temp files path
|
||||
|
||||
// executables path
|
||||
|
||||
// template cache path
|
||||
// |-- templates
|
||||
// | |-- <template_name>.json
|
||||
@ -64,6 +66,7 @@ namespace dropshell {
|
||||
// DROPSHELL_DIR
|
||||
// |-- backups
|
||||
// |-- temp_files
|
||||
// |-- executables
|
||||
// |-- services
|
||||
// |-- service name
|
||||
// |-- config
|
||||
@ -86,6 +89,7 @@ namespace dropshell {
|
||||
std::string service_template(const std::string &server_name, const std::string &service_name);
|
||||
std::string backups(const std::string &server_name);
|
||||
std::string temp_files(const std::string &server_name);
|
||||
std::string executables(const std::string &server_name);
|
||||
} // namespace remotepath
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "execute.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
#include "utils/b64ed.hpp"
|
||||
#include "config.hpp"
|
||||
|
||||
bool EXITSTATUSCHECK(int ret)
|
||||
{
|
||||
@ -69,8 +70,15 @@ namespace dropshell
|
||||
return EXITSTATUSCHECK(ret);
|
||||
}
|
||||
|
||||
bool execute_local_command(const sCommand &command, std::string *output /* = nullptr */, cMode mode /* = cMode::None */)
|
||||
bool execute_local_command(std::string command, std::string *output, cMode mode)
|
||||
{
|
||||
return execute_local_command("",command,{}, output, mode);
|
||||
}
|
||||
|
||||
bool execute_local_command(std::string directory_to_run_in, std::string command_to_run, const std::map<std::string, std::string> &env_vars, std::string *output, cMode mode)
|
||||
{
|
||||
sCommand command(directory_to_run_in, gConfig().get_local_executables_path(), command_to_run, env_vars);
|
||||
|
||||
if (hasFlag(mode, cMode::Interactive))
|
||||
{
|
||||
ASSERT(!hasFlag(mode, cMode::CaptureOutput), "Interactive mode and capture output mode cannot be used together");
|
||||
@ -102,9 +110,9 @@ namespace dropshell
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &command, cMode mode, std::string *output)
|
||||
bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &remote_command, cMode mode, std::string *output)
|
||||
{
|
||||
if (command.get_command_to_run().empty())
|
||||
if (remote_command.get_command_to_run().empty())
|
||||
return false;
|
||||
|
||||
ASSERT(!(hasFlag(mode, cMode::CaptureOutput) && output == nullptr), "Capture output mode must be used with an output string");
|
||||
@ -113,29 +121,32 @@ namespace dropshell
|
||||
ssh_cmd << "ssh -p " << ssh_info.port << " " << (hasFlag(mode, cMode::Interactive) ? "-tt " : "")
|
||||
<< ssh_info.user << "@" << ssh_info.host;
|
||||
|
||||
std::string cmdstr = command.construct_cmd();
|
||||
sCommand ssh_command(ssh_cmd.str() + " " + cmdstr);
|
||||
|
||||
bool rval = execute_local_command(ssh_command, output, mode);
|
||||
bool rval = execute_local_command(
|
||||
"", // directory to run in
|
||||
ssh_cmd.str() + " " + remote_command.construct_cmd(), // local command to run
|
||||
{}, // environment variables
|
||||
output, // output string
|
||||
mode // mode
|
||||
);
|
||||
|
||||
if (!rval && !hasFlag(mode, cMode::Silent))
|
||||
{
|
||||
std::cerr << std::endl
|
||||
<< std::endl;
|
||||
std::cerr << "Error: Failed to execute ssh command:" << std::endl;
|
||||
std::cerr << "\033[90m" << ssh_command.get_command_to_run() << "\033[0m" << std::endl;
|
||||
std::cerr << "\033[90m" << ssh_cmd.str() + " " + remote_command.construct_cmd() << "\033[0m" << std::endl;
|
||||
std::cerr << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
std::string makesafecmd(const std::string &command)
|
||||
std::string sCommand::makesafecmd(const std::string &command) const
|
||||
{
|
||||
if (command.empty())
|
||||
return "";
|
||||
std::string encoded = base64_encode(dequote(trim(command)));
|
||||
std::string commandstr = "bb64 " + encoded;
|
||||
std::string commandstr = mExecutablesPath + "/bb64 " + encoded;
|
||||
return commandstr;
|
||||
}
|
||||
|
||||
|
@ -30,42 +30,41 @@ typedef struct sSSHInfo {
|
||||
std::string port;
|
||||
} sSSHInfo;
|
||||
|
||||
bool execute_local_command(const sCommand & command, std::string * output = nullptr, cMode mode = cMode::None);
|
||||
bool execute_ssh_command(const sSSHInfo & ssh_info, const sCommand & command, cMode mode = cMode::None, std::string * output = nullptr);
|
||||
|
||||
std::string makesafecmd(const std::string& command);
|
||||
bool execute_local_command(std::string command, std::string * output = nullptr, cMode mode = cMode::None);
|
||||
bool execute_local_command(std::string directory_to_run_in, std::string command_to_run, const std::map<std::string, std::string> & env_vars, std::string * output = nullptr, cMode mode = cMode::None);
|
||||
bool execute_ssh_command(const sSSHInfo & ssh_info, const sCommand & remote_command, cMode mode = cMode::None, std::string * output = nullptr);
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// class to hold a command to run on the remote server.
|
||||
class sCommand {
|
||||
public:
|
||||
sCommand(std::string directory_to_run_in, std::string command_to_run, const std::map<std::string, std::string> & env_vars) :
|
||||
mDir(directory_to_run_in), mCmd(command_to_run), mVars(env_vars) {}
|
||||
sCommand(std::string command_to_run) :
|
||||
mDir(""), mCmd(command_to_run), mVars({}) {}
|
||||
sCommand() : mDir(""), mCmd(""), mVars({}) {}
|
||||
sCommand(std::string directory_to_run_in, std::string executables_path, std::string command_to_run, const std::map<std::string, std::string> & env_vars) :
|
||||
mDir(directory_to_run_in), mExecutablesPath(executables_path), mCmd(command_to_run), mVars(env_vars) {}
|
||||
|
||||
std::string get_directory_to_run_in() const { return mDir; }
|
||||
std::string get_executables_path() const { return mExecutablesPath; }
|
||||
std::string get_command_to_run() const { return mCmd; }
|
||||
const std::map<std::string, std::string>& get_env_vars() const { return mVars; }
|
||||
|
||||
void add_env_var(const std::string& key, const std::string& value) { mVars[key] = value; }
|
||||
|
||||
bool empty() const { return mCmd.empty(); }
|
||||
|
||||
|
||||
std::string construct_cmd() const;
|
||||
|
||||
|
||||
private:
|
||||
std::string makesafecmd(const std::string& command) const;
|
||||
|
||||
private:
|
||||
std::string mDir;
|
||||
std::string mExecutablesPath;
|
||||
std::string mCmd;
|
||||
std::map<std::string, std::string> mVars;
|
||||
};
|
||||
|
||||
|
||||
} // namespace dropshell
|
||||
|
||||
|
||||
|
@ -24,6 +24,37 @@ check_prerequisites() {
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
install_bb64() {
|
||||
# install bb64 into EXECUTABLES
|
||||
_check_required_env_vars EXECUTABLES
|
||||
|
||||
ARCH=$(uname -m)
|
||||
if [[ "$ARCH" == "x86_64" ]]; then
|
||||
BIN=bb64.amd64
|
||||
elif [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then
|
||||
BIN=bb64.arm64
|
||||
else
|
||||
echo "Unsupported architecture: $ARCH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# create the executables directory if it doesn't exist
|
||||
mkdir -p ${EXECUTABLES}
|
||||
|
||||
# download bb64
|
||||
if ! curl -fsSL https://gitea.jde.nz/public/bb64/releases/download/latest/bb64.${ARCH} -o ${EXECUTABLES}/bb64; then
|
||||
echo "Failed to download bb64 for architecture: $ARCH" >&2
|
||||
exit 1
|
||||
fi
|
||||
chmod +x ${EXECUTABLES}/bb64
|
||||
}
|
||||
|
||||
|
||||
check_prerequisites
|
||||
|
||||
# install bb64
|
||||
install_bb64
|
||||
|
||||
exit 0
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user