Skip to content

Commit 7874b67

Browse files
cbrackengspencergoog
authored andcommitted
Ensure Xcode major, minor version always return non-null (flutter#10980)
Previously, xcodeMajorVersion and xcodeMinorVersion returned null unless xcodeVersionSatisfactory had been called first. We now compute them on demand, and cache the resultant values.
1 parent 4392e3c commit 7874b67

File tree

2 files changed

+70
-19
lines changed

2 files changed

+70
-19
lines changed

packages/flutter_tools/lib/src/ios/mac.dart

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -121,37 +121,48 @@ class Xcode {
121121
return _eulaSigned;
122122
}
123123

124+
final RegExp xcodeVersionRegex = new RegExp(r'Xcode ([0-9.]+)');
125+
void _updateXcodeVersion() {
126+
try {
127+
_xcodeVersionText = processManager.runSync(<String>['/usr/bin/xcodebuild', '-version']).stdout.replaceAll('\n', ', ');
128+
final Match match = xcodeVersionRegex.firstMatch(xcodeVersionText);
129+
if (match == null)
130+
return;
131+
132+
final String version = match.group(1);
133+
final List<String> components = version.split('.');
134+
_xcodeMajorVersion = int.parse(components[0]);
135+
_xcodeMinorVersion = components.length == 1 ? 0 : int.parse(components[1]);
136+
} on ProcessException {
137+
// Ignore: leave values null.
138+
}
139+
}
140+
124141
String _xcodeVersionText;
125142
String get xcodeVersionText {
126-
if (_xcodeVersionText == null) {
127-
try {
128-
_xcodeVersionText = processManager.runSync(<String>['/usr/bin/xcodebuild', '-version']).stdout.replaceAll('\n', ', ');
129-
} on ProcessException {
130-
// Ignore: return null below.
131-
}
132-
}
143+
if (_xcodeVersionText == null)
144+
_updateXcodeVersion();
133145
return _xcodeVersionText;
134146
}
135147

136148
int _xcodeMajorVersion;
137-
int get xcodeMajorVersion => _xcodeMajorVersion;
149+
int get xcodeMajorVersion {
150+
if (_xcodeMajorVersion == null)
151+
_updateXcodeVersion();
152+
return _xcodeMajorVersion;
153+
}
138154

139155
int _xcodeMinorVersion;
140-
int get xcodeMinorVersion => _xcodeMinorVersion;
141-
142-
final RegExp xcodeVersionRegex = new RegExp(r'Xcode ([0-9.]+)');
156+
int get xcodeMinorVersion {
157+
if (_xcodeMinorVersion == null)
158+
_updateXcodeVersion();
159+
return _xcodeMinorVersion;
160+
}
143161

144162
bool get xcodeVersionSatisfactory {
145163
if (xcodeVersionText == null || !xcodeVersionRegex.hasMatch(xcodeVersionText))
146164
return false;
147-
148-
final String version = xcodeVersionRegex.firstMatch(xcodeVersionText).group(1);
149-
final List<String> components = version.split('.');
150-
151-
_xcodeMajorVersion = int.parse(components[0]);
152-
_xcodeMinorVersion = components.length == 1 ? 0 : int.parse(components[1]);
153-
154-
return _xcodeVersionCheckValid(_xcodeMajorVersion, _xcodeMinorVersion);
165+
return _xcodeVersionCheckValid(xcodeMajorVersion, xcodeMinorVersion);
155166
}
156167

157168
Future<String> getAvailableDevices() async {

packages/flutter_tools/test/ios/mac_test.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,46 @@ void main() {
116116
ProcessManager: () => mockProcessManager,
117117
});
118118

119+
testUsingContext('xcodeMajorVersion returns major version', () {
120+
when(mockProcessManager.runSync(<String>['/usr/bin/xcodebuild', '-version']))
121+
.thenReturn(new ProcessResult(1, 0, 'Xcode 8.3.3\nBuild version 8E3004b', ''));
122+
expect(xcode.xcodeMajorVersion, 8);
123+
}, overrides: <Type, Generator>{
124+
ProcessManager: () => mockProcessManager,
125+
});
126+
127+
testUsingContext('xcodeMajorVersion is null when version has unexpected format', () {
128+
when(mockProcessManager.runSync(<String>['/usr/bin/xcodebuild', '-version']))
129+
.thenReturn(new ProcessResult(1, 0, 'Xcode Ultra5000\nBuild version 8E3004b', ''));
130+
expect(xcode.xcodeMajorVersion, isNull);
131+
}, overrides: <Type, Generator>{
132+
ProcessManager: () => mockProcessManager,
133+
});
134+
135+
testUsingContext('xcodeMinorVersion returns minor version', () {
136+
when(mockProcessManager.runSync(<String>['/usr/bin/xcodebuild', '-version']))
137+
.thenReturn(new ProcessResult(1, 0, 'Xcode 8.3.3\nBuild version 8E3004b', ''));
138+
expect(xcode.xcodeMinorVersion, 3);
139+
}, overrides: <Type, Generator>{
140+
ProcessManager: () => mockProcessManager,
141+
});
142+
143+
testUsingContext('xcodeMinorVersion returns 0 when minor version is unspecified', () {
144+
when(mockProcessManager.runSync(<String>['/usr/bin/xcodebuild', '-version']))
145+
.thenReturn(new ProcessResult(1, 0, 'Xcode 8\nBuild version 8E3004b', ''));
146+
expect(xcode.xcodeMinorVersion, 0);
147+
}, overrides: <Type, Generator>{
148+
ProcessManager: () => mockProcessManager,
149+
});
150+
151+
testUsingContext('xcodeMajorVersion is null when version has unexpected format', () {
152+
when(mockProcessManager.runSync(<String>['/usr/bin/xcodebuild', '-version']))
153+
.thenReturn(new ProcessResult(1, 0, 'Xcode Ultra5000\nBuild version 8E3004b', ''));
154+
expect(xcode.xcodeMinorVersion, isNull);
155+
}, overrides: <Type, Generator>{
156+
ProcessManager: () => mockProcessManager,
157+
});
158+
119159
testUsingContext('eulaSigned is false when clang is not installed', () {
120160
when(mockProcessManager.runSync(<String>['/usr/bin/xcrun', 'clang']))
121161
.thenThrow(const ProcessException('/usr/bin/xcrun', const <String>['clang']));

0 commit comments

Comments
 (0)