Skip to content

Commit 466580e

Browse files
committed
Hacking.
1 parent 62bd702 commit 466580e

File tree

11 files changed

+147
-30
lines changed

11 files changed

+147
-30
lines changed

build_config/lib/src/build_config.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ class BuildConfig {
7878

7979
final List<String> additionalPublicAssets;
8080

81+
final Map<String, Object> triggers;
82+
8183
/// The default config if you have no `build.yaml` file.
8284
factory BuildConfig.useDefault(
8385
String packageName,
@@ -148,6 +150,7 @@ class BuildConfig {
148150
Map<String, PostProcessBuilderDefinition>? postProcessBuilderDefinitions =
149151
const {},
150152
this.additionalPublicAssets = const [],
153+
this.triggers = const {},
151154
}) : buildTargets =
152155
identical(buildTargets, BuildConfig._placeholderBuildTarget)
153156
? {

build_config/lib/src/build_config.g.dart

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build_config/pubspec.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ dependencies:
1717
dev_dependencies:
1818
build_runner: ^2.0.0
1919
# TODO(davidmorgan): add back when released for build 3.0.0.
20-
# json_serializable: ^6.0.0
20+
json_serializable: ^6.0.0
2121
term_glyph: ^1.2.0
2222
test: ^1.16.0
2323

2424
topics:
2525
- build-runner
26+
27+
dependency_overrides:
28+
json_serializable: ^6.0.0

build_runner_core/lib/src/generate/build.dart

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ class Build {
486486
readerWriter,
487487
),
488488
)) {
489-
buildLog.skipStep(phase: phase, lazy: lazy);
489+
buildLog.reuseStep(phase: phase, lazy: lazy);
490490
return <AssetId>[];
491491
}
492492

@@ -502,20 +502,22 @@ class Build {
502502
}
503503

504504
var reallyBuild = true;
505-
final buildRunnerOptions = phase.builderOptions.config['build_runner'];
506-
if (buildRunnerOptions != null) {
507-
String? primaryInputSource;
508-
final buildIfs = (buildRunnerOptions as Map)['build_if'];
509-
if (buildIfs != null) {
510-
for (final entry in (buildIfs as Map).entries) {
511-
if (entry.key == 'primary_input_contains') {
512-
primaryInputSource ??= await readerWriter.readAsString(
513-
primaryInput,
514-
);
515-
if (!primaryInputSource.contains(entry.value as String)) {
516-
reallyBuild = false;
517-
break;
518-
}
505+
final runsIfTriggered =
506+
phase.builderOptions.config['runs_only_if_triggered'];
507+
if (runsIfTriggered == true) {
508+
reallyBuild = false;
509+
final buildTriggers = options.targetGraph.buildTriggers;
510+
511+
// TODO(davidmorgan): pull out and digest triggers per build label.
512+
final thisBuilderTriggers = buildTriggers.triggers[phase.builderLabel];
513+
if (thisBuilderTriggers != null) {
514+
final primaryInputSource = await readerWriter.readAsString(
515+
primaryInput,
516+
);
517+
for (final trigger in thisBuilderTriggers) {
518+
if (trigger.triggersOnPrimaryInput(primaryInputSource)) {
519+
reallyBuild = true;
520+
break;
519521
}
520522
}
521523
}
@@ -574,7 +576,7 @@ class Build {
574576
lazy: lazy,
575577
);
576578
} else {
577-
buildLog.skipStep(phase: phase, lazy: lazy);
579+
buildLog.stepNotTriggered(phase: phase, lazy: lazy);
578580
}
579581

580582
return readerWriter.assetsWritten;

build_runner_core/lib/src/generate/options.dart

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,7 @@ class BuildOptions {
167167
requiredRootSourcePaths: [r'$package$', r'lib/$lib$'],
168168
);
169169
} on BuildConfigParseException catch (e) {
170-
buildLog.error('''
171-
Failed to parse `build.yaml` for ${e.packageName}.
172-
173-
If you believe you have gotten this message in error, especially if using a new
174-
feature, you may need to run `dart run build_runner clean` and then rebuild.
175-
''');
170+
buildLog.error(e.toString());
176171
throw const CannotBuildException();
177172
}
178173

build_runner_core/lib/src/logging/build_log.dart

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,29 @@ class BuildLog {
305305
}
306306
}
307307

308+
/// Logs that a build step was not triggered.
309+
void stepNotTriggered({required InBuildPhase phase, required bool lazy}) {
310+
final progress = _getProgress(phase: phase, lazy: lazy);
311+
progress.notTriggered++;
312+
progress.nextInput = null;
313+
final phaseName = phase.name(lazy: lazy);
314+
_tick();
315+
316+
// Usually the next step will immediately run and update with more useful
317+
// information, so only display if this is the last for the builder.
318+
if (progress.isFinished) {
319+
if (_display.displayingBlocks) {
320+
_display.block(render());
321+
} else {
322+
_display.message(Severity.info, _renderPhase(phaseName).toString());
323+
}
324+
}
325+
326+
_popPhase();
327+
}
328+
308329
/// Logs that a build step has been skipped during an incremental build.
309-
void skipStep({required InBuildPhase phase, required bool lazy}) {
330+
void reuseStep({required InBuildPhase phase, required bool lazy}) {
310331
final progress = _getProgress(phase: phase, lazy: lazy);
311332
progress.skipped++;
312333
progress.nextInput = null;
@@ -523,6 +544,8 @@ class BuildLog {
523544
AnsiBuffer.reset,
524545
if (progress.inputs != 0) ' on ${progress.inputs.renderNamed('input')}',
525546
if (progress.skipped != 0) '${separator()}${progress.skipped} skipped',
547+
if (progress.notTriggered != 0)
548+
'${separator()}${progress.notTriggered} not triggered',
526549
if (progress.builtNew != 0) '${separator()}${progress.builtNew} output',
527550
if (progress.builtSame != 0) '${separator()}${progress.builtSame} same',
528551
if (progress.builtNothing != 0)
@@ -583,6 +606,9 @@ class _PhaseProgress {
583606
/// outputs are up to date.
584607
int skipped = 0;
585608

609+
/// Build steps with `run_only_if_triggered` that were not triggered.
610+
int notTriggered = 0;
611+
586612
/// Build steps that ran and output new or different output.
587613
int builtNew = 0;
588614

@@ -598,7 +624,8 @@ class _PhaseProgress {
598624
_PhaseProgress();
599625

600626
/// The number of build steps that have run in this phase.
601-
int get runCount => skipped + builtNew + builtSame + builtNothing;
627+
int get runCount =>
628+
skipped + notTriggered + builtNew + builtSame + builtNothing;
602629

603630
/// Whether this progress in displayed.
604631
///

build_runner_core/lib/src/package_graph/apply_builders.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:async';
66

77
import 'package:build/build.dart';
88
import 'package:build_config/build_config.dart';
9+
import 'package:built_collection/built_collection.dart';
910
import 'package:graphs/graphs.dart';
1011

1112
import '../generate/build_phases.dart';
@@ -14,6 +15,7 @@ import '../generate/phase.dart';
1415
import '../logging/build_log.dart';
1516
import '../logging/build_log_logger.dart';
1617
import '../validation/config_validation.dart';
18+
import 'build_triggers.dart';
1719
import 'package_graph.dart';
1820
import 'target_graph.dart';
1921

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:built_collection/built_collection.dart';
6+
7+
class BuildTriggers {
8+
final BuiltMap<String, BuiltSet<BuildTrigger>> triggers;
9+
10+
BuildTriggers({required this.triggers});
11+
12+
// TODO(davidmorgan): fix.
13+
int get identity => triggers.toString().hashCode;
14+
}
15+
16+
abstract class BuildTrigger {
17+
static BuildTrigger? tryParse(String trigger) {
18+
if (trigger.startsWith('import ')) {
19+
trigger = trigger.substring('import '.length);
20+
return ImportBuildTrigger(trigger);
21+
}
22+
return null;
23+
}
24+
25+
bool triggersOnPrimaryInput(String source);
26+
}
27+
28+
class ImportBuildTrigger implements BuildTrigger {
29+
final String import;
30+
31+
ImportBuildTrigger(this.import);
32+
33+
@override
34+
bool triggersOnPrimaryInput(String source) {
35+
return source.contains(import);
36+
}
37+
}

build_runner_core/lib/src/package_graph/target_graph.dart

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import 'dart:async';
66

77
import 'package:build/build.dart';
88
import 'package:build_config/build_config.dart';
9+
import 'package:built_collection/built_collection.dart';
910
import 'package:glob/glob.dart';
1011

1112
import '../generate/input_matcher.dart';
1213
import '../generate/options.dart' show defaultNonRootVisibleAssets;
1314
import '../logging/build_log.dart';
15+
import 'build_triggers.dart';
1416
import 'package_graph.dart';
1517

1618
/// Like a [PackageGraph] but packages are further broken down into modules
@@ -36,11 +38,17 @@ class TargetGraph {
3638
/// The [BuildConfig] of the root package.
3739
final BuildConfig rootPackageConfig;
3840

41+
// The [BuildTrigger]s accumulated across all packages.
42+
final BuildTriggers buildTriggers;
43+
44+
/// The [BuildTriggers] accumulated across all packages.
45+
3946
TargetGraph._(
4047
this.allModules,
4148
this.modulesByPackage,
4249
this._publicAssetsByPackage,
4350
this.rootPackageConfig,
51+
this.buildTriggers,
4452
);
4553

4654
/// Builds a [TargetGraph] from [packageGraph].
@@ -66,10 +74,34 @@ class TargetGraph {
6674
final publicAssetsByPackage = <String, InputMatcher>{};
6775
final modulesByPackage = <String, List<TargetNode>>{};
6876
late BuildConfig rootPackageConfig;
77+
final buildTriggers = <String, Set<BuildTrigger>>{};
6978
for (final package in packageGraph.allPackages.values) {
7079
final config =
7180
overrideBuildConfig[package.name] ??
7281
await _packageBuildConfig(package);
82+
83+
final packageTriggers = config.triggers;
84+
for (final entry in packageTriggers.entries) {
85+
final triggerPackage = entry.key;
86+
final triggers = entry.value;
87+
if (triggers is List<Object?>) {
88+
for (final triggerString in triggers) {
89+
BuildTrigger? trigger;
90+
if (triggerString is String) {
91+
trigger = BuildTrigger.tryParse(triggerString);
92+
}
93+
if (trigger != null) {
94+
(buildTriggers[triggerPackage] ??= {}).add(trigger);
95+
} else {
96+
throw BuildConfigParseException(
97+
package.name,
98+
'Invalid trigger: `$triggerString`',
99+
);
100+
}
101+
}
102+
}
103+
}
104+
73105
List<String> defaultInclude;
74106
if (package.isRoot) {
75107
defaultInclude = [
@@ -124,6 +156,11 @@ class TargetGraph {
124156
modulesByPackage,
125157
publicAssetsByPackage,
126158
rootPackageConfig,
159+
BuildTriggers(
160+
triggers: BuiltMap.from(
161+
buildTriggers.map((k, v) => MapEntry(k, v.build())),
162+
),
163+
),
127164
);
128165
}
129166

@@ -229,15 +266,19 @@ Future<BuildConfig> _packageBuildConfig(PackageNode package) async {
229266
);
230267
} on ArgumentError // ignore: avoid_catching_errors
231268
catch (e) {
232-
throw BuildConfigParseException(package.name, e);
269+
throw BuildConfigParseException(package.name, e.toString());
233270
}
234271
}
235272

236273
class BuildConfigParseException implements Exception {
237274
final String packageName;
238-
final dynamic exception;
275+
final String message;
239276

240-
BuildConfigParseException(this.packageName, this.exception);
277+
BuildConfigParseException(this.packageName, this.message);
278+
279+
@override
280+
String toString() =>
281+
'Failed to parse `build.yaml` for $packageName. $message';
241282
}
242283

243284
/// Returns the [sources] are not included in any [targets].

build_runner_core/test/logging/build_log_console_mode_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ Building, full build.'''),
157157
primaryInput: AssetId('pkg', 'lib/l3.dart'),
158158
lazy: false,
159159
);
160-
buildLog.skipStep(phase: phases.keys.first, lazy: false);
160+
buildLog.reuseStep(phase: phases.keys.first, lazy: false);
161161
expect(
162162
render(),
163163
padLinesRight('''

0 commit comments

Comments
 (0)