mirror of https://github.com/mamba-org/mamba.git
215 lines
5.2 KiB
C++
215 lines
5.2 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_HPP
|
|
#define MAMBA_ENVIRONMENT_HPP
|
|
|
|
#include <map>
|
|
#include <cstdlib>
|
|
#include <cassert>
|
|
#include <string_view>
|
|
|
|
#include "thirdparty/filesystem.hpp"
|
|
|
|
namespace fs = ghc::filesystem;
|
|
|
|
#ifdef _WIN32
|
|
#include <Shlobj.h>;
|
|
#endif
|
|
|
|
#ifndef _WIN32
|
|
#include <sys/utsname.h>
|
|
#include <wordexp.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <pwd.h>
|
|
|
|
extern "C"
|
|
{
|
|
extern char **environ;
|
|
}
|
|
#endif
|
|
|
|
namespace mamba
|
|
{
|
|
|
|
namespace env
|
|
{
|
|
constexpr inline const char* pathsep()
|
|
{
|
|
#ifdef _WIN32
|
|
return ";";
|
|
#else
|
|
return ":";
|
|
#endif
|
|
}
|
|
|
|
inline std::string get(const std::string& key)
|
|
{
|
|
const char* value = std::getenv(key.c_str());
|
|
if (!value) return "";
|
|
return value;
|
|
}
|
|
|
|
inline bool set(const std::string& key, const std::string& value)
|
|
{
|
|
#ifdef _WIN32
|
|
return SetEnvironmentVariable(key.c_str(), value.c_str());
|
|
#else
|
|
return setenv(key.c_str(), value.c_str(), 1) == 0;
|
|
#endif
|
|
}
|
|
|
|
inline fs::path which(const std::string& exe)
|
|
{
|
|
// TODO maybe add a cache?
|
|
if (std::getenv("PATH"))
|
|
{
|
|
std::string path = std::getenv("PATH");
|
|
auto parts = split(path, pathsep());
|
|
for (auto& p : parts)
|
|
{
|
|
if (!fs::exists(p) || !fs::is_directory(p))
|
|
{
|
|
continue;
|
|
}
|
|
for (const auto & entry : fs::directory_iterator(p))
|
|
{
|
|
if (entry.path().filename() == exe)
|
|
{
|
|
return entry.path();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ""; // empty path
|
|
}
|
|
|
|
inline std::map<std::string, std::string> copy()
|
|
{
|
|
std::map<std::string, std::string> m;
|
|
#ifndef _WIN32
|
|
int i = 1;
|
|
const char* c = *environ;
|
|
for (; c; i++)
|
|
{
|
|
std::string_view s(c);
|
|
auto pos = s.find("=");
|
|
m[std::string(s.substr(0, pos))] = (pos != s.npos) ? std::string(s.substr(pos + 1)) : "";
|
|
c = *(environ + i);
|
|
}
|
|
#else
|
|
|
|
// inspired by https://github.com/gennaroprota/breath/blob/0709a9f0fe4e745b1d9fc44ab65d92853820b515
|
|
// /breath/environment/brt/dep/syst/windows/get_environment_map.cpp#L38-L80
|
|
char* start = GetEnvironmentStrings();
|
|
if (start == nullptr)
|
|
{
|
|
throw std::runtime_error("GetEnvironmentStrings() failed") ;
|
|
}
|
|
|
|
char* current = start;
|
|
while (*current != '\0')
|
|
{
|
|
std::string_view s = current;
|
|
auto pos = s.find("=");
|
|
assert (pos != std::string_view::npos);
|
|
std::string_view key = s.substr(0, pos) ;
|
|
|
|
if (!key.empty())
|
|
{
|
|
std::string_view value = (pos != s.npos) ? s.substr(pos + 1) : "";
|
|
m[std::string(key)] = value;
|
|
}
|
|
current += s.size() + 1;
|
|
}
|
|
#endif
|
|
return m;
|
|
}
|
|
|
|
|
|
inline std::string platform()
|
|
{
|
|
#ifndef _WIN32
|
|
utsname un;
|
|
int ret = uname(&un);
|
|
|
|
if (ret == -1)
|
|
{
|
|
throw std::runtime_error("uname() failed");
|
|
}
|
|
|
|
return std::string(un.sysname);
|
|
#else
|
|
return "win32";
|
|
#endif
|
|
}
|
|
|
|
inline fs::path home_directory()
|
|
{
|
|
#ifdef _WIN32
|
|
std::string maybe_home = env::get("USERPROFILE");
|
|
if (maybe_home.empty())
|
|
{
|
|
maybe_home = concat(env::get("HOMEDRIVE"), env::get("HOMEPATH"));
|
|
}
|
|
if (maybe_home.empty())
|
|
{
|
|
throw std::runtime_error("Cannot determine HOME (checked USERPROFILE, HOMEDRIVE and HOMEPATH env vars)");
|
|
}
|
|
#else
|
|
std::string maybe_home = env::get("HOME");
|
|
if (maybe_home.empty())
|
|
{
|
|
maybe_home = getpwuid(getuid())->pw_dir;
|
|
}
|
|
if (maybe_home.empty())
|
|
{
|
|
throw std::runtime_error("HOME not set.");
|
|
}
|
|
#endif
|
|
return maybe_home;
|
|
}
|
|
|
|
inline fs::path expand_user(const fs::path& path)
|
|
{
|
|
auto p = path.string();
|
|
if (p[0] == '~')
|
|
{
|
|
p.replace(0, 1, home_directory());
|
|
}
|
|
return p;
|
|
}
|
|
|
|
inline bool is_admin()
|
|
{
|
|
#ifdef _WIN32
|
|
return IsUserAnAdmin();
|
|
#else
|
|
return geteuid() == 0 || getegid() == 0;
|
|
#endif
|
|
}
|
|
|
|
// inline fs::path expand_vars(const fs::path& path)
|
|
// {
|
|
// #ifndef _WIN32
|
|
// wordexp_t w{};
|
|
// std::unique_ptr<wordexp_t, void(*)(wordexp_t*)> hold{&w, ::wordfree};
|
|
// ::wordexp(path.c_str(), &w, 0);
|
|
// if (w.we_wordc != 1)
|
|
// throw std::runtime_error("Cannot expand path: " + path.string());
|
|
// fs::path result = fs::absolute(w.we_wordv[0]);
|
|
// return result;
|
|
// #else
|
|
// // ExpandEnvironmentStringsW
|
|
// #endif
|
|
// }
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|