bundle.dart 7.61 KB
Newer Older
1 2 3 4 5 6
// 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';

7 8
import 'package:meta/meta.dart';

9
import 'artifacts.dart';
10
import 'asset.dart';
11
import 'base/build.dart';
12
import 'base/common.dart';
13
import 'base/file_system.dart';
14
import 'build_info.dart';
15
import 'compile.dart';
16
import 'dart/package_map.dart';
17
import 'devfs.dart';
18
import 'globals.dart';
19 20

const String defaultMainPath = 'lib/main.dart';
21
const String defaultAssetBasePath = '.';
22
const String defaultManifestPath = 'pubspec.yaml';
23
String get defaultDepfilePath => fs.path.join(getBuildDirectory(), 'snapshot_blob.bin.d');
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

String getDefaultApplicationKernelPath({@required bool trackWidgetCreation}) {
  return getKernelPathForTransformerOptions(
    fs.path.join(getBuildDirectory(), 'app.dill'),
    trackWidgetCreation: trackWidgetCreation,
  );
}

String getKernelPathForTransformerOptions(
  String path, {
  @required bool trackWidgetCreation,
}) {
  if (trackWidgetCreation) {
    path += '.track.dill';
  }
  return path;
}

42 43
const String defaultPrivateKeyPath = 'privatekey.der';

44
const String _kKernelKey = 'kernel_blob.bin';
45 46
const String _kVMSnapshotData = 'vm_snapshot_data';
const String _kIsolateSnapshotData = 'isolate_snapshot_data';
47
const String _kIsolateSnapshotInstr = 'isolate_snapshot_instr';
48

49
Future<void> build({
50 51
  TargetPlatform platform,
  BuildMode buildMode,
52 53
  String mainPath = defaultMainPath,
  String manifestPath = defaultManifestPath,
54
  String applicationKernelFilePath,
55
  String depfilePath,
56
  String privateKeyPath = defaultPrivateKeyPath,
57
  String assetDirPath,
58
  String packagesPath,
59 60 61
  bool precompiledSnapshot = false,
  bool reportLicensedPackages = false,
  bool trackWidgetCreation = false,
62
  String compilationTraceFilePath,
63
  bool buildHotUpdate = false,
64
  List<String> extraFrontEndOptions = const <String>[],
65
  List<String> extraGenSnapshotOptions = const <String>[],
66 67
  List<String> fileSystemRoots,
  String fileSystemScheme,
68
}) async {
69
  depfilePath ??= defaultDepfilePath;
70
  assetDirPath ??= getAssetBuildDirectory();
71
  packagesPath ??= fs.path.absolute(PackageMap.globalPackagesPath);
72
  applicationKernelFilePath ??= getDefaultApplicationKernelPath(trackWidgetCreation: trackWidgetCreation);
73

74
  DevFSContent kernelContent;
75
  if (!precompiledSnapshot) {
76 77
    if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty)
      printTrace('Extra front-end options: $extraFrontEndOptions');
78 79 80
    ensureDirectoryExists(applicationKernelFilePath);
    final CompilerOutput compilerOutput = await kernelCompiler.compile(
      sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
81
      incrementalCompilerByteStorePath: compilationTraceFilePath != null ? null :
82
          fs.path.absolute(getIncrementalCompilerByteStoreDirectory()),
83 84
      mainPath: fs.file(mainPath).absolute.path,
      outputFilePath: applicationKernelFilePath,
85
      depFilePath: depfilePath,
86
      trackWidgetCreation: trackWidgetCreation,
87
      extraFrontEndOptions: extraFrontEndOptions,
88 89 90
      fileSystemRoots: fileSystemRoots,
      fileSystemScheme: fileSystemScheme,
      packagesPath: packagesPath,
91
      linkPlatformKernelIn: compilationTraceFilePath != null,
92
    );
93 94
    if (compilerOutput?.outputFilename == null) {
      throwToolExit('Compiler failed on $mainPath');
95
    }
96
    kernelContent = DevFSFileContent(fs.file(compilerOutput.outputFilename));
97 98 99

    await fs.directory(getBuildDirectory()).childFile('frontend_server.d')
        .writeAsString('frontend_server.d: ${artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk)}\n');
100

101
    if (compilationTraceFilePath != null) {
102
      final JITSnapshotter snapshotter = JITSnapshotter();
103 104 105 106 107 108
      final int snapshotExitCode = await snapshotter.build(
        platform: platform,
        buildMode: buildMode,
        mainPath: applicationKernelFilePath,
        outputPath: getBuildDirectory(),
        packagesPath: packagesPath,
109
        compilationTraceFilePath: compilationTraceFilePath,
110
        extraGenSnapshotOptions: extraGenSnapshotOptions,
111
        buildHotUpdate: buildHotUpdate,
112 113
      );
      if (snapshotExitCode != 0) {
114
        throwToolExit('Snapshotting exited with non-zero exit code: $snapshotExitCode');
115 116
      }
    }
117
  }
118

119
  final AssetBundle assets = await buildAssets(
120
    manifestPath: manifestPath,
121
    assetDirPath: assetDirPath,
122 123 124 125
    packagesPath: packagesPath,
    reportLicensedPackages: reportLicensedPackages,
  );
  if (assets == null)
126
    throwToolExit('Error building assets', exitCode: 1);
127

128
  await assemble(
129
    buildMode: buildMode,
130
    assetBundle: assets,
131
    kernelContent: kernelContent,
Ian Hickson's avatar
Ian Hickson committed
132
    privateKeyPath: privateKeyPath,
133
    assetDirPath: assetDirPath,
134
    compilationTraceFilePath: compilationTraceFilePath,
135
  );
136 137
}

138
Future<AssetBundle> buildAssets({
139
  String manifestPath,
140
  String assetDirPath,
141
  String packagesPath,
142 143
  bool includeDefaultFonts = true,
  bool reportLicensedPackages = false
144
}) async {
145
  assetDirPath ??= getAssetBuildDirectory();
146
  packagesPath ??= fs.path.absolute(PackageMap.globalPackagesPath);
147

148
  // Build the asset bundle.
149
  final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
150
  final int result = await assetBundle.build(
151
    manifestPath: manifestPath,
152
    assetDirPath: assetDirPath,
153
    packagesPath: packagesPath,
154
    includeDefaultFonts: includeDefaultFonts,
155 156
    reportLicensedPackages: reportLicensedPackages
  );
157
  if (result != 0)
158 159 160 161 162
    return null;

  return assetBundle;
}

163
Future<void> assemble({
164
  BuildMode buildMode,
165 166
  AssetBundle assetBundle,
  DevFSContent kernelContent,
167
  String privateKeyPath = defaultPrivateKeyPath,
168
  String assetDirPath,
169
  String compilationTraceFilePath,
170
}) async {
171 172
  assetDirPath ??= getAssetBuildDirectory();
  printTrace('Building bundle');
173

174
  final Map<String, DevFSContent> assetEntries = Map<String, DevFSContent>.from(assetBundle.entries);
175
  if (kernelContent != null) {
176
    if (compilationTraceFilePath != null) {
177
      final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData);
178 179
      final String isolateSnapshotData = fs.path.join(getBuildDirectory(), _kIsolateSnapshotData);
      final String isolateSnapshotInstr = fs.path.join(getBuildDirectory(), _kIsolateSnapshotInstr);
180 181 182
      assetEntries[_kVMSnapshotData] = DevFSFileContent(fs.file(vmSnapshotData));
      assetEntries[_kIsolateSnapshotData] = DevFSFileContent(fs.file(isolateSnapshotData));
      assetEntries[_kIsolateSnapshotInstr] = DevFSFileContent(fs.file(isolateSnapshotInstr));
183
    } else {
184 185
      final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData, null, buildMode);
      final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData, null, buildMode);
186
      assetEntries[_kKernelKey] = kernelContent;
187 188
      assetEntries[_kVMSnapshotData] = DevFSFileContent(fs.file(vmSnapshotData));
      assetEntries[_kIsolateSnapshotData] = DevFSFileContent(fs.file(isolateSnapshotData));
189
    }
190
  }
191

192 193
  printTrace('Writing asset files to $assetDirPath');
  ensureDirectoryExists(assetDirPath);
194

195 196 197
  await writeBundle(fs.directory(assetDirPath), assetEntries);
  printTrace('Wrote $assetDirPath');
}
198

199 200 201 202 203 204
Future<void> writeBundle(
    Directory bundleDir, Map<String, DevFSContent> assetEntries) async {
  if (bundleDir.existsSync())
    bundleDir.deleteSync(recursive: true);
  bundleDir.createSync(recursive: true);

205 206
  await Future.wait<void>(
      assetEntries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
207 208 209 210 211
    final File file = fs.file(fs.path.join(bundleDir.path, entry.key));
    file.parent.createSync(recursive: true);
    await file.writeAsBytes(await entry.value.contentsAsBytes());
  }));
}