Commit 1f35d451 authored by Devon Carew's avatar Devon Carew

Merge pull request #1441 from devoncarew/unify_logging

Unify logging
parents 91c0af60 d7fbf530
...@@ -6,9 +6,9 @@ import 'dart:async'; ...@@ -6,9 +6,9 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import 'package:stack_trace/stack_trace.dart'; import 'package:stack_trace/stack_trace.dart';
import 'src/base/context.dart';
import 'src/base/process.dart'; import 'src/base/process.dart';
import 'src/commands/analyze.dart'; import 'src/commands/analyze.dart';
import 'src/commands/apk.dart'; import 'src/commands/apk.dart';
...@@ -33,28 +33,6 @@ import 'src/runner/flutter_command_runner.dart'; ...@@ -33,28 +33,6 @@ import 'src/runner/flutter_command_runner.dart';
/// ///
/// This function is intended to be used from the [flutter] command line tool. /// This function is intended to be used from the [flutter] command line tool.
Future main(List<String> args) async { Future main(List<String> args) async {
DateTime startTime = new DateTime.now();
// This level can be adjusted by users through the `--verbose` option.
Logger.root.level = Level.WARNING;
Logger.root.onRecord.listen((LogRecord record) {
String prefix = '';
if (Logger.root.level <= Level.FINE) {
Duration elapsed = record.time.difference(startTime);
prefix = '[${elapsed.inMilliseconds.toString().padLeft(4)} ms] ';
}
String level = record.level.name.toLowerCase();
if (record.level >= Level.WARNING) {
stderr.writeln('$prefix$level: ${record.message}');
} else {
print('$prefix$level: ${record.message}');
}
if (record.error != null)
stderr.writeln(record.error);
if (record.stackTrace != null)
stderr.writeln(record.stackTrace);
});
FlutterCommandRunner runner = new FlutterCommandRunner() FlutterCommandRunner runner = new FlutterCommandRunner()
..addCommand(new AnalyzeCommand()) ..addCommand(new AnalyzeCommand())
..addCommand(new ApkCommand()) ..addCommand(new ApkCommand())
...@@ -92,8 +70,7 @@ Future main(List<String> args) async { ...@@ -92,8 +70,7 @@ Future main(List<String> args) async {
// We've caught an exit code. // We've caught an exit code.
exit(error.exitCode); exit(error.exitCode);
} else { } else {
stderr.writeln(error); printError(error, chain.terse.toTrace());
Logger.root.log(Level.SEVERE, '\nException:', null, chain.terse.toTrace());
exit(1); exit(1);
} }
}); });
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import '../base/logging.dart'; import '../base/context.dart';
import '../base/process.dart'; import '../base/process.dart';
// https://android.googlesource.com/platform/system/core/+/android-4.4_r1/adb/OVERVIEW.TXT // https://android.googlesource.com/platform/system/core/+/android-4.4_r1/adb/OVERVIEW.TXT
...@@ -83,11 +83,11 @@ class Adb { ...@@ -83,11 +83,11 @@ class Adb {
controller = new StreamController( controller = new StreamController(
onListen: () async { onListen: () async {
socket = await Socket.connect(InternetAddress.LOOPBACK_IP_V4, adbServerPort); socket = await Socket.connect(InternetAddress.LOOPBACK_IP_V4, adbServerPort);
logging.fine('--> host:track-devices'); printTrace('--> host:track-devices');
socket.add(_createAdbRequest('host:track-devices')); socket.add(_createAdbRequest('host:track-devices'));
socket.listen((List<int> data) { socket.listen((List<int> data) {
String stringResult = new String.fromCharCodes(data); String stringResult = new String.fromCharCodes(data);
logging.fine('<-- ${stringResult.trim()}'); printTrace('<-- ${stringResult.trim()}');
_AdbServerResponse response = new _AdbServerResponse( _AdbServerResponse response = new _AdbServerResponse(
stringResult, stringResult,
noStatus: !isFirstNotification noStatus: !isFirstNotification
...@@ -116,14 +116,14 @@ class Adb { ...@@ -116,14 +116,14 @@ class Adb {
Socket socket = await Socket.connect(InternetAddress.LOOPBACK_IP_V4, adbServerPort); Socket socket = await Socket.connect(InternetAddress.LOOPBACK_IP_V4, adbServerPort);
try { try {
logging.fine('--> $command'); printTrace('--> $command');
socket.add(_createAdbRequest(command)); socket.add(_createAdbRequest(command));
List<List<int>> result = await socket.toList(); List<List<int>> result = await socket.toList();
List<int> data = result.fold(<int>[], (List<int> previous, List<int> element) { List<int> data = result.fold(<int>[], (List<int> previous, List<int> element) {
return previous..addAll(element); return previous..addAll(element);
}); });
String stringResult = new String.fromCharCodes(data); String stringResult = new String.fromCharCodes(data);
logging.fine('<-- ${stringResult.trim()}'); printTrace('<-- ${stringResult.trim()}');
return stringResult; return stringResult;
} finally { } finally {
socket.destroy(); socket.destroy();
......
...@@ -9,7 +9,7 @@ import 'package:crypto/crypto.dart'; ...@@ -9,7 +9,7 @@ import 'package:crypto/crypto.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import '../application_package.dart'; import '../application_package.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../build_configuration.dart'; import '../build_configuration.dart';
import '../device.dart'; import '../device.dart';
...@@ -74,7 +74,7 @@ class AndroidDevice extends Device { ...@@ -74,7 +74,7 @@ class AndroidDevice extends Device {
_hasValidAndroid = _checkForSupportedAndroidVersion(); _hasValidAndroid = _checkForSupportedAndroidVersion();
if (!_hasAdb || !_hasValidAndroid) { if (!_hasAdb || !_hasValidAndroid) {
logging.warning('Unable to run on Android.'); printError('Unable to run on Android.');
} }
} }
...@@ -88,11 +88,11 @@ class AndroidDevice extends Device { ...@@ -88,11 +88,11 @@ class AndroidDevice extends Device {
path.join(androidHomeDir, 'sdk', 'platform-tools'))) { path.join(androidHomeDir, 'sdk', 'platform-tools'))) {
return path.join(androidHomeDir, 'sdk'); return path.join(androidHomeDir, 'sdk');
} else { } else {
logging.warning('Android SDK not found at $androidHomeDir'); printError('Android SDK not found at $androidHomeDir');
return null; return null;
} }
} else { } else {
logging.warning('Android SDK not found. The ANDROID_HOME variable must be set.'); printError('Android SDK not found. The ANDROID_HOME variable must be set.');
return null; return null;
} }
} }
...@@ -125,7 +125,7 @@ class AndroidDevice extends Device { ...@@ -125,7 +125,7 @@ class AndroidDevice extends Device {
} }
return false; return false;
} }
logging.warning( printError(
'Unrecognized adb version string $adbVersion. Skipping version check.'); 'Unrecognized adb version string $adbVersion. Skipping version check.');
return true; return true;
} }
...@@ -138,16 +138,15 @@ class AndroidDevice extends Device { ...@@ -138,16 +138,15 @@ class AndroidDevice extends Device {
} }
String locatedAdbPath = runCheckedSync(['which', 'adb']); String locatedAdbPath = runCheckedSync(['which', 'adb']);
logging.severe('"$locatedAdbPath" is too old. ' printError('"$locatedAdbPath" is too old. '
'Please install version 1.0.32 or later.\n' 'Please install version 1.0.32 or later.\n'
'Try setting ANDROID_HOME to the path to your Android SDK install. ' 'Try setting ANDROID_HOME to the path to your Android SDK install. '
'Android builds are unavailable.'); 'Android builds are unavailable.');
} catch (e, stack) { } catch (e) {
logging.severe('"adb" not found in \$PATH. ' printError('"adb" not found in \$PATH. '
'Please install the Android SDK or set ANDROID_HOME ' 'Please install the Android SDK or set ANDROID_HOME '
'to the path of your Android SDK install.'); 'to the path of your Android SDK install.');
logging.info(e); printTrace('$e');
logging.info(stack);
} }
return false; return false;
} }
...@@ -162,7 +161,7 @@ class AndroidDevice extends Device { ...@@ -162,7 +161,7 @@ class AndroidDevice extends Device {
String ready = runSync(adbCommandForDevice(['shell', 'echo', 'ready'])); String ready = runSync(adbCommandForDevice(['shell', 'echo', 'ready']));
if (ready.trim() != 'ready') { if (ready.trim() != 'ready') {
logging.info('Android device not found.'); printTrace('Android device not found.');
return false; return false;
} }
...@@ -174,18 +173,18 @@ class AndroidDevice extends Device { ...@@ -174,18 +173,18 @@ class AndroidDevice extends Device {
int sdkVersionParsed = int sdkVersionParsed =
int.parse(sdkVersion, onError: (String source) => null); int.parse(sdkVersion, onError: (String source) => null);
if (sdkVersionParsed == null) { if (sdkVersionParsed == null) {
logging.severe('Unexpected response from getprop: "$sdkVersion"'); printError('Unexpected response from getprop: "$sdkVersion"');
return false; return false;
} }
if (sdkVersionParsed < minApiLevel) { if (sdkVersionParsed < minApiLevel) {
logging.severe( printError(
'The Android version ($sdkVersion) on the target device is too old. Please ' 'The Android version ($sdkVersion) on the target device is too old. Please '
'use a $minVersionName (version $minApiLevel / $minVersionText) device or later.'); 'use a $minVersionName (version $minApiLevel / $minVersionText) device or later.');
return false; return false;
} }
return true; return true;
} catch (e) { } catch (e) {
logging.severe('Unexpected failure from adb: ', e); printError('Unexpected failure from adb: $e');
} }
return false; return false;
} }
...@@ -213,12 +212,11 @@ class AndroidDevice extends Device { ...@@ -213,12 +212,11 @@ class AndroidDevice extends Device {
return false; return false;
} }
if (runCheckedSync(adbCommandForDevice(['shell', 'pm', 'path', app.id])) == '') { if (runCheckedSync(adbCommandForDevice(['shell', 'pm', 'path', app.id])) == '') {
logging.info( printTrace('TODO(iansf): move this log to the caller. ${app.name} is not on the device. Installing now...');
'TODO(iansf): move this log to the caller. ${app.name} is not on the device. Installing now...');
return false; return false;
} }
if (_getDeviceApkSha1(app) != _getSourceSha1(app)) { if (_getDeviceApkSha1(app) != _getSourceSha1(app)) {
logging.info( printTrace(
'TODO(iansf): move this log to the caller. ${app.name} is out of date. Installing now...'); 'TODO(iansf): move this log to the caller. ${app.name} is out of date. Installing now...');
return false; return false;
} }
...@@ -228,17 +226,17 @@ class AndroidDevice extends Device { ...@@ -228,17 +226,17 @@ class AndroidDevice extends Device {
@override @override
bool installApp(ApplicationPackage app) { bool installApp(ApplicationPackage app) {
if (!isConnected()) { if (!isConnected()) {
logging.info('Android device not connected. Not installing.'); printTrace('Android device not connected. Not installing.');
return false; return false;
} }
if (!FileSystemEntity.isFileSync(app.localPath)) { if (!FileSystemEntity.isFileSync(app.localPath)) {
logging.severe('"${app.localPath}" does not exist.'); printError('"${app.localPath}" does not exist.');
return false; return false;
} }
print('Installing ${app.name} on device.'); printStatus('Installing ${app.name} on device.');
runCheckedSync(adbCommandForDevice(['install', '-r', app.localPath])); runCheckedSync(adbCommandForDevice(<String>['install', '-r', app.localPath]));
runCheckedSync(adbCommandForDevice(['shell', 'echo', '-n', _getSourceSha1(app), '>', _getDeviceSha1Path(app)])); runCheckedSync(adbCommandForDevice(<String>['shell', 'echo', '-n', _getSourceSha1(app), '>', _getDeviceSha1Path(app)]));
return true; return true;
} }
...@@ -246,9 +244,9 @@ class AndroidDevice extends Device { ...@@ -246,9 +244,9 @@ class AndroidDevice extends Device {
// Set up port forwarding for observatory. // Set up port forwarding for observatory.
String portString = 'tcp:$_observatoryPort'; String portString = 'tcp:$_observatoryPort';
try { try {
runCheckedSync(adbCommandForDevice(['forward', portString, portString])); runCheckedSync(adbCommandForDevice(<String>['forward', portString, portString]));
} catch (e) { } catch (e) {
logging.warning('Unable to forward observatory port ($_observatoryPort):\n$e'); printError('Unable to forward observatory port ($_observatoryPort):\n$e');
} }
} }
...@@ -259,10 +257,10 @@ class AndroidDevice extends Device { ...@@ -259,10 +257,10 @@ class AndroidDevice extends Device {
String route, String route,
bool clearLogs: false bool clearLogs: false
}) { }) {
logging.fine('$this startBundle'); printTrace('$this startBundle');
if (!FileSystemEntity.isFileSync(bundlePath)) { if (!FileSystemEntity.isFileSync(bundlePath)) {
logging.severe('Cannot find $bundlePath'); printError('Cannot find $bundlePath');
return false; return false;
} }
...@@ -303,7 +301,7 @@ class AndroidDevice extends Device { ...@@ -303,7 +301,7 @@ class AndroidDevice extends Device {
toolchain, toolchain,
mainPath: mainPath mainPath: mainPath
).then((flx.DirectoryResult buildResult) { ).then((flx.DirectoryResult buildResult) {
logging.fine('Starting bundle for $this.'); printTrace('Starting bundle for $this.');
try { try {
if (startBundle( if (startBundle(
...@@ -426,7 +424,7 @@ class AndroidDevice extends Device { ...@@ -426,7 +424,7 @@ class AndroidDevice extends Device {
)); ));
return localPath; return localPath;
} }
logging.warning('No trace file detected. ' printError('No trace file detected. '
'Did you remember to start the trace before stopping it?'); 'Did you remember to start the trace before stopping it?');
return null; return null;
} }
...@@ -447,7 +445,7 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) { ...@@ -447,7 +445,7 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) {
try { try {
runCheckedSync([adbPath, 'version']); runCheckedSync([adbPath, 'version']);
} catch (e) { } catch (e) {
logging.severe('Unable to find adb. Is "adb" in your path?'); printError('Unable to find adb. Is "adb" in your path?');
return devices; return devices;
} }
...@@ -497,16 +495,16 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) { ...@@ -497,16 +495,16 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) {
} else if (unauthorizedRegex.hasMatch(line)) { } else if (unauthorizedRegex.hasMatch(line)) {
Match match = unauthorizedRegex.firstMatch(line); Match match = unauthorizedRegex.firstMatch(line);
String deviceID = match[1]; String deviceID = match[1];
logging.warning( printError(
'Device $deviceID is not authorized.\n' 'Device $deviceID is not authorized.\n'
'You might need to check your device for an authorization dialog.' 'You might need to check your device for an authorization dialog.'
); );
} else if (offlineRegex.hasMatch(line)) { } else if (offlineRegex.hasMatch(line)) {
Match match = offlineRegex.firstMatch(line); Match match = offlineRegex.firstMatch(line);
String deviceID = match[1]; String deviceID = match[1];
logging.warning('Device $deviceID is offline.'); printError('Device $deviceID is offline.');
} else { } else {
logging.warning( printError(
'Unexpected failure parsing device information from adb output:\n' 'Unexpected failure parsing device information from adb output:\n'
'$line\n' '$line\n'
'Please report a bug at https://github.com/flutter/flutter/issues/new'); 'Please report a bug at https://github.com/flutter/flutter/issues/new');
...@@ -525,7 +523,7 @@ String getAdbPath() { ...@@ -525,7 +523,7 @@ String getAdbPath() {
} else if (FileSystemEntity.isFileSync(adbPath2)) { } else if (FileSystemEntity.isFileSync(adbPath2)) {
return adbPath2; return adbPath2;
} else { } else {
logging.info('"adb" not found at\n "$adbPath1" or\n "$adbPath2"\n' + printTrace('"adb" not found at\n "$adbPath1" or\n "$adbPath2"\n' +
'using default path "$_defaultAdbPath"'); 'using default path "$_defaultAdbPath"');
return _defaultAdbPath; return _defaultAdbPath;
} }
......
...@@ -8,7 +8,7 @@ import 'dart:io'; ...@@ -8,7 +8,7 @@ import 'dart:io';
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'base/logging.dart'; import 'base/context.dart';
import 'base/os.dart'; import 'base/os.dart';
import 'base/process.dart'; import 'base/process.dart';
import 'build_configuration.dart'; import 'build_configuration.dart';
...@@ -187,7 +187,7 @@ class ArtifactStore { ...@@ -187,7 +187,7 @@ class ArtifactStore {
else else
message += '\nDid you run this command from the same directory as your pubspec.yaml file?'; message += '\nDid you run this command from the same directory as your pubspec.yaml file?';
} }
stderr.writeln(message); printError(message);
throw new ProcessExit(2); throw new ProcessExit(2);
} }
} }
...@@ -195,7 +195,7 @@ class ArtifactStore { ...@@ -195,7 +195,7 @@ class ArtifactStore {
static void ensureHasSkyEnginePackage() { static void ensureHasSkyEnginePackage() {
Directory skyEnginePackage = new Directory(path.join(packageRoot, 'sky_engine')); Directory skyEnginePackage = new Directory(path.join(packageRoot, 'sky_engine'));
if (!skyEnginePackage.existsSync()) { if (!skyEnginePackage.existsSync()) {
stderr.writeln("Cannot locate the sky_engine package; did you include 'flutter' in your pubspec.yaml file?"); printError("Cannot locate the sky_engine package; did you include 'flutter' in your pubspec.yaml file?");
throw new ProcessExit(2); throw new ProcessExit(2);
} }
} }
...@@ -221,12 +221,12 @@ class ArtifactStore { ...@@ -221,12 +221,12 @@ class ArtifactStore {
/// Download a file from the given URL and return the bytes. /// Download a file from the given URL and return the bytes.
static Future<List<int>> _downloadFile(Uri url) async { static Future<List<int>> _downloadFile(Uri url) async {
logging.info('Downloading $url.'); printStatus('Downloading $url.');
HttpClient httpClient = new HttpClient(); HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.getUrl(url); HttpClientRequest request = await httpClient.getUrl(url);
HttpClientResponse response = await request.close(); HttpClientResponse response = await request.close();
logging.fine('Received response statusCode=${response.statusCode}'); printTrace('Received response statusCode=${response.statusCode}');
if (response.statusCode != 200) if (response.statusCode != 200)
throw new Exception(response.reasonPhrase); throw new Exception(response.reasonPhrase);
...@@ -276,7 +276,7 @@ class ArtifactStore { ...@@ -276,7 +276,7 @@ class ArtifactStore {
if (_pendingZipDownloads.containsKey(platform)) { if (_pendingZipDownloads.containsKey(platform)) {
return _pendingZipDownloads[platform]; return _pendingZipDownloads[platform];
} }
print('Downloading $platform artifacts from the cloud, one moment please...'); printStatus('Downloading $platform artifacts from the cloud, one moment please...');
Future future = _doDownloadArtifactsFromZip(platform); Future future = _doDownloadArtifactsFromZip(platform);
_pendingZipDownloads[platform] = future; _pendingZipDownloads[platform] = future;
return future.then((_) => _pendingZipDownloads.remove(platform)); return future.then((_) => _pendingZipDownloads.remove(platform));
...@@ -286,7 +286,7 @@ class ArtifactStore { ...@@ -286,7 +286,7 @@ class ArtifactStore {
static Directory _getBaseCacheDir() { static Directory _getBaseCacheDir() {
if (flutterRoot == null) { if (flutterRoot == null) {
logging.severe('FLUTTER_ROOT not specified. Cannot find artifact cache.'); printError('FLUTTER_ROOT not specified. Cannot find artifact cache.');
throw new ProcessExit(2); throw new ProcessExit(2);
} }
Directory cacheDir = new Directory(path.join(flutterRoot, 'bin', 'cache', 'artifacts')); Directory cacheDir = new Directory(path.join(flutterRoot, 'bin', 'cache', 'artifacts'));
...@@ -313,7 +313,7 @@ class ArtifactStore { ...@@ -313,7 +313,7 @@ class ArtifactStore {
if (!cachedFile.existsSync()) { if (!cachedFile.existsSync()) {
await _downloadArtifactsFromZip(artifact.platform); await _downloadArtifactsFromZip(artifact.platform);
if (!cachedFile.existsSync()) { if (!cachedFile.existsSync()) {
logging.severe('File not found in the platform artifacts: ${cachedFile.path}'); printError('File not found in the platform artifacts: ${cachedFile.path}');
throw new ProcessExit(2); throw new ProcessExit(2);
} }
} }
...@@ -331,7 +331,7 @@ class ArtifactStore { ...@@ -331,7 +331,7 @@ class ArtifactStore {
try { try {
await _downloadFileToCache(url, cachedFile); await _downloadFileToCache(url, cachedFile);
} catch (e) { } catch (e) {
logging.severe('Failed to fetch third-party artifact: $url: $e'); printError('Failed to fetch third-party artifact: $url: $e');
throw new ProcessExit(2); throw new ProcessExit(2);
} }
} }
...@@ -340,7 +340,7 @@ class ArtifactStore { ...@@ -340,7 +340,7 @@ class ArtifactStore {
static void clear() { static void clear() {
Directory cacheDir = _getBaseCacheDir(); Directory cacheDir = _getBaseCacheDir();
logging.fine('Clearing cache directory ${cacheDir.path}'); printTrace('Clearing cache directory ${cacheDir.path}');
cacheDir.deleteSync(recursive: true); cacheDir.deleteSync(recursive: true);
} }
......
// Copyright 2016 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';
final AppContext _defaultContext = new _DefaultAppContext();
/// A singleton for application functionality. This singleton can be different
/// on a per-Zone basis.
AppContext get context {
AppContext currentContext = Zone.current['context'];
return currentContext == null ? _defaultContext : currentContext;
}
/// Display an error level message to the user. Commands should use this if they
/// fail in some way.
void printError(String message, [StackTrace stackTrace]) => context.printError(message, stackTrace);
/// Display normal output of the command. This should be used for things like
/// progress messages, success messages, or just normal command output.
void printStatus(String message) => context.printStatus(message);
/// Use this for verbose tracing output. Users can turn this output on in order
/// to help diagnose issues with the toolchain or with their setup.
void printTrace(String message) => context.printTrace(message);
abstract class AppContext {
bool get verbose;
set verbose(bool value);
void printError(String message, [StackTrace stackTrace]);
void printStatus(String message);
void printTrace(String message);
}
class _DefaultAppContext implements AppContext {
DateTime _startTime = new DateTime.now();
bool _verbose = false;
bool get verbose => _verbose;
set verbose(bool value) {
_verbose = value;
}
void printError(String message, [StackTrace stackTrace]) {
stderr.writeln(_prefix + message);
if (stackTrace != null)
stderr.writeln(stackTrace);
}
void printStatus(String message) {
print(_prefix + message);
}
void printTrace(String message) {
if (_verbose)
print('$_prefix- $message');
}
String get _prefix {
if (!_verbose)
return '';
Duration elapsed = new DateTime.now().difference(_startTime);
return '[${elapsed.inMilliseconds.toString().padLeft(4)} ms] ';
}
}
// 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:logging/logging.dart';
final Logger logging = new Logger('flutter_tools');
...@@ -6,7 +6,7 @@ import 'dart:async'; ...@@ -6,7 +6,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'logging.dart'; import 'context.dart';
/// This runs the command and streams stdout/stderr from the child process to /// This runs the command and streams stdout/stderr from the child process to
/// this process' stdout/stderr. /// this process' stdout/stderr.
...@@ -15,7 +15,7 @@ Future<int> runCommandAndStreamOutput(List<String> cmd, { ...@@ -15,7 +15,7 @@ Future<int> runCommandAndStreamOutput(List<String> cmd, {
RegExp filter, RegExp filter,
String workingDirectory String workingDirectory
}) async { }) async {
logging.info(cmd.join(' ')); printTrace(cmd.join(' '));
Process process = await Process.start( Process process = await Process.start(
cmd[0], cmd[0],
cmd.sublist(1), cmd.sublist(1),
...@@ -28,7 +28,7 @@ Future<int> runCommandAndStreamOutput(List<String> cmd, { ...@@ -28,7 +28,7 @@ Future<int> runCommandAndStreamOutput(List<String> cmd, {
dataLines = dataLines.where((String s) => filter.hasMatch(s)).toList(); dataLines = dataLines.where((String s) => filter.hasMatch(s)).toList();
} }
if (dataLines.length > 0) { if (dataLines.length > 0) {
stdout.write('$prefix${dataLines.join('\n$prefix')}\n'); printStatus('$prefix${dataLines.join('\n$prefix')}');
} }
}); });
process.stderr.transform(UTF8.decoder).listen((String data) { process.stderr.transform(UTF8.decoder).listen((String data) {
...@@ -38,7 +38,7 @@ Future<int> runCommandAndStreamOutput(List<String> cmd, { ...@@ -38,7 +38,7 @@ Future<int> runCommandAndStreamOutput(List<String> cmd, {
dataLines = dataLines.where((String s) => filter.hasMatch(s)); dataLines = dataLines.where((String s) => filter.hasMatch(s));
} }
if (dataLines.length > 0) { if (dataLines.length > 0) {
stderr.write('$prefix${dataLines.join('\n$prefix')}\n'); printError('$prefix${dataLines.join('\n$prefix')}');
} }
}); });
return await process.exitCode; return await process.exitCode;
...@@ -47,13 +47,13 @@ Future<int> runCommandAndStreamOutput(List<String> cmd, { ...@@ -47,13 +47,13 @@ Future<int> runCommandAndStreamOutput(List<String> cmd, {
Future runAndKill(List<String> cmd, Duration timeout) { Future runAndKill(List<String> cmd, Duration timeout) {
Future<Process> proc = runDetached(cmd); Future<Process> proc = runDetached(cmd);
return new Future.delayed(timeout, () async { return new Future.delayed(timeout, () async {
logging.info('Intentionally killing ${cmd[0]}'); printTrace('Intentionally killing ${cmd[0]}');
Process.killPid((await proc).pid); Process.killPid((await proc).pid);
}); });
} }
Future<Process> runDetached(List<String> cmd) { Future<Process> runDetached(List<String> cmd) {
logging.info(cmd.join(' ')); printTrace(cmd.join(' '));
Future<Process> proc = Process.start( Future<Process> proc = Process.start(
cmd[0], cmd.getRange(1, cmd.length).toList(), cmd[0], cmd.getRange(1, cmd.length).toList(),
mode: ProcessStartMode.DETACHED); mode: ProcessStartMode.DETACHED);
...@@ -81,20 +81,20 @@ String _runWithLoggingSync(List<String> cmd, { ...@@ -81,20 +81,20 @@ String _runWithLoggingSync(List<String> cmd, {
bool checked: false, bool checked: false,
String workingDirectory String workingDirectory
}) { }) {
logging.info(cmd.join(' ')); printTrace(cmd.join(' '));
ProcessResult results = ProcessResult results =
Process.runSync(cmd[0], cmd.getRange(1, cmd.length).toList(), workingDirectory: workingDirectory); Process.runSync(cmd[0], cmd.getRange(1, cmd.length).toList(), workingDirectory: workingDirectory);
if (results.exitCode != 0) { if (results.exitCode != 0) {
String errorDescription = 'Error code ${results.exitCode} ' String errorDescription = 'Error code ${results.exitCode} '
'returned when attempting to run command: ${cmd.join(' ')}'; 'returned when attempting to run command: ${cmd.join(' ')}';
logging.info(errorDescription); printTrace(errorDescription);
if (results.stderr.length > 0) if (results.stderr.length > 0)
logging.info('Errors logged: ${results.stderr.trim()}'); printTrace('Errors logged: ${results.stderr.trim()}');
if (checked) if (checked)
throw errorDescription; throw errorDescription;
} }
if (results.stdout.trim().isNotEmpty) if (results.stdout.trim().isNotEmpty)
logging.fine(results.stdout.trim()); printTrace(results.stdout.trim());
return results.stdout; return results.stdout;
} }
......
...@@ -6,7 +6,7 @@ import 'dart:io'; ...@@ -6,7 +6,7 @@ import 'dart:io';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'base/logging.dart'; import 'base/context.dart';
enum BuildType { enum BuildType {
prebuilt, prebuilt,
...@@ -32,7 +32,7 @@ HostPlatform getCurrentHostPlatform() { ...@@ -32,7 +32,7 @@ HostPlatform getCurrentHostPlatform() {
return HostPlatform.mac; return HostPlatform.mac;
if (Platform.isLinux) if (Platform.isLinux)
return HostPlatform.linux; return HostPlatform.linux;
logging.warning('Unsupported host platform, defaulting to Linux'); printError('Unsupported host platform, defaulting to Linux');
return HostPlatform.linux; return HostPlatform.linux;
} }
...@@ -41,7 +41,7 @@ TargetPlatform getCurrentHostPlatformAsTarget() { ...@@ -41,7 +41,7 @@ TargetPlatform getCurrentHostPlatformAsTarget() {
return TargetPlatform.mac; return TargetPlatform.mac;
if (Platform.isLinux) if (Platform.isLinux)
return TargetPlatform.linux; return TargetPlatform.linux;
logging.warning('Unsupported host platform, defaulting to Linux'); printError('Unsupported host platform, defaulting to Linux');
return TargetPlatform.linux; return TargetPlatform.linux;
} }
......
...@@ -11,7 +11,7 @@ import 'package:den_api/den_api.dart'; ...@@ -11,7 +11,7 @@ import 'package:den_api/den_api.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../build_configuration.dart'; import '../build_configuration.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -188,7 +188,7 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -188,7 +188,7 @@ class AnalyzeCommand extends FlutterCommand {
String packageName = pubSpecYaml.name; String packageName = pubSpecYaml.name;
String packagePath = path.normalize(path.absolute(path.join(directory.path, 'lib'))); String packagePath = path.normalize(path.absolute(path.join(directory.path, 'lib')));
if (packages.containsKey(packageName) && packages[packageName] != packagePath) { if (packages.containsKey(packageName) && packages[packageName] != packagePath) {
logging.warning('Inconsistent requirements for $packageName; using $packagePath (and not ${packages[packageName]}).'); printError('Inconsistent requirements for $packageName; using $packagePath (and not ${packages[packageName]}).');
hadInconsistentRequirements = true; hadInconsistentRequirements = true;
} }
packages[packageName] = packagePath; packages[packageName] = packagePath;
...@@ -208,7 +208,7 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -208,7 +208,7 @@ class AnalyzeCommand extends FlutterCommand {
for (String package in dependencies.keys) { for (String package in dependencies.keys) {
if (packages.containsKey(package)) { if (packages.containsKey(package)) {
if (packages[package] != dependencies[package]) { if (packages[package] != dependencies[package]) {
logging.warning('Inconsistent requirements for $package; using ${packages[package]} (and not ${dependencies[package]}).'); printError('Inconsistent requirements for $package; using ${packages[package]} (and not ${dependencies[package]}).');
hadInconsistentRequirements = true; hadInconsistentRequirements = true;
} }
} else { } else {
...@@ -219,9 +219,9 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -219,9 +219,9 @@ class AnalyzeCommand extends FlutterCommand {
} }
if (hadInconsistentRequirements) { if (hadInconsistentRequirements) {
if (foundAnyInFlutterRepo) if (foundAnyInFlutterRepo)
logging.warning('You may need to run "dart ${path.normalize(path.relative(path.join(ArtifactStore.flutterRoot, 'dev/update_packages.dart')))} --upgrade".'); printError('You may need to run "dart ${path.normalize(path.relative(path.join(ArtifactStore.flutterRoot, 'dev/update_packages.dart')))} --upgrade".');
if (foundAnyInCurrentDirectory) if (foundAnyInCurrentDirectory)
logging.warning('You may need to run "pub upgrade".'); printError('You may need to run "pub upgrade".');
} }
String buildDir = buildConfigurations.firstWhere((BuildConfiguration config) => config.testable, orElse: () => null)?.buildDir; String buildDir = buildConfigurations.firstWhere((BuildConfiguration config) => config.testable, orElse: () => null)?.buildDir;
...@@ -256,7 +256,7 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -256,7 +256,7 @@ class AnalyzeCommand extends FlutterCommand {
mainFile.path mainFile.path
]; ];
logging.info(cmd.join(' ')); printStatus(cmd.join(' '));
Process process = await Process.start( Process process = await Process.start(
cmd[0], cmd[0],
cmd.sublist(1), cmd.sublist(1),
...@@ -270,7 +270,7 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -270,7 +270,7 @@ class AnalyzeCommand extends FlutterCommand {
process.stderr.transform(UTF8.decoder).listen((String data) { process.stderr.transform(UTF8.decoder).listen((String data) {
// dartanalyzer doesn't seem to ever output anything on stderr // dartanalyzer doesn't seem to ever output anything on stderr
errorCount += 1; errorCount += 1;
print(data); printError(data);
}); });
int exitCode = await process.exitCode; int exitCode = await process.exitCode;
...@@ -336,7 +336,7 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -336,7 +336,7 @@ class AnalyzeCommand extends FlutterCommand {
if (shouldIgnore) if (shouldIgnore)
continue; continue;
} }
print(errorLine); printError(errorLine);
errorCount += 1; errorCount += 1;
} }
} }
...@@ -349,7 +349,7 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -349,7 +349,7 @@ class AnalyzeCommand extends FlutterCommand {
if (errorCount > 0) if (errorCount > 0)
return 1; // Doesn't this mean 'hints' per the above comment? return 1; // Doesn't this mean 'hints' per the above comment?
if (argResults['congratulate']) if (argResults['congratulate'])
print('No analyzer warnings! (ran in ${elapsed}s)'); printStatus('No analyzer warnings! (ran in ${elapsed}s)');
return 0; return 0;
} }
} }
...@@ -11,8 +11,8 @@ import 'package:yaml/yaml.dart'; ...@@ -11,8 +11,8 @@ import 'package:yaml/yaml.dart';
import '../android/device_android.dart'; import '../android/device_android.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/logging.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../build_configuration.dart'; import '../build_configuration.dart';
import '../flx.dart' as flx; import '../flx.dart' as flx;
...@@ -251,25 +251,25 @@ class ApkCommand extends FlutterCommand { ...@@ -251,25 +251,25 @@ class ApkCommand extends FlutterCommand {
if (!components.resources.existsSync()) { if (!components.resources.existsSync()) {
// TODO(eseidel): This level should be higher when path is manually set. // TODO(eseidel): This level should be higher when path is manually set.
logging.info('Can not locate Resources: ${components.resources}, ignoring.'); printStatus('Can not locate Resources: ${components.resources}, ignoring.');
components.resources = null; components.resources = null;
} }
if (!components.androidSdk.existsSync()) { if (!components.androidSdk.existsSync()) {
logging.severe('Can not locate Android SDK: $androidSdkPath'); printError('Can not locate Android SDK: $androidSdkPath');
return null; return null;
} }
if (!(new _ApkBuilder(components.androidSdk.path).checkSdkPath())) { if (!(new _ApkBuilder(components.androidSdk.path).checkSdkPath())) {
logging.severe('Can not locate expected Android SDK tools at $androidSdkPath'); printError('Can not locate expected Android SDK tools at $androidSdkPath');
logging.severe('You must install version $_kAndroidPlatformVersion of the SDK platform'); printError('You must install version $_kAndroidPlatformVersion of the SDK platform');
logging.severe('and version $_kBuildToolsVersion of the build tools.'); printError('and version $_kBuildToolsVersion of the build tools.');
return null; return null;
} }
for (File f in [components.manifest, components.icuData, for (File f in [components.manifest, components.icuData,
components.libSkyShell, components.debugKeystore] components.libSkyShell, components.debugKeystore]
..addAll(components.jars)) { ..addAll(components.jars)) {
if (!f.existsSync()) { if (!f.existsSync()) {
logging.severe('Can not locate file: ${f.path}'); printError('Can not locate file: ${f.path}');
return null; return null;
} }
} }
...@@ -327,7 +327,7 @@ class ApkCommand extends FlutterCommand { ...@@ -327,7 +327,7 @@ class ApkCommand extends FlutterCommand {
ensureDirectoryExists(finalApk.path); ensureDirectoryExists(finalApk.path);
builder.align(unalignedApk, finalApk); builder.align(unalignedApk, finalApk);
print('APK generated: ${finalApk.path}'); printStatus('APK generated: ${finalApk.path}');
return 0; return 0;
} finally { } finally {
...@@ -342,7 +342,7 @@ class ApkCommand extends FlutterCommand { ...@@ -342,7 +342,7 @@ class ApkCommand extends FlutterCommand {
String keyPassword; String keyPassword;
if (argResults['keystore'].isEmpty) { if (argResults['keystore'].isEmpty) {
logging.warning('Signing the APK using the debug keystore'); printError('Signing the APK using the debug keystore');
keystore = components.debugKeystore; keystore = components.debugKeystore;
keystorePassword = _kDebugKeystorePassword; keystorePassword = _kDebugKeystorePassword;
keyAlias = _kDebugKeystoreKeyAlias; keyAlias = _kDebugKeystoreKeyAlias;
...@@ -352,7 +352,7 @@ class ApkCommand extends FlutterCommand { ...@@ -352,7 +352,7 @@ class ApkCommand extends FlutterCommand {
keystorePassword = argResults['keystore-password']; keystorePassword = argResults['keystore-password'];
keyAlias = argResults['keystore-key-alias']; keyAlias = argResults['keystore-key-alias'];
if (keystorePassword.isEmpty || keyAlias.isEmpty) { if (keystorePassword.isEmpty || keyAlias.isEmpty) {
logging.severe('Must provide a keystore password and a key alias'); printError('Must provide a keystore password and a key alias');
return 1; return 1;
} }
keyPassword = argResults['keystore-key-password']; keyPassword = argResults['keystore-key-password'];
...@@ -373,7 +373,7 @@ class ApkCommand extends FlutterCommand { ...@@ -373,7 +373,7 @@ class ApkCommand extends FlutterCommand {
_ApkComponents components = await _findApkComponents(config); _ApkComponents components = await _findApkComponents(config);
if (components == null) { if (components == null) {
logging.severe('Unable to build APK.'); printError('Unable to build APK.');
return 1; return 1;
} }
...@@ -381,8 +381,8 @@ class ApkCommand extends FlutterCommand { ...@@ -381,8 +381,8 @@ class ApkCommand extends FlutterCommand {
if (!flxPath.isEmpty) { if (!flxPath.isEmpty) {
if (!FileSystemEntity.isFileSync(flxPath)) { if (!FileSystemEntity.isFileSync(flxPath)) {
logging.severe('FLX does not exist: $flxPath'); printError('FLX does not exist: $flxPath');
logging.severe('(Omit the --flx option to build the FLX automatically)'); printError('(Omit the --flx option to build the FLX automatically)');
return 1; return 1;
} }
return _buildApk(components, flxPath); return _buildApk(components, flxPath);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import 'dart:async'; import 'dart:async';
import '../base/logging.dart'; import '../base/context.dart';
import '../flx.dart'; import '../flx.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
import '../toolchain.dart'; import '../toolchain.dart';
...@@ -45,9 +45,9 @@ class BuildCommand extends FlutterCommand { ...@@ -45,9 +45,9 @@ class BuildCommand extends FlutterCommand {
precompiledSnapshot: argResults['precompiled'] precompiledSnapshot: argResults['precompiled']
).then((int result) { ).then((int result) {
if (result == 0) if (result == 0)
print('Built $outputPath.'); printStatus('Built $outputPath.');
else else
logging.severe('Error building $outputPath: $result.'); printError('Error building $outputPath: $result.');
return result; return result;
}); });
} }
......
...@@ -11,7 +11,7 @@ import 'package:path/path.dart' as path; ...@@ -11,7 +11,7 @@ import 'package:path/path.dart' as path;
import '../android/android.dart' as android; import '../android/android.dart' as android;
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../base/process.dart'; import '../base/process.dart';
class CreateCommand extends Command { class CreateCommand extends Command {
...@@ -28,21 +28,21 @@ class CreateCommand extends Command { ...@@ -28,21 +28,21 @@ class CreateCommand extends Command {
@override @override
Future<int> run() async { Future<int> run() async {
if (!argResults.wasParsed('out')) { if (!argResults.wasParsed('out')) {
print('No option specified for the output directory.'); printStatus('No option specified for the output directory.');
print(argParser.usage); printStatus(argParser.usage);
return 2; return 2;
} }
if (ArtifactStore.flutterRoot == null) { if (ArtifactStore.flutterRoot == null) {
stderr.writeln('Neither the --flutter-root command line flag nor the FLUTTER_ROOT environment'); printError('Neither the --flutter-root command line flag nor the FLUTTER_ROOT environment');
stderr.writeln('variable was specified. Unable to find package:flutter.'); printError('variable was specified. Unable to find package:flutter.');
return 2; return 2;
} }
String flutterRoot = path.absolute(ArtifactStore.flutterRoot); String flutterRoot = path.absolute(ArtifactStore.flutterRoot);
String flutterPackagePath = path.join(flutterRoot, 'packages', 'flutter'); String flutterPackagePath = path.join(flutterRoot, 'packages', 'flutter');
if (!FileSystemEntity.isFileSync(path.join(flutterPackagePath, 'pubspec.yaml'))) { if (!FileSystemEntity.isFileSync(path.join(flutterPackagePath, 'pubspec.yaml'))) {
print('Unable to find package:flutter in $flutterPackagePath'); printError('Unable to find package:flutter in $flutterPackagePath');
return 2; return 2;
} }
...@@ -50,7 +50,7 @@ class CreateCommand extends Command { ...@@ -50,7 +50,7 @@ class CreateCommand extends Command {
new FlutterSimpleTemplate().generateInto(out, flutterPackagePath); new FlutterSimpleTemplate().generateInto(out, flutterPackagePath);
print(''); printStatus('');
String message = '''All done! To run your application: String message = '''All done! To run your application:
...@@ -64,7 +64,7 @@ class CreateCommand extends Command { ...@@ -64,7 +64,7 @@ class CreateCommand extends Command {
return code; return code;
} }
print(message); printStatus(message);
return 0; return 0;
} }
...@@ -80,13 +80,13 @@ class CreateCommand extends Command { ...@@ -80,13 +80,13 @@ class CreateCommand extends Command {
if (!pubSpecYaml.existsSync()) { if (!pubSpecYaml.existsSync()) {
if (skipIfAbsent) if (skipIfAbsent)
return 0; return 0;
logging.severe('$directory: no pubspec.yaml found'); printError('$directory: no pubspec.yaml found');
return 1; return 1;
} }
if (!pubSpecLock.existsSync() || pubSpecYaml.lastModifiedSync().isAfter(pubSpecLock.lastModifiedSync())) { if (!pubSpecLock.existsSync() || pubSpecYaml.lastModifiedSync().isAfter(pubSpecLock.lastModifiedSync())) {
if (verbose) if (verbose)
print("Running pub get in $directory..."); printStatus("Running pub get in $directory...");
int code = await runCommandAndStreamOutput( int code = await runCommandAndStreamOutput(
[sdkBinaryName('pub'), 'get'], [sdkBinaryName('pub'), 'get'],
workingDirectory: directory workingDirectory: directory
...@@ -99,7 +99,7 @@ class CreateCommand extends Command { ...@@ -99,7 +99,7 @@ class CreateCommand extends Command {
(dotPackages.existsSync() && dotPackages.lastModifiedSync().isAfter(pubSpecYaml.lastModifiedSync()))) (dotPackages.existsSync() && dotPackages.lastModifiedSync().isAfter(pubSpecYaml.lastModifiedSync())))
return 0; return 0;
logging.severe('$directory: pubspec.yaml, pubspec.lock, and .packages are in an inconsistent state'); printError('$directory: pubspec.yaml, pubspec.lock, and .packages are in an inconsistent state');
return 1; return 1;
} }
} }
...@@ -115,7 +115,7 @@ abstract class Template { ...@@ -115,7 +115,7 @@ abstract class Template {
void generateInto(Directory dir, String flutterPackagePath) { void generateInto(Directory dir, String flutterPackagePath) {
String dirPath = path.normalize(dir.absolute.path); String dirPath = path.normalize(dir.absolute.path);
String projectName = _normalizeProjectName(path.basename(dirPath)); String projectName = _normalizeProjectName(path.basename(dirPath));
print('Creating ${path.basename(projectName)}...'); printStatus('Creating ${path.basename(projectName)}...');
dir.createSync(recursive: true); dir.createSync(recursive: true);
String relativeFlutterPackagePath = path.relative(flutterPackagePath, from: dirPath); String relativeFlutterPackagePath = path.relative(flutterPackagePath, from: dirPath);
...@@ -131,7 +131,7 @@ abstract class Template { ...@@ -131,7 +131,7 @@ abstract class Template {
File file = new File(path.join(dir.path, filePath)); File file = new File(path.join(dir.path, filePath));
file.parent.createSync(); file.parent.createSync();
file.writeAsStringSync(contents); file.writeAsStringSync(contents);
print(file.path); printStatus(file.path);
}); });
} }
......
...@@ -6,11 +6,9 @@ import 'dart:async'; ...@@ -6,11 +6,9 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:logging/logging.dart';
import '../android/adb.dart'; import '../android/adb.dart';
import '../android/device_android.dart'; import '../android/device_android.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../device.dart'; import '../device.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
import 'start.dart'; import 'start.dart';
...@@ -30,29 +28,32 @@ class DaemonCommand extends FlutterCommand { ...@@ -30,29 +28,32 @@ class DaemonCommand extends FlutterCommand {
bool get requiresProjectRoot => false; bool get requiresProjectRoot => false;
Future<int> runInProject() async { Future<int> runInProject() {
print('Starting device daemon...'); printStatus('Starting device daemon...');
NotifyingAppContext appContext = new NotifyingAppContext();
Stream<Map> commandStream = stdin return runZoned(() {
.transform(UTF8.decoder) Stream<Map<String, dynamic>> commandStream = stdin
.transform(const LineSplitter()) .transform(UTF8.decoder)
.where((String line) => line.startsWith('[{') && line.endsWith('}]')) .transform(const LineSplitter())
.map((String line) { .where((String line) => line.startsWith('[{') && line.endsWith('}]'))
line = line.substring(1, line.length - 1); .map((String line) {
return JSON.decode(line); line = line.substring(1, line.length - 1);
}); return JSON.decode(line);
});
Daemon daemon = new Daemon(commandStream, (Map command) { Daemon daemon = new Daemon(commandStream, (Map command) {
stdout.writeln('[${JSON.encode(command, toEncodable: _jsonEncodeObject)}]'); stdout.writeln('[${JSON.encode(command, toEncodable: _jsonEncodeObject)}]');
}, daemonCommand: this); }, daemonCommand: this, appContext: appContext);
return await daemon.onExit; return daemon.onExit;
}, zoneValues: {'context': appContext});
} }
dynamic _jsonEncodeObject(dynamic object) { dynamic _jsonEncodeObject(dynamic object) {
if (object is Device) if (object is Device)
return _deviceToMap(object); return _deviceToMap(object);
return object; return object;
} }
} }
...@@ -62,7 +63,10 @@ typedef void DispatchComand(Map<String, dynamic> command); ...@@ -62,7 +63,10 @@ typedef void DispatchComand(Map<String, dynamic> command);
typedef Future<dynamic> CommandHandler(dynamic args); typedef Future<dynamic> CommandHandler(dynamic args);
class Daemon { class Daemon {
Daemon(Stream<Map> commandStream, this.sendCommand, {this.daemonCommand}) { Daemon(Stream<Map> commandStream, this.sendCommand, {
this.daemonCommand,
this.appContext
}) {
// Set up domains. // Set up domains.
_registerDomain(new DaemonDomain(this)); _registerDomain(new DaemonDomain(this));
_registerDomain(new AppDomain(this)); _registerDomain(new AppDomain(this));
...@@ -77,6 +81,7 @@ class Daemon { ...@@ -77,6 +81,7 @@ class Daemon {
final DispatchComand sendCommand; final DispatchComand sendCommand;
final DaemonCommand daemonCommand; final DaemonCommand daemonCommand;
final NotifyingAppContext appContext;
final Completer<int> _onExitCompleter = new Completer<int>(); final Completer<int> _onExitCompleter = new Completer<int>();
final Map<String, Domain> _domainMap = <String, Domain>{}; final Map<String, Domain> _domainMap = <String, Domain>{};
...@@ -94,7 +99,7 @@ class Daemon { ...@@ -94,7 +99,7 @@ class Daemon {
dynamic id = request['id']; dynamic id = request['id'];
if (id == null) { if (id == null) {
logging.severe('no id for request: $request'); stderr.writeln('no id for request: $request');
return; return;
} }
...@@ -111,7 +116,8 @@ class Daemon { ...@@ -111,7 +116,8 @@ class Daemon {
_domainMap[prefix].handleCommand(name, id, request['params']); _domainMap[prefix].handleCommand(name, id, request['params']);
} catch (error, trace) { } catch (error, trace) {
_send({'id': id, 'error': _toJsonable(error)}); _send({'id': id, 'error': _toJsonable(error)});
logging.warning('error handling $request', error, trace); stderr.writeln('error handling $request: $error');
stderr.writeln(trace);
} }
} }
...@@ -152,7 +158,8 @@ abstract class Domain { ...@@ -152,7 +158,8 @@ abstract class Domain {
} }
}).catchError((error, trace) { }).catchError((error, trace) {
_send({'id': id, 'error': _toJsonable(error)}); _send({'id': id, 'error': _toJsonable(error)});
logging.warning("error handling '$name.$command'", error, trace); stderr.writeln("error handling '$name.$command': $error");
stderr.writeln(trace);
}); });
} }
...@@ -176,25 +183,23 @@ class DaemonDomain extends Domain { ...@@ -176,25 +183,23 @@ class DaemonDomain extends Domain {
registerHandler('version', version); registerHandler('version', version);
registerHandler('shutdown', shutdown); registerHandler('shutdown', shutdown);
_subscription = Logger.root.onRecord.listen((LogRecord record) { _subscription = daemon.appContext.onMessage.listen((LogMessage message) {
String message = record.error == null ? record.message : '${record.message}: ${record.error}'; if (message.stackTrace != null) {
if (record.stackTrace != null) {
sendEvent('daemon.logMessage', { sendEvent('daemon.logMessage', {
'level': record.level.name.toLowerCase(), 'level': message.level,
'message': message, 'message': message.message,
'stackTrace': record.stackTrace.toString() 'stackTrace': message.stackTrace.toString()
}); });
} else { } else {
sendEvent('daemon.logMessage', { sendEvent('daemon.logMessage', {
'level': record.level.name.toLowerCase(), 'level': message.level,
'message': message 'message': message.message
}); });
} }
}); });
} }
StreamSubscription<LogRecord> _subscription; StreamSubscription<LogMessage> _subscription;
Future<String> version(dynamic args) { Future<String> version(dynamic args) {
return new Future.value(protocolVersion); return new Future.value(protocolVersion);
...@@ -403,3 +408,31 @@ dynamic _toJsonable(dynamic obj) { ...@@ -403,3 +408,31 @@ dynamic _toJsonable(dynamic obj) {
return obj; return obj;
return '$obj'; return '$obj';
} }
class NotifyingAppContext implements AppContext {
StreamController<LogMessage> _messageController = new StreamController<LogMessage>.broadcast();
Stream<LogMessage> get onMessage => _messageController.stream;
bool verbose = false;
void printError(String message, [StackTrace stackTrace]) {
_messageController.add(new LogMessage('error', message, stackTrace));
}
void printStatus(String message) {
_messageController.add(new LogMessage('status', message));
}
void printTrace(String message) {
_messageController.add(new LogMessage('trace', message));
}
}
class LogMessage {
final String level;
final String message;
final StackTrace stackTrace;
LogMessage(this.level, this.message, [this.stackTrace]);
}
...@@ -8,7 +8,7 @@ import "dart:io"; ...@@ -8,7 +8,7 @@ import "dart:io";
import "package:path/path.dart" as path; import "package:path/path.dart" as path;
import "../artifacts.dart"; import "../artifacts.dart";
import "../base/logging.dart"; import "../base/context.dart";
import "../base/process.dart"; import "../base/process.dart";
import "../runner/flutter_command.dart"; import "../runner/flutter_command.dart";
import "../runner/flutter_command_runner.dart"; import "../runner/flutter_command_runner.dart";
...@@ -29,12 +29,12 @@ class IOSCommand extends FlutterCommand { ...@@ -29,12 +29,12 @@ class IOSCommand extends FlutterCommand {
} }
Future<List<int>> _fetchXcodeArchive() async { Future<List<int>> _fetchXcodeArchive() async {
print("Fetching the Xcode project archive from the cloud..."); printStatus("Fetching the Xcode project archive from the cloud...");
HttpClient client = new HttpClient(); HttpClient client = new HttpClient();
Uri xcodeProjectUri = _xcodeProjectUri(ArtifactStore.engineRevision); Uri xcodeProjectUri = _xcodeProjectUri(ArtifactStore.engineRevision);
logging.info("Downloading $xcodeProjectUri..."); printStatus("Downloading $xcodeProjectUri...");
HttpClientRequest request = await client.getUrl(xcodeProjectUri); HttpClientRequest request = await client.getUrl(xcodeProjectUri);
HttpClientResponse response = await request.close(); HttpClientResponse response = await request.close();
...@@ -49,7 +49,7 @@ class IOSCommand extends FlutterCommand { ...@@ -49,7 +49,7 @@ class IOSCommand extends FlutterCommand {
} }
Future<bool> _inflateXcodeArchive(String directory, List<int> archiveBytes) async { Future<bool> _inflateXcodeArchive(String directory, List<int> archiveBytes) async {
print("Unzipping Xcode project to local directory..."); printStatus("Unzipping Xcode project to local directory...");
// We cannot use ArchiveFile because this archive contains files that are exectuable // We cannot use ArchiveFile because this archive contains files that are exectuable
// and there is currently no provision to modify file permissions during // and there is currently no provision to modify file permissions during
...@@ -117,16 +117,16 @@ class IOSCommand extends FlutterCommand { ...@@ -117,16 +117,16 @@ class IOSCommand extends FlutterCommand {
List<int> archiveBytes = await _fetchXcodeArchive(); List<int> archiveBytes = await _fetchXcodeArchive();
if (archiveBytes.isEmpty) { if (archiveBytes.isEmpty) {
print("Error: No archive bytes received."); printError("Error: No archive bytes received.");
return 1; return 1;
} }
// Step 2: Inflate the archive into the user project directory // Step 2: Inflate the archive into the user project directory
bool result = await _inflateXcodeArchive(xcodeprojPath, archiveBytes); bool result = await _inflateXcodeArchive(xcodeprojPath, archiveBytes);
if (!result) { if (!result) {
print("Error: Could not init the Xcode project: the 'ios' directory already exists."); printError("Error: Could not init the Xcode project: the 'ios' directory already exists.");
print("To proceed, remove the 'ios' directory and try again."); printError("To proceed, remove the 'ios' directory and try again.");
print("Warning: You may have made manual changes to files in the 'ios' directory."); printError("Warning: You may have made manual changes to files in the 'ios' directory.");
return 1; return 1;
} }
...@@ -134,22 +134,22 @@ class IOSCommand extends FlutterCommand { ...@@ -134,22 +134,22 @@ class IOSCommand extends FlutterCommand {
_setupXcodeProjXcconfig(path.join(xcodeprojPath, "Local.xcconfig")); _setupXcodeProjXcconfig(path.join(xcodeprojPath, "Local.xcconfig"));
// Step 4: Tell the user the location of the generated project. // Step 4: Tell the user the location of the generated project.
print("An Xcode project has been placed in 'ios/'."); printStatus("An Xcode project has been placed in 'ios/'.");
print("You may edit it to modify iOS specific configuration."); printStatus("You may edit it to modify iOS specific configuration.");
return 0; return 0;
} }
@override @override
Future<int> runInProject() async { Future<int> runInProject() async {
if (!Platform.isMacOS) { if (!Platform.isMacOS) {
print("iOS specific commands may only be run on a Mac."); printStatus("iOS specific commands may only be run on a Mac.");
return 1; return 1;
} }
if (argResults['init']) if (argResults['init'])
return await _runInitCommand(); return await _runInitCommand();
print("No flags specified."); printError("No flags specified.");
return 1; return 1;
} }
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:async'; import 'dart:async';
import '../base/context.dart';
import '../device.dart'; import '../device.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -19,12 +20,13 @@ class ListCommand extends FlutterCommand { ...@@ -19,12 +20,13 @@ class ListCommand extends FlutterCommand {
List<Device> devices = await deviceManager.getDevices(); List<Device> devices = await deviceManager.getDevices();
if (devices.isEmpty) { if (devices.isEmpty) {
print('No connected devices.'); printStatus('No connected devices.');
} else { } else {
print('${devices.length} connected ${pluralize('device', devices.length)}:'); printStatus('${devices.length} connected ${pluralize('device', devices.length)}:');
print(''); printStatus('');
for (Device device in devices) { for (Device device in devices) {
print('${device.name} (${device.id})'); printStatus('${device.name} (${device.id})');
} }
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import '../base/logging.dart'; import '../base/context.dart';
import '../base/process.dart'; import '../base/process.dart';
import 'start.dart'; import 'start.dart';
...@@ -36,7 +36,7 @@ class ListenCommand extends StartCommandBase { ...@@ -36,7 +36,7 @@ class ListenCommand extends StartCommandBase {
int result = 0; int result = 0;
bool firstTime = true; bool firstTime = true;
do { do {
logging.info('Updating running Flutter apps...'); printStatus('Updating running Flutter apps...');
result = await startApp( result = await startApp(
devices, devices,
applicationPackages, applicationPackages,
...@@ -58,7 +58,7 @@ class ListenCommand extends StartCommandBase { ...@@ -58,7 +58,7 @@ class ListenCommand extends StartCommandBase {
try { try {
runCheckedSync(<String>['which', 'fswatch']); runCheckedSync(<String>['which', 'fswatch']);
} catch (e) { } catch (e) {
logging.severe('"listen" command is only useful if you have installed ' printError('"listen" command is only useful if you have installed '
'fswatch on Mac. Run "brew install fswatch" to install it with ' 'fswatch on Mac. Run "brew install fswatch" to install it with '
'homebrew.'); 'homebrew.');
return null; return null;
...@@ -68,7 +68,7 @@ class ListenCommand extends StartCommandBase { ...@@ -68,7 +68,7 @@ class ListenCommand extends StartCommandBase {
try { try {
runCheckedSync(<String>['which', 'inotifywait']); runCheckedSync(<String>['which', 'inotifywait']);
} catch (e) { } catch (e) {
logging.severe('"listen" command is only useful if you have installed ' printError('"listen" command is only useful if you have installed '
'inotifywait on Linux. Run "apt-get install inotify-tools" or ' 'inotifywait on Linux. Run "apt-get install inotify-tools" or '
'equivalent to install it.'); 'equivalent to install it.');
return null; return null;
...@@ -82,18 +82,18 @@ class ListenCommand extends StartCommandBase { ...@@ -82,18 +82,18 @@ class ListenCommand extends StartCommandBase {
'modify,close_write,move,create,delete', 'modify,close_write,move,create,delete',
]..addAll(directories); ]..addAll(directories);
} else { } else {
logging.severe('"listen" command is only available on Mac and Linux.'); printError('"listen" command is only available on Mac and Linux.');
} }
return null; return null;
} }
bool _watchDirectory(List<String> watchCommand) { bool _watchDirectory(List<String> watchCommand) {
logging.info('Attempting to listen to these directories: ${watchCommand.join(", ")}'); printStatus('Attempting to listen to these directories: ${watchCommand.join(", ")}');
assert(watchCommand != null); assert(watchCommand != null);
try { try {
runCheckedSync(watchCommand); runCheckedSync(watchCommand);
} catch (e) { } catch (e) {
logging.warning('Watching directories failed.', e); printError('Watching directories failed.', e);
return false; return false;
} }
return true; return true;
......
...@@ -5,11 +5,10 @@ ...@@ -5,11 +5,10 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../build_configuration.dart'; import '../build_configuration.dart';
import '../flx.dart' as flx; import '../flx.dart' as flx;
...@@ -119,12 +118,8 @@ class RunMojoCommand extends FlutterCommand { ...@@ -119,12 +118,8 @@ class RunMojoCommand extends FlutterCommand {
if (useDevtools) { if (useDevtools) {
final String buildFlag = argResults['mojo-debug'] ? '--debug' : '--release'; final String buildFlag = argResults['mojo-debug'] ? '--debug' : '--release';
args.add(buildFlag); args.add(buildFlag);
if (logging.level <= Level.INFO) { if (context.verbose)
args.add('--verbose'); args.add('--verbose');
if (logging.level <= Level.FINE) {
args.add('--verbose');
}
}
} }
if (argResults['checked']) { if (argResults['checked']) {
...@@ -132,19 +127,19 @@ class RunMojoCommand extends FlutterCommand { ...@@ -132,19 +127,19 @@ class RunMojoCommand extends FlutterCommand {
} }
args.addAll(argResults.rest); args.addAll(argResults.rest);
print(args); printStatus('$args');
return args; return args;
} }
@override @override
Future<int> runInProject() async { Future<int> runInProject() async {
if ((argResults['mojo-path'] == null && argResults['devtools-path'] == null) || (argResults['mojo-path'] != null && argResults['devtools-path'] != null)) { if ((argResults['mojo-path'] == null && argResults['devtools-path'] == null) || (argResults['mojo-path'] != null && argResults['devtools-path'] != null)) {
logging.severe('Must specify either --mojo-path or --devtools-path.'); printError('Must specify either --mojo-path or --devtools-path.');
return 1; return 1;
} }
if (argResults['mojo-debug'] && argResults['mojo-release']) { if (argResults['mojo-debug'] && argResults['mojo-release']) {
logging.severe('Cannot specify both --mojo-debug and --mojo-release'); printError('Cannot specify both --mojo-debug and --mojo-release');
return 1; return 1;
} }
......
...@@ -8,7 +8,7 @@ import 'dart:io'; ...@@ -8,7 +8,7 @@ import 'dart:io';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import '../application_package.dart'; import '../application_package.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../device.dart'; import '../device.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
import '../toolchain.dart'; import '../toolchain.dart';
...@@ -64,7 +64,7 @@ class StartCommand extends StartCommandBase { ...@@ -64,7 +64,7 @@ class StartCommand extends StartCommandBase {
@override @override
Future<int> runInProject() async { Future<int> runInProject() async {
logging.fine('Downloading toolchain.'); printTrace('Downloading toolchain.');
await Future.wait([ await Future.wait([
downloadToolchain(), downloadToolchain(),
...@@ -89,7 +89,7 @@ class StartCommand extends StartCommandBase { ...@@ -89,7 +89,7 @@ class StartCommand extends StartCommandBase {
clearLogs: clearLogs clearLogs: clearLogs
); );
logging.fine('Finished start command.'); printTrace('Finished start command.');
return result; return result;
} }
} }
...@@ -113,17 +113,17 @@ Future<int> startApp( ...@@ -113,17 +113,17 @@ Future<int> startApp(
String message = 'Tried to run $mainPath, but that file does not exist.'; String message = 'Tried to run $mainPath, but that file does not exist.';
if (target == null) if (target == null)
message += '\nConsider using the -t option to specify the Dart file to start.'; message += '\nConsider using the -t option to specify the Dart file to start.';
logging.severe(message); printError(message);
return 1; return 1;
} }
if (stop) { if (stop) {
logging.fine('Running stop command.'); printTrace('Running stop command.');
stopAll(devices, applicationPackages); stopAll(devices, applicationPackages);
} }
if (install) { if (install) {
logging.fine('Running install command.'); printTrace('Running install command.');
installApp(devices, applicationPackages); installApp(devices, applicationPackages);
} }
...@@ -134,7 +134,7 @@ Future<int> startApp( ...@@ -134,7 +134,7 @@ Future<int> startApp(
if (package == null || !device.isConnected()) if (package == null || !device.isConnected())
continue; continue;
logging.fine('Running build command for $device.'); printTrace('Running build command for $device.');
Map<String, dynamic> platformArgs = <String, dynamic>{}; Map<String, dynamic> platformArgs = <String, dynamic>{};
...@@ -155,7 +155,7 @@ Future<int> startApp( ...@@ -155,7 +155,7 @@ Future<int> startApp(
); );
if (!result) { if (!result) {
logging.severe('Could not start \'${package.name}\' on \'${device.id}\''); printError('Could not start \'${package.name}\' on \'${device.id}\'');
} else { } else {
startedSomething = true; startedSomething = true;
} }
...@@ -163,9 +163,9 @@ Future<int> startApp( ...@@ -163,9 +163,9 @@ Future<int> startApp(
if (!startedSomething) { if (!startedSomething) {
if (!devices.all.any((device) => device.isConnected())) { if (!devices.all.any((device) => device.isConnected())) {
logging.severe('Unable to run application - no connected devices.'); printError('Unable to run application - no connected devices.');
} else { } else {
logging.severe('Unable to run application.'); printError('Unable to run application.');
} }
} }
......
...@@ -9,7 +9,7 @@ import 'package:path/path.dart' as path; ...@@ -9,7 +9,7 @@ import 'package:path/path.dart' as path;
import 'package:test/src/executable.dart' as executable; import 'package:test/src/executable.dart' as executable;
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../build_configuration.dart'; import '../build_configuration.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
import '../test/loader.dart' as loader; import '../test/loader.dart' as loader;
...@@ -105,7 +105,7 @@ class TestCommand extends FlutterCommand { ...@@ -105,7 +105,7 @@ class TestCommand extends FlutterCommand {
foundOne = true; foundOne = true;
loader.shellPath = path.absolute(await _getShellPath(config)); loader.shellPath = path.absolute(await _getShellPath(config));
if (!FileSystemEntity.isFileSync(loader.shellPath)) { if (!FileSystemEntity.isFileSync(loader.shellPath)) {
logging.severe('Cannot find Flutter shell at ${loader.shellPath}'); printError('Cannot find Flutter shell at ${loader.shellPath}');
return 1; return 1;
} }
await _runTests(testArgs, testDir); await _runTests(testArgs, testDir);
...@@ -113,7 +113,7 @@ class TestCommand extends FlutterCommand { ...@@ -113,7 +113,7 @@ class TestCommand extends FlutterCommand {
return exitCode; return exitCode;
} }
if (!foundOne) { if (!foundOne) {
stderr.writeln('At least one of --debug or --release must be set, to specify the local build products to test.'); printError('At least one of --debug or --release must be set, to specify the local build products to test.');
return 1; return 1;
} }
......
...@@ -6,7 +6,7 @@ import 'dart:async'; ...@@ -6,7 +6,7 @@ import 'dart:async';
import '../android/device_android.dart'; import '../android/device_android.dart';
import '../application_package.dart'; import '../application_package.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
class TraceCommand extends FlutterCommand { class TraceCommand extends FlutterCommand {
...@@ -30,7 +30,7 @@ class TraceCommand extends FlutterCommand { ...@@ -30,7 +30,7 @@ class TraceCommand extends FlutterCommand {
await downloadApplicationPackagesAndConnectToDevices(); await downloadApplicationPackagesAndConnectToDevices();
if (!devices.android.isConnected()) { if (!devices.android.isConnected()) {
logging.warning('No device connected, so no trace was completed.'); printError('No device connected, so no trace was completed.');
return 1; return 1;
} }
...@@ -56,9 +56,9 @@ class TraceCommand extends FlutterCommand { ...@@ -56,9 +56,9 @@ class TraceCommand extends FlutterCommand {
Future _stopTracing(AndroidDevice android, AndroidApk androidApp) async { Future _stopTracing(AndroidDevice android, AndroidApk androidApp) async {
String tracePath = await android.stopTracing(androidApp, outPath: argResults['out']); String tracePath = await android.stopTracing(androidApp, outPath: argResults['out']);
if (tracePath == null) { if (tracePath == null) {
logging.warning('No trace file saved.'); printError('No trace file saved.');
} else { } else {
print('Trace file saved to $tracePath'); printStatus('Trace file saved to $tracePath');
} }
} }
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:async'; import 'dart:async';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/context.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -19,7 +20,7 @@ class UpgradeCommand extends FlutterCommand { ...@@ -19,7 +20,7 @@ class UpgradeCommand extends FlutterCommand {
'git', 'rev-parse', '@{u}' 'git', 'rev-parse', '@{u}'
], workingDirectory: ArtifactStore.flutterRoot); ], workingDirectory: ArtifactStore.flutterRoot);
} catch (e) { } catch (e) {
print('Unable to upgrade Flutter. No upstream repository configured for Flutter.'); printError('Unable to upgrade Flutter. No upstream repository configured for Flutter.');
return 1; return 1;
} }
......
...@@ -6,7 +6,7 @@ import 'dart:async'; ...@@ -6,7 +6,7 @@ import 'dart:async';
import 'android/device_android.dart'; import 'android/device_android.dart';
import 'application_package.dart'; import 'application_package.dart';
import 'base/logging.dart'; import 'base/context.dart';
import 'build_configuration.dart'; import 'build_configuration.dart';
import 'ios/device_ios.dart'; import 'ios/device_ios.dart';
import 'toolchain.dart'; import 'toolchain.dart';
...@@ -132,7 +132,7 @@ class DeviceStore { ...@@ -132,7 +132,7 @@ class DeviceStore {
(Device dev) => (dev.id == config.deviceId), (Device dev) => (dev.id == config.deviceId),
orElse: () => null); orElse: () => null);
if (device == null) { if (device == null) {
logging.severe('Warning: Device ID ${config.deviceId} not found'); printError('Warning: Device ID ${config.deviceId} not found');
} }
} else if (devices.length == 1) { } else if (devices.length == 1) {
// Step 2: If no identifier is specified and there is only one connected // Step 2: If no identifier is specified and there is only one connected
...@@ -140,8 +140,8 @@ class DeviceStore { ...@@ -140,8 +140,8 @@ class DeviceStore {
device = devices[0]; device = devices[0];
} else if (devices.length > 1) { } else if (devices.length > 1) {
// Step 3: D: // Step 3: D:
logging.fine('Multiple devices are connected, but no device ID was specified.'); printTrace('Multiple devices are connected, but no device ID was specified.');
logging.fine('Attempting to launch on all connected devices.'); printTrace('Attempting to launch on all connected devices.');
} }
return device; return device;
......
...@@ -12,8 +12,8 @@ import 'package:flx/signing.dart'; ...@@ -12,8 +12,8 @@ import 'package:flx/signing.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart'; import 'package:yaml/yaml.dart';
import 'base/context.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/logging.dart';
import 'toolchain.dart'; import 'toolchain.dart';
const String defaultMainPath = 'lib/main.dart'; const String defaultMainPath = 'lib/main.dart';
...@@ -158,7 +158,7 @@ Future<int> build( ...@@ -158,7 +158,7 @@ Future<int> build(
String privateKeyPath: defaultPrivateKeyPath, String privateKeyPath: defaultPrivateKeyPath,
bool precompiledSnapshot: false bool precompiledSnapshot: false
}) async { }) async {
logging.fine('Building $outputPath'); printTrace('Building $outputPath');
Map manifestDescriptor = _loadManifest(manifestPath); Map manifestDescriptor = _loadManifest(manifestPath);
...@@ -174,7 +174,7 @@ Future<int> build( ...@@ -174,7 +174,7 @@ Future<int> build(
// content equivalents // content equivalents
int result = await toolchain.compiler.compile(mainPath: mainPath, snapshotPath: snapshotPath); int result = await toolchain.compiler.compile(mainPath: mainPath, snapshotPath: snapshotPath);
if (result != 0) { if (result != 0) {
logging.severe('Failed to run the Flutter compiler. Exit code: $result'); printError('Failed to run the Flutter compiler. Exit code: $result');
return result; return result;
} }
...@@ -184,7 +184,7 @@ Future<int> build( ...@@ -184,7 +184,7 @@ Future<int> build(
for (_Asset asset in assets) { for (_Asset asset in assets) {
ArchiveFile file = _createFile(asset.key, asset.base); ArchiveFile file = _createFile(asset.key, asset.base);
if (file == null) { if (file == null) {
stderr.writeln('Cannot find asset "${asset.key}" in directory "${path.absolute(asset.base)}".'); printError('Cannot find asset "${asset.key}" in directory "${path.absolute(asset.base)}".');
return 1; return 1;
} }
archive.addFile(file); archive.addFile(file);
......
...@@ -8,7 +8,7 @@ import 'dart:io'; ...@@ -8,7 +8,7 @@ import 'dart:io';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import '../application_package.dart'; import '../application_package.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../build_configuration.dart'; import '../build_configuration.dart';
import '../device.dart'; import '../device.dart';
...@@ -129,9 +129,9 @@ class IOSDevice extends Device { ...@@ -129,9 +129,9 @@ class IOSDevice extends Device {
command = runCheckedSync(['which', command]).trim(); command = runCheckedSync(['which', command]).trim();
} catch (e) { } catch (e) {
if (Platform.isMacOS) { if (Platform.isMacOS) {
logging.severe('$command not found. $macInstructions'); printError('$command not found. $macInstructions');
} else { } else {
logging.severe('Cannot control iOS devices or simulators. $command is not available on your platform.'); printError('Cannot control iOS devices or simulators. $command is not available on your platform.');
} }
} }
return command; return command;
...@@ -187,13 +187,13 @@ class IOSDevice extends Device { ...@@ -187,13 +187,13 @@ class IOSDevice extends Device {
Map<String, dynamic> platformArgs Map<String, dynamic> platformArgs
}) async { }) async {
// TODO: Use checked, mainPath, route // TODO: Use checked, mainPath, route
logging.fine('Building ${app.name} for $id'); printTrace('Building ${app.name} for $id');
// Step 1: Install the precompiled application if necessary // Step 1: Install the precompiled application if necessary
bool buildResult = await _buildIOSXcodeProject(app, true); bool buildResult = await _buildIOSXcodeProject(app, true);
if (!buildResult) { if (!buildResult) {
logging.severe('Could not build the precompiled application for the device'); printError('Could not build the precompiled application for the device');
return false; return false;
} }
...@@ -202,7 +202,7 @@ class IOSDevice extends Device { ...@@ -202,7 +202,7 @@ class IOSDevice extends Device {
bool bundleExists = bundle.existsSync(); bool bundleExists = bundle.existsSync();
if (!bundleExists) { if (!bundleExists) {
logging.severe('Could not find the built application bundle at ${bundle.path}'); printError('Could not find the built application bundle at ${bundle.path}');
return false; return false;
} }
...@@ -217,11 +217,11 @@ class IOSDevice extends Device { ...@@ -217,11 +217,11 @@ class IOSDevice extends Device {
]); ]);
if (installationResult != 0) { if (installationResult != 0) {
logging.severe('Could not install ${bundle.path} on $id'); printError('Could not install ${bundle.path} on $id');
return false; return false;
} }
logging.fine('Installation successful'); printTrace('Installation successful');
return true; return true;
} }
...@@ -311,13 +311,13 @@ class IOSSimulator extends Device { ...@@ -311,13 +311,13 @@ class IOSSimulator extends Device {
// More than one simulator is listed as booted, which is not allowed but // More than one simulator is listed as booted, which is not allowed but
// sometimes happens erroneously. Kill them all because we don't know // sometimes happens erroneously. Kill them all because we don't know
// which one is actually running. // which one is actually running.
logging.warning('Multiple running simulators were detected, ' printError('Multiple running simulators were detected, '
'which is not supposed to happen.'); 'which is not supposed to happen.');
for (Match match in matches) { for (Match match in matches) {
if (match.groupCount > 0) { if (match.groupCount > 0) {
// TODO: We're killing simulator devices inside an accessor method; // TODO: We're killing simulator devices inside an accessor method;
// we probably shouldn't be changing state here. // we probably shouldn't be changing state here.
logging.warning('Killing simulator ${match.group(1)}'); printError('Killing simulator ${match.group(1)}');
runSync([xcrunPath, 'simctl', 'shutdown', match.group(2)]); runSync([xcrunPath, 'simctl', 'shutdown', match.group(2)]);
} }
} }
...@@ -328,7 +328,7 @@ class IOSSimulator extends Device { ...@@ -328,7 +328,7 @@ class IOSSimulator extends Device {
if (match != null && match.groupCount > 0) { if (match != null && match.groupCount > 0) {
return new _IOSSimulatorInfo(match.group(2), match.group(1)); return new _IOSSimulatorInfo(match.group(2), match.group(1));
} else { } else {
logging.info('No running simulators found'); printTrace('No running simulators found');
return null; return null;
} }
} }
...@@ -368,11 +368,11 @@ class IOSSimulator extends Device { ...@@ -368,11 +368,11 @@ class IOSSimulator extends Device {
runDetached([iOSSimPath]); runDetached([iOSSimPath]);
Future<bool> checkConnection([int attempts = 20]) async { Future<bool> checkConnection([int attempts = 20]) async {
if (attempts == 0) { if (attempts == 0) {
logging.info('Timed out waiting for iOS Simulator $id to boot.'); printStatus('Timed out waiting for iOS Simulator $id to boot.');
return false; return false;
} }
if (!isConnected()) { if (!isConnected()) {
logging.info('Waiting for iOS Simulator $id to boot...'); printStatus('Waiting for iOS Simulator $id to boot...');
return await new Future.delayed(new Duration(milliseconds: 500), return await new Future.delayed(new Duration(milliseconds: 500),
() => checkConnection(attempts - 1)); () => checkConnection(attempts - 1));
} }
...@@ -383,7 +383,7 @@ class IOSSimulator extends Device { ...@@ -383,7 +383,7 @@ class IOSSimulator extends Device {
try { try {
runCheckedSync([xcrunPath, 'simctl', 'boot', id]); runCheckedSync([xcrunPath, 'simctl', 'boot', id]);
} catch (e) { } catch (e) {
logging.warning('Unable to boot iOS Simulator $id: ', e); printError('Unable to boot iOS Simulator $id: ', e);
return false; return false;
} }
} }
...@@ -441,12 +441,12 @@ class IOSSimulator extends Device { ...@@ -441,12 +441,12 @@ class IOSSimulator extends Device {
Map<String, dynamic> platformArgs Map<String, dynamic> platformArgs
}) async { }) async {
// TODO: Use checked, mainPath, route // TODO: Use checked, mainPath, route
logging.fine('Building ${app.name} for $id'); printTrace('Building ${app.name} for $id');
// Step 1: Build the Xcode project // Step 1: Build the Xcode project
bool buildResult = await _buildIOSXcodeProject(app, false); bool buildResult = await _buildIOSXcodeProject(app, false);
if (!buildResult) { if (!buildResult) {
logging.severe('Could not build the application for the simulator'); printError('Could not build the application for the simulator');
return false; return false;
} }
...@@ -454,7 +454,7 @@ class IOSSimulator extends Device { ...@@ -454,7 +454,7 @@ class IOSSimulator extends Device {
Directory bundle = new Directory(path.join(app.localPath, 'build', 'Release-iphonesimulator', 'Runner.app')); Directory bundle = new Directory(path.join(app.localPath, 'build', 'Release-iphonesimulator', 'Runner.app'));
bool bundleExists = await bundle.exists(); bool bundleExists = await bundle.exists();
if (!bundleExists) { if (!bundleExists) {
logging.severe('Could not find the built application bundle at ${bundle.path}'); printError('Could not find the built application bundle at ${bundle.path}');
return false; return false;
} }
...@@ -468,7 +468,7 @@ class IOSSimulator extends Device { ...@@ -468,7 +468,7 @@ class IOSSimulator extends Device {
]); ]);
if (installResult != 0) { if (installResult != 0) {
logging.severe('Could not install the application bundle on the simulator'); printError('Could not install the application bundle on the simulator');
return false; return false;
} }
...@@ -482,11 +482,11 @@ class IOSSimulator extends Device { ...@@ -482,11 +482,11 @@ class IOSSimulator extends Device {
]); ]);
if (launchResult != 0) { if (launchResult != 0) {
logging.severe('Could not launch the freshly installed application on the simulator'); printError('Could not launch the freshly installed application on the simulator');
return false; return false;
} }
logging.fine('Successfully started ${app.name} on $id'); printTrace('Successfully started ${app.name} on $id');
return true; return true;
} }
...@@ -545,11 +545,11 @@ bool _checkXcodeVersion() { ...@@ -545,11 +545,11 @@ bool _checkXcodeVersion() {
String version = runCheckedSync(['xcodebuild', '-version']); String version = runCheckedSync(['xcodebuild', '-version']);
Match match = _xcodeVersionRegExp.firstMatch(version); Match match = _xcodeVersionRegExp.firstMatch(version);
if (int.parse(match[1]) < 7) { if (int.parse(match[1]) < 7) {
logging.severe('Found "${match[0]}". $_xcodeRequirement'); printError('Found "${match[0]}". $_xcodeRequirement');
return false; return false;
} }
} catch (e) { } catch (e) {
logging.severe('Cannot find "xcodebuid". $_xcodeRequirement'); printError('Cannot find "xcodebuid". $_xcodeRequirement');
return false; return false;
} }
return true; return true;
...@@ -557,7 +557,7 @@ bool _checkXcodeVersion() { ...@@ -557,7 +557,7 @@ bool _checkXcodeVersion() {
Future<bool> _buildIOSXcodeProject(ApplicationPackage app, bool isDevice) async { Future<bool> _buildIOSXcodeProject(ApplicationPackage app, bool isDevice) async {
if (!FileSystemEntity.isDirectorySync(app.localPath)) { if (!FileSystemEntity.isDirectorySync(app.localPath)) {
logging.severe('Path "${path.absolute(app.localPath)}" does not exist.\nDid you run `flutter ios --init`?'); printError('Path "${path.absolute(app.localPath)}" does not exist.\nDid you run `flutter ios --init`?');
return false; return false;
} }
......
...@@ -8,6 +8,7 @@ import 'dart:io'; ...@@ -8,6 +8,7 @@ import 'dart:io';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import '../application_package.dart'; import '../application_package.dart';
import '../base/context.dart';
import '../build_configuration.dart'; import '../build_configuration.dart';
import '../device.dart'; import '../device.dart';
import '../toolchain.dart'; import '../toolchain.dart';
...@@ -55,7 +56,7 @@ abstract class FlutterCommand extends Command { ...@@ -55,7 +56,7 @@ abstract class FlutterCommand extends Command {
bool validateProjectRoot() { bool validateProjectRoot() {
if (!FileSystemEntity.isFileSync('pubspec.yaml')) { if (!FileSystemEntity.isFileSync('pubspec.yaml')) {
stderr.writeln(projectRootValidationErrorMessage); printError(projectRootValidationErrorMessage);
return false; return false;
} }
return true; return true;
......
...@@ -7,11 +7,10 @@ import 'dart:io'; ...@@ -7,11 +7,10 @@ import 'dart:io';
import 'package:args/args.dart'; import 'package:args/args.dart';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/logging.dart'; import '../base/context.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../build_configuration.dart'; import '../build_configuration.dart';
import 'version.dart'; import 'version.dart';
...@@ -29,10 +28,6 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -29,10 +28,6 @@ class FlutterCommandRunner extends CommandRunner {
abbr: 'v', abbr: 'v',
negatable: false, negatable: false,
help: 'Noisy logging, including all shell commands executed.'); 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.addFlag('version', argParser.addFlag('version',
negatable: false, negatable: false,
help: 'Reports the version of this tool.'); help: 'Reports the version of this tool.');
...@@ -141,10 +136,7 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -141,10 +136,7 @@ class FlutterCommandRunner extends CommandRunner {
Future<int> runCommand(ArgResults globalResults) { Future<int> runCommand(ArgResults globalResults) {
if (globalResults['verbose']) if (globalResults['verbose'])
Logger.root.level = Level.INFO; context.verbose = true;
if (globalResults['very-verbose'])
Logger.root.level = Level.FINE;
_globalResults = globalResults; _globalResults = globalResults;
ArtifactStore.flutterRoot = path.normalize(path.absolute(globalResults['flutter-root'])); ArtifactStore.flutterRoot = path.normalize(path.absolute(globalResults['flutter-root']));
...@@ -152,7 +144,7 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -152,7 +144,7 @@ class FlutterCommandRunner extends CommandRunner {
ArtifactStore.packageRoot = path.normalize(path.absolute(globalResults['package-root'])); ArtifactStore.packageRoot = path.normalize(path.absolute(globalResults['package-root']));
if (globalResults['version']) { if (globalResults['version']) {
print(getVersion(ArtifactStore.flutterRoot)); printStatus(getVersion(ArtifactStore.flutterRoot));
return new Future<int>.value(0); return new Future<int>.value(0);
} }
...@@ -186,7 +178,7 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -186,7 +178,7 @@ class FlutterCommandRunner extends CommandRunner {
engineSourcePath = _tryEnginePath(path.join(ArtifactStore.flutterRoot, '../engine/src')); engineSourcePath = _tryEnginePath(path.join(ArtifactStore.flutterRoot, '../engine/src'));
if (engineSourcePath == null) { if (engineSourcePath == null) {
stderr.writeln('Unable to detect local Flutter engine build directory.\n' printError('Unable to detect local Flutter engine build directory.\n'
'Either specify a dependency_override for the $kFlutterEnginePackageName package in your pubspec.yaml and\n' 'Either specify a dependency_override for the $kFlutterEnginePackageName package in your pubspec.yaml and\n'
'ensure --package-root is set if necessary, or set the \$$kFlutterEngineEnvironmentVariableName environment variable, or\n' 'ensure --package-root is set if necessary, or set the \$$kFlutterEngineEnvironmentVariableName environment variable, or\n'
'use --engine-src-path to specify the path to the root of your flutter/engine repository.'); 'use --engine-src-path to specify the path to the root of your flutter/engine repository.');
...@@ -195,7 +187,7 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -195,7 +187,7 @@ class FlutterCommandRunner extends CommandRunner {
} }
if (engineSourcePath != null && _tryEnginePath(engineSourcePath) == null) { if (engineSourcePath != null && _tryEnginePath(engineSourcePath) == null) {
stderr.writeln('Unable to detect a Flutter engine build directory in $engineSourcePath.\n' printError('Unable to detect a Flutter engine build directory in $engineSourcePath.\n'
'Please ensure that $engineSourcePath is a Flutter engine \'src\' directory and that\n' 'Please ensure that $engineSourcePath is a Flutter engine \'src\' directory and that\n'
'you have compiled the engine in that directory, which should produce an \'out\' directory'); 'you have compiled the engine in that directory, which should produce an \'out\' directory');
throw new ProcessExit(2); throw new ProcessExit(2);
...@@ -240,7 +232,7 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -240,7 +232,7 @@ class FlutterCommandRunner extends CommandRunner {
} }
} else { } else {
if (!FileSystemEntity.isDirectorySync(enginePath)) if (!FileSystemEntity.isDirectorySync(enginePath))
logging.warning('$enginePath is not a valid directory'); printError('$enginePath is not a valid directory');
if (!isDebug && !isRelease) if (!isDebug && !isRelease)
isDebug = true; isDebug = true;
......
...@@ -7,8 +7,6 @@ import 'dart:convert'; ...@@ -7,8 +7,6 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:flutter_tools/src/test/json_socket.dart';
import 'package:flutter_tools/src/test/remote_test.dart';
import 'package:stack_trace/stack_trace.dart'; import 'package:stack_trace/stack_trace.dart';
import 'package:test/src/backend/group.dart'; import 'package:test/src/backend/group.dart';
import 'package:test/src/backend/metadata.dart'; import 'package:test/src/backend/metadata.dart';
...@@ -21,6 +19,9 @@ import 'package:test/src/runner/vm/environment.dart'; ...@@ -21,6 +19,9 @@ import 'package:test/src/runner/vm/environment.dart';
import 'package:test/src/util/io.dart'; import 'package:test/src/util/io.dart';
import 'package:test/src/util/remote_exception.dart'; import 'package:test/src/util/remote_exception.dart';
import 'json_socket.dart';
import 'remote_test.dart';
void installHook() { void installHook() {
hack.loadVMFileHook = _loadVMFile; hack.loadVMFileHook = _loadVMFile;
} }
......
...@@ -14,8 +14,8 @@ import 'package:test/src/backend/live_test.dart'; ...@@ -14,8 +14,8 @@ import 'package:test/src/backend/live_test.dart';
import 'package:test/src/backend/metadata.dart'; import 'package:test/src/backend/metadata.dart';
import 'package:test/src/backend/operating_system.dart'; import 'package:test/src/backend/operating_system.dart';
import 'package:test/src/backend/suite.dart'; import 'package:test/src/backend/suite.dart';
import 'package:test/src/backend/test_platform.dart';
import 'package:test/src/backend/test.dart'; import 'package:test/src/backend/test.dart';
import 'package:test/src/backend/test_platform.dart';
import 'package:test/src/util/remote_exception.dart'; import 'package:test/src/util/remote_exception.dart';
final OperatingSystem currentOS = (() { final OperatingSystem currentOS = (() {
......
...@@ -5,18 +5,18 @@ ...@@ -5,18 +5,18 @@
import 'dart:async'; import 'dart:async';
import 'package:stack_trace/stack_trace.dart'; import 'package:stack_trace/stack_trace.dart';
import 'package:test/src/backend/group.dart';
import 'package:test/src/backend/live_test.dart'; import 'package:test/src/backend/live_test.dart';
import 'package:test/src/backend/live_test_controller.dart'; import 'package:test/src/backend/live_test_controller.dart';
import 'package:test/src/backend/metadata.dart'; import 'package:test/src/backend/metadata.dart';
import 'package:test/src/backend/operating_system.dart'; import 'package:test/src/backend/operating_system.dart';
import 'package:test/src/backend/group.dart';
import 'package:test/src/backend/state.dart'; import 'package:test/src/backend/state.dart';
import 'package:test/src/backend/suite.dart'; import 'package:test/src/backend/suite.dart';
import 'package:test/src/backend/test.dart'; import 'package:test/src/backend/test.dart';
import 'package:test/src/backend/test_platform.dart'; import 'package:test/src/backend/test_platform.dart';
import 'package:test/src/util/remote_exception.dart'; import 'package:test/src/util/remote_exception.dart';
import 'package:flutter_tools/src/test/json_socket.dart'; import 'json_socket.dart';
class RemoteTest extends Test { class RemoteTest extends Test {
RemoteTest(this.name, this.metadata, this._socket, this._index); RemoteTest(this.name, this.metadata, this._socket, this._index);
......
// Copyright 2016 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:flutter_tools/src/base/context.dart';
import 'package:test/test.dart';
main() => defineTests();
defineTests() {
group('DeviceManager', () {
test('error', () async {
MockContext mockContext = new MockContext();
runZoned(() {
printError('foo bar');
}, zoneValues: {'context': mockContext});
expect(mockContext.errorText, 'foo bar\n');
expect(mockContext.statusText, '');
expect(mockContext.traceText, '');
});
test('status', () async {
MockContext mockContext = new MockContext();
runZoned(() {
printStatus('foo bar');
}, zoneValues: {'context': mockContext});
expect(mockContext.errorText, '');
expect(mockContext.statusText, 'foo bar\n');
expect(mockContext.traceText, '');
});
test('trace', () async {
MockContext mockContext = new MockContext();
runZoned(() {
printTrace('foo bar');
}, zoneValues: {'context': mockContext});
expect(mockContext.errorText, '');
expect(mockContext.statusText, '');
expect(mockContext.traceText, 'foo bar\n');
});
});
}
class MockContext implements AppContext {
bool verbose = false;
StringBuffer _error = new StringBuffer();
StringBuffer _status = new StringBuffer();
StringBuffer _trace = new StringBuffer();
String get errorText => _error.toString();
String get statusText => _status.toString();
String get traceText => _trace.toString();
void printError(String message, [StackTrace stackTrace]) => _error.writeln(message);
void printStatus(String message) => _status.writeln(message);
void printTrace(String message) => _trace.writeln(message);
}
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
import 'dart:io'; import 'dart:io';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:path/path.dart' as path;
import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/commands/create.dart';
import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/commands/create.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart'; import 'package:test/test.dart';
main() => defineTests(); main() => defineTests();
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_tools/src/base/logging.dart'; import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/commands/daemon.dart'; import 'package:flutter_tools/src/commands/daemon.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
...@@ -16,6 +16,11 @@ main() => defineTests(); ...@@ -16,6 +16,11 @@ main() => defineTests();
defineTests() { defineTests() {
group('daemon', () { group('daemon', () {
Daemon daemon; Daemon daemon;
NotifyingAppContext appContext;
setUp(() {
appContext = new NotifyingAppContext();
});
tearDown(() { tearDown(() {
if (daemon != null) if (daemon != null)
...@@ -23,11 +28,12 @@ defineTests() { ...@@ -23,11 +28,12 @@ defineTests() {
}); });
test('daemon.version', () async { test('daemon.version', () async {
StreamController<Map> commands = new StreamController(); StreamController<Map<String, dynamic>> commands = new StreamController();
StreamController<Map> responses = new StreamController(); StreamController<Map<String, dynamic>> responses = new StreamController();
daemon = new Daemon( daemon = new Daemon(
commands.stream, commands.stream,
(Map<String, dynamic> result) => responses.add(result) (Map<String, dynamic> result) => responses.add(result),
appContext: appContext
); );
commands.add({'id': 0, 'method': 'daemon.version'}); commands.add({'id': 0, 'method': 'daemon.version'});
Map response = await responses.stream.where(_notEvent).first; Map response = await responses.stream.where(_notEvent).first;
...@@ -36,30 +42,34 @@ defineTests() { ...@@ -36,30 +42,34 @@ defineTests() {
expect(response['result'] is String, true); expect(response['result'] is String, true);
}); });
test('daemon.logMessage', () async { test('daemon.logMessage', () {
StreamController<Map> commands = new StreamController(); return runZoned(() async {
StreamController<Map> responses = new StreamController(); StreamController<Map<String, dynamic>> commands = new StreamController();
daemon = new Daemon( StreamController<Map<String, dynamic>> responses = new StreamController();
commands.stream, daemon = new Daemon(
(Map<String, dynamic> result) => responses.add(result) commands.stream,
); (Map<String, dynamic> result) => responses.add(result),
logging.warning('daemon.logMessage test'); appContext: appContext
Map response = await responses.stream.where((Map<String, dynamic> map) { );
return map['event'] == 'daemon.logMessage' && map['params']['level'] == 'warning'; printError('daemon.logMessage test');
}).first; Map<String, dynamic> response = await responses.stream.where((Map<String, dynamic> map) {
expect(response['id'], isNull); return map['event'] == 'daemon.logMessage' && map['params']['level'] == 'error';
expect(response['event'], 'daemon.logMessage'); }).first;
Map<String, String> logMessage = response['params']; expect(response['id'], isNull);
expect(logMessage['level'], 'warning'); expect(response['event'], 'daemon.logMessage');
expect(logMessage['message'], 'daemon.logMessage test'); Map<String, String> logMessage = response['params'];
expect(logMessage['level'], 'error');
expect(logMessage['message'], 'daemon.logMessage test');
}, zoneValues: {'context': appContext});
}); });
test('daemon.shutdown', () async { test('daemon.shutdown', () async {
StreamController<Map> commands = new StreamController(); StreamController<Map<String, dynamic>> commands = new StreamController();
StreamController<Map> responses = new StreamController(); StreamController<Map<String, dynamic>> responses = new StreamController();
daemon = new Daemon( daemon = new Daemon(
commands.stream, commands.stream,
(Map<String, dynamic> result) => responses.add(result) (Map<String, dynamic> result) => responses.add(result),
appContext: appContext
); );
commands.add({'id': 0, 'method': 'daemon.shutdown'}); commands.add({'id': 0, 'method': 'daemon.shutdown'});
return daemon.onExit.then((int code) { return daemon.onExit.then((int code) {
...@@ -71,12 +81,13 @@ defineTests() { ...@@ -71,12 +81,13 @@ defineTests() {
DaemonCommand command = new DaemonCommand(); DaemonCommand command = new DaemonCommand();
applyMocksToCommand(command); applyMocksToCommand(command);
StreamController<Map> commands = new StreamController(); StreamController<Map<String, dynamic>> commands = new StreamController();
StreamController<Map> responses = new StreamController(); StreamController<Map<String, dynamic>> responses = new StreamController();
daemon = new Daemon( daemon = new Daemon(
commands.stream, commands.stream,
(Map<String, dynamic> result) => responses.add(result), (Map<String, dynamic> result) => responses.add(result),
daemonCommand: command daemonCommand: command,
appContext: appContext
); );
MockDeviceStore mockDevices = command.devices; MockDeviceStore mockDevices = command.devices;
...@@ -97,11 +108,12 @@ defineTests() { ...@@ -97,11 +108,12 @@ defineTests() {
}); });
test('device.getDevices', () async { test('device.getDevices', () async {
StreamController<Map> commands = new StreamController(); StreamController<Map<String, dynamic>> commands = new StreamController();
StreamController<Map> responses = new StreamController(); StreamController<Map<String, dynamic>> responses = new StreamController();
daemon = new Daemon( daemon = new Daemon(
commands.stream, commands.stream,
(Map<String, dynamic> result) => responses.add(result) (Map<String, dynamic> result) => responses.add(result),
appContext: appContext
); );
commands.add({'id': 0, 'method': 'device.getDevices'}); commands.add({'id': 0, 'method': 'device.getDevices'});
Map response = await responses.stream.where(_notEvent).first; Map response = await responses.stream.where(_notEvent).first;
......
// Copyright 2015 The Chromium Authors. All rights reserved. // Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/commands/install.dart'; import 'package:flutter_tools/src/commands/install.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'src/mocks.dart'; import 'src/mocks.dart';
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
import 'dart:io'; import 'dart:io';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/commands/list.dart'; import 'package:flutter_tools/src/commands/list.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'src/mocks.dart'; import 'src/mocks.dart';
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/commands/listen.dart'; import 'package:flutter_tools/src/commands/listen.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'src/mocks.dart'; import 'src/mocks.dart';
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/commands/logs.dart'; import 'package:flutter_tools/src/commands/logs.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'src/mocks.dart'; import 'src/mocks.dart';
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/os.dart';
import 'package:test/test.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:test/test.dart';
main() => defineTests(); main() => defineTests();
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/commands/stop.dart'; import 'package:flutter_tools/src/commands/stop.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'src/mocks.dart'; import 'src/mocks.dart';
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/commands/trace.dart'; import 'package:flutter_tools/src/commands/trace.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'src/mocks.dart'; import 'src/mocks.dart';
......
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