|  | // Copyright 2015 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. | 
|  |  | 
|  | import 'dart:async'; | 
|  | import 'dart:convert'; | 
|  |  | 
|  | import 'package:yaml/yaml.dart'; | 
|  |  | 
|  | import 'android/android_sdk.dart'; | 
|  | import 'base/file_system.dart'; | 
|  | import 'dart/package_map.dart'; | 
|  | import 'globals.dart'; | 
|  |  | 
|  | const String _kFlutterManifestPath = 'pubspec.yaml'; | 
|  | const String _kFlutterServicesManifestPath = 'flutter_services.yaml'; | 
|  |  | 
|  | dynamic _loadYamlFile(String path) { | 
|  | printTrace("Looking for YAML at '$path'"); | 
|  | if (!fs.isFileSync(path)) | 
|  | return null; | 
|  | final String manifestString = fs.file(path).readAsStringSync(); | 
|  | return loadYaml(manifestString); | 
|  | } | 
|  |  | 
|  | /// Loads all services specified in `pubspec.yaml`. Parses each service config file, | 
|  | /// storing meta data in [services] and the list of jar files in [jars]. | 
|  | Future<Null> parseServiceConfigs( | 
|  | List<Map<String, String>> services, { List<File> jars } | 
|  | ) async { | 
|  | Map<String, Uri> packageMap; | 
|  | try { | 
|  | packageMap = new PackageMap(PackageMap.globalPackagesPath).map; | 
|  | } on FormatException catch (error) { | 
|  | printTrace('Invalid ".packages" file while parsing service configs:\n$error'); | 
|  | return; | 
|  | } | 
|  |  | 
|  | dynamic manifest; | 
|  | try { | 
|  | manifest = _loadYamlFile(_kFlutterManifestPath); | 
|  | manifest = manifest['flutter']; | 
|  | } catch (error) { | 
|  | printStatus('Error detected in pubspec.yaml:', emphasis: true); | 
|  | printError('$error'); | 
|  | return; | 
|  | } | 
|  | if (manifest == null || manifest['services'] == null) { | 
|  | printTrace('No services specified in the manifest'); | 
|  | return; | 
|  | } | 
|  |  | 
|  | for (String service in manifest['services']) { | 
|  | final String serviceRoot = packageMap[service].path; | 
|  | final dynamic serviceConfig = _loadYamlFile('$serviceRoot/$_kFlutterServicesManifestPath'); | 
|  | if (serviceConfig == null) { | 
|  | printStatus('No $_kFlutterServicesManifestPath found for service "$serviceRoot"; skipping.'); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | for (Map<String, String> service in serviceConfig['services']) { | 
|  | services.add(<String, String>{ | 
|  | 'root': serviceRoot, | 
|  | 'name': service['name'], | 
|  | 'android-class': service['android-class'], | 
|  | 'ios-framework': service['ios-framework'] | 
|  | }); | 
|  | } | 
|  |  | 
|  | if (jars != null && serviceConfig['jars'] is Iterable) { | 
|  | for (String jar in serviceConfig['jars']) | 
|  | jars.add(fs.file(await getServiceFromUrl(jar, serviceRoot, service))); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<String> getServiceFromUrl(String url, String rootDir, String serviceName) async { | 
|  | if (url.startsWith('android-sdk:') && androidSdk != null) { | 
|  | // It's something shipped in the standard android SDK. | 
|  | return url.replaceAll('android-sdk:', '${androidSdk.directory}/'); | 
|  | } else if (url.startsWith('http:') || url.startsWith('https:')) { | 
|  | // It's a regular file to download. | 
|  | return await cache.getThirdPartyFile(url, serviceName); | 
|  | } else { | 
|  | // Assume url is a path relative to the service's root dir. | 
|  | return fs.path.join(rootDir, url); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Outputs a services.json file for the flutter engine to read. Format: | 
|  | /// { | 
|  | ///   services: [ | 
|  | ///     { name: string, framework: string }, | 
|  | ///     ... | 
|  | ///   ] | 
|  | /// } | 
|  | File generateServiceDefinitions( | 
|  | String dir, List<Map<String, String>> servicesIn | 
|  | ) { | 
|  | final List<Map<String, String>> services = | 
|  | servicesIn.map((Map<String, String> service) => <String, String>{ | 
|  | 'name': service['name'], | 
|  | 'class': service['android-class'] | 
|  | }).toList(); | 
|  |  | 
|  | final Map<String, dynamic> jsonObject = <String, dynamic>{ 'services': services }; | 
|  | final File servicesFile = fs.file(fs.path.join(dir, 'services.json')); | 
|  | servicesFile.writeAsStringSync(json.encode(jsonObject), mode: FileMode.WRITE, flush: true); | 
|  | return servicesFile; | 
|  | } |