runRegenerateHashesCli function
Future<void>
runRegenerateHashesCli(
- List<
String> args, { - required String defaultVersion,
- required PrebuiltReleaseConfig releaseConfigForVersion(
- String version
- String hashesFilePath = 'lib/src/hook_helpers/hashes.dart',
- String? versionFilePath = 'lib/src/hook_helpers/version.dart',
- String versionConstName = 'releaseVersion',
- String licenseHeader = '// Copyright 2026 Moritz Sümmermann. Licensed under the Apache License,\n' '// Version 2.0. See the LICENSE file for details.\n',
- List<
TargetSpec> targets = supportedTargets, - List<
bool> staticModes = const [false, true],
CLI runner for tool/regenerate_hashes.dart.
Computes SHA-256 digests for all targets and staticModes either from a
local directory (args[1], e.g. in CI before/during a release) or by
downloading from the release URLs returned by releaseConfigForVersion.
Writes the resulting hashes to hashesFilePath (and optionally updates
versionFilePath).
Implementation
Future<void> runRegenerateHashesCli(
List<String> args, {
required String defaultVersion,
required PrebuiltReleaseConfig Function(String version)
releaseConfigForVersion,
String hashesFilePath = 'lib/src/hook_helpers/hashes.dart',
String? versionFilePath = 'lib/src/hook_helpers/version.dart',
String versionConstName = 'releaseVersion',
String licenseHeader =
'// Copyright 2026 Moritz Sümmermann. Licensed under the Apache License,\n'
'// Version 2.0. See the LICENSE file for details.\n',
List<TargetSpec> targets = supportedTargets,
List<bool> staticModes = const [false, true],
}) async {
final version = args.isNotEmpty ? args[0] : defaultVersion;
final localDir = args.length > 1 ? Directory(args[1]) : null;
final releaseConfig = releaseConfigForVersion(version);
final httpClient = localDir == null
? (HttpClient()..findProxy = HttpClient.findProxyFromEnvironment)
: null;
stdout.writeln('Checking hashes for version $version...');
final fileHashes = <String, String>{};
try {
for (final (os, arch, iosSdk) in targets) {
for (final static in staticModes) {
final assetName = releaseConfig.resolveAssetName(
os,
arch,
iosSdk: iosSdk,
static: static,
);
if (localDir != null) {
final file = File('${localDir.path}/$assetName');
if (!await file.exists()) {
stdout.writeln(' Skipping missing local file: ${file.path}');
continue;
}
final fileHash = sha256.convert(await file.readAsBytes()).toString();
fileHashes[assetName] = fileHash;
stdout.writeln(' $assetName: $fileHash');
continue;
}
final uri = releaseConfig.resolveDownloadUri(version, assetName);
stdout.writeln('Fetching from $uri...');
try {
final request = await httpClient!.getUrl(uri);
final response = await request.close();
if (response.statusCode != 200) {
stdout.writeln(' Skipping: status ${response.statusCode}');
await response.drain<void>();
continue;
}
final builder = BytesBuilder(copy: false);
await response.forEach(builder.add);
final fileHash = sha256.convert(builder.takeBytes()).toString();
fileHashes[assetName] = fileHash;
stdout.writeln(' $assetName: $fileHash');
} catch (e) {
stdout.writeln(' Error fetching $uri: $e');
}
}
}
} finally {
httpClient?.close(force: true);
}
final filesToFormat = <String>[hashesFilePath];
if (versionFilePath != null) {
await File(versionFilePath).writeAsString(
'$licenseHeader\n'
"const $versionConstName = '$version';\n",
);
filesToFormat.add(versionFilePath);
}
final versionFileBasename = versionFilePath?.split('/').last;
final buffer = StringBuffer();
if (licenseHeader.isNotEmpty) {
buffer.write(licenseHeader);
if (!licenseHeader.endsWith('\n')) buffer.writeln();
buffer.writeln();
}
buffer
..writeln('// coverage:ignore-file')
..writeln('// THIS FILE IS GENERATED BY `tool/regenerate_hashes.dart`.')
..writeln();
if (versionFileBasename != null) {
buffer
..writeln("import '$versionFileBasename';")
..writeln()
..writeln('const version = $versionConstName;')
..writeln();
} else {
buffer
..writeln("const version = '$version';")
..writeln();
}
buffer
..writeln('/// Mapping from release asset name to SHA-256 hash.')
..writeln('const fileHashes = <String, String>{');
for (final entry in fileHashes.entries) {
buffer.writeln(" '${entry.key}':");
buffer.writeln(" '${entry.value}',");
}
buffer.writeln('};');
await File(hashesFilePath).writeAsString(buffer.toString());
await Process.run(Platform.resolvedExecutable, ['format', ...filesToFormat]);
stdout.writeln(
'Updated $hashesFilePath with ${fileHashes.length} hashes.',
);
}