@@ -13,6 +13,7 @@ import 'package:logging/logging.dart';
13
13
import 'package:path/path.dart' as p;
14
14
import 'package:stack_trace/stack_trace.dart' ;
15
15
16
+ import 'build_process_state.dart' ;
16
17
import 'build_script_generate.dart' ;
17
18
18
19
final _logger = Logger ('Bootstrap' );
@@ -39,9 +40,8 @@ Future<int> generateAndRun(
39
40
logger ?? = _logger;
40
41
ReceivePort ? exitPort;
41
42
ReceivePort ? errorPort;
42
- ReceivePort ? messagePort;
43
+ RawReceivePort ? messagePort;
43
44
StreamSubscription ? errorListener;
44
- int ? scriptExitCode;
45
45
46
46
var tryCount = 0 ;
47
47
var succeeded = false ;
@@ -52,6 +52,7 @@ Future<int> generateAndRun(
52
52
messagePort? .close ();
53
53
await errorListener? .cancel ();
54
54
55
+ var buildScriptChanged = false ;
55
56
try {
56
57
var buildScript = File (scriptLocation);
57
58
var oldContents = '' ;
@@ -61,6 +62,7 @@ Future<int> generateAndRun(
61
62
var newContents = await generateBuildScript ();
62
63
// Only trigger a build script update if necessary.
63
64
if (newContents != oldContents) {
65
+ buildScriptChanged = true ;
64
66
buildScript
65
67
..createSync (recursive: true )
66
68
..writeAsStringSync (newContents);
@@ -69,19 +71,27 @@ Future<int> generateAndRun(
69
71
return ExitCode .config.code;
70
72
}
71
73
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
+ }
74
81
75
82
exitPort = ReceivePort ();
76
83
errorPort = ReceivePort ();
77
- messagePort = ReceivePort ();
84
+ messagePort = RawReceivePort ();
78
85
errorListener = errorPort.listen ((e) {
79
86
e = e as List <Object ?>;
80
87
final error = e[0 ] ?? TypeError ();
81
88
final trace = Trace .parse (e[1 ] as String ? ?? '' ).terse;
82
89
83
90
handleUncaughtError (error, trace);
84
- if (scriptExitCode == 0 ) scriptExitCode = 1 ;
91
+ if (buildProcessState.isolateExitCode == null ||
92
+ buildProcessState.isolateExitCode == 0 ) {
93
+ buildProcessState.isolateExitCode = 1 ;
94
+ }
85
95
});
86
96
try {
87
97
await Isolate .spawnUri (
@@ -113,56 +123,64 @@ Future<int> generateAndRun(
113
123
}
114
124
}
115
125
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
+
129
138
await exitPort? .first;
130
139
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 ;
132
144
133
- return scriptExitCode ?? 1 ;
145
+ return buildProcessState.isolateExitCode ! ;
134
146
}
135
147
136
148
/// Creates a precompiled Kernel snapshot for the build script if necessary.
137
149
///
138
150
/// A snapshot is generated if:
139
151
///
152
+ /// - [buildScriptChanged] is `true`
140
153
/// - It doesn't exist currently
141
154
/// - Either build_runner or build_daemon point at a different location than
142
155
/// they used to, see https://github.com/dart-lang/build/issues/1929.
143
156
///
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 (
147
159
Logger logger,
148
- List <String > experiments,
149
- ) async {
160
+ List <String > experiments, {
161
+ bool buildScriptChanged = false ,
162
+ }) async {
150
163
var assetGraphFile = File (assetGraphPathFor (scriptKernelLocation));
151
164
var kernelFile = File (scriptKernelLocation);
152
165
var kernelCacheFile = File (scriptKernelCachedLocation);
153
166
154
167
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.
158
176
await kernelFile.rename (scriptKernelCachedLocation);
159
177
logger.warning (
160
178
'Invalidated precompiled build script due to missing asset graph.' ,
161
179
);
162
180
} else if (! await _checkImportantPackageDepsAndExperiments (experiments)) {
163
181
await kernelFile.rename (scriptKernelCachedLocation);
164
182
logger.warning (
165
- 'Invalidated precompiled build script due to core package update' ,
183
+ 'Invalidated precompiled build script due to core package update. ' ,
166
184
);
167
185
}
168
186
}
@@ -223,12 +241,12 @@ Future<int> _createKernelIfNeeded(
223
241
Failed to precompile build script $scriptLocation .
224
242
This is likely caused by a misconfigured builder definition.
225
243
''' );
226
- return ExitCode .config.code ;
244
+ return false ;
227
245
}
228
246
// Create _previousLocationsFile.
229
247
await _checkImportantPackageDepsAndExperiments (experiments);
230
248
}
231
- return 0 ;
249
+ return true ;
232
250
}
233
251
234
252
const _importantPackages = ['build_daemon' , 'build_runner' ];
0 commit comments