Support runtimeconfig.dev json
This commit is contained in:
parent
813049dabe
commit
f5411abdf0
14 changed files with 282 additions and 222 deletions
|
@ -67,7 +67,7 @@ bool parse_arguments(const pal::string_t& deps_path, const std::vector<pal::stri
|
|||
args.app_argc = argc - 1;
|
||||
}
|
||||
|
||||
std::unordered_map<pal::string_t, pal::string_t> opts;
|
||||
std::unordered_map<pal::string_t, std::vector<pal::string_t>> opts;
|
||||
std::vector<pal::string_t> 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<pal::stri
|
|||
args.app_argv += num_args;
|
||||
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] : deps_path;
|
||||
pal::string_t deps_file = get_last_known_arg(opts, opts_deps_file, deps_path);
|
||||
if (opts.count(opts_probe_path))
|
||||
{
|
||||
args.probe_paths.push_back(opts[opts_probe_path]);
|
||||
for (const auto& str : opts[opts_probe_path])
|
||||
{
|
||||
args.probe_paths.push_back(str);
|
||||
}
|
||||
}
|
||||
|
||||
if (!deps_file.empty())
|
||||
|
|
|
@ -207,11 +207,6 @@ void deps_resolver_t::setup_probe_config(
|
|||
{
|
||||
// Additional paths
|
||||
bool roll_fwd = config.get_fx_roll_fwd();
|
||||
if (m_package_cache == probe)
|
||||
{
|
||||
// FIXME: For now, no roll forward for nuget cache. This should come from config runtimeconfig.dev.json.
|
||||
roll_fwd = false;
|
||||
}
|
||||
m_probes.push_back(probe_config_t::additional(probe, roll_fwd));
|
||||
}
|
||||
|
||||
|
@ -240,17 +235,6 @@ void deps_resolver_t::setup_additional_probes(const std::vector<pal::string_t>&
|
|||
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)
|
||||
|
|
|
@ -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<pal::string_t> 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<pal::string_t, std::vector<pal::string_t>> 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<const pal::char_t*> 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<pal::string_t> probe_paths = opts.count(opts_probe_path) ? opts[opts_probe_path] : std::vector<pal::string_t>();
|
||||
|
||||
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<pal::string_t> known_opts = { _X("--depsfile"), _X("--additionalprobingpath") };
|
||||
|
||||
trace::verbose(_X("Exec mode, parsing known args"));
|
||||
int num_args = 0;
|
||||
std::unordered_map<pal::string_t, pal::string_t> 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<const pal::char_t*> 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<pal::string_t> 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<const pal::char_t*> 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<pal::string_t>(), 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<pal::string_t>(), _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<const pal::char_t*> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
#include "runtime_config.h"
|
||||
#include <cassert>
|
||||
|
||||
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<pal::string_t>& runtime_config_t::get_probe_paths() const
|
||||
const std::list<pal::string_t>& runtime_config_t::get_probe_paths() const
|
||||
{
|
||||
return m_probe_paths;
|
||||
}
|
||||
|
|
|
@ -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 <list>
|
||||
|
||||
#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<pal::string_t>& get_probe_paths() const;
|
||||
const std::list<pal::string_t>& 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<pal::string_t, pal::string_t> m_properties;
|
||||
std::vector<std::string> m_prop_keys;
|
||||
std::vector<std::string> m_prop_values;
|
||||
std::vector<pal::string_t> m_probe_paths;
|
||||
std::list<pal::string_t> 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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -156,18 +156,34 @@ const pal::char_t* get_arch()
|
|||
#endif
|
||||
}
|
||||
|
||||
pal::string_t get_last_known_arg(
|
||||
const std::unordered_map<pal::string_t, std::vector<pal::string_t>>& 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<pal::string_t>& known_opts,
|
||||
std::unordered_map<pal::string_t, pal::string_t>* opts,
|
||||
// Although multimap would provide this functionality the order of kv, values are
|
||||
// not preserved in C++ < C++0x
|
||||
std::unordered_map<pal::string_t, std::vector<pal::string_t>>* 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;
|
||||
|
|
|
@ -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<pal::string_t, std::vector<pal::string_t>>& 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<pal::string_t>& known_opts,
|
||||
std::unordered_map<pal::string_t, pal::string_t>* opts,
|
||||
std::unordered_map<pal::string_t, std::vector<pal::string_t>>* opts,
|
||||
int* num_args);
|
||||
bool skip_utf8_bom(pal::ifstream_t* stream);
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue