blob: 6f9b6adffe56e2ac5946d513ca92319bd7484eeb [file] [log] [blame]
// Copyright 2013 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 'dart:ffi' as ffi;
import 'dart:io' as io;
import 'package:engine_build_configs/engine_build_configs.dart';
import 'package:engine_repo_tools/engine_repo_tools.dart';
import 'package:path/path.dart' as p;
import 'package:platform/platform.dart';
import 'package:process_runner/process_runner.dart';
// This is an example of how to use the APIs of this library to parse and
// execute the build configurations json files under ci/builders.
//
// Usage:
// $ dart bin/run.dart [build config name] [build name]
// For example:
// $ dart bin/run.dart mac_unopt host_debug_unopt
//
// The build config names are the names of the json files under ci/builders
// The build names are the "name" fields of the maps in the list of "builds".
void main(List<String> args) async {
final String? configName;
final String? buildName;
if (args.length >= 2) {
configName = args[0];
buildName = args[1];
} else {
io.stderr.writeln(r'''
Usage:
$ dart bin/run.dart [build config name] [build name]
For example:
$ dart bin/run.dart mac_unopt host_debug_unopt
The build config names are the names of the json files under ci/builders.
The build names are the "name" fields of the maps in the list of "builds".
''');
io.exitCode = 1;
return;
}
// Find the engine repo.
final Engine engine;
try {
engine = Engine.findWithin();
} catch (e) {
io.stderr.writeln(e);
io.exitCode = 1;
return;
}
// Find and parse the engine build configs.
final io.Directory buildConfigsDir = io.Directory(p.join(
engine.flutterDir.path,
'ci',
'builders',
));
final BuildConfigLoader loader = BuildConfigLoader(
buildConfigsDir: buildConfigsDir,
);
// Treat it as an error if no build configs were found. The caller likely
// expected to find some.
final Map<String, BuilderConfig> configs = loader.configs;
if (configs.isEmpty) {
io.stderr.writeln(
'Error: No build configs found under ${buildConfigsDir.path}',
);
io.exitCode = 1;
return;
}
if (loader.errors.isNotEmpty) {
loader.errors.forEach(io.stderr.writeln);
io.exitCode = 1;
}
// Check the parsed build configs for validity.
final BuilderConfig? targetConfig = configs[configName];
if (targetConfig == null) {
io.stderr.writeln('Build config "$configName" not found.');
io.exitCode = 1;
return;
}
final List<String> buildConfigErrors = targetConfig.check(configName);
if (buildConfigErrors.isNotEmpty) {
io.stderr.writeln('Errors in "$configName":');
for (final String error in buildConfigErrors) {
io.stderr.writeln(' $error');
}
io.exitCode = 1;
return;
}
Build? targetBuild;
for (int i = 0; i < targetConfig.builds.length; i++) {
final Build build = targetConfig.builds[i];
if (build.name == buildName) {
targetBuild = build;
}
}
if (targetBuild == null) {
io.stderr.writeln(
'Target build not found. No build called $buildName in $configName',
);
io.exitCode = 1;
return;
}
// If RBE config files aren't in the tree, then disable RBE.
final String rbeConfigPath = p.join(
engine.srcDir.path,
'flutter',
'build',
'rbe',
);
final List<String> extraGnArgs = <String>[
if (!io.Directory(rbeConfigPath).existsSync()) '--no-rbe',
];
final BuildRunner buildRunner = BuildRunner(
platform: const LocalPlatform(),
processRunner: ProcessRunner(),
abi: ffi.Abi.current(),
engineSrcDir: engine.srcDir,
build: targetBuild,
extraGnArgs: extraGnArgs,
runGenerators: false,
runTests: false,
);
void handler(RunnerEvent event) {
switch (event) {
case RunnerStart():
io.stdout.writeln('$event: ${event.command.join(' ')}');
case RunnerProgress(done: true):
io.stdout.writeln(event);
case RunnerProgress(done: false):
{
final int width = io.stdout.terminalColumns;
final String percent = '${event.percent.toStringAsFixed(1)}%';
final String fraction = '(${event.completed}/${event.total})';
final String prefix = '[${event.name}] $percent $fraction ';
final int remainingSpace = width - prefix.length;
final String what;
if (remainingSpace >= event.what.length) {
what = event.what;
} else {
what = event.what.substring(event.what.length - remainingSpace + 1);
}
final String spaces = ' ' * width;
io.stdout.write('$spaces\r'); // Erase the old line.
io.stdout.write('$prefix$what\r'); // Print the new line.
}
default:
io.stdout.writeln(event);
}
}
final bool buildResult = await buildRunner.run(handler);
io.exitCode = buildResult ? 0 : 1;
}