• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 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 'dart:async';
6
7import 'package:meta/meta.dart';
8
9import '../asset.dart';
10import '../base/common.dart';
11import '../base/file_system.dart';
12import '../base/io.dart';
13import '../build_info.dart';
14import '../bundle.dart';
15import '../convert.dart';
16import '../devfs.dart';
17import '../globals.dart';
18import '../project.dart';
19import '../reporting/reporting.dart';
20
21import 'fuchsia_pm.dart';
22import 'fuchsia_sdk.dart';
23
24Future<void> _timedBuildStep(String name, Future<void> Function() action) async {
25  final Stopwatch sw = Stopwatch()..start();
26  await action();
27  printTrace('$name: ${sw.elapsedMilliseconds} ms.');
28  flutterUsage.sendTiming('build', name, Duration(milliseconds: sw.elapsedMilliseconds));
29}
30
31// Building a Fuchsia package has a few steps:
32// 1. Do the custom kernel compile using the kernel compiler from the Fuchsia
33//    SDK. This produces .dilp files (among others) and a manifest file.
34// 2. Create a manifest file for assets.
35// 3. Using these manifests, use the Fuchsia SDK 'pm' tool to create the
36//    Fuchsia package.
37Future<void> buildFuchsia(
38    {@required FuchsiaProject fuchsiaProject,
39    @required String target, // E.g., lib/main.dart
40    BuildInfo buildInfo = BuildInfo.debug}) async {
41  final Directory outDir = fs.directory(getFuchsiaBuildDirectory());
42  if (!outDir.existsSync()) {
43    outDir.createSync(recursive: true);
44  }
45
46  await _timedBuildStep('fuchsia-kernel-compile',
47    () => fuchsiaSdk.fuchsiaKernelCompiler.build(
48      fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo));
49  await _timedBuildStep('fuchsia-build-assets',
50    () => _buildAssets(fuchsiaProject, target, buildInfo));
51  await _timedBuildStep('fuchsia-build-package',
52    () => _buildPackage(fuchsiaProject, target, buildInfo));
53}
54
55Future<void> _buildAssets(
56    FuchsiaProject fuchsiaProject,
57    String target, // lib/main.dart
58    BuildInfo buildInfo) async {
59  final String assetDir = getAssetBuildDirectory();
60  final AssetBundle assets = await buildAssets(
61    manifestPath: fuchsiaProject.project.pubspecFile.path,
62    packagesPath: fuchsiaProject.project.packagesFile.path,
63    assetDirPath: assetDir,
64    includeDefaultFonts: false,
65  );
66
67  final Map<String, DevFSContent> assetEntries =
68      Map<String, DevFSContent>.from(assets.entries);
69  await writeBundle(fs.directory(assetDir), assetEntries);
70
71  final String appName = fuchsiaProject.project.manifest.appName;
72  final String outDir = getFuchsiaBuildDirectory();
73  final String assetManifest = fs.path.join(outDir, '${appName}_pkgassets');
74
75  final File destFile = fs.file(assetManifest);
76  await destFile.create(recursive: true);
77  final IOSink outFile = destFile.openWrite();
78
79  for (String path in assets.entries.keys) {
80    outFile.write('data/$appName/$path=$assetDir/$path\n');
81  }
82  await outFile.flush();
83  await outFile.close();
84}
85
86void _rewriteCmx(BuildMode mode, File src, File dst) {
87  final Map<String, dynamic> cmx = json.decode(src.readAsStringSync());
88  // If the app author has already specified the runner in the cmx file, then
89  // do not override it with something else.
90  if (cmx.containsKey('runner')) {
91    dst.writeAsStringSync(json.encode(cmx));
92    return;
93  }
94  String runner;
95  switch (mode) {
96    case BuildMode.debug:
97    case BuildMode.profile:
98      runner = 'flutter_jit_runner';
99      break;
100    case BuildMode.release:
101      runner = 'flutter_jit_product_runner';
102      break;
103    default:
104      throwToolExit('Fuchsia does not support build mode "$mode"');
105      break;
106  }
107  cmx['runner'] = 'fuchsia-pkg://fuchsia.com/$runner#meta/$runner.cmx';
108  dst.writeAsStringSync(json.encode(cmx));
109}
110
111// TODO(zra): Allow supplying a signing key.
112Future<void> _buildPackage(
113    FuchsiaProject fuchsiaProject,
114    String target, // lib/main.dart
115    BuildInfo buildInfo) async {
116  final String outDir = getFuchsiaBuildDirectory();
117  final String pkgDir = fs.path.join(outDir, 'pkg');
118  final String appName = fuchsiaProject.project.manifest.appName;
119  final String dilpmanifest = fs.path.join(outDir, '$appName.dilpmanifest');
120  final String pkgassets = fs.path.join(outDir, '${appName}_pkgassets');
121  final String packageManifest = fs.path.join(pkgDir, 'package_manifest');
122  final String devKeyPath = fs.path.join(pkgDir, 'development.key');
123
124  final Directory pkg = fs.directory(pkgDir);
125  if (!pkg.existsSync()) {
126    pkg.createSync(recursive: true);
127  }
128
129  final File srcCmx =
130      fs.file(fs.path.join(fuchsiaProject.meta.path, '$appName.cmx'));
131  final File dstCmx = fs.file(fs.path.join(outDir, '$appName.cmx'));
132  _rewriteCmx(buildInfo.mode, srcCmx, dstCmx);
133
134  // Concatenate dilpmanifest and pkgassets into package_manifest.
135  final File manifestFile = fs.file(packageManifest);
136  manifestFile.writeAsStringSync(fs.file(dilpmanifest).readAsStringSync());
137  manifestFile.writeAsStringSync(fs.file(pkgassets).readAsStringSync(),
138      mode: FileMode.append);
139  manifestFile.writeAsStringSync('meta/$appName.cmx=${dstCmx.path}\n',
140      mode: FileMode.append);
141  manifestFile.writeAsStringSync('meta/package=$pkgDir/meta/package\n',
142      mode: FileMode.append);
143
144  final FuchsiaPM fuchsiaPM = fuchsiaSdk.fuchsiaPM;
145  if (!await fuchsiaPM.init(pkgDir, appName)) {
146    return;
147  }
148  if (!await fuchsiaPM.genkey(pkgDir, devKeyPath)) {
149    return;
150  }
151  if (!await fuchsiaPM.build(pkgDir, devKeyPath, packageManifest)) {
152    return;
153  }
154  if (!await fuchsiaPM.archive(pkgDir, devKeyPath, packageManifest)) {
155    return;
156  }
157}
158