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

5
import 'package:file/memory.dart';
6
import 'package:meta/meta.dart';
7
import 'package:process/process.dart';
8

9
import 'base/common.dart';
10
import 'base/file_system.dart';
11
import 'base/os.dart';
12
import 'base/platform.dart';
13
import 'base/utils.dart';
14
import 'build_info.dart';
15
import 'cache.dart';
16
import 'globals_null_migrated.dart' as globals;
17 18

enum Artifact {
19
  /// The tool which compiles a dart kernel file into native code.
20
  genSnapshot,
21
  /// The flutter tester binary.
22
  flutterTester,
23
  flutterFramework,
24
  flutterXcframework,
25
  /// The framework directory of the macOS desktop.
26
  flutterMacOSFramework,
27
  vmSnapshotData,
28
  isolateSnapshotData,
29
  icuData,
30 31 32 33
  platformKernelDill,
  platformLibrariesJson,
  flutterPatchedSdkPath,
  frontendServerSnapshotForEngineDartSdk,
34 35 36 37 38 39
  /// 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,
40
  /// The root of the cpp client code for Windows desktop.
41
  windowsCppClientWrapper,
42 43
  /// The root of the cpp client code for Windows UWP desktop.
  windowsUwpCppClientWrapper,
44 45 46 47 48 49 50 51 52 53 54 55 56 57
  /// The root of the Windows UWP desktop sources.
  windowsUwpDesktopPath,
  /// The root of the sky_engine package.
  skyEnginePath,
  /// The location of the macOS engine podspec file.
  flutterMacOSPodspec,

  // Fuchsia artifacts from the engine prebuilts.
  fuchsiaKernelCompiler,
  fuchsiaFlutterRunner,

  /// Tools related to subsetting or icon font files.
  fontSubset,
  constFinder,
58 59 60

  // Windows UWP app management tool.
  uwptool,
61 62 63 64
}

/// A subset of [Artifact]s that are platform and build mode independent
enum HostArtifact {
65
  /// The root directory of the dart SDK.
66
  engineDartSdkPath,
67
  /// The dart binary used to execute any of the required snapshots.
68
  engineDartBinary,
69
  /// The dart snapshot of the dart2js compiler.
70
  dart2jsSnapshot,
71
  /// The dart snapshot of the dartdev compiler.
72
  dartdevcSnapshot,
73
  /// The dart snapshot of the kernel worker compiler.
74
  kernelWorkerSnapshot,
75
  /// The root of the web implementation of the dart SDK.
76
  flutterWebSdk,
77
  /// The libraries JSON file for web release builds.
78
  flutterWebLibrariesJson,
79 80
  /// The summary dill for the dartdevc target.
  webPlatformKernelDill,
81 82
  /// The summary dill with null safety enabled for the dartdevc target.
  webPlatformSoundKernelDill,
83

84 85 86 87 88
  /// The precompiled SDKs and sourcemaps for web debug builds.
  webPrecompiledSdk,
  webPrecompiledSdkSourcemaps,
  webPrecompiledCanvaskitSdk,
  webPrecompiledCanvaskitSdkSourcemaps,
89 90
  webPrecompiledCanvaskitAndHtmlSdk,
  webPrecompiledCanvaskitAndHtmlSdkSourcemaps,
91 92 93 94
  webPrecompiledSoundSdk,
  webPrecompiledSoundSdkSourcemaps,
  webPrecompiledCanvaskitSoundSdk,
  webPrecompiledCanvaskitSoundSdkSourcemaps,
95 96
  webPrecompiledCanvaskitAndHtmlSoundSdk,
  webPrecompiledCanvaskitAndHtmlSoundSdkSourcemaps,
97

98 99 100 101
  iosDeploy,
  idevicesyslog,
  idevicescreenshot,
  iproxy,
102
  /// The root of the sky_engine package.
103
  skyEnginePath,
104 105
}

106 107 108 109 110 111 112 113
// 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);
}

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
// 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.windows_uwp_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;
  }
}

bool _isWindows(TargetPlatform? platform) {
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
  switch (platform) {
    case TargetPlatform.windows_x64:
    case TargetPlatform.windows_uwp_x64:
      return true;
    case TargetPlatform.android:
    case TargetPlatform.android_arm:
    case TargetPlatform.android_arm64:
    case TargetPlatform.android_x64:
    case TargetPlatform.android_x86:
    case TargetPlatform.darwin:
    case TargetPlatform.fuchsia_arm64:
    case TargetPlatform.fuchsia_x64:
    case TargetPlatform.ios:
    case TargetPlatform.linux_arm64:
    case TargetPlatform.linux_x64:
    case TargetPlatform.tester:
    case TargetPlatform.web_javascript:
156
    case null:
157 158 159 160
      return false;
  }
}

161
String? _artifactToFileName(Artifact artifact, [ TargetPlatform? platform, BuildMode? mode ]) {
162
  final String exe = _isWindows(platform) ? '.exe' : '';
163 164
  switch (artifact) {
    case Artifact.genSnapshot:
165
      return 'gen_snapshot';
166
    case Artifact.flutterTester:
167
      return 'flutter_tester$exe';
168 169
    case Artifact.flutterFramework:
      return 'Flutter.framework';
170 171
    case Artifact.flutterXcframework:
      return 'Flutter.xcframework';
172 173
    case Artifact.flutterMacOSFramework:
      return 'FlutterMacOS.framework';
174 175 176 177
    case Artifact.vmSnapshotData:
      return 'vm_isolate_snapshot.bin';
    case Artifact.isolateSnapshotData:
      return 'isolate_snapshot.bin';
178 179
    case Artifact.icuData:
      return 'icudtl.dat';
180
    case Artifact.platformKernelDill:
181
      return 'platform_strong.dill';
182 183 184 185 186 187 188
    case Artifact.platformLibrariesJson:
      return 'libraries.json';
    case Artifact.flutterPatchedSdkPath:
      assert(false, 'No filename for sdk path, should not be invoked');
      return null;
    case Artifact.frontendServerSnapshotForEngineDartSdk:
      return 'frontend_server.dart.snapshot';
189 190
    case Artifact.linuxDesktopPath:
      return '';
191 192
    case Artifact.linuxHeaders:
      return 'flutter_linux';
193
    case Artifact.windowsCppClientWrapper:
194
    case Artifact.windowsUwpCppClientWrapper:
195
      return 'cpp_client_wrapper';
196 197 198
    case Artifact.windowsUwpDesktopPath:
    case Artifact.windowsDesktopPath:
      return '';
199 200
    case Artifact.skyEnginePath:
      return 'sky_engine';
201 202
    case Artifact.flutterMacOSPodspec:
      return 'FlutterMacOS.podspec';
203 204
    case Artifact.fuchsiaKernelCompiler:
      return 'kernel_compiler.snapshot';
205
    case Artifact.fuchsiaFlutterRunner:
206
      final String jitOrAot = mode!.isJit ? '_jit' : '_aot';
207 208
      final String productOrNo = mode.isRelease ? '_product' : '';
      return 'flutter$jitOrAot${productOrNo}_runner-0.far';
209 210 211 212
    case Artifact.fontSubset:
      return 'font-subset$exe';
    case Artifact.constFinder:
      return 'const_finder.dart.snapshot';
213 214
    case Artifact.uwptool:
      return 'uwptool$exe';
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
  }
}

String _hostArtifactToFileName(HostArtifact artifact, bool windows) {
  final String exe = windows ? '.exe' : '';
  switch (artifact) {
    case HostArtifact.flutterWebSdk:
      return '';
    case HostArtifact.engineDartSdkPath:
      return 'dart-sdk';
    case HostArtifact.engineDartBinary:
      return 'dart$exe';
    case HostArtifact.dart2jsSnapshot:
      return 'dart2js.dart.snapshot';
    case HostArtifact.dartdevcSnapshot:
      return 'dartdevc.dart.snapshot';
    case HostArtifact.kernelWorkerSnapshot:
      return 'kernel_worker.dart.snapshot';
    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.webPlatformKernelDill:
      return 'flutter_ddc_sdk.dill';
    case HostArtifact.webPlatformSoundKernelDill:
      return 'flutter_ddc_sdk_sound.dill';
    case HostArtifact.flutterWebLibrariesJson:
248
      return 'libraries.json';
249 250 251 252 253 254
    case HostArtifact.webPrecompiledSdk:
    case HostArtifact.webPrecompiledCanvaskitSdk:
    case HostArtifact.webPrecompiledCanvaskitAndHtmlSdk:
    case HostArtifact.webPrecompiledSoundSdk:
    case HostArtifact.webPrecompiledCanvaskitSoundSdk:
    case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdk:
255
      return 'dart_sdk.js';
256 257 258 259 260 261
    case HostArtifact.webPrecompiledSdkSourcemaps:
    case HostArtifact.webPrecompiledCanvaskitSdkSourcemaps:
    case HostArtifact.webPrecompiledCanvaskitAndHtmlSdkSourcemaps:
    case HostArtifact.webPrecompiledSoundSdkSourcemaps:
    case HostArtifact.webPrecompiledCanvaskitSoundSdkSourcemaps:
    case HostArtifact.webPrecompiledCanvaskitAndHtmlSoundSdkSourcemaps:
262
      return 'dart_sdk.js.map';
263 264 265
  }
}

266
class EngineBuildPaths {
267
  const EngineBuildPaths({
268 269
    required this.targetEngine,
    required this.hostEngine,
270 271
  }) : assert(targetEngine != null),
       assert(hostEngine != null);
272 273 274 275 276

  final String targetEngine;
  final String hostEngine;
}

277 278
// Manages the engine artifacts of Flutter.
abstract class Artifacts {
279 280
  /// A test-specific implementation of artifacts that returns stable paths for
  /// all artifacts.
281
  ///
282 283
  /// If a [fileSystem] is not provided, creates a new [MemoryFileSystem] instance.
  ///
284
  /// Creates a [LocalEngineArtifacts] if `localEngine` is non-null
285
  @visibleForTesting
286
  factory Artifacts.test({String? localEngine, FileSystem? fileSystem}) {
287
    fileSystem ??= MemoryFileSystem.test();
288
    if (localEngine != null) {
289
      return _TestLocalEngine(localEngine, fileSystem);
290
    }
291
    return _TestArtifacts(fileSystem);
292
  }
293

294
  static LocalEngineArtifacts getLocalEngine(EngineBuildPaths engineBuildPaths) {
295 296 297 298 299 300 301
    return LocalEngineArtifacts(
      engineBuildPaths.targetEngine,
      engineBuildPaths.hostEngine,
      cache: globals.cache,
      fileSystem: globals.fs,
      processManager: globals.processManager,
      platform: globals.platform,
302
      operatingSystemUtils: globals.os,
303
    );
304 305
  }

306 307 308
  /// Returns the requested [artifact] for the [platform], [mode], and [environmentType] combination.
  String getArtifactPath(
    Artifact artifact, {
309 310 311
    TargetPlatform? platform,
    BuildMode? mode,
    EnvironmentType? environmentType,
312
  });
313

314 315 316 317 318 319
  /// Retrieve a host specific artifact that does not depend on the
  /// current build mode or environment.
  FileSystemEntity getHostArtifact(
    HostArtifact artifact,
  );

320 321
  // Returns which set of engine artifacts is currently used for the [platform]
  // and [mode] combination.
322
  String getEngineType(TargetPlatform platform, [ BuildMode? mode ]);
323 324 325

  /// Whether these artifacts correspond to a non-versioned local engine.
  bool get isLocalEngine;
326 327 328
}

/// Manages the engine artifacts downloaded to the local cache.
329
class CachedArtifacts implements Artifacts {
330
  CachedArtifacts({
331 332 333 334
    required FileSystem fileSystem,
    required Platform platform,
    required Cache cache,
    required OperatingSystemUtils operatingSystemUtils,
335 336
  }) : _fileSystem = fileSystem,
       _platform = platform,
337 338
       _cache = cache,
       _operatingSystemUtils = operatingSystemUtils;
339 340 341 342

  final FileSystem _fileSystem;
  final Platform _platform;
  final Cache _cache;
343
  final OperatingSystemUtils _operatingSystemUtils;
344

345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
  @override
  FileSystemEntity getHostArtifact(
    HostArtifact artifact,
  ) {
    switch (artifact) {
      case HostArtifact.engineDartSdkPath:
        final String path = _dartSdkPath(_fileSystem);
        return _fileSystem.directory(path);
      case HostArtifact.engineDartBinary:
        final String path = _fileSystem.path.join(_dartSdkPath(_fileSystem), 'bin', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.flutterWebSdk:
        final String path = _getFlutterWebSdkPath();
        return _fileSystem.directory(path);
      case HostArtifact.flutterWebLibrariesJson:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPlatformKernelDill:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPlatformSoundKernelDill:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledSdk:
      case HostArtifact.webPrecompiledSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledCanvaskitSdk:
      case HostArtifact.webPrecompiledCanvaskitSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledCanvaskitAndHtmlSdk:
      case HostArtifact.webPrecompiledCanvaskitAndHtmlSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-html', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledSoundSdk:
      case HostArtifact.webPrecompiledSoundSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-sound', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledCanvaskitSoundSdk:
      case HostArtifact.webPrecompiledCanvaskitSoundSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-sound', _hostArtifactToFileName(artifact, _platform.isWindows));
        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.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.idevicesyslog:
      case HostArtifact.idevicescreenshot:
        final String artifactFileName = _hostArtifactToFileName(artifact, _platform.isWindows);
        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.isWindows));
        return _fileSystem.directory(path);
      case HostArtifact.dart2jsSnapshot:
      case HostArtifact.dartdevcSnapshot:
      case HostArtifact.kernelWorkerSnapshot:
        final String path = _fileSystem.path.join(_dartSdkPath(_fileSystem), 'bin', 'snapshots', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.iosDeploy:
        final String artifactFileName = _hostArtifactToFileName(artifact, _platform.isWindows);
        return _cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName);
      case HostArtifact.iproxy:
        final String artifactFileName = _hostArtifactToFileName(artifact, _platform.isWindows);
        return _cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName);
    }
  }

414
  @override
415 416
  String getArtifactPath(
    Artifact artifact, {
417 418 419
    TargetPlatform? platform,
    BuildMode? mode,
    EnvironmentType? environmentType,
420
  }) {
421
    platform = _mapTargetPlatform(platform);
422 423
    switch (platform) {
      case TargetPlatform.android_arm:
424
      case TargetPlatform.android_arm64:
425 426
      case TargetPlatform.android_x64:
      case TargetPlatform.android_x86:
427
        return _getAndroidArtifactPath(artifact, platform!, mode!);
428
      case TargetPlatform.ios:
429
        return _getIosArtifactPath(artifact, platform!, mode, environmentType);
430
      case TargetPlatform.darwin:
431
      case TargetPlatform.linux_x64:
432
      case TargetPlatform.linux_arm64:
433
      case TargetPlatform.windows_x64:
434
      case TargetPlatform.windows_uwp_x64:
435
        return _getDesktopArtifactPath(artifact, platform, mode);
436 437
      case TargetPlatform.fuchsia_arm64:
      case TargetPlatform.fuchsia_x64:
438
        return _getFuchsiaArtifactPath(artifact, platform!, mode!);
439
      case TargetPlatform.tester:
440
      case TargetPlatform.web_javascript:
441
      default: // could be null, but that can't be specified as a case.
442
        return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform(_platform, _operatingSystemUtils), mode);
443 444 445 446
    }
  }

  @override
447 448
  String getEngineType(TargetPlatform platform, [ BuildMode? mode ]) {
    return _fileSystem.path.basename(_getEngineArtifactsPath(platform, mode)!);
449 450
  }

451
  String _getDesktopArtifactPath(Artifact artifact, TargetPlatform? platform, BuildMode? mode) {
452 453 454
    // 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) {
455
      final String engineDir = _getEngineArtifactsPath(platform, mode)!;
456
      return _fileSystem.path.join(engineDir, _artifactToFileName(artifact));
457
    }
458
    return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform(_platform, _operatingSystemUtils), mode);
459 460
  }

461
  String _getAndroidArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
462
    final String engineDir = _getEngineArtifactsPath(platform, mode)!;
463
    switch (artifact) {
464
      case Artifact.frontendServerSnapshotForEngineDartSdk:
465
        assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.');
466
        return _fileSystem.path.join(engineDir, _artifactToFileName(artifact));
467 468
      case Artifact.genSnapshot:
        assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.');
469
        final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform());
470
        return _fileSystem.path.join(engineDir, hostPlatform, _artifactToFileName(artifact));
471
      default:
472
        return _getHostArtifactPath(artifact, platform, mode);
473 474 475
    }
  }

476
  String _getIosArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode? mode, EnvironmentType? environmentType) {
477 478
    switch (artifact) {
      case Artifact.genSnapshot:
479
      case Artifact.flutterXcframework:
480
      case Artifact.frontendServerSnapshotForEngineDartSdk:
481 482
        final String artifactFileName = _artifactToFileName(artifact)!;
        final String engineDir = _getEngineArtifactsPath(platform, mode)!;
483
        return _fileSystem.path.join(engineDir, artifactFileName);
484
      case Artifact.flutterFramework:
485
        final String engineDir = _getEngineArtifactsPath(platform, mode)!;
486
        return _getIosEngineArtifactPath(engineDir, environmentType, _fileSystem);
487
      default:
488
        return _getHostArtifactPath(artifact, platform, mode);
489 490 491
    }
  }

492
  String _getFuchsiaArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
493 494
    final String root = _fileSystem.path.join(
      _cache.getArtifactDirectory('flutter_runner').path,
495 496
      'flutter',
      fuchsiaArchForTargetPlatform(platform),
497
      mode.isRelease ? 'release' : mode.toString(),
498
    );
499
    final String runtime = mode.isJit ? 'jit' : 'aot';
500
    switch (artifact) {
501 502
      case Artifact.genSnapshot:
        final String genSnapshot = mode.isRelease ? 'gen_snapshot_product' : 'gen_snapshot';
503
        return _fileSystem.path.join(root, runtime, 'dart_binaries', genSnapshot);
504 505
      case Artifact.flutterPatchedSdkPath:
        const String artifactFileName = 'flutter_runner_patched_sdk';
506
        return _fileSystem.path.join(root, runtime, artifactFileName);
507
      case Artifact.platformKernelDill:
508
        final String artifactFileName = _artifactToFileName(artifact, platform, mode)!;
509
        return _fileSystem.path.join(root, runtime, 'flutter_runner_patched_sdk', artifactFileName);
510
      case Artifact.fuchsiaKernelCompiler:
511
        final String artifactFileName = _artifactToFileName(artifact, platform, mode)!;
512
        return _fileSystem.path.join(root, runtime, 'dart_binaries', artifactFileName);
513
      case Artifact.fuchsiaFlutterRunner:
514
        final String artifactFileName = _artifactToFileName(artifact, platform, mode)!;
515
        return _fileSystem.path.join(root, runtime, artifactFileName);
516
      default:
517
        return _getHostArtifactPath(artifact, platform, mode);
518 519 520
    }
  }

521
  String _getFlutterPatchedSdkPath(BuildMode? mode) {
522 523
    final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
    return _fileSystem.path.join(engineArtifactsPath, 'common',
524
        mode == BuildMode.release ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk');
525 526
  }

527
  String _getFlutterWebSdkPath() {
528
    return _cache.getWebSdkDirectory().path;
529 530
  }

531
  String _getHostArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode? mode) {
532
    assert(platform != null);
533
    switch (artifact) {
534 535 536 537
      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);
538
      case Artifact.flutterTester:
539 540
      case Artifact.vmSnapshotData:
      case Artifact.isolateSnapshotData:
541
      case Artifact.frontendServerSnapshotForEngineDartSdk:
542
      case Artifact.icuData:
543
        final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
544
        final String platformDirName = _enginePlatformDirectoryName(platform);
545
        return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, platform, mode));
546
      case Artifact.platformKernelDill:
547
        return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), _artifactToFileName(artifact));
548
      case Artifact.platformLibrariesJson:
549
        return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', _artifactToFileName(artifact));
550
      case Artifact.flutterPatchedSdkPath:
551
        return _getFlutterPatchedSdkPath(mode);
552
      case Artifact.flutterMacOSFramework:
553 554
      case Artifact.linuxDesktopPath:
      case Artifact.windowsDesktopPath:
555
      case Artifact.flutterMacOSPodspec:
556
      case Artifact.linuxHeaders:
557
        // TODO(zanderso): remove once debug desktop artifacts are uploaded
558 559
        // under a separate directory from the host artifacts.
        // https://github.com/flutter/flutter/issues/38935
560
        String platformDirName = _enginePlatformDirectoryName(platform);
561
        if (mode == BuildMode.profile || mode == BuildMode.release) {
562
          platformDirName = '$platformDirName-${getNameForBuildMode(mode!)}';
563
        }
564 565
        final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
        return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, platform, mode));
566 567
      case Artifact.windowsUwpDesktopPath:
        final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
568
        return _fileSystem.path.join(engineArtifactsPath, 'windows-uwp-x64-${getNameForBuildMode(mode!)}', _artifactToFileName(artifact, platform, mode));
569 570 571
      case Artifact.windowsCppClientWrapper:
        final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
        return _fileSystem.path.join(engineArtifactsPath, 'windows-x64', _artifactToFileName(artifact, platform, mode));
572 573 574
      case Artifact.windowsUwpCppClientWrapper:
        final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
        return _fileSystem.path.join(engineArtifactsPath, 'windows-uwp-x64-debug', _artifactToFileName(artifact, platform, mode));
575
      case Artifact.skyEnginePath:
576 577
        final Directory dartPackageDirectory = _cache.getCacheDir('pkg');
        return _fileSystem.path.join(dartPackageDirectory.path,  _artifactToFileName(artifact));
578 579
      case Artifact.fontSubset:
      case Artifact.constFinder:
580
        return _cache.getArtifactDirectory('engine')
581
                     .childDirectory(_enginePlatformDirectoryName(platform))
582
                     .childFile(_artifactToFileName(artifact, platform, mode)!)
583
                     .path;
584 585 586
      case Artifact.uwptool:
        return _cache.getArtifactDirectory('engine')
                     .childDirectory('windows-uwp-x64-${getNameForBuildMode(mode ?? BuildMode.debug)}')
587
                     .childFile(_artifactToFileName(artifact, platform, mode)!)
588
                     .path;
589
      default:
590
        throw StateError('Artifact $artifact not available for platform $platform.');
591 592 593
    }
  }

594
  String? _getEngineArtifactsPath(TargetPlatform platform, [ BuildMode? mode ]) {
595
    final String engineDir = _cache.getArtifactDirectory('engine').path;
596
    final String platformName = _enginePlatformDirectoryName(platform);
597
    switch (platform) {
598
      case TargetPlatform.linux_x64:
599
      case TargetPlatform.linux_arm64:
600
      case TargetPlatform.darwin:
601
      case TargetPlatform.windows_x64:
602
        // TODO(zanderso): remove once debug desktop artifacts are uploaded
603 604 605
        // under a separate directory from the host artifacts.
        // https://github.com/flutter/flutter/issues/38935
        if (mode == BuildMode.debug || mode == null) {
606
          return _fileSystem.path.join(engineDir, platformName);
607 608
        }
        final String suffix = mode != BuildMode.debug ? '-${snakeCase(getModeName(mode), '-')}' : '';
609
        return _fileSystem.path.join(engineDir, platformName + suffix);
610 611
      case TargetPlatform.fuchsia_arm64:
      case TargetPlatform.fuchsia_x64:
612
      case TargetPlatform.tester:
613
      case TargetPlatform.web_javascript:
614
        assert(mode == null, 'Platform $platform does not support different build modes.');
615
        return _fileSystem.path.join(engineDir, platformName);
616 617
      case TargetPlatform.ios:
      case TargetPlatform.android_arm:
618
      case TargetPlatform.android_arm64:
619 620
      case TargetPlatform.android_x64:
      case TargetPlatform.android_x86:
621
      case TargetPlatform.windows_uwp_x64:
622
        assert(mode != null, 'Need to specify a build mode for platform $platform.');
623
        final String suffix = mode != BuildMode.debug ? '-${snakeCase(getModeName(mode!), '-')}' : '';
624
        return _fileSystem.path.join(engineDir, platformName + suffix);
625 626 627
      case TargetPlatform.android:
        assert(false, 'cannot use TargetPlatform.android to look up artifacts');
        return null;
628 629
    }
  }
630 631 632

  @override
  bool get isLocalEngine => false;
633 634
}

635
TargetPlatform _currentHostPlatform(Platform platform, OperatingSystemUtils operatingSystemUtils) {
636
  if (platform.isMacOS) {
637
    return TargetPlatform.darwin;
638 639
  }
  if (platform.isLinux) {
640 641
    return operatingSystemUtils.hostPlatform == HostPlatform.linux_x64 ?
             TargetPlatform.linux_x64 : TargetPlatform.linux_arm64;
642 643
  }
  if (platform.isWindows) {
644
    return TargetPlatform.windows_x64;
645 646 647 648
  }
  throw UnimplementedError('Host OS not supported.');
}

649
String _getIosEngineArtifactPath(String engineDirectory,
650
    EnvironmentType? environmentType, FileSystem fileSystem) {
651 652
  final Directory xcframeworkDirectory = fileSystem
      .directory(engineDirectory)
653
      .childDirectory(_artifactToFileName(Artifact.flutterXcframework)!);
654 655

  if (!xcframeworkDirectory.existsSync()) {
656
    throwToolExit('No xcframework found at ${xcframeworkDirectory.path}. Try running "flutter precache --ios".');
657
  }
658
  Directory? flutterFrameworkSource;
659 660 661 662 663
  for (final Directory platformDirectory
      in xcframeworkDirectory.listSync().whereType<Directory>()) {
    if (!platformDirectory.basename.startsWith('ios-')) {
      continue;
    }
664 665
    // ios-x86_64-simulator, ios-arm64_x86_64-simulator, ios-armv7_arm64 (Xcode 11), or ios-arm64_armv7 (Xcode 12).
    final bool simulatorDirectory = platformDirectory.basename.endsWith('-simulator');
666 667 668 669 670 671 672 673 674 675
    if ((environmentType == EnvironmentType.simulator && simulatorDirectory) ||
        (environmentType == EnvironmentType.physical && !simulatorDirectory)) {
      flutterFrameworkSource = platformDirectory;
    }
  }
  if (flutterFrameworkSource == null) {
    throwToolExit('No iOS frameworks found in ${xcframeworkDirectory.path}');
  }

  return flutterFrameworkSource
676
      .childDirectory(_artifactToFileName(Artifact.flutterFramework)!)
677 678 679
      .path;
}

680 681
abstract class LocalEngineArtifacts implements Artifacts {
  factory LocalEngineArtifacts(String engineOutPath, String hostEngineOutPath, {
682 683 684 685 686
    required FileSystem fileSystem,
    required Cache cache,
    required ProcessManager processManager,
    required Platform platform,
    required OperatingSystemUtils operatingSystemUtils,
687 688 689 690 691
  }) = CachedLocalEngineArtifacts;

  String get engineOutPath;
}

692
/// Manages the artifacts of a locally built engine.
693 694
class CachedLocalEngineArtifacts implements LocalEngineArtifacts {
  CachedLocalEngineArtifacts(
695 696
    this.engineOutPath,
    this._hostEngineOutPath, {
697 698 699 700 701
    required FileSystem fileSystem,
    required Cache cache,
    required ProcessManager processManager,
    required Platform platform,
    required OperatingSystemUtils operatingSystemUtils,
702 703 704
  }) : _fileSystem = fileSystem,
       _cache = cache,
       _processManager = processManager,
705 706
       _platform = platform,
       _operatingSystemUtils = operatingSystemUtils;
707

708 709 710
  @override
  final String engineOutPath;

711
  final String _hostEngineOutPath;
712 713 714 715
  final FileSystem _fileSystem;
  final Cache _cache;
  final ProcessManager _processManager;
  final Platform _platform;
716
  final OperatingSystemUtils _operatingSystemUtils;
717

718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791

  @override
  FileSystemEntity getHostArtifact(
    HostArtifact artifact,
  ) {
    switch (artifact) {
      case HostArtifact.engineDartSdkPath:
        final String path = _fileSystem.path.join(_hostEngineOutPath, 'dart-sdk');
        return _fileSystem.directory(path);
      case HostArtifact.engineDartBinary:
        final String path = _fileSystem.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.dart2jsSnapshot:
        final String path = _fileSystem.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', 'snapshots', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.dartdevcSnapshot:
        final String path = _fileSystem.path.join(_dartSdkPath(_fileSystem), 'bin', 'snapshots', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.kernelWorkerSnapshot:
        final String path = _fileSystem.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', 'snapshots', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.flutterWebSdk:
        final String path = _getFlutterWebSdkPath();
        return _fileSystem.directory(path);
      case HostArtifact.flutterWebLibrariesJson:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPlatformKernelDill:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPlatformSoundKernelDill:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledSdk:
      case HostArtifact.webPrecompiledSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledCanvaskitSdk:
      case HostArtifact.webPrecompiledCanvaskitSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledCanvaskitAndHtmlSdk:
      case HostArtifact.webPrecompiledCanvaskitAndHtmlSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-html', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledSoundSdk:
      case HostArtifact.webPrecompiledSoundSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-sound', _hostArtifactToFileName(artifact, _platform.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.webPrecompiledCanvaskitSoundSdk:
      case HostArtifact.webPrecompiledCanvaskitSoundSdkSourcemaps:
        final String path = _fileSystem.path.join(_getFlutterWebSdkPath(), 'kernel', 'amd-canvaskit-sound', _hostArtifactToFileName(artifact, _platform.isWindows));
        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.isWindows));
        return _fileSystem.file(path);
      case HostArtifact.idevicesyslog:
      case HostArtifact.idevicescreenshot:
        final String artifactFileName = _hostArtifactToFileName(artifact, _platform.isWindows);
        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.isWindows));
        return _fileSystem.directory(path);
      case HostArtifact.iosDeploy:
        final String artifactFileName = _hostArtifactToFileName(artifact, _platform.isWindows);
        return _cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName);
      case HostArtifact.iproxy:
        final String artifactFileName = _hostArtifactToFileName(artifact, _platform.isWindows);
        return _cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName);
    }
  }

792
  @override
793 794
  String getArtifactPath(
    Artifact artifact, {
795 796 797
    TargetPlatform? platform,
    BuildMode? mode,
    EnvironmentType? environmentType,
798
  }) {
799
    platform ??= _currentHostPlatform(_platform, _operatingSystemUtils);
800
    platform = _mapTargetPlatform(platform);
801
    final bool isDirectoryArtifact = artifact == Artifact.flutterPatchedSdkPath;
802
    final String? artifactFileName = isDirectoryArtifact ? null : _artifactToFileName(artifact, platform, mode);
803 804
    switch (artifact) {
      case Artifact.genSnapshot:
805
        return _genSnapshotPath();
806
      case Artifact.flutterTester:
807
        return _flutterTesterPath(platform!);
808 809
      case Artifact.isolateSnapshotData:
      case Artifact.vmSnapshotData:
810
        return _fileSystem.path.join(engineOutPath, 'gen', 'flutter', 'lib', 'snapshot', artifactFileName);
811
      case Artifact.icuData:
812 813
      case Artifact.flutterXcframework:
      case Artifact.flutterMacOSFramework:
814
        return _fileSystem.path.join(engineOutPath, artifactFileName);
815
      case Artifact.platformKernelDill:
816
        if (platform == TargetPlatform.fuchsia_x64 || platform == TargetPlatform.fuchsia_arm64) {
817
          return _fileSystem.path.join(engineOutPath, 'flutter_runner_patched_sdk', artifactFileName);
818
        }
819
        return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), artifactFileName);
820
      case Artifact.platformLibrariesJson:
821
        return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', artifactFileName);
822
      case Artifact.flutterFramework:
823 824
        return _getIosEngineArtifactPath(
            engineOutPath, environmentType, _fileSystem);
825
      case Artifact.flutterPatchedSdkPath:
826 827 828 829
        // 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.
830
        if (platform == TargetPlatform.fuchsia_x64 || platform == TargetPlatform.fuchsia_arm64) {
831
          return _fileSystem.path.join(engineOutPath, 'flutter_runner_patched_sdk');
832
        }
833
        return _getFlutterPatchedSdkPath(BuildMode.debug);
834
      case Artifact.skyEnginePath:
835
        return _fileSystem.path.join(_hostEngineOutPath, 'gen', 'dart-pkg', artifactFileName);
836
      case Artifact.flutterMacOSPodspec:
837
        return _fileSystem.path.join(_hostEngineOutPath, _artifactToFileName(artifact));
838
      case Artifact.fuchsiaKernelCompiler:
839
        final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform());
840
        final String modeName = mode!.isRelease ? 'release' : mode.toString();
841
        final String dartBinaries = 'dart_binaries-$modeName-$hostPlatform';
842
        return _fileSystem.path.join(engineOutPath, 'host_bundle', dartBinaries, 'kernel_compiler.dart.snapshot');
843
      case Artifact.fuchsiaFlutterRunner:
844
        final String jitOrAot = mode!.isJit ? '_jit' : '_aot';
845
        final String productOrNo = mode.isRelease ? '_product' : '';
846
        return _fileSystem.path.join(engineOutPath, 'flutter$jitOrAot${productOrNo}_runner-0.far');
847 848 849 850
      case Artifact.fontSubset:
        return _fileSystem.path.join(_hostEngineOutPath, artifactFileName);
      case Artifact.constFinder:
        return _fileSystem.path.join(_hostEngineOutPath, 'gen', artifactFileName);
851 852 853 854 855
      case Artifact.windowsUwpDesktopPath:
      case Artifact.linuxDesktopPath:
      case Artifact.linuxHeaders:
      case Artifact.windowsDesktopPath:
      case Artifact.windowsCppClientWrapper:
856
      case Artifact.windowsUwpCppClientWrapper:
857
        return _fileSystem.path.join(_hostEngineOutPath, artifactFileName);
858 859
      case Artifact.frontendServerSnapshotForEngineDartSdk:
        return _fileSystem.path.join(_hostEngineOutPath, 'gen', artifactFileName);
860 861
      case Artifact.uwptool:
        return _fileSystem.path.join(_hostEngineOutPath, artifactFileName);
862 863 864 865
    }
  }

  @override
866
  String getEngineType(TargetPlatform platform, [ BuildMode? mode ]) {
867
    return _fileSystem.path.basename(engineOutPath);
868 869
  }

870
  String _getFlutterPatchedSdkPath(BuildMode? buildMode) {
871
    return _fileSystem.path.join(engineOutPath,
872
        buildMode == BuildMode.release ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk');
873 874
  }

875
  String _getFlutterWebSdkPath() {
876
    return _fileSystem.path.join(engineOutPath, 'flutter_web_sdk');
877 878
  }

879
  String _genSnapshotPath() {
880
    const List<String> clangDirs = <String>['.', 'clang_x64', 'clang_x86', 'clang_i386', 'clang_arm64'];
881
    final String genSnapshotName = _artifactToFileName(Artifact.genSnapshot)!;
882
    for (final String clangDir in clangDirs) {
883 884
      final String genSnapshotPath = _fileSystem.path.join(engineOutPath, clangDir, genSnapshotName);
      if (_processManager.canRun(genSnapshotPath)) {
885
        return genSnapshotPath;
886
      }
887
    }
888
    throw Exception('Unable to find $genSnapshotName');
889 890
  }

891
  String _flutterTesterPath(TargetPlatform platform) {
892
    if (_platform.isLinux) {
893
      return _fileSystem.path.join(engineOutPath, _artifactToFileName(Artifact.flutterTester));
894
    } else if (_platform.isMacOS) {
895
      return _fileSystem.path.join(engineOutPath, 'flutter_tester');
896
    } else if (_platform.isWindows) {
897
      return _fileSystem.path.join(engineOutPath, 'flutter_tester.exe');
898
    }
899
    throw Exception('Unsupported platform $platform.');
900
  }
901 902 903

  @override
  bool get isLocalEngine => true;
904
}
905 906 907 908 909 910 911 912 913

/// 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({
914
    required this.parent,
915
    this.frontendServer,
916
    this.engineDartBinary,
917 918
    this.platformKernelDill,
    this.flutterPatchedSdk,
919 920 921
  }) : assert(parent != null);

  final Artifacts parent;
922 923 924 925
  final File? frontendServer;
  final File? engineDartBinary;
  final File? platformKernelDill;
  final File? flutterPatchedSdk;
926 927

  @override
928 929
  String getArtifactPath(
    Artifact artifact, {
930 931 932
    TargetPlatform? platform,
    BuildMode? mode,
    EnvironmentType? environmentType,
933
  }) {
934
    if (artifact == Artifact.frontendServerSnapshotForEngineDartSdk && frontendServer != null) {
935
      return frontendServer!.path;
936
    }
937
    if (artifact == Artifact.platformKernelDill && platformKernelDill != null) {
938
      return platformKernelDill!.path;
939 940
    }
    if (artifact == Artifact.flutterPatchedSdkPath && flutterPatchedSdk != null) {
941
      return flutterPatchedSdk!.path;
942
    }
943 944 945 946 947 948
    return parent.getArtifactPath(
      artifact,
      platform: platform,
      mode: mode,
      environmentType: environmentType,
    );
949 950 951
  }

  @override
952
  String getEngineType(TargetPlatform platform, [ BuildMode? mode ]) => parent.getEngineType(platform, mode);
953 954 955

  @override
  bool get isLocalEngine => parent.isLocalEngine;
956 957 958 959

  @override
  FileSystemEntity getHostArtifact(HostArtifact artifact) {
    if (artifact == HostArtifact.engineDartBinary && engineDartBinary != null) {
960
      return engineDartBinary!;
961 962 963 964 965
    }
    return parent.getHostArtifact(
      artifact,
    );
  }
966
}
967 968 969

/// Locate the Dart SDK.
String _dartSdkPath(FileSystem fileSystem) {
970
  return fileSystem.path.join(Cache.flutterRoot!, 'bin', 'cache', 'dart-sdk');
971
}
972 973

class _TestArtifacts implements Artifacts {
974 975 976 977
  _TestArtifacts(this.fileSystem);

  final FileSystem fileSystem;

978
  @override
979 980
  String getArtifactPath(
    Artifact artifact, {
981 982 983
    TargetPlatform? platform,
    BuildMode? mode,
    EnvironmentType? environmentType,
984
  }) {
985 986 987 988 989 990 991 992
    final StringBuffer buffer = StringBuffer();
    buffer.write(artifact);
    if (platform != null) {
      buffer.write('.$platform');
    }
    if (mode != null) {
      buffer.write('.$mode');
    }
993 994 995
    if (environmentType != null) {
      buffer.write('.$environmentType');
    }
996 997 998 999
    return buffer.toString();
  }

  @override
1000
  String getEngineType(TargetPlatform platform, [ BuildMode? mode ]) {
1001 1002 1003 1004 1005
    return 'test-engine';
  }

  @override
  bool get isLocalEngine => false;
1006 1007 1008 1009 1010

  @override
  FileSystemEntity getHostArtifact(HostArtifact artifact) {
    return fileSystem.file(artifact.toString());
  }
1011
}
1012 1013

class _TestLocalEngine extends _TestArtifacts implements LocalEngineArtifacts {
1014
  _TestLocalEngine(this.engineOutPath, FileSystem fileSystem) : super(fileSystem);
1015 1016 1017 1018 1019 1020 1021

  @override
  bool get isLocalEngine => true;

  @override
  final String engineOutPath;
}