2024-04-30 23:38:49 +08:00
|
|
|
// ignore_for_file: avoid_print
|
|
|
|
|
|
|
|
|
|
import 'dart:convert';
|
|
|
|
|
import 'dart:io';
|
2024-12-03 21:47:12 +08:00
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
import 'package:args/command_runner.dart';
|
2025-04-18 17:50:46 +08:00
|
|
|
import 'package:crypto/crypto.dart';
|
2025-06-07 01:48:34 +08:00
|
|
|
import 'package:path/path.dart';
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2024-12-03 21:47:12 +08:00
|
|
|
enum Target {
|
2024-04-30 23:38:49 +08:00
|
|
|
windows,
|
|
|
|
|
linux,
|
|
|
|
|
android,
|
|
|
|
|
macos,
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-03 21:47:12 +08:00
|
|
|
extension TargetExt on Target {
|
|
|
|
|
String get os {
|
|
|
|
|
if (this == Target.macos) {
|
2025-06-07 01:48:34 +08:00
|
|
|
return 'darwin';
|
2024-12-03 21:47:12 +08:00
|
|
|
}
|
|
|
|
|
return name;
|
|
|
|
|
}
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2024-12-06 22:35:28 +08:00
|
|
|
bool get same {
|
|
|
|
|
if (this == Target.android) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (Platform.isWindows && this == Target.windows) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (Platform.isLinux && this == Target.linux) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (Platform.isMacOS && this == Target.macos) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
String get dynamicLibExtensionName {
|
|
|
|
|
final String extensionName;
|
2024-12-03 21:47:12 +08:00
|
|
|
switch (this) {
|
|
|
|
|
case Target.android || Target.linux:
|
2025-06-07 01:48:34 +08:00
|
|
|
extensionName = '.so';
|
2024-04-30 23:38:49 +08:00
|
|
|
break;
|
2024-12-03 21:47:12 +08:00
|
|
|
case Target.windows:
|
2025-06-07 01:48:34 +08:00
|
|
|
extensionName = '.dll';
|
2024-04-30 23:38:49 +08:00
|
|
|
break;
|
2024-12-03 21:47:12 +08:00
|
|
|
case Target.macos:
|
2025-06-07 01:48:34 +08:00
|
|
|
extensionName = '.dylib';
|
2024-04-30 23:38:49 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return extensionName;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-03 21:47:12 +08:00
|
|
|
String get executableExtensionName {
|
|
|
|
|
final String extensionName;
|
|
|
|
|
switch (this) {
|
|
|
|
|
case Target.windows:
|
2025-06-07 01:48:34 +08:00
|
|
|
extensionName = '.exe';
|
2024-12-03 21:47:12 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
2025-06-07 01:48:34 +08:00
|
|
|
extensionName = '';
|
2024-12-03 21:47:12 +08:00
|
|
|
break;
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
2024-12-03 21:47:12 +08:00
|
|
|
return extensionName;
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
2024-12-03 21:47:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum Mode { core, lib }
|
|
|
|
|
|
|
|
|
|
enum Arch { amd64, arm64, arm }
|
|
|
|
|
|
|
|
|
|
class BuildItem {
|
|
|
|
|
Target target;
|
|
|
|
|
Arch? arch;
|
|
|
|
|
String? archName;
|
|
|
|
|
|
|
|
|
|
BuildItem({
|
|
|
|
|
required this.target,
|
|
|
|
|
this.arch,
|
|
|
|
|
this.archName,
|
|
|
|
|
});
|
2024-07-17 17:02:25 +08:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
String toString() {
|
2024-12-03 21:47:12 +08:00
|
|
|
return 'BuildLibItem{target: $target, arch: $arch, archName: $archName}';
|
2024-07-17 17:02:25 +08:00
|
|
|
}
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Build {
|
2024-12-03 21:47:12 +08:00
|
|
|
static List<BuildItem> get buildItems => [
|
|
|
|
|
BuildItem(
|
|
|
|
|
target: Target.macos,
|
2024-12-06 22:35:28 +08:00
|
|
|
arch: Arch.arm64,
|
2024-07-17 17:02:25 +08:00
|
|
|
),
|
2024-12-03 21:47:12 +08:00
|
|
|
BuildItem(
|
2024-12-06 22:35:28 +08:00
|
|
|
target: Target.macos,
|
|
|
|
|
arch: Arch.amd64,
|
|
|
|
|
),
|
|
|
|
|
BuildItem(
|
|
|
|
|
target: Target.linux,
|
|
|
|
|
arch: Arch.arm64,
|
2024-07-17 17:02:25 +08:00
|
|
|
),
|
2024-12-03 21:47:12 +08:00
|
|
|
BuildItem(
|
|
|
|
|
target: Target.linux,
|
2024-12-06 22:35:28 +08:00
|
|
|
arch: Arch.amd64,
|
|
|
|
|
),
|
|
|
|
|
BuildItem(
|
|
|
|
|
target: Target.windows,
|
|
|
|
|
arch: Arch.amd64,
|
|
|
|
|
),
|
|
|
|
|
BuildItem(
|
|
|
|
|
target: Target.windows,
|
|
|
|
|
arch: Arch.arm64,
|
2024-04-30 23:38:49 +08:00
|
|
|
),
|
2024-12-03 21:47:12 +08:00
|
|
|
BuildItem(
|
|
|
|
|
target: Target.android,
|
2024-06-16 16:48:52 +08:00
|
|
|
arch: Arch.arm,
|
|
|
|
|
archName: 'armeabi-v7a',
|
|
|
|
|
),
|
2024-12-03 21:47:12 +08:00
|
|
|
BuildItem(
|
|
|
|
|
target: Target.android,
|
2024-04-30 23:38:49 +08:00
|
|
|
arch: Arch.arm64,
|
|
|
|
|
archName: 'arm64-v8a',
|
|
|
|
|
),
|
2024-12-03 21:47:12 +08:00
|
|
|
BuildItem(
|
|
|
|
|
target: Target.android,
|
2024-06-16 16:48:52 +08:00
|
|
|
arch: Arch.amd64,
|
|
|
|
|
archName: 'x86_64',
|
|
|
|
|
),
|
2024-04-30 23:38:49 +08:00
|
|
|
];
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static String get appName => 'FlClash';
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static String get coreName => 'FlClashCore';
|
2024-12-03 21:47:12 +08:00
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static String get libName => 'libclash';
|
2024-04-30 23:38:49 +08:00
|
|
|
|
|
|
|
|
static String get outDir => join(current, libName);
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static String get _coreDir => join(current, 'core');
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static String get _servicesDir => join(current, 'services', 'helper');
|
2024-12-03 21:47:12 +08:00
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static String get distPath => join(current, 'dist');
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2024-12-03 21:47:12 +08:00
|
|
|
static String _getCc(BuildItem buildItem) {
|
2024-04-30 23:38:49 +08:00
|
|
|
final environment = Platform.environment;
|
2024-12-03 21:47:12 +08:00
|
|
|
if (buildItem.target == Target.android) {
|
2025-06-07 01:48:34 +08:00
|
|
|
final ndk = environment['ANDROID_NDK'];
|
2024-04-30 23:38:49 +08:00
|
|
|
assert(ndk != null);
|
|
|
|
|
final prebuiltDir =
|
2025-06-07 01:48:34 +08:00
|
|
|
Directory(join(ndk!, 'toolchains', 'llvm', 'prebuilt'));
|
2024-04-30 23:38:49 +08:00
|
|
|
final prebuiltDirList = prebuiltDir.listSync();
|
|
|
|
|
final map = {
|
2025-06-07 01:48:34 +08:00
|
|
|
'armeabi-v7a': 'armv7a-linux-androideabi21-clang',
|
|
|
|
|
'arm64-v8a': 'aarch64-linux-android21-clang',
|
|
|
|
|
'x86': 'i686-linux-android21-clang',
|
|
|
|
|
'x86_64': 'x86_64-linux-android21-clang'
|
2024-04-30 23:38:49 +08:00
|
|
|
};
|
|
|
|
|
return join(
|
|
|
|
|
prebuiltDirList.first.path,
|
2025-06-07 01:48:34 +08:00
|
|
|
'bin',
|
2024-04-30 23:38:49 +08:00
|
|
|
map[buildItem.archName],
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-06-07 01:48:34 +08:00
|
|
|
return 'gcc';
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static String get tags => 'with_gvisor';
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2024-10-14 10:03:23 +08:00
|
|
|
static Future<void> exec(
|
|
|
|
|
List<String> executable, {
|
2024-04-30 23:38:49 +08:00
|
|
|
String? name,
|
|
|
|
|
Map<String, String>? environment,
|
|
|
|
|
String? workingDirectory,
|
|
|
|
|
bool runInShell = true,
|
|
|
|
|
}) async {
|
2025-06-07 01:48:34 +08:00
|
|
|
if (name != null) print('run $name');
|
2024-04-30 23:38:49 +08:00
|
|
|
final process = await Process.start(
|
|
|
|
|
executable[0],
|
|
|
|
|
executable.sublist(1),
|
|
|
|
|
environment: environment,
|
|
|
|
|
workingDirectory: workingDirectory,
|
|
|
|
|
runInShell: runInShell,
|
|
|
|
|
);
|
|
|
|
|
process.stdout.listen((data) {
|
|
|
|
|
print(utf8.decode(data));
|
|
|
|
|
});
|
|
|
|
|
process.stderr.listen((data) {
|
|
|
|
|
print(utf8.decode(data));
|
|
|
|
|
});
|
|
|
|
|
final exitCode = await process.exitCode;
|
2025-06-07 01:48:34 +08:00
|
|
|
if (exitCode != 0 && name != null) throw '$name error';
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
2025-04-18 17:50:46 +08:00
|
|
|
static Future<String> calcSha256(String filePath) async {
|
|
|
|
|
final file = File(filePath);
|
|
|
|
|
if (!await file.exists()) {
|
2025-06-07 01:48:34 +08:00
|
|
|
throw 'File not exists';
|
2025-04-18 17:50:46 +08:00
|
|
|
}
|
|
|
|
|
final stream = file.openRead();
|
|
|
|
|
return sha256.convert(await stream.reduce((a, b) => a + b)).toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Future<List<String>> buildCore({
|
2024-12-03 21:47:12 +08:00
|
|
|
required Mode mode,
|
|
|
|
|
required Target target,
|
2024-04-30 23:38:49 +08:00
|
|
|
Arch? arch,
|
|
|
|
|
}) async {
|
2024-12-03 21:47:12 +08:00
|
|
|
final isLib = mode == Mode.lib;
|
|
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
final items = buildItems.where(
|
2024-10-14 10:03:23 +08:00
|
|
|
(element) {
|
2024-12-03 21:47:12 +08:00
|
|
|
return element.target == target &&
|
2024-07-17 17:02:25 +08:00
|
|
|
(arch == null ? true : element.arch == arch);
|
2024-04-30 23:38:49 +08:00
|
|
|
},
|
|
|
|
|
).toList();
|
2024-12-03 21:47:12 +08:00
|
|
|
|
2025-04-18 17:50:46 +08:00
|
|
|
final List<String> corePaths = [];
|
|
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
for (final item in items) {
|
|
|
|
|
final outFileDir = join(
|
|
|
|
|
outDir,
|
2024-12-03 21:47:12 +08:00
|
|
|
item.target.name,
|
2024-04-30 23:38:49 +08:00
|
|
|
item.archName,
|
|
|
|
|
);
|
2024-12-03 21:47:12 +08:00
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
final file = File(outFileDir);
|
|
|
|
|
if (file.existsSync()) {
|
|
|
|
|
file.deleteSync(recursive: true);
|
|
|
|
|
}
|
2024-12-03 21:47:12 +08:00
|
|
|
|
|
|
|
|
final fileName = isLib
|
2025-06-07 01:48:34 +08:00
|
|
|
? '$libName${item.target.dynamicLibExtensionName}'
|
|
|
|
|
: '$coreName${item.target.executableExtensionName}';
|
2024-04-30 23:38:49 +08:00
|
|
|
final outPath = join(
|
|
|
|
|
outFileDir,
|
2024-12-03 21:47:12 +08:00
|
|
|
fileName,
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
2025-04-18 17:50:46 +08:00
|
|
|
corePaths.add(outPath);
|
2024-12-03 21:47:12 +08:00
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
final Map<String, String> env = {};
|
2025-06-07 01:48:34 +08:00
|
|
|
env['GOOS'] = item.target.os;
|
2024-12-06 22:35:28 +08:00
|
|
|
if (item.arch != null) {
|
2025-06-07 01:48:34 +08:00
|
|
|
env['GOARCH'] = item.arch!.name;
|
2024-12-06 22:35:28 +08:00
|
|
|
}
|
2024-12-03 21:47:12 +08:00
|
|
|
if (isLib) {
|
2025-06-07 01:48:34 +08:00
|
|
|
env['CGO_ENABLED'] = '1';
|
|
|
|
|
env['CC'] = _getCc(item);
|
|
|
|
|
env['CFLAGS'] = '-O3 -Werror';
|
2024-12-03 21:47:12 +08:00
|
|
|
} else {
|
2025-06-07 01:48:34 +08:00
|
|
|
env['CGO_ENABLED'] = '0';
|
2024-12-03 21:47:12 +08:00
|
|
|
}
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2024-12-03 21:47:12 +08:00
|
|
|
final execLines = [
|
2025-06-07 01:48:34 +08:00
|
|
|
'go',
|
|
|
|
|
'build',
|
|
|
|
|
'-ldflags=-w -s',
|
|
|
|
|
'-tags=$tags',
|
|
|
|
|
if (isLib) '-buildmode=c-shared',
|
|
|
|
|
'-o',
|
2024-12-03 21:47:12 +08:00
|
|
|
outPath,
|
|
|
|
|
];
|
2024-04-30 23:38:49 +08:00
|
|
|
await exec(
|
2024-12-03 21:47:12 +08:00
|
|
|
execLines,
|
2025-06-07 01:48:34 +08:00
|
|
|
name: 'build core',
|
2024-04-30 23:38:49 +08:00
|
|
|
environment: env,
|
|
|
|
|
workingDirectory: _coreDir,
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-04-18 17:50:46 +08:00
|
|
|
|
|
|
|
|
return corePaths;
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static Future<void> buildHelper(Target target, String token) async {
|
2024-12-03 21:47:12 +08:00
|
|
|
await exec(
|
|
|
|
|
[
|
2025-06-07 01:48:34 +08:00
|
|
|
'cargo',
|
|
|
|
|
'build',
|
|
|
|
|
'--release',
|
|
|
|
|
'--features',
|
|
|
|
|
'windows-service',
|
2024-12-03 21:47:12 +08:00
|
|
|
],
|
2025-04-18 17:50:46 +08:00
|
|
|
environment: {
|
2025-06-07 01:48:34 +08:00
|
|
|
'TOKEN': token,
|
2025-04-18 17:50:46 +08:00
|
|
|
},
|
2025-06-07 01:48:34 +08:00
|
|
|
name: 'build helper',
|
2024-12-03 21:47:12 +08:00
|
|
|
workingDirectory: _servicesDir,
|
|
|
|
|
);
|
|
|
|
|
final outPath = join(
|
|
|
|
|
_servicesDir,
|
2025-06-07 01:48:34 +08:00
|
|
|
'target',
|
|
|
|
|
'release',
|
|
|
|
|
'helper${target.executableExtensionName}',
|
2024-12-03 21:47:12 +08:00
|
|
|
);
|
2025-04-18 17:50:46 +08:00
|
|
|
final targetPath = join(
|
|
|
|
|
outDir,
|
|
|
|
|
target.name,
|
2025-06-07 01:48:34 +08:00
|
|
|
'FlClashHelperService${target.executableExtensionName}',
|
2025-04-18 17:50:46 +08:00
|
|
|
);
|
2024-12-03 21:47:12 +08:00
|
|
|
await File(outPath).copy(targetPath);
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
static List<String> getExecutable(String command) {
|
2025-06-07 01:48:34 +08:00
|
|
|
return command.split(' ');
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static Future<void> getDistributor() async {
|
2024-04-30 23:38:49 +08:00
|
|
|
final distributorDir = join(
|
|
|
|
|
current,
|
2025-06-07 01:48:34 +08:00
|
|
|
'plugins',
|
|
|
|
|
'flutter_distributor',
|
|
|
|
|
'packages',
|
|
|
|
|
'flutter_distributor',
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
name: 'clean distributor',
|
|
|
|
|
Build.getExecutable('flutter clean'),
|
2024-04-30 23:38:49 +08:00
|
|
|
workingDirectory: distributorDir,
|
|
|
|
|
);
|
2024-12-06 22:35:28 +08:00
|
|
|
await exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
name: 'upgrade distributor',
|
|
|
|
|
Build.getExecutable('flutter pub upgrade'),
|
2024-12-06 22:35:28 +08:00
|
|
|
workingDirectory: distributorDir,
|
|
|
|
|
);
|
2024-04-30 23:38:49 +08:00
|
|
|
await exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
name: 'get distributor',
|
|
|
|
|
Build.getExecutable('dart pub global activate -s path $distributorDir'),
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
static void copyFile(String sourceFilePath, String destinationFilePath) {
|
2024-04-30 23:38:49 +08:00
|
|
|
final sourceFile = File(sourceFilePath);
|
|
|
|
|
if (!sourceFile.existsSync()) {
|
2025-06-07 01:48:34 +08:00
|
|
|
throw 'SourceFilePath not exists';
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
final destinationFile = File(destinationFilePath);
|
|
|
|
|
final destinationDirectory = destinationFile.parent;
|
|
|
|
|
if (!destinationDirectory.existsSync()) {
|
|
|
|
|
destinationDirectory.createSync(recursive: true);
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
sourceFile.copySync(destinationFilePath);
|
2025-06-07 01:48:34 +08:00
|
|
|
print('File copied successfully!');
|
2024-04-30 23:38:49 +08:00
|
|
|
} catch (e) {
|
2025-06-07 01:48:34 +08:00
|
|
|
print('Failed to copy file: $e');
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class BuildCommand extends Command {
|
2024-12-03 21:47:12 +08:00
|
|
|
Target target;
|
2024-04-30 23:38:49 +08:00
|
|
|
|
|
|
|
|
BuildCommand({
|
2024-12-03 21:47:12 +08:00
|
|
|
required this.target,
|
2024-04-30 23:38:49 +08:00
|
|
|
}) {
|
2024-12-06 22:35:28 +08:00
|
|
|
if (target == Target.android || target == Target.linux) {
|
2024-12-03 21:47:12 +08:00
|
|
|
argParser.addOption(
|
2025-06-07 01:48:34 +08:00
|
|
|
'arch',
|
2024-12-03 21:47:12 +08:00
|
|
|
valueHelp: arches.map((e) => e.name).join(','),
|
|
|
|
|
help: 'The $name build desc',
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
argParser.addOption(
|
2025-06-07 01:48:34 +08:00
|
|
|
'arch',
|
2024-12-03 21:47:12 +08:00
|
|
|
help: 'The $name build archName',
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-04-30 23:38:49 +08:00
|
|
|
argParser.addOption(
|
2025-06-07 01:48:34 +08:00
|
|
|
'out',
|
2024-04-30 23:38:49 +08:00
|
|
|
valueHelp: [
|
2025-06-07 01:48:34 +08:00
|
|
|
if (target.same) 'app',
|
|
|
|
|
'core',
|
2024-04-30 23:38:49 +08:00
|
|
|
].join(','),
|
|
|
|
|
help: 'The $name build arch',
|
|
|
|
|
);
|
2025-03-12 17:15:31 +08:00
|
|
|
argParser.addOption(
|
2025-06-07 01:48:34 +08:00
|
|
|
'env',
|
2025-03-12 17:15:31 +08:00
|
|
|
valueHelp: [
|
2025-06-07 01:48:34 +08:00
|
|
|
'pre',
|
|
|
|
|
'stable',
|
2025-03-12 17:15:31 +08:00
|
|
|
].join(','),
|
|
|
|
|
help: 'The $name build env',
|
|
|
|
|
);
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
2025-06-07 01:48:34 +08:00
|
|
|
String get description => 'build $name application';
|
2024-04-30 23:38:49 +08:00
|
|
|
|
|
|
|
|
@override
|
2024-12-03 21:47:12 +08:00
|
|
|
String get name => target.name;
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2024-10-14 10:03:23 +08:00
|
|
|
List<Arch> get arches => Build.buildItems
|
2024-12-03 21:47:12 +08:00
|
|
|
.where((element) => element.target == target && element.arch != null)
|
|
|
|
|
.map((e) => e.arch!)
|
2024-10-14 10:03:23 +08:00
|
|
|
.toList();
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
Future<void> _getLinuxDependencies(Arch arch) async {
|
2024-04-30 23:38:49 +08:00
|
|
|
await Build.exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
Build.getExecutable('sudo apt update -y'),
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
|
|
|
|
await Build.exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
Build.getExecutable('sudo apt install -y ninja-build libgtk-3-dev'),
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
|
|
|
|
await Build.exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
Build.getExecutable('sudo apt install -y libayatana-appindicator3-dev'),
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
2024-09-08 21:21:21 +08:00
|
|
|
await Build.exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
Build.getExecutable('sudo apt-get install -y libkeybinder-3.0-dev'),
|
2024-09-08 21:21:21 +08:00
|
|
|
);
|
2024-04-30 23:38:49 +08:00
|
|
|
await Build.exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
Build.getExecutable('sudo apt install -y locate'),
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
2024-12-09 01:40:39 +08:00
|
|
|
if (arch == Arch.amd64) {
|
|
|
|
|
await Build.exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
Build.getExecutable('sudo apt install -y rpm patchelf'),
|
2024-12-09 01:40:39 +08:00
|
|
|
);
|
|
|
|
|
await Build.exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
Build.getExecutable('sudo apt install -y libfuse2'),
|
2024-12-09 01:40:39 +08:00
|
|
|
);
|
2025-04-18 17:50:46 +08:00
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
final downloadName = arch == Arch.amd64 ? 'x86_64' : 'aarch64';
|
2024-12-09 01:40:39 +08:00
|
|
|
await Build.exec(
|
|
|
|
|
Build.getExecutable(
|
2025-06-07 01:48:34 +08:00
|
|
|
'wget -O appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-$downloadName.AppImage',
|
2024-12-09 01:40:39 +08:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
await Build.exec(
|
|
|
|
|
Build.getExecutable(
|
2025-06-07 01:48:34 +08:00
|
|
|
'chmod +x appimagetool',
|
2024-12-09 01:40:39 +08:00
|
|
|
),
|
|
|
|
|
);
|
2025-04-18 17:50:46 +08:00
|
|
|
await Build.exec(
|
|
|
|
|
Build.getExecutable(
|
2025-06-07 01:48:34 +08:00
|
|
|
'sudo mv appimagetool /usr/local/bin/',
|
2025-04-18 17:50:46 +08:00
|
|
|
),
|
|
|
|
|
);
|
2024-12-09 01:40:39 +08:00
|
|
|
}
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
Future<void> _getMacosDependencies() async {
|
2024-04-30 23:38:49 +08:00
|
|
|
await Build.exec(
|
2025-06-07 01:48:34 +08:00
|
|
|
Build.getExecutable('npm install -g appdmg'),
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
Future<void> _buildDistributor({
|
2024-12-03 21:47:12 +08:00
|
|
|
required Target target,
|
2024-04-30 23:38:49 +08:00
|
|
|
required String targets,
|
|
|
|
|
String args = '',
|
2025-03-12 17:15:31 +08:00
|
|
|
required String env,
|
2024-04-30 23:38:49 +08:00
|
|
|
}) async {
|
|
|
|
|
await Build.getDistributor();
|
|
|
|
|
await Build.exec(
|
|
|
|
|
name: name,
|
|
|
|
|
Build.getExecutable(
|
2025-06-07 01:48:34 +08:00
|
|
|
'flutter_distributor package --skip-clean --platform ${target.name} --targets $targets --flutter-build-args=verbose$args --build-dart-define=APP_ENV=$env',
|
2024-04-30 23:38:49 +08:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-03 21:47:12 +08:00
|
|
|
Future<String?> get systemArch async {
|
|
|
|
|
if (Platform.isWindows) {
|
2025-06-07 01:48:34 +08:00
|
|
|
return Platform.environment['PROCESSOR_ARCHITECTURE'];
|
2024-12-03 21:47:12 +08:00
|
|
|
} else if (Platform.isLinux || Platform.isMacOS) {
|
|
|
|
|
final result = await Process.run('uname', ['-m']);
|
|
|
|
|
return result.stdout.toString().trim();
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
@override
|
|
|
|
|
Future<void> run() async {
|
2024-12-03 21:47:12 +08:00
|
|
|
final mode = target == Target.android ? Mode.lib : Mode.core;
|
2025-06-07 01:48:34 +08:00
|
|
|
final String out = argResults?['out'] ?? (target.same ? 'app' : 'core');
|
|
|
|
|
final archName = argResults?['arch'];
|
|
|
|
|
final env = argResults?['env'] ?? 'pre';
|
2024-12-06 22:35:28 +08:00
|
|
|
final currentArches =
|
|
|
|
|
arches.where((element) => element.name == archName).toList();
|
|
|
|
|
final arch = currentArches.isEmpty ? null : currentArches.first;
|
|
|
|
|
|
|
|
|
|
if (arch == null && target != Target.android) {
|
2025-06-07 01:48:34 +08:00
|
|
|
throw 'Invalid arch parameter';
|
2024-07-17 17:02:25 +08:00
|
|
|
}
|
2024-12-03 21:47:12 +08:00
|
|
|
|
2025-04-18 17:50:46 +08:00
|
|
|
final corePaths = await Build.buildCore(
|
2024-12-03 21:47:12 +08:00
|
|
|
target: target,
|
|
|
|
|
arch: arch,
|
|
|
|
|
mode: mode,
|
|
|
|
|
);
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
if (out != 'app') {
|
2024-04-30 23:38:49 +08:00
|
|
|
return;
|
|
|
|
|
}
|
2024-12-03 21:47:12 +08:00
|
|
|
|
|
|
|
|
switch (target) {
|
|
|
|
|
case Target.windows:
|
2025-04-18 17:50:46 +08:00
|
|
|
final token = target != Target.android
|
|
|
|
|
? await Build.calcSha256(corePaths.first)
|
|
|
|
|
: null;
|
|
|
|
|
Build.buildHelper(target, token!);
|
2024-04-30 23:38:49 +08:00
|
|
|
_buildDistributor(
|
2024-12-03 21:47:12 +08:00
|
|
|
target: target,
|
2025-06-07 01:48:34 +08:00
|
|
|
targets: 'exe,zip',
|
2025-04-18 17:50:46 +08:00
|
|
|
args:
|
2025-06-07 01:48:34 +08:00
|
|
|
' --description $archName --build-dart-define=CORE_SHA256=$token',
|
2025-03-12 17:15:31 +08:00
|
|
|
env: env,
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
2024-12-06 22:35:28 +08:00
|
|
|
return;
|
2024-12-03 21:47:12 +08:00
|
|
|
case Target.linux:
|
2024-12-06 22:35:28 +08:00
|
|
|
final targetMap = {
|
2025-06-07 01:48:34 +08:00
|
|
|
Arch.arm64: 'linux-arm64',
|
|
|
|
|
Arch.amd64: 'linux-x64',
|
2024-12-06 22:35:28 +08:00
|
|
|
};
|
2024-12-09 01:40:39 +08:00
|
|
|
final targets = [
|
2025-06-07 01:48:34 +08:00
|
|
|
'deb',
|
|
|
|
|
if (arch == Arch.amd64) 'appimage',
|
|
|
|
|
if (arch == Arch.amd64) 'rpm',
|
|
|
|
|
].join(',');
|
2024-12-06 22:35:28 +08:00
|
|
|
final defaultTarget = targetMap[arch];
|
|
|
|
|
await _getLinuxDependencies(arch!);
|
2024-04-30 23:38:49 +08:00
|
|
|
_buildDistributor(
|
2024-12-03 21:47:12 +08:00
|
|
|
target: target,
|
2024-12-09 01:40:39 +08:00
|
|
|
targets: targets,
|
2024-12-06 22:35:28 +08:00
|
|
|
args:
|
2025-06-07 01:48:34 +08:00
|
|
|
' --description $archName --build-target-platform $defaultTarget',
|
2025-03-12 17:15:31 +08:00
|
|
|
env: env,
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
2024-12-06 22:35:28 +08:00
|
|
|
return;
|
2024-12-03 21:47:12 +08:00
|
|
|
case Target.android:
|
2024-04-30 23:38:49 +08:00
|
|
|
final targetMap = {
|
2025-06-07 01:48:34 +08:00
|
|
|
Arch.arm: 'android-arm',
|
|
|
|
|
Arch.arm64: 'android-arm64',
|
|
|
|
|
Arch.amd64: 'android-x64',
|
2024-04-30 23:38:49 +08:00
|
|
|
};
|
2024-06-08 22:51:58 +08:00
|
|
|
final defaultArches = [Arch.arm, Arch.arm64, Arch.amd64];
|
2024-04-30 23:38:49 +08:00
|
|
|
final defaultTargets = defaultArches
|
|
|
|
|
.where((element) => arch == null ? true : element == arch)
|
|
|
|
|
.map((e) => targetMap[e])
|
|
|
|
|
.toList();
|
|
|
|
|
_buildDistributor(
|
2024-12-03 21:47:12 +08:00
|
|
|
target: target,
|
2025-06-07 01:48:34 +08:00
|
|
|
targets: 'apk',
|
2024-04-30 23:38:49 +08:00
|
|
|
args:
|
2025-04-09 16:46:14 +08:00
|
|
|
",split-per-abi --build-target-platform ${defaultTargets.join(",")}",
|
2025-03-12 17:15:31 +08:00
|
|
|
env: env,
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
2024-12-06 22:35:28 +08:00
|
|
|
return;
|
2024-12-03 21:47:12 +08:00
|
|
|
case Target.macos:
|
2024-04-30 23:38:49 +08:00
|
|
|
await _getMacosDependencies();
|
|
|
|
|
_buildDistributor(
|
2024-12-03 21:47:12 +08:00
|
|
|
target: target,
|
2025-06-07 01:48:34 +08:00
|
|
|
targets: 'dmg',
|
|
|
|
|
args: ' --description $archName',
|
2025-03-12 17:15:31 +08:00
|
|
|
env: env,
|
2024-04-30 23:38:49 +08:00
|
|
|
);
|
2024-12-06 22:35:28 +08:00
|
|
|
return;
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-07 01:48:34 +08:00
|
|
|
Future<void> main(Iterable<String> args) async {
|
|
|
|
|
final runner = CommandRunner('setup', 'build Application');
|
2024-12-03 21:47:12 +08:00
|
|
|
runner.addCommand(BuildCommand(target: Target.android));
|
2024-12-06 22:35:28 +08:00
|
|
|
runner.addCommand(BuildCommand(target: Target.linux));
|
|
|
|
|
runner.addCommand(BuildCommand(target: Target.windows));
|
|
|
|
|
runner.addCommand(BuildCommand(target: Target.macos));
|
2024-04-30 23:38:49 +08:00
|
|
|
runner.run(args);
|
|
|
|
|
}
|