mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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.
This commit is contained in:
parent
48c3d01587
commit
94b472ff67
@ -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 {
|
||||
android,
|
||||
iOS,
|
||||
iOSSimulator,
|
||||
enum HostPlatform {
|
||||
mac,
|
||||
linux,
|
||||
}
|
||||
|
||||
enum TargetPlatform {
|
||||
android,
|
||||
iOS,
|
||||
iOSSimulator,
|
||||
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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user