Skip to content

Commit fdfb78f

Browse files
committed
Consider if host has --arch
1 parent 9259f3b commit fdfb78f

File tree

6 files changed

+35
-29
lines changed

6 files changed

+35
-29
lines changed

vscode-dotnet-runtime-extension/src/extension.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ export function activate(vsCodeContext: vscode.ExtensionContext, extensionContex
510510
{
511511
throw new EventCancellationError('BadContextualFindPathError', `The find path request was missing required information: a mode, version, architecture, and requestingExtensionId.`);
512512
}
513+
const requestedArchitecture = commandContext.acquireContext.architecture;
513514

514515
globalEventStream.post(new DotnetFindPathLookupSetting(`Looking up vscode setting.`));
515516
const workerContext = getAcquisitionWorkerContext(commandContext.acquireContext.mode, commandContext.acquireContext);
@@ -527,7 +528,7 @@ export function activate(vsCodeContext: vscode.ExtensionContext, extensionContex
527528
const validator = new DotnetConditionValidator(workerContext, utilContext);
528529
const finder = new DotnetPathFinder(workerContext, utilContext);
529530

530-
const dotnetOnShellSpawn = (await finder.findDotnetFastFromListOnly())?.[0] ?? '';
531+
const dotnetOnShellSpawn = (await finder.findDotnetFastFromListOnly(requestedArchitecture))?.[0] ?? '';
531532
if (dotnetOnShellSpawn)
532533
{
533534
const validatedShellSpawn = await getPathIfValid(dotnetOnShellSpawn, validator, commandContext);
@@ -538,7 +539,7 @@ export function activate(vsCodeContext: vscode.ExtensionContext, extensionContex
538539
}
539540
}
540541

541-
const dotnetsOnPATH = await finder.findRawPathEnvironmentSetting();
542+
const dotnetsOnPATH = await finder.findRawPathEnvironmentSetting(requestedArchitecture);
542543
for (const dotnetPath of dotnetsOnPATH ?? [])
543544
{
544545
const validatedPATH = await getPathIfValid(dotnetPath, validator, commandContext);
@@ -549,7 +550,7 @@ export function activate(vsCodeContext: vscode.ExtensionContext, extensionContex
549550
}
550551
}
551552

552-
const dotnetsOnRealPATH = await finder.findRealPathEnvironmentSetting();
553+
const dotnetsOnRealPATH = await finder.findRealPathEnvironmentSetting(requestedArchitecture);
553554
for (const dotnetPath of dotnetsOnRealPATH ?? [])
554555
{
555556
const validatedRealPATH = await getPathIfValid(dotnetPath, validator, commandContext);
@@ -562,7 +563,7 @@ export function activate(vsCodeContext: vscode.ExtensionContext, extensionContex
562563

563564
if (commandContext.acquireContext.mode === 'runtime' || commandContext.acquireContext.mode === 'aspnetcore')
564565
{
565-
const extensionManagedRuntimeRecordPaths = await finder.findExtensionManagedRuntimes();
566+
const extensionManagedRuntimeRecordPaths = await finder.findExtensionManagedRuntimes(requestedArchitecture);
566567
const filteredExtensionManagedRuntimeRecordPaths = validator.filterValidPaths(extensionManagedRuntimeRecordPaths, commandContext);
567568
for (const dotnetPath of filteredExtensionManagedRuntimeRecordPaths ?? [])
568569
{

vscode-dotnet-runtime-library/src/Acquisition/DotnetConditionValidator.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Licensed to the .NET Foundation under one or more agreements.
33
* The .NET Foundation licenses this file to you under the MIT license.
44
*--------------------------------------------------------------------------------------------*/
5+
import * as os from 'os';
56
import { DotnetConditionsValidated, DotnetFindPathDidNotMeetCondition, DotnetUnableToCheckPATHArchitecture } from '../EventStream/EventStreamEvents';
67
import { IDotnetFindPathContext } from '../IDotnetFindPathContext';
78
import { CommandExecutor } from '../Utils/CommandExecutor';
@@ -27,11 +28,12 @@ export class DotnetConditionValidator implements IDotnetConditionValidator
2728

2829
public async dotnetMeetsRequirement(dotnetExecutablePath: string, requirement: IDotnetFindPathContext): Promise<boolean>
2930
{
30-
const hostArch = await this.getHostArchitecture(dotnetExecutablePath, requirement);
31+
let hostArch = '';
3132

3233
if (requirement.acquireContext.mode === 'sdk')
3334
{
34-
const availableSDKs = await this.getSDKs(dotnetExecutablePath);
35+
const availableSDKs = await this.getSDKs(dotnetExecutablePath, requirement.acquireContext.architecture ?? os.arch() === 'arm64' ? 'arm64' : 'x64');
36+
hostArch = availableSDKs?.at(0)?.architecture ?? await this.getHostArchitecture(dotnetExecutablePath, requirement);
3537
if (availableSDKs.some((sdk) =>
3638
{
3739
return this.stringArchitectureMeetsRequirement(hostArch, requirement.acquireContext.architecture) &&
@@ -45,7 +47,8 @@ export class DotnetConditionValidator implements IDotnetConditionValidator
4547
else
4648
{
4749
// No need to consider SDKs when looking for runtimes as all the runtimes installed with the SDKs will be included in the runtimes list.
48-
const availableRuntimes = await this.getRuntimes(dotnetExecutablePath);
50+
const availableRuntimes = await this.getRuntimes(dotnetExecutablePath, requirement.acquireContext.architecture ?? os.arch() === 'arm64' ? 'arm64' : 'x64');
51+
hostArch ??= availableRuntimes?.at(0)?.architecture ?? await this.getHostArchitecture(dotnetExecutablePath, requirement);
4952
if (availableRuntimes.some((runtime) =>
5053
{
5154
return runtime.mode === requirement.acquireContext.mode && this.stringArchitectureMeetsRequirement(hostArch, requirement.acquireContext.architecture) &&
@@ -113,14 +116,14 @@ Please set the PATH to a dotnet host that matches the architecture ${requirement
113116
return hostArch;
114117
}
115118

116-
public async getSDKs(existingPath: string): Promise<IDotnetListInfo[]>
119+
public async getSDKs(existingPath: string, requestedArchitecture: string): Promise<IDotnetListInfo[]>
117120
{
118121
if (!existingPath || existingPath === '""')
119122
{
120123
return [];
121124
}
122125

123-
const findSDKsCommand = CommandExecutor.makeCommand(`"${existingPath}"`, ['--list-sdks']);
126+
const findSDKsCommand = CommandExecutor.makeCommand(`"${existingPath}"`, ['--list-sdks', '--arch', requestedArchitecture]);
124127

125128
const sdkInfo = await (this.executor!).execute(findSDKsCommand, { dotnetInstallToolCacheTtlMs: DOTNET_INFORMATION_CACHE_DURATION_MS }, false).then((result) =>
126129
{
@@ -135,7 +138,8 @@ Please set the PATH to a dotnet host that matches the architecture ${requirement
135138
return {
136139
mode: 'sdk',
137140
version: parts[0],
138-
directory: sdk.split(' ').slice(1).join(' ').slice(1, -1) // need to remove the brackets from the path [path]
141+
directory: sdk.split(' ').slice(1).join(' ').slice(1, -1), // need to remove the brackets from the path [path],
142+
architecture: hostSupportsArchFlag ? requestedArchitecture : null
139143
} as IDotnetListInfo;
140144
}).filter(x => x !== null) as IDotnetListInfo[];
141145

@@ -281,14 +285,14 @@ Please set the PATH to a dotnet host that matches the architecture ${requirement
281285
return true;
282286
}
283287

284-
public async getRuntimes(existingPath: string): Promise<IDotnetListInfo[]>
288+
public async getRuntimes(existingPath: string, requestedArchitecture: string): Promise<IDotnetListInfo[]>
285289
{
286290
if (!existingPath || existingPath === '""')
287291
{
288292
return [];
289293
}
290294

291-
const findRuntimesCommand = CommandExecutor.makeCommand(`"${existingPath}"`, ['--list-runtimes']);
295+
const findRuntimesCommand = CommandExecutor.makeCommand(`"${existingPath}"`, ['--list-runtimes', '--arch', requestedArchitecture]);
292296

293297
const windowsDesktopString = 'Microsoft.WindowsDesktop.App';
294298
const aspnetCoreString = 'Microsoft.AspNetCore.App';
@@ -307,8 +311,9 @@ Please set the PATH to a dotnet host that matches the architecture ${requirement
307311
return {
308312
mode: parts[0] === aspnetCoreString ? 'aspnetcore' : parts[0] === runtimeString ? 'runtime' : 'sdk', // sdk is a placeholder for windows desktop, will never match since this is for runtime search only
309313
version: parts[1],
310-
directory: runtime.split(' ').slice(2).join(' ').slice(1, -1) // account for spaces in PATH, no space should appear before then and luckily path is last.
314+
directory: runtime.split(' ').slice(2).join(' ').slice(1, -1), // account for spaces in PATH, no space should appear before then and luckily path is last.
311315
// the 2nd slice needs to remove the brackets from the path [path]
316+
architecture: hostSupportsArchFlag ? requestedArchitecture : null
312317
} as IDotnetListInfo;
313318
}).filter(x => x !== null) as IDotnetListInfo[];
314319

vscode-dotnet-runtime-library/src/Acquisition/DotnetCoreAcquisitionWorker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ To keep your .NET version up to date, please reconnect to the internet at your s
360360
private async sdkIsFound(context: IAcquisitionWorkerContext, version: string): Promise<boolean>
361361
{
362362
const executor = new CommandExecutor(context, this.utilityContext);
363-
const listSDKsCommand = CommandExecutor.makeCommand('dotnet', ['--list-sdks']);
363+
const listSDKsCommand = CommandExecutor.makeCommand('dotnet', ['--list-sdks', '--arch']);
364364
const result = await executor.execute(listSDKsCommand, { dotnetInstallToolCacheTtlMs: DOTNET_INFORMATION_CACHE_DURATION_MS }, false);
365365

366366
if (result.status !== '0')

vscode-dotnet-runtime-library/src/Acquisition/DotnetPathFinder.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,13 @@ export class DotnetPathFinder implements IDotnetPathFinder
106106
* This allows skipping which, where, and also does not rely on --info which is slower because it shells to the SDK instead of just being the host.
107107
* @returns The path to the dotnet executable, which may be a symlink to the actual executable.
108108
*/
109-
public async findDotnetFastFromListOnly(): Promise<string[] | undefined>
109+
public async findDotnetFastFromListOnly(requestedArchitecture: string | null): Promise<string[] | undefined>
110110
{
111111
const oldLookup = process.env.DOTNET_MULTILEVEL_LOOKUP;
112112
try
113113
{
114114
process.env.DOTNET_MULTILEVEL_LOOKUP = '0'; // make it so --list-runtimes only finds the runtimes on that path: https://learn.microsoft.com/en-us/dotnet/core/compatibility/deployment/7.0/multilevel-lookup#reason-for-change
115-
const finalPath = await this.getTruePath(['dotnet']);
115+
const finalPath = await this.getTruePath(['dotnet'], requestedArchitecture);
116116
return this.returnWithRestoringEnvironment(finalPath, 'DOTNET_MULTILEVEL_LOOKUP', oldLookup);
117117
}
118118
finally
@@ -131,7 +131,7 @@ export class DotnetPathFinder implements IDotnetPathFinder
131131
* In an install such as homebrew, the PATH is not indicative of all of the PATHs. So dotnet may be missing in the PATH even though it is found in an alternative shell.
132132
* The PATH can be discovered using path_helper on mac.
133133
*/
134-
public async findRawPathEnvironmentSetting(tryUseTrueShell = true): Promise<string[] | undefined>
134+
public async findRawPathEnvironmentSetting(tryUseTrueShell = true, requestedArchitecture: string | null): Promise<string[] | undefined>
135135
{
136136
const oldLookup = process.env.DOTNET_MULTILEVEL_LOOKUP;
137137
process.env.DOTNET_MULTILEVEL_LOOKUP = '0'; // make it so --list-runtimes only finds the runtimes on that path: https://learn.microsoft.com/en-us/dotnet/core/compatibility/deployment/7.0/multilevel-lookup#reason-for-change
@@ -208,7 +208,7 @@ export class DotnetPathFinder implements IDotnetPathFinder
208208
if (dotnetsOnPATH && (dotnetsOnPATH?.length ?? 0) > 0)
209209
{
210210
this.workerContext.eventStream.post(new DotnetFindPathPATHFound(`Found.NET on the path: ${JSON.stringify(dotnetsOnPATH)}`));
211-
return this.returnWithRestoringEnvironment(await this.getTruePath(dotnetsOnPATH), 'DOTNET_MULTILEVEL_LOOKUP', oldLookup);
211+
return this.returnWithRestoringEnvironment(await this.getTruePath(dotnetsOnPATH, requestedArchitecture), 'DOTNET_MULTILEVEL_LOOKUP', oldLookup);
212212

213213
}
214214
else
@@ -259,10 +259,10 @@ export class DotnetPathFinder implements IDotnetPathFinder
259259
*
260260
* We can't use realpath on all paths, because some paths are polymorphic executables and the realpath is invalid.
261261
*/
262-
public async findRealPathEnvironmentSetting(tryUseTrueShell = true): Promise<string[] | undefined>
262+
public async findRealPathEnvironmentSetting(tryUseTrueShell = true, requestedArchitecture: string | null): Promise<string[] | undefined>
263263
{
264264
this.workerContext.eventStream.post(new DotnetFindPathLookupRealPATH(`Looking up.NET on the real path.`));
265-
const dotnetsOnPATH = await this.findRawPathEnvironmentSetting(tryUseTrueShell);
265+
const dotnetsOnPATH = await this.findRawPathEnvironmentSetting(tryUseTrueShell, requestedArchitecture);
266266
const realPaths = [];
267267

268268
for (const dotnetOnPATH of dotnetsOnPATH ?? [])
@@ -279,7 +279,7 @@ export class DotnetPathFinder implements IDotnetPathFinder
279279
{
280280
return undefined;
281281
}
282-
return this.getTruePath(realPaths);
282+
return this.getTruePath(realPaths, requestedArchitecture);
283283
}
284284

285285
public async findHostInstallPaths(requestedArchitecture: string): Promise<string[] | undefined>
@@ -312,7 +312,7 @@ export class DotnetPathFinder implements IDotnetPathFinder
312312
{
313313
this.workerContext.eventStream.post(new DotnetFindPathNoHostOnRegistry(`The host could not be found in the registry`));
314314
}
315-
return this.returnWithRestoringEnvironment(await this.getTruePath(lodash.uniq(paths)), 'DOTNET_MULTILEVEL_LOOKUP', oldLookup);
315+
return this.returnWithRestoringEnvironment(await this.getTruePath(lodash.uniq(paths), requestedArchitecture), 'DOTNET_MULTILEVEL_LOOKUP', oldLookup);
316316
}
317317
else
318318
{
@@ -337,7 +337,7 @@ export class DotnetPathFinder implements IDotnetPathFinder
337337
this.workerContext.eventStream.post(new DotnetFindPathNoHostOnFileSystem(`The host could not be found in the file system.`));
338338
}
339339

340-
return this.returnWithRestoringEnvironment(await this.getTruePath(lodash.uniq(paths)), 'DOTNET_MULTILEVEL_LOOKUP', oldLookup);
340+
return this.returnWithRestoringEnvironment(await this.getTruePath(lodash.uniq(paths), requestedArchitecture), 'DOTNET_MULTILEVEL_LOOKUP', oldLookup);
341341
}
342342
}
343343

@@ -377,14 +377,14 @@ export class DotnetPathFinder implements IDotnetPathFinder
377377
* @returns The actual physical location/path on disk where the executables lie for each of the paths.
378378
* Some of the symlinks etc resolve to a path which works but is still not the actual path.
379379
*/
380-
public async getTruePath(tentativePaths: string[]): Promise<string[]>
380+
public async getTruePath(tentativePaths: string[], requestedArchitecture: string | null): Promise<string[]>
381381
{
382382
const truePaths = [];
383383

384384
for (const tentativePath of tentativePaths)
385385
{
386386
// This will even work if only the sdk is installed, list-runtimes on an sdk installed host would work
387-
const runtimeInfo = await new DotnetConditionValidator(this.workerContext, this.utilityContext, this.executor).getRuntimes(tentativePath);
387+
const runtimeInfo = await new DotnetConditionValidator(this.workerContext, this.utilityContext, this.executor).getRuntimes(tentativePath, requestedArchitecture);
388388
if ((runtimeInfo?.length ?? 0) > 0)
389389
{
390390
// q.t. from @dibarbet on the C# Extension:

vscode-dotnet-runtime-library/src/Acquisition/IDotnetListInfo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55

66
import { DotnetInstallMode } from "./DotnetInstallMode";
77

8-
export interface IDotnetListInfo { mode: DotnetInstallMode, version: string, directory : string };
8+
export interface IDotnetListInfo { mode: DotnetInstallMode, version: string, directory : string, architecture: string | null };

vscode-dotnet-runtime-library/src/Acquisition/IDotnetPathFinder.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import { InstallRecordWithPath } from './InstallRecordWithPath';
88
export interface IDotnetPathFinder
99
{
1010
findDotnetRootPath(requestedArchitecture: string): Promise<string | undefined>;
11-
findRawPathEnvironmentSetting(tryUseTrueShell: boolean): Promise<string[] | undefined>;
12-
findRealPathEnvironmentSetting(tryUseTrueShell: boolean): Promise<string[] | undefined>;
11+
findRawPathEnvironmentSetting(tryUseTrueShell: boolean, requestedArchitecture: string | null): Promise<string[] | undefined>;
12+
findRealPathEnvironmentSetting(tryUseTrueShell: boolean, requestedArchitecture: string | null): Promise<string[] | undefined>;
1313
findHostInstallPaths(requestedArchitecture: string): Promise<string[] | undefined>;
14-
findExtensionManagedRuntimes(): Promise<InstallRecordWithPath[]>;
14+
findExtensionManagedRuntimes(requestedArchitecture: string | null): Promise<InstallRecordWithPath[]>;
1515
}

0 commit comments

Comments
 (0)