Probe shared locations
This commit is contained in:
parent
429eb93cd9
commit
3d691eb928
24 changed files with 694 additions and 524 deletions
|
@ -13,12 +13,12 @@ arguments_t::arguments_t() :
|
|||
app_argc(0),
|
||||
app_argv(nullptr),
|
||||
dotnet_packages_cache(_X("")),
|
||||
dotnet_servicing(_X("")),
|
||||
dotnet_extensions(_X("")),
|
||||
deps_path(_X(""))
|
||||
{
|
||||
}
|
||||
|
||||
bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_dir, host_mode_t mode,
|
||||
bool parse_arguments(const pal::string_t& deps_path, const std::vector<pal::string_t>& probe_paths, host_mode_t mode,
|
||||
const int argc, const pal::char_t* argv[], arguments_t* arg_out)
|
||||
{
|
||||
arguments_t& args = *arg_out;
|
||||
|
@ -80,7 +80,10 @@ bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_
|
|||
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 probe_path = opts.count(opts_probe_path) ? opts[opts_probe_path] : probe_dir;
|
||||
if (opts.count(opts_probe_path))
|
||||
{
|
||||
args.probe_paths.push_back(opts[opts_probe_path]);
|
||||
}
|
||||
|
||||
if (!deps_file.empty())
|
||||
{
|
||||
|
@ -88,7 +91,10 @@ bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_
|
|||
args.app_dir = get_directory(args.deps_path);
|
||||
}
|
||||
|
||||
args.probe_dir = probe_path;
|
||||
for (const auto& probe : probe_paths)
|
||||
{
|
||||
args.probe_paths.push_back(probe);
|
||||
}
|
||||
|
||||
if (args.deps_path.empty())
|
||||
{
|
||||
|
@ -102,7 +108,8 @@ bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_
|
|||
args.deps_path.append(_X(".deps.json"));
|
||||
}
|
||||
|
||||
pal::getenv(_X("DOTNET_PACKAGES_CACHE"), &args.dotnet_packages_cache);
|
||||
pal::getenv(_X("DOTNET_SERVICING"), &args.dotnet_servicing);
|
||||
pal::getenv(_X("DOTNET_HOSTING_OPTIMIZATION_CACHE"), &args.dotnet_packages_cache);
|
||||
pal::get_default_extensions_directory(&args.dotnet_extensions);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -7,15 +7,85 @@
|
|||
#include "utils.h"
|
||||
#include "pal.h"
|
||||
#include "trace.h"
|
||||
#include "deps_format.h"
|
||||
#include "libhost.h"
|
||||
|
||||
struct probe_config_t
|
||||
{
|
||||
pal::string_t probe_dir;
|
||||
bool match_hash;
|
||||
bool roll_forward;
|
||||
const deps_json_t* probe_deps_json;
|
||||
|
||||
bool only_runtime_assets;
|
||||
bool only_serviceable_assets;
|
||||
|
||||
void print() const
|
||||
{
|
||||
trace::verbose(_X("probe_config_t: probe=[%s] match-hash=[%d] roll-forward=[%d] deps-json=[%p]"),
|
||||
probe_dir.c_str(), match_hash, roll_forward, probe_deps_json);
|
||||
}
|
||||
|
||||
probe_config_t(
|
||||
const pal::string_t& probe_dir,
|
||||
bool match_hash,
|
||||
bool roll_forward,
|
||||
const deps_json_t* probe_deps_json,
|
||||
bool only_serviceable_assets,
|
||||
bool only_runtime_assets)
|
||||
: probe_dir(probe_dir)
|
||||
, match_hash(match_hash)
|
||||
, roll_forward(roll_forward)
|
||||
, probe_deps_json(probe_deps_json)
|
||||
, only_serviceable_assets(only_serviceable_assets)
|
||||
, only_runtime_assets(only_runtime_assets)
|
||||
{
|
||||
// Cannot roll forward and also match hash.
|
||||
assert(!roll_forward || !match_hash);
|
||||
// Will not roll forward within a deps json.
|
||||
assert(!roll_forward || probe_deps_json == nullptr);
|
||||
// Will not do hash match when probing a deps json.
|
||||
assert(!match_hash || probe_deps_json == nullptr);
|
||||
}
|
||||
|
||||
static probe_config_t svc_ni(const pal::string_t dir, bool roll_fwd)
|
||||
{
|
||||
return probe_config_t(dir, false, roll_fwd, nullptr, true, true);
|
||||
}
|
||||
|
||||
static probe_config_t svc(const pal::string_t dir, bool roll_fwd)
|
||||
{
|
||||
return probe_config_t(dir, false, roll_fwd, nullptr, true, false);
|
||||
}
|
||||
|
||||
static probe_config_t cache_ni(const pal::string_t dir)
|
||||
{
|
||||
return probe_config_t(dir, true, false, nullptr, false, true);
|
||||
}
|
||||
|
||||
static probe_config_t cache(const pal::string_t dir)
|
||||
{
|
||||
return probe_config_t(dir, true, false, nullptr, false, false);
|
||||
}
|
||||
|
||||
static probe_config_t fx(const pal::string_t dir, const deps_json_t* deps)
|
||||
{
|
||||
return probe_config_t(dir, false, false, deps, false, false);
|
||||
}
|
||||
|
||||
static probe_config_t additional(const pal::string_t dir, bool roll_fwd)
|
||||
{
|
||||
return probe_config_t(dir, false, roll_fwd, nullptr, false, false);
|
||||
}
|
||||
};
|
||||
|
||||
struct arguments_t
|
||||
{
|
||||
pal::string_t own_path;
|
||||
pal::string_t app_dir;
|
||||
pal::string_t deps_path;
|
||||
pal::string_t dotnet_servicing;
|
||||
pal::string_t probe_dir;
|
||||
pal::string_t dotnet_extensions;
|
||||
std::vector<pal::string_t> probe_paths;
|
||||
pal::string_t dotnet_packages_cache;
|
||||
pal::string_t managed_application;
|
||||
|
||||
|
@ -28,12 +98,16 @@ struct arguments_t
|
|||
{
|
||||
if (trace::is_enabled())
|
||||
{
|
||||
trace::verbose(_X("args: own_path=%s app_dir=%s deps=%s servicing=%s probe_dir=%s packages_cache=%s mgd_app=%s"),
|
||||
own_path.c_str(), app_dir.c_str(), deps_path.c_str(), dotnet_servicing.c_str(), probe_dir.c_str(), dotnet_packages_cache.c_str(), managed_application.c_str());
|
||||
trace::verbose(_X("-- arguments_t: own_path=%s app_dir=%s deps=%s extensions=%s packages_cache=%s mgd_app=%s"),
|
||||
own_path.c_str(), app_dir.c_str(), deps_path.c_str(), dotnet_extensions.c_str(), dotnet_packages_cache.c_str(), managed_application.c_str());
|
||||
for (const auto& probe : probe_paths)
|
||||
{
|
||||
trace::verbose(_X("-- arguments_t: probe dir: [%s]"), probe.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_dir, host_mode_t mode, const int argc, const pal::char_t* argv[], arguments_t* args);
|
||||
bool parse_arguments(const pal::string_t& deps_path, const std::vector<pal::string_t>& probe_paths, host_mode_t mode, const int argc, const pal::char_t* argv[], arguments_t* args);
|
||||
|
||||
#endif // ARGS_H
|
||||
|
|
|
@ -7,19 +7,7 @@
|
|||
#include "trace.h"
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Given a "base" directory, yield the relative path of this file in the package
|
||||
// layout.
|
||||
//
|
||||
// Parameters:
|
||||
// base - The base directory to look for the relative path of this entry
|
||||
// str - If the method returns true, contains the file path for this deps
|
||||
// entry relative to the "base" directory
|
||||
//
|
||||
// Returns:
|
||||
// If the file exists in the path relative to the "base" directory.
|
||||
//
|
||||
bool deps_entry_t::to_rel_path(const pal::string_t& base, pal::string_t* str) const
|
||||
bool deps_entry_t::to_path(const pal::string_t& base, bool look_in_base, pal::string_t* str) const
|
||||
{
|
||||
pal::string_t& candidate = *str;
|
||||
|
||||
|
@ -44,21 +32,55 @@ bool deps_entry_t::to_rel_path(const pal::string_t& base, pal::string_t* str) co
|
|||
pal_relative_path.length() + 3);
|
||||
|
||||
candidate.assign(base);
|
||||
append_path(&candidate, pal_relative_path.c_str());
|
||||
pal::string_t sub_path = look_in_base ? get_filename(pal_relative_path) : pal_relative_path;
|
||||
append_path(&candidate, sub_path.c_str());
|
||||
|
||||
bool exists = pal::file_exists(candidate);
|
||||
const pal::char_t* query_type = look_in_base ? _X("Local") : _X("Relative");
|
||||
if (!exists)
|
||||
{
|
||||
trace::verbose(_X("Relative path query did not exist %s"), candidate.c_str());
|
||||
trace::verbose(_X(" %s path query did not exist %s"), query_type, candidate.c_str());
|
||||
candidate.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
trace::verbose(_X("Relative path query exists %s"), candidate.c_str());
|
||||
trace::verbose(_X(" %s path query exists %s"), query_type, candidate.c_str());
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Given a "base" directory, yield the local path of this file
|
||||
//
|
||||
// Parameters:
|
||||
// base - The base directory to look for the relative path of this entry
|
||||
// str - If the method returns true, contains the file path for this deps
|
||||
// entry relative to the "base" directory
|
||||
//
|
||||
// Returns:
|
||||
// If the file exists in the path relative to the "base" directory.
|
||||
//
|
||||
bool deps_entry_t::to_dir_path(const pal::string_t& base, pal::string_t* str) const
|
||||
{
|
||||
return to_path(base, true, str);
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
// Given a "base" directory, yield the relative path of this file in the package
|
||||
// layout.
|
||||
//
|
||||
// Parameters:
|
||||
// base - The base directory to look for the relative path of this entry
|
||||
// str - If the method returns true, contains the file path for this deps
|
||||
// entry relative to the "base" directory
|
||||
//
|
||||
// Returns:
|
||||
// If the file exists in the path relative to the "base" directory.
|
||||
//
|
||||
bool deps_entry_t::to_rel_path(const pal::string_t& base, pal::string_t* str) const
|
||||
{
|
||||
return to_path(base, false, str);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Given a "base" directory, yield the relative path of this file in the package
|
||||
// layout.
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#define __DEPS_ENTRY_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "pal.h"
|
||||
|
||||
|
@ -18,14 +19,24 @@ struct deps_entry_t
|
|||
count
|
||||
};
|
||||
|
||||
static const std::array<const pal::char_t*, deps_entry_t::asset_types::count> s_known_asset_types;
|
||||
|
||||
pal::string_t library_type;
|
||||
pal::string_t library_name;
|
||||
pal::string_t library_version;
|
||||
pal::string_t library_hash;
|
||||
pal::string_t asset_type;
|
||||
asset_types asset_type;
|
||||
pal::string_t asset_name;
|
||||
pal::string_t relative_path;
|
||||
bool is_serviceable;
|
||||
bool is_rid_specific;
|
||||
|
||||
|
||||
// Given a "base" dir, yield the filepath within this directory or relative to this directory based on "look_in_base"
|
||||
bool to_path(const pal::string_t& base, bool look_in_base, pal::string_t* str) const;
|
||||
|
||||
// Given a "base" dir, yield the file path within this directory.
|
||||
bool to_dir_path(const pal::string_t& base, pal::string_t* str) const;
|
||||
|
||||
// Given a "base" dir, yield the relative path in the package layout.
|
||||
bool to_rel_path(const pal::string_t& base, pal::string_t* str) const;
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
// 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 "deps_entry.h"
|
||||
#include "deps_format.h"
|
||||
#include "utils.h"
|
||||
#include "trace.h"
|
||||
#include <unordered_set>
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
|
||||
const std::array<const pal::char_t*, deps_entry_t::asset_types::count> deps_json_t::s_known_asset_types = {
|
||||
_X("runtime"), _X("resources"), _X("native") };
|
||||
const std::array<const pal::char_t*, deps_entry_t::asset_types::count> deps_entry_t::s_known_asset_types = {
|
||||
_X("runtime"), _X("resources"), _X("native")
|
||||
};
|
||||
|
||||
const deps_entry_t& deps_json_t::try_ni(const deps_entry_t& entry) const
|
||||
{
|
||||
|
@ -27,7 +28,7 @@ const deps_entry_t& deps_json_t::try_ni(const deps_entry_t& entry) const
|
|||
void deps_json_t::reconcile_libraries_with_targets(
|
||||
const json_value& json,
|
||||
const std::function<bool(const pal::string_t&)>& library_exists_fn,
|
||||
const std::function<const std::vector<pal::string_t>&(const pal::string_t&, int)>& get_rel_paths_by_asset_type_fn)
|
||||
const std::function<const std::vector<pal::string_t>&(const pal::string_t&, int, bool*)>& get_rel_paths_by_asset_type_fn)
|
||||
{
|
||||
const auto& libraries = json.at(_X("libraries")).as_object();
|
||||
for (const auto& library : libraries)
|
||||
|
@ -50,9 +51,10 @@ void deps_json_t::reconcile_libraries_with_targets(
|
|||
const pal::string_t& hash = properties.at(_X("sha512")).as_string();
|
||||
bool serviceable = properties.at(_X("serviceable")).as_bool();
|
||||
|
||||
for (int i = 0; i < s_known_asset_types.size(); ++i)
|
||||
for (int i = 0; i < deps_entry_t::s_known_asset_types.size(); ++i)
|
||||
{
|
||||
for (const auto& rel_path : get_rel_paths_by_asset_type_fn(library.first, i))
|
||||
bool rid_specific = false;
|
||||
for (const auto& rel_path : get_rel_paths_by_asset_type_fn(library.first, i, &rid_specific))
|
||||
{
|
||||
bool ni_dll = false;
|
||||
auto asset_name = get_filename_without_ext(rel_path);
|
||||
|
@ -69,9 +71,10 @@ void deps_json_t::reconcile_libraries_with_targets(
|
|||
entry.library_type = _X("package");
|
||||
entry.library_hash = hash;
|
||||
entry.asset_name = asset_name;
|
||||
entry.asset_type = s_known_asset_types[i];
|
||||
entry.asset_type = (deps_entry_t::asset_types) i;
|
||||
entry.relative_path = rel_path;
|
||||
entry.is_serviceable = serviceable;
|
||||
entry.is_rid_specific = rid_specific;
|
||||
|
||||
// TODO: Deps file does not follow spec. It uses '\\', should use '/'
|
||||
replace_char(&entry.relative_path, _X('\\'), _X('/'));
|
||||
|
@ -84,7 +87,7 @@ void deps_json_t::reconcile_libraries_with_targets(
|
|||
[deps_entry_t::asset_types::runtime].size() - 1;
|
||||
}
|
||||
|
||||
trace::info(_X("Added %s %s deps entry [%d] [%s, %s, %s]"), s_known_asset_types[i], entry.asset_name.c_str(), m_deps_entries[i].size() - 1, entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());
|
||||
trace::info(_X("Added %s %s deps entry [%d] [%s, %s, %s]"), deps_entry_t::s_known_asset_types[i], entry.asset_name.c_str(), m_deps_entries[i].size() - 1, entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());
|
||||
|
||||
if (i == deps_entry_t::asset_types::native &&
|
||||
entry.asset_name == LIBCORECLR_FILENAME)
|
||||
|
@ -124,9 +127,9 @@ pal::string_t get_own_rid()
|
|||
bool deps_json_t::perform_rid_fallback(rid_specific_assets_t* portable_assets, const rid_fallback_graph_t& rid_fallback_graph)
|
||||
{
|
||||
pal::string_t host_rid = get_own_rid();
|
||||
for (auto& package : *portable_assets)
|
||||
for (auto& package : portable_assets->libs)
|
||||
{
|
||||
pal::string_t matched_rid = package.second.count(host_rid) ? host_rid : _X("");
|
||||
pal::string_t matched_rid = package.second.rid_assets.count(host_rid) ? host_rid : _X("");
|
||||
if (matched_rid.empty())
|
||||
{
|
||||
if (rid_fallback_graph.count(host_rid) == 0)
|
||||
|
@ -136,7 +139,7 @@ bool deps_json_t::perform_rid_fallback(rid_specific_assets_t* portable_assets, c
|
|||
}
|
||||
const auto& fallback_rids = rid_fallback_graph.find(host_rid)->second;
|
||||
auto iter = std::find_if(fallback_rids.begin(), fallback_rids.end(), [&package](const pal::string_t& rid) {
|
||||
return package.second.count(rid);
|
||||
return package.second.rid_assets.count(rid);
|
||||
});
|
||||
if (iter != fallback_rids.end())
|
||||
{
|
||||
|
@ -146,15 +149,15 @@ bool deps_json_t::perform_rid_fallback(rid_specific_assets_t* portable_assets, c
|
|||
|
||||
if (matched_rid.empty())
|
||||
{
|
||||
package.second.clear();
|
||||
package.second.rid_assets.clear();
|
||||
}
|
||||
|
||||
for (auto iter = package.second.begin(); iter != package.second.end(); /* */)
|
||||
for (auto iter = package.second.rid_assets.begin(); iter != package.second.rid_assets.end(); /* */)
|
||||
{
|
||||
if (iter->first != matched_rid)
|
||||
{
|
||||
trace::verbose(_X("Chose %s, so removing rid (%s) specific assets for package %s"), matched_rid.c_str(), iter->first.c_str(), package.first.c_str());
|
||||
iter = package.second.erase(iter);
|
||||
iter = package.second.rid_assets.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -182,12 +185,12 @@ bool deps_json_t::process_runtime_targets(const json_value& json, const pal::str
|
|||
for (const auto& file : files)
|
||||
{
|
||||
const auto& type = file.second.at(_X("assetType")).as_string();
|
||||
for (int i = 0; i < s_known_asset_types.size(); ++i)
|
||||
for (int i = 0; i < deps_entry_t::s_known_asset_types.size(); ++i)
|
||||
{
|
||||
if (pal::strcasecmp(type.c_str(), s_known_asset_types[i]) == 0)
|
||||
if (pal::strcasecmp(type.c_str(), deps_entry_t::s_known_asset_types[i]) == 0)
|
||||
{
|
||||
const auto& rid = file.second.at(_X("rid")).as_string();
|
||||
assets[package.first][rid][i].push_back(file.first);
|
||||
assets.libs[package.first].rid_assets[rid].by_type[i].vec.push_back(file.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,15 +211,15 @@ bool deps_json_t::process_targets(const json_value& json, const pal::string_t& t
|
|||
{
|
||||
// if (package.second.at(_X("type")).as_string() != _X("package")) continue;
|
||||
const auto& asset_types = package.second.as_object();
|
||||
for (int i = 0; i < s_known_asset_types.size(); ++i)
|
||||
for (int i = 0; i < deps_entry_t::s_known_asset_types.size(); ++i)
|
||||
{
|
||||
auto iter = asset_types.find(s_known_asset_types[i]);
|
||||
auto iter = asset_types.find(deps_entry_t::s_known_asset_types[i]);
|
||||
if (iter != asset_types.end())
|
||||
{
|
||||
for (const auto& file : iter->second.as_object())
|
||||
{
|
||||
trace::info(_X("Adding %s asset %s from %s"), s_known_asset_types[i], file.first.c_str(), package.first.c_str());
|
||||
assets[package.first][i].push_back(file.first);
|
||||
trace::info(_X("Adding %s asset %s from %s"), deps_entry_t::s_known_asset_types[i], file.first.c_str(), package.first.c_str());
|
||||
assets.libs[package.first].by_type[i].vec.push_back(file.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,40 +229,41 @@ bool deps_json_t::process_targets(const json_value& json, const pal::string_t& t
|
|||
|
||||
bool deps_json_t::load_portable(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph)
|
||||
{
|
||||
rid_specific_assets_t rid_assets;
|
||||
if (!process_runtime_targets(json, target_name, rid_fallback_graph, &rid_assets))
|
||||
if (!process_runtime_targets(json, target_name, rid_fallback_graph, &m_rid_assets))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
deps_assets_t non_rid_assets;
|
||||
if (!process_targets(json, target_name, &non_rid_assets))
|
||||
if (!process_targets(json, target_name, &m_assets))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto package_exists = [&rid_assets, &non_rid_assets](const pal::string_t& package) -> bool {
|
||||
return rid_assets.count(package) || non_rid_assets.count(package);
|
||||
auto package_exists = [&](const pal::string_t& package) -> bool {
|
||||
return m_rid_assets.libs.count(package) || m_assets.libs.count(package);
|
||||
};
|
||||
|
||||
std::vector<pal::string_t> empty;
|
||||
auto get_relpaths = [&rid_assets, &non_rid_assets, &empty](const pal::string_t& package, int type_index) -> const std::vector<pal::string_t>& {
|
||||
const std::vector<pal::string_t> empty;
|
||||
auto get_relpaths = [&](const pal::string_t& package, int type_index, bool* rid_specific) -> const std::vector<pal::string_t>& {
|
||||
|
||||
*rid_specific = false;
|
||||
|
||||
// Is there any rid specific assets for this type ("native" or "runtime" or "resources")
|
||||
if (rid_assets.count(package) && !rid_assets[package].empty())
|
||||
if (m_rid_assets.libs.count(package) && !m_rid_assets.libs[package].rid_assets.empty())
|
||||
{
|
||||
const auto& assets_by_type = rid_assets[package].begin()->second[type_index];
|
||||
const auto& assets_by_type = m_rid_assets.libs[package].rid_assets.begin()->second.by_type[type_index].vec;
|
||||
if (!assets_by_type.empty())
|
||||
{
|
||||
*rid_specific = true;
|
||||
return assets_by_type;
|
||||
}
|
||||
|
||||
trace::verbose(_X("There were no rid specific %s asset for %s"), deps_json_t::s_known_asset_types[type_index], package.c_str());
|
||||
trace::verbose(_X("There were no rid specific %s asset for %s"), deps_entry_t::s_known_asset_types[type_index], package.c_str());
|
||||
}
|
||||
|
||||
if (non_rid_assets.count(package))
|
||||
if (m_assets.libs.count(package))
|
||||
{
|
||||
return non_rid_assets[package][type_index];
|
||||
return m_assets.libs[package].by_type[type_index].vec;
|
||||
}
|
||||
|
||||
return empty;
|
||||
|
@ -272,19 +276,18 @@ bool deps_json_t::load_portable(const json_value& json, const pal::string_t& tar
|
|||
|
||||
bool deps_json_t::load_standalone(const json_value& json, const pal::string_t& target_name)
|
||||
{
|
||||
deps_assets_t assets;
|
||||
|
||||
if (!process_targets(json, target_name, &assets))
|
||||
if (!process_targets(json, target_name, &m_assets))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto package_exists = [&assets](const pal::string_t& package) -> bool {
|
||||
return assets.count(package);
|
||||
auto package_exists = [&](const pal::string_t& package) -> bool {
|
||||
return m_assets.libs.count(package);
|
||||
};
|
||||
|
||||
auto get_relpaths = [&assets](const pal::string_t& package, int type_index) -> const std::vector<pal::string_t>& {
|
||||
return assets[package][type_index];
|
||||
auto get_relpaths = [&](const pal::string_t& package, int type_index, bool* rid_specific) -> const std::vector<pal::string_t>& {
|
||||
*rid_specific = false;
|
||||
return m_assets.libs[package].by_type[type_index].vec;
|
||||
};
|
||||
|
||||
reconcile_libraries_with_targets(json, package_exists, get_relpaths);
|
||||
|
@ -320,6 +323,24 @@ bool deps_json_t::load_standalone(const json_value& json, const pal::string_t& t
|
|||
return true;
|
||||
}
|
||||
|
||||
bool deps_json_t::has_package(const pal::string_t& name, const pal::string_t& ver) const
|
||||
{
|
||||
pal::string_t pv = name;
|
||||
pv.push_back(_X('/'));
|
||||
pv.append(ver);
|
||||
|
||||
auto iter = m_rid_assets.libs.find(pv);
|
||||
if (iter != m_rid_assets.libs.end())
|
||||
{
|
||||
if (!iter->second.rid_assets.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return m_assets.libs.count(pv);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Load the deps file and parse its "entry" lines which contain the "fields" of
|
||||
// the entry. Populate an array of these entries.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <functional>
|
||||
#include "pal.h"
|
||||
#include "deps_entry.h"
|
||||
|
@ -14,13 +15,15 @@
|
|||
class deps_json_t
|
||||
{
|
||||
typedef web::json::value json_value;
|
||||
typedef std::array<std::vector<pal::string_t>, deps_entry_t::asset_types::count> vectors_t;
|
||||
typedef std::unordered_map<pal::string_t, vectors_t> str_to_vectors_map_t;
|
||||
typedef std::unordered_map<pal::string_t, std::vector<pal::string_t>> str_to_vector_map_t;
|
||||
struct vec_t { std::vector<pal::string_t> vec; };
|
||||
struct assets_t { std::array<vec_t, deps_entry_t::asset_types::count> by_type; };
|
||||
struct deps_assets_t { std::unordered_map<pal::string_t, assets_t> libs; };
|
||||
struct rid_assets_t { std::unordered_map<pal::string_t, assets_t> rid_assets; };
|
||||
struct rid_specific_assets_t { std::unordered_map<pal::string_t, rid_assets_t> libs; };
|
||||
|
||||
typedef std::unordered_map<pal::string_t, std::vector<pal::string_t>> str_to_vector_map_t;
|
||||
typedef str_to_vector_map_t rid_fallback_graph_t;
|
||||
typedef str_to_vectors_map_t deps_assets_t;
|
||||
typedef std::unordered_map<pal::string_t, str_to_vectors_map_t> rid_specific_assets_t;
|
||||
|
||||
|
||||
public:
|
||||
deps_json_t()
|
||||
|
@ -47,6 +50,8 @@ public:
|
|||
return m_deps_entries[type];
|
||||
}
|
||||
|
||||
bool has_package(const pal::string_t& name, const pal::string_t& ver) const;
|
||||
|
||||
bool has_coreclr_entry()
|
||||
{
|
||||
return m_coreclr_index >= 0;
|
||||
|
@ -91,14 +96,15 @@ private:
|
|||
void reconcile_libraries_with_targets(
|
||||
const json_value& json,
|
||||
const std::function<bool(const pal::string_t&)>& library_exists_fn,
|
||||
const std::function<const std::vector<pal::string_t>&(const pal::string_t&, int)>& get_rel_paths_by_asset_type_fn);
|
||||
const std::function<const std::vector<pal::string_t>&(const pal::string_t&, int, bool*)>& get_rel_paths_by_asset_type_fn);
|
||||
|
||||
bool perform_rid_fallback(rid_specific_assets_t* portable_assets, const rid_fallback_graph_t& rid_fallback_graph);
|
||||
|
||||
static const std::array<const pal::char_t*, deps_entry_t::asset_types::count> s_known_asset_types;
|
||||
|
||||
std::vector<deps_entry_t> m_deps_entries[deps_entry_t::asset_types::count];
|
||||
|
||||
deps_assets_t m_assets;
|
||||
rid_specific_assets_t m_rid_assets;
|
||||
|
||||
std::unordered_map<pal::string_t, int> m_ni_entries;
|
||||
rid_fallback_graph_t m_rid_fallback_graph;
|
||||
int m_coreclr_index;
|
||||
|
@ -106,21 +112,4 @@ private:
|
|||
bool m_valid;
|
||||
};
|
||||
|
||||
class deps_text_t
|
||||
{
|
||||
public:
|
||||
deps_text_t(const pal::string_t& deps_path)
|
||||
: m_valid(load(deps_path))
|
||||
{
|
||||
}
|
||||
|
||||
bool load(const pal::string_t& deps_path);
|
||||
bool is_valid() { return m_valid; }
|
||||
const std::vector<deps_entry_t>& get_entries() { return m_deps_entries; }
|
||||
|
||||
private:
|
||||
std::vector<deps_entry_t> m_deps_entries;
|
||||
bool m_valid;
|
||||
};
|
||||
|
||||
#endif // __DEPS_FORMAT_H_
|
||||
|
|
|
@ -6,9 +6,12 @@
|
|||
#include <cassert>
|
||||
|
||||
#include "trace.h"
|
||||
#include "deps_entry.h"
|
||||
#include "deps_format.h"
|
||||
#include "deps_resolver.h"
|
||||
#include "utils.h"
|
||||
#include "fx_ver.h"
|
||||
#include "libhost.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -43,7 +46,7 @@ void add_tpa_asset(
|
|||
// the "output" string.
|
||||
//
|
||||
void add_unique_path(
|
||||
const pal::string_t& type,
|
||||
deps_entry_t::asset_types asset_type,
|
||||
const pal::string_t& path,
|
||||
std::set<pal::string_t>* existing,
|
||||
pal::string_t* output)
|
||||
|
@ -57,7 +60,7 @@ void add_unique_path(
|
|||
return;
|
||||
}
|
||||
|
||||
trace::verbose(_X("Adding to %s path: %s"), type.c_str(), real.c_str());
|
||||
trace::verbose(_X("Adding to %s path: %s"), deps_entry_t::s_known_asset_types[asset_type], real.c_str());
|
||||
|
||||
output->append(real);
|
||||
|
||||
|
@ -119,6 +122,200 @@ void deps_resolver_t::get_dir_assemblies(
|
|||
}
|
||||
}
|
||||
|
||||
bool deps_resolver_t::try_roll_forward(const deps_entry_t& entry,
|
||||
const pal::string_t& probe_dir,
|
||||
pal::string_t* candidate)
|
||||
{
|
||||
trace::verbose(_X("Attempting a roll forward for [%s/%s/%s] in [%s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str(), probe_dir.c_str());
|
||||
|
||||
const pal::string_t& lib_ver = entry.library_version;
|
||||
|
||||
fx_ver_t cur_ver(-1, -1, -1);
|
||||
if (!fx_ver_t::parse(lib_ver, &cur_ver, false))
|
||||
{
|
||||
trace::verbose(_X("No roll forward as specified version [%s] could not be parsed"), lib_ver.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract glob string of the form: 1.0.* from the version 1.0.0-prerelease-00001.
|
||||
size_t pat_start = lib_ver.find(_X('.'), lib_ver.find(_X('.')) + 1);
|
||||
pal::string_t maj_min_star = lib_ver.substr(0, pat_start + 1) + _X('*');
|
||||
|
||||
pal::string_t path = probe_dir;
|
||||
append_path(&path, entry.library_name.c_str());
|
||||
|
||||
pal::string_t cache_key = path;
|
||||
append_path(&cache_key, maj_min_star.c_str());
|
||||
|
||||
pal::string_t max_str;
|
||||
if (m_roll_forward_cache.count(cache_key))
|
||||
{
|
||||
max_str = m_roll_forward_cache[cache_key];
|
||||
trace::verbose(_X("Found cached roll forward version [%s] -> [%s]"), lib_ver.c_str(), max_str.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
try_patch_roll_forward_in_dir(path, cur_ver, &max_str, true);
|
||||
m_roll_forward_cache[cache_key] = max_str;
|
||||
}
|
||||
|
||||
append_path(&path, max_str.c_str());
|
||||
|
||||
return entry.to_rel_path(path, candidate);
|
||||
}
|
||||
|
||||
void deps_resolver_t::setup_probe_config(
|
||||
const corehost_init_t* init,
|
||||
const runtime_config_t& config,
|
||||
const arguments_t& args)
|
||||
{
|
||||
if (pal::directory_exists(args.dotnet_extensions))
|
||||
{
|
||||
pal::string_t ext_ni = args.dotnet_extensions;
|
||||
append_path(&ext_ni, get_arch());
|
||||
if (pal::directory_exists(ext_ni))
|
||||
{
|
||||
// Servicing NI probe.
|
||||
m_probes.push_back(probe_config_t::svc_ni(ext_ni, config.get_fx_roll_fwd()));
|
||||
}
|
||||
|
||||
// Servicing normal probe.
|
||||
m_probes.push_back(probe_config_t::svc(args.dotnet_extensions, config.get_fx_roll_fwd()));
|
||||
}
|
||||
|
||||
if (pal::directory_exists(args.dotnet_packages_cache))
|
||||
{
|
||||
pal::string_t ni_packages_cache = args.dotnet_packages_cache;
|
||||
append_path(&ni_packages_cache, get_arch());
|
||||
if (pal::directory_exists(ni_packages_cache))
|
||||
{
|
||||
// Packages cache NI probe
|
||||
m_probes.push_back(probe_config_t::cache_ni(ni_packages_cache));
|
||||
}
|
||||
|
||||
// Packages cache probe
|
||||
m_probes.push_back(probe_config_t::cache(args.dotnet_packages_cache));
|
||||
}
|
||||
|
||||
if (pal::directory_exists(m_fx_dir))
|
||||
{
|
||||
// FX probe
|
||||
m_probes.push_back(probe_config_t::fx(m_fx_dir, m_fx_deps.get()));
|
||||
}
|
||||
|
||||
for (const auto& probe : m_additional_probes)
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
|
||||
if (trace::is_enabled())
|
||||
{
|
||||
trace::verbose(_X("-- Listing probe configurations..."));
|
||||
for (const auto& pc : m_probes)
|
||||
{
|
||||
pc.print();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deps_resolver_t::setup_additional_probes(const std::vector<pal::string_t>& probe_paths)
|
||||
{
|
||||
m_additional_probes.assign(probe_paths.begin(), probe_paths.end());
|
||||
|
||||
for (auto iter = m_additional_probes.begin(); iter != m_additional_probes.end(); )
|
||||
{
|
||||
if (pal::directory_exists(*iter))
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
candidate->clear();
|
||||
for (const auto& config : m_probes)
|
||||
{
|
||||
trace::verbose(_X(" Considering entry [%s/%s/%s] and probe dir [%s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str(), config.probe_dir.c_str());
|
||||
|
||||
if (config.only_serviceable_assets && !entry.is_serviceable)
|
||||
{
|
||||
trace::verbose(_X(" Skipping... not serviceable asset"));
|
||||
continue;
|
||||
}
|
||||
if (config.only_runtime_assets && entry.asset_type != deps_entry_t::asset_types::runtime)
|
||||
{
|
||||
trace::verbose(_X(" Skipping... not runtime asset"));
|
||||
continue;
|
||||
}
|
||||
pal::string_t probe_dir = config.probe_dir;
|
||||
if (config.match_hash)
|
||||
{
|
||||
if (entry.to_hash_matched_path(probe_dir, candidate))
|
||||
{
|
||||
assert(!config.roll_forward);
|
||||
trace::verbose(_X(" Matched hash for [%s]"), candidate->c_str());
|
||||
return true;
|
||||
}
|
||||
trace::verbose(_X(" Skipping... match hash failed"));
|
||||
}
|
||||
else if (config.probe_deps_json)
|
||||
{
|
||||
// If the deps json has it then someone has already done rid selection and put the right stuff in the dir.
|
||||
// So checking just package name and version would suffice. No need to check further for the exact asset relative path.
|
||||
if (config.probe_deps_json->has_package(entry.library_name, entry.library_version) && entry.to_dir_path(probe_dir, candidate))
|
||||
{
|
||||
trace::verbose(_X(" Probed deps json and matched [%s]"), candidate->c_str());
|
||||
return true;
|
||||
}
|
||||
trace::verbose(_X(" Skipping... probe in deps json failed"));
|
||||
}
|
||||
else if (!config.roll_forward)
|
||||
{
|
||||
if (entry.to_full_path(probe_dir, candidate))
|
||||
{
|
||||
trace::verbose(_X(" Specified no roll forward; matched [%s]"), candidate->c_str());
|
||||
return true;
|
||||
}
|
||||
trace::verbose(_X(" Skipping... not found in probe dir"));
|
||||
}
|
||||
else if (config.roll_forward)
|
||||
{
|
||||
if (try_roll_forward(entry, probe_dir, candidate))
|
||||
{
|
||||
trace::verbose(_X(" Specified roll forward; matched [%s]"), candidate->c_str());
|
||||
return true;
|
||||
}
|
||||
trace::verbose(_X(" Skipping... could not roll forward and match in probe dir"));
|
||||
}
|
||||
|
||||
// continue to try next probe config
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Resolve coreclr directory from the deps file.
|
||||
//
|
||||
|
@ -126,22 +323,21 @@ void deps_resolver_t::get_dir_assemblies(
|
|||
// Look for CoreCLR from the dependency list in the package cache and then
|
||||
// the packages directory.
|
||||
//
|
||||
pal::string_t deps_resolver_t::resolve_coreclr_dir(
|
||||
const pal::string_t& app_dir,
|
||||
const pal::string_t& package_dir,
|
||||
const pal::string_t& package_cache_dir)
|
||||
pal::string_t deps_resolver_t::resolve_coreclr_dir()
|
||||
{
|
||||
auto process_coreclr = [&]
|
||||
(bool is_portable, const pal::string_t& deps_dir, deps_json_t* deps) -> pal::string_t
|
||||
{
|
||||
pal::string_t candidate;
|
||||
|
||||
// Servicing override.
|
||||
if (deps->has_coreclr_entry())
|
||||
{
|
||||
const deps_entry_t& entry = deps->get_coreclr_entry();
|
||||
trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in servicing"), entry.library_name.c_str(), entry.library_version.c_str());
|
||||
if (entry.is_serviceable && m_svc.find_redirection(entry.library_name, entry.library_version, entry.relative_path, &candidate))
|
||||
if (probe_entry_in_configs(entry, &candidate))
|
||||
{
|
||||
return get_directory(candidate);
|
||||
}
|
||||
else if (entry.is_rid_specific && entry.to_rel_path(deps_dir, &candidate))
|
||||
{
|
||||
return get_directory(candidate);
|
||||
}
|
||||
|
@ -151,68 +347,21 @@ pal::string_t deps_resolver_t::resolve_coreclr_dir(
|
|||
trace::verbose(_X("Deps has no coreclr entry."));
|
||||
}
|
||||
|
||||
// Package cache.
|
||||
pal::string_t coreclr_cache;
|
||||
if (!package_cache_dir.empty())
|
||||
// App/FX main dir or standalone app dir.
|
||||
trace::verbose(_X("Probing for CoreCLR in deps directory=[%s]"), deps_dir.c_str());
|
||||
if (coreclr_exists_in_dir(deps_dir))
|
||||
{
|
||||
if (deps->has_coreclr_entry())
|
||||
{
|
||||
const deps_entry_t& entry = deps->get_coreclr_entry();
|
||||
trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in package cache=[%s]"), entry.library_name.c_str(), entry.library_version.c_str(), package_cache_dir.c_str());
|
||||
if (entry.to_hash_matched_path(package_cache_dir, &coreclr_cache))
|
||||
{
|
||||
return get_directory(coreclr_cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deps directory: lookup relative path if portable, else look sxs.
|
||||
if (is_portable)
|
||||
{
|
||||
pal::string_t coreclr_portable;
|
||||
if (deps->has_coreclr_entry())
|
||||
{
|
||||
const deps_entry_t& entry = deps->get_coreclr_entry();
|
||||
trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in portable app dir=[%s]"), entry.library_name.c_str(), entry.library_version.c_str(), deps_dir.c_str());
|
||||
if (entry.to_full_path(deps_dir, &coreclr_portable))
|
||||
{
|
||||
return get_directory(coreclr_portable);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// App main dir or standalone app dir.
|
||||
trace::verbose(_X("Probing for CoreCLR in deps directory=[%s]"), deps_dir.c_str());
|
||||
if (coreclr_exists_in_dir(deps_dir))
|
||||
{
|
||||
return deps_dir;
|
||||
}
|
||||
}
|
||||
|
||||
// Packages dir.
|
||||
pal::string_t coreclr_package;
|
||||
if (!package_dir.empty())
|
||||
{
|
||||
if (deps->has_coreclr_entry())
|
||||
{
|
||||
const deps_entry_t& entry = deps->get_coreclr_entry();
|
||||
trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in packages dir=[%s]"), entry.library_name.c_str(), entry.library_version.c_str(), package_dir.c_str());
|
||||
if (entry.to_full_path(package_dir, &coreclr_package))
|
||||
{
|
||||
return get_directory(coreclr_package);
|
||||
}
|
||||
}
|
||||
return deps_dir;
|
||||
}
|
||||
|
||||
return pal::string_t();
|
||||
};
|
||||
|
||||
trace::info(_X("--- Starting CoreCLR Proble from app deps.json"));
|
||||
pal::string_t clr_dir = process_coreclr(m_portable, app_dir, m_deps.get());
|
||||
trace::info(_X("-- Starting CoreCLR Probe from app deps.json"));
|
||||
pal::string_t clr_dir = process_coreclr(m_portable, m_app_dir, m_deps.get());
|
||||
if (clr_dir.empty() && m_portable)
|
||||
{
|
||||
trace::info(_X("--- Starting CoreCLR Proble from FX deps.json"));
|
||||
trace::info(_X("-- Starting CoreCLR Probe from FX deps.json"));
|
||||
clr_dir = process_coreclr(false, m_fx_dir, m_fx_deps.get());
|
||||
}
|
||||
if (!clr_dir.empty())
|
||||
|
@ -230,44 +379,14 @@ pal::string_t deps_resolver_t::resolve_coreclr_dir(
|
|||
return pal::string_t();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Resolve the TPA list order.
|
||||
//
|
||||
// Description:
|
||||
// First, add mscorlib to the TPA. Then for each deps entry, check if they
|
||||
// are serviced. If they are not serviced, then look if they are present
|
||||
// app local. Worst case, default to the primary and seconday package
|
||||
// caches. Finally, for cases where deps file may not be present or if deps
|
||||
// did not have an entry for an app local assembly, just use them from the
|
||||
// app dir in the TPA path.
|
||||
//
|
||||
// Parameters:
|
||||
// app_dir - The application local directory
|
||||
// package_dir - The directory path to where packages are restored
|
||||
// package_cache_dir - The directory path to secondary cache for packages
|
||||
// clr_dir - The directory where the host loads the CLR
|
||||
//
|
||||
// Returns:
|
||||
// output - Pointer to a string that will hold the resolved TPA paths
|
||||
//
|
||||
void deps_resolver_t::resolve_tpa_list(
|
||||
const pal::string_t& app_dir,
|
||||
const pal::string_t& package_dir,
|
||||
const pal::string_t& package_cache_dir,
|
||||
const pal::string_t& clr_dir,
|
||||
pal::string_t* output)
|
||||
{
|
||||
const std::vector<deps_entry_t> empty(0);
|
||||
|
||||
pal::string_t ni_package_cache_dir;
|
||||
if (!package_cache_dir.empty())
|
||||
{
|
||||
ni_package_cache_dir = package_cache_dir;
|
||||
append_path(&ni_package_cache_dir, get_arch());
|
||||
}
|
||||
|
||||
// Obtain the local assemblies in the app dir.
|
||||
get_dir_assemblies(app_dir, _X("local"), &m_local_assemblies);
|
||||
get_dir_assemblies(m_app_dir, _X("local"), &m_local_assemblies);
|
||||
if (m_portable)
|
||||
{
|
||||
// For portable also obtain FX dir assemblies.
|
||||
|
@ -276,9 +395,8 @@ void deps_resolver_t::resolve_tpa_list(
|
|||
|
||||
std::set<pal::string_t> items;
|
||||
|
||||
auto process_entry = [&](bool is_portable, deps_json_t* deps, const dir_assemblies_t& dir_assemblies, const deps_entry_t& entry)
|
||||
auto process_entry = [&](const pal::string_t& deps_dir, deps_json_t* deps, const dir_assemblies_t& dir_assemblies, const deps_entry_t& entry)
|
||||
{
|
||||
// Is this asset a "runtime" type?
|
||||
if (items.count(entry.asset_name))
|
||||
{
|
||||
return;
|
||||
|
@ -288,42 +406,31 @@ void deps_resolver_t::resolve_tpa_list(
|
|||
|
||||
trace::info(_X("Processing TPA for deps entry [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());
|
||||
|
||||
// Is this a serviceable entry and is there an entry in the servicing index?
|
||||
if (entry.is_serviceable && entry.library_type == _X("Package") &&
|
||||
m_svc.find_redirection(entry.library_name, entry.library_version, entry.relative_path, &candidate))
|
||||
// Try to probe from the shared locations.
|
||||
if (probe_entry_in_configs(entry, &candidate))
|
||||
{
|
||||
add_tpa_asset(entry.asset_name, candidate, &items, output);
|
||||
}
|
||||
// Is an NI image for this entry present in the secondary package cache?
|
||||
else if (entry.to_hash_matched_path(ni_package_cache_dir, &candidate))
|
||||
// The rid asset should be picked up from app relative subpath.
|
||||
else if (entry.is_rid_specific && entry.to_rel_path(deps_dir, &candidate))
|
||||
{
|
||||
add_tpa_asset(entry.asset_name, candidate, &items, output);
|
||||
}
|
||||
// Is this entry present in the secondary package cache? (note: no .ni extension)
|
||||
else if (entry.to_hash_matched_path(package_cache_dir, &candidate))
|
||||
{
|
||||
add_tpa_asset(entry.asset_name, candidate, &items, output);
|
||||
}
|
||||
// The app is portable so the rid asset should be picked up from relative subpath.
|
||||
else if (is_portable && deps->try_ni(entry).to_rel_path(app_dir, &candidate))
|
||||
{
|
||||
add_tpa_asset(entry.asset_name, candidate, &items, output);
|
||||
}
|
||||
// The app is portable, but there could be a rid-less asset in the app base.
|
||||
// The rid-less asset should be picked up from the app base.
|
||||
else if (dir_assemblies.count(entry.asset_name))
|
||||
{
|
||||
add_tpa_asset(entry.asset_name, dir_assemblies.find(entry.asset_name)->second, &items, output);
|
||||
}
|
||||
// Is this entry present in the package restore dir?
|
||||
else if (!package_dir.empty() && deps->try_ni(entry).to_full_path(package_dir, &candidate))
|
||||
else
|
||||
{
|
||||
add_tpa_asset(entry.asset_name, candidate, &items, output);
|
||||
// FIXME: Consider this error as a fail fast?
|
||||
trace::verbose(_X("Error: Could not resolve path to assembly: [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
const auto& deps_entries = m_deps->get_entries(deps_entry_t::asset_types::runtime);
|
||||
std::for_each(deps_entries.begin(), deps_entries.end(), [&](const deps_entry_t& entry) {
|
||||
process_entry(m_portable, m_deps.get(), m_local_assemblies, entry);
|
||||
process_entry(m_app_dir, m_deps.get(), m_local_assemblies, entry);
|
||||
});
|
||||
|
||||
// Finally, if the deps file wasn't present or has missing entries, then
|
||||
|
@ -335,7 +442,7 @@ void deps_resolver_t::resolve_tpa_list(
|
|||
|
||||
const auto& fx_entries = m_portable ? m_fx_deps->get_entries(deps_entry_t::asset_types::runtime) : empty;
|
||||
std::for_each(fx_entries.begin(), fx_entries.end(), [&](const deps_entry_t& entry) {
|
||||
process_entry(false, m_fx_deps.get(), m_fx_assemblies, entry);
|
||||
process_entry(m_fx_dir, m_fx_deps.get(), m_fx_assemblies, entry);
|
||||
});
|
||||
|
||||
for (const auto& kv : m_fx_assemblies)
|
||||
|
@ -366,14 +473,12 @@ void deps_resolver_t::resolve_tpa_list(
|
|||
// output - Pointer to a string that will hold the resolved lookup dirs
|
||||
//
|
||||
void deps_resolver_t::resolve_probe_dirs(
|
||||
const pal::string_t& asset_type,
|
||||
const pal::string_t& app_dir,
|
||||
const pal::string_t& package_dir,
|
||||
const pal::string_t& package_cache_dir,
|
||||
deps_entry_t::asset_types asset_type,
|
||||
const pal::string_t& clr_dir,
|
||||
pal::string_t* output)
|
||||
{
|
||||
assert(asset_type == _X("resources") || asset_type == _X("native"));
|
||||
bool is_resources = asset_type == deps_entry_t::asset_types::resources;
|
||||
assert(is_resources || asset_type == deps_entry_t::asset_types::native);
|
||||
|
||||
// For resources assemblies, we need to provide the base directory of the resources path.
|
||||
// For example: .../Foo/en-US/Bar.dll, then, the resolved path is .../Foo
|
||||
|
@ -384,51 +489,31 @@ void deps_resolver_t::resolve_probe_dirs(
|
|||
std::function<pal::string_t(const pal::string_t&)> native = [] (const pal::string_t& str) {
|
||||
return get_directory(str);
|
||||
};
|
||||
std::function<pal::string_t(const pal::string_t&)>& action = (asset_type == _X("resources")) ? resources : native;
|
||||
deps_entry_t::asset_types entry_type = (asset_type == _X("resources")) ? deps_entry_t::asset_types::resources : deps_entry_t::asset_types::native;
|
||||
std::function<pal::string_t(const pal::string_t&)>& action = is_resources ? resources : native;
|
||||
std::set<pal::string_t> items;
|
||||
|
||||
std::vector<deps_entry_t> empty(0);
|
||||
const auto& entries = m_deps->get_entries(entry_type);
|
||||
const auto& fx_entries = m_portable ? m_fx_deps->get_entries(entry_type) : empty;
|
||||
|
||||
// Fill the "output" with serviced DLL directories if they are serviceable
|
||||
// and have an entry present.
|
||||
auto add_serviced_entry = [&](const deps_entry_t& entry)
|
||||
{
|
||||
pal::string_t redirection_path;
|
||||
if (entry.is_serviceable && entry.library_type == _X("Package") &&
|
||||
m_svc.find_redirection(entry.library_name, entry.library_version, entry.relative_path, &redirection_path))
|
||||
{
|
||||
add_unique_path(asset_type, action(redirection_path), &items, output);
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each(entries.begin(), entries.end(), add_serviced_entry);
|
||||
std::for_each(fx_entries.begin(), fx_entries.end(), add_serviced_entry);
|
||||
const auto& entries = m_deps->get_entries(asset_type);
|
||||
const auto& fx_entries = m_portable ? m_fx_deps->get_entries(asset_type) : empty;
|
||||
|
||||
pal::string_t candidate;
|
||||
|
||||
// Take care of the secondary cache path
|
||||
if (!package_cache_dir.empty())
|
||||
auto add_package_cache_entry = [&](const deps_entry_t& entry)
|
||||
{
|
||||
auto add_package_cache_entry = [&](const deps_entry_t& entry)
|
||||
if (probe_entry_in_configs(entry, &candidate))
|
||||
{
|
||||
if (entry.to_hash_matched_path(package_cache_dir, &candidate))
|
||||
{
|
||||
add_unique_path(asset_type, action(candidate), &items, output);
|
||||
}
|
||||
};
|
||||
std::for_each(entries.begin(), entries.end(), add_package_cache_entry);
|
||||
std::for_each(fx_entries.begin(), fx_entries.end(), add_package_cache_entry);
|
||||
}
|
||||
add_unique_path(asset_type, action(candidate), &items, output);
|
||||
}
|
||||
};
|
||||
std::for_each(entries.begin(), entries.end(), add_package_cache_entry);
|
||||
std::for_each(fx_entries.begin(), fx_entries.end(), add_package_cache_entry);
|
||||
|
||||
// For portable path, the app relative directory must be used.
|
||||
// For portable rid specific assets, the app relative directory must be used.
|
||||
if (m_portable)
|
||||
{
|
||||
std::for_each(entries.begin(), entries.end(), [&](const deps_entry_t& entry)
|
||||
{
|
||||
if (entry.asset_type == asset_type && entry.to_rel_path(app_dir, &candidate))
|
||||
if (entry.is_rid_specific && entry.asset_type == asset_type && entry.to_rel_path(m_app_dir, &candidate))
|
||||
{
|
||||
add_unique_path(asset_type, action(candidate), &items, output);
|
||||
}
|
||||
|
@ -436,7 +521,7 @@ void deps_resolver_t::resolve_probe_dirs(
|
|||
}
|
||||
|
||||
// App local path
|
||||
add_unique_path(asset_type, app_dir, &items, output);
|
||||
add_unique_path(asset_type, m_app_dir, &items, output);
|
||||
|
||||
// FX path if present
|
||||
if (!m_fx_dir.empty())
|
||||
|
@ -444,20 +529,6 @@ void deps_resolver_t::resolve_probe_dirs(
|
|||
add_unique_path(asset_type, m_fx_dir, &items, output);
|
||||
}
|
||||
|
||||
// Take care of the package restore path
|
||||
if (!package_dir.empty())
|
||||
{
|
||||
auto add_packages_entry = [&](const deps_entry_t& entry)
|
||||
{
|
||||
if (entry.asset_type == asset_type && entry.to_full_path(package_dir, &candidate))
|
||||
{
|
||||
add_unique_path(asset_type, action(candidate), &items, output);
|
||||
}
|
||||
};
|
||||
std::for_each(entries.begin(), entries.end(), add_packages_entry);
|
||||
std::for_each(fx_entries.begin(), fx_entries.end(), add_packages_entry);
|
||||
}
|
||||
|
||||
// CLR path
|
||||
add_unique_path(asset_type, clr_dir, &items, output);
|
||||
}
|
||||
|
@ -475,15 +546,10 @@ void deps_resolver_t::resolve_probe_dirs(
|
|||
// resolved path ordering.
|
||||
//
|
||||
//
|
||||
bool deps_resolver_t::resolve_probe_paths(
|
||||
const pal::string_t& app_dir,
|
||||
const pal::string_t& package_dir,
|
||||
const pal::string_t& package_cache_dir,
|
||||
const pal::string_t& clr_dir,
|
||||
probe_paths_t* probe_paths)
|
||||
bool deps_resolver_t::resolve_probe_paths(const pal::string_t& clr_dir, probe_paths_t* probe_paths)
|
||||
{
|
||||
resolve_tpa_list(app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->tpa);
|
||||
resolve_probe_dirs(_X("native"), app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->native);
|
||||
resolve_probe_dirs(_X("resources"), app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->resources);
|
||||
resolve_tpa_list(clr_dir, &probe_paths->tpa);
|
||||
resolve_probe_dirs(deps_entry_t::asset_types::native, clr_dir, &probe_paths->native);
|
||||
resolve_probe_dirs(deps_entry_t::asset_types::resources, clr_dir, &probe_paths->resources);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
#include <vector>
|
||||
|
||||
#include "pal.h"
|
||||
#include "args.h"
|
||||
#include "trace.h"
|
||||
#include "deps_format.h"
|
||||
#include "deps_entry.h"
|
||||
#include "servicing_index.h"
|
||||
#include "runtime_config.h"
|
||||
|
||||
// Probe paths to be resolved for ordering
|
||||
|
@ -24,18 +24,20 @@ struct probe_paths_t
|
|||
class deps_resolver_t
|
||||
{
|
||||
public:
|
||||
deps_resolver_t(const pal::string_t& fx_dir, const runtime_config_t* config, const arguments_t& args)
|
||||
: m_svc(args.dotnet_servicing)
|
||||
, m_fx_dir(fx_dir)
|
||||
deps_resolver_t(const corehost_init_t* init, const runtime_config_t& config, const arguments_t& args)
|
||||
// Important: FX dir should come from "init" than "config",
|
||||
// since the host could be launching from FX dir.
|
||||
: m_fx_dir(init->fx_dir())
|
||||
, m_app_dir(args.app_dir)
|
||||
, m_coreclr_index(-1)
|
||||
, m_portable(config->get_portable())
|
||||
, m_portable(config.get_portable())
|
||||
, m_deps(nullptr)
|
||||
, m_fx_deps(nullptr)
|
||||
{
|
||||
m_deps_file = args.deps_path;
|
||||
if (m_portable)
|
||||
{
|
||||
m_fx_deps_file = get_fx_deps(fx_dir, config->get_fx_name());
|
||||
m_fx_deps_file = get_fx_deps(m_fx_dir, config.get_fx_name());
|
||||
trace::verbose(_X("Using %s FX deps file"), m_fx_deps_file.c_str());
|
||||
trace::verbose(_X("Using %s deps file"), m_deps_file.c_str());
|
||||
m_fx_deps = std::unique_ptr<deps_json_t>(new deps_json_t(false, m_fx_deps_file));
|
||||
|
@ -45,22 +47,25 @@ public:
|
|||
{
|
||||
m_deps = std::unique_ptr<deps_json_t>(new deps_json_t(false, m_deps_file));
|
||||
}
|
||||
}
|
||||
|
||||
setup_additional_probes(args.probe_paths);
|
||||
setup_probe_config(init, config, args);
|
||||
}
|
||||
|
||||
bool valid() { return m_deps->is_valid() && (!m_portable || m_fx_deps->is_valid()); }
|
||||
|
||||
void setup_probe_config(
|
||||
const corehost_init_t* init,
|
||||
const runtime_config_t& config,
|
||||
const arguments_t& args);
|
||||
|
||||
void setup_additional_probes(const std::vector<pal::string_t>& probe_paths);
|
||||
|
||||
bool resolve_probe_paths(
|
||||
const pal::string_t& app_dir,
|
||||
const pal::string_t& package_dir,
|
||||
const pal::string_t& package_cache_dir,
|
||||
const pal::string_t& clr_dir,
|
||||
probe_paths_t* probe_paths);
|
||||
|
||||
pal::string_t resolve_coreclr_dir(
|
||||
const pal::string_t& app_dir,
|
||||
const pal::string_t& package_dir,
|
||||
const pal::string_t& package_cache_dir);
|
||||
pal::string_t resolve_coreclr_dir();
|
||||
|
||||
const pal::string_t& get_fx_deps_file() const
|
||||
{
|
||||
|
@ -83,18 +88,12 @@ private:
|
|||
|
||||
// Resolve order for TPA lookup.
|
||||
void resolve_tpa_list(
|
||||
const pal::string_t& app_dir,
|
||||
const pal::string_t& package_dir,
|
||||
const pal::string_t& package_cache_dir,
|
||||
const pal::string_t& clr_dir,
|
||||
pal::string_t* output);
|
||||
|
||||
// Resolve order for culture and native DLL lookup.
|
||||
void resolve_probe_dirs(
|
||||
const pal::string_t& asset_type,
|
||||
const pal::string_t& app_dir,
|
||||
const pal::string_t& package_dir,
|
||||
const pal::string_t& package_cache_dir,
|
||||
deps_entry_t::asset_types asset_type,
|
||||
const pal::string_t& clr_dir,
|
||||
pal::string_t* output);
|
||||
|
||||
|
@ -104,18 +103,32 @@ private:
|
|||
const pal::string_t& dir_name,
|
||||
std::unordered_map<pal::string_t, pal::string_t>* dir_assemblies);
|
||||
|
||||
// Servicing index to resolve serviced assembly paths.
|
||||
servicing_index_t m_svc;
|
||||
// Probe entry in probe configurations.
|
||||
bool probe_entry_in_configs(
|
||||
const deps_entry_t& entry,
|
||||
pal::string_t* candidate);
|
||||
|
||||
// Try auto roll forward, if not return entry in probe dir.
|
||||
bool try_roll_forward(
|
||||
const deps_entry_t& entry,
|
||||
const pal::string_t& probe_dir,
|
||||
pal::string_t* candidate);
|
||||
|
||||
// Framework deps file.
|
||||
pal::string_t m_fx_dir;
|
||||
|
||||
pal::string_t m_app_dir;
|
||||
|
||||
// Map of simple name -> full path of local/fx assemblies populated
|
||||
// in priority order of their extensions.
|
||||
typedef std::unordered_map<pal::string_t, pal::string_t> dir_assemblies_t;
|
||||
dir_assemblies_t m_local_assemblies;
|
||||
dir_assemblies_t m_fx_assemblies;
|
||||
|
||||
std::unordered_map<pal::string_t, pal::string_t> m_roll_forward_cache;
|
||||
|
||||
pal::string_t m_package_cache;
|
||||
|
||||
// Special entry for coreclr in the deps entries
|
||||
int m_coreclr_index;
|
||||
|
||||
|
@ -131,9 +144,15 @@ private:
|
|||
// Deps files for the app
|
||||
std::unique_ptr<deps_json_t> m_deps;
|
||||
|
||||
// Various probe configurations.
|
||||
std::vector<probe_config_t> m_probes;
|
||||
|
||||
// Is the deps file valid
|
||||
bool m_deps_valid;
|
||||
|
||||
// Fallback probe dir
|
||||
std::vector<pal::string_t> m_additional_probes;
|
||||
|
||||
// Is the deps file portable app?
|
||||
bool m_portable;
|
||||
};
|
||||
|
|
|
@ -25,13 +25,13 @@ set(SOURCES
|
|||
../json/casablanca/src/json/json_parsing.cpp
|
||||
../json/casablanca/src/json/json_serialization.cpp
|
||||
../json/casablanca/src/utilities/asyncrt_utils.cpp
|
||||
../fxr/fx_ver.cpp
|
||||
../args.cpp
|
||||
../hostpolicy.cpp
|
||||
../coreclr.cpp
|
||||
../deps_resolver.cpp
|
||||
../deps_format.cpp
|
||||
../deps_entry.cpp
|
||||
../servicing_index.cpp)
|
||||
../deps_entry.cpp)
|
||||
|
||||
|
||||
if(WIN32)
|
||||
|
|
|
@ -263,13 +263,13 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[])
|
|||
{
|
||||
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(""), _X(""), fx_dir, host_mode_t::muxer, &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(""), _X(""), _X(""), host_mode_t::muxer, &config);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -321,11 +321,12 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[])
|
|||
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_path, fx_dir, host_mode_t::muxer, &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
|
||||
|
@ -344,7 +345,7 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[])
|
|||
}
|
||||
impl_dir = get_directory(candidate);
|
||||
}
|
||||
corehost_init_t init(deps_file, probe_path, _X(""), host_mode_t::muxer, &config);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -380,13 +381,13 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[])
|
|||
{
|
||||
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(""), _X(""), fx_dir, host_mode_t::muxer, &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(""), _X(""), _X(""), host_mode_t::muxer, &config);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ bool fx_ver_t::operator >(const fx_ver_t& b) const
|
|||
return compare(*this, b) > 0;
|
||||
}
|
||||
|
||||
pal::string_t fx_ver_t::as_str()
|
||||
pal::string_t fx_ver_t::as_str() const
|
||||
{
|
||||
pal::stringstream_t stream;
|
||||
stream << m_major << _X(".") << m_minor << _X(".") << m_patch;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// 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.
|
||||
|
||||
#ifndef __FX_VER_H__
|
||||
#define __FX_VER_H__
|
||||
|
||||
#include "pal.h"
|
||||
|
||||
// Note: This is not SemVer (esp., in comparing pre-release part, fx_ver_t does not
|
||||
|
@ -11,17 +14,17 @@ struct fx_ver_t
|
|||
fx_ver_t(int major, int minor, int patch, const pal::string_t& pre);
|
||||
fx_ver_t(int major, int minor, int patch, const pal::string_t& pre, const pal::string_t& build);
|
||||
|
||||
int get_major() { return m_major; }
|
||||
int get_minor() { return m_minor; }
|
||||
int get_patch() { return m_patch; }
|
||||
int get_major() const { return m_major; }
|
||||
int get_minor() const { return m_minor; }
|
||||
int get_patch() const { return m_patch; }
|
||||
|
||||
void set_major(int m) { m_major = m; }
|
||||
void set_minor(int m) { m_minor = m; }
|
||||
void set_patch(int p) { m_patch = p; }
|
||||
|
||||
bool is_prerelease() { return !m_pre.empty(); }
|
||||
bool is_prerelease() const { return !m_pre.empty(); }
|
||||
|
||||
pal::string_t as_str();
|
||||
pal::string_t as_str() const;
|
||||
|
||||
bool operator ==(const fx_ver_t& b) const;
|
||||
bool operator !=(const fx_ver_t& b) const;
|
||||
|
@ -40,3 +43,4 @@ private:
|
|||
static int compare(const fx_ver_t&a, const fx_ver_t& b);
|
||||
};
|
||||
|
||||
#endif // __FX_VER_H__
|
|
@ -6,6 +6,7 @@
|
|||
#include "pal.h"
|
||||
#include "utils.h"
|
||||
#include "libhost.h"
|
||||
#include "fx_ver.h"
|
||||
#include "fx_muxer.h"
|
||||
#include "error_codes.h"
|
||||
|
||||
|
@ -76,9 +77,13 @@ int execute_app(
|
|||
bool hostpolicy_exists_in_svc(pal::string_t* resolved_dir)
|
||||
{
|
||||
pal::string_t svc_dir;
|
||||
if (!pal::getenv(_X("DOTNET_SERVICING"), &svc_dir))
|
||||
pal::get_default_extensions_directory(&svc_dir);
|
||||
|
||||
pal::string_t version = _STRINGIFY(HOST_POLICY_PKG_VER);
|
||||
|
||||
fx_ver_t lib_ver(-1, -1, -1);
|
||||
if (!fx_ver_t::parse(version, &lib_ver, false))
|
||||
{
|
||||
trace::verbose(_X("Servicing root doesn't exist"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -90,14 +95,13 @@ bool hostpolicy_exists_in_svc(pal::string_t* resolved_dir)
|
|||
|
||||
pal::string_t path = svc_dir;
|
||||
append_path(&path, _STRINGIFY(HOST_POLICY_PKG_NAME));
|
||||
append_path(&path, _STRINGIFY(HOST_POLICY_PKG_VER));
|
||||
|
||||
pal::string_t max_ver;
|
||||
try_patch_roll_forward_in_dir(path, lib_ver, &max_ver, false);
|
||||
|
||||
append_path(&path, max_ver.c_str());
|
||||
append_path(&path, rel_dir.c_str());
|
||||
append_path(&path, LIBHOSTPOLICY_NAME);
|
||||
if (!pal::realpath(&path))
|
||||
{
|
||||
trace::verbose(_X("Servicing root ::realpath(%s) doesn't exist"), path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (library_exists_in_dir(path, LIBHOSTPOLICY_NAME, nullptr))
|
||||
{
|
||||
resolved_dir->assign(path);
|
||||
|
@ -127,7 +131,7 @@ SHARED_API int hostfxr_main(const int argc, const pal::char_t* argv[])
|
|||
case split_fx:
|
||||
{
|
||||
trace::info(_X("Host operating in split mode; own dir=[%s]"), own_dir.c_str());
|
||||
corehost_init_t init(_X(""), _X(""), own_dir, host_mode_t::split_fx, nullptr);
|
||||
corehost_init_t init(_X(""), std::vector<pal::string_t>(), own_dir, host_mode_t::split_fx, nullptr);
|
||||
return execute_app(own_dir, &init, argc, argv);
|
||||
}
|
||||
|
||||
|
@ -136,7 +140,7 @@ SHARED_API int hostfxr_main(const int argc, const pal::char_t* argv[])
|
|||
trace::info(_X("Host operating from standalone app dir %s"), own_dir.c_str());
|
||||
|
||||
pal::string_t svc_dir;
|
||||
corehost_init_t init(_X(""), _X(""), _X(""), host_mode_t::standalone, nullptr);
|
||||
corehost_init_t init(_X(""), std::vector<pal::string_t>(), _X(""), host_mode_t::standalone, nullptr);
|
||||
return execute_app(
|
||||
hostpolicy_exists_in_svc(&svc_dir) ? svc_dir : own_dir, &init, argc, argv);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ corehost_init_t* g_init = nullptr;
|
|||
int run(const corehost_init_t* init, const runtime_config_t& config, const arguments_t& args)
|
||||
{
|
||||
// Load the deps resolver
|
||||
deps_resolver_t resolver(init->fx_dir(), &config, args);
|
||||
deps_resolver_t resolver(init, config, args);
|
||||
|
||||
if (!resolver.valid())
|
||||
{
|
||||
|
@ -26,15 +26,7 @@ int run(const corehost_init_t* init, const runtime_config_t& config, const argum
|
|||
return StatusCode::ResolverInitFailure;
|
||||
}
|
||||
|
||||
// Add packages directory
|
||||
pal::string_t packages_dir = init->probe_dir();
|
||||
if (packages_dir.empty() || !pal::directory_exists(packages_dir))
|
||||
{
|
||||
(void)pal::get_default_packages_directory(&packages_dir);
|
||||
}
|
||||
trace::info(_X("Package directory: %s"), packages_dir.empty() ? _X("not specified") : packages_dir.c_str());
|
||||
|
||||
pal::string_t clr_path = resolver.resolve_coreclr_dir(args.app_dir, packages_dir, args.dotnet_packages_cache);
|
||||
pal::string_t clr_path = resolver.resolve_coreclr_dir();
|
||||
if (clr_path.empty() || !pal::realpath(&clr_path))
|
||||
{
|
||||
trace::error(_X("Could not resolve coreclr path"));
|
||||
|
@ -46,7 +38,7 @@ int run(const corehost_init_t* init, const runtime_config_t& config, const argum
|
|||
}
|
||||
|
||||
probe_paths_t probe_paths;
|
||||
if (!resolver.resolve_probe_paths(args.app_dir, packages_dir, args.dotnet_packages_cache, clr_path, &probe_paths))
|
||||
if (!resolver.resolve_probe_paths(clr_path, &probe_paths))
|
||||
{
|
||||
return StatusCode::ResolverResolveFailure;
|
||||
}
|
||||
|
@ -196,6 +188,11 @@ int run(const corehost_init_t* init, const runtime_config_t& config, const argum
|
|||
SHARED_API int corehost_load(corehost_init_t* init)
|
||||
{
|
||||
g_init = init;
|
||||
if (g_init->version() != corehost_init_t::s_version)
|
||||
{
|
||||
trace::error(_X("The structure of init data has changed, do not know how to interpret it"));
|
||||
return StatusCode::LibHostInitFailure;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -220,12 +217,15 @@ SHARED_API int corehost_main(const int argc, const pal::char_t* argv[])
|
|||
|
||||
trace::info(_X("Host mode: %d"), g_init->host_mode());
|
||||
trace::info(_X("Deps file: %s"), g_init->deps_file().c_str());
|
||||
trace::info(_X("Probe dir: %s"), g_init->probe_dir().c_str());
|
||||
for (const auto& probe : g_init->probe_paths())
|
||||
{
|
||||
trace::info(_X("Additional probe dir: %s"), probe.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Take care of arguments
|
||||
arguments_t args;
|
||||
if (!parse_arguments(g_init->deps_file(), g_init->probe_dir(), g_init->host_mode(), argc, argv, &args))
|
||||
if (!parse_arguments(g_init->deps_file(), g_init->probe_paths(), g_init->host_mode(), argc, argv, &args))
|
||||
{
|
||||
return StatusCode::LibHostInvalidArgs;
|
||||
}
|
||||
|
|
|
@ -59,3 +59,36 @@ host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
pal::string_t path = cur_dir;
|
||||
|
||||
if (trace::is_enabled())
|
||||
{
|
||||
pal::string_t start_str = start_ver.as_str();
|
||||
trace::verbose(_X("Reading roll forward candidates in dir [%s] for version [%s]"), path.c_str(), start_str.c_str());
|
||||
}
|
||||
|
||||
pal::string_t maj_min_star = pal::to_string(start_ver.get_major()) + _X(".") + pal::to_string(start_ver.get_minor()) + _X("*");
|
||||
|
||||
std::vector<pal::string_t> list;
|
||||
pal::readdir(path, maj_min_star, &list);
|
||||
|
||||
fx_ver_t max_ver = start_ver;
|
||||
fx_ver_t ver(-1, -1, -1);
|
||||
for (const auto& str : list)
|
||||
{
|
||||
trace::verbose(_X("Considering roll forward candidate version [%s]"), str.c_str());
|
||||
if (fx_ver_t::parse(str, &ver, only_production))
|
||||
{
|
||||
max_ver = std::max(ver, max_ver);
|
||||
}
|
||||
}
|
||||
max_str->assign(max_ver.as_str());
|
||||
|
||||
if (trace::is_enabled())
|
||||
{
|
||||
pal::string_t start_str = start_ver.as_str();
|
||||
trace::verbose(_X("Roll forwarded [%s] -> [%s] in [%s]"), start_str.c_str(), max_str->c_str(), path.c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#ifndef __LIBHOST_H__
|
||||
#define __LIBHOST_H__
|
||||
|
||||
#include "fx_ver.h"
|
||||
|
||||
enum host_mode_t
|
||||
{
|
||||
invalid = 0,
|
||||
|
@ -12,11 +14,21 @@ enum host_mode_t
|
|||
split_fx
|
||||
};
|
||||
|
||||
class fx_ver_t;
|
||||
class runtime_config_t;
|
||||
|
||||
class corehost_init_t
|
||||
{
|
||||
const pal::string_t m_probe_path;
|
||||
// // WARNING // WARNING // WARNING // WARNING // WARNING // WARNING //
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// !! If you change this class layout increment the s_version field; !!
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
public:
|
||||
static const int s_version = 0x8002;
|
||||
private:
|
||||
int m_version;
|
||||
std::vector<pal::string_t> m_probe_paths;
|
||||
const pal::string_t m_deps_file;
|
||||
const pal::string_t m_fx_dir;
|
||||
host_mode_t m_host_mode;
|
||||
|
@ -24,15 +36,16 @@ class corehost_init_t
|
|||
public:
|
||||
corehost_init_t(
|
||||
const pal::string_t& deps_file,
|
||||
const pal::string_t& probe_path,
|
||||
const std::vector<pal::string_t>& probe_paths,
|
||||
const pal::string_t& fx_dir,
|
||||
const host_mode_t mode,
|
||||
const runtime_config_t* runtime_config)
|
||||
: m_fx_dir(fx_dir)
|
||||
, m_runtime_config(runtime_config)
|
||||
, m_deps_file(deps_file)
|
||||
, m_probe_path(probe_path)
|
||||
, m_probe_paths(probe_paths)
|
||||
, m_host_mode(mode)
|
||||
, m_version(s_version)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -46,9 +59,9 @@ public:
|
|||
return m_deps_file;
|
||||
}
|
||||
|
||||
const pal::string_t& probe_dir() const
|
||||
const std::vector<pal::string_t>& probe_paths() const
|
||||
{
|
||||
return m_probe_path;
|
||||
return m_probe_paths;
|
||||
}
|
||||
|
||||
const pal::string_t& fx_dir() const
|
||||
|
@ -60,9 +73,16 @@ public:
|
|||
{
|
||||
return m_runtime_config;
|
||||
}
|
||||
|
||||
int version() const
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
};
|
||||
|
||||
pal::string_t get_runtime_config_from_file(const pal::string_t& 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);
|
||||
|
||||
#endif // __LIBHOST_H__
|
|
@ -38,6 +38,29 @@ bool runtime_config_t::parse_opts(const json_value& opts)
|
|||
}
|
||||
}
|
||||
|
||||
auto probe_paths = opts_obj.find(_X("additionalProbingPaths"));
|
||||
if (probe_paths != opts_obj.end())
|
||||
{
|
||||
if (probe_paths->second.is_string())
|
||||
{
|
||||
m_probe_paths.push_back(probe_paths->second.as_string());
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& arr = probe_paths->second.as_array();
|
||||
for (const auto& str : arr)
|
||||
{
|
||||
m_probe_paths.push_back(str.as_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto roll_fwd = opts_obj.find(_X("applyPatches"));
|
||||
if (roll_fwd != opts_obj.end())
|
||||
{
|
||||
m_fx_roll_fwd = roll_fwd->second.as_bool();
|
||||
}
|
||||
|
||||
auto framework = opts_obj.find(_X("framework"));
|
||||
if (framework == opts_obj.end())
|
||||
{
|
||||
|
@ -49,14 +72,6 @@ bool runtime_config_t::parse_opts(const json_value& opts)
|
|||
const auto& fx_obj = framework->second.as_object();
|
||||
m_fx_name = fx_obj.at(_X("name")).as_string();
|
||||
m_fx_ver = fx_obj.at(_X("version")).as_string();
|
||||
|
||||
auto value = fx_obj.find(_X("rollForward"));
|
||||
if (value == fx_obj.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
m_fx_roll_fwd = value->second.as_bool();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -118,6 +133,11 @@ bool runtime_config_t::get_portable() const
|
|||
return m_portable;
|
||||
}
|
||||
|
||||
const std::vector<pal::string_t>& runtime_config_t::get_probe_paths() const
|
||||
{
|
||||
return m_probe_paths;
|
||||
}
|
||||
|
||||
void runtime_config_t::config_kv(std::vector<std::string>* keys, std::vector<std::string>* values) const
|
||||
{
|
||||
for (const auto& kv : m_properties)
|
||||
|
|
|
@ -15,6 +15,7 @@ public:
|
|||
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;
|
||||
bool get_fx_roll_fwd() const;
|
||||
bool get_portable() const;
|
||||
bool parse_opts(const json_value& opts);
|
||||
|
@ -26,6 +27,7 @@ private:
|
|||
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;
|
||||
pal::string_t m_fx_name;
|
||||
pal::string_t m_fx_ver;
|
||||
bool m_fx_roll_fwd;
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
// 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 "trace.h"
|
||||
#include "servicing_index.h"
|
||||
|
||||
static const pal::char_t* DOTNET_SERVICING_INDEX_TXT = _X("dotnet_servicing_index.txt");
|
||||
|
||||
servicing_index_t::servicing_index_t(const pal::string_t& svc_dir)
|
||||
{
|
||||
m_patch_root = svc_dir;
|
||||
if (!m_patch_root.empty())
|
||||
{
|
||||
m_index_file.assign(m_patch_root);
|
||||
append_path(&m_index_file, DOTNET_SERVICING_INDEX_TXT);
|
||||
}
|
||||
m_parsed = m_index_file.empty() || !pal::file_exists(m_index_file);
|
||||
}
|
||||
|
||||
bool servicing_index_t::find_redirection(
|
||||
const pal::string_t& package_name,
|
||||
const pal::string_t& package_version,
|
||||
const pal::string_t& package_relative,
|
||||
pal::string_t* redirection)
|
||||
{
|
||||
ensure_redirections();
|
||||
|
||||
redirection->clear();
|
||||
|
||||
if (m_redirections.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pal::stringstream_t stream;
|
||||
stream << package_name << _X("|") << package_version << _X("|") << package_relative;
|
||||
|
||||
auto iter = m_redirections.find(stream.str());
|
||||
if (iter != m_redirections.end())
|
||||
{
|
||||
pal::string_t ni_root = m_patch_root;
|
||||
append_path(&ni_root, get_arch());
|
||||
|
||||
// First prefer the architecture specific NI image.
|
||||
pal::string_t paths[2] = { ni_root, m_patch_root };
|
||||
for (pal::string_t& full_path : paths)
|
||||
{
|
||||
append_path(&full_path, iter->second.c_str());
|
||||
if (pal::file_exists(full_path))
|
||||
{
|
||||
*redirection = full_path;
|
||||
if (trace::is_enabled())
|
||||
{
|
||||
pal::string_t stream_str = stream.str();
|
||||
trace::verbose(_X("Servicing %s with %s"), stream_str.c_str(), redirection->c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
trace::verbose(_X("Serviced file %s doesn't exist"), full_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (trace::is_enabled())
|
||||
{
|
||||
auto stream_str = stream.str();
|
||||
trace::verbose(_X("Entry %s not serviced or file doesn't exist"), stream_str.c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void servicing_index_t::ensure_redirections()
|
||||
{
|
||||
if (m_parsed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pal::ifstream_t fstream(m_index_file);
|
||||
if (!fstream.good())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pal::stringstream_t sstream;
|
||||
std::string line;
|
||||
while (std::getline(fstream, line))
|
||||
{
|
||||
pal::string_t str;
|
||||
pal::to_palstring(line.c_str(), &str);
|
||||
|
||||
// Can interpret line as "package"?
|
||||
pal::string_t prefix = _X("package|");
|
||||
if (str.find(prefix) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pal::string_t name, version, relative;
|
||||
pal::string_t* tokens[] = { &name, &version, &relative };
|
||||
pal::string_t delim[] = { pal::string_t(_X("|")), pal::string_t(_X("|")), pal::string_t(_X("=")) };
|
||||
|
||||
bool bad_line = false;
|
||||
|
||||
size_t from = prefix.length();
|
||||
for (size_t cur = 0; cur < (sizeof(delim) / sizeof(delim[0])); ++cur)
|
||||
{
|
||||
size_t pos = str.find(delim[cur], from);
|
||||
if (pos == pal::string_t::npos)
|
||||
{
|
||||
bad_line = true;
|
||||
break;
|
||||
}
|
||||
|
||||
tokens[cur]->assign(str.substr(from, pos - from));
|
||||
from = pos + 1;
|
||||
}
|
||||
|
||||
if (bad_line)
|
||||
{
|
||||
trace::error(_X("Invalid line in servicing index. Skipping..."));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save redirection for this package.
|
||||
sstream.str(_X(""));
|
||||
sstream << name << _X("|") << version << _X("|") << relative;
|
||||
|
||||
if (trace::is_enabled())
|
||||
{
|
||||
auto stream_str = sstream.str();
|
||||
trace::verbose(_X("Adding servicing entry %s => %s"), stream_str.c_str(), str.substr(from).c_str());
|
||||
}
|
||||
|
||||
// Store just the filename.
|
||||
pal::string_t redir = str.substr(from);
|
||||
if (_X('/') != DIR_SEPARATOR)
|
||||
{
|
||||
replace_char(&redir, _X('/'), DIR_SEPARATOR);
|
||||
}
|
||||
m_redirections.emplace(sstream.str(), redir);
|
||||
}
|
||||
|
||||
m_parsed = true;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// 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 "utils.h"
|
||||
#include "args.h"
|
||||
|
||||
class servicing_index_t
|
||||
{
|
||||
public:
|
||||
servicing_index_t(const pal::string_t& svc_dir);
|
||||
|
||||
bool find_redirection(const pal::string_t& package_name,
|
||||
const pal::string_t& package_version,
|
||||
const pal::string_t& package_relative,
|
||||
pal::string_t* redirection);
|
||||
|
||||
private:
|
||||
void ensure_redirections();
|
||||
|
||||
std::unordered_map<pal::string_t, pal::string_t> m_redirections;
|
||||
pal::string_t m_patch_root;
|
||||
pal::string_t m_index_file;
|
||||
bool m_parsed;
|
||||
};
|
|
@ -8,6 +8,8 @@ if(WIN32)
|
|||
add_definitions(-D_WIN64=1)
|
||||
endif()
|
||||
add_compile_options($<$<CONFIG:Debug>:-DDEBUG>)
|
||||
add_compile_options($<$<CONFIG:Release>:-DNDEBUG>)
|
||||
add_compile_options($<$<CONFIG:RelWithDebInfo>:-DNDEBUG>)
|
||||
add_compile_options($<$<CONFIG:Debug>:/Od>)
|
||||
add_compile_options(/DEBUG)
|
||||
add_compile_options(/GS)
|
||||
|
|
|
@ -163,11 +163,13 @@ namespace pal
|
|||
bool realpath(string_t* path);
|
||||
bool file_exists(const string_t& path);
|
||||
inline bool directory_exists(const string_t& path) { return file_exists(path); }
|
||||
void readdir(const string_t& path, const string_t& pattern, std::vector<pal::string_t>* list);
|
||||
void readdir(const string_t& path, std::vector<pal::string_t>* list);
|
||||
|
||||
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);
|
||||
|
||||
int xtoi(const char_t* input);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
|
@ -134,6 +134,14 @@ bool pal::get_default_packages_directory(pal::string_t* recv)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool pal::get_default_extensions_directory(string_t* recv)
|
||||
{
|
||||
recv->clear();
|
||||
append_path(recv, _X("opt"));
|
||||
append_path(recv, _X("dotnetextensions"));
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
bool pal::get_own_executable_path(pal::string_t* recv)
|
||||
{
|
||||
|
@ -200,7 +208,7 @@ bool pal::file_exists(const pal::string_t& path)
|
|||
return (::stat(path.c_str(), &buffer) == 0);
|
||||
}
|
||||
|
||||
void pal::readdir(const pal::string_t& path, std::vector<pal::string_t>* list)
|
||||
void pal::readdir(const string_t& path, const string_t& pattern, std::vector<pal::string_t>* list)
|
||||
{
|
||||
assert(list != nullptr);
|
||||
|
||||
|
@ -210,8 +218,13 @@ void pal::readdir(const pal::string_t& path, std::vector<pal::string_t>* list)
|
|||
if (dir != nullptr)
|
||||
{
|
||||
struct dirent* entry = nullptr;
|
||||
while((entry = readdir(dir)) != nullptr)
|
||||
while ((entry = readdir(dir)) != nullptr)
|
||||
{
|
||||
if (fnmatch(pattern.c_str(), entry->d_name, FNM_PATHNAME) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// We are interested in files only
|
||||
switch (entry->d_type)
|
||||
{
|
||||
|
@ -250,3 +263,8 @@ void pal::readdir(const pal::string_t& path, std::vector<pal::string_t>* list)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pal::readdir(const pal::string_t& path, std::vector<pal::string_t>* list)
|
||||
{
|
||||
readdir(path, _X("*"), list);
|
||||
}
|
||||
|
|
|
@ -130,8 +130,27 @@ bool pal::get_default_packages_directory(string_t* recv)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
append_path(&*recv, _X(".nuget"));
|
||||
append_path(&*recv, _X("packages"));
|
||||
append_path(recv, _X(".nuget"));
|
||||
append_path(recv, _X("packages"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pal::get_default_extensions_directory(string_t* recv)
|
||||
{
|
||||
recv->clear();
|
||||
|
||||
// See https://github.com/dotnet/cli/issues/2179
|
||||
#ifdef _TARGET_X86_
|
||||
// In WOW64 mode, PF maps to PFx86.
|
||||
if (!pal::getenv(_X("ProgramFiles"), recv))
|
||||
#elif defined(_TARGET_AMD64_)
|
||||
if (!pal::getenv(_X("ProgramFiles(x86)"), recv))
|
||||
#endif
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
append_path(recv, _X("dotnetextensions"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -231,15 +250,14 @@ bool pal::file_exists(const string_t& path)
|
|||
return found;
|
||||
}
|
||||
|
||||
void pal::readdir(const string_t& path, std::vector<pal::string_t>* list)
|
||||
void pal::readdir(const string_t& path, const string_t& pattern, std::vector<pal::string_t>* list)
|
||||
{
|
||||
assert(list != nullptr);
|
||||
|
||||
std::vector<string_t>& files = *list;
|
||||
|
||||
string_t search_string(path);
|
||||
search_string.push_back(DIR_SEPARATOR);
|
||||
search_string.push_back(L'*');
|
||||
append_path(&search_string, pattern.c_str());
|
||||
|
||||
WIN32_FIND_DATAW data;
|
||||
auto handle = ::FindFirstFileW(search_string.c_str(), &data);
|
||||
|
@ -250,3 +268,8 @@ void pal::readdir(const string_t& path, std::vector<pal::string_t>* list)
|
|||
} while (::FindNextFileW(handle, &data));
|
||||
::FindClose(handle);
|
||||
}
|
||||
|
||||
void pal::readdir(const string_t& path, std::vector<pal::string_t>* list)
|
||||
{
|
||||
pal::readdir(path, _X("*"), list);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue