1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:file/memory.dart';
6import 'package:meta/meta.dart';
7import 'package:process/process.dart';
8
9import 'base/common.dart';
10import 'base/file_system.dart';
11import 'base/os.dart';
12import 'base/platform.dart';
13import 'base/user_messages.dart';
14import 'base/utils.dart';
15import 'build_info.dart';
16import 'cache.dart';
17import 'globals.dart' as globals;
18
19//////////////////////////////////////////////////////////////////////
20// //
21// ✨ THINKING OF MOVING/REFACTORING THIS FILE? READ ME FIRST! ✨ //
22// //
23// There is a link to this file in //docs/tool/Engine-artfiacts.md //
24// and it would be very kind of you to update the link, if needed. //
25// //
26//////////////////////////////////////////////////////////////////////
27
28/// Defines what engine artifacts are available (not necessarily on each platform).
29enum Artifact {
30 /// The tool which compiles a dart kernel file into native code.
31 genSnapshot,
32 genSnapshotArm64,
33 genSnapshotX64,
34
35 /// The flutter tester binary.
36 flutterTester,
37 flutterFramework,
38 flutterFrameworkDsym,
39 flutterXcframework,
40
41 /// The framework directory of the macOS desktop.
42 flutterMacOSFramework,
43 flutterMacOSFrameworkDsym,
44 flutterMacOSXcframework,
45 vmSnapshotData,
46 isolateSnapshotData,
47 icuData,
48 platformKernelDill,
49 platformLibrariesJson,
50 flutterPatchedSdkPath,
51
52 /// The root directory of the dart SDK.
53 engineDartSdkPath,
54
55 /// The dart binary used to execute any of the required snapshots.
56 engineDartBinary,
57
58 /// The dart binary for running aot snapshots
59 engineDartAotRuntime,
60
61 /// The snapshot of frontend_server compiler.
62 frontendServerSnapshotForEngineDartSdk,
63
64 /// The root of the Linux desktop sources.
65 linuxDesktopPath,
66 // The root of the cpp headers for Linux desktop.
67 linuxHeaders,
68
69 /// The root of the Windows desktop sources.
70 windowsDesktopPath,
71
72 /// The root of the cpp client code for Windows desktop.
73 windowsCppClientWrapper,
74
75 /// The root of the sky_engine package.
76 skyEnginePath,
77
78 // Fuchsia artifacts from the engine prebuilts.
79 fuchsiaKernelCompiler,
80 fuchsiaFlutterRunner,
81
82 /// Tools related to subsetting or icon font files.
83 fontSubset,
84 constFinder,
85
86 /// The location of file generators.
87 flutterToolsFileGenerators,
88}
89
90/// A subset of [Artifact]s that are platform and build mode independent
91enum HostArtifact {
92 /// The root of the web implementation of the dart SDK.
93 flutterWebSdk,
94
95 /// The libraries JSON file for web release builds.
96 flutterWebLibrariesJson,
97
98 // The flutter.js bootstrapping file provided by the engine.
99 flutterJsDirectory,
100
101 /// Folder that contains platform dill files for the web sdk.
102 webPlatformKernelFolder,
103
104 // **NOTE**: All of the precompiled SDKs, summaries, and source maps are
105 // strictly with sound null-safety, there is no longer support for unsound
106 // null-safety within the Flutter tool or SDK.
107 //
108 // See https://github.com/flutter/flutter/issues/162846.
109
110 /// The summary dill for the dartdevc target.
111 webPlatformDDCKernelDill,
112
113 /// The summary dill for the dart2js target.
114 webPlatformDart2JSKernelDill,
115
116 /// The precompiled SDKs and sourcemaps for web debug builds with the AMD module system.
117 // TODO(markzipan): delete these when DDC's AMD module system is deprecated, https://github.com/flutter/flutter/issues/142060.
118 webPrecompiledAmdCanvaskitSdk,
119 webPrecompiledAmdCanvaskitSdkSourcemaps,
120
121 /// The precompiled SDKs and sourcemaps for web debug builds with the DDC
122 /// library bundle module system. Only SDKs built with sound null-safety are
123 /// provided here.
124 webPrecompiledDdcLibraryBundleCanvaskitSdk,
125 webPrecompiledDdcLibraryBundleCanvaskitSdkSourcemaps,
126
127 iosDeploy,
128 idevicesyslog,
129 idevicescreenshot,
130 iproxy,
131
132 /// The root of the sky_engine package.
133 skyEnginePath,
134
135 // The Impeller shader compiler.
136 impellerc,
137 // Impeller's tessellation library.
138 libtessellator,
139}
140
141// TODO(knopp): Remove once darwin artifacts are universal and moved out of darwin-x64
142String _enginePlatformDirectoryName(TargetPlatform platform) {
143 if (platform == TargetPlatform.darwin) {
144 return 'darwin-x64';
145 }
146 return getNameForTargetPlatform(platform);
147}
148
149// Remove android target platform type.
150TargetPlatform? _mapTargetPlatform(TargetPlatform? targetPlatform) {
151 switch (targetPlatform) {
152 case TargetPlatform.android:
153 return TargetPlatform.android_arm64;
154 case TargetPlatform.ios:
155 case TargetPlatform.darwin:
156 case TargetPlatform.linux_x64:
157 case TargetPlatform.linux_arm64:
158 case TargetPlatform.windows_x64:
159 case TargetPlatform.windows_arm64:
160 case TargetPlatform.fuchsia_arm64:
161 case TargetPlatform.fuchsia_x64:
162 case TargetPlatform.tester:
163 case TargetPlatform.web_javascript:
164 case TargetPlatform.android_arm:
165 case TargetPlatform.android_arm64:
166 case TargetPlatform.android_x64:
167 case TargetPlatform.unsupported:
168 case null:
169 return targetPlatform;
170 }
171}
172
173String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [BuildMode? mode]) {
174 final exe = hostPlatform.isWindows ? '.exe' : '';
175 switch (artifact) {
176 case Artifact.genSnapshot:
177 return 'gen_snapshot';
178 case Artifact.genSnapshotArm64:
179 return 'gen_snapshot_arm64';
180 case Artifact.genSnapshotX64:
181 return 'gen_snapshot_x64';
182 case Artifact.flutterTester:
183 return 'flutter_tester$exe';
184 case Artifact.flutterFramework:
185 return 'Flutter.framework';
186 case Artifact.flutterFrameworkDsym:
187 return 'Flutter.framework.dSYM';
188 case Artifact.flutterXcframework:
189 return 'Flutter.xcframework';
190 case Artifact.flutterMacOSFramework:
191 return 'FlutterMacOS.framework';
192 case Artifact.flutterMacOSFrameworkDsym:
193 return 'FlutterMacOS.framework.dSYM';
194 case Artifact.flutterMacOSXcframework:
195 return 'FlutterMacOS.xcframework';
196 case Artifact.vmSnapshotData:
197 return 'vm_isolate_snapshot.bin';
198 case Artifact.isolateSnapshotData:
199 return 'isolate_snapshot.bin';
200 case Artifact.icuData:
201 return 'icudtl.dat';
202 case Artifact.platformKernelDill:
203 return 'platform_strong.dill';
204 case Artifact.platformLibrariesJson:
205 return 'libraries.json';
206 case Artifact.flutterPatchedSdkPath:
207 assert(false, 'No filename for sdk path, should not be invoked');
208 return null;
209 case Artifact.engineDartSdkPath:
210 return 'dart-sdk';
211 case Artifact.engineDartBinary:
212 return 'dart$exe';
213 case Artifact.engineDartAotRuntime:
214 return 'dartaotruntime$exe';
215 case Artifact.frontendServerSnapshotForEngineDartSdk:
216 return 'frontend_server_aot.dart.snapshot';
217 case Artifact.linuxDesktopPath:
218 return '';
219 case Artifact.linuxHeaders:
220 return 'flutter_linux';
221 case Artifact.windowsCppClientWrapper:
222 return 'cpp_client_wrapper';
223 case Artifact.windowsDesktopPath:
224 return '';
225 case Artifact.skyEnginePath:
226 return 'sky_engine';
227 case Artifact.fuchsiaKernelCompiler:
228 return 'kernel_compiler.snapshot';
229 case Artifact.fuchsiaFlutterRunner:
230 final jitOrAot = mode!.isJit ? '_jit' : '_aot';
231 final productOrNo = mode.isRelease ? '_product' : '';
232 return 'flutter$jitOrAot${productOrNo}_runner-0.far';
233 case Artifact.fontSubset:
234 return 'font-subset$exe';
235 case Artifact.constFinder:
236 return 'const_finder.dart.snapshot';
237 case Artifact.flutterToolsFileGenerators:
238 return '';
239 }
240}
241
242String _hostArtifactToFileName(HostArtifact artifact, Platform platform) {
243 final exe = platform.isWindows ? '.exe' : '';
244 var dll = '.so';
245 if (platform.isWindows) {
246 dll = '.dll';
247 } else if (platform.isMacOS) {
248 dll = '.dylib';
249 }
250 switch (artifact) {
251 case HostArtifact.flutterWebSdk:
252 return '';
253 case HostArtifact.flutterJsDirectory:
254 return 'flutter_js';
255 case HostArtifact.iosDeploy:
256 return 'ios-deploy';
257 case HostArtifact.idevicesyslog:
258 return 'idevicesyslog';
259 case HostArtifact.idevicescreenshot:
260 return 'idevicescreenshot';
261 case HostArtifact.iproxy:
262 return 'iproxy';
263 case HostArtifact.skyEnginePath:
264 return 'sky_engine';
265 case HostArtifact.webPlatformKernelFolder:
266 return 'kernel';
267 case HostArtifact.webPlatformDDCKernelDill:
268 return 'ddc_outline.dill';
269 case HostArtifact.webPlatformDart2JSKernelDill:
270 return 'dart2js_platform.dill';
271 case HostArtifact.flutterWebLibrariesJson:
272 return 'libraries.json';
273 case HostArtifact.webPrecompiledAmdCanvaskitSdk:
274 case HostArtifact.webPrecompiledDdcLibraryBundleCanvaskitSdk:
275 return 'dart_sdk.js';
276 case HostArtifact.webPrecompiledAmdCanvaskitSdkSourcemaps:
277 case HostArtifact.webPrecompiledDdcLibraryBundleCanvaskitSdkSourcemaps:
278 return 'dart_sdk.js.map';
279 case HostArtifact.impellerc:
280 return 'impellerc$exe';
281 case HostArtifact.libtessellator:
282 return 'libtessellator$dll';
283 }
284}
285
286class EngineBuildPaths {
287 const EngineBuildPaths({
288 required this.targetEngine,
289 required this.hostEngine,
290 required this.webSdk,
291 });
292
293 final String? targetEngine;
294 final String? hostEngine;
295 final String? webSdk;
296}
297
298/// Information about a local engine build (i.e. `--local-engine[-host]=...`).
299///
300/// See https://github.com/flutter/flutter/blob/main/docs/tool/README.md#using-a-locally-built-engine-with-the-flutter-tool
301/// for more information about local engine builds.
302class LocalEngineInfo {
303 /// Creates a reference to a local engine build.
304 ///
305 /// The [targetOutPath] and [hostOutPath] are assumed to be resolvable
306 /// paths to the built engine artifacts for the target (device) and host
307 /// (build) platforms, respectively.
308 const LocalEngineInfo({required this.targetOutPath, required this.hostOutPath});
309
310 /// The path to the engine artifacts for the target (device) platform.
311 ///
312 /// For example, if the target platform is Android debug, this would be a path
313 /// like `/path/to/engine/src/out/android_debug_unopt`. To retrieve just the
314 /// name (platform), see [localTargetName].
315 final String targetOutPath;
316
317 /// The path to the engine artifacts for the host (build) platform.
318 ///
319 /// For example, if the host platform is debug, this would be a path like
320 /// `/path/to/engine/src/out/host_debug_unopt`. To retrieve just the name
321 /// (platform), see [localHostName].
322 final String hostOutPath;
323
324 /// The name of the target (device) platform, i.e. `android_debug_unopt`.
325 String get localTargetName => globals.fs.path.basename(targetOutPath);
326
327 /// The name of the host (build) platform, e.g. `host_debug_unopt`.
328 String get localHostName => globals.fs.path.basename(hostOutPath);
329}
330
331// Manages the engine artifacts of Flutter.
332abstract class Artifacts {
333 /// A test-specific implementation of artifacts that returns stable paths for
334 /// all artifacts.
335 ///
336 /// If a [fileSystem] is not provided, creates a new [MemoryFileSystem] instance.
337 @visibleForTesting
338 factory Artifacts.test({FileSystem? fileSystem}) {
339 return _TestArtifacts(fileSystem ?? MemoryFileSystem.test());
340 }
341
342 /// A test-specific implementation of artifacts that returns stable paths for
343 /// all artifacts, and uses a local engine.
344 ///
345 /// If a [fileSystem] is not provided, creates a new [MemoryFileSystem] instance.
346 @visibleForTesting
347 factory Artifacts.testLocalEngine({
348 required String localEngine,
349 required String localEngineHost,
350 FileSystem? fileSystem,
351 }) {
352 return _TestLocalEngine(localEngine, localEngineHost, fileSystem ?? MemoryFileSystem.test());
353 }
354
355 static Artifacts getLocalEngine(EngineBuildPaths engineBuildPaths) {
356 Artifacts artifacts = CachedArtifacts(
357 fileSystem: globals.fs,
358 platform: globals.platform,
359 cache: globals.cache,
360 operatingSystemUtils: globals.os,
361 );
362 if (engineBuildPaths.hostEngine != null && engineBuildPaths.targetEngine != null) {
363 artifacts = CachedLocalEngineArtifacts(
364 engineBuildPaths.hostEngine!,
365 engineOutPath: engineBuildPaths.targetEngine!,
366 cache: globals.cache,
367 fileSystem: globals.fs,
368 processManager: globals.processManager,
369 platform: globals.platform,
370 operatingSystemUtils: globals.os,
371 parent: artifacts,
372 );
373 }
374 if (engineBuildPaths.webSdk != null) {
375 artifacts = CachedLocalWebSdkArtifacts(
376 parent: artifacts,
377 webSdkPath: engineBuildPaths.webSdk!,
378 fileSystem: globals.fs,
379 platform: globals.platform,
380 operatingSystemUtils: globals.os,
381 );
382 }
383 return artifacts;
384 }
385
386 /// Returns the requested [artifact] for the [platform], [mode], and [environmentType] combination.
387 String getArtifactPath(
388 Artifact artifact, {
389 TargetPlatform? platform,
390 BuildMode? mode,
391 EnvironmentType? environmentType,
392 });
393
394 /// Retrieve a host specific artifact that does not depend on the
395 /// current build mode or environment.
396 FileSystemEntity getHostArtifact(HostArtifact artifact);
397
398 // Returns which set of engine artifacts is currently used for the [platform]
399 // and [mode] combination.
400 String getEngineType(TargetPlatform platform, [BuildMode? mode]);
401
402 /// Whether these artifacts use any locally built files that are not part of
403 /// a versioned engine.
404 bool get usesLocalArtifacts;
405
406 /// If these artifacts are bound to a local engine build, returns info about
407 /// the location and name of the local engine, otherwise returns null.
408 LocalEngineInfo? get localEngineInfo;
409}
410
411/// Manages the engine artifacts downloaded to the local cache.
412class CachedArtifacts implements Artifacts {
413 CachedArtifacts({
414 required FileSystem fileSystem,
415 required Platform platform,
416 required Cache cache,
417 required OperatingSystemUtils operatingSystemUtils,
418 }) : _fileSystem = fileSystem,
419 _platform = platform,
420 _cache = cache,
421 _operatingSystemUtils = operatingSystemUtils;
422
423 final FileSystem _fileSystem;
424 final Platform _platform;
425 final Cache _cache;
426 final OperatingSystemUtils _operatingSystemUtils;
427
428 @override
429 LocalEngineInfo? get localEngineInfo => null;
430
431 @override
432 FileSystemEntity getHostArtifact(HostArtifact artifact) {
433 switch (artifact) {
434 case HostArtifact.flutterWebSdk:
435 final String path = _getFlutterWebSdkPath();
436 return _fileSystem.directory(path);
437 case HostArtifact.flutterWebLibrariesJson:
438 final String path = _fileSystem.path.join(
439 _getFlutterWebSdkPath(),
440 _hostArtifactToFileName(artifact, _platform),
441 );
442 return _fileSystem.file(path);
443 case HostArtifact.flutterJsDirectory:
444 final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'flutter_js');
445 return _fileSystem.directory(path);
446 case HostArtifact.webPlatformKernelFolder:
447 final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel');
448 return _fileSystem.file(path);
449 case HostArtifact.webPlatformDDCKernelDill:
450 case HostArtifact.webPlatformDart2JSKernelDill:
451 final String path = _fileSystem.path.join(
452 _getFlutterWebSdkPath(),
453 'kernel',
454 _hostArtifactToFileName(artifact, _platform),
455 );
456 return _fileSystem.file(path);
457 case HostArtifact.webPrecompiledAmdCanvaskitSdk:
458 case HostArtifact.webPrecompiledAmdCanvaskitSdkSourcemaps:
459 final String path = _fileSystem.path.join(
460 _getFlutterWebSdkPath(),
461 'kernel',
462 'amd-canvaskit',
463 _hostArtifactToFileName(artifact, _platform),
464 );
465 return _fileSystem.file(path);
466 case HostArtifact.webPrecompiledDdcLibraryBundleCanvaskitSdk:
467 case HostArtifact.webPrecompiledDdcLibraryBundleCanvaskitSdkSourcemaps:
468 final String path = _fileSystem.path.join(
469 _getFlutterWebSdkPath(),
470 'kernel',
471 'ddcLibraryBundle-canvaskit',
472 _hostArtifactToFileName(artifact, _platform),
473 );
474 return _fileSystem.file(path);
475 case HostArtifact.idevicesyslog:
476 case HostArtifact.idevicescreenshot:
477 final String artifactFileName = _hostArtifactToFileName(artifact, _platform);
478 return _cache.getArtifactDirectory('libimobiledevice').childFile(artifactFileName);
479 case HostArtifact.skyEnginePath:
480 final Directory dartPackageDirectory = _cache.getCacheDir('pkg');
481 final String path = _fileSystem.path.join(
482 dartPackageDirectory.path,
483 _hostArtifactToFileName(artifact, _platform),
484 );
485 return _fileSystem.directory(path);
486 case HostArtifact.iosDeploy:
487 final String artifactFileName = _hostArtifactToFileName(artifact, _platform);
488 return _cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName);
489 case HostArtifact.iproxy:
490 final String artifactFileName = _hostArtifactToFileName(artifact, _platform);
491 return _cache.getArtifactDirectory('libusbmuxd').childFile(artifactFileName);
492 case HostArtifact.impellerc:
493 case HostArtifact.libtessellator:
494 final String artifactFileName = _hostArtifactToFileName(artifact, _platform);
495 final String engineDir = _getEngineArtifactsPath(
496 _currentHostPlatform(_platform, _operatingSystemUtils),
497 )!;
498 return _fileSystem.file(_fileSystem.path.join(engineDir, artifactFileName));
499 }
500 }
501
502 @override
503 String getArtifactPath(
504 Artifact artifact, {
505 TargetPlatform? platform,
506 BuildMode? mode,
507 EnvironmentType? environmentType,
508 }) {
509 platform = _mapTargetPlatform(platform);
510 switch (platform) {
511 case TargetPlatform.android:
512 case TargetPlatform.android_arm:
513 case TargetPlatform.android_arm64:
514 case TargetPlatform.android_x64:
515 assert(platform != TargetPlatform.android);
516 return _getAndroidArtifactPath(artifact, platform!, mode!);
517 case TargetPlatform.ios:
518 return _getIosArtifactPath(artifact, platform!, mode, environmentType);
519 case TargetPlatform.darwin:
520 case TargetPlatform.linux_x64:
521 case TargetPlatform.linux_arm64:
522 case TargetPlatform.windows_x64:
523 case TargetPlatform.windows_arm64:
524 return _getDesktopArtifactPath(artifact, platform!, mode);
525 case TargetPlatform.fuchsia_arm64:
526 case TargetPlatform.fuchsia_x64:
527 return _getFuchsiaArtifactPath(artifact, platform!, mode!);
528 case TargetPlatform.tester:
529 case TargetPlatform.web_javascript:
530 case null:
531 return _getHostArtifactPath(
532 artifact,
533 platform ?? _currentHostPlatform(_platform, _operatingSystemUtils),
534 mode,
535 );
536 case TargetPlatform.unsupported:
537 TargetPlatform.throwUnsupportedTarget();
538 }
539 }
540
541 @override
542 String getEngineType(TargetPlatform platform, [BuildMode? mode]) {
543 return _fileSystem.path.basename(_getEngineArtifactsPath(platform, mode)!);
544 }
545
546 String _getDesktopArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode? mode) {
547 // When platform is null, a generic host platform artifact is being requested
548 // and not the gen_snapshot for darwin as a target platform.
549 final String engineDir = _getEngineArtifactsPath(platform, mode)!;
550 switch (artifact) {
551 case Artifact.genSnapshot:
552 case Artifact.genSnapshotArm64:
553 case Artifact.genSnapshotX64:
554 return _fileSystem.path.join(engineDir, _artifactToFileName(artifact, _platform));
555 case Artifact.engineDartSdkPath:
556 case Artifact.engineDartBinary:
557 case Artifact.engineDartAotRuntime:
558 case Artifact.frontendServerSnapshotForEngineDartSdk:
559 case Artifact.constFinder:
560 case Artifact.flutterFramework:
561 case Artifact.flutterFrameworkDsym:
562 case Artifact.flutterMacOSFramework:
563 return _getMacOSFrameworkPath(engineDir, _fileSystem, _platform);
564 case Artifact.flutterMacOSFrameworkDsym:
565 return _getMacOSFrameworkDsymPath(engineDir, _fileSystem, _platform);
566 case Artifact.flutterMacOSXcframework:
567 case Artifact.flutterPatchedSdkPath:
568 case Artifact.flutterTester:
569 case Artifact.flutterXcframework:
570 case Artifact.fontSubset:
571 case Artifact.fuchsiaFlutterRunner:
572 case Artifact.fuchsiaKernelCompiler:
573 case Artifact.icuData:
574 case Artifact.isolateSnapshotData:
575 case Artifact.linuxDesktopPath:
576 case Artifact.linuxHeaders:
577 case Artifact.platformKernelDill:
578 case Artifact.platformLibrariesJson:
579 case Artifact.skyEnginePath:
580 case Artifact.vmSnapshotData:
581 case Artifact.windowsCppClientWrapper:
582 case Artifact.windowsDesktopPath:
583 case Artifact.flutterToolsFileGenerators:
584 return _getHostArtifactPath(artifact, platform, mode);
585 }
586 }
587
588 String _getAndroidArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
589 final String engineDir = _getEngineArtifactsPath(platform, mode)!;
590 switch (artifact) {
591 case Artifact.genSnapshot:
592 case Artifact.genSnapshotArm64:
593 case Artifact.genSnapshotX64:
594 assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.');
595
596 // TODO(cbracken): Build Android gen_snapshot as Arm64 binary to run
597 // natively on Apple Silicon. See:
598 // https://github.com/flutter/flutter/issues/152281
599 HostPlatform hostPlatform = getCurrentHostPlatform();
600 if (hostPlatform == HostPlatform.darwin_arm64) {
601 hostPlatform = HostPlatform.darwin_x64;
602 }
603
604 final String hostPlatformName = getNameForHostPlatform(hostPlatform);
605 return _fileSystem.path.join(
606 engineDir,
607 hostPlatformName,
608 _artifactToFileName(artifact, _platform),
609 );
610 case Artifact.engineDartSdkPath:
611 case Artifact.engineDartBinary:
612 case Artifact.engineDartAotRuntime:
613 case Artifact.frontendServerSnapshotForEngineDartSdk:
614 case Artifact.constFinder:
615 case Artifact.flutterFramework:
616 case Artifact.flutterFrameworkDsym:
617 case Artifact.flutterMacOSFramework:
618 case Artifact.flutterMacOSFrameworkDsym:
619 case Artifact.flutterMacOSXcframework:
620 case Artifact.flutterPatchedSdkPath:
621 case Artifact.flutterTester:
622 case Artifact.flutterXcframework:
623 case Artifact.fontSubset:
624 case Artifact.fuchsiaFlutterRunner:
625 case Artifact.fuchsiaKernelCompiler:
626 case Artifact.icuData:
627 case Artifact.isolateSnapshotData:
628 case Artifact.linuxDesktopPath:
629 case Artifact.linuxHeaders:
630 case Artifact.platformKernelDill:
631 case Artifact.platformLibrariesJson:
632 case Artifact.skyEnginePath:
633 case Artifact.vmSnapshotData:
634 case Artifact.windowsCppClientWrapper:
635 case Artifact.windowsDesktopPath:
636 case Artifact.flutterToolsFileGenerators:
637 return _getHostArtifactPath(artifact, platform, mode);
638 }
639 }
640
641 String _getIosArtifactPath(
642 Artifact artifact,
643 TargetPlatform platform,
644 BuildMode? mode,
645 EnvironmentType? environmentType,
646 ) {
647 switch (artifact) {
648 case Artifact.genSnapshot:
649 case Artifact.genSnapshotArm64:
650 case Artifact.genSnapshotX64:
651 case Artifact.flutterXcframework:
652 final String artifactFileName = _artifactToFileName(artifact, _platform)!;
653 final String engineDir = _getEngineArtifactsPath(platform, mode)!;
654 return _fileSystem.path.join(engineDir, artifactFileName);
655 case Artifact.flutterFramework:
656 final String engineDir = _getEngineArtifactsPath(platform, mode)!;
657 return _getIosFrameworkPath(engineDir, environmentType, _fileSystem, _platform);
658 case Artifact.flutterFrameworkDsym:
659 final String engineDir = _getEngineArtifactsPath(platform, mode)!;
660 return _getIosFrameworkDsymPath(engineDir, environmentType, _fileSystem, _platform);
661 case Artifact.engineDartSdkPath:
662 case Artifact.engineDartBinary:
663 case Artifact.engineDartAotRuntime:
664 case Artifact.frontendServerSnapshotForEngineDartSdk:
665 case Artifact.constFinder:
666 case Artifact.flutterMacOSFramework:
667 case Artifact.flutterMacOSFrameworkDsym:
668 case Artifact.flutterMacOSXcframework:
669 case Artifact.flutterPatchedSdkPath:
670 case Artifact.flutterTester:
671 case Artifact.fontSubset:
672 case Artifact.fuchsiaFlutterRunner:
673 case Artifact.fuchsiaKernelCompiler:
674 case Artifact.icuData:
675 case Artifact.isolateSnapshotData:
676 case Artifact.linuxDesktopPath:
677 case Artifact.linuxHeaders:
678 case Artifact.platformKernelDill:
679 case Artifact.platformLibrariesJson:
680 case Artifact.skyEnginePath:
681 case Artifact.vmSnapshotData:
682 case Artifact.windowsCppClientWrapper:
683 case Artifact.windowsDesktopPath:
684 case Artifact.flutterToolsFileGenerators:
685 return _getHostArtifactPath(artifact, platform, mode);
686 }
687 }
688
689 String _getFuchsiaArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
690 final String root = _fileSystem.path.join(
691 _cache.getArtifactDirectory('flutter_runner').path,
692 'flutter',
693 platform.fuchsiaArchForTargetPlatform,
694 mode.isRelease ? 'release' : mode.toString(),
695 );
696 final runtime = mode.isJit ? 'jit' : 'aot';
697 switch (artifact) {
698 case Artifact.genSnapshot:
699 final genSnapshot = mode.isRelease ? 'gen_snapshot_product' : 'gen_snapshot';
700 return _fileSystem.path.join(root, runtime, 'dart_binaries', genSnapshot);
701 case Artifact.genSnapshotArm64:
702 case Artifact.genSnapshotX64:
703 throw ArgumentError('$artifact is not available on this platform');
704 case Artifact.flutterPatchedSdkPath:
705 const artifactFileName = 'flutter_runner_patched_sdk';
706 return _fileSystem.path.join(root, runtime, artifactFileName);
707 case Artifact.platformKernelDill:
708 final String artifactFileName = _artifactToFileName(artifact, _platform, mode)!;
709 return _fileSystem.path.join(root, runtime, 'flutter_runner_patched_sdk', artifactFileName);
710 case Artifact.fuchsiaKernelCompiler:
711 final String artifactFileName = _artifactToFileName(artifact, _platform, mode)!;
712 return _fileSystem.path.join(root, runtime, 'dart_binaries', artifactFileName);
713 case Artifact.fuchsiaFlutterRunner:
714 final String artifactFileName = _artifactToFileName(artifact, _platform, mode)!;
715 return _fileSystem.path.join(root, runtime, artifactFileName);
716 case Artifact.constFinder:
717 case Artifact.flutterFramework:
718 case Artifact.flutterFrameworkDsym:
719 case Artifact.flutterMacOSFramework:
720 case Artifact.flutterMacOSFrameworkDsym:
721 case Artifact.flutterMacOSXcframework:
722 case Artifact.flutterTester:
723 case Artifact.flutterXcframework:
724 case Artifact.fontSubset:
725 case Artifact.engineDartSdkPath:
726 case Artifact.engineDartBinary:
727 case Artifact.engineDartAotRuntime:
728 case Artifact.frontendServerSnapshotForEngineDartSdk:
729 case Artifact.icuData:
730 case Artifact.isolateSnapshotData:
731 case Artifact.linuxDesktopPath:
732 case Artifact.linuxHeaders:
733 case Artifact.platformLibrariesJson:
734 case Artifact.skyEnginePath:
735 case Artifact.vmSnapshotData:
736 case Artifact.windowsCppClientWrapper:
737 case Artifact.windowsDesktopPath:
738 case Artifact.flutterToolsFileGenerators:
739 return _getHostArtifactPath(artifact, platform, mode);
740 }
741 }
742
743 String _getFlutterPatchedSdkPath(BuildMode? mode) {
744 final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
745 return _fileSystem.path.join(
746 engineArtifactsPath,
747 'common',
748 mode == BuildMode.release ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk',
749 );
750 }
751
752 String _getFlutterWebSdkPath() {
753 return _cache.getWebSdkDirectory().path;
754 }
755
756 String _getHostArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode? mode) {
757 switch (artifact) {
758 case Artifact.genSnapshot:
759 case Artifact.genSnapshotArm64:
760 case Artifact.genSnapshotX64:
761 // For script snapshots any gen_snapshot binary will do. Returning gen_snapshot for
762 // android_arm in profile mode because it is available on all supported host platforms.
763 return _getAndroidArtifactPath(artifact, TargetPlatform.android_arm, BuildMode.profile);
764 case Artifact.frontendServerSnapshotForEngineDartSdk:
765 return _fileSystem.path.join(
766 _dartSdkPath(_cache),
767 'bin',
768 'snapshots',
769 _artifactToFileName(artifact, _platform),
770 );
771 case Artifact.flutterTester:
772 case Artifact.vmSnapshotData:
773 case Artifact.isolateSnapshotData:
774 case Artifact.icuData:
775 final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
776 final String platformDirName = _enginePlatformDirectoryName(platform);
777 return _fileSystem.path.join(
778 engineArtifactsPath,
779 platformDirName,
780 _artifactToFileName(artifact, _platform, mode),
781 );
782 case Artifact.platformKernelDill:
783 return _fileSystem.path.join(
784 _getFlutterPatchedSdkPath(mode),
785 _artifactToFileName(artifact, _platform),
786 );
787 case Artifact.platformLibrariesJson:
788 return _fileSystem.path.join(
789 _getFlutterPatchedSdkPath(mode),
790 'lib',
791 _artifactToFileName(artifact, _platform),
792 );
793 case Artifact.flutterPatchedSdkPath:
794 return _getFlutterPatchedSdkPath(mode);
795 case Artifact.engineDartSdkPath:
796 return _dartSdkPath(_cache);
797 case Artifact.engineDartBinary:
798 case Artifact.engineDartAotRuntime:
799 return _fileSystem.path.join(
800 _dartSdkPath(_cache),
801 'bin',
802 _artifactToFileName(artifact, _platform),
803 );
804 case Artifact.flutterMacOSFramework:
805 String platformDirName = _enginePlatformDirectoryName(platform);
806 if (mode == BuildMode.profile || mode == BuildMode.release) {
807 platformDirName = '$platformDirName-${mode!.cliName}';
808 }
809 final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
810 return _getMacOSFrameworkPath(
811 _fileSystem.path.join(engineArtifactsPath, platformDirName),
812 _fileSystem,
813 _platform,
814 );
815 case Artifact.flutterMacOSFrameworkDsym:
816 String platformDirName = _enginePlatformDirectoryName(platform);
817 if (mode == BuildMode.profile || mode == BuildMode.release) {
818 platformDirName = '$platformDirName-${mode!.cliName}';
819 }
820 final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
821 return _getMacOSFrameworkDsymPath(
822 _fileSystem.path.join(engineArtifactsPath, platformDirName),
823 _fileSystem,
824 _platform,
825 );
826 case Artifact.flutterMacOSXcframework:
827 case Artifact.linuxDesktopPath:
828 case Artifact.windowsDesktopPath:
829 case Artifact.linuxHeaders:
830 // TODO(zanderso): remove once debug desktop artifacts are uploaded
831 // under a separate directory from the host artifacts.
832 // https://github.com/flutter/flutter/issues/38935
833 String platformDirName = _enginePlatformDirectoryName(platform);
834 if (mode == BuildMode.profile || mode == BuildMode.release) {
835 platformDirName = '$platformDirName-${mode!.cliName}';
836 }
837 final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
838 return _fileSystem.path.join(
839 engineArtifactsPath,
840 platformDirName,
841 _artifactToFileName(artifact, _platform, mode),
842 );
843 case Artifact.windowsCppClientWrapper:
844 final String platformDirName = _enginePlatformDirectoryName(platform);
845 final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
846 return _fileSystem.path.join(
847 engineArtifactsPath,
848 platformDirName,
849 _artifactToFileName(artifact, _platform, mode),
850 );
851 case Artifact.skyEnginePath:
852 final Directory dartPackageDirectory = _cache.getCacheDir('pkg');
853 return _fileSystem.path.join(
854 dartPackageDirectory.path,
855 _artifactToFileName(artifact, _platform),
856 );
857 case Artifact.fontSubset:
858 case Artifact.constFinder:
859 return _cache
860 .getArtifactDirectory('engine')
861 .childDirectory(_enginePlatformDirectoryName(platform))
862 .childFile(_artifactToFileName(artifact, _platform, mode)!)
863 .path;
864 case Artifact.flutterFramework:
865 case Artifact.flutterFrameworkDsym:
866 case Artifact.flutterXcframework:
867 case Artifact.fuchsiaFlutterRunner:
868 case Artifact.fuchsiaKernelCompiler:
869 throw StateError('Artifact $artifact not available for platform $platform.');
870 case Artifact.flutterToolsFileGenerators:
871 return _getFileGeneratorsPath();
872 }
873 }
874
875 String? _getEngineArtifactsPath(TargetPlatform platform, [BuildMode? mode]) {
876 final String engineDir = _cache.getArtifactDirectory('engine').path;
877 final String platformName = _enginePlatformDirectoryName(platform);
878 switch (platform) {
879 case TargetPlatform.linux_x64:
880 case TargetPlatform.linux_arm64:
881 case TargetPlatform.darwin:
882 case TargetPlatform.windows_x64:
883 case TargetPlatform.windows_arm64:
884 // TODO(zanderso): remove once debug desktop artifacts are uploaded
885 // under a separate directory from the host artifacts.
886 // https://github.com/flutter/flutter/issues/38935
887 if (mode == BuildMode.debug || mode == null) {
888 return _fileSystem.path.join(engineDir, platformName);
889 }
890 final suffix = mode != BuildMode.debug ? '-${kebabCase(mode.cliName)}' : '';
891 return _fileSystem.path.join(engineDir, platformName + suffix);
892 case TargetPlatform.fuchsia_arm64:
893 case TargetPlatform.fuchsia_x64:
894 case TargetPlatform.tester:
895 case TargetPlatform.web_javascript:
896 assert(mode == null, 'Platform $platform does not support different build modes.');
897 return _fileSystem.path.join(engineDir, platformName);
898 case TargetPlatform.ios:
899 case TargetPlatform.android_arm:
900 case TargetPlatform.android_arm64:
901 case TargetPlatform.android_x64:
902 assert(mode != null, 'Need to specify a build mode for platform $platform.');
903 final suffix = mode != BuildMode.debug ? '-${kebabCase(mode!.cliName)}' : '';
904 return _fileSystem.path.join(engineDir, platformName + suffix);
905 case TargetPlatform.android:
906 assert(false, 'cannot use TargetPlatform.android to look up artifacts');
907 return null;
908 case TargetPlatform.unsupported:
909 TargetPlatform.throwUnsupportedTarget();
910 }
911 }
912
913 @override
914 bool get usesLocalArtifacts => false;
915}
916
917TargetPlatform _currentHostPlatform(Platform platform, OperatingSystemUtils operatingSystemUtils) {
918 if (platform.isMacOS) {
919 return TargetPlatform.darwin;
920 }
921 if (platform.isLinux) {
922 return operatingSystemUtils.hostPlatform == HostPlatform.linux_x64
923 ? TargetPlatform.linux_x64
924 : TargetPlatform.linux_arm64;
925 }
926 if (platform.isWindows) {
927 return operatingSystemUtils.hostPlatform == HostPlatform.windows_arm64
928 ? TargetPlatform.windows_arm64
929 : TargetPlatform.windows_x64;
930 }
931 throw UnimplementedError('Host OS not supported.');
932}
933
934/// Returns the Flutter.xcframework platform directory for the specified environment type.
935///
936/// `Flutter.xcframework` contains target environment/architecture-specific
937/// subdirectories containing the appropriate `Flutter.framework` and
938/// `dSYMs/Flutter.framework.dSYMs` bundles for that target architecture.
939Directory _getIosFlutterFrameworkPlatformDirectory(
940 String engineDirectory,
941 EnvironmentType? environmentType,
942 FileSystem fileSystem,
943 Platform hostPlatform,
944) {
945 final Directory xcframeworkDirectory = fileSystem
946 .directory(engineDirectory)
947 .childDirectory(_artifactToFileName(Artifact.flutterXcframework, hostPlatform)!);
948
949 if (!xcframeworkDirectory.existsSync()) {
950 throwToolExit(
951 'No xcframework found at ${xcframeworkDirectory.path}. Try running "flutter precache --ios".',
952 );
953 }
954 for (final Directory platformDirectory
955 in xcframeworkDirectory.listSync().whereType<Directory>()) {
956 if (!platformDirectory.basename.startsWith('ios-')) {
957 continue;
958 }
959 // ios-x86_64-simulator, ios-arm64_x86_64-simulator, or ios-arm64.
960 final bool simulatorDirectory = platformDirectory.basename.endsWith('-simulator');
961 if ((environmentType == EnvironmentType.simulator && simulatorDirectory) ||
962 (environmentType == EnvironmentType.physical && !simulatorDirectory)) {
963 return platformDirectory;
964 }
965 }
966 throwToolExit('No iOS frameworks found in ${xcframeworkDirectory.path}');
967}
968
969/// Returns the path to Flutter.framework.
970String _getIosFrameworkPath(
971 String engineDirectory,
972 EnvironmentType? environmentType,
973 FileSystem fileSystem,
974 Platform hostPlatform,
975) {
976 final Directory platformDir = _getIosFlutterFrameworkPlatformDirectory(
977 engineDirectory,
978 environmentType,
979 fileSystem,
980 hostPlatform,
981 );
982 return platformDir
983 .childDirectory(_artifactToFileName(Artifact.flutterFramework, hostPlatform)!)
984 .path;
985}
986
987/// Returns the path to Flutter.framework.dSYM.
988String _getIosFrameworkDsymPath(
989 String engineDirectory,
990 EnvironmentType? environmentType,
991 FileSystem fileSystem,
992 Platform hostPlatform,
993) {
994 final Directory platformDir = _getIosFlutterFrameworkPlatformDirectory(
995 engineDirectory,
996 environmentType,
997 fileSystem,
998 hostPlatform,
999 );
1000 return platformDir
1001 .childDirectory('dSYMs')
1002 .childDirectory(_artifactToFileName(Artifact.flutterFrameworkDsym, hostPlatform)!)
1003 .path;
1004}
1005
1006/// Returns the Flutter.xcframework platform directory for the specified environment type.
1007///
1008/// `FlutterMacOS.xcframework` contains target environment/architecture-specific
1009/// subdirectories containing the appropriate `FlutterMacOS.framework` and
1010/// `FlutterMacOS.framework.dSYM` bundles for that target architecture. At present,
1011/// there is only one such directory: `macos-arm64_x86_64`.
1012Directory _getMacOSFrameworkPlatformDirectory(
1013 String engineDirectory,
1014 FileSystem fileSystem,
1015 Platform hostPlatform,
1016) {
1017 final Directory xcframeworkDirectory = fileSystem
1018 .directory(engineDirectory)
1019 .childDirectory(_artifactToFileName(Artifact.flutterMacOSXcframework, hostPlatform)!);
1020
1021 if (!xcframeworkDirectory.existsSync()) {
1022 throwToolExit(
1023 'No xcframework found at ${xcframeworkDirectory.path}. Try running "flutter precache --macos".',
1024 );
1025 }
1026 final Directory? platformDirectory = xcframeworkDirectory
1027 .listSync()
1028 .whereType<Directory>()
1029 .where((Directory platformDirectory) => platformDirectory.basename.startsWith('macos-'))
1030 .firstOrNull;
1031 if (platformDirectory == null) {
1032 throwToolExit('No macOS frameworks found in ${xcframeworkDirectory.path}');
1033 }
1034 return platformDirectory;
1035}
1036
1037/// Returns the path to `FlutterMacOS.framework`.
1038String _getMacOSFrameworkPath(
1039 String engineDirectory,
1040 FileSystem fileSystem,
1041 Platform hostPlatform,
1042) {
1043 final Directory platformDirectory = _getMacOSFrameworkPlatformDirectory(
1044 engineDirectory,
1045 fileSystem,
1046 hostPlatform,
1047 );
1048 return platformDirectory
1049 .childDirectory(_artifactToFileName(Artifact.flutterMacOSFramework, hostPlatform)!)
1050 .path;
1051}
1052
1053/// Returns the path to `FlutterMacOS.framework`.
1054String _getMacOSFrameworkDsymPath(
1055 String engineDirectory,
1056 FileSystem fileSystem,
1057 Platform hostPlatform,
1058) {
1059 final Directory platformDirectory = _getMacOSFrameworkPlatformDirectory(
1060 engineDirectory,
1061 fileSystem,
1062 hostPlatform,
1063 );
1064 return platformDirectory
1065 .childDirectory('dSYMs')
1066 .childDirectory(_artifactToFileName(Artifact.flutterMacOSFrameworkDsym, hostPlatform)!)
1067 .path;
1068}
1069
1070/// Manages the artifacts of a locally built engine.
1071class CachedLocalEngineArtifacts implements Artifacts {
1072 CachedLocalEngineArtifacts(
1073 this._hostEngineOutPath, {
1074 required String engineOutPath,
1075 required FileSystem fileSystem,
1076 required Cache cache,
1077 required ProcessManager processManager,
1078 required Platform platform,
1079 required OperatingSystemUtils operatingSystemUtils,
1080 Artifacts? parent,
1081 }) : _fileSystem = fileSystem,
1082 localEngineInfo = LocalEngineInfo(
1083 targetOutPath: engineOutPath,
1084 hostOutPath: _hostEngineOutPath,
1085 ),
1086 _cache = cache,
1087 _processManager = processManager,
1088 _platform = platform,
1089 _operatingSystemUtils = operatingSystemUtils,
1090 _backupCache =
1091 parent ??
1092 CachedArtifacts(
1093 fileSystem: fileSystem,
1094 platform: platform,
1095 cache: cache,
1096 operatingSystemUtils: operatingSystemUtils,
1097 );
1098
1099 @override
1100 final LocalEngineInfo localEngineInfo;
1101
1102 final String _hostEngineOutPath;
1103 final FileSystem _fileSystem;
1104 final Cache _cache;
1105 final ProcessManager _processManager;
1106 final Platform _platform;
1107 final OperatingSystemUtils _operatingSystemUtils;
1108 final Artifacts _backupCache;
1109
1110 @override
1111 FileSystemEntity getHostArtifact(HostArtifact artifact) {
1112 switch (artifact) {
1113 case HostArtifact.flutterWebSdk:
1114 final String path = _getFlutterWebSdkPath();
1115 return _fileSystem.directory(path);
1116 case HostArtifact.flutterWebLibrariesJson:
1117 final String path = _fileSystem.path.join(
1118 _getFlutterWebSdkPath(),
1119 _hostArtifactToFileName(artifact, _platform),
1120 );
1121 return _fileSystem.file(path);
1122 case HostArtifact.flutterJsDirectory:
1123 final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'flutter_js');
1124 return _fileSystem.directory(path);
1125 case HostArtifact.webPlatformKernelFolder:
1126 final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel');
1127 return _fileSystem.file(path);
1128 case HostArtifact.webPlatformDDCKernelDill:
1129 case HostArtifact.webPlatformDart2JSKernelDill:
1130 final String path = _fileSystem.path.join(
1131 _getFlutterWebSdkPath(),
1132 'kernel',
1133 _hostArtifactToFileName(artifact, _platform),
1134 );
1135 return _fileSystem.file(path);
1136 case HostArtifact.webPrecompiledAmdCanvaskitSdk:
1137 case HostArtifact.webPrecompiledAmdCanvaskitSdkSourcemaps:
1138 final String path = _fileSystem.path.join(
1139 _getFlutterWebSdkPath(),
1140 'kernel',
1141 'amd-canvaskit',
1142 _hostArtifactToFileName(artifact, _platform),
1143 );
1144 return _fileSystem.file(path);
1145 case HostArtifact.webPrecompiledDdcLibraryBundleCanvaskitSdk:
1146 case HostArtifact.webPrecompiledDdcLibraryBundleCanvaskitSdkSourcemaps:
1147 final String path = _fileSystem.path.join(
1148 _getFlutterWebSdkPath(),
1149 'kernel',
1150 'ddcLibraryBundle-canvaskit',
1151 _hostArtifactToFileName(artifact, _platform),
1152 );
1153 return _fileSystem.file(path);
1154 case HostArtifact.idevicesyslog:
1155 case HostArtifact.idevicescreenshot:
1156 final String artifactFileName = _hostArtifactToFileName(artifact, _platform);
1157 return _cache.getArtifactDirectory('libimobiledevice').childFile(artifactFileName);
1158 case HostArtifact.skyEnginePath:
1159 final Directory dartPackageDirectory = _cache.getCacheDir('pkg');
1160 final String path = _fileSystem.path.join(
1161 dartPackageDirectory.path,
1162 _hostArtifactToFileName(artifact, _platform),
1163 );
1164 return _fileSystem.directory(path);
1165 case HostArtifact.iosDeploy:
1166 final String artifactFileName = _hostArtifactToFileName(artifact, _platform);
1167 return _cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName);
1168 case HostArtifact.iproxy:
1169 final String artifactFileName = _hostArtifactToFileName(artifact, _platform);
1170 return _cache.getArtifactDirectory('libusbmuxd').childFile(artifactFileName);
1171 case HostArtifact.impellerc:
1172 case HostArtifact.libtessellator:
1173 final String artifactFileName = _hostArtifactToFileName(artifact, _platform);
1174 final File file = _fileSystem.file(
1175 _fileSystem.path.join(_hostEngineOutPath, artifactFileName),
1176 );
1177 if (!file.existsSync()) {
1178 return _backupCache.getHostArtifact(artifact);
1179 }
1180 return file;
1181 }
1182 }
1183
1184 @override
1185 String getArtifactPath(
1186 Artifact artifact, {
1187 TargetPlatform? platform,
1188 BuildMode? mode,
1189 EnvironmentType? environmentType,
1190 }) {
1191 platform ??= _currentHostPlatform(_platform, _operatingSystemUtils);
1192 platform = _mapTargetPlatform(platform);
1193 final isDirectoryArtifact = artifact == Artifact.flutterPatchedSdkPath;
1194 final String? artifactFileName = isDirectoryArtifact
1195 ? null
1196 : _artifactToFileName(artifact, _platform, mode);
1197 switch (artifact) {
1198 case Artifact.genSnapshot:
1199 case Artifact.genSnapshotArm64:
1200 case Artifact.genSnapshotX64:
1201 return _genSnapshotPath(artifact);
1202 case Artifact.flutterTester:
1203 return _flutterTesterPath(platform!);
1204 case Artifact.isolateSnapshotData:
1205 case Artifact.vmSnapshotData:
1206 return _fileSystem.path.join(
1207 localEngineInfo.targetOutPath,
1208 'gen',
1209 'flutter',
1210 'lib',
1211 'snapshot',
1212 artifactFileName,
1213 );
1214 case Artifact.icuData:
1215 case Artifact.flutterXcframework:
1216 case Artifact.flutterMacOSXcframework:
1217 return _fileSystem.path.join(localEngineInfo.targetOutPath, artifactFileName);
1218 case Artifact.platformKernelDill:
1219 if (platform == TargetPlatform.fuchsia_x64 || platform == TargetPlatform.fuchsia_arm64) {
1220 return _fileSystem.path.join(
1221 localEngineInfo.targetOutPath,
1222 'flutter_runner_patched_sdk',
1223 artifactFileName,
1224 );
1225 }
1226 return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), artifactFileName);
1227 case Artifact.platformLibrariesJson:
1228 return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', artifactFileName);
1229 case Artifact.flutterFramework:
1230 return _getIosFrameworkPath(
1231 localEngineInfo.targetOutPath,
1232 environmentType,
1233 _fileSystem,
1234 _platform,
1235 );
1236 case Artifact.flutterFrameworkDsym:
1237 return _getIosFrameworkDsymPath(
1238 localEngineInfo.targetOutPath,
1239 environmentType,
1240 _fileSystem,
1241 _platform,
1242 );
1243 case Artifact.flutterMacOSFramework:
1244 return _getMacOSFrameworkPath(localEngineInfo.targetOutPath, _fileSystem, _platform);
1245 case Artifact.flutterMacOSFrameworkDsym:
1246 return _getMacOSFrameworkDsymPath(localEngineInfo.targetOutPath, _fileSystem, _platform);
1247 case Artifact.flutterPatchedSdkPath:
1248 // When using local engine always use [BuildMode.debug] regardless of
1249 // what was specified in [mode] argument because local engine will
1250 // have only one flutter_patched_sdk in standard location, that
1251 // is happen to be what debug(non-release) mode is using.
1252 if (platform == TargetPlatform.fuchsia_x64 || platform == TargetPlatform.fuchsia_arm64) {
1253 return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_runner_patched_sdk');
1254 }
1255 return _getFlutterPatchedSdkPath(BuildMode.debug);
1256 case Artifact.skyEnginePath:
1257 return _fileSystem.path.join(_hostEngineOutPath, 'gen', 'dart-pkg', artifactFileName);
1258 case Artifact.fuchsiaKernelCompiler:
1259 final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform());
1260 final modeName = mode!.isRelease ? 'release' : mode.toString();
1261 final dartBinaries = 'dart_binaries-$modeName-$hostPlatform';
1262 return _fileSystem.path.join(
1263 localEngineInfo.targetOutPath,
1264 'host_bundle',
1265 dartBinaries,
1266 'kernel_compiler.dart.snapshot',
1267 );
1268 case Artifact.fuchsiaFlutterRunner:
1269 final jitOrAot = mode!.isJit ? '_jit' : '_aot';
1270 final productOrNo = mode.isRelease ? '_product' : '';
1271 return _fileSystem.path.join(
1272 localEngineInfo.targetOutPath,
1273 'flutter$jitOrAot${productOrNo}_runner-0.far',
1274 );
1275 case Artifact.fontSubset:
1276 return _fileSystem.path.join(_hostEngineOutPath, artifactFileName);
1277 case Artifact.constFinder:
1278 return _fileSystem.path.join(_hostEngineOutPath, 'gen', artifactFileName);
1279 case Artifact.linuxDesktopPath:
1280 case Artifact.linuxHeaders:
1281 case Artifact.windowsDesktopPath:
1282 case Artifact.windowsCppClientWrapper:
1283 return _fileSystem.path.join(_hostEngineOutPath, artifactFileName);
1284 case Artifact.engineDartSdkPath:
1285 return _getDartSdkPath();
1286 case Artifact.engineDartBinary:
1287 case Artifact.engineDartAotRuntime:
1288 return _fileSystem.path.join(_getDartSdkPath(), 'bin', artifactFileName);
1289 case Artifact.frontendServerSnapshotForEngineDartSdk:
1290 return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName);
1291 case Artifact.flutterToolsFileGenerators:
1292 return _getFileGeneratorsPath();
1293 }
1294 }
1295
1296 @override
1297 String getEngineType(TargetPlatform platform, [BuildMode? mode]) {
1298 return _fileSystem.path.basename(localEngineInfo.targetOutPath);
1299 }
1300
1301 String _getFlutterPatchedSdkPath(BuildMode? buildMode) {
1302 return _fileSystem.path.join(
1303 localEngineInfo.targetOutPath,
1304 buildMode == BuildMode.release ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk',
1305 );
1306 }
1307
1308 String _getDartSdkPath() {
1309 final String builtPath = _fileSystem.path.join(_hostEngineOutPath, 'dart-sdk');
1310 if (_fileSystem.isDirectorySync(_fileSystem.path.join(builtPath, 'bin'))) {
1311 return builtPath;
1312 }
1313
1314 // If we couldn't find a built dart sdk, let's look for a prebuilt one.
1315 final String prebuiltPath = _fileSystem.path.join(
1316 _getFlutterPrebuiltsPath(),
1317 _getPrebuiltTarget(),
1318 'dart-sdk',
1319 );
1320 if (_fileSystem.isDirectorySync(prebuiltPath)) {
1321 return prebuiltPath;
1322 }
1323
1324 throwToolExit(
1325 'Unable to find a built dart sdk at: "$builtPath" or a prebuilt dart sdk at: "$prebuiltPath"',
1326 );
1327 }
1328
1329 String _getFlutterPrebuiltsPath() {
1330 final String engineSrcPath = _fileSystem.path.dirname(
1331 _fileSystem.path.dirname(_hostEngineOutPath),
1332 );
1333 return _fileSystem.path.join(engineSrcPath, 'flutter', 'prebuilts');
1334 }
1335
1336 String _getPrebuiltTarget() {
1337 final TargetPlatform hostPlatform = _currentHostPlatform(_platform, _operatingSystemUtils);
1338 switch (hostPlatform) {
1339 case TargetPlatform.darwin:
1340 return 'macos-x64';
1341 case TargetPlatform.linux_arm64:
1342 return 'linux-arm64';
1343 case TargetPlatform.linux_x64:
1344 return 'linux-x64';
1345 case TargetPlatform.windows_x64:
1346 return 'windows-x64';
1347 case TargetPlatform.windows_arm64:
1348 return 'windows-arm64';
1349 case TargetPlatform.ios:
1350 case TargetPlatform.android:
1351 case TargetPlatform.android_arm:
1352 case TargetPlatform.android_arm64:
1353 case TargetPlatform.android_x64:
1354 case TargetPlatform.fuchsia_arm64:
1355 case TargetPlatform.fuchsia_x64:
1356 case TargetPlatform.web_javascript:
1357 case TargetPlatform.tester:
1358 throwToolExit('Unsupported host platform: $hostPlatform');
1359 case TargetPlatform.unsupported:
1360 TargetPlatform.throwUnsupportedTarget();
1361 }
1362 }
1363
1364 String _getFlutterWebSdkPath() {
1365 return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_web_sdk');
1366 }
1367
1368 String _genSnapshotPath(Artifact artifact) {
1369 const clangDirs = <String>[
1370 '.',
1371 'universal',
1372 'clang_x64',
1373 'clang_x86',
1374 'clang_i386',
1375 'clang_arm64',
1376 ];
1377 final String genSnapshotName = _artifactToFileName(artifact, _platform)!;
1378 for (final clangDir in clangDirs) {
1379 final String genSnapshotPath = _fileSystem.path.join(
1380 localEngineInfo.targetOutPath,
1381 clangDir,
1382 genSnapshotName,
1383 );
1384 if (_processManager.canRun(genSnapshotPath)) {
1385 return genSnapshotPath;
1386 }
1387 }
1388 throw Exception('Unable to find $genSnapshotName');
1389 }
1390
1391 String _flutterTesterPath(TargetPlatform platform) {
1392 return _fileSystem.path.join(
1393 localEngineInfo.hostOutPath,
1394 _artifactToFileName(Artifact.flutterTester, _platform),
1395 );
1396 }
1397
1398 @override
1399 bool get usesLocalArtifacts => true;
1400}
1401
1402class CachedLocalWebSdkArtifacts implements Artifacts {
1403 CachedLocalWebSdkArtifacts({
1404 required Artifacts parent,
1405 required String webSdkPath,
1406 required FileSystem fileSystem,
1407 required Platform platform,
1408 required OperatingSystemUtils operatingSystemUtils,
1409 }) : _parent = parent,
1410 _webSdkPath = webSdkPath,
1411 _fileSystem = fileSystem,
1412 _platform = platform,
1413 _operatingSystemUtils = operatingSystemUtils;
1414
1415 final Artifacts _parent;
1416 final String _webSdkPath;
1417 final FileSystem _fileSystem;
1418 final Platform _platform;
1419 final OperatingSystemUtils _operatingSystemUtils;
1420
1421 @override
1422 String getArtifactPath(
1423 Artifact artifact, {
1424 TargetPlatform? platform,
1425 BuildMode? mode,
1426 EnvironmentType? environmentType,
1427 }) {
1428 if (platform == TargetPlatform.web_javascript) {
1429 switch (artifact) {
1430 case Artifact.engineDartSdkPath:
1431 return _getDartSdkPath();
1432 case Artifact.engineDartBinary:
1433 case Artifact.engineDartAotRuntime:
1434 return _fileSystem.path.join(
1435 _getDartSdkPath(),
1436 'bin',
1437 _artifactToFileName(artifact, _platform, mode),
1438 );
1439 case Artifact.frontendServerSnapshotForEngineDartSdk:
1440 return _fileSystem.path.join(
1441 _getDartSdkPath(),
1442 'bin',
1443 'snapshots',
1444 _artifactToFileName(artifact, _platform, mode),
1445 );
1446 case Artifact.genSnapshot:
1447 case Artifact.genSnapshotArm64:
1448 case Artifact.genSnapshotX64:
1449 case Artifact.flutterTester:
1450 case Artifact.flutterFramework:
1451 case Artifact.flutterFrameworkDsym:
1452 case Artifact.flutterXcframework:
1453 case Artifact.flutterMacOSFramework:
1454 case Artifact.flutterMacOSFrameworkDsym:
1455 case Artifact.flutterMacOSXcframework:
1456 case Artifact.vmSnapshotData:
1457 case Artifact.isolateSnapshotData:
1458 case Artifact.icuData:
1459 case Artifact.platformKernelDill:
1460 case Artifact.platformLibrariesJson:
1461 case Artifact.flutterPatchedSdkPath:
1462 case Artifact.linuxDesktopPath:
1463 case Artifact.linuxHeaders:
1464 case Artifact.windowsDesktopPath:
1465 case Artifact.windowsCppClientWrapper:
1466 case Artifact.skyEnginePath:
1467 case Artifact.fuchsiaKernelCompiler:
1468 case Artifact.fuchsiaFlutterRunner:
1469 case Artifact.fontSubset:
1470 case Artifact.constFinder:
1471 case Artifact.flutterToolsFileGenerators:
1472 break;
1473 }
1474 }
1475 return _parent.getArtifactPath(
1476 artifact,
1477 platform: platform,
1478 mode: mode,
1479 environmentType: environmentType,
1480 );
1481 }
1482
1483 @override
1484 String getEngineType(TargetPlatform platform, [BuildMode? mode]) =>
1485 _parent.getEngineType(platform, mode);
1486
1487 @override
1488 FileSystemEntity getHostArtifact(HostArtifact artifact) {
1489 switch (artifact) {
1490 case HostArtifact.flutterWebSdk:
1491 final String path = _getFlutterWebSdkPath();
1492 return _fileSystem.directory(path);
1493 case HostArtifact.flutterWebLibrariesJson:
1494 final String path = _fileSystem.path.join(
1495 _getFlutterWebSdkPath(),
1496 _hostArtifactToFileName(artifact, _platform),
1497 );
1498 return _fileSystem.file(path);
1499 case HostArtifact.flutterJsDirectory:
1500 final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'flutter_js');
1501 return _fileSystem.directory(path);
1502 case HostArtifact.webPlatformKernelFolder:
1503 final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel');
1504 return _fileSystem.file(path);
1505 case HostArtifact.webPlatformDDCKernelDill:
1506 case HostArtifact.webPlatformDart2JSKernelDill:
1507 final String path = _fileSystem.path.join(
1508 _getFlutterWebSdkPath(),
1509 'kernel',
1510 _hostArtifactToFileName(artifact, _platform),
1511 );
1512 return _fileSystem.file(path);
1513 case HostArtifact.webPrecompiledAmdCanvaskitSdk:
1514 case HostArtifact.webPrecompiledAmdCanvaskitSdkSourcemaps:
1515 final String path = _fileSystem.path.join(
1516 _getFlutterWebSdkPath(),
1517 'kernel',
1518 'amd-canvaskit',
1519 _hostArtifactToFileName(artifact, _platform),
1520 );
1521 return _fileSystem.file(path);
1522 case HostArtifact.webPrecompiledDdcLibraryBundleCanvaskitSdk:
1523 case HostArtifact.webPrecompiledDdcLibraryBundleCanvaskitSdkSourcemaps:
1524 final String path = _fileSystem.path.join(
1525 _getFlutterWebSdkPath(),
1526 'kernel',
1527 'ddcLibraryBundle-canvaskit',
1528 _hostArtifactToFileName(artifact, _platform),
1529 );
1530 return _fileSystem.file(path);
1531 case HostArtifact.iosDeploy:
1532 case HostArtifact.idevicesyslog:
1533 case HostArtifact.idevicescreenshot:
1534 case HostArtifact.iproxy:
1535 case HostArtifact.skyEnginePath:
1536 case HostArtifact.impellerc:
1537 case HostArtifact.libtessellator:
1538 return _parent.getHostArtifact(artifact);
1539 }
1540 }
1541
1542 String _getDartSdkPath() {
1543 // If the parent is a local engine, then use the locally built Dart SDK.
1544 if (_parent.usesLocalArtifacts) {
1545 return _parent.getArtifactPath(Artifact.engineDartSdkPath);
1546 }
1547
1548 // If we couldn't find a built dart sdk, let's look for a prebuilt one.
1549 final String prebuiltPath = _fileSystem.path.join(
1550 _getFlutterPrebuiltsPath(),
1551 _getPrebuiltTarget(),
1552 'dart-sdk',
1553 );
1554 if (_fileSystem.isDirectorySync(prebuiltPath)) {
1555 return prebuiltPath;
1556 }
1557
1558 throwToolExit('Unable to find a prebuilt dart sdk at: "$prebuiltPath"');
1559 }
1560
1561 String _getFlutterPrebuiltsPath() {
1562 final String engineSrcPath = _fileSystem.path.dirname(_fileSystem.path.dirname(_webSdkPath));
1563 return _fileSystem.path.join(engineSrcPath, 'flutter', 'prebuilts');
1564 }
1565
1566 String _getPrebuiltTarget() {
1567 final TargetPlatform hostPlatform = _currentHostPlatform(_platform, _operatingSystemUtils);
1568 switch (hostPlatform) {
1569 case TargetPlatform.darwin:
1570 return 'macos-x64';
1571 case TargetPlatform.linux_arm64:
1572 return 'linux-arm64';
1573 case TargetPlatform.linux_x64:
1574 return 'linux-x64';
1575 case TargetPlatform.windows_x64:
1576 return 'windows-x64';
1577 case TargetPlatform.windows_arm64:
1578 return 'windows-arm64';
1579 case TargetPlatform.ios:
1580 case TargetPlatform.android:
1581 case TargetPlatform.android_arm:
1582 case TargetPlatform.android_arm64:
1583 case TargetPlatform.android_x64:
1584 case TargetPlatform.fuchsia_arm64:
1585 case TargetPlatform.fuchsia_x64:
1586 case TargetPlatform.web_javascript:
1587 case TargetPlatform.tester:
1588 throwToolExit('Unsupported host platform: $hostPlatform');
1589 case TargetPlatform.unsupported:
1590 TargetPlatform.throwUnsupportedTarget();
1591 }
1592 }
1593
1594 String _getFlutterWebSdkPath() {
1595 return _fileSystem.path.join(_webSdkPath, 'flutter_web_sdk');
1596 }
1597
1598 @override
1599 bool get usesLocalArtifacts => true;
1600
1601 @override
1602 LocalEngineInfo? get localEngineInfo => _parent.localEngineInfo;
1603}
1604
1605/// An implementation of [Artifacts] that provides individual overrides.
1606///
1607/// If an artifact is not provided, the lookup delegates to the parent.
1608class OverrideArtifacts implements Artifacts {
1609 /// Creates a new [OverrideArtifacts].
1610 ///
1611 /// [parent] must be provided.
1612 OverrideArtifacts({
1613 required this.parent,
1614 this.frontendServer,
1615 this.engineDartBinary,
1616 this.platformKernelDill,
1617 this.flutterPatchedSdk,
1618 });
1619
1620 final Artifacts parent;
1621 final File? frontendServer;
1622 final File? engineDartBinary;
1623 final File? platformKernelDill;
1624 final File? flutterPatchedSdk;
1625
1626 @override
1627 LocalEngineInfo? get localEngineInfo => parent.localEngineInfo;
1628
1629 @override
1630 String getArtifactPath(
1631 Artifact artifact, {
1632 TargetPlatform? platform,
1633 BuildMode? mode,
1634 EnvironmentType? environmentType,
1635 }) {
1636 if (artifact == Artifact.engineDartBinary && engineDartBinary != null) {
1637 return engineDartBinary!.path;
1638 }
1639 if (artifact == Artifact.frontendServerSnapshotForEngineDartSdk && frontendServer != null) {
1640 return frontendServer!.path;
1641 }
1642 if (artifact == Artifact.platformKernelDill && platformKernelDill != null) {
1643 return platformKernelDill!.path;
1644 }
1645 if (artifact == Artifact.flutterPatchedSdkPath && flutterPatchedSdk != null) {
1646 return flutterPatchedSdk!.path;
1647 }
1648 return parent.getArtifactPath(
1649 artifact,
1650 platform: platform,
1651 mode: mode,
1652 environmentType: environmentType,
1653 );
1654 }
1655
1656 @override
1657 String getEngineType(TargetPlatform platform, [BuildMode? mode]) =>
1658 parent.getEngineType(platform, mode);
1659
1660 @override
1661 bool get usesLocalArtifacts => parent.usesLocalArtifacts;
1662
1663 @override
1664 FileSystemEntity getHostArtifact(HostArtifact artifact) {
1665 return parent.getHostArtifact(artifact);
1666 }
1667}
1668
1669/// Locate the Dart SDK.
1670String _dartSdkPath(Cache cache) {
1671 return cache.getRoot().childDirectory('dart-sdk').path;
1672}
1673
1674class _TestArtifacts implements Artifacts {
1675 _TestArtifacts(this.fileSystem);
1676
1677 final FileSystem fileSystem;
1678
1679 @override
1680 LocalEngineInfo? get localEngineInfo => null;
1681
1682 @override
1683 String getArtifactPath(
1684 Artifact artifact, {
1685 TargetPlatform? platform,
1686 BuildMode? mode,
1687 EnvironmentType? environmentType,
1688 }) {
1689 // The path to file generators is the same even in the test environment.
1690 if (artifact == Artifact.flutterToolsFileGenerators) {
1691 return _getFileGeneratorsPath();
1692 }
1693
1694 final buffer = StringBuffer();
1695 buffer.write(artifact);
1696 if (platform != null) {
1697 buffer.write('.$platform');
1698 }
1699 if (mode != null) {
1700 buffer.write('.$mode');
1701 }
1702 if (environmentType != null) {
1703 buffer.write('.$environmentType');
1704 }
1705 return buffer.toString();
1706 }
1707
1708 @override
1709 String getEngineType(TargetPlatform platform, [BuildMode? mode]) {
1710 return 'test-engine';
1711 }
1712
1713 @override
1714 bool get usesLocalArtifacts => false;
1715
1716 @override
1717 FileSystemEntity getHostArtifact(HostArtifact artifact) {
1718 return fileSystem.file(artifact.toString());
1719 }
1720}
1721
1722class _TestLocalEngine extends _TestArtifacts {
1723 _TestLocalEngine(String engineOutPath, String engineHostOutPath, super.fileSystem)
1724 : localEngineInfo = LocalEngineInfo(
1725 targetOutPath: engineOutPath,
1726 hostOutPath: engineHostOutPath,
1727 );
1728
1729 @override
1730 bool get usesLocalArtifacts => true;
1731
1732 @override
1733 final LocalEngineInfo localEngineInfo;
1734}
1735
1736String _getFileGeneratorsPath() {
1737 final String flutterRoot = Cache.defaultFlutterRoot(
1738 fileSystem: globals.localFileSystem,
1739 platform: const LocalPlatform(),
1740 userMessages: UserMessages(),
1741 );
1742 return globals.localFileSystem.path.join(
1743 flutterRoot,
1744 'packages',
1745 'flutter_tools',
1746 'lib',
1747 'src',
1748 'web',
1749 'file_generators',
1750 );
1751}
1752