Fix `pub run` precompilation with relative PUB_CACHE paths (#2486)

diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index b4d66f5..7cff07c 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -305,8 +305,9 @@
     return waitAndPrintErrors(executables.keys.map((package) {
       var dir = p.join(_snapshotPath, package);
       cleanDir(dir);
-      return waitAndPrintErrors(executables[package]
-          .map((path) => _precompileExecutable(package, path)));
+      return waitAndPrintErrors(executables[package].map((path) =>
+          _precompileExecutable(
+              package, p.join(packageGraph.packages[package].dir, path))));
     }));
   }
 
@@ -321,8 +322,8 @@
 
   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'),
+    await dart.snapshot(
+        p.toUri(path), p.join(dir, p.basename(path) + '.snapshot.dart2'),
         packagesFile: p.toUri(packagesFile),
         name: '$package:${p.basenameWithoutExtension(path)}');
   }
diff --git a/test/run/precompile_test.dart b/test/run/precompile_test.dart
new file mode 100644
index 0000000..9c50b5c
--- /dev/null
+++ b/test/run/precompile_test.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. 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:test/test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+const SCRIPT = r'''
+import 'dart:io';
+
+main(List<String> args) {
+  print('running with PUB_CACHE: "${Platform.environment['PUB_CACHE']}"');
+}
+''';
+
+void main() {
+  test('`pub run` precompiles script', () async {
+    await d.dir(appPath, [
+      d.appPubspec({'test': '1.0.0'}),
+    ]).create();
+
+    await servePackages((server) => server
+      ..serve('test', '1.0.0', contents: [
+        d.dir('bin', [d.file('test.dart', SCRIPT)])
+      ]));
+
+    await pubGet(args: ['--no-precompile']);
+
+    var pub = await pubRun(args: ['test']);
+    await pub.shouldExit(0);
+    final lines = await pub.stdout.rest.toList();
+    expect(lines, contains('Precompiling executable...'));
+  });
+
+  // Regression test of https://github.com/dart-lang/pub/issues/2483
+  test('`pub run` precompiles script with relative PUB_CACHE', () async {
+    await d.dir(appPath, [
+      d.appPubspec({'test': '1.0.0'}),
+    ]).create();
+
+    await servePackages((server) => server
+      ..serve('test', '1.0.0', contents: [
+        d.dir('bin', [d.file('test.dart', SCRIPT)])
+      ]));
+
+    await pubGet(
+        args: ['--no-precompile'], environment: {'PUB_CACHE': '.pub_cache'});
+
+    var pub = await pubRun(
+      args: ['test'],
+      environment: {'PUB_CACHE': '.pub_cache'},
+    );
+    await pub.shouldExit(0);
+    final lines = await pub.stdout.rest.toList();
+    expect(lines, contains('Precompiling executable...'));
+    expect(lines, contains('running with PUB_CACHE: ".pub_cache"'));
+  });
+
+  test('`get --precompile` precompiles script', () async {
+    await d.dir(appPath, [
+      d.appPubspec({'test': '1.0.0'}),
+    ]).create();
+
+    await servePackages((server) => server
+      ..serve('test', '1.0.0', contents: [
+        d.dir('bin', [d.file('test.dart', SCRIPT)])
+      ]));
+
+    await pubGet(
+        args: ['--precompile'],
+        output: contains('Precompiling executables...'));
+
+    var pub = await pubRun(
+      args: ['test'],
+    );
+    await pub.shouldExit(0);
+    final lines = await pub.stdout.rest.toList();
+    expect(lines, isNot(contains('Precompiling executable...')));
+  });
+
+  // Regression test of https://github.com/dart-lang/pub/issues/2483
+  test('`get --precompile` precompiles script with relative PUB_CACHE',
+      () async {
+    await d.dir(appPath, [
+      d.appPubspec({'test': '1.0.0'}),
+    ]).create();
+
+    await servePackages((server) => server
+      ..serve('test', '1.0.0', contents: [
+        d.dir('bin', [d.file('test.dart', SCRIPT)])
+      ]));
+
+    await pubGet(
+        args: ['--precompile'],
+        environment: {'PUB_CACHE': '.pub_cache'},
+        output: contains('Precompiling executables...'));
+
+    var pub = await pubRun(
+      args: ['test'],
+      environment: {'PUB_CACHE': '.pub_cache'},
+    );
+    await pub.shouldExit(0);
+    final lines = await pub.stdout.rest.toList();
+    expect(lines, isNot(contains('Precompiling executable...')));
+    expect(lines, contains('running with PUB_CACHE: ".pub_cache"'));
+  });
+}
diff --git a/test/test_pub.dart b/test/test_pub.dart
index fe45ce0..af1ccc5 100644
--- a/test/test_pub.dart
+++ b/test/test_pub.dart
@@ -200,10 +200,13 @@
 /// "pub run".
 ///
 /// Returns the `pub run` process.
-Future<PubProcess> pubRun({bool global = false, Iterable<String> args}) async {
+Future<PubProcess> pubRun(
+    {bool global = false,
+    Iterable<String> args,
+    Map<String, String> environment}) async {
   var pubArgs = global ? ['global', 'run'] : ['run'];
   pubArgs.addAll(args);
-  var pub = await startPub(args: pubArgs);
+  var pub = await startPub(args: pubArgs, environment: environment);
 
   // Loading sources and transformers isn't normally printed, but the pub test
   // infrastructure runs pub in verbose mode, which enables this.