Commit 4fe1ca07 authored by Devon Carew's avatar Devon Carew

Merge pull request #2905 from devoncarew/run_cleanup

Run cleanup
parents 62757672 2fc8e9a1
......@@ -6,6 +6,7 @@ import 'dart:async';
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:path/path.dart' as path;
import 'package:stack_trace/stack_trace.dart';
import 'src/base/context.dart';
......@@ -31,6 +32,7 @@ import 'src/commands/update_packages.dart';
import 'src/commands/upgrade.dart';
import 'src/device.dart';
import 'src/doctor.dart';
import 'src/globals.dart';
import 'src/runner/flutter_command_runner.dart';
/// Main entry point for commands.
......@@ -89,9 +91,65 @@ Future<Null> main(List<String> args) async {
// We've caught an exit code.
exit(error.exitCode);
} else {
stderr.writeln(error);
stderr.writeln(chain.terse);
// We've crashed; emit a log report.
stderr.writeln();
stderr.writeln('Oops; flutter has crashed: "$error"');
File file = _createCrashReport(args, error, chain);
stderr.writeln();
stderr.writeln('Crash report written to ${path.relative(file.path)}.');
stderr.writeln('Please let us know at https://github.com/flutter/flutter/issues!');
exit(1);
}
});
}
File _createCrashReport(List<String> args, dynamic error, Chain chain) {
File crashFile = _createCrashFileName(Directory.current, 'flutter');
StringBuffer buf = new StringBuffer();
buf.writeln('Flutter crash report; please file at https://github.com/flutter/flutter/issues.\n');
buf.writeln('## command\n');
buf.writeln('flutter ${args.join(' ')}\n');
buf.writeln('## exception\n');
buf.writeln('$error\n');
buf.writeln('${chain.terse}');
buf.writeln('## flutter doctor\n');
buf.writeln(_doctorText());
crashFile.writeAsStringSync(buf.toString());
return crashFile;
}
File _createCrashFileName(Directory dir, String baseName) {
int i = 1;
while (true) {
String name = '${baseName}_${i.toString().padLeft(2, '0')}.log';
File file = new File(path.join(dir.path, name));
if (!file.existsSync())
return file;
i++;
}
}
String _doctorText() {
try {
BufferLogger logger = new BufferLogger();
AppContext appContext = new AppContext();
appContext[Logger] = logger;
appContext.runInZone(() => doctor.diagnose());
return logger.statusText;
} catch (error) {
return '';
}
}
......@@ -223,9 +223,9 @@ class AndroidDevice extends Device {
ServiceProtocolDiscovery serviceProtocolDiscovery =
new ServiceProtocolDiscovery(logReader);
// We take this future here but do not wait for completion until *after*
// we start the bundle.
Future<int> serviceProtocolPort = serviceProtocolDiscovery.nextPort();
// We take this future here but do not wait for completion until *after* we
// start the bundle.
Future<int> scrapeServicePort = serviceProtocolDiscovery.nextPort();
List<String> cmd = adbCommandForDevice(<String>[
'shell', 'am', 'start',
......@@ -250,13 +250,23 @@ class AndroidDevice extends Device {
return false;
}
// Wait for the service protocol port here. This will complete once
// the device has printed "Observatory is listening on..."
int devicePort = await serviceProtocolPort;
// Wait for the service protocol port here. This will complete once the
// device has printed "Observatory is listening on...".
printTrace('Waiting for observatory port to be available...');
try {
int devicePort = await scrapeServicePort.timeout(new Duration(seconds: 12));
printTrace('service protocol port = $devicePort');
await _forwardObservatoryPort(devicePort, debugPort);
return true;
} catch (error) {
if (error is TimeoutException)
printError('Timed out while waiting for a debug connection.');
else
printError('Error waiting for a debug connection: $error');
return false;
}
}
@override
......@@ -303,7 +313,7 @@ class AndroidDevice extends Device {
return runCommandAndStreamOutput(command).then((int exitCode) => exitCode == 0);
}
// TODO(devoncarew): Return android_arm or android_x64 based on [isLocalEmulator].
// TODO(devoncarew): Use isLocalEmulator to return android_arm or android_x64.
@override
TargetPlatform get platform => TargetPlatform.android_arm;
......@@ -533,7 +543,9 @@ class _AdbLogReader extends DeviceLogReader {
String lastTimestamp = device.lastLogcatTimestamp;
if (lastTimestamp != null)
args.addAll(<String>['-T', lastTimestamp]);
args.addAll(<String>['-s', 'flutter:V', 'ActivityManager:W', 'System.err:W', '*:F']);
args.addAll(<String>[
'-s', 'flutter:V', 'SkyMain:V', 'AndroidRuntime:W', 'ActivityManager:W', 'System.err:W', '*:F'
]);
_process = await runCommand(device.adbCommandForDevice(args));
_stdoutSubscription =
_process.stdout.transform(UTF8.decoder)
......
......@@ -125,8 +125,7 @@ class ApplicationPackageStore {
for (BuildConfiguration config in configs) {
switch (config.targetPlatform) {
case TargetPlatform.android_arm:
assert(android == null);
android = new AndroidApk.fromBuildConfiguration(config);
android ??= new AndroidApk.fromBuildConfiguration(config);
break;
case TargetPlatform.ios:
......
......@@ -72,12 +72,15 @@ class Artifact {
class ArtifactStore {
static const List<Artifact> knownArtifacts = const <Artifact>[
// tester
const Artifact._(
name: 'Flutter Tester',
fileName: 'sky_shell',
type: ArtifactType.shell,
targetPlatform: TargetPlatform.linux_x64
),
// snapshotters
const Artifact._(
name: 'Sky Snapshot',
fileName: 'sky_snapshot',
......@@ -90,6 +93,8 @@ class ArtifactStore {
type: ArtifactType.snapshot,
hostPlatform: HostPlatform.mac
),
// mojo
const Artifact._(
name: 'Flutter for Mojo',
fileName: 'flutter.mojo',
......@@ -102,6 +107,8 @@ class ArtifactStore {
type: ArtifactType.mojo,
targetPlatform: TargetPlatform.linux_x64
),
// android-arm
const Artifact._(
name: 'Compiled Java code',
fileName: 'classes.dex.jar',
......@@ -126,6 +133,8 @@ class ArtifactStore {
type: ArtifactType.androidLibSkyShell,
targetPlatform: TargetPlatform.android_arm
),
// iOS
const Artifact._(
name: 'iOS Runner (Xcode Project)',
fileName: 'FlutterXcode.zip',
......@@ -202,7 +211,7 @@ class ArtifactStore {
return cacheDir;
}
static Future<String> getPath(Artifact artifact) async {
static String getPath(Artifact artifact) {
File cachedFile = new File(path.join(
getBaseCacheDir().path, 'engine', artifact.platform, artifact.fileName
));
......
......@@ -116,22 +116,28 @@ String _runWithLoggingSync(List<String> cmd, {
printTrace(cmdText);
ProcessResult results =
Process.runSync(cmd[0], cmd.getRange(1, cmd.length).toList(), workingDirectory: workingDirectory);
printTrace('Exit code ${results.exitCode} from: ${cmd.join(' ')}');
if (results.stdout.isNotEmpty) {
if (results.exitCode != 0 && noisyErrors)
printStatus(results.stdout.trim());
else
printTrace(results.stdout.trim());
}
if (results.exitCode != 0) {
String errorDescription = 'Error code ${results.exitCode} '
'returned when attempting to run command: ${cmd.join(' ')}';
printTrace(errorDescription);
if (results.stderr.length > 0) {
if (noisyErrors) {
if (results.stderr.isNotEmpty) {
if (noisyErrors)
printError(results.stderr.trim());
} else {
printTrace('Errors logged: ${results.stderr.trim()}');
}
else
printTrace(results.stderr.trim());
}
if (checked)
throw errorDescription;
throw 'Exit code ${results.exitCode} from: ${cmd.join(' ')}';
}
if (results.stdout.trim().isNotEmpty)
printTrace(results.stdout.trim());
return results.stdout.trim();
}
......
......@@ -187,7 +187,10 @@ class BuildApkCommand extends FlutterCommand {
await downloadToolchain();
// TODO(devoncarew): This command should take an arg for the output type (arm / x64).
return await buildAndroid(
TargetPlatform.android_arm,
toolchain: toolchain,
configs: buildConfigurations,
enginePath: runner.enginePath,
......@@ -212,6 +215,7 @@ Future<_ApkComponents> _findApkComponents(
) async {
List<String> artifactPaths;
if (enginePath != null) {
// TODO(devoncarew): Support x64.
artifactPaths = [
'$enginePath/third_party/icu/android/icudtl.dat',
'${config.buildDir}/gen/sky/shell/shell/classes.dex.jar',
......@@ -225,10 +229,13 @@ Future<_ApkComponents> _findApkComponents(
ArtifactType.androidLibSkyShell,
ArtifactType.androidKeystore,
];
Iterable<Future<String>> pathFutures = artifactTypes.map(
(ArtifactType type) => ArtifactStore.getPath(ArtifactStore.getArtifact(
type: type, targetPlatform: TargetPlatform.android_arm)));
artifactPaths = await Future.wait(pathFutures);
Iterable<String> pathFutures = artifactTypes.map((ArtifactType type) {
return ArtifactStore.getPath(ArtifactStore.getArtifact(
type: type,
targetPlatform: config.targetPlatform
));
});
artifactPaths = pathFutures.toList();
}
_ApkComponents components = new _ApkComponents();
......@@ -254,9 +261,14 @@ Future<_ApkComponents> _findApkComponents(
}
int _buildApk(
_ApkComponents components, String flxPath, ApkKeystoreInfo keystore, String outputFile
TargetPlatform platform,
_ApkComponents components,
String flxPath,
ApkKeystoreInfo keystore,
String outputFile
) {
Directory tempDir = Directory.systemTemp.createTempSync('flutter_tools');
try {
_ApkBuilder builder = new _ApkBuilder(androidSdk.latestVersion);
......@@ -273,7 +285,9 @@ int _buildApk(
_AssetBuilder artifactBuilder = new _AssetBuilder(tempDir, 'artifacts');
artifactBuilder.add(classesDex, 'classes.dex');
artifactBuilder.add(components.libSkyShell, 'lib/armeabi-v7a/libsky_shell.so');
// x86? x86_64?
String abiDir = platform == TargetPlatform.android_arm ? 'armeabi-v7a' : 'x86';
artifactBuilder.add(components.libSkyShell, 'lib/$abiDir/libsky_shell.so');
File unalignedApk = new File('${tempDir.path}/app.apk.unaligned');
builder.package(
......@@ -359,7 +373,8 @@ bool _needsRebuild(String apkPath, String manifest) {
return false;
}
Future<int> buildAndroid({
Future<int> buildAndroid(
TargetPlatform platform, {
Toolchain toolchain,
List<BuildConfiguration> configs,
String enginePath,
......@@ -367,7 +382,7 @@ Future<int> buildAndroid({
String manifest: _kDefaultAndroidManifestPath,
String resources,
String outputFile: _kDefaultOutputPath,
String target: '',
String target,
String flxPath,
ApkKeystoreInfo keystore
}) async {
......@@ -399,10 +414,9 @@ Future<int> buildAndroid({
resources = _kDefaultResourcesPath;
}
BuildConfiguration config = configs.firstWhere(
(BuildConfiguration bc) => bc.targetPlatform == TargetPlatform.android_arm
);
BuildConfiguration config = configs.firstWhere((BuildConfiguration bc) => bc.targetPlatform == platform);
_ApkComponents components = await _findApkComponents(config, enginePath, manifest, resources);
if (components == null) {
printError('Failure building APK. Unable to find components.');
return 1;
......@@ -416,36 +430,34 @@ Future<int> buildAndroid({
printError('(Omit the --flx option to build the FLX automatically)');
return 1;
}
return _buildApk(components, flxPath, keystore, outputFile);
return _buildApk(platform, components, flxPath, keystore, outputFile);
} else {
// Find the path to the main Dart file; build the FLX.
String mainPath = findMainDartFile(target);
String localBundlePath = await flx.buildFlx(toolchain, mainPath: mainPath);
return _buildApk(components, localBundlePath, keystore, outputFile);
return _buildApk(platform, components, localBundlePath, keystore, outputFile);
}
}
// TODO(mpcomplete): move this to Device?
/// This is currently Android specific.
Future<int> buildAll(
List<Device> devices,
Future<int> buildForDevice(
Device device,
ApplicationPackageStore applicationPackages,
Toolchain toolchain,
List<BuildConfiguration> configs, {
String enginePath,
String target: ''
}) async {
for (Device device in devices) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null)
continue;
return 0;
// TODO(mpcomplete): Temporary hack. We only support the apk builder atm.
if (package != applicationPackages.android)
continue;
int result = await build(toolchain, configs, enginePath: enginePath, target: target);
if (package == applicationPackages.android) {
int result = await build(device.platform, toolchain, configs, enginePath: enginePath, target: target);
if (result != 0)
return result;
}
......@@ -454,10 +466,11 @@ Future<int> buildAll(
}
Future<int> build(
TargetPlatform platform,
Toolchain toolchain,
List<BuildConfiguration> configs, {
String enginePath,
String target: ''
String target
}) async {
if (!FileSystemEntity.isFileSync(_kDefaultAndroidManifestPath)) {
printError('Cannot build APK. Missing $_kDefaultAndroidManifestPath.');
......@@ -465,6 +478,7 @@ Future<int> build(
}
int result = await buildAndroid(
platform,
toolchain: toolchain,
configs: configs,
enginePath: enginePath,
......
......@@ -245,8 +245,10 @@ Future<int> startApp(DriveCommand command) async {
// TODO(devoncarew): We should remove the need to special case here.
if (command.device is AndroidDevice) {
printTrace('Building an APK.');
int result = await build_apk.build(command.toolchain, command.buildConfigurations,
enginePath: command.runner.enginePath, target: command.target);
int result = await build_apk.build(
command.device.platform, command.toolchain, command.buildConfigurations,
enginePath: command.runner.enginePath, target: command.target
);
if (result != 0)
return result;
......
......@@ -182,8 +182,8 @@ Future<int> startApp(
if (install) {
printTrace('Running build command.');
int result = await buildAll(
<Device>[device], applicationPackages, toolchain, configs,
int result = await buildForDevice(
device, applicationPackages, toolchain, configs,
enginePath: enginePath,
target: target
);
......@@ -232,15 +232,8 @@ Future<int> startApp(
platformArgs: platformArgs
);
if (!result) {
if (!result)
printError('Error running application on ${device.name}.');
} else {
// If the user specified --start-paused (and the device supports it) then
// wait for the observatory port to become available before returning from
// `startApp()`.
if (startPaused && device.supportsStartPaused)
await delayUntilObservatoryAvailable('localhost', debugPort);
}
return result ? 0 : 2;
}
......
......@@ -99,7 +99,7 @@ class RunMojoCommand extends FlutterCommand {
if (config == null || config.type == BuildType.prebuilt) {
TargetPlatform targetPlatform = argResults['android'] ? TargetPlatform.android_arm : TargetPlatform.linux_x64;
Artifact artifact = ArtifactStore.getArtifact(type: ArtifactType.mojo, targetPlatform: targetPlatform);
flutterPath = _makePathAbsolute(await ArtifactStore.getPath(artifact));
flutterPath = _makePathAbsolute(ArtifactStore.getPath(artifact));
} else {
String localPath = path.join(config.buildDir, 'flutter.mojo');
flutterPath = _makePathAbsolute(localPath);
......
......@@ -49,7 +49,7 @@ class TestCommand extends FlutterCommand {
if (config.type == BuildType.prebuilt) {
Artifact artifact = ArtifactStore.getArtifact(
type: ArtifactType.shell, targetPlatform: config.targetPlatform);
return await ArtifactStore.getPath(artifact);
return ArtifactStore.getPath(artifact);
} else {
switch (config.targetPlatform) {
case TargetPlatform.linux_x64:
......
......@@ -104,8 +104,8 @@ Future<int> setupXcodeProjectHarness(String flutterProjectPath) async {
targetPlatform: TargetPlatform.ios
);
String xcodeProjectPath = await ArtifactStore.getPath(xcodeProject);
List<int> archiveBytes = await new File(xcodeProjectPath).readAsBytes();
String xcodeProjectPath = ArtifactStore.getPath(xcodeProject);
List<int> archiveBytes = new File(xcodeProjectPath).readAsBytesSync();
if (archiveBytes.isEmpty) {
printError('Error: No archive bytes received.');
......
......@@ -459,9 +459,9 @@ class IOSSimulator extends Device {
ServiceProtocolDiscovery serviceProtocolDiscovery =
new ServiceProtocolDiscovery(logReader);
// We take this future here but do not wait for completion until *after*
// we start the application.
Future<int> serviceProtocolPort = serviceProtocolDiscovery.nextPort();
// We take this future here but do not wait for completion until *after* we
// start the application.
Future<int> scrapeServicePort = serviceProtocolDiscovery.nextPort();
// Prepare launch arguments.
List<String> args = <String>[
......@@ -487,14 +487,23 @@ class IOSSimulator extends Device {
return false;
}
// Wait for the service protocol port here. This will complete once
// the device has printed "Observatory is listening on..."
int devicePort = await serviceProtocolPort;
// Wait for the service protocol port here. This will complete once the
// device has printed "Observatory is listening on..."
printTrace('Waiting for observatory port to be available...');
try {
int devicePort = await scrapeServicePort.timeout(new Duration(seconds: 12));
printTrace('service protocol port = $devicePort');
printTrace('Successfully started ${app.name} on $id.');
printStatus('Observatory listening on http://127.0.0.1:$devicePort');
return true;
} catch (error) {
if (error is TimeoutException)
printError('Timed out while waiting for a debug connection.');
else
printError('Error waiting for a debug connection: $error');
return false;
}
}
bool _applicationIsInstalledAndRunning(ApplicationPackage app) {
......
......@@ -167,8 +167,9 @@ class FlutterCommandRunner extends CommandRunner {
@override
Future<dynamic> run(Iterable<String> args) {
return super.run(args).then((dynamic result) {
logger.flush();
return result;
}).whenComplete(() {
logger.flush();
});
}
......
......@@ -36,7 +36,7 @@ class SnapshotCompiler {
}
}
Future<String> _getCompilerPath(BuildConfiguration config) async {
String _getCompilerPath(BuildConfiguration config) {
if (config.type != BuildType.prebuilt) {
String compilerPath = path.join(config.buildDir, 'clang_x64', 'sky_snapshot');
if (FileSystemEntity.isFileSync(compilerPath))
......@@ -48,7 +48,7 @@ Future<String> _getCompilerPath(BuildConfiguration config) async {
}
Artifact artifact = ArtifactStore.getArtifact(
type: ArtifactType.snapshot, hostPlatform: config.hostPlatform);
return await ArtifactStore.getPath(artifact);
return ArtifactStore.getPath(artifact);
}
class Toolchain {
......@@ -58,7 +58,7 @@ class Toolchain {
static Future<Toolchain> forConfigs(List<BuildConfiguration> configs) async {
for (BuildConfiguration config in configs) {
String compilerPath = await _getCompilerPath(config);
String compilerPath = _getCompilerPath(config);
if (compilerPath != null)
return new Toolchain(compiler: new SnapshotCompiler(compilerPath));
}
......
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