diff --git a/packages/flutter_tools/BUILD.gn b/packages/flutter_tools/BUILD.gn index 09085bd297..d878a4010b 100644 --- a/packages/flutter_tools/BUILD.gn +++ b/packages/flutter_tools/BUILD.gn @@ -49,6 +49,16 @@ dart_tool("fuchsia_builder") { ] } +dart_tool("fuchsia_asset_builder") { + main_dart = "bin/fuchsia_asset_builder.dart" + + disable_analysis = true + + deps = [ + ":flutter_tools", + ] +} + dart_tool("fuchsia_tester") { main_dart = "bin/fuchsia_tester.dart" diff --git a/packages/flutter_tools/bin/fuchsia_asset_builder.dart b/packages/flutter_tools/bin/fuchsia_asset_builder.dart new file mode 100644 index 0000000000..e5feb7fb42 --- /dev/null +++ b/packages/flutter_tools/bin/fuchsia_asset_builder.dart @@ -0,0 +1,90 @@ +// Copyright 2018 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:args/args.dart'; + +import '../lib/src/asset.dart'; +import '../lib/src/base/file_system.dart' as libfs; +import '../lib/src/base/io.dart'; +import '../lib/src/base/platform.dart'; +import '../lib/src/cache.dart'; +import '../lib/src/context_runner.dart'; +import '../lib/src/devfs.dart'; +import '../lib/src/flx.dart'; +import '../lib/src/globals.dart'; + +const String _kOptionPackages = 'packages'; +const String _kOptionWorking = 'working-dir'; +const String _kOptionManifest = 'manifest'; +const String _kOptionAssetManifestOut = 'asset-manifest-out'; +const List _kRequiredOptions = const [ + _kOptionPackages, + _kOptionWorking, + _kOptionAssetManifestOut, +]; + +Future main(List args) async { + await runInContext(args, run); +} + +Future writeFile(libfs.File outputFile, DevFSContent content) async { + outputFile.createSync(recursive: true); + final List data = await content.contentsAsBytes(); + outputFile.writeAsBytesSync(data); + return null; +} + +Future run(List args) async { + final ArgParser parser = new ArgParser() + ..addOption(_kOptionPackages, help: 'The .packages file') + ..addOption(_kOptionWorking, + help: 'The directory where to put temporary files') + ..addOption(_kOptionManifest, help: 'The manifest file') + ..addOption(_kOptionAssetManifestOut); + final ArgResults argResults = parser.parse(args); + if (_kRequiredOptions + .any((String option) => !argResults.options.contains(option))) { + printError('Missing option! All options must be specified.'); + exit(1); + } + Cache.flutterRoot = platform.environment['FLUTTER_ROOT']; + + final String workingDir = argResults[_kOptionWorking]; + final AssetBundle assets = await buildAssets( + manifestPath: argResults[_kOptionManifest] ?? defaultManifestPath, + workingDirPath: workingDir, + packagesPath: argResults[_kOptionPackages], + includeDefaultFonts: false, + ); + + if (assets == null) { + print('Unable to find assets.'); + exit(1); + } + + final List> calls = >[]; + assets.entries.forEach((String fileName, DevFSContent content) { + final libfs.File outputFile = libfs.fs.file(libfs.fs.path.join(workingDir, fileName)); + calls.add(writeFile(outputFile, content)); + }); + await Future.wait(calls); + + final String outputMan = argResults[_kOptionAssetManifestOut]; + await writeFuchsiaManifest(assets, argResults[_kOptionWorking], outputMan); +} + +Future writeFuchsiaManifest(AssetBundle assets, String outputBase, String fileDest) async { + + final libfs.File destFile = libfs.fs.file(fileDest); + await destFile.create(recursive: true); + final libfs.IOSink outFile = destFile.openWrite(); + + for (String path in assets.entries.keys) { + outFile.write('data/$path=$outputBase/$path\n'); + } + await outFile.flush(); + await outFile.close(); +} diff --git a/packages/flutter_tools/bin/fuchsia_builder.dart b/packages/flutter_tools/bin/fuchsia_builder.dart index 5efe7e6f92..1ad33f33ce 100644 --- a/packages/flutter_tools/bin/fuchsia_builder.dart +++ b/packages/flutter_tools/bin/fuchsia_builder.dart @@ -5,21 +5,16 @@ import 'dart:async'; import 'package:args/args.dart'; -import 'package:process/process.dart'; +import '../lib/src/asset.dart'; import '../lib/src/base/common.dart'; -import '../lib/src/base/config.dart'; -import '../lib/src/base/context.dart'; import '../lib/src/base/file_system.dart'; import '../lib/src/base/io.dart'; -import '../lib/src/base/logger.dart'; -import '../lib/src/base/os.dart'; import '../lib/src/base/platform.dart'; import '../lib/src/cache.dart'; -import '../lib/src/disabled_usage.dart'; +import '../lib/src/context_runner.dart'; import '../lib/src/flx.dart'; import '../lib/src/globals.dart'; -import '../lib/src/usage.dart'; const String _kOptionPackages = 'packages'; const String _kOptionOutput = 'output-file'; @@ -40,22 +35,7 @@ const List _kRequiredOptions = const [ ]; Future main(List args) async { - final AppContext executableContext = new AppContext(); - executableContext.setVariable(Logger, new StdoutLogger()); - await executableContext.runInZone(() { - // Initialize the context with some defaults. - // This list must be kept in sync with lib/executable.dart. - context.putIfAbsent(Stdio, () => const Stdio()); - context.putIfAbsent(Platform, () => const LocalPlatform()); - context.putIfAbsent(FileSystem, () => const LocalFileSystem()); - context.putIfAbsent(ProcessManager, () => const LocalProcessManager()); - context.putIfAbsent(Logger, () => new StdoutLogger()); - context.putIfAbsent(Cache, () => new Cache()); - context.putIfAbsent(Config, () => new Config()); - context.putIfAbsent(OperatingSystemUtils, () => new OperatingSystemUtils()); - context.putIfAbsent(Usage, () => new DisabledUsage()); - return run(args); - }); + await runInContext(args, run); } Future run(List args) async { @@ -81,15 +61,23 @@ Future run(List args) async { try { final String snapshotPath = argResults[_kOptionSnapshot]; final String dylibPath = argResults[_kOptionDylib]; + final AssetBundle assets = await buildAssets( + manifestPath: argResults[_kOptionManifest] ?? defaultManifestPath, + workingDirPath: argResults[_kOptionWorking], + packagesPath: argResults[_kOptionPackages], + includeDefaultFonts: false, + ); + if (assets == null) + throwToolExit('Error building assets for $outputPath', exitCode: 1); + final List dependencies = await assemble( + assetBundle: assets, outputPath: outputPath, snapshotFile: snapshotPath == null ? null : fs.file(snapshotPath), dylibFile: dylibPath == null ? null : fs.file(dylibPath), workingDirPath: argResults[_kOptionWorking], - packagesPath: argResults[_kOptionPackages], - manifestPath: argResults[_kOptionManifest] ?? defaultManifestPath, - includeDefaultFonts: false, ); + final String depFilePath = argResults[_kOptionDepFile]; final int depFileResult = _createDepfile( depFilePath, diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart new file mode 100644 index 0000000000..7b0cd2b139 --- /dev/null +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -0,0 +1,39 @@ +// Copyright 2018 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:process/process.dart'; + +import 'base/config.dart'; +import 'base/context.dart'; +import 'base/file_system.dart'; +import 'base/io.dart'; +import 'base/logger.dart'; +import 'base/os.dart'; +import 'base/platform.dart'; +import 'cache.dart'; +import 'disabled_usage.dart'; +import 'usage.dart'; + +typedef Future Runner(List args); + +Future runInContext(List args, Runner runner) { + final AppContext executableContext = new AppContext(); + executableContext.setVariable(Logger, new StdoutLogger()); + return executableContext.runInZone(() { + // Initialize the context with some defaults. + // This list must be kept in sync with lib/executable.dart. + context.putIfAbsent(Stdio, () => const Stdio()); + context.putIfAbsent(Platform, () => const LocalPlatform()); + context.putIfAbsent(FileSystem, () => const LocalFileSystem()); + context.putIfAbsent(ProcessManager, () => const LocalProcessManager()); + context.putIfAbsent(Logger, () => new StdoutLogger()); + context.putIfAbsent(Cache, () => new Cache()); + context.putIfAbsent(Config, () => new Config()); + context.putIfAbsent(OperatingSystemUtils, () => new OperatingSystemUtils()); + context.putIfAbsent(Usage, () => new DisabledUsage()); + return runner(args); + }); +} diff --git a/packages/flutter_tools/lib/src/flx.dart b/packages/flutter_tools/lib/src/flx.dart index b2b0e4eab2..fe42e1524d 100644 --- a/packages/flutter_tools/lib/src/flx.dart +++ b/packages/flutter_tools/lib/src/flx.dart @@ -82,34 +82,34 @@ Future build({ kernelContent = new DevFSFileContent(fs.file(kernelBinaryFilename)); } - return assemble( + final AssetBundle assets = await buildAssets( manifestPath: manifestPath, + workingDirPath: workingDirPath, + packagesPath: packagesPath, + reportLicensedPackages: reportLicensedPackages, + ); + if (assets == null) + throwToolExit('Error building assets for $outputPath', exitCode: 1); + + return assemble( + assetBundle: assets, kernelContent: kernelContent, snapshotFile: snapshotFile, outputPath: outputPath, privateKeyPath: privateKeyPath, workingDirPath: workingDirPath, - packagesPath: packagesPath, - reportLicensedPackages: reportLicensedPackages ).then((_) => null); } -Future> assemble({ +Future buildAssets({ String manifestPath, - DevFSContent kernelContent, - File snapshotFile, - File dylibFile, - String outputPath, - String privateKeyPath: defaultPrivateKeyPath, String workingDirPath, String packagesPath, bool includeDefaultFonts: true, bool reportLicensedPackages: false }) async { - outputPath ??= defaultFlxOutputPath; workingDirPath ??= getAssetBuildDirectory(); packagesPath ??= fs.path.absolute(PackageMap.globalPackagesPath); - printTrace('Building $outputPath'); // Build the asset bundle. final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); @@ -121,7 +121,23 @@ Future> assemble({ reportLicensedPackages: reportLicensedPackages ); if (result != 0) - throwToolExit('Error building $outputPath: $result', exitCode: result); + return null; + + return assetBundle; +} + +Future> assemble({ + AssetBundle assetBundle, + DevFSContent kernelContent, + File snapshotFile, + File dylibFile, + String outputPath, + String privateKeyPath: defaultPrivateKeyPath, + String workingDirPath, +}) async { + outputPath ??= defaultFlxOutputPath; + workingDirPath ??= getAssetBuildDirectory(); + printTrace('Building $outputPath'); final ZipBuilder zipBuilder = new ZipBuilder();