4
4
5
5
import 'dart:io' ;
6
6
7
- import 'package:archive/archive_io .dart' ;
7
+ import 'package:crypto/crypto .dart' show sha256 ;
8
8
import 'package:native_assets_cli/native_assets_cli.dart' ;
9
9
import 'package:path/path.dart' as path;
10
10
11
+ import 'hashes.dart' ;
12
+ import 'version.dart' ;
13
+
11
14
const crateName = 'icu_capi' ;
12
15
const package = 'intl4x' ;
13
16
const assetId = 'src/bindings/lib.g.dart' ;
14
17
18
+ final env = 'ICU4X_BUILD_MODE' ;
19
+
15
20
void main (List <String > args) async {
16
21
await build (args, (config, output) async {
17
- final buildMode = switch (Platform .environment['ICU4X_BUILD_MODE' ]) {
18
- 'local' => LocalMode (),
22
+ final environmentBuildMode = Platform .environment[env];
23
+ final buildMode = switch (environmentBuildMode) {
24
+ 'local' => LocalMode (config),
19
25
'checkout' => CheckoutMode (config),
20
26
'fetch' || null => FetchMode (config),
21
27
String () => throw ArgumentError ('''
@@ -30,6 +36,8 @@ Unknown build mode for icu4x. Set the `ICU4X_BUILD_MODE` environment variable wi
30
36
};
31
37
32
38
final builtLibrary = await buildMode.build ();
39
+ // For debugging purposes
40
+ output.addMetadatum (env, environmentBuildMode ?? 'fetch' );
33
41
34
42
output.addAsset (NativeCodeAsset (
35
43
package: package,
@@ -44,86 +52,91 @@ Unknown build mode for icu4x. Set the `ICU4X_BUILD_MODE` environment variable wi
44
52
[
45
53
...buildMode.dependencies,
46
54
config.packageRoot.resolve ('hook/build.dart' ),
47
- //TODO: Fix this, currently causes a rebuild for checkout mode
48
- //builtLibrary,
49
55
],
50
56
);
51
57
});
52
58
}
53
59
54
- void unzipFirstFile ({required File input, required File output}) {
55
- final inputStream = InputFileStream (input.path);
56
- final archive = ZipDecoder ().decodeBuffer (inputStream);
57
- final file = archive.files.firstOrNull;
58
- // If it's a file and not a directory
59
- if (file? .isFile ?? false ) {
60
- final outputStream = OutputFileStream (output.path);
61
- file! .writeContent (outputStream);
62
- outputStream.close ();
63
- }
64
- }
65
-
66
60
sealed class BuildMode {
61
+ final BuildConfig config;
62
+
63
+ const BuildMode (this .config);
64
+
67
65
List <Uri > get dependencies;
68
66
69
67
Future <Uri > build ();
70
68
}
71
69
72
- final class FetchMode implements BuildMode {
73
- final BuildConfig config;
74
-
75
- FetchMode (this .config);
70
+ final class FetchMode extends BuildMode {
71
+ FetchMode (super .config);
76
72
77
73
@override
78
74
Future <Uri > build () async {
79
- // TODO: Get a nicer CDN than a generated link to a privately owned repo.
75
+ final target = '${ config . targetOS }_${ config . targetArchitecture }' ;
80
76
final uri = Uri .parse (
81
- 'https://nightly.link/mosuem /i18n/workflows/intl4x_artifacts/main/lib-$ platformName -latest.zip ' );
77
+ 'https://github.com/dart-lang /i18n/releases/download/$ version /$ target ' );
82
78
final request = await HttpClient ().getUrl (uri);
83
79
final response = await request.close ();
84
80
if (response.statusCode != 200 ) {
85
81
throw ArgumentError ('The request to $uri failed' );
86
82
}
87
- final zippedDynamicLibrary =
88
- File (path.join (Directory .systemTemp.path, 'tmp.zip' ));
89
- zippedDynamicLibrary.createSync ();
90
- await response.pipe (zippedDynamicLibrary.openWrite ());
91
-
92
- final dynamicLibrary =
93
- File .fromUri (config.outputDirectory.resolve ('icu4xlib' ));
83
+ final dynamicLibrary = File .fromUri (
84
+ config.outputDirectory.resolve (config.targetOS.dylibFileName ('icu4x' )));
94
85
await dynamicLibrary.create ();
95
- unzipFirstFile (input: zippedDynamicLibrary, output: dynamicLibrary);
96
- return dynamicLibrary.uri;
97
- }
86
+ await response.pipe (dynamicLibrary.openWrite ());
98
87
99
- String get platformName {
100
- if (Platform .isMacOS) {
101
- return 'macos' ;
102
- } else if (Platform .isWindows) {
103
- return 'windows' ;
88
+ final bytes = await dynamicLibrary.readAsBytes ();
89
+ final fileHash = sha256.convert (bytes).toString ();
90
+ final expectedFileHash = fileHashes[(
91
+ config.targetOS,
92
+ config.targetArchitecture,
93
+ )];
94
+ if (fileHash == expectedFileHash) {
95
+ return dynamicLibrary.uri;
104
96
} else {
105
- return 'ubuntu' ;
97
+ throw Exception (
98
+ 'The pre-built binary for the target $target at $uri has a hash of '
99
+ '$fileHash , which does not match $expectedFileHash fixed in the '
100
+ 'build hook of package:intl4x.' );
106
101
}
107
102
}
108
103
109
104
@override
110
105
List <Uri > get dependencies => [];
111
106
}
112
107
113
- final class LocalMode implements BuildMode {
114
- String get _localBinaryPath => Platform .environment['LOCAL_ICU4X_BINARY' ]! ;
108
+ final class LocalMode extends BuildMode {
109
+ LocalMode (super .config);
110
+
111
+ String get _localBinaryPath {
112
+ final localPath = Platform .environment['LOCAL_ICU4X_BINARY' ];
113
+ if (localPath != null ) {
114
+ return localPath;
115
+ }
116
+ throw ArgumentError ('`LOCAL_ICU4X_BINARY` is empty. '
117
+ 'If the `ICU4X_BUILD_MODE` is set to `local`, the '
118
+ '`LOCAL_ICU4X_BINARY` environment variable must contain the path to '
119
+ 'the binary.' );
120
+ }
115
121
116
122
@override
117
- Future <Uri > build () async => Uri .file (_localBinaryPath);
123
+ Future <Uri > build () async {
124
+ final dylibFileName = config.targetOS.dylibFileName ('icu4x' );
125
+ final dylibFileUri = config.outputDirectory.resolve (dylibFileName);
126
+ final file = File (_localBinaryPath);
127
+ if (! (await file.exists ())) {
128
+ throw FileSystemException ('Could not find binary.' , _localBinaryPath);
129
+ }
130
+ await file.copy (dylibFileUri.toFilePath (windows: Platform .isWindows));
131
+ return dylibFileUri;
132
+ }
118
133
119
134
@override
120
135
List <Uri > get dependencies => [Uri .file (_localBinaryPath)];
121
136
}
122
137
123
- final class CheckoutMode implements BuildMode {
124
- final BuildConfig config;
125
-
126
- CheckoutMode (this .config);
138
+ final class CheckoutMode extends BuildMode {
139
+ CheckoutMode (super .config);
127
140
128
141
String ? get workingDirectory => Platform .environment['LOCAL_ICU4X_CHECKOUT' ];
129
142
@@ -235,7 +248,7 @@ Future<Uri> buildLib(BuildConfig config, String workingDirectory) async {
235
248
if (! (await file.exists ())) {
236
249
throw FileSystemException ('Building the dylib failed' , builtPath);
237
250
}
238
- await file.copy (dylibFileUri.path );
251
+ await file.copy (dylibFileUri.toFilePath (windows : Platform .isWindows) );
239
252
}
240
253
return dylibFileUri;
241
254
}
0 commit comments