Skip to content

Commit

Permalink
Refactor shell subcommand function
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoinePrv committed May 11, 2023
1 parent 22adb85 commit 4cef0f2
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 107 deletions.
2 changes: 0 additions & 2 deletions libmamba/include/mamba/api/shell.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@

namespace mamba
{
void detect_shell(std::string& shell_type);

void shell(
const std::string& action,
std::string& shell_type,
Expand Down
256 changes: 151 additions & 105 deletions libmamba/src/api/shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <iostream>

#include <fmt/format.h>

#include "mamba/api/configuration.hpp"
#include "mamba/api/shell.hpp"
#include "mamba/core/activation.hpp"
Expand All @@ -20,165 +22,209 @@

namespace mamba
{
void detect_shell(std::string& shell_type)
namespace
{
if (shell_type.empty())
void detect_shell(std::string& shell_type)
{
LOG_DEBUG << "No shell type provided";

std::string guessed_shell = guess_shell();
if (!guessed_shell.empty())
if (shell_type.empty())
{
LOG_DEBUG << "Guessed shell: '" << guessed_shell << "'";
shell_type = guessed_shell;
LOG_DEBUG << "No shell type provided";

std::string guessed_shell = guess_shell();
if (!guessed_shell.empty())
{
LOG_DEBUG << "Guessed shell: '" << guessed_shell << "'";
shell_type = guessed_shell;
}

if (shell_type.empty())
{
LOG_ERROR << "Please provide a shell type." << std::endl
<< "Run with --help for more information." << std::endl;
throw std::runtime_error("Unknown shell type. Aborting.");
}
}
}

if (shell_type.empty())
auto make_activator(std::string_view name) -> std::unique_ptr<Activator>
{
if (name == "bash" || name == "zsh" || name == "dash" || name == "posix")
{
return std::make_unique<mamba::PosixActivator>();
}
if (name == "csh" || name == "tcsh")
{
return std::make_unique<mamba::CshActivator>();
}
if (name == "cmd.exe")
{
return std::make_unique<mamba::CmdExeActivator>();
}
if (name == "powershell")
{
return std::make_unique<mamba::PowerShellActivator>();
}
if (name == "xonsh")
{
LOG_ERROR << "Please provide a shell type." << std::endl
<< "Run with --help for more information." << std::endl;
throw std::runtime_error("Unknown shell type. Aborting.");
return std::make_unique<mamba::XonshActivator>();
}
if (name == "fish")
{
return std::make_unique<mamba::FishActivator>();
}
throw std::invalid_argument(fmt::format("Shell type not handled: {}", name));
}
}

void
shell(const std::string& action, std::string& shell_type, const std::string& prefix, bool stack)
void shell_init(const std::string& shell_type, std::string_view prefix)
{
auto& ctx = Context::instance();
auto& config = Configuration::instance();

config.at("show_banner").set_value(false);
config.at("use_target_prefix_fallback").set_value(false);
config.at("target_prefix_checks").set_value(MAMBA_NO_PREFIX_CHECK);
config.load();
if (prefix.empty() || prefix == "base")
{
init_shell(shell_type, ctx.prefix_params.root_prefix);
}
else
{
init_shell(shell_type, fs::weakly_canonical(env::expand_user(prefix)));
}
}

detect_shell(shell_type);
void shell_deinit(const std::string& shell_type, std::string_view prefix)
{
auto& ctx = Context::instance();
if (prefix.empty() || prefix == "base")
{
deinit_shell(shell_type, ctx.prefix_params.root_prefix);
}
else
{
deinit_shell(shell_type, fs::weakly_canonical(env::expand_user(prefix)));
}
}

std::unique_ptr<Activator> activator;
std::string shell_prefix;
void shell_reinit(std::string_view prefix)
{
// re-initialize all the shell scripts after update
for (const auto& shell_type : find_initialized_shells())
{
shell_init(shell_type, prefix);
}
}

if (shell_type == "bash" || shell_type == "zsh" || shell_type == "dash"
|| shell_type == "posix")
void shell_hook(const std::string& shell_type, Activator& activator)
{
auto& ctx = Context::instance();
// TODO do we need to do something wtih `shell_prefix -> root_prefix?`?
if (ctx.output_params.json)
{
activator = std::make_unique<mamba::PosixActivator>();
Console::instance().json_write({ { "success", true },
{ "operation", "shell_hook" },
{ "context", { { "shell_type", shell_type } } },
{ "actions",
{ { "print", { activator.hook(shell_type) } } } } });
}
else if (shell_type == "csh" || shell_type == "tcsh")
else
{
activator = std::make_unique<mamba::CshActivator>();
std::cout << activator.hook(shell_type);
}
else if (shell_type == "cmd.exe")
}

void shell_activate(std::string_view prefix, Activator& activator, bool stack)
{
auto& ctx = Context::instance();
fs::u8path shell_prefix;
if (prefix.empty() || prefix == "base")
{
activator = std::make_unique<mamba::CmdExeActivator>();
shell_prefix = ctx.prefix_params.root_prefix;
}
else if (shell_type == "powershell")
else if (prefix.find_first_of("/\\") == std::string::npos)
{
activator = std::make_unique<mamba::PowerShellActivator>();
shell_prefix = ctx.prefix_params.root_prefix / "envs" / prefix;
}
else if (shell_type == "xonsh")
else
{
activator = std::make_unique<mamba::XonshActivator>();
shell_prefix = fs::weakly_canonical(env::expand_user(prefix));
}
else if (shell_type == "fish")

if (!fs::exists(shell_prefix))
{
activator = std::make_unique<mamba::FishActivator>();
throw std::runtime_error(
fmt::format("Cannot activate, prefix does not exist at: {}", shell_prefix)
);
}
else

std::cout << activator.activate(shell_prefix, stack);
}

void shell_reactivate(Activator& activator)
{
std::cout << activator.deactivate();
}

void shell_deactivate(Activator& activator)
{
std::cout << activator.deactivate();
}
void shell_enable_long_path_support()
{
#ifdef _WIN32
if (const bool success = enable_long_paths_support(/* force= */ true); !success)
{
LOG_ERROR << "Not handled 'shell_type': " << shell_type;
return;
throw std::runtime_error("Error enabling Windows long-path support");
}
#else
throw std::invalid_argument("Long path support is a Windows only option");
#endif
}

void
shell(const std::string& action, std::string& shell_type, const std::string& prefix, bool stack)
{
auto& config = Configuration::instance();

config.at("show_banner").set_value(false);
config.at("use_target_prefix_fallback").set_value(false);
config.at("target_prefix_checks").set_value(MAMBA_NO_PREFIX_CHECK);
config.load();

detect_shell(shell_type);

auto activator = make_activator(shell_type);

std::string shell_prefix;

if (action == "init")
{
if (prefix.empty() || prefix == "base")
{
shell_prefix = ctx.prefix_params.root_prefix.string();
}
else
{
shell_prefix = fs::weakly_canonical(env::expand_user(prefix)).string();
}

init_shell(shell_type, shell_prefix);
shell_init(shell_type, prefix);
}
else if (action == "deinit")
{
if (prefix.empty() || prefix == "base")
{
shell_prefix = ctx.prefix_params.root_prefix.string();
}
else
{
shell_prefix = fs::weakly_canonical(env::expand_user(prefix)).string();
}

deinit_shell(shell_type, shell_prefix);
shell_deinit(shell_type, prefix);
}
else if (action == "reinit")
{
// re-initialize all the shell scripts after update
for (auto& lshell_type : find_initialized_shells())
{
shell("init", lshell_type, prefix, false);
}
shell_reinit(prefix);
}
else if (action == "hook")
{
// TODO do we need to do something wtih `shell_prefix -> root_prefix?`?
if (ctx.output_params.json)
{
Console::instance().json_write(
{ { "success", true },
{ "operation", "shell_hook" },
{ "context", { { "shell_type", shell_type } } },
{ "actions", { { "print", { activator->hook(shell_type) } } } } }
);
}
else
{
std::cout << activator->hook(shell_type);
}
shell_hook(shell_type, *activator);
}
else if (action == "activate")
{
if (prefix.empty() || prefix == "base")
{
shell_prefix = ctx.prefix_params.root_prefix.string();
}
else if (prefix.find_first_of("/\\") == std::string::npos)
{
shell_prefix = (ctx.prefix_params.root_prefix / "envs" / prefix).string();
}
else
{
shell_prefix = fs::weakly_canonical(env::expand_user(prefix)).string();
}

if (!fs::exists(shell_prefix))
{
throw std::runtime_error("Cannot activate, prefix does not exist at: " + shell_prefix);
}

std::cout << activator->activate(shell_prefix, stack);
shell_activate(prefix, *activator, stack);
}
else if (action == "reactivate")
{
std::cout << activator->reactivate();
shell_reactivate(*activator);
}
else if (action == "deactivate")
{
std::cout << activator->deactivate();
shell_deactivate(*activator);
}
#ifdef _WIN32
else if (action == "enable-long-paths-support")
{
if (!enable_long_paths_support(true))
{
throw std::runtime_error("Error enabling Windows long-path support");
}
shell_enable_long_path_support();
}
#endif
else
{
throw std::runtime_error("Need an action {init, hook, activate, deactivate, reactivate}");
Expand Down

0 comments on commit 4cef0f2

Please sign in to comment.