From f5411abdf0a5b85e60dde177535e817fc8e5d82d Mon Sep 17 00:00:00 2001 From: schellap Date: Fri, 1 Apr 2016 07:14:14 -0700 Subject: [PATCH] Support runtimeconfig.dev json --- src/corehost/cli/args.cpp | 9 +- src/corehost/cli/deps_resolver.cpp | 16 -- src/corehost/cli/fxr/fx_muxer.cpp | 320 +++++++++++++++------------- src/corehost/cli/fxr/fx_muxer.h | 1 + src/corehost/cli/hostpolicy.cpp | 9 +- src/corehost/cli/libhost.cpp | 9 +- src/corehost/cli/libhost.h | 2 +- src/corehost/cli/runtime_config.cpp | 64 +++++- src/corehost/cli/runtime_config.h | 11 +- src/corehost/common/pal.h | 1 - src/corehost/common/pal.unix.cpp | 22 -- src/corehost/common/pal.windows.cpp | 12 -- src/corehost/common/utils.cpp | 22 +- src/corehost/common/utils.h | 6 +- 14 files changed, 282 insertions(+), 222 deletions(-) diff --git a/src/corehost/cli/args.cpp b/src/corehost/cli/args.cpp index 07ae3e04a..ea8647eae 100644 --- a/src/corehost/cli/args.cpp +++ b/src/corehost/cli/args.cpp @@ -67,7 +67,7 @@ bool parse_arguments(const pal::string_t& deps_path, const std::vector opts; + std::unordered_map> opts; std::vector known_opts = { _X("--depsfile"), _X("--additionalprobingpath") }; int num_args = 0; if (!parse_known_args(args.app_argc, args.app_argv, known_opts, &opts, &num_args)) @@ -79,10 +79,13 @@ bool parse_arguments(const pal::string_t& deps_path, const std::vector& iter = m_additional_probes.erase(iter); } } - // FIXME: Remove nuget support with runtimeconfig.dev.json - // and setup roll forward to come from the config in setup_probe_config - if (m_additional_probes.empty()) - { - // FIXME: Remove this function call entirely including the functiond definition. - (void)pal::get_default_packages_directory(&m_package_cache); - if (pal::directory_exists(m_package_cache)) - { - m_additional_probes.push_back(m_package_cache); - } - } } bool deps_resolver_t::probe_entry_in_configs(const deps_entry_t& entry, pal::string_t* candidate) diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index 962d0c9c3..1bebcba96 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -226,11 +226,151 @@ bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::stri return !retval.empty(); } +int muxer_usage() +{ + trace::error(_X("Usage: dotnet [--help | app.dll]")); + return StatusCode::InvalidArgFailure; +} + +int fx_muxer_t::parse_args_and_execute(const pal::string_t& own_dir, int argoff, int argc, const pal::char_t* argv[], bool exec_mode, bool* is_an_app) +{ + *is_an_app = true; + + std::vector known_opts = { _X("--additionalprobingpath") }; + if (exec_mode) + { + known_opts.push_back(_X("--depsfile")); + } + + // Parse the known muxer arguments if any. + int num_parsed = 0; + std::unordered_map> opts; + if (!parse_known_args(argc - argoff, &argv[argoff], known_opts, &opts, &num_parsed)) + { + trace::error(_X("Failed to parse supported arguments.")); + return InvalidArgFailure; + } + int cur_i = argoff + num_parsed; + if (cur_i >= argc) + { + return muxer_usage(); + } + + pal::string_t app_candidate = argv[cur_i]; + bool is_app_runnable = ends_with(app_candidate, _X(".dll"), false) || ends_with(app_candidate, _X(".exe"), false); + + // If exec mode is on, then check we have a dll at this point + if (exec_mode) + { + if (!is_app_runnable) + { + trace::error(_X("dotnet exec needs a dll to execute. Try dotnet [--help]")); + return InvalidArgFailure; + } + } + // For non-exec, there is CLI invocation or app.dll execution after known args. + else + { + // Test if we have a real dll at this point. + if (!is_app_runnable) + { + // No we don't have a dll, this must be routed to the CLI. + *is_an_app = false; + return Success; + } + } + + // Transform dotnet [exec] [--additionalprobingpath path] [--depsfile file] dll [args] -> dotnet dll [args] + + std::vector vec_argv; + const pal::char_t** new_argv = argv; + int new_argc = argc; + if (cur_i != 1) + { + vec_argv.resize(argc - cur_i + 1, 0); // +1 for dotnet + memcpy(vec_argv.data() + 1, argv + cur_i, (argc - cur_i) * sizeof(pal::char_t*)); + vec_argv[0] = argv[0]; + new_argv = vec_argv.data(); + new_argc = vec_argv.size(); + } + + pal::string_t opts_deps_file = _X("--depsfile"); + pal::string_t opts_probe_path = _X("--additionalprobingpath"); + pal::string_t deps_file = get_last_known_arg(opts, opts_deps_file, _X("")); + std::vector probe_paths = opts.count(opts_probe_path) ? opts[opts_probe_path] : std::vector(); + + trace::verbose(_X("Current argv is %s"), app_candidate.c_str()); + + pal::string_t app_or_deps = deps_file.empty() ? app_candidate : deps_file; + pal::string_t no_json = app_candidate; + pal::string_t dev_config_file; + auto config_file = get_runtime_config_from_file(no_json, &dev_config_file); + runtime_config_t config(config_file, dev_config_file); + for (const auto& path : config.get_probe_paths()) + { + probe_paths.push_back(path); + } + + if (!config.is_valid()) + { + trace::error(_X("Invalid runtimeconfig.json [%s] [%s]"), config.get_path().c_str(), config.get_dev_path().c_str()); + return StatusCode::InvalidConfigFile; + } + if (!deps_file.empty() && !pal::file_exists(deps_file)) + { + trace::error(_X("Deps file [%s] specified but doesn't exist"), deps_file.c_str()); + return StatusCode::InvalidArgFailure; + } + + if (config.get_portable()) + { + trace::verbose(_X("Executing as a portable app as per config file [%s]"), config_file.c_str()); + pal::string_t fx_dir = resolve_fx_dir(own_dir, &config); + corehost_init_t init(deps_file, probe_paths, fx_dir, host_mode_t::muxer, &config); + return execute_app(fx_dir, &init, new_argc, new_argv); + } + else + { + trace::verbose(_X("Executing as a standalone app as per config file [%s]"), config_file.c_str()); + pal::string_t impl_dir = get_directory(app_or_deps); + if (!library_exists_in_dir(impl_dir, LIBHOSTPOLICY_NAME, nullptr) && !probe_paths.empty() && !deps_file.empty()) + { + bool found = false; + pal::string_t candidate = impl_dir; + deps_json_t deps_json(false, deps_file); + for (const auto& probe_path : probe_paths) + { + trace::verbose(_X("Considering %s for hostpolicy library"), probe_path.c_str()); + if (deps_json.is_valid() && + deps_json.has_hostpolicy_entry() && + deps_json.get_hostpolicy_entry().to_full_path(probe_path, &candidate)) + { + found = true; // candidate contains the right path. + break; + } + } + if (!found) + { + trace::error(_X("Policy library either not found in deps [%s] or not found in %d probe paths."), deps_file.c_str(), probe_paths.size()); + return StatusCode::CoreHostLibMissingFailure; + } + impl_dir = get_directory(candidate); + } + corehost_init_t init(deps_file, probe_paths, _X(""), host_mode_t::muxer, &config); + return execute_app(impl_dir, &init, new_argc, new_argv); + } +} + /* static */ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) { trace::verbose(_X("--- Executing in muxer mode...")); + if (argc <= 1) + { + return muxer_usage(); + } + pal::string_t own_path; // Get the full name of the application @@ -239,163 +379,43 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) trace::error(_X("Failed to locate current executable")); return StatusCode::LibHostCurExeFindFailure; } - auto own_dir = get_directory(own_path); - if (argc <= 1) + bool is_an_app = false; + if (pal::strcasecmp(_X("exec"), argv[1]) == 0) { - trace::error(_X("Usage: dotnet [--help | app.dll]")); - return StatusCode::InvalidArgFailure; + return parse_args_and_execute(own_dir, 2, argc, argv, true, &is_an_app); // arg offset 2 for dotnet, exec } - if (ends_with(argv[1], _X(".dll"), false)) + + int result = parse_args_and_execute(own_dir, 1, argc, argv, false, &is_an_app); // arg offset 1 for dotnet + if (is_an_app) { - pal::string_t app_path = argv[1]; - - if (!pal::realpath(&app_path)) - { - trace::error(_X("Could not resolve app's full path [%s]"), app_path.c_str()); - return StatusCode::LibHostExecModeFailure; - } - - auto config_file = get_runtime_config_from_file(app_path); - runtime_config_t config(config_file); - if (!config.is_valid()) - { - trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); - return StatusCode::InvalidConfigFile; - } - if (config.get_portable()) - { - trace::verbose(_X("Executing as a portable app as per config file [%s]"), config_file.c_str()); - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config); - corehost_init_t init(_X(""), config.get_probe_paths(), fx_dir, host_mode_t::muxer, &config); - return execute_app(fx_dir, &init, argc, argv); - } - else - { - trace::verbose(_X("Executing as a standlone app as per config file [%s]"), config_file.c_str()); - corehost_init_t init(_X(""), config.get_probe_paths(), _X(""), host_mode_t::muxer, &config); - return execute_app(get_directory(app_path), &init, argc, argv); - } + return result; } - else + + // Could not execute as an app, try the CLI SDK dotnet.dll + pal::string_t sdk_dotnet; + if (!resolve_sdk_dotnet_path(own_dir, &sdk_dotnet)) { - if (pal::strcasecmp(_X("exec"), argv[1]) == 0) - { - std::vector known_opts = { _X("--depsfile"), _X("--additionalprobingpath") }; - - trace::verbose(_X("Exec mode, parsing known args")); - int num_args = 0; - std::unordered_map opts; - if (!parse_known_args(argc - 2, &argv[2], known_opts, &opts, &num_args)) - { - trace::error(_X("Failed to parse known arguments.")); - return InvalidArgFailure; - } - int cur_i = 2 + num_args; - if (cur_i >= argc) - { - trace::error(_X("Parsed known args, but need more arguments.")); - return InvalidArgFailure; - } - - // Transform dotnet exec [--additionalprobingpath path] [--depsfile file] dll [args] -> dotnet dll [args] - - std::vector new_argv(argc - cur_i + 1); // +1 for dotnet - memcpy(new_argv.data() + 1, argv + cur_i, (argc - cur_i) * sizeof(pal::char_t*)); - new_argv[0] = argv[0]; - - pal::string_t opts_deps_file = _X("--depsfile"); - pal::string_t opts_probe_path = _X("--additionalprobingpath"); - pal::string_t deps_file = opts.count(opts_deps_file) ? opts[opts_deps_file] : _X(""); - pal::string_t probe_path = opts.count(opts_probe_path) ? opts[opts_probe_path] : _X(""); - - trace::verbose(_X("Current argv is %s"), argv[cur_i]); - - pal::string_t app_or_deps = deps_file.empty() ? argv[cur_i] : deps_file; - pal::string_t no_json = argv[cur_i]; - auto config_file = get_runtime_config_from_file(no_json); - runtime_config_t config(config_file); - if (!config.is_valid()) - { - trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); - return StatusCode::InvalidConfigFile; - } - if (!deps_file.empty() && !pal::file_exists(deps_file)) - { - trace::error(_X("Deps file [%s] specified but doesn't exist"), deps_file.c_str()); - return StatusCode::InvalidArgFailure; - } - std::vector probe_paths = { probe_path }; - if (config.get_portable()) - { - trace::verbose(_X("Executing as a portable app as per config file [%s]"), config_file.c_str()); - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config); - corehost_init_t init(deps_file, probe_paths, fx_dir, host_mode_t::muxer, &config); - return execute_app(fx_dir, &init, new_argv.size(), new_argv.data()); - } - else - { - trace::verbose(_X("Executing as a standalone app as per config file [%s]"), config_file.c_str()); - pal::string_t impl_dir = get_directory(app_or_deps); - if (!library_exists_in_dir(impl_dir, LIBHOSTPOLICY_NAME, nullptr) && !probe_path.empty() && !deps_file.empty()) - { - deps_json_t deps_json(false, deps_file); - pal::string_t candidate = impl_dir; - if (!deps_json.has_hostpolicy_entry() || - !deps_json.get_hostpolicy_entry().to_full_path(probe_path, &candidate)) - { - trace::error(_X("Policy library either not found in deps [%s] or not found in [%s]"), deps_file.c_str(), probe_path.c_str()); - return StatusCode::CoreHostLibMissingFailure; - } - impl_dir = get_directory(candidate); - } - corehost_init_t init(deps_file, probe_paths, _X(""), host_mode_t::muxer, &config); - return execute_app(impl_dir, &init, new_argv.size(), new_argv.data()); - } - } - else - { - pal::string_t sdk_dotnet; - if (!resolve_sdk_dotnet_path(own_dir, &sdk_dotnet)) - { - trace::error(_X("Could not resolve SDK directory from [%s]"), own_dir.c_str()); - return StatusCode::LibHostSdkFindFailure; - } - append_path(&sdk_dotnet, _X("dotnet.dll")); - - if (!pal::file_exists(sdk_dotnet)) - { - trace::error(_X("Could not find dotnet.dll at [%s]"), sdk_dotnet.c_str()); - return StatusCode::LibHostSdkFindFailure; - } - - // Transform dotnet [command] [args] -> dotnet [dotnet.dll] [command] [args] - - std::vector new_argv(argc + 1); - memcpy(&new_argv.data()[2], argv + 1, (argc - 1) * sizeof(pal::char_t*)); - new_argv[0] = argv[0]; - new_argv[1] = sdk_dotnet.c_str(); - - trace::verbose(_X("Using dotnet SDK dll=[%s]"), sdk_dotnet.c_str()); - - auto config_file = get_runtime_config_from_file(sdk_dotnet); - runtime_config_t config(config_file); - - if (config.get_portable()) - { - trace::verbose(_X("Executing dotnet.dll as a portable app as per config file [%s]"), config_file.c_str()); - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config); - corehost_init_t init(_X(""), std::vector(), fx_dir, host_mode_t::muxer, &config); - return execute_app(fx_dir, &init, new_argv.size(), new_argv.data()); - } - else - { - trace::verbose(_X("Executing dotnet.dll as a standalone app as per config file [%s]"), config_file.c_str()); - corehost_init_t init(_X(""), std::vector(), _X(""), host_mode_t::muxer, &config); - return execute_app(get_directory(sdk_dotnet), &init, new_argv.size(), new_argv.data()); - } - } + trace::error(_X("Could not resolve SDK directory from [%s]"), own_dir.c_str()); + return StatusCode::LibHostSdkFindFailure; } + append_path(&sdk_dotnet, _X("dotnet.dll")); + + if (!pal::file_exists(sdk_dotnet)) + { + trace::error(_X("Could not find dotnet.dll at [%s]"), sdk_dotnet.c_str()); + return StatusCode::LibHostSdkFindFailure; + } + + // Transform dotnet [command] [args] -> dotnet dotnet.dll [command] [args] + + std::vector new_argv(argc + 1); + memcpy(&new_argv.data()[2], argv + 1, (argc - 1) * sizeof(pal::char_t*)); + new_argv[0] = argv[0]; + new_argv[1] = sdk_dotnet.c_str(); + + trace::verbose(_X("Using dotnet SDK dll=[%s]"), sdk_dotnet.c_str()); + return parse_args_and_execute(own_dir, 1, new_argv.size(), new_argv.data(), false, &is_an_app); } diff --git a/src/corehost/cli/fxr/fx_muxer.h b/src/corehost/cli/fxr/fx_muxer.h index 1511651cb..a802d3043 100644 --- a/src/corehost/cli/fxr/fx_muxer.h +++ b/src/corehost/cli/fxr/fx_muxer.h @@ -15,6 +15,7 @@ class fx_muxer_t public: static int execute(const int argc, const pal::char_t* argv[]); private: + static int parse_args_and_execute(const pal::string_t& own_dir, int argoff, int argc, const pal::char_t* argv[], bool exec_mode, bool* can_execute); static pal::string_t resolve_fx_dir(const pal::string_t& muxer_path, runtime_config_t* runtime); static pal::string_t resolve_cli_version(const pal::string_t& global); static bool resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk); diff --git a/src/corehost/cli/hostpolicy.cpp b/src/corehost/cli/hostpolicy.cpp index a6588a674..fbab95b47 100644 --- a/src/corehost/cli/hostpolicy.cpp +++ b/src/corehost/cli/hostpolicy.cpp @@ -240,13 +240,16 @@ SHARED_API int corehost_main(const int argc, const pal::char_t* argv[]) } else { - auto config_path = get_runtime_config_from_file(args.managed_application); - runtime_config_t config(config_path); + pal::string_t dev_config_file; + auto config_path = get_runtime_config_from_file(args.managed_application, &dev_config_file); + runtime_config_t config(config_path, dev_config_file); if (!config.is_valid()) { - trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); + trace::error(_X("Invalid runtimeconfig.json [%s] [%s]"), config.get_path().c_str(), config.get_dev_path().c_str()); return StatusCode::InvalidConfigFile; } + // TODO: This is ugly. The whole runtime config/probe paths business should all be resolved by and come from the hostfxr.cpp. + args.probe_paths.insert(args.probe_paths.end(), config.get_probe_paths().begin(), config.get_probe_paths().end()); return run(g_init, config, args); } } diff --git a/src/corehost/cli/libhost.cpp b/src/corehost/cli/libhost.cpp index f8a3b7823..6a14177d7 100644 --- a/src/corehost/cli/libhost.cpp +++ b/src/corehost/cli/libhost.cpp @@ -6,14 +6,19 @@ #include "trace.h" #include "libhost.h" -pal::string_t get_runtime_config_from_file(const pal::string_t& file) +pal::string_t get_runtime_config_from_file(const pal::string_t& file, pal::string_t* dev_cfg) { auto name = get_filename_without_ext(file); auto json_name = name + _X(".runtimeconfig.json"); + auto dev_json_name = name + _X(".runtimeconfig.dev.json"); auto json_path = get_directory(file); + auto dev_json_path = json_path; append_path(&json_path, json_name.c_str()); - trace::verbose(_X("Runtime config is %s"), json_path.c_str()); + append_path(&dev_json_path, dev_json_name.c_str()); + trace::verbose(_X("Runtime config is cfg=%s dev=%s"), json_path.c_str(), dev_json_path.c_str()); + + dev_cfg->assign(dev_json_path); return json_path; } diff --git a/src/corehost/cli/libhost.h b/src/corehost/cli/libhost.h index 78bd31791..efa42505f 100644 --- a/src/corehost/cli/libhost.h +++ b/src/corehost/cli/libhost.h @@ -80,7 +80,7 @@ public: } }; -pal::string_t get_runtime_config_from_file(const pal::string_t& file); +pal::string_t get_runtime_config_from_file(const pal::string_t& file, pal::string_t* dev_config_file); host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* own_dir = nullptr); void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str, bool only_production); diff --git a/src/corehost/cli/runtime_config.cpp b/src/corehost/cli/runtime_config.cpp index f6fb1aaa2..d4d0fec0a 100644 --- a/src/corehost/cli/runtime_config.cpp +++ b/src/corehost/cli/runtime_config.cpp @@ -8,9 +8,10 @@ #include "runtime_config.h" #include -runtime_config_t::runtime_config_t(const pal::string_t& path) +runtime_config_t::runtime_config_t(const pal::string_t& path, const pal::string_t& dev_path) : m_fx_roll_fwd(true) , m_path(path) + , m_dev_path(dev_path) , m_portable(false) { m_valid = ensure_parsed(); @@ -19,6 +20,8 @@ runtime_config_t::runtime_config_t(const pal::string_t& path) bool runtime_config_t::parse_opts(const json_value& opts) { + // Note: both runtime_config and dev_runtime_config call into the function. + // runtime_config will override whatever dev_runtime_config populated. if (opts.is_null()) { return true; @@ -43,14 +46,14 @@ bool runtime_config_t::parse_opts(const json_value& opts) { if (probe_paths->second.is_string()) { - m_probe_paths.push_back(probe_paths->second.as_string()); + m_probe_paths.insert(m_probe_paths.begin(), probe_paths->second.as_string()); } else { const auto& arr = probe_paths->second.as_array(); - for (const auto& str : arr) + for (auto iter = arr.rbegin(); iter != arr.rend(); iter++) { - m_probe_paths.push_back(str.as_string()); + m_probe_paths.push_front(iter->as_string()); } } } @@ -75,8 +78,59 @@ bool runtime_config_t::parse_opts(const json_value& opts) return true; } +bool runtime_config_t::ensure_dev_config_parsed() +{ + trace::verbose(_X("Attempting to read dev runtime config: %s"), m_dev_path.c_str()); + + pal::string_t retval; + if (!pal::file_exists(m_dev_path)) + { + // Not existing is not an error. + return true; + } + + // Set dev mode default values, if the file exists. + m_fx_roll_fwd = false; + + pal::ifstream_t file(m_dev_path); + if (!file.good()) + { + trace::verbose(_X("File stream not good %s"), m_dev_path.c_str()); + return false; + } + + if (skip_utf8_bom(&file)) + { + trace::verbose(_X("UTF-8 BOM skipped while reading [%s]"), m_dev_path.c_str()); + } + + try + { + const auto root = json_value::parse(file); + const auto& json = root.as_object(); + const auto iter = json.find(_X("runtimeOptions")); + if (iter != json.end()) + { + parse_opts(iter->second); + } + } + catch (const web::json::json_exception& je) + { + pal::string_t jes = pal::to_palstring(je.what()); + trace::error(_X("A JSON parsing exception occurred in [%s]: %s"), m_dev_path.c_str(), jes.c_str()); + return false; + } + return true; +} + bool runtime_config_t::ensure_parsed() { + trace::verbose(_X("Attempting to read runtime config: %s"), m_path.c_str()); + if (!ensure_dev_config_parsed()) + { + trace::verbose(_X("Did not successfully parse the runtimeconfig.dev.json")); + } + pal::string_t retval; if (!pal::file_exists(m_path)) { @@ -138,7 +192,7 @@ bool runtime_config_t::get_portable() const return m_portable; } -const std::vector& runtime_config_t::get_probe_paths() const +const std::list& runtime_config_t::get_probe_paths() const { return m_probe_paths; } diff --git a/src/corehost/cli/runtime_config.h b/src/corehost/cli/runtime_config.h index 0c5466e53..49bce2299 100644 --- a/src/corehost/cli/runtime_config.h +++ b/src/corehost/cli/runtime_config.h @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#include + #include "pal.h" #include "cpprest/json.h" @@ -9,13 +11,14 @@ typedef web::json::value json_value; class runtime_config_t { public: - runtime_config_t(const pal::string_t& path); + runtime_config_t(const pal::string_t& path, const pal::string_t& dev_path); bool is_valid() { return m_valid; } const pal::string_t& get_path() { return m_path; } + const pal::string_t& get_dev_path() { return m_dev_path; } const pal::string_t& get_gc_server() const; const pal::string_t& get_fx_version() const; const pal::string_t& get_fx_name() const; - const std::vector& get_probe_paths() const; + const std::list& get_probe_paths() const; bool get_fx_roll_fwd() const; bool get_portable() const; bool parse_opts(const json_value& opts); @@ -23,15 +26,17 @@ public: private: bool ensure_parsed(); + bool ensure_dev_config_parsed(); std::unordered_map m_properties; std::vector m_prop_keys; std::vector m_prop_values; - std::vector m_probe_paths; + std::list m_probe_paths; pal::string_t m_fx_name; pal::string_t m_fx_ver; bool m_fx_roll_fwd; + pal::string_t m_dev_path; pal::string_t m_path; bool m_portable; bool m_valid; diff --git a/src/corehost/common/pal.h b/src/corehost/common/pal.h index 2e4543297..ab8787238 100644 --- a/src/corehost/common/pal.h +++ b/src/corehost/common/pal.h @@ -168,7 +168,6 @@ namespace pal bool get_own_executable_path(string_t* recv); bool getenv(const char_t* name, string_t* recv); - bool get_default_packages_directory(string_t* recv); bool get_default_extensions_directory(string_t* recv); bool is_path_rooted(const string_t& path); diff --git a/src/corehost/common/pal.unix.cpp b/src/corehost/common/pal.unix.cpp index a894ca843..a7a7de6ab 100644 --- a/src/corehost/common/pal.unix.cpp +++ b/src/corehost/common/pal.unix.cpp @@ -112,28 +112,6 @@ bool pal::is_path_rooted(const pal::string_t& path) return path.front() == '/'; } -bool pal::get_default_packages_directory(pal::string_t* recv) -{ - recv->clear(); - pal::string_t dir; - if (!pal::getenv("HOME", &dir)) - { - struct passwd* pw = getpwuid(getuid()); - if (pw && pw->pw_dir) - { - dir.assign(pw->pw_dir); - } - } - if (dir.empty()) - { - return false; - } - append_path(&dir, _X(".nuget")); - append_path(&dir, _X("packages")); - recv->assign(dir); - return true; -} - bool pal::get_default_extensions_directory(string_t* recv) { recv->clear(); diff --git a/src/corehost/common/pal.windows.cpp b/src/corehost/common/pal.windows.cpp index e3c90d6a1..5bffdd571 100644 --- a/src/corehost/common/pal.windows.cpp +++ b/src/corehost/common/pal.windows.cpp @@ -123,18 +123,6 @@ void pal::unload_library(dll_t library) // No-op. On windows, we pin the library, so it can't be unloaded. } -bool pal::get_default_packages_directory(string_t* recv) -{ - recv->clear(); - if (!pal::getenv(_X("USERPROFILE"), recv)) - { - return false; - } - append_path(recv, _X(".nuget")); - append_path(recv, _X("packages")); - return true; -} - bool pal::get_default_extensions_directory(string_t* recv) { recv->clear(); diff --git a/src/corehost/common/utils.cpp b/src/corehost/common/utils.cpp index 75491d634..7c11f830b 100644 --- a/src/corehost/common/utils.cpp +++ b/src/corehost/common/utils.cpp @@ -156,18 +156,34 @@ const pal::char_t* get_arch() #endif } +pal::string_t get_last_known_arg( + const std::unordered_map>& opts, + const pal::string_t& opt_key, + const pal::string_t& de_fault) +{ + if (opts.count(opt_key)) + { + const auto& val = opts.find(opt_key)->second; + return val[val.size() - 1]; + } + return de_fault; +} + bool parse_known_args( const int argc, const pal::char_t* argv[], const std::vector& known_opts, - std::unordered_map* opts, + // Although multimap would provide this functionality the order of kv, values are + // not preserved in C++ < C++0x + std::unordered_map>* opts, int* num_args) { int arg_i = *num_args; while (arg_i < argc) { pal::string_t arg = argv[arg_i]; - if (std::find(known_opts.begin(), known_opts.end(), pal::to_lower(arg)) == known_opts.end()) + pal::string_t arg_lower = pal::to_lower(arg); + if (std::find(known_opts.begin(), known_opts.end(), arg_lower) == known_opts.end()) { // Unknown argument. break; @@ -180,7 +196,7 @@ bool parse_known_args( } trace::verbose(_X("Parsed known arg %s = %s"), arg.c_str(), argv[arg_i + 1]); - (*opts)[arg] = argv[arg_i + 1]; + (*opts)[arg_lower].push_back(argv[arg_i + 1]); // Increment for both the option and its value. arg_i += 2; diff --git a/src/corehost/common/utils.h b/src/corehost/common/utils.h index 5f53e5068..7f8e5cef7 100644 --- a/src/corehost/common/utils.h +++ b/src/corehost/common/utils.h @@ -20,11 +20,15 @@ bool library_exists_in_dir(const pal::string_t& lib_dir, const pal::string_t& li bool coreclr_exists_in_dir(const pal::string_t& candidate); void replace_char(pal::string_t* path, pal::char_t match, pal::char_t repl); const pal::char_t* get_arch(); +pal::string_t get_last_known_arg( + const std::unordered_map>& opts, + const pal::string_t& opt_key, + const pal::string_t& de_fault); bool parse_known_args( const int argc, const pal::char_t* argv[], const std::vector& known_opts, - std::unordered_map* opts, + std::unordered_map>* opts, int* num_args); bool skip_utf8_bom(pal::ifstream_t* stream); #endif