diff --git a/README.md b/README.md index b60817d4a..5f0ff2628 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Installers |---------|:------:|:------:|:------:|:------:|:------:|:------:| |**Version**|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Ubuntu_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x86_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/OSX_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/CentOS_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/RHEL_x64_Release_version_badge.svg)| |**Installers**|[Download Debian Package](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-ubuntu-x64.latest.deb)|[Download Installer](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x64.latest.exe)|[Download Installer](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x86.latest.exe)|[Download Pkg](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-osx-x64.latest.pkg) |N/A |N/A | -|**Binaries**|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-ubuntu-x64.latest.tar.gz)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x64.latest.zip)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x86.latest.zip)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-osx-x64.latest.tar.gz) |[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-centos-x64.latest.tar.gz)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-rhel-x64.latest.tar.gz) | +|**Binaries**|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-ubuntu-x64.latest.tar.gz)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-win-x64.latest.zip)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-win-x86.latest.zip)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-osx-x64.latest.tar.gz) |[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-centos-x64.latest.tar.gz)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-rhel-x64.latest.tar.gz) | Interested in .NET Core + ASP.NET Core 1.0 RC1 bits? ---------------------------------------------------- diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/TargetConditions/EnvironmentAttribute.cs b/scripts/Microsoft.DotNet.Cli.Build.Framework/TargetConditions/EnvironmentAttribute.cs index 2a9aea581..0a8455e5c 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/TargetConditions/EnvironmentAttribute.cs +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/TargetConditions/EnvironmentAttribute.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Linq; namespace Microsoft.DotNet.Cli.Build.Framework { @@ -13,7 +13,11 @@ namespace Microsoft.DotNet.Cli.Build.Framework { if (string.IsNullOrEmpty(envVar)) { - throw new ArgumentNullException("envVar"); + throw new ArgumentNullException(nameof(envVar)); + } + if (expectedVals == null) + { + throw new ArgumentNullException(nameof(expectedVals)); } _envVar = envVar; @@ -24,15 +28,14 @@ namespace Microsoft.DotNet.Cli.Build.Framework { var actualVal = Environment.GetEnvironmentVariable(_envVar); - foreach (var expectedVal in _expectedVals) + if (_expectedVals.Any()) { - if (string.Equals(actualVal, expectedVal, StringComparison.Ordinal)) - { - return true; - } + return _expectedVals.Any(ev => string.Equals(actualVal, ev, StringComparison.Ordinal)); + } + else + { + return !string.IsNullOrEmpty(actualVal); } - - return false; } } } diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs index 0894ade05..b57ed91fa 100644 --- a/scripts/dotnet-cli-build/PublishTargets.cs +++ b/scripts/dotnet-cli-build/PublishTargets.cs @@ -1,12 +1,9 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Runtime.InteropServices; +using System.Net.Http; +using System.Text; using Microsoft.DotNet.Cli.Build.Framework; -using Microsoft.Extensions.PlatformAbstractions; -using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Storage; -using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.Blob; using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; @@ -36,7 +33,8 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(PrepareTargets.Init), nameof(PublishTargets.InitPublish), - nameof(PublishTargets.PublishArtifacts))] + nameof(PublishTargets.PublishArtifacts), + nameof(PublishTargets.TriggerDockerHubBuilds))] [Environment("PUBLISH_TO_AZURE_BLOB", "1", "true")] // This is set by CI systems public static BuildTargetResult Publish(BuildTargetContext c) { @@ -107,6 +105,45 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + [Target] + [Environment("DOCKER_HUB_REPO")] + [Environment("DOCKER_HUB_TRIGGER_TOKEN")] + public static BuildTargetResult TriggerDockerHubBuilds(BuildTargetContext c) + { + string dockerHubRepo = Environment.GetEnvironmentVariable("DOCKER_HUB_REPO"); + string dockerHubTriggerToken = Environment.GetEnvironmentVariable("DOCKER_HUB_TRIGGER_TOKEN"); + + Uri baseDockerHubUri = new Uri("https://registry.hub.docker.com/u/"); + Uri dockerHubTriggerUri; + if (!Uri.TryCreate(baseDockerHubUri, $"{dockerHubRepo}/trigger/{dockerHubTriggerToken}/", out dockerHubTriggerUri)) + { + return c.Failed("Invalid DOCKER_HUB_REPO and/or DOCKER_HUB_TRIGGER_TOKEN"); + } + + c.Info($"Triggering automated DockerHub builds for {dockerHubRepo}"); + using (HttpClient client = new HttpClient()) + { + StringContent requestContent = new StringContent("{\"build\": true}", Encoding.UTF8, "application/json"); + try + { + HttpResponseMessage response = client.PostAsync(dockerHubTriggerUri, requestContent).Result; + if (!response.IsSuccessStatusCode) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"HTTP request to {dockerHubTriggerUri.ToString()} was unsuccessful."); + sb.AppendLine($"Response status code: {response.StatusCode}. Reason phrase: {response.ReasonPhrase}."); + sb.Append($"Respone content: {response.Content.ReadAsStringAsync().Result}"); + return c.Failed(sb.ToString()); + } + } + catch (AggregateException e) + { + return c.Failed($"HTTP request to {dockerHubTriggerUri.ToString()} failed. {e.ToString()}"); + } + } + return c.Success(); + } + private static string GenerateUploadJsonFile(string packageName, string version, string uploadUrl) { var repoID = Environment.GetEnvironmentVariable("REPO_ID"); diff --git a/src/corehost/cli/deps_format.cpp b/src/corehost/cli/deps_format.cpp index e013ba89f..f9e02ffa4 100644 --- a/src/corehost/cli/deps_format.cpp +++ b/src/corehost/cli/deps_format.cpp @@ -129,23 +129,27 @@ bool deps_json_t::perform_rid_fallback(rid_specific_assets_t* portable_assets, c auto iter = std::find_if(fallback_rids.begin(), fallback_rids.end(), [&package](const pal::string_t& rid) { return package.second.count(rid); }); - if (iter == fallback_rids.end() || (*iter).empty()) + if (iter != fallback_rids.end()) { - trace::error(_X("Did not find a matching fallback rid for package %s for the host rid %s"), package.first.c_str(), host_rid.c_str()); - return false; + matched_rid = *iter; } - matched_rid = *iter; } - assert(!matched_rid.empty()); + + if (matched_rid.empty()) + { + package.second.clear(); + } + for (auto iter = package.second.begin(); iter != package.second.end(); /* */) { if (iter->first != matched_rid) { - iter = package.second.erase(iter); + 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); } else { - ++iter; + ++iter; } } } @@ -194,7 +198,6 @@ bool deps_json_t::process_targets(const json_value& json, const pal::string_t& t for (const auto& package : json.at(_X("targets")).at(target_name).as_object()) { // 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) { @@ -226,27 +229,31 @@ bool deps_json_t::load_portable(const json_value& json, const pal::string_t& tar return false; } - std::vector merged; 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 get_relpaths = [&rid_assets, &non_rid_assets, &merged](const pal::string_t& package, int type_index) -> const std::vector& { - if (rid_assets.count(package) && non_rid_assets.count(package)) + + std::vector empty; + auto get_relpaths = [&rid_assets, &non_rid_assets, &empty](const pal::string_t& package, int type_index) -> const std::vector& { + + // Is there any rid specific assets for this type ("native" or "runtime" or "resources") + if (rid_assets.count(package) && !rid_assets[package].empty()) { - const std::vector& rel1 = rid_assets[package].begin()->second[type_index]; - const std::vector& rel2 = non_rid_assets[package][type_index]; - merged.clear(); - merged.reserve(rel1.size() + rel2.size()); - merged.insert(merged.end(), rel1.begin(), rel1.end()); - merged.insert(merged.end(), rel2.begin(), rel2.end()); - return merged; + const auto& assets_by_type = rid_assets[package].begin()->second[type_index]; + if (!assets_by_type.empty()) + { + 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()); } - else + + if (non_rid_assets.count(package)) { - return rid_assets.count(package) - ? rid_assets[package].begin()->second[type_index] - : non_rid_assets[package][type_index]; + return non_rid_assets[package][type_index]; } + + return empty; }; reconcile_libraries_with_targets(json, package_exists, get_relpaths); diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index 8012d09c4..b371832bc 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -16,8 +16,9 @@ typedef web::json::value json_value; -pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime_config_t* runtime, const pal::string_t& app_path) +pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime_config_t* runtime) { + trace::verbose(_X("--- Resolving FX directory from muxer dir [%s]"), muxer_dir.c_str()); const auto fx_name = runtime->get_fx_name(); const auto fx_ver = runtime->get_fx_version(); const auto roll_fwd = runtime->get_fx_roll_fwd(); @@ -25,25 +26,31 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime fx_ver_t specified(-1, -1, -1); if (!fx_ver_t::parse(fx_ver, &specified, false)) { + trace::error(_X("The specified runtimeconfig.json version [%s] could not be parsed"), fx_ver.c_str()); return pal::string_t(); } auto fx_dir = muxer_dir; - append_path(&fx_dir, _X("Shared")); + append_path(&fx_dir, _X("shared")); append_path(&fx_dir, fx_name.c_str()); // If not roll forward or if pre-release, just return. if (!roll_fwd || specified.is_prerelease()) { + trace::verbose(_X("Did not roll forward because rollfwd=%d and [%s] is prerelease=%d"), + roll_fwd, fx_ver.c_str(), specified.is_prerelease()); append_path(&fx_dir, fx_ver.c_str()); } else { + trace::verbose(_X("Attempting production FX roll forward starting from [%s]"), fx_ver.c_str()); + std::vector list; pal::readdir(fx_dir, &list); fx_ver_t max_specified = specified; for (const auto& version : list) { + trace::verbose(_X("Inspecting version... [%s]"), version.c_str()); fx_ver_t ver(-1, -1, -1); if (fx_ver_t::parse(version, &ver, true) && ver.get_major() == max_specified.get_major() && @@ -55,21 +62,26 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime pal::string_t max_specified_str = max_specified.as_str(); append_path(&fx_dir, max_specified_str.c_str()); } - trace::verbose(_X("Found fx in: %s"), fx_dir.c_str()); + + trace::verbose(_X("Chose FX version [%s]"), fx_dir.c_str()); return pal::directory_exists(fx_dir) ? fx_dir : pal::string_t(); } pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json) { + trace::verbose(_X("--- Resolving CLI version from global json [%s]"), global_json.c_str()); + pal::string_t retval; if (!pal::file_exists(global_json)) { + trace::verbose(_X("[%s] does not exist"), global_json.c_str()); return retval; } pal::ifstream_t file(global_json); if (!file.good()) { + trace::verbose(_X("[%s] could not be opened"), global_json.c_str()); return retval; } @@ -80,6 +92,7 @@ pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json) const auto sdk_iter = json.find(_X("sdk")); if (sdk_iter == json.end() || sdk_iter->second.is_null()) { + trace::verbose(_X("CLI '/sdk/version' field not present/null in [%s]"), global_json.c_str()); return retval; } @@ -87,19 +100,23 @@ pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json) const auto ver_iter = sdk_obj.find(_X("version")); if (ver_iter == sdk_obj.end() || ver_iter->second.is_null()) { + trace::verbose(_X("CLI 'sdk/version' field not present/null in [%s]"), global_json.c_str()); return retval; } retval = ver_iter->second.as_string(); } catch (...) { + trace::verbose(_X("A JSON parsing exception occurred")); } - trace::verbose(_X("Found cli in: %s"), retval.c_str()); + trace::verbose(_X("CLI version is [%s] in global json file [%s]"), retval.c_str(), global_json.c_str()); return retval; } pal::string_t resolve_sdk_version(pal::string_t sdk_path) { + trace::verbose(_X("--- Resolving SDK version from SDK dir [%s]"), sdk_path.c_str()); + pal::string_t retval; std::vector versions; @@ -108,6 +125,8 @@ pal::string_t resolve_sdk_version(pal::string_t sdk_path) fx_ver_t max_pre(-1, -1, -1); for (const auto& version : versions) { + trace::verbose(_X("Considering version... [%s]"), version.c_str()); + fx_ver_t ver(-1, -1, -1); if (fx_ver_t::parse(version, &ver, true)) { @@ -122,20 +141,26 @@ pal::string_t resolve_sdk_version(pal::string_t sdk_path) // No production, use the max pre-release. if (max_ver == fx_ver_t(-1, -1, -1)) { + trace::verbose(_X("No production version found, so using latest prerelease")); max_ver = max_pre; } pal::string_t max_ver_str = max_ver.as_str(); append_path(&sdk_path, max_ver_str.c_str()); + + trace::verbose(_X("Checking if resolved SDK dir [%s] exists"), sdk_path.c_str()); if (pal::directory_exists(sdk_path)) { retval = sdk_path; } + + trace::verbose(_X("Resolved SDK dir is [%s]"), retval.c_str()); return retval; } bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk) { + trace::verbose(_X("--- Resolving dotnet from working dir")); pal::string_t cwd; pal::string_t global; if (pal::getcwd(&cwd)) @@ -144,18 +169,27 @@ bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::stri { pal::string_t file = cur_dir; append_path(&file, _X("global.json")); + + trace::verbose(_X("Probing path [%s] for global.json"), file.c_str()); if (pal::file_exists(file)) { global = file; + trace::verbose(_X("Found global.json [%s]"), global.c_str()); break; } parent_dir = get_directory(cur_dir); if (parent_dir.empty() || parent_dir.size() == cur_dir.size()) { + trace::verbose(_X("Terminating global.json search at [%s]"), parent_dir.c_str()); break; } } } + else + { + trace::verbose(_X("Failed to obtain current working dir")); + } + pal::string_t retval; if (!global.empty()) { @@ -165,10 +199,16 @@ bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::stri pal::string_t sdk_path = own_dir; append_path(&sdk_path, _X("sdk")); append_path(&sdk_path, cli_version.c_str()); + if (pal::directory_exists(sdk_path)) { + trace::verbose(_X("CLI directory [%s] from global.json exists"), sdk_path.c_str()); retval = sdk_path; } + else + { + trace::verbose(_X("CLI directory [%s] from global.json doesn't exist"), sdk_path.c_str()); + } } } if (retval.empty()) @@ -178,13 +218,15 @@ bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::stri retval = resolve_sdk_version(sdk_path); } cli_sdk->assign(retval); - trace::verbose(_X("Found cli sdk in: %s"), cli_sdk->c_str()); + trace::verbose(_X("Found CLI SDK in: %s"), cli_sdk->c_str()); return !retval.empty(); } /* static */ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) { + trace::verbose(_X("--- Executing in muxer mode...")); + pal::string_t own_path; // Get the full name of the application @@ -198,6 +240,7 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) if (argc <= 1) { + trace::error(_X("Usage: dotnet [--help | app.dll]")); return StatusCode::InvalidArgFailure; } if (ends_with(argv[1], _X(".dll"), false)) @@ -206,10 +249,12 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) if (!pal::realpath(&app_path)) { + trace::error(_X("Could not resolve app's full path [%s]"), app_path.c_str()); return StatusCode::LibHostExecModeFailure; } - runtime_config_t config(get_runtime_config_json(app_path)); + 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()); @@ -217,12 +262,14 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) } if (config.get_portable()) { - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, app_path); + 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); return policy_load_t::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); return policy_load_t::execute_app(get_directory(app_path), &init, argc, argv); } @@ -237,11 +284,13 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) std::unordered_map opts; if (!parse_known_args(argc - 2, &argv[2], known_opts, &opts, &num_args)) { + trace::error(_X("Failed to parse known arguments.")); return InvalidArgFailure; } int cur_i = 2 + num_args; if (cur_i >= argc) { + trace::error(_X("Parsed known args, but need more arguments.")); return InvalidArgFailure; } @@ -256,23 +305,31 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) 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(""); - pal::string_t app_path = argv[cur_i]; - runtime_config_t config(get_runtime_config_json(app_path)); + pal::string_t app_or_deps = deps_file.empty() ? argv[cur_i] : deps_file; + auto config_file = get_runtime_config_from_file(app_or_deps); + 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; + } if (config.get_portable()) { - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, app_path); + 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); return policy_load_t::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()); corehost_init_t init(deps_file, probe_path, _X(""), host_mode_t::muxer, &config); - pal::string_t impl_dir = get_directory(deps_file.empty() ? app_path : deps_file); + pal::string_t impl_dir = get_directory(app_or_deps); return policy_load_t::execute_app(impl_dir, &init, new_argv.size(), new_argv.data()); } } @@ -281,9 +338,17 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) pal::string_t sdk_dotnet; if (!resolve_sdk_dotnet_path(own_dir, &sdk_dotnet)) { + trace::error(_X("Could not resolve SDK directory from [%s]"), own_dir.c_str()); return StatusCode::LibHostSdkFindFailure; } append_path(&sdk_dotnet, _X("dotnet.dll")); + + if (!pal::file_exists(sdk_dotnet)) + { + trace::error(_X("Could not find dotnet.dll at [%s]"), sdk_dotnet.c_str()); + return StatusCode::LibHostSdkFindFailure; + } + // Transform dotnet [command] [args] -> dotnet [dotnet.dll] [command] [args] std::vector new_argv(argc + 1); @@ -291,20 +356,21 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) new_argv[0] = argv[0]; new_argv[1] = sdk_dotnet.c_str(); - trace::verbose(_X("Using SDK dll=[%s]"), sdk_dotnet.c_str()); + trace::verbose(_X("Using dotnet SDK dll=[%s]"), sdk_dotnet.c_str()); - assert(ends_with(sdk_dotnet, _X(".dll"), false)); - - runtime_config_t config(get_runtime_config_json(sdk_dotnet)); + auto config_file = get_runtime_config_from_file(sdk_dotnet); + runtime_config_t config(config_file); if (config.get_portable()) { - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, sdk_dotnet); + 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); return policy_load_t::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); return policy_load_t::execute_app(get_directory(sdk_dotnet), &init, new_argv.size(), new_argv.data()); } @@ -316,4 +382,4 @@ SHARED_API int hostfxr_main(const int argc, const pal::char_t* argv[]) { trace::setup(); return fx_muxer_t().execute(argc, argv); -} \ No newline at end of file +} diff --git a/src/corehost/cli/fxr/fx_muxer.h b/src/corehost/cli/fxr/fx_muxer.h index de6518a4c..5ea4cea8b 100644 --- a/src/corehost/cli/fxr/fx_muxer.h +++ b/src/corehost/cli/fxr/fx_muxer.h @@ -9,7 +9,7 @@ class fx_muxer_t public: static int execute(const int argc, const pal::char_t* argv[]); private: - static pal::string_t resolve_fx_dir(const pal::string_t& muxer_path, runtime_config_t* runtime, const pal::string_t& app_path); + static pal::string_t resolve_fx_dir(const pal::string_t& muxer_path, runtime_config_t* runtime); static pal::string_t resolve_cli_version(const pal::string_t& global); static bool resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk); }; diff --git a/src/corehost/cli/hostpolicy.cpp b/src/corehost/cli/hostpolicy.cpp index 32bdb924d..7cf161fba 100644 --- a/src/corehost/cli/hostpolicy.cpp +++ b/src/corehost/cli/hostpolicy.cpp @@ -215,7 +215,8 @@ SHARED_API int corehost_main(const int argc, const pal::char_t* argv[]) } else { - runtime_config_t config(get_runtime_config_json(args.managed_application)); + auto config_path = get_runtime_config_from_file(args.managed_application); + runtime_config_t config(config_path); if (!config.is_valid()) { trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); diff --git a/src/corehost/cli/libhost.cpp b/src/corehost/cli/libhost.cpp index 56d030505..4537554da 100644 --- a/src/corehost/cli/libhost.cpp +++ b/src/corehost/cli/libhost.cpp @@ -6,11 +6,12 @@ #include "trace.h" #include "libhost.h" -pal::string_t get_runtime_config_json(const pal::string_t& app_path) +pal::string_t get_runtime_config_from_file(const pal::string_t& file) { - auto name = get_filename_without_ext(app_path); + auto name = get_filename_without_ext(file); + name = name.substr(0, name.find(_X('.'))); auto json_name = name + _X(".runtimeconfig.json"); - auto json_path = get_directory(app_path); + auto json_path = get_directory(file); append_path(&json_path, json_name.c_str()); if (pal::file_exists(json_path)) diff --git a/src/corehost/cli/libhost.h b/src/corehost/cli/libhost.h index fa0d60e9c..d4e587e62 100644 --- a/src/corehost/cli/libhost.h +++ b/src/corehost/cli/libhost.h @@ -64,7 +64,7 @@ public: } }; -pal::string_t get_runtime_config_json(const pal::string_t& app_path); +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); #endif // __LIBHOST_H__ diff --git a/src/corehost/common/pal.unix.cpp b/src/corehost/common/pal.unix.cpp index a58ad8761..117b07a89 100644 --- a/src/corehost/common/pal.unix.cpp +++ b/src/corehost/common/pal.unix.cpp @@ -202,6 +202,7 @@ void pal::readdir(const pal::string_t& path, std::vector* list) // We are interested in files only switch (entry->d_type) { + case DT_DIR: case DT_REG: break; diff --git a/src/corehost/common/utils.cpp b/src/corehost/common/utils.cpp index 65f1b8c42..1587e7df5 100644 --- a/src/corehost/common/utils.cpp +++ b/src/corehost/common/utils.cpp @@ -74,7 +74,7 @@ pal::string_t get_filename_without_ext(const pal::string_t& path) size_t name_pos = path.find_last_of(_X("/\\")); size_t dot_pos = path.rfind(_X('.')); size_t start_pos = (name_pos == pal::string_t::npos) ? 0 : (name_pos + 1); - size_t count = (dot_pos == pal::string_t::npos) ? pal::string_t::npos : (dot_pos - start_pos); + size_t count = (dot_pos == pal::string_t::npos || dot_pos < start_pos) ? pal::string_t::npos : (dot_pos - start_pos); return path.substr(start_pos, count); } diff --git a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs index 2bff5ba89..46b7d7cb1 100644 --- a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs +++ b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs @@ -114,7 +114,7 @@ namespace Microsoft.DotNet.Tools.Compiler var dependencyContext = new DependencyContextBuilder().Build(compilationOptions, allExports, allExports, - true, // For now, just assume portable mode in the legacy deps file (this is going away soon anyway) + false, // For now, just assume non-portable mode in the legacy deps file (this is going away soon anyway) context.TargetFramework, context.RuntimeIdentifier ?? string.Empty);