[et] Add support for building Dart SDK from source
diff --git a/tools/engine_tool/lib/src/build_plan.dart b/tools/engine_tool/lib/src/build_plan.dart
index ccfbfeb..cc620e2 100644
--- a/tools/engine_tool/lib/src/build_plan.dart
+++ b/tools/engine_tool/lib/src/build_plan.dart
@@ -11,6 +11,8 @@
 import 'environment.dart';
 import 'logger.dart';
 
+const _flagBuildDart = 'build-dart';
+const _flagBuildDartFull = 'build-dart-full';
 const _flagConfig = 'config';
 const _flagConcurrency = 'concurrency';
 const _flagStrategy = 'build-strategy';
@@ -65,6 +67,15 @@
         }
         return !build.gn.contains('--no-lto');
       }(),
+      buildDart: () {
+        if (args.flag(_flagBuildDartFull)) {
+          return BuildDart.buildFull;
+        }
+        if (args.flag(_flagBuildDart)) {
+          return BuildDart.build;
+        }
+        return BuildDart.prebuilt;
+      }(),
       concurrency: () {
         final value = args.option(_flagConcurrency);
         if (value == null) {
@@ -84,6 +95,7 @@
     required this.useRbe,
     required this.useLto,
     required this.concurrency,
+    required this.buildDart,
   }) {
     if (!useRbe && strategy == BuildStrategy.remote) {
       throw FatalError(
@@ -156,6 +168,16 @@
       }(),
     );
 
+    /// Adds the --build-dart and --build-dart-full flags.
+    parser.addFlag(
+      _flagBuildDart,
+      help: 'Build Dart from source.',
+    );
+    parser.addFlag(
+      _flagBuildDartFull,
+      help: 'Build the full Dart SDK from source.',
+    );
+
     // Add --build-strategy.
     parser.addOption(
       _flagStrategy,
@@ -201,6 +223,9 @@
   /// Whether to build with LTO (link-time optimization).
   final bool useLto;
 
+  /// Whether to build Dart from source or not.
+  final BuildDart buildDart;
+
   @override
   bool operator ==(Object other) {
     return other is BuildPlan &&
@@ -208,12 +233,20 @@
         strategy == other.strategy &&
         useRbe == other.useRbe &&
         useLto == other.useLto &&
-        concurrency == other.concurrency;
+        concurrency == other.concurrency &&
+        buildDart == other.buildDart;
   }
 
   @override
   int get hashCode {
-    return Object.hash(build.name, strategy, useRbe, useLto, concurrency);
+    return Object.hash(
+      build.name,
+      strategy,
+      useRbe,
+      useLto,
+      concurrency,
+      buildDart,
+    );
   }
 
   /// Converts this build plan to its equivalent [RbeConfig].
@@ -236,6 +269,12 @@
     return [
       if (!useRbe) '--no-rbe',
       if (useLto) '--lto' else '--no-lto',
+      if (buildDart == BuildDart.build)
+        '--no-prebuilt-dart-sdk'
+      else if (buildDart == BuildDart.buildFull) ...[
+        '--no-prebuilt-dart-sdk',
+        '--full-dart-sdk',
+      ],
     ];
   }
 
@@ -246,6 +285,7 @@
     buffer.writeln('  build: ${build.name}');
     buffer.writeln('  useLto: $useLto');
     buffer.writeln('  useRbe: $useRbe');
+    buffer.writeln('  build dart: ${buildDart.name}');
     buffer.writeln('  strategy: $strategy');
     buffer.writeln('  concurrency: $concurrency');
     buffer.write('>');
@@ -277,3 +317,15 @@
   const BuildStrategy(this._help);
   final String _help;
 }
+
+/// Whether to build Dart from source or not.
+enum BuildDart {
+  /// Use the prebuilt Dart.
+  prebuilt,
+
+  /// Build Dart from source.
+  build,
+
+  /// Build the full Dart SDK from source.
+  buildFull,
+}
diff --git a/tools/engine_tool/lib/src/commands/build_command.dart b/tools/engine_tool/lib/src/commands/build_command.dart
index 6094ffd..59bf761 100644
--- a/tools/engine_tool/lib/src/commands/build_command.dart
+++ b/tools/engine_tool/lib/src/commands/build_command.dart
@@ -55,6 +55,7 @@
           environment,
           plan.build,
           enableRbe: plan.useRbe,
+          extraGnArgs: plan.toGnArgs(),
         )) {
       return 1;
     }
diff --git a/tools/engine_tool/lib/src/commands/query_command.dart b/tools/engine_tool/lib/src/commands/query_command.dart
index 178d2db..b747278 100644
--- a/tools/engine_tool/lib/src/commands/query_command.dart
+++ b/tools/engine_tool/lib/src/commands/query_command.dart
@@ -182,6 +182,7 @@
       environment,
       plan.build,
       enableRbe: plan.useRbe,
+      extraGnArgs: plan.toGnArgs(),
     )) {
       return 1;
     }
diff --git a/tools/engine_tool/lib/src/commands/test_command.dart b/tools/engine_tool/lib/src/commands/test_command.dart
index cf857ea..0ead18c 100644
--- a/tools/engine_tool/lib/src/commands/test_command.dart
+++ b/tools/engine_tool/lib/src/commands/test_command.dart
@@ -55,6 +55,7 @@
       environment,
       plan.build,
       enableRbe: plan.useRbe,
+      extraGnArgs: plan.toGnArgs(),
     )) {
       return 1;
     }
@@ -96,6 +97,7 @@
       targets: testTargets.map((target) => target.label).toList(),
       enableRbe: plan.useRbe,
       rbeConfig: plan.toRbeConfig(),
+      extraGnArgs: plan.toGnArgs(),
     );
     if (buildExitCode != 0) {
       return buildExitCode;
diff --git a/tools/engine_tool/test/build_plan_test.dart b/tools/engine_tool/test/build_plan_test.dart
index 529641f..509b3bc 100644
--- a/tools/engine_tool/test/build_plan_test.dart
+++ b/tools/engine_tool/test/build_plan_test.dart
@@ -546,6 +546,129 @@
     );
   });
 
+  test('dart build defaults to prebuilt', () {
+    final testEnv = TestEnvironment.withTestEngine(
+      withRbe: true,
+    );
+    addTearDown(testEnv.cleanup);
+
+    final testConfig = TestBuilderConfig();
+    testConfig.addBuild(
+      name: 'linux/host_debug',
+      dimension: TestDroneDimension.linux,
+    );
+
+    final parser = ArgParser();
+    final builds = BuildPlan.configureArgParser(
+      parser,
+      testEnv.environment,
+      configs: {
+        'linux_test_config': testConfig.buildConfig(
+          path: 'ci/builders/linux_test_config.json',
+        ),
+      },
+      help: false,
+    );
+
+    final plan = BuildPlan.fromArgResults(
+      parser.parse([]),
+      testEnv.environment,
+      builds: builds,
+    );
+
+    expect(plan.buildDart, BuildDart.prebuilt);
+    expect(
+      plan.toGnArgs(),
+      isNot(contains('--no-prebuilt-dart-sdk')),
+    );
+    expect(
+      plan.toGnArgs(),
+      isNot(contains('--full-dart-sdk')),
+    );
+  });
+
+  test('dart build can be set to from source', () {
+    final testEnv = TestEnvironment.withTestEngine(
+      withRbe: true,
+    );
+    addTearDown(testEnv.cleanup);
+
+    final testConfig = TestBuilderConfig();
+    testConfig.addBuild(
+      name: 'linux/host_debug',
+      dimension: TestDroneDimension.linux,
+    );
+
+    final parser = ArgParser();
+    final builds = BuildPlan.configureArgParser(
+      parser,
+      testEnv.environment,
+      configs: {
+        'linux_test_config': testConfig.buildConfig(
+          path: 'ci/builders/linux_test_config.json',
+        ),
+      },
+      help: false,
+    );
+
+    final plan = BuildPlan.fromArgResults(
+      parser.parse(['--build-dart']),
+      testEnv.environment,
+      builds: builds,
+    );
+
+    expect(plan.buildDart, BuildDart.build);
+    expect(
+      plan.toGnArgs(),
+      contains('--no-prebuilt-dart-sdk'),
+    );
+    expect(
+      plan.toGnArgs(),
+      isNot(contains('--full-dart-sdk')),
+    );
+  });
+
+  test('dart build can be set to full', () {
+    final testEnv = TestEnvironment.withTestEngine(
+      withRbe: true,
+    );
+    addTearDown(testEnv.cleanup);
+
+    final testConfig = TestBuilderConfig();
+    testConfig.addBuild(
+      name: 'linux/host_debug',
+      dimension: TestDroneDimension.linux,
+    );
+
+    final parser = ArgParser();
+    final builds = BuildPlan.configureArgParser(
+      parser,
+      testEnv.environment,
+      configs: {
+        'linux_test_config': testConfig.buildConfig(
+          path: 'ci/builders/linux_test_config.json',
+        ),
+      },
+      help: false,
+    );
+
+    final plan = BuildPlan.fromArgResults(
+      parser.parse(['--build-dart-full']),
+      testEnv.environment,
+      builds: builds,
+    );
+
+    expect(plan.buildDart, BuildDart.buildFull);
+    expect(
+      plan.toGnArgs(),
+      contains('--no-prebuilt-dart-sdk'),
+    );
+    expect(
+      plan.toGnArgs(),
+      contains('--full-dart-sdk'),
+    );
+  });
+
   test('build defaults to host_debug', () {
     final testEnv = TestEnvironment.withTestEngine(
       withRbe: true,