buildAppImage function

Future<void> buildAppImage({
  1. required String repoRoot,
  2. required ArtifactPayload payload,
  3. required AppImageConfig config,
  4. required String outputPath,
  5. required String arch,
  6. required String appImageToolPath,
})

Builds an AppImage from a prebuilt payload.

Implementation

Future<void> buildAppImage({
  required String repoRoot,
  required ArtifactPayload payload,
  required AppImageConfig config,
  required String outputPath,
  required String arch,
  required String appImageToolPath,
}) async {
  final appDir = p.join(repoRoot, '.shipworld', 'appimage', config.name);
  final artifactPath = p.join(repoRoot, outputPath);

  final appDirectory = Directory(appDir);

  if (appDirectory.existsSync()) {
    await appDirectory.delete(recursive: true);
  }

  await Directory(p.join(appDir, 'usr/bin')).create(recursive: true);
  await Directory(p.dirname(artifactPath)).create(recursive: true);
  await payload.stage(p.join(appDir, 'usr/bin'));
  await _makeExecutable(
    p.join(appDir, 'usr/bin', payload.launcherRelativePath),
  );

  await File(
    p.join(appDir, '${config.name}.desktop'),
  ).writeAsString(_desktopEntry(config, payload.launcherRelativePath));

  // The desktop entry's Icon= key is extension-agnostic, so the icon keeps its
  // source extension instead of being forced to one format.
  await File(
    config.iconPath,
  ).copy(p.join(appDir, '${config.name}${p.extension(config.iconPath)}'));

  await File(
    p.join(appDir, 'AppRun'),
  ).writeAsString(_appRun(payload.launcherRelativePath));
  await _makeExecutable(p.join(appDir, 'AppRun'));

  stdout.writeln('Building AppImage...');
  await runChecked(
    appImageToolPath,
    ['--appimage-extract-and-run', appDir, artifactPath],
    workingDirectory: repoRoot,
    environment: {'ARCH': arch},
  );
}