@@ -12,13 +12,14 @@ import 'package:build_daemon/data/build_status.dart' as build;
12
12
import 'package:build_daemon/client.dart' ;
13
13
import 'package:meta/meta.dart' ;
14
14
import 'package:yaml/yaml.dart' ;
15
+ import 'package:crypto/crypto.dart' show md5;
15
16
16
17
import '../artifacts.dart' ;
18
+ import '../base/common.dart' ;
17
19
import '../base/file_system.dart' ;
18
20
import '../base/io.dart' ;
19
21
import '../base/logger.dart' ;
20
22
import '../base/process_manager.dart' ;
21
- import '../cache.dart' ;
22
23
import '../codegen.dart' ;
23
24
import '../convert.dart' ;
24
25
import '../dart/pub.dart' ;
@@ -53,24 +54,23 @@ class BuildRunner extends CodeGenerator {
53
54
final String sdkRoot = artifacts.getArtifactPath (Artifact .flutterPatchedSdkPath);
54
55
final String engineDartBinaryPath = artifacts.getArtifactPath (Artifact .engineDartBinary);
55
56
final String packagesPath = flutterProject.packagesFile.absolute.path;
56
- final String buildScript = flutterProject
57
+ final String buildSnapshot = flutterProject
57
58
.dartTool
58
59
.childDirectory ('build' )
59
60
.childDirectory ('entrypoint' )
60
- .childFile ('build.dart' )
61
+ .childFile ('build.dart.snapshot ' )
61
62
.path;
62
63
final String scriptPackagesPath = flutterProject
63
64
.dartTool
64
65
.childDirectory ('flutter_tool' )
65
66
.childFile ('.packages' )
66
67
.path;
67
- final String dartPath = fs.path.join (Cache .flutterRoot, 'bin' , 'cache' , 'dart-sdk' , 'bin' , 'dart' );
68
68
final Status status = logger.startProgress ('running builders...' , timeout: null );
69
69
try {
70
70
final Process buildProcess = await processManager.start (< String > [
71
- dartPath ,
71
+ engineDartBinaryPath ,
72
72
'--packages=$scriptPackagesPath ' ,
73
- buildScript ,
73
+ buildSnapshot ,
74
74
'build' ,
75
75
'--skip-build-script-check' ,
76
76
'--define' , 'flutter_build|kernel=disabled=$disableKernelGeneration ' ,
@@ -95,7 +95,6 @@ class BuildRunner extends CodeGenerator {
95
95
.transform (utf8.decoder)
96
96
.transform (const LineSplitter ())
97
97
.listen (printError);
98
- await buildProcess.exitCode;
99
98
} finally {
100
99
status.stop ();
101
100
}
@@ -127,57 +126,84 @@ class BuildRunner extends CodeGenerator {
127
126
return CodeGenerationResult (packagesFile, dillFile);
128
127
}
129
128
130
- @override
131
- Future <void > invalidateBuildScript () async {
132
- final FlutterProject flutterProject = await FlutterProject .current ();
133
- final File buildScript = flutterProject.dartTool
134
- .absolute
135
- .childDirectory ('flutter_tool' )
136
- .childFile ('build.dart' );
137
- if (! buildScript.existsSync ()) {
138
- return ;
139
- }
140
- await buildScript.delete ();
141
- }
142
-
143
129
@override
144
130
Future <void > generateBuildScript () async {
145
131
final FlutterProject flutterProject = await FlutterProject .current ();
146
- final String generatedDirectory = fs.path.join (flutterProject.dartTool.path, 'flutter_tool' );
147
- final String resultScriptPath = fs.path.join (flutterProject.dartTool.path, 'build' , 'entrypoint' , 'build.dart' );
148
- if (fs.file (resultScriptPath).existsSync ()) {
149
- return ;
132
+ final Directory entrypointDirectory = fs.directory (fs.path.join (flutterProject.dartTool.path, 'build' , 'entrypoint' ));
133
+ final Directory generatedDirectory = fs.directory (fs.path.join (flutterProject.dartTool.path, 'flutter_tool' ));
134
+ final File buildScript = entrypointDirectory.childFile ('build.dart' );
135
+ final File buildSnapshot = entrypointDirectory.childFile ('build.dart.snapshot' );
136
+ final File scriptIdFile = entrypointDirectory.childFile ('id' );
137
+ final File syntheticPubspec = generatedDirectory.childFile ('pubspec.yaml' );
138
+
139
+ // Check if contents of builders changed. If so, invalidate build script
140
+ // and regnerate.
141
+ final YamlMap builders = await flutterProject.builders;
142
+ final List <int > appliedBuilderDigest = _produceScriptId (builders);
143
+ if (scriptIdFile.existsSync () && buildSnapshot.existsSync ()) {
144
+ final List <int > previousAppliedBuilderDigest = scriptIdFile.readAsBytesSync ();
145
+ bool digestsAreEqual = false ;
146
+ if (appliedBuilderDigest.length == previousAppliedBuilderDigest.length) {
147
+ digestsAreEqual = true ;
148
+ for (int i = 0 ; i < appliedBuilderDigest.length; i++ ) {
149
+ if (appliedBuilderDigest[i] != previousAppliedBuilderDigest[i]) {
150
+ digestsAreEqual = false ;
151
+ break ;
152
+ }
153
+ }
154
+ }
155
+ if (digestsAreEqual) {
156
+ return ;
157
+ }
158
+ }
159
+ // Clean-up all existing artifacts.
160
+ if (flutterProject.dartTool.existsSync ()) {
161
+ flutterProject.dartTool.deleteSync (recursive: true );
150
162
}
151
163
final Status status = logger.startProgress ('generating build script...' , timeout: null );
152
164
try {
153
- fs. directory ( generatedDirectory) .createSync (recursive: true );
154
-
155
- final File syntheticPubspec = fs. file (fs.path. join (generatedDirectory, 'pubspec.yaml' ) );
165
+ generatedDirectory.createSync (recursive: true );
166
+ entrypointDirectory. createSync (recursive : true );
167
+ flutterProject.dartTool. childDirectory ( 'build' ). childDirectory ( 'generated' ). createSync (recursive : true );
156
168
final StringBuffer stringBuffer = StringBuffer ();
157
169
158
170
stringBuffer.writeln ('name: flutter_tool' );
159
171
stringBuffer.writeln ('dependencies:' );
160
172
final YamlMap builders = await flutterProject.builders;
161
173
if (builders != null ) {
162
174
for (String name in builders.keys) {
163
- final YamlNode node = builders[name];
175
+ final Object node = builders[name];
164
176
stringBuffer.writeln (' $name : $node ' );
165
177
}
166
178
}
167
179
stringBuffer.writeln (' build_runner: any' );
168
180
stringBuffer.writeln (' flutter_build:' );
169
181
stringBuffer.writeln (' sdk: flutter' );
170
- await syntheticPubspec.writeAsString (stringBuffer.toString ());
182
+ syntheticPubspec.writeAsStringSync (stringBuffer.toString ());
171
183
172
184
await pubGet (
173
185
context: PubContext .pubGet,
174
- directory: generatedDirectory,
186
+ directory: generatedDirectory.path ,
175
187
upgrade: false ,
176
188
checkLastModified: false ,
177
189
);
190
+ if (! scriptIdFile.existsSync ()) {
191
+ scriptIdFile.createSync (recursive: true );
192
+ }
193
+ scriptIdFile.writeAsBytesSync (appliedBuilderDigest);
178
194
final PackageGraph packageGraph = PackageGraph .forPath (syntheticPubspec.parent.path);
179
195
final BuildScriptGenerator buildScriptGenerator = const BuildScriptGeneratorFactory ().create (flutterProject, packageGraph);
180
196
await buildScriptGenerator.generateBuildScript ();
197
+ final ProcessResult result = await processManager.run (< String > [
198
+ artifacts.getArtifactPath (Artifact .engineDartBinary),
199
+ '--snapshot=${buildSnapshot .path }' ,
200
+ '--snapshot-kind=app-jit' ,
201
+ '--packages=${fs .path .join (generatedDirectory .path , '.packages' )}' ,
202
+ buildScript.path,
203
+ ]);
204
+ if (result.exitCode != 0 ) {
205
+ throwToolExit ('Error generating build_script snapshot: ${result .stderr }' );
206
+ }
181
207
} finally {
182
208
status.stop ();
183
209
}
@@ -200,25 +226,23 @@ class BuildRunner extends CodeGenerator {
200
226
final String sdkRoot = artifacts.getArtifactPath (Artifact .flutterPatchedSdkPath);
201
227
final String engineDartBinaryPath = artifacts.getArtifactPath (Artifact .engineDartBinary);
202
228
final String packagesPath = flutterProject.packagesFile.absolute.path;
203
- final String buildScript = flutterProject
229
+ final File buildSnapshot = flutterProject
204
230
.dartTool
205
231
.childDirectory ('build' )
206
232
.childDirectory ('entrypoint' )
207
- .childFile ('build.dart' )
208
- .path;
233
+ .childFile ('build.dart.snapshot' );
209
234
final String scriptPackagesPath = flutterProject
210
235
.dartTool
211
236
.childDirectory ('flutter_tool' )
212
237
.childFile ('.packages' )
213
238
.path;
214
- final String dartPath = fs.path.join (Cache .flutterRoot, 'bin' , 'cache' , 'dart-sdk' , 'bin' , 'dart' );
215
239
final Status status = logger.startProgress ('starting build daemon...' , timeout: null );
216
240
BuildDaemonClient buildDaemonClient;
217
241
try {
218
242
final List <String > command = < String > [
219
- dartPath ,
243
+ engineDartBinaryPath ,
220
244
'--packages=$scriptPackagesPath ' ,
221
- buildScript ,
245
+ buildSnapshot.path ,
222
246
'daemon' ,
223
247
'--skip-build-script-check' ,
224
248
'--define' , 'flutter_build|kernel=disabled=false' ,
@@ -279,3 +303,14 @@ class _BuildRunnerCodegenDaemon implements CodegenDaemon {
279
303
buildDaemonClient.startBuild ();
280
304
}
281
305
}
306
+
307
+ // Sorts the builders by name and produces a hashcode of the resulting iterable.
308
+ List <int > _produceScriptId (YamlMap builders) {
309
+ if (builders == null || builders.isEmpty) {
310
+ return md5.convert (< int > []).bytes;
311
+ }
312
+ final List <String > orderedBuilders = builders.keys
313
+ .cast <String >()
314
+ .toList ()..sort ();
315
+ return md5.convert (orderedBuilders.join ('' ).codeUnits).bytes;
316
+ }
0 commit comments