// 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:file/memory.dart'; import 'package:meta/meta.dart'; import 'package:process/process.dart'; import 'base/common.dart'; import 'base/file_system.dart'; import 'base/os.dart'; import 'base/platform.dart'; import 'base/user_messages.dart'; import 'base/utils.dart'; import 'build_info.dart'; import 'cache.dart'; import 'globals.dart' as globals; enum Artifact { /// The tool which compiles a dart kernel file into native code. genSnapshot, /// The flutter tester binary. flutterTester, flutterFramework, flutterXcframework, /// The framework directory of the macOS desktop. flutterMacOSFramework, vmSnapshotData, isolateSnapshotData, icuData, platformKernelDill, platformLibrariesJson, flutterPatchedSdkPath, /// The root directory of the dart SDK. engineDartSdkPath, /// The dart binary used to execute any of the required snapshots. engineDartBinary, /// The dart binary for running aot snapshots engineDartAotRuntime, /// The snapshot of frontend_server compiler. frontendServerSnapshotForEngineDartSdk, /// The dart snapshot of the dart2js compiler. dart2jsSnapshot, /// The dart snapshot of the dart2wasm compiler. dart2wasmSnapshot, /// The wasm-opt binary that ships with the dart-sdk wasmOptBinary, /// The root of the Linux desktop sources. linuxDesktopPath, // The root of the cpp headers for Linux desktop. linuxHeaders, /// The root of the Windows desktop sources. windowsDesktopPath, /// The root of the cpp client code for Windows desktop. windowsCppClientWrapper, /// The root of the sky_engine package. skyEnginePath, // Fuchsia artifacts from the engine prebuilts. fuchsiaKernelCompiler, fuchsiaFlutterRunner, /// Tools related to subsetting or icon font files. fontSubset, constFinder, /// The location of file generators. flutterToolsFileGenerators, /// Pre-built desktop debug app. flutterPreviewDevice, } /// A subset of [Artifact]s that are platform and build mode independent enum HostArtifact { /// The root of the web implementation of the dart SDK. flutterWebSdk, /// The libraries JSON file for web release builds. flutterWebLibrariesJson, // The flutter.js bootstrapping file provided by the engine. flutterJsDirectory, /// Folder that contains platform dill files for the web sdk. webPlatformKernelFolder, /// The summary dill for the dartdevc target. webPlatformDDCKernelDill, /// The summary dill with null safety enabled for the dartdevc target.g webPlatformDDCSoundKernelDill, /// The summary dill for the dartdevc target. webPlatformDart2JSKernelDill, /// The summary dill with null safety enabled for the dartdevc target. webPlatformDart2JSSoundKernelDill, /// The precompiled SDKs and sourcemaps for web debug builds. webPrecompiledSdk, webPrecompiledSdkSourcemaps, webPrecompiledCanvaskitSdk, webPrecompiledCanvaskitSdkSourcemaps, webPrecompiledCanvaskitAndHtmlSdk, webPrecompiledCanvaskitAndHtmlSdkSourcemaps, webPrecompiledSoundSdk, webPrecompiledSoundSdkSourcemaps, webPrecompiledCanvaskitSoundSdk, webPrecompiledCanvaskitSoundSdkSourcemaps, webPrecompiledCanvaskitAndHtmlSoundSdk, webPrecompiledCanvaskitAndHtmlSoundSdkSourcemaps, iosDeploy, idevicesyslog, idevicescreenshot, iproxy, /// The root of the sky_engine package. skyEnginePath, // The Impeller shader compiler. impellerc, // The Impeller Scene 3D model importer. scenec, // Impeller's tessellation library. libtessellator, } // TODO(knopp): Remove once darwin artifacts are universal and moved out of darwin-x64 String _enginePlatformDirectoryName(TargetPlatform platform) { if (platform == TargetPlatform.darwin) { return 'darwin-x64'; } return getNameForTargetPlatform(platform); } // Remove android target platform type. TargetPlatform? _mapTargetPlatform(TargetPlatform? targetPlatform) { switch (targetPlatform) { case TargetPlatform.android: return TargetPlatform.android_arm64; case TargetPlatform.ios: case TargetPlatform.darwin: case TargetPlatform.linux_x64: case TargetPlatform.linux_arm64: case TargetPlatform.windows_x64: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.tester: case TargetPlatform.web_javascript: case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: case null: return targetPlatform; } } String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMode? mode ]) { final String exe = hostPlatform.isWindows ? '.exe' : ''; switch (artifact) { case Artifact.genSnapshot: return 'gen_snapshot'; case Artifact.flutterTester: return 'flutter_tester$exe'; case Artifact.flutterFramework: return 'Flutter.framework'; case Artifact.flutterXcframework: return 'Flutter.xcframework'; case Artifact.flutterMacOSFramework: return 'FlutterMacOS.framework'; case Artifact.vmSnapshotData: return 'vm_isolate_snapshot.bin'; case Artifact.isolateSnapshotData: return 'isolate_snapshot.bin'; case Artifact.icuData: return 'icudtl.dat'; case Artifact.platformKernelDill: return 'platform_strong.dill'; case Artifact.platformLibrariesJson: return 'libraries.json'; case Artifact.flutterPatchedSdkPath: assert(false, 'No filename for sdk path, should not be invoked'); return null; case Artifact.engineDartSdkPath: return 'dart-sdk'; case Artifact.engineDartBinary: return 'dart$exe'; case Artifact.engineDartAotRuntime: return 'dartaotruntime$exe'; case Artifact.dart2jsSnapshot: return 'dart2js.dart.snapshot'; case Artifact.dart2wasmSnapshot: return 'dart2wasm_product.snapshot'; case Artifact.wasmOptBinary: return 'wasm-opt$exe'; case Artifact.frontendServerSnapshotForEngineDartSdk: return 'frontend_server_aot.dart.snapshot'; case Artifact.linuxDesktopPath: return ''; case Artifact.linuxHeaders: return 'flutter_linux'; case Artifact.windowsCppClientWrapper: return 'cpp_client_wrapper'; case Artifact.windowsDesktopPath: return ''; case Artifact.skyEnginePath: return 'sky_engine'; case Artifact.fuchsiaKernelCompiler: return 'kernel_compiler.snapshot'; case Artifact.fuchsiaFlutterRunner: final String jitOrAot = mode!.isJit ? '_jit' : '_aot'; final String productOrNo = mode.isRelease ? '_product' : ''; return 'flutter$jitOrAot${productOrNo}_runner-0.far'; case Artifact.fontSubset: return 'font-subset$exe'; case Artifact.constFinder: return 'const_finder.dart.snapshot'; case Artifact.flutterToolsFileGenerators: return ''; case Artifact.flutterPreviewDevice: return 'flutter_preview$exe'; } } String _hostArtifactToFileName(HostArtifact artifact, Platform platform) { final String exe = platform.isWindows ? '.exe' : ''; String dll = '.so'; if (platform.isWindows) { dll = '.dll'; } else if (platform.isMacOS) { dll = '.dylib'; } switch (artifact) { case HostArtifact.flutterWebSdk: return ''; case HostArtifact.flutterJsDirectory: return 'flutter_js'; case HostArtifact.iosDeploy: return 'ios-deploy'; case HostArtifact.idevicesyslog: return 'idevicesyslog'; case HostArtifact.idevicescreenshot: return 'idevicescreenshot'; case HostArtifact.iproxy: return 'iproxy'; case HostArtifact.skyEnginePath: return 'sky_engine'; case HostArtifact.webPlatformKernelFolder: return 'kernel'; case HostArtifact.webPlatformDDCKernelDill: return 'ddc_outline.dill'; case HostArtifact.webPlatformDDCSoundKernelDill: return 'ddc_outline_sound.dill'; case HostArtifact.webPlatformDart2JSKernelDill: return 'dart2js_platform_unsound.dill'; case HostArtifact.webPlatformDart2JSSoundKernelDill: return 'dart2js_platform.dill'; case HostArtifact.flutterWebLibrariesJson: return 'libraries.json'; case HostArtifact.webPrecompiledSdk: case HostArtifact.webPrecompiledCanvaskitSdk: case HostArtifact.webPrecompiledCanvaskitAndHtmlSdk: case HostArtifact.webPrecompiledSoundSdk: case HostArtifact.webPrecompiledCanvaskitSoundSdk: case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdk: return 'dart_sdk.js'; case HostArtifact.webPrecompiledSdkSourcemaps: case HostArtifact.webPrecompiledCanvaskitSdkSourcemaps: case HostArtifact.webPrecompiledCanvaskitAndHtmlSdkSourcemaps: case HostArtifact.webPrecompiledSoundSdkSourcemaps: case HostArtifact.webPrecompiledCanvaskitSoundSdkSourcemaps: case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdkSourcemaps: return 'dart_sdk.js.map'; case HostArtifact.impellerc: return 'impellerc$exe'; case HostArtifact.scenec: return 'scenec$exe'; case HostArtifact.libtessellator: return 'libtessellator$dll'; } } class EngineBuildPaths { const EngineBuildPaths({ required this.targetEngine, required this.hostEngine, required this.webSdk, }); final String? targetEngine; final String? hostEngine; final String? webSdk; } /// Information about a local engine build (i.e. `--local-engine[-host]=...`). /// /// See https://github.com/flutter/flutter/wiki/The-flutter-tool#using-a-locally-built-engine-with-the-flutter-tool /// for more information about local engine builds. class LocalEngineInfo { /// Creates a reference to a local engine build. /// /// The [targetOutPath] and [hostOutPath] are assumed to be resolvable /// paths to the built engine artifacts for the target (device) and host /// (build) platforms, respectively. const LocalEngineInfo({ required this.targetOutPath, required this.hostOutPath, }); /// The path to the engine artifacts for the target (device) platform. /// /// For example, if the target platform is Android debug, this would be a path /// like `/path/to/engine/src/out/android_debug_unopt`. To retrieve just the /// name (platform), see [localTargetName]. final String targetOutPath; /// The path to the engine artifacts for the host (build) platform. /// /// For example, if the host platform is debug, this would be a path like /// `/path/to/engine/src/out/host_debug_unopt`. To retrieve just the name /// (platform), see [localHostName]. final String hostOutPath; /// The name of the target (device) platform, i.e. `android_debug_unopt`. String get localTargetName => globals.fs.path.basename(targetOutPath); /// The name of the host (build) platform, e.g. `host_debug_unopt`. String get localHostName => globals.fs.path.basename(hostOutPath); } // Manages the engine artifacts of Flutter. abstract class Artifacts { /// A test-specific implementation of artifacts that returns stable paths for /// all artifacts. /// /// If a [fileSystem] is not provided, creates a new [MemoryFileSystem] instance. /// /// Creates a [LocalEngineArtifacts] if `localEngine` is non-null @visibleForTesting factory Artifacts.test({FileSystem? fileSystem}) { return _TestArtifacts(fileSystem ?? MemoryFileSystem.test()); } /// A test-specific implementation of artifacts that returns stable paths for /// all artifacts, and uses a local engine. /// /// If a [fileSystem] is not provided, creates a new [MemoryFileSystem] instance. @visibleForTesting factory Artifacts.testLocalEngine({ required String localEngine, required String localEngineHost, FileSystem? fileSystem, }) { return _TestLocalEngine( localEngine, localEngineHost, fileSystem ?? MemoryFileSystem.test()); } static Artifacts getLocalEngine(EngineBuildPaths engineBuildPaths) { Artifacts artifacts = CachedArtifacts( fileSystem: globals.fs, platform: globals.platform, cache: globals.cache, operatingSystemUtils: globals.os ); if (engineBuildPaths.hostEngine != null && engineBuildPaths.targetEngine != null) { artifacts = CachedLocalEngineArtifacts( engineBuildPaths.hostEngine!, engineOutPath: engineBuildPaths.targetEngine!, cache: globals.cache, fileSystem: globals.fs, processManager: globals.processManager, platform: globals.platform, operatingSystemUtils: globals.os, parent: artifacts, ); } if (engineBuildPaths.webSdk != null) { artifacts = CachedLocalWebSdkArtifacts( parent: artifacts, webSdkPath: engineBuildPaths.webSdk!, fileSystem: globals.fs, platform: globals.platform, operatingSystemUtils: globals.os ); } return artifacts; } /// Returns the requested [artifact] for the [platform], [mode], and [environmentType] combination. String getArtifactPath( Artifact artifact, { TargetPlatform? platform, BuildMode? mode, EnvironmentType? environmentType, }); /// Retrieve a host specific artifact that does not depend on the /// current build mode or environment. FileSystemEntity getHostArtifact( HostArtifact artifact, ); // Returns which set of engine artifacts is currently used for the [platform] // and [mode] combination. String getEngineType(TargetPlatform platform, [ BuildMode? mode ]); /// Whether these artifacts correspond to a non-versioned local engine. bool get isLocalEngine; /// If these artifacts are bound to a local engine build, returns info about /// the location and name of the local engine, otherwise returns null. LocalEngineInfo? get localEngineInfo; } /// Manages the engine artifacts downloaded to the local cache. class CachedArtifacts implements Artifacts { CachedArtifacts({ required FileSystem fileSystem, required Platform platform, required Cache cache, required OperatingSystemUtils operatingSystemUtils, }) : _fileSystem = fileSystem, _platform = platform, _cache = cache, _operatingSystemUtils = operatingSystemUtils; final FileSystem _fileSystem; final Platform _platform; final Cache _cache; final OperatingSystemUtils _operatingSystemUtils; @override LocalEngineInfo? get localEngineInfo => null; @override FileSystemEntity getHostArtifact( HostArtifact artifact, ) { switch (artifact) { case HostArtifact.flutterWebSdk: final String path = _getFlutterWebSdkPath(); return _fileSystem.directory(path); case HostArtifact.flutterWebLibrariesJson: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.flutterJsDirectory: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'flutter_js'); return _fileSystem.directory(path); case HostArtifact.webPlatformKernelFolder: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel'); return _fileSystem.file(path); case HostArtifact.webPlatformDDCKernelDill: case HostArtifact.webPlatformDDCSoundKernelDill: case HostArtifact.webPlatformDart2JSKernelDill: case HostArtifact.webPlatformDart2JSSoundKernelDill: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledSdk: case HostArtifact.webPrecompiledSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitSdk: case HostArtifact.webPrecompiledCanvaskitSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitAndHtmlSdk: case HostArtifact.webPrecompiledCanvaskitAndHtmlSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-html', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledSoundSdk: case HostArtifact.webPrecompiledSoundSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-sound', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitSoundSdk: case HostArtifact.webPrecompiledCanvaskitSoundSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-sound', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdk: case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-html-sound', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.idevicesyslog: case HostArtifact.idevicescreenshot: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); return _cache.getArtifactDirectory('libimobiledevice').childFile(artifactFileName); case HostArtifact.skyEnginePath: final Directory dartPackageDirectory = _cache.getCacheDir('pkg'); final String path = _fileSystem.path.join(dartPackageDirectory.path, _hostArtifactToFileName(artifact, _platform)); return _fileSystem.directory(path); case HostArtifact.iosDeploy: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); return _cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName); case HostArtifact.iproxy: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); return _cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName); case HostArtifact.impellerc: case HostArtifact.scenec: case HostArtifact.libtessellator: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); final String engineDir = _getEngineArtifactsPath(_currentHostPlatform(_platform, _operatingSystemUtils))!; return _fileSystem.file(_fileSystem.path.join(engineDir, artifactFileName)); } } @override String getArtifactPath( Artifact artifact, { TargetPlatform? platform, BuildMode? mode, EnvironmentType? environmentType, }) { platform = _mapTargetPlatform(platform); switch (platform) { case TargetPlatform.android: case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: assert(platform != TargetPlatform.android); return _getAndroidArtifactPath(artifact, platform!, mode!); case TargetPlatform.ios: return _getIosArtifactPath(artifact, platform!, mode, environmentType); case TargetPlatform.darwin: case TargetPlatform.linux_x64: case TargetPlatform.linux_arm64: case TargetPlatform.windows_x64: return _getDesktopArtifactPath(artifact, platform, mode); case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: return _getFuchsiaArtifactPath(artifact, platform!, mode!); case TargetPlatform.tester: case TargetPlatform.web_javascript: case null: return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform(_platform, _operatingSystemUtils), mode); } } @override String getEngineType(TargetPlatform platform, [ BuildMode? mode ]) { return _fileSystem.path.basename(_getEngineArtifactsPath(platform, mode)!); } String _getDesktopArtifactPath(Artifact artifact, TargetPlatform? platform, BuildMode? mode) { // When platform is null, a generic host platform artifact is being requested // and not the gen_snapshot for darwin as a target platform. if (platform != null && artifact == Artifact.genSnapshot) { final String engineDir = _getEngineArtifactsPath(platform, mode)!; return _fileSystem.path.join(engineDir, _artifactToFileName(artifact, _platform)); } return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform(_platform, _operatingSystemUtils), mode); } String _getAndroidArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) { final String engineDir = _getEngineArtifactsPath(platform, mode)!; switch (artifact) { case Artifact.genSnapshot: assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.'); final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform()); return _fileSystem.path.join(engineDir, hostPlatform, _artifactToFileName(artifact, _platform)); case Artifact.engineDartSdkPath: case Artifact.engineDartBinary: case Artifact.engineDartAotRuntime: case Artifact.dart2jsSnapshot: case Artifact.dart2wasmSnapshot: case Artifact.wasmOptBinary: case Artifact.frontendServerSnapshotForEngineDartSdk: case Artifact.constFinder: case Artifact.flutterFramework: case Artifact.flutterMacOSFramework: case Artifact.flutterPatchedSdkPath: case Artifact.flutterTester: case Artifact.flutterXcframework: case Artifact.fontSubset: case Artifact.fuchsiaFlutterRunner: case Artifact.fuchsiaKernelCompiler: case Artifact.icuData: case Artifact.isolateSnapshotData: case Artifact.linuxDesktopPath: case Artifact.linuxHeaders: case Artifact.platformKernelDill: case Artifact.platformLibrariesJson: case Artifact.skyEnginePath: case Artifact.vmSnapshotData: case Artifact.windowsCppClientWrapper: case Artifact.windowsDesktopPath: case Artifact.flutterToolsFileGenerators: case Artifact.flutterPreviewDevice: return _getHostArtifactPath(artifact, platform, mode); } } String _getIosArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode? mode, EnvironmentType? environmentType) { switch (artifact) { case Artifact.genSnapshot: case Artifact.flutterXcframework: final String artifactFileName = _artifactToFileName(artifact, _platform)!; final String engineDir = _getEngineArtifactsPath(platform, mode)!; return _fileSystem.path.join(engineDir, artifactFileName); case Artifact.flutterFramework: final String engineDir = _getEngineArtifactsPath(platform, mode)!; return _getIosEngineArtifactPath(engineDir, environmentType, _fileSystem, _platform); case Artifact.engineDartSdkPath: case Artifact.engineDartBinary: case Artifact.engineDartAotRuntime: case Artifact.dart2jsSnapshot: case Artifact.dart2wasmSnapshot: case Artifact.wasmOptBinary: case Artifact.frontendServerSnapshotForEngineDartSdk: case Artifact.constFinder: case Artifact.flutterMacOSFramework: case Artifact.flutterPatchedSdkPath: case Artifact.flutterTester: case Artifact.fontSubset: case Artifact.fuchsiaFlutterRunner: case Artifact.fuchsiaKernelCompiler: case Artifact.icuData: case Artifact.isolateSnapshotData: case Artifact.linuxDesktopPath: case Artifact.linuxHeaders: case Artifact.platformKernelDill: case Artifact.platformLibrariesJson: case Artifact.skyEnginePath: case Artifact.vmSnapshotData: case Artifact.windowsCppClientWrapper: case Artifact.windowsDesktopPath: case Artifact.flutterToolsFileGenerators: case Artifact.flutterPreviewDevice: return _getHostArtifactPath(artifact, platform, mode); } } String _getFuchsiaArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) { final String root = _fileSystem.path.join( _cache.getArtifactDirectory('flutter_runner').path, 'flutter', platform.fuchsiaArchForTargetPlatform, mode.isRelease ? 'release' : mode.toString(), ); final String runtime = mode.isJit ? 'jit' : 'aot'; switch (artifact) { case Artifact.genSnapshot: final String genSnapshot = mode.isRelease ? 'gen_snapshot_product' : 'gen_snapshot'; return _fileSystem.path.join(root, runtime, 'dart_binaries', genSnapshot); case Artifact.flutterPatchedSdkPath: const String artifactFileName = 'flutter_runner_patched_sdk'; return _fileSystem.path.join(root, runtime, artifactFileName); case Artifact.platformKernelDill: final String artifactFileName = _artifactToFileName(artifact, _platform, mode)!; return _fileSystem.path.join(root, runtime, 'flutter_runner_patched_sdk', artifactFileName); case Artifact.fuchsiaKernelCompiler: final String artifactFileName = _artifactToFileName(artifact, _platform, mode)!; return _fileSystem.path.join(root, runtime, 'dart_binaries', artifactFileName); case Artifact.fuchsiaFlutterRunner: final String artifactFileName = _artifactToFileName(artifact, _platform, mode)!; return _fileSystem.path.join(root, runtime, artifactFileName); case Artifact.constFinder: case Artifact.flutterFramework: case Artifact.flutterMacOSFramework: case Artifact.flutterTester: case Artifact.flutterXcframework: case Artifact.fontSubset: case Artifact.engineDartSdkPath: case Artifact.engineDartBinary: case Artifact.engineDartAotRuntime: case Artifact.dart2jsSnapshot: case Artifact.dart2wasmSnapshot: case Artifact.wasmOptBinary: case Artifact.frontendServerSnapshotForEngineDartSdk: case Artifact.icuData: case Artifact.isolateSnapshotData: case Artifact.linuxDesktopPath: case Artifact.linuxHeaders: case Artifact.platformLibrariesJson: case Artifact.skyEnginePath: case Artifact.vmSnapshotData: case Artifact.windowsCppClientWrapper: case Artifact.windowsDesktopPath: case Artifact.flutterToolsFileGenerators: case Artifact.flutterPreviewDevice: return _getHostArtifactPath(artifact, platform, mode); } } String _getFlutterPatchedSdkPath(BuildMode? mode) { final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path; return _fileSystem.path.join(engineArtifactsPath, 'common', mode == BuildMode.release ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk'); } String _getFlutterWebSdkPath() { return _cache.getWebSdkDirectory().path; } String _getHostArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode? mode) { switch (artifact) { case Artifact.genSnapshot: // For script snapshots any gen_snapshot binary will do. Returning gen_snapshot for // android_arm in profile mode because it is available on all supported host platforms. return _getAndroidArtifactPath(artifact, TargetPlatform.android_arm, BuildMode.profile); case Artifact.dart2jsSnapshot: case Artifact.dart2wasmSnapshot: case Artifact.frontendServerSnapshotForEngineDartSdk: return _fileSystem.path.join( _dartSdkPath(_cache), 'bin', 'snapshots', _artifactToFileName(artifact, _platform), ); case Artifact.wasmOptBinary: return _fileSystem.path.join( _dartSdkPath(_cache), 'bin', 'utils', _artifactToFileName(artifact, _platform), ); case Artifact.flutterTester: case Artifact.vmSnapshotData: case Artifact.isolateSnapshotData: case Artifact.icuData: final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path; final String platformDirName = _enginePlatformDirectoryName(platform); return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode)); case Artifact.platformKernelDill: return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), _artifactToFileName(artifact, _platform)); case Artifact.platformLibrariesJson: return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', _artifactToFileName(artifact, _platform)); case Artifact.flutterPatchedSdkPath: return _getFlutterPatchedSdkPath(mode); case Artifact.engineDartSdkPath: return _dartSdkPath(_cache); case Artifact.engineDartBinary: case Artifact.engineDartAotRuntime: return _fileSystem.path.join(_dartSdkPath(_cache), 'bin', _artifactToFileName(artifact, _platform)); case Artifact.flutterMacOSFramework: case Artifact.linuxDesktopPath: case Artifact.windowsDesktopPath: case Artifact.linuxHeaders: // TODO(zanderso): remove once debug desktop artifacts are uploaded // under a separate directory from the host artifacts. // https://github.com/flutter/flutter/issues/38935 String platformDirName = _enginePlatformDirectoryName(platform); if (mode == BuildMode.profile || mode == BuildMode.release) { platformDirName = '$platformDirName-${mode!.cliName}'; } final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path; return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode)); case Artifact.windowsCppClientWrapper: final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path; return _fileSystem.path.join(engineArtifactsPath, 'windows-x64', _artifactToFileName(artifact, _platform, mode)); case Artifact.skyEnginePath: final Directory dartPackageDirectory = _cache.getCacheDir('pkg'); return _fileSystem.path.join(dartPackageDirectory.path, _artifactToFileName(artifact, _platform)); case Artifact.fontSubset: case Artifact.constFinder: return _cache.getArtifactDirectory('engine') .childDirectory(_enginePlatformDirectoryName(platform)) .childFile(_artifactToFileName(artifact, _platform, mode)!) .path; case Artifact.flutterFramework: case Artifact.flutterXcframework: case Artifact.fuchsiaFlutterRunner: case Artifact.fuchsiaKernelCompiler: throw StateError('Artifact $artifact not available for platform $platform.'); case Artifact.flutterToolsFileGenerators: return _getFileGeneratorsPath(); case Artifact.flutterPreviewDevice: assert(platform == TargetPlatform.windows_x64); return _cache.getArtifactDirectory('flutter_preview').childFile('flutter_preview.exe').path; } } String? _getEngineArtifactsPath(TargetPlatform platform, [ BuildMode? mode ]) { final String engineDir = _cache.getArtifactDirectory('engine').path; final String platformName = _enginePlatformDirectoryName(platform); switch (platform) { case TargetPlatform.linux_x64: case TargetPlatform.linux_arm64: case TargetPlatform.darwin: case TargetPlatform.windows_x64: // TODO(zanderso): remove once debug desktop artifacts are uploaded // under a separate directory from the host artifacts. // https://github.com/flutter/flutter/issues/38935 if (mode == BuildMode.debug || mode == null) { return _fileSystem.path.join(engineDir, platformName); } final String suffix = mode != BuildMode.debug ? '-${snakeCase(mode.cliName, '-')}' : ''; return _fileSystem.path.join(engineDir, platformName + suffix); case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.tester: case TargetPlatform.web_javascript: assert(mode == null, 'Platform $platform does not support different build modes.'); return _fileSystem.path.join(engineDir, platformName); case TargetPlatform.ios: case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: assert(mode != null, 'Need to specify a build mode for platform $platform.'); final String suffix = mode != BuildMode.debug ? '-${snakeCase(mode!.cliName, '-')}' : ''; return _fileSystem.path.join(engineDir, platformName + suffix); case TargetPlatform.android: assert(false, 'cannot use TargetPlatform.android to look up artifacts'); return null; } } @override bool get isLocalEngine => false; } TargetPlatform _currentHostPlatform(Platform platform, OperatingSystemUtils operatingSystemUtils) { if (platform.isMacOS) { return TargetPlatform.darwin; } if (platform.isLinux) { return operatingSystemUtils.hostPlatform == HostPlatform.linux_x64 ? TargetPlatform.linux_x64 : TargetPlatform.linux_arm64; } if (platform.isWindows) { return TargetPlatform.windows_x64; } throw UnimplementedError('Host OS not supported.'); } String _getIosEngineArtifactPath(String engineDirectory, EnvironmentType? environmentType, FileSystem fileSystem, Platform hostPlatform) { final Directory xcframeworkDirectory = fileSystem .directory(engineDirectory) .childDirectory(_artifactToFileName(Artifact.flutterXcframework, hostPlatform)!); if (!xcframeworkDirectory.existsSync()) { throwToolExit('No xcframework found at ${xcframeworkDirectory.path}. Try running "flutter precache --ios".'); } Directory? flutterFrameworkSource; for (final Directory platformDirectory in xcframeworkDirectory.listSync().whereType<Directory>()) { if (!platformDirectory.basename.startsWith('ios-')) { continue; } // ios-x86_64-simulator, ios-arm64_x86_64-simulator, or ios-arm64. final bool simulatorDirectory = platformDirectory.basename.endsWith('-simulator'); if ((environmentType == EnvironmentType.simulator && simulatorDirectory) || (environmentType == EnvironmentType.physical && !simulatorDirectory)) { flutterFrameworkSource = platformDirectory; } } if (flutterFrameworkSource == null) { throwToolExit('No iOS frameworks found in ${xcframeworkDirectory.path}'); } return flutterFrameworkSource .childDirectory(_artifactToFileName(Artifact.flutterFramework, hostPlatform)!) .path; } /// Manages the artifacts of a locally built engine. class CachedLocalEngineArtifacts implements Artifacts { CachedLocalEngineArtifacts( this._hostEngineOutPath, { required String engineOutPath, required FileSystem fileSystem, required Cache cache, required ProcessManager processManager, required Platform platform, required OperatingSystemUtils operatingSystemUtils, Artifacts? parent, }) : _fileSystem = fileSystem, localEngineInfo = LocalEngineInfo( targetOutPath: engineOutPath, hostOutPath: _hostEngineOutPath, ), _cache = cache, _processManager = processManager, _platform = platform, _operatingSystemUtils = operatingSystemUtils, _backupCache = parent ?? CachedArtifacts( fileSystem: fileSystem, platform: platform, cache: cache, operatingSystemUtils: operatingSystemUtils ); @override final LocalEngineInfo localEngineInfo; final String _hostEngineOutPath; final FileSystem _fileSystem; final Cache _cache; final ProcessManager _processManager; final Platform _platform; final OperatingSystemUtils _operatingSystemUtils; final Artifacts _backupCache; @override FileSystemEntity getHostArtifact(HostArtifact artifact) { switch (artifact) { case HostArtifact.flutterWebSdk: final String path = _getFlutterWebSdkPath(); return _fileSystem.directory(path); case HostArtifact.flutterWebLibrariesJson: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.flutterJsDirectory: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'flutter_js'); return _fileSystem.directory(path); case HostArtifact.webPlatformKernelFolder: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel'); return _fileSystem.file(path); case HostArtifact.webPlatformDDCKernelDill: case HostArtifact.webPlatformDDCSoundKernelDill: case HostArtifact.webPlatformDart2JSKernelDill: case HostArtifact.webPlatformDart2JSSoundKernelDill: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledSdk: case HostArtifact.webPrecompiledSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitSdk: case HostArtifact.webPrecompiledCanvaskitSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitAndHtmlSdk: case HostArtifact.webPrecompiledCanvaskitAndHtmlSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-html', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledSoundSdk: case HostArtifact.webPrecompiledSoundSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-sound', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitSoundSdk: case HostArtifact.webPrecompiledCanvaskitSoundSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-sound', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdk: case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-html-sound', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.idevicesyslog: case HostArtifact.idevicescreenshot: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); return _cache.getArtifactDirectory('libimobiledevice').childFile(artifactFileName); case HostArtifact.skyEnginePath: final Directory dartPackageDirectory = _cache.getCacheDir('pkg'); final String path = _fileSystem.path.join(dartPackageDirectory.path, _hostArtifactToFileName(artifact, _platform)); return _fileSystem.directory(path); case HostArtifact.iosDeploy: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); return _cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName); case HostArtifact.iproxy: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); return _cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName); case HostArtifact.impellerc: case HostArtifact.scenec: case HostArtifact.libtessellator: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); final File file = _fileSystem.file(_fileSystem.path.join(_hostEngineOutPath, artifactFileName)); if (!file.existsSync()) { return _backupCache.getHostArtifact(artifact); } return file; } } @override String getArtifactPath( Artifact artifact, { TargetPlatform? platform, BuildMode? mode, EnvironmentType? environmentType, }) { platform ??= _currentHostPlatform(_platform, _operatingSystemUtils); platform = _mapTargetPlatform(platform); final bool isDirectoryArtifact = artifact == Artifact.flutterPatchedSdkPath; final String? artifactFileName = isDirectoryArtifact ? null : _artifactToFileName(artifact, _platform, mode); switch (artifact) { case Artifact.genSnapshot: return _genSnapshotPath(); case Artifact.flutterTester: return _flutterTesterPath(platform!); case Artifact.isolateSnapshotData: case Artifact.vmSnapshotData: return _fileSystem.path.join(localEngineInfo.targetOutPath, 'gen', 'flutter', 'lib', 'snapshot', artifactFileName); case Artifact.icuData: case Artifact.flutterXcframework: case Artifact.flutterMacOSFramework: return _fileSystem.path.join(localEngineInfo.targetOutPath, artifactFileName); case Artifact.platformKernelDill: if (platform == TargetPlatform.fuchsia_x64 || platform == TargetPlatform.fuchsia_arm64) { return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_runner_patched_sdk', artifactFileName); } return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), artifactFileName); case Artifact.platformLibrariesJson: return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', artifactFileName); case Artifact.flutterFramework: return _getIosEngineArtifactPath( localEngineInfo.targetOutPath, environmentType, _fileSystem, _platform); case Artifact.flutterPatchedSdkPath: // When using local engine always use [BuildMode.debug] regardless of // what was specified in [mode] argument because local engine will // have only one flutter_patched_sdk in standard location, that // is happen to be what debug(non-release) mode is using. if (platform == TargetPlatform.fuchsia_x64 || platform == TargetPlatform.fuchsia_arm64) { return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_runner_patched_sdk'); } return _getFlutterPatchedSdkPath(BuildMode.debug); case Artifact.skyEnginePath: return _fileSystem.path.join(_hostEngineOutPath, 'gen', 'dart-pkg', artifactFileName); case Artifact.fuchsiaKernelCompiler: final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform()); final String modeName = mode!.isRelease ? 'release' : mode.toString(); final String dartBinaries = 'dart_binaries-$modeName-$hostPlatform'; return _fileSystem.path.join(localEngineInfo.targetOutPath, 'host_bundle', dartBinaries, 'kernel_compiler.dart.snapshot'); case Artifact.fuchsiaFlutterRunner: final String jitOrAot = mode!.isJit ? '_jit' : '_aot'; final String productOrNo = mode.isRelease ? '_product' : ''; return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter$jitOrAot${productOrNo}_runner-0.far'); case Artifact.fontSubset: return _fileSystem.path.join(_hostEngineOutPath, artifactFileName); case Artifact.constFinder: return _fileSystem.path.join(_hostEngineOutPath, 'gen', artifactFileName); case Artifact.linuxDesktopPath: case Artifact.linuxHeaders: case Artifact.windowsDesktopPath: case Artifact.windowsCppClientWrapper: return _fileSystem.path.join(_hostEngineOutPath, artifactFileName); case Artifact.engineDartSdkPath: return _getDartSdkPath(); case Artifact.engineDartBinary: case Artifact.engineDartAotRuntime: return _fileSystem.path.join(_getDartSdkPath(), 'bin', artifactFileName); case Artifact.dart2jsSnapshot: case Artifact.dart2wasmSnapshot: case Artifact.frontendServerSnapshotForEngineDartSdk: return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName); case Artifact.wasmOptBinary: return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'utils', artifactFileName); case Artifact.flutterToolsFileGenerators: return _getFileGeneratorsPath(); case Artifact.flutterPreviewDevice: return _backupCache.getArtifactPath( artifact, platform: platform, mode: mode, environmentType: environmentType, ); } } @override String getEngineType(TargetPlatform platform, [ BuildMode? mode ]) { return _fileSystem.path.basename(localEngineInfo.targetOutPath); } String _getFlutterPatchedSdkPath(BuildMode? buildMode) { return _fileSystem.path.join(localEngineInfo.targetOutPath, buildMode == BuildMode.release ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk'); } String _getDartSdkPath() { final String builtPath = _fileSystem.path.join(_hostEngineOutPath, 'dart-sdk'); if (_fileSystem.isDirectorySync(_fileSystem.path.join(builtPath, 'bin'))) { return builtPath; } // If we couldn't find a built dart sdk, let's look for a prebuilt one. final String prebuiltPath = _fileSystem.path.join(_getFlutterPrebuiltsPath(), _getPrebuiltTarget(), 'dart-sdk'); if (_fileSystem.isDirectorySync(prebuiltPath)) { return prebuiltPath; } throw ToolExit('Unable to find a built dart sdk at: "$builtPath" or a prebuilt dart sdk at: "$prebuiltPath"'); } String _getFlutterPrebuiltsPath() { final String engineSrcPath = _fileSystem.path.dirname(_fileSystem.path.dirname(_hostEngineOutPath)); return _fileSystem.path.join(engineSrcPath, 'flutter', 'prebuilts'); } String _getPrebuiltTarget() { final TargetPlatform hostPlatform = _currentHostPlatform(_platform, _operatingSystemUtils); switch (hostPlatform) { case TargetPlatform.darwin: return 'macos-x64'; case TargetPlatform.linux_arm64: return 'linux-arm64'; case TargetPlatform.linux_x64: return 'linux-x64'; case TargetPlatform.windows_x64: return 'windows-x64'; case TargetPlatform.ios: case TargetPlatform.android: case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.web_javascript: case TargetPlatform.tester: throwToolExit('Unsupported host platform: $hostPlatform'); } } String _getFlutterWebSdkPath() { return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_web_sdk'); } String _genSnapshotPath() { const List<String> clangDirs = <String>['.', 'clang_x64', 'clang_x86', 'clang_i386', 'clang_arm64']; final String genSnapshotName = _artifactToFileName(Artifact.genSnapshot, _platform)!; for (final String clangDir in clangDirs) { final String genSnapshotPath = _fileSystem.path.join(localEngineInfo.targetOutPath, clangDir, genSnapshotName); if (_processManager.canRun(genSnapshotPath)) { return genSnapshotPath; } } throw Exception('Unable to find $genSnapshotName'); } String _flutterTesterPath(TargetPlatform platform) { if (_platform.isLinux) { return _fileSystem.path.join(localEngineInfo.targetOutPath, _artifactToFileName(Artifact.flutterTester, _platform)); } else if (_platform.isMacOS) { return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_tester'); } else if (_platform.isWindows) { return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_tester.exe'); } throw Exception('Unsupported platform $platform.'); } @override bool get isLocalEngine => true; } class CachedLocalWebSdkArtifacts implements Artifacts { CachedLocalWebSdkArtifacts({ required Artifacts parent, required String webSdkPath, required FileSystem fileSystem, required Platform platform, required OperatingSystemUtils operatingSystemUtils }) : _parent = parent, _webSdkPath = webSdkPath, _fileSystem = fileSystem, _platform = platform, _operatingSystemUtils = operatingSystemUtils; final Artifacts _parent; final String _webSdkPath; final FileSystem _fileSystem; final Platform _platform; final OperatingSystemUtils _operatingSystemUtils; @override String getArtifactPath(Artifact artifact, {TargetPlatform? platform, BuildMode? mode, EnvironmentType? environmentType}) { if (platform == TargetPlatform.web_javascript) { switch (artifact) { case Artifact.engineDartSdkPath: return _getDartSdkPath(); case Artifact.engineDartBinary: case Artifact.engineDartAotRuntime: return _fileSystem.path.join( _getDartSdkPath(), 'bin', _artifactToFileName(artifact, _platform, mode)); case Artifact.dart2jsSnapshot: case Artifact.dart2wasmSnapshot: case Artifact.frontendServerSnapshotForEngineDartSdk: return _fileSystem.path.join( _getDartSdkPath(), 'bin', 'snapshots', _artifactToFileName(artifact, _platform, mode), ); case Artifact.wasmOptBinary: return _fileSystem.path.join( _getDartSdkPath(), 'bin', 'utils', _artifactToFileName(artifact, _platform, mode), ); case Artifact.genSnapshot: case Artifact.flutterTester: case Artifact.flutterFramework: case Artifact.flutterXcframework: case Artifact.flutterMacOSFramework: case Artifact.vmSnapshotData: case Artifact.isolateSnapshotData: case Artifact.icuData: case Artifact.platformKernelDill: case Artifact.platformLibrariesJson: case Artifact.flutterPatchedSdkPath: case Artifact.linuxDesktopPath: case Artifact.linuxHeaders: case Artifact.windowsDesktopPath: case Artifact.windowsCppClientWrapper: case Artifact.skyEnginePath: case Artifact.fuchsiaKernelCompiler: case Artifact.fuchsiaFlutterRunner: case Artifact.fontSubset: case Artifact.constFinder: case Artifact.flutterToolsFileGenerators: case Artifact.flutterPreviewDevice: break; } } return _parent.getArtifactPath(artifact, platform: platform, mode: mode, environmentType: environmentType); } @override String getEngineType(TargetPlatform platform, [BuildMode? mode]) => _parent.getEngineType(platform, mode); @override FileSystemEntity getHostArtifact(HostArtifact artifact) { switch (artifact) { case HostArtifact.flutterWebSdk: final String path = _getFlutterWebSdkPath(); return _fileSystem.directory(path); case HostArtifact.flutterWebLibrariesJson: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.flutterJsDirectory: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'flutter_js'); return _fileSystem.directory(path); case HostArtifact.webPlatformKernelFolder: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel'); return _fileSystem.file(path); case HostArtifact.webPlatformDDCKernelDill: case HostArtifact.webPlatformDDCSoundKernelDill: case HostArtifact.webPlatformDart2JSKernelDill: case HostArtifact.webPlatformDart2JSSoundKernelDill: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledSdk: case HostArtifact.webPrecompiledSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitSdk: case HostArtifact.webPrecompiledCanvaskitSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitAndHtmlSdk: case HostArtifact.webPrecompiledCanvaskitAndHtmlSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-html', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledSoundSdk: case HostArtifact.webPrecompiledSoundSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-sound', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitSoundSdk: case HostArtifact.webPrecompiledCanvaskitSoundSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-sound', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdk: case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdkSourcemaps: final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-html-sound', _hostArtifactToFileName(artifact, _platform)); return _fileSystem.file(path); case HostArtifact.iosDeploy: case HostArtifact.idevicesyslog: case HostArtifact.idevicescreenshot: case HostArtifact.iproxy: case HostArtifact.skyEnginePath: case HostArtifact.impellerc: case HostArtifact.scenec: case HostArtifact.libtessellator: return _parent.getHostArtifact(artifact); } } String _getDartSdkPath() { // If we couldn't find a built dart sdk, let's look for a prebuilt one. final String prebuiltPath = _fileSystem.path.join(_getFlutterPrebuiltsPath(), _getPrebuiltTarget(), 'dart-sdk'); if (_fileSystem.isDirectorySync(prebuiltPath)) { return prebuiltPath; } throw ToolExit('Unable to find a prebuilt dart sdk at: "$prebuiltPath"'); } String _getFlutterPrebuiltsPath() { final String engineSrcPath = _fileSystem.path.dirname(_fileSystem.path.dirname(_webSdkPath)); return _fileSystem.path.join(engineSrcPath, 'flutter', 'prebuilts'); } String _getPrebuiltTarget() { final TargetPlatform hostPlatform = _currentHostPlatform(_platform, _operatingSystemUtils); switch (hostPlatform) { case TargetPlatform.darwin: return 'macos-x64'; case TargetPlatform.linux_arm64: return 'linux-arm64'; case TargetPlatform.linux_x64: return 'linux-x64'; case TargetPlatform.windows_x64: return 'windows-x64'; case TargetPlatform.ios: case TargetPlatform.android: case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.web_javascript: case TargetPlatform.tester: throwToolExit('Unsupported host platform: $hostPlatform'); } } String _getFlutterWebSdkPath() { return _fileSystem.path.join(_webSdkPath, 'flutter_web_sdk'); } @override bool get isLocalEngine => _parent.isLocalEngine; @override LocalEngineInfo? get localEngineInfo => _parent.localEngineInfo; } /// An implementation of [Artifacts] that provides individual overrides. /// /// If an artifact is not provided, the lookup delegates to the parent. class OverrideArtifacts implements Artifacts { /// Creates a new [OverrideArtifacts]. /// /// [parent] must be provided. OverrideArtifacts({ required this.parent, this.frontendServer, this.engineDartBinary, this.platformKernelDill, this.flutterPatchedSdk, }); final Artifacts parent; final File? frontendServer; final File? engineDartBinary; final File? platformKernelDill; final File? flutterPatchedSdk; @override LocalEngineInfo? get localEngineInfo => parent.localEngineInfo; @override String getArtifactPath( Artifact artifact, { TargetPlatform? platform, BuildMode? mode, EnvironmentType? environmentType, }) { if (artifact == Artifact.engineDartBinary && engineDartBinary != null) { return engineDartBinary!.path; } if (artifact == Artifact.frontendServerSnapshotForEngineDartSdk && frontendServer != null) { return frontendServer!.path; } if (artifact == Artifact.platformKernelDill && platformKernelDill != null) { return platformKernelDill!.path; } if (artifact == Artifact.flutterPatchedSdkPath && flutterPatchedSdk != null) { return flutterPatchedSdk!.path; } return parent.getArtifactPath( artifact, platform: platform, mode: mode, environmentType: environmentType, ); } @override String getEngineType(TargetPlatform platform, [ BuildMode? mode ]) => parent.getEngineType(platform, mode); @override bool get isLocalEngine => parent.isLocalEngine; @override FileSystemEntity getHostArtifact(HostArtifact artifact) { return parent.getHostArtifact( artifact, ); } } /// Locate the Dart SDK. String _dartSdkPath(Cache cache) { return cache.getRoot().childDirectory('dart-sdk').path; } class _TestArtifacts implements Artifacts { _TestArtifacts(this.fileSystem); final FileSystem fileSystem; @override LocalEngineInfo? get localEngineInfo => null; @override String getArtifactPath( Artifact artifact, { TargetPlatform? platform, BuildMode? mode, EnvironmentType? environmentType, }) { // The path to file generators is the same even in the test environment. if (artifact == Artifact.flutterToolsFileGenerators) { return _getFileGeneratorsPath(); } final StringBuffer buffer = StringBuffer(); buffer.write(artifact); if (platform != null) { buffer.write('.$platform'); } if (mode != null) { buffer.write('.$mode'); } if (environmentType != null) { buffer.write('.$environmentType'); } return buffer.toString(); } @override String getEngineType(TargetPlatform platform, [ BuildMode? mode ]) { return 'test-engine'; } @override bool get isLocalEngine => false; @override FileSystemEntity getHostArtifact(HostArtifact artifact) { return fileSystem.file(artifact.toString()); } } class _TestLocalEngine extends _TestArtifacts { _TestLocalEngine( String engineOutPath, String engineHostOutPath, super.fileSystem, ) : localEngineInfo = LocalEngineInfo( targetOutPath: engineOutPath, hostOutPath: engineHostOutPath, ); @override bool get isLocalEngine => true; @override final LocalEngineInfo localEngineInfo; } String _getFileGeneratorsPath() { final String flutterRoot = Cache.defaultFlutterRoot( fileSystem: globals.localFileSystem, platform: const LocalPlatform(), userMessages: UserMessages(), ); return globals.localFileSystem.path.join( flutterRoot, 'packages', 'flutter_tools', 'lib', 'src', 'web', 'file_generators', ); }