mirror of https://github.com/mamba-org/mamba.git
201 lines
6.1 KiB
C++
201 lines
6.1 KiB
C++
// Copyright (c) 2019, QuantStack and Mamba Contributors
|
|
//
|
|
// Distributed under the terms of the BSD 3-Clause License.
|
|
//
|
|
// The full license is in the file LICENSE, distributed with this software.
|
|
|
|
#ifndef MAMBA_ENVIRONMENT_MANAGER
|
|
#define MAMBA_ENVIRONMENT_MANAGER
|
|
|
|
#include <set>
|
|
|
|
#include "util.hpp"
|
|
#include "environment.hpp"
|
|
#include "output.hpp"
|
|
|
|
namespace mamba
|
|
{
|
|
const std::string PREFIX_MAGIC_FILE = "conda-meta/history";
|
|
|
|
inline bool is_conda_environment(const fs::path& prefix)
|
|
{
|
|
return fs::exists(prefix / PREFIX_MAGIC_FILE);
|
|
}
|
|
|
|
class EnvironmentsManager
|
|
{
|
|
public:
|
|
|
|
void register_env(const fs::path& location)
|
|
{
|
|
fs::path env_txt_file = get_environments_txt_file(env::home_directory());
|
|
fs::path final_location = fs::absolute(location);
|
|
fs::path folder = final_location.parent_path();
|
|
|
|
if (!fs::exists(env_txt_file.parent_path()))
|
|
{
|
|
try
|
|
{
|
|
fs::create_directories(env_txt_file.parent_path());
|
|
} catch (...) {}
|
|
}
|
|
|
|
std::string final_location_string = remove_trailing_slash(final_location);
|
|
if (final_location_string.find("placehold_pl") != std::string::npos ||
|
|
final_location_string.find("skeleton_") != std::string::npos)
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto lines = read_lines(env_txt_file);
|
|
|
|
for (auto& l : lines)
|
|
{
|
|
if (l == final_location_string) return;
|
|
}
|
|
|
|
std::ofstream out(env_txt_file, std::ios::app);
|
|
out << final_location_string << std::endl;
|
|
if (out.bad())
|
|
{
|
|
if (errno == EACCES || errno == EROFS || errno == ENOENT)
|
|
{
|
|
LOG_ERROR << "Could not register environment. " << env_txt_file << " not writeable or missing?";
|
|
}
|
|
else
|
|
{
|
|
throw std::system_error(errno, std::system_category(), "failed to open " + env_txt_file.string());
|
|
}
|
|
}
|
|
}
|
|
|
|
void unregister_env(const fs::path& location)
|
|
{
|
|
if (fs::exists(location) && fs::is_directory(location))
|
|
{
|
|
fs::path meta_dir = location / "conda-meta";
|
|
if (fs::exists(meta_dir) && fs::is_directory(meta_dir))
|
|
{
|
|
std::size_t count = 0;
|
|
for (auto& _ : fs::directory_iterator(meta_dir))
|
|
{
|
|
(void)_;
|
|
++count;
|
|
}
|
|
if (count > 1)
|
|
{
|
|
// if files left other than `conda-meta/history` do not unregister
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
clean_environments_txt(get_environments_txt_file(env::home_directory()), location);
|
|
}
|
|
|
|
std::set<fs::path> list_all_known_prefixes()
|
|
{
|
|
std::vector<fs::path> search_dirs;
|
|
|
|
// TODO
|
|
// if (is_admin())
|
|
// {
|
|
// if (on_win)
|
|
// {
|
|
// fs::path home_dir_dir = env::home_directory().parent_path();
|
|
// search_dirs = tuple(join(home_dir_dir, d) for d in listdir(home_dir_dir))
|
|
// }
|
|
// else
|
|
// {
|
|
// from pwd import getpwall
|
|
// search_dirs = tuple(pwentry.pw_dir for pwentry in getpwall()) or (expand('~'),)
|
|
// }
|
|
// }
|
|
// else
|
|
{
|
|
search_dirs = std::vector<fs::path> { env::home_directory() };
|
|
}
|
|
|
|
std::set<fs::path> all_env_paths;
|
|
|
|
for (auto& d : search_dirs)
|
|
{
|
|
auto f = get_environments_txt_file(d);
|
|
if (fs::exists(f))
|
|
{
|
|
for (auto& env_path : clean_environments_txt(f, fs::path()))
|
|
{
|
|
all_env_paths.insert(env_path);
|
|
}
|
|
}
|
|
}
|
|
for (auto& d : Context::instance().envs_dirs)
|
|
{
|
|
if (fs::exists(d) && fs::is_directory(d))
|
|
{
|
|
for (auto& potential_env : fs::directory_iterator(d))
|
|
{
|
|
if (is_conda_environment(potential_env))
|
|
{
|
|
all_env_paths.insert(potential_env);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
all_env_paths.insert(Context::instance().root_prefix);
|
|
return all_env_paths;
|
|
}
|
|
|
|
private:
|
|
|
|
std::set<std::string>
|
|
clean_environments_txt(const fs::path& env_txt_file, const fs::path& location)
|
|
{
|
|
if (!fs::exists(env_txt_file))
|
|
return {};
|
|
|
|
fs::path abs_loc = fs::absolute(location);
|
|
|
|
std::vector<std::string> lines = read_lines(env_txt_file);
|
|
std::set<std::string> final_lines;
|
|
for (auto& l : lines)
|
|
{
|
|
if (l != abs_loc && is_conda_environment(l))
|
|
{
|
|
final_lines.insert(l);
|
|
}
|
|
}
|
|
if (final_lines.size() != lines.size())
|
|
{
|
|
std::ofstream out(env_txt_file);
|
|
for (auto& l : final_lines)
|
|
{
|
|
out << remove_trailing_slash(l) << std::endl;
|
|
}
|
|
if (out.bad())
|
|
{
|
|
LOG_ERROR << "failed to clean " + env_txt_file.string();
|
|
}
|
|
}
|
|
return final_lines;
|
|
}
|
|
|
|
std::string remove_trailing_slash(std::string p)
|
|
{
|
|
if (p[p.size() - 1] == '/' || p[p.size() - 1] == '\\')
|
|
{
|
|
p.pop_back();
|
|
}
|
|
return p;
|
|
}
|
|
|
|
fs::path get_environments_txt_file(const fs::path& home) const
|
|
{
|
|
return home / ".conda" / "environments.txt";
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
#endif
|