Revert "Merge dependency services (#3303)"

This reverts commit 0a6252c80bfc599bc7fc1d19798aa62537643193.
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 6177eba..f469a93 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,4 +1,4 @@
-include: package:lints/recommended.yaml
+include: package:pedantic/analysis_options.yaml
 
 analyzer:
   errors:
@@ -12,27 +12,52 @@
 linter:
   rules:
     - avoid_catching_errors
+    - avoid_function_literals_in_foreach_calls
     - avoid_private_typedef_functions
     - avoid_redundant_argument_values
+    - avoid_renaming_method_parameters
     - avoid_returning_null_for_future
+    - avoid_returning_null_for_void
     - avoid_unused_constructor_parameters
     - avoid_void_async
+    - await_only_futures
+    - camel_case_types
     - cancel_subscriptions
+    - control_flow_in_finally
     - directives_ordering
+    - empty_statements
+    - file_names
+    - implementation_imports
+    - iterable_contains_unrelated_type
+    - list_remove_unrelated_type
     - missing_whitespace_between_adjacent_strings
     - no_adjacent_strings_in_list
     - no_runtimeType_toString
+    - non_constant_identifier_names
     - only_throw_errors
+    - overridden_fields
     - package_api_docs
+    - package_names
+    - package_prefixed_library_names
     - prefer_asserts_in_initializer_lists
     - prefer_const_declarations
+    - prefer_function_declarations_over_variables
+    - prefer_initializing_formals
+    - prefer_inlined_adds
+    - prefer_is_not_operator
+    - prefer_null_aware_operators
     - prefer_relative_imports
-    - prefer_single_quotes
+    - prefer_typing_uninitialized_variables
+    - prefer_void_to_null
     - sort_pub_dependencies
     - test_types_in_equals
     - throw_in_finally
-    - unawaited_futures
+    - unnecessary_brace_in_string_interps
+    - unnecessary_getters_setters
     - unnecessary_lambdas
     - unnecessary_null_aware_assignments
+    - unnecessary_overrides
     - unnecessary_parenthesis
     - unnecessary_statements
+    - unnecessary_string_interpolations
+    - void_checks
diff --git a/bin/dependency_services.dart b/bin/dependency_services.dart
index 1e7b4c1..3b73165 100644
--- a/bin/dependency_services.dart
+++ b/bin/dependency_services.dart
@@ -97,7 +97,7 @@
   }
 
   @override
-  log.Verbosity get verbosity => log.Verbosity.normal;
+  log.Verbosity get verbosity => log.Verbosity.NORMAL;
 }
 
 Future<void> main(List<String> arguments) async {
diff --git a/doc/repository-spec-v2.md b/doc/repository-spec-v2.md
index 6ddfd0f..6db7763 100644
--- a/doc/repository-spec-v2.md
+++ b/doc/repository-spec-v2.md
@@ -227,7 +227,7 @@
   "replacedBy": "<package>", /* optional field, if isDiscontinued == true */
   "latest": {
     "version": "<version>",
-    "retracted": true || false, /* optional field, false if omitted */
+    "isRetracted": true || false, /* optional field, false if omitted */
     "archive_url": "https://.../archive.tar.gz",
     "pubspec": {
       /* pubspec contents as JSON object */
@@ -236,7 +236,7 @@
   "versions": [
     {
       "version": "<package>",
-      "retracted": true || false, /* optional field, false if omitted */
+      "isRetracted": true || false, /* optional field, false if omitted */
       "archive_url": "https://.../archive.tar.gz",
       "pubspec": {
         /* pubspec contents as JSON object */
@@ -371,9 +371,7 @@
 archive size, or enforce any other repository specific constraints.
 
 This upload flow allows for archives to be uploaded directly to a signed POST
-URL for [S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/HTTPPOSTExamples.html),
-[GCS](https://cloud.google.com/storage/docs/xml-api/post-object-forms) or
-similar blob storage service. Both the
+URL for S3, GCS or similar blob storage service. Both the
 `<multipart-upload-url>` and `<finalize-upload-url>` is allowed to contain
 query-string parameters, and both of these URLs need only be temporary.
 
diff --git a/lib/pub.dart b/lib/pub.dart
index 71de9d6..5b3054f 100644
--- a/lib/pub.dart
+++ b/lib/pub.dart
@@ -18,12 +18,8 @@
 ///
 /// If [analytics] is given, pub will use that analytics instance to send
 /// statistics about resolutions.
-///
-/// [isVerbose] should return `true` (after argument resolution) if the
-/// embedding top-level is in verbose mode.
-Command<int> pubCommand(
-        {PubAnalytics? analytics, required bool Function() isVerbose}) =>
-    PubEmbeddableCommand(analytics, isVerbose);
+Command<int> pubCommand({PubAnalytics? analytics}) =>
+    PubEmbeddableCommand(analytics);
 
 /// Support for the `pub` toplevel command.
 @Deprecated('Use [pubCommand] instead.')
diff --git a/lib/src/authentication/client.dart b/lib/src/authentication/client.dart
index a6001ec..1f37149 100644
--- a/lib/src/authentication/client.dart
+++ b/lib/src/authentication/client.dart
@@ -8,6 +8,7 @@
 import 'package:http/http.dart' as http;
 import 'package:http_parser/http_parser.dart';
 
+import '../exceptions.dart';
 import '../http.dart';
 import '../log.dart' as log;
 import '../system_cache.dart';
@@ -21,17 +22,14 @@
   /// Constructs Http client wrapper that injects `authorization` header to
   /// requests and handles authentication errors.
   ///
-  /// [_credential] might be `null`. In that case `authorization` header will not
+  /// [credential] might be `null`. In that case `authorization` header will not
   /// be injected to requests.
-  _AuthenticatedClient(this._inner, this._credential);
+  _AuthenticatedClient(this._inner, this.credential);
 
   final http.BaseClient _inner;
 
   /// Authentication scheme that could be used for authenticating requests.
-  final Credential? _credential;
-
-  /// Detected that [_credential] are invalid, happens when server responds 401.
-  bool _detectInvalidCredentials = false;
+  final Credential? credential;
 
   @override
   Future<http.StreamedResponse> send(http.BaseRequest request) async {
@@ -42,16 +40,15 @@
     // to given serverBaseUrl. Otherwise credential leaks might ocurr when
     // archive_url hosted on 3rd party server that should not receive
     // credentials of the first party.
-    if (_credential != null &&
-        _credential!.canAuthenticate(request.url.toString())) {
+    if (credential != null &&
+        credential!.canAuthenticate(request.url.toString())) {
       request.headers[HttpHeaders.authorizationHeader] =
-          await _credential!.getAuthorizationHeaderValue();
+          await credential!.getAuthorizationHeaderValue();
     }
 
     try {
       final response = await _inner.send(request);
       if (response.statusCode == 401) {
-        _detectInvalidCredentials = true;
         _throwAuthException(response);
       }
       return response;
@@ -127,17 +124,31 @@
   Future<T> Function(http.Client) fn,
 ) async {
   final credential = systemCache.tokenStore.findCredential(hostedUrl);
-  final client = _AuthenticatedClient(httpClient, credential);
+  final http.Client client = _AuthenticatedClient(httpClient, credential);
 
   try {
     return await fn(client);
-  } finally {
-    if (client._detectInvalidCredentials) {
-      // try to remove the credential, if we detected that it is invalid!
-      final removed = systemCache.tokenStore.removeCredential(hostedUrl);
-      if (removed) {
+  } on AuthenticationException catch (error) {
+    var message = '';
+
+    if (error.statusCode == 401) {
+      if (systemCache.tokenStore.removeCredential(hostedUrl)) {
         log.warning('Invalid token for $hostedUrl deleted.');
       }
+      message = '$hostedUrl package repository requested authentication! '
+          'You can provide credential using:\n'
+          '    pub token add $hostedUrl';
     }
+    if (error.statusCode == 403) {
+      message = 'Insufficient permissions to the resource in $hostedUrl '
+          'package repository. You can modify credential using:\n'
+          '    pub token add $hostedUrl';
+    }
+
+    if (error.serverMessage?.isNotEmpty == true) {
+      message += '\n${error.serverMessage}';
+    }
+
+    throw DataException(message);
   }
 }
diff --git a/lib/src/command.dart b/lib/src/command.dart
index ee62392..ea3c2d3 100644
--- a/lib/src/command.dart
+++ b/lib/src/command.dart
@@ -10,15 +10,16 @@
 import 'package:collection/collection.dart' show IterableExtension;
 import 'package:http/http.dart' as http;
 import 'package:meta/meta.dart';
-import 'package:path/path.dart' as p;
 
 import 'authentication/token_store.dart';
+import 'command_runner.dart';
 import 'entrypoint.dart';
 import 'exceptions.dart';
 import 'exit_codes.dart' as exit_codes;
 import 'git.dart' as git;
 import 'global_packages.dart';
 import 'http.dart';
+import 'io.dart';
 import 'log.dart' as log;
 import 'pub_embeddable_command.dart';
 import 'sdk.dart';
@@ -55,11 +56,7 @@
     return a;
   }
 
-  String get directory =>
-      (argResults.options.contains('directory')
-          ? argResults['directory']
-          : null) ??
-      _pubTopLevel.directory;
+  String get directory => argResults['directory'] ?? _pubTopLevel.directory;
 
   late final SystemCache cache = SystemCache(isOffline: isOffline);
 
@@ -174,11 +171,12 @@
   @nonVirtual
   FutureOr<int> run() async {
     computeCommand(_pubTopLevel.argResults);
-
+    if (_pubTopLevel.trace) {
+      log.recordTranscript();
+    }
     log.verbosity = _pubTopLevel.verbosity;
     log.fine('Pub ${sdk.version}');
 
-    var crashed = false;
     try {
       await captureErrors<void>(() async => runProtected(),
           captureStackChains: _pubTopLevel.captureStackChains);
@@ -190,61 +188,31 @@
       log.exception(error, chain);
 
       if (_pubTopLevel.trace) {
-        log.dumpTranscriptToStdErr();
+        log.dumpTranscript();
       } else if (!isUserFacingException(error)) {
-        log.error('''
-This is an unexpected error. The full log and other details are collected in:
+        log.error("""
+This is an unexpected error. Please run
 
-    $transcriptPath
+    dart pub --trace ${_topCommand.name} ${_topCommand.argResults!.arguments.map(protectArgument).join(' ')}
 
-Consider creating an issue on https://github.com/dart-lang/pub/issues/new
-and attaching the relevant parts of that log file.
-''');
-        crashed = true;
+and include the logs in an issue on https://github.com/dart-lang/pub/issues/new
+""");
       }
       return _chooseExitCode(error);
     } finally {
-      final verbose = _pubTopLevel.verbosity == log.Verbosity.all;
-
-      // Write the whole log transcript to file.
-      if (verbose || crashed) {
-        // Escape the argument for users to copy-paste in bash.
-        // Wrap with single quotation, and use '\'' to insert single quote, as
-        // long as we have no spaces this doesn't create a new argument.
-        String protectArgument(String x) =>
-            RegExp(r'^[a-zA-Z0-9-_]+$').stringMatch(x) == null
-                ? "'${x.replaceAll("'", r"'\''")}'"
-                : x;
-
-        late final Entrypoint? e;
-        try {
-          e = entrypoint;
-        } on ApplicationException {
-          e = null;
-        }
-        log.dumpTranscriptToFile(
-          transcriptPath,
-          'dart pub ${_topCommand.argResults!.arguments.map(protectArgument).join(' ')}',
-          e,
-        );
-
-        if (!crashed) {
-          log.message('Logs written to $transcriptPath.');
-        }
-      }
       httpClient.close();
     }
   }
 
   /// Returns the appropriate exit code for [exception], falling back on 1 if no
   /// appropriate exit code could be found.
-  int _chooseExitCode(Object exception) {
+  int _chooseExitCode(exception) {
     if (exception is SolveFailure) {
       var packageNotFound = exception.packageNotFound;
       if (packageNotFound != null) exception = packageNotFound;
     }
     while (exception is WrappedException && exception.innerError is Exception) {
-      exception = exception.innerError!;
+      exception = exception.innerError;
     }
 
     if (exception is HttpException ||
@@ -314,10 +282,6 @@
     }
     _command = list.join(' ');
   }
-
-  String get transcriptPath {
-    return p.join(cache.rootDir, 'log', 'pub_log.txt');
-  }
 }
 
 abstract class PubTopLevel {
diff --git a/lib/src/command/add.dart b/lib/src/command/add.dart
index 3557104..09cc426 100644
--- a/lib/src/command/add.dart
+++ b/lib/src/command/add.dart
@@ -13,7 +13,6 @@
 import '../exceptions.dart';
 import '../git.dart';
 import '../io.dart';
-import '../language_version.dart';
 import '../log.dart' as log;
 import '../package.dart';
 import '../package_name.dart';
@@ -34,10 +33,9 @@
   @override
   String get name => 'add';
   @override
-  String get description => 'Add dependencies to pubspec.yaml.';
+  String get description => 'Add a dependency to pubspec.yaml.';
   @override
-  String get argumentsDescription =>
-      '<package>[:<constraint>] [<package2>[:<constraint2>]...] [options]';
+  String get argumentsDescription => '<package>[:<constraint>] [options]';
   @override
   String get docUrl => 'https://dart.dev/tools/pub/cmd/pub-add';
   @override
@@ -55,24 +53,19 @@
   bool get hasGitOptions => gitUrl != null || gitRef != null || gitPath != null;
   bool get hasHostOptions => hostUrl != null;
 
-  bool get isHosted => !hasGitOptions && path == null && path == null;
-
   AddCommand() {
     argParser.addFlag('dev',
         abbr: 'd',
         negatable: false,
-        help: 'Adds to the development dependencies instead.');
+        help: 'Adds package to the development dependencies instead.');
 
     argParser.addOption('git-url', help: 'Git URL of the package');
     argParser.addOption('git-ref',
         help: 'Git branch or commit to be retrieved');
     argParser.addOption('git-path', help: 'Path of git package in repository');
     argParser.addOption('hosted-url', help: 'URL of package host server');
-    argParser.addOption('path', help: 'Add package from local path');
-    argParser.addOption('sdk',
-        help: 'add package from SDK source',
-        allowed: ['flutter'],
-        valueHelp: '[flutter]');
+    argParser.addOption('path', help: 'Local path');
+    argParser.addOption('sdk', help: 'SDK source for package');
     argParser.addFlag(
       'example',
       help:
@@ -91,30 +84,23 @@
     argParser.addFlag('precompile',
         help: 'Build executables in immediate dependencies.');
     argParser.addOption('directory',
-        abbr: 'C', help: 'Run this in the directory <dir>.', valueHelp: 'dir');
-    argParser.addFlag('legacy-packages-file',
-        help: 'Generate the legacy ".packages" file', negatable: false);
+        abbr: 'C', help: 'Run this in the directory<dir>.', valueHelp: 'dir');
   }
 
   @override
   Future<void> runProtected() async {
     if (argResults.rest.isEmpty) {
-      usageException('Must specify at least one package to be added.');
-    } else if (argResults.rest.length > 1 && gitUrl != null) {
-      usageException('Can only add a single git package at a time.');
-    } else if (argResults.rest.length > 1 && path != null) {
-      usageException('Can only add a single local package at a time.');
+      usageException('Must specify a package to be added.');
+    } else if (argResults.rest.length > 1) {
+      usageException('Takes only a single argument.');
     }
-    final languageVersion = entrypoint.root.pubspec.languageVersion;
-    final updates =
-        argResults.rest.map((p) => _parsePackage(p, languageVersion)).toList();
 
-    var updatedPubSpec = entrypoint.root.pubspec;
-    for (final update in updates) {
-      /// Perform version resolution in-memory.
-      updatedPubSpec =
-          await _addPackageToPubspec(updatedPubSpec, update.packageRange);
-    }
+    final packageInformation = _parsePackage(argResults.rest.first);
+    final package = packageInformation.first;
+
+    /// Perform version resolution in-memory.
+    final updatedPubSpec =
+        await _addPackageToPubspec(entrypoint.root.pubspec, package);
 
     late SolveResult solveResult;
 
@@ -125,11 +111,9 @@
       /// that a resolution exists before we update pubspec.yaml.
       // TODO(sigurdm): We should really use a spinner here.
       solveResult = await resolveVersions(
-          SolveType.upgrade, cache, Package.inMemory(updatedPubSpec));
+          SolveType.UPGRADE, cache, Package.inMemory(updatedPubSpec));
     } on GitException {
-      final packageRange = updates.first.packageRange;
-      dataError(
-          'Unable to resolve package "${packageRange.name}" with the given '
+      dataError('Unable to resolve package "${package.name}" with the given '
           'git parameters.');
     } on SolveFailure catch (e) {
       dataError(e.message);
@@ -138,63 +122,59 @@
       dataError(e.message);
     }
 
-    /// Verify the results for each package.
-    for (final update in updates) {
-      final packageRange = update.packageRange;
-      final name = packageRange.name;
-      final resultPackage = solveResult.packages
-          .firstWhere((packageId) => packageId.name == name);
+    final resultPackage = solveResult.packages
+        .firstWhere((packageId) => packageId.name == package.name);
 
-      /// Assert that [resultPackage] is within the original user's expectations.
-      var constraint = packageRange.constraint;
-      if (!constraint.allows(resultPackage.version)) {
-        var dependencyOverrides = updatedPubSpec.dependencyOverrides;
-        if (dependencyOverrides.isNotEmpty) {
-          dataError('"$name" resolved to "${resultPackage.version}" which '
-              'does not satisfy constraint "$constraint". This could be '
-              'caused by "dependency_overrides".');
-        }
-        dataError('"$name" resolved to "${resultPackage.version}" which '
-            'does not satisfy constraint "$constraint".');
+    /// Assert that [resultPackage] is within the original user's expectations.
+    var constraint = package.constraint;
+    if (!constraint.allows(resultPackage.version)) {
+      var dependencyOverrides = updatedPubSpec.dependencyOverrides;
+      if (dependencyOverrides.isNotEmpty) {
+        dataError(
+            '"${package.name}" resolved to "${resultPackage.version}" which '
+            'does not satisfy constraint "${package.constraint}". This could be '
+            'caused by "dependency_overrides".');
       }
+      dataError(
+          '"${package.name}" resolved to "${resultPackage.version}" which '
+          'does not satisfy constraint "${package.constraint}".');
     }
+
     if (isDryRun) {
       /// Even if it is a dry run, run `acquireDependencies` so that the user
       /// gets a report on the other packages that might change version due
       /// to this new dependency.
       final newRoot = Package.inMemory(updatedPubSpec);
 
-      await Entrypoint.inMemory(newRoot, cache,
-              solveResult: solveResult, lockFile: entrypoint.lockFile)
-          .acquireDependencies(SolveType.get,
+      // TODO(jonasfj): Stop abusing Entrypoint.global for dry-run output
+      await Entrypoint.global(newRoot, entrypoint.lockFile, cache,
+              solveResult: solveResult)
+          .acquireDependencies(SolveType.GET,
               dryRun: true,
               precompile: argResults['precompile'],
-              analytics: analytics,
-              generateDotPackages: false);
+              analytics: analytics);
     } else {
       /// Update the `pubspec.yaml` before calling [acquireDependencies] to
       /// ensure that the modification timestamp on `pubspec.lock` and
       /// `.dart_tool/package_config.json` is newer than `pubspec.yaml`,
       /// ensuring that [entrypoint.assertUptoDate] will pass.
-      _updatePubspec(solveResult.packages, updates, isDev);
+      _updatePubspec(resultPackage, packageInformation, isDev);
 
       /// Create a new [Entrypoint] since we have to reprocess the updated
       /// pubspec file.
       final updatedEntrypoint = Entrypoint(directory, cache);
       await updatedEntrypoint.acquireDependencies(
-        SolveType.get,
+        SolveType.GET,
         precompile: argResults['precompile'],
         analytics: analytics,
-        generateDotPackages: argResults['legacy-packages-file'],
       );
 
       if (argResults['example'] && entrypoint.example != null) {
         await entrypoint.example!.acquireDependencies(
-          SolveType.get,
+          SolveType.GET,
           precompile: argResults['precompile'],
           onlyReportSuccessOrFailure: true,
           analytics: analytics,
-          generateDotPackages: argResults['legacy-packages-file'],
         );
       }
     }
@@ -294,7 +274,9 @@
   ///
   /// If any of the other git options are defined when `--git-url` is not
   /// defined, an error will be thrown.
-  _ParseResult _parsePackage(String package, LanguageVersion languageVersion) {
+  Pair<PackageRange, dynamic> _parsePackage(String package) {
+    ArgumentError.checkNotNull(package, 'package');
+
     final _conflictingFlagSets = [
       ['git-url', 'git-ref', 'git-path'],
       ['hosted-url'],
@@ -398,18 +380,13 @@
           .withConstraint(constraint ?? VersionConstraint.any);
       pubspecInformation = {'sdk': sdk};
     } else {
-      // Hosted
-      final Object? hostInfo;
-      if (hasHostOptions) {
-        hostInfo = languageVersion.supportsShorterHostedSyntax
-            ? hostUrl
-            : {'url': hostUrl, 'name': packageName};
-        pubspecInformation = {
-          'hosted': hostInfo,
-        };
-      } else {
-        hostInfo = null;
+      final hostInfo =
+          hasHostOptions ? {'url': hostUrl, 'name': packageName} : null;
+
+      if (hostInfo == null) {
         pubspecInformation = constraint?.toString();
+      } else {
+        pubspecInformation = {'hosted': hostInfo};
       }
 
       packageRange = cache.hosted.source
@@ -431,64 +408,66 @@
       };
     }
 
-    return _ParseResult(packageRange, pubspecInformation);
+    return Pair(packageRange, pubspecInformation);
   }
 
   /// Writes the changes to the pubspec file.
-  void _updatePubspec(List<PackageId> resultPackages,
-      List<_ParseResult> updates, bool isDevelopment) {
+  void _updatePubspec(PackageId resultPackage,
+      Pair<PackageRange, dynamic> packageInformation, bool isDevelopment) {
+    ArgumentError.checkNotNull(resultPackage, 'resultPackage');
+    ArgumentError.checkNotNull(packageInformation, 'pubspecInformation');
+
+    final package = packageInformation.first;
+    var pubspecInformation = packageInformation.last;
+
+    if ((sdk != null || hasHostOptions) &&
+        pubspecInformation is Map &&
+        pubspecInformation['version'] == null) {
+      /// We cannot simply assign the value of version since it is likely that
+      /// [pubspecInformation] takes on the type
+      /// [Map<String, Map<String, String>>]
+      pubspecInformation = {
+        ...pubspecInformation,
+        'version': '^${resultPackage.version}'
+      };
+    }
+
+    final dependencyKey = isDevelopment ? 'dev_dependencies' : 'dependencies';
+    final packagePath = [dependencyKey, package.name];
+
     final yamlEditor = YamlEditor(readTextFile(entrypoint.pubspecPath));
     log.io('Reading ${entrypoint.pubspecPath}.');
     log.fine('Contents:\n$yamlEditor');
 
-    for (final update in updates) {
-      final packageRange = update.packageRange;
-      final name = packageRange.name;
-      final resultId = resultPackages.firstWhere((id) => id.name == name);
-      var description = update.description;
+    /// Handle situations where the user might not have the dependencies or
+    /// dev_dependencies map.
+    if (yamlEditor.parseAt([dependencyKey],
+            orElse: () => YamlScalar.wrap(null)).value ==
+        null) {
+      yamlEditor.update([dependencyKey],
+          {package.name: pubspecInformation ?? '^${resultPackage.version}'});
+    } else {
+      yamlEditor.update(
+          packagePath, pubspecInformation ?? '^${resultPackage.version}');
+    }
 
-      if (isHosted) {
-        final inferredConstraint =
-            VersionConstraint.compatibleWith(resultId.version).toString();
-        if (description == null) {
-          description = inferredConstraint;
-        } else if (description is Map && description['version'] == null) {
-          /// We cannot simply assign the value of version since it is likely that
-          /// [description] takes on the type
-          /// [Map<String, Map<String, String>>]
-          description = {...description, 'version': '^${resultId.version}'};
+    log.fine('Added ${package.name} to "$dependencyKey".');
+
+    /// Remove the package from dev_dependencies if we are adding it to
+    /// dependencies. Refer to [_addPackageToPubspec] for additional discussion.
+    if (!isDevelopment) {
+      final devDependenciesNode = yamlEditor
+          .parseAt(['dev_dependencies'], orElse: () => YamlScalar.wrap(null));
+
+      if (devDependenciesNode is YamlMap &&
+          devDependenciesNode.containsKey(package.name)) {
+        if (devDependenciesNode.length == 1) {
+          yamlEditor.remove(['dev_dependencies']);
+        } else {
+          yamlEditor.remove(['dev_dependencies', package.name]);
         }
-      }
 
-      final dependencyKey = isDevelopment ? 'dev_dependencies' : 'dependencies';
-      final packagePath = [dependencyKey, name];
-
-      /// Ensure we have a [dependencyKey] map in the `pubspec.yaml`.
-      if (yamlEditor.parseAt([dependencyKey],
-              orElse: () => YamlScalar.wrap(null)).value ==
-          null) {
-        yamlEditor.update([dependencyKey], {});
-      }
-      yamlEditor.update(packagePath, description);
-
-      log.fine('Added ${packageRange.name} to "$dependencyKey".');
-
-      /// Remove the package from dev_dependencies if we are adding it to
-      /// dependencies. Refer to [_addPackageToPubspec] for additional discussion.
-      if (!isDevelopment) {
-        final devDependenciesNode = yamlEditor
-            .parseAt(['dev_dependencies'], orElse: () => YamlScalar.wrap(null));
-
-        if (devDependenciesNode is YamlMap &&
-            devDependenciesNode.containsKey(name)) {
-          if (devDependenciesNode.length == 1) {
-            yamlEditor.remove(['dev_dependencies']);
-          } else {
-            yamlEditor.remove(['dev_dependencies', name]);
-          }
-
-          log.fine('Removed $name from "dev_dependencies".');
-        }
+        log.fine('Removed ${package.name} from "dev_dependencies".');
       }
     }
 
@@ -496,9 +475,3 @@
     writeTextFile(entrypoint.pubspecPath, yamlEditor.toString());
   }
 }
-
-class _ParseResult {
-  PackageRange packageRange;
-  Object? description;
-  _ParseResult(this.packageRange, this.description);
-}
diff --git a/lib/src/command/cache_repair.dart b/lib/src/command/cache_repair.dart
index 74968be..41bae2b 100644
--- a/lib/src/command/cache_repair.dart
+++ b/lib/src/command/cache_repair.dart
@@ -23,8 +23,6 @@
 
   @override
   Future<void> runProtected() async {
-    // Delete any eventual temp-files left in the cache.
-    cache.deleteTempDir();
     // Repair every cached source.
     final repairResults = (await Future.wait(
             cache.sources.all.map(cache.source).map((source) async {
diff --git a/lib/src/command/dependency_services.dart b/lib/src/command/dependency_services.dart
index 161a352..ca5c247 100644
--- a/lib/src/command/dependency_services.dart
+++ b/lib/src/command/dependency_services.dart
@@ -93,7 +93,7 @@
       }
 
       final resolution = await tryResolveVersions(
-        SolveType.get,
+        SolveType.GET,
         cache,
         Package.inMemory(pubspec),
         lockFile: lockFile,
@@ -210,7 +210,7 @@
 /// resolution was found.
 Future<List<PackageId>?> _tryResolve(Pubspec pubspec, SystemCache cache) async {
   final solveResult = await tryResolveVersions(
-    SolveType.upgrade,
+    SolveType.UPGRADE,
     cache,
     Package.inMemory(pubspec),
   );
@@ -346,8 +346,8 @@
     await log.warningsOnlyUnlessTerminal(
       () async {
         // This will fail if the new configuration does not resolve.
-        await Entrypoint(directory, cache).acquireDependencies(SolveType.get,
-            analytics: null, generateDotPackages: false);
+        await Entrypoint(directory, cache)
+            .acquireDependencies(SolveType.GET, analytics: null);
       },
     );
     // Dummy message.
diff --git a/lib/src/command/downgrade.dart b/lib/src/command/downgrade.dart
index fce5ef3..5dd9d41 100644
--- a/lib/src/command/downgrade.dart
+++ b/lib/src/command/downgrade.dart
@@ -42,8 +42,6 @@
 
     argParser.addOption('directory',
         abbr: 'C', help: 'Run this in the directory<dir>.', valueHelp: 'dir');
-    argParser.addFlag('legacy-packages-file',
-        help: 'Generate the legacy ".packages" file', negatable: false);
   }
 
   @override
@@ -55,21 +53,19 @@
     var dryRun = argResults['dry-run'];
 
     await entrypoint.acquireDependencies(
-      SolveType.downgrade,
+      SolveType.DOWNGRADE,
       unlock: argResults.rest,
       dryRun: dryRun,
       analytics: analytics,
-      generateDotPackages: argResults['legacy-packages-file'],
     );
     var example = entrypoint.example;
     if (argResults['example'] && example != null) {
       await example.acquireDependencies(
-        SolveType.get,
+        SolveType.GET,
         unlock: argResults.rest,
         dryRun: dryRun,
         onlyReportSuccessOrFailure: true,
         analytics: analytics,
-        generateDotPackages: argResults['legacy-packages-file'],
       );
     }
 
diff --git a/lib/src/command/get.dart b/lib/src/command/get.dart
index 7b8906c..9255e1e 100644
--- a/lib/src/command/get.dart
+++ b/lib/src/command/get.dart
@@ -33,9 +33,6 @@
 
     argParser.addFlag('packages-dir', hide: true);
 
-    argParser.addFlag('legacy-packages-file',
-        help: 'Generate the legacy ".packages" file', negatable: false);
-
     argParser.addFlag(
       'example',
       help: 'Also run in `example/` (if it exists).',
@@ -53,23 +50,19 @@
           'The --packages-dir flag is no longer used and does nothing.'));
     }
     await entrypoint.acquireDependencies(
-      SolveType.get,
+      SolveType.GET,
       dryRun: argResults['dry-run'],
       precompile: argResults['precompile'],
-      generateDotPackages: argResults['legacy-packages-file'],
       analytics: analytics,
     );
 
     var example = entrypoint.example;
     if (argResults['example'] && example != null) {
-      await example.acquireDependencies(
-        SolveType.get,
-        dryRun: argResults['dry-run'],
-        precompile: argResults['precompile'],
-        generateDotPackages: argResults['legacy-packages-file'],
-        analytics: analytics,
-        onlyReportSuccessOrFailure: true,
-      );
+      await example.acquireDependencies(SolveType.GET,
+          dryRun: argResults['dry-run'],
+          precompile: argResults['precompile'],
+          onlyReportSuccessOrFailure: true,
+          analytics: analytics);
     }
   }
 }
diff --git a/lib/src/command/lish.dart b/lib/src/command/lish.dart
index c927e07..325d482 100644
--- a/lib/src/command/lish.dart
+++ b/lib/src/command/lish.dart
@@ -91,7 +91,7 @@
 
     try {
       await log.progress('Uploading', () async {
-        var newUri = server.resolve('api/packages/versions/new');
+        var newUri = server.resolve('/api/packages/versions/new');
         var response = await client.get(newUri, headers: pubApiHeaders);
         var parameters = parseJsonResponse(response);
 
@@ -120,22 +120,6 @@
         handleJsonSuccess(
             await client.get(Uri.parse(location), headers: pubApiHeaders));
       });
-    } on AuthenticationException catch (error) {
-      var msg = '';
-      if (error.statusCode == 401) {
-        msg += '$server package repository requested authentication!\n'
-            'You can provide credentials using:\n'
-            '    pub token add $server\n';
-      }
-      if (error.statusCode == 403) {
-        msg += 'Insufficient permissions to the resource at the $server '
-            'package repository.\nYou can modify credentials using:\n'
-            '    pub token add $server\n';
-      }
-      if (error.serverMessage != null) {
-        msg += '\n' + error.serverMessage! + '\n';
-      }
-      dataError(msg + log.red('Authentication failed!'));
     } on PubHttpException catch (error) {
       var url = error.response.request!.url;
       if (url == cloudStorageUrl) {
diff --git a/lib/src/command/outdated.dart b/lib/src/command/outdated.dart
index 0d78c11..4384048 100644
--- a/lib/src/command/outdated.dart
+++ b/lib/src/command/outdated.dart
@@ -366,7 +366,7 @@
 /// resolution was found.
 Future<List<PackageId>?> _tryResolve(Pubspec pubspec, SystemCache cache) async {
   final solveResult = await tryResolveVersions(
-    SolveType.upgrade,
+    SolveType.UPGRADE,
     cache,
     Package.inMemory(pubspec),
   );
@@ -807,9 +807,6 @@
           _overridden == other._overridden &&
           _id.source == other._id.source &&
           _pubspec.version == other._pubspec.version;
-
-  @override
-  int get hashCode => Object.hash(_pubspec.version, _id.source, _overridden);
 }
 
 class _PackageDetails implements Comparable<_PackageDetails> {
diff --git a/lib/src/command/remove.dart b/lib/src/command/remove.dart
index 82a9547..c7c674a 100644
--- a/lib/src/command/remove.dart
+++ b/lib/src/command/remove.dart
@@ -50,9 +50,6 @@
 
     argParser.addOption('directory',
         abbr: 'C', help: 'Run this in the directory<dir>.', valueHelp: 'dir');
-
-    argParser.addFlag('legacy-packages-file',
-        help: 'Generate the legacy ".packages" file', negatable: false);
   }
 
   @override
@@ -68,12 +65,11 @@
       final newPubspec = _removePackagesFromPubspec(rootPubspec, packages);
       final newRoot = Package.inMemory(newPubspec);
 
-      await Entrypoint.inMemory(newRoot, cache, lockFile: entrypoint.lockFile)
-          .acquireDependencies(SolveType.get,
+      await Entrypoint.global(newRoot, entrypoint.lockFile, cache)
+          .acquireDependencies(SolveType.GET,
               precompile: argResults['precompile'],
               dryRun: true,
-              analytics: null,
-              generateDotPackages: false);
+              analytics: null);
     } else {
       /// Update the pubspec.
       _writeRemovalToPubspec(packages);
@@ -82,20 +78,18 @@
       /// pubspec file.
       final updatedEntrypoint = Entrypoint(directory, cache);
       await updatedEntrypoint.acquireDependencies(
-        SolveType.get,
+        SolveType.GET,
         precompile: argResults['precompile'],
         analytics: analytics,
-        generateDotPackages: argResults['legacy-packages-file'],
       );
 
       var example = entrypoint.example;
       if (argResults['example'] && example != null) {
         await example.acquireDependencies(
-          SolveType.get,
+          SolveType.GET,
           precompile: argResults['precompile'],
           onlyReportSuccessOrFailure: true,
           analytics: analytics,
-          generateDotPackages: argResults['legacy-packages-file'],
         );
       }
     }
diff --git a/lib/src/command/token_add.dart b/lib/src/command/token_add.dart
index caf3b8b..fddc0cc 100644
--- a/lib/src/command/token_add.dart
+++ b/lib/src/command/token_add.dart
@@ -57,11 +57,17 @@
     } on FormatException catch (e) {
       usageException('Invalid [hosted-url]: "$rawHostedUrl"\n'
           '${e.message}');
+    } on TimeoutException catch (_) {
+      // Timeout is added to readLine call to make sure automated jobs doesn't
+      // get stuck on noop state if user forget to pipe token to the 'token add'
+      // command. This behavior might be removed.
+      throw ApplicationException('Token is not provided within 15 minutes.');
     }
   }
 
   Future<void> _addTokenFromStdin(Uri hostedUrl) async {
-    final token = await stdinPrompt('Enter secret token:', echoMode: false);
+    final token = await stdinPrompt('Enter secret token:', echoMode: false)
+        .timeout(const Duration(minutes: 15));
     if (token.isEmpty) {
       usageException('Token is not provided.');
     }
diff --git a/lib/src/command/upgrade.dart b/lib/src/command/upgrade.dart
index 0dc5fb7..8e44abf 100644
--- a/lib/src/command/upgrade.dart
+++ b/lib/src/command/upgrade.dart
@@ -56,9 +56,6 @@
 
     argParser.addFlag('packages-dir', hide: true);
 
-    argParser.addFlag('legacy-packages-file',
-        help: 'Generate the legacy ".packages" file', negatable: false);
-
     argParser.addFlag(
       'major-versions',
       help: 'Upgrades packages to their latest resolvable versions, '
@@ -83,8 +80,6 @@
 
   bool get _precompile => argResults['precompile'];
 
-  bool get _packagesFile => argResults['legacy-packages-file'];
-
   bool get _upgradeNullSafety =>
       argResults['nullsafety'] || argResults['null-safety'];
 
@@ -126,12 +121,11 @@
 
   Future<void> _runUpgrade(Entrypoint e, {bool onlySummary = false}) async {
     await e.acquireDependencies(
-      SolveType.upgrade,
+      SolveType.UPGRADE,
       unlock: argResults.rest,
       dryRun: _dryRun,
       precompile: _precompile,
       onlyReportSuccessOrFailure: onlySummary,
-      generateDotPackages: _packagesFile,
       analytics: analytics,
     );
     _showOfflineWarning();
@@ -185,7 +179,7 @@
     final resolvedPackages = <String, PackageId>{};
     final solveResult = await log.spinner('Resolving dependencies', () async {
       return await resolveVersions(
-        SolveType.upgrade,
+        SolveType.UPGRADE,
         cache,
         Package.inMemory(resolvablePubspec),
       );
@@ -224,37 +218,32 @@
         resolvedPackage.version,
       ));
     }
-    final newPubspecText = _updatePubspec(changes);
 
     if (_dryRun) {
       // Even if it is a dry run, run `acquireDependencies` so that the user
       // gets a report on changes.
-      await Entrypoint.inMemory(
-        Package.inMemory(
-          Pubspec.parse(newPubspecText, cache.sources),
-        ),
+      // TODO(jonasfj): Stop abusing Entrypoint.global for dry-run output
+      await Entrypoint.global(
+        Package.inMemory(resolvablePubspec),
+        entrypoint.lockFile,
         cache,
-        lockFile: entrypoint.lockFile,
         solveResult: solveResult,
       ).acquireDependencies(
-        SolveType.get,
+        SolveType.UPGRADE,
         dryRun: true,
         precompile: _precompile,
         analytics: null, // No analytics for dry-run
-        generateDotPackages: false,
       );
     } else {
-      if (changes.isNotEmpty) {
-        writeTextFile(entrypoint.pubspecPath, newPubspecText);
-      }
+      await _updatePubspec(changes);
+
       // TODO: Allow Entrypoint to be created with in-memory pubspec, so that
       //       we can show the changes when not in --dry-run mode. For now we only show
       //       the changes made to pubspec.yaml in dry-run mode.
       await Entrypoint(directory, cache).acquireDependencies(
-        SolveType.get,
+        SolveType.UPGRADE,
         precompile: _precompile,
         analytics: analytics,
-        generateDotPackages: argResults['legacy-packages-file'],
       );
     }
 
@@ -287,7 +276,7 @@
     final resolvedPackages = <String, PackageId>{};
     final solveResult = await log.spinner('Resolving dependencies', () async {
       return await resolveVersions(
-        SolveType.upgrade,
+        SolveType.UPGRADE,
         cache,
         Package.inMemory(nullsafetyPubspec),
       );
@@ -324,35 +313,31 @@
       changes[dep] = dep.withConstraint(constraint);
     }
 
-    final newPubspecText = _updatePubspec(changes);
     if (_dryRun) {
       // Even if it is a dry run, run `acquireDependencies` so that the user
       // gets a report on changes.
       // TODO(jonasfj): Stop abusing Entrypoint.global for dry-run output
-      await Entrypoint.inMemory(
-        Package.inMemory(Pubspec.parse(newPubspecText, cache.sources)),
+      await Entrypoint.global(
+        Package.inMemory(nullsafetyPubspec),
+        entrypoint.lockFile,
         cache,
-        lockFile: entrypoint.lockFile,
         solveResult: solveResult,
       ).acquireDependencies(
-        SolveType.upgrade,
+        SolveType.UPGRADE,
         dryRun: true,
         precompile: _precompile,
         analytics: null,
-        generateDotPackages: false,
       );
     } else {
-      if (changes.isNotEmpty) {
-        writeTextFile(entrypoint.pubspecPath, newPubspecText);
-      }
+      await _updatePubspec(changes);
+
       // TODO: Allow Entrypoint to be created with in-memory pubspec, so that
       //       we can show the changes in --dry-run mode. For now we only show
       //       the changes made to pubspec.yaml in dry-run mode.
       await Entrypoint(directory, cache).acquireDependencies(
-        SolveType.upgrade,
+        SolveType.UPGRADE,
         precompile: _precompile,
         analytics: analytics,
-        generateDotPackages: argResults['legacy-packages-file'],
       );
     }
 
@@ -396,11 +381,13 @@
   }
 
   /// Updates `pubspec.yaml` with given [changes].
-  String _updatePubspec(
+  Future<void> _updatePubspec(
     Map<PackageRange, PackageRange> changes,
-  ) {
+  ) async {
     ArgumentError.checkNotNull(changes, 'changes');
 
+    if (changes.isEmpty) return;
+
     final yamlEditor = YamlEditor(readTextFile(entrypoint.pubspecPath));
     final deps = entrypoint.root.pubspec.dependencies.keys;
     final devDeps = entrypoint.root.pubspec.devDependencies.keys;
@@ -420,7 +407,9 @@
         );
       }
     }
-    return yamlEditor.toString();
+
+    /// Windows line endings are already handled by [yamlEditor]
+    writeTextFile(entrypoint.pubspecPath, yamlEditor.toString());
   }
 
   /// Outputs a summary of changes made to `pubspec.yaml`.
diff --git a/lib/src/command_runner.dart b/lib/src/command_runner.dart
index 21f568b..4ed33f6 100644
--- a/lib/src/command_runner.dart
+++ b/lib/src/command_runner.dart
@@ -58,22 +58,21 @@
   Verbosity get verbosity {
     switch (argResults['verbosity']) {
       case 'error':
-        return log.Verbosity.error;
+        return log.Verbosity.ERROR;
       case 'warning':
-        return log.Verbosity.warning;
+        return log.Verbosity.WARNING;
       case 'normal':
-        return log.Verbosity.normal;
+        return log.Verbosity.NORMAL;
       case 'io':
-        return log.Verbosity.io;
+        return log.Verbosity.IO;
       case 'solver':
-        return log.Verbosity.solver;
+        return log.Verbosity.SOLVER;
       case 'all':
-        return log.Verbosity.all;
+        return log.Verbosity.ALL;
       default:
         // No specific verbosity given, so check for the shortcut.
-        if (argResults['verbose']) return log.Verbosity.all;
-        if (runningFromTest) return log.Verbosity.testing;
-        return log.Verbosity.normal;
+        if (argResults['verbose']) return log.Verbosity.ALL;
+        return log.Verbosity.NORMAL;
     }
   }
 
diff --git a/lib/src/dart.dart b/lib/src/dart.dart
index f4f8686..97219dc 100644
--- a/lib/src/dart.dart
+++ b/lib/src/dart.dart
@@ -146,14 +146,11 @@
   String toString() => errors.join('\n');
 }
 
-/// Precompiles the Dart executable at [executablePath].
+/// Precompiles the Dart executable at [executablePath] to a kernel file at
+/// [outputPath].
 ///
-/// If the compilation succeeds it is saved to a kernel file at [outputPath].
-///
-/// If compilation fails, the output is cached at [incrementalDillOutputPath].
-///
-/// Whichever of [incrementalDillOutputPath] and [outputPath] already exists is
-/// used to initialize the compiler run.
+/// This file is also cached at [incrementalDillOutputPath] which is used to
+/// initialize the compiler on future runs.
 ///
 /// The [packageConfigPath] should point at the package config file to be used
 /// for `package:` uri resolution.
@@ -161,65 +158,39 @@
 /// The [name] is used to describe the executable in logs and error messages.
 Future<void> precompile({
   required String executablePath,
-  required String incrementalDillPath,
+  required String incrementalDillOutputPath,
   required String name,
   required String outputPath,
   required String packageConfigPath,
 }) async {
   ensureDir(p.dirname(outputPath));
-  ensureDir(p.dirname(incrementalDillPath));
-
+  ensureDir(p.dirname(incrementalDillOutputPath));
   const platformDill = 'lib/_internal/vm_platform_strong.dill';
   final sdkRoot = p.relative(p.dirname(p.dirname(Platform.resolvedExecutable)));
-  String? tempDir;
-  FrontendServerClient? client;
+  var client = await FrontendServerClient.start(
+    executablePath,
+    incrementalDillOutputPath,
+    platformDill,
+    sdkRoot: sdkRoot,
+    packagesJson: packageConfigPath,
+    printIncrementalDependencies: false,
+  );
   try {
-    tempDir = createTempDir(p.dirname(incrementalDillPath), 'tmp');
-    // To avoid potential races we copy the incremental data to a temporary file
-    // for just this compilation.
-    final temporaryIncrementalDill =
-        p.join(tempDir, '${p.basename(incrementalDillPath)}.incremental.dill');
-    try {
-      if (fileExists(incrementalDillPath)) {
-        copyFile(incrementalDillPath, temporaryIncrementalDill);
-      } else if (fileExists(outputPath)) {
-        copyFile(outputPath, temporaryIncrementalDill);
-      }
-    } on FileSystemException {
-      // Not able to copy existing file, compilation will start from scratch.
-    }
-
-    client = await FrontendServerClient.start(
-      executablePath,
-      temporaryIncrementalDill,
-      platformDill,
-      sdkRoot: sdkRoot,
-      packagesJson: packageConfigPath,
-      printIncrementalDependencies: false,
-    );
-    final result = await client.compile();
+    var result = await client.compile();
 
     final highlightedName = log.bold(name);
     if (result?.errorCount == 0) {
       log.message('Built $highlightedName.');
-      // By using rename we ensure atomicity. An external observer will either
-      // see the old or the new snapshot.
-      renameFile(temporaryIncrementalDill, outputPath);
+      await File(incrementalDillOutputPath).copy(outputPath);
     } else {
-      // By using rename we ensure atomicity. An external observer will either
-      // see the old or the new snapshot.
-      renameFile(temporaryIncrementalDill, incrementalDillPath);
-      // If compilation failed we don't want to leave an incorrect snapshot.
-      tryDeleteEntry(outputPath);
+      // Don't leave partial results.
+      deleteEntry(outputPath);
 
       throw ApplicationException(
           log.yellow('Failed to build $highlightedName:\n') +
               (result?.compilerOutputLines.join('\n') ?? ''));
     }
   } finally {
-    client?.kill();
-    if (tempDir != null) {
-      tryDeleteEntry(tempDir);
-    }
+    client.kill();
   }
 }
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index 202580c..453ef56 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -10,12 +10,12 @@
 import 'package:meta/meta.dart';
 import 'package:path/path.dart' as p;
 import 'package:pub_semver/pub_semver.dart';
-import 'package:yaml/yaml.dart';
 
 import 'command_runner.dart';
 import 'dart.dart' as dart;
 import 'exceptions.dart';
 import 'executable.dart';
+import 'http.dart' as http;
 import 'io.dart';
 import 'language_version.dart';
 import 'lock_file.dart';
@@ -72,14 +72,8 @@
 /// but may be the entrypoint when you're running its tests.
 class Entrypoint {
   /// The root package this entrypoint is associated with.
-  ///
-  /// For a global package, this is the activated package.
   final Package root;
 
-  /// For a global package, this is the directory that the package is installed
-  /// in. Non-global packages have null.
-  final String? globalDir;
-
   /// The system-wide cache which caches packages that need to be fetched over
   /// the network.
   final SystemCache cache;
@@ -88,8 +82,7 @@
   bool get isCached => !root.isInMemory && p.isWithin(cache.rootDir, root.dir);
 
   /// Whether this is an entrypoint for a globally-activated package.
-  // final bool isGlobal;
-  bool get isGlobal => globalDir != null;
+  final bool isGlobal;
 
   /// The lockfile for the entrypoint.
   ///
@@ -129,7 +122,8 @@
   ///
   /// Global packages (except those from path source)
   /// store these in the global cache.
-  String? get _configRoot => isCached ? globalDir : root.dir;
+  String? get _configRoot =>
+      isCached ? p.join(cache.rootDir, 'global_packages', root.name) : root.dir;
 
   /// The path to the entrypoint's ".packages" file.
   ///
@@ -158,7 +152,11 @@
   /// but the configuration is stored at the package itself.
   String get cachePath {
     if (isGlobal) {
-      return globalDir!;
+      return p.join(
+        cache.rootDir,
+        'global_packages',
+        root.name,
+      );
     } else {
       var newPath = root.path('.dart_tool/pub');
       var oldPath = root.path('.pub');
@@ -175,25 +173,15 @@
   String get _incrementalDillsPath => p.join(cachePath, 'incremental');
 
   /// Loads the entrypoint from a package at [rootDir].
-  Entrypoint(
-    String rootDir,
-    this.cache,
-  )   : root = Package.load(null, rootDir, cache.sources),
-        globalDir = null;
-
-  Entrypoint.inMemory(this.root, this.cache,
-      {required LockFile? lockFile, SolveResult? solveResult})
-      : _lockFile = lockFile,
-        globalDir = null {
-    if (solveResult != null) {
-      _packageGraph = PackageGraph.fromSolveResult(this, solveResult);
-    }
-  }
+  Entrypoint(String rootDir, this.cache)
+      : root = Package.load(null, rootDir, cache.sources),
+        isGlobal = false;
 
   /// Creates an entrypoint given package and lockfile objects.
   /// If a SolveResult is already created it can be passed as an optimization.
-  Entrypoint.global(this.globalDir, this.root, this._lockFile, this.cache,
-      {SolveResult? solveResult}) {
+  Entrypoint.global(this.root, this._lockFile, this.cache,
+      {SolveResult? solveResult})
+      : isGlobal = true {
     if (solveResult != null) {
       _packageGraph = PackageGraph.fromSolveResult(this, solveResult);
     }
@@ -213,25 +201,19 @@
   Entrypoint? _example;
 
   /// Writes .packages and .dart_tool/package_config.json
-  Future<void> writePackagesFiles({bool generateDotPackages = false}) async {
-    final entrypointName = isGlobal ? null : root.name;
-    if (generateDotPackages) {
-      writeTextFile(
-          packagesFile,
-          lockFile.packagesFile(cache,
-              entrypoint: entrypointName,
-              relativeFrom: isGlobal ? null : root.dir));
-    } else {
-      tryDeleteEntry(packagesFile);
-    }
+  Future<void> writePackagesFiles() async {
+    writeTextFile(
+        packagesFile,
+        lockFile.packagesFile(cache,
+            entrypoint: root.name, relativeFrom: root.dir));
     ensureDir(p.dirname(packageConfigFile));
     writeTextFile(
         packageConfigFile,
         await lockFile.packageConfigFile(cache,
-            entrypoint: entrypointName,
+            entrypoint: root.name,
             entrypointSdkConstraint:
                 root.pubspec.sdkConstraints[sdk.identifier],
-            relativeFrom: isGlobal ? null : root.dir));
+            relativeFrom: root.dir));
   }
 
   /// Gets all dependencies of the [root] package.
@@ -261,7 +243,6 @@
     Iterable<String>? unlock,
     bool dryRun = false,
     bool precompile = false,
-    required bool generateDotPackages,
     required PubAnalytics? analytics,
     bool onlyReportSuccessOrFailure = false,
   }) async {
@@ -269,7 +250,8 @@
     SolveResult result;
     try {
       result = await log.progress('Resolving dependencies$suffix', () async {
-        _checkSdkConstraint(root.pubspec);
+        // We require an SDK constraint lower-bound as of Dart 2.12.0
+        _checkSdkConstraintIsDefined(root.pubspec);
         return resolveVersions(
           type,
           cache,
@@ -312,7 +294,7 @@
       await result.showReport(type, cache);
     }
     if (!dryRun) {
-      await result.downloadCachedPackages(cache);
+      await Future.wait(result.packages.map(_get));
       _saveLockFile(result);
     }
     if (onlyReportSuccessOrFailure) {
@@ -330,7 +312,7 @@
       /// have to reload and reparse all the pubspecs.
       _packageGraph = PackageGraph.fromSolveResult(this, result);
 
-      await writePackagesFiles(generateDotPackages: generateDotPackages);
+      await writePackagesFiles();
 
       try {
         if (precompile) {
@@ -405,11 +387,10 @@
 
   Future<void> _precompileExecutable(Executable executable) async {
     final package = executable.package;
-
     await dart.precompile(
         executablePath: resolveExecutable(executable),
         outputPath: pathOfExecutable(executable),
-        incrementalDillPath: incrementalDillPathOfExecutable(executable),
+        incrementalDillOutputPath: incrementalDillPathOfExecutable(executable),
         packageConfigPath: packageConfigFile,
         name:
             '$package:${p.basenameWithoutExtension(executable.relativePath)}');
@@ -489,6 +470,21 @@
     }
   }
 
+  /// Makes sure the package at [id] is locally available.
+  ///
+  /// This automatically downloads the package to the system-wide cache as well
+  /// if it requires network access to retrieve (specifically, if the package's
+  /// source is a [CachedSource]).
+  Future<void> _get(PackageId id) async {
+    return await http.withDependencyType(root.dependencyType(id.name),
+        () async {
+      if (id.isRoot) return;
+
+      var source = cache.source(id.source);
+      if (source is CachedSource) await source.downloadToSystemCache(id);
+    });
+  }
+
   /// 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.
   ///
@@ -876,9 +872,7 @@
   }
 
   /// We require an SDK constraint lower-bound as of Dart 2.12.0
-  ///
-  /// We don't allow unknown sdks.
-  void _checkSdkConstraint(Pubspec pubspec) {
+  void _checkSdkConstraintIsDefined(Pubspec pubspec) {
     final dartSdkConstraint = pubspec.sdkConstraints['dart'];
     if (dartSdkConstraint is! VersionRange || dartSdkConstraint.min == null) {
       // Suggest version range '>=2.10.0 <3.0.0', we avoid using:
@@ -908,24 +902,6 @@
 See https://dart.dev/go/sdk-constraint
 ''');
     }
-    for (final sdk in pubspec.sdkConstraints.keys) {
-      if (!sdks.containsKey(sdk)) {
-        final environment = pubspec.fields.nodes['environment'] as YamlMap;
-        final keyNode = environment.nodes.entries
-            .firstWhere((e) => (e.key as YamlNode).value == sdk)
-            .key as YamlNode;
-        throw PubspecException('''
-$pubspecPath refers to an unknown sdk '$sdk'.
-
-Did you mean to add it as a dependency?
-
-Either remove the constraint, or upgrade to a version of pub that supports the
-given sdk.
-
-See https://dart.dev/go/sdk-constraint
-''', keyNode.span);
-      }
-    }
   }
 }
 
diff --git a/lib/src/exceptions.dart b/lib/src/exceptions.dart
index fcde747..82a5dac 100644
--- a/lib/src/exceptions.dart
+++ b/lib/src/exceptions.dart
@@ -11,6 +11,7 @@
 import 'package:yaml/yaml.dart';
 
 import 'dart.dart';
+import 'sdk.dart';
 
 /// An exception class for exceptions that are intended to be seen by the user.
 ///
@@ -88,20 +89,18 @@
 /// that other code in pub can use this to show a more detailed explanation of
 /// why the package was being requested.
 class PackageNotFoundException extends WrappedException {
-  /// A hint indicating an action the user could take to resolve this problem.
-  ///
-  /// This will be printed after the package resolution conflict.
-  final String? hint;
+  /// If this failure was caused by an SDK being unavailable, this is that SDK.
+  final Sdk? missingSdk;
 
   PackageNotFoundException(
     String message, {
     Object? innerError,
     StackTrace? innerTrace,
-    this.hint,
+    this.missingSdk,
   }) : super(message, innerError, innerTrace);
 
   @override
-  String toString() => 'Package not available ($message).';
+  String toString() => "Package doesn't exist ($message).";
 }
 
 /// Returns whether [error] is a user-facing error object.
diff --git a/lib/src/executable.dart b/lib/src/executable.dart
index 3f8f6a9..2112acc 100644
--- a/lib/src/executable.dart
+++ b/lib/src/executable.dart
@@ -306,9 +306,8 @@
     try {
       await warningsOnlyUnlessTerminal(
         () => entrypoint.acquireDependencies(
-          SolveType.get,
+          SolveType.GET,
           analytics: analytics,
-          generateDotPackages: false,
         ),
       );
     } on ApplicationException catch (e) {
diff --git a/lib/src/exit_codes.dart b/lib/src/exit_codes.dart
index c6acaf7..e072ef2 100644
--- a/lib/src/exit_codes.dart
+++ b/lib/src/exit_codes.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// ignore_for_file: constant_identifier_names
-
 /// Exit code constants.
 ///
 /// From [the BSD sysexits manpage][manpage]. Not every constant here is used,
diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart
index 07e2513..578eca1 100644
--- a/lib/src/global_packages.dart
+++ b/lib/src/global_packages.dart
@@ -12,6 +12,7 @@
 import 'entrypoint.dart';
 import 'exceptions.dart';
 import 'executable.dart' as exec;
+import 'http.dart' as http;
 import 'io.dart';
 import 'lock_file.dart';
 import 'log.dart' as log;
@@ -61,8 +62,6 @@
   /// The directory where the lockfiles for activated packages are stored.
   String get _directory => p.join(cache.rootDir, 'global_packages');
 
-  String _packageDir(String packageName) => p.join(_directory, packageName);
-
   /// The directory where binstubs for global package executables are stored.
   String get _binStubDir => p.join(cache.rootDir, 'bin');
 
@@ -150,25 +149,28 @@
     var entrypoint = Entrypoint(path, cache);
 
     // Get the package's dependencies.
-    await entrypoint.acquireDependencies(
-      SolveType.get,
-      analytics: analytics,
-      generateDotPackages: false,
-    );
+    await entrypoint.acquireDependencies(SolveType.GET, analytics: analytics);
     var name = entrypoint.root.name;
-    _describeActive(name, cache);
+
+    try {
+      var originalLockFile =
+          LockFile.load(_getLockFilePath(name), cache.sources);
+      // Call this just to log what the current active package is, if any.
+      _describeActive(originalLockFile, name);
+    } on IOException {
+      // Couldn't read the lock file. It probably doesn't exist.
+    }
 
     // Write a lockfile that points to the local package.
     var fullPath = canonicalize(entrypoint.root.dir);
     var id = cache.path.source.idFor(name, entrypoint.root.version, fullPath);
 
-    final tempDir = cache.createTempDir();
     // TODO(rnystrom): Look in "bin" and display list of binaries that
     // user can run.
-    _writeLockFile(tempDir, LockFile([id]));
+    _writeLockFile(name, LockFile([id]));
 
-    tryDeleteEntry(_packageDir(name));
-    tryRenameDir(tempDir, _packageDir(name));
+    var binDir = p.join(_directory, name, 'bin');
+    if (dirExists(binDir)) deleteEntry(binDir);
 
     _updateBinStubs(entrypoint, entrypoint.root, executables,
         overwriteBinStubs: overwriteBinStubs);
@@ -176,12 +178,17 @@
   }
 
   /// Installs the package [dep] and its dependencies into the system cache.
-  ///
-  /// If [silent] less logging will be printed.
   Future<void> _installInCache(PackageRange dep, List<String>? executables,
-      {required bool overwriteBinStubs, bool silent = false}) async {
-    final name = dep.name;
-    LockFile? originalLockFile = _describeActive(name, cache);
+      {required bool overwriteBinStubs}) async {
+    LockFile? originalLockFile;
+    try {
+      originalLockFile =
+          LockFile.load(_getLockFilePath(dep.name), cache.sources);
+      // Call this just to log what the current active package is, if any.
+      _describeActive(originalLockFile, dep.name);
+    } on IOException {
+      // Couldn't read the lock file. It probably doesn't exist.
+    }
 
     // Create a dummy package with just [dep] so we can do resolution on it.
     var root = Package.inMemory(Pubspec('pub global activate',
@@ -193,89 +200,103 @@
     // being available, report that as a [dataError].
     SolveResult result;
     try {
-      result = await log.spinner(
-        'Resolving dependencies',
-        () => resolveVersions(SolveType.get, cache, root),
-        condition: !silent,
-      );
+      result = await log.progress('Resolving dependencies',
+          () => resolveVersions(SolveType.GET, cache, root));
     } on SolveFailure catch (error) {
       for (var incompatibility
           in error.incompatibility.externalIncompatibilities) {
         if (incompatibility.cause != IncompatibilityCause.noVersions) continue;
-        if (incompatibility.terms.single.package.name != name) continue;
+        if (incompatibility.terms.single.package.name != dep.name) continue;
         dataError(error.toString());
       }
       rethrow;
     }
-    // We want the entrypoint to be rooted at 'dep' not the dummy-package.
-    result.packages.removeWhere((id) => id.name == 'pub global activate');
 
     final sameVersions = originalLockFile != null &&
         originalLockFile.samePackageIds(result.lockFile);
 
-    final PackageId id = result.lockFile.packages[name]!;
     if (sameVersions) {
       log.message('''
-The package $name is already activated at newest available version.
-To recompile executables, first run `$topLevelProgram pub global deactivate $name`.
+The package ${dep.name} is already activated at newest available version.
+To recompile executables, first run `$topLevelProgram pub global deactivate ${dep.name}`.
 ''');
     } else {
-      // Only precompile binaries if we have a new resolution.
-      if (!silent) await result.showReport(SolveType.get, cache);
-
-      await result.downloadCachedPackages(cache);
-
-      final lockFile = result.lockFile;
-      final tempDir = cache.createTempDir();
-      _writeLockFile(tempDir, lockFile);
-
-      // Load the package graph from [result] so we don't need to re-parse all
-      // the pubspecs.
-      final entrypoint = Entrypoint.global(
-        tempDir,
-        cache.loadCached(id),
-        lockFile,
-        cache,
-        solveResult: result,
-      );
-
-      await entrypoint.writePackagesFiles();
-
-      await entrypoint.precompileExecutables();
-
-      tryDeleteEntry(_packageDir(name));
-      tryRenameDir(tempDir, _packageDir(name));
+      await result.showReport(SolveType.GET, cache);
     }
+
+    // Make sure all of the dependencies are locally installed.
+    await Future.wait(result.packages.map((id) {
+      return http.withDependencyType(root.dependencyType(id.name), () async {
+        if (id.isRoot) return;
+
+        var source = cache.source(id.source);
+        if (source is CachedSource) await source.downloadToSystemCache(id);
+      });
+    }));
+
+    var lockFile = result.lockFile;
+    _writeLockFile(dep.name, lockFile);
+    await _writePackageConfigFiles(dep.name, lockFile);
+
+    // We want the entrypoint to be rooted at 'dep' not the dummy-package.
+    result.packages.removeWhere((id) => id.name == 'pub global activate');
+
+    var id = lockFile.packages[dep.name]!;
+    // Load the package graph from [result] so we don't need to re-parse all
+    // the pubspecs.
     final entrypoint = Entrypoint.global(
-      _packageDir(id.name),
-      cache.loadCached(id),
-      result.lockFile,
+      Package(
+        result.pubspecs[dep.name]!,
+        (cache.source(dep.source) as CachedSource).getDirectoryInCache(id),
+      ),
+      lockFile,
       cache,
       solveResult: result,
     );
+    if (!sameVersions) {
+      // Only precompile binaries if we have a new resolution.
+      await entrypoint.precompileExecutables();
+    }
+
     _updateBinStubs(
       entrypoint,
       cache.load(entrypoint.lockFile.packages[dep.name]!),
       executables,
       overwriteBinStubs: overwriteBinStubs,
     );
-    if (!silent) log.message('Activated ${_formatPackage(id)}.');
+
+    log.message('Activated ${_formatPackage(id)}.');
+  }
+
+  Future<void> _writePackageConfigFiles(
+      String package, LockFile lockFile) async {
+    // TODO(sigurdm): Use [Entrypoint.writePackagesFiles] instead.
+    final packagesFilePath = _getPackagesFilePath(package);
+    final packageConfigFilePath = _getPackageConfigFilePath(package);
+    final dir = p.dirname(packagesFilePath);
+    writeTextFile(
+        packagesFilePath, lockFile.packagesFile(cache, relativeFrom: dir));
+    ensureDir(p.dirname(packageConfigFilePath));
+    writeTextFile(packageConfigFilePath,
+        await lockFile.packageConfigFile(cache, relativeFrom: dir));
   }
 
   /// Finishes activating package [package] by saving [lockFile] in the cache.
-  void _writeLockFile(String dir, LockFile lockFile) {
-    writeTextFile(p.join(dir, 'pubspec.lock'), lockFile.serialize(null));
+  void _writeLockFile(String package, LockFile lockFile) {
+    ensureDir(p.join(_directory, package));
+
+    // TODO(nweiz): This cleans up Dart 1.6's old lockfile location. Remove it
+    // when Dart 1.6 is old enough that we don't think anyone will have these
+    // lockfiles anymore (issue 20703).
+    var oldPath = p.join(_directory, '$package.lock');
+    if (fileExists(oldPath)) deleteEntry(oldPath);
+
+    writeTextFile(_getLockFilePath(package),
+        lockFile.serialize(p.join(_directory, package)));
   }
 
   /// Shows the user the currently active package with [name], if any.
-  LockFile? _describeActive(String name, SystemCache cache) {
-    late final LockFile lockFile;
-    try {
-      lockFile = LockFile.load(_getLockFilePath(name), cache.sources);
-    } on IOException {
-      // Couldn't read the lock file. It probably doesn't exist.
-      return null;
-    }
+  void _describeActive(LockFile lockFile, String? name) {
     var id = lockFile.packages[name]!;
 
     var source = id.source;
@@ -291,7 +312,6 @@
       log.message('Package ${log.bold(name)} is currently active at version '
           '${log.bold(id.version)}.');
     }
-    return lockFile;
   }
 
   /// Deactivates a previously-activated package named [name].
@@ -321,8 +341,22 @@
     try {
       lockFile = LockFile.load(lockFilePath, cache.sources);
     } on IOException {
-      // If we couldn't read the lock file, it's not activated.
-      dataError('No active package ${log.bold(name)}.');
+      var oldLockFilePath = p.join(_directory, '$name.lock');
+      try {
+        // TODO(nweiz): This looks for Dart 1.6's old lockfile location.
+        // Remove it when Dart 1.6 is old enough that we don't think anyone
+        // will have these lockfiles anymore (issue 20703).
+        lockFile = LockFile.load(oldLockFilePath, cache.sources);
+      } on IOException {
+        // If we couldn't read the lock file, it's not activated.
+        dataError('No active package ${log.bold(name)}.');
+      }
+
+      // Move the old lockfile to its new location.
+      ensureDir(p.dirname(lockFilePath));
+      File(oldLockFilePath).renameSync(lockFilePath);
+      // Just make sure these files are created as well.
+      await _writePackageConfigFiles(name, lockFile);
     }
 
     // Remove the package itself from the lockfile. We put it in there so we
@@ -336,8 +370,7 @@
     if (source is CachedSource) {
       // For cached sources, the package itself is in the cache and the
       // lockfile is the one we just loaded.
-      entrypoint = Entrypoint.global(
-          _packageDir(id.name), cache.loadCached(id), lockFile, cache);
+      entrypoint = Entrypoint.global(cache.loadCached(id), lockFile, cache);
     } else {
       // For uncached sources (i.e. path), the ID just points to the real
       // directory for the package.
@@ -413,6 +446,16 @@
   String _getLockFilePath(String name) =>
       p.join(_directory, name, 'pubspec.lock');
 
+  /// Gets the path to the .packages file for an activated cached package with
+  /// [name].
+  String _getPackagesFilePath(String name) =>
+      p.join(_directory, name, '.packages');
+
+  /// Gets the path to the `package_config.json` file for an
+  /// activated cached package with [name].
+  String _getPackageConfigFilePath(String name) =>
+      p.join(_directory, name, '.dart_tool', 'package_config.json');
+
   /// Shows the user a formatted list of globally activated packages.
   void listActivePackages() {
     if (!dirExists(_directory)) return;
@@ -499,24 +542,17 @@
           log.message('Reactivating ${log.bold(id.name)} ${id.version}...');
 
           var entrypoint = await find(id.name);
-          final packageExecutables = executables.remove(id.name) ?? [];
 
-          if (entrypoint.isCached) {
-            deleteEntry(entrypoint.globalDir!);
-            await _installInCache(
-              id.toRange(),
-              packageExecutables,
-              overwriteBinStubs: true,
-              silent: true,
-            );
-          } else {
-            await activatePath(
-              entrypoint.root.dir,
-              packageExecutables,
-              overwriteBinStubs: true,
-              analytics: null,
-            );
-          }
+          await _writePackageConfigFiles(id.name, entrypoint.lockFile);
+          await entrypoint.precompileExecutables();
+          var packageExecutables = executables.remove(id.name) ?? [];
+          _updateBinStubs(
+            entrypoint,
+            cache.load(id),
+            packageExecutables,
+            overwriteBinStubs: true,
+            suggestIfNotOnPath: false,
+          );
           successes.add(id.name);
         } catch (error, stackTrace) {
           var message = 'Failed to reactivate '
@@ -670,7 +706,10 @@
     // Show errors for any missing scripts.
     // TODO(rnystrom): This can print false positives since a script may be
     // produced by a transformer. Do something better.
-    var binFiles = package.executablePaths;
+    var binFiles = package
+        .listFiles(beneath: 'bin', recursive: false)
+        .map(package.relative)
+        .toList();
     for (var executable in installed) {
       var script = package.pubspec.executables[executable];
       var scriptPath = p.join('bin', '$script.dart');
@@ -722,7 +761,6 @@
     // If the script was built to a snapshot, just try to invoke that
     // directly and skip pub global run entirely.
     String invocation;
-    late String binstub;
     if (Platform.isWindows) {
       if (fileExists(snapshot)) {
         // We expect absolute paths from the precompiler since relative ones
@@ -748,7 +786,7 @@
       } else {
         invocation = 'dart pub global run ${package.name}:$script %*';
       }
-      binstub = '''
+      var batch = '''
 @echo off
 rem This file was created by pub v${sdk.version}.
 rem Package: ${package.name}
@@ -757,6 +795,7 @@
 rem Script: $script
 $invocation
 ''';
+      writeTextFile(binStubPath, batch);
     } else {
       if (fileExists(snapshot)) {
         // We expect absolute paths from the precompiler since relative ones
@@ -779,7 +818,7 @@
       } else {
         invocation = 'dart pub global run ${package.name}:$script "\$@"';
       }
-      binstub = '''
+      var bash = '''
 #!/usr/bin/env sh
 # This file was created by pub v${sdk.version}.
 # Package: ${package.name}
@@ -788,31 +827,25 @@
 # Script: $script
 $invocation
 ''';
-    }
 
-    // Write the binstub to a temporary location, make it executable and move
-    // it into place afterwards to avoid races.
-    final tempDir = cache.createTempDir();
-    try {
-      final tmpPath = p.join(tempDir, binStubPath);
+      // Write this as the system encoding since the system is going to execute
+      // it and it might contain non-ASCII characters in the pathnames.
+      writeTextFile(binStubPath, bash, encoding: const SystemEncoding());
 
-      // Write this as the system encoding since the system is going to
-      // execute it and it might contain non-ASCII characters in the
-      // pathnames.
-      writeTextFile(tmpPath, binstub, encoding: const SystemEncoding());
-
-      if (Platform.isLinux || Platform.isMacOS) {
-        // Make it executable.
-        var result = Process.runSync('chmod', ['+x', tmpPath]);
-        if (result.exitCode != 0) {
-          // Couldn't make it executable so don't leave it laying around.
-          fail('Could not make "$tmpPath" executable (exit code '
-              '${result.exitCode}):\n${result.stderr}');
+      // Make it executable.
+      var result = Process.runSync('chmod', ['+x', binStubPath]);
+      if (result.exitCode != 0) {
+        // Couldn't make it executable so don't leave it laying around.
+        try {
+          deleteEntry(binStubPath);
+        } on IOException catch (err) {
+          // Do nothing. We're going to fail below anyway.
+          log.fine('Could not delete binstub:\n$err');
         }
+
+        fail('Could not make "$binStubPath" executable (exit code '
+            '${result.exitCode}):\n${result.stderr}');
       }
-      File(tmpPath).renameSync(binStubPath);
-    } finally {
-      deleteEntry(tempDir);
     }
 
     return previousPackage;
diff --git a/lib/src/http.dart b/lib/src/http.dart
index 724962b..fb6e9aa 100644
--- a/lib/src/http.dart
+++ b/lib/src/http.dart
@@ -10,6 +10,7 @@
 
 import 'package:http/http.dart' as http;
 import 'package:http/retry.dart';
+import 'package:pedantic/pedantic.dart';
 import 'package:pool/pool.dart';
 import 'package:stack_trace/stack_trace.dart';
 
diff --git a/lib/src/ignore.dart b/lib/src/ignore.dart
index ff22dff..fbd93e8 100644
--- a/lib/src/ignore.dart
+++ b/lib/src/ignore.dart
@@ -464,9 +464,6 @@
         } else {
           expr += '.*';
         }
-      } else if (peekChar() == '/' || peekChar() == null) {
-        // /a/* should not match '/a/'
-        expr += '[^/]+';
       } else {
         // Handle a single '*'
         expr += '[^/]*';
@@ -523,6 +520,7 @@
     expr = '$expr/\$';
   } else {
     expr = '$expr/?\$';
+    // expr = '$expr\$';
   }
   try {
     return _IgnoreParseResult(
diff --git a/lib/src/io.dart b/lib/src/io.dart
index acc1a6f..5e9a210 100644
--- a/lib/src/io.dart
+++ b/lib/src/io.dart
@@ -8,12 +8,14 @@
 import 'dart:convert';
 import 'dart:io';
 
+import 'package:async/async.dart';
 import 'package:cli_util/cli_util.dart'
     show EnvironmentNotFoundException, applicationConfigHome;
 import 'package:http/http.dart' show ByteStream;
 import 'package:http_multi_server/http_multi_server.dart';
 import 'package:meta/meta.dart';
 import 'package:path/path.dart' as path;
+import 'package:pedantic/pedantic.dart';
 import 'package:pool/pool.dart';
 import 'package:stack_trace/stack_trace.dart';
 
@@ -361,54 +363,52 @@
 /// when we try to delete or move something while it's being scanned. To
 /// mitigate that, on Windows, this will retry the operation a few times if it
 /// fails.
-///
-/// For some operations it makes sense to handle ERROR_DIR_NOT_EMPTY
-/// differently. They can pass [ignoreEmptyDir] = `true`.
-void _attempt(String description, void Function() operation,
-    {bool ignoreEmptyDir = false}) {
+void _attempt(String description, void Function() operation) {
   if (!Platform.isWindows) {
     operation();
     return;
   }
 
   String? getErrorReason(FileSystemException error) {
-    // ERROR_ACCESS_DENIED
     if (error.osError?.errorCode == 5) {
       return 'access was denied';
     }
 
-    // ERROR_SHARING_VIOLATION
     if (error.osError?.errorCode == 32) {
       return 'it was in use by another process';
     }
 
-    // ERROR_DIR_NOT_EMPTY
-    if (!ignoreEmptyDir && _isDirectoryNotEmptyException(error)) {
+    if (error.osError?.errorCode == 145) {
       return 'of dart-lang/sdk#25353';
     }
 
     return null;
   }
 
-  for (var i = 0; i < 3; i++) {
+  for (var i = 0; i < 2; i++) {
     try {
       operation();
-      break;
+      return;
     } on FileSystemException catch (error) {
       var reason = getErrorReason(error);
       if (reason == null) rethrow;
 
-      if (i < 2) {
-        log.io('Pub failed to $description because $reason. '
-            'Retrying in 50ms.');
-        sleep(Duration(milliseconds: 50));
-      } else {
-        fail('Pub failed to $description because $reason.\n'
-            'This may be caused by a virus scanner or having a file\n'
-            'in the directory open in another application.');
-      }
+      log.io('Pub failed to $description because $reason. '
+          'Retrying in 50ms.');
+      sleep(Duration(milliseconds: 50));
     }
   }
+
+  try {
+    operation();
+  } on FileSystemException catch (error) {
+    var reason = getErrorReason(error);
+    if (reason == null) rethrow;
+
+    fail('Pub failed to $description because $reason.\n'
+        'This may be caused by a virus scanner or having a file\n'
+        'in the directory open in another application.');
+  }
 }
 
 /// Deletes whatever's at [path], whether it's a file, directory, or symlink.
@@ -453,53 +453,14 @@
 void renameDir(String from, String to) {
   _attempt('rename directory', () {
     log.io('Renaming directory $from to $to.');
-    Directory(from).renameSync(to);
-  }, ignoreEmptyDir: true);
-}
-
-/// Renames directory [from] to [to].
-/// If it fails with "destination not empty" we log and continue, assuming
-/// another process got there before us.
-void tryRenameDir(String from, String to) {
-  ensureDir(path.dirname(to));
-  try {
-    renameDir(from, to);
-  } on FileSystemException catch (e) {
-    tryDeleteEntry(from);
-    if (!_isDirectoryNotEmptyException(e)) {
+    try {
+      Directory(from).renameSync(to);
+    } on IOException {
+      // Ensure that [to] isn't left in an inconsistent state. See issue 12436.
+      if (entryExists(to)) deleteEntry(to);
       rethrow;
     }
-    log.fine('''
-Destination directory $to already existed.
-Assuming a concurrent pub invocation installed it.''');
-  }
-}
-
-void copyFile(String from, String to) {
-  log.io('Copying "$from" to "$to".');
-  File(from).copySync(to);
-}
-
-void renameFile(String from, String to) {
-  log.io('Renaming "$from" to "$to".');
-  File(from).renameSync(to);
-}
-
-bool _isDirectoryNotEmptyException(FileSystemException e) {
-  final errorCode = e.osError?.errorCode;
-  return
-      // On Linux rename will fail with ENOTEMPTY if directory exists:
-      // https://man7.org/linux/man-pages/man2/rename.2.html
-      // #define	ENOTEMPTY	39	/* Directory not empty */
-      // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/errno.h#n20
-      (Platform.isLinux && errorCode == 39) ||
-          // On Windows this may fail with ERROR_DIR_NOT_EMPTY
-          // https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
-          (Platform.isWindows && errorCode == 145) ||
-          // On MacOS rename will fail with ENOTEMPTY if directory exists.
-          // #define ENOTEMPTY       66              /* Directory not empty */
-          // https://github.com/apple-oss-distributions/xnu/blob/bb611c8fecc755a0d8e56e2fa51513527c5b7a0e/bsd/sys/errno.h#L190
-          (Platform.isMacOS && errorCode == 66);
+  });
 }
 
 /// Creates a new symlink at path [symlink] that points to [target].
@@ -601,6 +562,10 @@
   return path.fromUri(url);
 })();
 
+/// A line-by-line stream of standard input.
+final StreamQueue<String> _stdinLines = StreamQueue(
+    ByteStream(stdin).toStringStream().transform(const LineSplitter()));
+
 /// Displays a message and reads a yes/no confirmation from the user.
 ///
 /// Returns a [Future] that completes to `true` if the user confirms or `false`
@@ -626,14 +591,14 @@
     final previousEchoMode = stdin.echoMode;
     try {
       stdin.echoMode = echoMode;
-      final result = stdin.readLineSync() ?? '';
+      final result = await _stdinLines.next;
       stdout.write('\n');
       return result;
     } finally {
       stdin.echoMode = previousEchoMode;
     }
   } else {
-    return stdin.readLineSync() ?? '';
+    return await _stdinLines.next;
   }
 }
 
@@ -1007,10 +972,10 @@
   log.fine(buffer.toString());
 
   ArgumentError.checkNotNull(baseDir, 'baseDir');
-  baseDir = path.normalize(path.absolute(baseDir));
+  baseDir = path.absolute(baseDir);
 
   final tarContents = Stream.fromIterable(contents.map((entry) {
-    entry = path.normalize(path.absolute(entry));
+    entry = path.absolute(entry);
     if (!path.isWithin(baseDir, entry)) {
       throw ArgumentError('Entry $entry is not inside $baseDir.');
     }
diff --git a/lib/src/language_version.dart b/lib/src/language_version.dart
index ad331b2..e294014 100644
--- a/lib/src/language_version.dart
+++ b/lib/src/language_version.dart
@@ -69,21 +69,6 @@
 
   bool get supportsNullSafety => this >= firstVersionWithNullSafety;
 
-  /// Minimum language version at which short hosted syntax is supported.
-  ///
-  /// This allows `hosted` dependencies to be expressed as:
-  /// ```yaml
-  /// dependencies:
-  ///   foo:
-  ///     hosted: https://some-pub.com/path
-  ///     version: ^1.0.0
-  /// ```
-  ///
-  /// At older versions, `hosted` dependencies had to be a map with a `url` and
-  /// a `name` key.
-  bool get supportsShorterHostedSyntax =>
-      this >= firstVersionWithShorterHostedSyntax;
-
   @override
   int compareTo(LanguageVersion other) {
     if (major != other.major) return major.compareTo(other.major);
@@ -104,7 +89,6 @@
 
   static const defaultLanguageVersion = LanguageVersion(2, 7);
   static const firstVersionWithNullSafety = LanguageVersion(2, 12);
-  static const firstVersionWithShorterHostedSyntax = LanguageVersion(2, 15);
 
   /// Transform language version to string that can be parsed with
   /// [LanguageVersion.parse].
diff --git a/lib/src/lock_file.dart b/lib/src/lock_file.dart
index 8f563ab..e2723c7 100644
--- a/lib/src/lock_file.dart
+++ b/lib/src/lock_file.dart
@@ -218,7 +218,7 @@
   String packagesFile(
     SystemCache cache, {
     String? entrypoint,
-    String? relativeFrom,
+    required String relativeFrom,
   }) {
     var header = '''
 This file is deprecated. Tools should instead consume 
@@ -256,7 +256,7 @@
     SystemCache cache, {
     String? entrypoint,
     VersionConstraint? entrypointSdkConstraint,
-    String? relativeFrom,
+    required String relativeFrom,
   }) async {
     final entries = <PackageConfigEntry>[];
     for (final name in ordered(packages.keys)) {
@@ -306,9 +306,8 @@
   /// Returns the serialized YAML text of the lock file.
   ///
   /// [packageDir] is the containing directory of the root package, used to
-  /// serialize relative path package descriptions. If it is null, they will be
-  /// serialized as absolute.
-  String serialize(String? packageDir) {
+  /// properly serialize package descriptions.
+  String serialize(String packageDir) {
     // Convert the dependencies to a simple object.
     var packageMap = {};
     packages.forEach((name, package) {
diff --git a/lib/src/log.dart b/lib/src/log.dart
index db24d7a..ff7fe29 100644
--- a/lib/src/log.dart
+++ b/lib/src/log.dart
@@ -12,11 +12,9 @@
 import 'package:source_span/source_span.dart';
 import 'package:stack_trace/stack_trace.dart';
 
-import 'entrypoint.dart';
 import 'exceptions.dart';
 import 'io.dart';
 import 'progress.dart';
-import 'sdk.dart';
 import 'transcript.dart';
 import 'utils.dart';
 
@@ -26,7 +24,7 @@
 final json = _JsonLogger();
 
 /// The current logging verbosity.
-Verbosity verbosity = Verbosity.normal;
+Verbosity verbosity = Verbosity.NORMAL;
 
 /// In cases where there's a ton of log spew, make sure we don't eat infinite
 /// memory.
@@ -34,11 +32,11 @@
 /// This can occur when the backtracking solver stumbles into a pathological
 /// dependency graph. It generally will find a solution, but it may log
 /// thousands and thousands of entries to get there.
-const _maxTranscript = 10000;
+const _MAX_TRANSCRIPT = 10000;
 
 /// The list of recorded log messages. Will only be recorded if
 /// [recordTranscript()] is called.
-final Transcript<_Entry> _transcript = Transcript(_maxTranscript);
+Transcript<_Entry>? _transcript;
 
 /// The currently-animated progress indicator, if any.
 ///
@@ -60,34 +58,34 @@
 /// An enum type for defining the different logging levels a given message can
 /// be associated with.
 ///
-/// By default, [error] and [warning] messages are printed to sterr. [message]
+/// By default, [ERROR] and [WARNING] messages are printed to sterr. [MESSAGE]
 /// messages are printed to stdout, and others are ignored.
 class Level {
   /// An error occurred and an operation could not be completed.
   ///
   /// Usually shown to the user on stderr.
-  static const error = Level._('ERR ');
+  static const ERROR = Level._('ERR ');
 
   /// Something unexpected happened, but the program was able to continue,
   /// though possibly in a degraded fashion.
-  static const warning = Level._('WARN');
+  static const WARNING = Level._('WARN');
 
   /// A message intended specifically to be shown to the user.
-  static const message = Level._('MSG ');
+  static const MESSAGE = Level._('MSG ');
 
   /// Some interaction with the external world occurred, such as a network
   /// operation, process spawning, or file IO.
-  static const io = Level._('IO  ');
+  static const IO = Level._('IO  ');
 
   /// Incremental output during pub's version constraint solver.
-  static const solver = Level._('SLVR');
+  static const SOLVER = Level._('SLVR');
 
   /// Fine-grained and verbose additional information.
   ///
   /// Used to provide program state context for other logs (such as what pub
   /// was doing when an IO operation occurred) or just more detail for an
   /// operation.
-  static const fine = Level._('FINE');
+  static const FINE = Level._('FINE');
 
   const Level._(this.name);
 
@@ -101,83 +99,73 @@
 /// displayed.
 class Verbosity {
   /// Silence all logging.
-  static const none = Verbosity._('none', {
-    Level.error: null,
-    Level.warning: null,
-    Level.message: null,
-    Level.io: null,
-    Level.solver: null,
-    Level.fine: null
+  static const NONE = Verbosity._('none', {
+    Level.ERROR: null,
+    Level.WARNING: null,
+    Level.MESSAGE: null,
+    Level.IO: null,
+    Level.SOLVER: null,
+    Level.FINE: null
   });
 
   /// Shows only errors.
-  static const error = Verbosity._('error', {
-    Level.error: _logToStderr,
-    Level.warning: null,
-    Level.message: null,
-    Level.io: null,
-    Level.solver: null,
-    Level.fine: null
+  static const ERROR = Verbosity._('error', {
+    Level.ERROR: _logToStderr,
+    Level.WARNING: null,
+    Level.MESSAGE: null,
+    Level.IO: null,
+    Level.SOLVER: null,
+    Level.FINE: null
   });
 
   /// Shows only errors and warnings.
-  static const warning = Verbosity._('warning', {
-    Level.error: _logToStderr,
-    Level.warning: _logToStderr,
-    Level.message: null,
-    Level.io: null,
-    Level.solver: null,
-    Level.fine: null
+  static const WARNING = Verbosity._('warning', {
+    Level.ERROR: _logToStderr,
+    Level.WARNING: _logToStderr,
+    Level.MESSAGE: null,
+    Level.IO: null,
+    Level.SOLVER: null,
+    Level.FINE: null
   });
 
   /// The default verbosity which shows errors, warnings, and messages.
-  static const normal = Verbosity._('normal', {
-    Level.error: _logToStderr,
-    Level.warning: _logToStderr,
-    Level.message: _logToStdout,
-    Level.io: null,
-    Level.solver: null,
-    Level.fine: null
+  static const NORMAL = Verbosity._('normal', {
+    Level.ERROR: _logToStderr,
+    Level.WARNING: _logToStderr,
+    Level.MESSAGE: _logToStdout,
+    Level.IO: null,
+    Level.SOLVER: null,
+    Level.FINE: null
   });
 
   /// Shows errors, warnings, messages, and IO event logs.
-  static const io = Verbosity._('io', {
-    Level.error: _logToStderrWithLabel,
-    Level.warning: _logToStderrWithLabel,
-    Level.message: _logToStdoutWithLabel,
-    Level.io: _logToStderrWithLabel,
-    Level.solver: null,
-    Level.fine: null
+  static const IO = Verbosity._('io', {
+    Level.ERROR: _logToStderrWithLabel,
+    Level.WARNING: _logToStderrWithLabel,
+    Level.MESSAGE: _logToStdoutWithLabel,
+    Level.IO: _logToStderrWithLabel,
+    Level.SOLVER: null,
+    Level.FINE: null
   });
 
   /// Shows errors, warnings, messages, and version solver logs.
-  static const solver = Verbosity._('solver', {
-    Level.error: _logToStderr,
-    Level.warning: _logToStderr,
-    Level.message: _logToStdout,
-    Level.io: null,
-    Level.solver: _logToStdout,
-    Level.fine: null
+  static const SOLVER = Verbosity._('solver', {
+    Level.ERROR: _logToStderr,
+    Level.WARNING: _logToStderr,
+    Level.MESSAGE: _logToStdout,
+    Level.IO: null,
+    Level.SOLVER: _logToStdout,
+    Level.FINE: null
   });
 
   /// Shows all logs.
-  static const all = Verbosity._('all', {
-    Level.error: _logToStderrWithLabel,
-    Level.warning: _logToStderrWithLabel,
-    Level.message: _logToStdoutWithLabel,
-    Level.io: _logToStderrWithLabel,
-    Level.solver: _logToStderrWithLabel,
-    Level.fine: _logToStderrWithLabel
-  });
-
-  /// Shows all logs.
-  static const testing = Verbosity._('testing', {
-    Level.error: _logToStderrWithLabel,
-    Level.warning: _logToStderrWithLabel,
-    Level.message: _logToStdoutWithLabel,
-    Level.io: _logToStderrWithLabel,
-    Level.solver: _logToStderrWithLabel,
-    Level.fine: _logToStderrWithLabel
+  static const ALL = Verbosity._('all', {
+    Level.ERROR: _logToStderrWithLabel,
+    Level.WARNING: _logToStderrWithLabel,
+    Level.MESSAGE: _logToStdoutWithLabel,
+    Level.IO: _logToStderrWithLabel,
+    Level.SOLVER: _logToStderrWithLabel,
+    Level.FINE: _logToStderrWithLabel
   });
 
   const Verbosity._(this.name, this._loggers);
@@ -200,7 +188,7 @@
   _Entry(this.level, this.lines);
 }
 
-/// Logs [message] at [Level.error].
+/// Logs [message] at [Level.ERROR].
 ///
 /// If [error] is passed, it's appended to [message]. If [trace] is passed, it's
 /// printed at log level fine.
@@ -210,24 +198,24 @@
     message = message.isEmpty ? '$error' : '$message: $error';
     if (error is Error && trace == null) trace = error.stackTrace;
   }
-  write(Level.error, message);
-  if (trace != null) write(Level.fine, Chain.forTrace(trace));
+  write(Level.ERROR, message);
+  if (trace != null) write(Level.FINE, Chain.forTrace(trace));
 }
 
-/// Logs [message] at [Level.warning].
-void warning(message) => write(Level.warning, message);
+/// Logs [message] at [Level.WARNING].
+void warning(message) => write(Level.WARNING, message);
 
-/// Logs [message] at [Level.message].
-void message(message) => write(Level.message, message);
+/// Logs [message] at [Level.MESSAGE].
+void message(message) => write(Level.MESSAGE, message);
 
-/// Logs [message] at [Level.io].
-void io(message) => write(Level.io, message);
+/// Logs [message] at [Level.IO].
+void io(message) => write(Level.IO, message);
 
-/// Logs [message] at [Level.solver].
-void solver(message) => write(Level.solver, message);
+/// Logs [message] at [Level.SOLVER].
+void solver(message) => write(Level.SOLVER, message);
 
-/// Logs [message] at [Level.fine].
-void fine(message) => write(Level.fine, message);
+/// Logs [message] at [Level.FINE].
+void fine(message) => write(Level.FINE, message);
 
 /// Logs [message] at [level].
 void write(Level level, message) {
@@ -245,10 +233,10 @@
   var logFn = verbosity._loggers[level];
   if (logFn != null) logFn(entry);
 
-  _transcript.add(entry);
+  if (_transcript != null) _transcript!.add(entry);
 }
 
-/// Logs the spawning of an [executable] process with [arguments] at [io]
+/// Logs the spawning of an [executable] process with [arguments] at [IO]
 /// level.
 void process(
     String executable, List<String> arguments, String workingDirectory) {
@@ -325,10 +313,18 @@
   }
 }
 
-/// Prints the recorded log transcript to stderr.
-void dumpTranscriptToStdErr() {
+/// Enables recording of log entries.
+void recordTranscript() {
+  _transcript = Transcript<_Entry>(_MAX_TRANSCRIPT);
+}
+
+/// If [recordTranscript()] was called, then prints the previously recorded log
+/// transcript to stderr.
+void dumpTranscript() {
+  if (_transcript == null) return;
+
   stderr.writeln('---- Log transcript ----');
-  _transcript.forEach((entry) {
+  _transcript!.forEach((entry) {
     _printToStream(stderr, entry, showLabel: true);
   }, (discarded) {
     stderr.writeln('---- ($discarded discarded) ----');
@@ -336,68 +332,6 @@
   stderr.writeln('---- End log transcript ----');
 }
 
-String _limit(String input, int limit) {
-  const snip = '[...]';
-  if (input.length < limit - snip.length) return input;
-  return '${input.substring(0, limit ~/ 2 - snip.length)}'
-      '$snip'
-      '${input.substring(limit)}';
-}
-
-/// Prints relevant system information and the log transcript to [path].
-void dumpTranscriptToFile(String path, String command, Entrypoint? entrypoint) {
-  final buffer = StringBuffer();
-  buffer.writeln('''
-Information about the latest pub run.
-
-If you believe something is not working right, you can go to 
-https://github.com/dart-lang/pub/issues/new to post a new issue and attach this file.
-
-Before making this file public, make sure to remove any sensitive information!
-
-Pub version: ${sdk.version}
-Created: ${DateTime.now().toIso8601String()}
-FLUTTER_ROOT: ${Platform.environment['FLUTTER_ROOT'] ?? '<not set>'}
-PUB_HOSTED_URL: ${Platform.environment['PUB_HOSTED_URL'] ?? '<not set>'}
-PUB_CACHE: "${Platform.environment['PUB_CACHE'] ?? '<not set>'}"
-Command: $command
-Platform: ${Platform.operatingSystem}
-''');
-
-  if (entrypoint != null) {
-    buffer.writeln('---- ${p.absolute(entrypoint.pubspecPath)} ----');
-    if (fileExists(entrypoint.pubspecPath)) {
-      buffer.writeln(_limit(readTextFile(entrypoint.pubspecPath), 5000));
-    } else {
-      buffer.writeln('<No pubspec.yaml>');
-    }
-    buffer.writeln('---- End pubspec.yaml ----');
-    buffer.writeln('---- ${p.absolute(entrypoint.lockFilePath)} ----');
-    if (fileExists(entrypoint.lockFilePath)) {
-      buffer.writeln(_limit(readTextFile(entrypoint.lockFilePath), 5000));
-    } else {
-      buffer.writeln('<No pubspec.lock>');
-    }
-    buffer.writeln('---- End pubspec.lock ----');
-  }
-
-  buffer.writeln('---- Log transcript ----');
-
-  _transcript.forEach((entry) {
-    _printToStream(buffer, entry, showLabel: true);
-  }, (discarded) {
-    buffer.writeln('---- ($discarded entries discarded) ----');
-  });
-  buffer.writeln('---- End log transcript ----');
-  ensureDir(p.dirname(path));
-  try {
-    writeTextFile(path, buffer.toString(), dontLogContents: true);
-  } on IOException catch (e) {
-    stderr.writeln('Failed writing log to `$path` ($e), writing it to stderr:');
-    dumpTranscriptToStdErr();
-  }
-}
-
 /// Filter out normal pub output when not attached to a terminal
 ///
 /// Unless the user has overriden the verbosity,
@@ -405,8 +339,8 @@
 /// This is useful to not pollute stdout when the output is piped somewhere.
 Future<T> warningsOnlyUnlessTerminal<T>(FutureOr<T> Function() callback) async {
   final oldVerbosity = verbosity;
-  if (verbosity == Verbosity.normal && !stdout.hasTerminal) {
-    verbosity = Verbosity.warning;
+  if (verbosity == Verbosity.NORMAL && !stdout.hasTerminal) {
+    verbosity = Verbosity.WARNING;
   }
   final result = await callback();
   verbosity = oldVerbosity;
@@ -419,7 +353,7 @@
 /// If anything else is logged during this (including another call to
 /// [progress]) that cancels the progress animation, although the total time
 /// will still be printed once it finishes. If [fine] is passed, the progress
-/// information will only be visible at [Level.fine].
+/// information will only be visible at [Level.FINE].
 Future<T> progress<T>(String message, Future<T> Function() callback) {
   _stopProgress();
 
@@ -558,7 +492,7 @@
   _printToStream(sink, entry, showLabel: showLabel);
 }
 
-void _printToStream(StringSink sink, _Entry entry, {required bool showLabel}) {
+void _printToStream(IOSink sink, _Entry entry, {required bool showLabel}) {
   _stopProgress();
 
   var firstLine = true;
diff --git a/lib/src/null_safety_analysis.dart b/lib/src/null_safety_analysis.dart
index 5b882a8..2ad034d 100644
--- a/lib/src/null_safety_analysis.dart
+++ b/lib/src/null_safety_analysis.dart
@@ -109,7 +109,7 @@
     SolveResult result;
     try {
       result = await resolveVersions(
-        SolveType.get,
+        SolveType.GET,
         _systemCache,
         fakeRoot,
       );
diff --git a/lib/src/package.dart b/lib/src/package.dart
index d100157..0bc6f89 100644
--- a/lib/src/package.dart
+++ b/lib/src/package.dart
@@ -83,12 +83,10 @@
       ..addAll(dependencyOverrides);
   }
 
-  /// Returns a list of paths to all Dart executables in this package's bin
+  /// Returns a list of asset ids for all Dart executables in this package's bin
   /// directory.
   List<String> get executablePaths {
-    final binDir = p.join(dir, 'bin');
-    if (!dirExists(binDir)) return <String>[];
-    return ordered(listDir(p.join(dir, 'bin'), includeDirs: false))
+    return ordered(listFiles(beneath: 'bin', recursive: false))
         .where((executable) => p.extension(executable) == '.dart')
         .map((executable) => p.relative(executable, from: dir))
         .toList();
diff --git a/lib/src/package_config.dart b/lib/src/package_config.dart
index d64808b..0493dcc 100644
--- a/lib/src/package_config.dart
+++ b/lib/src/package_config.dart
@@ -2,8 +2,6 @@
 // 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 'dart:convert';
-
 import 'package:pub_semver/pub_semver.dart';
 
 import 'language_version.dart';
@@ -162,6 +160,8 @@
   /// Given as `<major>.<minor>` version, similar to the `// @dart = X.Y`
   /// comment. This is derived from the lower-bound on the Dart SDK requirement
   /// in the `pubspec.yaml` for the given package.
+  ///
+  /// `null` if not given.
   LanguageVersion? languageVersion;
 
   /// Additional properties not in the specification for the
@@ -173,8 +173,10 @@
     required this.rootUri,
     this.packageUri,
     this.languageVersion,
-    this.additionalProperties = const {},
-  });
+    this.additionalProperties,
+  }) {
+    additionalProperties ??= {};
+  }
 
   /// Create [PackageConfigEntry] from JSON [data].
   ///
@@ -247,13 +249,7 @@
   Map<String, Object?> toJson() => {
         'name': name,
         'rootUri': rootUri.toString(),
-        if (packageUri != null) 'packageUri': packageUri.toString(),
+        if (packageUri != null) 'packageUri': packageUri?.toString(),
         if (languageVersion != null) 'languageVersion': '$languageVersion',
       }..addAll(additionalProperties ?? {});
-
-  @override
-  String toString() {
-    // TODO: implement toString
-    return JsonEncoder.withIndent('  ').convert(toJson());
-  }
 }
diff --git a/lib/src/package_name.dart b/lib/src/package_name.dart
index d83f466..50f4bcc 100644
--- a/lib/src/package_name.dart
+++ b/lib/src/package_name.dart
@@ -57,10 +57,6 @@
   }
 
   @override
-  bool operator ==(Object other) =>
-      throw UnimplementedError('Subclass should implement ==');
-
-  @override
   int get hashCode {
     var thisSource = source;
     if (thisSource == null) return name.hashCode;
@@ -108,9 +104,6 @@
 
   @override
   bool operator ==(other) => other is PackageRef && samePackage(other);
-
-  @override
-  int get hashCode => super.hashCode ^ 'PackageRef'.hashCode;
 }
 
 /// A reference to a specific version of a package.
diff --git a/lib/src/progress.dart b/lib/src/progress.dart
index b9c6931..06ad9e9 100644
--- a/lib/src/progress.dart
+++ b/lib/src/progress.dart
@@ -34,7 +34,7 @@
   Progress(this._message, {bool fine = false}) {
     _stopwatch.start();
 
-    var level = fine ? log.Level.fine : log.Level.message;
+    var level = fine ? log.Level.FINE : log.Level.MESSAGE;
 
     // The animation is only shown when it would be meaningful to a human.
     // That means we're writing a visible message to a TTY at normal log levels
@@ -43,7 +43,7 @@
         !log.verbosity.isLevelVisible(level) ||
         log.json.enabled ||
         fine ||
-        log.verbosity.isLevelVisible(log.Level.fine)) {
+        log.verbosity.isLevelVisible(log.Level.FINE)) {
       // Not animating, so just log the start and wait until the task is
       // completed.
       log.write(level, '$_message...');
diff --git a/lib/src/pub_embeddable_command.dart b/lib/src/pub_embeddable_command.dart
index b9e59c6..c1fa863 100644
--- a/lib/src/pub_embeddable_command.dart
+++ b/lib/src/pub_embeddable_command.dart
@@ -58,13 +58,11 @@
   @override
   final PubAnalytics? analytics;
 
-  final bool Function() isVerbose;
-
-  PubEmbeddableCommand(this.analytics, this.isVerbose) : super() {
+  PubEmbeddableCommand(this.analytics) : super() {
     argParser.addFlag('trace',
         help: 'Print debugging information when an error occurs.');
     argParser.addFlag('verbose',
-        abbr: 'v', negatable: false, help: 'Print detailed logging.');
+        abbr: 'v', negatable: false, help: 'Shortcut for "--verbosity=all".');
     argParser.addOption(
       'directory',
       abbr: 'C',
@@ -103,15 +101,12 @@
   }
 
   @override
-  bool get captureStackChains => _isVerbose;
+  bool get captureStackChains => argResults['verbose'];
 
   @override
-  Verbosity get verbosity => _isVerbose ? Verbosity.all : Verbosity.normal;
+  Verbosity get verbosity =>
+      argResults['verbose'] ? Verbosity.ALL : Verbosity.NORMAL;
 
   @override
-  bool get trace => _isVerbose;
-
-  bool get _isVerbose {
-    return argResults['verbose'] || isVerbose();
-  }
+  bool get trace => argResults['verbose'];
 }
diff --git a/lib/src/rate_limited_scheduler.dart b/lib/src/rate_limited_scheduler.dart
index 85d73cd..2d301d3 100644
--- a/lib/src/rate_limited_scheduler.dart
+++ b/lib/src/rate_limited_scheduler.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 import 'dart:collection';
 
+import 'package:pedantic/pedantic.dart';
 import 'package:pool/pool.dart';
 
 /// Handles rate-limited scheduling of tasks.
diff --git a/lib/src/solver/failure.dart b/lib/src/solver/failure.dart
index 60f70c5..ba27a3b 100644
--- a/lib/src/solver/failure.dart
+++ b/lib/src/solver/failure.dart
@@ -7,6 +7,7 @@
 import '../exceptions.dart';
 import '../log.dart' as log;
 import '../package_name.dart';
+import '../sdk.dart';
 import '../utils.dart';
 import 'incompatibility.dart';
 import 'incompatibility_cause.dart';
@@ -92,20 +93,39 @@
   String write() {
     var buffer = StringBuffer();
 
-    // Find all notices from incompatibility causes. This allows an
-    // [IncompatibilityCause] to provide a notice that is printed before the
-    // explanation of the conflict.
-    // Notably, this is used for stating which SDK version is currently
-    // installed, if an SDK is incompatible with a dependency.
-    final notices = _root.externalIncompatibilities
-        .map((c) => c.cause.notice)
-        .whereNotNull()
-        .toSet() // Avoid duplicates
-        .sortedBy((n) => n); // sort for consistency
-    for (final n in notices) {
-      buffer.writeln(n);
+    // SDKs whose version constraints weren't matched.
+    var sdkConstraintCauses = <Sdk>{};
+
+    // SDKs implicated in any way in the solve failure.
+    var sdkCauses = <Sdk>{};
+
+    for (var incompatibility in _root.externalIncompatibilities) {
+      var cause = incompatibility.cause;
+      if (cause is PackageNotFoundCause) {
+        var sdk = cause.sdk;
+        if (sdk != null) {
+          sdkCauses.add(sdk);
+        }
+      } else if (cause is SdkCause) {
+        sdkCauses.add(cause.sdk);
+        sdkConstraintCauses.add(cause.sdk);
+      }
     }
-    if (notices.isNotEmpty) buffer.writeln();
+
+    // If the failure was caused in part by unsatisfied SDK constraints,
+    // indicate the actual versions so we don't have to list them (possibly
+    // multiple times) in the main body of the error message.
+    //
+    // Iterate through [sdks] to ensure that SDKs versions are printed in a
+    // consistent order
+    var wroteLine = false;
+    for (var sdk in sdks.values) {
+      if (!sdkConstraintCauses.contains(sdk)) continue;
+      if (!sdk.isAvailable) continue;
+      wroteLine = true;
+      buffer.writeln('The current ${sdk.name} SDK version is ${sdk.version}.');
+    }
+    if (wroteLine) buffer.writeln();
 
     if (_root.cause is ConflictCause) {
       _visit(_root, const {});
@@ -139,21 +159,15 @@
       buffer.writeln(wordWrap(message, prefix: ' ' * (padding + 2)));
     }
 
-    // Iterate through all hints, these are intended to be actionable, such as:
-    //  * How to install an SDK, and,
-    //  * How to provide authentication.
-    // Hence, it makes sense to show these at the end of the explanation, as the
-    // user will ideally see these before reading the actual conflict and
-    // understand how to fix the issue.
-    _root.externalIncompatibilities
-        .map((c) => c.cause.hint)
-        .whereNotNull()
-        .toSet() // avoid duplicates
-        .sortedBy((hint) => hint) // sort hints for consistent ordering.
-        .forEach((hint) {
+    // Iterate through [sdks] to ensure that SDKs versions are printed in a
+    // consistent order
+    for (var sdk in sdks.values) {
+      if (!sdkCauses.contains(sdk)) continue;
+      if (sdk.isAvailable) continue;
+      if (sdk.installMessage == null) continue;
       buffer.writeln();
-      buffer.writeln(hint);
-    });
+      buffer.writeln(sdk.installMessage);
+    }
 
     return buffer.toString();
   }
diff --git a/lib/src/solver/incompatibility_cause.dart b/lib/src/solver/incompatibility_cause.dart
index a2a2327..53dcfe2 100644
--- a/lib/src/solver/incompatibility_cause.dart
+++ b/lib/src/solver/incompatibility_cause.dart
@@ -10,8 +10,6 @@
 
 /// The reason an [Incompatibility]'s terms are incompatible.
 abstract class IncompatibilityCause {
-  const IncompatibilityCause._();
-
   /// The incompatibility represents the requirement that the root package
   /// exists.
   static const IncompatibilityCause root = _Cause('root');
@@ -29,26 +27,11 @@
 
   /// The incompatibility indicates that the package has an unknown source.
   static const IncompatibilityCause unknownSource = _Cause('unknown source');
-
-  /// Human readable notice / information providing context for this
-  /// incompatibility.
-  ///
-  /// This may be multiple lines, and will be printed before the explanation.
-  /// This is used highlight information that is useful for understanding the
-  /// why this conflict happened.
-  String? get notice => null;
-
-  /// Human readable hint indicating how this incompatibility may be resolved.
-  ///
-  /// This may be multiple lines, and will be printed after the explanation.
-  /// This should only be included if it is actionable and likely to resolve the
-  /// issue for the user.
-  String? get hint => null;
 }
 
 /// The incompatibility was derived from two existing incompatibilities during
 /// conflict resolution.
-class ConflictCause extends IncompatibilityCause {
+class ConflictCause implements IncompatibilityCause {
   /// The incompatibility that was originally found to be in conflict, from
   /// which the target incompatibility was derived.
   final Incompatibility conflict;
@@ -57,14 +40,14 @@
   /// from which the target incompatibility was derived.
   final Incompatibility other;
 
-  ConflictCause(this.conflict, this.other) : super._();
+  ConflictCause(this.conflict, this.other);
 }
 
 /// A class for stateless [IncompatibilityCause]s.
-class _Cause extends IncompatibilityCause {
+class _Cause implements IncompatibilityCause {
   final String _name;
 
-  const _Cause(this._name) : super._();
+  const _Cause(this._name);
 
   @override
   String toString() => _name;
@@ -72,7 +55,7 @@
 
 /// The incompatibility represents a package's SDK constraint being
 /// incompatible with the current SDK.
-class SdkCause extends IncompatibilityCause {
+class SdkCause implements IncompatibilityCause {
   /// The union of all the incompatible versions' constraints on the SDK.
   // TODO(zarah): Investigate if this can be non-nullable
   final VersionConstraint? constraint;
@@ -80,41 +63,20 @@
   /// The SDK with which the package was incompatible.
   final Sdk sdk;
 
-  @override
-  String? get notice {
-    // If the SDK is not available, then we have an actionable [hint] printed
-    // after the explanation. So we don't need to state that the SDK is not
-    // available.
-    if (!sdk.isAvailable) {
-      return null;
-    }
-    // If the SDK is available and we have an incompatibility, then the user has
-    // the wrong SDK version (one that is not compatible with any solution).
-    // Thus, it makes sense to highlight the current SDK version.
-    return 'The current ${sdk.name} SDK version is ${sdk.version}.';
-  }
-
-  @override
-  String? get hint {
-    // If the SDK is available, then installing it won't help
-    if (sdk.isAvailable) {
-      return null;
-    }
-    // Return an install message for the SDK, if there is an install message.
-    return sdk.installMessage;
-  }
-
-  SdkCause(this.constraint, this.sdk) : super._();
+  SdkCause(this.constraint, this.sdk);
 }
 
 /// The incompatibility represents a package that couldn't be found by its
 /// source.
-class PackageNotFoundCause extends IncompatibilityCause {
+class PackageNotFoundCause implements IncompatibilityCause {
   /// The exception indicating why the package couldn't be found.
   final PackageNotFoundException exception;
 
-  PackageNotFoundCause(this.exception) : super._();
+  /// If the incompatibility was caused by an SDK being unavailable, this is
+  /// that SDK.
+  ///
+  /// Otherwise `null`.
+  Sdk? get sdk => exception.missingSdk;
 
-  @override
-  String? get hint => exception.hint;
+  PackageNotFoundCause(this.exception);
 }
diff --git a/lib/src/solver/report.dart b/lib/src/solver/report.dart
index e3dd5dc..e345413 100644
--- a/lib/src/solver/report.dart
+++ b/lib/src/solver/report.dart
@@ -89,7 +89,7 @@
       }
     } else {
       if (numChanged == 0) {
-        if (_type == SolveType.get) {
+        if (_type == SolveType.GET) {
           log.message('Got dependencies$suffix!');
         } else {
           log.message('No dependencies changed$suffix.');
@@ -245,7 +245,7 @@
     String? message;
     // See if there are any newer versions of the package that we were
     // unable to upgrade to.
-    if (newId != null && _type != SolveType.downgrade) {
+    if (newId != null && _type != SolveType.DOWNGRADE) {
       var versions = _result.availableVersions[newId.name]!;
 
       var newerStable = false;
@@ -292,7 +292,7 @@
       }
     }
 
-    if (_type == SolveType.get &&
+    if (_type == SolveType.GET &&
         !(alwaysShow || changed || addedOrRemoved || message != null)) {
       return;
     }
diff --git a/lib/src/solver/result.dart b/lib/src/solver/result.dart
index bc01162..692b05f 100644
--- a/lib/src/solver/result.dart
+++ b/lib/src/solver/result.dart
@@ -5,7 +5,6 @@
 import 'package:collection/collection.dart';
 import 'package:pub_semver/pub_semver.dart';
 
-import '../http.dart';
 import '../io.dart';
 import '../lock_file.dart';
 import '../log.dart' as log;
@@ -13,7 +12,6 @@
 import '../package_name.dart';
 import '../pub_embeddable_command.dart';
 import '../pubspec.dart';
-import '../source/cached.dart';
 import '../source/hosted.dart';
 import '../source_registry.dart';
 import '../system_cache.dart';
@@ -80,18 +78,6 @@
 
   final LockFile _previousLockFile;
 
-  /// Downloads all cached packages in [packages].
-  Future<void> downloadCachedPackages(SystemCache cache) async {
-    await Future.wait(packages.map((id) async {
-      if (id.source == null) return;
-      final source = cache.source(id.source);
-      if (source is! CachedSource) return;
-      return await withDependencyType(_root.dependencyType(id.name), () async {
-        await source.downloadToSystemCache(id);
-      });
-    }));
-  }
-
   /// Returns the names of all packages that were changed.
   ///
   /// This includes packages that were added or removed.
@@ -136,7 +122,7 @@
     final report =
         SolveReport(type, _sources, _root, _previousLockFile, this, cache);
     report.summarize(dryRun: dryRun);
-    if (type == SolveType.upgrade) {
+    if (type == SolveType.UPGRADE) {
       await report.reportDiscontinued();
       report.reportOutdated();
     }
diff --git a/lib/src/solver/type.dart b/lib/src/solver/type.dart
index 28a3230..c899e31 100644
--- a/lib/src/solver/type.dart
+++ b/lib/src/solver/type.dart
@@ -6,15 +6,15 @@
 class SolveType {
   /// As few changes to the lockfile as possible to be consistent with the
   /// pubspec.
-  static const get = SolveType._('get');
+  static const GET = SolveType._('get');
 
   /// Upgrade all packages or specific packages to the highest versions
   /// possible, regardless of the lockfile.
-  static const upgrade = SolveType._('upgrade');
+  static const UPGRADE = SolveType._('upgrade');
 
   /// Downgrade all packages or specific packages to the lowest versions
   /// possible, regardless of the lockfile.
-  static const downgrade = SolveType._('downgrade');
+  static const DOWNGRADE = SolveType._('downgrade');
 
   final String _name;
 
diff --git a/lib/src/solver/version_solver.dart b/lib/src/solver/version_solver.dart
index d4e3a75..120244a 100644
--- a/lib/src/solver/version_solver.dart
+++ b/lib/src/solver/version_solver.dart
@@ -485,7 +485,7 @@
           _root.dependencyType(package.name),
           overridden,
           _getAllowedRetracted(ref.name),
-          downgrade: _type == SolveType.downgrade);
+          downgrade: _type == SolveType.DOWNGRADE);
     });
   }
 
@@ -493,7 +493,7 @@
   ///
   /// Returns `null` if it isn't in the lockfile (or has been unlocked).
   PackageId? _getLocked(String? package) {
-    if (_type == SolveType.get) {
+    if (_type == SolveType.GET) {
       if (_unlock.contains(package)) {
         return null;
       }
@@ -503,7 +503,7 @@
     // When downgrading, we don't want to force the latest versions of
     // non-hosted packages, since they don't support multiple versions and thus
     // can't be downgraded.
-    if (_type == SolveType.downgrade) {
+    if (_type == SolveType.DOWNGRADE) {
       var locked = _lockFile.packages[package];
       if (locked != null && !locked.source!.hasMultipleVersions) return locked;
     }
diff --git a/lib/src/source.dart b/lib/src/source.dart
index ecbc5eb..add55fa 100644
--- a/lib/src/source.dart
+++ b/lib/src/source.dart
@@ -116,7 +116,7 @@
   /// [description] in the right format.
   ///
   /// [containingPath] is the containing directory of the root package.
-  dynamic serializeDescription(String? containingPath, description) {
+  dynamic serializeDescription(String containingPath, description) {
     return description;
   }
 
diff --git a/lib/src/source/git.dart b/lib/src/source/git.dart
index 3be752c..0d98ae9 100644
--- a/lib/src/source/git.dart
+++ b/lib/src/source/git.dart
@@ -108,10 +108,10 @@
   /// For the descriptions where `relative` attribute is `true`, tries to make
   /// `url` relative to the specified [containingPath].
   @override
-  dynamic serializeDescription(String? containingPath, description) {
+  dynamic serializeDescription(String containingPath, description) {
     final copy = Map.from(description);
     copy.remove('relative');
-    if (description['relative'] == true && containingPath != null) {
+    if (description['relative'] == true) {
       copy['url'] = p.url.relative(description['url'],
           from: Uri.file(containingPath).toString());
     }
diff --git a/lib/src/source/hosted.dart b/lib/src/source/hosted.dart
index 2cfc52a..def4a98 100644
--- a/lib/src/source/hosted.dart
+++ b/lib/src/source/hosted.dart
@@ -10,6 +10,7 @@
     show maxBy, IterableNullableExtension;
 import 'package:http/http.dart' as http;
 import 'package:path/path.dart' as p;
+import 'package:pedantic/pedantic.dart';
 import 'package:pub_semver/pub_semver.dart';
 import 'package:stack_trace/stack_trace.dart';
 
@@ -159,7 +160,7 @@
   }
 
   @override
-  dynamic serializeDescription(String? containingPath, description) {
+  dynamic serializeDescription(String containingPath, description) {
     final desc = _asDescription(description);
     return _serializedDescriptionFor(desc.packageName, desc.uri);
   }
@@ -232,7 +233,8 @@
       return _HostedDescription(packageName, defaultUrl);
     }
 
-    final canUseShorthandSyntax = languageVersion.supportsShorterHostedSyntax;
+    final canUseShorthandSyntax =
+        languageVersion >= _minVersionForShorterHostedSyntax;
 
     if (description is String) {
       // Old versions of pub (pre Dart 2.15) interpret `hosted: foo` as
@@ -255,7 +257,7 @@
         } else {
           throw FormatException(
             'Using `hosted: <url>` is only supported with a minimum SDK '
-            'constraint of ${LanguageVersion.firstVersionWithShorterHostedSyntax}.',
+            'constraint of $_minVersionForShorterHostedSyntax.',
           );
         }
       }
@@ -270,7 +272,7 @@
 
     if (name is! String) {
       throw FormatException("The 'name' key must have a string value without "
-          'a minimum Dart SDK constraint of ${LanguageVersion.firstVersionWithShorterHostedSyntax}.0 or higher.');
+          'a minimum Dart SDK constraint of $_minVersionForShorterHostedSyntax.0 or higher.');
     }
 
     var url = defaultUrl;
@@ -285,6 +287,21 @@
     return _HostedDescription(name, url);
   }
 
+  /// Minimum language version at which short hosted syntax is supported.
+  ///
+  /// This allows `hosted` dependencies to be expressed as:
+  /// ```yaml
+  /// dependencies:
+  ///   foo:
+  ///     hosted: https://some-pub.com/path
+  ///     version: ^1.0.0
+  /// ```
+  ///
+  /// At older versions, `hosted` dependencies had to be a map with a `url` and
+  /// a `name` key.
+  static const LanguageVersion _minVersionForShorterHostedSyntax =
+      LanguageVersion(2, 15);
+
   static final RegExp _looksLikePackageName =
       RegExp(r'^[a-zA-Z_]+[a-zA-Z0-9_]*$');
 }
@@ -389,8 +406,8 @@
       body = decoded;
       result = _versionInfoFromPackageListing(body, ref, url);
     } on Exception catch (error, stackTrace) {
-      final packageName = source._asDescription(ref.description).packageName;
-      _throwFriendlyError(error, stackTrace, packageName, serverUrl);
+      var parsed = source._asDescription(ref.description);
+      _throwFriendlyError(error, stackTrace, parsed.packageName, parsed.uri);
     }
 
     // Cache the response on disk.
@@ -688,7 +705,6 @@
           packages.map((package) async {
             var id = source.idFor(package.name, package.version, url: url);
             try {
-              deleteEntry(package.dir);
               await _download(id, package.dir);
               return RepairResult(id, success: true);
             } catch (error, stackTrace) {
@@ -797,74 +813,51 @@
       var tempDir = systemCache.createTempDir();
       await extractTarGz(readBinaryFileAsSream(archivePath), tempDir);
 
+      // Remove the existing directory if it exists. This will happen if
+      // we're forcing a download to repair the cache.
+      if (dirExists(destPath)) deleteEntry(destPath);
+
       // Now that the get has succeeded, move it to the real location in the
-      // cache.
-      //
-      // If this fails with a "directory not empty" exception we assume that
-      // another pub process has installed the same package version while we
-      // downloaded.
-      tryRenameDir(tempDir, destPath);
+      // cache. This ensures that we don't leave half-busted ghost
+      // directories in the user's pub cache if a get fails.
+      renameDir(tempDir, destPath);
     });
   }
 
-  /// When an error occurs trying to read something about [package] from [hostedUrl],
+  /// When an error occurs trying to read something about [package] from [url],
   /// this tries to translate into a more user friendly error message.
   ///
   /// Always throws an error, either the original one or a better one.
   Never _throwFriendlyError(
-    Exception error,
+    error,
     StackTrace stackTrace,
     String package,
-    Uri hostedUrl,
+    Uri url,
   ) {
     if (error is PubHttpException) {
       if (error.response.statusCode == 404) {
         throw PackageNotFoundException(
-            'could not find package $package at $hostedUrl',
+            'could not find package $package at $url',
             innerError: error,
             innerTrace: stackTrace);
       }
 
       fail(
           '${error.response.statusCode} ${error.response.reasonPhrase} trying '
-          'to find package $package at $hostedUrl.',
+          'to find package $package at $url.',
           error,
           stackTrace);
     } else if (error is io.SocketException) {
-      fail('Got socket error trying to find package $package at $hostedUrl.',
-          error, stackTrace);
+      fail('Got socket error trying to find package $package at $url.', error,
+          stackTrace);
     } else if (error is io.TlsException) {
-      fail('Got TLS error trying to find package $package at $hostedUrl.',
-          error, stackTrace);
-    } else if (error is AuthenticationException) {
-      String? hint;
-      var message = 'authentication failed';
-
-      assert(error.statusCode == 401 || error.statusCode == 403);
-      if (error.statusCode == 401) {
-        hint = '$hostedUrl package repository requested authentication!\n'
-            'You can provide credentials using:\n'
-            '    pub token add $hostedUrl';
-      }
-      if (error.statusCode == 403) {
-        hint = 'Insufficient permissions to the resource at the $hostedUrl '
-            'package repository.\nYou can modify credentials using:\n'
-            '    pub token add $hostedUrl';
-        message = 'authorization failed';
-      }
-
-      if (error.serverMessage?.isNotEmpty == true && hint != null) {
-        hint += '\n${error.serverMessage}';
-      }
-
-      throw PackageNotFoundException(message, hint: hint);
+      fail('Got TLS error trying to find package $package at $url.', error,
+          stackTrace);
     } else if (error is FormatException) {
       throw PackageNotFoundException(
-        'Got badly formatted response trying to find package $package at $hostedUrl',
-        innerError: error,
-        innerTrace: stackTrace,
-        hint: 'Check that "$hostedUrl" is a valid package repository.',
-      );
+          'Got badly formatted response trying to find package $package at $url',
+          innerError: error,
+          innerTrace: stackTrace);
     } else {
       // Otherwise re-throw the original exception.
       throw error;
@@ -982,9 +975,7 @@
     // If there are no versions in the cache, report a clearer error.
     if (versions.isEmpty) {
       throw PackageNotFoundException(
-        'could not find package ${ref.name} in cache',
-        hint: 'Try again without --offline!',
-      );
+          'could not find package ${ref.name} in cache');
     }
 
     return versions;
@@ -1000,9 +991,7 @@
   @override
   Future<Pubspec> describeUncached(PackageId id) {
     throw PackageNotFoundException(
-      '${id.name} ${id.version} is not available in cache',
-      hint: 'Try again without --offline!',
-    );
+        '${id.name} ${id.version} is not available in your system cache');
   }
 
   @override
diff --git a/lib/src/source/path.dart b/lib/src/source/path.dart
index 4679f98..0401ebd 100644
--- a/lib/src/source/path.dart
+++ b/lib/src/source/path.dart
@@ -130,11 +130,9 @@
   ///
   /// For the descriptions where `relative` attribute is `true`, tries to make
   /// `path` relative to the specified [containingPath].
-  ///
-  /// If [containingPath] is `null` they are serialized as absolute.
   @override
-  dynamic serializeDescription(String? containingPath, description) {
-    if (description['relative'] == true && containingPath != null) {
+  dynamic serializeDescription(String containingPath, description) {
+    if (description['relative']) {
       return {
         'path': relativePathWithPosixSeparators(
             p.relative(description['path'], from: containingPath)),
diff --git a/lib/src/source/sdk.dart b/lib/src/source/sdk.dart
index 1458d1b..f1dde9e 100644
--- a/lib/src/source/sdk.dart
+++ b/lib/src/source/sdk.dart
@@ -101,10 +101,8 @@
     if (sdk == null) {
       throw PackageNotFoundException('unknown SDK "$identifier"');
     } else if (!sdk.isAvailable) {
-      throw PackageNotFoundException(
-        'the ${sdk.name} SDK is not available',
-        hint: sdk.installMessage,
-      );
+      throw PackageNotFoundException('the ${sdk.name} SDK is not available',
+          missingSdk: sdk);
     }
 
     var path = sdk.packagePath(package.name);
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 2a5768e..39439e9 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -375,7 +375,7 @@
 
   // If we're using verbose logging, be more verbose but more accurate when
   // reporting timing information.
-  var msString = log.verbosity.isLevelVisible(log.Level.fine)
+  var msString = log.verbosity.isLevelVisible(log.Level.FINE)
       ? _padLeft(ms.toString(), 3, '0')
       : (ms ~/ 100).toString();
 
diff --git a/lib/src/validator.dart b/lib/src/validator.dart
index 1b07560..29392fa 100644
--- a/lib/src/validator.dart
+++ b/lib/src/validator.dart
@@ -101,7 +101,7 @@
         'Make sure your SDK constraint excludes old versions:\n'
         '\n'
         'environment:\n'
-        '  sdk: "$newSdkConstraint"');
+        '  sdk: \"$newSdkConstraint\"');
   }
 
   /// Returns whether [version1] and [version2] are pre-releases of the same version.
diff --git a/lib/src/validator/changelog.dart b/lib/src/validator/changelog.dart
index 614eba2..694ace2 100644
--- a/lib/src/validator/changelog.dart
+++ b/lib/src/validator/changelog.dart
@@ -21,7 +21,7 @@
       final changelog = entrypoint.root.changelogPath;
 
       if (changelog == null) {
-        warnings.add('Please add a `CHANGELOG.md` to your package. '
+        warnings.add('Please add a`CHANGELOG.md` to your package. '
             'See https://dart.dev/tools/pub/publishing#important-files.');
         return;
       }
diff --git a/lib/src/validator/gitignore.dart b/lib/src/validator/gitignore.dart
index 4fb49b1..7770b57 100644
--- a/lib/src/validator/gitignore.dart
+++ b/lib/src/validator/gitignore.dart
@@ -46,10 +46,8 @@
         beneath: beneath,
         listDir: (dir) {
           var contents = Directory(resolve(dir)).listSync();
-          return contents
-              .where((e) => !(linkExists(e.path) && dirExists(e.path)))
-              .map((entity) => p.posix
-                  .joinAll(p.split(p.relative(entity.path, from: root))));
+          return contents.map((entity) =>
+              p.posix.joinAll(p.split(p.relative(entity.path, from: root))));
         },
         ignoreForDir: (dir) {
           final gitIgnore = resolve('$dir/.gitignore');
@@ -71,7 +69,7 @@
 
       if (ignoredFilesCheckedIn.isNotEmpty) {
         warnings.add('''
-${ignoredFilesCheckedIn.length} checked-in ${pluralize('file', ignoredFilesCheckedIn.length)} ${ignoredFilesCheckedIn.length == 1 ? 'is' : 'are'} ignored by a `.gitignore`.
+${ignoredFilesCheckedIn.length} checked in ${pluralize('file', ignoredFilesCheckedIn.length)} ${ignoredFilesCheckedIn.length == 1 ? 'is' : 'are'} ignored by a `.gitignore`.
 Previous versions of Pub would include those in the published package.
 
 Consider adjusting your `.gitignore` files to not ignore those files, and if you do not wish to
diff --git a/lib/src/validator/sdk_constraint.dart b/lib/src/validator/sdk_constraint.dart
index ff25e53..063ad7e 100644
--- a/lib/src/validator/sdk_constraint.dart
+++ b/lib/src/validator/sdk_constraint.dart
@@ -50,7 +50,7 @@
             'Expand it manually instead:\n'
             '\n'
             'environment:\n'
-            '  sdk: "$dartConstraintWithoutCaret"');
+            '  sdk: \"$dartConstraintWithoutCaret\"');
       }
 
       if (dartConstraint.max == null) {
diff --git a/lib/src/validator/size.dart b/lib/src/validator/size.dart
index e989518..8f258a9 100644
--- a/lib/src/validator/size.dart
+++ b/lib/src/validator/size.dart
@@ -10,7 +10,7 @@
 import '../validator.dart';
 
 /// The maximum size of the package to upload (100 MB).
-const _maxSize = 100 * 1024 * 1024;
+const _MAX_SIZE = 100 * 1024 * 1024;
 
 /// A validator that validates that a package isn't too big.
 class SizeValidator extends Validator {
@@ -21,7 +21,7 @@
   @override
   Future validate() {
     return packageSize.then((size) {
-      if (size <= _maxSize) return;
+      if (size <= _MAX_SIZE) return;
       var sizeInMb = (size / math.pow(2, 20)).toStringAsPrecision(4);
       // Current implementation of Package.listFiles skips hidden files
       var ignoreExists = fileExists(entrypoint.root.path('.gitignore'));
diff --git a/pubspec.yaml b/pubspec.yaml
index a7d9bb4..8c76708 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -18,6 +18,7 @@
   meta: ^1.3.0
   oauth2: ^2.0.0
   path: ^1.8.0
+  pedantic: ^1.11.0
   pool: ^1.5.0
   pub_semver: ^2.1.0
   shelf: ^1.1.1
@@ -28,7 +29,6 @@
   yaml_edit: ^2.0.0
 
 dev_dependencies:
-  lints: ^1.0.1
   shelf_test_handler: ^2.0.0
   test: ^1.17.3
   test_descriptor: ^2.0.0
diff --git a/test/add/common/add_test.dart b/test/add/common/add_test.dart
index 82e098b..e124be8 100644
--- a/test/add/common/add_test.dart
+++ b/test/add/common/add_test.dart
@@ -13,7 +13,7 @@
 
 void main() {
   test('URL encodes the package name', () async {
-    await servePackages();
+    await serveNoPackages();
 
     await d.appDir({}).create();
 
@@ -37,48 +37,49 @@
   });
 
   group('normally', () {
+    test('fails if extra arguments are passed', () async {
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.2');
+      });
+
+      await d.dir(appPath, [
+        d.pubspec({'name': 'myapp'})
+      ]).create();
+
+      await pubAdd(
+          args: ['foo', '^1.2.2'],
+          exitCode: exit_codes.USAGE,
+          error: contains('Takes only a single argument.'));
+
+      await d.dir(appPath, [
+        d.pubspec({
+          'name': 'myapp',
+        }),
+        d.nothing('.dart_tool/package_config.json'),
+        d.nothing('pubspec.lock'),
+        d.nothing('.packages'),
+      ]).validate();
+    });
+
     test('adds a package from a pub server', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
+      await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
       await d.appDir({}).create();
 
       await pubAdd(args: ['foo:1.2.3']);
 
       await d.cacheDir({'foo': '1.2.3'}).validate();
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.2.3'}).validate();
       await d.appDir({'foo': '1.2.3'}).validate();
     });
 
-    test('adds multiple package from a pub server', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
-      server.serve('bar', '1.1.0');
-      server.serve('baz', '2.5.3');
-
-      await d.appDir({}).create();
-
-      await pubAdd(args: ['foo:1.2.3', 'bar:1.1.0', 'baz:2.5.3']);
-
-      await d.cacheDir(
-          {'foo': '1.2.3', 'bar': '1.1.0', 'baz': '2.5.3'}).validate();
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-        d.packageConfigEntry(name: 'bar', version: '1.1.0'),
-        d.packageConfigEntry(name: 'baz', version: '2.5.3'),
-      ]).validate();
-      await d
-          .appDir({'foo': '1.2.3', 'bar': '1.1.0', 'baz': '2.5.3'}).validate();
-    });
-
     test(
         'does not remove empty dev_dependencies while adding to normal dependencies',
         () async {
-      await servePackages()
-        ..serve('foo', '1.2.3')
-        ..serve('foo', '1.2.2');
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3');
+        builder.serve('foo', '1.2.2');
+      });
 
       await d.dir(appPath, [
         d.file('pubspec.yaml', '''
@@ -95,9 +96,7 @@
       await pubAdd(args: ['foo:1.2.3']);
 
       await d.cacheDir({'foo': '1.2.3'}).validate();
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.2.3'}).validate();
 
       await d.dir(appPath, [
         d.pubspec({
@@ -110,8 +109,7 @@
 
     test('dry run does not actually add the package or modify the pubspec',
         () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
+      await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
       await d.appDir({}).create();
 
@@ -133,8 +131,7 @@
     test(
         'adds a package from a pub server even when dependencies key does not exist',
         () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
+      await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
       await d.dir(appPath, [
         d.pubspec({'name': 'myapp'})
@@ -143,17 +140,16 @@
       await pubAdd(args: ['foo:1.2.3']);
 
       await d.cacheDir({'foo': '1.2.3'}).validate();
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.2.3'}).validate();
       await d.appDir({'foo': '1.2.3'}).validate();
     });
 
     group('warns user to use pub upgrade if package exists', () {
       test('if package is added without a version constraint', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.appDir({'foo': '1.2.2'}).create();
 
@@ -168,9 +164,10 @@
       });
 
       test('if package is added with a specific version constraint', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.appDir({'foo': '1.2.2'}).create();
 
@@ -185,9 +182,10 @@
       });
 
       test('if package is added with a version constraint range', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.appDir({'foo': '1.2.2'}).create();
 
@@ -203,9 +201,10 @@
     });
 
     test('removes dev_dependency and add to normal dependency', () async {
-      await servePackages()
-        ..serve('foo', '1.2.3')
-        ..serve('foo', '1.2.2');
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3');
+        builder.serve('foo', '1.2.2');
+      });
 
       await d.dir(appPath, [
         d.file('pubspec.yaml', '''
@@ -226,9 +225,7 @@
               'adding it to dependencies instead.'));
 
       await d.cacheDir({'foo': '1.2.3'}).validate();
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.2.3'}).validate();
 
       await d.dir(appPath, [
         d.pubspec({
@@ -240,9 +237,10 @@
 
     group('dependency override', () {
       test('passes if package does not specify a range', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -255,9 +253,7 @@
         await pubAdd(args: ['foo']);
 
         await d.cacheDir({'foo': '1.2.2'}).validate();
-        await d.appPackageConfigFile([
-          d.packageConfigEntry(name: 'foo', version: '1.2.2'),
-        ]).validate();
+        await d.appPackagesFile({'foo': '1.2.2'}).validate();
         await d.dir(appPath, [
           d.pubspec({
             'name': 'myapp',
@@ -268,8 +264,9 @@
       });
 
       test('passes if constraint matches git dependency override', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.3');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+        });
 
         await d.git('foo.git',
             [d.libDir('foo'), d.libPubspec('foo', '1.2.3')]).create();
@@ -298,8 +295,9 @@
       });
 
       test('passes if constraint matches path dependency override', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.2');
+        });
         await d.dir(
             'foo', [d.libDir('foo'), d.libPubspec('foo', '1.2.2')]).create();
 
@@ -327,8 +325,9 @@
       });
 
       test('fails with bad version constraint', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.3');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+        });
 
         await d.dir(appPath, [
           d.pubspec({'name': 'myapp', 'dependencies': {}})
@@ -349,9 +348,10 @@
       });
 
       test('fails if constraint does not match override', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -381,8 +381,9 @@
       });
 
       test('fails if constraint matches git dependency override', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.3');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+        });
 
         await d.git('foo.git',
             [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create();
@@ -420,8 +421,9 @@
 
       test('fails if constraint does not match path dependency override',
           () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.2');
+        });
         await d.dir(
             'foo', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create();
 
@@ -460,8 +462,7 @@
 
   group('--dev', () {
     test('--dev adds packages to dev_dependencies instead', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
+      await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
       await d.dir(appPath, [
         d.pubspec({'name': 'myapp', 'dev_dependencies': {}})
@@ -469,9 +470,7 @@
 
       await pubAdd(args: ['--dev', 'foo:1.2.3']);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.2.3'}).validate();
 
       await d.dir(appPath, [
         d.pubspec({
@@ -483,9 +482,10 @@
 
     group('warns user to use pub upgrade if package exists', () {
       test('if package is added without a version constraint', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -510,9 +510,10 @@
       });
 
       test('if package is added with a specific version constraint', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -537,9 +538,10 @@
       });
 
       test('if package is added with a version constraint range', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -566,9 +568,10 @@
 
     group('dependency override', () {
       test('passes if package does not specify a range', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -581,9 +584,7 @@
         await pubAdd(args: ['foo', '--dev']);
 
         await d.cacheDir({'foo': '1.2.2'}).validate();
-        await d.appPackageConfigFile([
-          d.packageConfigEntry(name: 'foo', version: '1.2.2'),
-        ]).validate();
+        await d.appPackagesFile({'foo': '1.2.2'}).validate();
         await d.dir(appPath, [
           d.pubspec({
             'name': 'myapp',
@@ -594,8 +595,10 @@
       });
 
       test('passes if constraint is git dependency', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.3');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+        });
+
         await d.git('foo.git',
             [d.libDir('foo'), d.libPubspec('foo', '1.2.3')]).create();
 
@@ -623,8 +626,9 @@
       });
 
       test('passes if constraint matches path dependency override', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.2');
+        });
         await d.dir(
             'foo', [d.libDir('foo'), d.libPubspec('foo', '1.2.2')]).create();
 
@@ -652,9 +656,10 @@
       });
 
       test('fails if constraint does not match override', () async {
-        await servePackages()
-          ..serve('foo', '1.2.3')
-          ..serve('foo', '1.2.2');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+          builder.serve('foo', '1.2.2');
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -684,8 +689,9 @@
       });
 
       test('fails if constraint matches git dependency override', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.3');
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3');
+        });
 
         await d.git('foo.git',
             [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create();
@@ -723,9 +729,9 @@
 
       test('fails if constraint does not match path dependency override',
           () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.2');
-
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.2');
+        });
         await d.dir(
             'foo', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create();
 
@@ -764,9 +770,10 @@
     test(
         'prints information saying that package is already a dependency if it '
         'already exists and exits with a usage exception', () async {
-      await servePackages()
-        ..serve('foo', '1.2.3')
-        ..serve('foo', '1.2.2');
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3');
+        builder.serve('foo', '1.2.2');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -798,8 +805,9 @@
 
   /// Differs from the previous test because this tests YAML in flow format.
   test('adds to empty ', () async {
-    final server = await servePackages();
-    server.serve('bar', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.file('pubspec.yaml', '''
@@ -817,9 +825,10 @@
   });
 
   test('preserves comments', () async {
-    await servePackages()
-      ..serve('bar', '1.0.0')
-      ..serve('foo', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('bar', '1.0.0');
+      builder.serve('foo', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.file('pubspec.yaml', '''
diff --git a/test/add/common/invalid_options.dart b/test/add/common/invalid_options.dart
index f5bf23d..0b60ed8 100644
--- a/test/add/common/invalid_options.dart
+++ b/test/add/common/invalid_options.dart
@@ -39,10 +39,12 @@
   test('cannot use both --path and --host-<option> flags', () async {
     // Make the default server serve errors. Only the custom server should
     // be accessed.
-    (await servePackages()).serveErrors();
+    await serveNoPackages();
+    globalPackageServer!.serveErrors();
 
-    final server = await startPackageServer();
-    server.serve('foo', '1.2.3');
+    final server = await PackageServer.start((builder) {
+      builder.serve('foo', '1.2.3');
+    });
 
     await d
         .dir('bar', [d.libDir('bar'), d.libPubspec('foo', '0.0.1')]).create();
@@ -74,10 +76,12 @@
   test('cannot use both --hosted-url and --git-<option> flags', () async {
     // Make the default server serve errors. Only the custom server should
     // be accessed.
-    (await servePackages()).serveErrors();
+    await serveNoPackages();
+    globalPackageServer!.serveErrors();
 
-    final server = await startPackageServer();
-    server.serve('foo', '1.2.3');
+    final server = await PackageServer.start((builder) {
+      builder.serve('foo', '1.2.3');
+    });
 
     ensureGit();
 
diff --git a/test/add/common/version_constraint_test.dart b/test/add/common/version_constraint_test.dart
index f058082..d865727 100644
--- a/test/add/common/version_constraint_test.dart
+++ b/test/add/common/version_constraint_test.dart
@@ -10,96 +10,86 @@
 
 void main() {
   test('allows empty version constraint', () async {
-    await servePackages()
-      ..serve('foo', '0.2.3')
-      ..serve('foo', '1.0.1')
-      ..serve('foo', '1.2.3')
-      ..serve('foo', '2.0.0-dev')
-      ..serve('foo', '1.3.4-dev');
+    await servePackages((builder) {
+      builder.serve('foo', '0.2.3');
+      builder.serve('foo', '1.0.1');
+      builder.serve('foo', '1.2.3');
+      builder.serve('foo', '2.0.0-dev');
+      builder.serve('foo', '1.3.4-dev');
+    });
 
     await d.appDir({}).create();
 
     await pubAdd(args: ['foo']);
 
     await d.cacheDir({'foo': '1.2.3'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
     await d.appDir({'foo': '^1.2.3'}).validate();
   });
 
   test('allows specific version constraint', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
     await d.appDir({}).create();
 
     await pubAdd(args: ['foo:1.2.3']);
 
     await d.cacheDir({'foo': '1.2.3'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
     await d.appDir({'foo': '1.2.3'}).validate();
   });
 
   test('allows specific pre-release version constraint', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3-dev');
+    await servePackages((builder) => builder.serve('foo', '1.2.3-dev'));
 
     await d.appDir({}).create();
 
     await pubAdd(args: ['foo:1.2.3-dev']);
 
     await d.cacheDir({'foo': '1.2.3-dev'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3-dev'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3-dev'}).validate();
     await d.appDir({'foo': '1.2.3-dev'}).validate();
   });
 
   test('allows the "any" version constraint', () async {
-    await servePackages()
-      ..serve('foo', '0.2.3')
-      ..serve('foo', '1.0.1')
-      ..serve('foo', '1.2.3')
-      ..serve('foo', '2.0.0-dev')
-      ..serve('foo', '1.3.4-dev');
+    await servePackages((builder) {
+      builder.serve('foo', '0.2.3');
+      builder.serve('foo', '1.0.1');
+      builder.serve('foo', '1.2.3');
+      builder.serve('foo', '2.0.0-dev');
+      builder.serve('foo', '1.3.4-dev');
+    });
 
     await d.appDir({}).create();
 
     await pubAdd(args: ['foo:any']);
 
     await d.cacheDir({'foo': '1.2.3'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
     await d.appDir({'foo': 'any'}).validate();
   });
 
   test('allows version constraint range', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
     await d.appDir({}).create();
 
     await pubAdd(args: ['foo:>1.2.0 <2.0.0']);
 
     await d.cacheDir({'foo': '1.2.3'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
     await d.appDir({'foo': '>1.2.0 <2.0.0'}).validate();
   });
 
   test(
       'empty constraint allows it to choose the latest version not in conflict',
       () async {
-    await servePackages()
-      ..serve('foo', '0.1.0')
-      ..serve('foo', '1.2.3', deps: {'bar': '2.0.4'})
-      ..serve('bar', '2.0.3')
-      ..serve('bar', '2.0.4');
+    await servePackages((builder) {
+      builder.serve('foo', '0.1.0');
+      builder.serve('foo', '1.2.3', deps: {'bar': '2.0.4'});
+      builder.serve('bar', '2.0.3');
+      builder.serve('bar', '2.0.4');
+    });
 
     await d.appDir({'bar': '2.0.3'}).create();
 
@@ -108,16 +98,12 @@
     await d.appDir({'foo': '^0.1.0', 'bar': '2.0.3'}).validate();
 
     await d.cacheDir({'foo': '0.1.0', 'bar': '2.0.3'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '0.1.0'),
-      d.packageConfigEntry(name: 'bar', version: '2.0.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '0.1.0', 'bar': '2.0.3'}).validate();
   });
 
   group('does not update pubspec if no available version found', () {
     test('simple', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.3');
+      await servePackages((builder) => builder.serve('foo', '1.0.3'));
 
       await d.appDir({}).create();
 
@@ -138,10 +124,11 @@
     });
 
     test('transitive', () async {
-      await servePackages()
-        ..serve('foo', '1.2.3', deps: {'bar': '2.0.4'})
-        ..serve('bar', '2.0.3')
-        ..serve('bar', '2.0.4');
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3', deps: {'bar': '2.0.4'});
+        builder.serve('bar', '2.0.3');
+        builder.serve('bar', '2.0.4');
+      });
 
       await d.appDir({'bar': '2.0.3'}).create();
 
diff --git a/test/add/common/version_resolution_test.dart b/test/add/common/version_resolution_test.dart
index 0f44d2b..4bd355b 100644
--- a/test/add/common/version_resolution_test.dart
+++ b/test/add/common/version_resolution_test.dart
@@ -13,10 +13,10 @@
   test('unlocks transitive dependencies', () async {
     /// The server used to only have the foo v3.2.1 as the latest,
     /// so pub get will create a pubspec.lock to foo 3.2.1
-    final server = await servePackages();
-
-    server.serve('foo', '3.2.1');
-    server.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'});
+    await servePackages((builder) {
+      builder.serve('foo', '3.2.1');
+      builder.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'});
+    });
 
     await d.appDir({'bar': '1.0.0'}).create();
     await pubGet();
@@ -24,69 +24,66 @@
     /// foo's package creator releases a newer version of foo, and we
     /// want to test that this is what the user gets when they run
     /// pub add foo.
-    server.serve('foo', '3.5.0');
-    server.serve('foo', '3.1.0');
-    server.serve('foo', '2.5.0');
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '3.5.0');
+      builder.serve('foo', '3.1.0');
+      builder.serve('foo', '2.5.0');
+    });
 
     await pubAdd(args: ['foo']);
 
     await d.appDir({'foo': '^3.5.0', 'bar': '1.0.0'}).validate();
     await d.cacheDir({'foo': '3.5.0', 'bar': '1.0.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '3.5.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '3.5.0', 'bar': '1.0.0'}).validate();
   });
 
   test('chooses the appropriate version to not break other dependencies',
       () async {
     /// The server used to only have the foo v3.2.1 as the latest,
     /// so pub get will create a pubspec.lock to foo 3.2.1
-    final server = await servePackages();
-
-    server.serve('foo', '3.2.1');
-    server.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'});
+    await servePackages((builder) {
+      builder.serve('foo', '3.2.1');
+      builder.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'});
+    });
 
     await d.appDir({'bar': '1.0.0'}).create();
     await pubGet();
 
-    server.serve('foo', '4.0.0');
-    server.serve('foo', '2.0.0');
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '4.0.0');
+      builder.serve('foo', '2.0.0');
+    });
 
     await pubAdd(args: ['foo']);
 
     await d.appDir({'foo': '^3.2.1', 'bar': '1.0.0'}).validate();
     await d.cacheDir({'foo': '3.2.1', 'bar': '1.0.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '3.2.1'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '3.2.1', 'bar': '1.0.0'}).validate();
   });
 
   test('may upgrade other packages if they allow a later version to be chosen',
       () async {
     /// The server used to only have the foo v3.2.1 as the latest,
     /// so pub get will create a pubspec.lock to foo 3.2.1
-    final server = await servePackages();
-
-    server.serve('foo', '3.2.1');
-    server.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'});
+    await servePackages((builder) {
+      builder.serve('foo', '3.2.1');
+      builder.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'});
+    });
 
     await d.appDir({'bar': '^1.0.0'}).create();
     await pubGet();
 
-    server.serve('foo', '5.0.0');
-    server.serve('foo', '4.0.0');
-    server.serve('foo', '2.0.0');
-    server.serve('bar', '1.5.0', deps: {'foo': '^4.0.0'});
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '5.0.0');
+      builder.serve('foo', '4.0.0');
+      builder.serve('foo', '2.0.0');
+      builder.serve('bar', '1.5.0', deps: {'foo': '^4.0.0'});
+    });
 
     await pubAdd(args: ['foo']);
 
     await d.appDir({'foo': '^4.0.0', 'bar': '^1.0.0'}).validate();
     await d.cacheDir({'foo': '4.0.0', 'bar': '1.5.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '4.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.5.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '4.0.0', 'bar': '1.5.0'}).validate();
   });
 }
diff --git a/test/add/git/git_test.dart b/test/add/git/git_test.dart
index d976172..2577af8 100644
--- a/test/add/git/git_test.dart
+++ b/test/add/git/git_test.dart
@@ -156,8 +156,9 @@
   });
 
   test('can be overriden by dependency override', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.2');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.2');
+    });
 
     await d.git(
         'foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create();
@@ -173,9 +174,7 @@
     await pubAdd(args: ['foo', '--git-url', '../foo.git']);
 
     await d.cacheDir({'foo': '1.2.2'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.2'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.2'}).validate();
     await d.dir(appPath, [
       d.pubspec({
         'name': 'myapp',
@@ -186,18 +185,4 @@
       })
     ]).validate();
   });
-
-  test('fails if multiple packages passed for git source', () async {
-    ensureGit();
-
-    await d.git(
-        'foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create();
-
-    await d.appDir({}).create();
-
-    await pubAdd(
-        args: ['foo', 'bar', 'baz', '--git-url', '../foo.git'],
-        exitCode: exit_codes.USAGE,
-        error: contains('Can only add a single git package at a time.'));
-  });
 }
diff --git a/test/add/git/subdir_test.dart b/test/add/git/subdir_test.dart
index 8e8c39c..0f78069 100644
--- a/test/add/git/subdir_test.dart
+++ b/test/add/git/subdir_test.dart
@@ -30,11 +30,10 @@
         ])
       ])
     ]).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'sub',
-          path: pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir')),
-    ]).validate();
+
+    await d.appPackagesFile({
+      'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir')
+    }).validate();
 
     await d.appDir({
       'sub': {
@@ -69,11 +68,9 @@
       ])
     ]).validate();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'sub',
-          path: pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir')),
-    ]).validate();
+    await d.appPackagesFile({
+      'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir')
+    }).validate();
 
     await d.appDir({
       'sub': {
diff --git a/test/add/hosted/non_default_pub_server_test.dart b/test/add/hosted/non_default_pub_server_test.dart
index 60538e3..fbe966e 100644
--- a/test/add/hosted/non_default_pub_server_test.dart
+++ b/test/add/hosted/non_default_pub_server_test.dart
@@ -12,12 +12,13 @@
   test('adds a package from a non-default pub server', () async {
     // Make the default server serve errors. Only the custom server should
     // be accessed.
-    (await servePackages()).serveErrors();
+    await serveErrors();
 
-    final server = await servePackages();
-    server.serve('foo', '0.2.5');
-    server.serve('foo', '1.1.0');
-    server.serve('foo', '1.2.3');
+    var server = await PackageServer.start((builder) {
+      builder.serve('foo', '0.2.5');
+      builder.serve('foo', '1.1.0');
+      builder.serve('foo', '1.2.3');
+    });
 
     await d.appDir({}).create();
 
@@ -26,9 +27,7 @@
     await pubAdd(args: ['foo:1.2.3', '--hosted-url', url]);
 
     await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
     await d.appDir({
       'foo': {
         'version': '1.2.3',
@@ -37,49 +36,6 @@
     }).validate();
   });
 
-  test('adds multiple packages from a non-default pub server', () async {
-    // Make the default server serve errors. Only the custom server should
-    // be accessed.
-    (await servePackages()).serveErrors();
-
-    final server = await servePackages();
-    server.serve('foo', '1.1.0');
-    server.serve('foo', '1.2.3');
-    server.serve('bar', '0.2.5');
-    server.serve('bar', '3.2.3');
-    server.serve('baz', '0.1.3');
-    server.serve('baz', '1.3.5');
-
-    await d.appDir({}).create();
-
-    final url = server.url;
-
-    await pubAdd(
-        args: ['foo:1.2.3', 'bar:3.2.3', 'baz:1.3.5', '--hosted-url', url]);
-
-    await d.cacheDir({'foo': '1.2.3', 'bar': '3.2.3', 'baz': '1.3.5'},
-        port: server.port).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      d.packageConfigEntry(name: 'bar', version: '3.2.3'),
-      d.packageConfigEntry(name: 'baz', version: '1.3.5'),
-    ]).validate();
-    await d.appDir({
-      'foo': {
-        'version': '1.2.3',
-        'hosted': {'name': 'foo', 'url': url}
-      },
-      'bar': {
-        'version': '3.2.3',
-        'hosted': {'name': 'bar', 'url': url}
-      },
-      'baz': {
-        'version': '1.3.5',
-        'hosted': {'name': 'baz', 'url': url}
-      }
-    }).validate();
-  });
-
   test('fails when adding from an invalid url', () async {
     ensureGit();
 
@@ -108,12 +64,13 @@
       () async {
     // Make the default server serve errors. Only the custom server should
     // be accessed.
-    (await servePackages()).serveErrors();
+    await serveErrors();
 
-    final server = await servePackages();
-    server.serve('foo', '0.2.5');
-    server.serve('foo', '1.1.0');
-    server.serve('foo', '1.2.3');
+    var server = await PackageServer.start((builder) {
+      builder.serve('foo', '0.2.5');
+      builder.serve('foo', '1.1.0');
+      builder.serve('foo', '1.2.3');
+    });
 
     await d.appDir({}).create();
 
@@ -122,9 +79,7 @@
     await pubAdd(args: ['foo', '--hosted-url', url]);
 
     await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
     await d.appDir({
       'foo': {
         'version': '^1.2.3',
@@ -137,12 +92,13 @@
       () async {
     // Make the default server serve errors. Only the custom server should
     // be accessed.
-    (await servePackages()).serveErrors();
+    await serveErrors();
 
-    final server = await servePackages();
-    server.serve('foo', '0.2.5');
-    server.serve('foo', '1.1.0');
-    server.serve('foo', '1.2.3');
+    var server = await PackageServer.start((builder) {
+      builder.serve('foo', '0.2.5');
+      builder.serve('foo', '1.1.0');
+      builder.serve('foo', '1.2.3');
+    });
 
     await d.appDir({}).create();
 
@@ -151,9 +107,7 @@
     await pubAdd(args: ['foo', '--hosted-url', url]);
 
     await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
     await d.appDir({
       'foo': {
         'version': '^1.2.3',
@@ -167,11 +121,13 @@
       'constraint', () async {
     // Make the default server serve errors. Only the custom server should
     // be accessed.
-    (await servePackages()).serveErrors();
-    final server = await servePackages();
-    server.serve('foo', '0.2.5');
-    server.serve('foo', '1.1.0');
-    server.serve('foo', '1.2.3');
+    await serveErrors();
+
+    var server = await PackageServer.start((builder) {
+      builder.serve('foo', '0.2.5');
+      builder.serve('foo', '1.1.0');
+      builder.serve('foo', '1.2.3');
+    });
 
     await d.appDir({}).create();
 
@@ -180,9 +136,7 @@
     await pubAdd(args: ['foo:any', '--hosted-url', url]);
 
     await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
     await d.appDir({
       'foo': {
         'version': 'any',
diff --git a/test/add/path/absolute_path_test.dart b/test/add/path/absolute_path_test.dart
index 5e63679..0811bea 100644
--- a/test/add/path/absolute_path_test.dart
+++ b/test/add/path/absolute_path_test.dart
@@ -20,9 +20,7 @@
 
     await pubAdd(args: ['foo', '--path', absolutePath]);
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: absolutePath),
-    ]).validate();
+    await d.appPackagesFile({'foo': absolutePath}).validate();
 
     await d.appDir({
       'foo': {'path': absolutePath}
@@ -43,28 +41,6 @@
     }).validate();
   });
 
-  test('fails when adding multiple packages through local path', () async {
-    ensureGit();
-
-    await d.git(
-        'foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create();
-
-    await d.appDir({}).create();
-    final absolutePath = path.join(d.sandbox, 'foo');
-
-    await pubAdd(
-        args: ['foo:2.0.0', 'bar:0.1.3', 'baz:1.3.1', '--path', absolutePath],
-        error: contains('Can only add a single local package at a time.'),
-        exitCode: exit_codes.USAGE);
-
-    await d.appDir({}).validate();
-    await d.dir(appPath, [
-      d.nothing('.dart_tool/package_config.json'),
-      d.nothing('pubspec.lock'),
-      d.nothing('.packages'),
-    ]).validate();
-  });
-
   test('fails when adding with an invalid version constraint', () async {
     ensureGit();
 
@@ -112,8 +88,9 @@
   });
 
   test('can be overriden by dependency override', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.2');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.2');
+    });
     await d
         .dir('foo', [d.libDir('foo'), d.libPubspec('foo', '0.0.1')]).create();
 
@@ -129,9 +106,7 @@
     await pubAdd(args: ['foo', '--path', absolutePath]);
 
     await d.cacheDir({'foo': '1.2.2'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.2'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.2'}).validate();
     await d.dir(appPath, [
       d.pubspec({
         'name': 'myapp',
diff --git a/test/add/path/relative_path_test.dart b/test/add/path/relative_path_test.dart
index e08ba3c..8fa1932 100644
--- a/test/add/path/relative_path_test.dart
+++ b/test/add/path/relative_path_test.dart
@@ -19,9 +19,7 @@
 
     await pubAdd(args: ['foo', '--path', '../foo']);
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '../foo'}).validate();
 
     await d.appDir({
       'foo': {'path': '../foo'}
@@ -40,9 +38,7 @@
       output: contains('Changed 1 dependency in myapp!'),
     );
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '../foo'}).validate();
 
     await d.appDir({
       'foo': {'path': '../foo'}
@@ -106,8 +102,9 @@
   });
 
   test('can be overriden by dependency override', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.2');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.2');
+    });
     await d
         .dir('foo', [d.libDir('foo'), d.libPubspec('foo', '0.0.1')]).create();
 
@@ -122,9 +119,7 @@
     await pubAdd(args: ['foo', '--path', '../foo']);
 
     await d.cacheDir({'foo': '1.2.2'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.2'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.2'}).validate();
     await d.dir(appPath, [
       d.pubspec({
         'name': 'myapp',
diff --git a/test/add/sdk/sdk_test.dart b/test/add/sdk/sdk_test.dart
index ff7d442..25995e3 100644
--- a/test/add/sdk/sdk_test.dart
+++ b/test/add/sdk/sdk_test.dart
@@ -11,8 +11,9 @@
 
 void main() {
   setUp(() async {
-    final server = await servePackages();
-    server.serve('bar', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.dir('flutter', [
       d.dir('packages', [
@@ -42,12 +43,11 @@
           'foo': {'sdk': 'flutter', 'version': '^0.0.1'}
         }
       }),
-    ]).validate();
-
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'foo', path: p.join(d.sandbox, 'flutter', 'packages', 'foo')),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
+      d.packagesFile({
+        'myapp': '.',
+        'foo': p.join(d.sandbox, 'flutter', 'packages', 'foo'),
+        'bar': '1.0.0'
+      })
     ]).validate();
   });
 
@@ -66,11 +66,11 @@
           'foo': {'sdk': 'flutter', 'version': '0.0.1'}
         }
       }),
-    ]).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'foo', path: p.join(d.sandbox, 'flutter', 'packages', 'foo')),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
+      d.packagesFile({
+        'myapp': '.',
+        'foo': p.join(d.sandbox, 'flutter', 'packages', 'foo'),
+        'bar': '1.0.0'
+      })
     ]).validate();
   });
 
@@ -80,10 +80,11 @@
         args: ['baz', '--sdk', 'flutter'],
         environment: {'FLUTTER_ROOT': p.join(d.sandbox, 'flutter')});
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'baz',
-          path: p.join(d.sandbox, 'flutter', 'bin', 'cache', 'pkg', 'baz'))
+    await d.dir(appPath, [
+      d.packagesFile({
+        'myapp': '.',
+        'baz': p.join(d.sandbox, 'flutter', 'bin', 'cache', 'pkg', 'baz')
+      })
     ]).validate();
   });
 
diff --git a/test/cache/add/adds_latest_matching_version_test.dart b/test/cache/add/adds_latest_matching_version_test.dart
index 7bf9625..0e78b12 100644
--- a/test/cache/add/adds_latest_matching_version_test.dart
+++ b/test/cache/add/adds_latest_matching_version_test.dart
@@ -13,11 +13,12 @@
   test(
       'adds the latest version of the package matching the '
       'version constraint', () async {
-    await servePackages()
-      ..serve('foo', '1.2.2')
-      ..serve('foo', '1.2.3')
-      ..serve('foo', '2.0.0-dev')
-      ..serve('foo', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.2');
+      builder.serve('foo', '1.2.3');
+      builder.serve('foo', '2.0.0-dev');
+      builder.serve('foo', '2.0.0');
+    });
 
     await runPub(
         args: ['cache', 'add', 'foo', '-v', '>=1.0.0 <2.0.0'],
diff --git a/test/cache/add/adds_latest_version_test.dart b/test/cache/add/adds_latest_version_test.dart
index cf34857..6e196f6 100644
--- a/test/cache/add/adds_latest_version_test.dart
+++ b/test/cache/add/adds_latest_version_test.dart
@@ -9,10 +9,11 @@
 
 void main() {
   test('adds the latest stable version of the package', () async {
-    await servePackages()
-      ..serve('foo', '1.2.2')
-      ..serve('foo', '1.2.3')
-      ..serve('foo', '1.2.4-dev');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.2');
+      builder.serve('foo', '1.2.3');
+      builder.serve('foo', '1.2.4-dev');
+    });
 
     await runPub(
         args: ['cache', 'add', 'foo'], output: 'Downloading foo 1.2.3...');
diff --git a/test/cache/add/all_adds_all_matching_versions_test.dart b/test/cache/add/all_adds_all_matching_versions_test.dart
index a05e8dc..9dfb3c7 100644
--- a/test/cache/add/all_adds_all_matching_versions_test.dart
+++ b/test/cache/add/all_adds_all_matching_versions_test.dart
@@ -9,11 +9,12 @@
 
 void main() {
   test('"--all" adds all matching versions of the package', () async {
-    await servePackages()
-      ..serve('foo', '1.2.2')
-      ..serve('foo', '1.2.3-dev')
-      ..serve('foo', '1.2.3')
-      ..serve('foo', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.2');
+      builder.serve('foo', '1.2.3-dev');
+      builder.serve('foo', '1.2.3');
+      builder.serve('foo', '2.0.0');
+    });
 
     await runPub(
         args: ['cache', 'add', 'foo', '-v', '>=1.0.0 <2.0.0', '--all'],
diff --git a/test/cache/add/all_with_some_versions_present_test.dart b/test/cache/add/all_with_some_versions_present_test.dart
index 7b5b36d..861ac4c 100644
--- a/test/cache/add/all_with_some_versions_present_test.dart
+++ b/test/cache/add/all_with_some_versions_present_test.dart
@@ -9,11 +9,12 @@
 
 void main() {
   test('"--all" adds all non-installed versions of the package', () async {
-    await servePackages()
-      ..serve('foo', '1.2.1')
-      ..serve('foo', '1.2.2')
-      ..serve('foo', '1.2.3')
-      ..serve('foo', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.1');
+      builder.serve('foo', '1.2.2');
+      builder.serve('foo', '1.2.3');
+      builder.serve('foo', '2.0.0');
+    });
 
     // Install a couple of versions first.
     await runPub(
diff --git a/test/cache/add/already_cached_test.dart b/test/cache/add/already_cached_test.dart
index 8c74da9..ac244dc 100644
--- a/test/cache/add/already_cached_test.dart
+++ b/test/cache/add/already_cached_test.dart
@@ -9,8 +9,9 @@
 
 void main() {
   test('does nothing if the package is already cached', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.3');
+    });
 
     // Run once to put it in the cache.
     await runPub(
diff --git a/test/cache/add/no_matching_version_test.dart b/test/cache/add/no_matching_version_test.dart
index a860294..4b4455c 100644
--- a/test/cache/add/no_matching_version_test.dart
+++ b/test/cache/add/no_matching_version_test.dart
@@ -8,9 +8,10 @@
 
 void main() {
   test('fails if no version matches the version constraint', () async {
-    await servePackages()
-      ..serve('foo', '1.2.2')
-      ..serve('foo', '1.2.3');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.2');
+      builder.serve('foo', '1.2.3');
+    });
 
     await runPub(
         args: ['cache', 'add', 'foo', '-v', '>2.0.0'],
diff --git a/test/cache/add/package_not_found_test.dart b/test/cache/add/package_not_found_test.dart
index caf45f4..91f3f3e 100644
--- a/test/cache/add/package_not_found_test.dart
+++ b/test/cache/add/package_not_found_test.dart
@@ -9,13 +9,12 @@
 
 void main() {
   test('fails if the package cound not be found on the source', () async {
-    await servePackages();
+    await serveNoPackages();
 
     await runPub(
         args: ['cache', 'add', 'foo'],
-        error: RegExp(
-          r'Package not available \(could not find package foo at http://.*\)\.',
-        ),
+        error: RegExp(r"Package doesn't exist \(could not find package foo at "
+            r'http://.*\)\.'),
         exitCode: exit_codes.UNAVAILABLE);
   });
 }
diff --git a/test/cache/clean_test.dart b/test/cache/clean_test.dart
index 7a79bc8..b03c0c8 100644
--- a/test/cache/clean_test.dart
+++ b/test/cache/clean_test.dart
@@ -17,9 +17,9 @@
   });
 
   test('running pub cache clean --force deletes cache', () async {
-    await servePackages()
+    await servePackages((b) => b
       ..serve('foo', '1.1.2')
-      ..serve('bar', '1.2.3');
+      ..serve('bar', '1.2.3'));
     await d.appDir({'foo': 'any', 'bar': 'any'}).create();
     await pubGet();
     final cache = path.join(d.sandbox, cachePath);
@@ -32,9 +32,9 @@
 
   test('running pub cache clean deletes cache only with confirmation',
       () async {
-    await servePackages()
+    await servePackages((b) => b
       ..serve('foo', '1.1.2')
-      ..serve('bar', '1.2.3');
+      ..serve('bar', '1.2.3'));
     await d.appDir({'foo': 'any', 'bar': 'any'}).create();
     await pubGet();
     final cache = path.join(d.sandbox, cachePath);
diff --git a/test/cache/repair/handles_corrupted_binstub_test.dart b/test/cache/repair/handles_corrupted_binstub_test.dart
index 0ca169f..9991ec1 100644
--- a/test/cache/repair/handles_corrupted_binstub_test.dart
+++ b/test/cache/repair/handles_corrupted_binstub_test.dart
@@ -9,10 +9,11 @@
 
 void main() {
   test('handles a corrupted binstub script', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/cache/repair/handles_failure_test.dart b/test/cache/repair/handles_failure_test.dart
index d5637ca..471bcf8 100644
--- a/test/cache/repair/handles_failure_test.dart
+++ b/test/cache/repair/handles_failure_test.dart
@@ -11,14 +11,15 @@
 void main() {
   test('handles failure to reinstall some packages', () async {
     // Only serve two packages so repairing will have a failure.
-    final server = await servePackages()
-      ..serve('foo', '1.2.3')
-      ..serve('foo', '1.2.5');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.3');
+      builder.serve('foo', '1.2.5');
+    });
 
     // Set up a cache with some packages.
     await d.dir(cachePath, [
       d.dir('hosted', [
-        d.dir('localhost%58${server.port}', [
+        d.dir('localhost%58${globalServer!.port}', [
           d.dir('foo-1.2.3',
               [d.libPubspec('foo', '1.2.3'), d.file('broken.txt')]),
           d.dir('foo-1.2.4',
@@ -38,7 +39,7 @@
     expect(pub.stderr, emits(startsWith('Failed to repair foo 1.2.4. Error:')));
     expect(
         pub.stderr,
-        emits('Package not available '
+        emits('Package doesn\'t exist '
             '(Package foo has no version 1.2.4).'));
 
     expect(pub.stdout, emits('Reinstalled 2 packages.'));
diff --git a/test/cache/repair/handles_orphaned_binstub_test.dart b/test/cache/repair/handles_orphaned_binstub_test.dart
index 0754496..9c4e74a 100644
--- a/test/cache/repair/handles_orphaned_binstub_test.dart
+++ b/test/cache/repair/handles_orphaned_binstub_test.dart
@@ -7,7 +7,7 @@
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
-const _orphanedBinstub = '''
+const _ORPHANED_BINSTUB = '''
 #!/usr/bin/env sh
 # This file was created by pub v0.1.2-3.
 # Package: foo
@@ -20,7 +20,7 @@
 void main() {
   test('handles an orphaned binstub script', () async {
     await d.dir(cachePath, [
-      d.dir('bin', [d.file(binStubName('script'), _orphanedBinstub)])
+      d.dir('bin', [d.file(binStubName('script'), _ORPHANED_BINSTUB)])
     ]).create();
 
     await runPub(
diff --git a/test/cache/repair/hosted.dart b/test/cache/repair/hosted.dart
index ec3786b..97c8167 100644
--- a/test/cache/repair/hosted.dart
+++ b/test/cache/repair/hosted.dart
@@ -11,20 +11,21 @@
 import '../../test_pub.dart';
 
 void main() {
-  setUp(() async {
-    await servePackages()
-      ..serve('foo', '1.2.3')
-      ..serve('foo', '1.2.4')
-      ..serve('foo', '1.2.5')
-      ..serve('bar', '1.2.3')
-      ..serve('bar', '1.2.4');
+  setUp(() {
+    return servePackages((builder) {
+      builder.serve('foo', '1.2.3');
+      builder.serve('foo', '1.2.4');
+      builder.serve('foo', '1.2.5');
+      builder.serve('bar', '1.2.3');
+      builder.serve('bar', '1.2.4');
+    });
   });
 
   test('reinstalls previously cached hosted packages', () async {
     // Set up a cache with some broken packages.
     await d.dir(cachePath, [
       d.dir('hosted', [
-        d.dir('localhost%58${globalServer.port}', [
+        d.dir('localhost%58${globalServer!.port}', [
           d.dir('foo-1.2.3',
               [d.libPubspec('foo', '1.2.3'), d.file('broken.txt')]),
           d.dir('foo-1.2.5',
@@ -63,7 +64,7 @@
     // Set up a cache with some broken packages.
     await d.dir(cachePath, [
       d.dir('hosted', [
-        d.dir('localhost%58${globalServer.port}', [
+        d.dir('localhost%58${globalServer!.port}', [
           d.dir('bar-1.2.4', [d.file('broken.txt')]),
           d.dir('foo-1.2.3', [d.file('broken.txt')]),
           d.dir('foo-1.2.5', [d.file('broken.txt')]),
@@ -99,7 +100,7 @@
     // Set up a cache with some broken packages.
     await d.dir(cachePath, [
       d.dir('hosted', [
-        d.dir('localhost%58${globalServer.port}', [
+        d.dir('localhost%58${globalServer!.port}', [
           d.dir('bar-1.2.4', [d.file('pubspec.yaml', '{')]),
           d.dir('foo-1.2.3', [d.file('pubspec.yaml', '{')]),
           d.dir('foo-1.2.5', [d.file('pubspec.yaml', '{')]),
diff --git a/test/cache/repair/recompiles_snapshots_test.dart b/test/cache/repair/recompiles_snapshots_test.dart
index f3c3d6c..89b3575 100644
--- a/test/cache/repair/recompiles_snapshots_test.dart
+++ b/test/cache/repair/recompiles_snapshots_test.dart
@@ -9,10 +9,11 @@
 
 void main() {
   test('recompiles activated executable snapshots', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/cache/repair/updates_binstubs_test.dart b/test/cache/repair/updates_binstubs_test.dart
index e8cbfb4..1cd848b 100644
--- a/test/cache/repair/updates_binstubs_test.dart
+++ b/test/cache/repair/updates_binstubs_test.dart
@@ -7,7 +7,7 @@
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
-const _outdatedBinstub = '''
+const _OUTDATED_BINSTUB = '''
 #!/usr/bin/env sh
 # This file was created by pub v0.1.2-3.
 # Package: foo
@@ -19,17 +19,19 @@
 
 void main() {
   test('updates an outdated binstub script', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {'foo-script': 'script'}
-    }, contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {'foo-script': 'script'}
+      }, contents: [
+        d.dir(
+            'bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
     await d.dir(cachePath, [
-      d.dir('bin', [d.file(binStubName('foo-script'), _outdatedBinstub)])
+      d.dir('bin', [d.file(binStubName('foo-script'), _OUTDATED_BINSTUB)])
     ]).create();
 
     // Repair them.
diff --git a/test/dependency_override_test.dart b/test/dependency_override_test.dart
index 59f59e4..2ea5abc 100644
--- a/test/dependency_override_test.dart
+++ b/test/dependency_override_test.dart
@@ -12,10 +12,11 @@
 void main() {
   forBothPubGetAndUpgrade((command) {
     test('chooses best version matching override constraint', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('foo', '2.0.0')
-        ..serve('foo', '3.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('foo', '2.0.0');
+        builder.serve('foo', '3.0.0');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -27,14 +28,13 @@
 
       await pubCommand(command);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '2.0.0'}).validate();
     });
 
     test('treats override as implicit dependency', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -45,19 +45,18 @@
 
       await pubCommand(command);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.0.0'}).validate();
     });
 
     test('ignores other constraints on overridden package', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('foo', '2.0.0')
-        ..serve('foo', '3.0.0')
-        ..serve('bar', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('foo', '2.0.0');
+        builder.serve('foo', '3.0.0');
+        builder.serve('bar', '1.0.0', pubspec: {
           'dependencies': {'foo': '5.0.0-nonexistent'}
         });
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -69,16 +68,14 @@
 
       await pubCommand(command);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-        d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '2.0.0', 'bar': '1.0.0'}).validate();
     });
 
     test('ignores SDK constraints', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0', pubspec: {
-        'environment': {'sdk': '5.6.7-fblthp'}
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
+          'environment': {'sdk': '5.6.7-fblthp'}
+        });
       });
 
       await d.dir(appPath, [
@@ -89,15 +86,15 @@
       ]).create();
 
       await pubCommand(command);
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      ]).validate();
+
+      await d.appPackagesFile({'foo': '1.0.0'}).validate();
     });
 
     test('warns about overridden dependencies', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('bar', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('bar', '1.0.0');
+      });
 
       await d
           .dir('baz', [d.libDir('baz'), d.libPubspec('baz', '0.0.1')]).create();
diff --git a/test/dependency_services/dependency_services_test.dart b/test/dependency_services/dependency_services_test.dart
index 58bf303..3bdd224 100644
--- a/test/dependency_services/dependency_services_test.dart
+++ b/test/dependency_services/dependency_services_test.dart
@@ -37,7 +37,7 @@
   await precompile(
       executablePath: p.join('bin', 'dependency_services.dart'),
       outputPath: snapshotFilename,
-      incrementalDillPath: snapshotIncrementalFilename,
+      incrementalDillOutputPath: snapshotIncrementalFilename,
       name: 'bin/pub.dart',
       packageConfigPath: p.join('.dart_tool', 'package_config.json'));
   return snapshotFilename;
@@ -99,10 +99,10 @@
 
 Future<void> main() async {
   testWithGolden('Removing transitive', (context) async {
-    (await servePackages())
+    await servePackages((builder) => builder
       ..serve('foo', '1.2.3', deps: {'transitive': '^1.0.0'})
       ..serve('foo', '2.2.3')
-      ..serve('transitive', '1.0.0');
+      ..serve('transitive', '1.0.0'));
 
     await d.dir(appPath, [
       d.pubspec({
@@ -120,11 +120,11 @@
   });
 
   testWithGolden('Compatible', (context) async {
-    final server = (await servePackages())
+    await servePackages((builder) => builder
       ..serve('foo', '1.2.3')
       ..serve('foo', '2.2.3')
       ..serve('bar', '1.2.3')
-      ..serve('bar', '2.2.3');
+      ..serve('bar', '2.2.3'));
     await d.dir(appPath, [
       d.pubspec({
         'name': 'app',
@@ -135,7 +135,7 @@
       })
     ]).create();
     await pubGet();
-    server.serve('foo', '1.2.4');
+    globalPackageServer!.add((b) => b.serve('foo', '1.2.4'));
     await listReportApply(context, [
       _PackageVersion('foo', Version.parse('1.2.3')),
       _PackageVersion('transitive', null)
@@ -143,10 +143,10 @@
   });
 
   testWithGolden('Adding transitive', (context) async {
-    (await servePackages())
+    await servePackages((builder) => builder
       ..serve('foo', '1.2.3')
       ..serve('foo', '2.2.3', deps: {'transitive': '^1.0.0'})
-      ..serve('transitive', '1.0.0');
+      ..serve('transitive', '1.0.0'));
 
     await d.dir(appPath, [
       d.pubspec({
@@ -164,9 +164,9 @@
   });
 
   testWithGolden('multibreaking', (context) async {
-    final server = (await servePackages())
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0')
-      ..serve('bar', '1.0.0');
+      ..serve('bar', '1.0.0'));
 
     await d.dir(appPath, [
       d.pubspec({
@@ -178,13 +178,13 @@
       })
     ]).create();
     await pubGet();
-    server
+    globalPackageServer!.add((builder) => builder
       ..serve('foo', '1.5.0') // compatible
       ..serve('foo', '2.0.0') // single breaking
       ..serve('foo', '3.0.0', deps: {'bar': '^2.0.0'}) // multi breaking
       ..serve('foo', '3.0.1', deps: {'bar': '^2.0.0'})
       ..serve('bar', '2.0.0', deps: {'foo': '^3.0.0'})
-      ..serve('transitive', '1.0.0');
+      ..serve('transitive', '1.0.0'));
     await listReportApply(context, [
       _PackageVersion('foo', Version.parse('3.0.1'),
           constraint: VersionConstraint.parse('^3.0.0')),
diff --git a/test/deps_test.dart b/test/deps_test.dart
index 7336f13..207e8e7 100644
--- a/test/deps_test.dart
+++ b/test/deps_test.dart
@@ -10,19 +10,21 @@
 
 void main() {
   setUp(() async {
-    await servePackages()
-      ..serve('normal', '1.2.3',
-          deps: {'transitive': 'any', 'circular_a': 'any'})
-      ..serve('transitive', '1.2.3', deps: {'shared': 'any'})
-      ..serve('shared', '1.2.3', deps: {'other': 'any'})
-      ..serve('dev_only', '1.2.3')
-      ..serve('unittest', '1.2.3', deps: {'shared': 'any', 'dev_only': 'any'})
-      ..serve('other', '1.0.0', deps: {'myapp': 'any'})
-      ..serve('overridden', '1.0.0')
-      ..serve('overridden', '2.0.0')
-      ..serve('override_only', '1.2.3')
-      ..serve('circular_a', '1.2.3', deps: {'circular_b': 'any'})
-      ..serve('circular_b', '1.2.3', deps: {'circular_a': 'any'});
+    await servePackages((builder) {
+      builder.serve('normal', '1.2.3',
+          deps: {'transitive': 'any', 'circular_a': 'any'});
+      builder.serve('transitive', '1.2.3', deps: {'shared': 'any'});
+      builder.serve('shared', '1.2.3', deps: {'other': 'any'});
+      builder.serve('dev_only', '1.2.3');
+      builder.serve('unittest', '1.2.3',
+          deps: {'shared': 'any', 'dev_only': 'any'});
+      builder.serve('other', '1.0.0', deps: {'myapp': 'any'});
+      builder.serve('overridden', '1.0.0');
+      builder.serve('overridden', '2.0.0');
+      builder.serve('override_only', '1.2.3');
+      builder.serve('circular_a', '1.2.3', deps: {'circular_b': 'any'});
+      builder.serve('circular_b', '1.2.3', deps: {'circular_a': 'any'});
+    });
 
     await d.dir('from_path',
         [d.libDir('from_path'), d.libPubspec('from_path', '1.2.3')]).create();
diff --git a/test/descriptor.dart b/test/descriptor.dart
index ee50851..7a592db 100644
--- a/test/descriptor.dart
+++ b/test/descriptor.dart
@@ -179,7 +179,7 @@
 /// that this cache represents. It defaults to [globalServer.port].
 Descriptor hostedCache(Iterable<Descriptor> contents, {int? port}) {
   return dir(cachePath, [
-    dir('hosted', [dir('localhost%58${port ?? globalServer.port}', contents)])
+    dir('hosted', [dir('localhost%58${port ?? globalServer?.port}', contents)])
   ]);
 }
 
@@ -277,23 +277,6 @@
 }) =>
     PackageConfigFileDescriptor(packages, generatorVersion);
 
-Descriptor appPackageConfigFile(
-  List<PackageConfigEntry> packages, {
-  String generatorVersion = '0.1.2+3',
-}) =>
-    dir(
-      appPath,
-      [
-        packageConfigFile(
-          [
-            packageConfigEntry(name: 'myapp', path: '.'),
-            ...packages,
-          ],
-          generatorVersion: generatorVersion,
-        ),
-      ],
-    );
-
 /// Create a [PackageConfigEntry] which assumes package with [name] is either
 /// a cached package with given [version] or a path dependency at given [path].
 PackageConfigEntry packageConfigEntry({
@@ -301,7 +284,6 @@
   String? version,
   String? path,
   String? languageVersion,
-  PackageServer? server,
 }) {
   if (version != null && path != null) {
     throw ArgumentError.value(
@@ -313,7 +295,7 @@
   }
   Uri rootUri;
   if (version != null) {
-    rootUri = p.toUri((server ?? globalServer).pathInCache(name, version));
+    rootUri = p.toUri(globalPackageServer!.pathInCache(name, version));
   } else {
     rootUri = p.toUri(p.join('..', path));
   }
diff --git a/test/descriptor/packages.dart b/test/descriptor/packages.dart
index b670322..de52a80 100644
--- a/test/descriptor/packages.dart
+++ b/test/descriptor/packages.dart
@@ -156,20 +156,10 @@
 
     // Compare packages as sets to ignore ordering.
     expect(
-      config.packages,
-      _packages
-          .map(
-            (p) => isA<PackageConfigEntry>()
-                .having((p0) => p0.name, 'name', p.name)
-                .having(
-                    (p0) => p0.languageVersion,
-                    'languageVersion',
-                    // If the expected entry has no language-version we don't check it.
-                    p.languageVersion ?? anything)
-                .having((p0) => p0.rootUri, 'rootUri', p.rootUri)
-                .having((p0) => p0.packageUri, 'packageUri', p.packageUri),
-          )
-          .toSet(),
+      config.packages.map((e) => e.toJson()).toSet(),
+      equals(_packages.map((e) => e.toJson()).toSet()),
+      reason:
+          '"packages" property in "$packageConfigFile" does not expected values',
     );
 
     final expected = PackageConfig.fromJson(_config.toJson());
diff --git a/test/descriptor_server.dart b/test/descriptor_server.dart
new file mode 100644
index 0000000..973a49c
--- /dev/null
+++ b/test/descriptor_server.dart
@@ -0,0 +1,142 @@
+// Copyright (c) 2016, 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 'dart:async';
+
+import 'package:collection/collection.dart' show IterableExtension;
+import 'package:path/path.dart' as p;
+import 'package:shelf/shelf.dart' as shelf;
+import 'package:shelf/shelf_io.dart' as shelf_io;
+import 'package:test/test.dart' hide fail;
+
+import 'descriptor.dart' as d;
+
+/// The global [DescriptorServer] that's used by default.
+///
+/// `null` if there's no global server in use. This can be set to replace the
+/// existing global server.
+DescriptorServer? get globalServer => _globalServer;
+set globalServer(DescriptorServer? value) {
+  var server = _globalServer;
+  if (server == null) {
+    addTearDown(() {
+      _globalServer = null;
+    });
+  } else {
+    expect(server.close(), completes);
+  }
+
+  _globalServer = value;
+}
+
+DescriptorServer? _globalServer;
+
+/// Creates a global [DescriptorServer] to serve [contents] as static files.
+///
+/// This server will exist only for the duration of the pub run. It's accessible
+/// via [server]. Subsequent calls to [serve] replace the previous server.
+Future serve([List<d.Descriptor> contents = const []]) async {
+  globalServer = (await DescriptorServer.start())..contents.addAll(contents);
+}
+
+class DescriptorServer {
+  /// The underlying server.
+  final shelf.Server _server;
+
+  /// A future that will complete to the port used for the server.
+  int get port => _server.url.port;
+
+  /// The list of paths that have been requested from this server.
+  final requestedPaths = <String>[];
+
+  /// The base directory descriptor of the directories served by [this].
+  final d.DirectoryDescriptor _baseDir;
+
+  /// The descriptors served by this server.
+  ///
+  /// This can safely be modified between requests.
+  List<d.Descriptor> get contents => _baseDir.contents;
+
+  /// Handlers for requests not easily described as files.
+  final Map<Pattern, shelf.Handler> extraHandlers = {};
+
+  /// Creates an HTTP server to serve [contents] as static files.
+  ///
+  /// This server exists only for the duration of the pub run. Subsequent calls
+  /// to [serve] replace the previous server.
+  static Future<DescriptorServer> start() async =>
+      DescriptorServer._(await shelf_io.IOServer.bind('localhost', 0));
+
+  /// Creates a server that reports an error if a request is ever received.
+  static Future<DescriptorServer> errors() async =>
+      DescriptorServer._(await shelf_io.IOServer.bind('localhost', 0));
+
+  DescriptorServer._(this._server) : _baseDir = d.dir('serve-dir', []) {
+    _server.mount((request) async {
+      final pathWithInitialSlash = '/${request.url.path}';
+      final key = extraHandlers.keys.firstWhereOrNull((pattern) {
+        final match = pattern.matchAsPrefix(pathWithInitialSlash);
+        return match != null && match.end == pathWithInitialSlash.length;
+      });
+      if (key != null) return extraHandlers[key]!(request);
+
+      var path = p.posix.fromUri(request.url.path);
+      requestedPaths.add(path);
+
+      try {
+        var stream = await _validateStream(_baseDir.load(path));
+        return shelf.Response.ok(stream);
+      } catch (_) {
+        return shelf.Response.notFound('File "$path" not found.');
+      }
+    });
+    addTearDown(_server.close);
+  }
+
+  /// Closes this server.
+  Future close() => _server.close();
+}
+
+/// Ensures that [stream] can emit at least one value successfully (or close
+/// without any values).
+///
+/// For example, reading asynchronously from a non-existent file will return a
+/// stream that fails on the first chunk. In order to handle that more
+/// gracefully, you may want to check that the stream looks like it's working
+/// before you pipe the stream to something else.
+///
+/// This lets you do that. It returns a [Future] that completes to a [Stream]
+/// emitting the same values and errors as [stream], but only if at least one
+/// value can be read successfully. If an error occurs before any values are
+/// emitted, the returned Future completes to that error.
+Future<Stream<T>> _validateStream<T>(Stream<T> stream) {
+  var completer = Completer<Stream<T>>();
+  var controller = StreamController<T>(sync: true);
+
+  late StreamSubscription subscription;
+  subscription = stream.listen((value) {
+    // We got a value, so the stream is valid.
+    if (!completer.isCompleted) completer.complete(controller.stream);
+    controller.add(value);
+  }, onError: (error, [StackTrace? stackTrace]) {
+    // If the error came after values, it's OK.
+    if (completer.isCompleted) {
+      controller.addError(error, stackTrace);
+      return;
+    }
+
+    // Otherwise, the error came first and the stream is invalid.
+    completer.completeError(error, stackTrace);
+
+    // We won't be returning the stream at all in this case, so unsubscribe
+    // and swallow the error.
+    subscription.cancel();
+  }, onDone: () {
+    // It closed with no errors, so the stream is valid.
+    if (!completer.isCompleted) completer.complete(controller.stream);
+    controller.close();
+  });
+
+  return completer.future;
+}
diff --git a/test/dev_dependency_test.dart b/test/dev_dependency_test.dart
index b192444..88f321b 100644
--- a/test/dev_dependency_test.dart
+++ b/test/dev_dependency_test.dart
@@ -27,10 +27,7 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-      d.packageConfigEntry(name: 'bar', path: '../bar'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '../foo', 'bar': '../bar'}).validate();
   });
 
   test("includes dev dependency's transitive dependencies", () async {
@@ -55,10 +52,7 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-      d.packageConfigEntry(name: 'bar', path: '../bar'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '../foo', 'bar': '../bar'}).validate();
   });
 
   test("ignores transitive dependency's dev dependencies", () async {
@@ -84,8 +78,6 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '../foo'}).validate();
   });
 }
diff --git a/test/directory_option_test.dart b/test/directory_option_test.dart
index 65193bf..2865a69 100644
--- a/test/directory_option_test.dart
+++ b/test/directory_option_test.dart
@@ -14,21 +14,20 @@
 Future<void> main() async {
   testWithGolden('commands taking a --directory/-C parameter work',
       (ctx) async {
-    await servePackages()
+    await servePackages((b) => b
       ..serve('foo', '1.0.0')
       ..serve('foo', '0.1.2')
-      ..serve('bar', '1.2.3');
-    await credentialsFile(globalServer, 'access token').create();
-    globalServer.handle(
-      RegExp('/api/packages/test_pkg/uploaders'),
-      (request) {
-        return shelf.Response.ok(
-            jsonEncode({
-              'success': {'message': 'Good job!'}
-            }),
-            headers: {'content-type': 'application/json'});
-      },
-    );
+      ..serve('bar', '1.2.3'));
+    await credentialsFile(globalPackageServer!, 'access token').create();
+    globalPackageServer!
+        .extraHandlers[RegExp('/api/packages/test_pkg/uploaders')] = (request) {
+      return shelf.Response.ok(
+        jsonEncode({
+          'success': {'message': 'Good job!'}
+        }),
+        headers: {'content-type': 'application/json'},
+      );
+    };
 
     await validPackage.create();
     await dir(appPath, [
diff --git a/test/downgrade/does_not_show_other_versions_test.dart b/test/downgrade/does_not_show_other_versions_test.dart
index 884bbaf..ca872c8 100644
--- a/test/downgrade/does_not_show_other_versions_test.dart
+++ b/test/downgrade/does_not_show_other_versions_test.dart
@@ -9,10 +9,11 @@
 
 void main() {
   test('does not show how many other versions are available', () async {
-    await servePackages()
-      ..serve('downgraded', '1.0.0')
-      ..serve('downgraded', '2.0.0')
-      ..serve('downgraded', '3.0.0-dev');
+    await servePackages((builder) {
+      builder.serve('downgraded', '1.0.0');
+      builder.serve('downgraded', '2.0.0');
+      builder.serve('downgraded', '3.0.0-dev');
+    });
 
     await d.appDir({'downgraded': '3.0.0-dev'}).create();
 
diff --git a/test/downgrade/dry_run_does_not_apply_changes_test.dart b/test/downgrade/dry_run_does_not_apply_changes_test.dart
index 38fbebe..ebe2dbf 100644
--- a/test/downgrade/dry_run_does_not_apply_changes_test.dart
+++ b/test/downgrade/dry_run_does_not_apply_changes_test.dart
@@ -11,9 +11,10 @@
 
 void main() {
   test('--dry-run shows report but does not apply changes', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0');
+    });
 
     // Create the first lockfile.
     await d.appDir({'foo': '2.0.0'}).create();
diff --git a/test/downgrade/unlock_if_necessary_test.dart b/test/downgrade/unlock_if_necessary_test.dart
index c8b55af..eac39a8 100644
--- a/test/downgrade/unlock_if_necessary_test.dart
+++ b/test/downgrade/unlock_if_necessary_test.dart
@@ -11,27 +11,24 @@
   test(
       "downgrades one locked hosted package's dependencies if it's "
       'necessary', () async {
-    final server = await servePackages();
-    server.serve('foo', '2.0.0', deps: {'foo_dep': 'any'});
-    server.serve('foo_dep', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '2.0.0', deps: {'foo_dep': 'any'});
+      builder.serve('foo_dep', '2.0.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-      d.packageConfigEntry(name: 'foo_dep', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '2.0.0', 'foo_dep': '2.0.0'}).validate();
 
-    server.serve('foo', '1.0.0', deps: {'foo_dep': '<2.0.0'});
-    server.serve('foo_dep', '1.0.0');
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '1.0.0', deps: {'foo_dep': '<2.0.0'});
+      builder.serve('foo_dep', '1.0.0');
+    });
 
     await pubDowngrade(args: ['foo']);
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'foo_dep', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'foo_dep': '1.0.0'}).validate();
   });
 }
diff --git a/test/downgrade/unlock_single_package_test.dart b/test/downgrade/unlock_single_package_test.dart
index 1188e41..8997ba2 100644
--- a/test/downgrade/unlock_single_package_test.dart
+++ b/test/downgrade/unlock_single_package_test.dart
@@ -9,60 +9,51 @@
 
 void main() {
   test('can unlock a single package only in downgrade', () async {
-    final server = await servePackages();
-    server.serve('foo', '2.1.0', deps: {'bar': '>1.0.0'});
-    server.serve('bar', '2.1.0');
+    await servePackages((builder) {
+      builder.serve('foo', '2.1.0', deps: {'bar': '>1.0.0'});
+      builder.serve('bar', '2.1.0');
+    });
 
     await d.appDir({'foo': 'any', 'bar': 'any'}).create();
 
     await pubGet();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.1.0'),
-      d.packageConfigEntry(name: 'bar', version: '2.1.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '2.1.0', 'bar': '2.1.0'}).validate();
 
-    server.serve('foo', '1.0.0', deps: {'bar': 'any'});
-    server.serve('bar', '1.0.0');
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': 'any'});
+      builder.serve('bar', '1.0.0');
+    });
 
     await pubDowngrade(args: ['bar']);
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.1.0'),
-      d.packageConfigEntry(name: 'bar', version: '2.1.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '2.1.0', 'bar': '2.1.0'}).validate();
 
-    server.serve('foo', '2.0.0', deps: {'bar': 'any'});
-    server.serve('bar', '2.0.0');
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '2.0.0', deps: {'bar': 'any'});
+      builder.serve('bar', '2.0.0');
+    });
 
     await pubDowngrade(args: ['bar']);
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.1.0'),
-      d.packageConfigEntry(name: 'bar', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '2.1.0', 'bar': '2.0.0'}).validate();
 
     await pubDowngrade();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate();
   });
 
   test('will not downgrade below constraint #2629', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0')
-      ..serve('foo', '2.1.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0');
+      builder.serve('foo', '2.1.0');
+    });
 
     await d.appDir({'foo': '^2.0.0'}).create();
 
     await pubGet();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.1.0'),
-    ]).validate();
+
+    await d.appPackagesFile({'foo': '2.1.0'}).validate();
 
     await pubDowngrade(args: ['foo']);
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '2.0.0'}).validate();
   });
 }
diff --git a/test/embedding/embedding_test.dart b/test/embedding/embedding_test.dart
index a9795ea..20e127e 100644
--- a/test/embedding/embedding_test.dart
+++ b/test/embedding/embedding_test.dart
@@ -6,20 +6,16 @@
 import 'dart:io';
 
 import 'package:path/path.dart' as path;
-import 'package:path/path.dart' as p;
 import 'package:test/test.dart';
 import 'package:test_process/test_process.dart';
-
 import '../descriptor.dart' as d;
 import '../golden_file.dart';
 import '../test_pub.dart';
 
-const _commandRunner = 'tool/test-bin/pub_command_runner.dart';
+const _command_runner = 'tool/test-bin/pub_command_runner.dart';
 
 late String snapshot;
 
-final logFile = p.join(d.sandbox, cachePath, 'log', 'pub_log.txt');
-
 /// Runs `dart tool/test-bin/pub_command_runner.dart [args]` and appends the output to [buffer].
 Future<void> runEmbeddingToBuffer(
   List<String> args,
@@ -40,10 +36,13 @@
   await process.shouldExit(exitCode);
 
   buffer.writeln([
-    '\$ $_commandRunner ${args.join(' ')}',
-    ...await process.stdout.rest.map(_filter).toList(),
-    ...await process.stderr.rest.map((e) => '[E] ${_filter(e)}').toList(),
+    '\$ $_command_runner ${args.join(' ')}',
+    ...await process.stdout.rest.toList(),
   ].join('\n'));
+  final stdErr = await process.stderr.rest.toList();
+  if (stdErr.isNotEmpty) {
+    buffer.writeln(stdErr.map((e) => '[E] $e').join('\n'));
+  }
   buffer.write('\n');
 }
 
@@ -52,7 +51,7 @@
   /// next section in golden file.
   Future<void> runEmbedding(
     List<String> args, {
-    String? workingDirectory,
+    String? workingDirextory,
     Map<String, String>? environment,
     dynamic exitCode = 0,
   }) async {
@@ -60,7 +59,7 @@
     await runEmbeddingToBuffer(
       args,
       buffer,
-      workingDirectory: workingDirectory,
+      workingDirectory: workingDirextory,
       environment: environment,
       exitCode: exitCode,
     );
@@ -74,7 +73,7 @@
     final tempDir = Directory.systemTemp.createTempSync();
     snapshot = path.join(tempDir.path, 'command_runner.dart.snapshot');
     final r = Process.runSync(
-        Platform.resolvedExecutable, ['--snapshot=$snapshot', _commandRunner]);
+        Platform.resolvedExecutable, ['--snapshot=$snapshot', _command_runner]);
     expect(r.exitCode, 0, reason: r.stderr);
   });
 
@@ -83,7 +82,6 @@
   });
 
   testWithGolden('run works, though hidden', (ctx) async {
-    await servePackages();
     await d.dir(appPath, [
       d.pubspec({
         'name': 'myapp',
@@ -103,60 +101,19 @@
     ]).create();
     await ctx.runEmbedding(
       ['pub', 'get'],
-      workingDirectory: d.path(appPath),
+      workingDirextory: d.path(appPath),
     );
     await ctx.runEmbedding(
       ['pub', 'run', 'bin/main.dart'],
       exitCode: 123,
-      workingDirectory: d.path(appPath),
-    );
-  });
-
-  testWithGolden(
-      'logfile is written with --verbose and on unexpected exceptions',
-      (context) async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
-    await d.appDir({'foo': 'any'}).create();
-
-    // TODO(sigurdm) This logs the entire verbose trace to a golden file.
-    //
-    // This is fragile, and can break for all sorts of small reasons. We think
-    // this might be worth while having to have at least minimal testing of the
-    // verbose stack trace.
-    //
-    // But if you, future contributor, think this test is annoying: feel free to
-    // remove it, or rewrite it to filter out the stack-trace itself, only
-    // testing for creation of the file.
-    //
-    //  It is a fragile test, and we acknowledge that it's usefulness can be
-    //  debated...
-    await context.runEmbedding(
-      ['pub', '--verbose', 'get'],
-      workingDirectory: d.path(appPath),
-    );
-    context.expectNextSection(
-      _filter(
-        File(logFile).readAsStringSync(),
-      ),
-    );
-    await d.dir('empty').create();
-    await context.runEmbedding(
-      ['pub', 'fail'],
-      workingDirectory: d.path('empty'),
-      exitCode: 1,
-    );
-    context.expectNextSection(
-      _filter(
-        File(logFile).readAsStringSync(),
-      ),
+      workingDirextory: d.path(appPath),
     );
   });
 
   test('analytics', () async {
-    await servePackages()
+    await servePackages((b) => b
       ..serve('foo', '1.0.0', deps: {'bar': 'any'})
-      ..serve('bar', '1.0.0');
+      ..serve('bar', '1.0.0'));
     await d.dir('dep', [
       d.pubspec({
         'name': 'dep',
@@ -218,113 +175,5 @@
         }
       },
     });
-    // Don't write the logs to file on a normal run.
-    expect(File(logFile).existsSync(), isFalse);
   });
-
-  test('`embedding --verbose pub` is verbose', () async {
-    await servePackages();
-    final buffer = StringBuffer();
-    await runEmbeddingToBuffer(['--verbose', 'pub', 'logout'], buffer);
-    expect(buffer.toString(), contains('FINE: Pub 0.1.2+3'));
-  });
-}
-
-String _filter(String input) {
-  return input
-      .replaceAll(p.toUri(d.sandbox).toString(), r'file://$SANDBOX')
-      .replaceAll(d.sandbox, r'$SANDBOX')
-      .replaceAll(Platform.pathSeparator, '/')
-      .replaceAll(Platform.operatingSystem, r'$OS')
-      .replaceAll(globalServer.port.toString(), r'$PORT')
-      .replaceAll(
-        RegExp(r'^Created:(.*)$', multiLine: true),
-        r'Created: $TIME',
-      )
-      .replaceAll(
-        RegExp(r'Generated by pub on (.*)$', multiLine: true),
-        r'Generated by pub on $TIME',
-      )
-      .replaceAll(
-        RegExp(r'X-Pub-Session-ID(.*)$', multiLine: true),
-        r'X-Pub-Session-ID: $ID',
-      )
-      .replaceAll(
-        RegExp(r'took (.*)$', multiLine: true),
-        r'took: $TIME',
-      )
-      .replaceAll(
-        RegExp(r'date: (.*)$', multiLine: true),
-        r'date: $TIME',
-      )
-      .replaceAll(
-        RegExp(r'Creating (.*) from stream\.$', multiLine: true),
-        r'Creating $FILE from stream',
-      )
-      .replaceAll(
-        RegExp(r'Created (.*) from stream\.$', multiLine: true),
-        r'Created $FILE from stream',
-      )
-      .replaceAll(
-        RegExp(r'Renaming directory $SANDBOX/cache/_temp/(.*?) to',
-            multiLine: true),
-        r'Renaming directory $SANDBOX/cache/_temp/',
-      )
-      .replaceAll(
-        RegExp(r'Extracting .tar.gz stream to (.*?)$', multiLine: true),
-        r'Extracting .tar.gz stream to $DIR',
-      )
-      .replaceAll(
-        RegExp(r'Extracted .tar.gz to (.*?)$', multiLine: true),
-        r'Extracted .tar.gz to $DIR',
-      )
-      .replaceAll(
-        RegExp(r'Reading binary file (.*?)$', multiLine: true),
-        r'Reading binary file $FILE.',
-      )
-      .replaceAll(
-        RegExp(r'Deleting directory (.*)$', multiLine: true),
-        r'Deleting directory $DIR',
-      )
-      .replaceAll(
-        RegExp(r'Deleting directory (.*)$', multiLine: true),
-        r'Deleting directory $DIR',
-      )
-      .replaceAll(
-        RegExp(r'Resolving dependencies finished (.*)$', multiLine: true),
-        r'Resolving dependencies finished ($TIME)',
-      )
-      .replaceAll(
-        RegExp(r'Created temp directory (.*)$', multiLine: true),
-        r'Created temp directory $DIR',
-      )
-      .replaceAll(
-        RegExp(r'Renaming directory (.*)$', multiLine: true),
-        r'Renaming directory $A to $B',
-      )
-      .replaceAll(
-        RegExp(r'"_fetchedAt":"(.*)"}$', multiLine: true),
-        r'"_fetchedAt": "$TIME"}',
-      )
-      .replaceAll(
-        RegExp(r'"generated": "(.*)",$', multiLine: true),
-        r'"generated": "$TIME",',
-      )
-      .replaceAll(
-        RegExp(r'( |^)(/|[A-Z]:)(.*)/tool/test-bin/pub_command_runner.dart',
-            multiLine: true),
-        r' tool/test-bin/pub_command_runner.dart',
-      )
-      .replaceAll(
-        RegExp(r'[ ]{4,}', multiLine: true),
-        r'   ',
-      )
-      .replaceAll(
-        RegExp(r' [\d]+:[\d]+ ', multiLine: true),
-        r' $LINE:$COL ',
-      )
-      .replaceAll(
-        RegExp(r'Writing \d+ characters', multiLine: true),
-        r'Writing $N characters',
-      );
 }
diff --git a/test/embedding/get_executable_for_command_test.dart b/test/embedding/get_executable_for_command_test.dart
index 0edfa72..611f5ef 100644
--- a/test/embedding/get_executable_for_command_test.dart
+++ b/test/embedding/get_executable_for_command_test.dart
@@ -25,7 +25,7 @@
 }) async {
   final _cachePath = getPubTestEnvironment()['PUB_CACHE'];
   final oldVerbosity = log.verbosity;
-  log.verbosity = log.Verbosity.none;
+  log.verbosity = log.Verbosity.NONE;
   if (executable == null) {
     expect(
       () => getExecutableForCommand(
@@ -129,7 +129,7 @@
       ])
     ]).create();
 
-    await servePackages();
+    await serveNoPackages();
     // The solver uses word-wrapping in its error message, so we use \s to
     // accomodate.
     await testGetExecutable(
@@ -166,7 +166,7 @@
       ])
     ]).create();
 
-    await servePackages();
+    await serveNoPackages();
     // The solver uses word-wrapping in its error message, so we use \s to
     // accomodate.
     await testGetExecutable(
@@ -178,15 +178,15 @@
   });
 
   test('Finds files', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'environment': {'sdk': '>=$_currentVersion <3.0.0'}
-    }, contents: [
-      d.dir('bin', [
-        d.file('foo.dart', 'main() {print(42);}'),
-        d.file('tool.dart', 'main() {print(42);}')
-      ])
-    ]);
+    await servePackages((b) => b
+      ..serve('foo', '1.0.0', pubspec: {
+        'environment': {'sdk': '>=$_currentVersion <3.0.0'}
+      }, contents: [
+        d.dir('bin', [
+          d.file('foo.dart', 'main() {print(42);}'),
+          d.file('tool.dart', 'main() {print(42);}')
+        ])
+      ]));
 
     await d.dir(appPath, [
       d.pubspec({
diff --git a/test/get/dry_run_does_not_apply_changes_test.dart b/test/get/dry_run_does_not_apply_changes_test.dart
index 3e44bf9..27969ae 100644
--- a/test/get/dry_run_does_not_apply_changes_test.dart
+++ b/test/get/dry_run_does_not_apply_changes_test.dart
@@ -9,8 +9,9 @@
 
 void main() {
   test('--dry-run shows but does not apply changes', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+    });
 
     await d.appDir({'foo': '1.0.0'}).create();
 
diff --git a/test/get/git/path_test.dart b/test/get/git/path_test.dart
index a323be7..49607a1 100644
--- a/test/get/git/path_test.dart
+++ b/test/get/git/path_test.dart
@@ -37,11 +37,9 @@
       ])
     ]).validate();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'sub',
-          path: pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir')),
-    ]).validate();
+    await d.appPackagesFile({
+      'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir')
+    }).validate();
   });
 
   test('depends on a package in a deep subdirectory', () async {
@@ -73,12 +71,9 @@
       ])
     ]).validate();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'sub',
-          path:
-              pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir%25')),
-    ]).validate();
+    await d.appPackagesFile({
+      'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir%25')
+    }).validate();
 
     final lockFile = LockFile.load(
         p.join(d.sandbox, appPath, 'pubspec.lock'), SourceRegistry());
@@ -120,12 +115,9 @@
       ])
     ]).validate();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'sub',
-          path:
-              pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir%25')),
-    ]).validate();
+    await d.appPackagesFile({
+      'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir%25')
+    }).validate();
 
     final lockFile = LockFile.load(
         p.join(d.sandbox, appPath, 'pubspec.lock'), SourceRegistry());
@@ -166,14 +158,10 @@
       ])
     ]).validate();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'sub1',
-          path: pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir1')),
-      d.packageConfigEntry(
-          name: 'sub2',
-          path: pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir2')),
-    ]).validate();
+    await d.appPackagesFile({
+      'sub1': pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir1'),
+      'sub2': pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir2')
+    }).validate();
   });
 
   test('depends on packages in the same subdirectory at different revisions',
@@ -218,11 +206,9 @@
       ])
     ]).validate();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(
-          name: 'sub1', path: pathInCache('git/foo-$oldRevision/subdir')),
-      d.packageConfigEntry(
-          name: 'sub2', path: pathInCache('git/foo-$newRevision/subdir')),
-    ]).validate();
+    await d.appPackagesFile({
+      'sub1': pathInCache('git/foo-$oldRevision/subdir'),
+      'sub2': pathInCache('git/foo-$newRevision/subdir')
+    }).validate();
   });
 }
diff --git a/test/get/hosted/avoid_network_requests_test.dart b/test/get/hosted/avoid_network_requests_test.dart
index c62fa7c..369a187 100644
--- a/test/get/hosted/avoid_network_requests_test.dart
+++ b/test/get/hosted/avoid_network_requests_test.dart
@@ -9,13 +9,14 @@
 
 void main() {
   test('only requests versions that are needed during solving', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '1.1.0')
-      ..serve('foo', '1.2.0')
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '1.1.0')
-      ..serve('bar', '1.2.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '1.1.0');
+      builder.serve('foo', '1.2.0');
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '1.1.0');
+      builder.serve('bar', '1.2.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
 
@@ -24,22 +25,20 @@
 
     // Clear the cache. We don't care about anything that was served during
     // the initial get.
-    globalServer.requestedPaths.clear();
+    globalServer!.requestedPaths.clear();
 
     // Add "bar" to the dependencies.
     await d.appDir({'foo': 'any', 'bar': 'any'}).create();
 
     // Run the solver again.
     await pubGet();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.2.0'),
-    ]).validate();
+
+    await d.appPackagesFile({'foo': '1.2.0', 'bar': '1.2.0'}).validate();
 
     // The get should not have done any network requests since the lock file is
     // up to date.
     expect(
-        globalServer.requestedPaths,
+        globalServer!.requestedPaths,
         unorderedEquals([
           // Bar should be requested because it's new, but not foo.
           'api/packages/bar',
diff --git a/test/get/hosted/cached_pubspec_test.dart b/test/get/hosted/cached_pubspec_test.dart
index fa9decc..88551ac 100644
--- a/test/get/hosted/cached_pubspec_test.dart
+++ b/test/get/hosted/cached_pubspec_test.dart
@@ -9,8 +9,7 @@
 
 void main() {
   test('does not request a pubspec for a cached package', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
     await d.appDir({'foo': '1.2.3'}).create();
 
@@ -19,18 +18,16 @@
 
     // Clear the cache. We don't care about anything that was served during
     // the initial get.
-    server.requestedPaths.clear();
+    globalServer!.requestedPaths.clear();
 
     await d.cacheDir({'foo': '1.2.3'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
 
     // Run the solver again now that it's cached.
     await pubGet();
 
     // The get should not have requested the pubspec since it's local already.
-    expect(server.requestedPaths,
+    expect(globalServer!.requestedPaths,
         isNot(contains('packages/foo/versions/1.2.3.yaml')));
   });
 }
diff --git a/test/get/hosted/do_not_upgrade_on_removed_constraints_test.dart b/test/get/hosted/do_not_upgrade_on_removed_constraints_test.dart
index 44fe075..30e4a65 100644
--- a/test/get/hosted/do_not_upgrade_on_removed_constraints_test.dart
+++ b/test/get/hosted/do_not_upgrade_on_removed_constraints_test.dart
@@ -11,29 +11,24 @@
   test(
       "doesn't upgrade dependencies whose constraints have been "
       'removed', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'shared_dep': 'any'})
-      ..serve('bar', '1.0.0', deps: {'shared_dep': '<2.0.0'})
-      ..serve('shared_dep', '1.0.0')
-      ..serve('shared_dep', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'shared_dep': 'any'});
+      builder.serve('bar', '1.0.0', deps: {'shared_dep': '<2.0.0'});
+      builder.serve('shared_dep', '1.0.0');
+      builder.serve('shared_dep', '2.0.0');
+    });
 
     await d.appDir({'foo': 'any', 'bar': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-      d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile(
+        {'foo': '1.0.0', 'bar': '1.0.0', 'shared_dep': '1.0.0'}).validate();
 
     await d.appDir({'foo': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'shared_dep': '1.0.0'}).validate();
   });
 }
diff --git a/test/get/hosted/does_no_network_requests_when_possible_test.dart b/test/get/hosted/does_no_network_requests_when_possible_test.dart
index 4324776..3038624 100644
--- a/test/get/hosted/does_no_network_requests_when_possible_test.dart
+++ b/test/get/hosted/does_no_network_requests_when_possible_test.dart
@@ -9,10 +9,11 @@
 
 void main() {
   test('does not request versions if the lockfile is up to date', () async {
-    final server = await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '1.1.0')
-      ..serve('foo', '1.2.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '1.1.0');
+      builder.serve('foo', '1.2.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
 
@@ -21,18 +22,16 @@
 
     // Clear the cache. We don't care about anything that was served during
     // the initial get.
-    server.requestedPaths.clear();
+    globalServer!.requestedPaths.clear();
 
     // Run the solver again now that it's cached.
     await pubGet();
 
     await d.cacheDir({'foo': '1.2.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.0'}).validate();
 
     // The get should not have done any network requests since the lock file is
     // up to date.
-    expect(server.requestedPaths, isEmpty);
+    expect(globalServer!.requestedPaths, isEmpty);
   });
 }
diff --git a/test/get/hosted/explain_bad_hosted_url_test.dart b/test/get/hosted/explain_bad_hosted_url_test.dart
index feebf67..5628ecb 100644
--- a/test/get/hosted/explain_bad_hosted_url_test.dart
+++ b/test/get/hosted/explain_bad_hosted_url_test.dart
@@ -32,12 +32,11 @@
   });
 
   test('Allows PUB_HOSTED_URL to end with a slash', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((b) => b.serve('foo', '1.0.0'));
     await d.appDir({'foo': 'any'}).create();
 
     await pubGet(
-      environment: {'PUB_HOSTED_URL': '${globalServer.url}/'},
+      environment: {'PUB_HOSTED_URL': '${globalPackageServer!.url}/'},
     );
   });
 }
diff --git a/test/get/hosted/get_stress_test.dart b/test/get/hosted/get_stress_test.dart
index 026c0c1..da45309 100644
--- a/test/get/hosted/get_stress_test.dart
+++ b/test/get/hosted/get_stress_test.dart
@@ -9,11 +9,12 @@
 
 void main() {
   test('gets more than 16 packages from a pub server', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
-    for (var i = 0; i < 20; i++) {
-      server.serve('pkg$i', '1.$i.0');
-    }
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.3');
+      for (var i = 0; i < 20; i++) {
+        builder.serve('pkg$i', '1.$i.0');
+      }
+    });
 
     await d.appDir({
       'foo': '1.2.3',
@@ -26,10 +27,10 @@
       'foo': '1.2.3',
       for (var i = 0; i < 20; i++) 'pkg$i': '1.$i.0',
     }).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      for (var i = 0; i < 20; i++)
-        d.packageConfigEntry(name: 'pkg$i', version: '1.$i.0')
-    ]).validate();
+
+    await d.appPackagesFile({
+      'foo': '1.2.3',
+      for (var i = 0; i < 20; i++) 'pkg$i': '1.$i.0',
+    }).validate();
   });
 }
diff --git a/test/get/hosted/get_test.dart b/test/get/hosted/get_test.dart
index f0270a3..31c1f2e 100644
--- a/test/get/hosted/get_test.dart
+++ b/test/get/hosted/get_test.dart
@@ -13,21 +13,18 @@
 
 void main() {
   test('gets a package from a pub server', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
     await d.appDir({'foo': '1.2.3'}).create();
 
     await pubGet();
 
     await d.cacheDir({'foo': '1.2.3'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
   });
 
   test('URL encodes the package name', () async {
-    await servePackages();
+    await serveNoPackages();
 
     await d.appDir({'bad name!': '1.2.3'}).create();
 
@@ -44,10 +41,11 @@
   test('gets a package from a non-default pub server', () async {
     // Make the default server serve errors. Only the custom server should
     // be accessed.
-    (await servePackages()).serveErrors();
+    await serveErrors();
 
-    var server = await startPackageServer();
-    server.serve('foo', '1.2.3');
+    var server = await PackageServer.start((builder) {
+      builder.serve('foo', '1.2.3');
+    });
 
     await d.appDir({
       'foo': {
@@ -59,21 +57,18 @@
     await pubGet();
 
     await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3', server: server),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
   });
 
   group('categorizes dependency types in the lockfile', () {
-    setUp(() async {
-      await servePackages()
-        ..serve('foo', '1.2.3', deps: {'bar': 'any'})
-        ..serve('bar', '1.2.3')
-        ..serve('baz', '1.2.3', deps: {'qux': 'any'})
-        ..serve('qux', '1.2.3')
-        ..serve('zip', '1.2.3', deps: {'zap': 'any'})
-        ..serve('zap', '1.2.3');
-    });
+    setUp(() => servePackages((builder) {
+          builder.serve('foo', '1.2.3', deps: {'bar': 'any'});
+          builder.serve('bar', '1.2.3');
+          builder.serve('baz', '1.2.3', deps: {'qux': 'any'});
+          builder.serve('qux', '1.2.3');
+          builder.serve('zip', '1.2.3', deps: {'zap': 'any'});
+          builder.serve('zap', '1.2.3');
+        }));
 
     test('for main, dev, and overridden dependencies', () async {
       await d.dir(appPath, [
diff --git a/test/get/hosted/get_transitive_test.dart b/test/get/hosted/get_transitive_test.dart
index 0ae18ac..f68006a 100644
--- a/test/get/hosted/get_transitive_test.dart
+++ b/test/get/hosted/get_transitive_test.dart
@@ -9,20 +9,18 @@
 
 void main() {
   test('gets packages transitively from a pub server', () async {
-    await servePackages()
-      ..serve('foo', '1.2.3', deps: {'bar': '2.0.4'})
-      ..serve('bar', '2.0.3')
-      ..serve('bar', '2.0.4')
-      ..serve('bar', '2.0.5');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.3', deps: {'bar': '2.0.4'});
+      builder.serve('bar', '2.0.3');
+      builder.serve('bar', '2.0.4');
+      builder.serve('bar', '2.0.5');
+    });
 
     await d.appDir({'foo': '1.2.3'}).create();
 
     await pubGet();
 
     await d.cacheDir({'foo': '1.2.3', 'bar': '2.0.4'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      d.packageConfigEntry(name: 'bar', version: '2.0.4'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3', 'bar': '2.0.4'}).validate();
   });
 }
diff --git a/test/get/hosted/gets_a_package_with_busted_dev_dependencies_test.dart b/test/get/hosted/gets_a_package_with_busted_dev_dependencies_test.dart
index 585cfba..c53079c 100644
--- a/test/get/hosted/gets_a_package_with_busted_dev_dependencies_test.dart
+++ b/test/get/hosted/gets_a_package_with_busted_dev_dependencies_test.dart
@@ -12,11 +12,12 @@
   test(
       'gets a dependency with broken dev dependencies from a pub '
       'server', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3', pubspec: {
-      'dev_dependencies': {
-        'busted': {'not a real source': null}
-      }
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.3', pubspec: {
+        'dev_dependencies': {
+          'busted': {'not a real source': null}
+        }
+      });
     });
 
     await d.appDir({'foo': '1.2.3'}).create();
@@ -24,8 +25,6 @@
     await pubGet();
 
     await d.cacheDir({'foo': '1.2.3'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
   });
 }
diff --git a/test/get/hosted/resolve_constraints_test.dart b/test/get/hosted/resolve_constraints_test.dart
index 466902e..c515c8e 100644
--- a/test/get/hosted/resolve_constraints_test.dart
+++ b/test/get/hosted/resolve_constraints_test.dart
@@ -9,12 +9,13 @@
 
 void main() {
   test('resolves version constraints from a pub server', () async {
-    await servePackages()
-      ..serve('foo', '1.2.3', deps: {'baz': '>=2.0.0'})
-      ..serve('bar', '2.3.4', deps: {'baz': '<3.0.0'})
-      ..serve('baz', '2.0.3')
-      ..serve('baz', '2.0.4')
-      ..serve('baz', '3.0.1');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.3', deps: {'baz': '>=2.0.0'});
+      builder.serve('bar', '2.3.4', deps: {'baz': '<3.0.0'});
+      builder.serve('baz', '2.0.3');
+      builder.serve('baz', '2.0.4');
+      builder.serve('baz', '3.0.1');
+    });
 
     await d.appDir({'foo': 'any', 'bar': 'any'}).create();
 
@@ -22,10 +23,8 @@
 
     await d
         .cacheDir({'foo': '1.2.3', 'bar': '2.3.4', 'baz': '2.0.4'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      d.packageConfigEntry(name: 'bar', version: '2.3.4'),
-      d.packageConfigEntry(name: 'baz', version: '2.0.4'),
-    ]).validate();
+
+    await d.appPackagesFile(
+        {'foo': '1.2.3', 'bar': '2.3.4', 'baz': '2.0.4'}).validate();
   });
 }
diff --git a/test/get/hosted/resolve_with_retracted_package_versions_test.dart b/test/get/hosted/resolve_with_retracted_package_versions_test.dart
index d9b33a4..033e2a6 100644
--- a/test/get/hosted/resolve_with_retracted_package_versions_test.dart
+++ b/test/get/hosted/resolve_with_retracted_package_versions_test.dart
@@ -13,29 +13,28 @@
 
 void main() {
   test('Do not consider retracted packages', () async {
-    final server = await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'})
       ..serve('bar', '1.0.0')
-      ..serve('bar', '1.1.0');
+      ..serve('bar', '1.1.0'));
     await d.appDir({'foo': '1.0.0'}).create();
 
-    server.retractPackageVersion('bar', '1.1.0');
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('bar', '1.1.0'));
     await pubGet();
 
     await d.cacheDir({'foo': '1.0.0', 'bar': '1.0.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate();
   });
 
   test('Error when the only available package version is retracted', () async {
-    final server = await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'})
-      ..serve('bar', '1.0.0');
+      ..serve('bar', '1.0.0'));
     await d.appDir({'foo': '1.0.0'}).create();
 
-    server.retractPackageVersion('bar', '1.0.0');
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('bar', '1.0.0'));
     await pubGet(
         error:
             '''Because every version of foo depends on bar ^1.0.0 which doesn't match any versions, foo is forbidden. 
@@ -48,51 +47,39 @@
   // In this case we expect a newer version to be published at some point which
   // will then cause pub upgrade to choose that one.
   test('Allow retracted version when it was already in pubspec.lock', () async {
-    final server = await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'})
       ..serve('bar', '1.0.0')
-      ..serve('bar', '1.1.0');
+      ..serve('bar', '1.1.0'));
     await d.appDir({'foo': '1.0.0'}).create();
 
     await pubGet();
     await d.cacheDir({'foo': '1.0.0', 'bar': '1.1.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.1.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate();
 
-    server.retractPackageVersion('bar', '1.1.0');
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('bar', '1.1.0'));
     await pubUpgrade();
     await d.cacheDir({'foo': '1.0.0', 'bar': '1.1.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.1.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate();
 
-    server.serve('bar', '2.0.0');
+    globalPackageServer!.add((builder) => builder..serve('bar', '2.0.0'));
     await pubUpgrade();
     await d.cacheDir({'foo': '1.0.0', 'bar': '1.1.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.1.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate();
 
-    server.serve('bar', '1.2.0');
+    globalPackageServer!.add((builder) => builder..serve('bar', '1.2.0'));
     await pubUpgrade();
     await d.cacheDir({'foo': '1.0.0', 'bar': '1.2.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.2.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.2.0'}).validate();
   });
 
   test('Offline versions of pub commands also handle retracted packages',
       () async {
-    final server = await servePackages();
     await populateCache({
       'foo': ['1.0.0'],
       'bar': ['1.0.0', '1.1.0']
-    }, server);
+    });
 
     await d.cacheDir({
       'foo': '1.0.0',
@@ -100,27 +87,25 @@
     }).validate();
 
     final barVersionsCache =
-        p.join(globalServer.cachingPath, '.cache', 'bar-versions.json');
+        p.join(globalPackageServer!.cachingPath, '.cache', 'bar-versions.json');
     expect(fileExists(barVersionsCache), isTrue);
     deleteEntry(barVersionsCache);
 
-    server.retractPackageVersion('bar', '1.1.0');
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('bar', '1.1.0'));
     await pubGet();
 
     await d.cacheDir({'bar': '1.1.0'}).validate();
 
     // Now serve only errors - to validate we are truly offline.
-    server.serveErrors();
+    await serveErrors();
 
     await d.appDir({'foo': '1.0.0', 'bar': '^1.0.0'}).create();
 
     await pubUpgrade(args: ['--offline']);
 
     // We choose bar 1.1.0 since we already have it in pubspec.lock
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.1.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate();
 
     // Delete lockfile so that retracted versions are not considered.
     final lockFile = p.join(d.sandbox, appPath, 'pubspec.lock');
@@ -128,17 +113,15 @@
     deleteEntry(lockFile);
 
     await pubGet(args: ['--offline']);
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate();
   });
 
   test('Allow retracted version when pinned in dependency_overrides', () async {
-    final server = await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0')
-      ..serve('foo', '3.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0');
+      builder.serve('foo', '3.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -148,31 +131,31 @@
       })
     ]).create();
 
-    server.retractPackageVersion('foo', '2.0.0');
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('foo', '2.0.0'));
 
     await pubGet();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '2.0.0'}).validate();
   });
 
   test('Prefer retracted version in dependency_overrides over pubspec.lock',
       () async {
-    final server = await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0')
-      ..serve('foo', '3.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0');
+      builder.serve('foo', '3.0.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
     await pubGet();
 
-    server.retractPackageVersion('foo', '2.0.0');
-    server.retractPackageVersion('foo', '3.0.0');
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('foo', '2.0.0'));
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('foo', '3.0.0'));
 
     await pubUpgrade();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '3.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '3.0.0'}).validate();
 
     await d.dir(appPath, [
       d.pubspec({
@@ -183,8 +166,6 @@
     ]).create();
 
     await pubUpgrade();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '2.0.0'}).validate();
   });
 }
diff --git a/test/get/hosted/stay_locked_if_compatible_test.dart b/test/get/hosted/stay_locked_if_compatible_test.dart
index df04579..52129f2 100644
--- a/test/get/hosted/stay_locked_if_compatible_test.dart
+++ b/test/get/hosted/stay_locked_if_compatible_test.dart
@@ -11,24 +11,20 @@
   test(
       "doesn't upgrade a locked pub server package with a new "
       'compatible constraint', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((builder) => builder.serve('foo', '1.0.0'));
 
     await d.appDir({'foo': 'any'}).create();
 
     await pubGet();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-    ]).validate();
 
-    server.serve('foo', '1.0.1');
+    await d.appPackagesFile({'foo': '1.0.0'}).validate();
+
+    globalPackageServer!.add((builder) => builder.serve('foo', '1.0.1'));
 
     await d.appDir({'foo': '>=1.0.0'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0'}).validate();
   });
 }
diff --git a/test/get/hosted/stay_locked_if_new_is_satisfied_test.dart b/test/get/hosted/stay_locked_if_new_is_satisfied_test.dart
index c75c435..73077b1 100644
--- a/test/get/hosted/stay_locked_if_new_is_satisfied_test.dart
+++ b/test/get/hosted/stay_locked_if_new_is_satisfied_test.dart
@@ -11,34 +11,35 @@
   test(
       "doesn't unlock dependencies if a new dependency is already "
       'satisfied', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'});
-    server.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'});
-    server.serve('baz', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'});
+      builder.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'});
+      builder.serve('baz', '1.0.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
 
     await pubGet();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-      d.packageConfigEntry(name: 'baz', version: '1.0.0'),
-    ]).validate();
 
-    server.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'});
-    server.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'});
-    server.serve('baz', '2.0.0');
-    server.serve('newdep', '2.0.0', deps: {'baz': '>=1.0.0'});
+    await d.appPackagesFile(
+        {'foo': '1.0.0', 'bar': '1.0.0', 'baz': '1.0.0'}).validate();
+
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'});
+      builder.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'});
+      builder.serve('baz', '2.0.0');
+      builder.serve('newdep', '2.0.0', deps: {'baz': '>=1.0.0'});
+    });
 
     await d.appDir({'foo': 'any', 'newdep': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-      d.packageConfigEntry(name: 'baz', version: '1.0.0'),
-      d.packageConfigEntry(name: 'newdep', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({
+      'foo': '1.0.0',
+      'bar': '1.0.0',
+      'baz': '1.0.0',
+      'newdep': '2.0.0'
+    }).validate();
   });
 }
diff --git a/test/get/hosted/stay_locked_test.dart b/test/get/hosted/stay_locked_test.dart
index 8b819ea..eb26ea8 100644
--- a/test/get/hosted/stay_locked_test.dart
+++ b/test/get/hosted/stay_locked_test.dart
@@ -13,28 +13,24 @@
   test(
       'keeps a hosted package locked to the version in the '
       'lockfile', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((builder) => builder.serve('foo', '1.0.0'));
 
     await d.appDir({'foo': 'any'}).create();
 
     // This should lock the foo dependency to version 1.0.0.
     await pubGet();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-    ]).validate();
+
+    await d.appPackagesFile({'foo': '1.0.0'}).validate();
 
     // 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.
-    server.serve('foo', '1.0.1');
+    globalPackageServer!.add((builder) => builder.serve('foo', '1.0.1'));
 
     // This shouldn't upgrade the foo dependency due to the lockfile.
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0'}).validate();
   });
 }
diff --git a/test/get/hosted/unlock_if_incompatible_test.dart b/test/get/hosted/unlock_if_incompatible_test.dart
index 007231e..fad5400 100644
--- a/test/get/hosted/unlock_if_incompatible_test.dart
+++ b/test/get/hosted/unlock_if_incompatible_test.dart
@@ -11,23 +11,18 @@
   test(
       'upgrades a locked pub server package with a new incompatible '
       'constraint', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((builder) => builder.serve('foo', '1.0.0'));
 
     await d.appDir({'foo': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-    ]).validate();
-    server.serve('foo', '1.0.1');
+    await d.appPackagesFile({'foo': '1.0.0'}).validate();
+    globalPackageServer!.add((builder) => builder.serve('foo', '1.0.1'));
     await d.appDir({'foo': '>1.0.0'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.1'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.1'}).validate();
   });
 }
diff --git a/test/get/hosted/unlock_if_new_is_unsatisfied_test.dart b/test/get/hosted/unlock_if_new_is_unsatisfied_test.dart
index ae6a4e6..aa45b76 100644
--- a/test/get/hosted/unlock_if_new_is_unsatisfied_test.dart
+++ b/test/get/hosted/unlock_if_new_is_unsatisfied_test.dart
@@ -11,40 +11,42 @@
   test(
       'unlocks dependencies if necessary to ensure that a new '
       'dependency is satisfied', () async {
-    final server = await servePackages();
-
-    server.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'});
-    server.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'});
-    server.serve('baz', '1.0.0', deps: {'qux': '<2.0.0'});
-    server.serve('qux', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'});
+      builder.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'});
+      builder.serve('baz', '1.0.0', deps: {'qux': '<2.0.0'});
+      builder.serve('qux', '1.0.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-      d.packageConfigEntry(name: 'baz', version: '1.0.0'),
-      d.packageConfigEntry(name: 'qux', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({
+      'foo': '1.0.0',
+      'bar': '1.0.0',
+      'baz': '1.0.0',
+      'qux': '1.0.0'
+    }).validate();
 
-    server.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'});
-    server.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'});
-    server.serve('baz', '2.0.0', deps: {'qux': '<3.0.0'});
-    server.serve('qux', '2.0.0');
-    server.serve('newdep', '2.0.0', deps: {'baz': '>=1.5.0'});
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'});
+      builder.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'});
+      builder.serve('baz', '2.0.0', deps: {'qux': '<3.0.0'});
+      builder.serve('qux', '2.0.0');
+      builder.serve('newdep', '2.0.0', deps: {'baz': '>=1.5.0'});
+    });
 
     await d.appDir({'foo': 'any', 'newdep': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '2.0.0'),
-      d.packageConfigEntry(name: 'baz', version: '2.0.0'),
-      d.packageConfigEntry(name: 'qux', version: '1.0.0'),
-      d.packageConfigEntry(name: 'newdep', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({
+      'foo': '2.0.0',
+      'bar': '2.0.0',
+      'baz': '2.0.0',
+      'qux': '1.0.0',
+      'newdep': '2.0.0'
+    }).validate();
   });
 }
diff --git a/test/get/hosted/unlock_if_version_doesnt_exist_test.dart b/test/get/hosted/unlock_if_version_doesnt_exist_test.dart
index e4cc01b..328745e 100644
--- a/test/get/hosted/unlock_if_version_doesnt_exist_test.dart
+++ b/test/get/hosted/unlock_if_version_doesnt_exist_test.dart
@@ -12,23 +12,16 @@
 void main() {
   test('upgrades a locked pub server package with a nonexistent version',
       () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((builder) => builder.serve('foo', '1.0.0'));
 
     await d.appDir({'foo': 'any'}).create();
     await pubGet();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0'}).validate();
 
     deleteEntry(p.join(d.sandbox, cachePath));
 
-    server.clearPackages();
-    server.serve('foo', '1.0.1');
-
+    globalPackageServer!.replace((builder) => builder.serve('foo', '1.0.1'));
     await pubGet();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.1'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.1'}).validate();
   });
 }
diff --git a/test/get/hosted/warn_about_discontinued_test.dart b/test/get/hosted/warn_about_discontinued_test.dart
index 7057f9b..6df08b8 100644
--- a/test/get/hosted/warn_about_discontinued_test.dart
+++ b/test/get/hosted/warn_about_discontinued_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:path/path.dart' as p;
 import 'package:pub/src/io.dart';
-import 'package:shelf/shelf.dart' as shelf;
+import 'package:shelf/shelf.dart';
 import 'package:test/test.dart';
 
 import '../../descriptor.dart' as d;
@@ -14,22 +14,22 @@
 
 void main() {
   test('Warns about discontinued dependencies', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3', deps: {'transitive': 'any'});
-    server.serve('transitive', '1.0.0');
+    await servePackages((builder) => builder
+      ..serve('foo', '1.2.3', deps: {'transitive': 'any'})
+      ..serve('transitive', '1.0.0'));
     await d.appDir({'foo': '1.2.3'}).create();
     await pubGet();
 
-    server
+    globalPackageServer!.add((builder) => builder
       ..discontinue('foo')
-      ..discontinue('transitive');
+      ..discontinue('transitive'));
     // A pub get straight away will not trigger the warning, as we cache
     // responses for a while.
     await pubGet();
     final fooVersionsCache =
-        p.join(globalServer.cachingPath, '.cache', 'foo-versions.json');
-    final transitiveVersionsCache =
-        p.join(globalServer.cachingPath, '.cache', 'transitive-versions.json');
+        p.join(globalPackageServer!.cachingPath, '.cache', 'foo-versions.json');
+    final transitiveVersionsCache = p.join(
+        globalPackageServer!.cachingPath, '.cache', 'transitive-versions.json');
     expect(fileExists(fooVersionsCache), isTrue);
     expect(fileExists(transitiveVersionsCache), isTrue);
     deleteEntry(fooVersionsCache);
@@ -46,9 +46,8 @@
     c['_fetchedAt'] =
         DateTime.now().subtract(Duration(days: 5)).toIso8601String();
     writeTextFile(fooVersionsCache, json.encode(c));
-
-    server.discontinue('foo', replacementText: 'bar');
-
+    globalPackageServer!
+        .add((builder) => builder.discontinue('foo', replacementText: 'bar'));
     await pubGet(output: '''
 Resolving dependencies...
   foo 1.2.3 (discontinued replaced by bar)
@@ -68,7 +67,7 @@
 Got dependencies!''');
     // Test that --offline won't try to access the server for retrieving the
     // status.
-    server.serveErrors();
+    await serveErrors();
     await pubGet(args: ['--offline'], output: '''
 Resolving dependencies...
   foo 1.2.3 (discontinued replaced by bar)
@@ -82,10 +81,9 @@
   });
 
   test('Warns about discontinued dev dependencies', () async {
-    final builder = await servePackages();
-    builder
+    await servePackages((builder) => builder
       ..serve('foo', '1.2.3', deps: {'transitive': 'any'})
-      ..serve('transitive', '1.0.0');
+      ..serve('transitive', '1.0.0'));
 
     await d.dir(appPath, [
       d.file('pubspec.yaml', '''
@@ -100,14 +98,14 @@
     ]).create();
     await pubGet();
 
-    builder
+    globalPackageServer!.add((builder) => builder
       ..discontinue('foo')
-      ..discontinue('transitive');
+      ..discontinue('transitive'));
     // A pub get straight away will not trigger the warning, as we cache
     // responses for a while.
     await pubGet();
     final fooVersionsCache =
-        p.join(globalServer.cachingPath, '.cache', 'foo-versions.json');
+        p.join(globalPackageServer!.cachingPath, '.cache', 'foo-versions.json');
     expect(fileExists(fooVersionsCache), isTrue);
     deleteEntry(fooVersionsCache);
     // We warn only about the direct dependency here:
@@ -122,7 +120,8 @@
     c['_fetchedAt'] =
         DateTime.now().subtract(Duration(days: 5)).toIso8601String();
     writeTextFile(fooVersionsCache, json.encode(c));
-    builder.discontinue('foo', replacementText: 'bar');
+    globalPackageServer!
+        .add((builder) => builder.discontinue('foo', replacementText: 'bar'));
     await pubGet(output: '''
 Resolving dependencies...
   foo 1.2.3 (discontinued replaced by bar)
@@ -142,7 +141,7 @@
 Got dependencies!''');
     // Test that --offline won't try to access the server for retrieving the
     // status.
-    builder.serveErrors();
+    await serveErrors();
     await pubGet(args: ['--offline'], output: '''
 Resolving dependencies...
   foo 1.2.3 (discontinued replaced by bar)
@@ -155,17 +154,17 @@
   });
 
   test('get does not fail when status listing fails', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder..serve('foo', '1.2.3'));
     await d.appDir({'foo': '1.2.3'}).create();
     await pubGet();
     final fooVersionsCache =
-        p.join(globalServer.cachingPath, '.cache', 'foo-versions.json');
+        p.join(globalPackageServer!.cachingPath, '.cache', 'foo-versions.json');
     expect(fileExists(fooVersionsCache), isTrue);
     deleteEntry(fooVersionsCache);
     // Serve 400 on all requests.
-    globalServer.handle(RegExp('.*'),
-        (shelf.Request request) => shelf.Response.notFound('Not found'));
+    globalPackageServer!.extraHandlers
+      ..clear()
+      ..[RegExp('.*')] = (request) async => Response(400);
 
     /// Even if we fail to get status we still report success if versions don't unlock.
     await pubGet();
diff --git a/test/get/hosted/warn_about_retracted_package_test.dart b/test/get/hosted/warn_about_retracted_package_test.dart
index 2336c7f..5031061 100644
--- a/test/get/hosted/warn_about_retracted_package_test.dart
+++ b/test/get/hosted/warn_about_retracted_package_test.dart
@@ -11,36 +11,38 @@
 
 void main() {
   test('Report retracted packages', () async {
-    final server = await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', deps: {'bar': 'any'})
-      ..serve('bar', '1.0.0');
+      ..serve('bar', '1.0.0'));
     await d.appDir({'foo': '1.0.0'}).create();
 
     await pubGet();
 
-    server.retractPackageVersion('bar', '1.0.0');
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('bar', '1.0.0'));
     // Delete the cache to trigger the report.
     final barVersionsCache =
-        p.join(server.cachingPath, '.cache', 'bar-versions.json');
+        p.join(globalPackageServer!.cachingPath, '.cache', 'bar-versions.json');
     expect(fileExists(barVersionsCache), isTrue);
     deleteEntry(barVersionsCache);
     await pubGet(output: contains('bar 1.0.0 (retracted)'));
   });
 
   test('Report retracted packages with newer version available', () async {
-    final server = await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'})
       ..serve('bar', '1.0.0')
       ..serve('bar', '2.0.0')
-      ..serve('bar', '2.0.1-pre');
+      ..serve('bar', '2.0.1-pre'));
     await d.appDir({'foo': '1.0.0'}).create();
 
     await pubGet();
 
-    server.retractPackageVersion('bar', '1.0.0');
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('bar', '1.0.0'));
     // Delete the cache to trigger the report.
     final barVersionsCache =
-        p.join(server.cachingPath, '.cache', 'bar-versions.json');
+        p.join(globalPackageServer!.cachingPath, '.cache', 'bar-versions.json');
     expect(fileExists(barVersionsCache), isTrue);
     deleteEntry(barVersionsCache);
     await pubGet(output: contains('bar 1.0.0 (retracted, 2.0.0 available)'));
@@ -48,18 +50,19 @@
 
   test('Report retracted packages with newer prerelease version available',
       () async {
-    final server = await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0-pre'})
       ..serve('bar', '1.0.0-pre')
-      ..serve('bar', '2.0.1-pre');
+      ..serve('bar', '2.0.1-pre'));
     await d.appDir({'foo': '1.0.0'}).create();
 
     await pubGet();
 
-    server.retractPackageVersion('bar', '1.0.0-pre');
+    globalPackageServer!
+        .add((builder) => builder..retractPackageVersion('bar', '1.0.0-pre'));
     // Delete the cache to trigger the report.
     final barVersionsCache =
-        p.join(server.cachingPath, '.cache', 'bar-versions.json');
+        p.join(globalPackageServer!.cachingPath, '.cache', 'bar-versions.json');
     expect(fileExists(barVersionsCache), isTrue);
     deleteEntry(barVersionsCache);
     await pubGet(
diff --git a/test/get/package_name_test.dart b/test/get/package_name_test.dart
index b1328cc..46ca386 100644
--- a/test/get/package_name_test.dart
+++ b/test/get/package_name_test.dart
@@ -56,8 +56,7 @@
     await pubGet();
 
     await d.dir(appPath, [
-      d.packageConfigFile(
-          [d.packageConfigEntry(name: 'foo.bar.baz', path: '.')])
+      d.packagesFile({'foo.bar.baz': '.'}),
     ]).validate();
   });
 }
diff --git a/test/get/path/absolute_path_test.dart b/test/get/path/absolute_path_test.dart
index e1897e9..0fc987a 100644
--- a/test/get/path/absolute_path_test.dart
+++ b/test/get/path/absolute_path_test.dart
@@ -21,8 +21,6 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: path.join(d.sandbox, 'foo')),
-    ]).validate();
+    await d.appPackagesFile({'foo': path.join(d.sandbox, 'foo')}).validate();
   });
 }
diff --git a/test/get/path/absolute_symlink_test.dart b/test/get/path/absolute_symlink_test.dart
index 83d3433..1a2d912 100644
--- a/test/get/path/absolute_symlink_test.dart
+++ b/test/get/path/absolute_symlink_test.dart
@@ -24,8 +24,8 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: fooPath),
+    await d.dir(appPath, [
+      d.packagesFile({'myapp': '.', 'foo': fooPath})
     ]).validate();
 
     await d.dir('moved').create();
@@ -35,9 +35,9 @@
     renameInSandbox(appPath, path.join('moved', appPath));
 
     await d.dir('moved', [
-      d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', path: fooPath),
-      ]),
+      d.dir(appPath, [
+        d.packagesFile({'myapp': '.', 'foo': fooPath})
+      ])
     ]).validate();
   });
 }
diff --git a/test/get/path/relative_path_test.dart b/test/get/path/relative_path_test.dart
index e56a453..4255d49 100644
--- a/test/get/path/relative_path_test.dart
+++ b/test/get/path/relative_path_test.dart
@@ -23,9 +23,7 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '../foo'}).validate();
   });
 
   test('path is relative to containing pubspec', () async {
@@ -47,10 +45,8 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../relative/foo'),
-      d.packageConfigEntry(name: 'bar', path: '../relative/bar'),
-    ]).validate();
+    await d.appPackagesFile(
+        {'foo': '../relative/foo', 'bar': '../relative/bar'}).validate();
   });
 
   test('path is relative to containing pubspec when using --directory',
@@ -76,10 +72,9 @@
         workingDirectory: d.sandbox,
         output: contains('Changed 2 dependencies in myapp!'));
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../relative/foo'),
-      d.packageConfigEntry(name: 'bar', path: '../relative/bar'),
-    ]).validate();
+    await d.appPackagesFile(
+      {'foo': '../relative/foo', 'bar': '../relative/bar'},
+    ).validate();
   });
 
   test('relative path preserved in the lockfile', () async {
diff --git a/test/get/path/relative_symlink_test.dart b/test/get/path/relative_symlink_test.dart
index 9136a34..af7185b 100644
--- a/test/get/path/relative_symlink_test.dart
+++ b/test/get/path/relative_symlink_test.dart
@@ -28,8 +28,8 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
+    await d.dir(appPath, [
+      d.packagesFile({'myapp': '.', 'foo': '../foo'})
     ]).validate();
 
     await d.dir('moved').create();
@@ -41,8 +41,8 @@
     renameInSandbox(appPath, path.join('moved', appPath));
 
     await d.dir('moved', [
-      d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', path: '../foo'),
+      d.dir(appPath, [
+        d.packagesFile({'myapp': '.', 'foo': '../foo'})
       ])
     ]).validate();
   });
diff --git a/test/get/path/shared_dependency_symlink_test.dart b/test/get/path/shared_dependency_symlink_test.dart
index d450838..46a78c6 100644
--- a/test/get/path/shared_dependency_symlink_test.dart
+++ b/test/get/path/shared_dependency_symlink_test.dart
@@ -40,10 +40,13 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-      d.packageConfigEntry(name: 'bar', path: '../bar'),
-      d.packageConfigEntry(name: 'shared', path: '../shared'),
+    await d.dir(appPath, [
+      d.packagesFile({
+        'myapp': '.',
+        'foo': '../foo',
+        'bar': '../bar',
+        'shared': '../shared'
+      })
     ]).validate();
   });
 }
diff --git a/test/get/path/shared_dependency_test.dart b/test/get/path/shared_dependency_test.dart
index 3ef91ae..7072221 100644
--- a/test/get/path/shared_dependency_test.dart
+++ b/test/get/path/shared_dependency_test.dart
@@ -35,11 +35,8 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-      d.packageConfigEntry(name: 'bar', path: '../bar'),
-      d.packageConfigEntry(name: 'shared', path: '../shared'),
-    ]).validate();
+    await d.appPackagesFile(
+        {'foo': '../foo', 'bar': '../bar', 'shared': '../shared'}).validate();
   });
 
   test('shared dependency with paths that normalize the same', () async {
@@ -69,10 +66,7 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-      d.packageConfigEntry(name: 'bar', path: '../bar'),
-      d.packageConfigEntry(name: 'shared', path: '../shared'),
-    ]).validate();
+    await d.appPackagesFile(
+        {'foo': '../foo', 'bar': '../bar', 'shared': '../shared'}).validate();
   });
 }
diff --git a/test/get/sdk_constraint_required_test.dart b/test/get/sdk_constraint_required_test.dart
index 3f1e5c0..1b6fbc5 100644
--- a/test/get/sdk_constraint_required_test.dart
+++ b/test/get/sdk_constraint_required_test.dart
@@ -25,8 +25,8 @@
       d.nothing('pubspec.lock'),
       // The "packages" directory should not have been generated.
       d.nothing('packages'),
-      // The package config file should not have been created.
-      d.nothing('.dart_tool/package_config.json'),
+      // The ".packages" file should not have been created.
+      d.nothing('.packages'),
     ]).validate();
   });
 }
diff --git a/test/get/switch_source_test.dart b/test/get/switch_source_test.dart
index 7e56652..dd8c97d 100644
--- a/test/get/switch_source_test.dart
+++ b/test/get/switch_source_test.dart
@@ -9,8 +9,7 @@
 
 void main() {
   test('re-gets a package if its source has changed', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
     await d.dir('foo',
         [d.libDir('foo', 'foo 0.0.1'), d.libPubspec('foo', '0.0.1')]).create();
@@ -21,15 +20,11 @@
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', path: '../foo'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '../foo'}).validate();
     await d.appDir({'foo': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.2.3'}).validate();
   });
 }
diff --git a/test/get/unknown_sdk_test.dart b/test/get/unknown_sdk_test.dart
deleted file mode 100644
index d0c1de3..0000000
--- a/test/get/unknown_sdk_test.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2020, 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:pub/src/exit_codes.dart' as exit_codes;
-import 'package:test/test.dart';
-
-import '../descriptor.dart' as d;
-import '../test_pub.dart';
-
-void main() {
-  test('pub get barks at unknown sdk', () async {
-    await d.dir(appPath, [
-      d.pubspec({
-        'environment': {'foo': '>=1.2.4 <2.0.0'}
-      })
-    ]).create();
-
-    await pubGet(
-      error: contains(
-          "Error on line 1, column 40 of pubspec.yaml: pubspec.yaml refers to an unknown sdk 'foo'."),
-      exitCode: exit_codes.DATA,
-    );
-  });
-}
diff --git a/test/get/with_empty_environment_test.dart b/test/get/with_empty_environment_test.dart
index 30768c4..9a9f9e2 100644
--- a/test/get/with_empty_environment_test.dart
+++ b/test/get/with_empty_environment_test.dart
@@ -11,8 +11,7 @@
 
 void main() {
   test(r'runs even with an empty environment (eg. no $HOME)', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
     await d.appDir({'foo': 'any'}).create();
 
diff --git a/test/global/activate/activate_git_after_hosted_test.dart b/test/global/activate/activate_git_after_hosted_test.dart
index c553041..75925d3 100644
--- a/test/global/activate/activate_git_after_hosted_test.dart
+++ b/test/global/activate/activate_git_after_hosted_test.dart
@@ -11,10 +11,11 @@
   test('activating a Git package deactivates the hosted one', () async {
     ensureGit();
 
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")])
+      ]);
+    });
 
     await d.git('foo.git', [
       d.libPubspec('foo', '1.0.0'),
diff --git a/test/global/activate/activate_hosted_after_git_test.dart b/test/global/activate/activate_hosted_after_git_test.dart
index 1546280..ba267b6 100644
--- a/test/global/activate/activate_hosted_after_git_test.dart
+++ b/test/global/activate/activate_hosted_after_git_test.dart
@@ -2,7 +2,6 @@
 // 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:path/path.dart' as p;
 import 'package:test/test.dart';
 
 import '../../descriptor.dart' as d;
@@ -10,10 +9,11 @@
 
 void main() {
   test('activating a hosted package deactivates the Git one', () async {
-    final server = await servePackages();
-    server.serve('foo', '2.0.0', contents: [
-      d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '2.0.0', contents: [
+        d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")])
+      ]);
+    });
 
     await d.git('foo.git', [
       d.libPubspec('foo', '1.0.0'),
@@ -22,9 +22,8 @@
 
     await runPub(args: ['global', 'activate', '-sgit', '../foo.git']);
 
-    final locationUri = p.toUri(p.join(d.sandbox, 'foo.git'));
     await runPub(args: ['global', 'activate', 'foo'], output: '''
-        Package foo is currently active from Git repository "$locationUri".
+        Package foo is currently active from Git repository "../foo.git".
         Resolving dependencies...
         + foo 2.0.0
         Downloading foo 2.0.0...
diff --git a/test/global/activate/activate_hosted_after_path_test.dart b/test/global/activate/activate_hosted_after_path_test.dart
index 4cd753f..92985bd 100644
--- a/test/global/activate/activate_hosted_after_path_test.dart
+++ b/test/global/activate/activate_hosted_after_path_test.dart
@@ -11,10 +11,11 @@
 
 void main() {
   test('activating a hosted package deactivates the path one', () async {
-    final server = await servePackages();
-    server.serve('foo', '2.0.0', contents: [
-      d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '2.0.0', contents: [
+        d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")])
+      ]);
+    });
 
     await d.dir('foo', [
       d.libPubspec('foo', '1.0.0'),
diff --git a/test/global/activate/activate_hosted_twice_test.dart b/test/global/activate/activate_hosted_twice_test.dart
index a4d1337..1923641 100644
--- a/test/global/activate/activate_hosted_twice_test.dart
+++ b/test/global/activate/activate_hosted_twice_test.dart
@@ -9,8 +9,7 @@
 
 void main() {
   test('activating a hosted package twice will not precompile', () async {
-    final server = await servePackages();
-    server
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', deps: {
         'bar': 'any'
       }, contents: [
@@ -22,9 +21,17 @@
       ])
       ..serve('bar', '1.0.0', contents: [
         d.dir('lib', [d.file('bar.dart', 'final version = "1.0.0";')])
-      ]);
+      ]));
 
-    await runPub(args: ['global', 'activate', 'foo'], output: anything);
+    await runPub(args: ['global', 'activate', 'foo'], output: '''
+Resolving dependencies...
++ bar 1.0.0
++ foo 1.0.0
+Downloading foo 1.0.0...
+Downloading bar 1.0.0...
+Building package executables...
+Built foo:foo.
+Activated foo 1.0.0.''');
 
     await runPub(args: ['global', 'activate', 'foo'], output: '''
 Package foo is currently active at version 1.0.0.
@@ -39,9 +46,10 @@
 
     await runPub(args: ['global', 'activate', 'foo']);
 
-    server.serve('bar', '2.0.0', contents: [
-      d.dir('lib', [d.file('bar.dart', 'final version = "2.0.0";')])
-    ]);
+    globalPackageServer!
+        .add((builder) => builder.serve('bar', '2.0.0', contents: [
+              d.dir('lib', [d.file('bar.dart', 'final version = "2.0.0";')])
+            ]));
 
     await runPub(args: ['global', 'activate', 'foo'], output: '''
 Package foo is currently active at version 1.0.0.
diff --git a/test/global/activate/activate_path_after_hosted_test.dart b/test/global/activate/activate_path_after_hosted_test.dart
index 01d493d..f7cfa95 100644
--- a/test/global/activate/activate_path_after_hosted_test.dart
+++ b/test/global/activate/activate_path_after_hosted_test.dart
@@ -10,11 +10,12 @@
 import '../../test_pub.dart';
 
 void main() {
-  test('activating a path package deactivates the hosted one', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")])
-    ]);
+  test('activating a hosted package deactivates the path one', () async {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")])
+      ]);
+    });
 
     await d.dir('foo', [
       d.libPubspec('foo', '2.0.0'),
diff --git a/test/global/activate/cached_package_test.dart b/test/global/activate/cached_package_test.dart
index 98db402..2daeaad 100644
--- a/test/global/activate/cached_package_test.dart
+++ b/test/global/activate/cached_package_test.dart
@@ -9,10 +9,11 @@
 
 void main() {
   test('can activate an already cached package', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')])
+      ]);
+    });
 
     await runPub(args: ['cache', 'add', 'foo']);
 
diff --git a/test/global/activate/constraint_test.dart b/test/global/activate/constraint_test.dart
index 23386c0..0a18257 100644
--- a/test/global/activate/constraint_test.dart
+++ b/test/global/activate/constraint_test.dart
@@ -9,11 +9,12 @@
 
 void main() {
   test('chooses the highest version that matches the constraint', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '1.0.1')
-      ..serve('foo', '1.1.0')
-      ..serve('foo', '1.2.3');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '1.0.1');
+      builder.serve('foo', '1.1.0');
+      builder.serve('foo', '1.2.3');
+    });
 
     await runPub(args: ['global', 'activate', 'foo', '<1.1.0']);
 
diff --git a/test/global/activate/custom_hosted_url_test.dart b/test/global/activate/custom_hosted_url_test.dart
index 8b2f0fc..54ee463 100644
--- a/test/global/activate/custom_hosted_url_test.dart
+++ b/test/global/activate/custom_hosted_url_test.dart
@@ -9,21 +9,22 @@
 void main() {
   test('activating a package from a custom pub server', () async {
     // The default pub server (i.e. pub.dartlang.org).
-    final server = await servePackages();
-    server.serve('baz', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('baz', '1.0.0');
+    });
 
     // The custom pub server.
-    final customServer = await startPackageServer();
-    Map<String, dynamic> hostedDep(String name, String constraint) => {
-          'hosted': {
-            'url': customServer.url,
-            'name': name,
-          },
-          'version': constraint,
-        };
-
-    customServer.serve('foo', '1.0.0', deps: {'bar': hostedDep('bar', 'any')});
-    customServer.serve('bar', '1.0.0', deps: {'baz': 'any'});
+    final customServer = await PackageServer.start((builder) {
+      Map<String, dynamic> hostedDep(String name, String constraint) => {
+            'hosted': {
+              'url': builder.serverUrl,
+              'name': name,
+            },
+            'version': constraint,
+          };
+      builder.serve('foo', '1.0.0', deps: {'bar': hostedDep('bar', 'any')});
+      builder.serve('bar', '1.0.0', deps: {'baz': 'any'});
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo', '-u', customServer.url],
diff --git a/test/global/activate/different_version_test.dart b/test/global/activate/different_version_test.dart
index 8406b92..dd6cca2 100644
--- a/test/global/activate/different_version_test.dart
+++ b/test/global/activate/different_version_test.dart
@@ -11,13 +11,14 @@
   test(
       "discards the previous active version if it doesn't match the "
       'constraint', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', contents: [
-        d.dir('bin', [d.file('foo.dart', 'main() => print("hi");')])
-      ])
-      ..serve('foo', '2.0.0', contents: [
-        d.dir('bin', [d.file('foo.dart', 'main() => print("hi2");')])
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')])
       ]);
+      builder.serve('foo', '2.0.0', contents: [
+        d.dir('bin', [d.file('foo.dart', 'main() => print("hi2"); ')])
+      ]);
+    });
 
     // Activate 1.0.0.
     await runPub(args: ['global', 'activate', 'foo', '1.0.0']);
diff --git a/test/global/activate/empty_constraint_test.dart b/test/global/activate/empty_constraint_test.dart
index d893bcd..fe0bd27 100644
--- a/test/global/activate/empty_constraint_test.dart
+++ b/test/global/activate/empty_constraint_test.dart
@@ -9,9 +9,10 @@
 
 void main() {
   test('errors if the constraint matches no versions', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '1.0.1');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '1.0.1');
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo', '>1.1.0'],
diff --git a/test/global/activate/feature_test.dart b/test/global/activate/feature_test.dart
index 58119d1..6095aa1 100644
--- a/test/global/activate/feature_test.dart
+++ b/test/global/activate/feature_test.dart
@@ -10,8 +10,8 @@
 
 void main() {
   test('enables default-on features by default', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'dependencies': {'bar': '1.0.0'}
@@ -21,9 +21,11 @@
             'dependencies': {'baz': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0')
-      ..serve('baz', '1.0.0');
+      });
+
+      builder.serve('bar', '1.0.0');
+      builder.serve('baz', '1.0.0');
+    });
 
     await runPub(args: ['global', 'activate', 'foo'], output: contains('''
 Resolving dependencies...
@@ -33,8 +35,8 @@
   });
 
   test('can enable default-off features', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'dependencies': {'bar': '1.0.0'}
@@ -44,9 +46,11 @@
             'dependencies': {'baz': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0')
-      ..serve('baz', '1.0.0');
+      });
+
+      builder.serve('bar', '1.0.0');
+      builder.serve('baz', '1.0.0');
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo', '--features', 'things'],
@@ -59,8 +63,8 @@
   });
 
   test('can disable default-on features', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'dependencies': {'bar': '1.0.0'}
@@ -70,9 +74,11 @@
             'dependencies': {'baz': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0')
-      ..serve('baz', '1.0.0');
+      });
+
+      builder.serve('bar', '1.0.0');
+      builder.serve('baz', '1.0.0');
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo', '--omit-features', 'stuff'],
@@ -83,8 +89,8 @@
   });
 
   test('supports multiple arguments', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
@@ -95,9 +101,11 @@
             'dependencies': {'baz': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0')
-      ..serve('baz', '1.0.0');
+      });
+
+      builder.serve('bar', '1.0.0');
+      builder.serve('baz', '1.0.0');
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo', '--features', 'things,stuff'],
@@ -110,8 +118,8 @@
   });
 
   test('can both enable and disable', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'dependencies': {'bar': '1.0.0'}
@@ -121,9 +129,11 @@
             'dependencies': {'baz': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0')
-      ..serve('baz', '1.0.0');
+      });
+
+      builder.serve('bar', '1.0.0');
+      builder.serve('baz', '1.0.0');
+    });
 
     await runPub(args: [
       'global',
diff --git a/test/global/activate/ignores_active_version_test.dart b/test/global/activate/ignores_active_version_test.dart
index 777a631..949456f 100644
--- a/test/global/activate/ignores_active_version_test.dart
+++ b/test/global/activate/ignores_active_version_test.dart
@@ -9,14 +9,15 @@
 
 void main() {
   test('ignores previously activated version', () async {
-    await servePackages()
-      ..serve(
+    await servePackages((builder) {
+      builder.serve(
         'foo',
         '1.2.3',
-      )
-      ..serve('foo', '1.3.0', contents: [
+      );
+      builder.serve('foo', '1.3.0', contents: [
         d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')])
       ]);
+    });
 
     // Activate 1.2.3.
     await runPub(args: ['global', 'activate', 'foo', '1.2.3']);
diff --git a/test/global/activate/installs_dependencies_for_git_test.dart b/test/global/activate/installs_dependencies_for_git_test.dart
index 6018f50..e67fad4 100644
--- a/test/global/activate/installs_dependencies_for_git_test.dart
+++ b/test/global/activate/installs_dependencies_for_git_test.dart
@@ -9,9 +9,10 @@
 
 void main() {
   test('activating a Git package installs its dependencies', () async {
-    await servePackages()
-      ..serve('bar', '1.0.0', deps: {'baz': 'any'})
-      ..serve('baz', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('bar', '1.0.0', deps: {'baz': 'any'});
+      builder.serve('baz', '1.0.0');
+    });
 
     await d.git('foo.git', [
       d.libPubspec('foo', '1.0.0', deps: {'bar': 'any'}),
diff --git a/test/global/activate/installs_dependencies_for_path_test.dart b/test/global/activate/installs_dependencies_for_path_test.dart
index 4688f07..52f3e65 100644
--- a/test/global/activate/installs_dependencies_for_path_test.dart
+++ b/test/global/activate/installs_dependencies_for_path_test.dart
@@ -9,9 +9,10 @@
 
 void main() {
   test('activating a path package installs dependencies', () async {
-    await servePackages()
-      ..serve('bar', '1.0.0', deps: {'baz': 'any'})
-      ..serve('baz', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('bar', '1.0.0', deps: {'baz': 'any'});
+      builder.serve('baz', '2.0.0');
+    });
 
     await d.dir('foo', [
       d.libPubspec('foo', '0.0.0', deps: {'bar': 'any'}),
diff --git a/test/global/activate/installs_dependencies_test.dart b/test/global/activate/installs_dependencies_test.dart
index 770ebcf..7114170 100644
--- a/test/global/activate/installs_dependencies_test.dart
+++ b/test/global/activate/installs_dependencies_test.dart
@@ -8,10 +8,11 @@
 
 void main() {
   test('activating a package installs its dependencies', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': 'any'})
-      ..serve('bar', '1.0.0', deps: {'baz': 'any'})
-      ..serve('baz', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': 'any'});
+      builder.serve('bar', '1.0.0', deps: {'baz': 'any'});
+      builder.serve('baz', '1.0.0');
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo'],
diff --git a/test/global/activate/outdated_binstub_test.dart b/test/global/activate/outdated_binstub_test.dart
index 6d9e298..5a5a0e6 100644
--- a/test/global/activate/outdated_binstub_test.dart
+++ b/test/global/activate/outdated_binstub_test.dart
@@ -7,7 +7,7 @@
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
-const _outdatedBinstub = '''
+const _OUTDATED_BINSTUB = '''
 #!/usr/bin/env sh
 # This file was created by pub v0.1.2-3.
 # Package: foo
@@ -19,17 +19,19 @@
 
 void main() {
   test('an outdated binstub is replaced', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {'foo-script': 'script'}
-    }, contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {'foo-script': 'script'}
+      }, contents: [
+        d.dir(
+            'bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
     await d.dir(cachePath, [
-      d.dir('bin', [d.file(binStubName('foo-script'), _outdatedBinstub)])
+      d.dir('bin', [d.file(binStubName('foo-script'), _OUTDATED_BINSTUB)])
     ]).create();
 
     await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/activate/path_package_test.dart b/test/global/activate/path_package_test.dart
index 514176a..6a08e9c 100644
--- a/test/global/activate/path_package_test.dart
+++ b/test/global/activate/path_package_test.dart
@@ -55,13 +55,14 @@
   });
 
   test("Doesn't precompile binaries when activating from path", () async {
-    final server = await servePackages();
-    server.serve(
-      'bar',
-      '1.0.0',
-      contents: [
-        d.dir('bin', [d.file('bar.dart', "main() => print('bar');")])
-      ],
+    await servePackages(
+      (builder) => builder.serve(
+        'bar',
+        '1.0.0',
+        contents: [
+          d.dir('bin', [d.file('bar.dart', "main() => print('bar');")])
+        ],
+      ),
     );
 
     await d.dir('foo', [
diff --git a/test/global/activate/reactivating_git_upgrades_test.dart b/test/global/activate/reactivating_git_upgrades_test.dart
index 68102da..100aaea 100644
--- a/test/global/activate/reactivating_git_upgrades_test.dart
+++ b/test/global/activate/reactivating_git_upgrades_test.dart
@@ -2,7 +2,6 @@
 // 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:path/path.dart' as p;
 import 'package:test/test.dart';
 
 import '../../descriptor.dart' as d;
@@ -30,12 +29,11 @@
     await d.git('foo.git', [d.libPubspec('foo', '1.0.1')]).commit();
 
     // Activating it again pulls down the latest commit.
-    final locationUri = p.toUri(p.join(d.sandbox, 'foo.git'));
     await runPub(
         args: ['global', 'activate', '-sgit', '../foo.git'],
         output: allOf(
             startsWith('Package foo is currently active from Git repository '
-                '"$locationUri".\n'
+                '"../foo.git".\n'
                 'Resolving dependencies...\n'
                 '+ foo 1.0.1 from git ../foo.git at '),
             // Specific revision number goes here.
diff --git a/test/global/activate/removes_old_lockfile_test.dart b/test/global/activate/removes_old_lockfile_test.dart
new file mode 100644
index 0000000..a91a153
--- /dev/null
+++ b/test/global/activate/removes_old_lockfile_test.dart
@@ -0,0 +1,34 @@
+// 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';
+
+void main() {
+  test('removes the 1.6-style lockfile', () async {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+    });
+
+    await d.dir(cachePath, [
+      d.dir('global_packages', [
+        d.file(
+            'foo.lock',
+            'packages: {foo: {description: foo, source: hosted, '
+                'version: "1.0.0"}}}')
+      ])
+    ]).create();
+
+    await runPub(args: ['global', 'activate', 'foo']);
+
+    await d.dir(cachePath, [
+      d.dir('global_packages', [
+        d.nothing('foo.lock'),
+        d.dir('foo', [d.file('pubspec.lock', contains('1.0.0'))])
+      ])
+    ]).validate();
+  });
+}
diff --git a/test/global/activate/snapshots_hosted_executables_test.dart b/test/global/activate/snapshots_hosted_executables_test.dart
index bc2b332..c400ec7 100644
--- a/test/global/activate/snapshots_hosted_executables_test.dart
+++ b/test/global/activate/snapshots_hosted_executables_test.dart
@@ -9,15 +9,16 @@
 
 void main() {
   test('snapshots the executables for a hosted package', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [
-        d.file('hello.dart', "void main() => print('hello!');"),
-        d.file('goodbye.dart', "void main() => print('goodbye!');"),
-        d.file('shell.sh', 'echo shell'),
-        d.dir('subdir', [d.file('sub.dart', "void main() => print('sub!');")])
-      ])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [
+          d.file('hello.dart', "void main() => print('hello!');"),
+          d.file('goodbye.dart', "void main() => print('goodbye!');"),
+          d.file('shell.sh', 'echo shell'),
+          d.dir('subdir', [d.file('sub.dart', "void main() => print('sub!');")])
+        ])
+      ]);
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo'],
diff --git a/test/global/activate/supports_version_solver_backtracking_test.dart b/test/global/activate/supports_version_solver_backtracking_test.dart
index c8c138d..7731bc6 100644
--- a/test/global/activate/supports_version_solver_backtracking_test.dart
+++ b/test/global/activate/supports_version_solver_backtracking_test.dart
@@ -9,13 +9,14 @@
 
 void main() {
   test('performs verison solver backtracking if necessary', () async {
-    await servePackages()
-      ..serve('foo', '1.1.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.1.0', pubspec: {
         'environment': {'sdk': '>=0.1.2 <0.2.0'}
-      })
-      ..serve('foo', '1.2.0', pubspec: {
+      });
+      builder.serve('foo', '1.2.0', pubspec: {
         'environment': {'sdk': '>=0.1.3 <0.2.0'}
       });
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/activate/uncached_package_test.dart b/test/global/activate/uncached_package_test.dart
index 1a18d70..98b12af 100644
--- a/test/global/activate/uncached_package_test.dart
+++ b/test/global/activate/uncached_package_test.dart
@@ -9,16 +9,17 @@
 
 void main() {
   test('installs and activates the best version of a package', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', contents: [
-        d.dir('bin', [d.file('foo.dart', 'main() => print("hi");')])
-      ])
-      ..serve('foo', '1.2.3', contents: [
-        d.dir('bin', [d.file('foo.dart', 'main() => print("hi 1.2.3");')])
-      ])
-      ..serve('foo', '2.0.0-wildly.unstable', contents: [
-        d.dir('bin', [d.file('foo.dart', 'main() => print("hi unstable");')])
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')])
       ]);
+      builder.serve('foo', '1.2.3', contents: [
+        d.dir('bin', [d.file('foo.dart', 'main() => print("hi 1.2.3"); ')])
+      ]);
+      builder.serve('foo', '2.0.0-wildly.unstable', contents: [
+        d.dir('bin', [d.file('foo.dart', 'main() => print("hi unstable"); ')])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo'], output: '''
         Resolving dependencies...
diff --git a/test/global/activate/unknown_package_test.dart b/test/global/activate/unknown_package_test.dart
index 271545d..93a5d3a 100644
--- a/test/global/activate/unknown_package_test.dart
+++ b/test/global/activate/unknown_package_test.dart
@@ -9,7 +9,7 @@
 
 void main() {
   test('errors if the package could not be found', () async {
-    await servePackages();
+    await serveNoPackages();
 
     await runPub(
         args: ['global', 'activate', 'foo'],
diff --git a/test/global/binstubs/binstub_runs_executable_test.dart b/test/global/binstubs/binstub_runs_executable_test.dart
index 98ab53b..c733f47 100644
--- a/test/global/binstubs/binstub_runs_executable_test.dart
+++ b/test/global/binstubs/binstub_runs_executable_test.dart
@@ -12,12 +12,14 @@
 
 void main() {
   test('the generated binstub runs a snapshotted executable', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {'foo-script': 'script'}
-    }, contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {'foo-script': 'script'}
+      }, contents: [
+        d.dir(
+            'bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/binstubs/binstub_runs_precompiled_snapshot_test.dart b/test/global/binstubs/binstub_runs_precompiled_snapshot_test.dart
index cd477db..f66a251 100644
--- a/test/global/binstubs/binstub_runs_precompiled_snapshot_test.dart
+++ b/test/global/binstubs/binstub_runs_precompiled_snapshot_test.dart
@@ -9,12 +9,13 @@
 
 void main() {
   test('the binstubs runs a built snapshot if present', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {'foo-script': 'script'}
-    }, contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {'foo-script': 'script'}
+      }, contents: [
+        d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/binstubs/creates_executables_in_pubspec_test.dart b/test/global/binstubs/creates_executables_in_pubspec_test.dart
index a6604ab..8fe53dc 100644
--- a/test/global/binstubs/creates_executables_in_pubspec_test.dart
+++ b/test/global/binstubs/creates_executables_in_pubspec_test.dart
@@ -9,16 +9,17 @@
 
 void main() {
   test('creates binstubs for each executable in the pubspec', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {'one': null, 'two-renamed': 'second'}
-    }, contents: [
-      d.dir('bin', [
-        d.file('one.dart', "main(args) => print('one');"),
-        d.file('second.dart', "main(args) => print('two');"),
-        d.file('nope.dart', "main(args) => print('nope');")
-      ])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {'one': null, 'two-renamed': 'second'}
+      }, contents: [
+        d.dir('bin', [
+          d.file('one.dart', "main(args) => print('one');"),
+          d.file('second.dart', "main(args) => print('two');"),
+          d.file('nope.dart', "main(args) => print('nope');")
+        ])
+      ]);
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo'],
diff --git a/test/global/binstubs/does_not_warn_if_no_executables_test.dart b/test/global/binstubs/does_not_warn_if_no_executables_test.dart
index 9814f15..b7ca722 100644
--- a/test/global/binstubs/does_not_warn_if_no_executables_test.dart
+++ b/test/global/binstubs/does_not_warn_if_no_executables_test.dart
@@ -9,10 +9,12 @@
 
 void main() {
   test('does not warn if the package has no executables', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir(
+            'bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
+      ]);
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo'],
diff --git a/test/global/binstubs/does_not_warn_if_on_path_test.dart b/test/global/binstubs/does_not_warn_if_on_path_test.dart
index 9b11386..fd0dfa7 100644
--- a/test/global/binstubs/does_not_warn_if_on_path_test.dart
+++ b/test/global/binstubs/does_not_warn_if_on_path_test.dart
@@ -12,12 +12,14 @@
 
 void main() {
   test('does not warn if the binstub directory is on the path', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {'script': null}
-    }, contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {'script': null}
+      }, contents: [
+        d.dir(
+            'bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
+      ]);
+    });
 
     // Add the test's cache bin directory to the path.
     var binDir = p.dirname(Platform.executable);
diff --git a/test/global/binstubs/outdated_binstub_runs_pub_global_test.dart b/test/global/binstubs/outdated_binstub_runs_pub_global_test.dart
index 442dfbc..e86757c 100644
--- a/test/global/binstubs/outdated_binstub_runs_pub_global_test.dart
+++ b/test/global/binstubs/outdated_binstub_runs_pub_global_test.dart
@@ -24,22 +24,23 @@
 void main() {
   test("an outdated binstub runs 'pub global run', which replaces old binstub",
       () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {
-        'foo-script': 'script',
-        'foo-script2': 'script',
-        'foo-script-not-installed': 'script',
-        'foo-another-script': 'another-script',
-        'foo-another-script-not-installed': 'another-script'
-      }
-    }, contents: [
-      d.dir('bin', [
-        d.file('script.dart', r"main(args) => print('ok $args');"),
-        d.file(
-            'another-script.dart', r"main(args) => print('not so good $args');")
-      ])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {
+          'foo-script': 'script',
+          'foo-script2': 'script',
+          'foo-script-not-installed': 'script',
+          'foo-another-script': 'another-script',
+          'foo-another-script-not-installed': 'another-script'
+        }
+      }, contents: [
+        d.dir('bin', [
+          d.file('script.dart', r"main(args) => print('ok $args');"),
+          d.file('another-script.dart',
+              r"main(args) => print('not so good $args');")
+        ])
+      ]);
+    });
 
     await runPub(args: [
       'global',
diff --git a/test/global/binstubs/outdated_snapshot_test.dart b/test/global/binstubs/outdated_snapshot_test.dart
index 91bfff6..e749a5c 100644
--- a/test/global/binstubs/outdated_snapshot_test.dart
+++ b/test/global/binstubs/outdated_snapshot_test.dart
@@ -13,12 +13,14 @@
 
 void main() {
   test("a binstub runs 'pub global run' for an outdated snapshot", () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {'foo-script': 'script'}
-    }, contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {'foo-script': 'script'}
+      }, contents: [
+        d.dir(
+            'bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/binstubs/removes_when_deactivated_test.dart b/test/global/binstubs/removes_when_deactivated_test.dart
index 975defe..05c8413 100644
--- a/test/global/binstubs/removes_when_deactivated_test.dart
+++ b/test/global/binstubs/removes_when_deactivated_test.dart
@@ -9,15 +9,16 @@
 
 void main() {
   test('removes binstubs when the package is deactivated', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {'one': null, 'two': null}
-    }, contents: [
-      d.dir('bin', [
-        d.file('one.dart', "main(args) => print('one');"),
-        d.file('two.dart', "main(args) => print('two');")
-      ])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {'one': null, 'two': null}
+      }, contents: [
+        d.dir('bin', [
+          d.file('one.dart', "main(args) => print('one');"),
+          d.file('two.dart', "main(args) => print('two');")
+        ])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
     await runPub(args: ['global', 'deactivate', 'foo']);
diff --git a/test/global/binstubs/runs_once_even_when_dart_is_batch_test.dart b/test/global/binstubs/runs_once_even_when_dart_is_batch_test.dart
index 99eeaaf..54f3932 100644
--- a/test/global/binstubs/runs_once_even_when_dart_is_batch_test.dart
+++ b/test/global/binstubs/runs_once_even_when_dart_is_batch_test.dart
@@ -14,17 +14,18 @@
   test(
       'runs only once even when dart on path is a batch file (as in flutter/bin)',
       () async {
-    final server = await servePackages();
-    server.serve(
-      'foo',
-      '1.0.0',
-      contents: [
-        d.dir('bin', [d.file('script.dart', 'main(args) => print(args);')]),
-      ],
-      pubspec: {
-        'executables': {'script': 'script'},
-      },
-    );
+    await servePackages((builder) {
+      builder.serve(
+        'foo',
+        '1.0.0',
+        contents: [
+          d.dir('bin', [d.file('script.dart', 'main(args) => print(args);')]),
+        ],
+        pubspec: {
+          'executables': {'script': 'script'},
+        },
+      );
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/binstubs/warns_if_not_on_path_test.dart b/test/global/binstubs/warns_if_not_on_path_test.dart
index d98bf76..d09e698 100644
--- a/test/global/binstubs/warns_if_not_on_path_test.dart
+++ b/test/global/binstubs/warns_if_not_on_path_test.dart
@@ -9,12 +9,14 @@
 
 void main() {
   test('warns if the binstub directory is not on the path', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'executables': {'some-dart-script': 'script'}
-    }, contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'executables': {'some-dart-script': 'script'}
+      }, contents: [
+        d.dir(
+            'bin', [d.file('script.dart', "main(args) => print('ok \$args');")])
+      ]);
+    });
 
     await runPub(
         args: ['global', 'activate', 'foo'],
diff --git a/test/global/deactivate/deactivate_and_reactivate_package_test.dart b/test/global/deactivate/deactivate_and_reactivate_package_test.dart
index da33486..cc7f597 100644
--- a/test/global/deactivate/deactivate_and_reactivate_package_test.dart
+++ b/test/global/deactivate/deactivate_and_reactivate_package_test.dart
@@ -8,9 +8,10 @@
 
 void main() {
   test('activates a different version after deactivating', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0');
+    });
 
     // Activate an old version.
     await runPub(args: ['global', 'activate', 'foo', '1.0.0']);
diff --git a/test/global/deactivate/git_package_test.dart b/test/global/deactivate/git_package_test.dart
index 7fc2855..f06ce53 100644
--- a/test/global/deactivate/git_package_test.dart
+++ b/test/global/deactivate/git_package_test.dart
@@ -2,7 +2,6 @@
 // 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:path/path.dart' as p;
 import 'package:test/test.dart';
 
 import '../../descriptor.dart' as d;
@@ -19,10 +18,9 @@
 
     await runPub(args: ['global', 'activate', '-sgit', '../foo.git']);
 
-    final locationUri = p.toUri(p.join(d.sandbox, 'foo.git'));
     await runPub(
         args: ['global', 'deactivate', 'foo'],
         output:
-            'Deactivated package foo 1.0.0 from Git repository "$locationUri".');
+            'Deactivated package foo 1.0.0 from Git repository "../foo.git".');
   });
 }
diff --git a/test/global/deactivate/hosted_package_test.dart b/test/global/deactivate/hosted_package_test.dart
index fa91829..854d6a9 100644
--- a/test/global/deactivate/hosted_package_test.dart
+++ b/test/global/deactivate/hosted_package_test.dart
@@ -8,8 +8,7 @@
 
 void main() {
   test('deactivates an active hosted package', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((builder) => builder.serve('foo', '1.0.0'));
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/deactivate/removes_precompiled_snapshots_test.dart b/test/global/deactivate/removes_precompiled_snapshots_test.dart
index a7670e2..7ea6d58 100644
--- a/test/global/deactivate/removes_precompiled_snapshots_test.dart
+++ b/test/global/deactivate/removes_precompiled_snapshots_test.dart
@@ -9,8 +9,7 @@
 
 void main() {
   test('removes built snapshots', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((builder) => builder.serve('foo', '1.0.0'));
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/deactivate/unknown_package_test.dart b/test/global/deactivate/unknown_package_test.dart
index 35023ad..d67460d 100644
--- a/test/global/deactivate/unknown_package_test.dart
+++ b/test/global/deactivate/unknown_package_test.dart
@@ -9,7 +9,7 @@
 
 void main() {
   test('errors if the package is not activated', () async {
-    await servePackages();
+    await serveNoPackages();
 
     await runPub(
         args: ['global', 'deactivate', 'foo'],
diff --git a/test/global/list_test.dart b/test/global/list_test.dart
index 00ca22c..4b50184 100644
--- a/test/global/list_test.dart
+++ b/test/global/list_test.dart
@@ -12,8 +12,9 @@
 
 void main() {
   test('lists an activated hosted package', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
@@ -30,10 +31,9 @@
 
     await runPub(args: ['global', 'activate', '-sgit', '../foo.git']);
 
-    final locationUri = p.toUri(p.join(d.sandbox, 'foo.git'));
     await runPub(
         args: ['global', 'list'],
-        output: 'foo 1.0.0 from Git repository "$locationUri"');
+        output: 'foo 1.0.0 from Git repository "../foo.git"');
   });
 
   test('lists an activated Path package', () async {
@@ -49,10 +49,11 @@
   });
 
   test('lists activated packages in alphabetical order', () async {
-    await servePackages()
-      ..serve('aaa', '1.0.0')
-      ..serve('bbb', '1.0.0')
-      ..serve('ccc', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('aaa', '1.0.0');
+      builder.serve('bbb', '1.0.0');
+      builder.serve('ccc', '1.0.0');
+    });
 
     await runPub(args: ['global', 'activate', 'ccc']);
     await runPub(args: ['global', 'activate', 'aaa']);
diff --git a/test/global/run/errors_if_outside_bin_test.dart b/test/global/run/errors_if_outside_bin_test.dart
index 72bcd4f..098f0bb 100644
--- a/test/global/run/errors_if_outside_bin_test.dart
+++ b/test/global/run/errors_if_outside_bin_test.dart
@@ -10,10 +10,11 @@
 
 void main() {
   test('errors if the script is in a subdirectory.', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('example', [d.file('script.dart', "main(args) => print('ok');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('example', [d.file('script.dart', "main(args) => print('ok');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
     await runPub(
diff --git a/test/global/run/fails_if_sdk_constraint_is_unmet_test.dart b/test/global/run/fails_if_sdk_constraint_is_unmet_test.dart
index 3bef340..08adbcc 100644
--- a/test/global/run/fails_if_sdk_constraint_is_unmet_test.dart
+++ b/test/global/run/fails_if_sdk_constraint_is_unmet_test.dart
@@ -10,10 +10,11 @@
 
 void main() {
   test("fails if the current SDK doesn't match the constraint", () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
@@ -40,14 +41,15 @@
   });
 
   test('fails if SDK is downgraded below the constraints', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'environment': {
-        'sdk': '>=2.0.0 <3.0.0',
-      },
-    }, contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('123-OK');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'environment': {
+          'sdk': '>=2.0.0 <3.0.0',
+        },
+      }, contents: [
+        d.dir('bin', [d.file('script.dart', "main(args) => print('123-OK');")])
+      ]);
+    });
 
     await runPub(
       environment: {'_PUB_TEST_SDK_VERSION': '2.0.0'},
@@ -67,8 +69,8 @@
   });
 
   test('fails if SDK is downgraded below dependency SDK constraints', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {
         'bar': '^1.0.0',
       }, pubspec: {
         'environment': {
@@ -76,12 +78,13 @@
         },
       }, contents: [
         d.dir('bin', [d.file('script.dart', "main(args) => print('123-OK');")])
-      ])
-      ..serve('bar', '1.0.0', pubspec: {
+      ]);
+      builder.serve('bar', '1.0.0', pubspec: {
         'environment': {
           'sdk': '>=2.2.0 <3.0.0',
         },
       });
+    });
 
     await runPub(
       environment: {'_PUB_TEST_SDK_VERSION': '2.2.0'},
diff --git a/test/global/run/implicit_executable_name_test.dart b/test/global/run/implicit_executable_name_test.dart
index 9757772..fa7bf51 100644
--- a/test/global/run/implicit_executable_name_test.dart
+++ b/test/global/run/implicit_executable_name_test.dart
@@ -9,10 +9,11 @@
 
 void main() {
   test('defaults to the package name if the script is omitted', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('foo.dart', "main(args) => print('foo');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('foo.dart', "main(args) => print('foo');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/run/nonexistent_script_test.dart b/test/global/run/nonexistent_script_test.dart
index 8ff0a42..d4f9577 100644
--- a/test/global/run/nonexistent_script_test.dart
+++ b/test/global/run/nonexistent_script_test.dart
@@ -10,10 +10,9 @@
 
 void main() {
   test('errors if the script does not exist.', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'dev_dependencies': {'bar': '1.0.0'}
-    });
+    await servePackages((builder) => builder.serve('foo', '1.0.0', pubspec: {
+          'dev_dependencies': {'bar': '1.0.0'}
+        }));
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/run/package_api_test.dart b/test/global/run/package_api_test.dart
index 5db401b..4ce34ee 100644
--- a/test/global/run/package_api_test.dart
+++ b/test/global/run/package_api_test.dart
@@ -10,9 +10,10 @@
 
 void main() {
   test('an immutable application sees a file: package config', () async {
-    await servePackages()
-      ..serve('bar', '1.0.0')
-      ..serve('foo', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('bar', '1.0.0');
+
+      builder.serve('foo', '1.0.0', deps: {
         'bar': '1.0.0'
       }, contents: [
         d.dir('bin', [
@@ -30,6 +31,7 @@
 """)
         ])
       ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
@@ -41,12 +43,12 @@
         'global_packages/foo/.dart_tool/package_config.json');
     expect(pub.stdout, emits(p.toUri(packageConfigPath).toString()));
 
-    var fooResourcePath =
-        p.join(globalServer.pathInCache('foo', '1.0.0'), 'lib/resource.txt');
+    var fooResourcePath = p.join(
+        globalPackageServer!.pathInCache('foo', '1.0.0'), 'lib/resource.txt');
     expect(pub.stdout, emits(p.toUri(fooResourcePath).toString()));
 
-    var barResourcePath =
-        p.join(globalServer.pathInCache('bar', '1.0.0'), 'lib/resource.txt');
+    var barResourcePath = p.join(
+        globalPackageServer!.pathInCache('bar', '1.0.0'), 'lib/resource.txt');
     expect(pub.stdout, emits(p.toUri(barResourcePath).toString()));
     await pub.shouldExit(0);
   });
diff --git a/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart b/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart
index 24e65bf..97c69f2 100644
--- a/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart
+++ b/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart
@@ -11,10 +11,11 @@
 
 void main() {
   test('recompiles a script if the snapshot is out-of-date', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/run/runs_script_in_checked_mode_test.dart b/test/global/run/runs_script_in_checked_mode_test.dart
index d0511cf..69cd393 100644
--- a/test/global/run/runs_script_in_checked_mode_test.dart
+++ b/test/global/run/runs_script_in_checked_mode_test.dart
@@ -9,10 +9,11 @@
 
 void main() {
   test('runs a script with assertions enabled', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', 'main() { assert(false); }')])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('script.dart', 'main() { assert(false); }')])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/run/runs_script_in_unchecked_mode_test.dart b/test/global/run/runs_script_in_unchecked_mode_test.dart
index ca752b2..d684c27 100644
--- a/test/global/run/runs_script_in_unchecked_mode_test.dart
+++ b/test/global/run/runs_script_in_unchecked_mode_test.dart
@@ -7,7 +7,7 @@
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
-const _script = '''
+const SCRIPT = '''
 main() {
   assert(false);
   print("no checks");
@@ -16,10 +16,11 @@
 
 void main() {
   test('runs a script in unchecked mode by default', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', _script)])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('script.dart', SCRIPT)])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/run/runs_script_test.dart b/test/global/run/runs_script_test.dart
index f3f0e99..fe767ef 100644
--- a/test/global/run/runs_script_test.dart
+++ b/test/global/run/runs_script_test.dart
@@ -9,10 +9,11 @@
 
 void main() {
   test('runs a script in an activated package', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
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 dc225ba..cb63be2 100644
--- a/test/global/run/runs_script_without_packages_file_test.dart
+++ b/test/global/run/runs_script_without_packages_file_test.dart
@@ -12,10 +12,11 @@
 void main() {
   test('runs a snapshotted script without a .dart_tool/package_config file',
       () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")])
+      ]);
+    });
 
     await runPub(args: ['global', 'activate', 'foo']);
 
diff --git a/test/global/run/unknown_package_test.dart b/test/global/run/unknown_package_test.dart
index adcb666..a5fba21 100644
--- a/test/global/run/unknown_package_test.dart
+++ b/test/global/run/unknown_package_test.dart
@@ -9,7 +9,7 @@
 
 void main() {
   test('errors if the package is not activated', () async {
-    await servePackages();
+    await serveNoPackages();
 
     await runPub(
         args: ['global', 'run', 'foo:bar'],
diff --git a/test/global/run/uses_old_lockfile_test.dart b/test/global/run/uses_old_lockfile_test.dart
new file mode 100644
index 0000000..5eb8406
--- /dev/null
+++ b/test/global/run/uses_old_lockfile_test.dart
@@ -0,0 +1,55 @@
+// 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';
+
+void main() {
+  test('uses the 1.6-style lockfile if necessary', () async {
+    await servePackages((builder) {
+      builder.serve('bar', '1.0.0');
+      builder.serve('foo', '1.0.0', deps: {
+        'bar': 'any'
+      }, contents: [
+        d.dir('bin', [
+          d.file('script.dart', """
+              import 'package:bar/bar.dart' as bar;
+
+              main(args) => print(bar.main());""")
+        ])
+      ]);
+    });
+
+    await runPub(args: ['cache', 'add', 'foo']);
+    await runPub(args: ['cache', 'add', 'bar']);
+
+    await d.dir(cachePath, [
+      d.dir('global_packages', [
+        d.file('foo.lock', '''
+packages:
+  foo:
+    description: foo
+    source: hosted
+    version: "1.0.0"
+  bar:
+    description: bar
+    source: hosted
+    version: "1.0.0"''')
+      ])
+    ]).create();
+
+    var pub = await pubRun(global: true, args: ['foo:script']);
+    expect(pub.stdout, emitsThrough('bar 1.0.0'));
+    await pub.shouldExit();
+
+    await d.dir(cachePath, [
+      d.dir('global_packages', [
+        d.nothing('foo.lock'),
+        d.dir('foo', [d.file('pubspec.lock', contains('1.0.0'))])
+      ])
+    ]).validate();
+  });
+}
diff --git a/test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart b/test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart
index 7fb22a3..be875a2 100644
--- a/test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart
+++ b/test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart
@@ -9,7 +9,6 @@
 import 'package:test/test.dart';
 
 import '../descriptor.dart' as d;
-import '../golden_file.dart';
 import '../test_pub.dart';
 
 void main() {
@@ -17,18 +16,15 @@
     test(
         'fails gracefully if the package server responds with broken package listings',
         () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
-      server.expect(
-        'GET',
-        RegExp('/api/packages/.*'),
-        expectAsync1((request) {
-          return Response(200,
-              body: jsonEncode({
-                'notTheRight': {'response': 'type'}
-              }));
-        }),
-      );
+      await servePackages((b) => b..serve('foo', '1.2.3'));
+      globalPackageServer!.extraHandlers[RegExp('/api/packages/.*')] =
+          expectAsync1((request) {
+        expect(request.method, 'GET');
+        return Response(200,
+            body: jsonEncode({
+              'notTheRight': {'response': 'type'}
+            }));
+      });
       await d.appDir({'foo': '1.2.3'}).create();
 
       await pubCommand(command,
@@ -40,80 +36,4 @@
           exitCode: exit_codes.DATA);
     });
   });
-
-  testWithGolden('bad_json', (ctx) async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
-    server.expect('GET', RegExp('/api/packages/.*'), (request) {
-      return Response(200,
-          body: jsonEncode({
-            'notTheRight': {'response': 'type'}
-          }));
-    });
-    await d.appDir({'foo': '1.2.3'}).create();
-
-    await ctx.run(['get']);
-  });
-
-  testWithGolden('403', (ctx) async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
-    server.expect('GET', RegExp('/api/packages/.*'), (request) {
-      return Response(403,
-          body: jsonEncode({
-            'notTheRight': {'response': 'type'}
-          }));
-    });
-    await d.appDir({'foo': '1.2.3'}).create();
-
-    await ctx.run(['get']);
-  });
-
-  testWithGolden('401', (ctx) async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
-    server.expect('GET', RegExp('/api/packages/.*'), (request) {
-      return Response(401,
-          body: jsonEncode({
-            'notTheRight': {'response': 'type'}
-          }));
-    });
-    await d.appDir({'foo': '1.2.3'}).create();
-
-    await ctx.run(['get']);
-  });
-
-  testWithGolden('403-with-message', (ctx) async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
-    server.expect('GET', RegExp('/api/packages/.*'), (request) {
-      return Response(403,
-          headers: {
-            'www-authenticate': 'Bearer realm="pub", message="<message>"',
-          },
-          body: jsonEncode({
-            'notTheRight': {'response': 'type'}
-          }));
-    });
-    await d.appDir({'foo': '1.2.3'}).create();
-
-    await ctx.run(['get']);
-  });
-
-  testWithGolden('401-with-message', (ctx) async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
-    server.expect('GET', RegExp('/api/packages/.*'), (request) {
-      return Response(401,
-          headers: {
-            'www-authenticate': 'Bearer realm="pub", message="<message>"',
-          },
-          body: jsonEncode({
-            'notTheRight': {'response': 'type'}
-          }));
-    });
-    await d.appDir({'foo': '1.2.3'}).create();
-
-    await ctx.run(['get']);
-  });
 }
diff --git a/test/hosted/fail_gracefully_on_missing_package_test.dart b/test/hosted/fail_gracefully_on_missing_package_test.dart
index 7c6290d..1840f18 100644
--- a/test/hosted/fail_gracefully_on_missing_package_test.dart
+++ b/test/hosted/fail_gracefully_on_missing_package_test.dart
@@ -11,7 +11,7 @@
 void main() {
   forBothPubGetAndUpgrade((command) {
     test('fails gracefully if the package does not exist', () async {
-      await servePackages();
+      await serveNoPackages();
 
       await d.appDir({'foo': '1.2.3'}).create();
 
diff --git a/test/hosted/fail_gracefully_with_hint_test.dart b/test/hosted/fail_gracefully_with_hint_test.dart
deleted file mode 100644
index 4f1a326..0000000
--- a/test/hosted/fail_gracefully_with_hint_test.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2012, 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:pub/src/exit_codes.dart' as exit_codes;
-import 'package:test/test.dart';
-
-import '../descriptor.dart' as d;
-import '../golden_file.dart';
-import '../test_pub.dart';
-
-void main() {
-  testWithGolden('hint: try without --offline', (ctx) async {
-    // Run the server so that we know what URL to use in the system cache.
-    (await servePackages()).serveErrors();
-
-    await d.appDir({'foo': 'any'}).create();
-
-    await pubGet(
-      args: ['--offline'],
-      exitCode: exit_codes.UNAVAILABLE,
-      error: contains('Try again without --offline!'),
-    );
-  });
-
-  testWithGolden('supports two hints', (ctx) async {
-    // Run the server so that we know what URL to use in the system cache.
-    (await servePackages()).serveErrors();
-
-    await d.hostedCache([
-      d.dir('foo-1.2.3', [
-        d.pubspec({
-          'name': 'foo',
-          'version': '1.2.3',
-          'environment': {
-            'flutter': 'any', // generates hint -> flutter pub get
-          },
-        }),
-      ]),
-      d.dir('foo-1.2.4', [
-        d.pubspec({
-          'name': 'foo',
-          'version': '1.2.4',
-          'dependencies': {
-            'bar': 'any', // generates hint -> try without --offline
-          },
-        }),
-      ]),
-    ]).create();
-
-    await d.appDir({'foo': 'any'}).create();
-
-    await pubGet(
-      args: ['--offline'],
-      exitCode: exit_codes.UNAVAILABLE,
-      error: allOf(
-        contains('Try again without --offline!'),
-        contains('flutter pub get'), // hint that
-      ),
-    );
-
-    await ctx.run(['get', '--offline']);
-  });
-}
diff --git a/test/hosted/metadata_test.dart b/test/hosted/metadata_test.dart
index c705ac7..7554a0f 100644
--- a/test/hosted/metadata_test.dart
+++ b/test/hosted/metadata_test.dart
@@ -12,8 +12,9 @@
 void main() {
   forBothPubGetAndUpgrade((command) {
     test('sends metadata headers for a direct dependency', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.appDir({'foo': '1.0.0'}).create();
 
@@ -32,8 +33,9 @@
     });
 
     test('sends metadata headers for a dev dependency', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -57,8 +59,9 @@
     });
 
     test('sends metadata headers for a transitive dependency', () async {
-      final server = await servePackages();
-      server.serve('bar', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('bar', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {'path': '../foo'}
@@ -79,8 +82,9 @@
     });
 
     test("doesn't send metadata headers to a foreign server", () async {
-      var server = await startPackageServer()
-        ..serve('foo', '1.0.0');
+      var server = await PackageServer.start((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {
@@ -93,7 +97,9 @@
     });
 
     test("doesn't send metadata headers when CI=true", () async {
-      (await servePackages()).serve('foo', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.appDir({'foo': '1.0.0'}).create();
 
diff --git a/test/hosted/offline_test.dart b/test/hosted/offline_test.dart
index ca3dc80..713ea3f 100644
--- a/test/hosted/offline_test.dart
+++ b/test/hosted/offline_test.dart
@@ -8,13 +8,14 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-Future<void> populateCache(
-    Map<String, List<String>> versions, PackageServer server) async {
-  for (final entry in versions.entries) {
-    for (final version in entry.value) {
-      server.serve(entry.key, version);
+Future<void> populateCache(Map<String, List<String>> versions) async {
+  await servePackages((b) {
+    for (final entry in versions.entries) {
+      for (final version in entry.value) {
+        b.serve(entry.key, version);
+      }
     }
-  }
+  });
   for (final entry in versions.entries) {
     for (final version in entry.value) {
       await d.appDir({entry.key: version}).create();
@@ -26,14 +27,13 @@
 void main() {
   forBothPubGetAndUpgrade((command) {
     test('upgrades a package using the cache', () async {
-      final server = await servePackages();
       await populateCache({
         'foo': ['1.2.2', '1.2.3'],
         'bar': ['1.2.3']
-      }, server);
+      });
 
       // Now serve only errors - to validate we are truly offline.
-      server.serveErrors();
+      await serveErrors();
 
       await d.appDir({'foo': 'any', 'bar': 'any'}).create();
 
@@ -44,19 +44,16 @@
       }
 
       await pubCommand(command, args: ['--offline'], warning: warning);
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-        d.packageConfigEntry(name: 'bar', version: '1.2.3'),
-      ]).validate();
+
+      await d.appPackagesFile({'foo': '1.2.3', 'bar': '1.2.3'}).validate();
     });
 
     test('supports prerelease versions', () async {
-      final server = await servePackages();
       await populateCache({
         'foo': ['1.2.3-alpha.1']
-      }, server);
+      });
       // Now serve only errors - to validate we are truly offline.
-      server.serveErrors();
+      await serveErrors();
 
       await d.appDir({'foo': 'any'}).create();
 
@@ -68,15 +65,12 @@
 
       await pubCommand(command, args: ['--offline'], warning: warning);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.3-alpha.1'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.2.3-alpha.1'}).validate();
     });
 
     test('fails gracefully if a dependency is not cached', () async {
       // Run the server so that we know what URL to use in the system cache.
-      final server = await servePackages();
-      server.serveErrors();
+      await serveErrors();
 
       await d.appDir({'foo': 'any'}).create();
 
@@ -86,19 +80,16 @@
           error: equalsIgnoringWhitespace("""
             Because myapp depends on foo any which doesn't exist (could not find
               package foo in cache), version solving failed.
-
-            Try again without --offline!
           """));
     });
 
     test('fails gracefully if no cached versions match', () async {
-      final server = await servePackages();
       await populateCache({
         'foo': ['1.2.2', '1.2.3']
-      }, server);
+      });
 
       // Run the server so that we know what URL to use in the system cache.
-      server.serveErrors();
+      await serveErrors();
 
       await d.appDir({'foo': '>2.0.0'}).create();
 
@@ -112,10 +103,8 @@
     test(
         'fails gracefully if a dependency is not cached and a lockfile '
         'exists', () async {
-      final server = await servePackages();
-
       // Run the server so that we know what URL to use in the system cache.
-      server.serveErrors();
+      await serveErrors();
 
       await d.appDir({'foo': 'any'}).create();
 
@@ -127,19 +116,15 @@
           error: equalsIgnoringWhitespace("""
             Because myapp depends on foo any which doesn't exist (could not find
               package foo in cache), version solving failed.
-
-            Try again without --offline!
           """));
     });
 
     test('downgrades to the version in the cache if necessary', () async {
-      final server = await servePackages();
-
       await populateCache({
         'foo': ['1.2.2', '1.2.3']
-      }, server);
+      });
       // Run the server so that we know what URL to use in the system cache.
-      server.serveErrors();
+      await serveErrors();
 
       await d.appDir({'foo': 'any'}).create();
 
@@ -147,19 +132,15 @@
 
       await pubCommand(command, args: ['--offline']);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.3'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.2.3'}).validate();
     });
 
     test('skips invalid cached versions', () async {
-      final server = await servePackages();
-
       await populateCache({
         'foo': ['1.2.2', '1.2.3']
-      }, server);
+      });
       // Run the server so that we know what URL to use in the system cache.
-      server.serveErrors();
+      await serveErrors();
 
       await d.hostedCache([
         d.dir('foo-1.2.3', [d.file('pubspec.yaml', '{')]),
@@ -170,19 +151,15 @@
 
       await pubCommand(command, args: ['--offline']);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.2'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.2.2'}).validate();
     });
 
     test('skips invalid locked versions', () async {
-      final server = await servePackages();
-
       await populateCache({
         'foo': ['1.2.2', '1.2.3']
-      }, server);
+      });
       // Run the server so that we know what URL to use in the system cache.
-      server.serveErrors();
+      await serveErrors();
 
       await d.hostedCache([
         d.dir('foo-1.2.3', [d.file('pubspec.yaml', '{')])
@@ -194,9 +171,7 @@
 
       await pubCommand(command, args: ['--offline']);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.2.2'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.2.2'}).validate();
     });
   });
 }
diff --git a/test/hosted/remove_removed_dependency_test.dart b/test/hosted/remove_removed_dependency_test.dart
index a0446c0..d326384 100644
--- a/test/hosted/remove_removed_dependency_test.dart
+++ b/test/hosted/remove_removed_dependency_test.dart
@@ -10,25 +10,22 @@
 void main() {
   forBothPubGetAndUpgrade((command) {
     test("removes a dependency that's removed from the pubspec", () async {
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('bar', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('bar', '1.0.0');
+      });
 
       await d.appDir({'foo': 'any', 'bar': 'any'}).create();
 
       await pubCommand(command);
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-        d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-      ]).validate();
+
+      await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate();
 
       await d.appDir({'foo': 'any'}).create();
 
       await pubCommand(command);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.0.0'}).validate();
     });
   });
 }
diff --git a/test/hosted/remove_removed_transitive_dependency_test.dart b/test/hosted/remove_removed_transitive_dependency_test.dart
index 182ec3f..50702d7 100644
--- a/test/hosted/remove_removed_transitive_dependency_test.dart
+++ b/test/hosted/remove_removed_transitive_dependency_test.dart
@@ -12,30 +12,31 @@
     test(
         "removes a transitive dependency that's no longer depended "
         'on', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', deps: {'shared_dep': 'any'})
-        ..serve('bar', '1.0.0', deps: {'shared_dep': 'any', 'bar_dep': 'any'})
-        ..serve('shared_dep', '1.0.0')
-        ..serve('bar_dep', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', deps: {'shared_dep': 'any'});
+        builder.serve('bar', '1.0.0',
+            deps: {'shared_dep': 'any', 'bar_dep': 'any'});
+        builder.serve('shared_dep', '1.0.0');
+        builder.serve('bar_dep', '1.0.0');
+      });
 
       await d.appDir({'foo': 'any', 'bar': 'any'}).create();
 
       await pubCommand(command);
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-        d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-        d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'),
-        d.packageConfigEntry(name: 'bar_dep', version: '1.0.0'),
-      ]).validate();
+
+      await d.appPackagesFile({
+        'foo': '1.0.0',
+        'bar': '1.0.0',
+        'shared_dep': '1.0.0',
+        'bar_dep': '1.0.0',
+      }).validate();
 
       await d.appDir({'foo': 'any'}).create();
 
       await pubCommand(command);
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-        d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'),
-      ]).validate();
+      await d
+          .appPackagesFile({'foo': '1.0.0', 'shared_dep': '1.0.0'}).validate();
     });
   });
 }
diff --git a/test/hosted/short_syntax_test.dart b/test/hosted/short_syntax_test.dart
index 5d4cf28..70738a9 100644
--- a/test/hosted/short_syntax_test.dart
+++ b/test/hosted/short_syntax_test.dart
@@ -12,12 +12,10 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(() async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3', pubspec: {
-      'environment': {'sdk': '^2.0.0'}
-    });
-  });
+  setUp(() => servePackages((b) => b.serve('foo', '1.2.3', pubspec: {
+        'environment': {'sdk': '^2.0.0'}
+      })));
+
   forBothPubGetAndUpgrade((command) {
     Future<void> testWith(dynamic dependency) async {
       await d.dir(appPath, [
@@ -44,19 +42,19 @@
         'source': 'hosted',
         'description': {
           'name': 'foo',
-          'url': globalServer.url,
+          'url': globalPackageServer!.url,
         },
         'version': '1.2.3',
       });
     }
 
     test('supports hosted: <url> syntax', () async {
-      return testWith({'hosted': globalServer.url});
+      return testWith({'hosted': globalPackageServer!.url});
     });
 
     test('supports hosted map without name', () {
       return testWith({
-        'hosted': {'url': globalServer.url},
+        'hosted': {'url': globalPackageServer!.url},
       });
     });
 
@@ -82,8 +80,8 @@
         await File(p.join(d.sandbox, appPath, 'pubspec.lock')).readAsString(),
       );
 
-      expect(
-          lockFile['packages']['foo']['description']['url'], globalServer.url);
+      expect(lockFile['packages']['foo']['description']['url'],
+          globalPackageServer!.url);
     });
   });
 }
diff --git a/test/hosted/version_negotiation_test.dart b/test/hosted/version_negotiation_test.dart
index 44dbe7a..ff491cd 100644
--- a/test/hosted/version_negotiation_test.dart
+++ b/test/hosted/version_negotiation_test.dart
@@ -16,11 +16,11 @@
 
       await d.appDir({
         'foo': {
-          'hosted': {'name': 'foo', 'url': globalServer.url}
+          'hosted': {'name': 'foo', 'url': globalPackageServer!.url}
         }
       }).create();
 
-      globalServer.expect('GET', '/api/packages/foo', (request) {
+      globalPackageServer!.expect('GET', '/api/packages/foo', (request) {
         expect(
             request.headers['accept'], equals('application/vnd.pub.v2+json'));
         return shelf.Response(404);
@@ -35,14 +35,14 @@
 
       await d.appDir({
         'foo': {
-          'hosted': {'name': 'foo', 'url': globalServer.url}
+          'hosted': {'name': 'foo', 'url': globalPackageServer!.url}
         }
       }).create();
 
       var pub = await startPub(args: [command.name]);
 
-      globalServer.expect(
-          'GET', '/api/packages/foo', (request) => shelf.Response(406));
+      globalPackageServer!
+          .expect('GET', '/api/packages/foo', (request) => shelf.Response(406));
 
       await pub.shouldExit(1);
 
diff --git a/test/hosted/will_normalize_hosted_url_test.dart b/test/hosted/will_normalize_hosted_url_test.dart
index 6cc3888..38bc574 100644
--- a/test/hosted/will_normalize_hosted_url_test.dart
+++ b/test/hosted/will_normalize_hosted_url_test.dart
@@ -13,50 +13,47 @@
 void main() {
   forBothPubGetAndUpgrade((command) {
     test('does not require slash on bare domain', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
-      // All the tests in this file assumes that [globalServer.url]
+      await servePackages((b) => b..serve('foo', '1.2.3'));
+      // All the tests in this file assumes that [globalPackageServer.url]
       // will be on the form:
       //   http://localhost:<port>
       // In particular, that it doesn't contain anything path segment.
-      expect(Uri.parse(globalServer.url).path, isEmpty);
+      expect(Uri.parse(globalPackageServer!.url).path, isEmpty);
 
       await d.dir(appPath, [
         d.appPubspec({
           'foo': {
-            'hosted': {'name': 'foo', 'url': globalServer.url},
+            'hosted': {'name': 'foo', 'url': globalPackageServer!.url},
           },
         }),
       ]).create();
 
       await pubCommand(
         command,
-        silent: contains('${globalServer.url}/api/packages/foo'),
+        silent: contains('${globalPackageServer!.url}/api/packages/foo'),
       );
     });
 
     test('normalizes extra slash', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
+      await servePackages((b) => b..serve('foo', '1.2.3'));
 
       await d.dir(appPath, [
         d.appPubspec({
           'foo': {
-            'hosted': {'name': 'foo', 'url': globalServer.url + '/'},
+            'hosted': {'name': 'foo', 'url': globalPackageServer!.url + '/'},
           },
         }),
       ]).create();
 
       await pubCommand(
         command,
-        silent: contains('${globalServer.url}/api/packages/foo'),
+        silent: contains('${globalPackageServer!.url}/api/packages/foo'),
       );
     });
 
     test('cannot normalize double slash', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
-      globalServer.expect(
+      await servePackages((b) => b..serve('foo', '1.2.3'));
+      globalPackageServer!.expect(
         'GET',
         '//api/packages/foo',
         (request) => Response.notFound(''),
@@ -65,14 +62,15 @@
       await d.dir(appPath, [
         d.appPubspec({
           'foo': {
-            'hosted': {'name': 'foo', 'url': globalServer.url + '//'},
+            'hosted': {'name': 'foo', 'url': globalPackageServer!.url + '//'},
           },
         }),
       ]).create();
 
       await pubCommand(
         command,
-        error: contains('could not find package foo at ${globalServer.url}//'),
+        error: contains(
+            'could not find package foo at ${globalPackageServer!.url}//'),
         exitCode: exit_codes.UNAVAILABLE,
       );
     });
@@ -82,31 +80,27 @@
     /// This is a bit of a hack, to easily test if hosted pub URLs with a path
     /// segment works and if the slashes are normalized.
     void _proxyMyFolderToRoot() {
-      globalServer.handle(
-        RegExp('/my-folder/.*'),
-        (r) async {
-          if (r.method != 'GET' && r.method != 'HEAD') {
-            return Response.forbidden(null);
-          }
-          final path = r.requestedUri.path.substring('/my-folder/'.length);
-          final res = await http.get(
-            Uri.parse(globalServer.url + '/$path'),
-          );
-          return Response(res.statusCode, body: res.bodyBytes, headers: {
-            'Content-Type': res.headers['content-type']!,
-          });
-        },
-      );
+      globalPackageServer!.extraHandlers[RegExp('/my-folder/.*')] = (r) async {
+        if (r.method != 'GET' && r.method != 'HEAD') {
+          return Response.forbidden(null);
+        }
+        final path = r.requestedUri.path.substring('/my-folder/'.length);
+        final res = await http.get(
+          Uri.parse(globalPackageServer!.url + '/$path'),
+        );
+        return Response(res.statusCode, body: res.bodyBytes, headers: {
+          'content-type': res.headers['content-type']!,
+        });
+      };
     }
 
     test('will use normalized url with path', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
+      await servePackages((b) => b..serve('foo', '1.2.3'));
       _proxyMyFolderToRoot();
 
       // testing with a normalized URL
-      final testUrl = globalServer.url + '/my-folder/';
-      final normalizedUrl = globalServer.url + '/my-folder/';
+      final testUrl = globalPackageServer!.url + '/my-folder/';
+      final normalizedUrl = globalPackageServer!.url + '/my-folder/';
 
       await d.dir(appPath, [
         d.appPubspec({
@@ -124,13 +118,12 @@
     });
 
     test('will normalize url with path by adding slash', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3');
+      await servePackages((b) => b..serve('foo', '1.2.3'));
       _proxyMyFolderToRoot();
 
       // Testing with a URL that is missing the slash.
-      final testUrl = globalServer.url + '/my-folder';
-      final normalizedUrl = globalServer.url + '/my-folder/';
+      final testUrl = globalPackageServer!.url + '/my-folder';
+      final normalizedUrl = globalPackageServer!.url + '/my-folder/';
 
       await d.dir(appPath, [
         d.appPubspec({
diff --git a/test/ignore_test.dart b/test/ignore_test.dart
index a8ab8ac..42a189a 100644
--- a/test/ignore_test.dart
+++ b/test/ignore_test.dart
@@ -977,13 +977,6 @@
     'folder/a.txt': true,
   }),
 
-  TestData('folder/* does not ignore `folder` itself', {
-    '.': ['folder/*', '!folder/a.txt'],
-  }, {
-    'folder/a.txt': false,
-    'folder/b.txt': true,
-  }),
-
   // Case sensitivity
   TestData(
     'simple',
diff --git a/test/lish/archives_and_uploads_a_package_test.dart b/test/lish/archives_and_uploads_a_package_test.dart
index 88e4862..0fffb5a 100644
--- a/test/lish/archives_and_uploads_a_package_test.dart
+++ b/test/lish/archives_and_uploads_a_package_test.dart
@@ -19,44 +19,14 @@
 
   test('archives and uploads a package', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
-    globalServer.expect('GET', '/create', (request) {
-      return shelf.Response.ok(jsonEncode({
-        'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
-      }));
-    });
-
-    expect(pub.stdout, emits(startsWith('Uploading...')));
-    expect(pub.stdout, emits('Package test_pkg 1.0.0 uploaded!'));
-    await pub.shouldExit(exit_codes.SUCCESS);
-  });
-
-  test('publishes to hosted-url with path', () async {
-    await servePackages();
-    await d.tokensFile({
-      'version': 1,
-      'hosted': [
-        {'url': globalServer.url + '/sub/folder', 'env': 'TOKEN'},
-      ]
-    }).create();
-    var pub = await startPublish(
-      globalServer,
-      path: '/sub/folder',
-      authMethod: 'token',
-      environment: {'TOKEN': 'access token'},
-    );
-
-    await confirmPublish(pub);
-    handleUploadForm(globalServer, path: '/sub/folder');
-    handleUpload(globalServer);
-
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.ok(jsonEncode({
         'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
       }));
@@ -83,14 +53,14 @@
     await d.dir(p.join(appPath, 'empty')).create();
 
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.ok(jsonEncode({
         'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
       }));
diff --git a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
index 0f792d5..e4489e4 100644
--- a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
+++ b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
@@ -14,13 +14,13 @@
 
   test("cloud storage upload doesn't redirect", () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
+    handleUploadForm(globalPackageServer!);
 
-    globalServer.expect('POST', '/upload', (request) async {
+    globalPackageServer!.expect('POST', '/upload', (request) async {
       await request.read().drain();
       return shelf.Response(200);
     });
diff --git a/test/lish/cloud_storage_upload_provides_an_error_test.dart b/test/lish/cloud_storage_upload_provides_an_error_test.dart
index 5dec03d..ebb463a 100644
--- a/test/lish/cloud_storage_upload_provides_an_error_test.dart
+++ b/test/lish/cloud_storage_upload_provides_an_error_test.dart
@@ -14,13 +14,13 @@
 
   test('cloud storage upload provides an error', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
+    handleUploadForm(globalPackageServer!);
 
-    globalServer.expect('POST', '/upload', (request) {
+    globalPackageServer!.expect('POST', '/upload', (request) {
       return request.read().drain().then((_) {
         return shelf.Response.notFound(
             '<Error><Message>Your request sucked.</Message></Error>',
diff --git a/test/lish/does_not_include_dot_file.dart b/test/lish/does_not_include_dot_file.dart
index cec8ab0..9f1b24f 100644
--- a/test/lish/does_not_include_dot_file.dart
+++ b/test/lish/does_not_include_dot_file.dart
@@ -30,14 +30,14 @@
 
   test('Check if package doesn\'t include dot-files', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.ok(jsonEncode({
         'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
       }));
diff --git a/test/lish/dot_folder_name_test.dart b/test/lish/dot_folder_name_test.dart
deleted file mode 100644
index 9f64839..0000000
--- a/test/lish/dot_folder_name_test.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2022, 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:pub/src/exit_codes.dart' as exit_codes;
-import 'package:test/test.dart';
-
-import '../descriptor.dart' as d;
-import '../test_pub.dart';
-
-void main() {
-  test('Can publish files in a .folder', () async {
-    await d.git(appPath).create();
-    await d.validPackage.create();
-    await d.dir(appPath, [
-      d.dir('.vscode', [d.file('a')]),
-      d.file('.pubignore', '!.vscode/')
-    ]).create();
-
-    await runPub(
-      args: ['lish', '--dry-run'],
-      output: contains('''
-|-- .vscode
-|   '-- a'''),
-      exitCode: exit_codes.SUCCESS,
-    );
-  });
-}
diff --git a/test/lish/force_does_not_publish_if_there_are_errors_test.dart b/test/lish/force_does_not_publish_if_there_are_errors_test.dart
index 481f627..58c12fa 100644
--- a/test/lish/force_does_not_publish_if_there_are_errors_test.dart
+++ b/test/lish/force_does_not_publish_if_there_are_errors_test.dart
@@ -21,7 +21,7 @@
     ]).create();
 
     await servePackages();
-    var pub = await startPublish(globalServer, args: ['--force']);
+    var pub = await startPublish(globalPackageServer!, args: ['--force']);
 
     await pub.shouldExit(exit_codes.DATA);
     expect(
diff --git a/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart b/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart
index c5d8957..cc05354 100644
--- a/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart
+++ b/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart
@@ -17,13 +17,13 @@
 
   test('--force publishes if there are no warnings or errors', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer, args: ['--force']);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!, args: ['--force']);
 
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.ok(jsonEncode({
         'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
       }));
diff --git a/test/lish/force_publishes_if_there_are_warnings_test.dart b/test/lish/force_publishes_if_there_are_warnings_test.dart
index 9fb3d53..9797e9c 100644
--- a/test/lish/force_publishes_if_there_are_warnings_test.dart
+++ b/test/lish/force_publishes_if_there_are_warnings_test.dart
@@ -22,13 +22,13 @@
     await d.dir(appPath, [d.pubspec(pkg)]).create();
 
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer, args: ['--force']);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!, args: ['--force']);
 
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.ok(jsonEncode({
         'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
       }));
diff --git a/test/lish/many_files_test.dart b/test/lish/many_files_test.dart
index 36f4ed7..dfe13f3 100644
--- a/test/lish/many_files_test.dart
+++ b/test/lish/many_files_test.dart
@@ -73,14 +73,14 @@
     }
 
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.ok(jsonEncode({
         'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
       }));
diff --git a/test/lish/package_creation_provides_a_malformed_error_test.dart b/test/lish/package_creation_provides_a_malformed_error_test.dart
index 7ab0bcd..1587165 100644
--- a/test/lish/package_creation_provides_a_malformed_error_test.dart
+++ b/test/lish/package_creation_provides_a_malformed_error_test.dart
@@ -16,15 +16,15 @@
 
   test('package creation provides a malformed error', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
     var body = {'error': 'Your package was too boring.'};
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.notFound(jsonEncode(body));
     });
 
diff --git a/test/lish/package_creation_provides_a_malformed_success_test.dart b/test/lish/package_creation_provides_a_malformed_success_test.dart
index 089d09e..b47461f 100644
--- a/test/lish/package_creation_provides_a_malformed_success_test.dart
+++ b/test/lish/package_creation_provides_a_malformed_success_test.dart
@@ -16,15 +16,15 @@
 
   test('package creation provides a malformed success', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
     var body = {'success': 'Your package was awesome.'};
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.ok(jsonEncode(body));
     });
 
diff --git a/test/lish/package_creation_provides_an_error_test.dart b/test/lish/package_creation_provides_an_error_test.dart
index f5ff128..a0c7153 100644
--- a/test/lish/package_creation_provides_an_error_test.dart
+++ b/test/lish/package_creation_provides_an_error_test.dart
@@ -16,14 +16,14 @@
 
   test('package creation provides an error', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.notFound(jsonEncode({
         'error': {'message': 'Your package was too boring.'}
       }));
diff --git a/test/lish/package_creation_provides_invalid_json_test.dart b/test/lish/package_creation_provides_invalid_json_test.dart
index 2cd6212..025d8f9 100644
--- a/test/lish/package_creation_provides_invalid_json_test.dart
+++ b/test/lish/package_creation_provides_invalid_json_test.dart
@@ -14,14 +14,14 @@
 
   test('package creation provides invalid JSON', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.ok('{not json');
     });
 
diff --git a/test/lish/package_validation_has_a_warning_and_continues_test.dart b/test/lish/package_validation_has_a_warning_and_continues_test.dart
index c39dbc4..15e9185 100644
--- a/test/lish/package_validation_has_a_warning_and_continues_test.dart
+++ b/test/lish/package_validation_has_a_warning_and_continues_test.dart
@@ -22,13 +22,13 @@
     await d.dir(appPath, [d.pubspec(pkg)]).create();
 
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
     pub.stdin.writeln('y');
-    handleUploadForm(globalServer);
-    handleUpload(globalServer);
+    handleUploadForm(globalPackageServer!);
+    handleUpload(globalPackageServer!);
 
-    globalServer.expect('GET', '/create', (request) {
+    globalPackageServer!.expect('GET', '/create', (request) {
       return shelf.Response.ok(jsonEncode({
         'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
       }));
diff --git a/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart b/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart
index 0d5a563..c478b05 100644
--- a/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart
+++ b/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart
@@ -18,7 +18,7 @@
     await d.dir(appPath, [d.pubspec(pkg)]).create();
 
     await servePackages();
-    var pub = await startPublish(globalServer);
+    var pub = await startPublish(globalPackageServer!);
 
     pub.stdin.writeln('n');
     await pub.shouldExit(exit_codes.DATA);
diff --git a/test/lish/package_validation_has_an_error_test.dart b/test/lish/package_validation_has_an_error_test.dart
index 14c83c0..df747c6 100644
--- a/test/lish/package_validation_has_an_error_test.dart
+++ b/test/lish/package_validation_has_an_error_test.dart
@@ -21,7 +21,7 @@
     ]).create();
 
     await servePackages();
-    var pub = await startPublish(globalServer);
+    var pub = await startPublish(globalPackageServer!);
 
     await pub.shouldExit(exit_codes.DATA);
     expect(
diff --git a/test/lish/preview_package_validation_has_a_warning_test.dart b/test/lish/preview_package_validation_has_a_warning_test.dart
index 69f59af..bbb3967 100644
--- a/test/lish/preview_package_validation_has_a_warning_test.dart
+++ b/test/lish/preview_package_validation_has_a_warning_test.dart
@@ -19,7 +19,7 @@
     await d.dir(appPath, [d.pubspec(pkg)]).create();
 
     await servePackages();
-    var pub = await startPublish(globalServer, args: ['--dry-run']);
+    var pub = await startPublish(globalPackageServer!, args: ['--dry-run']);
 
     await pub.shouldExit(exit_codes.DATA);
     expect(
diff --git a/test/lish/preview_package_validation_has_no_warnings_test.dart b/test/lish/preview_package_validation_has_no_warnings_test.dart
index 179c648..a1bffaf 100644
--- a/test/lish/preview_package_validation_has_no_warnings_test.dart
+++ b/test/lish/preview_package_validation_has_no_warnings_test.dart
@@ -17,8 +17,8 @@
         packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=1.8.0 <2.0.0'});
     await d.dir(appPath, [d.pubspec(pkg)]).create();
 
-    await servePackages();
-    var pub = await startPublish(globalServer, args: ['--dry-run']);
+    await servePackages((_) {});
+    var pub = await startPublish(globalPackageServer!, args: ['--dry-run']);
 
     await pub.shouldExit(exit_codes.SUCCESS);
     expect(pub.stderr, emitsThrough('Package has 0 warnings.'));
diff --git a/test/lish/server_arg_overrides_publish_to_url_test.dart b/test/lish/server_arg_overrides_publish_to_url_test.dart
index 1597146..b2d4c14 100644
--- a/test/lish/server_arg_overrides_publish_to_url_test.dart
+++ b/test/lish/server_arg_overrides_publish_to_url_test.dart
@@ -13,15 +13,16 @@
   test('an explicit --server argument overrides a "publish_to" url', () async {
     // Create a real server that can reject requests because validators will
     // try to ping it, and will use multiple retries when doing so.
-    final packageServer = await startPackageServer();
+    final packageServer = await DescriptorServer.start();
+    final fakePackageServer = 'http://localhost:${packageServer.port}';
 
     var pkg = packageMap('test_pkg', '1.0.0');
     pkg['publish_to'] = 'http://pubspec.com';
     await d.dir(appPath, [d.pubspec(pkg)]).create();
 
     await runPub(
-        args: ['lish', '--dry-run', '--server', packageServer.url],
-        output: contains(packageServer.url),
+        args: ['lish', '--dry-run', '--server', fakePackageServer],
+        output: contains(fakePackageServer),
         exitCode: exit_codes.DATA);
 
     await packageServer.close();
diff --git a/test/lish/upload_form_fields_has_a_non_string_value_test.dart b/test/lish/upload_form_fields_has_a_non_string_value_test.dart
index 78a54fa..3be8f4c 100644
--- a/test/lish/upload_form_fields_has_a_non_string_value_test.dart
+++ b/test/lish/upload_form_fields_has_a_non_string_value_test.dart
@@ -14,9 +14,9 @@
   setUp(d.validPackage.create);
 
   test('upload form fields has a non-string value', () async {
-    await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await servePackages((_) {});
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
 
@@ -24,7 +24,7 @@
       'url': 'http://example.com/upload',
       'fields': {'field': 12}
     };
-    handleUploadForm(globalServer, body: body);
+    handleUploadForm(globalPackageServer!, body);
     expect(pub.stderr, emits('Invalid server response:'));
     expect(pub.stderr, emits(jsonEncode(body)));
     await pub.shouldExit(1);
diff --git a/test/lish/upload_form_fields_is_not_a_map_test.dart b/test/lish/upload_form_fields_is_not_a_map_test.dart
index d18c1ee..53f36da 100644
--- a/test/lish/upload_form_fields_is_not_a_map_test.dart
+++ b/test/lish/upload_form_fields_is_not_a_map_test.dart
@@ -15,13 +15,13 @@
 
   test('upload form fields is not a map', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
 
     var body = {'url': 'http://example.com/upload', 'fields': 12};
-    handleUploadForm(globalServer, body: body);
+    handleUploadForm(globalPackageServer!, body);
     expect(pub.stderr, emits('Invalid server response:'));
     expect(pub.stderr, emits(jsonEncode(body)));
     await pub.shouldExit(1);
diff --git a/test/lish/upload_form_is_missing_fields_test.dart b/test/lish/upload_form_is_missing_fields_test.dart
index b0032f8..27036f6 100644
--- a/test/lish/upload_form_is_missing_fields_test.dart
+++ b/test/lish/upload_form_is_missing_fields_test.dart
@@ -15,13 +15,13 @@
 
   test('upload form is missing fields', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
 
     var body = {'url': 'http://example.com/upload'};
-    handleUploadForm(globalServer, body: body);
+    handleUploadForm(globalPackageServer!, body);
     expect(pub.stderr, emits('Invalid server response:'));
     expect(pub.stderr, emits(jsonEncode(body)));
     await pub.shouldExit(1);
diff --git a/test/lish/upload_form_is_missing_url_test.dart b/test/lish/upload_form_is_missing_url_test.dart
index eae43ea..f9f6e8b 100644
--- a/test/lish/upload_form_is_missing_url_test.dart
+++ b/test/lish/upload_form_is_missing_url_test.dart
@@ -15,8 +15,8 @@
 
   test('upload form is missing url', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
 
@@ -24,7 +24,7 @@
       'fields': {'field1': 'value1', 'field2': 'value2'}
     };
 
-    handleUploadForm(globalServer, body: body);
+    handleUploadForm(globalPackageServer!, body);
     expect(pub.stderr, emits('Invalid server response:'));
     expect(pub.stderr, emits(jsonEncode(body)));
     await pub.shouldExit(1);
diff --git a/test/lish/upload_form_provides_an_error_test.dart b/test/lish/upload_form_provides_an_error_test.dart
index 35932b8..1d9b0c5 100644
--- a/test/lish/upload_form_provides_an_error_test.dart
+++ b/test/lish/upload_form_provides_an_error_test.dart
@@ -14,13 +14,15 @@
   setUp(d.validPackage.create);
 
   test('upload form provides an error', () async {
-    await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await servePackages((_) {});
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
 
-    globalServer.expect('GET', '/api/packages/versions/new', (request) async {
+    globalPackageServer!.extraHandlers['/api/packages/versions/new'] =
+        expectAsync1((request) {
+      expect(request.method, 'GET');
       return shelf.Response.notFound(jsonEncode({
         'error': {'message': 'your request sucked'}
       }));
diff --git a/test/lish/upload_form_provides_invalid_json_test.dart b/test/lish/upload_form_provides_invalid_json_test.dart
index a046755..c0996f9 100644
--- a/test/lish/upload_form_provides_invalid_json_test.dart
+++ b/test/lish/upload_form_provides_invalid_json_test.dart
@@ -13,12 +13,12 @@
 
   test('upload form provides invalid JSON', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
 
-    globalServer.expect('GET', '/api/packages/versions/new',
+    globalPackageServer!.expect('GET', '/api/packages/versions/new',
         (request) => shelf.Response.ok('{not json'));
 
     expect(
diff --git a/test/lish/upload_form_url_is_not_a_string_test.dart b/test/lish/upload_form_url_is_not_a_string_test.dart
index f69fd1f..a999537 100644
--- a/test/lish/upload_form_url_is_not_a_string_test.dart
+++ b/test/lish/upload_form_url_is_not_a_string_test.dart
@@ -15,8 +15,8 @@
 
   test('upload form url is not a string', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
 
@@ -25,7 +25,7 @@
       'fields': {'field1': 'value1', 'field2': 'value2'}
     };
 
-    handleUploadForm(globalServer, body: body);
+    handleUploadForm(globalPackageServer!, body);
     expect(pub.stderr, emits('Invalid server response:'));
     expect(pub.stderr, emits(jsonEncode(body)));
     await pub.shouldExit(1);
diff --git a/test/lish/utils.dart b/test/lish/utils.dart
index f134e4a..8e1ed5f 100644
--- a/test/lish/utils.dart
+++ b/test/lish/utils.dart
@@ -9,8 +9,8 @@
 
 import '../test_pub.dart';
 
-void handleUploadForm(PackageServer server, {Map? body, String path = ''}) {
-  server.expect('GET', '$path/api/packages/versions/new', (request) {
+void handleUploadForm(PackageServer server, [Map? body]) {
+  server.expect('GET', '/api/packages/versions/new', (request) {
     expect(
         request.headers, containsPair('authorization', 'Bearer access token'));
 
diff --git a/test/list_package_dirs/lists_dependency_directories_test.dart b/test/list_package_dirs/lists_dependency_directories_test.dart
index 2cd9664..af019a6 100644
--- a/test/list_package_dirs/lists_dependency_directories_test.dart
+++ b/test/list_package_dirs/lists_dependency_directories_test.dart
@@ -12,8 +12,7 @@
 
 void main() {
   test('prints the local paths to all packages in the lockfile', () async {
-    final server = await servePackages()
-      ..serve('bar', '1.0.0');
+    await servePackages((builder) => builder.serve('bar', '1.0.0'));
 
     await d
         .dir('foo', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create();
@@ -38,7 +37,7 @@
       'packages': {
         'foo': path.join(d.sandbox, 'foo', 'lib'),
         'bar': path.join(d.sandbox, cachePath, 'hosted',
-            'localhost%58${server.port}', 'bar-1.0.0', 'lib'),
+            'localhost%58${globalServer!.port}', 'bar-1.0.0', 'lib'),
         'myapp': canonicalize(path.join(d.sandbox, appPath, 'lib'))
       },
       'input_files': [
diff --git a/test/must_pub_get_test.dart b/test/must_pub_get_test.dart
index 71d9c16..3451fc7 100644
--- a/test/must_pub_get_test.dart
+++ b/test/must_pub_get_test.dart
@@ -14,14 +14,12 @@
 import 'descriptor.dart' as d;
 import 'test_pub.dart';
 
-late PackageServer server;
-
 void main() {
   setUp(() async {
-    server = await servePackages();
-
-    server.serve('foo', '1.0.0');
-    server.serve('foo', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0');
+    });
 
     await d.dir(appPath, [
       d.appPubspec(),
@@ -213,7 +211,7 @@
           d.appPubspec({'foo': '1.0.0'})
         ]).create();
 
-        await pubGet(args: ['--legacy-packages-file']);
+        await pubGet();
 
         deleteEntry(p.join(d.sandbox, cachePath));
 
@@ -235,7 +233,7 @@
           })
         ]).create();
 
-        await pubGet(args: ['--legacy-packages-file']);
+        await pubGet();
 
         await createPackagesFile(appPath);
 
@@ -257,7 +255,7 @@
           })
         ]).create();
 
-        await pubGet(args: ['--legacy-packages-file']);
+        await pubGet();
 
         await d.dir(appPath, [
           d.file('.packages', '''
@@ -284,7 +282,7 @@
           })
         ]).create();
 
-        await pubGet(args: ['--legacy-packages-file']);
+        await pubGet();
 
         await createPackagesFile(appPath, dependenciesInSandBox: ['foo']);
 
@@ -334,8 +332,10 @@
       setUp(() async {
         // Avoid using a path dependency because it triggers the full validation
         // logic. We want to be sure SDK-validation works without that logic.
-        server.serve('foo', '3.0.0', pubspec: {
-          'environment': {'sdk': '>=1.0.0 <2.0.0'}
+        globalPackageServer!.add((builder) {
+          builder.serve('foo', '3.0.0', pubspec: {
+            'environment': {'sdk': '>=1.0.0 <2.0.0'}
+          });
         });
 
         await d.dir(appPath, [
@@ -360,8 +360,10 @@
         'current Flutter SDK', () async {
       // Avoid using a path dependency because it triggers the full validation
       // logic. We want to be sure SDK-validation works without that logic.
-      server.serve('foo', '3.0.0', pubspec: {
-        'environment': {'flutter': '>=1.0.0 <2.0.0'}
+      globalPackageServer!.add((builder) {
+        builder.serve('foo', '3.0.0', pubspec: {
+          'environment': {'flutter': '>=1.0.0 <2.0.0'}
+        });
       });
 
       await d.dir('flutter', [d.file('version', '1.2.3')]).create();
@@ -452,7 +454,7 @@
   group("doesn't require the user to run pub get first if", () {
     group(
         'the pubspec is older than the lockfile which is older than the '
-        'package-config, even if the contents are wrong', () {
+        'packages file, even if the contents are wrong', () {
       setUp(() async {
         await d.dir(appPath, [
           d.appPubspec({'foo': '1.0.0'})
@@ -461,6 +463,7 @@
         await _touch('pubspec.yaml');
 
         await _touch('pubspec.lock');
+        await _touch('.packages');
         await _touch('.dart_tool/package_config.json');
       });
 
@@ -519,8 +522,10 @@
 
     group("an overridden dependency's SDK constraint is unmatched", () {
       setUp(() async {
-        server.serve('bar', '1.0.0', pubspec: {
-          'environment': {'sdk': '0.0.0-fake'}
+        globalPackageServer!.add((builder) {
+          builder.serve('bar', '1.0.0', pubspec: {
+            'environment': {'sdk': '0.0.0-fake'}
+          });
         });
 
         await d.dir(appPath, [
@@ -542,8 +547,10 @@
         () async {
       // Avoid using a path dependency because it triggers the full validation
       // logic. We want to be sure SDK-validation works without that logic.
-      server.serve('foo', '3.0.0', pubspec: {
-        'environment': {'flutter': '>=1.0.0 <2.0.0'}
+      globalPackageServer!.add((builder) {
+        builder.serve('foo', '3.0.0', pubspec: {
+          'environment': {'flutter': '>=1.0.0 <2.0.0'}
+        });
       });
 
       await d.dir('flutter', [d.file('version', '1.2.3')]).create();
@@ -599,11 +606,14 @@
           File(p.join(d.sandbox, 'myapp/pubspec.yaml')).lastModifiedSync();
       var lockFileModified =
           File(p.join(d.sandbox, 'myapp/pubspec.lock')).lastModifiedSync();
+      var packagesModified =
+          File(p.join(d.sandbox, 'myapp/.packages')).lastModifiedSync();
       var packageConfigModified =
           File(p.join(d.sandbox, 'myapp/.dart_tool/package_config.json'))
               .lastModifiedSync();
 
       expect(!pubspecModified.isAfter(lockFileModified), isTrue);
+      expect(!lockFileModified.isAfter(packagesModified), isTrue);
       expect(!lockFileModified.isAfter(packageConfigModified), isTrue);
     });
   }
diff --git a/test/oauth2/logout_test.dart b/test/oauth2/logout_test.dart
index a12a652..7398884 100644
--- a/test/oauth2/logout_test.dart
+++ b/test/oauth2/logout_test.dart
@@ -11,7 +11,7 @@
   test('with an existing credentials file, deletes it.', () async {
     await servePackages();
     await d
-        .credentialsFile(globalServer, 'access token',
+        .credentialsFile(globalPackageServer!, 'access token',
             refreshToken: 'refresh token',
             expiration: DateTime.now().add(Duration(hours: 1)))
         .create();
@@ -28,7 +28,7 @@
     await servePackages();
     await d
         .credentialsFile(
-          globalServer,
+          globalPackageServer!,
           'access token',
           refreshToken: 'refresh token',
           expiration: DateTime.now().add(Duration(hours: 1)),
@@ -37,7 +37,7 @@
 
     await d
         .legacyCredentialsFile(
-          globalServer,
+          globalPackageServer!,
           'access token',
           refreshToken: 'refresh token',
           expiration: DateTime.now().add(Duration(hours: 1)),
diff --git a/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart b/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart
index 75b47ab..79d89a7 100644
--- a/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart
+++ b/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart
@@ -19,11 +19,11 @@
     await d.dir(
         configPath, [d.file('pub-credentials.json', '{bad json')]).create();
 
-    var pub = await startPublish(globalServer);
+    var pub = await startPublish(globalPackageServer!);
     await confirmPublish(pub);
-    await authorizePub(pub, globalServer, 'new access token');
+    await authorizePub(pub, globalPackageServer!, 'new access token');
 
-    globalServer.expect('GET', '/api/packages/versions/new', (request) {
+    globalPackageServer!.expect('GET', '/api/packages/versions/new', (request) {
       expect(request.headers,
           containsPair('authorization', 'Bearer new access token'));
 
@@ -34,6 +34,8 @@
     // do so rather than killing it so it'll write out the credentials file.
     await pub.shouldExit(1);
 
-    await d.credentialsFile(globalServer, 'new access token').validate();
+    await d
+        .credentialsFile(globalPackageServer!, 'new access token')
+        .validate();
   });
 }
diff --git a/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart b/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart
index 3c22994..0ecd305 100644
--- a/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart
+++ b/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart
@@ -12,8 +12,8 @@
     await d.validPackage.create();
 
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
 
diff --git a/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart b/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
index 624f427..63a91d4 100644
--- a/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
+++ b/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
@@ -21,14 +21,14 @@
 
     await servePackages();
     await d
-        .credentialsFile(globalServer, 'access token',
+        .credentialsFile(globalPackageServer!, 'access token',
             refreshToken: 'bad refresh token',
             expiration: DateTime.now().subtract(Duration(hours: 1)))
         .create();
 
-    var pub = await startPublish(globalServer);
+    var pub = await startPublish(globalPackageServer!);
 
-    globalServer.expect('POST', '/token', (request) {
+    globalPackageServer!.expect('POST', '/token', (request) {
       return request.read().drain().then((_) {
         return shelf.Response(400,
             body: jsonEncode({'error': 'invalid_request'}),
@@ -39,10 +39,11 @@
     await confirmPublish(pub);
 
     await expectLater(pub.stdout, emits(startsWith('Uploading...')));
-    await authorizePub(pub, globalServer, 'new access token');
+    await authorizePub(pub, globalPackageServer!, 'new access token');
 
     var done = Completer();
-    globalServer.expect('GET', '/api/packages/versions/new', (request) async {
+    globalPackageServer!.expect('GET', '/api/packages/versions/new',
+        (request) async {
       expect(request.headers,
           containsPair('authorization', 'Bearer new access token'));
 
diff --git a/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart b/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart
index 7fbbb9f..3d303a5 100644
--- a/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart
+++ b/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart
@@ -18,15 +18,15 @@
 
     await servePackages();
     await d
-        .credentialsFile(globalServer, 'access token',
+        .credentialsFile(globalPackageServer!, 'access token',
             refreshToken: 'refresh token',
             expiration: DateTime.now().subtract(Duration(hours: 1)))
         .create();
 
-    var pub = await startPublish(globalServer);
+    var pub = await startPublish(globalPackageServer!);
     await confirmPublish(pub);
 
-    globalServer.expect('POST', '/token', (request) {
+    globalPackageServer!.expect('POST', '/token', (request) {
       return request.readAsString().then((body) {
         expect(
             body, matches(RegExp(r'(^|&)refresh_token=refresh\+token(&|$)')));
@@ -38,7 +38,7 @@
       });
     });
 
-    globalServer.expect('GET', '/api/packages/versions/new', (request) {
+    globalPackageServer!.expect('GET', '/api/packages/versions/new', (request) {
       expect(request.headers,
           containsPair('authorization', 'Bearer new access token'));
 
@@ -48,7 +48,7 @@
     await pub.shouldExit();
 
     await d
-        .credentialsFile(globalServer, 'new access token',
+        .credentialsFile(globalPackageServer!, 'new access token',
             refreshToken: 'refresh token')
         .validate();
   });
diff --git a/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart b/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart
index 803c529..dbb4280 100644
--- a/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart
+++ b/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart
@@ -17,20 +17,20 @@
 
     await servePackages();
     await d
-        .credentialsFile(globalServer, 'access token',
+        .credentialsFile(globalPackageServer!, 'access token',
             expiration: DateTime.now().subtract(Duration(hours: 1)))
         .create();
 
-    var pub = await startPublish(globalServer);
+    var pub = await startPublish(globalPackageServer!);
     await confirmPublish(pub);
 
     await expectLater(
         pub.stderr,
         emits("Pub's authorization to upload packages has expired and "
             "can't be automatically refreshed."));
-    await authorizePub(pub, globalServer, 'new access token');
+    await authorizePub(pub, globalPackageServer!, 'new access token');
 
-    globalServer.expect('GET', '/api/packages/versions/new', (request) {
+    globalPackageServer!.expect('GET', '/api/packages/versions/new', (request) {
       expect(request.headers,
           containsPair('authorization', 'Bearer new access token'));
 
@@ -41,6 +41,8 @@
     // do so rather than killing it so it'll write out the credentials file.
     await pub.shouldExit(1);
 
-    await d.credentialsFile(globalServer, 'new access token').validate();
+    await d
+        .credentialsFile(globalPackageServer!, 'new access token')
+        .validate();
   });
 }
diff --git a/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart b/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart
index 961a465..fe7bc1b 100644
--- a/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart
+++ b/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart
@@ -16,11 +16,11 @@
     await d.validPackage.create();
 
     await servePackages();
-    var pub = await startPublish(globalServer);
+    var pub = await startPublish(globalPackageServer!);
     await confirmPublish(pub);
-    await authorizePub(pub, globalServer);
+    await authorizePub(pub, globalPackageServer!);
 
-    globalServer.expect('GET', '/api/packages/versions/new', (request) {
+    globalPackageServer!.expect('GET', '/api/packages/versions/new', (request) {
       expect(request.headers,
           containsPair('authorization', 'Bearer access token'));
 
@@ -31,6 +31,6 @@
     // do so rather than killing it so it'll write out the credentials file.
     await pub.shouldExit(1);
 
-    await d.credentialsFile(globalServer, 'access token').validate();
+    await d.credentialsFile(globalPackageServer!, 'access token').validate();
   });
 }
diff --git a/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart b/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart
index 2e3b62f..433a9ed 100644
--- a/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart
+++ b/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart
@@ -16,12 +16,12 @@
       'credentials.json', () async {
     await d.validPackage.create();
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPublish(globalServer);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPublish(globalPackageServer!);
 
     await confirmPublish(pub);
 
-    globalServer.expect('GET', '/api/packages/versions/new', (request) {
+    globalPackageServer!.expect('GET', '/api/packages/versions/new', (request) {
       return shelf.Response(401,
           body: jsonEncode({
             'error': {'message': 'your token sucks'}
diff --git a/test/outdated/outdated_test.dart b/test/outdated/outdated_test.dart
index 31113c7..f2dee0c 100644
--- a/test/outdated/outdated_test.dart
+++ b/test/outdated/outdated_test.dart
@@ -45,10 +45,10 @@
 
   testWithGolden('no lockfile', (ctx) async {
     await d.appDir({'foo': '^1.0.0', 'bar': '^1.0.0'}).create();
-    await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.2.3')
       ..serve('bar', '1.2.3')
-      ..serve('bar', '2.0.0');
+      ..serve('bar', '2.0.0'));
 
     await ctx.runOutdatedTests();
   });
@@ -61,8 +61,7 @@
   });
 
   testWithGolden('newer versions available', (ctx) async {
-    final builder = await servePackages();
-    builder
+    await servePackages((builder) => builder
       ..serve('foo', '1.2.3', deps: {'transitive': '^1.0.0'})
       ..serve('bar', '1.0.0')
       ..serve('builder', '1.2.3', deps: {
@@ -70,7 +69,7 @@
         'dev_trans': '^1.0.0',
       })
       ..serve('transitive', '1.2.3')
-      ..serve('dev_trans', '1.0.0');
+      ..serve('dev_trans', '1.0.0'));
 
     await d.dir('local_package', [
       d.libDir('local_package'),
@@ -89,7 +88,7 @@
       })
     ]).create();
     await pubGet();
-    builder
+    globalPackageServer!.add((builder) => builder
       ..serve('foo', '1.3.0', deps: {'transitive': '>=1.0.0<3.0.0'})
       ..serve('foo', '2.0.0',
           deps: {'transitive': '>=1.0.0<3.0.0', 'transitive2': '^1.0.0'})
@@ -105,13 +104,15 @@
       ..serve('transitive', '2.0.0')
       ..serve('transitive2', '1.0.0')
       ..serve('transitive3', '1.0.0')
-      ..serve('dev_trans', '2.0.0');
+      ..serve('dev_trans', '2.0.0'));
+
     await ctx.runOutdatedTests();
   });
 
   testWithGolden('circular dependency on root', (ctx) async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3', deps: {'app': '^1.0.0'});
+    await servePackages(
+      (builder) => builder..serve('foo', '1.2.3', deps: {'app': '^1.0.0'}),
+    );
 
     await d.dir(appPath, [
       d.pubspec({
@@ -125,7 +126,10 @@
 
     await pubGet();
 
-    server.serve('foo', '1.3.0', deps: {'app': '^1.0.1'});
+    globalPackageServer!.add(
+      (builder) => builder..serve('foo', '1.3.0', deps: {'app': '^1.0.1'}),
+    );
+
     await ctx.runOutdatedTests();
   });
 
@@ -141,11 +145,11 @@
       })
     ]).create();
 
-    await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'})
       ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'})
       ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'})
-      ..serve('bar', '2.0.0', deps: {'foo': '^1.0.0'});
+      ..serve('bar', '2.0.0', deps: {'foo': '^1.0.0'}));
     await pubGet();
 
     await ctx.runOutdatedTests();
@@ -168,60 +172,62 @@
       }),
     ]).create();
 
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {
-        'bar': '^1.0.0'
-      }, pubspec: {
-        'environment': {'sdk': '>=2.9.0 < 3.0.0'}
-      })
-      ..serve('bar', '1.0.0', pubspec: {
-        'environment': {'sdk': '>=2.9.0 < 3.0.0'}
-      })
-      ..serve('foo', '2.0.0-nullsafety.0', deps: {
-        'bar': '^2.0.0'
-      }, pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'}
-      })
-      ..serve('foo', '2.0.0', deps: {
-        'bar': '^1.0.0'
-      }, pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'}
-      })
-      ..serve('bar', '2.0.0', pubspec: {
-        'environment': {'sdk': '>=2.13.0 < 3.0.0'}
-      })
-      ..serve('file_opts_out', '1.0.0', pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'},
-      }, contents: [
-        d.dir('lib', [d.file('main.dart', '// @dart = 2.9\n')])
-      ])
-      ..serve('file_opts_out', '2.0.0', pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'},
-      })
-      ..serve('fails_analysis', '1.0.0', pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'},
-      }, contents: [
-        d.dir('lib', [d.file('main.dart', 'syntax error\n')])
-      ])
-      ..serve('fails_analysis', '2.0.0', pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'},
-      })
-      ..serve('file_in_dependency_opts_out', '1.0.0', deps: {
-        'file_opts_out': '^1.0.0'
-      }, pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'},
-      })
-      ..serve('file_in_dependency_opts_out', '2.0.0', pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'},
-      })
-      ..serve('fails_analysis_in_dependency', '1.0.0', deps: {
-        'fails_analysis': '^1.0.0'
-      }, pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'},
-      })
-      ..serve('fails_analysis_in_dependency', '2.0.0', pubspec: {
-        'environment': {'sdk': '>=2.12.0 < 3.0.0'},
-      });
+    await servePackages(
+      (builder) => builder
+        ..serve('foo', '1.0.0', deps: {
+          'bar': '^1.0.0'
+        }, pubspec: {
+          'environment': {'sdk': '>=2.9.0 < 3.0.0'}
+        })
+        ..serve('bar', '1.0.0', pubspec: {
+          'environment': {'sdk': '>=2.9.0 < 3.0.0'}
+        })
+        ..serve('foo', '2.0.0-nullsafety.0', deps: {
+          'bar': '^2.0.0'
+        }, pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'}
+        })
+        ..serve('foo', '2.0.0', deps: {
+          'bar': '^1.0.0'
+        }, pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'}
+        })
+        ..serve('bar', '2.0.0', pubspec: {
+          'environment': {'sdk': '>=2.13.0 < 3.0.0'}
+        })
+        ..serve('file_opts_out', '1.0.0', pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'},
+        }, contents: [
+          d.dir('lib', [d.file('main.dart', '// @dart = 2.9\n')])
+        ])
+        ..serve('file_opts_out', '2.0.0', pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'},
+        })
+        ..serve('fails_analysis', '1.0.0', pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'},
+        }, contents: [
+          d.dir('lib', [d.file('main.dart', 'syntax error\n')])
+        ])
+        ..serve('fails_analysis', '2.0.0', pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'},
+        })
+        ..serve('file_in_dependency_opts_out', '1.0.0', deps: {
+          'file_opts_out': '^1.0.0'
+        }, pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'},
+        })
+        ..serve('file_in_dependency_opts_out', '2.0.0', pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'},
+        })
+        ..serve('fails_analysis_in_dependency', '1.0.0', deps: {
+          'fails_analysis': '^1.0.0'
+        }, pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'},
+        })
+        ..serve('fails_analysis_in_dependency', '2.0.0', pubspec: {
+          'environment': {'sdk': '>=2.12.0 < 3.0.0'},
+        }),
+    );
     await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'});
 
     await ctx.runOutdatedTests(environment: {
@@ -230,7 +236,7 @@
   });
 
   testWithGolden('null-safety no resolution', (ctx) async {
-    await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', pubspec: {
         'environment': {'sdk': '>=2.9.0 < 3.0.0'}
       })
@@ -246,7 +252,7 @@
         'foo': '^1.0.0'
       }, pubspec: {
         'environment': {'sdk': '>=2.12.0 < 3.0.0'}
-      });
+      }));
 
     await d.dir(appPath, [
       d.pubspec({
@@ -268,7 +274,7 @@
   });
 
   testWithGolden('null-safety already migrated', (ctx) async {
-    await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', pubspec: {
         'environment': {'sdk': '>=2.9.0 < 3.0.0'}
       })
@@ -285,7 +291,7 @@
       })
       ..serve('devTransitive', '1.0.0', pubspec: {
         'environment': {'sdk': '>=2.9.0 < 3.0.0'}
-      });
+      }));
 
     await d.dir(appPath, [
       d.pubspec({
@@ -310,13 +316,15 @@
 
   testWithGolden('overridden dependencies', (ctx) async {
     ensureGit();
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'})
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '2.0.0')
-      ..serve('baz', '1.0.0')
-      ..serve('baz', '2.0.0');
+    await servePackages(
+      (builder) => builder
+        ..serve('foo', '1.0.0')
+        ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'})
+        ..serve('bar', '1.0.0')
+        ..serve('bar', '2.0.0')
+        ..serve('baz', '1.0.0')
+        ..serve('baz', '2.0.0'),
+    );
 
     await d.git('foo.git', [
       d.libPubspec('foo', '1.0.1'),
@@ -352,11 +360,13 @@
 
   testWithGolden('overridden dependencies - no resolution', (ctx) async {
     ensureGit();
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '^2.0.0'})
-      ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'})
-      ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'})
-      ..serve('bar', '2.0.0', deps: {'foo': '^2.0.0'});
+    await servePackages(
+      (builder) => builder
+        ..serve('foo', '1.0.0', deps: {'bar': '^2.0.0'})
+        ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'})
+        ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'})
+        ..serve('bar', '2.0.0', deps: {'foo': '^2.0.0'}),
+    );
 
     await d.dir(appPath, [
       d.pubspec({
@@ -381,7 +391,7 @@
   testWithGolden(
       'latest version reported while locked on a prerelease can be a prerelease',
       (ctx) async {
-    await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '0.9.0')
       ..serve('foo', '1.0.0-dev.1')
       ..serve('foo', '1.0.0-dev.2')
@@ -390,7 +400,7 @@
       ..serve('bar', '1.0.0-dev.2')
       ..serve('mop', '0.10.0-dev')
       ..serve('mop', '0.10.0')
-      ..serve('mop', '1.0.0-dev');
+      ..serve('mop', '1.0.0-dev'));
     await d.dir(appPath, [
       d.pubspec({
         'name': 'app',
@@ -409,7 +419,7 @@
   });
 
   testWithGolden('Handles SDK dependencies', (ctx) async {
-    await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.0.0', pubspec: {
         'environment': {'sdk': '>=2.10.0 <3.0.0'}
       })
@@ -418,7 +428,7 @@
       })
       ..serve('foo', '2.0.0', pubspec: {
         'environment': {'sdk': '>=2.12.0 <3.0.0'}
-      });
+      }));
 
     await d.dir('flutter-root', [
       d.file('version', '1.2.3'),
diff --git a/test/package_config_file_test.dart b/test/package_config_file_test.dart
index 763ce42..82882ae 100644
--- a/test/package_config_file_test.dart
+++ b/test/package_config_file_test.dart
@@ -12,12 +12,13 @@
 void main() {
   forBothPubGetAndUpgrade((command) {
     test('package_config.json file is created', () async {
-      await servePackages()
-        ..serve('foo', '1.2.3',
-            deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])])
-        ..serve('bar', '3.2.1', contents: [d.dir('lib', [])])
-        ..serve('baz', '2.2.2',
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3',
+            deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]);
+        builder.serve('bar', '3.2.1', contents: [d.dir('lib', [])]);
+        builder.serve('baz', '2.2.2',
             deps: {'bar': '3.2.1'}, contents: [d.dir('lib', [])]);
+      });
 
       await d.dir(appPath, [
         d.appPubspec({'foo': '1.2.3'}),
@@ -53,12 +54,13 @@
     });
 
     test('package_config.json file is overwritten', () async {
-      await servePackages()
-        ..serve('foo', '1.2.3',
-            deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])])
-        ..serve('bar', '3.2.1', contents: [d.dir('lib', [])])
-        ..serve('baz', '2.2.2',
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3',
+            deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]);
+        builder.serve('bar', '3.2.1', contents: [d.dir('lib', [])]);
+        builder.serve('baz', '2.2.2',
             deps: {'bar': '3.2.1'}, contents: [d.dir('lib', [])]);
+      });
 
       await d.dir(appPath, [
         d.appPubspec({'foo': '1.2.3'}),
@@ -115,8 +117,6 @@
           args: ['--offline'], error: equalsIgnoringWhitespace("""
             Because myapp depends on foo any which doesn't exist (could not find
               package foo in cache), version solving failed.
-
-            Try again without --offline!
           """), exitCode: exit_codes.UNAVAILABLE);
 
       await d.dir(appPath, [
@@ -127,10 +127,11 @@
     test(
         '.dart_tool/package_config.json file has relative path to path dependency',
         () async {
-      await servePackages()
-        ..serve('foo', '1.2.3',
-            deps: {'baz': 'any'}, contents: [d.dir('lib', [])])
-        ..serve('baz', '9.9.9', deps: {}, contents: [d.dir('lib', [])]);
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3',
+            deps: {'baz': 'any'}, contents: [d.dir('lib', [])]);
+        builder.serve('baz', '9.9.9', deps: {}, contents: [d.dir('lib', [])]);
+      });
 
       await d.dir('local_baz', [
         d.libDir('baz', 'baz 3.2.1'),
@@ -177,17 +178,18 @@
     });
 
     test('package_config.json has language version', () async {
-      final server = await servePackages();
-      server.serve(
-        'foo',
-        '1.2.3',
-        pubspec: {
-          'environment': {
-            'sdk': '>=0.0.1 <=0.2.2+2', // tests runs with '0.1.2+3'
+      await servePackages((builder) {
+        builder.serve(
+          'foo',
+          '1.2.3',
+          pubspec: {
+            'environment': {
+              'sdk': '>=0.0.1 <=0.2.2+2', // tests runs with '0.1.2+3'
+            },
           },
-        },
-        contents: [d.dir('lib', [])],
-      );
+          contents: [d.dir('lib', [])],
+        );
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -221,17 +223,18 @@
     });
 
     test('package_config.json has 2.7 default language version', () async {
-      final server = await servePackages();
-      server.serve(
-        'foo',
-        '1.2.3',
-        pubspec: {
-          'environment': {
-            'sdk': 'any',
+      await servePackages((builder) {
+        builder.serve(
+          'foo',
+          '1.2.3',
+          pubspec: {
+            'environment': {
+              'sdk': 'any',
+            },
           },
-        },
-        contents: [d.dir('lib', [])],
-      );
+          contents: [d.dir('lib', [])],
+        );
+      });
 
       await d.dir(appPath, [
         d.pubspec({
diff --git a/test/package_server.dart b/test/package_server.dart
index 952c189..12b542a 100644
--- a/test/package_server.dart
+++ b/test/package_server.dart
@@ -4,156 +4,160 @@
 
 import 'dart:async';
 import 'dart:convert';
-import 'dart:io';
 
 import 'package:path/path.dart' as p;
-import 'package:pub/src/third_party/tar/tar.dart';
 import 'package:pub_semver/pub_semver.dart';
 import 'package:shelf/shelf.dart' as shelf;
-import 'package:shelf/shelf_io.dart' as shelf_io;
 import 'package:test/test.dart';
 import 'package:test/test.dart' as test show expect;
 
 import 'descriptor.dart' as d;
 import 'test_pub.dart';
 
+/// The current global [PackageServer].
+PackageServer? get globalPackageServer => _globalPackageServer;
+PackageServer? _globalPackageServer;
+
+/// Creates an HTTP server that replicates the structure of pub.dartlang.org and
+/// makes it the current [globalServer].
+///
+/// Calls [callback] with a [PackageServerBuilder] that's used to specify
+/// which packages to serve.
+Future servePackages([void Function(PackageServerBuilder)? callback]) async {
+  _globalPackageServer = await PackageServer.start(callback ?? (_) {});
+  globalServer = _globalPackageServer!._inner;
+
+  addTearDown(() {
+    _globalPackageServer = null;
+  });
+}
+
+/// Like [servePackages], but instead creates an empty server with no packages
+/// registered.
+///
+/// This will always replace a previous server.
+Future serveNoPackages() => servePackages((_) {});
+
+/// Sets up the global package server to report an error on any request.
+///
+/// If no server has been set up, an empty server will be started.
+Future serveErrors() async {
+  var packageServer = globalPackageServer;
+  if (packageServer == null) {
+    await serveNoPackages();
+  } else {
+    packageServer.serveErrors();
+  }
+}
+
 class PackageServer {
   /// The inner [DescriptorServer] that this uses to serve its descriptors.
-  final shelf.Server _inner;
+  final DescriptorServer _inner;
 
-  /// Handlers of requests. Last matching handler will be used.
-  final List<_PatternAndHandler> _handlers = [];
+  /// The [d.DirectoryDescriptor] describing the server layout of
+  /// `/api/packages` on the test server.
+  ///
+  /// This contains metadata for packages that are being served via
+  /// [servePackages].
+  final _servedApiPackageDir = d.dir('packages', []);
 
-  // A list of all the requests recieved up till now.
-  final List<String> requestedPaths = <String>[];
+  /// The [d.DirectoryDescriptor] describing the server layout of `/packages` on
+  /// the test server.
+  ///
+  /// This contains the tarballs for packages that are being served via
+  /// [servePackages].
+  final _servedPackageDir = d.dir('packages', []);
 
-  PackageServer._(this._inner) {
-    _inner.mount((request) {
-      final path = request.url.path;
-      requestedPaths.add(path);
+  /// The current [PackageServerBuilder] that a user uses to specify which
+  /// package to serve.
+  ///
+  /// This is preserved so that additional packages can be added.
+  late final PackageServerBuilder _builder;
 
-      final pathWithInitialSlash = '/$path';
-      for (final entry in _handlers.reversed) {
-        final match = entry.pattern.matchAsPrefix(pathWithInitialSlash);
-        if (match != null && match.end == pathWithInitialSlash.length) {
-          final a = entry.handler(request);
-          return a;
-        }
-      }
-      return shelf.Response.notFound('Could not find ${request.url}');
-    });
-  }
+  /// The port used for the server.
+  int get port => _inner.port;
 
-  static final _versionInfoPattern = RegExp(r'/api/packages/([a-zA-Z_0-9]*)');
-  static final _downloadPattern =
-      RegExp(r'/packages/([^/]*)/versions/([^/]*).tar.gz');
+  /// The URL for the server.
+  String get url => 'http://localhost:$port';
 
-  static Future<PackageServer> start() async {
-    final server =
-        PackageServer._(await shelf_io.IOServer.bind('localhost', 0));
-    server.handle(
-      _versionInfoPattern,
-      (shelf.Request request) {
-        final parts = request.url.pathSegments;
-        assert(parts[0] == 'api');
-        assert(parts[1] == 'packages');
-        final name = parts[2];
+  /// Handlers for requests not easily described as packages.
+  Map<Pattern, shelf.Handler> get extraHandlers => _inner.extraHandlers;
 
-        final package = server._packages[name];
-        if (package == null) {
-          return shelf.Response.notFound('No package named $name');
-        }
-        return shelf.Response.ok(jsonEncode({
-          'name': name,
-          'uploaders': ['nweiz@google.com'],
-          'versions': package.versions.values
-              .map((version) => packageVersionApiMap(
-                    server._inner.url.toString(),
-                    version.pubspec,
-                    retracted: version.isRetracted,
-                  ))
-              .toList(),
-          if (package.isDiscontinued) 'isDiscontinued': true,
-          if (package.discontinuedReplacementText != null)
-            'replacedBy': package.discontinuedReplacementText,
-        }));
-      },
-    );
+  /// From now on report errors on any request.
+  void serveErrors() => extraHandlers
+    ..clear()
+    ..[RegExp('.*')] = (request) {
+      fail('The HTTP server received an unexpected request:\n'
+          '${request.method} ${request.requestedUri}');
+    };
 
-    server.handle(
-      _downloadPattern,
-      (shelf.Request request) {
-        final parts = request.url.pathSegments;
-        assert(parts[0] == 'packages');
-        final name = parts[1];
-        assert(parts[2] == 'versions');
-        final package = server._packages[name];
-        if (package == null) {
-          return shelf.Response.notFound('No package $name');
-        }
-
-        final version = Version.parse(
-            parts[3].substring(0, parts[3].length - '.tar.gz'.length));
-        assert(parts[3].endsWith('.tar.gz'));
-
-        for (final packageVersion in package.versions.values) {
-          if (packageVersion.version == version) {
-            return shelf.Response.ok(packageVersion.contents());
-          }
-        }
-        return shelf.Response.notFound('No version $version of $name');
-      },
-    );
+  /// Creates an HTTP server that replicates the structure of pub.dartlang.org.
+  ///
+  /// Calls [callback] with a [PackageServerBuilder] that's used to specify
+  /// which packages to serve.
+  static Future<PackageServer> start(
+      void Function(PackageServerBuilder) callback) async {
+    var descriptorServer = await DescriptorServer.start();
+    var server = PackageServer._(descriptorServer);
+    descriptorServer.contents
+      ..add(d.dir('api', [server._servedApiPackageDir]))
+      ..add(server._servedPackageDir);
+    server.add(callback);
     return server;
   }
 
-  Future<void> close() async {
-    await _inner.close();
+  PackageServer._(this._inner) {
+    _builder = PackageServerBuilder._(this);
   }
 
-  /// The port used for the server.
-  int get port => _inner.url.port;
+  /// Add to the current set of packages that are being served.
+  void add(void Function(PackageServerBuilder) callback) {
+    callback(_builder);
 
-  /// The URL for the server.
-  String get url => _inner.url.toString();
+    _servedApiPackageDir.contents.clear();
+    _servedPackageDir.contents.clear();
 
-  /// From now on report errors on any request.
-  void serveErrors() => _handlers
-    ..clear()
-    ..add(
-      _PatternAndHandler(
-        RegExp('.*'),
-        (request) {
-          fail('The HTTP server received an unexpected request:\n'
-              '${request.method} ${request.requestedUri}');
-        },
-      ),
-    );
+    _builder._packages.forEach((name, package) {
+      _servedApiPackageDir.contents.addAll([
+        d.file(
+            name,
+            jsonEncode({
+              'name': name,
+              'uploaders': ['nweiz@google.com'],
+              'versions': package.versions.values
+                  .map((version) => packageVersionApiMap(url, version.pubspec,
+                      retracted: version.isRetracted))
+                  .toList(),
+              if (package.isDiscontinued) 'isDiscontinued': true,
+              if (package.discontinuedReplacementText != null)
+                'replacedBy': package.discontinuedReplacementText,
+            })),
+        d.dir(name, [
+          d.dir('versions', package.versions.values.map((version) {
+            return d.file(
+                version.version.toString(),
+                jsonEncode(packageVersionApiMap(url, version.pubspec,
+                    retracted: version.isRetracted, full: true)));
+          }))
+        ])
+      ]);
 
-  void handle(Pattern pattern, shelf.Handler handler) {
-    _handlers.add(
-      _PatternAndHandler(
-        pattern,
-        handler,
-      ),
-    );
+      _servedPackageDir.contents.add(d.dir(name, [
+        d.dir(
+            'versions',
+            package.versions.values.map((version) =>
+                d.tar('${version.version}.tar.gz', version.contents)))
+      ]));
+    });
   }
 
   // Installs a handler at [pattern] that expects to be called exactly once with
   // the given [method].
-  //
-  // The handler is installed as the start to give it priority over more general
-  // handlers.
   void expect(String method, Pattern pattern, shelf.Handler handler) {
-    handle(
-      pattern,
-      expectAsync1(
-        (request) {
-          test.expect(request.method, method);
-          return handler(request);
-        },
-      ),
-    );
+    extraHandlers[pattern] = expectAsync1((request) {
+      test.expect(request.method, method);
+      return handler(request);
+    });
   }
 
   /// Returns the path of [package] at [version], installed from this server, in
@@ -165,9 +169,26 @@
   String get cachingPath =>
       p.join(d.sandbox, cachePath, 'hosted', 'localhost%58$port');
 
+  /// Replace the current set of packages that are being served.
+  void replace(void Function(PackageServerBuilder) callback) {
+    _builder._clear();
+    add(callback);
+  }
+}
+
+/// A builder for specifying which packages should be served by [servePackages].
+class PackageServerBuilder {
   /// A map from package names to the concrete packages to serve.
   final _packages = <String, _ServedPackage>{};
 
+  /// The package server that this builder is associated with.
+  final PackageServer _server;
+
+  /// The URL for the server that this builder is associated with.
+  String get serverUrl => _server.url;
+
+  PackageServerBuilder._(this._server);
+
   /// Specifies that a package named [name] with [version] should be served.
   ///
   /// If [deps] is passed, it's used as the "dependencies" field of the pubspec.
@@ -187,44 +208,7 @@
     contents = [d.file('pubspec.yaml', yaml(pubspecFields)), ...contents];
 
     var package = _packages.putIfAbsent(name, () => _ServedPackage());
-    package.versions[version] = _ServedPackageVersion(
-      pubspecFields,
-      contents: () {
-        final entries = <TarEntry>[];
-
-        void addDescriptor(d.Descriptor descriptor, String path) {
-          if (descriptor is d.DirectoryDescriptor) {
-            for (final e in descriptor.contents) {
-              addDescriptor(e, p.posix.join(path, descriptor.name));
-            }
-          } else {
-            entries.add(
-              TarEntry(
-                TarHeader(
-                  // Ensure paths in tar files use forward slashes
-                  name: p.posix.join(path, descriptor.name),
-                  // We want to keep executable bits, but otherwise use the default
-                  // file mode
-                  mode: 420,
-                  // size: 100,
-                  modified: DateTime.now(),
-                  userName: 'pub',
-                  groupName: 'pub',
-                ),
-                (descriptor as d.FileDescriptor).readAsBytes(),
-              ),
-            );
-          }
-        }
-
-        for (final e in contents ?? <d.Descriptor>[]) {
-          addDescriptor(e, '');
-        }
-        return Stream.fromIterable(entries)
-            .transform(tarWriterWith(format: OutputFormat.gnuLongName))
-            .transform(gzip.encoder);
-      },
-    );
+    package.versions[version] = _ServedPackageVersion(pubspecFields, contents);
   }
 
   // Mark a package discontinued.
@@ -236,7 +220,7 @@
   }
 
   /// Clears all existing packages from this builder.
-  void clearPackages() {
+  void _clear() {
     _packages.clear();
   }
 
@@ -254,17 +238,10 @@
 /// A package that's intended to be served.
 class _ServedPackageVersion {
   final Map pubspec;
-  final Stream<List<int>> Function() contents;
+  final List<d.Descriptor> contents;
   bool isRetracted = false;
 
   Version get version => Version.parse(pubspec['version']);
 
-  _ServedPackageVersion(this.pubspec, {required this.contents});
-}
-
-class _PatternAndHandler {
-  Pattern pattern;
-  shelf.Handler handler;
-
-  _PatternAndHandler(this.pattern, this.handler);
+  _ServedPackageVersion(this.pubspec, this.contents);
 }
diff --git a/test/packages_file_test.dart b/test/packages_file_test.dart
index c245a9a..67ca572 100644
--- a/test/packages_file_test.dart
+++ b/test/packages_file_test.dart
@@ -11,20 +11,21 @@
 
 void main() {
   forBothPubGetAndUpgrade((command) {
-    test('.packages file is created with flag', () async {
-      await servePackages()
-        ..serve('foo', '1.2.3',
-            deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])])
-        ..serve('bar', '3.2.1', contents: [d.dir('lib', [])])
-        ..serve('baz', '2.2.2',
+    test('.packages file is created', () async {
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3',
+            deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]);
+        builder.serve('bar', '3.2.1', contents: [d.dir('lib', [])]);
+        builder.serve('baz', '2.2.2',
             deps: {'bar': '3.2.1'}, contents: [d.dir('lib', [])]);
+      });
 
       await d.dir(appPath, [
         d.appPubspec({'foo': '1.2.3'}),
         d.dir('lib')
       ]).create();
 
-      await pubCommand(command, args: ['--legacy-packages-file']);
+      await pubCommand(command);
 
       await d.dir(appPath, [
         d.packagesFile(
@@ -32,13 +33,14 @@
       ]).validate();
     });
 
-    test('.packages file is overwritten with flag', () async {
-      await servePackages()
-        ..serve('foo', '1.2.3',
-            deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])])
-        ..serve('bar', '3.2.1', contents: [d.dir('lib', [])])
-        ..serve('baz', '2.2.2',
+    test('.packages file is overwritten', () async {
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3',
+            deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]);
+        builder.serve('bar', '3.2.1', contents: [d.dir('lib', [])]);
+        builder.serve('baz', '2.2.2',
             deps: {'bar': '3.2.1'}, contents: [d.dir('lib', [])]);
+      });
 
       await d.dir(appPath, [
         d.appPubspec({'foo': '1.2.3'}),
@@ -51,7 +53,7 @@
       await oldFile.create();
       await oldFile.validate(); // Sanity-check that file was created correctly.
 
-      await pubCommand(command, args: ['--legacy-packages-file']);
+      await pubCommand(command);
 
       await d.dir(appPath, [
         d.packagesFile(
@@ -59,32 +61,27 @@
       ]).validate();
     });
 
-    test('.packages file is not created if pub command fails with flag',
-        () async {
+    test('.packages file is not created if pub command fails', () async {
       await d.dir(appPath, [
         d.appPubspec({'foo': '1.2.3'}),
         d.dir('lib')
       ]).create();
 
       await pubCommand(command,
-          args: ['--offline', '--legacy-packages-file'],
-          error: equalsIgnoringWhitespace("""
+          args: ['--offline'], error: equalsIgnoringWhitespace("""
             Because myapp depends on foo any which doesn't exist (could not find
               package foo in cache), version solving failed.
-
-            Try again without --offline!
-          """),
-          exitCode: exit_codes.UNAVAILABLE);
+          """), exitCode: exit_codes.UNAVAILABLE);
 
       await d.dir(appPath, [d.nothing('.packages')]).validate();
     });
 
-    test('.packages file has relative path to path dependency with flag',
-        () async {
-      await servePackages()
-        ..serve('foo', '1.2.3',
-            deps: {'baz': 'any'}, contents: [d.dir('lib', [])])
-        ..serve('baz', '9.9.9', deps: {}, contents: [d.dir('lib', [])]);
+    test('.packages file has relative path to path dependency', () async {
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3',
+            deps: {'baz': 'any'}, contents: [d.dir('lib', [])]);
+        builder.serve('baz', '9.9.9', deps: {}, contents: [d.dir('lib', [])]);
+      });
 
       await d.dir('local_baz', [
         d.libDir('baz', 'baz 3.2.1'),
@@ -104,7 +101,7 @@
         d.dir('lib')
       ]).create();
 
-      await pubCommand(command, args: ['--legacy-packages-file']);
+      await pubCommand(command);
 
       await d.dir(appPath, [
         d.packagesFile({'myapp': '.', 'baz': '../local_baz', 'foo': '1.2.3'}),
diff --git a/test/pub_get_and_upgrade_test.dart b/test/pub_get_and_upgrade_test.dart
index f64f93b..62004a4 100644
--- a/test/pub_get_and_upgrade_test.dart
+++ b/test/pub_get_and_upgrade_test.dart
@@ -45,8 +45,7 @@
       await pubCommand(command);
 
       await d.dir('myapp', [
-        d.packageConfigFile(
-            [d.packageConfigEntry(name: 'myapp_name', path: '.')]),
+        d.packagesFile({'myapp_name': '.'})
       ]).validate();
     });
 
diff --git a/test/pub_uploader_test.dart b/test/pub_uploader_test.dart
index 47d50d3..daec6bc 100644
--- a/test/pub_uploader_test.dart
+++ b/test/pub_uploader_test.dart
@@ -40,11 +40,12 @@
 
   test('adds an uploader', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
     var pub = await startPubUploader(
-        globalServer, ['--package', 'pkg', 'add', 'email']);
+        globalPackageServer!, ['--package', 'pkg', 'add', 'email']);
 
-    globalServer.expect('POST', '/api/packages/pkg/uploaders', (request) {
+    globalPackageServer!.expect('POST', '/api/packages/pkg/uploaders',
+        (request) {
       return request.readAsString().then((body) {
         expect(body, equals('email=email'));
 
@@ -62,11 +63,11 @@
 
   test('removes an uploader', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
     var pub = await startPubUploader(
-        globalServer, ['--package', 'pkg', 'remove', 'email']);
+        globalPackageServer!, ['--package', 'pkg', 'remove', 'email']);
 
-    globalServer.expect('DELETE', '/api/packages/pkg/uploaders/email',
+    globalPackageServer!.expect('DELETE', '/api/packages/pkg/uploaders/email',
         (request) {
       return shelf.Response.ok(
           jsonEncode({
@@ -83,10 +84,11 @@
     await d.validPackage.create();
 
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
-    var pub = await startPubUploader(globalServer, ['add', 'email']);
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
+    var pub = await startPubUploader(globalPackageServer!, ['add', 'email']);
 
-    globalServer.expect('POST', '/api/packages/test_pkg/uploaders', (request) {
+    globalPackageServer!.expect('POST', '/api/packages/test_pkg/uploaders',
+        (request) {
       return shelf.Response.ok(
           jsonEncode({
             'success': {'message': 'Good job!'}
@@ -100,11 +102,12 @@
 
   test('add provides an error', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
     var pub = await startPubUploader(
-        globalServer, ['--package', 'pkg', 'add', 'email']);
+        globalPackageServer!, ['--package', 'pkg', 'add', 'email']);
 
-    globalServer.expect('POST', '/api/packages/pkg/uploaders', (request) {
+    globalPackageServer!.expect('POST', '/api/packages/pkg/uploaders',
+        (request) {
       return shelf.Response(400,
           body: jsonEncode({
             'error': {'message': 'Bad job!'}
@@ -118,12 +121,12 @@
 
   test('remove provides an error', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
     var pub = await startPubUploader(
-        globalServer, ['--package', 'pkg', 'remove', 'e/mail']);
+        globalPackageServer!, ['--package', 'pkg', 'remove', 'e/mail']);
 
-    globalServer.expect('DELETE', '/api/packages/pkg/uploaders/e%2Fmail',
-        (request) {
+    globalPackageServer!
+        .expect('DELETE', '/api/packages/pkg/uploaders/e%2Fmail', (request) {
       return shelf.Response(400,
           body: jsonEncode({
             'error': {'message': 'Bad job!'}
@@ -137,11 +140,11 @@
 
   test('add provides invalid JSON', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
     var pub = await startPubUploader(
-        globalServer, ['--package', 'pkg', 'add', 'email']);
+        globalPackageServer!, ['--package', 'pkg', 'add', 'email']);
 
-    globalServer.expect('POST', '/api/packages/pkg/uploaders',
+    globalPackageServer!.expect('POST', '/api/packages/pkg/uploaders',
         (request) => shelf.Response.ok('{not json'));
 
     expect(
@@ -153,11 +156,11 @@
 
   test('remove provides invalid JSON', () async {
     await servePackages();
-    await d.credentialsFile(globalServer, 'access token').create();
+    await d.credentialsFile(globalPackageServer!, 'access token').create();
     var pub = await startPubUploader(
-        globalServer, ['--package', 'pkg', 'remove', 'email']);
+        globalPackageServer!, ['--package', 'pkg', 'remove', 'email']);
 
-    globalServer.expect('DELETE', '/api/packages/pkg/uploaders/email',
+    globalPackageServer!.expect('DELETE', '/api/packages/pkg/uploaders/email',
         (request) => shelf.Response.ok('{not json'));
 
     expect(
diff --git a/test/rate_limited_scheduler_test.dart b/test/rate_limited_scheduler_test.dart
index 8562b07..e94bbc7 100644
--- a/test/rate_limited_scheduler_test.dart
+++ b/test/rate_limited_scheduler_test.dart
@@ -4,6 +4,7 @@
 
 import 'dart:async';
 
+import 'package:pedantic/pedantic.dart';
 import 'package:pub/src/rate_limited_scheduler.dart';
 import 'package:test/test.dart';
 
diff --git a/test/remove/remove_test.dart b/test/remove/remove_test.dart
index 8c82527..52194c9 100644
--- a/test/remove/remove_test.dart
+++ b/test/remove/remove_test.dart
@@ -12,8 +12,7 @@
 
 void main() {
   test('removes a package from dependencies', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
     await d.appDir({'foo': '1.2.3'}).create();
     await pubGet();
@@ -21,16 +20,17 @@
     await pubRemove(args: ['foo']);
 
     await d.cacheDir({}).validate();
-    await d.appPackageConfigFile([]).validate();
+    await d.appPackagesFile({}).validate();
     await d.appDir().validate();
   });
 
   test('removing a package from dependencies does not affect dev_dependencies',
       () async {
-    await servePackages()
-      ..serve('foo', '1.2.3')
-      ..serve('foo', '1.2.2')
-      ..serve('bar', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.3');
+      builder.serve('foo', '1.2.2');
+      builder.serve('bar', '2.0.0');
+    });
 
     await d.dir(appPath, [
       d.file('pubspec.yaml', '''
@@ -49,9 +49,7 @@
     await pubRemove(args: ['foo']);
 
     await d.cacheDir({'bar': '2.0.0'}).validate();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'bar', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'bar': '2.0.0'}).validate();
 
     await d.dir(appPath, [
       d.pubspec({
@@ -62,8 +60,7 @@
   });
 
   test('dry-run does not actually remove dependency', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
     await d.appDir({'foo': '1.2.3'}).create();
     await pubGet();
@@ -101,8 +98,7 @@
   });
 
   test('removes a package from dev_dependencies', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.2.3');
+    await servePackages((builder) => builder.serve('foo', '1.2.3'));
 
     await d.dir(appPath, [
       d.pubspec({
@@ -115,7 +111,7 @@
     await pubRemove(args: ['foo']);
 
     await d.cacheDir({}).validate();
-    await d.appPackageConfigFile([]).validate();
+    await d.appPackagesFile({}).validate();
 
     await d.dir(appPath, [
       d.pubspec({'name': 'myapp'})
@@ -124,11 +120,12 @@
 
   test('removes multiple packages from dependencies and dev_dependencies',
       () async {
-    await servePackages()
-      ..serve('foo', '1.2.3')
-      ..serve('bar', '2.3.4')
-      ..serve('baz', '3.2.1')
-      ..serve('jfj', '0.2.1');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.3');
+      builder.serve('bar', '2.3.4');
+      builder.serve('baz', '3.2.1');
+      builder.serve('jfj', '0.2.1');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -142,10 +139,7 @@
     await pubRemove(args: ['foo', 'bar', 'baz']);
 
     await d.cacheDir({'jfj': '0.2.1'}).validate();
-
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'jfj', version: '0.2.1'),
-    ]).validate();
+    await d.appPackagesFile({'jfj': '0.2.1'}).validate();
 
     await d.dir(appPath, [
       d.pubspec({
@@ -156,8 +150,7 @@
   });
 
   test('removes git dependencies', () async {
-    final server = await servePackages();
-    server.serve('bar', '1.2.3');
+    await servePackages((builder) => builder.serve('bar', '1.2.3'));
 
     ensureGit();
     final repo = d.git('foo.git', [
@@ -175,16 +168,12 @@
     await pubGet();
 
     await pubRemove(args: ['foo']);
-
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'bar', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'bar': '1.2.3'}).validate();
     await d.appDir({'bar': '1.2.3'}).validate();
   });
 
   test('removes path dependencies', () async {
-    final server = await servePackages();
-    server.serve('bar', '1.2.3');
+    await servePackages((builder) => builder.serve('bar', '1.2.3'));
     await d
         .dir('foo', [d.libDir('foo'), d.libPubspec('foo', '0.0.1')]).create();
 
@@ -196,23 +185,21 @@
     await pubGet();
 
     await pubRemove(args: ['foo']);
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'bar', version: '1.2.3'),
-    ]).validate();
+    await d.appPackagesFile({'bar': '1.2.3'}).validate();
     await d.appDir({'bar': '1.2.3'}).validate();
   });
 
   test('removes hosted dependencies', () async {
-    final server = await servePackages();
-    server.serve('bar', '2.0.1');
+    await servePackages((builder) => builder.serve('bar', '2.0.1'));
 
-    var custom = await startPackageServer();
-    custom.serve('foo', '1.2.3');
+    var server = await PackageServer.start((builder) {
+      builder.serve('foo', '1.2.3');
+    });
 
     await d.appDir({
       'foo': {
         'version': '1.2.3',
-        'hosted': {'name': 'foo', 'url': 'http://localhost:${custom.port}'}
+        'hosted': {'name': 'foo', 'url': 'http://localhost:${server.port}'}
       },
       'bar': '2.0.1'
     }).create();
@@ -220,16 +207,15 @@
     await pubGet();
 
     await pubRemove(args: ['foo']);
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'bar', version: '2.0.1'),
-    ]).validate();
+    await d.appPackagesFile({'bar': '2.0.1'}).validate();
     await d.appDir({'bar': '2.0.1'}).validate();
   });
 
   test('preserves comments', () async {
-    await servePackages()
-      ..serve('bar', '1.0.0')
-      ..serve('foo', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('bar', '1.0.0');
+      builder.serve('foo', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.file('pubspec.yaml', '''
diff --git a/test/run/allows_dart_extension_test.dart b/test/run/allows_dart_extension_test.dart
index 962270f..27640fc 100644
--- a/test/run/allows_dart_extension_test.dart
+++ b/test/run/allows_dart_extension_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const _script = """
+const SCRIPT = """
 import 'dart:io';
 
 main() {
@@ -21,7 +21,7 @@
   test('allows a ".dart" extension on the argument', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('script.dart', _script)])
+      d.dir('bin', [d.file('script.dart', SCRIPT)])
     ]).create();
 
     await pubGet();
diff --git a/test/run/forwards_signal_posix_test.dart b/test/run/forwards_signal_posix_test.dart
index 5205145..1a32be8 100644
--- a/test/run/forwards_signal_posix_test.dart
+++ b/test/run/forwards_signal_posix_test.dart
@@ -23,7 +23,7 @@
   ProcessSignal.sigwinch,
 ];
 
-const _script = """
+const SCRIPT = """
 import 'dart:io';
 
 main() {
@@ -41,7 +41,7 @@
   test('forwards signals to the inner script', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('script.dart', _script)])
+      d.dir('bin', [d.file('script.dart', SCRIPT)])
     ]).create();
 
     await pubGet();
diff --git a/test/run/includes_parent_directories_of_entrypoint_test.dart b/test/run/includes_parent_directories_of_entrypoint_test.dart
index 6bc4e27..d351ac4 100644
--- a/test/run/includes_parent_directories_of_entrypoint_test.dart
+++ b/test/run/includes_parent_directories_of_entrypoint_test.dart
@@ -8,7 +8,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const _script = r"""
+const SCRIPT = r"""
 import '../../a.dart';
 import '../b.dart';
 main() {
@@ -26,7 +26,7 @@
         d.file('a.dart', "var a = 'a';"),
         d.dir('a', [
           d.file('b.dart', "var b = 'b';"),
-          d.dir('b', [d.file('app.dart', _script)])
+          d.dir('b', [d.file('app.dart', SCRIPT)])
         ])
       ])
     ]).create();
diff --git a/test/run/package_api_test.dart b/test/run/package_api_test.dart
index 4d05408..161cbf9 100644
--- a/test/run/package_api_test.dart
+++ b/test/run/package_api_test.dart
@@ -49,10 +49,11 @@
   });
 
   test('a snapshotted application sees a file: package root', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', contents: [
-      d.dir('bin', [d.file('script.dart', _script)])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', contents: [
+        d.dir('bin', [d.file('script.dart', _script)])
+      ]);
+    });
 
     await d.dir(appPath, [
       d.appPubspec({'foo': 'any'})
@@ -72,8 +73,8 @@
             .toString()));
     expect(pub.stdout,
         emits(p.toUri(p.join(d.sandbox, 'myapp/lib/resource.txt')).toString()));
-    var fooResourcePath =
-        p.join(globalServer.pathInCache('foo', '1.0.0'), 'lib/resource.txt');
+    var fooResourcePath = p.join(
+        globalPackageServer!.pathInCache('foo', '1.0.0'), 'lib/resource.txt');
     expect(pub.stdout, emits(p.toUri(fooResourcePath).toString()));
     await pub.shouldExit(0);
   });
diff --git a/test/run/passes_along_arguments_test.dart b/test/run/passes_along_arguments_test.dart
index 624d9f2..66a7d53 100644
--- a/test/run/passes_along_arguments_test.dart
+++ b/test/run/passes_along_arguments_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const _script = '''
+const SCRIPT = '''
 main(List<String> args) {
   print(args.join(" "));
 }
@@ -17,7 +17,7 @@
   test('passes arguments to the spawned script', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('args.dart', _script)])
+      d.dir('bin', [d.file('args.dart', SCRIPT)])
     ]).create();
 
     await pubGet();
diff --git a/test/run/precompile_test.dart b/test/run/precompile_test.dart
index 2d70b4c..ef8787d 100644
--- a/test/run/precompile_test.dart
+++ b/test/run/precompile_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const _script = r'''
+const SCRIPT = r'''
 import 'dart:io';
 
 main(List<String> args) {
@@ -21,11 +21,11 @@
       d.appPubspec({'test': '1.0.0'}),
     ]).create();
 
-    final server = await servePackages();
-    server.serve('test', '1.0.0', contents: [
-      d.dir('bin',
-          [d.file('test.dart', 'main(List<String> args) => print("hello");')])
-    ]);
+    await servePackages((server) => server
+      ..serve('test', '1.0.0', contents: [
+        d.dir('bin',
+            [d.file('test.dart', 'main(List<String> args) => print("hello");')])
+      ]));
 
     await pubGet(args: ['--no-precompile']);
   }
@@ -57,10 +57,10 @@
       d.appPubspec({'test': '1.0.0'}),
     ]).create();
 
-    final server = await servePackages();
-    server.serve('test', '1.0.0', contents: [
-      d.dir('bin', [d.file('test.dart', _script)])
-    ]);
+    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'});
@@ -80,10 +80,10 @@
       d.appPubspec({'test': '1.0.0'}),
     ]).create();
 
-    final server = await servePackages();
-    server.serve('test', '1.0.0', contents: [
-      d.dir('bin', [d.file('test.dart', _script)])
-    ]);
+    await servePackages((server) => server
+      ..serve('test', '1.0.0', contents: [
+        d.dir('bin', [d.file('test.dart', SCRIPT)])
+      ]));
 
     await pubGet(
         args: ['--precompile'],
@@ -104,10 +104,10 @@
       d.appPubspec({'test': '1.0.0'}),
     ]).create();
 
-    final server = await servePackages();
-    server.serve('test', '1.0.0', contents: [
-      d.dir('bin', [d.file('test.dart', _script)])
-    ]);
+    await servePackages((server) => server
+      ..serve('test', '1.0.0', contents: [
+        d.dir('bin', [d.file('test.dart', SCRIPT)])
+      ]));
 
     await pubGet(
         args: ['--precompile'],
diff --git a/test/run/runs_app_in_entrypoint_test.dart b/test/run/runs_app_in_entrypoint_test.dart
index 6cb932a..27a7381 100644
--- a/test/run/runs_app_in_entrypoint_test.dart
+++ b/test/run/runs_app_in_entrypoint_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const _script = """
+const SCRIPT = """
 import 'dart:io';
 
 main() {
@@ -21,7 +21,7 @@
   test('runs a Dart application in the entrypoint package', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('script.dart', _script)])
+      d.dir('bin', [d.file('script.dart', SCRIPT)])
     ]).create();
 
     await pubGet();
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 c11bacb..f7e7c7a 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
@@ -10,13 +10,14 @@
 void main() {
   // Regression test for issue 23113
   test('runs a named Dart application in a dependency', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'name': 'foo',
-      'version': '1.0.0'
-    }, contents: [
-      d.dir('bin', [d.file('bar.dart', "main() => print('foobar');")])
-    ]);
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'name': 'foo',
+        'version': '1.0.0'
+      }, contents: [
+        d.dir('bin', [d.file('bar.dart', "main() => print('foobar');")])
+      ]);
+    });
 
     await d.dir(appPath, [
       d.appPubspec({'foo': null})
diff --git a/test/run/runs_the_script_in_unchecked_mode_test.dart b/test/run/runs_the_script_in_unchecked_mode_test.dart
index 026a748..2652706 100644
--- a/test/run/runs_the_script_in_unchecked_mode_test.dart
+++ b/test/run/runs_the_script_in_unchecked_mode_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const _script = '''
+const SCRIPT = '''
 main() {
   assert(false);
   print("no checks");
@@ -18,7 +18,7 @@
   test('runs the script without assertions by default', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('script.dart', _script)])
+      d.dir('bin', [d.file('script.dart', SCRIPT)])
     ]).create();
 
     await pubGet();
diff --git a/test/sdk_test.dart b/test/sdk_test.dart
index 6165cd5..3f3b00b 100644
--- a/test/sdk_test.dart
+++ b/test/sdk_test.dart
@@ -13,8 +13,9 @@
 void main() {
   forBothPubGetAndUpgrade((command) {
     setUp(() async {
-      final server = await servePackages();
-      server.serve('bar', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('bar', '1.0.0');
+      });
 
       await d.dir('flutter', [
         d.dir('packages', [
@@ -37,10 +38,13 @@
       }).create();
       await pubCommand(command,
           environment: {'FLUTTER_ROOT': p.join(d.sandbox, 'flutter')});
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(
-            name: 'foo', path: p.join(d.sandbox, 'flutter', 'packages', 'foo')),
-        d.packageConfigEntry(name: 'bar', version: '1.0.0'),
+
+      await d.dir(appPath, [
+        d.packagesFile({
+          'myapp': '.',
+          'foo': p.join(d.sandbox, 'flutter', 'packages', 'foo'),
+          'bar': '1.0.0'
+        })
       ]).validate();
     });
 
@@ -51,10 +55,11 @@
       await pubCommand(command,
           environment: {'FLUTTER_ROOT': p.join(d.sandbox, 'flutter')});
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(
-            name: 'baz',
-            path: p.join(d.sandbox, 'flutter', 'bin', 'cache', 'pkg', 'baz')),
+      await d.dir(appPath, [
+        d.packagesFile({
+          'myapp': '.',
+          'baz': p.join(d.sandbox, 'flutter', 'bin', 'cache', 'pkg', 'baz')
+        })
       ]).validate();
     });
 
@@ -89,7 +94,10 @@
       deleteEntry(p.join(d.sandbox, 'flutter', 'version'));
       await pubCommand(command,
           environment: {'FLUTTER_ROOT': p.join(d.sandbox, 'flutter')});
-      await d.appPackageConfigFile([]).validate();
+
+      await d.dir(appPath, [
+        d.packagesFile({'myapp': '.'})
+      ]).validate();
     });
 
     group('fails if', () {
@@ -162,10 +170,13 @@
       }).create();
       await pubCommand(command,
           environment: {'FUCHSIA_DART_SDK_ROOT': p.join(d.sandbox, 'fuchsia')});
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(
-            name: 'foo', path: p.join(d.sandbox, 'fuchsia', 'packages', 'foo')),
-        d.packageConfigEntry(name: 'bar', version: '1.0.0'),
+
+      await d.dir(appPath, [
+        d.packagesFile({
+          'myapp': '.',
+          'foo': p.join(d.sandbox, 'fuchsia', 'packages', 'foo'),
+          'bar': '1.0.0'
+        })
       ]).validate();
     });
   });
diff --git a/test/snapshot_test.dart b/test/snapshot_test.dart
index 8143f7e..215fcdf 100644
--- a/test/snapshot_test.dart
+++ b/test/snapshot_test.dart
@@ -11,15 +11,17 @@
 void main() {
   group('creates a snapshot', () {
     test('for an immediate dependency', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.2.3', contents: [
-        d.dir('bin', [
-          d.file('hello.dart', "void main() => print('hello!');"),
-          d.file('goodbye.dart', "void main() => print('goodbye!');"),
-          d.file('shell.sh', 'echo shell'),
-          d.dir('subdir', [d.file('sub.dart', "void main() => print('sub!');")])
-        ])
-      ]);
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3', contents: [
+          d.dir('bin', [
+            d.file('hello.dart', "void main() => print('hello!');"),
+            d.file('goodbye.dart', "void main() => print('goodbye!');"),
+            d.file('shell.sh', 'echo shell'),
+            d.dir(
+                'subdir', [d.file('sub.dart', "void main() => print('sub!');")])
+          ])
+        ]);
+      });
 
       await d.appDir({'foo': '1.2.3'}).create();
 
@@ -47,8 +49,8 @@
     });
 
     test("for an immediate dependency that's also transitive", () async {
-      await servePackages()
-        ..serve('foo', '1.2.3', contents: [
+      await servePackages((builder) {
+        builder.serve('foo', '1.2.3', contents: [
           d.dir('bin', [
             d.file('hello.dart', "void main() => print('hello!');"),
             d.file('goodbye.dart', "void main() => print('goodbye!');"),
@@ -56,8 +58,9 @@
             d.dir(
                 'subdir', [d.file('sub.dart', "void main() => print('sub!');")])
           ])
-        ])
-        ..serve('bar', '1.2.3', deps: {'foo': '1.2.3'});
+        ]);
+        builder.serve('bar', '1.2.3', deps: {'foo': '1.2.3'});
+      });
 
       await d.appDir({'foo': '1.2.3'}).create();
 
@@ -86,11 +89,12 @@
 
     group('again if', () {
       test('its package is updated', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.2.3', contents: [
-          d.dir(
-              'bin', [d.file('hello.dart', "void main() => print('hello!');")])
-        ]);
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3', contents: [
+            d.dir('bin',
+                [d.file('hello.dart', "void main() => print('hello!');")])
+          ]);
+        });
 
         await d.appDir({'foo': 'any'}).create();
 
@@ -101,10 +105,12 @@
           d.file('hello.dart-$versionSuffix.snapshot', contains('hello!'))
         ]).validate();
 
-        server.serve('foo', '1.2.4', contents: [
-          d.dir('bin',
-              [d.file('hello.dart', "void main() => print('hello 2!');")])
-        ]);
+        globalPackageServer!.add((builder) {
+          builder.serve('foo', '1.2.4', contents: [
+            d.dir('bin',
+                [d.file('hello.dart', "void main() => print('hello 2!');")])
+          ]);
+        });
 
         await pubUpgrade(
             args: ['--precompile'], output: contains('Built foo:hello.'));
@@ -119,22 +125,22 @@
       });
 
       test('a dependency of its package is updated', () async {
-        final server = await servePackages();
-
-        server.serve('foo', '1.2.3', pubspec: {
-          'dependencies': {'bar': 'any'}
-        }, contents: [
-          d.dir('bin', [
-            d.file('hello.dart', """
+        await servePackages((builder) {
+          builder.serve('foo', '1.2.3', pubspec: {
+            'dependencies': {'bar': 'any'}
+          }, contents: [
+            d.dir('bin', [
+              d.file('hello.dart', """
             import 'package:bar/bar.dart';
 
             void main() => print(message);
           """)
-          ])
-        ]);
-        server.serve('bar', '1.2.3', contents: [
-          d.dir('lib', [d.file('bar.dart', "final message = 'hello!';")])
-        ]);
+            ])
+          ]);
+          builder.serve('bar', '1.2.3', contents: [
+            d.dir('lib', [d.file('bar.dart', "final message = 'hello!';")])
+          ]);
+        });
 
         await d.appDir({'foo': 'any'}).create();
 
@@ -145,9 +151,11 @@
           d.file('hello.dart-$versionSuffix.snapshot', contains('hello!'))
         ]).validate();
 
-        server.serve('bar', '1.2.4', contents: [
-          d.dir('lib', [d.file('bar.dart', "final message = 'hello 2!';")]),
-        ]);
+        globalPackageServer!.add((builder) {
+          builder.serve('bar', '1.2.4', contents: [
+            d.dir('lib', [d.file('bar.dart', "final message = 'hello 2!';")]),
+          ]);
+        });
 
         await pubUpgrade(
             args: ['--precompile'], output: contains('Built foo:hello.'));
@@ -199,11 +207,12 @@
       });
 
       test('the SDK is out of date', () async {
-        final server = await servePackages();
-        server.serve('foo', '5.6.7', contents: [
-          d.dir(
-              'bin', [d.file('hello.dart', "void main() => print('hello!');")])
-        ]);
+        await servePackages((builder) {
+          builder.serve('foo', '5.6.7', contents: [
+            d.dir('bin',
+                [d.file('hello.dart', "void main() => print('hello!');")])
+          ]);
+        });
 
         await d.appDir({'foo': '5.6.7'}).create();
 
diff --git a/test/test_pub.dart b/test/test_pub.dart
index e30c590..22d8cfa 100644
--- a/test/test_pub.dart
+++ b/test/test_pub.dart
@@ -36,9 +36,11 @@
 import 'package:test_process/test_process.dart';
 
 import 'descriptor.dart' as d;
+import 'descriptor_server.dart';
 import 'package_server.dart';
 
-export 'package_server.dart' show PackageServer;
+export 'descriptor_server.dart';
+export 'package_server.dart';
 
 /// A [Matcher] that matches JavaScript generated by dart2js with minification
 /// enabled.
@@ -373,12 +375,11 @@
   List<String>? args,
   String authMethod = 'oauth2',
   Map<String, String>? environment,
-  String path = '',
 }) async {
   var tokenEndpoint = Uri.parse(server.url).resolve('/token').toString();
   args = ['lish', ...?args];
   return await startPub(args: args, tokenEndpoint: tokenEndpoint, environment: {
-    'PUB_HOSTED_URL': server.url + path,
+    'PUB_HOSTED_URL': server.url,
     '_PUB_TEST_AUTH_METHOD': authMethod,
     if (environment != null) ...environment,
   });
@@ -411,19 +412,29 @@
 String testVersion = '0.1.2+3';
 
 /// Gets the environment variables used to run pub in a test context.
-Map<String, String> getPubTestEnvironment([String? tokenEndpoint]) => {
-      'CI': 'false', // unless explicitly given tests don't run pub in CI mode
-      '_PUB_TESTING': 'true',
-      '_PUB_TEST_CONFIG_DIR': _pathInSandbox(configPath),
-      'PUB_CACHE': _pathInSandbox(cachePath),
-      'PUB_ENVIRONMENT': 'test-environment',
+Map<String, String> getPubTestEnvironment([String? tokenEndpoint]) {
+  var environment = {
+    'CI': 'false', // unless explicitly given tests don't run pub in CI mode
+    '_PUB_TESTING': 'true',
+    '_PUB_TEST_CONFIG_DIR': _pathInSandbox(configPath),
+    'PUB_CACHE': _pathInSandbox(cachePath),
+    'PUB_ENVIRONMENT': 'test-environment',
 
-      // Ensure a known SDK version is set for the tests that rely on that.
-      '_PUB_TEST_SDK_VERSION': testVersion,
-      if (tokenEndpoint != null) '_PUB_TEST_TOKEN_ENDPOINT': tokenEndpoint,
-      if (_globalServer?.port != null)
-        'PUB_HOSTED_URL': 'http://localhost:${_globalServer?.port}'
-    };
+    // Ensure a known SDK version is set for the tests that rely on that.
+    '_PUB_TEST_SDK_VERSION': testVersion
+  };
+
+  if (tokenEndpoint != null) {
+    environment['_PUB_TEST_TOKEN_ENDPOINT'] = tokenEndpoint;
+  }
+
+  var server = globalServer;
+  if (server != null) {
+    environment['PUB_HOSTED_URL'] = 'http://localhost:${server.port}';
+  }
+
+  return environment;
+}
 
 /// The path to the root of pub's sources in the pub repo.
 final String _pubRoot = (() {
@@ -466,7 +477,7 @@
 
   var dartArgs = ['--packages=$dotPackagesPath', '--enable-asserts'];
   dartArgs
-    ..addAll([pubPath, if (!verbose) '--verbosity=normal'])
+    ..addAll([pubPath, if (verbose) '--verbose'])
     ..addAll(args);
 
   final mergedEnvironment = getPubTestEnvironment(tokenEndpoint);
@@ -495,8 +506,8 @@
 
   StreamSplitter<Pair<log.Level, String>> createLogSplitter() {
     return StreamSplitter(StreamGroup.merge([
-      _outputToLog(super.stdoutStream(), log.Level.message),
-      _outputToLog(super.stderrStream(), log.Level.error)
+      _outputToLog(super.stdoutStream(), log.Level.MESSAGE),
+      _outputToLog(super.stderrStream(), log.Level.ERROR)
     ]));
   }
 
@@ -533,12 +544,12 @@
 
   final _logLineRegExp = RegExp(r'^([A-Z ]{4})[:|] (.*)$');
   final Map<String, log.Level> _logLevels = [
-    log.Level.error,
-    log.Level.warning,
-    log.Level.message,
-    log.Level.io,
-    log.Level.solver,
-    log.Level.fine
+    log.Level.ERROR,
+    log.Level.WARNING,
+    log.Level.MESSAGE,
+    log.Level.IO,
+    log.Level.SOLVER,
+    log.Level.FINE
   ].fold({}, (levels, level) {
     levels[level.name] = level;
     return levels;
@@ -560,7 +571,7 @@
   @override
   Stream<String> stdoutStream() {
     return _logSplitter.split().expand((entry) {
-      if (entry.first != log.Level.message) return [];
+      if (entry.first != log.Level.MESSAGE) return [];
       return [entry.last];
     });
   }
@@ -568,7 +579,7 @@
   @override
   Stream<String> stderrStream() {
     return _logSplitter.split().expand((entry) {
-      if (entry.first != log.Level.error && entry.first != log.Level.warning) {
+      if (entry.first != log.Level.ERROR && entry.first != log.Level.WARNING) {
         return [];
       }
       return [entry.last];
@@ -578,9 +589,9 @@
   /// A stream of log messages that are silent by default.
   Stream<String> silentStream() {
     return _logSplitter.split().expand((entry) {
-      if (entry.first == log.Level.message) return [];
-      if (entry.first == log.Level.error) return [];
-      if (entry.first == log.Level.warning) return [];
+      if (entry.first == log.Level.MESSAGE) return [];
+      if (entry.first == log.Level.ERROR) return [];
+      if (entry.first == log.Level.WARNING) return [];
       return [entry.last];
     });
   }
@@ -903,9 +914,9 @@
     line = line
         .replaceAll(d.sandbox, r'$SANDBOX')
         .replaceAll(Platform.pathSeparator, '/');
-    var port = _globalServer?.port;
-    if (port != null) {
-      line = line.replaceAll(port.toString(), '\$PORT');
+    var packageServer = globalPackageServer;
+    if (packageServer != null) {
+      line = line.replaceAll(packageServer.port.toString(), '\$PORT');
     }
     return line;
   });
@@ -953,28 +964,3 @@
   }
   buffer.write('\n');
 }
-
-/// The current global [PackageServer].
-PackageServer get globalServer => _globalServer!;
-PackageServer? _globalServer;
-
-/// Creates an HTTP server that replicates the structure of pub.dartlang.org and
-/// makes it the current [globalServer].
-Future<PackageServer> servePackages() async {
-  final server = await startPackageServer();
-  _globalServer = server;
-
-  addTearDown(() {
-    _globalServer = null;
-  });
-  return server;
-}
-
-Future<PackageServer> startPackageServer() async {
-  final server = await PackageServer.start();
-
-  addTearDown(() async {
-    await server.close();
-  });
-  return server;
-}
diff --git a/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt b/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt
deleted file mode 100644
index fc69b03..0000000
--- a/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt
+++ /dev/null
@@ -1,308 +0,0 @@
-# GENERATED BY: test/embedding/embedding_test.dart
-
-$ tool/test-bin/pub_command_runner.dart pub --verbose get
-MSG : Resolving dependencies...
-MSG : + foo 1.0.0
-MSG : Downloading foo 1.0.0...
-MSG : Changed 1 dependency!
-MSG : Logs written to $SANDBOX/cache/log/pub_log.txt.
-[E] FINE: Pub 0.1.2+3
-[E] SLVR: fact: myapp is 0.0.0
-[E] SLVR: derived: myapp
-[E] SLVR: fact: myapp depends on foo any
-[E] SLVR:   selecting myapp
-[E] SLVR:   derived: foo any
-[E] IO  : Get versions from http://localhost:$PORT/api/packages/foo.
-[E] IO  : HTTP GET http://localhost:$PORT/api/packages/foo
-[E]    | Accept: application/vnd.pub.v2+json
-[E]    | X-Pub-OS: $OS
-[E]    | X-Pub-Command: get
-[E]    | X-Pub-Session-ID: $ID
-[E]    | X-Pub-Environment: test-environment
-[E]    | X-Pub-Reason: direct
-[E]    | user-agent: Dart pub 0.1.2+3
-[E] IO  : HTTP response 200 OK for GET http://localhost:$PORT/api/packages/foo
-[E]    | took: $TIME
-[E]    | date: $TIME
-[E]    | content-length: 197
-[E]    | x-frame-options: SAMEORIGIN
-[E]    | content-type: text/plain; charset=utf-8
-[E]    | x-xss-protection: 1; mode=block
-[E]    | x-content-type-options: nosniff
-[E]    | server: dart:io with Shelf
-[E] IO  : Writing $N characters to text file $SANDBOX/cache/hosted/localhost%58$PORT/.cache/foo-versions.json.
-[E] FINE: Contents:
-[E]    | {"name":"foo","uploaders":["nweiz@google.com"],"versions":[{"pubspec":{"name":"foo","version":"1.0.0"},"version":"1.0.0","archive_url":"http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz"}],"_fetchedAt": "$TIME"}
-[E] SLVR:   selecting foo 1.0.0
-[E] SLVR: Version solving took: $TIME
-[E]    | Tried 1 solutions.
-[E] FINE: Resolving dependencies finished ($TIME)
-[E] IO  : Get package from http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz.
-[E] IO  : Created temp directory $DIR
-[E] IO  : HTTP GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz
-[E]    | X-Pub-OS: $OS
-[E]    | X-Pub-Command: get
-[E]    | X-Pub-Session-ID: $ID
-[E]    | X-Pub-Environment: test-environment
-[E]    | X-Pub-Reason: direct
-[E]    | user-agent: Dart pub 0.1.2+3
-[E] IO  : HTTP response 200 OK for GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz
-[E]    | took: $TIME
-[E]    | transfer-encoding: chunked
-[E]    | date: $TIME
-[E]    | x-frame-options: SAMEORIGIN
-[E]    | content-type: text/plain; charset=utf-8
-[E]    | x-xss-protection: 1; mode=block
-[E]    | x-content-type-options: nosniff
-[E]    | server: dart:io with Shelf
-[E] IO  : Creating $FILE from stream
-[E] FINE: Created $FILE from stream
-[E] IO  : Created temp directory $DIR
-[E] IO  : Reading binary file $FILE.
-[E] FINE: Extracting .tar.gz stream to $DIR
-[E] IO  : Creating $FILE from stream
-[E] FINE: Created $FILE from stream
-[E] IO  : Creating $FILE from stream
-[E] FINE: Created $FILE from stream
-[E] FINE: Extracted .tar.gz to $DIR
-[E] IO  : Renaming directory $A to $B
-[E] IO  : Deleting directory $DIR
-[E] IO  : Writing $N characters to text file pubspec.lock.
-[E] FINE: Contents:
-[E]    | # Generated by pub
-[E]    | # See https://dart.dev/tools/pub/glossary#lockfile
-[E]    | packages:
-[E]    |   foo:
-[E]    |   dependency: "direct main"
-[E]    |   description:
-[E]    |   name: foo
-[E]    |   url: "http://localhost:$PORT"
-[E]    |   source: hosted
-[E]    |   version: "1.0.0"
-[E]    | sdks:
-[E]    |   dart: ">=0.1.2 <1.0.0"
-[E] IO  : Writing $N characters to text file .dart_tool/package_config.json.
-[E] FINE: Contents:
-[E]    | {
-[E]    |   "configVersion": 2,
-[E]    |   "packages": [
-[E]    |   {
-[E]    |   "name": "foo",
-[E]    |   "rootUri": "file://$SANDBOX/cache/hosted/localhost%2558$PORT/foo-1.0.0",
-[E]    |   "packageUri": "lib/",
-[E]    |   "languageVersion": "2.7"
-[E]    |   },
-[E]    |   {
-[E]    |   "name": "myapp",
-[E]    |   "rootUri": "../",
-[E]    |   "packageUri": "lib/",
-[E]    |   "languageVersion": "0.1"
-[E]    |   }
-[E]    |   ],
-[E]    |   "generated": "$TIME",
-[E]    |   "generator": "pub",
-[E]    |   "generatorVersion": "0.1.2+3"
-[E]    | }
-[E] IO  : Writing $N characters to text file $SANDBOX/cache/log/pub_log.txt.
-
--------------------------------- END OF OUTPUT ---------------------------------
-
-Information about the latest pub run.
-
-If you believe something is not working right, you can go to 
-https://github.com/dart-lang/pub/issues/new to post a new issue and attach this file.
-
-Before making this file public, make sure to remove any sensitive information!
-
-Pub version: 0.1.2+3
-Created: $TIME
-FLUTTER_ROOT: <not set>
-PUB_HOSTED_URL: http://localhost:$PORT
-PUB_CACHE: "$SANDBOX/cache"
-Command: dart pub --verbose get
-Platform: $OS
-
----- $SANDBOX/myapp/pubspec.yaml ----
-{"name":"myapp","environment":{"sdk":">=0.1.2 <1.0.0"},"dependencies":{"foo":"any"}}
----- End pubspec.yaml ----
----- $SANDBOX/myapp/pubspec.lock ----
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
-  foo:
-   dependency: "direct main"
-   description:
-   name: foo
-   url: "http://localhost:$PORT"
-   source: hosted
-   version: "1.0.0"
-sdks:
-  dart: ">=0.1.2 <1.0.0"
-
----- End pubspec.lock ----
----- Log transcript ----
-FINE: Pub 0.1.2+3
-MSG : Resolving dependencies...
-SLVR: fact: myapp is 0.0.0
-SLVR: derived: myapp
-SLVR: fact: myapp depends on foo any
-SLVR:   selecting myapp
-SLVR:   derived: foo any
-IO  : Get versions from http://localhost:$PORT/api/packages/foo.
-IO  : HTTP GET http://localhost:$PORT/api/packages/foo
-   | Accept: application/vnd.pub.v2+json
-   | X-Pub-OS: $OS
-   | X-Pub-Command: get
-   | X-Pub-Session-ID: $ID
-   | X-Pub-Environment: test-environment
-   | X-Pub-Reason: direct
-   | user-agent: Dart pub 0.1.2+3
-IO  : HTTP response 200 OK for GET http://localhost:$PORT/api/packages/foo
-   | took: $TIME
-   | date: $TIME
-   | content-length: 197
-   | x-frame-options: SAMEORIGIN
-   | content-type: text/plain; charset=utf-8
-   | x-xss-protection: 1; mode=block
-   | x-content-type-options: nosniff
-   | server: dart:io with Shelf
-IO  : Writing $N characters to text file $SANDBOX/cache/hosted/localhost%58$PORT/.cache/foo-versions.json.
-FINE: Contents:
-   | {"name":"foo","uploaders":["nweiz@google.com"],"versions":[{"pubspec":{"name":"foo","version":"1.0.0"},"version":"1.0.0","archive_url":"http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz"}],"_fetchedAt": "$TIME"}
-SLVR:   selecting foo 1.0.0
-SLVR: Version solving took: $TIME
-   | Tried 1 solutions.
-FINE: Resolving dependencies finished ($TIME)
-MSG : + foo 1.0.0
-IO  : Get package from http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz.
-MSG : Downloading foo 1.0.0...
-IO  : Created temp directory $DIR
-IO  : HTTP GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz
-   | X-Pub-OS: $OS
-   | X-Pub-Command: get
-   | X-Pub-Session-ID: $ID
-   | X-Pub-Environment: test-environment
-   | X-Pub-Reason: direct
-   | user-agent: Dart pub 0.1.2+3
-IO  : HTTP response 200 OK for GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz
-   | took: $TIME
-   | transfer-encoding: chunked
-   | date: $TIME
-   | x-frame-options: SAMEORIGIN
-   | content-type: text/plain; charset=utf-8
-   | x-xss-protection: 1; mode=block
-   | x-content-type-options: nosniff
-   | server: dart:io with Shelf
-IO  : Creating $FILE from stream
-FINE: Created $FILE from stream
-IO  : Created temp directory $DIR
-IO  : Reading binary file $FILE.
-FINE: Extracting .tar.gz stream to $DIR
-IO  : Creating $FILE from stream
-FINE: Created $FILE from stream
-IO  : Creating $FILE from stream
-FINE: Created $FILE from stream
-FINE: Extracted .tar.gz to $DIR
-IO  : Renaming directory $A to $B
-IO  : Deleting directory $DIR
-IO  : Writing $N characters to text file pubspec.lock.
-FINE: Contents:
-   | # Generated by pub
-   | # See https://dart.dev/tools/pub/glossary#lockfile
-   | packages:
-   |   foo:
-   |   dependency: "direct main"
-   |   description:
-   |   name: foo
-   |   url: "http://localhost:$PORT"
-   |   source: hosted
-   |   version: "1.0.0"
-   | sdks:
-   |   dart: ">=0.1.2 <1.0.0"
-MSG : Changed 1 dependency!
-IO  : Writing $N characters to text file .dart_tool/package_config.json.
-FINE: Contents:
-   | {
-   |   "configVersion": 2,
-   |   "packages": [
-   |   {
-   |   "name": "foo",
-   |   "rootUri": "file://$SANDBOX/cache/hosted/localhost%2558$PORT/foo-1.0.0",
-   |   "packageUri": "lib/",
-   |   "languageVersion": "2.7"
-   |   },
-   |   {
-   |   "name": "myapp",
-   |   "rootUri": "../",
-   |   "packageUri": "lib/",
-   |   "languageVersion": "0.1"
-   |   }
-   |   ],
-   |   "generated": "$TIME",
-   |   "generator": "pub",
-   |   "generatorVersion": "0.1.2+3"
-   | }
----- End log transcript ----
--------------------------------- END OF OUTPUT ---------------------------------
-
-$ tool/test-bin/pub_command_runner.dart pub fail
-[E] Bad state: Pub has crashed
-[E]  tool/test-bin/pub_command_runner.dart $LINE:$COL   ThrowingCommand.runProtected
-[E] package:pub/src/command.dart $LINE:$COL   PubCommand.run.<fn>
-[E] package:pub/src/command.dart $LINE:$COL   PubCommand.run.<fn>
-[E] dart:async   new Future.sync
-[E] package:pub/src/utils.dart $LINE:$COL   captureErrors.wrappedCallback
-[E] dart:async   runZonedGuarded
-[E] package:pub/src/utils.dart $LINE:$COL   captureErrors
-[E] package:pub/src/command.dart $LINE:$COL   PubCommand.run
-[E] package:args/command_runner.dart $LINE:$COL   CommandRunner.runCommand
-[E]  tool/test-bin/pub_command_runner.dart $LINE:$COL  Runner.runCommand
-[E]  tool/test-bin/pub_command_runner.dart $LINE:$COL  Runner.run
-[E]  tool/test-bin/pub_command_runner.dart $LINE:$COL  main
-[E] This is an unexpected error. The full log and other details are collected in:
-[E] 
-[E]    $SANDBOX/cache/log/pub_log.txt
-[E] 
-[E] Consider creating an issue on https://github.com/dart-lang/pub/issues/new
-[E] and attaching the relevant parts of that log file.
-
--------------------------------- END OF OUTPUT ---------------------------------
-
-Information about the latest pub run.
-
-If you believe something is not working right, you can go to 
-https://github.com/dart-lang/pub/issues/new to post a new issue and attach this file.
-
-Before making this file public, make sure to remove any sensitive information!
-
-Pub version: 0.1.2+3
-Created: $TIME
-FLUTTER_ROOT: <not set>
-PUB_HOSTED_URL: http://localhost:$PORT
-PUB_CACHE: "$SANDBOX/cache"
-Command: dart pub fail
-Platform: $OS
-
----- Log transcript ----
-FINE: Pub 0.1.2+3
-ERR : Bad state: Pub has crashed
-FINE: Exception type: StateError
-ERR : tool/test-bin/pub_command_runner.dart $LINE:$COL   ThrowingCommand.runProtected
-   | package:pub/src/command.dart $LINE:$COL   PubCommand.run.<fn>
-   | package:pub/src/command.dart $LINE:$COL   PubCommand.run.<fn>
-   | dart:async   new Future.sync
-   | package:pub/src/utils.dart $LINE:$COL   captureErrors.wrappedCallback
-   | dart:async   runZonedGuarded
-   | package:pub/src/utils.dart $LINE:$COL   captureErrors
-   | package:pub/src/command.dart $LINE:$COL   PubCommand.run
-   | package:args/command_runner.dart $LINE:$COL   CommandRunner.runCommand
-   | tool/test-bin/pub_command_runner.dart $LINE:$COL  Runner.runCommand
-   | tool/test-bin/pub_command_runner.dart $LINE:$COL  Runner.run
-   | tool/test-bin/pub_command_runner.dart $LINE:$COL  main
-ERR : This is an unexpected error. The full log and other details are collected in:
-   | 
-   |   $SANDBOX/cache/log/pub_log.txt
-   | 
-   | Consider creating an issue on https://github.com/dart-lang/pub/issues/new
-   | and attaching the relevant parts of that log file.
----- End log transcript ----
diff --git a/test/testdata/goldens/help_test/pub add --help.txt b/test/testdata/goldens/help_test/pub add --help.txt
index 3d1f429..5d32e5e 100644
--- a/test/testdata/goldens/help_test/pub add --help.txt
+++ b/test/testdata/goldens/help_test/pub add --help.txt
@@ -2,25 +2,22 @@
 
 ## Section 0
 $ pub add --help
-Add dependencies to pubspec.yaml.
+Add a dependency to pubspec.yaml.
 
-Usage: pub add <package>[:<constraint>] [<package2>[:<constraint2>]...] [options]
--h, --help                    Print this usage information.
--d, --dev                     Adds to the development dependencies instead.
-    --git-url                 Git URL of the package
-    --git-ref                 Git branch or commit to be retrieved
-    --git-path                Path of git package in repository
-    --hosted-url              URL of package host server
-    --path                    Add package from local path
-    --sdk=<[flutter]>         add package from SDK source
-                              [flutter]
-    --[no-]offline            Use cached packages instead of accessing the
-                              network.
--n, --dry-run                 Report what dependencies would change but don't
-                              change any.
-    --[no-]precompile         Build executables in immediate dependencies.
--C, --directory=<dir>         Run this in the directory <dir>.
-    --legacy-packages-file    Generate the legacy ".packages" file
+Usage: pub add <package>[:<constraint>] [options]
+-h, --help               Print this usage information.
+-d, --dev                Adds package to the development dependencies instead.
+    --git-url            Git URL of the package
+    --git-ref            Git branch or commit to be retrieved
+    --git-path           Path of git package in repository
+    --hosted-url         URL of package host server
+    --path               Local path
+    --sdk                SDK source for package
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+    --[no-]precompile    Build executables in immediate dependencies.
+-C, --directory=<dir>    Run this in the directory<dir>.
 
 Run "pub help" to see global options.
 See https://dart.dev/tools/pub/cmd/pub-add for detailed documentation.
diff --git a/test/testdata/goldens/help_test/pub downgrade --help.txt b/test/testdata/goldens/help_test/pub downgrade --help.txt
index ddf71e7..4497da2 100644
--- a/test/testdata/goldens/help_test/pub downgrade --help.txt
+++ b/test/testdata/goldens/help_test/pub downgrade --help.txt
@@ -7,13 +7,11 @@
 
 
 Usage: pub downgrade [dependencies...]
--h, --help                    Print this usage information.
-    --[no-]offline            Use cached packages instead of accessing the
-                              network.
--n, --dry-run                 Report what dependencies would change but don't
-                              change any.
--C, --directory=<dir>         Run this in the directory<dir>.
-    --legacy-packages-file    Generate the legacy ".packages" file
+-h, --help               Print this usage information.
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+-C, --directory=<dir>    Run this in the directory<dir>.
 
 Run "pub help" to see global options.
 See https://dart.dev/tools/pub/cmd/pub-downgrade for detailed documentation.
diff --git a/test/testdata/goldens/help_test/pub get --help.txt b/test/testdata/goldens/help_test/pub get --help.txt
index 104f69c..74648a2 100644
--- a/test/testdata/goldens/help_test/pub get --help.txt
+++ b/test/testdata/goldens/help_test/pub get --help.txt
@@ -5,14 +5,12 @@
 Get the current package's dependencies.
 
 Usage: pub get <subcommand> [arguments...]
--h, --help                    Print this usage information.
-    --[no-]offline            Use cached packages instead of accessing the
-                              network.
--n, --dry-run                 Report what dependencies would change but don't
-                              change any.
-    --[no-]precompile         Build executables in immediate dependencies.
-    --legacy-packages-file    Generate the legacy ".packages" file
--C, --directory=<dir>         Run this in the directory<dir>.
+-h, --help               Print this usage information.
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+    --[no-]precompile    Build executables in immediate dependencies.
+-C, --directory=<dir>    Run this in the directory<dir>.
 
 Run "pub help" to see global options.
 See https://dart.dev/tools/pub/cmd/pub-get for detailed documentation.
diff --git a/test/testdata/goldens/help_test/pub remove --help.txt b/test/testdata/goldens/help_test/pub remove --help.txt
index b82f9b6..7d14ed0 100644
--- a/test/testdata/goldens/help_test/pub remove --help.txt
+++ b/test/testdata/goldens/help_test/pub remove --help.txt
@@ -5,14 +5,12 @@
 Removes a dependency from the current package.
 
 Usage: pub remove <package>
--h, --help                    Print this usage information.
-    --[no-]offline            Use cached packages instead of accessing the
-                              network.
--n, --dry-run                 Report what dependencies would change but don't
-                              change any.
-    --[no-]precompile         Precompile executables in immediate dependencies.
--C, --directory=<dir>         Run this in the directory<dir>.
-    --legacy-packages-file    Generate the legacy ".packages" file
+-h, --help               Print this usage information.
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+    --[no-]precompile    Precompile executables in immediate dependencies.
+-C, --directory=<dir>    Run this in the directory<dir>.
 
 Run "pub help" to see global options.
 See https://dart.dev/tools/pub/cmd/pub-remove for detailed documentation.
diff --git a/test/testdata/goldens/help_test/pub upgrade --help.txt b/test/testdata/goldens/help_test/pub upgrade --help.txt
index c787951..d1a29b9 100644
--- a/test/testdata/goldens/help_test/pub upgrade --help.txt
+++ b/test/testdata/goldens/help_test/pub upgrade --help.txt
@@ -5,18 +5,16 @@
 Upgrade the current package's dependencies to latest versions.
 
 Usage: pub upgrade [dependencies...]
--h, --help                    Print this usage information.
-    --[no-]offline            Use cached packages instead of accessing the
-                              network.
--n, --dry-run                 Report what dependencies would change but don't
-                              change any.
-    --[no-]precompile         Precompile executables in immediate dependencies.
-    --null-safety             Upgrade constraints in pubspec.yaml to null-safety
-                              versions
-    --legacy-packages-file    Generate the legacy ".packages" file
-    --major-versions          Upgrades packages to their latest resolvable
-                              versions, and updates pubspec.yaml.
--C, --directory=<dir>         Run this in the directory<dir>.
+-h, --help               Print this usage information.
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+    --[no-]precompile    Precompile executables in immediate dependencies.
+    --null-safety        Upgrade constraints in pubspec.yaml to null-safety
+                         versions
+    --major-versions     Upgrades packages to their latest resolvable versions,
+                         and updates pubspec.yaml.
+-C, --directory=<dir>    Run this in the directory<dir>.
 
 Run "pub help" to see global options.
 See https://dart.dev/tools/pub/cmd/pub-upgrade for detailed documentation.
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401-with-message.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401-with-message.txt
deleted file mode 100644
index 8dcaaf5..0000000
--- a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401-with-message.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart
-
-## Section 0
-$ pub get
-Resolving dependencies...
-[STDERR] Because myapp depends on foo any which doesn't exist (authentication failed), version solving failed.
-[STDERR] 
-[STDERR] http://localhost:$PORT package repository requested authentication!
-[STDERR] You can provide credentials using:
-[STDERR]     pub token add http://localhost:$PORT
-[STDERR] <message>
-[EXIT CODE] 69
-
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401.txt
deleted file mode 100644
index 68d5bd0..0000000
--- a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart
-
-## Section 0
-$ pub get
-Resolving dependencies...
-[STDERR] Because myapp depends on foo any which doesn't exist (authentication failed), version solving failed.
-[STDERR] 
-[STDERR] http://localhost:$PORT package repository requested authentication!
-[STDERR] You can provide credentials using:
-[STDERR]     pub token add http://localhost:$PORT
-[EXIT CODE] 69
-
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403-with-message.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403-with-message.txt
deleted file mode 100644
index 882660c..0000000
--- a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403-with-message.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart
-
-## Section 0
-$ pub get
-Resolving dependencies...
-[STDERR] Because myapp depends on foo any which doesn't exist (authorization failed), version solving failed.
-[STDERR] 
-[STDERR] Insufficient permissions to the resource at the http://localhost:$PORT package repository.
-[STDERR] You can modify credentials using:
-[STDERR]     pub token add http://localhost:$PORT
-[STDERR] <message>
-[EXIT CODE] 69
-
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403.txt
deleted file mode 100644
index f8a5af9..0000000
--- a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart
-
-## Section 0
-$ pub get
-Resolving dependencies...
-[STDERR] Because myapp depends on foo any which doesn't exist (authorization failed), version solving failed.
-[STDERR] 
-[STDERR] Insufficient permissions to the resource at the http://localhost:$PORT package repository.
-[STDERR] You can modify credentials using:
-[STDERR]     pub token add http://localhost:$PORT
-[EXIT CODE] 69
-
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/bad_json.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/bad_json.txt
deleted file mode 100644
index 8e446c2..0000000
--- a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/bad_json.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart
-
-## Section 0
-$ pub get
-Resolving dependencies...
-[STDERR] Because myapp depends on foo any which doesn't exist (Got badly formatted response trying to find package foo at http://localhost:$PORT), version solving failed.
-[STDERR] 
-[STDERR] Check that "http://localhost:$PORT" is a valid package repository.
-[EXIT CODE] 65
-
diff --git a/test/testdata/goldens/hosted/fail_gracefully_with_hint_test/supports two hints.txt b/test/testdata/goldens/hosted/fail_gracefully_with_hint_test/supports two hints.txt
deleted file mode 100644
index a45b0f0..0000000
--- a/test/testdata/goldens/hosted/fail_gracefully_with_hint_test/supports two hints.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-# GENERATED BY: test/hosted/fail_gracefully_with_hint_test.dart
-
-## Section 0
-$ pub get --offline
-Resolving dependencies...
-[STDERR] Because foo <1.2.4 requires the Flutter SDK and foo >=1.2.4 depends on bar any, every version of foo requires bar any.
-[STDERR] So, because bar doesn't exist (could not find package bar in cache) and myapp depends on foo any, version solving failed.
-[STDERR] 
-[STDERR] Flutter users should run `flutter pub get` instead of `dart pub get`.
-[STDERR] 
-[STDERR] Try again without --offline!
-[EXIT CODE] 69
-
diff --git a/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
index ae304ea..2cc96c0 100644
--- a/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
+++ b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
@@ -17,7 +17,9 @@
 ## Section 1
 $ pub upgrade --major-versions --directory example
 Resolving dependencies in example...
+  bar 2.0.0
 > foo 2.0.0 (was 1.0.0)
+  myapp 0.0.0 from path .
 Changed 1 dependency in example!
 
 Changed 1 constraint in pubspec.yaml:
diff --git a/test/token/error_message_test.dart b/test/token/error_message_test.dart
index 53431a5..b7bc553 100644
--- a/test/token/error_message_test.dart
+++ b/test/token/error_message_test.dart
@@ -9,7 +9,7 @@
 import '../test_pub.dart';
 
 void respondWithWwwAuthenticate(String headerValue) {
-  globalServer.expect('GET', '/api/packages/versions/new', (request) {
+  globalPackageServer!.expect('GET', '/api/packages/versions/new', (request) {
     return shelf.Response(403, headers: {'www-authenticate': headerValue});
   });
 }
@@ -18,7 +18,7 @@
   return runPub(
     args: ['lish'],
     environment: {
-      'PUB_HOSTED_URL': globalServer.url,
+      'PUB_HOSTED_URL': globalPackageServer!.url,
       '_PUB_TEST_AUTH_METHOD': 'token',
     },
     exitCode: 65,
@@ -34,7 +34,7 @@
     await d.tokensFile({
       'version': 1,
       'hosted': [
-        {'url': globalServer.url, 'token': 'access token'},
+        {'url': globalPackageServer!.url, 'token': 'access token'},
       ]
     }).create();
   });
diff --git a/test/token/token_authentication_test.dart b/test/token/token_authentication_test.dart
index c020ac0..667c47f 100644
--- a/test/token/token_authentication_test.dart
+++ b/test/token/token_authentication_test.dart
@@ -16,14 +16,14 @@
     await d.tokensFile({
       'version': 1,
       'hosted': [
-        {'url': globalServer.url, 'env': 'TOKEN'},
+        {'url': globalPackageServer!.url, 'env': 'TOKEN'},
       ]
     }).create();
-    var pub = await startPublish(globalServer,
+    var pub = await startPublish(globalPackageServer!,
         authMethod: 'token', environment: {'TOKEN': 'access token'});
     await confirmPublish(pub);
 
-    handleUploadForm(globalServer);
+    handleUploadForm(globalPackageServer!);
 
     await pub.shouldExit(1);
   });
@@ -33,13 +33,13 @@
     await d.tokensFile({
       'version': 1,
       'hosted': [
-        {'url': globalServer.url, 'token': 'access token'},
+        {'url': globalPackageServer!.url, 'token': 'access token'},
       ]
     }).create();
-    var pub = await startPublish(globalServer, authMethod: 'token');
+    var pub = await startPublish(globalPackageServer!, authMethod: 'token');
     await confirmPublish(pub);
 
-    handleUploadForm(globalServer);
+    handleUploadForm(globalPackageServer!);
 
     await pub.shouldExit(1);
   });
diff --git a/test/token/when_receives_401_removes_token_test.dart b/test/token/when_receives_401_removes_token_test.dart
index 86c0559..b674597 100644
--- a/test/token/when_receives_401_removes_token_test.dart
+++ b/test/token/when_receives_401_removes_token_test.dart
@@ -12,17 +12,17 @@
   setUp(d.validPackage.create);
 
   test('when receives 401 response removes saved token', () async {
-    final server = await servePackages();
+    await servePackages();
     await d.tokensFile({
       'version': 1,
       'hosted': [
-        {'url': server.url, 'token': 'access token'},
+        {'url': globalPackageServer!.url, 'token': 'access token'},
       ]
     }).create();
-    var pub = await startPublish(server, authMethod: 'token');
+    var pub = await startPublish(globalPackageServer!, authMethod: 'token');
     await confirmPublish(pub);
 
-    server.expect('GET', '/api/packages/versions/new', (request) {
+    globalPackageServer!.expect('GET', '/api/packages/versions/new', (request) {
       return shelf.Response(401);
     });
 
diff --git a/test/token/when_receives_403_persists_saved_token_test.dart b/test/token/when_receives_403_persists_saved_token_test.dart
index 45fc7a4..ffcbab0 100644
--- a/test/token/when_receives_403_persists_saved_token_test.dart
+++ b/test/token/when_receives_403_persists_saved_token_test.dart
@@ -12,17 +12,17 @@
   setUp(d.validPackage.create);
 
   test('when receives 403 response persists saved token', () async {
-    final server = await servePackages();
+    await servePackages();
     await d.tokensFile({
       'version': 1,
       'hosted': [
-        {'url': server.url, 'token': 'access token'},
+        {'url': globalPackageServer!.url, 'token': 'access token'},
       ]
     }).create();
-    var pub = await startPublish(server, authMethod: 'token');
+    var pub = await startPublish(globalPackageServer!, authMethod: 'token');
     await confirmPublish(pub);
 
-    server.expect('GET', '/api/packages/versions/new', (request) {
+    globalPackageServer!.expect('GET', '/api/packages/versions/new', (request) {
       return shelf.Response(403);
     });
 
@@ -31,7 +31,7 @@
     await d.tokensFile({
       'version': 1,
       'hosted': [
-        {'url': server.url, 'token': 'access token'},
+        {'url': globalPackageServer!.url, 'token': 'access token'},
       ]
     }).validate();
   });
diff --git a/test/unknown_source_test.dart b/test/unknown_source_test.dart
index 37591d0..fc53621 100644
--- a/test/unknown_source_test.dart
+++ b/test/unknown_source_test.dart
@@ -72,9 +72,7 @@
       await pubCommand(command);
 
       // Should upgrade to the new one.
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', path: '../foo'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '../foo'}).validate();
     });
   });
 }
diff --git a/test/upgrade/dry_run_does_not_apply_changes_test.dart b/test/upgrade/dry_run_does_not_apply_changes_test.dart
index 8c942ca..de1e6b5 100644
--- a/test/upgrade/dry_run_does_not_apply_changes_test.dart
+++ b/test/upgrade/dry_run_does_not_apply_changes_test.dart
@@ -11,9 +11,10 @@
 
 void main() {
   test('--dry-run: shows report, changes nothing', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0');
+    });
 
     // Create the first lockfile.
     await d.appDir({'foo': '1.0.0'}).create();
@@ -49,9 +50,10 @@
   });
 
   test('--dry-run --major-versions: shows report, changes nothing', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0');
+    });
 
     await d.appDir({'foo': '^1.0.0'}).create();
 
diff --git a/test/upgrade/example_warns_about_major_versions_test.dart b/test/upgrade/example_warns_about_major_versions_test.dart
index b5c9a67..a9b2965 100644
--- a/test/upgrade/example_warns_about_major_versions_test.dart
+++ b/test/upgrade/example_warns_about_major_versions_test.dart
@@ -10,11 +10,11 @@
   testWithGolden(
       'pub upgrade --major-versions does not update major versions in example/',
       (ctx) async {
-    await servePackages()
+    await servePackages((b) => b
       ..serve('foo', '1.0.0')
       ..serve('foo', '2.0.0')
       ..serve('bar', '1.0.0')
-      ..serve('bar', '2.0.0');
+      ..serve('bar', '2.0.0'));
     await d.dir(appPath, [
       d.pubspec({
         'name': 'myapp',
@@ -39,7 +39,7 @@
   testWithGolden(
       'pub upgrade --null-safety does not update null-safety of dependencies in example/',
       (ctx) async {
-    await servePackages()
+    await servePackages((b) => b
       ..serve('foo', '1.0.0', pubspec: {
         'environment': {'sdk': '>=2.7.0 <3.0.0'},
       })
@@ -51,7 +51,7 @@
       })
       ..serve('bar', '2.0.0', pubspec: {
         'environment': {'sdk': '>=2.12.0 <3.0.0'},
-      });
+      }));
     await d.dir(appPath, [
       d.pubspec({
         'name': 'myapp',
diff --git a/test/upgrade/hosted/unlock_if_necessary_test.dart b/test/upgrade/hosted/unlock_if_necessary_test.dart
index 2707100..5066727 100644
--- a/test/upgrade/hosted/unlock_if_necessary_test.dart
+++ b/test/upgrade/hosted/unlock_if_necessary_test.dart
@@ -11,28 +11,24 @@
   test(
       "upgrades one locked pub server package's dependencies if it's "
       'necessary', () async {
-    final server = await servePackages();
-
-    server.serve('foo', '1.0.0', deps: {'foo_dep': 'any'});
-    server.serve('foo_dep', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'foo_dep': 'any'});
+      builder.serve('foo_dep', '1.0.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'foo_dep', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'foo_dep': '1.0.0'}).validate();
 
-    server.serve('foo', '2.0.0', deps: {'foo_dep': '>1.0.0'});
-    server.serve('foo_dep', '2.0.0');
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '2.0.0', deps: {'foo_dep': '>1.0.0'});
+      builder.serve('foo_dep', '2.0.0');
+    });
 
     await pubUpgrade(args: ['foo']);
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-      d.packageConfigEntry(name: 'foo_dep', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '2.0.0', 'foo_dep': '2.0.0'}).validate();
   });
 }
diff --git a/test/upgrade/hosted/unlock_single_package_test.dart b/test/upgrade/hosted/unlock_single_package_test.dart
index e443a6a..29dabe7 100644
--- a/test/upgrade/hosted/unlock_single_package_test.dart
+++ b/test/upgrade/hosted/unlock_single_package_test.dart
@@ -9,43 +9,37 @@
 
 void main() {
   test('can unlock a single package only in upgrade', () async {
-    final server = await servePackages();
-
-    server.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'});
-    server.serve('bar', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'});
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.appDir({'foo': 'any', 'bar': 'any'}).create();
 
     await pubGet();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate();
 
-    server.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'});
-    server.serve('bar', '2.0.0');
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'});
+      builder.serve('bar', '2.0.0');
+    });
 
     // This can't upgrade 'bar'
     await pubUpgrade(args: ['bar']);
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate();
+
     // Introducing foo and bar 1.1.0, to show that only 'bar' will be upgraded
-    server.serve('foo', '1.1.0', deps: {'bar': '<2.0.0'});
-    server.serve('bar', '1.1.0');
+    globalPackageServer!.add((builder) {
+      builder.serve('foo', '1.1.0', deps: {'bar': '<2.0.0'});
+      builder.serve('bar', '1.1.0');
+    });
 
     await pubUpgrade(args: ['bar']);
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.1.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate();
+
     await pubUpgrade();
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '2.0.0', 'bar': '2.0.0'}).validate();
   });
 }
diff --git a/test/upgrade/hosted/upgrade_removed_constraints_test.dart b/test/upgrade/hosted/upgrade_removed_constraints_test.dart
index cf72c07..7c20816 100644
--- a/test/upgrade/hosted/upgrade_removed_constraints_test.dart
+++ b/test/upgrade/hosted/upgrade_removed_constraints_test.dart
@@ -9,29 +9,24 @@
 
 void main() {
   test('upgrades dependencies whose constraints have been removed', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'shared_dep': 'any'})
-      ..serve('bar', '1.0.0', deps: {'shared_dep': '<2.0.0'})
-      ..serve('shared_dep', '1.0.0')
-      ..serve('shared_dep', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'shared_dep': 'any'});
+      builder.serve('bar', '1.0.0', deps: {'shared_dep': '<2.0.0'});
+      builder.serve('shared_dep', '1.0.0');
+      builder.serve('shared_dep', '2.0.0');
+    });
 
     await d.appDir({'foo': 'any', 'bar': 'any'}).create();
 
     await pubUpgrade();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-      d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'),
-    ]).validate();
+    await d.appPackagesFile(
+        {'foo': '1.0.0', 'bar': '1.0.0', 'shared_dep': '1.0.0'}).validate();
 
     await d.appDir({'foo': 'any'}).create();
 
     await pubUpgrade();
 
-    await d.appPackageConfigFile([
-      d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-      d.packageConfigEntry(name: 'shared_dep', version: '2.0.0'),
-    ]).validate();
+    await d.appPackagesFile({'foo': '1.0.0', 'shared_dep': '2.0.0'}).validate();
   });
 }
diff --git a/test/upgrade/hosted/warn_about_discontinued_test.dart b/test/upgrade/hosted/warn_about_discontinued_test.dart
index ba7fc57..8444c10 100644
--- a/test/upgrade/hosted/warn_about_discontinued_test.dart
+++ b/test/upgrade/hosted/warn_about_discontinued_test.dart
@@ -9,15 +9,15 @@
 
 void main() {
   test('Warns about discontinued dependencies', () async {
-    final server = await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.2.3', deps: {'transitive': 'any'})
-      ..serve('transitive', '1.0.0');
+      ..serve('transitive', '1.0.0'));
     await d.appDir({'foo': '1.2.3'}).create();
     await pubGet();
 
-    server
+    globalPackageServer!.add((builder) => builder
       ..discontinue('foo')
-      ..discontinue('transitive');
+      ..discontinue('transitive'));
     // We warn only about the direct dependency here:
     await pubUpgrade(output: '''
 Resolving dependencies...
@@ -26,7 +26,8 @@
   No dependencies changed.
   1 package is discontinued.
 ''');
-    server.discontinue('foo', replacementText: 'bar');
+    globalPackageServer!
+        .add((builder) => builder.discontinue('foo', replacementText: 'bar'));
     // We warn only about the direct dependency here:
     await pubUpgrade(output: '''
 Resolving dependencies...
@@ -38,9 +39,9 @@
   });
 
   test('Warns about discontinued dev_dependencies', () async {
-    final server = await servePackages()
+    await servePackages((builder) => builder
       ..serve('foo', '1.2.3', deps: {'transitive': 'any'})
-      ..serve('transitive', '1.0.0');
+      ..serve('transitive', '1.0.0'));
 
     await d.dir(appPath, [
       d.file('pubspec.yaml', '''
@@ -55,9 +56,9 @@
     ]).create();
     await pubGet();
 
-    server
+    globalPackageServer!.add((builder) => builder
       ..discontinue('foo')
-      ..discontinue('transitive');
+      ..discontinue('transitive'));
 
     // We warn only about the direct dependency here:
     await pubUpgrade(output: '''
@@ -67,7 +68,8 @@
   No dependencies changed.
   1 package is discontinued.
 ''');
-    server.discontinue('foo', replacementText: 'bar');
+    globalPackageServer!
+        .add((builder) => builder.discontinue('foo', replacementText: 'bar'));
     // We warn only about the direct dependency here:
     await pubUpgrade(output: '''
 Resolving dependencies...
diff --git a/test/upgrade/renamed_package_circular_dependency.dart b/test/upgrade/renamed_package_circular_dependency.dart
index ec10b82..ca033bb 100644
--- a/test/upgrade/renamed_package_circular_dependency.dart
+++ b/test/upgrade/renamed_package_circular_dependency.dart
@@ -8,9 +8,10 @@
 
 void main() {
   test('The upgrade report handles a package becoming root', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'myapp': 'any'})
-      ..serve('myapp', '1.0.0', deps: {'foo': 'any'});
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'myapp': 'any'});
+      builder.serve('myapp', '1.0.0', deps: {'foo': 'any'});
+    });
 
     await d.dir(appPath, [
       d.pubspec({
diff --git a/test/upgrade/report/describes_change_test.dart b/test/upgrade/report/describes_change_test.dart
index 96410cb..3d93541 100644
--- a/test/upgrade/report/describes_change_test.dart
+++ b/test/upgrade/report/describes_change_test.dart
@@ -9,11 +9,11 @@
 
 void main() {
   test('Shows count of discontinued packages', () async {
-    final server = await servePackages();
+    await servePackages((builder) {
+      builder.serve('foo', '2.0.0');
+    });
 
-    server.serve('foo', '2.0.0');
-
-    server.discontinue('foo');
+    globalPackageServer!.add((builder) => builder..discontinue('foo'));
 
     // Create the first lockfile.
     await d.appDir({'foo': '2.0.0'}).create();
@@ -33,11 +33,12 @@
   });
 
   test('shows how package changed from previous lockfile', () async {
-    await servePackages()
-      ..serve('unchanged', '1.0.0')
-      ..serve('version_changed', '1.0.0')
-      ..serve('version_changed', '2.0.0')
-      ..serve('source_changed', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('unchanged', '1.0.0');
+      builder.serve('version_changed', '1.0.0');
+      builder.serve('version_changed', '2.0.0');
+      builder.serve('source_changed', '1.0.0');
+    });
 
     await d.dir('source_changed', [
       d.libDir('source_changed'),
diff --git a/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart b/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart
index ef987b9..7a232d0 100644
--- a/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart
+++ b/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart
@@ -11,13 +11,14 @@
   test(
       'Shows newer versions available for packages that are locked and not being upgraded',
       () async {
-    await servePackages()
-      ..serve('not_upgraded', '1.0.0')
-      ..serve('not_upgraded', '2.0.0')
-      ..serve('not_upgraded', '3.0.0-dev')
-      ..serve('upgraded', '1.0.0')
-      ..serve('upgraded', '2.0.0')
-      ..serve('upgraded', '3.0.0-dev');
+    await servePackages((builder) {
+      builder.serve('not_upgraded', '1.0.0');
+      builder.serve('not_upgraded', '2.0.0');
+      builder.serve('not_upgraded', '3.0.0-dev');
+      builder.serve('upgraded', '1.0.0');
+      builder.serve('upgraded', '2.0.0');
+      builder.serve('upgraded', '3.0.0-dev');
+    });
 
     // Constraint everything to the first version.
     await d.appDir({'not_upgraded': '1.0.0', 'upgraded': '1.0.0'}).create();
diff --git a/test/upgrade/report/highlights_overrides_test.dart b/test/upgrade/report/highlights_overrides_test.dart
index 93f9f3b..94608d9 100644
--- a/test/upgrade/report/highlights_overrides_test.dart
+++ b/test/upgrade/report/highlights_overrides_test.dart
@@ -9,8 +9,7 @@
 
 void main() {
   test('highlights overridden packages', () async {
-    final server = await servePackages();
-    server.serve('overridden', '1.0.0');
+    await servePackages((builder) => builder.serve('overridden', '1.0.0'));
 
     await d.dir(appPath, [
       d.pubspec({
diff --git a/test/upgrade/report/leading_character_shows_change_test.dart b/test/upgrade/report/leading_character_shows_change_test.dart
index 88f7ed2..d7f870c 100644
--- a/test/upgrade/report/leading_character_shows_change_test.dart
+++ b/test/upgrade/report/leading_character_shows_change_test.dart
@@ -9,16 +9,17 @@
 
 void main() {
   test('the character before each package describes the change', () async {
-    await servePackages()
-      ..serve('added', '1.0.0')
-      ..serve('downgraded', '1.0.0')
-      ..serve('downgraded', '2.0.0')
-      ..serve('overridden', '1.0.0')
-      ..serve('removed', '1.0.0')
-      ..serve('source_changed', '1.0.0')
-      ..serve('upgraded', '1.0.0')
-      ..serve('upgraded', '2.0.0')
-      ..serve('unchanged', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('added', '1.0.0');
+      builder.serve('downgraded', '1.0.0');
+      builder.serve('downgraded', '2.0.0');
+      builder.serve('overridden', '1.0.0');
+      builder.serve('removed', '1.0.0');
+      builder.serve('source_changed', '1.0.0');
+      builder.serve('upgraded', '1.0.0');
+      builder.serve('upgraded', '2.0.0');
+      builder.serve('unchanged', '1.0.0');
+    });
 
     await d.dir('description_changed_1', [
       d.libDir('description_changed'),
diff --git a/test/upgrade/report/shows_newer_available_versions_test.dart b/test/upgrade/report/shows_newer_available_versions_test.dart
index 39d4e1a..4c1ca56 100644
--- a/test/upgrade/report/shows_newer_available_versions_test.dart
+++ b/test/upgrade/report/shows_newer_available_versions_test.dart
@@ -9,26 +9,28 @@
 
 void main() {
   test('shows how many newer versions are available', () async {
-    await servePackages()
-      ..serve('multiple_newer', '1.0.0')
-      ..serve('multiple_newer', '1.0.1-unstable.1')
-      ..serve('multiple_newer', '1.0.1')
-      ..serve('multiple_newer', '1.0.2-unstable.1')
-      ..serve('multiple_newer_stable', '1.0.0')
-      ..serve('multiple_newer_stable', '1.0.1')
-      ..serve('multiple_newer_stable', '1.0.2')
-      ..serve('multiple_newer_unstable', '1.0.0')
-      ..serve('multiple_newer_unstable', '1.0.1-unstable.1')
-      ..serve('multiple_newer_unstable', '1.0.1-unstable.2')
-      ..serve('multiple_newer_unstable2', '1.0.1-unstable.1')
-      ..serve('multiple_newer_unstable2', '1.0.1-unstable.2')
-      ..serve('no_newer', '1.0.0')
-      ..serve('one_newer_unstable', '1.0.0')
-      ..serve('one_newer_unstable', '1.0.1-unstable.1')
-      ..serve('one_newer_unstable2', '1.0.1-unstable.1')
-      ..serve('one_newer_unstable2', '1.0.1-unstable.2')
-      ..serve('one_newer_stable', '1.0.0')
-      ..serve('one_newer_stable', '1.0.1');
+    await servePackages((builder) {
+      builder.serve('multiple_newer', '1.0.0');
+      builder.serve('multiple_newer', '1.0.1-unstable.1');
+      builder.serve('multiple_newer', '1.0.1');
+      builder.serve('multiple_newer', '1.0.2-unstable.1');
+      builder.serve('multiple_newer_stable', '1.0.0');
+      builder.serve('multiple_newer_stable', '1.0.1');
+      builder.serve('multiple_newer_stable', '1.0.2');
+      builder.serve('multiple_newer_unstable', '1.0.0');
+      builder.serve('multiple_newer_unstable', '1.0.1-unstable.1');
+      builder.serve('multiple_newer_unstable', '1.0.1-unstable.2');
+      builder.serve('multiple_newer_unstable2', '1.0.1-unstable.1');
+      builder.serve('multiple_newer_unstable2', '1.0.1-unstable.2');
+      builder.serve('multiple_newer_unstable2', '1.0.1-unstable.2');
+      builder.serve('no_newer', '1.0.0');
+      builder.serve('one_newer_unstable', '1.0.0');
+      builder.serve('one_newer_unstable', '1.0.1-unstable.1');
+      builder.serve('one_newer_unstable2', '1.0.1-unstable.1');
+      builder.serve('one_newer_unstable2', '1.0.1-unstable.2');
+      builder.serve('one_newer_stable', '1.0.0');
+      builder.serve('one_newer_stable', '1.0.1');
+    });
 
     // Constraint everything to the first version.
     await d.appDir({
diff --git a/test/upgrade/report/shows_number_of_changed_dependencies_test.dart b/test/upgrade/report/shows_number_of_changed_dependencies_test.dart
index 91ba5aa..5ba3af6 100644
--- a/test/upgrade/report/shows_number_of_changed_dependencies_test.dart
+++ b/test/upgrade/report/shows_number_of_changed_dependencies_test.dart
@@ -11,10 +11,11 @@
   test(
       'does not show how many newer versions are available for '
       'packages that are locked and not being upgraded', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('b', '1.0.0')
-      ..serve('c', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('b', '1.0.0');
+      builder.serve('c', '2.0.0');
+    });
 
     await d.appDir({'a': 'any'}).create();
 
diff --git a/test/upgrade/report/shows_pub_outdated_test.dart b/test/upgrade/report/shows_pub_outdated_test.dart
index 0fdb322..9c0fa3d 100644
--- a/test/upgrade/report/shows_pub_outdated_test.dart
+++ b/test/upgrade/report/shows_pub_outdated_test.dart
@@ -9,23 +9,24 @@
 
 void main() {
   test('shows pub outdated', () async {
-    await servePackages()
-      ..serve('multiple_newer', '1.0.0')
-      ..serve('multiple_newer', '1.0.1-unstable.1')
-      ..serve('multiple_newer', '1.0.1')
-      ..serve('multiple_newer', '1.0.2-unstable.1')
-      ..serve('multiple_newer', '1.0.2-unstable.2')
-      ..serve('multiple_newer_stable', '1.0.0')
-      ..serve('multiple_newer_stable', '1.0.1')
-      ..serve('multiple_newer_stable', '1.0.2')
-      ..serve('multiple_newer_unstable', '1.0.0')
-      ..serve('multiple_newer_unstable', '1.0.1-unstable.1')
-      ..serve('multiple_newer_unstable', '1.0.1-unstable.2')
-      ..serve('no_newer', '1.0.0')
-      ..serve('one_newer_unstable', '1.0.0')
-      ..serve('one_newer_unstable', '1.0.1-unstable.1')
-      ..serve('one_newer_stable', '1.0.0')
-      ..serve('one_newer_stable', '1.0.1');
+    await servePackages((builder) {
+      builder.serve('multiple_newer', '1.0.0');
+      builder.serve('multiple_newer', '1.0.1-unstable.1');
+      builder.serve('multiple_newer', '1.0.1');
+      builder.serve('multiple_newer', '1.0.2-unstable.1');
+      builder.serve('multiple_newer', '1.0.2-unstable.2');
+      builder.serve('multiple_newer_stable', '1.0.0');
+      builder.serve('multiple_newer_stable', '1.0.1');
+      builder.serve('multiple_newer_stable', '1.0.2');
+      builder.serve('multiple_newer_unstable', '1.0.0');
+      builder.serve('multiple_newer_unstable', '1.0.1-unstable.1');
+      builder.serve('multiple_newer_unstable', '1.0.1-unstable.2');
+      builder.serve('no_newer', '1.0.0');
+      builder.serve('one_newer_unstable', '1.0.0');
+      builder.serve('one_newer_unstable', '1.0.1-unstable.1');
+      builder.serve('one_newer_stable', '1.0.0');
+      builder.serve('one_newer_stable', '1.0.1');
+    });
 
     // Constraint everything to the first version.
     await d.appDir({
diff --git a/test/upgrade/upgrade_major_versions_test.dart b/test/upgrade/upgrade_major_versions_test.dart
index c5f0994..c312717 100644
--- a/test/upgrade/upgrade_major_versions_test.dart
+++ b/test/upgrade/upgrade_major_versions_test.dart
@@ -10,13 +10,14 @@
 void main() {
   group('pub upgrade --major-versions', () {
     test('bumps dependency constraints and shows summary report', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('foo', '2.0.0')
-        ..serve('bar', '0.1.0')
-        ..serve('bar', '0.2.0')
-        ..serve('baz', '1.0.0')
-        ..serve('baz', '1.0.1');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('foo', '2.0.0');
+        builder.serve('bar', '0.1.0');
+        builder.serve('bar', '0.2.0');
+        builder.serve('baz', '1.0.0');
+        builder.serve('baz', '1.0.1');
+      });
 
       await d.appDir({
         'foo': '^1.0.0',
@@ -41,21 +42,23 @@
         'bar': '^0.2.0',
         'baz': '^1.0.0',
       }).validate();
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-        d.packageConfigEntry(name: 'bar', version: '0.2.0'),
-        d.packageConfigEntry(name: 'baz', version: '1.0.1'),
-      ]).validate();
+
+      await d.appPackagesFile({
+        'foo': '2.0.0',
+        'bar': '0.2.0',
+        'baz': '1.0.1',
+      }).validate();
     });
 
     test('bumps dev_dependency constraints and shows summary report', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('foo', '2.0.0')
-        ..serve('bar', '0.1.0')
-        ..serve('bar', '0.2.0')
-        ..serve('baz', '1.0.0')
-        ..serve('baz', '1.0.1');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('foo', '2.0.0');
+        builder.serve('bar', '0.1.0');
+        builder.serve('bar', '0.2.0');
+        builder.serve('baz', '1.0.0');
+        builder.serve('baz', '1.0.1');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -91,18 +94,20 @@
         }),
       ]).validate();
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-        d.packageConfigEntry(name: 'bar', version: '0.2.0'),
-        d.packageConfigEntry(name: 'baz', version: '1.0.1'),
-      ]).validate();
+      await d.appPackagesFile({
+        'foo': '2.0.0',
+        'bar': '0.2.0',
+        'baz': '1.0.1',
+      }).validate();
     });
 
     test('upgrades only the selected package', () async {
-      final server = await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('foo', '2.0.0')
-        ..serve('bar', '0.1.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('foo', '2.0.0');
+        builder.serve('bar', '0.1.0');
+        builder.serve('bar', '0.2.0');
+      });
 
       await d.appDir({
         'foo': '^1.0.0',
@@ -111,8 +116,6 @@
 
       await pubGet();
 
-      server.serve('bar', '0.1.1');
-
       // 1 constraint should be updated
       await pubUpgrade(
         args: ['--major-versions', 'foo'],
@@ -127,17 +130,15 @@
         'bar': '^0.1.0',
       }).validate();
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '2.0.0'),
-        d.packageConfigEntry(name: 'bar', version: '0.1.0'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '2.0.0', 'bar': '0.1.0'}).validate();
     });
 
     test('chooses the latest version where possible', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('foo', '2.0.0')
-        ..serve('foo', '3.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('foo', '2.0.0');
+        builder.serve('foo', '3.0.0');
+      });
 
       await d.appDir({'foo': '^1.0.0'}).create();
 
@@ -161,17 +162,17 @@
         d.file('pubspec.lock', contains('3.0.0'))
       ]).validate();
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '3.0.0'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '3.0.0'}).validate();
     });
 
     test('overridden dependencies - no resolution', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', deps: {'bar': '^2.0.0'})
-        ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'})
-        ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'})
-        ..serve('bar', '2.0.0', deps: {'foo': '^2.0.0'});
+      await servePackages(
+        (builder) => builder
+          ..serve('foo', '1.0.0', deps: {'bar': '^2.0.0'})
+          ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'})
+          ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'})
+          ..serve('bar', '2.0.0', deps: {'foo': '^2.0.0'}),
+      );
 
       await d.dir(appPath, [
         d.pubspec({
@@ -215,25 +216,23 @@
         })
       ]).validate();
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-        d.packageConfigEntry(name: 'bar', version: '1.0.0'),
-      ]).validate();
+      await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate();
     });
 
     test('upgrade should not downgrade any versions', () async {
       /// The version solver solves the packages with the least number of
       /// versions remaining, so we add more 'bar' packages to force 'foo' to be
       /// resolved first
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('foo', '2.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('foo', '2.0.0', pubspec: {
           'dependencies': {'bar': '1.0.0'}
-        })
-        ..serve('bar', '1.0.0')
-        ..serve('bar', '2.0.0')
-        ..serve('bar', '3.0.0')
-        ..serve('bar', '4.0.0');
+        });
+        builder.serve('bar', '1.0.0');
+        builder.serve('bar', '2.0.0');
+        builder.serve('bar', '3.0.0');
+        builder.serve('bar', '4.0.0');
+      });
 
       await d.appDir({
         'foo': '^1.0.0',
@@ -256,10 +255,10 @@
         'bar': '^4.0.0',
       }).validate();
 
-      await d.appPackageConfigFile([
-        d.packageConfigEntry(name: 'foo', version: '1.0.0'),
-        d.packageConfigEntry(name: 'bar', version: '4.0.0'),
-      ]).validate();
+      await d.appPackagesFile({
+        'foo': '1.0.0',
+        'bar': '4.0.0',
+      }).validate();
     });
   });
 }
diff --git a/test/upgrade/upgrade_null_safety_test.dart b/test/upgrade/upgrade_null_safety_test.dart
index 557c589..921c737 100644
--- a/test/upgrade/upgrade_null_safety_test.dart
+++ b/test/upgrade/upgrade_null_safety_test.dart
@@ -9,28 +9,29 @@
 void main() {
   group('pub upgrade --null-safety', () {
     setUp(() async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'environment': {'sdk': '>=2.10.0<3.0.0'},
-        })
-        ..serve('foo', '2.0.0', pubspec: {
+        });
+        builder.serve('foo', '2.0.0', pubspec: {
           'environment': {'sdk': '>=2.12.0<3.0.0'},
-        })
-        ..serve('bar', '1.0.0', pubspec: {
+        });
+        builder.serve('bar', '1.0.0', pubspec: {
           'environment': {'sdk': '>=2.9.0<3.0.0'},
-        })
-        ..serve('bar', '2.0.0-nullsafety.0', pubspec: {
+        });
+        builder.serve('bar', '2.0.0-nullsafety.0', pubspec: {
           'environment': {'sdk': '>=2.12.0<3.0.0'},
-        })
-        ..serve('baz', '1.0.0', pubspec: {
+        });
+        builder.serve('baz', '1.0.0', pubspec: {
           'environment': {'sdk': '>=2.9.0<3.0.0'},
-        })
-        ..serve('has_conflict', '1.0.0', pubspec: {
+        });
+        builder.serve('has_conflict', '1.0.0', pubspec: {
           'environment': {'sdk': '>=2.9.0<3.0.0'},
-        })
-        ..serve('has_conflict', '2.0.0', pubspec: {
+        });
+        builder.serve('has_conflict', '2.0.0', pubspec: {
           'environment': {'sdk': '>=2.13.0<3.0.0'},
         });
+      });
     });
 
     test('upgrades to null-safety versions', () async {
diff --git a/test/validator/gitignore_test.dart b/test/validator/gitignore_test.dart
index f7b02fe..1112934 100644
--- a/test/validator/gitignore_test.dart
+++ b/test/validator/gitignore_test.dart
@@ -2,8 +2,6 @@
 // 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 'dart:io';
-
 import 'package:path/path.dart' as p;
 import 'package:pub/src/exit_codes.dart' as exit_codes;
 import 'package:test/test.dart';
@@ -84,22 +82,4 @@
         exit_codes.DATA,
         workingDirectory: packageRoot);
   });
-
-  test('Should not follow symlinks', () async {
-    await d.git('myapp', [
-      ...d.validPackage.contents,
-    ]).create();
-    final packageRoot = p.join(d.sandbox, 'myapp');
-    await pubGet(
-        environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'},
-        workingDirectory: packageRoot);
-
-    Link(p.join(packageRoot, '.abc', 'itself')).createSync(
-      packageRoot,
-      recursive: true,
-    );
-
-    await expectValidation(contains('Package has 0 warnings.'), 0,
-        workingDirectory: packageRoot);
-  });
 }
diff --git a/test/validator/null_safety_mixed_mode_test.dart b/test/validator/null_safety_mixed_mode_test.dart
index d62d051..e2a8dfb 100644
--- a/test/validator/null_safety_mixed_mode_test.dart
+++ b/test/validator/null_safety_mixed_mode_test.dart
@@ -45,13 +45,14 @@
   group('should consider a package valid if it', () {
     test('is not opting in to null-safety, but depends on package that is',
         () async {
-      final server = await servePackages();
-      server.serve(
-        'foo',
-        '0.0.1',
-        pubspec: {
-          'environment': {'sdk': '>=2.12.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'foo',
+          '0.0.1',
+          pubspec: {
+            'environment': {'sdk': '>=2.12.0<3.0.0'}
+          },
+        ),
       );
 
       await setup(
@@ -60,13 +61,14 @@
     });
     test('is opting in to null-safety and depends on package that is',
         () async {
-      final server = await servePackages();
-      server.serve(
-        'foo',
-        '0.0.1',
-        pubspec: {
-          'environment': {'sdk': '>=2.12.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'foo',
+          '0.0.1',
+          pubspec: {
+            'environment': {'sdk': '>=2.12.0<3.0.0'}
+          },
+        ),
       );
 
       await setup(
@@ -76,13 +78,14 @@
 
     test('is opting in to null-safety has dev_dependency that is not',
         () async {
-      final server = await servePackages();
-      server.serve(
-        'foo',
-        '0.0.1',
-        pubspec: {
-          'environment': {'sdk': '>=2.9.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'foo',
+          '0.0.1',
+          pubspec: {
+            'environment': {'sdk': '>=2.9.0<3.0.0'}
+          },
+        ),
       );
 
       await setup(sdkConstraint: '>=2.12.0 <3.0.0', devDependencies: {
@@ -95,13 +98,14 @@
   group('should consider a package invalid if it', () {
     test('is opting in to null-safety, but depends on package that is not',
         () async {
-      final server = await servePackages();
-      server.serve(
-        'foo',
-        '0.0.1',
-        pubspec: {
-          'environment': {'sdk': '>=2.9.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'foo',
+          '0.0.1',
+          pubspec: {
+            'environment': {'sdk': '>=2.9.0<3.0.0'}
+          },
+        ),
       );
 
       await setup(
@@ -130,16 +134,17 @@
     test(
         'is opting in to null-safety, but depends on package has file opting out',
         () async {
-      final server = await servePackages();
-      server.serve('foo', '0.0.1', pubspec: {
-        'environment': {'sdk': '>=2.12.0<3.0.0'}
-      }, contents: [
-        d.dir('lib', [
-          d.file('foo.dart', '''
+      await servePackages(
+        (server) => server.serve('foo', '0.0.1', pubspec: {
+          'environment': {'sdk': '>=2.12.0<3.0.0'}
+        }, contents: [
+          d.dir('lib', [
+            d.file('foo.dart', '''
 // @dart = 2.9
           ''')
-        ])
-      ]);
+          ])
+        ]),
+      );
 
       await setup(
           sdkConstraint: '>=2.12.0 <3.0.0', dependencies: {'foo': '^0.0.1'});
diff --git a/test/validator/relative_version_numbering_test.dart b/test/validator/relative_version_numbering_test.dart
index 2f3da5c..07e8dbc 100644
--- a/test/validator/relative_version_numbering_test.dart
+++ b/test/validator/relative_version_numbering_test.dart
@@ -13,7 +13,7 @@
 
 Validator validator(Entrypoint entrypoint) => RelativeVersionNumberingValidator(
       entrypoint,
-      Uri.parse(globalServer.url),
+      Uri.parse(globalPackageServer!.url),
     );
 
 Future<void> setup({required String sdkConstraint}) async {
@@ -33,13 +33,14 @@
   group('should consider a package valid if it', () {
     test('is not opting in to null-safety with previous non-null-safe version',
         () async {
-      final server = await servePackages();
-      server.serve(
-        'test_pkg',
-        '0.0.1',
-        pubspec: {
-          'environment': {'sdk': '>=2.9.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'test_pkg',
+          '0.0.1',
+          pubspec: {
+            'environment': {'sdk': '>=2.9.0<3.0.0'}
+          },
+        ),
       );
 
       await setup(sdkConstraint: '>=2.9.0 <3.0.0');
@@ -49,21 +50,23 @@
     test(
         'is not opting in to null-safety with previous non-null-safe version. '
         'Even with a later null-safe version', () async {
-      await servePackages()
-        ..serve(
-          'test_pkg',
-          '0.0.1',
-          pubspec: {
-            'environment': {'sdk': '>=2.9.0<3.0.0'}
-          },
-        )
-        ..serve(
-          'test_pkg',
-          '2.0.0',
-          pubspec: {
-            'environment': {'sdk': '>=2.12.0<3.0.0'}
-          },
-        );
+      await servePackages(
+        (server) => server
+          ..serve(
+            'test_pkg',
+            '0.0.1',
+            pubspec: {
+              'environment': {'sdk': '>=2.9.0<3.0.0'}
+            },
+          )
+          ..serve(
+            'test_pkg',
+            '2.0.0',
+            pubspec: {
+              'environment': {'sdk': '>=2.12.0<3.0.0'}
+            },
+          ),
+      );
 
       await setup(sdkConstraint: '>=2.9.0 <3.0.0');
       await expectValidation(validator);
@@ -71,13 +74,14 @@
 
     test('is opting in to null-safety with previous null-safe version',
         () async {
-      final server = await servePackages();
-      server.serve(
-        'test_pkg',
-        '0.0.1',
-        pubspec: {
-          'environment': {'sdk': '>=2.12.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'test_pkg',
+          '0.0.1',
+          pubspec: {
+            'environment': {'sdk': '>=2.12.0<3.0.0'}
+          },
+        ),
       );
 
       await setup(sdkConstraint: '>=2.12.0 <3.0.0');
@@ -87,13 +91,14 @@
     test(
         'is opting in to null-safety using a pre-release of 2.12.0 '
         'with previous null-safe version', () async {
-      final server = await servePackages();
-      server.serve(
-        'test_pkg',
-        '0.0.1',
-        pubspec: {
-          'environment': {'sdk': '>=2.12.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'test_pkg',
+          '0.0.1',
+          pubspec: {
+            'environment': {'sdk': '>=2.12.0<3.0.0'}
+          },
+        ),
       );
 
       await setup(sdkConstraint: '>=2.12.0-dev <3.0.0');
@@ -103,21 +108,23 @@
     test(
         'is opting in to null-safety with previous null-safe version. '
         'Even with a later non-null-safe version', () async {
-      await servePackages()
-        ..serve(
-          'test_pkg',
-          '0.0.1',
-          pubspec: {
-            'environment': {'sdk': '>=2.12.0<3.0.0'}
-          },
-        )
-        ..serve(
-          'test_pkg',
-          '2.0.1',
-          pubspec: {
-            'environment': {'sdk': '>=2.9.0<3.0.0'}
-          },
-        );
+      await servePackages(
+        (server) => server
+          ..serve(
+            'test_pkg',
+            '0.0.1',
+            pubspec: {
+              'environment': {'sdk': '>=2.12.0<3.0.0'}
+            },
+          )
+          ..serve(
+            'test_pkg',
+            '2.0.1',
+            pubspec: {
+              'environment': {'sdk': '>=2.9.0<3.0.0'}
+            },
+          ),
+      );
 
       await setup(sdkConstraint: '>=2.12.0 <3.0.0');
       await expectValidation(validator);
@@ -125,13 +132,13 @@
 
     test('is opting in to null-safety with no existing versions', () async {
       await setup(sdkConstraint: '>=2.12.0 <3.0.0');
-      await servePackages();
+      await servePackages((x) => x);
       await expectValidation(validator);
     });
 
     test('is not opting in to null-safety with no existing versions', () async {
       await setup(sdkConstraint: '>=2.9.0 <3.0.0');
-      await servePackages();
+      await servePackages((x) => x);
 
       await expectValidation(validator);
     });
@@ -139,21 +146,23 @@
     test(
         'is not opting in to null-safety with previous null-safe stable version. '
         'With an in-between not null-safe prerelease', () async {
-      await servePackages()
-        ..serve(
-          'test_pkg',
-          '0.0.1',
-          pubspec: {
-            'environment': {'sdk': '>=2.12.0<3.0.0'}
-          },
-        )
-        ..serve(
-          'test_pkg',
-          '0.0.2-dev',
-          pubspec: {
-            'environment': {'sdk': '>=2.9.0<3.0.0'}
-          },
-        );
+      await servePackages(
+        (server) => server
+          ..serve(
+            'test_pkg',
+            '0.0.1',
+            pubspec: {
+              'environment': {'sdk': '>=2.12.0<3.0.0'}
+            },
+          )
+          ..serve(
+            'test_pkg',
+            '0.0.2-dev',
+            pubspec: {
+              'environment': {'sdk': '>=2.9.0<3.0.0'}
+            },
+          ),
+      );
 
       await setup(sdkConstraint: '>=2.9.0 <3.0.0');
       await expectValidation(validator);
@@ -162,21 +171,23 @@
     test(
         'opts in to null-safety, with previous stable version not-null-safe. '
         'With an in-between non-null-safe prerelease', () async {
-      await servePackages()
-        ..serve(
-          'test_pkg',
-          '0.0.1',
-          pubspec: {
-            'environment': {'sdk': '>=2.9.0<3.0.0'}
-          },
-        )
-        ..serve(
-          'test_pkg',
-          '0.0.2-dev',
-          pubspec: {
-            'environment': {'sdk': '>=2.12.0<3.0.0'}
-          },
-        );
+      await servePackages(
+        (server) => server
+          ..serve(
+            'test_pkg',
+            '0.0.1',
+            pubspec: {
+              'environment': {'sdk': '>=2.9.0<3.0.0'}
+            },
+          )
+          ..serve(
+            'test_pkg',
+            '0.0.2-dev',
+            pubspec: {
+              'environment': {'sdk': '>=2.12.0<3.0.0'}
+            },
+          ),
+      );
 
       await setup(sdkConstraint: '>=2.12.0 <3.0.0');
       await expectValidation(validator);
@@ -186,13 +197,14 @@
   group('should warn if ', () {
     test('opts in to null-safety, with previous version not-null-safe',
         () async {
-      final server = await servePackages();
-      server.serve(
-        'test_pkg',
-        '0.0.1',
-        pubspec: {
-          'environment': {'sdk': '>=2.9.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'test_pkg',
+          '0.0.1',
+          pubspec: {
+            'environment': {'sdk': '>=2.9.0<3.0.0'}
+          },
+        ),
       );
 
       await setup(sdkConstraint: '>=2.12.0 <3.0.0');
@@ -203,13 +215,14 @@
         'is not opting in to null-safety with no existing stable versions. '
         'With a previous in-between null-safe prerelease', () async {
       await setup(sdkConstraint: '>=2.9.0 <3.0.0');
-      final server = await servePackages();
-      server.serve(
-        'test_pkg',
-        '0.0.2-dev',
-        pubspec: {
-          'environment': {'sdk': '>=2.12.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'test_pkg',
+          '0.0.2-dev',
+          pubspec: {
+            'environment': {'sdk': '>=2.12.0<3.0.0'}
+          },
+        ),
       );
 
       await expectValidation(validator, hints: isNotEmpty);
@@ -217,21 +230,23 @@
     test(
         'is not opting in to null-safety with previous non-null-safe stable version. '
         'With an in-between null-safe prerelease', () async {
-      await servePackages()
-        ..serve(
-          'test_pkg',
-          '0.0.1',
-          pubspec: {
-            'environment': {'sdk': '>=2.9.0<3.0.0'}
-          },
-        )
-        ..serve(
-          'test_pkg',
-          '0.0.2-dev',
-          pubspec: {
-            'environment': {'sdk': '>=2.12.0<3.0.0'}
-          },
-        );
+      await servePackages(
+        (server) => server
+          ..serve(
+            'test_pkg',
+            '0.0.1',
+            pubspec: {
+              'environment': {'sdk': '>=2.9.0<3.0.0'}
+            },
+          )
+          ..serve(
+            'test_pkg',
+            '0.0.2-dev',
+            pubspec: {
+              'environment': {'sdk': '>=2.12.0<3.0.0'}
+            },
+          ),
+      );
 
       await setup(sdkConstraint: '>=2.9.0 <3.0.0');
       await expectValidation(validator, hints: isNotEmpty);
@@ -240,21 +255,23 @@
     test(
         'opts in to null-safety, with previous version not-null-safe. '
         'Even with a later null-safe version', () async {
-      await servePackages()
-        ..serve(
-          'test_pkg',
-          '0.0.1',
-          pubspec: {
-            'environment': {'sdk': '>=2.9.0<3.0.0'}
-          },
-        )
-        ..serve(
-          'test_pkg',
-          '2.0.0',
-          pubspec: {
-            'environment': {'sdk': '>=2.12.0<3.0.0'}
-          },
-        );
+      await servePackages(
+        (server) => server
+          ..serve(
+            'test_pkg',
+            '0.0.1',
+            pubspec: {
+              'environment': {'sdk': '>=2.9.0<3.0.0'}
+            },
+          )
+          ..serve(
+            'test_pkg',
+            '2.0.0',
+            pubspec: {
+              'environment': {'sdk': '>=2.12.0<3.0.0'}
+            },
+          ),
+      );
 
       await setup(sdkConstraint: '>=2.12.0 <3.0.0');
       await expectValidation(validator, hints: isNotEmpty);
@@ -262,13 +279,14 @@
 
     test('is not opting in to null-safety with previous null-safe version',
         () async {
-      final server = await servePackages();
-      server.serve(
-        'test_pkg',
-        '0.0.1',
-        pubspec: {
-          'environment': {'sdk': '>=2.12.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'test_pkg',
+          '0.0.1',
+          pubspec: {
+            'environment': {'sdk': '>=2.12.0<3.0.0'}
+          },
+        ),
       );
 
       await setup(sdkConstraint: '>=2.9.0 <3.0.0');
@@ -278,21 +296,23 @@
     test(
         'is not opting in to null-safety with previous null-safe version. '
         'Even with a later non-null-safe version', () async {
-      await servePackages()
-        ..serve(
-          'test_pkg',
-          '0.0.1',
-          pubspec: {
-            'environment': {'sdk': '>=2.12.0<3.0.0'}
-          },
-        )
-        ..serve(
-          'test_pkg',
-          '2.0.0',
-          pubspec: {
-            'environment': {'sdk': '>=2.9.0<3.0.0'}
-          },
-        );
+      await servePackages(
+        (server) => server
+          ..serve(
+            'test_pkg',
+            '0.0.1',
+            pubspec: {
+              'environment': {'sdk': '>=2.12.0<3.0.0'}
+            },
+          )
+          ..serve(
+            'test_pkg',
+            '2.0.0',
+            pubspec: {
+              'environment': {'sdk': '>=2.9.0<3.0.0'}
+            },
+          ),
+      );
 
       await setup(sdkConstraint: '>=2.9.0 <3.0.0');
       await expectValidation(validator, hints: isNotEmpty);
@@ -301,21 +321,23 @@
     test(
         'is opting in to null-safety with previous null-safe stable version. '
         'with an in-between non-null-safe prerelease', () async {
-      await servePackages()
-        ..serve(
-          'test_pkg',
-          '0.0.1',
-          pubspec: {
-            'environment': {'sdk': '>=2.12.0<3.0.0'}
-          },
-        )
-        ..serve(
-          'test_pkg',
-          '0.0.2-dev',
-          pubspec: {
-            'environment': {'sdk': '>=2.9.0<3.0.0'}
-          },
-        );
+      await servePackages(
+        (server) => server
+          ..serve(
+            'test_pkg',
+            '0.0.1',
+            pubspec: {
+              'environment': {'sdk': '>=2.12.0<3.0.0'}
+            },
+          )
+          ..serve(
+            'test_pkg',
+            '0.0.2-dev',
+            pubspec: {
+              'environment': {'sdk': '>=2.9.0<3.0.0'}
+            },
+          ),
+      );
 
       await setup(sdkConstraint: '>=2.12.0 <3.0.0');
       await expectValidation(validator, hints: isNotEmpty);
@@ -325,13 +347,14 @@
         'is opting in to null-safety with no existing stable versions. '
         'With a previous non-null-safe prerelease', () async {
       await setup(sdkConstraint: '>=2.12.0 <3.0.0');
-      final server = await servePackages();
-      server.serve(
-        'test_pkg',
-        '0.0.2-dev',
-        pubspec: {
-          'environment': {'sdk': '>=2.9.0<3.0.0'}
-        },
+      await servePackages(
+        (server) => server.serve(
+          'test_pkg',
+          '0.0.2-dev',
+          pubspec: {
+            'environment': {'sdk': '>=2.9.0<3.0.0'}
+          },
+        ),
       );
       await expectValidation(validator, hints: isNotEmpty);
     });
diff --git a/test/version_solver_test.dart b/test/version_solver_test.dart
index d36a16f..261c493 100644
--- a/test/version_solver_test.dart
+++ b/test/version_solver_test.dart
@@ -40,13 +40,14 @@
   });
 
   test('simple dependency tree', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'aa': '1.0.0', 'ab': '1.0.0'})
-      ..serve('aa', '1.0.0')
-      ..serve('ab', '1.0.0')
-      ..serve('b', '1.0.0', deps: {'ba': '1.0.0', 'bb': '1.0.0'})
-      ..serve('ba', '1.0.0')
-      ..serve('bb', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'aa': '1.0.0', 'ab': '1.0.0'});
+      builder.serve('aa', '1.0.0');
+      builder.serve('ab', '1.0.0');
+      builder.serve('b', '1.0.0', deps: {'ba': '1.0.0', 'bb': '1.0.0'});
+      builder.serve('ba', '1.0.0');
+      builder.serve('bb', '1.0.0');
+    });
 
     await d.appDir({'a': '1.0.0', 'b': '1.0.0'}).create();
     await expectResolves(result: {
@@ -60,14 +61,15 @@
   });
 
   test('shared dependency with overlapping constraints', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'shared': '>=2.0.0 <4.0.0'})
-      ..serve('b', '1.0.0', deps: {'shared': '>=3.0.0 <5.0.0'})
-      ..serve('shared', '2.0.0')
-      ..serve('shared', '3.0.0')
-      ..serve('shared', '3.6.9')
-      ..serve('shared', '4.0.0')
-      ..serve('shared', '5.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'shared': '>=2.0.0 <4.0.0'});
+      builder.serve('b', '1.0.0', deps: {'shared': '>=3.0.0 <5.0.0'});
+      builder.serve('shared', '2.0.0');
+      builder.serve('shared', '3.0.0');
+      builder.serve('shared', '3.6.9');
+      builder.serve('shared', '4.0.0');
+      builder.serve('shared', '5.0.0');
+    });
 
     await d.appDir({'a': '1.0.0', 'b': '1.0.0'}).create();
     await expectResolves(
@@ -77,15 +79,16 @@
   test(
       'shared dependency where dependent version in turn affects other '
       'dependencies', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '1.0.1', deps: {'bang': '1.0.0'})
-      ..serve('foo', '1.0.2', deps: {'whoop': '1.0.0'})
-      ..serve('foo', '1.0.3', deps: {'zoop': '1.0.0'})
-      ..serve('bar', '1.0.0', deps: {'foo': '<=1.0.1'})
-      ..serve('bang', '1.0.0')
-      ..serve('whoop', '1.0.0')
-      ..serve('zoop', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '1.0.1', deps: {'bang': '1.0.0'});
+      builder.serve('foo', '1.0.2', deps: {'whoop': '1.0.0'});
+      builder.serve('foo', '1.0.3', deps: {'zoop': '1.0.0'});
+      builder.serve('bar', '1.0.0', deps: {'foo': '<=1.0.1'});
+      builder.serve('bang', '1.0.0');
+      builder.serve('whoop', '1.0.0');
+      builder.serve('zoop', '1.0.0');
+    });
 
     await d.appDir({'foo': '<=1.0.2', 'bar': '1.0.0'}).create();
     await expectResolves(
@@ -93,21 +96,23 @@
   });
 
   test('circular dependency', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'})
-      ..serve('bar', '1.0.0', deps: {'foo': '1.0.0'});
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'});
+      builder.serve('bar', '1.0.0', deps: {'foo': '1.0.0'});
+    });
 
     await d.appDir({'foo': '1.0.0'}).create();
     await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'});
   });
 
   test('removed dependency', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0')
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '2.0.0', deps: {'baz': '1.0.0'})
-      ..serve('baz', '1.0.0', deps: {'foo': '2.0.0'});
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0');
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '2.0.0', deps: {'baz': '1.0.0'});
+      builder.serve('baz', '1.0.0', deps: {'foo': '2.0.0'});
+    });
 
     await d.appDir({'foo': '1.0.0', 'bar': 'any'}).create();
     await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'}, tries: 2);
@@ -116,13 +121,14 @@
 
 void withLockFile() {
   test('with compatible locked dependency', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'})
-      ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'})
-      ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'})
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '1.0.1')
-      ..serve('bar', '1.0.2');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'});
+      builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'});
+      builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'});
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '1.0.1');
+      builder.serve('bar', '1.0.2');
+    });
 
     await d.appDir({'foo': '1.0.1'}).create();
     await expectResolves(result: {'foo': '1.0.1', 'bar': '1.0.1'});
@@ -132,13 +138,14 @@
   });
 
   test('with incompatible locked dependency', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'})
-      ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'})
-      ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'})
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '1.0.1')
-      ..serve('bar', '1.0.2');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'});
+      builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'});
+      builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'});
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '1.0.1');
+      builder.serve('bar', '1.0.2');
+    });
 
     await d.appDir({'foo': '1.0.1'}).create();
     await expectResolves(result: {'foo': '1.0.1', 'bar': '1.0.1'});
@@ -148,14 +155,15 @@
   });
 
   test('with unrelated locked dependency', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'})
-      ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'})
-      ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'})
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '1.0.1')
-      ..serve('bar', '1.0.2')
-      ..serve('baz', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'});
+      builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'});
+      builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'});
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '1.0.1');
+      builder.serve('bar', '1.0.2');
+      builder.serve('baz', '1.0.0');
+    });
 
     await d.appDir({'baz': '1.0.0'}).create();
     await expectResolves(result: {'baz': '1.0.0'});
@@ -167,16 +175,17 @@
   test(
       'unlocks dependencies if necessary to ensure that a new '
       'dependency is satisfied', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '<2.0.0'})
-      ..serve('bar', '1.0.0', deps: {'baz': '<2.0.0'})
-      ..serve('baz', '1.0.0', deps: {'qux': '<2.0.0'})
-      ..serve('qux', '1.0.0')
-      ..serve('foo', '2.0.0', deps: {'bar': '<3.0.0'})
-      ..serve('bar', '2.0.0', deps: {'baz': '<3.0.0'})
-      ..serve('baz', '2.0.0', deps: {'qux': '<3.0.0'})
-      ..serve('qux', '2.0.0')
-      ..serve('newdep', '2.0.0', deps: {'baz': '>=1.5.0'});
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'});
+      builder.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'});
+      builder.serve('baz', '1.0.0', deps: {'qux': '<2.0.0'});
+      builder.serve('qux', '1.0.0');
+      builder.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'});
+      builder.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'});
+      builder.serve('baz', '2.0.0', deps: {'qux': '<3.0.0'});
+      builder.serve('qux', '2.0.0');
+      builder.serve('newdep', '2.0.0', deps: {'baz': '>=1.5.0'});
+    });
 
     await d.appDir({'foo': '1.0.0'}).create();
     await expectResolves(result: {
@@ -200,10 +209,11 @@
   test(
       "produces a nice message for a locked dependency that's the only "
       'version of its package', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '>=2.0.0'})
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '>=2.0.0'});
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '2.0.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
     await expectResolves(result: {'foo': '1.0.0', 'bar': '2.0.0'});
@@ -219,27 +229,30 @@
 
 void rootDependency() {
   test('with root source', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', deps: {'myapp': 'any'});
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'myapp': 'any'});
+    });
 
     await d.appDir({'foo': '1.0.0'}).create();
     await expectResolves(result: {'foo': '1.0.0'});
   });
 
   test('with mismatched sources', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'myapp': 'any'})
-      ..serve('bar', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'myapp': 'any'});
+      builder.serve('bar', '1.0.0', deps: {
         'myapp': {'git': 'http://nowhere.com/'}
       });
+    });
 
     await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create();
     await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'});
   });
 
   test('with wrong version', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', deps: {'myapp': '>0.0.0'});
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'myapp': '>0.0.0'});
+    });
 
     await d.appDir({'foo': '1.0.0'}).create();
     await expectResolves(error: equalsIgnoringWhitespace('''
@@ -252,9 +265,10 @@
 
 void devDependency() {
   test("includes root package's dev dependencies", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('bar', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -267,9 +281,10 @@
   });
 
   test("includes dev dependency's transitive dependencies", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'})
-      ..serve('bar', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'});
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -282,9 +297,10 @@
   });
 
   test("ignores transitive dependency's dev dependencies", () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'dev_dependencies': {'bar': '1.0.0'}
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'dev_dependencies': {'bar': '1.0.0'}
+      });
     });
 
     await d.appDir({'foo': '1.0.0'}).create();
@@ -293,10 +309,11 @@
 
   group('with both a dev and regular dependency', () {
     test('succeeds when both are satisfied', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('foo', '2.0.0')
-        ..serve('foo', '3.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('foo', '2.0.0');
+        builder.serve('foo', '3.0.0');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -310,8 +327,9 @@
     });
 
     test("fails when main dependency isn't satisfied", () async {
-      final server = await servePackages();
-      server.serve('foo', '3.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '3.0.0');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -329,8 +347,9 @@
     });
 
     test("fails when dev dependency isn't satisfied", () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -348,8 +367,9 @@
     });
 
     test('fails when dev and main constraints are incompatible', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -366,8 +386,9 @@
     });
 
     test('fails when dev and main sources are incompatible', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -386,8 +407,9 @@
     });
 
     test('fails when dev and main descriptions are incompatible', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.dir(appPath, [
         d.pubspec({
@@ -411,9 +433,10 @@
 
 void unsolvable() {
   test('no version that matches constraint', () async {
-    await servePackages()
-      ..serve('foo', '2.0.0')
-      ..serve('foo', '2.1.3');
+    await servePackages((builder) {
+      builder.serve('foo', '2.0.0');
+      builder.serve('foo', '2.1.3');
+    });
 
     await d.appDir({'foo': '>=1.0.0 <2.0.0'}).create();
     await expectResolves(error: equalsIgnoringWhitespace("""
@@ -423,11 +446,12 @@
   });
 
   test('no version that matches combined constraint', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'shared': '>=2.0.0 <3.0.0'})
-      ..serve('bar', '1.0.0', deps: {'shared': '>=2.9.0 <4.0.0'})
-      ..serve('shared', '2.5.0')
-      ..serve('shared', '3.5.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'shared': '>=2.0.0 <3.0.0'});
+      builder.serve('bar', '1.0.0', deps: {'shared': '>=2.9.0 <4.0.0'});
+      builder.serve('shared', '2.5.0');
+      builder.serve('shared', '3.5.0');
+    });
 
     await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create();
     await expectResolves(error: equalsIgnoringWhitespace('''
@@ -442,11 +466,12 @@
   });
 
   test('disjoint constraints', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'shared': '<=2.0.0'})
-      ..serve('bar', '1.0.0', deps: {'shared': '>3.0.0'})
-      ..serve('shared', '2.0.0')
-      ..serve('shared', '4.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'shared': '<=2.0.0'});
+      builder.serve('bar', '1.0.0', deps: {'shared': '>3.0.0'});
+      builder.serve('shared', '2.0.0');
+      builder.serve('shared', '4.0.0');
+    });
 
     await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create();
     await expectResolves(error: equalsIgnoringWhitespace('''
@@ -458,18 +483,20 @@
   });
 
   test('mismatched descriptions', () async {
-    var otherServer = await startPackageServer();
-    otherServer.serve('shared', '1.0.0');
+    var otherServer = await PackageServer.start((builder) {
+      builder.serve('shared', '1.0.0');
+    });
 
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'shared': '1.0.0'})
-      ..serve('bar', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'shared': '1.0.0'});
+      builder.serve('bar', '1.0.0', deps: {
         'shared': {
           'hosted': {'name': 'shared', 'url': otherServer.url},
           'version': '1.0.0'
         }
-      })
-      ..serve('shared', '1.0.0');
+      });
+      builder.serve('shared', '1.0.0');
+    });
 
     await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create();
 
@@ -488,12 +515,13 @@
   test('mismatched sources', () async {
     await d.dir('shared', [d.libPubspec('shared', '1.0.0')]).create();
 
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'shared': '1.0.0'})
-      ..serve('bar', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'shared': '1.0.0'});
+      builder.serve('bar', '1.0.0', deps: {
         'shared': {'path': p.join(d.sandbox, 'shared')}
-      })
-      ..serve('shared', '1.0.0');
+      });
+      builder.serve('shared', '1.0.0');
+    });
 
     await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create();
     await expectResolves(error: equalsIgnoringWhitespace('''
@@ -506,11 +534,12 @@
   });
 
   test('no valid solution', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'b': '1.0.0'})
-      ..serve('a', '2.0.0', deps: {'b': '2.0.0'})
-      ..serve('b', '1.0.0', deps: {'a': '2.0.0'})
-      ..serve('b', '2.0.0', deps: {'a': '1.0.0'});
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'b': '1.0.0'});
+      builder.serve('a', '2.0.0', deps: {'b': '2.0.0'});
+      builder.serve('b', '1.0.0', deps: {'a': '2.0.0'});
+      builder.serve('b', '2.0.0', deps: {'a': '1.0.0'});
+    });
 
     await d.appDir({'a': 'any', 'b': 'any'}).create();
     await expectResolves(error: equalsIgnoringWhitespace('''
@@ -525,9 +554,10 @@
 
   // This is a regression test for #15550.
   test('no version that matches while backtracking', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('b', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('b', '1.0.0');
+    });
 
     await d.appDir({'a': 'any', 'b': '>1.0.0'}).create();
     await expectResolves(error: equalsIgnoringWhitespace("""
@@ -538,18 +568,19 @@
 
   // This is a regression test for #18300.
   test('issue 18300', () async {
-    await servePackages()
-      ..serve('analyzer', '0.12.2')
-      ..serve('angular', '0.10.0',
-          deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'})
-      ..serve('angular', '0.9.11',
-          deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'})
-      ..serve('angular', '0.9.10',
-          deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'})
-      ..serve('collection', '0.9.0')
-      ..serve('collection', '0.9.1')
-      ..serve('di', '0.0.37', deps: {'analyzer': '>=0.13.0 <0.14.0'})
-      ..serve('di', '0.0.36', deps: {'analyzer': '>=0.13.0 <0.14.0'});
+    await servePackages((builder) {
+      builder.serve('analyzer', '0.12.2');
+      builder.serve('angular', '0.10.0',
+          deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'});
+      builder.serve('angular', '0.9.11',
+          deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'});
+      builder.serve('angular', '0.9.10',
+          deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'});
+      builder.serve('collection', '0.9.0');
+      builder.serve('collection', '0.9.1');
+      builder.serve('di', '0.0.37', deps: {'analyzer': '>=0.13.0 <0.14.0'});
+      builder.serve('di', '0.0.36', deps: {'analyzer': '>=0.13.0 <0.14.0'});
+    });
 
     await d.appDir({'angular': 'any', 'collection': 'any'}).create();
     await expectResolves(error: equalsIgnoringWhitespace('''
@@ -589,16 +620,17 @@
   });
 
   test('fail if all versions have bad source in dep', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {
         'bar': {'bad': 'any'}
-      })
-      ..serve('foo', '1.0.1', deps: {
+      });
+      builder.serve('foo', '1.0.1', deps: {
         'baz': {'bad': 'any'}
-      })
-      ..serve('foo', '1.0.2', deps: {
+      });
+      builder.serve('foo', '1.0.2', deps: {
         'bang': {'bad': 'any'}
       });
+    });
 
     await d.appDir({'foo': 'any'}).create();
     await expectResolves(error: equalsIgnoringWhitespace('''
@@ -614,15 +646,16 @@
   });
 
   test('ignore versions with bad source in dep', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': 'any'})
-      ..serve('foo', '1.0.1', deps: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': 'any'});
+      builder.serve('foo', '1.0.1', deps: {
         'bar': {'bad': 'any'}
-      })
-      ..serve('foo', '1.0.2', deps: {
+      });
+      builder.serve('foo', '1.0.2', deps: {
         'bar': {'bad': 'any'}
-      })
-      ..serve('bar', '1.0.0');
+      });
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
     await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'}, tries: 2);
@@ -630,10 +663,11 @@
 
   // Issue 1853
   test('reports a nice error across a collapsed cause', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': 'any'})
-      ..serve('bar', '1.0.0', deps: {'baz': 'any'})
-      ..serve('baz', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': 'any'});
+      builder.serve('bar', '1.0.0', deps: {'baz': 'any'});
+      builder.serve('baz', '1.0.0');
+    });
     await d.dir('baz', [d.libPubspec('baz', '1.0.0')]).create();
 
     await d.appDir({
@@ -651,24 +685,28 @@
 
 void backtracking() {
   test('circular dependency on older version', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '2.0.0', deps: {'b': '1.0.0'})
-      ..serve('b', '1.0.0', deps: {'a': '1.0.0'});
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '2.0.0', deps: {'b': '1.0.0'});
+      builder.serve('b', '1.0.0', deps: {'a': '1.0.0'});
+    });
 
     await d.appDir({'a': '>=1.0.0'}).create();
     await expectResolves(result: {'a': '1.0.0'}, tries: 2);
   });
 
   test('diamond dependency graph', () async {
-    await servePackages()
-      ..serve('a', '2.0.0', deps: {'c': '^1.0.0'})
-      ..serve('a', '1.0.0')
-      ..serve('b', '2.0.0', deps: {'c': '^3.0.0'})
-      ..serve('b', '1.0.0', deps: {'c': '^2.0.0'})
-      ..serve('c', '3.0.0')
-      ..serve('c', '2.0.0')
-      ..serve('c', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '2.0.0', deps: {'c': '^1.0.0'});
+      builder.serve('a', '1.0.0');
+
+      builder.serve('b', '2.0.0', deps: {'c': '^3.0.0'});
+      builder.serve('b', '1.0.0', deps: {'c': '^2.0.0'});
+
+      builder.serve('c', '3.0.0');
+      builder.serve('c', '2.0.0');
+      builder.serve('c', '1.0.0');
+    });
 
     await d.appDir({'a': 'any', 'b': 'any'}).create();
     await expectResolves(result: {'a': '1.0.0', 'b': '2.0.0', 'c': '3.0.0'});
@@ -678,16 +716,20 @@
   // requirement only exists because of both a and b. The solver should be able
   // to deduce c 2.0.0's incompatibility and select c 1.0.0 instead.
   test('backjumps after a partial satisfier', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'x': '>=1.0.0'})
-      ..serve('b', '1.0.0', deps: {'x': '<2.0.0'})
-      ..serve('c', '1.0.0')
-      ..serve('c', '2.0.0', deps: {'a': 'any', 'b': 'any'})
-      ..serve('x', '0.0.0')
-      ..serve('x', '1.0.0', deps: {'y': '1.0.0'})
-      ..serve('x', '2.0.0')
-      ..serve('y', '1.0.0')
-      ..serve('y', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'x': '>=1.0.0'});
+      builder.serve('b', '1.0.0', deps: {'x': '<2.0.0'});
+
+      builder.serve('c', '1.0.0');
+      builder.serve('c', '2.0.0', deps: {'a': 'any', 'b': 'any'});
+
+      builder.serve('x', '0.0.0');
+      builder.serve('x', '1.0.0', deps: {'y': '1.0.0'});
+      builder.serve('x', '2.0.0');
+
+      builder.serve('y', '1.0.0');
+      builder.serve('y', '2.0.0');
+    });
 
     await d.appDir({'c': 'any', 'y': '^2.0.0'}).create();
     await expectResolves(result: {'c': '1.0.0', 'y': '2.0.0'}, tries: 2);
@@ -696,15 +738,16 @@
   // This matches the Branching Error Reporting example in the version solver
   // documentation, and tests that we display line numbers correctly.
   test('branching error reporting', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'a': '^1.0.0', 'b': '^1.0.0'})
-      ..serve('foo', '1.1.0', deps: {'x': '^1.0.0', 'y': '^1.0.0'})
-      ..serve('a', '1.0.0', deps: {'b': '^2.0.0'})
-      ..serve('b', '1.0.0')
-      ..serve('b', '2.0.0')
-      ..serve('x', '1.0.0', deps: {'y': '^2.0.0'})
-      ..serve('y', '1.0.0')
-      ..serve('y', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'a': '^1.0.0', 'b': '^1.0.0'});
+      builder.serve('foo', '1.1.0', deps: {'x': '^1.0.0', 'y': '^1.0.0'});
+      builder.serve('a', '1.0.0', deps: {'b': '^2.0.0'});
+      builder.serve('b', '1.0.0');
+      builder.serve('b', '2.0.0');
+      builder.serve('x', '1.0.0', deps: {'y': '^2.0.0'});
+      builder.serve('y', '1.0.0');
+      builder.serve('y', '2.0.0');
+    });
 
     await d.appDir({'foo': '^1.0.0'}).create();
     await expectResolves(
@@ -729,13 +772,14 @@
   // will resolve the problem. This test validates that b, which is farther
   // in the dependency graph from myapp is downgraded first.
   test('rolls back leaf versions first', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'b': 'any'})
-      ..serve('a', '2.0.0', deps: {'b': 'any', 'c': '2.0.0'})
-      ..serve('b', '1.0.0')
-      ..serve('b', '2.0.0', deps: {'c': '1.0.0'})
-      ..serve('c', '1.0.0')
-      ..serve('c', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'b': 'any'});
+      builder.serve('a', '2.0.0', deps: {'b': 'any', 'c': '2.0.0'});
+      builder.serve('b', '1.0.0');
+      builder.serve('b', '2.0.0', deps: {'c': '1.0.0'});
+      builder.serve('c', '1.0.0');
+      builder.serve('c', '2.0.0');
+    });
 
     await d.appDir({'a': 'any'}).create();
     await expectResolves(result: {'a': '2.0.0', 'b': '1.0.0', 'c': '2.0.0'});
@@ -744,14 +788,15 @@
   // Only one version of baz, so foo and bar will have to downgrade until they
   // reach it.
   test('simple transitive', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'})
-      ..serve('foo', '2.0.0', deps: {'bar': '2.0.0'})
-      ..serve('foo', '3.0.0', deps: {'bar': '3.0.0'})
-      ..serve('bar', '1.0.0', deps: {'baz': 'any'})
-      ..serve('bar', '2.0.0', deps: {'baz': '2.0.0'})
-      ..serve('bar', '3.0.0', deps: {'baz': '3.0.0'})
-      ..serve('baz', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'});
+      builder.serve('foo', '2.0.0', deps: {'bar': '2.0.0'});
+      builder.serve('foo', '3.0.0', deps: {'bar': '3.0.0'});
+      builder.serve('bar', '1.0.0', deps: {'baz': 'any'});
+      builder.serve('bar', '2.0.0', deps: {'baz': '2.0.0'});
+      builder.serve('bar', '3.0.0', deps: {'baz': '3.0.0'});
+      builder.serve('baz', '1.0.0');
+    });
 
     await d.appDir({'foo': 'any'}).create();
     await expectResolves(
@@ -763,13 +808,14 @@
   // make sure b has more versions than a so that the solver tries a first
   // since it sorts sibling dependencies by number of versions.
   test('backjump to nearer unsatisfied package', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'c': '1.0.0'})
-      ..serve('a', '2.0.0', deps: {'c': '2.0.0-nonexistent'})
-      ..serve('b', '1.0.0')
-      ..serve('b', '2.0.0')
-      ..serve('b', '3.0.0')
-      ..serve('c', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'c': '1.0.0'});
+      builder.serve('a', '2.0.0', deps: {'c': '2.0.0-nonexistent'});
+      builder.serve('b', '1.0.0');
+      builder.serve('b', '2.0.0');
+      builder.serve('b', '3.0.0');
+      builder.serve('c', '1.0.0');
+    });
 
     await d.appDir({'a': 'any', 'b': 'any'}).create();
     await expectResolves(
@@ -793,17 +839,18 @@
   test('successful backjump to conflicting source', () async {
     await d.dir('a', [d.libPubspec('a', '1.0.0')]).create();
 
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('b', '1.0.0', deps: {'a': 'any'})
-      ..serve('b', '2.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('b', '1.0.0', deps: {'a': 'any'});
+      builder.serve('b', '2.0.0', deps: {
         'a': {'path': p.join(d.sandbox, 'a')}
-      })
-      ..serve('c', '1.0.0')
-      ..serve('c', '2.0.0')
-      ..serve('c', '3.0.0')
-      ..serve('c', '4.0.0')
-      ..serve('c', '5.0.0');
+      });
+      builder.serve('c', '1.0.0');
+      builder.serve('c', '2.0.0');
+      builder.serve('c', '3.0.0');
+      builder.serve('c', '4.0.0');
+      builder.serve('c', '5.0.0');
+    });
 
     await d.appDir({'a': 'any', 'b': 'any', 'c': 'any'}).create();
     await expectResolves(result: {'a': '1.0.0', 'b': '1.0.0', 'c': '5.0.0'});
@@ -811,22 +858,24 @@
 
   // Like the above test, but for a conflicting description.
   test('successful backjump to conflicting description', () async {
-    var otherServer = await startPackageServer();
-    otherServer.serve('a', '1.0.0');
+    var otherServer = await PackageServer.start((builder) {
+      builder.serve('a', '1.0.0');
+    });
 
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('b', '1.0.0', deps: {'a': 'any'})
-      ..serve('b', '2.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('b', '1.0.0', deps: {'a': 'any'});
+      builder.serve('b', '2.0.0', deps: {
         'a': {
           'hosted': {'name': 'a', 'url': otherServer.url}
         }
-      })
-      ..serve('c', '1.0.0')
-      ..serve('c', '2.0.0')
-      ..serve('c', '3.0.0')
-      ..serve('c', '4.0.0')
-      ..serve('c', '5.0.0');
+      });
+      builder.serve('c', '1.0.0');
+      builder.serve('c', '2.0.0');
+      builder.serve('c', '3.0.0');
+      builder.serve('c', '4.0.0');
+      builder.serve('c', '5.0.0');
+    });
 
     await d.appDir({'a': 'any', 'b': 'any', 'c': 'any'}).create();
     await expectResolves(result: {'a': '1.0.0', 'b': '1.0.0', 'c': '5.0.0'});
@@ -837,16 +886,17 @@
   test('failing backjump to conflicting source', () async {
     await d.dir('a', [d.libPubspec('a', '1.0.0')]).create();
 
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('b', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('b', '1.0.0', deps: {
         'a': {'path': p.join(d.sandbox, 'shared')}
-      })
-      ..serve('c', '1.0.0')
-      ..serve('c', '2.0.0')
-      ..serve('c', '3.0.0')
-      ..serve('c', '4.0.0')
-      ..serve('c', '5.0.0');
+      });
+      builder.serve('c', '1.0.0');
+      builder.serve('c', '2.0.0');
+      builder.serve('c', '3.0.0');
+      builder.serve('c', '4.0.0');
+      builder.serve('c', '5.0.0');
+    });
 
     await d.appDir({'a': 'any', 'b': 'any', 'c': 'any'}).create();
     await expectResolves(error: equalsIgnoringWhitespace('''
@@ -857,21 +907,23 @@
   });
 
   test('failing backjump to conflicting description', () async {
-    var otherServer = await startPackageServer();
-    otherServer.serve('a', '1.0.0');
+    var otherServer = await PackageServer.start((builder) {
+      builder.serve('a', '1.0.0');
+    });
 
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('b', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('b', '1.0.0', deps: {
         'a': {
           'hosted': {'name': 'a', 'url': otherServer.url}
         }
-      })
-      ..serve('c', '1.0.0')
-      ..serve('c', '2.0.0')
-      ..serve('c', '3.0.0')
-      ..serve('c', '4.0.0')
-      ..serve('c', '5.0.0');
+      });
+      builder.serve('c', '1.0.0');
+      builder.serve('c', '2.0.0');
+      builder.serve('c', '3.0.0');
+      builder.serve('c', '4.0.0');
+      builder.serve('c', '5.0.0');
+    });
 
     await d.appDir({'a': 'any', 'b': 'any', 'c': 'any'}).create();
     await expectResolves(
@@ -890,37 +942,39 @@
   // Since b has fewer versions, it will be traversed first, which means a will
   // come later. Since later selections are revised first, a gets downgraded.
   test('traverse into package with fewer versions first', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'c': 'any'})
-      ..serve('a', '2.0.0', deps: {'c': 'any'})
-      ..serve('a', '3.0.0', deps: {'c': 'any'})
-      ..serve('a', '4.0.0', deps: {'c': 'any'})
-      ..serve('a', '5.0.0', deps: {'c': '1.0.0'})
-      ..serve('b', '1.0.0', deps: {'c': 'any'})
-      ..serve('b', '2.0.0', deps: {'c': 'any'})
-      ..serve('b', '3.0.0', deps: {'c': 'any'})
-      ..serve('b', '4.0.0', deps: {'c': '2.0.0'})
-      ..serve('c', '1.0.0')
-      ..serve('c', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'c': 'any'});
+      builder.serve('a', '2.0.0', deps: {'c': 'any'});
+      builder.serve('a', '3.0.0', deps: {'c': 'any'});
+      builder.serve('a', '4.0.0', deps: {'c': 'any'});
+      builder.serve('a', '5.0.0', deps: {'c': '1.0.0'});
+      builder.serve('b', '1.0.0', deps: {'c': 'any'});
+      builder.serve('b', '2.0.0', deps: {'c': 'any'});
+      builder.serve('b', '3.0.0', deps: {'c': 'any'});
+      builder.serve('b', '4.0.0', deps: {'c': '2.0.0'});
+      builder.serve('c', '1.0.0');
+      builder.serve('c', '2.0.0');
+    });
 
     await d.appDir({'a': 'any', 'b': 'any'}).create();
     await expectResolves(result: {'a': '4.0.0', 'b': '4.0.0', 'c': '2.0.0'});
   });
 
   test('complex backtrack', () async {
-    final server = await servePackages();
-    // This sets up a hundred versions of foo and bar, 0.0.0 through 9.9.0. Each
-    // version of foo depends on a baz with the same major version. Each version
-    // of bar depends on a baz with the same minor version. There is only one
-    // version of baz, 0.0.0, so only older versions of foo and bar will
-    // satisfy it.
-    server.serve('baz', '0.0.0');
-    for (var i = 0; i < 10; i++) {
-      for (var j = 0; j < 10; j++) {
-        server.serve('foo', '$i.$j.0', deps: {'baz': '$i.0.0'});
-        server.serve('bar', '$i.$j.0', deps: {'baz': '0.$j.0'});
+    await servePackages((builder) {
+      // This sets up a hundred versions of foo and bar, 0.0.0 through 9.9.0. Each
+      // version of foo depends on a baz with the same major version. Each version
+      // of bar depends on a baz with the same minor version. There is only one
+      // version of baz, 0.0.0, so only older versions of foo and bar will
+      // satisfy it.
+      builder.serve('baz', '0.0.0');
+      for (var i = 0; i < 10; i++) {
+        for (var j = 0; j < 10; j++) {
+          builder.serve('foo', '$i.$j.0', deps: {'baz': '$i.0.0'});
+          builder.serve('bar', '$i.$j.0', deps: {'baz': '0.$j.0'});
+        }
       }
-    }
+    });
 
     await d.appDir({'foo': 'any', 'bar': 'any'}).create();
     await expectResolves(
@@ -931,18 +985,19 @@
   // versions of it is a waste of time: no possible versions can match. We need
   // to jump past it to the most recent package that affected the constraint.
   test('backjump past failed package on disjoint constraint', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {
         'foo': 'any' // ok
-      })
-      ..serve('a', '2.0.0', deps: {
+      });
+      builder.serve('a', '2.0.0', deps: {
         'foo': '<1.0.0' // disjoint with myapp's constraint on foo
-      })
-      ..serve('foo', '2.0.0')
-      ..serve('foo', '2.0.1')
-      ..serve('foo', '2.0.2')
-      ..serve('foo', '2.0.3')
-      ..serve('foo', '2.0.4');
+      });
+      builder.serve('foo', '2.0.0');
+      builder.serve('foo', '2.0.1');
+      builder.serve('foo', '2.0.2');
+      builder.serve('foo', '2.0.3');
+      builder.serve('foo', '2.0.4');
+    });
 
     await d.appDir({'a': 'any', 'foo': '>2.0.0'}).create();
     await expectResolves(result: {'a': '1.0.0', 'foo': '2.0.4'});
@@ -953,13 +1008,14 @@
   // would backtrack over the failed package instead of trying different
   // versions of it.
   test('finds solution with less strict constraint', () async {
-    await servePackages()
-      ..serve('a', '2.0.0')
-      ..serve('a', '1.0.0')
-      ..serve('b', '1.0.0', deps: {'a': '1.0.0'})
-      ..serve('c', '1.0.0', deps: {'b': 'any'})
-      ..serve('d', '2.0.0', deps: {'myapp': 'any'})
-      ..serve('d', '1.0.0', deps: {'myapp': '<1.0.0'});
+    await servePackages((builder) {
+      builder.serve('a', '2.0.0');
+      builder.serve('a', '1.0.0');
+      builder.serve('b', '1.0.0', deps: {'a': '1.0.0'});
+      builder.serve('c', '1.0.0', deps: {'b': 'any'});
+      builder.serve('d', '2.0.0', deps: {'myapp': 'any'});
+      builder.serve('d', '1.0.0', deps: {'myapp': '<1.0.0'});
+    });
 
     await d.appDir({'a': 'any', 'c': 'any', 'd': 'any'}).create();
     await expectResolves(
@@ -995,9 +1051,10 @@
   });
 
   test('dependency does not match SDK', () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0', pubspec: {
-      'environment': {'sdk': '0.0.0'}
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
+        'environment': {'sdk': '0.0.0'}
+      });
     });
 
     await d.appDir({'foo': 'any'}).create();
@@ -1010,11 +1067,12 @@
   });
 
   test('transitive dependency does not match SDK', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': 'any'})
-      ..serve('bar', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': 'any'});
+      builder.serve('bar', '1.0.0', pubspec: {
         'environment': {'sdk': '0.0.0'}
       });
+    });
 
     await d.appDir({'foo': 'any'}).create();
     await expectResolves(error: equalsIgnoringWhitespace('''
@@ -1027,39 +1085,41 @@
   });
 
   test('selects a dependency version that allows the SDK', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'environment': {'sdk': '0.1.2+3'}
-      })
-      ..serve('foo', '2.0.0', pubspec: {
+      });
+      builder.serve('foo', '2.0.0', pubspec: {
         'environment': {'sdk': '0.1.2+3'}
-      })
-      ..serve('foo', '3.0.0', pubspec: {
-        'environment': {'sdk': '0.0.0'}
-      })
-      ..serve('foo', '4.0.0', pubspec: {
+      });
+      builder.serve('foo', '3.0.0', pubspec: {
         'environment': {'sdk': '0.0.0'}
       });
+      builder.serve('foo', '4.0.0', pubspec: {
+        'environment': {'sdk': '0.0.0'}
+      });
+    });
 
     await d.appDir({'foo': 'any'}).create();
     await expectResolves(result: {'foo': '2.0.0'});
   });
 
   test('selects a transitive dependency version that allows the SDK', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': 'any'})
-      ..serve('bar', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': 'any'});
+      builder.serve('bar', '1.0.0', pubspec: {
         'environment': {'sdk': '0.1.2+3'}
-      })
-      ..serve('bar', '2.0.0', pubspec: {
+      });
+      builder.serve('bar', '2.0.0', pubspec: {
         'environment': {'sdk': '0.1.2+3'}
-      })
-      ..serve('bar', '3.0.0', pubspec: {
-        'environment': {'sdk': '0.0.0'}
-      })
-      ..serve('bar', '4.0.0', pubspec: {
+      });
+      builder.serve('bar', '3.0.0', pubspec: {
         'environment': {'sdk': '0.0.0'}
       });
+      builder.serve('bar', '4.0.0', pubspec: {
+        'environment': {'sdk': '0.0.0'}
+      });
+    });
 
     await d.appDir({'foo': 'any'}).create();
     await expectResolves(result: {'foo': '1.0.0', 'bar': '2.0.0'});
@@ -1068,23 +1128,24 @@
   test(
       'selects a dependency version that allows a transitive '
       'dependency that allows the SDK', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'})
-      ..serve('foo', '2.0.0', deps: {'bar': '2.0.0'})
-      ..serve('foo', '3.0.0', deps: {'bar': '3.0.0'})
-      ..serve('foo', '4.0.0', deps: {'bar': '4.0.0'})
-      ..serve('bar', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'});
+      builder.serve('foo', '2.0.0', deps: {'bar': '2.0.0'});
+      builder.serve('foo', '3.0.0', deps: {'bar': '3.0.0'});
+      builder.serve('foo', '4.0.0', deps: {'bar': '4.0.0'});
+      builder.serve('bar', '1.0.0', pubspec: {
         'environment': {'sdk': '0.1.2+3'}
-      })
-      ..serve('bar', '2.0.0', pubspec: {
+      });
+      builder.serve('bar', '2.0.0', pubspec: {
         'environment': {'sdk': '0.1.2+3'}
-      })
-      ..serve('bar', '3.0.0', pubspec: {
-        'environment': {'sdk': '0.0.0'}
-      })
-      ..serve('bar', '4.0.0', pubspec: {
+      });
+      builder.serve('bar', '3.0.0', pubspec: {
         'environment': {'sdk': '0.0.0'}
       });
+      builder.serve('bar', '4.0.0', pubspec: {
+        'environment': {'sdk': '0.0.0'}
+      });
+    });
 
     await d.appDir({'foo': 'any'}).create();
     await expectResolves(result: {'foo': '2.0.0', 'bar': '2.0.0'}, tries: 2);
@@ -1402,9 +1463,10 @@
     });
 
     test('fails for a dependency', () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0', pubspec: {
-        'environment': {'flutter': '0.0.0'}
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
+          'environment': {'flutter': '0.0.0'}
+        });
       });
 
       await d.appDir({'foo': 'any'}).create();
@@ -1417,12 +1479,13 @@
     });
 
     test("chooses a version that doesn't need Flutter", () async {
-      await servePackages()
-        ..serve('foo', '1.0.0')
-        ..serve('foo', '2.0.0')
-        ..serve('foo', '3.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+        builder.serve('foo', '2.0.0');
+        builder.serve('foo', '3.0.0', pubspec: {
           'environment': {'flutter': '0.0.0'}
         });
+      });
 
       await d.appDir({'foo': 'any'}).create();
       await expectResolves(result: {'foo': '2.0.0'});
@@ -1549,16 +1612,17 @@
     });
 
     test('selects the latest dependency with a matching constraint', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'environment': {'flutter': '^0.0.0'}
-        })
-        ..serve('foo', '2.0.0', pubspec: {
+        });
+        builder.serve('foo', '2.0.0', pubspec: {
           'environment': {'flutter': '^1.0.0'}
-        })
-        ..serve('foo', '3.0.0', pubspec: {
+        });
+        builder.serve('foo', '3.0.0', pubspec: {
           'environment': {'flutter': '^2.0.0'}
         });
+      });
 
       await d.appDir({'foo': 'any'}).create();
       await expectResolves(
@@ -1570,33 +1634,36 @@
 
 void prerelease() {
   test('prefer stable versions over unstable', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '1.1.0-dev')
-      ..serve('a', '2.0.0-dev')
-      ..serve('a', '3.0.0-dev');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '1.1.0-dev');
+      builder.serve('a', '2.0.0-dev');
+      builder.serve('a', '3.0.0-dev');
+    });
 
     await d.appDir({'a': 'any'}).create();
     await expectResolves(result: {'a': '1.0.0'});
   });
 
   test('use latest allowed prerelease if no stable versions match', () async {
-    await servePackages()
-      ..serve('a', '1.0.0-dev')
-      ..serve('a', '1.1.0-dev')
-      ..serve('a', '1.9.0-dev')
-      ..serve('a', '3.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0-dev');
+      builder.serve('a', '1.1.0-dev');
+      builder.serve('a', '1.9.0-dev');
+      builder.serve('a', '3.0.0');
+    });
 
     await d.appDir({'a': '<2.0.0'}).create();
     await expectResolves(result: {'a': '1.9.0-dev'});
   });
 
   test('use an earlier stable version on a < constraint', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '1.1.0')
-      ..serve('a', '2.0.0-dev')
-      ..serve('a', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '1.1.0');
+      builder.serve('a', '2.0.0-dev');
+      builder.serve('a', '2.0.0');
+    });
 
     await d.appDir({'a': '<2.0.0'}).create();
     await expectResolves(result: {'a': '1.1.0'});
@@ -1604,30 +1671,33 @@
 
   test('prefer a stable version even if constraint mentions unstable',
       () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '1.1.0')
-      ..serve('a', '2.0.0-dev')
-      ..serve('a', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '1.1.0');
+      builder.serve('a', '2.0.0-dev');
+      builder.serve('a', '2.0.0');
+    });
 
     await d.appDir({'a': '<=2.0.0-dev'}).create();
     await expectResolves(result: {'a': '1.1.0'});
   });
 
   test('use pre-release when desired', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '1.1.0-dev');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '1.1.0-dev');
+    });
 
     await d.appDir({'a': '^1.1.0-dev'}).create();
     await expectResolves(result: {'a': '1.1.0-dev'});
   });
 
   test('can upgrade from pre-release', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '1.1.0-dev')
-      ..serve('a', '1.1.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '1.1.0-dev');
+      builder.serve('a', '1.1.0');
+    });
 
     await d.appDir({'a': '^1.1.0-dev'}).create();
     await expectResolves(result: {'a': '1.1.0'});
@@ -1636,11 +1706,12 @@
   test('will use pre-release if depended on in stable release', () async {
     // This behavior is desired because a stable package has dependency on a
     // pre-release.
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'b': '^1.0.0'})
-      ..serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'})
-      ..serve('b', '1.0.0')
-      ..serve('b', '1.1.0-dev');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'b': '^1.0.0'});
+      builder.serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'});
+      builder.serve('b', '1.0.0');
+      builder.serve('b', '1.1.0-dev');
+    });
 
     await d.appDir({'a': '^1.0.0'}).create();
     await expectResolves(result: {
@@ -1650,11 +1721,12 @@
   });
 
   test('backtracks pre-release choice with direct dependency', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'b': '^1.0.0'})
-      ..serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'})
-      ..serve('b', '1.0.0')
-      ..serve('b', '1.1.0-dev');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'b': '^1.0.0'});
+      builder.serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'});
+      builder.serve('b', '1.0.0');
+      builder.serve('b', '1.1.0-dev');
+    });
 
     await d.appDir({
       'a': '^1.0.0',
@@ -1669,12 +1741,13 @@
   test('backtracking pre-release fails with indirect dependency', () async {
     // NOTE: This behavior is not necessarily desired.
     //       If feasible it might worth changing this behavior in the future.
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'b': '^1.0.0'})
-      ..serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'})
-      ..serve('b', '1.0.0')
-      ..serve('b', '1.1.0-dev')
-      ..serve('c', '1.0.0', deps: {'b': '^1.0.0'});
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'b': '^1.0.0'});
+      builder.serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'});
+      builder.serve('b', '1.0.0');
+      builder.serve('b', '1.1.0-dev');
+      builder.serve('c', '1.0.0', deps: {'b': '^1.0.0'});
+    });
 
     await d.appDir({
       'a': '^1.0.0',
@@ -1689,13 +1762,14 @@
 
   test('https://github.com/dart-lang/pub/issues/3057 regression', () async {
     // This used to cause an infinite loop.
-    await servePackages()
-      ..serve('a', '0.12.0', deps: {})
-      ..serve('b', '0.1.0', deps: {'c': '2.0.0'})
-      ..serve('b', '0.9.0-1', deps: {'c': '^1.6.0'})
-      ..serve('b', '0.10.0', deps: {'a': '1.0.0'})
-      ..serve('b', '0.17.0', deps: {'a': '1.0.0'})
-      ..serve('c', '2.0.1', deps: {});
+    await servePackages((builder) {
+      builder.serve('a', '0.12.0', deps: {});
+      builder.serve('b', '0.1.0', deps: {'c': '2.0.0'});
+      builder.serve('b', '0.9.0-1', deps: {'c': '^1.6.0'});
+      builder.serve('b', '0.10.0', deps: {'a': '1.0.0'});
+      builder.serve('b', '0.17.0', deps: {'a': '1.0.0'});
+      builder.serve('c', '2.0.1', deps: {});
+    });
 
     await d.appDir(
       {
@@ -1710,12 +1784,13 @@
   });
 
   test('https://github.com/dart-lang/pub/pull/3038 regression', () async {
-    await servePackages()
-      ..serve('a', '1.1.0', deps: {'b': '^1.0.0'})
-      ..serve('b', '1.0.0', deps: {'c': '^1.0.0'})
-      ..serve('c', '0.9.0')
-      ..serve('b', '1.1.0-alpha')
-      ..serve('a', '1.0.0', deps: {'b': '^1.1.0-alpha'});
+    await servePackages((builder) {
+      builder.serve('a', '1.1.0', deps: {'b': '^1.0.0'});
+      builder.serve('b', '1.0.0', deps: {'c': '^1.0.0'});
+      builder.serve('c', '0.9.0');
+      builder.serve('b', '1.1.0-alpha');
+      builder.serve('a', '1.0.0', deps: {'b': '^1.1.0-alpha'});
+    });
 
     await d.appDir({
       'a': '^1.0.0',
@@ -1726,10 +1801,11 @@
 
 void override() {
   test('chooses best version matching override constraint', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '2.0.0')
-      ..serve('a', '3.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '2.0.0');
+      builder.serve('a', '3.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -1743,10 +1819,11 @@
   });
 
   test('uses override as dependency', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '2.0.0')
-      ..serve('a', '3.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '2.0.0');
+      builder.serve('a', '3.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -1759,12 +1836,13 @@
   });
 
   test('ignores other constraints on overridden package', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '2.0.0')
-      ..serve('a', '3.0.0')
-      ..serve('b', '1.0.0', deps: {'a': '1.0.0'})
-      ..serve('c', '1.0.0', deps: {'a': '3.0.0'});
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '2.0.0');
+      builder.serve('a', '3.0.0');
+      builder.serve('b', '1.0.0', deps: {'a': '1.0.0'});
+      builder.serve('c', '1.0.0', deps: {'a': '3.0.0'});
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -1778,11 +1856,12 @@
   });
 
   test('backtracks on overidden package for its constraints', () async {
-    await servePackages()
-      ..serve('a', '1.0.0', deps: {'shared': 'any'})
-      ..serve('a', '2.0.0', deps: {'shared': '1.0.0'})
-      ..serve('shared', '1.0.0')
-      ..serve('shared', '2.0.0');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0', deps: {'shared': 'any'});
+      builder.serve('a', '2.0.0', deps: {'shared': '1.0.0'});
+      builder.serve('shared', '1.0.0');
+      builder.serve('shared', '2.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -1796,13 +1875,14 @@
   });
 
   test('override compatible with locked dependency', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'})
-      ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'})
-      ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'})
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '1.0.1')
-      ..serve('bar', '1.0.2');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'});
+      builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'});
+      builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'});
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '1.0.1');
+      builder.serve('bar', '1.0.2');
+    });
 
     await d.appDir({'foo': '1.0.1'}).create();
     await expectResolves(result: {'foo': '1.0.1', 'bar': '1.0.1'});
@@ -1818,13 +1898,14 @@
   });
 
   test('override incompatible with locked dependency', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'})
-      ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'})
-      ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'})
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '1.0.1')
-      ..serve('bar', '1.0.2');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'});
+      builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'});
+      builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'});
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '1.0.1');
+      builder.serve('bar', '1.0.2');
+    });
 
     await d.appDir({'foo': '1.0.1'}).create();
     await expectResolves(result: {'foo': '1.0.1', 'bar': '1.0.1'});
@@ -1840,9 +1921,10 @@
   });
 
   test('no version that matches override', () async {
-    await servePackages()
-      ..serve('foo', '2.0.0')
-      ..serve('foo', '2.1.3');
+    await servePackages((builder) {
+      builder.serve('foo', '2.0.0');
+      builder.serve('foo', '2.1.3');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -1858,8 +1940,9 @@
   });
 
   test('overrides a bad source without error', () async {
-    final server = await servePackages();
-    server.serve('foo', '0.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '0.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -1875,9 +1958,10 @@
   });
 
   test('overrides an unmatched SDK constraint', () async {
-    final server = await servePackages();
-    server.serve('foo', '0.0.0', pubspec: {
-      'environment': {'sdk': '0.0.0'}
+    await servePackages((builder) {
+      builder.serve('foo', '0.0.0', pubspec: {
+        'environment': {'sdk': '0.0.0'}
+      });
     });
 
     await d.dir(appPath, [
@@ -1891,8 +1975,9 @@
   });
 
   test('overrides an unmatched root dependency', () async {
-    final server = await servePackages();
-    server.serve('foo', '0.0.0', deps: {'myapp': '1.0.0'});
+    await servePackages((builder) {
+      builder.serve('foo', '0.0.0', deps: {'myapp': '1.0.0'});
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -1907,10 +1992,11 @@
 
   // Regression test for #1853
   test("overrides a locked package's dependency", () async {
-    await servePackages()
-      ..serve('foo', '1.2.3', deps: {'bar': '1.2.3'})
-      ..serve('bar', '1.2.3')
-      ..serve('bar', '0.0.1');
+    await servePackages((builder) {
+      builder.serve('foo', '1.2.3', deps: {'bar': '1.2.3'});
+      builder.serve('bar', '1.2.3');
+      builder.serve('bar', '0.0.1');
+    });
 
     await d.appDir({'foo': 'any'}).create();
 
@@ -1930,11 +2016,12 @@
 
 void downgrade() {
   test('downgrades a dependency to the lowest matching version', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('foo', '2.0.0-dev')
-      ..serve('foo', '2.0.0')
-      ..serve('foo', '2.1.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('foo', '2.0.0-dev');
+      builder.serve('foo', '2.0.0');
+      builder.serve('foo', '2.1.0');
+    });
 
     await d.appDir({'foo': '2.1.0'}).create();
     await expectResolves(result: {'foo': '2.1.0'});
@@ -1946,11 +2033,12 @@
   test(
       'use earliest allowed prerelease if no stable versions match '
       'while downgrading', () async {
-    await servePackages()
-      ..serve('a', '1.0.0')
-      ..serve('a', '2.0.0-dev.1')
-      ..serve('a', '2.0.0-dev.2')
-      ..serve('a', '2.0.0-dev.3');
+    await servePackages((builder) {
+      builder.serve('a', '1.0.0');
+      builder.serve('a', '2.0.0-dev.1');
+      builder.serve('a', '2.0.0-dev.2');
+      builder.serve('a', '2.0.0-dev.3');
+    });
 
     await d.appDir({'a': '>=2.0.0-dev.1 <3.0.0'}).create();
     await expectResolves(result: {'a': '2.0.0-dev.1'}, downgrade: true);
@@ -1959,63 +2047,67 @@
 
 void features() {
   test("doesn't enable an opt-in feature by default", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0');
+      });
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.appDir({'foo': '1.0.0'}).create();
     await expectResolves(result: {'foo': '1.0.0'});
   });
 
   test('enables an opt-out feature by default', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'default': true,
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0');
+      });
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.appDir({'foo': '1.0.0'}).create();
     await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'});
   });
 
   test('features are opt-out by default', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0');
+      });
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.appDir({'foo': '1.0.0'}).create();
     await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'});
   });
 
   test("enables an opt-in feature if it's required", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0');
+      });
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.appDir({
       'foo': {
@@ -2027,15 +2119,16 @@
   });
 
   test("doesn't enable an opt-out feature if it's disabled", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0');
+      });
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.appDir({
       'foo': {
@@ -2047,21 +2140,22 @@
   });
 
   test('opting in takes precedence over opting out', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0')
-      ..serve('baz', '1.0.0', deps: {
+      });
+      builder.serve('bar', '1.0.0');
+      builder.serve('baz', '1.0.0', deps: {
         'foo': {
           'version': '1.0.0',
           'features': {'stuff': true}
         }
       });
+    });
 
     await d.appDir({
       'foo': {
@@ -2075,20 +2169,21 @@
   });
 
   test('implicitly opting in takes precedence over opting out', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0')
-      ..serve('baz', '1.0.0', deps: {
+      });
+      builder.serve('bar', '1.0.0');
+      builder.serve('baz', '1.0.0', deps: {
         'foo': {
           'version': '1.0.0',
         }
       });
+    });
 
     await d.appDir({
       'foo': {
@@ -2102,17 +2197,18 @@
   });
 
   test("doesn't select a version with an unavailable feature", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('foo', '1.1.0')
-      ..serve('bar', '1.0.0');
+      });
+      builder.serve('foo', '1.1.0');
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.appDir({
       'foo': {
@@ -2124,25 +2220,26 @@
   });
 
   test("doesn't select a version with an incompatible feature", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('foo', '1.1.0', pubspec: {
+      });
+      builder.serve('foo', '1.1.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
             'dependencies': {'bar': '2.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0')
-      ..serve('bar', '2.0.0');
+      });
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '2.0.0');
+    });
 
     await d.appDir({
       'foo': {
@@ -2157,8 +2254,8 @@
   test(
       'backtracks if a feature is transitively incompatible with another '
       'feature', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
@@ -2170,24 +2267,27 @@
             }
           }
         }
-      })
-      ..serve('foo', '1.1.0', pubspec: {
+      });
+      builder.serve('foo', '1.1.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0', pubspec: {
+      });
+
+      builder.serve('bar', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'dependencies': {'baz': '1.0.0'}
           }
         }
-      })
-      ..serve('baz', '1.0.0')
-      ..serve('baz', '2.0.0');
+      });
+
+      builder.serve('baz', '1.0.0');
+      builder.serve('baz', '2.0.0');
+    });
 
     await d.appDir({
       'foo': {
@@ -2202,27 +2302,30 @@
 
   test("backtracks if a feature's dependencies are transitively incompatible",
       () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', pubspec: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
             'dependencies': {'bar': '1.0.0'}
           }
         }
-      })
-      ..serve('foo', '1.1.0', pubspec: {
+      });
+      builder.serve('foo', '1.1.0', pubspec: {
         'features': {
           'stuff': {
             'default': false,
             'dependencies': {'bar': '2.0.0'}
           }
         }
-      })
-      ..serve('bar', '1.0.0', deps: {'baz': '1.0.0'})
-      ..serve('bar', '2.0.0', deps: {'baz': '2.0.0'})
-      ..serve('baz', '1.0.0')
-      ..serve('baz', '2.0.0');
+      });
+
+      builder.serve('bar', '1.0.0', deps: {'baz': '1.0.0'});
+      builder.serve('bar', '2.0.0', deps: {'baz': '2.0.0'});
+
+      builder.serve('baz', '1.0.0');
+      builder.serve('baz', '2.0.0');
+    });
 
     await d.appDir({
       'foo': {
@@ -2236,9 +2339,9 @@
   });
 
   test('disables a feature when it backtracks', () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {'myapp': '0.0.0'})
-      ..serve('foo', '1.1.0', deps: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'myapp': '0.0.0'});
+      builder.serve('foo', '1.1.0', deps: {
         // This is a transitively incompatible dependency with myapp, which will
         // force the solver to backtrack and unselect foo 1.1.0.
         'bar': '1.0.0',
@@ -2246,11 +2349,15 @@
           'version': '0.0.0',
           'features': {'stuff': true}
         }
-      })
-      ..serve('bar', '1.0.0', deps: {'baz': '2.0.0'})
-      ..serve('baz', '1.0.0')
-      ..serve('baz', '2.0.0')
-      ..serve('qux', '1.0.0');
+      });
+
+      builder.serve('bar', '1.0.0', deps: {'baz': '2.0.0'});
+
+      builder.serve('baz', '1.0.0');
+      builder.serve('baz', '2.0.0');
+
+      builder.serve('qux', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -2268,9 +2375,10 @@
   });
 
   test("the root package's features are opt-out by default", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('bar', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -2287,9 +2395,10 @@
   });
 
   test("the root package's features can be made opt-in", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0')
-      ..serve('bar', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -2312,13 +2421,14 @@
   // increases the total number of dependencies.
   test("the root package's features can't be disabled by dependencies",
       () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {
         'myapp': {
           'features': {'stuff': false}
         }
-      })
-      ..serve('bar', '1.0.0');
+      });
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -2335,13 +2445,14 @@
   });
 
   test("the root package's features can be enabled by dependencies", () async {
-    await servePackages()
-      ..serve('foo', '1.0.0', deps: {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {
         'myapp': {
           'features': {'stuff': true}
         }
-      })
-      ..serve('bar', '1.0.0');
+      });
+      builder.serve('bar', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -2359,8 +2470,9 @@
   });
 
   test("resolution fails because a feature doesn't exist", () async {
-    final server = await servePackages();
-    server.serve('foo', '1.0.0');
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0');
+    });
 
     await d.dir(appPath, [
       d.pubspec({
@@ -2380,16 +2492,17 @@
 
   group('an "if available" dependency', () {
     test('enables an opt-in feature', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'features': {
             'stuff': {
               'default': false,
               'dependencies': {'bar': '1.0.0'}
             }
           }
-        })
-        ..serve('bar', '1.0.0');
+        });
+        builder.serve('bar', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {
@@ -2401,8 +2514,9 @@
     });
 
     test("is compatible with a feature that doesn't exist", () async {
-      final server = await servePackages();
-      server.serve('foo', '1.0.0');
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {
@@ -2421,13 +2535,14 @@
 
     group('succeeds when', () {
       test('a Dart SDK constraint is matched', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.0.0', pubspec: {
-          'features': {
-            'stuff': {
-              'environment': {'sdk': '^0.1.0'}
+        await servePackages((builder) {
+          builder.serve('foo', '1.0.0', pubspec: {
+            'features': {
+              'stuff': {
+                'environment': {'sdk': '^0.1.0'}
+              }
             }
-          }
+          });
         });
 
         await d.dir(appPath, [
@@ -2441,13 +2556,14 @@
       });
 
       test('a Flutter SDK constraint is matched', () async {
-        final server = await servePackages();
-        server.serve('foo', '1.0.0', pubspec: {
-          'features': {
-            'stuff': {
-              'environment': {'flutter': '^1.0.0'}
+        await servePackages((builder) {
+          builder.serve('foo', '1.0.0', pubspec: {
+            'features': {
+              'stuff': {
+                'environment': {'flutter': '^1.0.0'}
+              }
             }
-          }
+          });
         });
 
         await d.dir(appPath, [
@@ -2465,15 +2581,16 @@
 
     group("doesn't choose a version because", () {
       test("a Dart SDK constraint isn't matched", () async {
-        await servePackages()
-          ..serve('foo', '1.0.0')
-          ..serve('foo', '1.1.0', pubspec: {
+        await servePackages((builder) {
+          builder.serve('foo', '1.0.0');
+          builder.serve('foo', '1.1.0', pubspec: {
             'features': {
               'stuff': {
                 'environment': {'sdk': '0.0.1'}
               }
             }
           });
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -2486,15 +2603,16 @@
       });
 
       test("Flutter isn't available", () async {
-        await servePackages()
-          ..serve('foo', '1.0.0')
-          ..serve('foo', '1.1.0', pubspec: {
+        await servePackages((builder) {
+          builder.serve('foo', '1.0.0');
+          builder.serve('foo', '1.1.0', pubspec: {
             'features': {
               'stuff': {
                 'environment': {'flutter': '1.0.0'}
               }
             }
           });
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -2507,15 +2625,16 @@
       });
 
       test("a Flutter SDK constraint isn't matched", () async {
-        await servePackages()
-          ..serve('foo', '1.0.0')
-          ..serve('foo', '1.1.0', pubspec: {
+        await servePackages((builder) {
+          builder.serve('foo', '1.0.0');
+          builder.serve('foo', '1.1.0', pubspec: {
             'features': {
               'stuff': {
                 'environment': {'flutter': '^2.0.0'}
               }
             }
           });
+        });
 
         await d.dir(appPath, [
           d.pubspec({
@@ -2532,13 +2651,14 @@
 
     group('resolution fails because', () {
       test("a Dart SDK constraint isn't matched", () async {
-        final server = await servePackages();
-        server.serve('foo', '1.0.0', pubspec: {
-          'features': {
-            'stuff': {
-              'environment': {'sdk': '0.0.1'}
+        await servePackages((builder) {
+          builder.serve('foo', '1.0.0', pubspec: {
+            'features': {
+              'stuff': {
+                'environment': {'sdk': '0.0.1'}
+              }
             }
-          }
+          });
         });
 
         await d.dir(appPath, [
@@ -2555,13 +2675,14 @@
       });
 
       test("Flutter isn't available", () async {
-        final server = await servePackages();
-        server.serve('foo', '1.0.0', pubspec: {
-          'features': {
-            'stuff': {
-              'environment': {'flutter': '1.0.0'}
+        await servePackages((builder) {
+          builder.serve('foo', '1.0.0', pubspec: {
+            'features': {
+              'stuff': {
+                'environment': {'flutter': '1.0.0'}
+              }
             }
-          }
+          });
         });
 
         await d.dir(appPath, [
@@ -2577,13 +2698,14 @@
       });
 
       test("a Flutter SDK constraint isn't matched", () async {
-        final server = await servePackages();
-        server.serve('foo', '1.0.0', pubspec: {
-          'features': {
-            'stuff': {
-              'environment': {'flutter': '^2.0.0'}
+        await servePackages((builder) {
+          builder.serve('foo', '1.0.0', pubspec: {
+            'features': {
+              'stuff': {
+                'environment': {'flutter': '^2.0.0'}
+              }
             }
-          }
+          });
         });
 
         await d.dir(appPath, [
@@ -2603,8 +2725,8 @@
 
   group('with overlapping dependencies', () {
     test('can enable extra features', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'dependencies': {'bar': '1.0.0'},
           'features': {
             'stuff': {
@@ -2616,16 +2738,19 @@
               }
             }
           }
-        })
-        ..serve('bar', '1.0.0', pubspec: {
+        });
+
+        builder.serve('bar', '1.0.0', pubspec: {
           'features': {
             'stuff': {
               'default': false,
               'dependencies': {'baz': '1.0.0'}
             }
           }
-        })
-        ..serve('baz', '1.0.0');
+        });
+
+        builder.serve('baz', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {'version': '1.0.0'}
@@ -2643,8 +2768,8 @@
     });
 
     test("can't disable features", () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'dependencies': {
             'bar': {
               'version': '1.0.0',
@@ -2661,16 +2786,19 @@
               }
             }
           }
-        })
-        ..serve('bar', '1.0.0', pubspec: {
+        });
+
+        builder.serve('bar', '1.0.0', pubspec: {
           'features': {
             'stuff': {
               'default': true,
               'dependencies': {'baz': '1.0.0'}
             }
           }
-        })
-        ..serve('baz', '1.0.0');
+        });
+
+        builder.serve('baz', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {
@@ -2685,8 +2813,8 @@
 
   group('with required features', () {
     test('enables those features', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'features': {
             'main': {
               'default': false,
@@ -2701,9 +2829,10 @@
               'dependencies': {'baz': '1.0.0'}
             }
           }
-        })
-        ..serve('bar', '1.0.0')
-        ..serve('baz', '1.0.0');
+        });
+        builder.serve('bar', '1.0.0');
+        builder.serve('baz', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {
@@ -2716,8 +2845,8 @@
     });
 
     test('enables those features by default', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'features': {
             'main': {
               'requires': ['required1', 'required2']
@@ -2731,9 +2860,10 @@
               'dependencies': {'baz': '1.0.0'}
             }
           }
-        })
-        ..serve('bar', '1.0.0')
-        ..serve('baz', '1.0.0');
+        });
+        builder.serve('bar', '1.0.0');
+        builder.serve('baz', '1.0.0');
+      });
 
       await d.appDir({'foo': '1.0.0'}).create();
       await expectResolves(
@@ -2741,8 +2871,8 @@
     });
 
     test("doesn't enable those features if it's disabled", () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'features': {
             'main': {
               'requires': ['required']
@@ -2752,8 +2882,9 @@
               'dependencies': {'bar': '1.0.0'}
             }
           }
-        })
-        ..serve('bar', '1.0.0');
+        });
+        builder.serve('bar', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {
@@ -2766,8 +2897,8 @@
 
     test("enables those features even if they'd otherwise be disabled",
         () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'features': {
             'main': {
               'requires': ['required']
@@ -2777,8 +2908,9 @@
               'dependencies': {'bar': '1.0.0'}
             }
           }
-        })
-        ..serve('bar', '1.0.0');
+        });
+        builder.serve('bar', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {
@@ -2790,8 +2922,8 @@
     });
 
     test('enables features transitively', () async {
-      await servePackages()
-        ..serve('foo', '1.0.0', pubspec: {
+      await servePackages((builder) {
+        builder.serve('foo', '1.0.0', pubspec: {
           'features': {
             'main': {
               'requires': ['required1']
@@ -2805,8 +2937,9 @@
               'dependencies': {'bar': '1.0.0'}
             }
           }
-        })
-        ..serve('bar', '1.0.0');
+        });
+        builder.serve('bar', '1.0.0');
+      });
 
       await d.appDir({
         'foo': {
@@ -2874,7 +3007,7 @@
       // If the dep uses the default hosted source, grab it from the test
       // package server rather than pub.dartlang.org.
       dep = registry.hosted
-          .refFor(dep.name, url: Uri.parse(globalServer.url))
+          .refFor(dep.name, url: Uri.parse(globalPackageServer!.url))
           .withConstraint(dep.constraint);
     }
     expect(dep.allows(id), isTrue, reason: 'Expected $id to match $dep.');
@@ -2885,12 +3018,14 @@
 
 void regressions() {
   test('reformatRanges with a build', () async {
-    await servePackages()
-      ..serve('integration_test', '1.0.1',
-          deps: {'vm_service': '>= 4.2.0 <6.0.0'})
-      ..serve('integration_test', '1.0.2+2',
-          deps: {'vm_service': '>= 4.2.0 <7.0.0'})
-      ..serve('vm_service', '7.3.0');
+    await servePackages((b) {
+      b.serve('integration_test', '1.0.1',
+          deps: {'vm_service': '>= 4.2.0 <6.0.0'});
+      b.serve('integration_test', '1.0.2+2',
+          deps: {'vm_service': '>= 4.2.0 <7.0.0'});
+
+      b.serve('vm_service', '7.3.0');
+    });
     await d.appDir({'integration_test': '^1.0.2'}).create();
     await expectResolves(
       error: contains(
diff --git a/tool/test-bin/pub_command_runner.dart b/tool/test-bin/pub_command_runner.dart
index e438aae..2be51e8 100644
--- a/tool/test-bin/pub_command_runner.dart
+++ b/tool/test-bin/pub_command_runner.dart
@@ -9,30 +9,12 @@
 import 'package:args/args.dart';
 import 'package:args/command_runner.dart';
 import 'package:pub/pub.dart';
-import 'package:pub/src/command.dart';
 import 'package:pub/src/exit_codes.dart' as exit_codes;
 import 'package:pub/src/log.dart' as log;
 import 'package:usage/usage.dart';
 
 final _LoggingAnalytics loggingAnalytics = _LoggingAnalytics();
 
-// A command for explicitly throwing an exception, to test the handling of
-// unexpected eceptions.
-class ThrowingCommand extends PubCommand {
-  @override
-  String get name => 'fail';
-
-  @override
-  String get description => 'Throws an exception';
-
-  bool get hide => true;
-
-  @override
-  Future<int> runProtected() async {
-    throw StateError('Pub has crashed');
-  }
-}
-
 class Runner extends CommandRunner<int> {
   late ArgResults _options;
 
@@ -41,10 +23,7 @@
         ? PubAnalytics(() => loggingAnalytics,
             dependencyKindCustomDimensionName: 'cd1')
         : null;
-    addCommand(
-        pubCommand(analytics: analytics, isVerbose: () => _options['verbose'])
-          ..addSubcommand(ThrowingCommand()));
-    argParser.addFlag('verbose');
+    addCommand(pubCommand(analytics: analytics));
   }
 
   @override
diff --git a/tool/test.dart b/tool/test.dart
index 7d98156..e7877a2 100755
--- a/tool/test.dart
+++ b/tool/test.dart
@@ -29,7 +29,7 @@
     await precompile(
         executablePath: path.join('bin', 'pub.dart'),
         outputPath: pubSnapshotFilename,
-        incrementalDillPath: pubSnapshotIncrementalFilename,
+        incrementalDillOutputPath: pubSnapshotIncrementalFilename,
         name: 'bin/pub.dart',
         packageConfigPath: path.join('.dart_tool', 'package_config.json'));
     testProcess = await Process.start(