Skip to content

[flutter_tools] post process the gradle log output #71499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 11 additions & 33 deletions packages/flutter_tools/lib/src/android/gradle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import '../globals.dart' as globals;
import '../project.dart';
import '../reporting/reporting.dart';
import 'gradle_errors.dart';
import 'gradle_log_processor.dart';
import 'gradle_utils.dart';

/// The directory where the APK artifact is generated.
Expand Down Expand Up @@ -360,31 +361,7 @@ Future<void> buildGradleApp({
}
command.add(assembleTask);

GradleHandledError detectedGradleError;
String detectedGradleErrorLine;
String consumeLog(String line) {
// This message was removed from first-party plugins,
// but older plugin versions still display this message.
if (androidXPluginWarningRegex.hasMatch(line)) {
// Don't pipe.
return null;
}
if (detectedGradleError != null) {
// Pipe stdout/stderr from Gradle.
return line;
}
for (final GradleHandledError gradleError in localGradleErrors) {
if (gradleError.test(line)) {
detectedGradleErrorLine = line;
detectedGradleError = gradleError;
// The first error match wins.
break;
}
}
// Pipe stdout/stderr from Gradle.
return line;
}

final GradleLogProcessor gradleLogProcessor = GradleLogProcessor(localGradleErrors, globals.logger.isVerbose);
final Stopwatch sw = Stopwatch()..start();
int exitCode = 1;
try {
Expand All @@ -393,13 +370,14 @@ Future<void> buildGradleApp({
workingDirectory: project.android.hostAppGradleRoot.path,
allowReentrantFlutter: true,
environment: gradleEnvironment,
mapFunction: consumeLog,
mapFunction: gradleLogProcessor.consumeLog,
);
} on ProcessException catch (exception) {
consumeLog(exception.toString());
gradleLogProcessor.atFailureFooter = false;
gradleLogProcessor.consumeLog(exception.toString());
// Rethrow the exception if the error isn't handled by any of the
// `localGradleErrors`.
if (detectedGradleError == null) {
if (gradleLogProcessor.detectedGradleError == null) {
rethrow;
}
} finally {
Expand All @@ -409,22 +387,22 @@ Future<void> buildGradleApp({
globals.flutterUsage.sendTiming('build', 'gradle', sw.elapsed);

if (exitCode != 0) {
if (detectedGradleError == null) {
if (gradleLogProcessor.detectedGradleError == null) {
BuildEvent('gradle-unknown-failure', flutterUsage: globals.flutterUsage).send();
throwToolExit(
'Gradle task $assembleTask failed with exit code $exitCode',
exitCode: exitCode,
);
} else {
final GradleBuildStatus status = await detectedGradleError.handler(
line: detectedGradleErrorLine,
final GradleBuildStatus status = await gradleLogProcessor.detectedGradleError.handler(
line: gradleLogProcessor.detectedGradleErrorLine,
project: project,
usesAndroidX: usesAndroidX,
shouldBuildPluginAsAar: shouldBuildPluginAsAar,
);

if (retries >= 1) {
final String successEventLabel = 'gradle-${detectedGradleError.eventLabel}-success';
final String successEventLabel = 'gradle-${gradleLogProcessor.detectedGradleError.eventLabel}-success';
switch (status) {
case GradleBuildStatus.retry:
await buildGradleApp(
Expand Down Expand Up @@ -454,7 +432,7 @@ Future<void> buildGradleApp({
// noop.
}
}
BuildEvent('gradle-${detectedGradleError.eventLabel}-failure', flutterUsage: globals.flutterUsage).send();
BuildEvent('gradle-${gradleLogProcessor.detectedGradleError.eventLabel}-failure', flutterUsage: globals.flutterUsage).send();
throwToolExit(
'Gradle task $assembleTask failed with exit code $exitCode',
exitCode: exitCode,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'gradle_errors.dart';

/// Process log output from gradle, removing irrelevant output and capturing
/// exception information.
class GradleLogProcessor {
GradleLogProcessor(this.localGradleErrors, this.verbose);

final List<GradleHandledError> localGradleErrors;
final bool verbose;

GradleHandledError detectedGradleError;
String detectedGradleErrorLine;
bool atFailureFooter = false;

String consumeLog(String line) {
// All gradle failures lead to a fairly long footer which contains mostly
// irrelevant information for a flutter build, along with misleading advice to
// run with --stacktrace (which does not exist for the flutter CLI). remove this.
if (!verbose && (line.startsWith('FAILURE: Build failed with an exception.') || atFailureFooter)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way split on output that we control instead of a line from gradle? Like could the tool emit a known line from the recursive call?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate a bit on what that would be used for?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, just taking a possibly naive look at the example 'before' output in the PR description, we have:

[lines emitted by the tool or the Dart compiler]
FAILURE: Build failed with an exception. [First line emitted by gradle?]
[more lines emitted by gradle]
[more lines emitted by the tool]

Instead of detecting gradle output using the first line emitted by gradle, which we don't control, the idea would be to detect gradle output using the last line of [lines emitted by the tool or the Dart compiler], which we do control, adding a new sentinel line there if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't hide all Gradle output though. For example, a compilation error in the users Java code:

If you are deploying the app to the Play Store, it's recommended to use app bundles or split the APK to reduce the APK size.
    To generate an app bundle, run:
        flutter build appbundle --target-platform android-arm,android-arm64,android-x64
        Learn more: https://developer.android.com/guide/app-bundle
    To split the APKs per ABI, run:
        flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi
        Learn more: https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split
/Users/jonahwilliams/Documents/flutter/dev/integration_tests/flutter_gallery/android/app/src/main/java/io/flutter/demo/gallery/MainActivity.java:11: error: '{' expected
public class MainActivity extends FlutterActivity                       
                                                 ^                      
1 error                                                                 
                                                                        
FAILURE: Build failed with an exception.                                
                                                                        
* What went wrong:                                                      
Execution failed for task ':app:compileReleaseJavaWithJavac'.           
> Compilation failed; see the compiler error output for details.        
                                                                        
* Try:                                                                  
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
                                                                        
* Get more help at https://help.gradle.org                              
                                                                        
BUILD FAILED in 55s                  

We still want to chop off the footer since it is wrong, but we need to show the output from the javac task

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, okay. Got it. Thanks.

atFailureFooter = true;
return null;
}
// This message was removed from first-party plugins,
// but older plugin versions still display this message.
if (androidXPluginWarningRegex.hasMatch(line)) {
// Don't pipe.
return null;
}
if (detectedGradleError != null) {
// Pipe stdout/stderr from Gradle.
return line;
}
for (final GradleHandledError gradleError in localGradleErrors) {
if (gradleError.test(line)) {
detectedGradleErrorLine = line;
detectedGradleError = gradleError;
// The first error match wins.
break;
}
}
// Pipe stdout/stderr from Gradle.
return line;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter_tools/src/android/gradle_errors.dart';
import 'package:flutter_tools/src/android/gradle_log_processor.dart';

import '../../src/common.dart';

final List<String> gradleErrorOutputLines = r'''
Some other stuff.
FAILURE: Build failed with an exception.

* Where:
Script '/Users/mit/dev/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 900

* What went wrong:
Execution failed for task ':app:compileFlutterBuildRelease'.
> Process 'command '/Users/mit/dev/flutter/bin/flutter'' finished with non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 24s
'''.split('\n');

void main() {
testWithoutContext('Does not print failure footer in non-verbose mode', () async {
final GradleLogProcessor gradleLogProcessor = GradleLogProcessor(<GradleHandledError>[], false);

expect(gradleErrorOutputLines.map(gradleLogProcessor.consumeLog).where((String line) => line != null), <String>['Some other stuff.']);
expect(gradleLogProcessor.atFailureFooter, true);
});

testWithoutContext('Does print failure footer in verbose mode', () async {
final GradleLogProcessor gradleLogProcessor = GradleLogProcessor(<GradleHandledError>[], true);

expect(gradleErrorOutputLines.map(gradleLogProcessor.consumeLog).where((String line) => line != null), gradleErrorOutputLines);
expect(gradleLogProcessor.atFailureFooter, false);
});
}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy