mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Refactor the way the releases are built
This workflow is not manually triggered and can create automatically the appropriate tag. The build number is not increase to the next multiple of ten, to stay in sync with the iOS releases, which seem to cause more trouble and often need reuploads. The individual steps have been moved out to their own files, for better readability. We also now build the app for all supported platforms.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'flatpak_shared.dart';
|
||||
|
||||
/// Creates an archive containing all the sources for the Flatpak package for a
|
||||
@@ -25,7 +26,8 @@ void main(List<String> arguments) async {
|
||||
final metaIndex = arguments.indexOf('--meta');
|
||||
if (metaIndex == -1) {
|
||||
throw Exception(
|
||||
'You must run this script with a metadata file argument, using the --meta flag.');
|
||||
'You must run this script with a metadata file argument, using the --meta flag.',
|
||||
);
|
||||
}
|
||||
if (arguments.length == metaIndex + 1) {
|
||||
throw Exception('The --meta flag must be followed by the path to the metadata file.');
|
||||
@@ -54,12 +56,16 @@ void main(List<String> arguments) async {
|
||||
await outputDir.create();
|
||||
|
||||
final packageGenerator = PackageGenerator(
|
||||
inputDir: metaFile.parent, meta: meta, addedTodaysVersion: addedTodaysVersion);
|
||||
inputDir: metaFile.parent,
|
||||
meta: meta,
|
||||
addedTodaysVersion: addedTodaysVersion,
|
||||
);
|
||||
|
||||
await packageGenerator.generatePackage(
|
||||
outputDir,
|
||||
await PackageGenerator.runningOnARM() ? CPUArchitecture.aarch64 : CPUArchitecture.x86_64,
|
||||
fetchFromGithub);
|
||||
outputDir,
|
||||
await PackageGenerator.runningOnARM() ? CPUArchitecture.aarch64 : CPUArchitecture.x86_64,
|
||||
fetchFromGithub,
|
||||
);
|
||||
}
|
||||
|
||||
class PackageGenerator {
|
||||
@@ -67,10 +73,17 @@ class PackageGenerator {
|
||||
final FlatpakMeta meta;
|
||||
final String? addedTodaysVersion;
|
||||
|
||||
PackageGenerator({required this.inputDir, required this.meta, required this.addedTodaysVersion});
|
||||
const PackageGenerator({
|
||||
required this.inputDir,
|
||||
required this.meta,
|
||||
required this.addedTodaysVersion,
|
||||
});
|
||||
|
||||
Future<void> generatePackage(
|
||||
Directory outputDir, CPUArchitecture arch, bool fetchReleasesFromGithub) async {
|
||||
Directory outputDir,
|
||||
CPUArchitecture arch,
|
||||
bool fetchReleasesFromGithub,
|
||||
) async {
|
||||
final tempDir = await outputDir.createTemp('flutter_generator_temp');
|
||||
final appId = meta.appId;
|
||||
|
||||
@@ -79,7 +92,8 @@ class PackageGenerator {
|
||||
|
||||
if (!(await desktopFile.exists())) {
|
||||
throw Exception(
|
||||
'The desktop file does not exist under the specified path: ${desktopFile.path}');
|
||||
'The desktop file does not exist under the specified path: ${desktopFile.path}',
|
||||
);
|
||||
}
|
||||
|
||||
await desktopFile.copy('${tempDir.path}/$appId.desktop');
|
||||
@@ -101,12 +115,14 @@ class PackageGenerator {
|
||||
final origAppStreamFile = File('${inputDir.path}/${meta.appStreamPath}');
|
||||
if (!(await origAppStreamFile.exists())) {
|
||||
throw Exception(
|
||||
'The app data file does not exist under the specified path: ${origAppStreamFile.path}');
|
||||
'The app data file does not exist under the specified path: ${origAppStreamFile.path}',
|
||||
);
|
||||
}
|
||||
|
||||
final editedAppStreamContent = AppStreamModifier.replaceVersions(
|
||||
await origAppStreamFile.readAsString(),
|
||||
await meta.getReleases(fetchReleasesFromGithub, addedTodaysVersion));
|
||||
await origAppStreamFile.readAsString(),
|
||||
await meta.getReleases(fetchReleasesFromGithub, addedTodaysVersion),
|
||||
);
|
||||
|
||||
final editedAppStreamFile = File('${tempDir.path}/$appId.metainfo.xml');
|
||||
await editedAppStreamFile.writeAsString(editedAppStreamContent);
|
||||
@@ -117,7 +133,8 @@ class PackageGenerator {
|
||||
final buildDir = Directory(bundlePath);
|
||||
if (!(await buildDir.exists())) {
|
||||
throw Exception(
|
||||
'The linux build directory does not exist under the specified path: ${buildDir.path}');
|
||||
'The linux build directory does not exist under the specified path: ${buildDir.path}',
|
||||
);
|
||||
}
|
||||
final destDir = Directory('${tempDir.path}/bin');
|
||||
await destDir.create();
|
||||
@@ -159,9 +176,10 @@ class AppStreamModifier {
|
||||
.replaceAll('\n', '<~>')
|
||||
.replaceFirst(RegExp('<releases.*</releases>'), releasesSection)
|
||||
.replaceAll('<~>', '\n');
|
||||
} else {
|
||||
return origAppStreamContent.replaceFirst(
|
||||
'</component>', '\n\t$releasesSection\n</component>');
|
||||
}
|
||||
return origAppStreamContent.replaceFirst(
|
||||
'</component>',
|
||||
'\n\t$releasesSection\n</component>',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ class Release {
|
||||
final String version;
|
||||
final String date; //TODO add resources
|
||||
|
||||
Release({required this.version, required this.date});
|
||||
const Release({required this.version, required this.date});
|
||||
}
|
||||
|
||||
enum CPUArchitecture {
|
||||
@@ -18,6 +18,7 @@ enum CPUArchitecture {
|
||||
|
||||
final String flatpakArchCode;
|
||||
final String flutterDirName;
|
||||
|
||||
const CPUArchitecture(this.flatpakArchCode, this.flutterDirName);
|
||||
}
|
||||
|
||||
@@ -27,11 +28,12 @@ class ReleaseAsset {
|
||||
final bool isRelativeLocalPath;
|
||||
final String tarballSha256;
|
||||
|
||||
ReleaseAsset(
|
||||
{required this.arch,
|
||||
required this.tarballUrlOrPath,
|
||||
required this.isRelativeLocalPath,
|
||||
required this.tarballSha256});
|
||||
const ReleaseAsset({
|
||||
required this.arch,
|
||||
required this.tarballUrlOrPath,
|
||||
required this.isRelativeLocalPath,
|
||||
required this.tarballSha256,
|
||||
});
|
||||
}
|
||||
|
||||
class Icon {
|
||||
@@ -72,9 +74,10 @@ class GithubReleases {
|
||||
|
||||
Future<void> _fetchReleasesAndAssets(bool canBeEmpty) async {
|
||||
final releaseJsonContent = (await http.get(Uri(
|
||||
scheme: 'https',
|
||||
host: 'api.github.com',
|
||||
path: '/repos/$githubReleaseOrganization/$githubReleaseProject/releases')))
|
||||
scheme: 'https',
|
||||
host: 'api.github.com',
|
||||
path: '/repos/$githubReleaseOrganization/$githubReleaseProject/releases',
|
||||
)))
|
||||
.body;
|
||||
final decodedJson = jsonDecode(releaseJsonContent) as List;
|
||||
|
||||
@@ -154,17 +157,19 @@ class GithubReleases {
|
||||
final res = List<ReleaseAsset>.empty(growable: true);
|
||||
if (x64TarballUrl != null && x64Sha != null) {
|
||||
res.add(ReleaseAsset(
|
||||
arch: CPUArchitecture.x86_64,
|
||||
tarballUrlOrPath: x64TarballUrl,
|
||||
isRelativeLocalPath: false,
|
||||
tarballSha256: x64Sha));
|
||||
arch: CPUArchitecture.x86_64,
|
||||
tarballUrlOrPath: x64TarballUrl,
|
||||
isRelativeLocalPath: false,
|
||||
tarballSha256: x64Sha,
|
||||
));
|
||||
}
|
||||
if (aarch64TarballUrl != null && aarch64Sha != null) {
|
||||
res.add(ReleaseAsset(
|
||||
arch: CPUArchitecture.aarch64,
|
||||
tarballUrlOrPath: aarch64TarballUrl,
|
||||
isRelativeLocalPath: false,
|
||||
tarballSha256: aarch64Sha));
|
||||
arch: CPUArchitecture.aarch64,
|
||||
tarballUrlOrPath: aarch64TarballUrl,
|
||||
isRelativeLocalPath: false,
|
||||
tarballSha256: aarch64Sha,
|
||||
));
|
||||
}
|
||||
return res.isEmpty ? null : res;
|
||||
}
|
||||
@@ -196,22 +201,22 @@ class FlatpakMeta {
|
||||
final String? githubReleaseProject;
|
||||
late final GithubReleases? _githubReleases;
|
||||
|
||||
FlatpakMeta(
|
||||
{required this.appId,
|
||||
required this.lowercaseAppName,
|
||||
required this.githubReleaseOrganization,
|
||||
required this.githubReleaseProject,
|
||||
required List<Release>? localReleases,
|
||||
required List<ReleaseAsset>? localReleaseAssets,
|
||||
required this.localLinuxBuildDir,
|
||||
required this.appStreamPath,
|
||||
required this.desktopPath,
|
||||
required this.icons,
|
||||
required this.freedesktopRuntime,
|
||||
required this.buildCommandsAfterUnpack,
|
||||
required this.extraModules,
|
||||
required this.finishArgs})
|
||||
: _localReleases = localReleases,
|
||||
FlatpakMeta({
|
||||
required this.appId,
|
||||
required this.lowercaseAppName,
|
||||
required this.githubReleaseOrganization,
|
||||
required this.githubReleaseProject,
|
||||
required List<Release>? localReleases,
|
||||
required List<ReleaseAsset>? localReleaseAssets,
|
||||
required this.localLinuxBuildDir,
|
||||
required this.appStreamPath,
|
||||
required this.desktopPath,
|
||||
required this.icons,
|
||||
required this.freedesktopRuntime,
|
||||
required this.buildCommandsAfterUnpack,
|
||||
required this.extraModules,
|
||||
required this.finishArgs,
|
||||
}) : _localReleases = localReleases,
|
||||
_localReleaseAssets = localReleaseAssets {
|
||||
if (githubReleaseOrganization != null && githubReleaseProject != null) {
|
||||
_githubReleases = GithubReleases(githubReleaseOrganization!, githubReleaseProject!);
|
||||
@@ -219,16 +224,21 @@ class FlatpakMeta {
|
||||
}
|
||||
|
||||
Future<List<Release>> getReleases(
|
||||
bool fetchReleasesFromGithub, String? addedTodaysVersion) async {
|
||||
bool fetchReleasesFromGithub,
|
||||
String? addedTodaysVersion,
|
||||
) async {
|
||||
final releases = List<Release>.empty(growable: true);
|
||||
if (addedTodaysVersion != null) {
|
||||
releases.add(Release(
|
||||
version: addedTodaysVersion, date: DateTime.now().toIso8601String().split('T').first));
|
||||
version: addedTodaysVersion,
|
||||
date: DateTime.now().toIso8601String().split('T').first,
|
||||
));
|
||||
}
|
||||
if (fetchReleasesFromGithub) {
|
||||
if (_githubReleases == null) {
|
||||
throw Exception(
|
||||
'Metadata must include Github repository info if fetching releases from Github.');
|
||||
'Metadata must include Github repository info if fetching releases from Github.',
|
||||
);
|
||||
}
|
||||
releases.addAll(await _githubReleases!.getReleases(addedTodaysVersion != null));
|
||||
} else {
|
||||
@@ -246,71 +256,73 @@ class FlatpakMeta {
|
||||
if (fetchReleasesFromGithub) {
|
||||
if (_githubReleases == null) {
|
||||
throw Exception(
|
||||
'Metadata must include Github repository info if fetching releases from Github.');
|
||||
'Metadata must include Github repository info if fetching releases from Github.',
|
||||
);
|
||||
}
|
||||
return _githubReleases!.getLatestReleaseAssets();
|
||||
} else {
|
||||
if (_localReleases == null) {
|
||||
throw Exception('Metadata must include releases if not fetching releases from Github.');
|
||||
}
|
||||
return _localReleaseAssets;
|
||||
}
|
||||
if (_localReleases == null) {
|
||||
throw Exception('Metadata must include releases if not fetching releases from Github.');
|
||||
}
|
||||
return _localReleaseAssets;
|
||||
}
|
||||
|
||||
static FlatpakMeta fromJson(File jsonFile, {bool skipLocalReleases = false}) {
|
||||
try {
|
||||
final dynamic json = jsonDecode(jsonFile.readAsStringSync());
|
||||
return FlatpakMeta(
|
||||
appId: json['appId'] as String,
|
||||
lowercaseAppName: json['lowercaseAppName'] as String,
|
||||
githubReleaseOrganization: json['githubReleaseOrganization'] as String?,
|
||||
githubReleaseProject: json['githubReleaseProject'] as String?,
|
||||
localReleases: skipLocalReleases
|
||||
? null
|
||||
: (json['localReleases'] as List?)?.map((dynamic r) {
|
||||
final rMap = r as Map;
|
||||
return Release(version: rMap['version'] as String, date: rMap['date'] as String);
|
||||
}).toList(),
|
||||
localReleaseAssets: skipLocalReleases
|
||||
? null
|
||||
: (json['localReleaseAssets'] as List?)?.map((dynamic ra) {
|
||||
final raMap = ra as Map;
|
||||
final archString = raMap['arch'] as String;
|
||||
final arch = (archString == CPUArchitecture.x86_64.flatpakArchCode)
|
||||
? CPUArchitecture.x86_64
|
||||
: (archString == CPUArchitecture.aarch64.flatpakArchCode)
|
||||
? CPUArchitecture.aarch64
|
||||
: null;
|
||||
if (arch == null) {
|
||||
throw Exception(
|
||||
'Architecture must be either "${CPUArchitecture.x86_64.flatpakArchCode}" or "${CPUArchitecture.aarch64.flatpakArchCode}"');
|
||||
}
|
||||
final tarballFile =
|
||||
File('${jsonFile.parent.path}/${raMap['tarballPath'] as String}');
|
||||
final tarballPath = tarballFile.absolute.path;
|
||||
final preShasum = Process.runSync('shasum', ['-a', '256', tarballPath]);
|
||||
final shasum = preShasum.stdout.toString().split(' ').first;
|
||||
if (preShasum.exitCode != 0) {
|
||||
throw Exception(preShasum.stderr);
|
||||
}
|
||||
return ReleaseAsset(
|
||||
arch: arch,
|
||||
tarballUrlOrPath: tarballPath,
|
||||
isRelativeLocalPath: true,
|
||||
tarballSha256: shasum);
|
||||
}).toList(),
|
||||
localLinuxBuildDir: json['localLinuxBuildDir'] as String,
|
||||
appStreamPath: json['appStreamPath'] as String,
|
||||
desktopPath: json['desktopPath'] as String,
|
||||
icons: (json['icons'] as Map).entries.map((mapEntry) {
|
||||
return Icon(type: mapEntry.key as String, path: mapEntry.value as String);
|
||||
}).toList(),
|
||||
freedesktopRuntime: json['freedesktopRuntime'] as String,
|
||||
buildCommandsAfterUnpack: (json['buildCommandsAfterUnpack'] as List?)
|
||||
?.map((dynamic bc) => bc as String)
|
||||
.toList(),
|
||||
extraModules: json['extraModules'] as List?,
|
||||
finishArgs: (json['finishArgs'] as List).map((dynamic fa) => fa as String).toList());
|
||||
appId: json['appId'] as String,
|
||||
lowercaseAppName: json['lowercaseAppName'] as String,
|
||||
githubReleaseOrganization: json['githubReleaseOrganization'] as String?,
|
||||
githubReleaseProject: json['githubReleaseProject'] as String?,
|
||||
localReleases: skipLocalReleases
|
||||
? null
|
||||
: (json['localReleases'] as List?)?.map((dynamic r) {
|
||||
final rMap = r as Map;
|
||||
return Release(version: rMap['version'] as String, date: rMap['date'] as String);
|
||||
}).toList(),
|
||||
localReleaseAssets: skipLocalReleases
|
||||
? null
|
||||
: (json['localReleaseAssets'] as List?)?.map((dynamic ra) {
|
||||
final raMap = ra as Map;
|
||||
final archString = raMap['arch'] as String;
|
||||
final arch = (archString == CPUArchitecture.x86_64.flatpakArchCode)
|
||||
? CPUArchitecture.x86_64
|
||||
: (archString == CPUArchitecture.aarch64.flatpakArchCode)
|
||||
? CPUArchitecture.aarch64
|
||||
: null;
|
||||
if (arch == null) {
|
||||
throw Exception(
|
||||
'Architecture must be either "${CPUArchitecture.x86_64.flatpakArchCode}" or "${CPUArchitecture.aarch64.flatpakArchCode}"',
|
||||
);
|
||||
}
|
||||
final tarballFile =
|
||||
File('${jsonFile.parent.path}/${raMap['tarballPath'] as String}');
|
||||
final tarballPath = tarballFile.absolute.path;
|
||||
final preShasum = Process.runSync('shasum', ['-a', '256', tarballPath]);
|
||||
final shasum = preShasum.stdout.toString().split(' ').first;
|
||||
if (preShasum.exitCode != 0) {
|
||||
throw Exception(preShasum.stderr);
|
||||
}
|
||||
return ReleaseAsset(
|
||||
arch: arch,
|
||||
tarballUrlOrPath: tarballPath,
|
||||
isRelativeLocalPath: true,
|
||||
tarballSha256: shasum,
|
||||
);
|
||||
}).toList(),
|
||||
localLinuxBuildDir: json['localLinuxBuildDir'] as String,
|
||||
appStreamPath: json['appStreamPath'] as String,
|
||||
desktopPath: json['desktopPath'] as String,
|
||||
icons: (json['icons'] as Map).entries.map((mapEntry) {
|
||||
return Icon(type: mapEntry.key as String, path: mapEntry.value as String);
|
||||
}).toList(),
|
||||
freedesktopRuntime: json['freedesktopRuntime'] as String,
|
||||
buildCommandsAfterUnpack:
|
||||
(json['buildCommandsAfterUnpack'] as List?)?.map((dynamic bc) => bc as String).toList(),
|
||||
extraModules: json['extraModules'] as List?,
|
||||
finishArgs: (json['finishArgs'] as List).map((dynamic fa) => fa as String).toList(),
|
||||
);
|
||||
} catch (e) {
|
||||
throw Exception('Could not parse JSON file, due to this error:\n$e');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user