Commit bdd20661 authored by Adam Barth's avatar Adam Barth

Teach sky_tools about prebuilt artifacts

This patch makes `flutter start` work without a clone of the engine git
repository. Making this work pulled a relatively large refactor of how the
commands interact with application packages and devices. Now commands that want
to interact with application packages or devices inherit from a common base
class that holds stores of those objects as members.

In production, the commands download and connect to devices based on the build
configuration stored on the FlutterCommandRunner. In testing, these fields are
used to mock out the real application package and devices.
parent a6a3f212
......@@ -2,14 +2,9 @@
// 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 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import 'src/application_package.dart';
import 'src/artifacts.dart';
import 'src/commands/flutter_command_runner.dart';
import 'src/commands/build.dart';
import 'src/commands/cache.dart';
import 'src/commands/init.dart';
......@@ -22,136 +17,20 @@ import 'src/commands/start.dart';
import 'src/commands/stop.dart';
import 'src/commands/trace.dart';
class _FlutterCommandRunner extends CommandRunner {
_FlutterCommandRunner()
: super('flutter', 'Manage your Flutter app development.') {
argParser.addFlag('verbose',
abbr: 'v',
negatable: false,
help: 'Noisy logging, including all shell commands executed.');
argParser.addFlag('very-verbose',
negatable: false,
help: 'Very noisy logging, including the output of all '
'shell commands executed.');
argParser.addSeparator('Global build selection options:');
argParser.addFlag('debug',
negatable: false,
help:
'Set this if you are building Sky locally and want to use the debug build products. '
'When set, attempts to automaticaly determine sky-src-path if sky-src-path is '
'not set. Not normally required.');
argParser.addFlag('release',
negatable: false,
help:
'Set this if you are building Sky locally and want to use the release build products. '
'When set, attempts to automaticaly determine sky-src-path if sky-src-path is '
'not set. Note that release is not compatible with the listen command '
'on iOS devices and simulators. Not normally required.');
argParser.addOption('sky-src-path',
help:
'Path to your Sky src directory, if you are building Sky locally. '
'Ignored if neither debug nor release is set. Not normally required.');
argParser.addOption('android-debug-build-path',
help:
'Path to your Android Debug out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/android_Debug/');
argParser.addOption('android-release-build-path',
help:
'Path to your Android Release out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/android_Release/');
argParser.addOption('ios-debug-build-path',
help:
'Path to your iOS Debug out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/ios_Debug/');
argParser.addOption('ios-release-build-path',
help:
'Path to your iOS Release out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/ios_Release/');
argParser.addOption('ios-sim-debug-build-path',
help:
'Path to your iOS Simulator Debug out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/ios_sim_Debug/');
argParser.addOption('ios-sim-release-build-path',
help:
'Path to your iOS Simulator Release out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/ios_sim_Release/');
argParser.addOption('package-root',
help: 'Path to your packages directory.', defaultsTo: 'packages');
}
Future<int> runCommand(ArgResults topLevelResults) async {
if (topLevelResults['verbose']) {
Logger.root.level = Level.INFO;
}
if (topLevelResults['very-verbose']) {
Logger.root.level = Level.FINE;
}
_setupPaths(topLevelResults);
return super.runCommand(topLevelResults);
}
void _setupPaths(ArgResults results) {
ArtifactStore.packageRoot = results['package-root'];
if (results['debug'] || results['release']) {
if (results['sky-src-path'] == null) {
// TODO(iansf): Figure out how to get the default src path
assert(false);
}
ApplicationPackageFactory.srcPath = results['sky-src-path'];
} else {
assert(false);
// TODO(iansf): set paths up for commands using PREBUILT binaries
// ApplicationPackageFactory.setBuildPath(BuildType.PREBUILT,
// BuildPlatform.android, results['android-debug-build-path']);
}
if (results['debug']) {
ApplicationPackageFactory.defaultBuildType = BuildType.debug;
ApplicationPackageFactory.setBuildPath(BuildType.debug,
BuildPlatform.android, results['android-debug-build-path']);
ApplicationPackageFactory.setBuildPath(
BuildType.debug, BuildPlatform.iOS, results['ios-debug-build-path']);
ApplicationPackageFactory.setBuildPath(BuildType.debug,
BuildPlatform.iOSSimulator, results['ios-sim-debug-build-path']);
}
if (results['release']) {
ApplicationPackageFactory.defaultBuildType = BuildType.release;
ApplicationPackageFactory.setBuildPath(BuildType.release,
BuildPlatform.android, results['android-release-build-path']);
ApplicationPackageFactory.setBuildPath(BuildType.release,
BuildPlatform.iOS, results['ios-release-build-path']);
ApplicationPackageFactory.setBuildPath(BuildType.release,
BuildPlatform.iOSSimulator, results['ios-sim-release-build-path']);
}
}
}
/// Main entry point for commands.
///
/// This function is intended to be used from the [flutter] command line tool.
void main(List<String> args) {
Logger.root.level = Level.WARNING;
Logger.root.onRecord.listen((LogRecord rec) {
print('${rec.level.name}: ${rec.message}');
if (rec.error != null) {
print(rec.error);
}
if (rec.stackTrace != null) {
print(rec.stackTrace);
}
Logger.root.onRecord.listen((LogRecord record) {
print('${record.level.name}: ${record.message}');
if (record.error != null)
print(record.error);
if (record.stackTrace != null)
print(record.stackTrace);
});
new _FlutterCommandRunner()
new FlutterCommandRunner()
..addCommand(new BuildCommand())
..addCommand(new CacheCommand())
..addCommand(new InitCommand())
......
......@@ -2,137 +2,119 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.application_package;
import 'dart:io';
import 'dart:async';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'artifacts.dart';
import 'build_configuration.dart';
final Logger _logging = new Logger('sky_tools.application_package');
abstract class ApplicationPackage {
/// Path to the directory the apk or bundle lives in.
String appDir;
/// Path to the actual apk or bundle.
String get appPath => path.join(appDir, appFileName);
final String localPath;
/// Package ID from the Android Manifest or equivalent.
String appPackageID;
final String id;
/// File name of the apk or bundle.
String appFileName;
ApplicationPackage(this.appDir, this.appPackageID, this.appFileName);
final String name;
ApplicationPackage({
String localPath,
this.id
}) : localPath = localPath, name = path.basename(localPath) {
assert(localPath != null);
assert(id != null);
}
}
class AndroidApk extends ApplicationPackage {
static const String _apkName = 'SkyShell.apk';
static const String _packageID = 'org.domokit.sky.shell';
static const String _componentID = '$_packageID/$_packageID.SkyActivity';
static const String _defaultName = 'SkyShell.apk';
static const String _defaultId = 'org.domokit.sky.shell';
static const String _defaultLaunchActivity = '$_defaultId/$_defaultId.SkyActivity';
/// The path to the activity that should be launched.
/// Defaults to 'org.domokit.sky.shell/org.domokit.sky.shell.SkyActivity'
String component;
AndroidApk(String appDir,
{String appPackageID: _packageID,
String appFileName: _apkName,
this.component: _componentID})
: super(path.join(appDir, 'apks'), appPackageID, appFileName);
final String launchActivity;
AndroidApk({
String localPath,
String id: _defaultId,
this.launchActivity: _defaultLaunchActivity
}) : super(localPath: localPath, id: id) {
assert(launchActivity != null);
}
}
class IOSApp extends ApplicationPackage {
static const String _appName = 'SkyShell.app';
static const String _packageID = 'com.google.SkyShell';
static const String _defaultName = 'SkyShell.app';
static const String _defaultId = 'com.google.SkyShell';
IOSApp(String appDir,
{String appPackageID: _packageID, String appFileName: _appName})
: super(appDir, appPackageID, appFileName);
IOSApp({
String localPath,
String id: _defaultId
}) : super(localPath: localPath, id: id);
}
enum BuildType { prebuilt, release, debug, }
enum BuildPlatform { android, iOS, iOSSimulator, mac, linux, }
class ApplicationPackageFactory {
static final Map<BuildPlatform, Map<BuildType, String>> _buildPaths =
_initBuildPaths();
/// Path to your Sky src directory, if you are building Sky locally.
/// Required if you are requesting release or debug BuildTypes.
static String _srcPath = null;
static String get srcPath => _srcPath;
static void set srcPath(String newPath) {
_srcPath = path.normalize(newPath);
class ApplicationPackageStore {
final AndroidApk android;
final IOSApp iOS;
final IOSApp iOSSimulator;
ApplicationPackageStore({ this.android, this.iOS, this.iOSSimulator });
ApplicationPackage getPackageForPlatform(BuildPlatform platform) {
switch (platform) {
case BuildPlatform.android:
return android;
case BuildPlatform.iOS:
return iOS;
case BuildPlatform.iOSSimulator:
return iOSSimulator;
case BuildPlatform.mac:
case BuildPlatform.linux:
return null;
}
}
/// Default BuildType chosen if no BuildType is specified.
static BuildType defaultBuildType = BuildType.prebuilt;
/// Default BuildPlatforms chosen if no BuildPlatforms are specified.
static List<BuildPlatform> defaultBuildPlatforms = [
BuildPlatform.android,
BuildPlatform.iOS,
BuildPlatform.iOSSimulator,
];
static Map<BuildPlatform, ApplicationPackage> getAvailableApplicationPackages(
{BuildType requestedType, List<BuildPlatform> requestedPlatforms}) {
if (requestedType == null) {
requestedType = defaultBuildType;
}
if (requestedPlatforms == null) {
requestedPlatforms = defaultBuildPlatforms;
}
static Future<ApplicationPackageStore> forConfigs(List<BuildConfiguration> configs) async {
AndroidApk android;
IOSApp iOS;
IOSApp iOSSimulator;
Map<BuildPlatform, ApplicationPackage> packages = {};
for (BuildPlatform platform in requestedPlatforms) {
String buildPath = _getBuildPath(requestedType, platform);
switch (platform) {
for (BuildConfiguration config in configs) {
switch (config.platform) {
case BuildPlatform.android:
packages[platform] = new AndroidApk(buildPath);
assert(android == null);
String localPath = config.type == BuildType.prebuilt ?
await ArtifactStore.getPath(Artifact.flutterShell) :
path.join(config.buildDir, 'apks', AndroidApk._defaultName);
android = new AndroidApk(localPath: localPath);
break;
case BuildPlatform.iOS:
packages[platform] = new IOSApp(buildPath);
assert(iOS == null);
assert(config.type != BuildType.prebuilt);
iOS = new IOSApp(localPath: path.join(config.buildDir, IOSApp._defaultName));
break;
case BuildPlatform.iOSSimulator:
packages[platform] = new IOSApp(buildPath);
assert(iOSSimulator == null);
assert(config.type != BuildType.prebuilt);
iOSSimulator = new IOSApp(localPath: path.join(config.buildDir, IOSApp._defaultName));
break;
default:
// TODO(iansf): Add other platforms
case BuildPlatform.mac:
case BuildPlatform.linux:
// TODO(abarth): Support mac and linux targets.
assert(false);
break;
}
}
return packages;
}
static Map<BuildPlatform, Map<BuildType, String>> _initBuildPaths() {
Map<BuildPlatform, Map<BuildType, String>> buildPaths = {};
for (BuildPlatform platform in BuildPlatform.values) {
buildPaths[platform] = {};
}
return buildPaths;
}
static String _getBuildPath(BuildType type, BuildPlatform platform) {
String path = _buildPaths[platform][type];
// You must set paths before getting them
assert(path != null);
return path;
}
static void setBuildPath(
BuildType type, BuildPlatform platform, String buildPath) {
// You must set srcPath before attempting to set a BuildPath for
// non prebuilt ApplicationPackages.
assert(type != BuildType.prebuilt || srcPath != null);
if (type != BuildType.prebuilt) {
buildPath = path.join(srcPath, buildPath);
}
if (!FileSystemEntity.isDirectorySync(buildPath)) {
_logging.warning('$buildPath is not a valid directory');
}
_buildPaths[platform][type] = path.normalize(buildPath);
return new ApplicationPackageStore(android: android, iOS: iOS, iOSSimulator: iOSSimulator);
}
}
......@@ -12,7 +12,11 @@ import 'package:path/path.dart' as path;
final Logger _logging = new Logger('sky_tools.artifacts');
enum Artifact { FlutterCompiler, SkyViewerMojo, }
enum Artifact {
flutterCompiler,
flutterShell,
skyViewerMojo,
}
class ArtifactStore {
static String packageRoot;
......@@ -66,20 +70,27 @@ class ArtifactStore {
// Whether the artifact needs to be marked as executable on disk.
static bool _needsToBeExecutable(Artifact artifact) {
return artifact == Artifact.FlutterCompiler;
return artifact == Artifact.flutterCompiler;
}
static Future<String> getPath(Artifact artifact) async {
Directory cacheDir = await _engineSpecificCacheDir();
String category, name;
String category;
String platform;
String name;
switch (artifact) {
case Artifact.FlutterCompiler:
case Artifact.flutterCompiler:
category = 'shell';
name = 'sky_snapshot';
break;
case Artifact.SkyViewerMojo:
case Artifact.flutterShell:
category = 'shell';
platform = 'android-arm';
name = 'SkyShell.apk';
break;
case Artifact.skyViewerMojo:
category = 'viewer';
name = 'sky_viewer.mojo';
break;
......@@ -88,9 +99,12 @@ class ArtifactStore {
File cachedFile = new File(path.join(cacheDir.path, name));
if (!await cachedFile.exists()) {
_logging.info('Downloading ${name} from the cloud, one moment please...');
if (!Platform.isLinux)
throw new Exception('Platform unsupported.');
String url = googleStorageUrl(category, 'linux-x64') + name;
if (platform == null) {
if (!Platform.isLinux)
throw new Exception('Platform unsupported.');
platform = 'linux-x64';
}
String url = googleStorageUrl(category, platform) + name;
await _downloadFile(url, cachedFile);
if (_needsToBeExecutable(artifact)) {
ProcessResult result = await Process.run('chmod', ['u+x', cachedFile.path]);
......
// 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 'package:path/path.dart' as path;
enum BuildType {
prebuilt,
release,
debug,
}
enum BuildPlatform {
android,
iOS,
iOSSimulator,
mac,
linux,
}
class BuildConfiguration {
BuildConfiguration.prebuilt({ this.platform })
: type = BuildType.prebuilt, buildDir = null;
BuildConfiguration.local({
this.type,
this.platform,
String enginePath,
String buildPath
}) : buildDir = path.normalize(path.join(enginePath, buildPath)) {
assert(type == BuildType.debug || type == BuildType.release);
}
final BuildType type;
final BuildPlatform platform;
final String buildDir;
}
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.build;
import 'dart:async';
import 'dart:io';
......@@ -105,7 +103,7 @@ Future _compileSnapshot({
String snapshotPath
}) async {
if (compilerPath == null) {
compilerPath = await ArtifactStore.getPath(Artifact.FlutterCompiler);
compilerPath = await ArtifactStore.getPath(Artifact.flutterCompiler);
}
ProcessResult result = await Process.run(compilerPath, [
mainPath,
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.cache;
import 'dart:async';
import 'package:args/command_runner.dart';
......@@ -14,8 +12,8 @@ import '../artifacts.dart';
final Logger _logging = new Logger('sky_tools.cache');
class CacheCommand extends Command {
final name = 'cache';
final description = 'Manages sky_tools\' cache of binary artifacts.';
final String name = 'cache';
final String description = 'Manages sky_tools\' cache of binary artifacts.';
CacheCommand() {
addSubcommand(new _ClearCommand());
addSubcommand(new _PopulateCommand());
......@@ -23,8 +21,8 @@ class CacheCommand extends Command {
}
class _ClearCommand extends Command {
final name = 'clear';
final description = 'Clears all artifacts from the cache.';
final String name = 'clear';
final String description = 'Clears all artifacts from the cache.';
@override
Future<int> run() async {
......@@ -34,8 +32,8 @@ class _ClearCommand extends Command {
}
class _PopulateCommand extends Command {
final name = 'populate';
final description = 'Populates the cache with all known artifacts.';
final String name = 'populate';
final String description = 'Populates the cache with all known artifacts.';
@override
Future<int> run() async {
......
// 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/command_runner.dart';
import '../application_package.dart';
import '../device.dart';
import 'flutter_command_runner.dart';
abstract class FlutterCommand extends Command {
FlutterCommandRunner get runner => super.runner;
Future downloadApplicationPackages() async {
if (applicationPackages == null)
applicationPackages = await ApplicationPackageStore.forConfigs(runner.buildConfigurations);
}
void connectToDevices() {
if (devices == null)
devices = new DeviceStore.forConfigs(runner.buildConfigurations);
}
Future downloadApplicationPackagesAndConnectToDevices() async {
await downloadApplicationPackages();
connectToDevices();
}
void inheritFromParent(FlutterCommand other) {
applicationPackages = other.applicationPackages;
devices = other.devices;
}
ApplicationPackageStore applicationPackages;
DeviceStore devices;
}
// 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 'dart:io';
import 'package:args/args.dart';
import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import '../artifacts.dart';
import '../build_configuration.dart';
final Logger _logging = new Logger('sky_tools.flutter_command_runner');
class FlutterCommandRunner extends CommandRunner {
FlutterCommandRunner()
: super('flutter', 'Manage your Flutter app development.') {
argParser.addFlag('verbose',
abbr: 'v',
negatable: false,
help: 'Noisy logging, including all shell commands executed.');
argParser.addFlag('very-verbose',
negatable: false,
help: 'Very noisy logging, including the output of all '
'shell commands executed.');
argParser.addSeparator('Global build selection options:');
argParser.addFlag('debug',
negatable: false,
help:
'Set this if you are building Sky locally and want to use the debug build products. '
'When set, attempts to automaticaly determine sky-src-path if sky-src-path is '
'not set. Not normally required.');
argParser.addFlag('release',
negatable: false,
help:
'Set this if you are building Sky locally and want to use the release build products. '
'When set, attempts to automaticaly determine sky-src-path if sky-src-path is '
'not set. Note that release is not compatible with the listen command '
'on iOS devices and simulators. Not normally required.');
argParser.addOption('sky-src-path',
help:
'Path to your Sky src directory, if you are building Sky locally. '
'Ignored if neither debug nor release is set. Not normally required.');
argParser.addOption('android-debug-build-path',
help:
'Path to your Android Debug out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/android_Debug/');
argParser.addOption('android-release-build-path',
help:
'Path to your Android Release out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/android_Release/');
argParser.addOption('ios-debug-build-path',
help:
'Path to your iOS Debug out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/ios_Debug/');
argParser.addOption('ios-release-build-path',
help:
'Path to your iOS Release out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/ios_Release/');
argParser.addOption('ios-sim-debug-build-path',
help:
'Path to your iOS Simulator Debug out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/ios_sim_Debug/');
argParser.addOption('ios-sim-release-build-path',
help:
'Path to your iOS Simulator Release out directory, if you are building Sky locally. '
'This path is relative to sky-src-path. Not normally required.',
defaultsTo: 'out/ios_sim_Release/');
argParser.addOption('package-root',
help: 'Path to your packages directory.', defaultsTo: 'packages');
}
List<BuildConfiguration> buildConfigurations;
Future<int> runCommand(ArgResults globalResults) async {
if (globalResults['verbose'])
Logger.root.level = Level.INFO;
if (globalResults['very-verbose'])
Logger.root.level = Level.FINE;
ArtifactStore.packageRoot = globalResults['package-root'];
buildConfigurations = _createBuildConfigurations(globalResults);
return super.runCommand(globalResults);
}
List<BuildConfiguration> _createBuildConfigurations(ArgResults globalResults) {
// TODO(iansf): Figure out how to get the default src path
String enginePath = globalResults['sky-src-path'];
List<BuildConfiguration> configs = <BuildConfiguration>[];
if (enginePath == null) {
configs.add(new BuildConfiguration.prebuilt(platform: BuildPlatform.android));
} else {
if (!FileSystemEntity.isDirectorySync(enginePath))
_logging.warning('$enginePath is not a valid directory');
if (globalResults['debug']) {
configs.add(new BuildConfiguration.local(
type: BuildType.debug,
platform: BuildPlatform.android,
enginePath: enginePath,
buildPath: globalResults['android-debug-build-path']
));
if (Platform.isMacOS) {
configs.add(new BuildConfiguration.local(
type: BuildType.debug,
platform: BuildPlatform.iOS,
enginePath: enginePath,
buildPath: globalResults['ios-debug-build-path']
));
configs.add(new BuildConfiguration.local(
type: BuildType.debug,
platform: BuildPlatform.iOSSimulator,
enginePath: enginePath,
buildPath: globalResults['ios-sim-debug-build-path']
));
}
}
if (globalResults['release']) {
configs.add(new BuildConfiguration.local(
type: BuildType.release,
platform: BuildPlatform.android,
enginePath: enginePath,
buildPath: globalResults['android-release-build-path']
));
if (Platform.isMacOS) {
configs.add(new BuildConfiguration.local(
type: BuildType.release,
platform: BuildPlatform.iOS,
enginePath: enginePath,
buildPath: globalResults['ios-release-build-path']
));
configs.add(new BuildConfiguration.local(
type: BuildType.release,
platform: BuildPlatform.iOSSimulator,
enginePath: enginePath,
buildPath: globalResults['ios-sim-release-build-path']
));
}
}
}
return configs;
}
}
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.init;
import 'dart:async';
import 'dart:io';
......@@ -12,8 +10,8 @@ import 'package:mustache4dart/mustache4dart.dart' as mustache;
import 'package:path/path.dart' as p;
class InitCommand extends Command {
final name = 'init';
final description = 'Create a new Flutter project.';
final String name = 'init';
final String description = 'Create a new Flutter project.';
InitCommand() {
argParser.addOption('out', abbr: 'o', help: 'The output directory.');
......
......@@ -2,70 +2,39 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.install;
import 'dart:async';
import 'package:args/command_runner.dart';
import '../application_package.dart';
import '../device.dart';
import 'flutter_command.dart';
class InstallCommand extends Command {
final name = 'install';
final description = 'Install your Flutter app on attached devices.';
class InstallCommand extends FlutterCommand {
final String name = 'install';
final String description = 'Install your Flutter app on attached devices.';
AndroidDevice android;
IOSDevice ios;
IOSSimulator iosSim;
InstallCommand({this.android, this.ios, this.iosSim}) {
InstallCommand() {
argParser.addFlag('boot',
help: 'Boot the iOS Simulator if it isn\'t already running.');
}
@override
Future<int> run() async {
if (install(argResults['boot'])) {
return 0;
} else {
return 2;
}
await downloadApplicationPackagesAndConnectToDevices();
return install(boot: argResults['boot']) ? 0 : 2;
}
bool install([bool boot = false]) {
if (android == null) {
android = new AndroidDevice();
}
if (ios == null) {
ios = new IOSDevice();
}
if (iosSim == null) {
iosSim = new IOSSimulator();
}
if (boot) {
iosSim.boot();
}
bool install({ bool boot: false }) {
if (boot)
devices.iOSSimulator?.boot();
bool installedSomewhere = false;
Map<BuildPlatform, ApplicationPackage> packages =
ApplicationPackageFactory.getAvailableApplicationPackages();
ApplicationPackage androidApp = packages[BuildPlatform.android];
ApplicationPackage iosApp = packages[BuildPlatform.iOS];
ApplicationPackage iosSimApp = packages[BuildPlatform.iOSSimulator];
if (androidApp != null && android.isConnected()) {
installedSomewhere = android.installApp(androidApp) || installedSomewhere;
}
if (iosApp != null && ios.isConnected()) {
installedSomewhere = ios.installApp(iosApp) || installedSomewhere;
}
if (iosSimApp != null && iosSim.isConnected()) {
installedSomewhere = iosSim.installApp(iosSimApp) || installedSomewhere;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected())
continue;
if (device.installApp(package))
installedSomewhere = true;
}
return installedSomewhere;
......
......@@ -2,25 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.list;
import 'dart:async';
import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import 'flutter_command.dart';
import '../device.dart';
final Logger _logging = new Logger('sky_tools.list');
class ListCommand extends Command {
final name = 'list';
final description = 'List all connected devices.';
AndroidDevice android;
IOSDevice ios;
IOSSimulator iosSim;
class ListCommand extends FlutterCommand {
final String name = 'list';
final String description = 'List all connected devices.';
ListCommand({this.android, this.ios, this.iosSim}) {
ListCommand() {
argParser.addFlag('details',
abbr: 'd',
negatable: false,
......@@ -29,11 +24,14 @@ class ListCommand extends Command {
@override
Future<int> run() async {
connectToDevices();
bool details = argResults['details'];
if (details) {
if (details)
print('Android Devices:');
}
for (AndroidDevice device in AndroidDevice.getAttachedDevices(android)) {
for (AndroidDevice device in AndroidDevice.getAttachedDevices(devices.android)) {
if (details) {
print('${device.id}\t'
'${device.modelID}\t'
......@@ -44,10 +42,10 @@ class ListCommand extends Command {
}
}
if (details) {
if (details)
print('iOS Devices:');
}
for (IOSDevice device in IOSDevice.getAttachedDevices(ios)) {
for (IOSDevice device in IOSDevice.getAttachedDevices(devices.iOS)) {
if (details) {
print('${device.id}\t${device.name}');
} else {
......@@ -58,7 +56,7 @@ class ListCommand extends Command {
if (details) {
print('iOS Simulators:');
}
for (IOSSimulator device in IOSSimulator.getAttachedDevices(iosSim)) {
for (IOSSimulator device in IOSSimulator.getAttachedDevices(devices.iOSSimulator)) {
if (details) {
print('${device.id}\t${device.name}');
} else {
......
......@@ -2,45 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.listen;
import 'dart:async';
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import 'flutter_command.dart';
import '../application_package.dart';
import '../device.dart';
import '../process.dart';
final Logger _logging = new Logger('sky_tools.listen');
class ListenCommand extends Command {
final name = 'listen';
final description = 'Listen for changes to files and reload the running app '
'on all connected devices.';
AndroidDevice android;
IOSDevice ios;
IOSSimulator iosSim;
class ListenCommand extends FlutterCommand {
final String name = 'listen';
final String description = 'Listen for changes to files and reload the running app on all connected devices.';
List<String> watchCommand;
/// Only run once. Used for testing.
bool singleRun;
ListenCommand({this.android, this.ios, this.iosSim, this.singleRun: false}) {}
ListenCommand({ this.singleRun: false });
@override
Future<int> run() async {
if (android == null) {
android = new AndroidDevice();
}
if (ios == null) {
ios = new IOSDevice();
}
if (iosSim == null) {
iosSim = new IOSSimulator();
}
await downloadApplicationPackagesAndConnectToDevices();
if (argResults.rest.length > 0) {
watchCommand = _initWatchCommand(argResults.rest);
......@@ -48,14 +34,8 @@ class ListenCommand extends Command {
watchCommand = _initWatchCommand(['.']);
}
Map<BuildPlatform, ApplicationPackage> packages =
ApplicationPackageFactory.getAvailableApplicationPackages();
ApplicationPackage androidApp = packages[BuildPlatform.android];
ApplicationPackage iosApp = packages[BuildPlatform.iOS];
ApplicationPackage iosSimApp = packages[BuildPlatform.iOSSimulator];
while (true) {
_logging.info('Updating running Sky apps...');
_logging.info('Updating running Flutter apps...');
// TODO(iansf): refactor build command so that this doesn't have
// to call out like this.
......@@ -76,25 +56,29 @@ class ListenCommand extends Command {
} catch (e) {}
runSync(command);
String localFLXPath = 'app.flx';
String remoteFLXPath = 'Documents/app.flx';
if (ios.isConnected()) {
await ios.pushFile(iosApp, localFLXPath, remoteFLXPath);
}
if (iosSim.isConnected()) {
await iosSim.pushFile(iosSimApp, localFLXPath, remoteFLXPath);
}
if (android.isConnected()) {
await android.startServer(
argResults['target'], true, argResults['checked'], androidApp);
String localFlutterBundle = 'app.flx';
String remoteFlutterBundle = 'Documents/app.flx';
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected())
continue;
if (device is AndroidDevice) {
await devices.android.startServer(
argResults['target'], true, argResults['checked'], package);
} else if (device is IOSDevice) {
device.pushFile(package, localFlutterBundle, remoteFlutterBundle);
} else if (device is IOSSimulator) {
// TODO(abarth): Move pushFile up to Device once Android supports
// pushing new bundles.
device.pushFile(package, localFlutterBundle, remoteFlutterBundle);
} else {
assert(false);
}
}
if (singleRun || !watchDirectory()) {
if (singleRun || !watchDirectory())
break;
}
}
return 0;
......@@ -135,9 +119,8 @@ class ListenCommand extends Command {
}
bool watchDirectory() {
if (watchCommand == null) {
if (watchCommand == null)
return false;
}
try {
runCheckedSync(watchCommand);
......@@ -145,6 +128,7 @@ class ListenCommand extends Command {
_logging.warning('Watching directories failed.', e);
return false;
}
return true;
}
}
......@@ -2,25 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.logs;
import 'dart:async';
import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import 'flutter_command.dart';
import '../device.dart';
final Logger _logging = new Logger('sky_tools.logs');
class LogsCommand extends Command {
class LogsCommand extends FlutterCommand {
final name = 'logs';
final description = 'Show logs for running Sky apps.';
AndroidDevice android;
IOSDevice ios;
IOSSimulator iosSim;
LogsCommand({this.android, this.ios, this.iosSim}) {
LogsCommand() {
argParser.addFlag('clear',
negatable: false,
help: 'Clear log history before reading from logs (Android only).');
......@@ -28,42 +23,15 @@ class LogsCommand extends Command {
@override
Future<int> run() async {
if (android == null) {
android = new AndroidDevice();
}
if (ios == null) {
ios = new IOSDevice();
}
if (iosSim == null) {
iosSim = new IOSSimulator();
}
Future<int> androidLogProcess = null;
if (android.isConnected()) {
androidLogProcess = android.logs(clear: argResults['clear']);
}
Future<int> iosLogProcess = null;
if (ios.isConnected()) {
iosLogProcess = ios.logs(clear: argResults['clear']);
}
Future<int> iosSimLogProcess = null;
if (iosSim.isConnected()) {
iosSimLogProcess = iosSim.logs(clear: argResults['clear']);
}
connectToDevices();
if (androidLogProcess != null) {
await androidLogProcess;
}
bool clear = argResults['clear'];
if (iosLogProcess != null) {
await iosLogProcess;
}
Iterable<Future<int>> results = devices.all.map(
(Device device) => device.logs(clear: clear));
if (iosSimLogProcess != null) {
await iosSimLogProcess;
}
for (Future<int> result in results)
await result;
return 0;
}
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.run_mojo;
import 'dart:async';
import 'dart:io';
......@@ -19,8 +17,9 @@ final Logger _logging = new Logger('sky_tools.run_mojo');
enum _MojoConfig { Debug, Release }
class RunMojoCommand extends Command {
final name = 'run_mojo';
final description = 'Run a Flutter app in mojo.';
final String name = 'run_mojo';
final String description = 'Run a Flutter app in mojo.';
RunMojoCommand() {
argParser.addFlag('android', negatable: false, help: 'Run on an Android device');
argParser.addFlag('checked', negatable: false, help: 'Run Flutter in checked mode');
......@@ -31,6 +30,7 @@ class RunMojoCommand extends Command {
argParser.addOption('mojo-path', help: 'Path to directory containing mojo_shell and services');
}
// TODO(abarth): Why not use path.absolute?
Future<String> _makePathAbsolute(String relativePath) async {
File file = new File(relativePath);
if (!await file.exists()) {
......@@ -65,7 +65,7 @@ class RunMojoCommand extends Command {
}
Future<int> _runLinux(String mojoPath, _MojoConfig mojoConfig, String appPath, List<String> additionalArgs) async {
String viewerPath = await _makePathAbsolute(await ArtifactStore.getPath(Artifact.SkyViewerMojo));
String viewerPath = await _makePathAbsolute(await ArtifactStore.getPath(Artifact.skyViewerMojo));
String mojoBuildType = mojoConfig == _MojoConfig.Debug ? 'Debug' : 'Release';
String mojoShellPath = await _makePathAbsolute(path.join(mojoPath, 'out', mojoBuildType, 'mojo_shell'));
List<String> cmd = [
......
......@@ -2,29 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.start;
import 'dart:async';
import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import '../application_package.dart';
import '../device.dart';
import 'flutter_command.dart';
import 'install.dart';
import 'stop.dart';
final Logger _logging = new Logger('sky_tools.start');
class StartCommand extends Command {
final name = 'start';
final description = 'Start your Flutter app on attached devices.';
AndroidDevice android;
IOSDevice ios;
IOSSimulator iosSim;
class StartCommand extends FlutterCommand {
final String name = 'start';
final String description = 'Start your Flutter app on attached devices.';
StartCommand({this.android, this.ios, this.iosSim}) {
StartCommand() {
argParser.addFlag('poke',
negatable: false,
help: 'Restart the connection to the server (Android only).');
......@@ -42,53 +37,36 @@ class StartCommand extends Command {
@override
Future<int> run() async {
if (android == null) {
android = new AndroidDevice();
}
if (ios == null) {
ios = new IOSDevice();
}
if (iosSim == null) {
iosSim = new IOSSimulator();
}
await downloadApplicationPackagesAndConnectToDevices();
bool startedSomewhere = false;
bool poke = argResults['poke'];
if (!poke) {
StopCommand stopper = new StopCommand(android: android, ios: ios);
StopCommand stopper = new StopCommand();
stopper.inheritFromParent(this);
stopper.stop();
// Only install if the user did not specify a poke
InstallCommand installer =
new InstallCommand(android: android, ios: ios, iosSim: iosSim);
installer.install(argResults['boot']);
InstallCommand installer = new InstallCommand();
installer.inheritFromParent(this);
installer.install(boot: argResults['boot']);
}
Map<BuildPlatform, ApplicationPackage> packages =
ApplicationPackageFactory.getAvailableApplicationPackages();
ApplicationPackage androidApp = packages[BuildPlatform.android];
ApplicationPackage iosApp = packages[BuildPlatform.iOS];
ApplicationPackage iosSimApp = packages[BuildPlatform.iOSSimulator];
bool startedSomething = false;
bool startedOnAndroid = false;
if (androidApp != null && android.isConnected()) {
String target = path.absolute(argResults['target']);
startedOnAndroid = await android.startServer(
target, poke, argResults['checked'], androidApp);
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected())
continue;
if (device is AndroidDevice) {
String target = path.absolute(argResults['target']);
if (await device.startServer(target, poke, argResults['checked'], package))
startedSomething = true;
} else {
if (await device.startApp(package))
startedSomething = true;
}
}
if (iosApp != null && ios.isConnected()) {
startedSomewhere = await ios.startApp(iosApp) || startedSomewhere;
}
if (iosSimApp != null && iosSim.isConnected()) {
startedSomewhere = await iosSim.startApp(iosSimApp) || startedSomewhere;
}
if (startedSomewhere || startedOnAndroid) {
return 0;
} else {
return 2;
}
return startedSomething ? 0 : 2;
}
}
......@@ -2,64 +2,35 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.stop;
import 'dart:async';
import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import '../application_package.dart';
import '../device.dart';
import 'flutter_command.dart';
final Logger _logging = new Logger('sky_tools.stop');
class StopCommand extends Command {
final name = 'stop';
final description = 'Stop your Flutter app on all attached devices.';
AndroidDevice android;
IOSDevice ios;
IOSSimulator iosSim;
StopCommand({this.android, this.ios, this.iosSim});
class StopCommand extends FlutterCommand {
final String name = 'stop';
final String description = 'Stop your Flutter app on all attached devices.';
@override
Future<int> run() async {
if (await stop()) {
return 0;
} else {
return 2;
}
await downloadApplicationPackagesAndConnectToDevices();
return await stop() ? 0 : 2;
}
Future<bool> stop() async {
if (android == null) {
android = new AndroidDevice();
}
if (ios == null) {
ios = new IOSDevice();
}
if (iosSim == null) {
iosSim = new IOSSimulator();
}
bool stoppedSomething = false;
Map<BuildPlatform, ApplicationPackage> packages =
ApplicationPackageFactory.getAvailableApplicationPackages();
if (android.isConnected()) {
ApplicationPackage androidApp = packages[BuildPlatform.android];
stoppedSomething = await android.stopApp(androidApp) || stoppedSomething;
}
if (ios.isConnected()) {
ApplicationPackage iosApp = packages[BuildPlatform.iOS];
stoppedSomething = await ios.stopApp(iosApp) || stoppedSomething;
}
if (iosSim.isConnected()) {
ApplicationPackage iosApp = packages[BuildPlatform.iOSSimulator];
stoppedSomething = await iosSim.stopApp(iosApp) || stoppedSomething;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected())
continue;
if (await device.stopApp(package))
stoppedSomething = true;
}
return stoppedSomething;
......
......@@ -2,28 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sky_tools.trace;
import 'dart:async';
import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import 'flutter_command.dart';
import '../application_package.dart';
import '../device.dart';
final Logger _logging = new Logger('sky_tools.trace');
class TraceCommand extends Command {
final name = 'trace';
final description = 'Start and stop tracing a running Flutter app '
class TraceCommand extends FlutterCommand {
final String name = 'trace';
final String description = 'Start and stop tracing a running Flutter app '
'(Android only, requires root).\n'
'To start a trace, wait, and then stop the trace, don\'t set any flags '
'except (optionally) duration.\n'
'Otherwise, specify either start or stop to manually control the trace.';
AndroidDevice android;
TraceCommand([this.android]) {
TraceCommand() {
argParser.addFlag('start', negatable: false, help: 'Start tracing.');
argParser.addFlag('stop', negatable: false, help: 'Stop tracing.');
argParser.addOption('duration',
......@@ -32,35 +29,32 @@ class TraceCommand extends Command {
@override
Future<int> run() async {
if (android == null) {
android = new AndroidDevice();
}
await downloadApplicationPackagesAndConnectToDevices();
if (!android.isConnected()) {
if (!devices.android.isConnected()) {
_logging.warning('No device connected, so no trace was completed.');
return 1;
}
Map<BuildPlatform, ApplicationPackage> packages =
ApplicationPackageFactory.getAvailableApplicationPackages();
ApplicationPackage androidApp = packages[BuildPlatform.android];
ApplicationPackage androidApp = applicationPackages.android;
if ((!argResults['start'] && !argResults['stop']) ||
(argResults['start'] && argResults['stop'])) {
// Setting neither flags or both flags means do both commands and wait
// duration seconds in between.
android.startTracing(androidApp);
devices.android.startTracing(androidApp);
await new Future.delayed(
new Duration(seconds: int.parse(argResults['duration'])),
() => _stopTracing(androidApp));
() => _stopTracing(devices.android, androidApp));
} else if (argResults['stop']) {
_stopTracing(androidApp);
_stopTracing(devices.android, androidApp);
} else {
android.startTracing(androidApp);
devices.android.startTracing(androidApp);
}
return 0;
}
void _stopTracing(AndroidApk androidApp) {
void _stopTracing(AndroidDevice android, AndroidApk androidApp) {
String tracePath = android.stopTracing(androidApp);
if (tracePath == null) {
_logging.warning('No trace file saved.');
......
This diff is collapsed.
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library android_device_test;
import 'package:sky_tools/src/device.dart';
import 'package:test/test.dart';
......@@ -17,9 +15,9 @@ defineTests() {
});
test('stores the requested id', () {
String deviceID = '1234';
AndroidDevice android = new AndroidDevice(id: deviceID);
expect(android.id, equals(deviceID));
String deviceId = '1234';
AndroidDevice android = new AndroidDevice(id: deviceId);
expect(android.id, equals(deviceId));
});
test('correctly creates only one of each requested device id', () {
......
......@@ -2,35 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library install_test;
import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/commands/install.dart';
import 'package:test/test.dart';
import 'src/common.dart';
import 'src/mocks.dart';
main() => defineTests();
defineTests() {
group('install', () {
test('returns 0 when Android is connected and ready for an install', () {
applicationPackageSetup();
InstallCommand command = new InstallCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(true);
when(android.installApp(any)).thenReturn(true);
when(mockDevices.android.isConnected()).thenReturn(true);
when(mockDevices.android.installApp(any)).thenReturn(true);
MockIOSDevice ios = new MockIOSDevice();
when(ios.isConnected()).thenReturn(false);
when(ios.installApp(any)).thenReturn(false);
when(mockDevices.iOS.isConnected()).thenReturn(false);
when(mockDevices.iOS.installApp(any)).thenReturn(false);
MockIOSSimulator iosSim = new MockIOSSimulator();
when(iosSim.isConnected()).thenReturn(false);
when(iosSim.installApp(any)).thenReturn(false);
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
when(mockDevices.iOSSimulator.installApp(any)).thenReturn(false);
InstallCommand command = new InstallCommand(android: android, ios: ios);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
......@@ -38,22 +34,18 @@ defineTests() {
});
test('returns 0 when iOS is connected and ready for an install', () {
applicationPackageSetup();
MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(false);
when(android.installApp(any)).thenReturn(false);
InstallCommand command = new InstallCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
MockIOSDevice ios = new MockIOSDevice();
when(ios.isConnected()).thenReturn(true);
when(ios.installApp(any)).thenReturn(true);
when(mockDevices.android.isConnected()).thenReturn(false);
when(mockDevices.android.installApp(any)).thenReturn(false);
MockIOSSimulator iosSim = new MockIOSSimulator();
when(iosSim.isConnected()).thenReturn(false);
when(iosSim.installApp(any)).thenReturn(false);
when(mockDevices.iOS.isConnected()).thenReturn(true);
when(mockDevices.iOS.installApp(any)).thenReturn(true);
InstallCommand command =
new InstallCommand(android: android, ios: ios, iosSim: iosSim);
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
when(mockDevices.iOSSimulator.installApp(any)).thenReturn(false);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
......
......@@ -2,41 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library list_test;
import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/commands/list.dart';
import 'package:test/test.dart';
import 'src/common.dart';
import 'src/mocks.dart';
main() => defineTests();
defineTests() {
group('list', () {
test('returns 0 when called', () {
applicationPackageSetup();
ListCommand command = new ListCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
MockAndroidDevice android = new MockAndroidDevice();
// Avoid relying on adb being installed on the test system.
// Instead, cause the test to run the echo command.
when(android.adbPath).thenReturn('echo');
when(mockDevices.android.adbPath).thenReturn('echo');
MockIOSDevice ios = new MockIOSDevice();
// Avoid relying on idevice* being installed on the test system.
// Instead, cause the test to run the echo command.
when(ios.informerPath).thenReturn('echo');
when(ios.installerPath).thenReturn('echo');
when(ios.listerPath).thenReturn('echo');
when(mockDevices.iOS.informerPath).thenReturn('echo');
when(mockDevices.iOS.installerPath).thenReturn('echo');
when(mockDevices.iOS.listerPath).thenReturn('echo');
MockIOSSimulator iosSim = new MockIOSSimulator();
// Avoid relying on xcrun being installed on the test system.
// Instead, cause the test to run the echo command.
when(iosSim.xcrunPath).thenReturn('echo');
when(mockDevices.iOSSimulator.xcrunPath).thenReturn('echo');
ListCommand command =
new ListCommand(android: android, ios: ios, iosSim: iosSim);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
runner.run(['list']).then((int code) => expect(code, equals(0)));
......
......@@ -2,30 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library listen_test;
import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/commands/listen.dart';
import 'package:test/test.dart';
import 'src/common.dart';
import 'src/mocks.dart';
main() => defineTests();
defineTests() {
group('listen', () {
test('returns 0 when no device is connected', () {
applicationPackageSetup();
ListenCommand command = new ListenCommand(singleRun: true);
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(false);
MockIOSDevice ios = new MockIOSDevice();
when(ios.isConnected()).thenReturn(false);
MockIOSSimulator iosSim = new MockIOSSimulator();
when(iosSim.isConnected()).thenReturn(false);
ListenCommand command = new ListenCommand(
android: android, ios: ios, iosSim: iosSim, singleRun: true);
when(mockDevices.android.isConnected()).thenReturn(false);
when(mockDevices.iOS.isConnected()).thenReturn(false);
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
......
......@@ -2,31 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library logs_test;
import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/commands/logs.dart';
import 'package:test/test.dart';
import 'src/common.dart';
import 'src/mocks.dart';
main() => defineTests();
defineTests() {
group('logs', () {
test('returns 0 when no device is connected', () {
applicationPackageSetup();
MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(false);
MockIOSDevice ios = new MockIOSDevice();
when(ios.isConnected()).thenReturn(false);
MockIOSSimulator iosSim = new MockIOSSimulator();
when(iosSim.isConnected()).thenReturn(false);
LogsCommand command = new LogsCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
LogsCommand command =
new LogsCommand(android: android, ios: ios, iosSim: iosSim);
when(mockDevices.android.isConnected()).thenReturn(false);
when(mockDevices.iOS.isConnected()).thenReturn(false);
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
......
......@@ -4,29 +4,47 @@
import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/application_package.dart';
import 'package:sky_tools/src/build_configuration.dart';
import 'package:sky_tools/src/commands/flutter_command.dart';
import 'package:sky_tools/src/device.dart';
class MockApplicationPackageStore extends ApplicationPackageStore {
MockApplicationPackageStore() : super(
android: new AndroidApk(localPath: '/mock/path/to/android/SkyShell.apk'),
iOS: new IOSApp(localPath: '/mock/path/to/iOS/SkyShell.app'),
iOSSimulator: new IOSApp(localPath: '/mock/path/to/iOSSimulator/SkyShell.app'));
}
class MockAndroidDevice extends Mock implements AndroidDevice {
BuildPlatform get platform => BuildPlatform.android;
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockIOSDevice extends Mock implements IOSDevice {
BuildPlatform get platform => BuildPlatform.iOS;
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockIOSSimulator extends Mock implements IOSSimulator {
BuildPlatform get platform => BuildPlatform.iOSSimulator;
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
void applicationPackageSetup() {
ApplicationPackageFactory.srcPath = './';
ApplicationPackageFactory.setBuildPath(
BuildType.prebuilt, BuildPlatform.android, './');
ApplicationPackageFactory.setBuildPath(
BuildType.prebuilt, BuildPlatform.iOS, './');
ApplicationPackageFactory.setBuildPath(
BuildType.prebuilt, BuildPlatform.iOSSimulator, './');
class MockDeviceStore extends DeviceStore {
MockDeviceStore() : super(
android: new MockAndroidDevice(),
iOS: new MockIOSDevice(),
iOSSimulator: new MockIOSSimulator());
}
void applyMocksToCommand(FlutterCommand command) {
command
..applicationPackages = new MockApplicationPackageStore()
..devices = new MockDeviceStore();
}
......@@ -2,42 +2,36 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library start_test;
import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/commands/start.dart';
import 'package:test/test.dart';
import 'src/common.dart';
import 'src/mocks.dart';
main() => defineTests();
defineTests() {
group('start', () {
test('returns 0 when Android is connected and ready to be started', () {
applicationPackageSetup();
MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(true);
when(android.installApp(any)).thenReturn(true);
when(android.startServer(any, any, any, any)).thenReturn(true);
when(android.stopApp(any)).thenReturn(true);
StartCommand command = new StartCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
MockIOSDevice ios = new MockIOSDevice();
when(ios.isConnected()).thenReturn(false);
when(ios.installApp(any)).thenReturn(false);
when(ios.startApp(any)).thenReturn(false);
when(ios.stopApp(any)).thenReturn(false);
when(mockDevices.android.isConnected()).thenReturn(true);
when(mockDevices.android.installApp(any)).thenReturn(true);
when(mockDevices.android.startServer(any, any, any, any)).thenReturn(true);
when(mockDevices.android.stopApp(any)).thenReturn(true);
MockIOSSimulator iosSim = new MockIOSSimulator();
when(iosSim.isConnected()).thenReturn(false);
when(iosSim.installApp(any)).thenReturn(false);
when(iosSim.startApp(any)).thenReturn(false);
when(iosSim.stopApp(any)).thenReturn(false);
when(mockDevices.iOS.isConnected()).thenReturn(false);
when(mockDevices.iOS.installApp(any)).thenReturn(false);
when(mockDevices.iOS.startApp(any)).thenReturn(false);
when(mockDevices.iOS.stopApp(any)).thenReturn(false);
StartCommand command =
new StartCommand(android: android, ios: ios, iosSim: iosSim);
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
when(mockDevices.iOSSimulator.installApp(any)).thenReturn(false);
when(mockDevices.iOSSimulator.startApp(any)).thenReturn(false);
when(mockDevices.iOSSimulator.stopApp(any)).thenReturn(false);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
......@@ -45,28 +39,24 @@ defineTests() {
});
test('returns 0 when iOS is connected and ready to be started', () {
applicationPackageSetup();
MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(false);
when(android.installApp(any)).thenReturn(false);
when(android.startServer(any, any, any, any)).thenReturn(false);
when(android.stopApp(any)).thenReturn(false);
MockIOSDevice ios = new MockIOSDevice();
when(ios.isConnected()).thenReturn(true);
when(ios.installApp(any)).thenReturn(true);
when(ios.startApp(any)).thenReturn(true);
when(ios.stopApp(any)).thenReturn(false);
MockIOSSimulator iosSim = new MockIOSSimulator();
when(iosSim.isConnected()).thenReturn(false);
when(iosSim.installApp(any)).thenReturn(false);
when(iosSim.startApp(any)).thenReturn(false);
when(iosSim.stopApp(any)).thenReturn(false);
StartCommand command =
new StartCommand(android: android, ios: ios, iosSim: iosSim);
StartCommand command = new StartCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
when(mockDevices.android.isConnected()).thenReturn(false);
when(mockDevices.android.installApp(any)).thenReturn(false);
when(mockDevices.android.startServer(any, any, any, any)).thenReturn(false);
when(mockDevices.android.stopApp(any)).thenReturn(false);
when(mockDevices.iOS.isConnected()).thenReturn(true);
when(mockDevices.iOS.installApp(any)).thenReturn(true);
when(mockDevices.iOS.startApp(any)).thenReturn(true);
when(mockDevices.iOS.stopApp(any)).thenReturn(false);
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
when(mockDevices.iOSSimulator.installApp(any)).thenReturn(false);
when(mockDevices.iOSSimulator.startApp(any)).thenReturn(false);
when(mockDevices.iOSSimulator.stopApp(any)).thenReturn(false);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
......
......@@ -9,29 +9,25 @@ import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/commands/stop.dart';
import 'package:test/test.dart';
import 'src/common.dart';
import 'src/mocks.dart';
main() => defineTests();
defineTests() {
group('stop', () {
test('returns 0 when Android is connected and ready to be stopped', () {
applicationPackageSetup();
StopCommand command = new StopCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(true);
when(android.stopApp(any)).thenReturn(true);
when(mockDevices.android.isConnected()).thenReturn(true);
when(mockDevices.android.stopApp(any)).thenReturn(true);
MockIOSDevice ios = new MockIOSDevice();
when(ios.isConnected()).thenReturn(false);
when(ios.stopApp(any)).thenReturn(false);
when(mockDevices.iOS.isConnected()).thenReturn(false);
when(mockDevices.iOS.stopApp(any)).thenReturn(false);
MockIOSSimulator iosSim = new MockIOSSimulator();
when(iosSim.isConnected()).thenReturn(false);
when(iosSim.stopApp(any)).thenReturn(false);
StopCommand command =
new StopCommand(android: android, ios: ios, iosSim: iosSim);
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
when(mockDevices.iOSSimulator.stopApp(any)).thenReturn(false);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
......@@ -39,22 +35,18 @@ defineTests() {
});
test('returns 0 when iOS is connected and ready to be stopped', () {
applicationPackageSetup();
MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(false);
when(android.stopApp(any)).thenReturn(false);
StopCommand command = new StopCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
MockIOSDevice ios = new MockIOSDevice();
when(ios.isConnected()).thenReturn(true);
when(ios.stopApp(any)).thenReturn(true);
when(mockDevices.android.isConnected()).thenReturn(false);
when(mockDevices.android.stopApp(any)).thenReturn(false);
MockIOSSimulator iosSim = new MockIOSSimulator();
when(iosSim.isConnected()).thenReturn(false);
when(iosSim.stopApp(any)).thenReturn(false);
when(mockDevices.iOS.isConnected()).thenReturn(true);
when(mockDevices.iOS.stopApp(any)).thenReturn(true);
StopCommand command =
new StopCommand(android: android, ios: ios, iosSim: iosSim);
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
when(mockDevices.iOSSimulator.stopApp(any)).thenReturn(false);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
......
......@@ -9,18 +9,18 @@ import 'package:mockito/mockito.dart';
import 'package:sky_tools/src/commands/trace.dart';
import 'package:test/test.dart';
import 'src/common.dart';
import 'src/mocks.dart';
main() => defineTests();
defineTests() {
group('trace', () {
test('returns 1 when no Android device is connected', () {
applicationPackageSetup();
TraceCommand command = new TraceCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
MockAndroidDevice android = new MockAndroidDevice();
when(android.isConnected()).thenReturn(false);
TraceCommand command = new TraceCommand(android);
when(mockDevices.android.isConnected()).thenReturn(false);
CommandRunner runner = new CommandRunner('test_flutter', '')
..addCommand(command);
......
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