150 lines
4.7 KiB
Dart
150 lines
4.7 KiB
Dart
/// Runs the Build workspace script.
|
|
library;
|
|
|
|
import 'dart:io';
|
|
|
|
/// Builds platform-specific Flutter desktop release artifacts.
|
|
Future<void> main(List<String> arguments) async {
|
|
final platform = _option(arguments, '--platform') ?? 'current';
|
|
final outputDirectory =
|
|
Directory(_option(arguments, '--output') ?? 'build/releases');
|
|
await outputDirectory.create(recursive: true);
|
|
|
|
final resolved = platform == 'current' ? _currentPlatform() : platform;
|
|
switch (resolved) {
|
|
case 'macos':
|
|
await _buildMacOs(outputDirectory);
|
|
break;
|
|
case 'windows':
|
|
await _buildWindows(outputDirectory);
|
|
break;
|
|
case 'linux':
|
|
await _buildLinux(outputDirectory);
|
|
break;
|
|
default:
|
|
throw ArgumentError.value(
|
|
platform,
|
|
'--platform',
|
|
'Expected current, macos, windows, or linux.',
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> _buildMacOs(Directory outputDirectory) async {
|
|
await _run('flutter', <String>['build', 'macos', '--release']);
|
|
final releaseDir = Directory('build/macos/Build/Products/Release');
|
|
final apps = releaseDir
|
|
.listSync()
|
|
.whereType<Directory>()
|
|
.where((entry) => entry.path.endsWith('.app'))
|
|
.toList(growable: false);
|
|
if (apps.isEmpty) {
|
|
throw StateError('No macOS .app found in ${releaseDir.path}.');
|
|
}
|
|
for (final app in apps) {
|
|
await _copyDirectory(
|
|
app, Directory(_join(outputDirectory.path, _basename(app.path))));
|
|
}
|
|
}
|
|
|
|
Future<void> _buildWindows(Directory outputDirectory) async {
|
|
await _run('flutter', <String>['build', 'windows', '--release']);
|
|
final bundle = Directory('build/windows/x64/runner/Release');
|
|
if (!await bundle.exists()) {
|
|
throw StateError('No Windows release bundle found in ${bundle.path}.');
|
|
}
|
|
await _copyDirectory(
|
|
bundle, Directory(_join(outputDirectory.path, 'windows')));
|
|
await _run('dart', <String>['run', 'msix:create']);
|
|
final msixFiles = Directory.current
|
|
.listSync(recursive: true)
|
|
.whereType<File>()
|
|
.where((file) => file.path.endsWith('.msix'))
|
|
.toList(growable: false);
|
|
if (msixFiles.isEmpty) {
|
|
throw StateError('No .msix artifact produced by dart run msix:create.');
|
|
}
|
|
for (final file in msixFiles) {
|
|
await file.copy(_join(outputDirectory.path, _basename(file.path)));
|
|
}
|
|
}
|
|
|
|
Future<void> _buildLinux(Directory outputDirectory) async {
|
|
await _run('flutter', <String>['build', 'linux', '--release']);
|
|
await _run('appimage-builder', <String>[
|
|
'--recipe',
|
|
'AppImageBuilder.yml',
|
|
'--skip-test',
|
|
]);
|
|
final appImages = Directory.current
|
|
.listSync(recursive: true)
|
|
.whereType<File>()
|
|
.where((file) => file.path.endsWith('.AppImage'))
|
|
.toList(growable: false);
|
|
if (appImages.isEmpty) {
|
|
throw StateError('No AppImage artifact produced by appimage-builder.');
|
|
}
|
|
for (final file in appImages) {
|
|
await file.copy(_join(outputDirectory.path, _basename(file.path)));
|
|
}
|
|
}
|
|
|
|
Future<void> _run(String executable, List<String> arguments) async {
|
|
stdout.writeln('> $executable ${arguments.join(' ')}');
|
|
final result = await Process.run(
|
|
executable,
|
|
arguments,
|
|
runInShell: Platform.isWindows,
|
|
);
|
|
stdout.write(result.stdout);
|
|
stderr.write(result.stderr);
|
|
if (result.exitCode != 0) {
|
|
throw ProcessException(
|
|
executable,
|
|
arguments,
|
|
'Command failed with exit code ${result.exitCode}.',
|
|
result.exitCode,
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> _copyDirectory(Directory source, Directory destination) async {
|
|
await destination.create(recursive: true);
|
|
await for (final entity in source.list(recursive: false)) {
|
|
final targetPath = _join(destination.path, _basename(entity.path));
|
|
if (entity is Directory) {
|
|
await _copyDirectory(entity, Directory(targetPath));
|
|
} else if (entity is File) {
|
|
await entity.copy(targetPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
String _currentPlatform() {
|
|
if (Platform.isMacOS) return 'macos';
|
|
if (Platform.isWindows) return 'windows';
|
|
if (Platform.isLinux) return 'linux';
|
|
throw UnsupportedError('No Flutter desktop build target for this platform.');
|
|
}
|
|
|
|
String _basename(String path) {
|
|
final normalized = path.replaceAll('\\', '/');
|
|
return normalized.substring(normalized.lastIndexOf('/') + 1);
|
|
}
|
|
|
|
String _join(String first, String second) {
|
|
final separator = Platform.pathSeparator;
|
|
final left = first.endsWith(separator)
|
|
? first.substring(0, first.length - separator.length)
|
|
: first;
|
|
final right = second.startsWith(separator) ? second.substring(1) : second;
|
|
return '$left$separator$right';
|
|
}
|
|
|
|
String? _option(List<String> arguments, String name) {
|
|
final index = arguments.indexOf(name);
|
|
if (index == -1 || index + 1 >= arguments.length) {
|
|
return null;
|
|
}
|
|
return arguments[index + 1];
|
|
}
|