Don't precompile on pub get/upgrade by default (#2277)

And only precompile the single desired executable on pub run.

`pub run` will avoid printing "precompiling executable..." if we don't have a terminal attached.
That allows the output of `pub run` to be piped but still explains the user where time is going on first run of eg. pub run test in the terminal.

This does not change pub global behavior. We probably want to continue recompiling all executables on pub global activate.

`pub get` still allows --precompile for those who prefer the old behavior.
diff --git a/lib/src/command/get.dart b/lib/src/command/get.dart
index b941140..a5ea742 100644
--- a/lib/src/command/get.dart
+++ b/lib/src/command/get.dart
@@ -27,7 +27,7 @@
         help: "Report what dependencies would change but don't change any.");
 
     argParser.addFlag('precompile',
-        defaultsTo: true,
+        defaultsTo: false,
         help: "Precompile executables in immediate dependencies.");
 
     argParser.addFlag('packages-dir', negatable: true, hide: true);
diff --git a/lib/src/command/run.dart b/lib/src/command/run.dart
index 7014348..c5da1b3 100644
--- a/lib/src/command/run.dart
+++ b/lib/src/command/run.dart
@@ -71,8 +71,13 @@
 
     var exitCode = await runExecutable(entrypoint, package, executable, args,
         checked: argResults['enable-asserts'] || argResults['checked'],
-        snapshotPath: useSnapshot ? snapshotPath : null,
-        recompile: entrypoint.precompileExecutables);
+        snapshotPath: useSnapshot ? snapshotPath : null, recompile: () {
+      final pkg = entrypoint.packageGraph.packages[package];
+      // The recompile function will only be called when [package] exists.
+      assert(pkg != null);
+      final executablePath = pkg.path(p.join("bin", executable));
+      return entrypoint.precompileExecutable(package, executablePath);
+    });
     await flushThenExit(exitCode);
   }
 }
diff --git a/lib/src/command/upgrade.dart b/lib/src/command/upgrade.dart
index e65e75c..98e44ae 100644
--- a/lib/src/command/upgrade.dart
+++ b/lib/src/command/upgrade.dart
@@ -29,7 +29,7 @@
         help: "Report what dependencies would change but don't change any.");
 
     argParser.addFlag('precompile',
-        defaultsTo: true,
+        defaultsTo: false,
         help: "Precompile executables in immediate dependencies.");
 
     argParser.addFlag('packages-dir', negatable: true, hide: true);
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index 1b407fc..36a9d2b 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -213,7 +213,7 @@
   Future acquireDependencies(SolveType type,
       {List<String> useLatest,
       bool dryRun = false,
-      bool precompile = true}) async {
+      bool precompile = false}) async {
     var result = await resolveVersions(type, cache, root,
         lockFile: lockFile, useLatest: useLatest);
 
@@ -294,20 +294,32 @@
   }
 
   //// Precompiles [executables] to snapshots from the filesystem.
-  Future _precompileExecutables(Map<String, List<String>> executables) {
+  Future<void> _precompileExecutables(Map<String, List<String>> executables) {
     return waitAndPrintErrors(executables.keys.map((package) {
       var dir = p.join(_snapshotPath, package);
       cleanDir(dir);
-      return waitAndPrintErrors(executables[package].map((path) {
-        var url = p.toUri(p.join(packageGraph.packages[package].dir, path));
-        return dart.snapshot(
-            url, p.join(dir, p.basename(path) + '.snapshot.dart2'),
-            packagesFile: p.toUri(packagesFile),
-            name: '$package:${p.basenameWithoutExtension(path)}');
-      }));
+      return waitAndPrintErrors(executables[package]
+          .map((path) => _precompileExecutable(package, path)));
     }));
   }
 
+  /// Precompiles executable .dart file at [path] to a snapshot.
+  Future<void> precompileExecutable(String package, String path) async {
+    return await log.progress("Precompiling executable", () async {
+      var dir = p.join(_snapshotPath, package);
+      ensureDir(dir);
+      return waitAndPrintErrors([_precompileExecutable(package, path)]);
+    });
+  }
+
+  Future<void> _precompileExecutable(String package, String path) async {
+    var dir = p.join(_snapshotPath, package);
+    var url = p.toUri(p.join(packageGraph.packages[package].dir, path));
+    await dart.snapshot(url, p.join(dir, p.basename(path) + '.snapshot.dart2'),
+        packagesFile: p.toUri(packagesFile),
+        name: '$package:${p.basenameWithoutExtension(path)}');
+  }
+
   /// Deletes outdated cached executable snapshots.
   ///
   /// If [changed] is passed, only dependencies whose contents might be changed
diff --git a/lib/src/executable.dart b/lib/src/executable.dart
index e381888..a48c333 100644
--- a/lib/src/executable.dart
+++ b/lib/src/executable.dart
@@ -58,8 +58,10 @@
   entrypoint.migrateCache();
 
   // Unless the user overrides the verbosity, we want to filter out the
-  // normal pub output that may be shown when recompiling snapshots.
-  if (log.verbosity == log.Verbosity.NORMAL) {
+  // normal pub output that may be shown when recompiling snapshots if we are
+  // not attached to a terminal. This is to not pollute stdout when the output
+  // of `pub run` is piped somewhere.
+  if (log.verbosity == log.Verbosity.NORMAL && !stdout.hasTerminal) {
     log.verbosity = log.Verbosity.WARNING;
   }
 
diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart
index e13c63e..eafdea8 100644
--- a/lib/src/global_packages.dart
+++ b/lib/src/global_packages.dart
@@ -145,7 +145,7 @@
     var entrypoint = Entrypoint(path, cache);
 
     // Get the package's dependencies.
-    await entrypoint.acquireDependencies(SolveType.GET);
+    await entrypoint.acquireDependencies(SolveType.GET, precompile: true);
     var name = entrypoint.root.name;
 
     // Call this just to log what the current active package is, if any.
diff --git a/test/run/package_api_test.dart b/test/run/package_api_test.dart
index cdb6b5b..e79e841 100644
--- a/test/run/package_api_test.dart
+++ b/test/run/package_api_test.dart
@@ -56,10 +56,12 @@
       d.appPubspec({"foo": "any"})
     ]).create();
 
-    await pubGet(output: contains("Precompiled foo:script."));
+    await pubGet();
 
     var pub = await pubRun(args: ["foo:script"]);
 
+    expect(pub.stdout, emits('Precompiling executable...'));
+    expect(pub.stdout, emits('Precompiled foo:script.'));
     expect(pub.stdout, emits("null"));
     expect(pub.stdout,
         emits(p.toUri(p.join(d.sandbox, "myapp/.packages")).toString()));
diff --git a/test/run/runs_from_a_dependency_override_after_dependency_test.dart b/test/run/runs_from_a_dependency_override_after_dependency_test.dart
index 12d0f99..b283169 100644
--- a/test/run/runs_from_a_dependency_override_after_dependency_test.dart
+++ b/test/run/runs_from_a_dependency_override_after_dependency_test.dart
@@ -23,7 +23,7 @@
       d.appPubspec({"foo": null})
     ]).create();
 
-    await pubGet();
+    await pubGet(args: ['--precompile']);
 
     var pub = await pubRun(args: ["foo:bar"]);
     expect(pub.stdout, emits("foobar"));
diff --git a/test/snapshot_test.dart b/test/snapshot_test.dart
index bc3ff73..310b685 100644
--- a/test/snapshot_test.dart
+++ b/test/snapshot_test.dart
@@ -26,10 +26,11 @@
       await d.appDir({"foo": "1.2.3"}).create();
 
       await pubGet(
+          args: ['--precompile'],
           output: allOf([
-        contains("Precompiled foo:hello."),
-        contains("Precompiled foo:goodbye.")
-      ]));
+            contains("Precompiled foo:hello."),
+            contains("Precompiled foo:goodbye.")
+          ]));
 
       await d.dir(p.join(appPath, '.dart_tool', 'pub', 'bin'), [
         d.file('sdk-version', '0.1.2+3\n'),
@@ -67,10 +68,11 @@
       await d.appDir({"foo": "1.2.3"}).create();
 
       await pubGet(
+          args: ['--precompile'],
           output: allOf([
-        contains("Precompiled foo:hello."),
-        contains("Precompiled foo:goodbye.")
-      ]));
+            contains("Precompiled foo:hello."),
+            contains("Precompiled foo:goodbye.")
+          ]));
 
       await d.dir(p.join(appPath, '.dart_tool', 'pub', 'bin'), [
         d.file('sdk-version', '0.1.2+3\n'),
@@ -102,7 +104,8 @@
 
         await d.appDir({"foo": "any"}).create();
 
-        await pubGet(output: contains("Precompiled foo:hello."));
+        await pubGet(
+            args: ['--precompile'], output: contains("Precompiled foo:hello."));
 
         await d.dir(p.join(appPath, '.dart_tool', 'pub', 'bin', 'foo'), [
           d.file('hello.dart.snapshot.dart2', contains('hello!'))
@@ -115,7 +118,8 @@
           ]);
         });
 
-        await pubUpgrade(output: contains("Precompiled foo:hello."));
+        await pubUpgrade(
+            args: ['--precompile'], output: contains("Precompiled foo:hello."));
 
         await d.dir(p.join(appPath, '.dart_tool', 'pub', 'bin', 'foo'), [
           d.file('hello.dart.snapshot.dart2', contains('hello 2!'))
@@ -146,7 +150,8 @@
 
         await d.appDir({"foo": "any"}).create();
 
-        await pubGet(output: contains("Precompiled foo:hello."));
+        await pubGet(
+            args: ['--precompile'], output: contains("Precompiled foo:hello."));
 
         await d.dir(p.join(appPath, '.dart_tool', 'pub', 'bin', 'foo'), [
           d.file('hello.dart.snapshot.dart2', contains('hello!'))
@@ -158,7 +163,8 @@
           ]);
         });
 
-        await pubUpgrade(output: contains("Precompiled foo:hello."));
+        await pubUpgrade(
+            args: ['--precompile'], output: contains("Precompiled foo:hello."));
 
         await d.dir(p.join(appPath, '.dart_tool', 'pub', 'bin', 'foo'), [
           d.file('hello.dart.snapshot.dart2', contains('hello 2!'))
@@ -182,7 +188,8 @@
           "foo": {"git": "../foo.git"}
         }).create();
 
-        await pubGet(output: contains("Precompiled foo:hello."));
+        await pubGet(
+            args: ['--precompile'], output: contains("Precompiled foo:hello."));
 
         await d.dir(p.join(appPath, '.dart_tool', 'pub', 'bin', 'foo'), [
           d.file('hello.dart.snapshot.dart2', contains('Hello!'))
@@ -193,7 +200,8 @@
               [d.file("hello.dart", "void main() => print('Goodbye!');")])
         ]).commit();
 
-        await pubUpgrade(output: contains("Precompiled foo:hello."));
+        await pubUpgrade(
+            args: ['--precompile'], output: contains("Precompiled foo:hello."));
 
         await d.dir(p.join(appPath, '.dart_tool', 'pub', 'bin', 'foo'), [
           d.file('hello.dart.snapshot.dart2', contains('Goodbye!'))
@@ -214,7 +222,8 @@
 
         await d.appDir({"foo": "5.6.7"}).create();
 
-        await pubGet(output: contains("Precompiled foo:hello."));
+        await pubGet(
+            args: ['--precompile'], output: contains("Precompiled foo:hello."));
 
         await d.dir(p.join(appPath, '.dart_tool', 'pub', 'bin'), [
           d.dir('foo', [d.outOfDateSnapshot('hello.dart.snapshot.dart2')])
@@ -224,7 +233,7 @@
 
         // In the real world this would just print "hello!", but since we collect
         // all output we see the precompilation messages as well.
-        expect(process.stdout, emits("Precompiling executables..."));
+        expect(process.stdout, emits("Precompiling executable..."));
         expect(process.stdout, emitsThrough("hello!"));
         await process.shouldExit();