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

Add an initial 'build' command to engine_tool #50681

Merged
merged 1 commit into from
Feb 23, 2024

Conversation

johnmccutchan
Copy link
Contributor

  • Adds a 'build' command to et.
  • Renamed query builds to query builders because that seemed to be more precise(?)

Some extra requests during review:

  1. I've left some questions I'd like answers to at the top of build_command.dart I suspect @zanderso and @loic-sharma can give me (some?) answers.
  2. I suspect I'm holding the FakeProcessManager wrong or there is a better way to write the tests in build_command_test.dart. Pointers to good examples are appreciated.

@zanderso
Copy link
Member

Thanks for starting on this =)

I hadn't thought this command all the way through, but my vague thought was that it would leverage the library here as much as makes sense, similar to the example code here.

There are kind of two paths for the build command. Down one path it uses the pre-canned builds from the json files, possibly with some options/targets overridden/added. Down the second path, it ignores the pre-canned builds, and you specify everything, falling back on defaults. The second path can still use the GlobalBuildRunner by hand-crafting a GlobalBuild instead of deserializing one from the json files. I'm not sure what that looks like in terms of command line flags for this command.

// Some wrinkles I'd like to iron out:
// - There can be multiple GlobalBuild objects with the same name. How
// should we deal with these conflicts? "mac_clang_tidy" and
// "mac_host_engine" both define "host_debug".
Copy link
Member

Choose a reason for hiding this comment

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

As far as the CI recipes are concerned, the names don't matter. We can go through the json files and make them unique, and then enforce it in the script here.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

// - There can be multiple GlobalBuild objects with the same name. How
// should we deal with these conflicts? "mac_clang_tidy" and
// "mac_host_engine" both define "host_debug".
// - Naming: Should BuildConfig be BuilderConfig and GlobalBuild be BuildConfig?
Copy link
Member

Choose a reason for hiding this comment

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

That makes sense to me. I'm not married to any of the names, and happy if we can find better ones.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 names

// "mac_host_engine" both define "host_debug".
// - Naming: Should BuildConfig be BuilderConfig and GlobalBuild be BuildConfig?
// - The BuildConfig database seems to be lacking things I expected:
// - There is no "android_debug_*" GlobalBuild in any of the builders that run on mac?
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, the configurations built on CI are a subset of what's useful to build locally. I have some thoughts about that. One is to provide an option to ignore the platform that the build config is asking for. Another is to create some new json files that we only run locally and not on CI. Open to suggestions about what to do.

Copy link
Contributor

Choose a reason for hiding this comment

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

It could also be a sign that we have too many configurations (or too few on CI)

That being said, the easiest suggestion I think is to have local JSON files.

Copy link
Member

@loic-sharma loic-sharma Feb 15, 2024

Choose a reason for hiding this comment

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

Another is to create some new json files that we only run locally and not on CI. Open to suggestions about what to do.

I lean strongly towards introducing new builders for local development. The CI builders run targets/tests that aren't necessary for local development, resulting in a slower inner loop. For example: producing engine .zip archives is rarely necessary when developing.

Crank's builders are a fork of the CI builders targeted for local development scenarios: https://github.com/loic-sharma/crank/blob/4b114fed1668a383e1540b2bf4d29dc0b1dc1148/lib/builders.dart#L5-L359

// - Naming: Should BuildConfig be BuilderConfig and GlobalBuild be BuildConfig?
// - The BuildConfig database seems to be lacking things I expected:
// - There is no "android_debug_*" GlobalBuild in any of the builders that run on mac?
// - The gn flags specified in the GlobalBuilds don't reference rbe or goma? Should this be a local configuration that the user selects?
Copy link
Member

Choose a reason for hiding this comment

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

The gn script and CI try to enable Goma implicitly, so the flag doesn't show up too much in the CI configs.

The migration to RBE is in-progress, but there are a few builds that have it. It has to be requested explicitly both locally and in CI.

// TODO(johnmccutchan): List all available build targets and allow the user
// to specify which one(s) we should build on the cli.

// TODO(johnmccutchan): Can we show a progress indicator like 'running gn...'?
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I think we can copy some code from flutter_tool for this.

/// returns false.
Map<String, BuildConfig> filterBuildConfigs(
Map<String, BuildConfig> input, ConfigFilter test) {
final Map<String, BuildConfig> r = <String, BuildConfig>{};
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a great place for the inline-for, imo:

return {
  for (final entry in input.entries)
    if (test(entry.name, entry.value))
      entry.name: entry.value
};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


List<GlobalBuild> filterBuilds(
Map<String, BuildConfig> input, BuildFilter test) {
final List<GlobalBuild> r = <GlobalBuild>[];
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto here, I'd just use the inline-for:
https://dart.dev/language/collections#control-flow-operators

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


/// A function that returns true or false when given a [BuildConfig] and its
/// name.
typedef ConfigFilter = bool Function(String name, BuildConfig config);
Copy link
Contributor

Choose a reason for hiding this comment

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

Personally (here and below) I'd just inline the function definition.

That avoids having to explain these generically "returns true or false" and you can just document how it's used in the (single?) function below.

// Some wrinkles I'd like to iron out:
// - There can be multiple GlobalBuild objects with the same name. How
// should we deal with these conflicts? "mac_clang_tidy" and
// "mac_host_engine" both define "host_debug".
Copy link
Contributor

Choose a reason for hiding this comment

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

+1

// - There can be multiple GlobalBuild objects with the same name. How
// should we deal with these conflicts? "mac_clang_tidy" and
// "mac_host_engine" both define "host_debug".
// - Naming: Should BuildConfig be BuilderConfig and GlobalBuild be BuildConfig?
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 names

// "mac_host_engine" both define "host_debug".
// - Naming: Should BuildConfig be BuilderConfig and GlobalBuild be BuildConfig?
// - The BuildConfig database seems to be lacking things I expected:
// - There is no "android_debug_*" GlobalBuild in any of the builders that run on mac?
Copy link
Contributor

Choose a reason for hiding this comment

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

It could also be a sign that we have too many configurations (or too few on CI)

That being said, the easiest suggestion I think is to have local JSON files.

argParser.addOption(
_configFlag,
abbr: 'c',
defaultsTo: 'host_debug',
Copy link
Contributor

Choose a reason for hiding this comment

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

Definitely a TODO (unless you feel inspired) but I have the perfect default for you here:

https://github.com/flutter/engine/tree/main/tools/pkg/engine_repo_tools

Specifically:

/// Returns the most recently modified output target in [outDir].
///
/// If there are no output targets, returns `null`.
Output? latestOutput() {
final List<Output> outputs = this.outputs();
if (outputs.isEmpty) {
return null;
}
outputs.sort((Output a, Output b) {
return b.path.statSync().modified.compareTo(a.path.statSync().modified);
});
return outputs.first;
}
}

You can see a recent example of this being used here (not exactly the same, but close):

defaultsTo:
engine?.
outputs().
where((Output o) => basename(o.path.path).startsWith('android_')).
firstOrNull?.
path.path,

Copy link
Member

@loic-sharma loic-sharma Feb 15, 2024

Choose a reason for hiding this comment

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

Personally I'd rather have a deterministic default.

For Crank, you can set your default builder in a ~/.config/crank/config.json config file.

This config file also lets you add your own custom builders, which is useful if the CI builders don't support your desired scenario like Android from a macOS host. See: https://github.com/loic-sharma/crank#custom-builders

Copy link
Member

Choose a reason for hiding this comment

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

Hardcoding a default for now sgtm. I suspect we'll want a config file with defaults at some point, but that's big enough for a separate PR.

.runProcess(commandLine, workingDirectory: environment.engine.outDir);
if (r.exitCode != 0) {
// TODO(johnmccutchan): We probably want to stream the ninja output
// so we can see build progress and compilation failures immediately.
Copy link
Member

Choose a reason for hiding this comment

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

This also loses output colors, which are really helpful. You probably want something like:

Future<int> runProcess(String executable, List<String> arguments) async {
  var process = await Process.start(
    executable,
    arguments,
    runInShell: true,
    mode: ProcessStartMode.inheritStdio,
  );

  return await process.exitCode;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This code has been deleted.

@loic-sharma
Copy link
Member

loic-sharma commented Feb 15, 2024

@johnmccutchan If you haven't already, consider playing with Crank to see what its UX is like: https://github.com/loic-sharma/crank#crank-

If you'd like, I'd be happy to do a quick call to demo it!

@johnmccutchan
Copy link
Contributor Author

Thanks for starting on this =)

I hadn't thought this command all the way through, but my vague thought was that it would leverage the library here as much as makes sense, similar to the example code here.

There are kind of two paths for the build command. Down one path it uses the pre-canned builds from the json files, possibly with some options/targets overridden/added. Down the second path, it ignores the pre-canned builds, and you specify everything, falling back on defaults. The second path can still use the GlobalBuildRunner by hand-crafting a GlobalBuild instead of deserializing one from the json files. I'm not sure what that looks like in terms of command line flags for this command.

I've updated the PR to use GlobalBuildRunner.

tools/engine_tool/lib/src/build_utils.dart Show resolved Hide resolved
tools/engine_tool/lib/src/build_utils.dart Outdated Show resolved Hide resolved
tools/engine_tool/lib/src/commands/build_command.dart Outdated Show resolved Hide resolved
argParser.addOption(
_configFlag,
abbr: 'c',
defaultsTo: 'host_debug',
Copy link
Member

Choose a reason for hiding this comment

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

Hardcoding a default for now sgtm. I suspect we'll want a config file with defaults at some point, but that's big enough for a separate PR.

tools/engine_tool/lib/src/commands/build_command.dart Outdated Show resolved Hide resolved
tools/engine_tool/lib/src/commands/build_command.dart Outdated Show resolved Hide resolved
tools/engine_tool/lib/src/commands/build_command.dart Outdated Show resolved Hide resolved
tools/engine_tool/lib/src/commands/build_command.dart Outdated Show resolved Hide resolved
tools/engine_tool/test/build_command_test.dart Outdated Show resolved Hide resolved
@johnmccutchan johnmccutchan force-pushed the et_build1 branch 3 times, most recently from 7bcee93 to 551edbd Compare February 23, 2024 02:23
@matanlurey
Copy link
Contributor

@johnmccutchan Do you still need help with FakeProcess?

I admit that class sucks, I'd be willing to either (a) work with you to improve it or (b) help you with the specific test(s).

Ping me tomorrow!

Copy link
Member

@zanderso zanderso left a comment

Choose a reason for hiding this comment

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

This is great! I'll make some improvements to the logger after this lands that will help with clearing the progress log messages. (Even when disabling newlines and appending '\r', if a message goes over a single line, then the terminal scrolls...)

@johnmccutchan johnmccutchan merged commit 0f21eba into flutter:main Feb 23, 2024
23 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 23, 2024
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Feb 23, 2024
…144041)

flutter/engine@b5bebfe...fbc9b88

2024-02-23 [email protected] Roll Skia from 037e08e92598 to 49dd7ed24bec (3 revisions) (flutter/engine#50916)
2024-02-23 [email protected] Add an initial 'build' command to engine_tool (flutter/engine#50681)
2024-02-23 [email protected] Roll Dart SDK from 7f6eccd65255 to 9849ca5fcaec (1 revision) (flutter/engine#50915)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants