Skip to content
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

[flutter_tools] correctly forward error only stdout in non-verbose modes #63815

Merged
merged 5 commits into from
Aug 18, 2020

Conversation

jonahwilliams
Copy link
Member

@jonahwilliams jonahwilliams commented Aug 14, 2020

Description

Xcode is internally aware of the distinction between stderr and stdout, but will forward everything to stdout by default. Providing the -quiet flag will cause it to only surface what it considers an "error" as part of stdout.

Additionally, the inclusion of the "touch" after the assemble script meant that in the event assemble failed, the overall status code would still be 0.

Fixes #63748

@flutter-dashboard flutter-dashboard bot added team Infra upgrades, team productivity, code health, technical debt. See also team: labels. tool Affects the "flutter" command-line tool. See also t: labels. work in progress; do not review labels Aug 14, 2020
@jonahwilliams jonahwilliams marked this pull request as ready for review August 14, 2020 22:21
@@ -280,7 +280,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n";
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh";
Copy link
Member Author

Choose a reason for hiding this comment

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

A reasonable follow up to this PR would be to add an automatic migration using the tooling that @jmagman already wrote, but its not something I have time for right now

Copy link
Member

Choose a reason for hiding this comment

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

I'm guessing it doesn't matter if it gets "tripped" twice in a row?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, just as long as it gets modified at least once

Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't the reason that we were doing this here was that if we fix it to not need the tripwire, we need to update the project with the input/output files? It seems like this sets us up to accidentally change the script later while forgetting that we need to fix all the projects in the wild.

Copy link
Member Author

Choose a reason for hiding this comment

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

The project input/output files are correct and can work 100% of the time, if you are building through flutter. When building through the xcode UI, changing configurations does not lead to any sort of change in files on disk - so Xcode thinks that our task can be skipped.

I have no idea how to fix this.

Copy link
Contributor

Choose a reason for hiding this comment

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

changing configurations does not lead to any sort of change in files on disk - so Xcode thinks that our task can be skipped.

I have no idea how to fix this.

I thought we had a potential solution for this now, inspired by @jmagman's iOS work with App.framework: have three different copies of the framework in ephemeral, rather than just one (e.g., ephemeral/debug/..., ephemeral/profile/..., ephemeral/release/...) and control the linking ourselves with linker flags, including a configuration-variable-based linker search directory.

Copy link
Member Author

Choose a reason for hiding this comment

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

different locations for debug/profile/release artifacts would definitely help. I can't say for sure if it would solve the issue completely

Copy link
Contributor

Choose a reason for hiding this comment

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

Anyway, that part was a tangent. Going back to my main concern: what is the goal for moving this logic out of the project? This PR seems unrelated to the tripwire, and AFAIK nothing has changed since we made a deliberate decision to put the tripwire logic on this side of the divide (per my comment above).

Copy link
Member Author

Choose a reason for hiding this comment

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

I think (now I need to double check, because I could have mixed it up) that ending with && touch was causing failures of the actual script to be suppressed. I bet there is some sort of bash-fu to fix it..

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I see. I missed that there wasn't anything else in macos_assemble.sh before, and thought the error exit you added there was to fix that problem.

Yeah, the current Xcode script is definitely wrong, because it's just two statements. Changing the \n to && should be the easy fix there.

Comment on lines 90 to 95
'VERBOSE_SCRIPT_LOGGING=YES'
else
'-quiet',
'COMPILER_INDEX_STORE_ENABLE=NO',
...environmentVariablesAsXcodeBuildSettings(globals.platform)
], trace: true);
], trace: false);
Copy link
Member

Choose a reason for hiding this comment

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

Would love to combine more logic, iOS and macOS building should look almost the same.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused here; IIRC you recently turned trace on for Windows and Linux to fix missing Dart failure output. Why do we want it for Windows and Linux but not macOS?

Copy link
Member Author

Choose a reason for hiding this comment

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

trace only prints stderr by default, and forwards stdout to our verbose logging (hidden by default). with -quiet, xcode writes errors to stdout so we need to surface them.

Why do we want it for Windows and Linux but not macOS?

Everything is doing something different with error logs 🕵️‍♂️

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I see. Could we use the new stdout error regex logic I added for MSBuild here, so the logic is more unified?

Copy link
Member Author

Choose a reason for hiding this comment

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

with -quiet there shouldn't be any need, since only task stderr should be surfaced

Copy link
Contributor

Choose a reason for hiding this comment

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

But there are other differences in the code flow. For instance, won't your current approach mean that errors are printed in the normal color on macOS, rather than red on every other platform? And any code, future or current, that hooks into the logger mechanism to know what the errors are won't see the macOS error output as errors.

Whereas if you pass .* as an error regex (along with using -quiet) then macOS errors will use the same path through the logger as errors on other platforms.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ahh, cool I didn't know it did that :)

@@ -280,7 +280,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n";
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh";
Copy link
Member

Choose a reason for hiding this comment

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

I'm guessing it doesn't matter if it gets "tripped" twice in a row?

Comment on lines 98 to 99
EchoError "Failed to build ${project_path}."
exit -1
Copy link
Member

Choose a reason for hiding this comment

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

This makes sense for now.
A better solution for both platforms would be to craft one-line error messages (not like the ======================= errors we have now) and echo prefixed with "error " or "warning ". This will show up as a real Xcode error instead of just a failure of a script exiting with nonzero, as discussed in chat one time.

unnamed
unnamed-1
except that's supposed to say "This is an error message" and I'm too lazy to recreate this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Is this something we need to do for our printError calls? That is not that most difficult thing to add...

Copy link
Member

Choose a reason for hiding this comment

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

We are way too chatty with out printError calls to just prepend error . For example, I believe every dart compilation failure line is a separate printError, including the _^_ whatever ASCII annotation line that points to the column of the printed line, so there would be like 5 Xcode errors for every dart compilation error, when there should just be one. I may be misremembering though.

I have a branch for this I never finished, for iOS:
logger.dart

class XcodeScriptPhaseStdoutLogger extends StdoutLogger {
  XcodeScriptPhaseStdoutLogger({
    @required AnsiTerminal terminal,
    @required Stdio stdio,
    @required TimeoutConfiguration timeoutConfiguration,
    StopwatchFactory stopwatchFactory = const StopwatchFactory(),
  }) : super(
    terminal: terminal,
    stdio: stdio,
    outputPreferences: OutputPreferences(
      wrapText: false,
      showColor: false,
    ),
    timeoutConfiguration: timeoutConfiguration,
    stopwatchFactory: stopwatchFactory,
  );

  @override
  void printError(
      String message, {
        StackTrace stackTrace,
        bool emphasis,
        TerminalColor color,
        int indent,
        int hangingIndent,
        bool wrap,
      }) {
    String xcodeMessage = message;
    if (message.contains('Error:')) { // <-- "Error:" was the best indicator I had for a dart issue.
      xcodeMessage = 'error: $message'; 
    } // <-- Probably need more cases here.

    super.printError(
      xcodeMessage,
      stackTrace: stackTrace,
      emphasis: false,
      color: color,
      indent: indent,
      hangingIndent:
      hangingIndent,
      wrap: wrap
    );
  }
}

xcode_backend.sh

  RunCompileCommand "${FLUTTER_ROOT}/bin/flutter"                                \
    ${verbose_flag}                                                       \
    ${flutter_engine_flag}                                                \
    ${local_engine_flag}                                                  \
    assemble                                                              \
    --output="${derived_dir}/"                                            \
    ${performance_measurement_option}                                     \
    --logging-style=xcode-build-phase                                     \
...

assemble.dart

    argParser.addOption(
      'logging-style',
      hide: true,
      allowed: <String>['xcode-build-phase'],
      help: 'Format logging.',
    );

On the right track?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah that seems like a good place to start, though I would leave out the message introspection and instead configure it via the calls to printError

@@ -93,3 +93,12 @@ RunCommand "${FLUTTER_ROOT}/bin/flutter" \
--build-outputs="${build_outputs_path}" \
--output="${ephemeral_dir}" \
"${build_mode}_macos_bundle_flutter_assets"

if [[ $? -ne 0 ]]; then
Copy link
Member

Choose a reason for hiding this comment

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

Hopefully no one ever adds set -e to the top like #50664.

Copy link
Member

@jmagman jmagman left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -280,7 +280,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n";
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh";
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't the reason that we were doing this here was that if we fix it to not need the tripwire, we need to update the project with the input/output files? It seems like this sets us up to accidentally change the script later while forgetting that we need to fix all the projects in the wild.

@@ -93,3 +93,12 @@ RunCommand "${FLUTTER_ROOT}/bin/flutter" \
--build-outputs="${build_outputs_path}" \
--output="${ephemeral_dir}" \
"${build_mode}_macos_bundle_flutter_assets"

if [[ $? -ne 0 ]]; then
Copy link
Contributor

Choose a reason for hiding this comment

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

I forget, is there something blocking us from merging this into the Dart script we're using for Windows and Linux? It would be nice to go in that direction instead of adding even more logic to the shell script version.

Copy link
Member Author

Choose a reason for hiding this comment

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

No, its do-able with some light refactoring besides the tripwire. If we can resolve that its 5 mins of work

Copy link
Contributor

Choose a reason for hiding this comment

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

Couldn't we combine scripts, and have the tripwire logic based on OS (if we really need the tripwire here rather than in the project, which per my other comment I'm still not convinced of)

Copy link
Member Author

Choose a reason for hiding this comment

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

Couldn't we combine scripts, and have the tripwire logic based on OS

We could for new projects, with some backwards compat for macos_assemble (unless we add the project migration support, but like I said I don't really have time for that this week)

Copy link
Contributor

Choose a reason for hiding this comment

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

I was just thinking converting macos_assemble.sh into a thin tool_backend.dart wrapper, not doing an actual migration at this point. Just so we're not adding more bash logic and continuing to maintain bash complexity, when we already have a Dart version that's more testable and more maintainable basically ready to swap in.

Comment on lines 90 to 95
'VERBOSE_SCRIPT_LOGGING=YES'
else
'-quiet',
'COMPILER_INDEX_STORE_ENABLE=NO',
...environmentVariablesAsXcodeBuildSettings(globals.platform)
], trace: true);
], trace: false);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused here; IIRC you recently turned trace on for Windows and Linux to fix missing Dart failure output. Why do we want it for Windows and Linux but not macOS?

@jonahwilliams
Copy link
Member Author

Updated to the minimal && change and to use the error regex

Copy link
Contributor

@stuartmorgan stuartmorgan left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -14,6 +14,8 @@ import '../ios/xcodeproj.dart';
import '../project.dart';
import 'cocoapod_utils.dart';

final RegExp _anyOutput = RegExp('.*');
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's worth commenting why this is done (i.e., the interaction with -quiet) since it's non-obvious without context.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

@fluttergithubbot
Copy link
Contributor

This pull request is not suitable for automatic merging in its current state.

  • The status or check suite tool_tests-general-windows has failed. Please fix the issues identified (or deflake) before re-applying this label.
  • The status or check suite tool_tests-commands-windows has failed. Please fix the issues identified (or deflake) before re-applying this label.
  • The status or check suite tool_tests-integration-windows has failed. Please fix the issues identified (or deflake) before re-applying this label.
  • The status or check suite hostonly_devicelab_tests-0-windows has failed. Please fix the issues identified (or deflake) before re-applying this label.
  • The status or check suite hostonly_devicelab_tests-1-windows has failed. Please fix the issues identified (or deflake) before re-applying this label.
  • The status or check suite hostonly_devicelab_tests-2-windows has failed. Please fix the issues identified (or deflake) before re-applying this label.
  • The status or check suite hostonly_devicelab_tests-3_last-windows has failed. Please fix the issues identified (or deflake) before re-applying this label.
  • The status or check suite customer_testing-windows has failed. Please fix the issues identified (or deflake) before re-applying this label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team Infra upgrades, team productivity, code health, technical debt. See also team: labels. tool Affects the "flutter" command-line tool. See also t: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Build failure does not stop app execution
5 participants