Merge pull request #35 from abarth/rm_http

Remove the --http option
diff --git a/bin/flutter b/bin/flutter
index 5ea9410..a83fb57 100755
--- a/bin/flutter
+++ b/bin/flutter
@@ -14,6 +14,9 @@
 
 if [ "$FLUTTER_TOOLS_DIR/pubspec.yaml" -nt "$FLUTTER_TOOLS_DIR/pubspec.lock" ]; then
   (cd "$FLUTTER_TOOLS_DIR"; pub get)
+  if [ -f "$SNAPSHOT_PATH" ]; then
+    rm "$SNAPSHOT_PATH"
+  fi
 fi
 
 REVISION=`(cd "$FLUTTER_ROOT"; git rev-parse HEAD)`
diff --git a/packages/flutter_tools/bin/sky_server.dart b/packages/flutter_tools/bin/sky_server.dart
deleted file mode 100644
index 04bb6e9..0000000
--- a/packages/flutter_tools/bin/sky_server.dart
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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 'dart:io';
-
-import 'package:args/args.dart';
-import 'package:shelf/shelf.dart';
-import 'package:shelf/shelf_io.dart' as io;
-import 'package:shelf_route/shelf_route.dart' as shelf_route;
-import 'package:shelf_static/shelf_static.dart';
-
-void printUsage(parser) {
-  print('Usage: sky_server [-v] PORT');
-  print(parser.usage);
-}
-
-void addRoute(var router, String route, String path) {
-  router.add(
-    route,
-    ['GET', 'HEAD'],
-    createStaticHandler(
-      path,
-      serveFilesOutsidePath: true,
-      listDirectories: true
-    ), exactMatch: false
-  );
-}
-
-main(List<String> argv) async {
-  ArgParser parser = new ArgParser();
-  parser.addFlag('help', abbr: 'h', negatable: false,
-                 help: 'Display this help message.');
-  parser.addFlag('verbose', abbr: 'v', negatable: false,
-                 help: 'Log requests to stdout.');
-  parser.addOption('route', allowMultiple: true, splitCommas: false,
-                   help: 'Adds a virtual directory to the root.');
-
-  ArgResults args = parser.parse(argv);
-
-  if (args['help'] || args.rest.length != 1) {
-    printUsage(parser);
-    return;
-  }
-
-  int port;
-  try {
-    port = int.parse(args.rest[0]);
-  } catch(e) {
-    printUsage(parser);
-    return;
-  }
-
-  var router = shelf_route.router();
-
-  if (args['route'] != null) {
-    for (String arg in args['route']) {
-      List<String> parsedArgs = arg.split(',');
-      addRoute(router, parsedArgs[0], parsedArgs[1]);
-    }
-  }
-
-  addRoute(router, '/', Directory.current.path);
-
-  var handler = router.handler;
-
-  if (args['verbose'])
-    handler = const Pipeline().addMiddleware(logRequests()).addHandler(handler);
-
-  HttpServer server;
-  try {
-    server = await io.serve(handler, InternetAddress.LOOPBACK_IP_V4, port);
-    print('Serving ${Directory.current.absolute.path} from '
-        'http://${server.address.address}:${server.port}.');
-  } catch(e) {
-    print(e);
-    exit(1);
-  }
-
-  server.defaultResponseHeaders
-    ..removeAll('x-content-type-options')
-    ..removeAll('x-frame-options')
-    ..removeAll('x-xss-protection')
-    ..add('cache-control', 'no-store');
-}
diff --git a/packages/flutter_tools/lib/src/commands/build.dart b/packages/flutter_tools/lib/src/commands/build.dart
index 1d47dfc..caee7e6 100644
--- a/packages/flutter_tools/lib/src/commands/build.dart
+++ b/packages/flutter_tools/lib/src/commands/build.dart
@@ -9,6 +9,7 @@
 import 'package:archive/archive.dart';
 import 'package:flx/bundle.dart';
 import 'package:flx/signing.dart';
+import 'package:path/path.dart' as path;
 import 'package:yaml/yaml.dart';
 
 import '../toolchain.dart';
@@ -147,6 +148,27 @@
     );
   }
 
+  Future<int> buildInTempDir({
+    String mainPath: _kDefaultMainPath,
+    void onBundleAvailable(String bundlePath)
+  }) async {
+    int result;
+    Directory tempDir = await Directory.systemTemp.createTemp('flutter_tools');
+    try {
+      String localBundlePath = path.join(tempDir.path, 'app.flx');
+      String localSnapshotPath = path.join(tempDir.path, 'snapshot_blob.bin');
+      result = await build(
+        snapshotPath: localSnapshotPath,
+        outputPath: localBundlePath,
+        mainPath: mainPath
+      );
+      onBundleAvailable(localBundlePath);
+    } finally {
+      tempDir.deleteSync(recursive: true);
+    }
+    return result;
+  }
+
   Future<int> build({
     String assetBase: _kDefaultAssetBase,
     String mainPath: _kDefaultMainPath,
diff --git a/packages/flutter_tools/lib/src/commands/listen.dart b/packages/flutter_tools/lib/src/commands/listen.dart
index 93bd19e..e384e85 100644
--- a/packages/flutter_tools/lib/src/commands/listen.dart
+++ b/packages/flutter_tools/lib/src/commands/listen.dart
@@ -34,7 +34,6 @@
         help: 'Target app path or filename to start.');
   }
 
-  static const String _localFlutterBundle = 'app.flx';
   static const String _remoteFlutterBundle = 'Documents/app.flx';
 
   @override
@@ -53,25 +52,26 @@
 
       BuildCommand builder = new BuildCommand();
       builder.inheritFromParent(this);
-      builder.build(outputPath: _localFlutterBundle);
-
-      for (Device device in devices.all) {
-        ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
-        if (package == null || !device.isConnected())
-          continue;
-        if (device is AndroidDevice) {
-          await devices.android.startServer(
-              argResults['target'], true, argResults['checked'], package);
-        } else if (device is IOSDevice) {
-          device.pushFile(package, _localFlutterBundle, _remoteFlutterBundle);
-        } else if (device is IOSSimulator) {
-          // TODO(abarth): Move pushFile up to Device once Android supports
-          // pushing new bundles.
-          device.pushFile(package, _localFlutterBundle, _remoteFlutterBundle);
-        } else {
-          assert(false);
+      await builder.buildInTempDir(
+        onBundleAvailable: (String localBundlePath) {
+          for (Device device in devices.all) {
+            ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
+            if (package == null || !device.isConnected())
+              continue;
+            if (device is AndroidDevice) {
+              device.startBundle(package, localBundlePath, true, argResults['checked']);
+            } else if (device is IOSDevice) {
+              device.pushFile(package, localBundlePath, _remoteFlutterBundle);
+            } else if (device is IOSSimulator) {
+              // TODO(abarth): Move pushFile up to Device once Android supports
+              // pushing new bundles.
+              device.pushFile(package, localBundlePath, _remoteFlutterBundle);
+            } else {
+              assert(false);
+            }
+          }
         }
-      }
+      );
 
       if (singleRun || !watchDirectory())
         break;
diff --git a/packages/flutter_tools/lib/src/commands/start.dart b/packages/flutter_tools/lib/src/commands/start.dart
index d851593..90a588d 100644
--- a/packages/flutter_tools/lib/src/commands/start.dart
+++ b/packages/flutter_tools/lib/src/commands/start.dart
@@ -16,8 +16,6 @@
 import 'stop.dart';
 
 final Logger _logging = new Logger('sky_tools.start');
-const String _localBundleName = 'app.flx';
-const String _localSnapshotName = 'snapshot_blob.bin';
 
 class StartCommand extends FlutterCommand {
   final String name = 'start';
@@ -35,9 +33,6 @@
         defaultsTo: '.',
         abbr: 't',
         help: 'Target app path or filename to start.');
-    argParser.addFlag('http',
-        negatable: true,
-        help: 'Use a local HTTP server to serve your app to your device.');
     argParser.addFlag('boot',
         help: 'Boot the iOS Simulator if it isn\'t already running.');
   }
@@ -69,30 +64,18 @@
         continue;
       if (device is AndroidDevice) {
         String target = path.absolute(argResults['target']);
-        if (argResults['http']) {
-          if (await device.startServer(target, poke, argResults['checked'], package))
-            startedSomething = true;
-        } else {
-          String mainPath = target;
-          if (FileSystemEntity.isDirectorySync(target))
-            mainPath = path.join(target, 'lib', 'main.dart');
-          BuildCommand builder = new BuildCommand();
-          builder.inheritFromParent(this);
-
-          Directory tempDir = await Directory.systemTemp.createTemp('flutter_tools');
-          try {
-            String localBundlePath = path.join(tempDir.path, _localBundleName);
-            String localSnapshotPath = path.join(tempDir.path, _localSnapshotName);
-            await builder.build(
-              snapshotPath: localSnapshotPath,
-              outputPath: localBundlePath,
-              mainPath: mainPath);
+        String mainPath = target;
+        if (FileSystemEntity.isDirectorySync(target))
+          mainPath = path.join(target, 'lib', 'main.dart');
+        BuildCommand builder = new BuildCommand();
+        builder.inheritFromParent(this);
+        await builder.buildInTempDir(
+          mainPath: mainPath,
+          onBundleAvailable: (String localBundlePath) {
             if (device.startBundle(package, localBundlePath, poke, argResults['checked']))
               startedSomething = true;
-          } finally {
-            tempDir.deleteSync(recursive: true);
           }
-        }
+        );
       } else {
         if (await device.startApp(package))
           startedSomething = true;
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index c968e3c..c3fa641 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -3,9 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:convert';
 import 'dart:io';
-import 'dart:math';
 
 import 'package:crypto/crypto.dart';
 import 'package:logging/logging.dart';
@@ -13,7 +11,6 @@
 
 import 'application_package.dart';
 import 'build_configuration.dart';
-import 'os_utils.dart';
 import 'process.dart';
 
 final Logger _logging = new Logger('sky_tools.device');
@@ -507,14 +504,10 @@
 class AndroidDevice extends Device {
   static const String _ADB_PATH = 'adb';
   static const int _observatoryPort = 8181;
-  static const int _serverPort = 9888;
 
   static const String className = 'AndroidDevice';
   static final String defaultDeviceID = 'default_android_device';
 
-  static const String _kFlutterServerStartMessage = 'Serving';
-  static const Duration _kFlutterServerTimeout = const Duration(seconds: 3);
-
   String productID;
   String modelID;
   String deviceCodeName;
@@ -718,13 +711,6 @@
     return CryptoUtils.bytesToHex(sha1.close());
   }
 
-  /**
-   * Since Window's paths have backslashes, we need to convert those to forward slashes to make a valid URL
-   */
-  String _convertToURL(String path) {
-    return path.replaceAll('\\', '/');
-  }
-
   @override
   bool isAppInstalled(ApplicationPackage app) {
     if (!isConnected()) {
@@ -793,81 +779,16 @@
     return true;
   }
 
-  Future<bool> startServer(
-      String target, bool poke, bool checked, AndroidApk apk) async {
-    String serverRoot = '';
-    String mainDart = '';
-    String missingMessage = '';
-    if (FileSystemEntity.isDirectorySync(target)) {
-      serverRoot = target;
-      mainDart = path.join(serverRoot, 'lib', 'main.dart');
-      missingMessage = 'Missing lib/main.dart in project: $serverRoot';
-    } else {
-      serverRoot = Directory.current.path;
-      mainDart = target;
-      missingMessage = '$mainDart does not exist.';
-    }
-
-    if (!FileSystemEntity.isFileSync(mainDart)) {
-      _logging.severe(missingMessage);
-      return false;
-    }
-
-    if (!poke) {
-      _forwardObservatoryPort();
-
-      // Actually start the server.
-      Process server = await Process.start(
-          sdkBinaryName('pub'), ['run', 'sky_tools:sky_server', _serverPort.toString()],
-          workingDirectory: serverRoot,
-          mode: ProcessStartMode.DETACHED_WITH_STDIO
-      );
-      await server.stdout.transform(UTF8.decoder)
-          .firstWhere((String value) => value.startsWith(_kFlutterServerStartMessage))
-          .timeout(_kFlutterServerTimeout);
-
-      // Set up reverse port-forwarding so that the Android app can reach the
-      // server running on localhost.
-      String serverPortString = 'tcp:$_serverPort';
-      runCheckedSync(adbCommandForDevice(['reverse', serverPortString, serverPortString]));
-    }
-
-    String relativeDartMain = _convertToURL(path.relative(mainDart, from: serverRoot));
-    String url = 'http://localhost:$_serverPort/$relativeDartMain';
-    if (poke)
-      url += '?rand=${new Random().nextDouble()}';
-
-    // Actually launch the app on Android.
-    List<String> cmd = adbCommandForDevice([
-      'shell', 'am', 'start',
-      '-a', 'android.intent.action.VIEW',
-      '-d', url,
-    ]);
-    if (checked)
-      cmd.addAll(['--ez', 'enable-checked-mode', 'true']);
-    cmd.add(apk.launchActivity);
-    runCheckedSync(cmd);
-    return true;
-  }
-
   @override
   Future<bool> startApp(ApplicationPackage app) async {
-    // Android currently has to be started with startServer(...).
+    // Android currently has to be started with startBundle(...).
     assert(false);
     return false;
   }
 
   Future<bool> stopApp(ApplicationPackage app) async {
     final AndroidApk apk = app;
-
-    // Turn off reverse port forwarding
-    runSync(adbCommandForDevice(['reverse', '--remove', 'tcp:$_serverPort']));
-    // Stop the app
     runSync(adbCommandForDevice(['shell', 'am', 'force-stop', apk.id]));
-
-    // Kill the server
-    osUtils.killTcpPortListeners(_serverPort);
-
     return true;
   }
 
diff --git a/packages/flutter_tools/lib/src/os_utils.dart b/packages/flutter_tools/lib/src/os_utils.dart
index caf124d..d200652 100644
--- a/packages/flutter_tools/lib/src/os_utils.dart
+++ b/packages/flutter_tools/lib/src/os_utils.dart
@@ -6,8 +6,6 @@
 
 import 'package:logging/logging.dart';
 
-import 'process.dart';
-
 final OperatingSystemUtils osUtils = new OperatingSystemUtils._();
 
 final Logger _logging = new Logger('sky_tools.os');
@@ -16,21 +14,16 @@
   factory OperatingSystemUtils._() {
     if (Platform.isWindows) {
       return new _WindowsUtils();
-    } else if (Platform.isMacOS) {
-      return new _MacUtils();
     } else {
-      return new _LinuxUtils();
+      return new _PosixUtils();
     }
   }
 
   /// Make the given file executable. This may be a no-op on some platforms.
   ProcessResult makeExecutable(File file);
-
-  /// A best-effort attempt to kill all listeners on the given TCP port.
-  void killTcpPortListeners(int tcpPort);
 }
 
-abstract class _PosixUtils implements OperatingSystemUtils {
+class _PosixUtils implements OperatingSystemUtils {
   ProcessResult makeExecutable(File file) {
     return Process.runSync('chmod', ['u+x', file.path]);
   }
@@ -41,51 +34,4 @@
   ProcessResult makeExecutable(File file) {
     return new ProcessResult(0, 0, null, null);
   }
-
-  void killTcpPortListeners(int tcpPort) {
-    // Get list of network processes and split on newline
-    List<String> processes = runSync(['netstat.exe','-ano']).split("\r");
-
-    // List entries from netstat is formatted like so:
-    //   TCP    192.168.2.11:50945     192.30.252.90:443      LISTENING     1304
-    // This regexp is to find process where the the port exactly matches
-    RegExp pattern = new RegExp(':$tcpPort[ ]+');
-
-    // Split the columns by 1 or more spaces
-    RegExp columnPattern = new RegExp('[ ]+');
-    processes.forEach((String process) {
-      if (process.contains(pattern)) {
-        // The last column is the Process ID
-        String processId = process.split(columnPattern).last;
-        // Force and Tree kill the process
-        _logging.info('kill $processId');
-        runSync(['TaskKill.exe', '/F', '/T', '/PID', processId]);
-      }
-    });
-  }
-}
-
-class _MacUtils extends _PosixUtils {
-  void killTcpPortListeners(int tcpPort) {
-    String pids = runSync(['lsof', '-i', ':$tcpPort', '-t']).trim();
-    if (pids.isNotEmpty) {
-      // Handle multiple returned pids.
-      for (String pidString in pids.split('\n')) {
-        // Killing a pid with a shell command from within dart is hard, so use a
-        // library command, but it's still nice to give the equivalent command
-        // when doing verbose logging.
-        _logging.info('kill $pidString');
-
-        int pid = int.parse(pidString, onError: (_) => null);
-        if (pid != null)
-          Process.killPid(pid);
-      }
-    }
-  }
-}
-
-class _LinuxUtils extends _PosixUtils {
-  void killTcpPortListeners(int tcpPort) {
-    runSync(['fuser', '-k', '$tcpPort/tcp']);
-  }
 }
diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml
index 1ee0e87..37c85be 100644
--- a/packages/flutter_tools/pubspec.yaml
+++ b/packages/flutter_tools/pubspec.yaml
@@ -15,9 +15,6 @@
   crypto: ^0.9.1
   mustache4dart: ^1.0.0
   path: ^1.3.0
-  shelf_route: ^0.13.4
-  shelf_static: ^0.2.3
-  shelf: ^0.6.2
   stack_trace: ^1.4.0
   test: ^0.12.5
   yaml: ^2.1.3
diff --git a/packages/flutter_tools/test/os_utils_test.dart b/packages/flutter_tools/test/os_utils_test.dart
index 999fc9c..c38e638 100644
--- a/packages/flutter_tools/test/os_utils_test.dart
+++ b/packages/flutter_tools/test/os_utils_test.dart
@@ -34,33 +34,5 @@
         expect(mode.substring(0, 3), endsWith('x'));
       }
     });
-
-    /// Start a script listening on a port, try and kill that process.
-    test('killTcpPortListeners', () async {
-      final int port = 40170;
-
-      File file = new File(p.join(temp.path, 'script.dart'));
-      file.writeAsStringSync('''
-import 'dart:io';
-
-void main() async {
-  ServerSocket serverSocket = await ServerSocket.bind(
-      InternetAddress.LOOPBACK_IP_V4, ${port});
-  // wait...
-  print('listening on port ${port}...');
-}
-''');
-      Process process = await Process.start('dart', [file.path]);
-      await process.stdout.first;
-
-      osUtils.killTcpPortListeners(40170);
-      int exitCode = await process.exitCode;
-      expect(exitCode, isNot(equals(0)));
-    });
-
-    /// Try and kill with a port that no process is listening to.
-    test('killTcpPortListeners none', () {
-      osUtils.killTcpPortListeners(40171);
-    });
   });
 }