Commit cae053c3 authored by Ian Fischer's avatar Ian Fischer

Refactor all the commands to be Commands from the Args package. Also use...

Refactor all the commands to be Commands from the Args package.  Also use CommandRunner for the top-level command.
parent a49120c6
This diff is collapsed.
...@@ -8,11 +8,10 @@ import 'dart:async'; ...@@ -8,11 +8,10 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'package:args/args.dart'; import 'package:args/command_runner.dart';
import 'package:yaml/yaml.dart'; import 'package:yaml/yaml.dart';
import 'artifacts.dart'; import 'artifacts.dart';
import 'common.dart';
const String _kSnapshotKey = 'snapshot_blob.bin'; const String _kSnapshotKey = 'snapshot_blob.bin';
const List<String> _kDensities = const ['drawable-xxhdpi']; const List<String> _kDensities = const ['drawable-xxhdpi'];
...@@ -127,41 +126,33 @@ Future<ArchiveFile> _createSnapshotFile(String snapshotPath) async { ...@@ -127,41 +126,33 @@ Future<ArchiveFile> _createSnapshotFile(String snapshotPath) async {
return new ArchiveFile(_kSnapshotKey, content.length, content); return new ArchiveFile(_kSnapshotKey, content.length, content);
} }
class BuildCommandHandler extends CommandHandler { class BuildCommand extends Command {
BuildCommandHandler() : super('build', 'Create a Flutter app.'); final name = 'build';
final description = 'Create a Flutter app.';
ArgParser get parser { BuildCommand() {
ArgParser parser = new ArgParser(); argParser.addOption('asset-base', defaultsTo: 'packages/material_design_icons/icons');
parser.addFlag('help', abbr: 'h', negatable: false); argParser.addOption('compiler');
parser.addOption('asset-base', defaultsTo: 'packages/material_design_icons/icons'); argParser.addOption('main', defaultsTo: 'lib/main.dart');
parser.addOption('compiler'); argParser.addOption('manifest');
parser.addOption('main', defaultsTo: 'lib/main.dart'); argParser.addOption('output-file', abbr: 'o', defaultsTo: 'app.flx');
parser.addOption('manifest'); argParser.addOption('package-root', defaultsTo: 'packages');
parser.addOption('output-file', abbr: 'o', defaultsTo: 'app.flx'); argParser.addOption('snapshot', defaultsTo: 'snapshot_blob.bin');
parser.addOption('package-root', defaultsTo: 'packages');
parser.addOption('snapshot', defaultsTo: 'snapshot_blob.bin');
return parser;
} }
@override @override
Future<int> processArgResults(ArgResults results) async { Future<int> run() async {
if (results['help']) { String manifestPath = argResults['manifest'];
print(parser.usage);
return 0;
}
String manifestPath = results['manifest'];
Map manifestDescriptor = await _loadManifest(manifestPath); Map manifestDescriptor = await _loadManifest(manifestPath);
Iterable<_Asset> assets = _parseAssets(manifestDescriptor, manifestPath); Iterable<_Asset> assets = _parseAssets(manifestDescriptor, manifestPath);
Iterable<_MaterialAsset> materialAssets = _parseMaterialAssets(manifestDescriptor); Iterable<_MaterialAsset> materialAssets = _parseMaterialAssets(manifestDescriptor);
Archive archive = new Archive(); Archive archive = new Archive();
String snapshotPath = results['snapshot']; String snapshotPath = argResults['snapshot'];
await _compileSnapshot( await _compileSnapshot(
compilerPath: results['compiler'], compilerPath: argResults['compiler'],
mainPath: results['main'], mainPath: argResults['main'],
packageRoot: results['package-root'], packageRoot: argResults['package-root'],
snapshotPath: snapshotPath); snapshotPath: snapshotPath);
archive.addFile(await _createSnapshotFile(snapshotPath)); archive.addFile(await _createSnapshotFile(snapshotPath));
...@@ -169,12 +160,12 @@ class BuildCommandHandler extends CommandHandler { ...@@ -169,12 +160,12 @@ class BuildCommandHandler extends CommandHandler {
archive.addFile(await _createFile(asset.key, asset.base)); archive.addFile(await _createFile(asset.key, asset.base));
for (_MaterialAsset asset in materialAssets) { for (_MaterialAsset asset in materialAssets) {
ArchiveFile file = await _createFile(asset.key, results['asset-base']); ArchiveFile file = await _createFile(asset.key, argResults['asset-base']);
if (file != null) if (file != null)
archive.addFile(file); archive.addFile(file);
} }
File outputFile = new File(results['output-file']); File outputFile = new File(argResults['output-file']);
await outputFile.writeAsString('#!mojo mojo:sky_viewer\n'); await outputFile.writeAsString('#!mojo mojo:sky_viewer\n');
await outputFile.writeAsBytes(new ZipEncoder().encode(archive), mode: FileMode.APPEND); await outputFile.writeAsBytes(new ZipEncoder().encode(archive), mode: FileMode.APPEND);
return 0; return 0;
......
...@@ -6,63 +6,48 @@ library sky_tools.cache; ...@@ -6,63 +6,48 @@ library sky_tools.cache;
import 'dart:async'; import 'dart:async';
import 'package:args/args.dart'; import 'package:args/command_runner.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'artifacts.dart'; import 'artifacts.dart';
import 'common.dart';
final Logger _logging = new Logger('sky_tools.cache'); final Logger _logging = new Logger('sky_tools.cache');
class CacheCommandHandler extends CommandHandler { class CacheCommand extends Command {
CacheCommandHandler() : super('cache', 'Manages sky_tools\' cache of binary artifacts.'); final name = 'cache';
final description = 'Manages sky_tools\' cache of binary artifacts.';
ArgParser get parser { CacheCommand() {
ArgParser parser = new ArgParser(); addSubcommand(new _ClearCommand());
parser.addFlag('help', abbr: 'h', negatable: false); addSubcommand(new _PopulateCommand());
parser.addOption('package-root', defaultsTo: 'packages');
ArgParser clearParser = parser.addCommand('clear');
clearParser.addFlag('help', abbr: 'h', negatable: false);
ArgParser populateParser = parser.addCommand('populate');
populateParser.addFlag('help', abbr: 'h', negatable: false);
return parser;
} }
}
Future<int> _clear(String packageRoot, ArgResults results) async { class _ClearCommand extends Command {
if (results['help']) { final name = 'clear';
print('Clears all artifacts from the cache.'); final description = 'Clears all artifacts from the cache.';
print(parser.usage); _ClearCommand() {
return 0; argParser.addOption('package-root', defaultsTo: 'packages');
}
ArtifactStore artifacts = new ArtifactStore(packageRoot);
await artifacts.clear();
return 0;
} }
Future<int> _populate(String packageRoot, ArgResults results) async { @override
if (results['help']) { Future<int> run() async {
print('Populates the cache with all known artifacts.'); ArtifactStore artifacts = new ArtifactStore(argResults['package-root']);
print(parser.usage);
return 0;
}
ArtifactStore artifacts = new ArtifactStore(packageRoot);
await artifacts.populate(); await artifacts.populate();
return 0; return 0;
} }
}
class _PopulateCommand extends Command {
final name = 'populate';
final description = 'Populates the cache with all known artifacts.';
_PopulateCommand() {
argParser.addOption('package-root', defaultsTo: 'packages');
}
@override @override
Future<int> processArgResults(ArgResults results) async { Future<int> run() async {
if (results['help'] || results.command == null) { ArtifactStore artifacts = new ArtifactStore(argResults['package-root']);
print(parser.usage); await artifacts.populate();
return 0; return 0;
}
if (results.command.name == 'clear') {
return _clear(results['package-root'], results.command);
} else if (results.command.name == 'populate') {
return _populate(results['package-root'], results.command);
} else {
_logging.severe('Unknown cache command \"${results.command.name}\"');
return 2;
}
} }
} }
// 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';
import 'package:args/args.dart';
abstract class CommandHandler {
final String name;
final String description;
CommandHandler(this.name, this.description);
ArgParser get parser;
/// Returns 0 for no errors or warnings executing command, 1 for warnings, 2
/// for errors.
Future<int> processArgResults(ArgResults results);
void printUsage([String message]) {
if (message != null) {
print('${message}\n');
}
print('usage: sky_tools ${name} [arguments]');
print('');
print(parser.usage);
}
String toString() => name;
}
...@@ -9,8 +9,8 @@ import 'dart:io'; ...@@ -9,8 +9,8 @@ import 'dart:io';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'process_wrapper.dart';
import 'application_package.dart'; import 'application_package.dart';
import 'process_wrapper.dart';
final Logger _logging = new Logger('sky_tools.device'); final Logger _logging = new Logger('sky_tools.device');
......
...@@ -7,41 +7,30 @@ library sky_tools.init; ...@@ -7,41 +7,30 @@ library sky_tools.init;
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:args/args.dart'; import 'package:args/command_runner.dart';
import 'package:mustache4dart/mustache4dart.dart' as mustache; import 'package:mustache4dart/mustache4dart.dart' as mustache;
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'common.dart'; class InitCommand extends Command {
final name = 'init';
class InitCommandHandler extends CommandHandler { final description = 'Create a new sky project.';
InitCommandHandler() : super('init', 'Create a new sky project.'); InitCommand() {
argParser.addOption('out', abbr: 'o', help: 'The output directory.');
ArgParser get parser { argParser.addFlag('pub',
// TODO: Add a --template option for template selection when we have more than one.
ArgParser parser = new ArgParser();
parser.addFlag('help',
abbr: 'h', negatable: false, help: 'Display this help message.');
parser.addOption('out', abbr: 'o', help: 'The output directory.');
parser.addFlag('pub',
defaultsTo: true, defaultsTo: true,
help: 'Whether to run pub after the project has been created.'); help: 'Whether to run pub after the project has been created.');
return parser;
} }
@override @override
Future<int> processArgResults(ArgResults results) async { Future<int> run() async {
if (results['help']) { if (!argResults.wasParsed('out')) {
printUsage(); print('No option specified for the output directory.');
return 0; print(argParser.getUsage());
}
if (!results.wasParsed('out')) {
printUsage('No option specified for the output directory.');
return 2; return 2;
} }
// TODO: Confirm overwrite of an existing directory with the user. // TODO: Confirm overwrite of an existing directory with the user.
Directory out = new Directory(results['out']); Directory out = new Directory(argResults['out']);
new SkySimpleTemplate().generateInto(out); new SkySimpleTemplate().generateInto(out);
...@@ -58,7 +47,7 @@ Or if the Sky APK is not already on your device, run: ...@@ -58,7 +47,7 @@ Or if the Sky APK is not already on your device, run:
'''; ''';
if (results['pub']) { if (argResults['pub']) {
print("Running pub get..."); print("Running pub get...");
Process process = Process process =
await Process.start('pub', ['get'], workingDirectory: out.path); await Process.start('pub', ['get'], workingDirectory: out.path);
......
...@@ -6,32 +6,19 @@ library sky_tools.install; ...@@ -6,32 +6,19 @@ library sky_tools.install;
import 'dart:async'; import 'dart:async';
import 'package:args/args.dart'; import 'package:args/command_runner.dart';
import 'application_package.dart'; import 'application_package.dart';
import 'common.dart';
import 'device.dart'; import 'device.dart';
class InstallCommandHandler extends CommandHandler { class InstallCommand extends Command {
final name = 'install';
final description = 'Install your Flutter app on attached devices.';
AndroidDevice android = null; AndroidDevice android = null;
InstallCommandHandler([this.android]) InstallCommand([this.android]);
: super('install', 'Install your Sky app on attached devices.');
@override @override
ArgParser get parser { Future<int> run() async {
ArgParser parser = new ArgParser();
parser.addFlag('help',
abbr: 'h', negatable: false, help: 'Display this help message.');
return parser;
}
@override
Future<int> processArgResults(ArgResults results) async {
if (results['help']) {
printUsage();
return 0;
}
bool installedSomewhere = false; bool installedSomewhere = false;
Map<BuildPlatform, ApplicationPackage> packages = Map<BuildPlatform, ApplicationPackage> packages =
......
...@@ -8,26 +8,23 @@ import 'dart:async'; ...@@ -8,26 +8,23 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:args/args.dart'; import 'package:args/args.dart';
import 'package:args/command_runner.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'artifacts.dart'; import 'artifacts.dart';
import 'common.dart';
import 'process.dart'; import 'process.dart';
final Logger _logging = new Logger('sky_tools.run_mojo'); final Logger _logging = new Logger('sky_tools.run_mojo');
class RunMojoCommandHandler extends CommandHandler { class RunMojoCommand extends Command {
RunMojoCommandHandler() : super('run_mojo', 'Run a Flutter app in mojo.'); final name = 'run_mojo';
final description = 'Run a Flutter app in mojo.';
ArgParser get parser { RunMojoCommand() {
ArgParser parser = new ArgParser(); argParser.addFlag('android', negatable: false, help: 'Run on an Android device');
parser.addFlag('android', negatable: false, help: 'Run on an Android device'); argParser.addOption('app', defaultsTo: 'app.flx');
parser.addFlag('help', abbr: 'h', negatable: false); argParser.addOption('mojo-path', help: 'Path to directory containing mojo_shell and services');
parser.addOption('app', defaultsTo: 'app.flx'); argParser.addOption('package-root', defaultsTo: 'packages');
parser.addOption('mojo-path', help: 'Path to directory containing mojo_shell and services');
parser.addOption('package-root', defaultsTo: 'packages');
return parser;
} }
Future<String> _makePathAbsolute(String relativePath) async { Future<String> _makePathAbsolute(String relativePath) async {
...@@ -71,22 +68,18 @@ class RunMojoCommandHandler extends CommandHandler { ...@@ -71,22 +68,18 @@ class RunMojoCommandHandler extends CommandHandler {
} }
@override @override
Future<int> processArgResults(ArgResults results) async { Future<int> run() async {
if (results['help']) { if (argResults['mojo-path'] == null) {
print(parser.usage);
return 0;
}
if (results['mojo-path'] == null) {
_logging.severe('Must specify --mojo-path to mojo_run'); _logging.severe('Must specify --mojo-path to mojo_run');
return 1; return 1;
} }
String packageRoot = results['package-root']; String packageRoot = argResults['package-root'];
ArtifactStore artifacts = new ArtifactStore(packageRoot); ArtifactStore artifacts = new ArtifactStore(packageRoot);
String appPath = await _makePathAbsolute(results['app']); String appPath = await _makePathAbsolute(argResults['app']);
if (results['android']) { if (argResults['android']) {
return _runAndroid(results, appPath, artifacts); return _runAndroid(argResults, appPath, artifacts);
} else { } else {
return _runLinux(results, appPath, artifacts); return _runLinux(argResults, appPath, artifacts);
} }
} }
} }
...@@ -4,13 +4,11 @@ ...@@ -4,13 +4,11 @@
import 'dart:io'; import 'dart:io';
import 'package:mockito/mockito.dart'; import 'package:args/command_runner.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:sky_tools/src/init.dart'; import 'package:sky_tools/src/init.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'src/common.dart';
main() => defineTests(); main() => defineTests();
defineTests() { defineTests() {
...@@ -27,14 +25,13 @@ defineTests() { ...@@ -27,14 +25,13 @@ defineTests() {
// Verify that we create a project that is well-formed. // Verify that we create a project that is well-formed.
test('init sky-simple', () async { test('init sky-simple', () async {
InitCommandHandler handler = new InitCommandHandler(); InitCommand command = new InitCommand();
MockArgResults results = new MockArgResults(); CommandRunner runner = new CommandRunner('test_flutter', '')
when(results['help']).thenReturn(false); ..addCommand(command);
when(results['pub']).thenReturn(true); await runner.run(['init', '--out', temp.path])
when(results.wasParsed('out')).thenReturn(true); .then((int code) => expect(code, equals(0)));
when(results['out']).thenReturn(temp.path);
await handler.processArgResults(results); String path = p.join(temp.path, 'lib', 'main.dart');
String path = p.join(temp.path, 'lib/main.dart');
expect(new File(path).existsSync(), true); expect(new File(path).existsSync(), true);
ProcessResult exec = Process.runSync( ProcessResult exec = Process.runSync(
'dartanalyzer', ['--fatal-warnings', path], 'dartanalyzer', ['--fatal-warnings', path],
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
library install_test; library install_test;
import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/install.dart';
import 'package:sky_tools/src/application_package.dart'; import 'package:sky_tools/src/application_package.dart';
import 'package:sky_tools/src/install.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'src/common.dart'; import 'src/common.dart';
...@@ -23,12 +24,11 @@ defineTests() { ...@@ -23,12 +24,11 @@ defineTests() {
MockAndroidDevice android = new MockAndroidDevice(); MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(true); when(android.isConnected()).thenReturn(true);
when(android.installApp(any)).thenReturn(true); when(android.installApp(any)).thenReturn(true);
InstallCommandHandler handler = new InstallCommandHandler(android); InstallCommand command = new InstallCommand(android);
MockArgResults results = new MockArgResults(); CommandRunner runner = new CommandRunner('test_flutter', '')
when(results['help']).thenReturn(false); ..addCommand(command);
handler runner.run(['install'])
.processArgResults(results)
.then((int code) => expect(code, equals(0))); .then((int code) => expect(code, equals(0)));
}); });
}); });
......
...@@ -2,15 +2,9 @@ ...@@ -2,15 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:args/args.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/device.dart'; import 'package:sky_tools/src/device.dart';
class MockArgResults extends Mock implements ArgResults {
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockAndroidDevice extends Mock implements AndroidDevice { class MockAndroidDevice extends Mock implements AndroidDevice {
@override @override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
......
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