Skip to content

Commit 20e5237

Browse files
authored
List other architectures and DOTNET_ROOT environment variables in dotnet --info (#70403)
1 parent 367193d commit 20e5237

25 files changed

+435
-114
lines changed

src/installer/tests/HostActivation.Tests/MultiArchInstallLocation.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.IO;
66
using System.Runtime.InteropServices;
7+
using Microsoft.DotNet.Cli.Build;
78
using Microsoft.DotNet.Cli.Build.Framework;
89
using Microsoft.DotNet.CoreSetup.Test;
910
using Microsoft.DotNet.CoreSetup.Test.HostActivation;
@@ -146,6 +147,44 @@ public void EnvironmentVariable_DotnetRootPathExistsButHasNoHost()
146147
}
147148
}
148149

150+
[Fact]
151+
public void EnvironmentVariable_DotNetInfo_ListEnvironment()
152+
{
153+
var dotnet = new DotNetCli(sharedTestState.RepoDirectories.BuiltDotnet);
154+
155+
var command = dotnet.Exec("--info")
156+
.CaptureStdOut();
157+
158+
var envVars = new (string Architecture, string Path)[] {
159+
("arm64", "/arm64/dotnet/root"),
160+
("x64", "/x64/dotnet/root"),
161+
("x86", "/x86/dotnet/root")
162+
};
163+
foreach(var envVar in envVars)
164+
{
165+
command = command.DotNetRoot(envVar.Path, envVar.Architecture);
166+
}
167+
168+
string dotnetRootNoArch = "/dotnet/root";
169+
command = command.DotNetRoot(dotnetRootNoArch);
170+
171+
(string Architecture, string Path) unknownEnvVar = ("unknown", "/unknown/dotnet/root");
172+
command = command.DotNetRoot(unknownEnvVar.Path, unknownEnvVar.Architecture);
173+
174+
var result = command.Execute();
175+
result.Should().Pass()
176+
.And.HaveStdOutContaining("Environment variables:")
177+
.And.HaveStdOutMatching($@"{Constants.DotnetRoot.EnvironmentVariable}\s*\[{dotnetRootNoArch}\]")
178+
.And.NotHaveStdOutContaining($"{Constants.DotnetRoot.ArchitectureEnvironmentVariablePrefix}{unknownEnvVar.Architecture.ToUpper()}")
179+
.And.NotHaveStdOutContaining($"[{unknownEnvVar.Path}]");
180+
181+
foreach ((string architecture, string path) in envVars)
182+
{
183+
result.Should()
184+
.HaveStdOutMatching($@"{Constants.DotnetRoot.ArchitectureEnvironmentVariablePrefix}{architecture.ToUpper()}\s*\[{path}\]");
185+
}
186+
}
187+
149188
[Fact]
150189
public void RegisteredInstallLocation_ArchSpecificLocationIsPickedFirst()
151190
{
@@ -241,6 +280,49 @@ public void InstallLocationFile_MissingFile()
241280
}
242281
}
243282

283+
[Fact]
284+
public void RegisteredInstallLocation_DotNetInfo_ListOtherArchitectures()
285+
{
286+
using (var testArtifact = new TestArtifact(SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "listOtherArchs"))))
287+
{
288+
var dotnet = new DotNetBuilder(testArtifact.Location, sharedTestState.RepoDirectories.BuiltDotnet, "exe").Build();
289+
using (var registeredInstallLocationOverride = new RegisteredInstallLocationOverride(dotnet.GreatestVersionHostFxrFilePath))
290+
{
291+
var installLocations = new (string, string)[] {
292+
("arm64", "/arm64/install/path"),
293+
("x64", "/x64/install/path"),
294+
("x86", "/x86/install/path")
295+
};
296+
(string Architecture, string Path) unknownArchInstall = ("unknown", "/unknown/install/path");
297+
registeredInstallLocationOverride.SetInstallLocation(installLocations);
298+
registeredInstallLocationOverride.SetInstallLocation(unknownArchInstall);
299+
300+
var result = dotnet.Exec("--info")
301+
.CaptureStdOut()
302+
.ApplyRegisteredInstallLocationOverride(registeredInstallLocationOverride)
303+
.Execute();
304+
305+
result.Should().Pass()
306+
.And.HaveStdOutContaining("Other architectures found:")
307+
.And.NotHaveStdOutContaining(unknownArchInstall.Architecture)
308+
.And.NotHaveStdOutContaining($"[{unknownArchInstall.Path}]");
309+
310+
string pathOverride = OperatingSystem.IsWindows() // Host uses short form of base key for Windows
311+
? registeredInstallLocationOverride.PathValueOverride.Replace(Microsoft.Win32.Registry.CurrentUser.Name, "HKCU")
312+
: registeredInstallLocationOverride.PathValueOverride;
313+
pathOverride = System.Text.RegularExpressions.Regex.Escape(pathOverride);
314+
foreach ((string arch, string path) in installLocations)
315+
{
316+
if (arch == sharedTestState.RepoDirectories.BuildArchitecture)
317+
continue;
318+
319+
result.Should()
320+
.HaveStdOutMatching($@"{arch}\s*\[{path}\]\r?$\s*registered at \[{pathOverride}.*{arch}.*\]", System.Text.RegularExpressions.RegexOptions.Multiline);
321+
}
322+
}
323+
}
324+
}
325+
244326
public class SharedTestState : IDisposable
245327
{
246328
public string BaseDirectory { get; }

src/installer/tests/HostActivation.Tests/SDKLookup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public void SdkLookup_Global_Json_Single_Digit_Patch_Rollup()
4949
.Should().Fail()
5050
.And.NotFindCompatibleSdk(globalJsonPath, requestedVersion)
5151
.And.FindAnySdk(false)
52-
.And.HaveStdErrContaining("aka.ms/dotnet-download")
52+
.And.HaveStdErrContaining("aka.ms/dotnet/download")
5353
.And.NotHaveStdErrContaining("Checking if resolved SDK dir");
5454

5555
// Add SDK versions

src/installer/tests/TestUtils/DotNetCli.cs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public partial class DotNetCli
1212
{
1313
public string BinPath { get; }
1414
public string GreatestVersionSharedFxPath { get; }
15-
public string GreatestVersionHostFxrPath { get; }
15+
public string GreatestVersionHostFxrPath { get; }
1616
public string GreatestVersionHostFxrFilePath { get => Path.Combine(
1717
GreatestVersionHostFxrPath,
1818
RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")); }
@@ -29,30 +29,22 @@ public DotNetCli(string binPath)
2929
BinPath = binPath;
3030

3131
var sharedFxBaseDirectory = Path.Combine(BinPath, "shared", "Microsoft.NETCore.App");
32-
if (!Directory.Exists(sharedFxBaseDirectory))
32+
if (Directory.Exists(sharedFxBaseDirectory))
3333
{
34-
GreatestVersionSharedFxPath = null;
35-
return;
34+
var sharedFxVersionDirectories = Directory.EnumerateDirectories(sharedFxBaseDirectory);
35+
GreatestVersionSharedFxPath = sharedFxVersionDirectories
36+
.OrderByDescending(p => p.ToLower())
37+
.First();
3638
}
3739

3840
var hostFxrBaseDirectory = Path.Combine(BinPath, "host", "fxr");
39-
40-
if (!Directory.Exists(hostFxrBaseDirectory))
41+
if (Directory.Exists(hostFxrBaseDirectory))
4142
{
42-
GreatestVersionHostFxrPath = null;
43-
return;
43+
var hostFxrVersionDirectories = Directory.EnumerateDirectories(hostFxrBaseDirectory);
44+
GreatestVersionHostFxrPath = hostFxrVersionDirectories
45+
.OrderByDescending(p => p.ToLower())
46+
.First();
4447
}
45-
46-
var sharedFxVersionDirectories = Directory.EnumerateDirectories(sharedFxBaseDirectory);
47-
48-
GreatestVersionSharedFxPath = sharedFxVersionDirectories
49-
.OrderByDescending(p => p.ToLower())
50-
.First();
51-
52-
var hostFxrVersionDirectories = Directory.EnumerateDirectories(hostFxrBaseDirectory);
53-
GreatestVersionHostFxrPath = hostFxrVersionDirectories
54-
.OrderByDescending(p => p.ToLower())
55-
.First();
5648
}
5749

5850
public Command Exec(string command, params string[] args)

src/native/corehost/apphost/apphost.windows.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ namespace
7373
pal::string_t get_apphost_details_message()
7474
{
7575
pal::string_t msg = _X("Architecture: ");
76-
msg.append(get_arch());
76+
msg.append(get_current_arch_name());
7777
msg.append(_X("\n")
7878
_X("App host version: ") _STRINGIFY(COMMON_HOST_PKG_VER) _X("\n\n"));
7979
return msg;

src/native/corehost/corehost.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ void need_newer_framework_error(const pal::string_t& dotnet_root, const pal::str
100100
_X("Download the .NET runtime:\n")
101101
_X("%s&apphost_version=%s"),
102102
host_path.c_str(),
103-
get_arch(),
103+
get_current_arch_name(),
104104
_STRINGIFY(COMMON_HOST_PKG_VER),
105105
dotnet_root.c_str(),
106106
get_download_url().c_str(),
@@ -225,7 +225,7 @@ int exe_start(const int argc, const pal::char_t* argv[])
225225
else
226226
{
227227
// An outdated hostfxr can only be found for framework-related apps.
228-
trace::error(_X("The required library %s does not support single-file apps."), fxr.fxr_path().c_str());
228+
trace::error(_X("The required library %s does not support single-file apps."), fxr.fxr_path().c_str());
229229
need_newer_framework_error(fxr.dotnet_root(), host_path);
230230
rc = StatusCode::FrameworkMissingFailure;
231231
}

src/native/corehost/deps_format.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ pal::string_t deps_json_t::get_current_rid(const rid_fallback_graph_t& rid_fallb
130130
// We do the same even when the RID is empty.
131131
if (currentRid.empty() || (rid_fallback_graph.count(currentRid) == 0))
132132
{
133-
currentRid = pal::get_current_os_fallback_rid() + pal::string_t(_X("-")) + get_arch();
133+
currentRid = pal::get_current_os_fallback_rid() + pal::string_t(_X("-")) + get_current_arch_name();
134134

135135
trace::info(_X("Falling back to base HostRID: %s"), currentRid.c_str());
136136
}

src/native/corehost/fxr/command_line.cpp

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "command_line.h"
55
#include <error_codes.h>
66
#include "framework_info.h"
7+
#include "install_info.h"
78
#include <pal.h>
89
#include "sdk_info.h"
910
#include <trace.h>
@@ -279,37 +280,58 @@ int command_line::parse_args_for_sdk_command(
279280
return parse_args(host_info, 1, argc, argv, false, host_mode_t::muxer, new_argoff, app_candidate, opts);
280281
}
281282

282-
void command_line::print_muxer_info(const pal::string_t &dotnet_root)
283+
void command_line::print_muxer_info(const pal::string_t &dotnet_root, const pal::string_t &global_json_path)
283284
{
284-
trace::println();
285-
trace::println(_X("Host:"));
286-
trace::println(_X(" Version: %s"), _STRINGIFY(HOST_FXR_PKG_VER));
287-
trace::println(_X(" Architecture: %s"), get_arch());
288-
289285
pal::string_t commit = _STRINGIFY(REPO_COMMIT_HASH);
290-
trace::println(_X(" Commit: %s"), commit.substr(0, 10).c_str());
291-
292-
trace::println();
293-
trace::println(_X(".NET SDKs installed:"));
286+
trace::println(_X("\n")
287+
_X("Host:\n")
288+
_X(" Version: ") _STRINGIFY(HOST_FXR_PKG_VER) _X("\n")
289+
_X(" Architecture: %s\n")
290+
_X(" Commit: %s"),
291+
get_current_arch_name(),
292+
commit.substr(0, 10).c_str());
293+
294+
trace::println(_X("\n")
295+
_X(".NET SDKs installed:"));
294296
if (!sdk_info::print_all_sdks(dotnet_root, _X(" ")))
295297
{
296298
trace::println(_X(" No SDKs were found."));
297299
}
298300

299-
trace::println();
300-
trace::println(_X(".NET runtimes installed:"));
301+
trace::println(_X("\n")
302+
_X(".NET runtimes installed:"));
301303
if (!framework_info::print_all_frameworks(dotnet_root, _X(" ")))
302304
{
303305
trace::println(_X(" No runtimes were found."));
304306
}
305307

306-
trace::println();
307-
trace::println(_X("Download .NET:"));
308-
trace::println(_X(" %s"), DOTNET_CORE_DOWNLOAD_URL);
308+
trace::println(_X("\n")
309+
_X("Other architectures found:"));
310+
if (!install_info::print_other_architectures(_X(" ")))
311+
{
312+
trace::println(_X(" None"));
313+
}
309314

310-
trace::println();
311-
trace::println(_X("Learn about .NET Runtimes and SDKs:"));
312-
trace::println(_X(" %s"), DOTNET_INFO_URL);}
315+
trace::println(_X("\n")
316+
_X("Environment variables:"));
317+
if (!install_info::print_environment(_X(" ")))
318+
{
319+
trace::println(_X(" Not set"));
320+
}
321+
322+
trace::println(_X("\n")
323+
_X("global.json file:\n")
324+
_X(" %s"),
325+
global_json_path.empty() ? _X("Not found") : global_json_path.c_str());
326+
327+
trace::println(_X("\n")
328+
_X("Learn more:\n")
329+
_X(" ") DOTNET_INFO_URL);
330+
331+
trace::println(_X("\n")
332+
_X("Download .NET:\n")
333+
_X(" ") DOTNET_CORE_DOWNLOAD_URL);
334+
}
313335

314336
void command_line::print_muxer_usage(bool is_sdk_present)
315337
{

src/native/corehost/fxr/command_line.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ namespace command_line
5757
/*out*/ pal::string_t &app_candidate,
5858
/*out*/ opt_map_t &opts);
5959

60-
void print_muxer_info(const pal::string_t &dotnet_root);
60+
void print_muxer_info(const pal::string_t &dotnet_root, const pal::string_t &global_json_path);
6161
void print_muxer_usage(bool is_sdk_present);
6262
};
6363

src/native/corehost/fxr/files.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ list(APPEND SOURCES
1515
${CMAKE_CURRENT_LIST_DIR}/fx_resolver.messages.cpp
1616
${CMAKE_CURRENT_LIST_DIR}/framework_info.cpp
1717
${CMAKE_CURRENT_LIST_DIR}/host_context.cpp
18+
${CMAKE_CURRENT_LIST_DIR}/install_info.cpp
1819
${CMAKE_CURRENT_LIST_DIR}/sdk_info.cpp
1920
${CMAKE_CURRENT_LIST_DIR}/sdk_resolver.cpp
2021
)
@@ -31,6 +32,7 @@ list(APPEND HEADERS
3132
${CMAKE_CURRENT_LIST_DIR}/fx_resolver.h
3233
${CMAKE_CURRENT_LIST_DIR}/framework_info.h
3334
${CMAKE_CURRENT_LIST_DIR}/host_context.h
35+
${CMAKE_CURRENT_LIST_DIR}/install_info.h
3436
${CMAKE_CURRENT_LIST_DIR}/sdk_info.h
3537
${CMAKE_CURRENT_LIST_DIR}/sdk_resolver.h
3638
)

src/native/corehost/fxr/fx_muxer.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ void append_probe_realpath(const pal::string_t& path, std::vector<pal::string_t>
245245

246246
if (pos_placeholder != pal::string_t::npos)
247247
{
248-
pal::string_t segment = get_arch();
248+
pal::string_t segment = get_current_arch_name();
249249
segment.push_back(DIR_SEPARATOR);
250250
segment.append(tfm);
251251
probe_path.replace(pos_placeholder, placeholder.length(), segment);
@@ -1066,8 +1066,7 @@ int fx_muxer_t::handle_cli(
10661066
}
10671067
else if (pal::strcasecmp(_X("--info"), argv[1]) == 0)
10681068
{
1069-
resolver.print_global_file_path();
1070-
command_line::print_muxer_info(host_info.dotnet_root);
1069+
command_line::print_muxer_info(host_info.dotnet_root, resolver.global_file_path());
10711070
return StatusCode::Success;
10721071
}
10731072

@@ -1124,8 +1123,7 @@ int fx_muxer_t::handle_cli(
11241123

11251124
if (pal::strcasecmp(_X("--info"), argv[1]) == 0)
11261125
{
1127-
resolver.print_global_file_path();
1128-
command_line::print_muxer_info(host_info.dotnet_root);
1126+
command_line::print_muxer_info(host_info.dotnet_root, resolver.global_file_path());
11291127
}
11301128

11311129
return result;

0 commit comments

Comments
 (0)