diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart index 37f22077083..3808b83977b 100644 --- a/packages/flutter_tools/lib/src/asset.dart +++ b/packages/flutter_tools/lib/src/asset.dart @@ -52,9 +52,33 @@ class AssetBundle { static const String _kFontSetMaterial = 'material'; static const String _kFontSetRoboto = 'roboto'; + bool _fixed = false; DateTime _lastBuildTimestamp; + /// Constructs an [AssetBundle] that gathers the set of assets from the + /// flutter.yaml manifest. + AssetBundle(); + + /// Constructs an [AssetBundle] with a fixed set of assets. + /// [projectRoot] The absolute path to the project root. + /// [projectAssets] comma separated list of assets. + AssetBundle.fixed(String projectRoot, String projectAssets) { + _fixed = true; + if ((projectRoot == null) || (projectAssets == null)) + return; + + List assets = projectAssets.split(','); + for (String asset in assets) { + final String assetPath = path.join(projectRoot, asset); + final String archivePath = asset; + entries.add( + new AssetBundleEntry.fromFile(archivePath, new File(assetPath))); + } + } + bool needsBuild({String manifestPath: defaultManifestPath}) { + if (_fixed) + return false; if (_lastBuildTimestamp == null) return true; diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 03981eee914..92f6ef1d7fd 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -63,9 +63,12 @@ class RunCommand extends RunCommandBase { argParser.addOption('packages', hide: !verboseHelp, help: 'Specify the path to the .packages file.'); - argParser.addOption('project_root', + argParser.addOption('project-root', hide: !verboseHelp, help: 'Specify the project root directory.'); + argParser.addOption('project-assets', + hide: !verboseHelp, + help: 'Specify the project assets relative to the root directory.'); argParser.addFlag('machine', hide: !verboseHelp, help: 'Handle machine structured JSON command input\n' @@ -219,8 +222,9 @@ class RunCommand extends RunCommandBase { debuggingOptions: options, benchmarkMode: argResults['benchmark'], applicationBinary: argResults['use-application-binary'], - projectRootPath: argResults['project_root'], + projectRootPath: argResults['project-root'], packagesFilePath: argResults['packages'], + projectAssets: argResults['project-assets'] ); } else { runner = new RunAndStayResident( diff --git a/packages/flutter_tools/lib/src/hot.dart b/packages/flutter_tools/lib/src/hot.dart index 4f84a4c7bbe..d2753d7078e 100644 --- a/packages/flutter_tools/lib/src/hot.dart +++ b/packages/flutter_tools/lib/src/hot.dart @@ -99,6 +99,7 @@ class HotRunner extends ResidentRunner { this.applicationBinary, String projectRootPath, String packagesFilePath, + String projectAssets, }) : super(device, target: target, debuggingOptions: debuggingOptions, @@ -106,6 +107,10 @@ class HotRunner extends ResidentRunner { _projectRootPath = projectRootPath ?? Directory.current.path; _packagesFilePath = packagesFilePath ?? path.absolute(PackageMap.globalPackagesPath); + if (projectAssets != null) + _bundle = new AssetBundle.fixed(_projectRootPath, projectAssets); + else + _bundle = new AssetBundle(); } ApplicationPackage _package; @@ -116,7 +121,8 @@ class HotRunner extends ResidentRunner { bool get prebuiltMode => applicationBinary != null; Set _dartDependencies; int _observatoryPort; - final AssetBundle bundle = new AssetBundle(); + AssetBundle _bundle; + AssetBundle get bundle => _bundle; final bool benchmarkMode; final Map benchmarkData = new Map(); diff --git a/packages/flutter_tools/test/all.dart b/packages/flutter_tools/test/all.dart index 201f6675432..e70eda3428f 100644 --- a/packages/flutter_tools/test/all.dart +++ b/packages/flutter_tools/test/all.dart @@ -15,6 +15,7 @@ import 'analyze_duplicate_names_test.dart' as analyze_duplicate_names_test; import 'analyze_test.dart' as analyze_test; import 'android_device_test.dart' as android_device_test; import 'android_sdk_test.dart' as android_sdk_test; +import 'asset_bundle_test.dart' as asset_bundle_test; import 'application_package_test.dart' as application_package_test; import 'base_utils_test.dart' as base_utils_test; import 'channel_test.dart' as channel_test; @@ -49,6 +50,7 @@ void main() { android_device_test.main(); android_sdk_test.main(); application_package_test.main(); + asset_bundle_test.main(); base_utils_test.main(); channel_test.main(); config_test.main(); diff --git a/packages/flutter_tools/test/asset_bundle_test.dart b/packages/flutter_tools/test/asset_bundle_test.dart new file mode 100644 index 00000000000..a4bb3672196 --- /dev/null +++ b/packages/flutter_tools/test/asset_bundle_test.dart @@ -0,0 +1,60 @@ +// Copyright 2016 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:io'; +import 'dart:convert'; +import 'package:flutter_tools/src/asset.dart'; +import 'package:path/path.dart' as path; +import 'package:test/test.dart'; + +void main() { + // Create a temporary directory and write a single file into it. + Directory tempDir = Directory.systemTemp.createTempSync(); + String projectRoot = tempDir.path; + String assetPath = 'banana.txt'; + String assetContents = 'banana'; + File tempFile = new File(path.join(projectRoot, assetPath)); + tempFile.parent.createSync(recursive: true); + tempFile.writeAsBytesSync(UTF8.encode(assetContents)); + + // Fixed asset bundle tests. + group('AssetBundle.fixed', () { + test('empty strings', () async { + expect(new AssetBundle.fixed(null, null), isNotNull); + expect(new AssetBundle.fixed('', ''), isNotNull); + expect(new AssetBundle.fixed(null, null).entries, isEmpty); + }); + test('does not need a rebuild', () async { + expect(new AssetBundle.fixed(null, null).needsBuild(), isFalse); + }); + test('single entry', () async { + AssetBundle ab = new AssetBundle.fixed('', 'apple.txt'); + expect(ab.entries, isNotEmpty); + expect(ab.entries.length, 1); + AssetBundleEntry entry = ab.entries.first; + expect(entry, isNotNull); + expect(entry.archivePath, 'apple.txt'); + }); + test('two entries', () async { + AssetBundle ab = new AssetBundle.fixed('', 'apple.txt,packages/flutter_gallery_assets/shrine/products/heels.png'); + expect(ab.entries, isNotEmpty); + expect(ab.entries.length, 2); + AssetBundleEntry firstEntry = ab.entries.first; + expect(firstEntry, isNotNull); + expect(firstEntry.archivePath, 'apple.txt'); + AssetBundleEntry lastEntry = ab.entries.last; + expect(lastEntry, isNotNull); + expect(lastEntry.archivePath, 'packages/flutter_gallery_assets/shrine/products/heels.png'); + }); + test('file contents', () async { + AssetBundle ab = new AssetBundle.fixed(projectRoot, assetPath); + expect(ab.entries, isNotEmpty); + expect(ab.entries.length, 1); + AssetBundleEntry entry = ab.entries.first; + expect(entry, isNotNull); + expect(entry.archivePath, assetPath); + expect(assetContents, UTF8.decode(entry.contentsAsBytes())); + }); + }); +}