ensureVersion method
Ensures version is downloaded, checksum verified, and extracted.
Returns null on success, or an error message describing the failure.
Already-installed versions are silently skipped.
Implementation
Future<String?> ensureVersion(
String version, {
String? githubToken,
}) async {
if (compareVersions(version, minSupportedVersion) < 0) {
return 'Inno Setup $version is below the minimum supported version '
'($minSupportedVersion) of inno_bundle and would never be used. '
'Install $minSupportedVersion or newer.';
}
if (isccPath(version) != null) return null;
final versionTag = version.replaceAll('.', '_');
final apiUrl = 'https://api.github.com'
'/repos/jrsoftware/issrc/releases/tags/is-$versionTag';
final releaseData = await fetchGitHubReleaseData(
apiUrl,
githubToken: githubToken,
);
if (releaseData == null) {
return 'Failed to fetch release info for version $version — '
'check that the version exists.' +
(githubToken == null
? ' Tip: set GITHUB_TOKEN (or GH_TOKEN) to avoid API rate limits.'
: '');
}
// after Inno Setup 7 it started having 32-bit and 64-bit versions,
// flutter only needs the 64-bit version.
final isVersionEqualOrGreaterThan7 = version.compareTo('7.0.0') >= 0;
final assetName =
'innosetup-$version${isVersionEqualOrGreaterThan7 ? '-x64' : ''}.exe';
final assets = releaseData['assets'] as List<dynamic>?;
Map<String, dynamic>? asset;
if (assets != null) {
for (final a in assets) {
if (a is Map<String, dynamic> && a['name'] == assetName) {
asset = a;
break;
}
}
}
if (asset == null) {
return 'Asset $assetName not found for version $version.';
}
final downloadUrl = asset['browser_download_url'] as String;
final digest = asset['digest'] as String;
final expectedHash =
digest.startsWith('sha256:') ? digest.substring(7) : digest;
final tempDir = Directory.systemTemp;
final installerPath = p.join(tempDir.path, assetName);
final installerFileCached = await _tryUseCachedInstaller(
installerPath,
expectedHash,
);
if (!installerFileCached) {
try {
await downloadFile(downloadUrl, installerPath);
} catch (e) {
return 'Failed to download $version: $e';
}
final actualHash = await sha256HashFile(installerPath);
if (actualHash == null ||
actualHash.toLowerCase() != expectedHash.toLowerCase()) {
File(installerPath).deleteSync();
return 'Checksum mismatch for $version.\n'
' Expected: $expectedHash\n'
' Actual: $actualHash';
}
}
final dest = p.join(versionsDir, version);
Directory(dest).createSync(recursive: true);
final result = await Process.run(
installerPath,
[
'/VERYSILENT',
'/SUPPRESSMSGBOXES',
'/NORESTART',
'/CURRENTUSER',
'/DIR=$dest',
],
runInShell: true);
File(installerPath).deleteSync();
if (result.exitCode != 0) {
return 'Installer for $version exited with code ${result.exitCode}.';
}
if (!File(p.join(dest, 'ISCC.exe')).existsSync()) {
return 'ISCC.exe not found after extracting $version.';
}
return null;
}