verify that we're running from the root of a project

remove an unused import

review comments

rename st --> stack
diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart
index cdecdd0..4643ccb 100644
--- a/packages/flutter_tools/lib/executable.dart
+++ b/packages/flutter_tools/lib/executable.dart
@@ -20,6 +20,7 @@
 import 'src/commands/start.dart';
 import 'src/commands/stop.dart';
 import 'src/commands/trace.dart';
+import 'src/process.dart';
 
 /// Main entry point for commands.
 ///
@@ -58,6 +59,16 @@
       exit(result);
   } on UsageException catch (e) {
     stderr.writeln(e);
-    exit(4);
+    // Args error exit code.
+    exit(64);
+  } catch (e, stack) {
+    if (e is ProcessExit) {
+      // We've caught an exit code.
+      exit(e.exitCode);
+    }
+
+    stderr.writeln(e);
+    Logger.root.log(Level.SEVERE, '\nException:', null, stack);
+    exit(1);
   }
 }
diff --git a/packages/flutter_tools/lib/src/commands/build.dart b/packages/flutter_tools/lib/src/commands/build.dart
index 1360f39..6abcf13 100644
--- a/packages/flutter_tools/lib/src/commands/build.dart
+++ b/packages/flutter_tools/lib/src/commands/build.dart
@@ -127,7 +127,7 @@
   }
 
   @override
-  Future<int> run() async {
+  Future<int> runInProject() async {
     String compilerPath = argResults['compiler'];
 
     if (compilerPath == null)
diff --git a/packages/flutter_tools/lib/src/commands/flutter_command.dart b/packages/flutter_tools/lib/src/commands/flutter_command.dart
index d56cdcc..917ece3 100644
--- a/packages/flutter_tools/lib/src/commands/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/commands/flutter_command.dart
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:async';
+import 'dart:io';
 
 import 'package:args/command_runner.dart';
 
@@ -14,6 +15,9 @@
 abstract class FlutterCommand extends Command {
   FlutterCommandRunner get runner => super.runner;
 
+  /// Whether this command needs to be run from the root of a project.
+  bool get requiresProjectRoot => true;
+
   Future downloadApplicationPackages() async {
     if (applicationPackages == null)
       applicationPackages = await ApplicationPackageStore.forConfigs(runner.buildConfigurations);
@@ -40,6 +44,20 @@
     devices = other.devices;
   }
 
+  Future<int> run() async {
+    if (requiresProjectRoot) {
+      if (!FileSystemEntity.isFileSync('pubspec.yaml')) {
+        stderr.writeln('No pubspec.yaml file found. '
+            'This command should be run from the root of a project.');
+        return 1;
+      }
+    }
+
+    return runInProject();
+  }
+
+  Future<int> runInProject();
+
   ApplicationPackageStore applicationPackages;
   Toolchain toolchain;
   DeviceStore devices;
diff --git a/packages/flutter_tools/lib/src/commands/flutter_command_runner.dart b/packages/flutter_tools/lib/src/commands/flutter_command_runner.dart
index 8749a24..b12c257 100644
--- a/packages/flutter_tools/lib/src/commands/flutter_command_runner.dart
+++ b/packages/flutter_tools/lib/src/commands/flutter_command_runner.dart
@@ -12,6 +12,7 @@
 
 import '../artifacts.dart';
 import '../build_configuration.dart';
+import '../process.dart';
 
 final Logger _logging = new Logger('sky_tools.flutter_command_runner');
 
@@ -116,8 +117,8 @@
         else
           message += '\nDid you run this command from the same directory as your pubspec.yaml file?';
       }
-      _logging.severe(message);
-      exit(2);
+      stderr.writeln(message);
+      throw new ProcessExit(2);
     }
 
     String enginePath = globalResults['engine-src-path'];
@@ -129,9 +130,11 @@
       String realFlutterPath = flutterDir.resolveSymbolicLinksSync();
 
       enginePath = path.dirname(path.dirname(path.dirname(path.dirname(realFlutterPath))));
-      if (enginePath == '/' || enginePath.isEmpty || !FileSystemEntity.isDirectorySync(path.join(enginePath, 'out'))) {
-        _logging.severe('Unable to detect local build in $enginePath.\nDo you have a dependency override for the flutter package?');
-        exit(2);
+      bool dirExists = FileSystemEntity.isDirectorySync(path.join(enginePath, 'out'));
+      if (enginePath == '/' || enginePath.isEmpty || !dirExists) {
+        stderr.writeln('Unable to detect local build in $enginePath.\n'
+            'Do you have a dependency override for the flutter package?');
+        throw new ProcessExit(2);
       }
     }
 
diff --git a/packages/flutter_tools/lib/src/commands/init.dart b/packages/flutter_tools/lib/src/commands/init.dart
index 4e3512d..57eac43 100644
--- a/packages/flutter_tools/lib/src/commands/init.dart
+++ b/packages/flutter_tools/lib/src/commands/init.dart
@@ -160,8 +160,7 @@
        ),
       floatingActionButton: new FloatingActionButton(
         child: new Icon(
-          type: 'content/add',
-          size: 24
+          type: 'content/add'
         )
       )
     );
diff --git a/packages/flutter_tools/lib/src/commands/install.dart b/packages/flutter_tools/lib/src/commands/install.dart
index a8cb776..235243e 100644
--- a/packages/flutter_tools/lib/src/commands/install.dart
+++ b/packages/flutter_tools/lib/src/commands/install.dart
@@ -18,7 +18,7 @@
   }
 
   @override
-  Future<int> run() async {
+  Future<int> runInProject() async {
     await downloadApplicationPackagesAndConnectToDevices();
     return install(boot: argResults['boot']) ? 0 : 2;
   }
diff --git a/packages/flutter_tools/lib/src/commands/list.dart b/packages/flutter_tools/lib/src/commands/list.dart
index 379f733..498f0a5 100644
--- a/packages/flutter_tools/lib/src/commands/list.dart
+++ b/packages/flutter_tools/lib/src/commands/list.dart
@@ -23,7 +23,7 @@
   }
 
   @override
-  Future<int> run() async {
+  Future<int> runInProject() async {
     connectToDevices();
 
     bool details = argResults['details'];
diff --git a/packages/flutter_tools/lib/src/commands/listen.dart b/packages/flutter_tools/lib/src/commands/listen.dart
index 64dc314..93bd19e 100644
--- a/packages/flutter_tools/lib/src/commands/listen.dart
+++ b/packages/flutter_tools/lib/src/commands/listen.dart
@@ -38,7 +38,7 @@
   static const String _remoteFlutterBundle = 'Documents/app.flx';
 
   @override
-  Future<int> run() async {
+  Future<int> runInProject() async {
     await downloadApplicationPackagesAndConnectToDevices();
     await downloadToolchain();
 
diff --git a/packages/flutter_tools/lib/src/commands/logs.dart b/packages/flutter_tools/lib/src/commands/logs.dart
index 5785db8..992187f 100644
--- a/packages/flutter_tools/lib/src/commands/logs.dart
+++ b/packages/flutter_tools/lib/src/commands/logs.dart
@@ -22,7 +22,7 @@
   }
 
   @override
-  Future<int> run() async {
+  Future<int> runInProject() async {
     connectToDevices();
 
     bool clear = argResults['clear'];
diff --git a/packages/flutter_tools/lib/src/commands/start.dart b/packages/flutter_tools/lib/src/commands/start.dart
index 434fa77..33f9f46 100644
--- a/packages/flutter_tools/lib/src/commands/start.dart
+++ b/packages/flutter_tools/lib/src/commands/start.dart
@@ -36,7 +36,7 @@
   }
 
   @override
-  Future<int> run() async {
+  Future<int> runInProject() async {
     await downloadApplicationPackagesAndConnectToDevices();
 
     bool poke = argResults['poke'];
diff --git a/packages/flutter_tools/lib/src/commands/stop.dart b/packages/flutter_tools/lib/src/commands/stop.dart
index 6118b9b..9117443 100644
--- a/packages/flutter_tools/lib/src/commands/stop.dart
+++ b/packages/flutter_tools/lib/src/commands/stop.dart
@@ -17,7 +17,7 @@
   final String description = 'Stop your Flutter app on all attached devices.';
 
   @override
-  Future<int> run() async {
+  Future<int> runInProject() async {
     await downloadApplicationPackagesAndConnectToDevices();
     return await stop() ? 0 : 2;
   }
diff --git a/packages/flutter_tools/lib/src/commands/trace.dart b/packages/flutter_tools/lib/src/commands/trace.dart
index 31582a8..b30f570 100644
--- a/packages/flutter_tools/lib/src/commands/trace.dart
+++ b/packages/flutter_tools/lib/src/commands/trace.dart
@@ -28,7 +28,7 @@
   }
 
   @override
-  Future<int> run() async {
+  Future<int> runInProject() async {
     await downloadApplicationPackagesAndConnectToDevices();
 
     if (!devices.android.isConnected()) {
diff --git a/packages/flutter_tools/lib/src/process.dart b/packages/flutter_tools/lib/src/process.dart
index a23c3db..2332b58 100644
--- a/packages/flutter_tools/lib/src/process.dart
+++ b/packages/flutter_tools/lib/src/process.dart
@@ -89,3 +89,10 @@
   _logging.fine(results.stdout.trim());
   return results.stdout;
 }
+
+class ProcessExit implements Exception {
+  final int exitCode;
+  ProcessExit(this.exitCode);
+  String get message => 'ProcessExit: ${exitCode}';
+  String toString() => message;
+}
diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml
index 202bcce..3577ccb 100644
--- a/packages/flutter_tools/pubspec.yaml
+++ b/packages/flutter_tools/pubspec.yaml
@@ -19,7 +19,7 @@
   shelf_route: ^0.13.4
   shelf_static: ^0.2.3
   shelf: ^0.6.2
-  test: ^0.12.5
+  test: 0.12.4+9
   yaml: ^2.1.3
 
 dev_dependencies: