application_package.dart 3.53 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
import 'package:archive/archive.dart';

7 8
import '../application_package.dart';
import '../base/file_system.dart';
9
import '../base/utils.dart';
10
import '../build_info.dart';
11
import '../cmake.dart';
12
import '../cmake_project.dart';
13
import '../globals.dart' as globals;
14 15

abstract class WindowsApp extends ApplicationPackage {
16
  WindowsApp({required String projectBundleId}) : super(id: projectBundleId);
17 18 19 20 21 22 23 24

  /// Creates a new [WindowsApp] from a windows sub project.
  factory WindowsApp.fromWindowsProject(WindowsProject project) {
    return BuildableWindowsApp(
      project: project,
    );
  }

25
  /// Creates a new [WindowsApp] from an existing executable or a zip archive.
26
  ///
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  /// `applicationBinary` is the path to the executable or the zipped archive.
  static WindowsApp? fromPrebuiltApp(FileSystemEntity applicationBinary) {
    if (!applicationBinary.existsSync()) {
      globals.printError('File "${applicationBinary.path}" does not exist.');
      return null;
    }

    if (applicationBinary.path.endsWith('.exe')) {
      return PrebuiltWindowsApp(
        executable: applicationBinary.path,
        applicationPackage: applicationBinary,
      );
    }

    if (!applicationBinary.path.endsWith('.zip')) {
      // Unknown file type
      globals.printError('Unknown windows application type.');
      return null;
    }

    // Try to unpack as a zip.
    final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_app.');
    try {
      globals.os.unzip(globals.fs.file(applicationBinary), tempDir);
    } on ArchiveException {
      globals.printError('Invalid prebuilt Windows app. Unable to extract from archive.');
      return null;
    }
    final List<FileSystemEntity> exeFilesFound = <FileSystemEntity>[];
    for (final FileSystemEntity file in tempDir.listSync()) {
      if (file.basename.endsWith('.exe')) {
        exeFilesFound.add(file);
      }
    }

    if (exeFilesFound.isEmpty) {
      globals.printError('Cannot find .exe files in the zip archive.');
      return null;
    }

    if (exeFilesFound.length > 1) {
      globals.printError('Archive "${applicationBinary.path}" contains more than one .exe files.');
      return null;
    }

72
    return PrebuiltWindowsApp(
73 74
      executable: exeFilesFound.single.path,
      applicationPackage: applicationBinary,
75 76 77 78 79 80 81 82 83
    );
  }

  @override
  String get displayName => id;

  String executable(BuildMode buildMode);
}

84
class PrebuiltWindowsApp extends WindowsApp implements PrebuiltApplicationPackage {
85
  PrebuiltWindowsApp({
86
    required String executable,
87
    required this.applicationPackage,
88 89 90 91 92 93 94 95 96 97
  }) : _executable = executable,
       super(projectBundleId: executable);

  final String _executable;

  @override
  String executable(BuildMode buildMode) => _executable;

  @override
  String get name => _executable;
98 99 100

  @override
  final FileSystemEntity applicationPackage;
101 102 103 104
}

class BuildableWindowsApp extends WindowsApp {
  BuildableWindowsApp({
105
    required this.project,
106
  }) : super(projectBundleId: project.parent.manifest.appName);
107 108 109 110 111

  final WindowsProject project;

  @override
  String executable(BuildMode buildMode) {
112
    final String? binaryName = getCmakeExecutableName(project);
113
    return globals.fs.path.join(
114
        getWindowsBuildDirectory(),
115
        'runner',
116
        sentenceCase(getNameForBuildMode(buildMode)),
117 118
        '$binaryName.exe',
    );
119 120 121
  }

  @override
122
  String get name => project.parent.manifest.appName;
123
}