@@ -34,30 +34,12 @@ Unknown build mode for icu4x. Set the `ICU4X_BUILD_MODE` environment variable wi
34
34
''' ),
35
35
};
36
36
37
- final builtLibrary = await buildMode.build ();
37
+ final buildResult = await buildMode.build ();
38
38
// For debugging purposes
39
39
// ignore: deprecated_member_use
40
40
output.addMetadatum (env, environmentBuildMode ?? 'fetch' );
41
-
42
- final nativeCodeAsset = NativeCodeAsset (
43
- package: package,
44
- name: assetId,
45
- linkMode: DynamicLoadingBundled (),
46
- architecture: config.targetArchitecture,
47
- os: config.targetOS,
48
- file: builtLibrary,
49
- );
50
- output.addAsset (
51
- nativeCodeAsset,
52
- linkInPackage: config.linkingEnabled ? config.packageName : null ,
53
- );
54
-
55
- output.addDependencies (
56
- [
57
- ...buildMode.dependencies,
58
- config.packageRoot.resolve ('hook/build.dart' ),
59
- ],
60
- );
41
+ buildResult.addAssets (config, output);
42
+ output.addDependencies (buildMode.dependencies);
61
43
});
62
44
}
63
45
@@ -68,26 +50,74 @@ sealed class BuildMode {
68
50
69
51
List <Uri > get dependencies;
70
52
71
- Future <Uri > build ();
53
+ Future <BuildResult > build ();
54
+ }
55
+
56
+ final class BuildResult {
57
+ final Uri library;
58
+ final Uri ? datagen;
59
+ final Uri ? postcard;
60
+
61
+ BuildResult ({
62
+ required this .library,
63
+ required this .datagen,
64
+ required this .postcard,
65
+ });
66
+
67
+ void addAssets (BuildConfig config, BuildOutput output) {
68
+ output.addAssets (
69
+ [
70
+ NativeCodeAsset (
71
+ package: package,
72
+ name: assetId,
73
+ linkMode: DynamicLoadingBundled (),
74
+ architecture: config.targetArchitecture,
75
+ os: config.targetOS,
76
+ file: library,
77
+ ),
78
+ if (datagen != null )
79
+ DataAsset (
80
+ package: package,
81
+ name: 'datagen' ,
82
+ file: datagen! ,
83
+ ),
84
+ if (postcard != null )
85
+ DataAsset (
86
+ package: package,
87
+ name: 'postcard' ,
88
+ file: postcard! ,
89
+ ),
90
+ ],
91
+ linkInPackage: config.linkingEnabled ? config.packageName : null ,
92
+ );
93
+ }
72
94
}
73
95
74
96
final class FetchMode extends BuildMode {
75
97
FetchMode (super .config);
98
+ final httpClient = HttpClient ();
76
99
77
100
@override
78
- Future <Uri > build () async {
101
+ Future <BuildResult > build () async {
79
102
final target = '${config .targetOS }_${config .targetArchitecture }' ;
80
- final uri = Uri .parse (
103
+ final dylibRemoteUri = Uri .parse (
81
104
'https://github.com/dart-lang/i18n/releases/download/$version /$target ' );
82
- final request = await HttpClient ().getUrl (uri);
83
- final response = await request.close ();
84
- if (response.statusCode != 200 ) {
85
- throw ArgumentError ('The request to $uri failed' );
86
- }
87
- final dynamicLibrary =
88
- File .fromUri (config.outputDirectory.resolve (config.filename ('icu4x' )));
89
- await dynamicLibrary.create ();
90
- await response.pipe (dynamicLibrary.openWrite ());
105
+ final dynamicLibrary = await fetchToFile (
106
+ dylibRemoteUri,
107
+ config.outputDirectory.resolve (config.filename ('icu4x' )),
108
+ );
109
+
110
+ final datagen = await fetchToFile (
111
+ Uri .parse (
112
+ 'https://github.com/dart-lang/i18n/releases/download/$version /$target -datagen' ),
113
+ config.outputDirectory.resolve ('datagen' ),
114
+ );
115
+
116
+ final postcard = await fetchToFile (
117
+ Uri .parse (
118
+ 'https://github.com/dart-lang/i18n/releases/download/$version /full.postcard' ),
119
+ config.outputDirectory.resolve ('full.postcard' ),
120
+ );
91
121
92
122
final bytes = await dynamicLibrary.readAsBytes ();
93
123
final fileHash = sha256.convert (bytes).toString ();
@@ -96,47 +126,90 @@ final class FetchMode extends BuildMode {
96
126
config.targetArchitecture,
97
127
)];
98
128
if (fileHash == expectedFileHash) {
99
- return dynamicLibrary.uri;
129
+ return BuildResult (
130
+ library: dynamicLibrary.uri,
131
+ datagen: datagen.uri,
132
+ postcard: postcard.uri,
133
+ );
100
134
} else {
101
135
throw Exception (
102
- 'The pre-built binary for the target $target at $uri has a hash of '
103
- '$fileHash , which does not match $expectedFileHash fixed in the '
104
- 'build hook of package:intl4x.' );
136
+ 'The pre-built binary for the target $target at $dylibRemoteUri has a'
137
+ ' hash of $fileHash , which does not match $expectedFileHash fixed in'
138
+ ' the build hook of package:intl4x.' );
105
139
}
106
140
}
107
141
142
+ Future <File > fetchToFile (Uri uri, Uri fileUri) async {
143
+ final request = await httpClient.getUrl (uri);
144
+ final response = await request.close ();
145
+ if (response.statusCode != 200 ) {
146
+ throw ArgumentError ('The request to $uri failed' );
147
+ }
148
+ final file = File .fromUri (fileUri);
149
+ await file.create ();
150
+ await response.pipe (file.openWrite ());
151
+ return file;
152
+ }
153
+
108
154
@override
109
155
List <Uri > get dependencies => [];
110
156
}
111
157
112
158
final class LocalMode extends BuildMode {
113
- LocalMode (super .config);
114
-
115
- String get _localBinaryPath {
116
- final localPath = Platform .environment['LOCAL_ICU4X_BINARY' ];
117
- if (localPath != null ) {
159
+ final String localLibraryPath;
160
+ final String ? localDatagenPath;
161
+ final String ? localPostcardPath;
162
+
163
+ LocalMode (super .config)
164
+ : localLibraryPath = _getFromEnvironment (
165
+ 'LOCAL_ICU4X_BINARY_${config .linkingEnabled ? 'STATIC' : 'DYNAMIC' }' ,
166
+ true ,
167
+ )! ,
168
+ localDatagenPath = _getFromEnvironment ('LOCAL_ICU4X_DATAGEN' , false ),
169
+ localPostcardPath = _getFromEnvironment ('LOCAL_ICU4X_POSTCARD' , false );
170
+
171
+ static String ? _getFromEnvironment (String key, bool mustExist) {
172
+ final localPath = Platform .environment[key];
173
+ if (localPath != null || ! mustExist) {
118
174
return localPath;
119
175
}
120
- throw ArgumentError ('`LOCAL_ICU4X_BINARY ` is empty. '
176
+ throw ArgumentError ('`$ key ` is empty. '
121
177
'If the `ICU4X_BUILD_MODE` is set to `local`, the '
122
- '`LOCAL_ICU4X_BINARY` environment variable must contain the path to '
123
- 'the binary.' );
178
+ '`$key ` environment variable must be set.' );
124
179
}
125
180
126
181
@override
127
- Future <Uri > build () async {
128
- final libFileName = config.filename ('icu4x' );
129
- final libFileUri = config.outputDirectory.resolve (libFileName);
130
- final file = File (_localBinaryPath);
131
- if (! (await file.exists ())) {
132
- throw FileSystemException ('Could not find binary.' , _localBinaryPath);
182
+ Future <BuildResult > build () async {
183
+ final libFileUri = config.outputDirectory.resolve (config.filename ('icu4x' ));
184
+ await copyFile (localLibraryPath, libFileUri);
185
+
186
+ final Uri ? datagenFileUri;
187
+ if (localDatagenPath != null ) {
188
+ datagenFileUri = config.outputDirectory.resolve ('datagen' );
189
+ await copyFile (localDatagenPath! , datagenFileUri);
190
+ } else {
191
+ datagenFileUri = null ;
192
+ }
193
+
194
+ final Uri ? postcardFileUri;
195
+ if (localPostcardPath != null ) {
196
+ postcardFileUri = config.outputDirectory.resolve ('postcard' );
197
+ await copyFile (localPostcardPath! , postcardFileUri);
198
+ } else {
199
+ postcardFileUri = null ;
133
200
}
134
- await file.copy (libFileUri.toFilePath (windows: Platform .isWindows));
135
- return libFileUri;
201
+
202
+ return BuildResult (
203
+ library: libFileUri,
204
+ datagen: datagenFileUri,
205
+ postcard: postcardFileUri,
206
+ );
136
207
}
137
208
138
209
@override
139
- List <Uri > get dependencies => [Uri .file (_localBinaryPath)];
210
+ List <Uri > get dependencies => [
211
+ Uri .file (localLibraryPath),
212
+ ];
140
213
}
141
214
142
215
final class CheckoutMode extends BuildMode {
@@ -145,7 +218,7 @@ final class CheckoutMode extends BuildMode {
145
218
String ? get workingDirectory => Platform .environment['LOCAL_ICU4X_CHECKOUT' ];
146
219
147
220
@override
148
- Future <Uri > build () async {
221
+ Future <BuildResult > build () async {
149
222
if (workingDirectory == null ) {
150
223
throw ArgumentError ('Specify the ICU4X checkout folder'
151
224
'with the LOCAL_ICU4X_CHECKOUT variable' );
@@ -159,11 +232,14 @@ final class CheckoutMode extends BuildMode {
159
232
];
160
233
}
161
234
162
- Future <Uri > buildLib (BuildConfig config, String workingDirectory) async {
235
+ Future <BuildResult > buildLib (
236
+ BuildConfig config, String workingDirectory) async {
163
237
final crateNameFixed = crateName.replaceAll ('-' , '_' );
164
238
final libFileName = config.filename (crateNameFixed);
165
239
166
240
final libFileUri = config.outputDirectory.resolve (libFileName);
241
+ final datagenFileUri = config.outputDirectory.resolve ('datagen' );
242
+ final postcardFileUri = config.outputDirectory.resolve ('postcard' );
167
243
if (! config.dryRun) {
168
244
final rustTarget = _asRustTarget (
169
245
config.targetOS,
@@ -247,13 +323,56 @@ Future<Uri> buildLib(BuildConfig config, String workingDirectory) async {
247
323
'release' ,
248
324
libFileName,
249
325
);
250
- final file = File (builtPath);
251
- if (! (await file.exists ())) {
252
- throw FileSystemException ('Building the dylib failed' , builtPath);
326
+ await copyFile (builtPath, libFileUri);
327
+
328
+ if (config.linkingEnabled) {
329
+ final postcardPath = path.join (tempDir.path, 'full.postcard' );
330
+ await Process .run (
331
+ 'cargo' ,
332
+ [
333
+ 'run' ,
334
+ ...['-p' , 'icu_datagen' ],
335
+ '--' ,
336
+ ...['--locales' , 'full' ],
337
+ ...['--keys' , 'all' ],
338
+ ...['--format' , 'blob' ],
339
+ ...['--out' , postcardPath],
340
+ ],
341
+ workingDirectory: workingDirectory,
342
+ );
343
+ await copyFile (postcardPath, postcardFileUri);
344
+
345
+ final datagenPath = path.join (tempDir.path, 'datagen' );
346
+ final datagenDirectory = path.join (workingDirectory, 'provider/datagen' );
347
+ await Process .run (
348
+ 'rustup' ,
349
+ ['target' , 'add' , 'aarch64-unknown-linux-gnu' ],
350
+ workingDirectory: datagenDirectory,
351
+ );
352
+ await Process .run (
353
+ 'cargo' ,
354
+ [
355
+ 'build' ,
356
+ '--release' ,
357
+ '--bin' ,
358
+ 'icu4x-datagen' ,
359
+ '--no-default-features' ,
360
+ ...[
361
+ '--features' ,
362
+ 'bin,blob_exporter,blob_input,rayon,experimental_components'
363
+ ],
364
+ ...['--target' , 'aarch64-unknown-linux-gnu' ]
365
+ ],
366
+ workingDirectory: datagenDirectory,
367
+ );
368
+ await copyFile (datagenPath, datagenFileUri);
253
369
}
254
- await file.copy (libFileUri.toFilePath (windows: Platform .isWindows));
255
370
}
256
- return libFileUri;
371
+ return BuildResult (
372
+ library: libFileUri,
373
+ datagen: config.linkingEnabled ? datagenFileUri : null ,
374
+ postcard: config.linkingEnabled ? postcardFileUri : null ,
375
+ );
257
376
}
258
377
259
378
String _asRustTarget (OS os, Architecture ? architecture, bool isSimulator) {
@@ -297,3 +416,11 @@ extension on BuildConfig {
297
416
String Function (String ) get filename =>
298
417
buildStatic ? targetOS.staticlibFileName : targetOS.dylibFileName;
299
418
}
419
+
420
+ Future <void > copyFile (String path, Uri libFileUri) async {
421
+ final file = File (path);
422
+ if (! (await file.exists ())) {
423
+ throw FileSystemException ('File does not exist.' , path);
424
+ }
425
+ await file.copy (libFileUri.toFilePath (windows: Platform .isWindows));
426
+ }
0 commit comments