Unverified Commit 39e4d9d1 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Expand scope of rethrown gradle errors (#42966)

parent f7018c2a
......@@ -304,6 +304,18 @@ String _locateGradlewExecutable(Directory directory) {
return null;
}
// Gradle crashes for several known reasons when downloading that are not
// actionable by flutter.
const List<String> _kKnownErrorPrefixes = <String>[
'java.io.FileNotFoundException: https://downloads.gradle.org',
'java.io.IOException: Unable to tunnel through proxy',
'java.lang.RuntimeException: Timeout of',
'java.util.zip.ZipException: error in opening zip file',
'javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake',
'java.net.SocketException: Connection reset',
'java.io.FileNotFoundException',
];
// Note: Gradle may be bootstrapped and possibly downloaded as a side-effect
// of validating the Gradle executable. This may take several seconds.
Future<String> _initializeGradle(FlutterProject project) async {
......@@ -333,9 +345,25 @@ Future<String> _initializeGradle(FlutterProject project) async {
);
} on ProcessException catch (e) {
final String error = e.toString();
if (error.contains('java.io.FileNotFoundException: https://downloads.gradle.org') ||
error.contains('java.io.IOException: Unable to tunnel through proxy')) {
throwToolExit('$gradle threw an error while trying to update itself.\n$e');
// TODO(jonahwilliams): automatically retry on network errors.
if (_kKnownErrorPrefixes.any((String candidate) => error.contains(candidate))) {
throwToolExit(
'$gradle threw an error while trying to update itself.'
' Try rerunning to retry the update.\n$e');
}
// gradlew is missing execute.
if (error.contains('Permission denied')) {
throwToolExit(
'$gradle does not have permission to execute by your user.\n'
'You should change the ownership of the project directory to your user'
', or move the project to a directory with execute permissions.\n$error'
);
}
// No idea what went wrong but we can't do anything about it.
if (error.contains('ProcessException: Process exited abnormally')) {
throwToolExit(
'$gradle exited abnormally. Try rerunning with \'-v\' for more '
'infomration, or check the gradlew script above for errors.\n$error');
}
rethrow;
} finally {
......
......@@ -861,7 +861,7 @@ flutter:
});
});
group('Gradle HTTP failures', () {
group('Gradle failures', () {
MemoryFileSystem fs;
Directory tempDir;
Directory gradleWrapperDirectory;
......@@ -969,6 +969,245 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws toolExit if gradle is missing execute permissions. ', () async {
final List<String> cmd = <String>[
fs.path.join(fs.currentDirectory.path, 'android', gradleBinary),
'-v',
];
final ProcessException exception = ProcessException(
gradleBinary,
<String>['-v'],
'Permission denied\nCommand: /home/android/gradlew -v',
1,
);
when(mockProcessManager.run(cmd, workingDirectory: anyNamed('workingDirectory'), environment: anyNamed('environment')))
.thenThrow(exception);
await expectLater(() async {
await checkGradleDependencies();
}, throwsToolExit(message: 'does not have permission to execute by your user'));
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws toolExit if gradle times out waiting for exclusive access to zip', () async {
final List<String> cmd = <String>[
fs.path.join(fs.currentDirectory.path, 'android', gradleBinary),
'-v',
];
const String errorMessage = '''
Exception in thread "main" java.lang.RuntimeException: Timeout of 120000 reached waiting for exclusive access to file: /User/documents/gradle-5.6.2-all.zip
at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:61)
at org.gradle.wrapper.Install.createDist(Install.java:48)
at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:128)
at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
final ProcessException exception = ProcessException(
gradleBinary,
<String>['-v'],
errorMessage,
1,
);
when(mockProcessManager.run(cmd, workingDirectory: anyNamed('workingDirectory'), environment: anyNamed('environment')))
.thenThrow(exception);
await expectLater(() async {
await checkGradleDependencies();
}, throwsToolExit(message: errorMessage));
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws toolExit if gradle fails to unzip file', () async {
final List<String> cmd = <String>[
fs.path.join(fs.currentDirectory.path, 'android', gradleBinary),
'-v',
];
const String errorMessage = '''
Exception in thread "main" java.util.zip.ZipException: error in opening zip file /User/documents/gradle-5.6.2-all.zip
at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:61)
at org.gradle.wrapper.Install.createDist(Install.java:48)
at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:128)
at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
final ProcessException exception = ProcessException(
gradleBinary,
<String>['-v'],
errorMessage,
1,
);
when(mockProcessManager.run(cmd, workingDirectory: anyNamed('workingDirectory'), environment: anyNamed('environment')))
.thenThrow(exception);
await expectLater(() async {
await checkGradleDependencies();
}, throwsToolExit(message: errorMessage));
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws toolExit if remote host closes connection', () async {
final List<String> cmd = <String>[
fs.path.join(fs.currentDirectory.path, 'android', gradleBinary),
'-v',
];
const String errorMessage = '''
Downloading https://services.gradle.org/distributions/gradle-5.6.2-all.zip
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:994)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.followRedirect0(HttpURLConnection.java:2729)
at sun.net.www.protocol.http.HttpURLConnection.followRedirect(HttpURLConnection.java:2641)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1824)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:263)
at org.gradle.wrapper.Download.downloadInternal(Download.java:58)
at org.gradle.wrapper.Download.download(Download.java:44)
at org.gradle.wrapper.Install\$1.call(Install.java:61)
at org.gradle.wrapper.Install\$1.call(Install.java:48)
at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:65)
at org.gradle.wrapper.Install.createDist(Install.java:48)
at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:128)
at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
final ProcessException exception = ProcessException(
gradleBinary,
<String>['-v'],
errorMessage,
1,
);
when(mockProcessManager.run(cmd, workingDirectory: anyNamed('workingDirectory'), environment: anyNamed('environment')))
.thenThrow(exception);
await expectLater(() async {
await checkGradleDependencies();
}, throwsToolExit(message: errorMessage));
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws toolExit if file opening fails', () async {
final List<String> cmd = <String>[
fs.path.join(fs.currentDirectory.path, 'android', gradleBinary),
'-v',
];
const String errorMessage = r'''
Downloading https://services.gradle.org/distributions/gradle-3.5.0-all.zip
Exception in thread "main" java.io.FileNotFoundException: https://downloads.gradle-dn.com/distributions/gradle-3.5.0-all.zip
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1890)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:263)
at org.gradle.wrapper.Download.downloadInternal(Download.java:58)
at org.gradle.wrapper.Download.download(Download.java:44)
at org.gradle.wrapper.Install$1.call(Install.java:61)
at org.gradle.wrapper.Install$1.call(Install.java:48)
at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:65)
at org.gradle.wrapper.Install.createDist(Install.java:48)
at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:128)
at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
final ProcessException exception = ProcessException(
gradleBinary,
<String>['-v'],
errorMessage,
1,
);
when(mockProcessManager.run(cmd, workingDirectory: anyNamed('workingDirectory'), environment: anyNamed('environment')))
.thenThrow(exception);
await expectLater(() async {
await checkGradleDependencies();
}, throwsToolExit(message: errorMessage));
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws toolExit if the connection is reset', () async {
final List<String> cmd = <String>[
fs.path.join(fs.currentDirectory.path, 'android', gradleBinary),
'-v',
];
const String errorMessage = '''
Downloading https://services.gradle.org/distributions/gradle-5.6.2-all.zip
Exception in thread "main" java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:210)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.readV3Record(InputRecord.java:593)
at sun.security.ssl.InputRecord.read(InputRecord.java:532)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1564)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:263)
at org.gradle.wrapper.Download.downloadInternal(Download.java:58)
at org.gradle.wrapper.Download.download(Download.java:44)
at org.gradle.wrapper.Install\$1.call(Install.java:61)
at org.gradle.wrapper.Install\$1.call(Install.java:48)
at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:65)
at org.gradle.wrapper.Install.createDist(Install.java:48)
at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:128)
at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
final ProcessException exception = ProcessException(
gradleBinary,
<String>['-v'],
errorMessage,
1,
);
when(mockProcessManager.run(cmd, workingDirectory: anyNamed('workingDirectory'), environment: anyNamed('environment')))
.thenThrow(exception);
await expectLater(() async {
await checkGradleDependencies();
}, throwsToolExit(message: errorMessage));
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws toolExit if gradle exits abnormally', () async {
final List<String> cmd = <String>[
fs.path.join(fs.currentDirectory.path, 'android', gradleBinary),
'-v',
];
const String errorMessage = '''
ProcessException: Process exited abnormally:
Exception in thread "main" java.lang.NullPointerException
at org.gradle.wrapper.BootstrapMainStarter.findLauncherJar(BootstrapMainStarter.java:34)
at org.gradle.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:25)
at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:129)
at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
final ProcessException exception = ProcessException(
gradleBinary,
<String>['-v'],
errorMessage,
1,
);
when(mockProcessManager.run(cmd, workingDirectory: anyNamed('workingDirectory'), environment: anyNamed('environment')))
.thenThrow(exception);
await expectLater(() async {
await checkGradleDependencies();
}, throwsToolExit(message: errorMessage));
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
});
group('injectGradleWrapperIfNeeded', () {
......
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