Commit 94b472ff authored by Adam Barth's avatar Adam Barth

Add a --no-http flag to start command

This flag builds a local FLX file and pushes that to the device instead of
using an HTTP server.
parent 48c3d015
......@@ -66,16 +66,15 @@ class ApplicationPackageStore {
ApplicationPackageStore({ this.android, this.iOS, this.iOSSimulator });
ApplicationPackage getPackageForPlatform(BuildPlatform platform) {
ApplicationPackage getPackageForPlatform(TargetPlatform platform) {
switch (platform) {
case BuildPlatform.android:
case TargetPlatform.android:
return android;
case BuildPlatform.iOS:
case TargetPlatform.iOS:
return iOS;
case BuildPlatform.iOSSimulator:
case TargetPlatform.iOSSimulator:
return iOSSimulator;
case BuildPlatform.mac:
case BuildPlatform.linux:
case TargetPlatform.linux:
return null;
}
}
......@@ -86,31 +85,32 @@ class ApplicationPackageStore {
IOSApp iOSSimulator;
for (BuildConfiguration config in configs) {
switch (config.platform) {
case BuildPlatform.android:
switch (config.targetPlatform) {
case TargetPlatform.android:
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);
if (config.type != BuildType.prebuilt) {
String localPath = path.join(config.buildDir, 'apks', AndroidApk._defaultName);
android = new AndroidApk(localPath: localPath);
} else {
Artifact artifact = ArtifactStore.getArtifact(
type: ArtifactType.shell, targetPlatform: TargetPlatform.android);
android = new AndroidApk(localPath: await ArtifactStore.getPath(artifact));
}
break;
case BuildPlatform.iOS:
case TargetPlatform.iOS:
assert(iOS == null);
assert(config.type != BuildType.prebuilt);
iOS = new IOSApp(localPath: path.join(config.buildDir, IOSApp._defaultName));
break;
case BuildPlatform.iOSSimulator:
case TargetPlatform.iOSSimulator:
assert(iOSSimulator == null);
assert(config.type != BuildType.prebuilt);
iOSSimulator = new IOSApp(localPath: path.join(config.buildDir, IOSApp._defaultName));
break;
case BuildPlatform.mac:
case BuildPlatform.linux:
// TODO(abarth): Support mac and linux targets.
assert(false);
case TargetPlatform.linux:
break;
}
}
......
......@@ -10,15 +10,147 @@ import 'dart:io';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'build_configuration.dart';
final Logger _logging = new Logger('sky_tools.artifacts');
enum Artifact {
flutterCompiler,
flutterShell,
skyViewerMojo,
const String _kShellCategory = 'shell';
const String _kViewerCategory = 'viewer';
String _getNameForHostPlatform(HostPlatform platform) {
switch (platform) {
case HostPlatform.linux:
return 'linux-x64';
case HostPlatform.mac:
return 'darwin-x64';
}
}
String _getNameForTargetPlatform(TargetPlatform platform) {
switch (platform) {
case TargetPlatform.android:
return 'android-arm';
case TargetPlatform.iOS:
return 'ios-arm';
case TargetPlatform.iOSSimulator:
return 'ios-x64';
case TargetPlatform.linux:
return 'linux-x64';
}
}
// Keep in sync with https://github.com/flutter/engine/blob/master/sky/tools/big_red_button.py#L50
String _getCloudStorageBaseUrl({String category, String platform, String revision}) {
if (platform == 'darwin-x64') {
// In the fullness of time, we'll have a consistent URL pattern for all of
// our artifacts, but, for the time being, darwin artifacts are stored in a
// different cloud storage bucket.
return 'https://storage.googleapis.com/mojo_infra/flutter/${platform}/${revision}/';
}
return 'https://storage.googleapis.com/mojo/sky/${category}/${platform}/${revision}/';
}
enum ArtifactType {
snapshot,
shell,
viewer,
}
class Artifact {
const Artifact._({
this.name,
this.fileName,
this.category,
this.type,
this.hostPlatform,
this.targetPlatform
});
final String name;
final String fileName;
final String category; // TODO(abarth): Remove categories.
final ArtifactType type;
final HostPlatform hostPlatform;
final TargetPlatform targetPlatform;
String get platform {
if (targetPlatform != null)
return _getNameForTargetPlatform(targetPlatform);
if (hostPlatform != null)
return _getNameForHostPlatform(hostPlatform);
assert(false);
return null;
}
String getUrl(String revision) {
return _getCloudStorageBaseUrl(category: category, platform: platform, revision: revision) + fileName;
}
// Whether the artifact needs to be marked as executable on disk.
bool get executable => type == ArtifactType.snapshot;
}
class ArtifactStore {
static const List<Artifact> knownArtifacts = const <Artifact>[
const Artifact._(
name: 'Sky Shell',
fileName: 'SkyShell.apk',
category: _kShellCategory,
type: ArtifactType.shell,
targetPlatform: TargetPlatform.android
),
const Artifact._(
name: 'Sky Snapshot',
fileName: 'sky_snapshot',
category: _kShellCategory,
type: ArtifactType.snapshot,
hostPlatform: HostPlatform.linux
),
const Artifact._(
name: 'Sky Snapshot',
fileName: 'sky_snapshot',
category: _kShellCategory,
type: ArtifactType.snapshot,
hostPlatform: HostPlatform.mac
),
const Artifact._(
name: 'Sky Viewer',
fileName: 'sky_viewer.mojo',
category: _kViewerCategory,
type: ArtifactType.viewer,
targetPlatform: TargetPlatform.android
),
const Artifact._(
name: 'Sky Viewer',
fileName: 'sky_viewer.mojo',
category: _kViewerCategory,
type: ArtifactType.viewer,
targetPlatform: TargetPlatform.linux
),
];
static Artifact getArtifact({
ArtifactType type,
HostPlatform hostPlatform,
TargetPlatform targetPlatform
}) {
for (Artifact artifact in ArtifactStore.knownArtifacts) {
if (type != null &&
type != artifact.type)
continue;
if (hostPlatform != null &&
artifact.hostPlatform != null &&
hostPlatform != artifact.hostPlatform)
continue;
if (targetPlatform != null &&
artifact.targetPlatform != null &&
targetPlatform != artifact.targetPlatform)
continue;
return artifact;
}
return null;
}
static String packageRoot;
static String _engineRevision;
......@@ -31,102 +163,68 @@ class ArtifactStore {
return _engineRevision;
}
// Keep in sync with https://github.com/flutter/engine/blob/master/sky/tools/big_red_button.py#L50
static String googleStorageUrl(String category, String platform) {
return 'https://storage.googleapis.com/mojo/sky/${category}/${platform}/${engineRevision}/';
static String getCloudStorageBaseUrl(String category, String platform) {
return _getCloudStorageBaseUrl(category: category, platform: platform, revision: engineRevision);
}
static Future _downloadFile(String url, File file) async {
print('Downloading $url to ${file.path}.');
_logging.info('Downloading $url to ${file.path}.');
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.getUrl(Uri.parse(url));
HttpClientResponse response = await request.close();
_logging.fine('Received response');
if (response.statusCode != 200) throw new Exception(response.reasonPhrase);
_logging.fine('Received response statusCode=${response.statusCode}');
if (response.statusCode != 200)
throw new Exception(response.reasonPhrase);
IOSink sink = file.openWrite();
await sink.addStream(response);
await sink.close();
_logging.fine('Wrote file');
}
static Future<Directory> _cacheDir() async {
static Directory _getBaseCacheDir() {
Directory cacheDir = new Directory(path.join(packageRoot, 'sky_tools', 'cache'));
if (!await cacheDir.exists()) {
await cacheDir.create(recursive: true);
}
if (!cacheDir.existsSync())
cacheDir.createSync(recursive: true);
return cacheDir;
}
static Future<Directory> _engineSpecificCacheDir() async {
Directory cacheDir = await _cacheDir();
static Directory _getCacheDirForArtifact(Artifact artifact) {
Directory baseDir = _getBaseCacheDir();
// For now, all downloaded artifacts are release mode host binaries so use
// a path that mirrors a local release build.
// TODO(jamesr): Add support for more configurations.
String config = 'Release';
Directory engineSpecificDir = new Directory(path.join(cacheDir.path, 'sky_engine', engineRevision, config));
if (!await engineSpecificDir.exists()) {
await engineSpecificDir.create(recursive: true);
}
return engineSpecificDir;
}
// Whether the artifact needs to be marked as executable on disk.
static bool _needsToBeExecutable(Artifact artifact) {
return artifact == Artifact.flutterCompiler;
Directory artifactSpecificDir = new Directory(path.join(
baseDir.path, 'sky_engine', engineRevision, config, artifact.platform));
if (!artifactSpecificDir.existsSync())
artifactSpecificDir.createSync(recursive: true);
return artifactSpecificDir;
}
static Future<String> getPath(Artifact artifact) async {
Directory cacheDir = await _engineSpecificCacheDir();
String category;
String platform;
String name;
switch (artifact) {
case Artifact.flutterCompiler:
category = 'shell';
name = 'sky_snapshot';
break;
case Artifact.flutterShell:
category = 'shell';
platform = 'android-arm';
name = 'SkyShell.apk';
break;
case Artifact.skyViewerMojo:
category = 'viewer';
name = 'sky_viewer.mojo';
break;
}
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 == 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]);
if (result.exitCode != 0) throw new Exception(result.stderr);
Directory cacheDir = _getCacheDirForArtifact(artifact);
File cachedFile = new File(path.join(cacheDir.path, artifact.fileName));
if (!cachedFile.existsSync()) {
print('Downloading ${artifact.name} from the cloud, one moment please...');
await _downloadFile(artifact.getUrl(engineRevision), cachedFile);
if (artifact.executable) {
// TODO(abarth): We should factor this out into a separate function that
// can have a platform-specific implementation.
ProcessResult result = Process.runSync('chmod', ['u+x', cachedFile.path]);
if (result.exitCode != 0)
throw new Exception(result.stderr);
}
}
return cachedFile.path;
}
static Future clear() async {
Directory cacheDir = await _cacheDir();
static void clear() {
Directory cacheDir = _getBaseCacheDir();
_logging.fine('Clearing cache directory ${cacheDir.path}');
await cacheDir.delete(recursive: true);
cacheDir.deleteSync(recursive: true);
}
static Future populate() async {
for (Artifact artifact in Artifact.values) {
_logging.fine('Populating cache with $artifact');
await getPath(artifact);
}
static Future populate() {
return Future.wait(knownArtifacts.map((artifact) => getPath(artifact)));
}
}
......@@ -2,29 +2,48 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
final Logger _logging = new Logger('sky_tools.build_configuration');
enum BuildType {
prebuilt,
release,
debug,
}
enum BuildPlatform {
enum HostPlatform {
mac,
linux,
}
enum TargetPlatform {
android,
iOS,
iOSSimulator,
mac,
linux,
}
HostPlatform getCurrentHostPlatform() {
if (Platform.isMacOS)
return HostPlatform.mac;
if (Platform.isLinux)
return HostPlatform.linux;
_logging.warning('Unsupported host platform, defaulting to Linux');
return HostPlatform.linux;
}
class BuildConfiguration {
BuildConfiguration.prebuilt({ this.platform })
BuildConfiguration.prebuilt({ this.hostPlatform, this.targetPlatform })
: type = BuildType.prebuilt, buildDir = null;
BuildConfiguration.local({
this.type,
this.platform,
this.hostPlatform,
this.targetPlatform,
String enginePath,
String buildPath
}) : buildDir = path.normalize(path.join(enginePath, buildPath)) {
......@@ -32,6 +51,7 @@ class BuildConfiguration {
}
final BuildType type;
final BuildPlatform platform;
final HostPlatform hostPlatform;
final TargetPlatform targetPlatform;
final String buildDir;
}
......@@ -27,8 +27,10 @@ class FlutterCommandRunner extends CommandRunner {
negatable: false,
help: 'Very noisy logging, including the output of all '
'shell commands executed.');
argParser.addOption('package-root',
help: 'Path to your packages directory.', defaultsTo: 'packages');
argParser.addSeparator('Global build selection options:');
argParser.addSeparator('Local build selection options:');
argParser.addFlag('debug',
negatable: false,
help:
......@@ -48,42 +50,40 @@ class FlutterCommandRunner extends CommandRunner {
'Automatically detect your engine src directory from an overridden Flutter package.'
'Useful if you are building Flutter locally and are using a dependency_override for'
'the Flutter package that points to your engine src directory.');
argParser.addOption('engine-src-path',
argParser.addOption('engine-src-path', hide: true,
help:
'Path to your engine src directory, if you are building Flutter locally. '
'Ignored if neither debug nor release is set. Not normally required.');
argParser.addOption('android-debug-build-path',
argParser.addOption('android-debug-build-path', hide: true,
help:
'Path to your Android Debug out directory, if you are building Flutter locally. '
'This path is relative to engine-src-path. Not normally required.',
defaultsTo: 'out/android_Debug/');
argParser.addOption('android-release-build-path',
argParser.addOption('android-release-build-path', hide: true,
help:
'Path to your Android Release out directory, if you are building Flutter locally. '
'This path is relative to engine-src-path. Not normally required.',
defaultsTo: 'out/android_Release/');
argParser.addOption('ios-debug-build-path',
argParser.addOption('ios-debug-build-path', hide: true,
help:
'Path to your iOS Debug out directory, if you are building Flutter locally. '
'This path is relative to engine-src-path. Not normally required.',
defaultsTo: 'out/ios_Debug/');
argParser.addOption('ios-release-build-path',
argParser.addOption('ios-release-build-path', hide: true,
help:
'Path to your iOS Release out directory, if you are building Flutter locally. '
'This path is relative to engine-src-path. Not normally required.',
defaultsTo: 'out/ios_Release/');
argParser.addOption('ios-sim-debug-build-path',
argParser.addOption('ios-sim-debug-build-path', hide: true,
help:
'Path to your iOS Simulator Debug out directory, if you are building Sky locally. '
'This path is relative to engine-src-path. Not normally required.',
defaultsTo: 'out/ios_sim_Debug/');
argParser.addOption('ios-sim-release-build-path',
argParser.addOption('ios-sim-release-build-path', hide: true,
help:
'Path to your iOS Simulator Release out directory, if you are building Sky locally. '
'This path is relative to engine-src-path. Not normally required.',
defaultsTo: 'out/ios_sim_Release/');
argParser.addOption('package-root',
help: 'Path to your packages directory.', defaultsTo: 'packages');
}
List<BuildConfiguration> get buildConfigurations {
......@@ -124,6 +124,7 @@ class FlutterCommandRunner extends CommandRunner {
String enginePath = globalResults['engine-src-path'];
bool isDebug = globalResults['debug'];
bool isRelease = globalResults['release'];
HostPlatform hostPlatform = getCurrentHostPlatform();
if (enginePath == null && globalResults['local-build']) {
Directory flutterDir = new Directory(path.join(globalResults['package-root'], 'flutter'));
......@@ -141,7 +142,8 @@ class FlutterCommandRunner extends CommandRunner {
List<BuildConfiguration> configs = <BuildConfiguration>[];
if (enginePath == null) {
configs.add(new BuildConfiguration.prebuilt(platform: BuildPlatform.android));
configs.add(new BuildConfiguration.prebuilt(
hostPlatform: hostPlatform, targetPlatform: TargetPlatform.android));
} else {
if (!FileSystemEntity.isDirectorySync(enginePath))
_logging.warning('$enginePath is not a valid directory');
......@@ -152,7 +154,8 @@ class FlutterCommandRunner extends CommandRunner {
if (isDebug) {
configs.add(new BuildConfiguration.local(
type: BuildType.debug,
platform: BuildPlatform.android,
hostPlatform: hostPlatform,
targetPlatform: TargetPlatform.android,
enginePath: enginePath,
buildPath: globalResults['android-debug-build-path']
));
......@@ -160,14 +163,16 @@ class FlutterCommandRunner extends CommandRunner {
if (Platform.isMacOS) {
configs.add(new BuildConfiguration.local(
type: BuildType.debug,
platform: BuildPlatform.iOS,
hostPlatform: hostPlatform,
targetPlatform: TargetPlatform.iOS,
enginePath: enginePath,
buildPath: globalResults['ios-debug-build-path']
));
configs.add(new BuildConfiguration.local(
type: BuildType.debug,
platform: BuildPlatform.iOSSimulator,
hostPlatform: hostPlatform,
targetPlatform: TargetPlatform.iOSSimulator,
enginePath: enginePath,
buildPath: globalResults['ios-sim-debug-build-path']
));
......@@ -177,7 +182,8 @@ class FlutterCommandRunner extends CommandRunner {
if (isRelease) {
configs.add(new BuildConfiguration.local(
type: BuildType.release,
platform: BuildPlatform.android,
hostPlatform: hostPlatform,
targetPlatform: TargetPlatform.android,
enginePath: enginePath,
buildPath: globalResults['android-release-build-path']
));
......@@ -185,14 +191,16 @@ class FlutterCommandRunner extends CommandRunner {
if (Platform.isMacOS) {
configs.add(new BuildConfiguration.local(
type: BuildType.release,
platform: BuildPlatform.iOS,
hostPlatform: hostPlatform,
targetPlatform: TargetPlatform.iOS,
enginePath: enginePath,
buildPath: globalResults['ios-release-build-path']
));
configs.add(new BuildConfiguration.local(
type: BuildType.release,
platform: BuildPlatform.iOSSimulator,
hostPlatform: hostPlatform,
targetPlatform: TargetPlatform.iOSSimulator,
enginePath: enginePath,
buildPath: globalResults['ios-sim-release-build-path']
));
......
......@@ -9,6 +9,7 @@ import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import '../build_configuration.dart';
import '../artifacts.dart';
import '../process.dart';
......@@ -40,7 +41,7 @@ class RunMojoCommand extends Command {
}
Future<int> _runAndroid(String devtoolsPath, _MojoConfig mojoConfig, String appPath, List<String> additionalArgs) {
String skyViewerUrl = ArtifactStore.googleStorageUrl('viewer', 'android-arm');
String skyViewerUrl = ArtifactStore.getCloudStorageBaseUrl('viewer', 'android-arm');
String command = _makePathAbsolute(devtoolsPath);
String appName = path.basename(appPath);
String appDir = path.dirname(appPath);
......@@ -65,7 +66,8 @@ class RunMojoCommand extends Command {
}
Future<int> _runLinux(String mojoPath, _MojoConfig mojoConfig, String appPath, List<String> additionalArgs) async {
String viewerPath = _makePathAbsolute(await ArtifactStore.getPath(Artifact.skyViewerMojo));
Artifact artifact = ArtifactStore.getArtifact(type: ArtifactType.viewer, targetPlatform: TargetPlatform.linux);
String viewerPath = _makePathAbsolute(await ArtifactStore.getPath(artifact));
String mojoBuildType = mojoConfig == _MojoConfig.Debug ? 'Debug' : 'Release';
String mojoShellPath = _makePathAbsolute(path.join(mojoPath, 'out', mojoBuildType, 'mojo_shell'));
List<String> cmd = [
......
......@@ -3,17 +3,21 @@
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import '../application_package.dart';
import '../device.dart';
import 'build.dart';
import 'flutter_command.dart';
import 'install.dart';
import 'stop.dart';
final Logger _logging = new Logger('sky_tools.start');
const String _localBundlePath = 'app.flx';
const bool _kUseServer = true;
class StartCommand extends FlutterCommand {
final String name = 'start';
......@@ -31,13 +35,20 @@ class StartCommand extends FlutterCommand {
defaultsTo: '.',
abbr: 't',
help: 'Target app path or filename to start.');
argParser.addFlag('http',
negatable: true,
defaultsTo: true,
help: 'Use a local HTTP server to serve your app to your device.');
argParser.addFlag('boot',
help: 'Boot the iOS Simulator if it isn\'t already running.');
}
@override
Future<int> runInProject() async {
await downloadApplicationPackagesAndConnectToDevices();
await Future.wait([
downloadToolchain(),
downloadApplicationPackagesAndConnectToDevices(),
]);
bool poke = argResults['poke'];
if (!poke) {
......@@ -59,8 +70,19 @@ class StartCommand extends FlutterCommand {
continue;
if (device is AndroidDevice) {
String target = path.absolute(argResults['target']);
if (await device.startServer(target, poke, argResults['checked'], package))
startedSomething = true;
if (argResults['http']) {
if (await device.startServer(target, poke, argResults['checked'], package))
startedSomething = true;
} else {
String mainPath = target;
if (FileSystemEntity.isDirectorySync(target))
mainPath = path.join(target, 'lib', 'main.dart');
BuildCommand builder = new BuildCommand();
builder.inheritFromParent(this);
await builder.build(outputPath: _localBundlePath, mainPath: mainPath);
if (device.startBundle(package, _localBundlePath, poke, argResults['checked']))
startedSomething = true;
}
} else {
if (await device.startApp(package))
startedSomething = true;
......
......@@ -66,7 +66,7 @@ abstract class Device {
/// Check if the current version of the given app is already installed
bool isAppInstalled(ApplicationPackage app);
BuildPlatform get platform;
TargetPlatform get platform;
Future<int> logs({bool clear: false});
......@@ -271,7 +271,7 @@ class IOSDevice extends Device {
}
@override
BuildPlatform get platform => BuildPlatform.iOS;
TargetPlatform get platform => TargetPlatform.iOS;
/// Note that clear is not supported on iOS at this time.
Future<int> logs({bool clear: false}) async {
......@@ -487,7 +487,7 @@ class IOSSimulator extends Device {
}
@override
BuildPlatform get platform => BuildPlatform.iOSSimulator;
TargetPlatform get platform => TargetPlatform.iOSSimulator;
Future<int> logs({bool clear: false}) async {
if (!isConnected()) {
......@@ -695,6 +695,10 @@ class AndroidDevice extends Device {
return '${_getDeviceDataPath(app)}/${app.name}.sha1';
}
String _getDeviceBundlePath(ApplicationPackage app) {
return '${_getDeviceDataPath(app)}/dev.flx';
}
String _getDeviceApkSha1(ApplicationPackage app) {
return runCheckedSync([adbPath, 'shell', 'cat', _getDeviceSha1Path(app)]);
}
......@@ -750,12 +754,45 @@ class AndroidDevice extends Device {
return true;
}
void _forwardObservatoryPort() {
// Set up port forwarding for observatory.
String observatoryPortString = 'tcp:$_observatoryPort';
runCheckedSync(
[adbPath, 'forward', observatoryPortString, observatoryPortString]);
}
bool startBundle(AndroidApk apk, String bundlePath, bool poke, bool checked) {
if (!FileSystemEntity.isFileSync(bundlePath)) {
_logging.severe('Cannot find $bundlePath');
return false;
}
if (!poke)
_forwardObservatoryPort();
String deviceTmpPath = '/data/local/tmp/dev.flx';
String deviceBundlePath = _getDeviceBundlePath(apk);
runCheckedSync([adbPath, 'push', bundlePath, deviceTmpPath]);
runCheckedSync([adbPath, 'shell', 'mv', deviceTmpPath, deviceBundlePath]);
List<String> cmd = [
adbPath,
'shell', 'am', 'start',
'-a', 'android.intent.action.RUN',
'-d', deviceBundlePath,
];
if (checked)
cmd.addAll(['--ez', 'enable-checked-mode', 'true']);
cmd.add(apk.launchActivity);
runCheckedSync(cmd);
return true;
}
Future<bool> startServer(
String target, bool poke, bool checked, AndroidApk apk) async {
String serverRoot = '';
String mainDart = '';
String missingMessage = '';
if (await FileSystemEntity.isDirectory(target)) {
if (FileSystemEntity.isDirectorySync(target)) {
serverRoot = target;
mainDart = path.join(serverRoot, 'lib', 'main.dart');
missingMessage = 'Missing lib/main.dart in project: $serverRoot';
......@@ -765,16 +802,13 @@ class AndroidDevice extends Device {
missingMessage = '$mainDart does not exist.';
}
if (!await FileSystemEntity.isFile(mainDart)) {
if (!FileSystemEntity.isFileSync(mainDart)) {
_logging.severe(missingMessage);
return false;
}
if (!poke) {
// Set up port forwarding for observatory.
String observatoryPortString = 'tcp:$_observatoryPort';
runCheckedSync(
[adbPath, 'forward', observatoryPortString, observatoryPortString]);
_forwardObservatoryPort();
// Actually start the server.
Process server = await Process.start(
......@@ -794,28 +828,20 @@ class AndroidDevice extends Device {
String relativeDartMain = _convertToURL(path.relative(mainDart, from: serverRoot));
String url = 'http://localhost:$_serverPort/$relativeDartMain';
if (poke) {
if (poke)
url += '?rand=${new Random().nextDouble()}';
}
// Actually launch the app on Android.
List<String> cmd = [
adbPath,
'shell',
'am',
'start',
'-a',
'android.intent.action.VIEW',
'-d',
url,
'shell', 'am', 'start',
'-a', 'android.intent.action.VIEW',
'-d', url,
];
if (checked) {
if (checked)
cmd.addAll(['--ez', 'enable-checked-mode', 'true']);
}
cmd.add(apk.launchActivity);
runCheckedSync(cmd);
return true;
}
......@@ -880,7 +906,7 @@ class AndroidDevice extends Device {
}
@override
BuildPlatform get platform => BuildPlatform.android;
TargetPlatform get platform => TargetPlatform.android;
void clearLogs() {
runSync([adbPath, 'logcat', '-c']);
......@@ -985,24 +1011,20 @@ class DeviceStore {
IOSSimulator iOSSimulator;
for (BuildConfiguration config in configs) {
switch (config.platform) {
case BuildPlatform.android:
switch (config.targetPlatform) {
case TargetPlatform.android:
assert(android == null);
android = new AndroidDevice();
break;
case BuildPlatform.iOS:
case TargetPlatform.iOS:
assert(iOS == null);
iOS = new IOSDevice();
break;
case BuildPlatform.iOSSimulator:
case TargetPlatform.iOSSimulator:
assert(iOSSimulator == null);
iOSSimulator = new IOSSimulator();
break;
case BuildPlatform.mac:
case BuildPlatform.linux:
// TODO(abarth): Support mac and linux targets.
assert(false);
case TargetPlatform.linux:
break;
}
}
......
......@@ -11,16 +11,16 @@ import 'build_configuration.dart';
import 'process.dart';
class Compiler {
Compiler(this._compilerPath);
Compiler(this._path);
String _compilerPath;
String _path;
Future<int> compile({
String mainPath,
String snapshotPath
}) {
return runCommandAndStreamOutput([
_compilerPath,
_path,
mainPath,
'--package-root=${ArtifactStore.packageRoot}',
'--snapshot=$snapshotPath'
......@@ -28,18 +28,22 @@ class Compiler {
}
}
Future<String> _getCompilerPath(BuildConfiguration config) async {
if (config.type != BuildType.prebuilt)
return path.join(config.buildDir, 'clang_x64', 'sky_snapshot');
Artifact artifact = ArtifactStore.getArtifact(
type: ArtifactType.snapshot, hostPlatform: config.hostPlatform);
return await ArtifactStore.getPath(artifact);
}
class Toolchain {
Toolchain({ this.compiler });
final Compiler compiler;
static Future<Toolchain> forConfigs(List<BuildConfiguration> configs) async {
// TODO(abarth): Add a notion of "host platform" to the build configs.
BuildConfiguration config = configs.first;
String compilerPath = config.type == BuildType.prebuilt ?
await ArtifactStore.getPath(Artifact.flutterCompiler) :
path.join(config.buildDir, 'clang_x64', 'sky_snapshot');
// TODO(abarth): Shouldn't we consider all the configs?
String compilerPath = await _getCompilerPath(configs.first);
return new Toolchain(compiler: new Compiler(compilerPath));
}
}
......@@ -26,21 +26,21 @@ class MockToolchain extends Toolchain {
}
class MockAndroidDevice extends Mock implements AndroidDevice {
BuildPlatform get platform => BuildPlatform.android;
TargetPlatform get platform => TargetPlatform.android;
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockIOSDevice extends Mock implements IOSDevice {
BuildPlatform get platform => BuildPlatform.iOS;
TargetPlatform get platform => TargetPlatform.iOS;
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockIOSSimulator extends Mock implements IOSSimulator {
BuildPlatform get platform => BuildPlatform.iOSSimulator;
TargetPlatform get platform => TargetPlatform.iOSSimulator;
@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