blob: 376920ebfcbbef40172b46a1b11562d7fadc87d9 [file] [log] [blame]
// Copyright 2019 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:meta/meta.dart';
import '../asset.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../build_info.dart';
import '../bundle.dart';
import '../convert.dart';
import '../devfs.dart';
import '../globals.dart';
import '../project.dart';
import '../usage.dart';
import 'fuchsia_pm.dart';
import 'fuchsia_sdk.dart';
Future<void> _timedBuildStep(String name, Future<void> Function() action) async {
final Stopwatch sw = Stopwatch()..start();
await action();
printTrace('$name: ${sw.elapsedMilliseconds} ms.');
flutterUsage.sendTiming('build', name, Duration(milliseconds: sw.elapsedMilliseconds));
}
// Building a Fuchsia package has a few steps:
// 1. Do the custom kernel compile using the kernel compiler from the Fuchsia
// SDK. This produces .dilp files (among others) and a manifest file.
// 2. Create a manifest file for assets.
// 3. Using these manifests, use the Fuchsia SDK 'pm' tool to create the
// Fuchsia package.
Future<void> buildFuchsia(
{@required FuchsiaProject fuchsiaProject,
@required String target, // E.g., lib/main.dart
BuildInfo buildInfo = BuildInfo.debug}) async {
final Directory outDir = fs.directory(getFuchsiaBuildDirectory());
if (!outDir.existsSync()) {
outDir.createSync(recursive: true);
}
await _timedBuildStep('fuchsia-kernel-compile',
() => fuchsiaSdk.fuchsiaKernelCompiler.build(
fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo));
await _timedBuildStep('fuchsia-build-assets',
() => _buildAssets(fuchsiaProject, target, buildInfo));
await _timedBuildStep('fuchsia-build-package',
() => _buildPackage(fuchsiaProject, target, buildInfo));
}
Future<void> _buildAssets(
FuchsiaProject fuchsiaProject,
String target, // lib/main.dart
BuildInfo buildInfo) async {
final String assetDir = getAssetBuildDirectory();
final AssetBundle assets = await buildAssets(
manifestPath: fuchsiaProject.project.pubspecFile.path,
packagesPath: fuchsiaProject.project.packagesFile.path,
assetDirPath: assetDir,
includeDefaultFonts: false,
);
final Map<String, DevFSContent> assetEntries =
Map<String, DevFSContent>.from(assets.entries);
await writeBundle(fs.directory(assetDir), assetEntries);
final String appName = fuchsiaProject.project.manifest.appName;
final String outDir = getFuchsiaBuildDirectory();
final String assetManifest = fs.path.join(outDir, '${appName}_pkgassets');
final File destFile = fs.file(assetManifest);
await destFile.create(recursive: true);
final IOSink outFile = destFile.openWrite();
for (String path in assets.entries.keys) {
outFile.write('data/$appName/$path=$assetDir/$path\n');
}
await outFile.flush();
await outFile.close();
}
void _rewriteCmx(BuildMode mode, File src, File dst) {
final Map<String, dynamic> cmx = json.decode(src.readAsStringSync());
// If the app author has already specified the runner in the cmx file, then
// do not override it with something else.
if (cmx.containsKey('runner')) {
dst.writeAsStringSync(json.encode(cmx));
return;
}
String runner;
switch (mode) {
case BuildMode.debug:
case BuildMode.profile:
runner = 'flutter_jit_runner';
break;
case BuildMode.release:
runner = 'flutter_jit_product_runner';
break;
default:
throwToolExit('Fuchsia does not support build mode "$mode"');
break;
}
cmx['runner'] = 'fuchsia-pkg://fuchsia.com/$runner#meta/$runner.cmx';
dst.writeAsStringSync(json.encode(cmx));
}
// TODO(zra): Allow supplying a signing key.
Future<void> _buildPackage(
FuchsiaProject fuchsiaProject,
String target, // lib/main.dart
BuildInfo buildInfo) async {
final String outDir = getFuchsiaBuildDirectory();
final String pkgDir = fs.path.join(outDir, 'pkg');
final String appName = fuchsiaProject.project.manifest.appName;
final String dilpmanifest = fs.path.join(outDir, '$appName.dilpmanifest');
final String pkgassets = fs.path.join(outDir, '${appName}_pkgassets');
final String packageManifest = fs.path.join(pkgDir, 'package_manifest');
final String devKeyPath = fs.path.join(pkgDir, 'development.key');
final Directory pkg = fs.directory(pkgDir);
if (!pkg.existsSync()) {
pkg.createSync(recursive: true);
}
final File srcCmx =
fs.file(fs.path.join(fuchsiaProject.meta.path, '$appName.cmx'));
final File dstCmx = fs.file(fs.path.join(outDir, '$appName.cmx'));
_rewriteCmx(buildInfo.mode, srcCmx, dstCmx);
// Concatenate dilpmanifest and pkgassets into package_manifest.
final File manifestFile = fs.file(packageManifest);
manifestFile.writeAsStringSync(fs.file(dilpmanifest).readAsStringSync());
manifestFile.writeAsStringSync(fs.file(pkgassets).readAsStringSync(),
mode: FileMode.append);
manifestFile.writeAsStringSync('meta/$appName.cmx=${dstCmx.path}\n',
mode: FileMode.append);
manifestFile.writeAsStringSync('meta/package=$pkgDir/meta/package\n',
mode: FileMode.append);
final FuchsiaPM fuchsiaPM = fuchsiaSdk.fuchsiaPM;
if (!await fuchsiaPM.init(pkgDir, appName)) {
return;
}
if (!await fuchsiaPM.genkey(pkgDir, devKeyPath)) {
return;
}
if (!await fuchsiaPM.build(pkgDir, devKeyPath, packageManifest)) {
return;
}
if (!await fuchsiaPM.archive(pkgDir, devKeyPath, packageManifest)) {
return;
}
}