• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 The Chromium 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:meta/meta.dart';
6
7import 'base/context.dart';
8import 'base/file_system.dart';
9import 'base/platform.dart';
10import 'base/process_manager.dart';
11import 'base/utils.dart';
12import 'build_info.dart';
13import 'dart/sdk.dart';
14import 'globals.dart';
15
16enum Artifact {
17  /// The tool which compiles a dart kernel file into native code.
18  genSnapshot,
19  /// The flutter tester binary.
20  flutterTester,
21  snapshotDart,
22  flutterFramework,
23  /// The framework directory of the macOS desktop.
24  flutterMacOSFramework,
25  vmSnapshotData,
26  isolateSnapshotData,
27  platformKernelDill,
28  platformLibrariesJson,
29  flutterPatchedSdkPath,
30  frontendServerSnapshotForEngineDartSdk,
31  /// The root directory of the dartk SDK.
32  engineDartSdkPath,
33  /// The dart binary used to execute any of the required snapshots.
34  engineDartBinary,
35  /// The dart snapshot of the dart2js compiler.
36  dart2jsSnapshot,
37  /// The dart snapshot of the dartdev compiler.
38  dartdevcSnapshot,
39  /// The dart snpashot of the kernel worker compiler.
40  kernelWorkerSnapshot,
41  /// The root of the web implementation of the dart SDK.
42  flutterWebSdk,
43  iosDeploy,
44  ideviceinfo,
45  ideviceId,
46  idevicename,
47  idevicesyslog,
48  idevicescreenshot,
49  ideviceinstaller,
50  iproxy,
51  /// The root of the Linux desktop sources.
52  linuxDesktopPath,
53  /// The root of the Windows desktop sources.
54  windowsDesktopPath,
55  /// The root of the sky_engine package
56  skyEnginePath,
57  /// The location of the macOS engine podspec file.
58  flutterMacOSPodspec,
59}
60
61String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMode mode ]) {
62  switch (artifact) {
63    case Artifact.genSnapshot:
64      return 'gen_snapshot';
65    case Artifact.flutterTester:
66      if (platform == TargetPlatform.windows_x64) {
67        return 'flutter_tester.exe';
68      }
69      return 'flutter_tester';
70    case Artifact.snapshotDart:
71      return 'snapshot.dart';
72    case Artifact.flutterFramework:
73      return 'Flutter.framework';
74    case Artifact.flutterMacOSFramework:
75      return 'FlutterMacOS.framework';
76    case Artifact.vmSnapshotData:
77      return 'vm_isolate_snapshot.bin';
78    case Artifact.isolateSnapshotData:
79      return 'isolate_snapshot.bin';
80    case Artifact.platformKernelDill:
81      return 'platform_strong.dill';
82    case Artifact.platformLibrariesJson:
83      return 'libraries.json';
84    case Artifact.flutterPatchedSdkPath:
85      assert(false, 'No filename for sdk path, should not be invoked');
86      return null;
87    case Artifact.flutterWebSdk:
88      assert(false, 'No filename for web sdk path, should not be invoked');
89      return null;
90    case Artifact.engineDartSdkPath:
91      return 'dart-sdk';
92    case Artifact.frontendServerSnapshotForEngineDartSdk:
93      return 'frontend_server.dart.snapshot';
94    case Artifact.engineDartBinary:
95      return 'dart';
96    case Artifact.dart2jsSnapshot:
97      return 'dart2js.dart.snapshot';
98    case Artifact.dartdevcSnapshot:
99      return 'dartdevc.dart.snapshot';
100    case Artifact.kernelWorkerSnapshot:
101      return 'kernel_worker.dart.snapshot';
102    case Artifact.iosDeploy:
103      return 'ios-deploy';
104    case Artifact.ideviceinfo:
105      return 'ideviceinfo';
106    case Artifact.ideviceId:
107      return 'idevice_id';
108    case Artifact.idevicename:
109      return 'idevicename';
110    case Artifact.idevicesyslog:
111      return 'idevicesyslog';
112    case Artifact.idevicescreenshot:
113      return 'idevicescreenshot';
114    case Artifact.ideviceinstaller:
115      return 'ideviceinstaller';
116    case Artifact.iproxy:
117      return 'iproxy';
118    case Artifact.linuxDesktopPath:
119      return '';
120    case Artifact.windowsDesktopPath:
121      return '';
122    case Artifact.skyEnginePath:
123      return 'sky_engine';
124    case Artifact.flutterMacOSPodspec:
125      return 'FlutterMacOS.podspec';
126  }
127  assert(false, 'Invalid artifact $artifact.');
128  return null;
129}
130
131class EngineBuildPaths {
132  const EngineBuildPaths({
133    @required this.targetEngine,
134    @required this.hostEngine,
135  }) : assert(targetEngine != null),
136       assert(hostEngine != null);
137
138  final String targetEngine;
139  final String hostEngine;
140}
141
142// Manages the engine artifacts of Flutter.
143abstract class Artifacts {
144  static Artifacts get instance => context.get<Artifacts>();
145
146  static LocalEngineArtifacts getLocalEngine(String engineSrcPath, EngineBuildPaths engineBuildPaths) {
147    return LocalEngineArtifacts(engineSrcPath, engineBuildPaths.targetEngine, engineBuildPaths.hostEngine);
148  }
149
150  // Returns the requested [artifact] for the [platform] and [mode] combination.
151  String getArtifactPath(Artifact artifact, { TargetPlatform platform, BuildMode mode });
152
153  // Returns which set of engine artifacts is currently used for the [platform]
154  // and [mode] combination.
155  String getEngineType(TargetPlatform platform, [ BuildMode mode ]);
156}
157
158/// Manages the engine artifacts downloaded to the local cache.
159class CachedArtifacts extends Artifacts {
160
161  @override
162  String getArtifactPath(Artifact artifact, { TargetPlatform platform, BuildMode mode }) {
163    platform ??= _currentHostPlatform;
164    switch (platform) {
165      case TargetPlatform.android_arm:
166      case TargetPlatform.android_arm64:
167      case TargetPlatform.android_x64:
168      case TargetPlatform.android_x86:
169        return _getAndroidArtifactPath(artifact, platform, mode);
170      case TargetPlatform.ios:
171        return _getIosArtifactPath(artifact, platform, mode);
172      case TargetPlatform.darwin_x64:
173      case TargetPlatform.linux_x64:
174      case TargetPlatform.windows_x64:
175      case TargetPlatform.fuchsia:
176      case TargetPlatform.tester:
177      case TargetPlatform.web_javascript:
178        return _getHostArtifactPath(artifact, platform, mode);
179    }
180    assert(false, 'Invalid platform $platform.');
181    return null;
182  }
183
184  @override
185  String getEngineType(TargetPlatform platform, [ BuildMode mode ]) {
186    return fs.path.basename(_getEngineArtifactsPath(platform, mode));
187  }
188
189  String _getAndroidArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
190    final String engineDir = _getEngineArtifactsPath(platform, mode);
191    switch (artifact) {
192      case Artifact.frontendServerSnapshotForEngineDartSdk:
193        assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.');
194        return fs.path.join(engineDir, _artifactToFileName(artifact));
195      case Artifact.genSnapshot:
196        assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.');
197        final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform());
198        return fs.path.join(engineDir, hostPlatform, _artifactToFileName(artifact));
199      default:
200        assert(false, 'Artifact $artifact not available for platform $platform.');
201        return null;
202    }
203  }
204
205  String _getIosArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
206    final String artifactFileName = _artifactToFileName(artifact);
207    switch (artifact) {
208      case Artifact.genSnapshot:
209      case Artifact.snapshotDart:
210      case Artifact.flutterFramework:
211      case Artifact.frontendServerSnapshotForEngineDartSdk:
212        final String engineDir = _getEngineArtifactsPath(platform, mode);
213        return fs.path.join(engineDir, artifactFileName);
214      case Artifact.ideviceId:
215      case Artifact.ideviceinfo:
216      case Artifact.idevicescreenshot:
217      case Artifact.idevicesyslog:
218      case Artifact.idevicename:
219        return cache.getArtifactDirectory('libimobiledevice').childFile(artifactFileName).path;
220      case Artifact.iosDeploy:
221        return cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName).path;
222      case Artifact.ideviceinstaller:
223        return cache.getArtifactDirectory('ideviceinstaller').childFile(artifactFileName).path;
224      case Artifact.iproxy:
225        return cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName).path;
226      default:
227        assert(false, 'Artifact $artifact not available for platform $platform.');
228        return null;
229    }
230  }
231
232  String _getFlutterPatchedSdkPath(BuildMode mode) {
233    final String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
234    return fs.path.join(engineArtifactsPath, 'common',
235        mode == BuildMode.release ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk');
236  }
237
238  String _getFlutterWebSdkPath() {
239    return cache.getWebSdkDirectory().path;
240  }
241
242  String _getHostArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
243    switch (artifact) {
244      case Artifact.genSnapshot:
245        // For script snapshots any gen_snapshot binary will do. Returning gen_snapshot for
246        // android_arm in profile mode because it is available on all supported host platforms.
247        return _getAndroidArtifactPath(artifact, TargetPlatform.android_arm, BuildMode.profile);
248      case Artifact.flutterTester:
249      case Artifact.vmSnapshotData:
250      case Artifact.isolateSnapshotData:
251      case Artifact.frontendServerSnapshotForEngineDartSdk:
252        final String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
253        final String platformDirName = getNameForTargetPlatform(platform);
254        return fs.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, platform, mode));
255      case Artifact.engineDartSdkPath:
256        return dartSdkPath;
257      case Artifact.engineDartBinary:
258        return fs.path.join(dartSdkPath, 'bin', _artifactToFileName(artifact));
259      case Artifact.platformKernelDill:
260        return fs.path.join(_getFlutterPatchedSdkPath(mode), _artifactToFileName(artifact));
261      case Artifact.platformLibrariesJson:
262        return fs.path.join(_getFlutterPatchedSdkPath(mode), 'lib', _artifactToFileName(artifact));
263      case Artifact.flutterPatchedSdkPath:
264        return _getFlutterPatchedSdkPath(mode);
265      case Artifact.flutterWebSdk:
266        return _getFlutterWebSdkPath();
267      case Artifact.dart2jsSnapshot:
268        return fs.path.join(dartSdkPath, 'bin', 'snapshots', _artifactToFileName(artifact));
269      case Artifact.dartdevcSnapshot:
270        return fs.path.join(dartSdkPath, 'bin', 'snapshots', _artifactToFileName(artifact));
271      case Artifact.kernelWorkerSnapshot:
272        return fs.path.join(dartSdkPath, 'bin', 'snapshots', _artifactToFileName(artifact));
273      case Artifact.flutterMacOSFramework:
274      case Artifact.linuxDesktopPath:
275      case Artifact.windowsDesktopPath:
276      case Artifact.flutterMacOSPodspec:
277        final String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
278        final String platformDirName = getNameForTargetPlatform(platform);
279        return fs.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, platform, mode));
280      case Artifact.skyEnginePath:
281        final Directory dartPackageDirectory = cache.getCacheDir('pkg');
282        return fs.path.join(dartPackageDirectory.path,  _artifactToFileName(artifact));
283      default:
284        assert(false, 'Artifact $artifact not available for platform $platform.');
285        return null;
286    }
287  }
288
289  String _getEngineArtifactsPath(TargetPlatform platform, [ BuildMode mode ]) {
290    final String engineDir = cache.getArtifactDirectory('engine').path;
291    final String platformName = getNameForTargetPlatform(platform);
292    switch (platform) {
293      case TargetPlatform.linux_x64:
294      case TargetPlatform.darwin_x64:
295      case TargetPlatform.windows_x64:
296      case TargetPlatform.fuchsia:
297      case TargetPlatform.tester:
298      case TargetPlatform.web_javascript:
299        assert(mode == null, 'Platform $platform does not support different build modes.');
300        return fs.path.join(engineDir, platformName);
301      case TargetPlatform.ios:
302      case TargetPlatform.android_arm:
303      case TargetPlatform.android_arm64:
304      case TargetPlatform.android_x64:
305      case TargetPlatform.android_x86:
306        assert(mode != null, 'Need to specify a build mode for platform $platform.');
307        final String suffix = mode != BuildMode.debug ? '-${snakeCase(getModeName(mode), '-')}' : '';
308        return fs.path.join(engineDir, platformName + suffix);
309    }
310    assert(false, 'Invalid platform $platform.');
311    return null;
312  }
313
314  TargetPlatform get _currentHostPlatform {
315    if (platform.isMacOS)
316      return TargetPlatform.darwin_x64;
317    if (platform.isLinux)
318      return TargetPlatform.linux_x64;
319    if (platform.isWindows)
320      return TargetPlatform.windows_x64;
321    throw UnimplementedError('Host OS not supported.');
322  }
323}
324
325/// Manages the artifacts of a locally built engine.
326class LocalEngineArtifacts extends Artifacts {
327  LocalEngineArtifacts(this._engineSrcPath, this.engineOutPath, this._hostEngineOutPath);
328
329  final String _engineSrcPath;
330  final String engineOutPath; // TODO(goderbauer): This should be private.
331  final String _hostEngineOutPath;
332
333  @override
334  String getArtifactPath(Artifact artifact, { TargetPlatform platform, BuildMode mode }) {
335    final String artifactFileName = _artifactToFileName(artifact);
336    switch (artifact) {
337      case Artifact.snapshotDart:
338        return fs.path.join(_engineSrcPath, 'flutter', 'lib', 'snapshot', artifactFileName);
339      case Artifact.genSnapshot:
340        return _genSnapshotPath();
341      case Artifact.flutterTester:
342        return _flutterTesterPath(platform);
343      case Artifact.isolateSnapshotData:
344      case Artifact.vmSnapshotData:
345        return fs.path.join(engineOutPath, 'gen', 'flutter', 'lib', 'snapshot', artifactFileName);
346      case Artifact.platformKernelDill:
347        return fs.path.join(_getFlutterPatchedSdkPath(mode), artifactFileName);
348      case Artifact.platformLibrariesJson:
349        return fs.path.join(_getFlutterPatchedSdkPath(mode), 'lib', artifactFileName);
350      case Artifact.flutterFramework:
351        return fs.path.join(engineOutPath, artifactFileName);
352      case Artifact.flutterMacOSFramework:
353        return fs.path.join(engineOutPath, artifactFileName);
354      case Artifact.flutterPatchedSdkPath:
355        // When using local engine always use [BuildMode.debug] regardless of
356        // what was specified in [mode] argument because local engine will
357        // have only one flutter_patched_sdk in standard location, that
358        // is happen to be what debug(non-release) mode is using.
359        return _getFlutterPatchedSdkPath(BuildMode.debug);
360      case Artifact.flutterWebSdk:
361        return _getFlutterWebSdkPath();
362      case Artifact.frontendServerSnapshotForEngineDartSdk:
363        return fs.path.join(_hostEngineOutPath, 'gen', artifactFileName);
364      case Artifact.engineDartSdkPath:
365        return fs.path.join(_hostEngineOutPath, 'dart-sdk');
366      case Artifact.engineDartBinary:
367        return fs.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', artifactFileName);
368      case Artifact.dart2jsSnapshot:
369        return fs.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', 'snapshots', artifactFileName);
370      case Artifact.dartdevcSnapshot:
371        return fs.path.join(dartSdkPath, 'bin', 'snapshots', artifactFileName);
372      case Artifact.kernelWorkerSnapshot:
373        return fs.path.join(_hostEngineOutPath, 'dart-sdk', 'bin', 'snapshots', artifactFileName);
374      case Artifact.ideviceId:
375      case Artifact.ideviceinfo:
376      case Artifact.idevicename:
377      case Artifact.idevicescreenshot:
378      case Artifact.idevicesyslog:
379        return cache.getArtifactDirectory('libimobiledevice').childFile(artifactFileName).path;
380      case Artifact.ideviceinstaller:
381        return cache.getArtifactDirectory('ideviceinstaller').childFile(artifactFileName).path;
382      case Artifact.iosDeploy:
383        return cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName).path;
384      case Artifact.iproxy:
385        return cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName).path;
386      case Artifact.linuxDesktopPath:
387        return fs.path.join(_hostEngineOutPath, artifactFileName);
388      case Artifact.windowsDesktopPath:
389        return fs.path.join(_hostEngineOutPath, artifactFileName);
390      case Artifact.skyEnginePath:
391        return fs.path.join(_hostEngineOutPath, 'gen', 'dart-pkg', artifactFileName);
392      case Artifact.flutterMacOSPodspec:
393        return fs.path.join(_hostEngineOutPath, _artifactToFileName(artifact));
394    }
395    assert(false, 'Invalid artifact $artifact.');
396    return null;
397  }
398
399  @override
400  String getEngineType(TargetPlatform platform, [ BuildMode mode ]) {
401    return fs.path.basename(engineOutPath);
402  }
403
404  String _getFlutterPatchedSdkPath(BuildMode buildMode) {
405    return fs.path.join(engineOutPath,
406        buildMode == BuildMode.release ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk');
407  }
408
409  String _getFlutterWebSdkPath() {
410    return fs.path.join(engineOutPath, 'flutter_web_sdk');
411  }
412
413  String _genSnapshotPath() {
414    const List<String> clangDirs = <String>['.', 'clang_x64', 'clang_x86', 'clang_i386'];
415    final String genSnapshotName = _artifactToFileName(Artifact.genSnapshot);
416    for (String clangDir in clangDirs) {
417      final String genSnapshotPath = fs.path.join(engineOutPath, clangDir, genSnapshotName);
418      if (processManager.canRun(genSnapshotPath))
419        return genSnapshotPath;
420    }
421    throw Exception('Unable to find $genSnapshotName');
422  }
423
424  String _flutterTesterPath(TargetPlatform platform) {
425    if (getCurrentHostPlatform() == HostPlatform.linux_x64) {
426      return fs.path.join(engineOutPath, _artifactToFileName(Artifact.flutterTester));
427    } else if (getCurrentHostPlatform() == HostPlatform.darwin_x64) {
428      return fs.path.join(engineOutPath, 'flutter_tester');
429    } else if (getCurrentHostPlatform() == HostPlatform.windows_x64) {
430      return fs.path.join(engineOutPath, 'flutter_tester.exe');
431    }
432    throw Exception('Unsupported platform $platform.');
433  }
434}
435
436/// An implementation of [Artifacts] that provides individual overrides.
437///
438/// If an artifact is not provided, the lookup delegates to the parent.
439class OverrideArtifacts implements Artifacts {
440  /// Creates a new [OverrideArtifacts].
441  ///
442  /// [parent] must be provided.
443  OverrideArtifacts({
444    @required this.parent,
445    this.frontendServer,
446    this.engineDartBinary,
447    this.platformKernelDill,
448    this.flutterPatchedSdk,
449  }) : assert(parent != null);
450
451  final Artifacts parent;
452  final File frontendServer;
453  final File engineDartBinary;
454  final File platformKernelDill;
455  final File flutterPatchedSdk;
456
457  @override
458  String getArtifactPath(Artifact artifact, { TargetPlatform platform, BuildMode mode }) {
459    if (artifact == Artifact.frontendServerSnapshotForEngineDartSdk && frontendServer != null) {
460      return frontendServer.path;
461    }
462    if (artifact == Artifact.engineDartBinary && engineDartBinary != null) {
463      return engineDartBinary.path;
464    }
465    if (artifact == Artifact.platformKernelDill && platformKernelDill != null) {
466      return platformKernelDill.path;
467    }
468    if (artifact == Artifact.flutterPatchedSdkPath && flutterPatchedSdk != null) {
469      return flutterPatchedSdk.path;
470    }
471    return parent.getArtifactPath(artifact, platform: platform, mode: mode);
472  }
473
474  @override
475  String getEngineType(TargetPlatform platform, [ BuildMode mode ]) => parent.getEngineType(platform, mode);
476}
477