Unverified Commit 2321b72d authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] move gradle download failure handling into tool (#68140)

This crash affects anyone using flutter, so move it into the tool where it can be tested and documented. Ensure it works on windows devicelab too.
parent e800de1a
......@@ -161,10 +161,5 @@ Future<void> cleanupSystem() async {
} else {
print('Could not determine JAVA_HOME; not shutting down Gradle.');
}
// Removes the .gradle directory because sometimes gradle fails in downloading
// a new version and leaves a corrupted zip archive, which could cause the
// next devicelab task to fail.
// https://github.com/flutter/flutter/issues/65277
rmTree(dir('${Platform.environment['HOME']}/.gradle'));
}
}
......@@ -4,6 +4,8 @@
import 'package:meta/meta.dart';
import '../base/error_handling_io.dart';
import '../base/file_system.dart';
import '../base/process.dart';
import '../base/terminal.dart';
import '../globals.dart' as globals;
......@@ -96,8 +98,14 @@ final GradleHandledError permissionDeniedErrorHandler = GradleHandledError(
eventLabel: 'permission-denied',
);
// Gradle crashes for several known reasons when downloading that are not
// actionable by flutter.
/// Gradle crashes for several known reasons when downloading that are not
/// actionable by Flutter.
///
/// The Gradle cache directory must be deleted, otherwise it may attempt to
/// re-use the bad zip file.
///
/// See also:
/// * https://docs.gradle.org/current/userguide/directory_layout.html#dir:gradle_user_home
@visibleForTesting
final GradleHandledError networkErrorHandler = GradleHandledError(
test: _lineMatcher(const <String>[
......@@ -120,6 +128,15 @@ final GradleHandledError networkErrorHandler = GradleHandledError(
'$warningMark Gradle threw an error while downloading artifacts from the network. '
'Retrying to download...'
);
try {
final String homeDir = globals.platform.environment['HOME'];
if (homeDir != null) {
final Directory directory = globals.fs.directory(globals.fs.path.join(homeDir, '.gradle'));
ErrorHandlingFileSystem.deleteIfExists(directory, recursive: true);
}
} on FileSystemException catch (err) {
globals.printTrace('Failed to delete Gradle cache: $err');
}
return GradleBuildStatus.retry;
},
eventLabel: 'network',
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/android/gradle_errors.dart';
import 'package:flutter_tools/src/android/gradle_utils.dart';
import 'package:flutter_tools/src/base/context.dart';
......@@ -37,6 +38,47 @@ void main() {
});
group('network errors', () {
testUsingContext('retries and deletes zip if gradle fails to unzip', () async {
globals.fs.file('foo/.gradle/fizz.zip').createSync(recursive: true);
const String errorMessage = r'''
Exception in thread "main" java.util.zip.ZipException: error in opening zip file
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.(ZipFile.java:225)
at java.util.zip.ZipFile.(ZipFile.java:155)
at java.util.zip.ZipFile.(ZipFile.java:169)
at org.gradle.wrapper.Install.unzip(Install.java:214)
at org.gradle.wrapper.Install.access$600(Install.java:27)
at org.gradle.wrapper.Install$1.call(Install.java:74)
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)
[!] Gradle threw an error while trying to update itself. Retrying the update...
Exception in thread "main" java.util.zip.ZipException: error in opening zip file
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.(ZipFile.java:225)
at java.util.zip.ZipFile.(ZipFile.java:155)
at java.util.zip.ZipFile.(ZipFile.java:169)
at org.gradle.wrapper.Install.unzip(Install.java:214)
at org.gradle.wrapper.Install.access$600(Install.java:27)
at org.gradle.wrapper.Install$1.call(Install.java:74)
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)
''';
expect(formatTestErrorMessage(errorMessage, networkErrorHandler), isTrue);
expect(await networkErrorHandler.handler(), equals(GradleBuildStatus.retry));
expect(globals.fs.file('foo/.gradle/fizz.zip'), isNot(exists));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Platform: () => FakePlatform(environment: <String, String>{'HOME': 'foo/'}),
});
testUsingContext('retries if gradle fails while downloading', () async {
const String errorMessage = r'''
Exception in thread "main" java.io.FileNotFoundException: https://downloads.gradle.org/distributions/gradle-4.1.1-all.zip
......@@ -61,6 +103,9 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
'Retrying to download...'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('retries if gradle fails downloading with proxy error', () async {
......@@ -89,6 +134,9 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
'Retrying to download...'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('retries if gradle times out waiting for exclusive access to zip', () async {
......@@ -108,6 +156,9 @@ Exception in thread "main" java.lang.RuntimeException: Timeout of 120000 reached
'Retrying to download...'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('retries if remote host closes connection', () async {
......@@ -143,6 +194,9 @@ Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host clos
'Retrying to download...'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('retries if file opening fails', () async {
......@@ -170,6 +224,9 @@ Exception in thread "main" java.io.FileNotFoundException: https://downloads.grad
'Retrying to download...'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('retries if the connection is reset', () async {
......@@ -208,6 +265,9 @@ Exception in thread "main" java.net.SocketException: Connection reset
'Retrying to download...'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('retries if Gradle could not get a resource', () async {
......@@ -233,6 +293,9 @@ A problem occurred configuring root project 'android'.
'Retrying to download...'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
});
......
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