@@ -13,6 +13,7 @@ import 'package:logging/logging.dart';
1313import 'package:path/path.dart' as p;
1414import 'package:stack_trace/stack_trace.dart' ;
1515
16+ import 'build_process_state.dart' ;
1617import 'build_script_generate.dart' ;
1718
1819final _logger = Logger ('Bootstrap' );
@@ -39,9 +40,8 @@ Future<int> generateAndRun(
3940 logger ?? = _logger;
4041 ReceivePort ? exitPort;
4142 ReceivePort ? errorPort;
42- ReceivePort ? messagePort;
43+ RawReceivePort ? messagePort;
4344 StreamSubscription ? errorListener;
44- int ? scriptExitCode;
4545
4646 var tryCount = 0 ;
4747 var succeeded = false ;
@@ -52,6 +52,7 @@ Future<int> generateAndRun(
5252 messagePort? .close ();
5353 await errorListener? .cancel ();
5454
55+ var buildScriptChanged = false ;
5556 try {
5657 var buildScript = File (scriptLocation);
5758 var oldContents = '' ;
@@ -61,6 +62,7 @@ Future<int> generateAndRun(
6162 var newContents = await generateBuildScript ();
6263 // Only trigger a build script update if necessary.
6364 if (newContents != oldContents) {
65+ buildScriptChanged = true ;
6466 buildScript
6567 ..createSync (recursive: true )
6668 ..writeAsStringSync (newContents);
@@ -69,19 +71,27 @@ Future<int> generateAndRun(
6971 return ExitCode .config.code;
7072 }
7173
72- scriptExitCode = await _createKernelIfNeeded (logger, experiments);
73- if (scriptExitCode != 0 ) return scriptExitCode! ;
74+ if (! await _createKernelIfNeeded (
75+ logger,
76+ experiments,
77+ buildScriptChanged: buildScriptChanged,
78+ )) {
79+ return buildProcessState.isolateExitCode = ExitCode .config.code;
80+ }
7481
7582 exitPort = ReceivePort ();
7683 errorPort = ReceivePort ();
77- messagePort = ReceivePort ();
84+ messagePort = RawReceivePort ();
7885 errorListener = errorPort.listen ((e) {
7986 e = e as List <Object ?>;
8087 final error = e[0 ] ?? TypeError ();
8188 final trace = Trace .parse (e[1 ] as String ? ?? '' ).terse;
8289
8390 handleUncaughtError (error, trace);
84- if (scriptExitCode == 0 ) scriptExitCode = 1 ;
91+ if (buildProcessState.isolateExitCode == null ||
92+ buildProcessState.isolateExitCode == 0 ) {
93+ buildProcessState.isolateExitCode = 1 ;
94+ }
8595 });
8696 try {
8797 await Isolate .spawnUri (
@@ -113,56 +123,64 @@ Future<int> generateAndRun(
113123 }
114124 }
115125
116- StreamSubscription ? exitCodeListener;
117- exitCodeListener = messagePort! .listen ((isolateExitCode) {
118- if (isolateExitCode is int ) {
119- scriptExitCode = isolateExitCode;
120- } else {
121- throw StateError (
122- 'Bad response from isolate, expected an exit code but got '
123- '$isolateExitCode ' ,
124- );
125- }
126- exitCodeListener! .cancel ();
127- exitCodeListener = null ;
128- });
126+ final sendPortCompleter = Completer <SendPort >();
127+ messagePort! .handler = (Object ? message) {
128+ sendPortCompleter.complete (message as SendPort );
129+ };
130+ final sendPort = await sendPortCompleter.future;
131+
132+ await buildProcessState.send (sendPort);
133+ buildProcessState.isolateExitCode = null ;
134+ final buildProcessStateListener = buildProcessState.listen (
135+ ReceivePort .fromRawReceivePort (messagePort),
136+ );
137+
129138 await exitPort? .first;
130139 await errorListener? .cancel ();
131- await exitCodeListener? .cancel ();
140+ await buildProcessStateListener.cancel ();
141+
142+ // Can be null if the isolate did not set any exit code.
143+ buildProcessState.isolateExitCode ?? = 1 ;
132144
133- return scriptExitCode ?? 1 ;
145+ return buildProcessState.isolateExitCode ! ;
134146}
135147
136148/// Creates a precompiled Kernel snapshot for the build script if necessary.
137149///
138150/// A snapshot is generated if:
139151///
152+ /// - [buildScriptChanged] is `true`
140153/// - It doesn't exist currently
141154/// - Either build_runner or build_daemon point at a different location than
142155/// they used to, see https://github.com/dart-lang/build/issues/1929.
143156///
144- /// Returns zero for success or a number for failure which should be set to the
145- /// exit code.
146- Future <int > _createKernelIfNeeded (
157+ /// Returns `true` on success or `false` on failure.
158+ Future <bool > _createKernelIfNeeded (
147159 Logger logger,
148- List <String > experiments,
149- ) async {
160+ List <String > experiments, {
161+ bool buildScriptChanged = false ,
162+ }) async {
150163 var assetGraphFile = File (assetGraphPathFor (scriptKernelLocation));
151164 var kernelFile = File (scriptKernelLocation);
152165 var kernelCacheFile = File (scriptKernelCachedLocation);
153166
154167 if (await kernelFile.exists ()) {
155- // If we failed to serialize an asset graph for the snapshot, then we don't
156- // want to re-use it because we can't check if it is up to date.
157- if (! await assetGraphFile.exists ()) {
168+ if (buildScriptChanged) {
169+ await kernelFile.rename (scriptKernelCachedLocation);
170+ logger.warning (
171+ 'Invalidated precompiled build script because script changed.' ,
172+ );
173+ } else if (! await assetGraphFile.exists ()) {
174+ // If we failed to serialize an asset graph for the snapshot, then we
175+ // don't want to re-use it because we can't check if it is up to date.
158176 await kernelFile.rename (scriptKernelCachedLocation);
159177 logger.warning (
160178 'Invalidated precompiled build script due to missing asset graph.' ,
161179 );
162180 } else if (! await _checkImportantPackageDepsAndExperiments (experiments)) {
163181 await kernelFile.rename (scriptKernelCachedLocation);
164182 logger.warning (
165- 'Invalidated precompiled build script due to core package update' ,
183+ 'Invalidated precompiled build script due to core package update. ' ,
166184 );
167185 }
168186 }
@@ -223,12 +241,12 @@ Future<int> _createKernelIfNeeded(
223241Failed to precompile build script $scriptLocation .
224242This is likely caused by a misconfigured builder definition.
225243''' );
226- return ExitCode .config.code ;
244+ return false ;
227245 }
228246 // Create _previousLocationsFile.
229247 await _checkImportantPackageDepsAndExperiments (experiments);
230248 }
231- return 0 ;
249+ return true ;
232250}
233251
234252const _importantPackages = ['build_daemon' , 'build_runner' ];
0 commit comments