Suppress stderr during Xcode command line installation check (#163785)
Xcode is in some kind of half-installed state (missing a cert? unknown)
on some devicelab Macs https://github.com/flutter/flutter/issues/161655.
As of https://github.com/flutter/flutter/pull/163685 Xcode cipd
installation isn't requested as part of the builder configuration, so it
seems like Xcode is just hanging out on that devicelab bot
quasi-installed, unrelated to the recipe.
In any case, the tool is actually doing the right thing and detecting
that Xcode isn't in a good state and continuing as if it isn't
installed, but is logging a wall of error text about it to stderr, which
that Android test doesn't like. Instead of updating the test to allow
stderr, instead swap the Xcode installation path to `exitsHappySync` to
only check the exit code (or exception), which is the original intention
behind the Xcode command line checks.
e6730613c9/packages/flutter_tools/lib/src/base/process.dart (L596-L601)
Fixes https://github.com/flutter/flutter/issues/161655
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
If you need help, consider asking for advice on the #hackers-new channel
on [Discord].
<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
911aa7547e
commit
bb306c53a3
@ -172,22 +172,15 @@ class Xcode {
|
|||||||
|
|
||||||
/// Verifies that simctl is installed by trying to run it.
|
/// Verifies that simctl is installed by trying to run it.
|
||||||
bool get isSimctlInstalled {
|
bool get isSimctlInstalled {
|
||||||
if (_isSimctlInstalled == null) {
|
// This command will error if additional components need to be installed in
|
||||||
try {
|
// xcode 9.2 and above.
|
||||||
// This command will error if additional components need to be installed in
|
_isSimctlInstalled ??= _processUtils.exitsHappySync(<String>[
|
||||||
// xcode 9.2 and above.
|
...xcrunCommand(),
|
||||||
final RunResult result = _processUtils.runSync(<String>[
|
'simctl',
|
||||||
...xcrunCommand(),
|
'list',
|
||||||
'simctl',
|
'devices',
|
||||||
'list',
|
'booted',
|
||||||
'devices',
|
]);
|
||||||
'booted',
|
|
||||||
]);
|
|
||||||
_isSimctlInstalled = result.exitCode == 0;
|
|
||||||
} on ProcessException {
|
|
||||||
_isSimctlInstalled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _isSimctlInstalled ?? false;
|
return _isSimctlInstalled ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,20 +190,15 @@ class Xcode {
|
|||||||
/// to run it. `devicectl` is made available in Xcode 15.
|
/// to run it. `devicectl` is made available in Xcode 15.
|
||||||
bool get isDevicectlInstalled {
|
bool get isDevicectlInstalled {
|
||||||
if (_isDevicectlInstalled == null) {
|
if (_isDevicectlInstalled == null) {
|
||||||
try {
|
if (currentVersion == null || currentVersion!.major < 15) {
|
||||||
if (currentVersion == null || currentVersion!.major < 15) {
|
|
||||||
_isDevicectlInstalled = false;
|
|
||||||
return _isDevicectlInstalled!;
|
|
||||||
}
|
|
||||||
final RunResult result = _processUtils.runSync(<String>[
|
|
||||||
...xcrunCommand(),
|
|
||||||
'devicectl',
|
|
||||||
'--version',
|
|
||||||
]);
|
|
||||||
_isDevicectlInstalled = result.exitCode == 0;
|
|
||||||
} on ProcessException {
|
|
||||||
_isDevicectlInstalled = false;
|
_isDevicectlInstalled = false;
|
||||||
|
return _isDevicectlInstalled!;
|
||||||
}
|
}
|
||||||
|
_isDevicectlInstalled = _processUtils.exitsHappySync(<String>[
|
||||||
|
...xcrunCommand(),
|
||||||
|
'devicectl',
|
||||||
|
'--version',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
return _isDevicectlInstalled ?? false;
|
return _isDevicectlInstalled ?? false;
|
||||||
}
|
}
|
||||||
|
@ -78,18 +78,45 @@ void main() {
|
|||||||
fakeProcessManager.addCommand(
|
fakeProcessManager.addCommand(
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['xcrun', 'simctl', 'list', 'devices', 'booted'],
|
command: <String>['xcrun', 'simctl', 'list', 'devices', 'booted'],
|
||||||
|
stderr: 'failed to run',
|
||||||
exitCode: 1,
|
exitCode: 1,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final Xcode xcode = Xcode.test(
|
final Xcode xcode = Xcode.test(
|
||||||
processManager: fakeProcessManager,
|
processManager: fakeProcessManager,
|
||||||
xcodeProjectInterpreter: xcodeProjectInterpreter,
|
xcodeProjectInterpreter: xcodeProjectInterpreter,
|
||||||
|
logger: logger,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(xcode.isSimctlInstalled, isFalse);
|
expect(xcode.isSimctlInstalled, isFalse);
|
||||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
|
expect(logger.statusText, isEmpty);
|
||||||
|
expect(logger.errorText, isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext(
|
||||||
|
'isSimctlInstalled is false when simctl list throws process exception',
|
||||||
|
() {
|
||||||
|
fakeProcessManager.addCommand(
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>['xcrun', 'simctl', 'list', 'devices', 'booted'],
|
||||||
|
exception: ProcessException('xcrun', <String>['simctl']),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final Xcode xcode = Xcode.test(
|
||||||
|
processManager: fakeProcessManager,
|
||||||
|
xcodeProjectInterpreter: xcodeProjectInterpreter,
|
||||||
|
logger: logger,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(xcode.isSimctlInstalled, isFalse);
|
||||||
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
|
expect(logger.statusText, isEmpty);
|
||||||
|
expect(logger.errorText, isEmpty);
|
||||||
|
expect(logger.traceText, contains('ProcessException'));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
group('isDevicectlInstalled', () {
|
group('isDevicectlInstalled', () {
|
||||||
testWithoutContext('is true when Xcode is 15+ and devicectl succeeds', () {
|
testWithoutContext('is true when Xcode is 15+ and devicectl succeeds', () {
|
||||||
fakeProcessManager.addCommand(
|
fakeProcessManager.addCommand(
|
||||||
@ -113,10 +140,35 @@ void main() {
|
|||||||
final Xcode xcode = Xcode.test(
|
final Xcode xcode = Xcode.test(
|
||||||
processManager: fakeProcessManager,
|
processManager: fakeProcessManager,
|
||||||
xcodeProjectInterpreter: xcodeProjectInterpreter,
|
xcodeProjectInterpreter: xcodeProjectInterpreter,
|
||||||
|
logger: logger,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(xcode.isDevicectlInstalled, isFalse);
|
expect(xcode.isDevicectlInstalled, isFalse);
|
||||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
|
expect(logger.statusText, isEmpty);
|
||||||
|
expect(logger.errorText, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('is false when devicectl throws process exception', () {
|
||||||
|
fakeProcessManager.addCommand(
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>['xcrun', 'devicectl', '--version'],
|
||||||
|
exitCode: 1,
|
||||||
|
exception: ProcessException('xcrun', <String>['devicectl']),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
xcodeProjectInterpreter.version = Version(15, 0, 0);
|
||||||
|
final Xcode xcode = Xcode.test(
|
||||||
|
processManager: fakeProcessManager,
|
||||||
|
xcodeProjectInterpreter: xcodeProjectInterpreter,
|
||||||
|
logger: logger,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(xcode.isDevicectlInstalled, isFalse);
|
||||||
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
|
expect(logger.statusText, isEmpty);
|
||||||
|
expect(logger.errorText, isEmpty);
|
||||||
|
expect(logger.traceText, contains('ProcessException'));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('is false when Xcode is less than 15', () {
|
testWithoutContext('is false when Xcode is less than 15', () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user