Stop depending on .packages (#2764)

diff --git a/lib/src/dart.dart b/lib/src/dart.dart
index 5b40579..eff5648 100644
--- a/lib/src/dart.dart
+++ b/lib/src/dart.dart
@@ -38,36 +38,35 @@
 /// Snapshots the Dart executable at [executablePath] to a snapshot at
 /// [snapshotPath].
 ///
-/// If [packagesFile] is passed, it's used to resolve `package:` URIs in the
-/// executable. Otherwise, a `packages/` directory or a package spec is inferred
-/// from the executable's location.
+/// If [packageConfigFile] is passed, it's used to resolve `package:` URIs in
+/// the executable. Otherwise, a `packages/` directory or a package spec is
+/// inferred from the executable's location.
 ///
 /// If [name] is passed, it is used to describe the executable in logs and error
 /// messages.
 Future snapshot(
   String executablePath,
   String snapshotPath, {
-  Uri packagesFile,
+  String packageConfigFile,
   String name,
 }) async {
-  name = log.bold(name ?? executablePath.toString());
+  final args = [
+    if (packageConfigFile != null) '--packages=$packageConfigFile',
+    '--snapshot=$snapshotPath',
+    p.toUri(executablePath).toString()
+  ];
 
-  var args = ['--snapshot=$snapshotPath', p.toUri(executablePath).toString()];
-
-  if (packagesFile != null) {
-    // Resolve [packagesFile] in case it's relative to work around sdk#33177.
-    args.insert(0, '--packages=${Uri.base.resolveUri(packagesFile)}');
-  }
-
-  var result = await runProcess(Platform.executable, args);
+  final result = await runProcess(Platform.executable, args);
+  final highlightedName = name = log.bold(name ?? executablePath.toString());
   if (result.success) {
-    log.message('Precompiled $name.');
+    log.message('Precompiled $highlightedName.');
   } else {
     // Don't leave partial results.
     deleteEntry(snapshotPath);
 
     throw ApplicationException(
-        log.yellow('Failed to precompile $name:\n') + result.stderr.join('\n'));
+        log.yellow('Failed to precompile $highlightedName:\n') +
+            result.stderr.join('\n'));
   }
 }
 
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index b9f9eed..a7b3fa2 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -103,8 +103,8 @@
   /// The package graph for the application and all of its transitive
   /// dependencies.
   ///
-  /// Throws a [DataError] if the `.packages` file isn't up-to-date relative to
-  /// the pubspec and the lockfile.
+  /// Throws a [DataError] if the `.dart_tool/package_config.json` file isn't
+  /// up-to-date relative to the pubspec and the lockfile.
   PackageGraph get packageGraph {
     if (_packageGraph != null) return _packageGraph;
 
@@ -127,10 +127,11 @@
   String get _configRoot =>
       isCached ? p.join(cache.rootDir, 'global_packages', root.name) : root.dir;
 
-  /// The path to the entrypoint's "packages" directory.
-  String get packagesPath => root.path('packages');
-
   /// The path to the entrypoint's ".packages" file.
+  ///
+  /// This file is being slowly deprecated in favor of
+  /// `.dart_tool/package_config.json`. Pub will still create it, but will
+  /// not require it or make use of it within pub.
   String get packagesFile => p.join(_configRoot, '.packages');
 
   /// The path to the entrypoint's ".dart_tool/package_config.json" file.
@@ -353,7 +354,7 @@
     final package = executable.package;
     await dart.snapshot(
         resolveExecutable(executable), snapshotPathOfExecutable(executable),
-        packagesFile: p.toUri(packagesFile),
+        packageConfigFile: packageConfigFile,
         name:
             '$package:${p.basenameWithoutExtension(executable.relativePath)}');
   }
@@ -436,9 +437,11 @@
     });
   }
 
-  /// Throws a [DataError] if the `.packages` file or the
-  /// `.dart_tool/package_config.json` file doesn't exist or if it's out-of-date
-  /// relative to the lockfile or the pubspec.
+  /// Throws a [DataError] if the `.dart_tool/package_config.json` file doesn't
+  /// exist or if it's out-of-date relative to the lockfile or the pubspec.
+  ///
+  /// A `.packages` file is not required. But if it exists it is checked for
+  /// consistency with the pubspec.lock.
   void assertUpToDate() {
     if (isCached) return;
 
@@ -453,9 +456,6 @@
         'resolution of package import URIs; run "pub get" to generate it.',
       );
     }
-    if (!entryExists(packagesFile)) {
-      dataError('No .packages file found, please run "pub get" first.');
-    }
 
     // Manually parse the lockfile because a full YAML parse is relatively slow
     // and this is on the hot path for "pub run".
@@ -483,12 +483,14 @@
       }
     }
 
-    var packagesModified = File(packagesFile).lastModifiedSync();
-    if (packagesModified.isBefore(lockFileModified)) {
-      _checkPackagesFileUpToDate();
-      touch(packagesFile);
-    } else if (touchedLockFile) {
-      touch(packagesFile);
+    if (fileExists(packagesFile)) {
+      var packagesModified = File(packagesFile).lastModifiedSync();
+      if (packagesModified.isBefore(lockFileModified)) {
+        _checkPackagesFileUpToDate();
+        touch(packagesFile);
+      } else if (touchedLockFile) {
+        touch(packagesFile);
+      }
     }
 
     var packageConfigModified = File(packageConfigFile).lastModifiedSync();
diff --git a/lib/src/executable.dart b/lib/src/executable.dart
index d178362..cc1b245 100644
--- a/lib/src/executable.dart
+++ b/lib/src/executable.dart
@@ -43,9 +43,6 @@
 ///
 /// If [enableAsserts] is true, the program is run with assertions enabled.
 ///
-/// If [packagesFile] is passed, it's used as the package config file path for
-/// the executable. Otherwise, `entrypoint.packagesFile` is used.
-///
 /// If the executable is in an immutable package and we pass no [vmArgs], it
 /// run from snapshot (and precompiled if the snapshot doesn't already exist).
 ///
@@ -53,12 +50,10 @@
 Future<int> runExecutable(
     Entrypoint entrypoint, Executable executable, Iterable<String> args,
     {bool enableAsserts = false,
-    String packagesFile,
     Future<void> Function(Executable) recompile,
     List<String> vmArgs = const [],
     @required bool alwaysUseSubprocess}) async {
   final package = executable.package;
-  packagesFile ??= entrypoint.packagesFile;
 
   // Make sure the package is an immediate dependency of the entrypoint or the
   // entrypoint itself.
@@ -122,13 +117,13 @@
   // helpful for the subprocess to be able to spawn Dart with
   // Platform.executableArguments and have that work regardless of the working
   // directory.
-  var packageConfig = p.absolute(packagesFile);
+  final packageConfigAbsolute = p.absolute(entrypoint.packageConfigFile);
 
   try {
     return await _runDartProgram(
       executablePath,
       args,
-      packageConfig,
+      packageConfigAbsolute,
       enableAsserts: enableAsserts,
       vmArgs: vmArgs,
       alwaysUseSubprocess: alwaysUseSubprocess,
@@ -144,7 +139,7 @@
     return await _runDartProgram(
       executablePath,
       args,
-      packageConfig,
+      packageConfigAbsolute,
       enableAsserts: enableAsserts,
       vmArgs: vmArgs,
       alwaysUseSubprocess: alwaysUseSubprocess,
diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart
index a140721..43cf996 100644
--- a/lib/src/global_packages.dart
+++ b/lib/src/global_packages.dart
@@ -373,7 +373,6 @@
   Future<int> runExecutable(
       Entrypoint entrypoint, exec.Executable executable, Iterable<String> args,
       {bool enableAsserts = false,
-      String packagesFile,
       Future<void> Function(exec.Executable) recompile,
       List<String> vmArgs = const [],
       @required bool alwaysUseSubprocess}) async {
@@ -382,7 +381,6 @@
       executable,
       args,
       enableAsserts: enableAsserts,
-      packagesFile: packagesFile,
       recompile: (exectuable) async {
         await recompile(exectuable);
         _refreshBinStubs(entrypoint, executable);
diff --git a/lib/src/lock_file.dart b/lib/src/lock_file.dart
index 23cf4e9..795dfc4 100644
--- a/lib/src/lock_file.dart
+++ b/lib/src/lock_file.dart
@@ -239,7 +239,7 @@
   /// Returns the contents of the `.dart_tools/package_config` file generated
   /// from this lockfile.
   ///
-  /// This file is planned to eventually replace the `.packages` file.
+  /// This file will replace the `.packages` file.
   ///
   /// If [entrypoint] is passed, an accompanying [entrypointSdkConstraint]
   /// should be given, these identify the current package in which this file is
diff --git a/test/downgrade/doesnt_change_git_dependencies_test.dart b/test/downgrade/doesnt_change_git_dependencies_test.dart
index 9f87792..1450af5 100644
--- a/test/downgrade/doesnt_change_git_dependencies_test.dart
+++ b/test/downgrade/doesnt_change_git_dependencies_test.dart
@@ -20,13 +20,13 @@
 
     await pubGet();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     await d.git('foo.git',
         [d.libDir('foo', 'foo 2'), d.libPubspec('foo', '1.0.0')]).commit();
 
     await pubDowngrade();
 
-    expect(packageSpecLine('foo'), originalFooSpec);
+    expect(packageSpec('foo'), originalFooSpec);
   });
 }
diff --git a/test/get/git/check_out_and_upgrade_test.dart b/test/get/git/check_out_and_upgrade_test.dart
index b2c8895..42044af 100644
--- a/test/get/git/check_out_and_upgrade_test.dart
+++ b/test/get/git/check_out_and_upgrade_test.dart
@@ -36,7 +36,7 @@
       ])
     ]).validate();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     await d.git('foo.git',
         [d.libDir('foo', 'foo 2'), d.libPubspec('foo', '1.0.0')]).commit();
@@ -53,6 +53,6 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo'), isNot(originalFooSpec));
+    expect(packageSpec('foo'), isNot(originalFooSpec));
   });
 }
diff --git a/test/get/git/check_out_revision_test.dart b/test/get/git/check_out_revision_test.dart
index 43a5849..2428d7c 100644
--- a/test/get/git/check_out_revision_test.dart
+++ b/test/get/git/check_out_revision_test.dart
@@ -36,6 +36,6 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo'), contains(commit));
+    expect(packageSpec('foo')['rootUri'], contains(commit));
   });
 }
diff --git a/test/get/git/check_out_test.dart b/test/get/git/check_out_test.dart
index 24484f9..0b902a6 100644
--- a/test/get/git/check_out_test.dart
+++ b/test/get/git/check_out_test.dart
@@ -33,7 +33,7 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo'), isNotNull);
+    expect(packageSpec('foo'), isNotNull);
   }, skip: true);
 
   test(
@@ -65,7 +65,7 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo'), isNotNull);
+    expect(packageSpec('foo'), isNotNull);
   });
 }
 
diff --git a/test/get/git/check_out_transitive_test.dart b/test/get/git/check_out_transitive_test.dart
index a505bb7..1e897fb 100644
--- a/test/get/git/check_out_transitive_test.dart
+++ b/test/get/git/check_out_transitive_test.dart
@@ -36,7 +36,7 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo'), isNotNull);
-    expect(packageSpecLine('bar'), isNotNull);
+    expect(packageSpec('foo'), isNotNull);
+    expect(packageSpec('bar'), isNotNull);
   });
 }
diff --git a/test/get/git/check_out_twice_test.dart b/test/get/git/check_out_twice_test.dart
index 8860db8..b6de388 100644
--- a/test/get/git/check_out_twice_test.dart
+++ b/test/get/git/check_out_twice_test.dart
@@ -27,7 +27,7 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo'), isNotNull);
+    expect(packageSpec('foo'), isNotNull);
 
     // Verify that nothing breaks if we get a Git revision that's already
     // in the cache.
diff --git a/test/get/git/check_out_unfetched_revision_of_cached_repo_test.dart b/test/get/git/check_out_unfetched_revision_of_cached_repo_test.dart
index 4e4732e..4b915df 100644
--- a/test/get/git/check_out_unfetched_revision_of_cached_repo_test.dart
+++ b/test/get/git/check_out_unfetched_revision_of_cached_repo_test.dart
@@ -29,7 +29,7 @@
 
     await pubGet();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     // Switch to a new cache.
     renameInSandbox(cachePath, '$cachePath.old');
@@ -56,6 +56,6 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo'), isNot(originalFooSpec));
+    expect(packageSpec('foo'), isNot(originalFooSpec));
   });
 }
diff --git a/test/get/git/different_repo_name_test.dart b/test/get/git/different_repo_name_test.dart
index 52cf3a5..1d8f9c4 100644
--- a/test/get/git/different_repo_name_test.dart
+++ b/test/get/git/different_repo_name_test.dart
@@ -24,6 +24,6 @@
 
     await pubGet();
 
-    expect(packageSpecLine('weirdname'), contains('foo'));
+    expect(packageSpec('weirdname')['rootUri'], contains('foo'));
   });
 }
diff --git a/test/get/git/doesnt_fetch_if_nothing_changes_test.dart b/test/get/git/doesnt_fetch_if_nothing_changes_test.dart
index 9d81081..69ae47f 100644
--- a/test/get/git/doesnt_fetch_if_nothing_changes_test.dart
+++ b/test/get/git/doesnt_fetch_if_nothing_changes_test.dart
@@ -25,7 +25,7 @@
 
     await pubGet();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     // Delete the repo. This will cause "pub get" to fail if it tries to
     // re-fetch.
@@ -33,6 +33,6 @@
 
     await pubGet();
 
-    expect(packageSpecLine('foo'), originalFooSpec);
+    expect(packageSpec('foo'), originalFooSpec);
   });
 }
diff --git a/test/get/git/lock_version_test.dart b/test/get/git/lock_version_test.dart
index b3efdb8..393a1d6 100644
--- a/test/get/git/lock_version_test.dart
+++ b/test/get/git/lock_version_test.dart
@@ -33,10 +33,10 @@
       ])
     ]).validate();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     // Delete the package spec to simulate a new checkout of the application.
-    deleteEntry(path.join(d.sandbox, packagesFilePath));
+    deleteEntry(path.join(d.sandbox, packageConfigFilePath));
 
     await d.git('foo.git',
         [d.libDir('foo', 'foo 2'), d.libPubspec('foo', '1.0.0')]).commit();
@@ -44,6 +44,6 @@
     // This get shouldn't upgrade the foo.git dependency due to the lockfile.
     await pubGet();
 
-    expect(packageSpecLine('foo'), originalFooSpec);
+    expect(packageSpec('foo'), originalFooSpec);
   });
 }
diff --git a/test/get/git/locked_revision_without_repo_test.dart b/test/get/git/locked_revision_without_repo_test.dart
index 907909b..27052b5 100644
--- a/test/get/git/locked_revision_without_repo_test.dart
+++ b/test/get/git/locked_revision_without_repo_test.dart
@@ -35,11 +35,11 @@
       ])
     ]).validate();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     // Delete the package spec and the cache to simulate a brand new checkout
     // of the application.
-    deleteEntry(path.join(d.sandbox, packagesFilePath));
+    deleteEntry(path.join(d.sandbox, packageConfigFilePath));
     deleteEntry(path.join(d.sandbox, cachePath));
 
     await d.git('foo.git',
@@ -48,6 +48,6 @@
     // This get shouldn't upgrade the foo.git dependency due to the lockfile.
     await pubGet();
 
-    expect(packageSpecLine('foo'), originalFooSpec);
+    expect(packageSpec('foo'), originalFooSpec);
   });
 }
diff --git a/test/get/git/stay_locked_if_compatible_test.dart b/test/get/git/stay_locked_if_compatible_test.dart
index acd7b05..d7f6eb9 100644
--- a/test/get/git/stay_locked_if_compatible_test.dart
+++ b/test/get/git/stay_locked_if_compatible_test.dart
@@ -22,7 +22,7 @@
 
     await pubGet();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     await d.git('foo.git',
         [d.libDir('foo', 'foo 1.0.1'), d.libPubspec('foo', '1.0.1')]).commit();
@@ -33,6 +33,6 @@
 
     await pubGet();
 
-    expect(packageSpecLine('foo'), originalFooSpec);
+    expect(packageSpec('foo'), originalFooSpec);
   });
 }
diff --git a/test/get/git/unlock_if_incompatible_test.dart b/test/get/git/unlock_if_incompatible_test.dart
index 53dc46d..61b60e6 100644
--- a/test/get/git/unlock_if_incompatible_test.dart
+++ b/test/get/git/unlock_if_incompatible_test.dart
@@ -31,7 +31,7 @@
       ])
     ]).validate();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     await d.git('foo.git',
         [d.libDir('foo', 'foo 2'), d.libPubspec('foo', '1.0.0')]).commit();
@@ -48,6 +48,6 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo'), isNot(originalFooSpec));
+    expect(packageSpec('foo'), isNot(originalFooSpec));
   });
 }
diff --git a/test/get/hosted/stay_locked_test.dart b/test/get/hosted/stay_locked_test.dart
index 972336d..ab03a76 100644
--- a/test/get/hosted/stay_locked_test.dart
+++ b/test/get/hosted/stay_locked_test.dart
@@ -23,8 +23,8 @@
 
     await d.appPackagesFile({'foo': '1.0.0'}).validate();
 
-    // Delete the .packages file to simulate a new checkout of the application.
-    deleteEntry(path.join(d.sandbox, packagesFilePath));
+    // Delete the .dart_tool/package_config.json file to simulate a new checkout of the application.
+    deleteEntry(path.join(d.sandbox, packageConfigFilePath));
 
     // Start serving a newer package as well.
     globalPackageServer.add((builder) => builder.serve('foo', '1.0.1'));
diff --git a/test/global/run/package_api_test.dart b/test/global/run/package_api_test.dart
index d72c711..0048e99 100644
--- a/test/global/run/package_api_test.dart
+++ b/test/global/run/package_api_test.dart
@@ -39,8 +39,8 @@
 
     expect(pub.stdout, emits('null'));
 
-    var packageConfigPath =
-        p.join(d.sandbox, cachePath, 'global_packages/foo/.packages');
+    var packageConfigPath = p.join(d.sandbox, cachePath,
+        'global_packages/foo/.dart_tool/package_config.json');
     expect(pub.stdout, emits(p.toUri(packageConfigPath).toString()));
 
     var fooResourcePath = p.join(
@@ -83,7 +83,8 @@
 
     expect(pub.stdout, emits('null'));
 
-    var packageConfigPath = p.join(d.sandbox, 'myapp/.packages');
+    var packageConfigPath =
+        p.join(d.sandbox, 'myapp/.dart_tool/package_config.json');
     expect(pub.stdout, emits(p.toUri(packageConfigPath).toString()));
 
     var myappResourcePath = p.join(d.sandbox, 'myapp/lib/resource.txt');
diff --git a/test/global/run/runs_script_without_packages_file_test.dart b/test/global/run/runs_script_without_packages_file_test.dart
index 421e200..3db1129 100644
--- a/test/global/run/runs_script_without_packages_file_test.dart
+++ b/test/global/run/runs_script_without_packages_file_test.dart
@@ -11,7 +11,8 @@
 import '../../test_pub.dart';
 
 void main() {
-  test('runs a snapshotted script without a .packages file', () async {
+  test('runs a snapshotted script without a .dart_tool/package_config file',
+      () async {
     await servePackages((builder) {
       builder.serve('foo', '1.0.0', contents: [
         d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
@@ -22,14 +23,17 @@
 
     // Mimic the global packages installed by pub <1.12, which didn't create a
     // .packages file for global installs.
-    deleteEntry(p.join(d.sandbox, cachePath, 'global_packages/foo/.packages'));
+    deleteEntry(p.join(d.sandbox, cachePath,
+        'global_packages/foo/.dart_tool/package_config.json'));
 
     var pub = await pubRun(global: true, args: ['foo:script']);
     expect(pub.stdout, emits('ok'));
     await pub.shouldExit();
   });
 
-  test('runs an unsnapshotted script without a .packages file', () async {
+  test(
+      'runs an unsnapshotted script without a .dart_tool/package_config.json file',
+      () async {
     await d.dir('foo', [
       d.libPubspec('foo', '1.0.0'),
       d.dir('bin', [d.file('foo.dart', "main() => print('ok');")])
@@ -37,7 +41,8 @@
 
     await runPub(args: ['global', 'activate', '--source', 'path', '../foo']);
 
-    deleteEntry(p.join(d.sandbox, cachePath, 'global_packages/foo/.packages'));
+    deleteEntry(p.join(d.sandbox, cachePath,
+        'global_packages/foo/.dart_tool/package_config.json'));
 
     var pub = await pubRun(global: true, args: ['foo']);
     expect(pub.stdout, emits('ok'));
diff --git a/test/must_pub_get_test.dart b/test/must_pub_get_test.dart
index d0f52ba..e228f55 100644
--- a/test/must_pub_get_test.dart
+++ b/test/must_pub_get_test.dart
@@ -40,14 +40,6 @@
           'No pubspec.lock file found, please run "pub get" first.');
     });
 
-    group("there's no .packages", () {
-      setUp(() {
-        deleteEntry(p.join(d.sandbox, 'myapp/.packages'));
-      });
-
-      _requiresPubGet('No .packages file found, please run "pub get" first.');
-    });
-
     group("there's no package_config.json", () {
       setUp(() {
         deleteEntry(p.join(d.sandbox, 'myapp/.dart_tool/package_config.json'));
@@ -487,8 +479,7 @@
       _runsSuccessfully();
     });
 
-    group(
-        "the lockfile is newer than .packages and package_config.json, but they're up-to-date",
+    group("the lockfile is newer than package_config.json, but it's up-to-date",
         () {
       setUp(() async {
         await d.dir(appPath, [
diff --git a/test/run/dartdev/package_api_test.dart b/test/run/dartdev/package_api_test.dart
index 484e370..5617401 100644
--- a/test/run/dartdev/package_api_test.dart
+++ b/test/run/dartdev/package_api_test.dart
@@ -36,8 +36,11 @@
     var pub = await pubRunFromDartDev(args: ['myapp:script']);
 
     expect(pub.stdout, emits('null'));
-    expect(pub.stdout,
-        emits(p.toUri(p.join(d.sandbox, 'myapp/.packages')).toString()));
+    expect(
+        pub.stdout,
+        emits(p
+            .toUri(p.join(d.sandbox, 'myapp/.dart_tool/package_config.json'))
+            .toString()));
     expect(pub.stdout,
         emits(p.toUri(p.join(d.sandbox, 'myapp/lib/resource.txt')).toString()));
     expect(pub.stdout,
@@ -63,8 +66,11 @@
     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()));
+    expect(
+        pub.stdout,
+        emits(p
+            .toUri(p.join(d.sandbox, 'myapp/.dart_tool/package_config.json'))
+            .toString()));
     expect(pub.stdout,
         emits(p.toUri(p.join(d.sandbox, 'myapp/lib/resource.txt')).toString()));
     var fooResourcePath = p.join(
diff --git a/test/run/package_api_test.dart b/test/run/package_api_test.dart
index 954f5b7..ed491e0 100644
--- a/test/run/package_api_test.dart
+++ b/test/run/package_api_test.dart
@@ -36,8 +36,11 @@
     var pub = await pubRun(args: ['bin/script']);
 
     expect(pub.stdout, emits('null'));
-    expect(pub.stdout,
-        emits(p.toUri(p.join(d.sandbox, 'myapp/.packages')).toString()));
+    expect(
+        pub.stdout,
+        emits(p
+            .toUri(p.join(d.sandbox, 'myapp/.dart_tool/package_config.json'))
+            .toString()));
     expect(pub.stdout,
         emits(p.toUri(p.join(d.sandbox, 'myapp/lib/resource.txt')).toString()));
     expect(pub.stdout,
@@ -63,8 +66,11 @@
     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()));
+    expect(
+        pub.stdout,
+        emits(p
+            .toUri(p.join(d.sandbox, 'myapp/.dart_tool/package_config.json'))
+            .toString()));
     expect(pub.stdout,
         emits(p.toUri(p.join(d.sandbox, 'myapp/lib/resource.txt')).toString()));
     var fooResourcePath = p.join(
diff --git a/test/test_pub.dart b/test/test_pub.dart
index c98dcb8..a63048d 100644
--- a/test/test_pub.dart
+++ b/test/test_pub.dart
@@ -65,14 +65,16 @@
 /// directory.
 const String appPath = 'myapp';
 
-/// The path of the ".packages" file in the mock app used for tests, relative
-/// to the sandbox directory.
-const String packagesFilePath = '$appPath/.packages';
+/// The path of the ".dart_tool/package_config.json" file in the mock app used
+/// for tests, relative to the sandbox directory.
+String packageConfigFilePath =
+    p.join(appPath, '.dart_tool', 'package_config.json');
 
-/// The line from the `.packages` file for [packageName].
-String packageSpecLine(String packageName) => File(d.path(packagesFilePath))
-    .readAsLinesSync()
-    .firstWhere((l) => l.startsWith('$packageName:'));
+/// The entry from the `.dart_tool/package_config.json` file for [packageName].
+Map<String, dynamic> packageSpec(String packageName) => json
+    .decode(File(d.path(packageConfigFilePath)).readAsStringSync())['packages']
+    .firstWhere((e) => e['name'] == packageName,
+        orElse: () => null) as Map<String, dynamic>;
 
 /// The suffix appended to a precompiled snapshot.
 final versionSuffix = testVersion ?? sdk.version;
diff --git a/test/upgrade/git/do_not_upgrade_if_unneeded_test.dart b/test/upgrade/git/do_not_upgrade_if_unneeded_test.dart
index 59b7aab..2b948b3 100644
--- a/test/upgrade/git/do_not_upgrade_if_unneeded_test.dart
+++ b/test/upgrade/git/do_not_upgrade_if_unneeded_test.dart
@@ -40,7 +40,7 @@
       ])
     ]).validate();
 
-    var originalFooDepSpec = packageSpecLine('foo_dep');
+    var originalFooDepSpec = packageSpec('foo_dep');
 
     await d.git('foo.git', [
       d.libDir('foo', 'foo 2'),
@@ -62,6 +62,6 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo_dep'), originalFooDepSpec);
+    expect(packageSpec('foo_dep'), originalFooDepSpec);
   });
 }
diff --git a/test/upgrade/git/upgrade_locked_test.dart b/test/upgrade/git/upgrade_locked_test.dart
index 6d8f63d..a8e744f 100644
--- a/test/upgrade/git/upgrade_locked_test.dart
+++ b/test/upgrade/git/upgrade_locked_test.dart
@@ -33,8 +33,8 @@
       ])
     ]).validate();
 
-    var originalFooSpec = packageSpecLine('foo');
-    var originalBarSpec = packageSpecLine('bar');
+    var originalFooSpec = packageSpec('foo');
+    var originalBarSpec = packageSpec('bar');
 
     await d.git('foo.git',
         [d.libDir('foo', 'foo 2'), d.libPubspec('foo', '1.0.0')]).commit();
@@ -51,7 +51,7 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('foo'), isNot(originalFooSpec));
-    expect(packageSpecLine('bar'), isNot(originalBarSpec));
+    expect(packageSpec('foo'), isNot(originalFooSpec));
+    expect(packageSpec('bar'), isNot(originalBarSpec));
   });
 }
diff --git a/test/upgrade/git/upgrade_one_locked_test.dart b/test/upgrade/git/upgrade_one_locked_test.dart
index b1cfa69..5c41fa6 100644
--- a/test/upgrade/git/upgrade_one_locked_test.dart
+++ b/test/upgrade/git/upgrade_one_locked_test.dart
@@ -33,7 +33,7 @@
       ])
     ]).validate();
 
-    var originalBarSpec = packageSpecLine('bar');
+    var originalBarSpec = packageSpec('bar');
 
     await d.git('foo.git',
         [d.libDir('foo', 'foo 2'), d.libPubspec('foo', '1.0.0')]).commit();
@@ -49,6 +49,6 @@
       ])
     ]).validate();
 
-    expect(packageSpecLine('bar'), originalBarSpec);
+    expect(packageSpec('bar'), originalBarSpec);
   });
 }
diff --git a/test/upgrade/git/upgrade_to_incompatible_pubspec_test.dart b/test/upgrade/git/upgrade_to_incompatible_pubspec_test.dart
index bda2003..4dcef66 100644
--- a/test/upgrade/git/upgrade_to_incompatible_pubspec_test.dart
+++ b/test/upgrade/git/upgrade_to_incompatible_pubspec_test.dart
@@ -31,7 +31,7 @@
       ])
     ]).validate();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     await d.git(
         'foo.git', [d.libDir('zoo'), d.libPubspec('zoo', '1.0.0')]).commit();
@@ -40,6 +40,6 @@
         error: contains('"name" field doesn\'t match expected name "foo".'),
         exitCode: exit_codes.DATA);
 
-    expect(packageSpecLine('foo'), originalFooSpec);
+    expect(packageSpec('foo'), originalFooSpec);
   });
 }
diff --git a/test/upgrade/git/upgrade_to_nonexistent_pubspec_test.dart b/test/upgrade/git/upgrade_to_nonexistent_pubspec_test.dart
index f3f5eef..ae865eb 100644
--- a/test/upgrade/git/upgrade_to_nonexistent_pubspec_test.dart
+++ b/test/upgrade/git/upgrade_to_nonexistent_pubspec_test.dart
@@ -21,7 +21,7 @@
 
     await pubGet();
 
-    var originalFooSpec = packageSpecLine('foo');
+    var originalFooSpec = packageSpec('foo');
 
     await repo.runGit(['rm', 'pubspec.yaml']);
     await repo.runGit(['commit', '-m', 'delete']);
@@ -30,6 +30,6 @@
         error: RegExp(r'Could not find a file named "pubspec.yaml" '
             r'in [^\n]*\.'));
 
-    expect(packageSpecLine('foo'), originalFooSpec);
+    expect(packageSpec('foo'), originalFooSpec);
   });
 }