Unverified Commit 4fba7747 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Support Xcode patch version comparison (#61484)

parent a1a5a8f6
......@@ -138,8 +138,8 @@ class UserMessages {
// Messages used in XcodeValidator
String xcodeLocation(String location) => 'Xcode at $location';
String xcodeOutdated(int versionMajor, int versionMinor) =>
'Flutter requires a minimum Xcode version of $versionMajor.$versionMinor.0.\n'
String xcodeOutdated(int versionMajor, int versionMinor, int versionPatch) =>
'Flutter requires a minimum Xcode version of $versionMajor.$versionMinor.$versionPatch.\n'
'Download the latest version or update via the Mac App Store.';
String get xcodeEula => "Xcode end user license agreement not signed; open Xcode or run the command 'sudo xcodebuild -license'.";
String get xcodeMissingSimct =>
......
......@@ -600,7 +600,7 @@ class XcodeBuildExecution {
final Map<String, String> buildSettings;
}
const String _xcodeRequirement = 'Xcode $kXcodeRequiredVersionMajor.$kXcodeRequiredVersionMinor or greater is required to develop for iOS.';
const String _xcodeRequirement = 'Xcode $kXcodeRequiredVersionMajor.$kXcodeRequiredVersionMinor.$kXcodeRequiredVersionPatch or greater is required to develop for iOS.';
bool _checkXcodeVersion() {
if (!globals.platform.isMacOS) {
......
......@@ -261,13 +261,15 @@ class XcodeProjectInterpreter {
return;
}
try {
final RunResult result = _processUtils.runSync(
<String>[_executable, '-version'],
);
if (result.exitCode != 0) {
return;
if (_versionText == null) {
final RunResult result = _processUtils.runSync(
<String>[_executable, '-version'],
);
if (result.exitCode != 0) {
return;
}
_versionText = result.stdout.trim().replaceAll('\n', ', ');
}
_versionText = result.stdout.trim().replaceAll('\n', ', ');
final Match match = _versionRegex.firstMatch(versionText);
if (match == null) {
return;
......@@ -275,7 +277,8 @@ class XcodeProjectInterpreter {
final String version = match.group(1);
final List<String> components = version.split('.');
_majorVersion = int.parse(components[0]);
_minorVersion = components.length == 1 ? 0 : int.parse(components[1]);
_minorVersion = components.length < 2 ? 0 : int.parse(components[1]);
_patchVersion = components.length < 3 ? 0 : int.parse(components[2]);
} on ProcessException {
// Ignored, leave values null.
}
......@@ -307,6 +310,14 @@ class XcodeProjectInterpreter {
return _minorVersion;
}
int _patchVersion;
int get patchVersion {
if (_patchVersion == null) {
_updateVersion();
}
return _patchVersion;
}
/// Asynchronously retrieve xcode build settings. This one is preferred for
/// new call-sites.
///
......
......@@ -27,6 +27,7 @@ import '../reporting/reporting.dart';
const int kXcodeRequiredVersionMajor = 11;
const int kXcodeRequiredVersionMinor = 0;
const int kXcodeRequiredVersionPatch = 0;
enum SdkType {
iPhone,
......@@ -97,8 +98,8 @@ class Xcode {
}
int get majorVersion => _xcodeProjectInterpreter.majorVersion;
int get minorVersion => _xcodeProjectInterpreter.minorVersion;
int get patchVersion => _xcodeProjectInterpreter.patchVersion;
String get versionText => _xcodeProjectInterpreter.versionText;
......@@ -151,6 +152,9 @@ class Xcode {
return true;
}
if (majorVersion == kXcodeRequiredVersionMajor) {
if (minorVersion == kXcodeRequiredVersionMinor) {
return patchVersion >= kXcodeRequiredVersionPatch;
}
return minorVersion >= kXcodeRequiredVersionMinor;
}
return false;
......
......@@ -39,7 +39,7 @@ class XcodeValidator extends DoctorValidator {
if (!_xcode.isInstalledAndMeetsVersionCheck) {
xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.error(
_userMessages.xcodeOutdated(kXcodeRequiredVersionMajor, kXcodeRequiredVersionMinor)
_userMessages.xcodeOutdated(kXcodeRequiredVersionMajor, kXcodeRequiredVersionMinor, kXcodeRequiredVersionPatch)
));
}
......
......@@ -136,49 +136,38 @@ void main() {
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild majorVersion returns major version', () {
testWithoutContext('xcodebuild version parts can be parsed', () {
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode 11.4.1\nBuild version 11N111s',
));
expect(xcodeProjectInterpreter.majorVersion, 11);
expect(xcodeProjectInterpreter.minorVersion, 4);
expect(xcodeProjectInterpreter.patchVersion, 1);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild majorVersion is null when version has unexpected format', () {
testWithoutContext('xcodebuild minor and patch version default to 0', () {
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode Ultra5000\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.majorVersion, isNull);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild minorVersion returns minor version', () {
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode 8.3.3\nBuild version 8E3004b',
stdout: 'Xcode 11\nBuild version 11N111s',
));
expect(xcodeProjectInterpreter.minorVersion, 3);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild minorVersion returns 0 when minor version is unspecified', () {
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode 8\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.majorVersion, 11);
expect(xcodeProjectInterpreter.minorVersion, 0);
expect(xcodeProjectInterpreter.patchVersion, 0);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild minorVersion is null when version has unexpected format', () {
testWithoutContext('xcodebuild version parts is null when version has unexpected format', () {
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode Ultra5000\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.majorVersion, isNull);
expect(xcodeProjectInterpreter.minorVersion, isNull);
expect(xcodeProjectInterpreter.patchVersion, isNull);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
......
......@@ -157,6 +157,7 @@ void main() {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(9);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isVersionSatisfactory, isFalse);
});
......@@ -171,6 +172,7 @@ void main() {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isVersionSatisfactory, isTrue);
});
......@@ -179,6 +181,7 @@ void main() {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(12);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isVersionSatisfactory, isTrue);
});
......@@ -187,6 +190,16 @@ void main() {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(3);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isVersionSatisfactory, isTrue);
});
testWithoutContext('xcodeVersionSatisfactory is true when patch version exceeds minimum', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(1);
expect(xcode.isVersionSatisfactory, isTrue);
});
......@@ -219,6 +232,7 @@ void main() {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isInstalledAndMeetsVersionCheck, isFalse);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
......@@ -233,6 +247,7 @@ void main() {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(10);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(2);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isInstalledAndMeetsVersionCheck, isFalse);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
......@@ -247,6 +262,7 @@ void main() {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isInstalledAndMeetsVersionCheck, isTrue);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
......
......@@ -394,6 +394,9 @@ class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter {
@override
int get minorVersion => 0;
@override
int get patchVersion => 0;
@override
Future<Map<String, String>> getBuildSettings(
String projectPath, {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment