#!/usr/bin/env dart
// Generated by alef. Do not edit by hand.
// Download platform-specific native library for {{ crate_name }} from GitHub releases.
import 'dart:io';
import 'dart:typed_data';
import 'package:http/http.dart' as http;
const String _moduleVersion = '{{ version }}';
const String _repoUrl = '{{ repo_url }}';
const String _assetPrefix = '{{ crate_name }}';
const String _libStem = '{{ lib_stem }}';
void main() async {
try {
await _run();
} catch (e) {
stderr.writeln('Error: $e');
exit(1);
}
}
Future<void> _run() async {
final (cacheDir, libPath) = _determinePaths();
// Check if library already exists
if (File(libPath).existsSync()) {
return;
}
// Download the FFI library archive
await _downloadAndExtractLibrary(cacheDir);
}
(String, String) _determinePaths() {
final osName = _osName();
final arch = _arch();
// Use the package root (where pubspec.yaml lives) as base
final packageRoot = _packageRoot();
final libDir = '$packageRoot${Platform.pathSeparator}lib${Platform.pathSeparator}src${Platform.pathSeparator}native${Platform.pathSeparator}$osName-$arch';
final libPath = '$libDir${Platform.pathSeparator}${_libFilename()}';
return (libDir, libPath);
}
String _osName() {
if (Platform.isMacOS) return 'macos';
if (Platform.isWindows) return 'windows';
if (Platform.isLinux) return 'linux';
throw UnsupportedError('Unsupported OS: ${Platform.operatingSystem}');
}
String _arch() {
// Determine architecture from Dart's `Abi` at runtime if available,
// or fallback to sysctl/getconf inspection.
// For now, use a simple heuristic based on Platform.resolvedExecutable.
final exe = Platform.resolvedExecutable;
if (exe.contains('arm64') || exe.contains('aarch64')) return 'arm64';
if (exe.contains('x86_64') || exe.contains('amd64')) return 'x64';
if (exe.contains('x86')) return 'x86';
throw UnsupportedError('Cannot determine architecture');
}
String _libFilename() {
if (Platform.isMacOS) return 'lib${_libStem}_dart.dylib';
if (Platform.isWindows) return '${_libStem}_dart.dll';
return 'lib${_libStem}_dart.so';
}
String _packageRoot() {
// Use the directory containing this script (bin/) as reference
// to find the package root (parent of bin/).
final scriptPath = Platform.script.toFilePath();
final binDir = File(scriptPath).parent;
return binDir.parent.path;
}
Future<void> _downloadAndExtractLibrary(String cacheDir) async {
final osName = _osName();
var arch = _arch();
// Map Dart arch names to alef platform names used in release asset filenames.
// Go uses x86_64/aarch64; macOS arm64 may differ.
if (arch == 'arm64' && !Platform.isMacOS) {
arch = 'aarch64';
} else if (arch == 'x64') {
arch = 'x86_64';
}
// Clean version for asset name
final version = _moduleVersion.startsWith('v')
? _moduleVersion.substring(1)
: _moduleVersion;
final assetName = '$_assetPrefix-dart-v$version-$osName-$arch.tar.gz';
final downloadUrl = '$_repoUrl/releases/download/v$version/$assetName';
// Create cache directory
await Directory(cacheDir).create(recursive: true);
// Download tarball
final response = await http.get(Uri.parse(downloadUrl));
if (response.statusCode != 200) {
throw Exception('HTTP ${response.statusCode}: Failed to download $downloadUrl');
}
// Extract tarball to cache directory
await _extractTarGz(response.bodyBytes, cacheDir);
}
Future<void> _extractTarGz(Uint8List bytes, String dstDir) async {
// Simple tar.gz extraction via a native tar command (Unix/macOS) or 7-Zip (Windows).
// A pure-Dart implementation would require a tar+gzip library; invoking the OS
// tool is simpler and more reliable.
final tempFile = File('$dstDir/.download.tar.gz');
try {
await tempFile.writeAsBytes(bytes);
if (Platform.isWindows) {
// Windows: use 7z if available (usually bundled), else tar.exe (Win10+)
await Process.run('tar', ['-xzf', tempFile.path, '-C', dstDir]);
} else {
// Unix/macOS: tar command is ubiquitous
await Process.run('tar', ['-xzf', tempFile.path, '-C', dstDir]);
}
} finally {
if (tempFile.existsSync()) {
await tempFile.delete();
}
}
}