Unverified Commit 1859e82a authored by Todd Volkert's avatar Todd Volkert Committed by GitHub

Extensibility improvements to flutter_tools (#14299)

* Make the current command injected into the AppContext, allowing
  other classes to inject the current command.
* Introduce `AssetBundleFactory`, an injected factory class for
  spawning instances of `AssetBundle`. This allows other run contexts
  to use custom asset bundling logic.
* Clean up RunCommand by removing a 'packages' argument that duplicated
  a global argument by the same name (and for the same purpose).
  Duplicate arguments are confusing and error-prone.
parent 492e311c
......@@ -7,6 +7,7 @@ import 'dart:convert';
import 'package:yaml/yaml.dart';
import 'base/context.dart';
import 'base/file_system.dart';
import 'build_info.dart';
import 'cache.dart';
......@@ -15,8 +16,46 @@ import 'devfs.dart';
import 'flutter_manifest.dart';
import 'globals.dart';
/// A bundle of assets.
class AssetBundle {
const AssetBundleFactory _kManifestFactory = const _ManifestAssetBundleFactory();
/// Injected factory class for spawning [AssetBundle] instances.
abstract class AssetBundleFactory {
/// The singleton instance, pulled from the [AppContext].
static AssetBundleFactory get instance => context == null
? _kManifestFactory
: context.putIfAbsent(AssetBundleFactory, () => _kManifestFactory);
/// Creates a new [AssetBundle].
AssetBundle createBundle();
}
abstract class AssetBundle {
factory AssetBundle.fixed(String projectRoot, String projectAssets) =>
new _ManifestAssetBundle.fixed(projectRoot, projectAssets);
Map<String, DevFSContent> get entries;
bool needsBuild({String manifestPath: _ManifestAssetBundle.defaultManifestPath});
/// Returns 0 for success; non-zero for failure.
Future<int> build({
String manifestPath: _ManifestAssetBundle.defaultManifestPath,
String workingDirPath,
String packagesPath,
bool includeDefaultFonts: true,
bool reportLicensedPackages: false
});
}
class _ManifestAssetBundleFactory implements AssetBundleFactory {
const _ManifestAssetBundleFactory();
@override
AssetBundle createBundle() => new _ManifestAssetBundle();
}
class _ManifestAssetBundle implements AssetBundle {
@override
final Map<String, DevFSContent> entries = <String, DevFSContent>{};
static const String defaultManifestPath = 'pubspec.yaml';
......@@ -28,14 +67,14 @@ class AssetBundle {
bool _fixed = false;
DateTime _lastBuildTimestamp;
/// Constructs an [AssetBundle] that gathers the set of assets from the
/// Constructs an [_ManifestAssetBundle] that gathers the set of assets from the
/// pubspec.yaml manifest.
AssetBundle();
_ManifestAssetBundle();
/// Constructs an [AssetBundle] with a fixed set of assets.
/// Constructs an [_ManifestAssetBundle] 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) {
_ManifestAssetBundle.fixed(String projectRoot, String projectAssets) {
_fixed = true;
if ((projectRoot == null) || (projectAssets == null))
return;
......@@ -50,6 +89,7 @@ class AssetBundle {
}
}
@override
bool needsBuild({String manifestPath: defaultManifestPath}) {
if (_fixed)
return false;
......@@ -63,6 +103,7 @@ class AssetBundle {
return stat.modified.isAfter(_lastBuildTimestamp);
}
@override
Future<int> build({
String manifestPath: defaultManifestPath,
String workingDirPath,
......@@ -191,11 +232,6 @@ class AssetBundle {
return 0;
}
void dump() {
printTrace('Dumping AssetBundle:');
(entries.keys.toList()..sort()).forEach(printTrace);
}
}
class _Asset {
......@@ -369,7 +405,7 @@ List<Map<String, dynamic>> _parseFonts(
}) {
final List<Map<String, dynamic>> fonts = <Map<String, dynamic>>[];
if (manifest.usesMaterialDesign && includeDefaultFonts) {
fonts.addAll(_getMaterialFonts(AssetBundle._kFontSetMaterial));
fonts.addAll(_getMaterialFonts(_ManifestAssetBundle._kFontSetMaterial));
}
if (packageName == null) {
fonts.addAll(manifest.fontsDescriptor);
......
......@@ -109,10 +109,6 @@ class RunCommand extends RunCommandBase {
hide: !verboseHelp,
help: 'Turn on strong mode semantics.\n'
'Valid only when --preview-dart-2 is also specified');
argParser.addOption('packages',
hide: !verboseHelp,
valueHelp: 'path',
help: 'Specify the path to the .packages file.');
argParser.addOption('project-root',
hide: !verboseHelp,
help: 'Specify the project root directory.');
......@@ -260,7 +256,7 @@ class RunCommand extends RunCommandBase {
previewDart2: argResults['preview-dart-2'],
strongMode: argResults['strong'],
projectRootPath: argResults['project-root'],
packagesFilePath: argResults['packages'],
packagesFilePath: globalResults['packages'],
projectAssets: argResults['project-assets'],
ipv6: ipv6,
);
......@@ -313,7 +309,7 @@ class RunCommand extends RunCommandBase {
previewDart2: argResults['preview-dart-2'],
strongMode: argResults['strong'],
projectRootPath: argResults['project-root'],
packagesFilePath: argResults['packages'],
packagesFilePath: globalResults['packages'],
projectAssets: argResults['project-assets'],
stayResident: stayResident,
ipv6: ipv6,
......
......@@ -114,7 +114,7 @@ Future<List<String>> assemble({
printTrace('Building $outputPath');
// Build the asset bundle.
final AssetBundle assetBundle = new AssetBundle();
final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
final int result = await assetBundle.build(
manifestPath: manifestPath,
workingDirPath: workingDirPath,
......
......@@ -420,7 +420,7 @@ abstract class ResidentRunner {
if (projectAssets != null)
_assetBundle = new AssetBundle.fixed(_projectRootPath, projectAssets);
else
_assetBundle = new AssetBundle();
_assetBundle = AssetBundleFactory.instance.createBundle();
}
final List<FlutterDevice> flutterDevices;
......
......@@ -11,6 +11,7 @@ import 'package:quiver/strings.dart';
import '../application_package.dart';
import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/utils.dart';
import '../build_info.dart';
......@@ -62,6 +63,11 @@ class FlutterOptions {
}
abstract class FlutterCommand extends Command<Null> {
/// The currently executing command (or sub-command).
///
/// Will be `null` until the top-most command has begun execution.
static FlutterCommand get current => context[FlutterCommand];
@override
ArgParser get argParser => _argParser;
final ArgParser _argParser = new ArgParser(allowTrailingOptions: false);
......@@ -203,6 +209,8 @@ abstract class FlutterCommand extends Command<Null> {
Future<Null> run() async {
final DateTime startTime = clock.now();
context.setVariable(FlutterCommand, this);
if (flutterUsage.isFirstRun)
flutterUsage.printWelcome();
......
......@@ -57,7 +57,7 @@ $fontsSection
List<String> packages,
String expectedAssetManifest,
) async {
final AssetBundle bundle = new AssetBundle();
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
await bundle.build(manifestPath: 'pubspec.yaml');
for (String packageName in packages) {
......@@ -121,7 +121,7 @@ $fontsSection
writePackagesFile('test_package:p/p/lib/');
writePubspecFile('p/p/pubspec.yaml', 'test_package');
final AssetBundle bundle = new AssetBundle();
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
await bundle.build(manifestPath: 'pubspec.yaml');
expect(bundle.entries.length, 2); // LICENSE, AssetManifest
expect(bundle.entries.containsKey('FontManifest.json'), false);
......
......@@ -64,7 +64,7 @@ $assetsSection
List<String> packages,
String expectedAssetManifest,
) async {
final AssetBundle bundle = new AssetBundle();
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
await bundle.build(manifestPath: 'pubspec.yaml');
for (String packageName in packages) {
......@@ -122,7 +122,7 @@ $assetsSection
writePackagesFile('test_package:p/p/lib/');
writePubspecFile('p/p/pubspec.yaml', 'test_package');
final AssetBundle bundle = new AssetBundle();
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
await bundle.build(manifestPath: 'pubspec.yaml');
expect(bundle.entries.length, 2); // LICENSE, AssetManifest
final String expectedAssetManifest = '{}';
......@@ -142,7 +142,7 @@ $assetsSection
final List<String> assets = <String>['a/foo'];
writeAssets('p/p/', assets);
final AssetBundle bundle = new AssetBundle();
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
await bundle.build(manifestPath: 'pubspec.yaml');
expect(bundle.entries.length, 2); // LICENSE, AssetManifest
final String expectedAssetManifest = '{}';
......
......@@ -97,8 +97,8 @@ void main() {
}
});
test('nonempty', () async {
final AssetBundle ab = new AssetBundle();
testUsingContext('nonempty', () async {
final AssetBundle ab = AssetBundleFactory.instance.createBundle();
expect(await ab.build(), 0);
expect(ab.entries.length, greaterThan(0));
});
......@@ -108,7 +108,7 @@ void main() {
..createSync()
..writeAsStringSync('');
final AssetBundle bundle = new AssetBundle();
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
await bundle.build(manifestPath: 'pubspec.yaml');
expect(bundle.entries.length, 1);
final String expectedAssetManifest = '{}';
......
......@@ -71,7 +71,7 @@ flutter:
..writeAsStringSync(asset);
}
AssetBundle bundle = new AssetBundle();
AssetBundle bundle = AssetBundleFactory.instance.createBundle();
await bundle.build(manifestPath: 'pubspec.yaml');
// The main asset file, /a/b/c/foo, and its variants exist.
......@@ -81,7 +81,7 @@ flutter:
}
fs.file('a/b/c/foo').deleteSync();
bundle = new AssetBundle();
bundle = AssetBundleFactory.instance.createBundle();
await bundle.build(manifestPath: 'pubspec.yaml');
// Now the main asset file, /a/b/c/foo, does not exist. This is OK because
......
......@@ -29,7 +29,7 @@ void main() {
// This test intentionally does not use a memory file system to ensure
// that AssetBundle with fonts also works on Windows.
testUsingContext('app font uses local font file', () async {
final AssetBundle asset = new AssetBundle();
final AssetBundle asset = AssetBundleFactory.instance.createBundle();
await asset.build(
manifestPath : fs.path.join(dataPath, 'main', 'pubspec.yaml'),
packagesPath: fs.path.join(dataPath, 'main', '.packages'),
......
......@@ -27,7 +27,7 @@ void main() {
Directory tempDir;
String basePath;
DevFS devFS;
final AssetBundle assetBundle = new AssetBundle();
final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
setUpAll(() {
fs = new MemoryFileSystem();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment