diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index b280f8ce5da..c4e041c7b71 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -5,6 +5,8 @@ import 'dart:async'; import 'dart:io'; +import 'package:flutter_tools/src/dart/pub.dart'; +import 'package:flutter_tools/src/dart/summary.dart'; import 'package:path/path.dart' as path; import 'base/context.dart'; @@ -236,13 +238,17 @@ class MaterialFonts { } class FlutterEngine { + FlutterEngine(this.cache); static const String kName = 'engine'; + static const String kSkyEngine = 'sky_engine'; + static const String kSkyServices = 'sky_services'; + static const String kSdkBundle = 'sdk.ds'; final Cache cache; - List _getPackageDirs() => ['sky_engine', 'sky_services']; + List _getPackageDirs() => const [kSkyEngine, kSkyServices]; List _getEngineDirs() { List dirs = [ @@ -292,11 +298,17 @@ class FlutterEngine { bool isUpToDate() { Directory pkgDir = cache.getCacheDir('pkg'); for (String pkgName in _getPackageDirs()) { - Directory dir = new Directory(path.join(pkgDir.path, pkgName)); - if (!dir.existsSync()) + String pkgPath = path.join(pkgDir.path, pkgName); + String dotPackagesPath = path.join(pkgPath, '.packages'); + if (!new Directory(pkgPath).existsSync()) + return false; + if (!new File(dotPackagesPath).existsSync()) return false; } + if (!new File(path.join(pkgDir.path, kSkyEngine, kSdkBundle)).existsSync()) + return false; + Directory engineDir = cache.getArtifactDirectory(kName); for (String dirName in _getEngineDirs()) { Directory dir = new Directory(path.join(engineDir.path, dirName)); @@ -319,10 +331,21 @@ class FlutterEngine { Directory pkgDir = cache.getCacheDir('pkg'); for (String pkgName in _getPackageDirs()) { - Directory dir = new Directory(path.join(pkgDir.path, pkgName)); + String pkgPath = path.join(pkgDir.path, pkgName); + Directory dir = new Directory(pkgPath); if (dir.existsSync()) dir.deleteSync(recursive: true); await _downloadItem('Downloading package $pkgName...', url + pkgName + '.zip', pkgDir); + await pubGet(directory: pkgPath); + } + + Status summaryStatus = logger.startProgress('Building Dart SDK summary...'); + try { + String skyEnginePath = path.join(pkgDir.path, kSkyEngine); + String skyServicesPath = path.join(pkgDir.path, kSkyServices); + buildSkyEngineSdkSummary(skyEnginePath, skyServicesPath, kSdkBundle); + } finally { + summaryStatus.stop(showElapsedTime: true); } Directory engineDir = cache.getArtifactDirectory(kName); diff --git a/packages/flutter_tools/lib/src/dart/summary.dart b/packages/flutter_tools/lib/src/dart/summary.dart new file mode 100644 index 00000000000..b5bf2462893 --- /dev/null +++ b/packages/flutter_tools/lib/src/dart/summary.dart @@ -0,0 +1,76 @@ +import 'dart:io' as io; + +import 'package:analyzer/file_system/file_system.dart'; +import 'package:analyzer/file_system/physical_file_system.dart'; +import 'package:analyzer/source/sdk_ext.dart'; +import 'package:analyzer/src/context/builder.dart'; // ignore: implementation_imports +import 'package:analyzer/src/dart/sdk/sdk.dart'; // ignore: implementation_imports +import 'package:analyzer/src/generated/engine.dart'; // ignore: implementation_imports +import 'package:analyzer/src/generated/source.dart'; // ignore: implementation_imports +import 'package:analyzer/src/summary/summary_file_builder.dart'; // ignore: implementation_imports +import 'package:flutter_tools/src/globals.dart'; +import 'package:package_config/packages.dart'; +import 'package:path/path.dart' as pathos; +import 'package:yaml/src/yaml_node.dart'; // ignore: implementation_imports + +/// Given the [skyEnginePath] and [skyServicesPath], locate corresponding +/// `_embedder.yaml` and `_sdkext`, compose the full embedded Dart SDK, and +/// build the [outBundleName] file with its linked summary. +void buildSkyEngineSdkSummary( + String skyEnginePath, String skyServicesPath, String outBundleName) { + ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE; + + ContextBuilder builder = new ContextBuilder(resourceProvider, null, null); + Packages packages = builder.createPackageMap(skyServicesPath); + Map> packageMap = builder.convertPackagesToMap(packages); + if (packageMap == null) { + printError('The expected .packages was not found in $skyServicesPath.'); + return; + } + packageMap['sky_engine'] = [ + resourceProvider.getFolder(pathos.join(skyEnginePath, 'lib')) + ]; + + // + // Read the `_embedder.yaml` file. + // + EmbedderYamlLocator yamlLocator = new EmbedderYamlLocator(packageMap); + Map embedderYamls = yamlLocator.embedderYamls; + if (embedderYamls.length != 1) { + printError('Exactly one _embedder.yaml was expected in $packageMap, ' + 'but $embedderYamls found.'); + return; + } + + // + // Read the `_sdkext` file. + // + SdkExtUriResolver extResolver = new SdkExtUriResolver(packageMap); + Map urlMappings = extResolver.urlMappings; + if (embedderYamls.length != 1) { + printError('Exactly one extension library was expected in $packageMap, ' + 'but $urlMappings found.'); + return; + } + + // + // Create the EmbedderSdk instance. + // + EmbedderSdk sdk = new EmbedderSdk(resourceProvider, embedderYamls); + sdk.addExtensions(urlMappings); + sdk.analysisOptions = new AnalysisOptionsImpl()..strongMode = true; + + // + // Gather sources. + // + List sources = sdk.uris.map(sdk.mapDartUri).toList(); + + // + // Build. + // + SummaryBuildConfig config = new SummaryBuildConfig(strongMode: true); + BuilderOutput output = + new SummaryBuilder(sources, sdk.context, config).build(); + String outputPath = pathos.join(skyEnginePath, outBundleName); + new io.File(outputPath).writeAsBytesSync(output.sum); +}