Skip to content

Commit

Permalink
[vcpkg] Enable recursive vcpkg calls
Browse files Browse the repository at this point in the history
Via envvars VCPKG_COMMAND and VCPKG_X_RECURSIVE_DATA. Child processes can call vcpkg via "$VCPKG_COMMAND <args>" in limited internal circumstances.
  • Loading branch information
ras0219-msft committed Sep 26, 2020
1 parent 6d6c664 commit 6061702
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 80 deletions.
18 changes: 18 additions & 0 deletions toolsrc/include/vcpkg/base/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ namespace vcpkg
constexpr OptionalStorage() noexcept : m_is_present(false), m_inactive() { }
constexpr OptionalStorage(const T& t) : m_is_present(true), m_t(t) { }
constexpr OptionalStorage(T&& t) : m_is_present(true), m_t(std::move(t)) { }
template<class U>
constexpr OptionalStorage(Optional<U>&& t) : m_is_present(false), m_inactive()
{
if (auto p = t.get())
{
m_is_present = true;
new (&m_t) T(std::move(*p));
}
}
template<class U>
constexpr OptionalStorage(const Optional<U>& t) : m_is_present(false), m_inactive()
{
if (auto p = t.get())
{
m_is_present = true;
new (&m_t) T(*p);
}
}

~OptionalStorage() noexcept
{
Expand Down
1 change: 1 addition & 0 deletions toolsrc/include/vcpkg/base/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace vcpkg::System
{
Optional<std::string> get_environment_variable(ZStringView varname) noexcept;
void set_environment_variable(ZStringView varname, Optional<ZStringView> value) noexcept;

const ExpectedS<fs::path>& get_home_dir() noexcept;

Expand Down
4 changes: 4 additions & 0 deletions toolsrc/include/vcpkg/vcpkgcmdarguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,13 @@ namespace vcpkg
constexpr static StringLiteral REGISTRIES_FEATURE = "registries";
Optional<bool> registries_feature = nullopt;

constexpr static StringLiteral RECURSIVE_DATA_ENV = "VCPKG_X_RECURSIVE_DATA";

bool binary_caching_enabled() const { return binary_caching.value_or(true); }
bool compiler_tracking_enabled() const { return compiler_tracking.value_or(true); }
bool registries_enabled() const { return registries_feature.value_or(false); }
bool output_json() const { return json.value_or(false); }
bool is_recursive_invocation() const { return m_is_recursive_invocation; }

std::string command;
std::vector<std::string> command_arguments;
Expand All @@ -191,6 +194,7 @@ namespace vcpkg
void track_feature_flag_metrics() const;

private:
bool m_is_recursive_invocation = false;
std::unordered_set<std::string> command_switches;
std::unordered_map<std::string, std::vector<std::string>> command_options;
};
Expand Down
10 changes: 10 additions & 0 deletions toolsrc/src/vcpkg-test/optional.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ TEST_CASE ("ref conversion", "[optional]")
REQUIRE(cref_1.get() == &x);
}

TEST_CASE ("value conversion", "[optional]")
{
using vcpkg::Optional;

Optional<long> j = 1;
Optional<int> i = j;
Optional<const char*> cstr = "hello, world!";
Optional<std::string> cppstr = cstr;
}

TEST_CASE ("common_projection", "[optional]")
{
using vcpkg::Util::common_projection;
Expand Down
30 changes: 1 addition & 29 deletions toolsrc/src/vcpkg-test/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,39 +23,11 @@ using vcpkg::Checks::check_exit;
using vcpkg::System::CPUArchitecture;
using vcpkg::System::get_environment_variable;
using vcpkg::System::guess_visual_studio_prompt_target_architecture;
using vcpkg::System::set_environment_variable;
using vcpkg::System::to_cpu_architecture;

namespace
{
void set_environment_variable(ZStringView varname, Optional<std::string> value)
{
#if defined(_WIN32)
const auto w_varname = vcpkg::Strings::to_utf16(varname);
const auto w_varcstr = w_varname.c_str();
BOOL exit_code;
if (value)
{
const auto w_value = vcpkg::Strings::to_utf16(value.value_or_exit(VCPKG_LINE_INFO));
exit_code = SetEnvironmentVariableW(w_varcstr, w_value.c_str());
}
else
{
exit_code = SetEnvironmentVariableW(w_varcstr, nullptr);
}

check_exit(VCPKG_LINE_INFO, exit_code != 0);
#else // ^^^ defined(_WIN32) / !defined(_WIN32) vvv
if (auto v = value.get())
{
check_exit(VCPKG_LINE_INFO, setenv(varname.c_str(), v->c_str(), 1) == 0);
}
else
{
check_exit(VCPKG_LINE_INFO, unsetenv(varname.c_str()) == 0);
}
#endif // defined(_WIN32)
}

struct environment_variable_resetter
{
explicit environment_variable_resetter(ZStringView varname_)
Expand Down
1 change: 1 addition & 0 deletions toolsrc/src/vcpkg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ int main(const int argc, const char* const* const argv)

System::initialize_global_job_object();
#endif
System::set_environment_variable("VCPKG_COMMAND", fs::generic_u8string(System::get_exe_path_of_current_process()));

Checks::register_global_shutdown_handler([]() {
const auto elapsed_us_inner = GlobalState::timer.lock()->microseconds();
Expand Down
28 changes: 28 additions & 0 deletions toolsrc/src/vcpkg/base/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,34 @@ namespace vcpkg
#endif // defined(_WIN32)
}

void System::set_environment_variable(ZStringView varname, Optional<ZStringView> value) noexcept
{
#if defined(_WIN32)
const auto w_varname = Strings::to_utf16(varname);
const auto w_varcstr = w_varname.c_str();
BOOL exit_code;
if (auto v = value.get())
{
exit_code = SetEnvironmentVariableW(w_varcstr, Strings::to_utf16(*v).c_str());
}
else
{
exit_code = SetEnvironmentVariableW(w_varcstr, nullptr);
}

Checks::check_exit(VCPKG_LINE_INFO, exit_code != 0);
#else // ^^^ defined(_WIN32) / !defined(_WIN32) vvv
if (auto v = value.get())
{
Checks::check_exit(VCPKG_LINE_INFO, setenv(varname.c_str(), v->c_str(), 1) == 0);
}
else
{
Checks::check_exit(VCPKG_LINE_INFO, unsetenv(varname.c_str()) == 0);
}
#endif // defined(_WIN32)
}

const ExpectedS<fs::path>& System::get_home_dir() noexcept
{
static ExpectedS<fs::path> s_home = []() -> ExpectedS<fs::path> {
Expand Down
1 change: 0 additions & 1 deletion toolsrc/src/vcpkg/base/system.process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,6 @@ namespace vcpkg
L"USERDOMAIN_ROAMINGPROFILE",
L"USERNAME",
L"USERPROFILE",
L"VCPKG_DISABLE_METRICS",
L"windir",
// Enables proxy information to be passed to Curl, the underlying download library in cmake.exe
L"http_proxy",
Expand Down
11 changes: 11 additions & 0 deletions toolsrc/src/vcpkg/build.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,17 @@ namespace vcpkg::Build
env[env_var] = env_val.value_or_exit(VCPKG_LINE_INFO);
}
}
static constexpr StringLiteral s_extra_vars[] = {
"VCPKG_COMMAND",
"VCPKG_FORCE_SYSTEM_BINARIES",
VcpkgCmdArguments::RECURSIVE_DATA_ENV,
};

for (auto var : s_extra_vars)
{
auto val = System::get_environment_variable(var);
if (auto p_val = val.get()) env.emplace(var, *p_val);
}

return {env};
});
Expand Down
23 changes: 1 addition & 22 deletions toolsrc/src/vcpkg/metrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,23 +258,6 @@ namespace vcpkg::Metrics
#endif
;

// for child vcpkg processes, we also want to disable metrics
static void set_vcpkg_disable_metrics_environment_variable(bool disabled)
{
#if defined(_WIN32)
SetEnvironmentVariableW(L"VCPKG_DISABLE_METRICS", disabled ? L"1" : nullptr);
#else
if (disabled)
{
setenv("VCPKG_DISABLE_METRICS", "1", true);
}
else
{
unsetenv("VCPKG_DISABLE_METRICS");
}
#endif
}

std::string get_MAC_user()
{
#if defined(_WIN32)
Expand Down Expand Up @@ -323,11 +306,7 @@ namespace vcpkg::Metrics

void Metrics::set_print_metrics(bool should_print_metrics) { g_should_print_metrics = should_print_metrics; }

void Metrics::set_disabled(bool disabled)
{
set_vcpkg_disable_metrics_environment_variable(disabled);
g_metrics_disabled = disabled;
}
void Metrics::set_disabled(bool disabled) { g_metrics_disabled = disabled; }

bool Metrics::metrics_enabled()
{
Expand Down
89 changes: 61 additions & 28 deletions toolsrc/src/vcpkg/vcpkgcmdarguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,8 +628,26 @@ namespace vcpkg
table.format(opt(JSON_SWITCH, "", ""), "(Experimental) Request JSON output");
}

static void from_env(ZStringView var, std::unique_ptr<std::string>& dst)
{
if (dst) return;

auto maybe_val = System::get_environment_variable(var);
if (auto val = maybe_val.get())
{
dst = std::make_unique<std::string>(std::move(*val));
}
}

void VcpkgCmdArguments::imbue_from_environment()
{
static bool s_reentrancy_guard = false;
Checks::check_exit(VCPKG_LINE_INFO,
!s_reentrancy_guard,
"VcpkgCmdArguments::imbue_from_environment() modifies global state and thus may only be "
"called once per process.");
s_reentrancy_guard = true;

if (!disable_metrics)
{
const auto vcpkg_disable_metrics_env = System::get_environment_variable(DISABLE_METRICS_ENV);
Expand All @@ -639,14 +657,10 @@ namespace vcpkg
}
}

if (!triplet)
{
const auto vcpkg_default_triplet_env = System::get_environment_variable(TRIPLET_ENV);
if (const auto unpacked = vcpkg_default_triplet_env.get())
{
triplet = std::make_unique<std::string>(*unpacked);
}
}
from_env(TRIPLET_ENV, triplet);
from_env(VCPKG_ROOT_DIR_ENV, vcpkg_root_dir);
from_env(DOWNLOADS_ROOT_DIR_ENV, downloads_root_dir);
from_env(DEFAULT_VISUAL_STUDIO_PATH_ENV, default_visual_studio_path);

{
const auto vcpkg_overlay_ports_env = System::get_environment_variable(OVERLAY_PORTS_ENV);
Expand All @@ -661,36 +675,53 @@ namespace vcpkg
}
}

if (!vcpkg_root_dir)
{
const auto vcpkg_root_env = System::get_environment_variable(VCPKG_ROOT_DIR_ENV);
if (const auto unpacked = vcpkg_root_env.get())
const auto vcpkg_feature_flags_env = System::get_environment_variable(FEATURE_FLAGS_ENV);
if (const auto v = vcpkg_feature_flags_env.get())
{
vcpkg_root_dir = std::make_unique<std::string>(*unpacked);
auto flags = Strings::split(*v, ',');
parse_feature_flags(flags, *this);
}
}

if (!downloads_root_dir)
{
const auto vcpkg_downloads_env = vcpkg::System::get_environment_variable(DOWNLOADS_ROOT_DIR_ENV);
if (const auto unpacked = vcpkg_downloads_env.get())
auto maybe_vcpkg_recursive_data = System::get_environment_variable(RECURSIVE_DATA_ENV);
if (auto vcpkg_recursive_data = maybe_vcpkg_recursive_data.get())
{
downloads_root_dir = std::make_unique<std::string>(*unpacked);
}
}
m_is_recursive_invocation = true;

const auto vcpkg_feature_flags_env = System::get_environment_variable(FEATURE_FLAGS_ENV);
if (const auto v = vcpkg_feature_flags_env.get())
{
auto flags = Strings::split(*v, ',');
parse_feature_flags(flags, *this);
}
auto rec_doc = Json::parse(*vcpkg_recursive_data).value_or_exit(VCPKG_LINE_INFO).first;
const auto& obj = rec_doc.object();

{
const auto vcpkg_visual_studio_path_env = System::get_environment_variable(DEFAULT_VISUAL_STUDIO_PATH_ENV);
if (const auto unpacked = vcpkg_visual_studio_path_env.get())
if (auto entry = obj.get(DOWNLOADS_ROOT_DIR_ENV))
{
downloads_root_dir = std::make_unique<std::string>(entry->string().to_string());
}

if (obj.get(DISABLE_METRICS_ENV))
{
disable_metrics = true;
}

// Setting the recursive data to 'poison' prevents more than one level of recursion because
// Json::parse() will fail.
System::set_environment_variable(RECURSIVE_DATA_ENV, "poison");
}
else
{
default_visual_studio_path = std::make_unique<std::string>(*unpacked);
Json::Object obj;
if (downloads_root_dir)
{
obj.insert(DOWNLOADS_ROOT_DIR_ENV, Json::Value::string(*downloads_root_dir.get()));
}

if (disable_metrics)
{
obj.insert(DISABLE_METRICS_ENV, Json::Value::boolean(true));
}

System::set_environment_variable(RECURSIVE_DATA_ENV,
Json::stringify(obj, Json::JsonStyle::with_spaces(0)));
}
}
}
Expand Down Expand Up @@ -898,4 +929,6 @@ namespace vcpkg
constexpr StringLiteral VcpkgCmdArguments::COMPILER_TRACKING_FEATURE;
constexpr StringLiteral VcpkgCmdArguments::MANIFEST_MODE_FEATURE;
constexpr StringLiteral VcpkgCmdArguments::REGISTRIES_FEATURE;

constexpr StringLiteral VcpkgCmdArguments::RECURSIVE_DATA_ENV;
}

0 comments on commit 6061702

Please sign in to comment.