// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:archive/archive.dart'; import '../application_package.dart'; import '../base/file_system.dart'; import '../base/utils.dart'; import '../build_info.dart'; import '../cmake.dart'; import '../cmake_project.dart'; import '../globals.dart' as globals; abstract class WindowsApp extends ApplicationPackage { WindowsApp({required String projectBundleId}) : super(id: projectBundleId); /// Creates a new [WindowsApp] from a windows sub project. factory WindowsApp.fromWindowsProject(WindowsProject project) { return BuildableWindowsApp( project: project, ); } /// Creates a new [WindowsApp] from an existing executable or a zip archive. /// /// `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; } return PrebuiltWindowsApp( executable: exeFilesFound.single.path, applicationPackage: applicationBinary, ); } @override String get displayName => id; String executable(BuildMode buildMode); } class PrebuiltWindowsApp extends WindowsApp implements PrebuiltApplicationPackage { PrebuiltWindowsApp({ required String executable, required this.applicationPackage, }) : _executable = executable, super(projectBundleId: executable); final String _executable; @override String executable(BuildMode buildMode) => _executable; @override String get name => _executable; @override final FileSystemEntity applicationPackage; } class BuildableWindowsApp extends WindowsApp { BuildableWindowsApp({ required this.project, }) : super(projectBundleId: project.parent.manifest.appName); final WindowsProject project; @override String executable(BuildMode buildMode) { final String? binaryName = getCmakeExecutableName(project); return globals.fs.path.join( getWindowsBuildDirectory(), 'runner', sentenceCase(getNameForBuildMode(buildMode)), '$binaryName.exe', ); } @override String get name => project.parent.manifest.appName; }