blob: 7cd0a58dac8019254df9ace5a06e1baaae31078f [file] [log] [blame]
// 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 'package:yaml/yaml.dart';
import 'android/android_sdk.dart';
import 'base/file_system.dart';
import 'convert.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<void> parseServiceConfigs(
List<Map<String, String>> services, {
List<File> jars,
}) async {
Map<String, Uri> packageMap;
try {
packageMap = 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>>((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;
}