Commit 3638f938 authored by Ian Fischer's avatar Ian Fischer

Merge pull request #46 from iansf/android_start

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