Skip to content

Commit 1cc0363

Browse files
authored
[native_assets_cli] Version protocol between Dart SDK and packages (#26)
1 parent db3983d commit 1cc0363

File tree

6 files changed

+98
-9
lines changed

6 files changed

+98
-9
lines changed

pkgs/native_assets_cli/lib/src/model/build_config.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'package:cli_config/cli_config.dart';
66
import 'package:collection/collection.dart';
7+
import 'package:pub_semver/pub_semver.dart';
78

89
import '../utils/map.dart';
910
import '../utils/yaml.dart';
@@ -105,6 +106,16 @@ class BuildConfig {
105106

106107
BuildConfig._();
107108

109+
/// The version of [BuildConfig].
110+
///
111+
/// This class is used in the protocol between the Dart and Flutter SDKs
112+
/// and packages through `build.dart` invocations.
113+
///
114+
/// If we ever were to make breaking changes, it would be useful to give
115+
/// proper error messages rather than just fail to parse the YAML
116+
/// representation in the protocol.
117+
static Version version = Version(1, 0, 0);
118+
108119
factory BuildConfig.fromConfig(Config config) {
109120
final result = BuildConfig._();
110121
final configExceptions = <Object>[];
@@ -159,11 +170,29 @@ class BuildConfig {
159170
static const toolchainEnvScriptArgsConfigKey =
160171
'toolchain_env_script_arguments';
161172
static const dependencyMetadataConfigKey = 'dependency_metadata';
173+
static const _versionKey = 'version';
162174

163175
List<void Function(Config)> _readFieldsFromConfig() {
164176
var targetSet = false;
165177
var ccSet = false;
166178
return [
179+
(config) {
180+
final configVersion = Version.parse(config.string('version'));
181+
if (configVersion.major > version.major) {
182+
throw FormatException(
183+
'The config version $configVersion is newer than this '
184+
'package:native_assets_cli config version $version, '
185+
'please update native_assets_cli.',
186+
);
187+
}
188+
if (configVersion.major < version.major) {
189+
throw FormatException(
190+
'The config version $configVersion is newer than this '
191+
'package:native_assets_cli config version $version, '
192+
'please update the Dart or Flutter SDK.',
193+
);
194+
}
195+
},
167196
(config) => _config = config,
168197
(config) => _outDir = config.path(outDirConfigKey),
169198
(config) => _packageRoot = config.path(packageRootConfigKey),
@@ -255,6 +284,7 @@ class BuildConfig {
255284
for (final entry in _dependencyMetadata!.entries)
256285
entry.key: entry.value.toYaml(),
257286
},
287+
_versionKey: version.toString(),
258288
}.sortOnKey();
259289

260290
String toYamlString() => yamlEncode(toYaml());

pkgs/native_assets_cli/lib/src/model/build_output.dart

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'dart:io';
66

77
import 'package:collection/collection.dart';
8+
import 'package:pub_semver/pub_semver.dart';
89
import 'package:yaml/yaml.dart';
910

1011
import '../utils/datetime.dart';
@@ -39,29 +40,59 @@ class BuildOutput {
3940
static const _dependenciesKey = 'dependencies';
4041
static const _metadataKey = 'metadata';
4142
static const _timestampKey = 'timestamp';
43+
static const _versionKey = 'version';
4244

4345
factory BuildOutput.fromYamlString(String yaml) {
4446
final yamlObject = loadYaml(yaml) as YamlMap;
4547
return BuildOutput.fromYaml(yamlObject);
4648
}
4749

48-
factory BuildOutput.fromYaml(YamlMap yamlMap) => BuildOutput(
49-
timestamp: DateTime.parse(yamlMap[_timestampKey] as String),
50-
assets: Asset.listFromYamlList(yamlMap[_assetsKey] as YamlList),
51-
dependencies:
52-
Dependencies.fromYaml(yamlMap[_dependenciesKey] as YamlList?),
53-
metadata: Metadata.fromYaml(yamlMap[_metadataKey] as YamlMap?),
50+
factory BuildOutput.fromYaml(YamlMap yamlMap) {
51+
final outputVersion = Version.parse(yamlMap['version'] as String);
52+
if (outputVersion.major > version.major) {
53+
throw FormatException(
54+
'The output version $outputVersion is newer than the '
55+
'package:native_assets_cli config version $version in Dart or Flutter, '
56+
'please update the Dart or Flutter SDK.',
5457
);
58+
}
59+
if (outputVersion.major < version.major) {
60+
throw FormatException(
61+
'The output version $outputVersion is newer than this '
62+
'package:native_assets_cli config version $version in Dart or Flutter, '
63+
'please update native_assets_cli.',
64+
);
65+
}
66+
67+
return BuildOutput(
68+
timestamp: DateTime.parse(yamlMap[_timestampKey] as String),
69+
assets: Asset.listFromYamlList(yamlMap[_assetsKey] as YamlList),
70+
dependencies:
71+
Dependencies.fromYaml(yamlMap[_dependenciesKey] as YamlList?),
72+
metadata: Metadata.fromYaml(yamlMap[_metadataKey] as YamlMap?),
73+
);
74+
}
5575

5676
Map<String, Object> toYaml() => {
5777
_timestampKey: timestamp.toString(),
5878
_assetsKey: assets.toYaml(),
5979
_dependenciesKey: dependencies.toYaml(),
6080
_metadataKey: metadata.toYaml(),
81+
_versionKey: version.toString(),
6182
}..sortOnKey();
6283

6384
String toYamlString() => yamlEncode(toYaml());
6485

86+
/// The version of [BuildOutput].
87+
///
88+
/// This class is used in the protocol between the Dart and Flutter SDKs
89+
/// and packages through `build.dart` invocations.
90+
///
91+
/// If we ever were to make breaking changes, it would be useful to give
92+
/// proper error messages rather than just fail to parse the YAML
93+
/// representation in the protocol.
94+
static Version version = Version(1, 0, 0);
95+
6596
static const fileName = 'build_output.yaml';
6697

6798
/// Writes the YAML file from [outDir]/[fileName].

pkgs/native_assets_cli/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ environment:
99
dependencies:
1010
cli_config: ^0.1.1
1111
collection: ^1.17.1
12+
pub_semver: ^2.1.3
1213
yaml: ^3.1.1
1314
yaml_edit: ^2.1.0
1415

pkgs/native_assets_cli/test/example/native_add_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ void main() async {
4141
if (toolchainEnvScriptArgs != null)
4242
'-D${BuildConfig.toolchainEnvScriptArgsConfigKey}='
4343
'${toolchainEnvScriptArgs!.join(' ')}',
44+
'-Dversion=${BuildConfig.version}',
4445
],
4546
workingDirectory: testPackageUri.toFilePath(),
4647
);

pkgs/native_assets_cli/test/model/build_config_test.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ void main() async {
7979
'package_root': tempUri.resolve('packageRoot/').toFilePath(),
8080
'target': 'android_arm64',
8181
'link_mode_preference': 'prefer-static',
82+
'version': BuildOutput.version.toString(),
8283
});
8384

8485
final fromConfig = BuildConfig.fromConfig(config);
@@ -175,7 +176,8 @@ link_mode_preference: prefer-static
175176
out_dir: ${outDir.toFilePath()}
176177
package_root: ${tempUri.toFilePath()}
177178
target: ios_arm64
178-
target_ios_sdk: iphoneos''';
179+
target_ios_sdk: iphoneos
180+
version: ${BuildConfig.version}''';
179181
expect(yamlString, equals(expectedYamlString));
180182

181183
final buildConfig2 = BuildConfig.fromConfig(
@@ -298,4 +300,18 @@ target_ios_sdk: iphoneos''';
298300
final fromConfig = BuildConfig.fromConfig(config);
299301
expect(fromConfig, equals(buildConfig1));
300302
});
303+
304+
for (final version in ['9001.0.0', '0.0.1']) {
305+
test('BuildConfig version $version', () {
306+
final outDir = tempUri.resolve('out1/');
307+
final config = Config(fileParsed: {
308+
'link_mode_preference': 'prefer-static',
309+
'out_dir': outDir.toFilePath(),
310+
'package_root': tempUri.toFilePath(),
311+
'target': 'linux_x64',
312+
'version': version,
313+
});
314+
expect(() => BuildConfig.fromConfig(config), throwsFormatException);
315+
});
316+
}
301317
}

pkgs/native_assets_cli/test/model/build_output_test.dart

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void main() {
4242
}),
4343
);
4444

45-
const yamlEncoding = '''timestamp: 2022-11-10 13:25:01.000
45+
final yamlEncoding = '''timestamp: 2022-11-10 13:25:01.000
4646
assets:
4747
- name: foo
4848
link_mode: dynamic
@@ -59,7 +59,8 @@ assets:
5959
dependencies:
6060
- path/to/file.ext
6161
metadata:
62-
key: value''';
62+
key: value
63+
version: ${BuildOutput.version}''';
6364

6465
test('built info yaml', () {
6566
final yaml = buildOutput.toYamlString().replaceAll('\\', '/');
@@ -94,4 +95,13 @@ metadata:
9495
);
9596
expect(buildOutput3.timestamp, DateTime.parse('2022-11-10 13:25:01.000'));
9697
});
98+
99+
for (final version in ['9001.0.0', '0.0.1']) {
100+
test('BuildOutput version $version', () {
101+
expect(
102+
() => BuildOutput.fromYamlString('version: $version'),
103+
throwsFormatException,
104+
);
105+
});
106+
}
97107
}

0 commit comments

Comments
 (0)