Add stop command and supporting Android support.
This commit is contained in:
parent
9996d4255e
commit
fa59233746
@ -14,9 +14,11 @@ import 'package:sky_tools/src/cache.dart';
|
|||||||
import 'package:sky_tools/src/init.dart';
|
import 'package:sky_tools/src/init.dart';
|
||||||
import 'package:sky_tools/src/install.dart';
|
import 'package:sky_tools/src/install.dart';
|
||||||
import 'package:sky_tools/src/run_mojo.dart';
|
import 'package:sky_tools/src/run_mojo.dart';
|
||||||
|
import 'package:sky_tools/src/stop.dart';
|
||||||
|
|
||||||
class FlutterCommandRunner extends CommandRunner {
|
class FlutterCommandRunner extends CommandRunner {
|
||||||
FlutterCommandRunner() : super('flutter', 'Manage your flutter app development.') {
|
FlutterCommandRunner()
|
||||||
|
: super('flutter', 'Manage your flutter app development.') {
|
||||||
argParser.addFlag('verbose',
|
argParser.addFlag('verbose',
|
||||||
abbr: 'v',
|
abbr: 'v',
|
||||||
negatable: false,
|
negatable: false,
|
||||||
@ -41,7 +43,8 @@ class FlutterCommandRunner extends CommandRunner {
|
|||||||
'not set. Note that release is not compatible with the listen command '
|
'not set. Note that release is not compatible with the listen command '
|
||||||
'on iOS devices and simulators. Not normally required.');
|
'on iOS devices and simulators. Not normally required.');
|
||||||
argParser.addOption('sky-src-path',
|
argParser.addOption('sky-src-path',
|
||||||
help: 'Path to your Sky src directory, if you are building Sky locally. '
|
help:
|
||||||
|
'Path to your Sky src directory, if you are building Sky locally. '
|
||||||
'Ignored if neither debug nor release is set. Not normally required.');
|
'Ignored if neither debug nor release is set. Not normally required.');
|
||||||
argParser.addOption('android-debug-build-path',
|
argParser.addOption('android-debug-build-path',
|
||||||
help:
|
help:
|
||||||
@ -120,8 +123,8 @@ class FlutterCommandRunner extends CommandRunner {
|
|||||||
ApplicationPackageFactory.defaultBuildType = BuildType.release;
|
ApplicationPackageFactory.defaultBuildType = BuildType.release;
|
||||||
ApplicationPackageFactory.setBuildPath(BuildType.release,
|
ApplicationPackageFactory.setBuildPath(BuildType.release,
|
||||||
BuildPlatform.android, results['android-release-build-path']);
|
BuildPlatform.android, results['android-release-build-path']);
|
||||||
ApplicationPackageFactory.setBuildPath(BuildType.release, BuildPlatform.iOS,
|
ApplicationPackageFactory.setBuildPath(BuildType.release,
|
||||||
results['ios-release-build-path']);
|
BuildPlatform.iOS, results['ios-release-build-path']);
|
||||||
ApplicationPackageFactory.setBuildPath(BuildType.release,
|
ApplicationPackageFactory.setBuildPath(BuildType.release,
|
||||||
BuildPlatform.iOSSimulator, results['ios-sim-release-build-path']);
|
BuildPlatform.iOSSimulator, results['ios-sim-release-build-path']);
|
||||||
}
|
}
|
||||||
@ -141,6 +144,7 @@ void main(List<String> args) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
new FlutterCommandRunner()
|
new FlutterCommandRunner()
|
||||||
|
..addCommand(new StopCommand())
|
||||||
..addCommand(new BuildCommand())
|
..addCommand(new BuildCommand())
|
||||||
..addCommand(new CacheCommand())
|
..addCommand(new CacheCommand())
|
||||||
..addCommand(new InitCommand())
|
..addCommand(new InitCommand())
|
||||||
|
@ -29,10 +29,16 @@ abstract class ApplicationPackage {
|
|||||||
|
|
||||||
class AndroidApk extends ApplicationPackage {
|
class AndroidApk extends ApplicationPackage {
|
||||||
static const String _apkName = 'SkyShell.apk';
|
static const String _apkName = 'SkyShell.apk';
|
||||||
static const String _androidPackage = 'org.domokit.sky.shell';
|
static const String _packageID = 'org.domokit.sky.shell';
|
||||||
|
static const String _componentID = '$_packageID/$_packageID.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,
|
AndroidApk(String appDir,
|
||||||
[String appPackageID = _androidPackage, String appFileName = _apkName])
|
{String appPackageID: _packageID,
|
||||||
|
String appFileName: _apkName,
|
||||||
|
this.component: _componentID})
|
||||||
: super(path.join(appDir, 'apks'), appPackageID, appFileName);
|
: super(path.join(appDir, 'apks'), appPackageID, appFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ abstract class _Device {
|
|||||||
|
|
||||||
class AndroidDevice extends _Device {
|
class AndroidDevice extends _Device {
|
||||||
static const String _ADB_PATH = 'adb';
|
static const String _ADB_PATH = 'adb';
|
||||||
|
static const String _serverPort = '9888';
|
||||||
|
|
||||||
static const String className = 'AndroidDevice';
|
static const String className = 'AndroidDevice';
|
||||||
static final String defaultDeviceID = 'default';
|
static final String defaultDeviceID = 'default';
|
||||||
@ -232,6 +233,31 @@ class AndroidDevice extends _Device {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool stop(AndroidApk apk) {
|
||||||
|
// Turn off reverse port forwarding
|
||||||
|
try {
|
||||||
|
runCheckedSync([adbPath, 'reverse', '--remove', 'tcp:$_serverPort']);
|
||||||
|
} catch (e) {}
|
||||||
|
// Stop the app
|
||||||
|
runCheckedSync([adbPath, 'shell', 'am', 'force-stop', apk.appPackageID]);
|
||||||
|
// Kill the server
|
||||||
|
try {
|
||||||
|
if (Platform.isMacOS) {
|
||||||
|
String pid = runCheckedSync(['lsof', '-i', ':$_serverPort', '-t']);
|
||||||
|
// Killing a pid with a shell command from within dart is hard,
|
||||||
|
// so use a library command, but it's still nice to give the
|
||||||
|
// equivalent command when doing verbose logging.
|
||||||
|
_logging.info('kill $pid');
|
||||||
|
Process.killPid(int.parse(pid));
|
||||||
|
} else {
|
||||||
|
runCheckedSync(['fuser', '-k', '$_serverPort/tcp']);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool isConnected() => _hasValidAndroid;
|
bool isConnected() => _hasValidAndroid;
|
||||||
}
|
}
|
||||||
|
47
packages/flutter_tools/lib/src/stop.dart
Normal file
47
packages/flutter_tools/lib/src/stop.dart
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
library sky_tools.stop;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:sky_tools/src/application_package.dart';
|
||||||
|
import 'package:sky_tools/src/device.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 = null;
|
||||||
|
|
||||||
|
StopCommand([this.android]) {
|
||||||
|
if (android == null) {
|
||||||
|
android = new AndroidDevice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> run() async {
|
||||||
|
if (stop()) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool stop() {
|
||||||
|
bool stoppedSomething = false;
|
||||||
|
if (android.isConnected()) {
|
||||||
|
Map<BuildPlatform, ApplicationPackage> packages =
|
||||||
|
ApplicationPackageFactory.getAvailableApplicationPackages();
|
||||||
|
ApplicationPackage androidApp = packages[BuildPlatform.android];
|
||||||
|
stoppedSomething = android.stop(androidApp) || stoppedSomething;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stoppedSomething;
|
||||||
|
}
|
||||||
|
}
|
34
packages/flutter_tools/test/stop_test.dart
Normal file
34
packages/flutter_tools/test/stop_test.dart
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
library stop_test;
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:sky_tools/src/application_package.dart';
|
||||||
|
import 'package:sky_tools/src/stop.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'src/common.dart';
|
||||||
|
|
||||||
|
main() => defineTests();
|
||||||
|
|
||||||
|
defineTests() {
|
||||||
|
group('stop', () {
|
||||||
|
test('returns 0 when Android is connected and ready to be stopped', () {
|
||||||
|
ApplicationPackageFactory.srcPath = './';
|
||||||
|
ApplicationPackageFactory.setBuildPath(
|
||||||
|
BuildType.prebuilt, BuildPlatform.android, './');
|
||||||
|
|
||||||
|
MockAndroidDevice android = new MockAndroidDevice();
|
||||||
|
when(android.isConnected()).thenReturn(true);
|
||||||
|
when(android.stop(any)).thenReturn(true);
|
||||||
|
StopCommand command = new StopCommand(android);
|
||||||
|
|
||||||
|
CommandRunner runner = new CommandRunner('test_flutter', '')
|
||||||
|
..addCommand(command);
|
||||||
|
runner.run(['stop']).then((int code) => expect(code, equals(0)));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user