mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[ Tool ] Support Powershell v6+ to determine Windows version in flutter doctor (#156476)
Powershell v6+ use the executable name `pwsh.exe` instead of `powershell.exe`. This change adds support for determining the Windows version on systems that solely use `pwsh.exe` and don't have `powershell.exe` on the `PATH`. Fixes #156189. --------- Co-authored-by: Andrew Kolos <andrewrkolos@gmail.com>
This commit is contained in:
parent
2b1e71b4a4
commit
ad370c8fa7
@ -37,9 +37,22 @@ class WindowsVersionValidator extends DoctorValidator {
|
||||
final ProcessLister _processLister;
|
||||
|
||||
Future<ValidationResult> _topazScan() async {
|
||||
if (!_processLister.canRunPowershell()) {
|
||||
return const ValidationResult(
|
||||
ValidationType.missing,
|
||||
<ValidationMessage>[
|
||||
ValidationMessage.hint('Failed to find ${ProcessLister.powershell} or ${ProcessLister.pwsh} on PATH'),
|
||||
],
|
||||
);
|
||||
}
|
||||
final ProcessResult getProcessesResult = await _processLister.getProcessesWithPath();
|
||||
if (getProcessesResult.exitCode != 0) {
|
||||
return const ValidationResult(ValidationType.missing, <ValidationMessage>[ValidationMessage.hint('Get-Process failed to complete')]);
|
||||
return const ValidationResult(
|
||||
ValidationType.missing,
|
||||
<ValidationMessage>[
|
||||
ValidationMessage.hint('Get-Process failed to complete'),
|
||||
],
|
||||
);
|
||||
}
|
||||
final RegExp topazRegex = RegExp(kCoreProcessPattern, caseSensitive: false, multiLine: true);
|
||||
final String processes = getProcessesResult.stdout as String;
|
||||
@ -106,8 +119,22 @@ class ProcessLister {
|
||||
|
||||
final ProcessManager processManager;
|
||||
|
||||
static const String powershell = 'powershell';
|
||||
static const String pwsh = 'pwsh';
|
||||
|
||||
bool canRunPowershell() {
|
||||
return processManager.canRun(powershell) || processManager.canRun(pwsh);
|
||||
}
|
||||
|
||||
Future<ProcessResult> getProcessesWithPath() async {
|
||||
const String argument = 'Get-Process | Format-List Path';
|
||||
return processManager.run(<String>['powershell', '-command', argument]);
|
||||
const List<String> psArgs = <String>['-command', argument];
|
||||
if (processManager.canRun(powershell)) {
|
||||
return processManager.run(<String>[powershell, ...psArgs]);
|
||||
}
|
||||
if (processManager.canRun(pwsh)) {
|
||||
return processManager.run(<String>[pwsh, ...psArgs]);
|
||||
}
|
||||
throw StateError('Failed to find $powershell or $pwsh on PATH');
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import 'package:flutter_tools/src/windows/windows_version_validator.dart';
|
||||
import 'package:test/fake.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/context.dart';
|
||||
|
||||
/// Fake [_WindowsUtils] to use for testing
|
||||
class FakeValidOperatingSystemUtils extends Fake
|
||||
@ -21,14 +22,22 @@ class FakeValidOperatingSystemUtils extends Fake
|
||||
}
|
||||
|
||||
class FakeProcessLister extends Fake implements ProcessLister {
|
||||
FakeProcessLister({required this.result, this.exitCode = 0});
|
||||
FakeProcessLister({
|
||||
required this.result,
|
||||
this.exitCode = 0,
|
||||
this.powershellAvailable = true,
|
||||
});
|
||||
final String result;
|
||||
final int exitCode;
|
||||
final bool powershellAvailable;
|
||||
|
||||
@override
|
||||
Future<ProcessResult> getProcessesWithPath() async {
|
||||
return ProcessResult(0, exitCode, result, null);
|
||||
}
|
||||
|
||||
@override
|
||||
bool canRunPowershell() => powershellAvailable;
|
||||
}
|
||||
|
||||
FakeProcessLister ofdRunning() {
|
||||
@ -43,6 +52,10 @@ FakeProcessLister failure() {
|
||||
return FakeProcessLister(result: r'Path: "C:\Program Files\Google\Chrome\Application\chrome.exe', exitCode: 10);
|
||||
}
|
||||
|
||||
FakeProcessLister powershellUnavailable() {
|
||||
return FakeProcessLister(result: '', powershellAvailable: false);
|
||||
}
|
||||
|
||||
/// The expected validation result object for
|
||||
/// a passing windows version test
|
||||
const ValidationResult validWindows10ValidationResult = ValidationResult(
|
||||
@ -70,6 +83,15 @@ const ValidationResult ofdFoundRunning = ValidationResult(
|
||||
statusInfo: 'Problem detected with Windows installation',
|
||||
);
|
||||
|
||||
const ValidationResult powershellUnavailableResult = ValidationResult(
|
||||
ValidationType.partial,
|
||||
<ValidationMessage>[
|
||||
ValidationMessage.hint('Failed to find ${ProcessLister.powershell} or ${ProcessLister.pwsh} on PATH'),
|
||||
],
|
||||
statusInfo: 'Problem detected with Windows installation',
|
||||
);
|
||||
|
||||
|
||||
const ValidationResult getProcessFailed = ValidationResult(
|
||||
ValidationType.partial,
|
||||
<ValidationMessage>[
|
||||
@ -158,6 +180,18 @@ OS 版本: 10.0.22621 暂缺 Build 22621
|
||||
expect(result.messages[0].message, ofdFoundRunning.messages[0].message, reason: 'The ValidationMessage message should be the same');
|
||||
});
|
||||
|
||||
testWithoutContext('Reports missing powershell', () async {
|
||||
final WindowsVersionValidator validator =
|
||||
WindowsVersionValidator(
|
||||
operatingSystemUtils: FakeValidOperatingSystemUtils(),
|
||||
processLister: powershellUnavailable());
|
||||
final ValidationResult result = await validator.validate();
|
||||
expect(result.type, powershellUnavailableResult.type, reason: 'The ValidationResult type should be the same (partial)');
|
||||
expect(result.statusInfo, powershellUnavailableResult.statusInfo, reason: 'The ValidationResult statusInfo should be the same');
|
||||
expect(result.messages.length, 1, reason: 'The ValidationResult should have precisely 1 message');
|
||||
expect(result.messages[0].message, powershellUnavailableResult.messages[0].message, reason: 'The ValidationMessage message should be the same');
|
||||
});
|
||||
|
||||
testWithoutContext('Reports failure of Get-Process', () async {
|
||||
final WindowsVersionValidator validator =
|
||||
WindowsVersionValidator(
|
||||
@ -169,4 +203,75 @@ OS 版本: 10.0.22621 暂缺 Build 22621
|
||||
expect(result.messages.length, 1, reason: 'The ValidationResult should have precisely 1 message');
|
||||
expect(result.messages[0].message, getProcessFailed.messages[0].message, reason: 'The ValidationMessage message should be the same');
|
||||
});
|
||||
|
||||
testWithoutContext('getProcessesWithPath successfully runs with powershell', () async {
|
||||
final ProcessLister processLister = ProcessLister(
|
||||
FakeProcessManager.list(
|
||||
<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
ProcessLister.powershell,
|
||||
'-command',
|
||||
'Get-Process | Format-List Path',
|
||||
],
|
||||
stdout: ProcessLister.powershell,
|
||||
),
|
||||
],
|
||||
)..excludedExecutables.add(ProcessLister.pwsh),
|
||||
);
|
||||
|
||||
try {
|
||||
final ProcessResult result = await processLister.getProcessesWithPath();
|
||||
expect(result.stdout, ProcessLister.powershell);
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
fail('Unexpected exception: $e');
|
||||
}
|
||||
});
|
||||
|
||||
testWithoutContext('getProcessesWithPath falls back to pwsh when powershell is not on the path', () async {
|
||||
final ProcessLister processLister = ProcessLister(
|
||||
FakeProcessManager.list(
|
||||
<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
ProcessLister.pwsh,
|
||||
'-command',
|
||||
'Get-Process | Format-List Path',
|
||||
],
|
||||
stdout: ProcessLister.pwsh,
|
||||
),
|
||||
],
|
||||
)..excludedExecutables.add(ProcessLister.powershell),
|
||||
);
|
||||
|
||||
try {
|
||||
final ProcessResult result = await processLister.getProcessesWithPath();
|
||||
expect(result.stdout, ProcessLister.pwsh);
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
fail('Unexpected exception: $e');
|
||||
}
|
||||
});
|
||||
|
||||
testWithoutContext('getProcessesWithPath throws if both powershell and pwsh are not on PATH', () async {
|
||||
final ProcessLister processLister = ProcessLister(
|
||||
FakeProcessManager.empty()..excludedExecutables.addAll(
|
||||
<String>[
|
||||
ProcessLister.powershell,
|
||||
ProcessLister.pwsh,
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
final ProcessResult result = await processLister.getProcessesWithPath();
|
||||
fail('Should have thrown, but successfully ran ${result.stdout}');
|
||||
} on StateError {
|
||||
// Expected
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
fail('Unexpected exception: $e');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user