artifacts.dart 12.8 KB
Newer Older
1 2 3 4
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

7 8 9
import 'base/context.dart';
import 'base/file_system.dart';
import 'base/platform.dart';
10
import 'base/process_manager.dart';
11
import 'base/utils.dart';
12
import 'build_info.dart';
13
import 'dart/sdk.dart';
14 15 16 17
import 'globals.dart';

enum Artifact {
  genSnapshot,
18
  flutterTester,
19 20
  snapshotDart,
  flutterFramework,
21
  vmSnapshotData,
22 23 24 25 26
  isolateSnapshotData,
  platformKernelDill,
  platformLibrariesJson,
  flutterPatchedSdkPath,
  frontendServerSnapshotForEngineDartSdk,
27
  engineDartSdkPath,
28
  engineDartBinary,
29 30
}

31
String _artifactToFileName(Artifact artifact, [TargetPlatform platform, BuildMode mode]) {
32 33
  switch (artifact) {
    case Artifact.genSnapshot:
34
      return 'gen_snapshot';
35
    case Artifact.flutterTester:
36 37 38
      if (platform == TargetPlatform.windows_x64) {
        return 'flutter_tester.exe';
      }
39
      return 'flutter_tester';
40 41 42 43
    case Artifact.snapshotDart:
      return 'snapshot.dart';
    case Artifact.flutterFramework:
      return 'Flutter.framework';
44
    case Artifact.vmSnapshotData:
45 46 47 48 49 50 51 52 53
      // Flutter debug and dynamic profile modes for all target platforms use Dart
      // RELEASE VM snapshot that comes from host debug build and has the metadata
      // related to development tools.
      if (mode == BuildMode.dynamicRelease) {
        return 'product_vm_isolate_snapshot.bin';
      }
      // Flutter dynamic release mode for all target platforms uses Dart PRODUCT
      // VM snapshot from host dynamic release build that strips out the metadata
      // related to development tools.
54 55
      return 'vm_isolate_snapshot.bin';
    case Artifact.isolateSnapshotData:
56 57 58
      if (mode == BuildMode.dynamicRelease) {
        return 'product_isolate_snapshot.bin';
      }
59
      return 'isolate_snapshot.bin';
60
    case Artifact.platformKernelDill:
61
      return 'platform_strong.dill';
62 63 64 65 66
    case Artifact.platformLibrariesJson:
      return 'libraries.json';
    case Artifact.flutterPatchedSdkPath:
      assert(false, 'No filename for sdk path, should not be invoked');
      return null;
67 68
    case Artifact.engineDartSdkPath:
      return 'dart-sdk';
69 70
    case Artifact.frontendServerSnapshotForEngineDartSdk:
      return 'frontend_server.dart.snapshot';
71 72
    case Artifact.engineDartBinary:
      return 'dart';
73 74 75 76 77
  }
  assert(false, 'Invalid artifact $artifact.');
  return null;
}

78 79 80 81 82 83 84 85 86
class EngineBuildPaths {
  const EngineBuildPaths({ @required this.targetEngine, @required this.hostEngine }):
      assert(targetEngine != null),
      assert(hostEngine != null);

  final String targetEngine;
  final String hostEngine;
}

87 88 89 90
// Manages the engine artifacts of Flutter.
abstract class Artifacts {
  static Artifacts get instance => context[Artifacts];

91
  static LocalEngineArtifacts getLocalEngine(String engineSrcPath, EngineBuildPaths engineBuildPaths) {
92
    return LocalEngineArtifacts(engineSrcPath, engineBuildPaths.targetEngine, engineBuildPaths.hostEngine);
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
  }

  // Returns the requested [artifact] for the [platform] and [mode] combination.
  String getArtifactPath(Artifact artifact, [TargetPlatform platform, BuildMode mode]);

  // Returns which set of engine artifacts is currently used for the [platform]
  // and [mode] combination.
  String getEngineType(TargetPlatform platform, [BuildMode mode]);
}

/// Manages the engine artifacts downloaded to the local cache.
class CachedArtifacts extends Artifacts {

  @override
  String getArtifactPath(Artifact artifact, [TargetPlatform platform, BuildMode mode]) {
    platform ??= _currentHostPlatform;
    switch (platform) {
      case TargetPlatform.android_arm:
111
      case TargetPlatform.android_arm64:
112 113 114 115 116 117 118
      case TargetPlatform.android_x64:
      case TargetPlatform.android_x86:
        return _getAndroidArtifactPath(artifact, platform, mode);
      case TargetPlatform.ios:
        return _getIosArtifactPath(artifact, platform, mode);
      case TargetPlatform.darwin_x64:
      case TargetPlatform.linux_x64:
119
      case TargetPlatform.windows_x64:
120
      case TargetPlatform.fuchsia:
121
      case TargetPlatform.tester:
122
        return _getHostArtifactPath(artifact, platform, mode);
123 124 125 126 127 128
    }
    assert(false, 'Invalid platform $platform.');
    return null;
  }

  @override
129
  String getEngineType(TargetPlatform platform, [BuildMode mode]) {
130 131 132 133
    return fs.path.basename(_getEngineArtifactsPath(platform, mode));
  }

  String _getAndroidArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
134
    final String engineDir = _getEngineArtifactsPath(platform, mode);
135
    switch (artifact) {
136
      case Artifact.frontendServerSnapshotForEngineDartSdk:
137 138 139 140
        assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.');
        return fs.path.join(engineDir, _artifactToFileName(artifact));
      case Artifact.genSnapshot:
        assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.');
141
        final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform());
142 143 144 145 146 147 148 149
        return fs.path.join(engineDir, hostPlatform, _artifactToFileName(artifact));
      default:
        assert(false, 'Artifact $artifact not available for platform $platform.');
        return null;
    }
  }

  String _getIosArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
150
    final String engineDir = _getEngineArtifactsPath(platform, mode);
151 152 153 154
    switch (artifact) {
      case Artifact.genSnapshot:
      case Artifact.snapshotDart:
      case Artifact.flutterFramework:
155
      case Artifact.frontendServerSnapshotForEngineDartSdk:
156 157 158 159 160 161 162
        return fs.path.join(engineDir, _artifactToFileName(artifact));
      default:
        assert(false, 'Artifact $artifact not available for platform $platform.');
        return null;
    }
  }

163 164 165 166 167
  String _getFlutterPatchedSdkPath() {
    final String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
    return fs.path.join(engineArtifactsPath, 'common', 'flutter_patched_sdk');
  }

168
  String _getHostArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
169
    switch (artifact) {
170 171 172 173
      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);
174
      case Artifact.flutterTester:
175 176
      case Artifact.vmSnapshotData:
      case Artifact.isolateSnapshotData:
177
      case Artifact.frontendServerSnapshotForEngineDartSdk:
178 179
        final String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
        final String platformDirName = getNameForTargetPlatform(platform);
180
        return fs.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, platform, mode));
181 182
      case Artifact.engineDartSdkPath:
        return dartSdkPath;
183 184
      case Artifact.engineDartBinary:
        return fs.path.join(dartSdkPath,'bin', _artifactToFileName(artifact));
185 186 187 188 189 190
      case Artifact.platformKernelDill:
        return fs.path.join(_getFlutterPatchedSdkPath(), _artifactToFileName(artifact));
      case Artifact.platformLibrariesJson:
        return fs.path.join(_getFlutterPatchedSdkPath(), 'lib', _artifactToFileName(artifact));
      case Artifact.flutterPatchedSdkPath:
        return _getFlutterPatchedSdkPath();
191 192 193 194 195 196 197
      default:
        assert(false, 'Artifact $artifact not available for platform $platform.');
        return null;
    }
  }

  String _getEngineArtifactsPath(TargetPlatform platform, [BuildMode mode]) {
198 199
    final String engineDir = cache.getArtifactDirectory('engine').path;
    final String platformName = getNameForTargetPlatform(platform);
200 201 202
    switch (platform) {
      case TargetPlatform.linux_x64:
      case TargetPlatform.darwin_x64:
203
      case TargetPlatform.windows_x64:
204
      case TargetPlatform.fuchsia:
205
      case TargetPlatform.tester:
206 207 208 209
        assert(mode == null, 'Platform $platform does not support different build modes.');
        return fs.path.join(engineDir, platformName);
      case TargetPlatform.ios:
      case TargetPlatform.android_arm:
210
      case TargetPlatform.android_arm64:
211 212 213
      case TargetPlatform.android_x64:
      case TargetPlatform.android_x86:
        assert(mode != null, 'Need to specify a build mode for platform $platform.');
214
        final String suffix = mode != BuildMode.debug ? '-${snakeCase(getModeName(mode), '-')}' : '';
215 216 217 218 219 220 221 222 223 224 225
        return fs.path.join(engineDir, platformName + suffix);
    }
    assert(false, 'Invalid platform $platform.');
    return null;
  }

  TargetPlatform get _currentHostPlatform {
    if (platform.isMacOS)
      return TargetPlatform.darwin_x64;
    if (platform.isLinux)
      return TargetPlatform.linux_x64;
226 227
    if (platform.isWindows)
      return TargetPlatform.windows_x64;
228
    throw UnimplementedError('Host OS not supported.');
229 230 231 232 233
  }
}

/// Manages the artifacts of a locally built engine.
class LocalEngineArtifacts extends Artifacts {
234 235
  LocalEngineArtifacts(this._engineSrcPath, this.engineOutPath, this._hostEngineOutPath);

236 237
  final String _engineSrcPath;
  final String engineOutPath; // TODO(goderbauer): This should be private.
238
  String _hostEngineOutPath;
239 240 241 242 243 244 245

  @override
  String getArtifactPath(Artifact artifact, [TargetPlatform platform, BuildMode mode]) {
    switch (artifact) {
      case Artifact.snapshotDart:
        return fs.path.join(_engineSrcPath, 'flutter', 'lib', 'snapshot', _artifactToFileName(artifact));
      case Artifact.genSnapshot:
246
        return _genSnapshotPath();
247 248
      case Artifact.flutterTester:
        return _flutterTesterPath(platform);
249 250 251
      case Artifact.isolateSnapshotData:
      case Artifact.vmSnapshotData:
        return fs.path.join(engineOutPath, 'gen', 'flutter', 'lib', 'snapshot', _artifactToFileName(artifact));
252 253 254 255
      case Artifact.platformKernelDill:
        return fs.path.join(_getFlutterPatchedSdkPath(), _artifactToFileName(artifact));
      case Artifact.platformLibrariesJson:
        return fs.path.join(_getFlutterPatchedSdkPath(), 'lib', _artifactToFileName(artifact));
256 257
      case Artifact.flutterFramework:
        return fs.path.join(engineOutPath, _artifactToFileName(artifact));
258 259 260 261
      case Artifact.flutterPatchedSdkPath:
        return _getFlutterPatchedSdkPath();
      case Artifact.frontendServerSnapshotForEngineDartSdk:
        return fs.path.join(_hostEngineOutPath, 'gen', _artifactToFileName(artifact));
262 263
      case Artifact.engineDartSdkPath:
        return fs.path.join(_hostEngineOutPath, 'dart-sdk');
264 265
      case Artifact.engineDartBinary:
        return fs.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', _artifactToFileName(artifact));
266 267 268 269 270 271 272 273 274 275
    }
    assert(false, 'Invalid artifact $artifact.');
    return null;
  }

  @override
  String getEngineType(TargetPlatform platform, [BuildMode mode]) {
    return fs.path.basename(engineOutPath);
  }

276 277 278 279
  String _getFlutterPatchedSdkPath() {
    return fs.path.join(engineOutPath, 'flutter_patched_sdk');
  }

280
  String _genSnapshotPath() {
281
    const List<String> clangDirs = <String>['.', 'clang_x86', 'clang_x64', 'clang_i386'];
282 283 284
    final String genSnapshotName = _artifactToFileName(Artifact.genSnapshot);
    for (String clangDir in clangDirs) {
      final String genSnapshotPath = fs.path.join(engineOutPath, clangDir, genSnapshotName);
285
      if (processManager.canRun(genSnapshotPath))
286
        return genSnapshotPath;
287
    }
288
    throw Exception('Unable to find $genSnapshotName');
289 290
  }

291
  String _flutterTesterPath(TargetPlatform platform) {
292
    if (getCurrentHostPlatform() == HostPlatform.linux_x64) {
293
      return fs.path.join(engineOutPath, _artifactToFileName(Artifact.flutterTester));
294
    } else if (getCurrentHostPlatform() == HostPlatform.darwin_x64) {
295
      return fs.path.join(engineOutPath, 'flutter_tester');
296 297
    } else if (getCurrentHostPlatform() == HostPlatform.windows_x64) {
      return fs.path.join(engineOutPath, 'flutter_tester.exe');
298
    }
299
    throw Exception('Unsupported platform $platform.');
300 301
  }
}
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

/// An implementation of [Artifacts] that provides individual overrides.
///
/// If an artifact is not provided, the lookup delegates to the parent.
/// Currently only allows overriding the location of the [frontendServer].
class OverrideArtifacts implements Artifacts {
  /// Creates a new [OverrideArtifacts].
  ///
  /// [parent] must be provided.
  OverrideArtifacts({
    @required this.parent,
    this.frontendServer,
  }) : assert(parent != null);

  final Artifacts parent;
  final File frontendServer;

  @override
  String getArtifactPath(Artifact artifact, [TargetPlatform platform, BuildMode mode]) {
    if (artifact == Artifact.frontendServerSnapshotForEngineDartSdk && frontendServer != null) {
      return frontendServer.path;
    }
    return parent.getArtifactPath(artifact, platform, mode);
  }

  @override
  String getEngineType(TargetPlatform platform, [BuildMode mode]) => parent.getEngineType(platform, mode);
}