diff --git a/.github/ISSUE_TEMPLATE/1-PUB_SITE.md b/.github/ISSUE_TEMPLATE/1-PUB_SITE.md
index df33eee..3b90c7a 100644
--- a/.github/ISSUE_TEMPLATE/1-PUB_SITE.md
+++ b/.github/ISSUE_TEMPLATE/1-PUB_SITE.md
@@ -1,6 +1,6 @@
 ---
 name: There is a problem with pub.dev
-about: A `pub get` fails because of an outage at `pub.dev`, the site
+about: A `dart pub get` or `flutter pub get` fails because of an outage at `pub.dev`, the site
   cannot be loaded, or there is an issue with a particular package such as a
   request to have a published package removed.
 
diff --git a/README.md b/README.md
index 0d40e6c..83f7ec1 100644
--- a/README.md
+++ b/README.md
@@ -64,7 +64,7 @@
 the test description. This is used when tests can take a long time to run to
 avoid having the tests time out when running on the build bots. For example,
 `tests/get/hosted/get_transitive_test.dart` tests the resolution of transitive
-hosted dependencies when using `pub get`.
+hosted dependencies when using `dart pub get`/`flutter pub get`.
 
 ## Landing your patch
 
diff --git a/doc/repository-spec-v2.md b/doc/repository-spec-v2.md
index 224aa2d..b65b4d2 100644
--- a/doc/repository-spec-v2.md
+++ b/doc/repository-spec-v2.md
@@ -4,12 +4,12 @@
 implement.
 
 A package repository is a server from which packages can be downloaded,
-the default package repository is `'https://pub.dartlang.org'`, with public
-interface hosted at [pub.dev](https://pub.dev).
+the default package repository is `'https://pub.dev'`.
+It used to be [pub.dartlang.org](https://pub.dartlang.org).
 
 ## Hosted URL
 A custom package repository is identified by a _hosted-url_, like
-`https://pub.dartlang.org` or `https://some-server.com/prefix/pub/`.
+`https://pub.dev` or `https://some-server.com/prefix/pub/`.
 The _hosted-url_ always includes protocol `http://` or `https://`.
 For the purpose of this specification the _hosted-url_ should always be
 normalized such that it doesn't end with a slash (`/`). As all URL end-points
@@ -17,7 +17,7 @@
 
 For the remainder of this specification the placeholder `<hosted-url>` will be
 used in place of a _hosted-url_ such as:
- * `https://pub.dartlang.org`
+ * `https://pub.dev`
  * `https://some-server.com/prefix/pub`
  * `https://pub.other-server.com/prefix`
  * `http://localhost:8080`
diff --git a/lib/src/ascii_tree.dart b/lib/src/ascii_tree.dart
index 302607f..a63d623 100644
--- a/lib/src/ascii_tree.dart
+++ b/lib/src/ascii_tree.dart
@@ -2,13 +2,21 @@
 // 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.
 
-/// A simple library for rendering tree-like structures in ASCII.
+/// A simple library for rendering tree-like structures in Unicode symbols with
+/// a fallback to ASCII.
+import 'dart:io';
+
 import 'package:path/path.dart' as path;
 
 import 'log.dart' as log;
 import 'utils.dart';
 
-/// Draws a tree for the given list of files. Given files like:
+/// Draws a tree for the given list of files
+///
+/// Shows each file with the file size if [showFileSize] is `true`.
+/// This will stats each file in the list for finding the size.
+///
+/// Given files like:
 ///
 ///     TODO
 ///     example/console_example.dart
@@ -16,11 +24,6 @@
 ///     example/web copy/web_example.dart
 ///     test/absolute_test.dart
 ///     test/basename_test.dart
-///     test/dirname_test.dart
-///     test/extension_test.dart
-///     test/is_absolute_test.dart
-///     test/is_relative_test.dart
-///     test/join_test.dart
 ///     test/normalize_test.dart
 ///     test/relative_test.dart
 ///     test/split_test.dart
@@ -34,48 +37,52 @@
 ///
 /// this renders:
 ///
-///     |-- .gitignore
-///     |-- README.md
-///     |-- TODO
+///     |-- .gitignore (1 KB)
+///     |-- README.md (23 KB)
+///     |-- TODO (1 MB)
 ///     |-- example
-///     |   |-- console_example.dart
-///     |   |-- main.dart
+///     |   |-- console_example.dart (20 B)
+///     |   |-- main.dart (200 B)
 ///     |   '-- web copy
-///     |       '-- web_example.dart
+///     |       '-- web_example.dart (3 KB)
 ///     |-- lib
-///     |   '-- path.dart
-///     |-- pubspec.yaml
+///     |   '-- path.dart (4 KB)
+///     |-- pubspec.yaml (10 KB)
 ///     '-- test
-///         |-- absolute_test.dart
-///         |-- all_test.dart
-///         |-- basename_test.dart
-///         | (7 more...)
-///         |-- path_windows_test.dart
-///         |-- relative_test.dart
-///         '-- split_test.dart
+///         |-- absolute_test.dart (102 KB)
+///         |-- all_test.dart (100 KB)
+///         |-- basename_test.dart (4 KB)
+///         |-- path_windows_test.dart (2 KB)
+///         |-- relative_test.dart (10 KB)
+///         '-- split_test.dart (50 KB)
 ///
 /// If [baseDir] is passed, it will be used as the root of the tree.
-///
-/// If [showAllChildren] is `false`, then directories with more than ten items
-/// will have their contents truncated. Defaults to `false`.
+
 String fromFiles(
   List<String> files, {
   String? baseDir,
-  bool showAllChildren = false,
+  required bool showFileSizes,
 }) {
   // Parse out the files into a tree of nested maps.
   var root = <String, Map>{};
   for (var file in files) {
-    if (baseDir != null) file = path.relative(file, from: baseDir);
+    final relativeFile =
+        baseDir == null ? file : path.relative(file, from: baseDir);
+    final parts = path.split(relativeFile);
+    if (showFileSizes) {
+      final size = File(path.normalize(file)).statSync().size;
+      final sizeString = _readableFileSize(size);
+      parts.last = '${parts.last} $sizeString';
+    }
     var directory = root;
-    for (var part in path.split(file)) {
+    for (var part in parts) {
       directory = directory.putIfAbsent(part, () => <String, Map>{})
           as Map<String, Map>;
     }
   }
 
   // Walk the map recursively and render to a string.
-  return fromMap(root, showAllChildren: showAllChildren);
+  return fromMap(root);
 }
 
 /// Draws a tree from a nested map. Given a map like:
@@ -99,12 +106,9 @@
 ///     barback
 ///
 /// Items with no children should have an empty map as the value.
-///
-/// If [showAllChildren] is `false`, then directories with more than ten items
-/// will have their contents truncated. Defaults to `false`.
-String fromMap(Map<String, Map> map, {bool showAllChildren = false}) {
+String fromMap(Map<String, Map> map) {
   var buffer = StringBuffer();
-  _draw(buffer, '', null, map, showAllChildren: showAllChildren);
+  _draw(buffer, '', null, map);
   return buffer.toString();
 }
 
@@ -118,9 +122,9 @@
   buffer.write(prefix);
   if (name != null) {
     if (isLastChild) {
-      buffer.write(log.gray("'-- "));
+      buffer.write(log.gray(emoji('└── ', "'-- ")));
     } else {
-      buffer.write(log.gray('|-- '));
+      buffer.write(log.gray(emoji('├── ', '|-- ')));
     }
   }
 
@@ -131,7 +135,7 @@
 String _getPrefix(bool isRoot, bool isLast) {
   if (isRoot) return '';
   if (isLast) return '    ';
-  return log.gray('|   ');
+  return log.gray(emoji('│   ', '|   '));
 }
 
 void _draw(
@@ -155,25 +159,19 @@
         showAllChildren: showAllChildren, isLast: isLastChild);
   }
 
-  if (name == null || showAllChildren || childNames.length <= 10) {
-    // Not too many, so show all the children.
-    for (var i = 0; i < childNames.length; i++) {
-      drawChild(i == childNames.length - 1, childNames[i]);
-    }
+  for (var i = 0; i < childNames.length; i++) {
+    drawChild(i == childNames.length - 1, childNames[i]);
+  }
+}
+
+String _readableFileSize(int size) {
+  if (size >= 1 << 30) {
+    return log.red('(${size ~/ (1 << 30)} GB)');
+  } else if (size >= 1 << 20) {
+    return log.yellow('(${size ~/ (1 << 20)} MB)');
+  } else if (size >= 1 << 10) {
+    return log.gray('(${size ~/ (1 << 10)} KB)');
   } else {
-    // Show the first few.
-    drawChild(false, childNames[0]);
-    drawChild(false, childNames[1]);
-    drawChild(false, childNames[2]);
-
-    // Elide the middle ones.
-    buffer.write(prefix);
-    buffer.write(_getPrefix(false, isLast));
-    buffer.writeln(log.gray('| (${childNames.length - 6} more...)'));
-
-    // Show the last few.
-    drawChild(false, childNames[childNames.length - 3]);
-    drawChild(false, childNames[childNames.length - 2]);
-    drawChild(true, childNames[childNames.length - 1]);
+    return log.gray('(<1 KB)');
   }
 }
diff --git a/lib/src/command/add.dart b/lib/src/command/add.dart
index 78b1e5d..15b64a4 100644
--- a/lib/src/command/add.dart
+++ b/lib/src/command/add.dart
@@ -213,11 +213,10 @@
     final range =
         package.ref.withConstraint(package.constraint ?? VersionConstraint.any);
     if (isDev) {
-      /// TODO(walnut): Change the error message once pub upgrade --bump is
-      /// released
       if (devDependencyNames.contains(name)) {
-        dataError('"$name" is already in "dev_dependencies". '
-            'Use "pub upgrade $name" to upgrade to a later version!');
+        log.message('"$name" is already in "dev_dependencies". '
+            'Will try to update the constraint.');
+        devDependencies.removeWhere((element) => element.name == name);
       }
 
       /// If package is originally in dependencies and we wish to add it to
@@ -232,11 +231,10 @@
 
       devDependencies.add(range);
     } else {
-      /// TODO(walnut): Change the error message once pub upgrade --bump is
-      /// released
       if (dependencyNames.contains(name)) {
-        dataError('"$name" is already in "dependencies". '
-            'Use "pub upgrade $name" to upgrade to a later version!');
+        log.message(
+            '"$name" is already in "dependencies". Will try to update the constraint.');
+        dependencies.removeWhere((element) => element.name == name);
       }
 
       /// If package is originally in dev_dependencies and we wish to add it to
@@ -245,7 +243,7 @@
       if (devDependencyNames.contains(name)) {
         log.message('"$name" was found in dev_dependencies. '
             'Removing "$name" and adding it to dependencies instead.');
-        devDependencies = devDependencies.where((d) => d.name != name).toList();
+        devDependencies.removeWhere((element) => element.name == name);
       }
 
       dependencies.add(range);
diff --git a/lib/src/command/deps.dart b/lib/src/command/deps.dart
index 678aafa..a4203ab 100644
--- a/lib/src/command/deps.dart
+++ b/lib/src/command/deps.dart
@@ -102,8 +102,7 @@
                     ? 'dev'
                     : 'transitive'));
         final source =
-            entrypoint.packageGraph.lockFile.packages[current]?.source.name ??
-                'root';
+            entrypoint.lockFile.packages[current]?.source.name ?? 'root';
         packagesJson.add({
           'name': current,
           'version': currentPackage.version.toString(),
@@ -288,7 +287,7 @@
       }
     }
 
-    _buffer.write(tree.fromMap(packageTree, showAllChildren: true));
+    _buffer.write(tree.fromMap(packageTree));
   }
 
   String _labelPackage(Package package) =>
diff --git a/lib/src/command/lish.dart b/lib/src/command/lish.dart
index 69c1c7e..e45a735 100644
--- a/lib/src/command/lish.dart
+++ b/lib/src/command/lish.dart
@@ -16,6 +16,7 @@
 import '../io.dart';
 import '../log.dart' as log;
 import '../oauth2.dart' as oauth2;
+import '../solver/type.dart';
 import '../source/hosted.dart' show validateAndNormalizeHostedUrl;
 import '../utils.dart';
 import '../validator.dart';
@@ -25,7 +26,7 @@
   @override
   String get name => 'publish';
   @override
-  String get description => 'Publish the current package to pub.dartlang.org.';
+  String get description => 'Publish the current package to pub.dev.';
   @override
   String get argumentsDescription => '[options]';
   @override
@@ -154,9 +155,9 @@
   Future<void> _publish(List<int> packageBytes) async {
     try {
       final officialPubServers = {
-        'https://pub.dartlang.org',
-        // [validateAndNormalizeHostedUrl] normalizes https://pub.dev to
-        // https://pub.dartlang.org, so we don't need to do allow that here.
+        'https://pub.dev',
+        // [validateAndNormalizeHostedUrl] normalizes https://pub.dartlang.org
+        // to https://pub.dev, so we don't need to do allow that here.
 
         // Pub uses oauth2 credentials only for authenticating official pub
         // servers for security purposes (to not expose pub.dev access token to
@@ -219,6 +220,8 @@
           'pubspec.');
     }
 
+    await entrypoint.acquireDependencies(SolveType.get, analytics: analytics);
+
     var files = entrypoint.root.listFiles();
     log.fine('Archiving and publishing ${entrypoint.root.name}.');
 
@@ -226,7 +229,7 @@
     var package = entrypoint.root;
     log.message(
       'Publishing ${package.name} ${package.version} to $host:\n'
-      '${tree.fromFiles(files, baseDir: entrypoint.root.dir, showAllChildren: true)}',
+      '${tree.fromFiles(files, baseDir: entrypoint.root.dir, showFileSizes: true)}',
     );
 
     var packageBytesFuture =
diff --git a/lib/src/command/login.dart b/lib/src/command/login.dart
index 96c04d8..8f428ab 100644
--- a/lib/src/command/login.dart
+++ b/lib/src/command/login.dart
@@ -40,7 +40,7 @@
             'Run `$topLevelProgram pub logout` to delete your credentials and try again.');
       }
       log.warning('You are already logged in as $userInfo\n'
-          'Run `pub logout` to log out and try again.');
+          'Run `$topLevelProgram pub logout` to log out and try again.');
     }
   }
 
diff --git a/lib/src/command/outdated.dart b/lib/src/command/outdated.dart
index 59131c4..6f22fd5 100644
--- a/lib/src/command/outdated.dart
+++ b/lib/src/command/outdated.dart
@@ -556,7 +556,7 @@
     }
   } else {
     log.message('\nNo pubspec.lock found. There are no Current versions.\n'
-        'Run `pub get` to create a pubspec.lock with versions matching your '
+        'Run `$topLevelProgram pub get` to create a pubspec.lock with versions matching your '
         'pubspec.yaml.');
   }
   if (notAtResolvable != 0) {
diff --git a/lib/src/command/upgrade.dart b/lib/src/command/upgrade.dart
index 25feb70..a83d129 100644
--- a/lib/src/command/upgrade.dart
+++ b/lib/src/command/upgrade.dart
@@ -222,6 +222,14 @@
     }
     final newPubspecText = _updatePubspec(changes);
 
+    // When doing '--majorVersions' for specific packages we try to update other
+    // packages as little as possible to make a focused change (SolveType.get).
+    //
+    // But without a specific package we want to get as many non-major updates
+    // as possible (SolveType.upgrade).
+    final solveType =
+        argResults.rest.isEmpty ? SolveType.upgrade : SolveType.get;
+
     if (_dryRun) {
       // Even if it is a dry run, run `acquireDependencies` so that the user
       // gets a report on changes.
@@ -233,7 +241,7 @@
         lockFile: entrypoint.lockFile,
         solveResult: solveResult,
       ).acquireDependencies(
-        SolveType.get,
+        solveType,
         dryRun: true,
         precompile: _precompile,
         analytics: null, // No analytics for dry-run
@@ -246,7 +254,7 @@
       //       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,
         precompile: _precompile,
         analytics: analytics,
       );
diff --git a/lib/src/command/uploader.dart b/lib/src/command/uploader.dart
index cae4963..07ffacc 100644
--- a/lib/src/command/uploader.dart
+++ b/lib/src/command/uploader.dart
@@ -13,8 +13,7 @@
   @override
   String get name => 'uploader';
   @override
-  String get description =>
-      'Manage uploaders for a package on pub.dartlang.org.';
+  String get description => 'Manage uploaders for a package on pub.dev.';
   @override
   String get argumentsDescription => '[options] {add/remove} <email>';
   @override
diff --git a/lib/src/crc32c.dart b/lib/src/crc32c.dart
new file mode 100644
index 0000000..e346a59
--- /dev/null
+++ b/lib/src/crc32c.dart
@@ -0,0 +1,103 @@
+// 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.
+
+/// Computes a crc32c checksum.
+class Crc32c {
+  int _current = mask;
+  static const mask = 0xFFFFFFFF;
+
+  // Algorithm based on https://en.wikipedia.org/wiki/Cyclic_redundancy_check
+  void update(List<int> data) {
+    for (var i = 0; i < data.length; i++) {
+      final lookupIndex = (_current ^ data[i]) & 0xff;
+      _current = (_current >> 8) ^ _crcTable[lookupIndex];
+    }
+  }
+
+  int finalize() {
+    // Finalize the CRC-32 value by inverting all the bits
+    return _current ^ mask & mask;
+  }
+
+  /// Consumes the entirety of "stream" and returns the CRC32C checksum of its
+  /// data once the stream is finished.
+  static Future<int> computeByConsumingStream(Stream<List<int>> stream) async {
+    final checksumComputer = Crc32c();
+
+    await for (final chunk in stream) {
+      checksumComputer.update(chunk);
+    }
+
+    return checksumComputer.finalize();
+  }
+}
+
+// Generated by ./pycrc.py --algorithm=table-driven --model=crc-32c --generate=c
+// See: https://pycrc.org/
+const _crcTable = [
+  0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, //
+  0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
+  0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
+  0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
+  0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
+  0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
+  0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
+  0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
+  0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
+  0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
+  0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
+  0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
+  0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
+  0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
+  0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
+  0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
+  0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
+  0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
+  0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
+  0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
+  0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
+  0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
+  0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
+  0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
+  0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
+  0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
+  0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
+  0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
+  0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
+  0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
+  0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
+  0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
+  0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
+  0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
+  0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
+  0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
+  0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
+  0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
+  0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
+  0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
+  0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
+  0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
+  0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
+  0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
+  0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
+  0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
+  0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
+  0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
+  0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
+  0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
+  0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
+  0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
+  0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
+  0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
+  0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
+  0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
+  0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
+  0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
+  0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
+  0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
+  0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
+  0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
+  0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
+  0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351
+];
diff --git a/lib/src/dart.dart b/lib/src/dart.dart
index 0169174..5c3828e 100644
--- a/lib/src/dart.dart
+++ b/lib/src/dart.dart
@@ -186,7 +186,7 @@
     final result = await client.compile();
 
     final highlightedName = log.bold(name);
-    if (result?.errorCount == 0) {
+    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.
@@ -200,7 +200,7 @@
 
       throw ApplicationException(
           log.yellow('Failed to build $highlightedName:\n') +
-              (result?.compilerOutputLines.join('\n') ?? ''));
+              result.compilerOutputLines.join('\n'));
     }
   } finally {
     client?.kill();
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index eb643fe..b536cca 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -107,6 +107,34 @@
 
   LockFile? _lockFile;
 
+  /// The `.dart_tool/package_config.json` package-config of this entrypoint.
+  ///
+  /// Lazily initialized. Will throw [DataError] when initializing if the
+  /// `.dart_tool/packageConfig.json` file doesn't exist or has a bad format .
+  late PackageConfig packageConfig = () {
+    late String packageConfigRaw;
+    try {
+      packageConfigRaw = readTextFile(packageConfigPath);
+    } on FileException {
+      dataError(
+          'The "$packageConfigPath" file does not exist, please run "$topLevelProgram pub get".');
+    }
+    late PackageConfig result;
+    try {
+      result = PackageConfig.fromJson(json.decode(packageConfigRaw));
+    } on FormatException {
+      badPackageConfig();
+    }
+    // Version 2 is the initial version number for `package_config.json`,
+    // because `.packages` was version 1 (even if it was a different file).
+    // If the version is different from 2, then it must be a newer incompatible
+    // version, hence, the user should run `pub get` with the downgraded SDK.
+    if (result.configVersion != 2) {
+      badPackageConfig();
+    }
+    return result;
+  }();
+
   /// The package graph for the application and all of its transitive
   /// dependencies.
   ///
@@ -117,11 +145,16 @@
   PackageGraph _createPackageGraph() {
     assertUpToDate();
     var packages = {
-      for (var id in lockFile.packages.values) id.name: cache.load(id)
+      for (var packageEntry in packageConfig.nonInjectedPackages)
+        packageEntry.name: Package.load(
+          packageEntry.name,
+          packageEntry.resolvedRootDir(packageConfigPath),
+          cache.sources,
+        ),
     };
     packages[root.name] = root;
 
-    return PackageGraph(this, lockFile, packages);
+    return PackageGraph(this, packages);
   }
 
   PackageGraph? _packageGraph;
@@ -139,9 +172,10 @@
   /// not require it or make use of it within pub.
   String get packagesFile => p.normalize(p.join(_configRoot!, '.packages'));
 
-  /// The path to the entrypoint's ".dart_tool/package_config.json" file.
-  String get packageConfigFile =>
-      p.normalize(p.join(_configRoot!, '.dart_tool', 'package_config.json'));
+  /// The path to the entrypoint's ".dart_tool/package_config.json" file
+  /// relative to the current working directory .
+  late String packageConfigPath = p.relative(
+      p.normalize(p.join(_configRoot!, '.dart_tool', 'package_config.json')));
 
   /// The path to the entrypoint package's pubspec.
   String get pubspecPath => p.normalize(root.path('pubspec.yaml'));
@@ -190,7 +224,11 @@
     bool withPubspecOverrides = true,
   })  : root = Package.load(null, rootDir, cache.sources,
             withPubspecOverrides: withPubspecOverrides),
-        globalDir = null;
+        globalDir = null {
+    if (p.isWithin(cache.rootDir, rootDir)) {
+      fail('Cannot operate on packages inside the cache.');
+    }
+  }
 
   Entrypoint.inMemory(this.root, this.cache,
       {required LockFile? lockFile, SolveResult? solveResult})
@@ -226,9 +264,9 @@
   /// Writes .packages and .dart_tool/package_config.json
   Future<void> writePackageConfigFile() async {
     final entrypointName = isGlobal ? null : root.name;
-    ensureDir(p.dirname(packageConfigFile));
+    ensureDir(p.dirname(packageConfigPath));
     writeTextFile(
-      packageConfigFile,
+      packageConfigPath,
       await lockFile.packageConfigFile(
         cache,
         entrypoint: entrypointName,
@@ -421,7 +459,7 @@
         executablePath: resolveExecutable(executable),
         outputPath: pathOfExecutable(executable),
         incrementalDillPath: incrementalDillPathOfExecutable(executable),
-        packageConfigPath: packageConfigFile,
+        packageConfigPath: packageConfigPath,
         name:
             '$package:${p.basenameWithoutExtension(executable.relativePath)}');
   }
@@ -512,9 +550,9 @@
       dataError(
           'No $lockFilePath file found, please run "$topLevelProgram pub get" first.');
     }
-    if (!entryExists(packageConfigFile)) {
+    if (!entryExists(packageConfigPath)) {
       dataError(
-        'No $packageConfigFile file found, please run "$topLevelProgram pub get".\n'
+        'No $packageConfigPath file found, please run "$topLevelProgram pub get".\n'
         '\n'
         'Starting with Dart 2.7, the package_config.json file configures '
         'resolution of package import URIs; run "$topLevelProgram pub get" to generate it.',
@@ -559,7 +597,7 @@
       }
     }
 
-    var packageConfigModified = File(packageConfigFile).lastModifiedSync();
+    var packageConfigModified = File(packageConfigPath).lastModifiedSync();
     if (packageConfigModified.isBefore(lockFileModified) ||
         hasPathDependencies) {
       // If `package_config.json` is older than `pubspec.lock` or we have
@@ -568,9 +606,9 @@
       //  * Mitigate issues when copying a folder from one machine to another.
       //  * Force `pub get` if a path dependency has changed language version.
       _checkPackageConfigUpToDate();
-      touch(packageConfigFile);
+      touch(packageConfigPath);
     } else if (touchedLockFile) {
-      touch(packageConfigFile);
+      touch(packageConfigPath);
     }
 
     for (var match in _sdkConstraint.allMatches(lockFileText)) {
@@ -724,49 +762,13 @@
   void _checkPackageConfigUpToDate() {
     void outOfDate() {
       dataError('The $lockFilePath file has changed since the '
-          '$packageConfigFile file '
+          '$packageConfigPath file '
           'was generated, please run "$topLevelProgram pub get" again.');
     }
 
-    void badPackageConfig() {
-      dataError('The "$packageConfigFile" file is not recognized by '
-          '"pub" version, please run "$topLevelProgram pub get".');
-    }
-
-    late String packageConfigRaw;
-    try {
-      packageConfigRaw = readTextFile(packageConfigFile);
-    } on FileException {
-      dataError(
-          'The "$packageConfigFile" file does not exist, please run "$topLevelProgram pub get".');
-    }
-
-    late PackageConfig cfg;
-    try {
-      cfg = PackageConfig.fromJson(json.decode(packageConfigRaw));
-    } on FormatException {
-      badPackageConfig();
-    }
-
-    // Version 2 is the initial version number for `package_config.json`,
-    // because `.packages` was version 1 (even if it was a different file).
-    // If the version is different from 2, then it must be a newer incompatible
-    // version, hence, the user should run `pub get` with the downgraded SDK.
-    if (cfg.configVersion != 2) {
-      badPackageConfig();
-    }
-
     final packagePathsMapping = <String, String>{};
 
-    // We allow the package called 'flutter_gen' to be injected into
-    // package_config.
-    //
-    // This is somewhat a hack. But it allows flutter to generate code in a
-    // package as it likes.
-    //
-    // See https://github.com/flutter/flutter/issues/73870 .
-    final packagesToCheck =
-        cfg.packages.where((package) => package.name != 'flutter_gen');
+    final packagesToCheck = packageConfig.nonInjectedPackages;
     for (final pkg in packagesToCheck) {
       // Pub always makes a packageUri of lib/
       if (pkg.packageUri == null || pkg.packageUri.toString() != 'lib/') {
@@ -781,7 +783,7 @@
 
     // Check if language version specified in the `package_config.json` is
     // correct. This is important for path dependencies as these can mutate.
-    for (final pkg in cfg.packages) {
+    for (final pkg in packageConfig.packages) {
       if (pkg.name == root.name || pkg.name == 'flutter_gen') continue;
       final id = lockFile.packages[pkg.name];
       if (id == null) {
@@ -909,6 +911,11 @@
       }
     }
   }
+
+  Never badPackageConfig() {
+    dataError('The "$packageConfigPath" file is not recognized by '
+        '"pub" version, please run "$topLevelProgram pub get".');
+  }
 }
 
 /// Returns `true` if the [text] looks like it uses windows line endings.
diff --git a/lib/src/exceptions.dart b/lib/src/exceptions.dart
index fcde747..ec9f876 100644
--- a/lib/src/exceptions.dart
+++ b/lib/src/exceptions.dart
@@ -104,6 +104,15 @@
   String toString() => 'Package not available ($message).';
 }
 
+/// A class for exceptions where a package's checksum could not be validated.
+class PackageIntegrityException extends WrappedException {
+  PackageIntegrityException(
+    String message, {
+    Object? innerError,
+    StackTrace? innerTrace,
+  }) : super(message, innerError, innerTrace);
+}
+
 /// Returns whether [error] is a user-facing error object.
 ///
 /// This includes both [ApplicationException] and any dart:io errors.
diff --git a/lib/src/executable.dart b/lib/src/executable.dart
index 5d8ea8b..d926023 100644
--- a/lib/src/executable.dart
+++ b/lib/src/executable.dart
@@ -106,7 +106,7 @@
   // helpful for the subprocess to be able to spawn Dart with
   // Platform.executableArguments and have that work regardless of the working
   // directory.
-  final packageConfigAbsolute = p.absolute(entrypoint.packageConfigFile);
+  final packageConfigAbsolute = p.absolute(entrypoint.packageConfigPath);
 
   try {
     return await _runDartProgram(
@@ -335,14 +335,13 @@
     command = package;
   }
 
-  if (!entrypoint.packageGraph.packages.containsKey(package)) {
+  if (!entrypoint.packageConfig.packages.any((p) => p.name == package)) {
     throw CommandResolutionFailedException._(
       'Could not find package `$package` or file `$descriptor`',
       CommandResolutionIssue.packageNotFound,
     );
   }
   final executable = Executable(package, p.join('bin', '$command.dart'));
-  final packageConfig = p.join('.dart_tool', 'package_config.json');
 
   final path = entrypoint.resolveExecutable(executable);
   if (!fileExists(path)) {
@@ -351,10 +350,12 @@
       CommandResolutionIssue.noBinaryFound,
     );
   }
+  final packageConfigPath =
+      p.relative(entrypoint.packageConfigPath, from: root);
   if (!allowSnapshot) {
     return DartExecutableWithPackageConfig(
       executable: p.relative(path, from: root),
-      packageConfig: packageConfig,
+      packageConfig: packageConfigPath,
     );
   } else {
     final snapshotPath = entrypoint.pathOfExecutable(executable);
@@ -373,7 +374,7 @@
     }
     return DartExecutableWithPackageConfig(
       executable: p.relative(snapshotPath, from: root),
-      packageConfig: packageConfig,
+      packageConfig: packageConfigPath,
     );
   }
 }
diff --git a/lib/src/http.dart b/lib/src/http.dart
index 724962b..6473a8e 100644
--- a/lib/src/http.dart
+++ b/lib/src/http.dart
@@ -19,14 +19,15 @@
 import 'oauth2.dart' as oauth2;
 import 'package.dart';
 import 'sdk.dart';
+import 'source/hosted.dart';
 import 'utils.dart';
 
 /// Headers and field names that should be censored in the log output.
 const _censoredFields = ['refresh_token', 'authorization'];
 
-/// Headers required for pub.dartlang.org API requests.
+/// Headers required for pub.dev API requests.
 ///
-/// The Accept header tells pub.dartlang.org which version of the API we're
+/// The Accept header tells pub.dev which version of the API we're
 /// expecting, so it can either serve that version or give us a 406 error if
 /// it's not supported.
 const pubApiHeaders = {'Accept': 'application/vnd.pub.v2+json'};
@@ -79,7 +80,7 @@
         return false;
       }
     } else {
-      if (request.url.origin != 'https://pub.dartlang.org') return false;
+      if (!HostedSource.isPubDevUrl(request.url.toString())) return false;
     }
 
     if (Platform.environment.containsKey('CI') &&
@@ -222,7 +223,7 @@
     }
 
     if (status == 500 &&
-        (request.url.host == 'pub.dartlang.org' ||
+        (request.url.host == 'pub.dev' ||
             request.url.host == 'storage.googleapis.com')) {
       fail('HTTP error 500: Internal Server Error at ${request.url}.\n'
           'This is likely a transient error. Please try again later.');
@@ -281,7 +282,7 @@
 http.Client get innerHttpClient => _pubClient._inner;
 set innerHttpClient(http.Client client) => _pubClient._inner = client;
 
-/// Runs [callback] in a zone where all HTTP requests sent to `pub.dartlang.org`
+/// Runs [callback] in a zone where all HTTP requests sent to `pub.dev`
 /// will indicate the [type] of the relationship between the root package and
 /// the package being requested.
 ///
@@ -293,7 +294,7 @@
   return runZoned(callback, zoneValues: {#_dependencyType: type});
 }
 
-/// Handles a successful JSON-formatted response from pub.dartlang.org.
+/// Handles a successful JSON-formatted response from pub.dev.
 ///
 /// These responses are expected to be of the form `{"success": {"message":
 /// "some message"}}`. If the format is correct, the message will be printed;
@@ -308,7 +309,7 @@
   log.message(log.green(parsed['success']['message']));
 }
 
-/// Handles an unsuccessful JSON-formatted response from pub.dartlang.org.
+/// Handles an unsuccessful JSON-formatted response from pub.dev.
 ///
 /// These responses are expected to be of the form `{"error": {"message": "some
 /// message"}}`. If the format is correct, the message will be raised as an
diff --git a/lib/src/io.dart b/lib/src/io.dart
index 50f7eb9..2b5d0cd 100644
--- a/lib/src/io.dart
+++ b/lib/src/io.dart
@@ -172,7 +172,7 @@
 }
 
 /// Reads the contents of the binary file [file] as a [Stream].
-Stream<List<int>> readBinaryFileAsSream(String file) {
+Stream<List<int>> readBinaryFileAsStream(String file) {
   log.io('Reading binary file $file.');
   var contents = File(file).openRead();
   return contents;
diff --git a/lib/src/oauth2.dart b/lib/src/oauth2.dart
index 7229bb1..802a8c2 100644
--- a/lib/src/oauth2.dart
+++ b/lib/src/oauth2.dart
@@ -78,7 +78,7 @@
 void logout(SystemCache cache) {
   var credentialsFile = _credentialsFile(cache);
   if (credentialsFile != null && entryExists(credentialsFile)) {
-    log.message('Logging out of pub.dartlang.org.');
+    log.message('Logging out of pub.dev.');
     log.message('Deleting $credentialsFile');
     _clearCredentials(cache);
     // Test if we also have a legacy credentials file.
diff --git a/lib/src/package_config.dart b/lib/src/package_config.dart
index e5e5e7d..dec8b5c 100644
--- a/lib/src/package_config.dart
+++ b/lib/src/package_config.dart
@@ -4,6 +4,7 @@
 
 import 'dart:convert';
 
+import 'package:path/path.dart' as p;
 import 'package:pub_semver/pub_semver.dart';
 
 import 'language_version.dart';
@@ -139,6 +140,16 @@
         'generator': generator,
         'generatorVersion': generatorVersion?.toString(),
       }..addAll(additionalProperties);
+
+  // We allow the package called 'flutter_gen' to be injected into
+  // package_config.
+  //
+  // This is somewhat a hack. But it allows flutter to generate code in a
+  // package as it likes.
+  //
+  // See https://github.com/flutter/flutter/issues/73870 .
+  Iterable<PackageConfigEntry> get nonInjectedPackages =>
+      packages.where((package) => package.name != 'flutter_gen');
 }
 
 class PackageConfigEntry {
@@ -260,4 +271,8 @@
     // TODO: implement toString
     return JsonEncoder.withIndent('  ').convert(toJson());
   }
+
+  String resolvedRootDir(String packageConfigPath) {
+    return p.join(p.dirname(packageConfigPath), p.fromUri(rootUri));
+  }
 }
diff --git a/lib/src/package_graph.dart b/lib/src/package_graph.dart
index cbd91ec..6c736e6 100644
--- a/lib/src/package_graph.dart
+++ b/lib/src/package_graph.dart
@@ -3,12 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:collection/collection.dart' hide mapMap;
+import 'package:path/path.dart' as p;
 
 import 'entrypoint.dart';
-import 'lock_file.dart';
 import 'package.dart';
 import 'solver.dart';
-import 'source/cached.dart';
 import 'utils.dart';
 
 /// A holistic view of the entire transitive dependency graph for an entrypoint.
@@ -16,12 +15,6 @@
   /// The entrypoint.
   final Entrypoint entrypoint;
 
-  /// The entrypoint's lockfile.
-  ///
-  /// This describes the sources and resolved descriptions of everything in
-  /// [packages].
-  final LockFile lockFile;
-
   /// The transitive dependencies of the entrypoint (including itself).
   ///
   /// This may not include all transitive dependencies of the entrypoint if the
@@ -32,7 +25,7 @@
   /// A map of transitive dependencies for each package.
   Map<String, Set<Package>>? _transitiveDependencies;
 
-  PackageGraph(this.entrypoint, this.lockFile, this.packages);
+  PackageGraph(this.entrypoint, this.packages);
 
   /// Creates a package graph using the data from [result].
   ///
@@ -50,7 +43,7 @@
               )
     };
 
-    return PackageGraph(entrypoint, result.lockFile, packages);
+    return PackageGraph(entrypoint, packages);
   }
 
   /// Returns all transitive dependencies of [package].
@@ -81,12 +74,7 @@
     // the entrypoint.
     // TODO(sigurdm): there should be a way to get the id of any package
     // including the root.
-    if (package == entrypoint.root.name) {
-      return entrypoint.isCached;
-    } else {
-      var id = lockFile.packages[package]!;
-      return id.source is CachedSource;
-    }
+    return p.isWithin(entrypoint.cache.rootDir, packages[package]!.dir);
   }
 
   /// Returns whether [package] is mutable.
diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart
index d06b025..0b6cd5b 100644
--- a/lib/src/pubspec.dart
+++ b/lib/src/pubspec.dart
@@ -301,7 +301,6 @@
       {String? expectedName, bool allowOverridesFile = false}) {
     var pubspecPath = path.join(packageDir, pubspecYamlFilename);
     var overridesPath = path.join(packageDir, pubspecOverridesFilename);
-
     if (!fileExists(pubspecPath)) {
       throw FileException(
           // Make the package dir absolute because for the entrypoint it'll just
diff --git a/lib/src/pubspec_parse.dart b/lib/src/pubspec_parse.dart
index 62eaa13..c86a706 100644
--- a/lib/src/pubspec_parse.dart
+++ b/lib/src/pubspec_parse.dart
@@ -14,7 +14,7 @@
 ///
 /// This allows dot-separated valid Dart identifiers. The dots are there for
 /// compatibility with Google's internal Dart packages, but they may not be used
-/// when publishing a package to pub.dartlang.org.
+/// when publishing a package to pub.dev.
 final packageNameRegExp =
     RegExp('^${identifierRegExp.pattern}(\\.${identifierRegExp.pattern})*\$');
 
diff --git a/lib/src/solver/package_lister.dart b/lib/src/solver/package_lister.dart
index 1198864..ce2b4c1 100644
--- a/lib/src/solver/package_lister.dart
+++ b/lib/src/solver/package_lister.dart
@@ -140,22 +140,22 @@
   ///
   /// Throws a [PackageNotFoundException] if this lister's package doesn't
   /// exist.
-  Future<PackageId?> bestVersion(VersionConstraint? constraint) async {
+  Future<PackageId?> bestVersion(VersionConstraint constraint) async {
     final locked = _locked;
-    if (locked != null && constraint!.allows(locked.version)) return locked;
+    if (locked != null && constraint.allows(locked.version)) return locked;
 
     var versions = await _versions;
 
     // If [constraint] has a minimum (or a maximum in downgrade mode), we can
     // bail early once we're past it.
-    var isPastLimit = (Version? _) => false;
+    var isPastLimit = (Version _) => false;
     if (constraint is VersionRange) {
       if (_isDowngrade) {
         var max = constraint.max;
-        if (max != null) isPastLimit = (version) => version! > max;
+        if (max != null) isPastLimit = (version) => version > max;
       } else {
         var min = constraint.min;
-        if (min != null) isPastLimit = (version) => version! < min;
+        if (min != null) isPastLimit = (version) => version < min;
       }
     }
 
@@ -166,7 +166,7 @@
     for (var id in _isDowngrade ? versions : versions.reversed) {
       if (isPastLimit(id.version)) break;
 
-      if (!constraint!.allows(id.version)) continue;
+      if (!constraint.allows(id.version)) continue;
       if (!id.version.isPreRelease) {
         return id;
       }
diff --git a/lib/src/source.dart b/lib/src/source.dart
index e331da1..a918c68 100644
--- a/lib/src/source.dart
+++ b/lib/src/source.dart
@@ -66,7 +66,7 @@
   /// [containingDir] is the path to the directory of the pubspec where this
   /// description appears. It may be `null` if the description is coming from
   /// some in-memory source (such as pulling down a pubspec from
-  /// pub.dartlang.org).
+  /// pub.dev).
   ///
   /// [languageVersion] is the minimum Dart version parsed from the pubspec's
   /// `environment` field. Source implementations may use this parameter to only
diff --git a/lib/src/source/hosted.dart b/lib/src/source/hosted.dart
index e7dc870..451dce1 100644
--- a/lib/src/source/hosted.dart
+++ b/lib/src/source/hosted.dart
@@ -5,15 +5,19 @@
 import 'dart:async';
 import 'dart:convert';
 import 'dart:io' as io;
+import 'dart:math' as math;
+import 'dart:typed_data';
 
 import 'package:collection/collection.dart'
     show maxBy, IterableNullableExtension;
 import 'package:http/http.dart' as http;
+import 'package:meta/meta.dart';
 import 'package:path/path.dart' as p;
 import 'package:pub_semver/pub_semver.dart';
 import 'package:stack_trace/stack_trace.dart';
 
 import '../authentication/client.dart';
+import '../crc32c.dart';
 import '../exceptions.dart';
 import '../http.dart';
 import '../io.dart';
@@ -31,15 +35,18 @@
 /// Validates and normalizes a [hostedUrl] which is pointing to a pub server.
 ///
 /// A [hostedUrl] is a URL pointing to a _hosted pub server_ as defined by the
-/// [repository-spec-v2][1]. The default value is `pub.dartlang.org`, and can be
+/// [repository-spec-v2][1]. The default value is `pub.dev`, and can be
 /// overwritten using `PUB_HOSTED_URL`. It can also specified for individual
 /// hosted-dependencies in `pubspec.yaml`, and for the root package using the
 /// `publish_to` key.
 ///
 /// The [hostedUrl] is always normalized to a [Uri] with path that ends in slash
-/// unless the path is merely `/`, in which case we normalize to the bare domain
-/// this keeps the [hostedUrl] and maintains avoids unnecessary churn in
-/// `pubspec.lock` files which contain `https://pub.dartlang.org`.
+/// unless the path is merely `/`, in which case we normalize to the bare
+/// domain.
+///
+/// We change `https://pub.dev` to `https://pub.dartlang.org`, this  maintains
+/// avoids churn for `pubspec.lock`-files which contain
+/// `https://pub.dartlang.org`.
 ///
 /// Throws [FormatException] if there is anything wrong [hostedUrl].
 ///
@@ -83,6 +90,18 @@
   //
   // We rewrite here to avoid caching both, and to avoid having different
   // credentials for these two.
+  //
+  // Changing this to pub.dev raises the following concerns:
+  //
+  //  1. It would blow through users caches.
+  //  2. It would cause conflicts for users checking pubspec.lock into git, if using
+  //     different versions of the dart-sdk / pub client.
+  //  3. It might cause other problems (investigation needed) for pubspec.lock across
+  //     different versions of the dart-sdk / pub client.
+  //  4. It would expand the API surface we're committed to supporting long-term.
+  //
+  // Clearly, a bit of investigation is necessary before we update this to
+  // pub.dev, it might be attractive to do next time we change the server API.
   if (u == Uri.parse('https://pub.dev')) {
     log.fine('Using https://pub.dartlang.org instead of https://pub.dev.');
     u = Uri.parse('https://pub.dartlang.org');
@@ -91,7 +110,7 @@
 }
 
 /// A package source that gets packages from a package hosting site that uses
-/// the same API as pub.dartlang.org.
+/// the same API as pub.dev.
 class HostedSource extends CachedSource {
   static HostedSource instance = HostedSource._();
 
@@ -102,11 +121,17 @@
   @override
   final hasMultipleVersions = true;
 
-  static String pubDevUrl = 'https://pub.dartlang.org';
+  static String pubDevUrl = 'https://pub.dev';
+  static String pubDartlangUrl = 'https://pub.dartlang.org';
+
+  static bool isPubDevUrl(String url) {
+    final origin = Uri.parse(url).origin;
+    return origin == pubDevUrl || origin == pubDartlangUrl;
+  }
 
   static bool isFromPubDev(PackageId id) {
     final description = id.description.description;
-    return description is HostedDescription && description.url == pubDevUrl;
+    return description is HostedDescription && isPubDevUrl(description.url);
   }
 
   /// Gets the default URL for the package server for hosted dependencies.
@@ -851,27 +876,53 @@
           'Package $packageName has no version $version');
     }
 
-    var url = versionInfo.archiveUrl;
-    log.io('Get package from $url.');
+    final archiveUrl = versionInfo.archiveUrl;
+    log.io('Get package from $archiveUrl.');
     log.message('Downloading ${log.bold(id.name)} ${id.version}...');
 
     // Download and extract the archive to a temp directory.
     await withTempDir((tempDirForArchive) async {
-      var archivePath =
-          p.join(tempDirForArchive, '$packageName-$version.tar.gz');
-      var response = await withAuthenticatedClient(
-          cache,
-          Uri.parse(description.url),
-          (client) => client.send(http.Request('GET', url)));
+      var fileName = '$packageName-$version.tar.gz';
+      var archivePath = p.join(tempDirForArchive, fileName);
 
-      // We download the archive to disk instead of streaming it directly into
-      // the tar unpacking. This simplifies stream handling.
-      // Package:tar cancels the stream when it reaches end-of-archive, and
-      // cancelling a http stream makes it not reusable.
-      // There are ways around this, and we might revisit this later.
-      await createFileFromStream(response.stream, archivePath);
+      // The client from `withAuthenticatedClient` will retry HTTP requests.
+      // This wrapper is one layer up and will retry checksum validation errors.
+      await retry(
+        // Attempt to download archive and validate its checksum.
+        () async {
+          final request = http.Request('GET', archiveUrl);
+          final response = await withAuthenticatedClient(cache,
+              Uri.parse(description.url), (client) => client.send(request));
+          final expectedChecksum = _parseCrc32c(response.headers, fileName);
+
+          Stream<List<int>> stream = response.stream;
+          if (expectedChecksum != null) {
+            stream = _validateStream(
+                response.stream, expectedChecksum, id, archiveUrl);
+          }
+
+          // We download the archive to disk instead of streaming it directly
+          // into the tar unpacking. This simplifies stream handling.
+          // Package:tar cancels the stream when it reaches end-of-archive, and
+          // cancelling a http stream makes it not reusable.
+          // There are ways around this, and we might revisit this later.
+          await createFileFromStream(stream, archivePath);
+        },
+        // Retry if the checksum response header was malformed or the actual
+        // checksum did not match the expected checksum.
+        retryIf: (e) => e is PackageIntegrityException,
+        onRetry: (e, retryCount) => log
+            .io('Retry #${retryCount + 1} because of checksum error with GET '
+                '$archiveUrl...'),
+        maxAttempts: math.max(
+          1, // Having less than 1 attempt doesn't make sense.
+          int.tryParse(io.Platform.environment['PUB_MAX_HTTP_RETRIES'] ?? '') ??
+              7,
+        ),
+      );
+
       var tempDir = cache.createTempDir();
-      await extractTarGz(readBinaryFileAsSream(archivePath), tempDir);
+      await extractTarGz(readBinaryFileAsStream(archivePath), tempDir);
 
       // Now that the get has succeeded, move it to the real location in the
       // cache.
@@ -1100,3 +1151,84 @@
   @override
   bool operator ==(Object other) => other is _RefAndCache && other.ref == ref;
 }
+
+@visibleForTesting
+const checksumHeaderName = 'x-goog-hash';
+
+/// Adds a checksum validation "tap" to the response stream and returns a
+/// wrapped `Stream` object, which should be used to consume the incoming data.
+///
+/// As chunks are received, a CRC32C checksum is updated.
+/// Once the download is completed, the final checksum is compared with
+/// the one present in the checksum response header.
+///
+/// Throws [PackageIntegrityException] if there is a checksum mismatch.
+Stream<List<int>> _validateStream(Stream<List<int>> stream,
+    int expectedChecksum, PackageId id, Uri archiveUrl) async* {
+  final crc32c = Crc32c();
+
+  await for (final chunk in stream) {
+    crc32c.update(chunk);
+    yield chunk;
+  }
+
+  final actualChecksum = crc32c.finalize();
+
+  log.fine(
+      'Computed checksum $actualChecksum for ${id.name} ${id.version} with '
+      'expected CRC32C of $expectedChecksum.');
+
+  if (actualChecksum != expectedChecksum) {
+    throw PackageIntegrityException(
+        'Package archive for ${id.name} ${id.version} downloaded from '
+        '"$archiveUrl" has "x-goog-hash: crc32c=$expectedChecksum", which '
+        'doesn\'t match the checksum of the archive downloaded.');
+  }
+}
+
+/// Parses response [headers] and returns the archive's CRC32C checksum.
+///
+/// In most cases, GCS provides both MD5 and CRC32C checksums in its response
+/// headers. It uses the header name "x-goog-hash" for these values. It has
+/// been documented and observed that GCS will send multiple response headers
+/// with the same "x-goog-hash" token as the key.
+/// https://cloud.google.com/storage/docs/xml-api/reference-headers#xgooghash
+///
+/// Additionally, when the Dart http client encounters multiple response
+/// headers with the same key, it concatenates their values with a comma
+/// before inserting a single item with that key and concatenated value into
+/// its response "headers" Map.
+/// See https://github.com/dart-lang/http/issues/24
+/// https://github.com/dart-lang/http/blob/06649afbb5847dbb0293816ba8348766b116e419/pkgs/http/lib/src/base_response.dart#L29
+///
+/// Throws [PackageIntegrityException] if the CRC32C checksum cannot be parsed.
+int? _parseCrc32c(Map<String, String> headers, String fileName) {
+  final checksumHeader = headers[checksumHeaderName];
+  if (checksumHeader == null) return null;
+
+  final parts = checksumHeader.split(',');
+  for (final part in parts) {
+    if (part.startsWith('crc32c=')) {
+      final undecoded = part.substring('crc32c='.length);
+
+      try {
+        final bytes = base64Decode(undecoded);
+
+        // CRC32C must be 32 bits, or 4 bytes.
+        if (bytes.length != 4) {
+          throw FormatException('CRC32C checksum has invalid length', bytes);
+        }
+
+        return ByteData.view(bytes.buffer).getUint32(0);
+      } on FormatException catch (e, s) {
+        throw PackageIntegrityException(
+            'Package archive "$fileName" has a malformed CRC32C checksum in '
+            'its response headers',
+            innerError: e,
+            innerTrace: s);
+      }
+    }
+  }
+
+  return null;
+}
diff --git a/lib/src/third_party/tar/README.md b/lib/src/third_party/tar/README.md
index a2fbf7b..5e12e5a 100644
--- a/lib/src/third_party/tar/README.md
+++ b/lib/src/third_party/tar/README.md
@@ -4,4 +4,4 @@
 tar-archives.
 
  * Repository: `https://github.com/simolus3/tar/`
- * Revision: `901ae404e0a225d9b08e5253415ca092f5c08706`
+ * Revision: `23ee71d667f003fba8c80ee126d5e1330d17c141`
diff --git a/lib/src/third_party/tar/src/reader.dart b/lib/src/third_party/tar/src/reader.dart
index b9bc3d3..8502a26 100644
--- a/lib/src/third_party/tar/src/reader.dart
+++ b/lib/src/third_party/tar/src/reader.dart
@@ -3,7 +3,6 @@
 import 'dart:convert';
 import 'dart:typed_data';
 
-import 'package:async/async.dart';
 import 'package:meta/meta.dart';
 import 'package:typed_data/typed_data.dart';
 
@@ -27,21 +26,7 @@
   final int _maxSpecialFileSize;
 
   TarEntry? _current;
-
-  /// The underlying content stream for the [_current] entry. Draining this
-  /// stream will move the tar reader to the beginning of the next file.
-  ///
-  /// This is not the same as `_current.stream` for sparse files, which are
-  /// reported as expanded through [TarEntry.contents].
-  /// For that reason, we prefer to drain this stream when skipping a tar entry.
-  /// When we know we're skipping data, there's no point expanding sparse holes.
-  ///
-  /// This stream is always set to null after being drained, and there can only
-  /// be one [_underlyingContentStream] at a time.
-  Stream<List<int>>? _underlyingContentStream;
-
-  /// Whether [_current] has ever been listened to.
-  bool _listenedToContentsOnce = false;
+  _CurrentEntryStream? _currentStream;
 
   /// Whether we're in the process of reading tar headers.
   bool _isReadingHeaders = false;
@@ -220,7 +205,9 @@
         nextHeader.format = format;
 
         _current = TarEntry(nextHeader, content);
-        _listenedToContentsOnce = false;
+        final currentStreams = _currentStream;
+        assert(currentStreams == null ||
+            currentStreams.state == _EntryStreamState.preListen);
         _isReadingHeaders = false;
         return true;
       }
@@ -233,8 +220,7 @@
 
     _isDone = true;
     _current = null;
-    _underlyingContentStream = null;
-    _listenedToContentsOnce = false;
+    _currentStream = null;
     _isReadingHeaders = false;
 
     // Note: Calling cancel is safe when the stream has already been completed.
@@ -276,18 +262,51 @@
     }
     _isReadingHeaders = true;
 
-    final underlyingStream = _underlyingContentStream;
+    final underlyingStream = _currentStream;
     if (underlyingStream != null) {
-      if (_listenedToContentsOnce) {
-        throw StateError(
+      switch (underlyingStream.state) {
+        case _EntryStreamState.preListen:
+          await underlyingStream.drain<void>();
+          // The stream should reset when drained (we do this in _publishStream)
+          assert(_currentStream == null);
+
+          break;
+        case _EntryStreamState.subscriptionActive:
+          throw StateError(
             'Illegal call to TarReader.moveNext() while a previous stream was '
             'active.\n'
             'When listening to tar contents, make sure the stream is '
-            'complete or cancelled before calling TarReader.moveNext() again.');
-      } else {
-        await underlyingStream.drain<void>();
-        // The stream should reset when drained (we do this in _publishStream)
-        assert(_underlyingContentStream == null);
+            'complete or cancelled before calling TarReader.moveNext() again.',
+          );
+        case _EntryStreamState.cancelled:
+          // ignore: cancel_subscriptions
+          final subscription = underlyingStream._sourceSubscription!;
+
+          // Re-purpose the existing subscription to drain the stream
+          assert(subscription.isPaused);
+
+          subscription
+            ..onData(null)
+            ..resume();
+
+          try {
+            await subscription.asFuture<void>();
+          } on Object {
+            await cancel();
+            rethrow;
+          } finally {
+            // This also draines the stream
+            _currentStream = null;
+          }
+
+          break;
+        case _EntryStreamState.done:
+          assert(
+            false,
+            'Unreachable: There should not be a currentStream in a done state, '
+            'as the stream is no longer current at that point.',
+          );
+          break;
       }
     }
   }
@@ -418,59 +437,14 @@
   /// Publishes an library-internal stream for users.
   ///
   /// This adds a check to ensure that the stream we're exposing has the
-  /// expected length. It also sets the [_underlyingContentStream] field when
-  /// the stream starts and resets it when it's done.
-  Stream<List<int>> _publishStream(Stream<List<int>> stream, int length) {
+  /// expected length. It also sets the [_currentStream] field and resets it
+  /// when it's done.
+  Stream<List<int>> _publishStream(Stream<Uint8List> stream, int length) {
     // There can only be one content stream at a time. This precondition is
     // checked by _prepareToReadHeaders.
-    assert(_underlyingContentStream == null);
-    Stream<List<int>>? thisStream;
+    assert(_currentStream == null);
 
-    return thisStream =
-        _underlyingContentStream = Stream.eventTransformed(stream, (sink) {
-      // This callback is called when we have a listener. Make sure that, at
-      // this point, this stream is still the active content stream.
-      // If users store the contents of a tar header, then read more tar
-      // entries, and finally try to read the stream of the old contents, they'd
-      // get an exception about the straem already being listened to.
-      // This can be a bit confusing, so this check enables a better error UX.
-      if (thisStream != _underlyingContentStream) {
-        throw StateError(
-          'Tried listening to an outdated tar entry. \n'
-          'As all tar entries found by a reader are backed by a single source '
-          'stream, only the latest tar entry can be read. It looks like you '
-          'stored the results of `tarEntry.contents` somewhere, called '
-          '`reader.moveNext()` and then read the contents of the previous '
-          'entry.\n'
-          'For more details, including a discussion of workarounds, see '
-          'https://github.com/simolus3/tar/issues/18',
-        );
-      } else if (_listenedToContentsOnce) {
-        throw StateError(
-          'A tar entry has been listened to multiple times. \n'
-          'As all tar entries are read from what\'s likely a single-'
-          'subscription stream, this is unsupported. If you didn\'t read a tar '
-          'entry multiple times yourself, perhaps you\'ve called `moveNext()` '
-          'before reading contents?',
-        );
-      }
-
-      _listenedToContentsOnce = true;
-
-      late _OutgoingStreamGuard guard;
-      return guard = _OutgoingStreamGuard(
-        length,
-        sink,
-        // Reset state when the stream is done. This will only be called when
-        // the stream is done, not when a listener cancels.
-        () {
-          _underlyingContentStream = null;
-          if (guard.hadError) {
-            cancel();
-          }
-        },
-      );
-    });
+    return _currentStream = _CurrentEntryStream(this, stream, length);
   }
 
   /// Checks the PAX headers for GNU sparse headers.
@@ -881,23 +855,96 @@
   }
 }
 
-/// Event-sink tracking the length of emitted tar entry streams.
+enum _EntryStreamState {
+  preListen,
+  subscriptionActive,
+  cancelled,
+  done,
+}
+
+/// The underlying content stream for the [TarReader._current] entry. Draining
+/// this stream will move the tar reader to the beginning of the next file.
 ///
-/// [ChunkedStreamReader.readStream] might return a stream shorter than
-/// expected. That indicates an invalid tar file though, since the correct size
-/// is stored in the header.
-class _OutgoingStreamGuard extends EventSink<Uint8List> {
-  int remainingContentSize;
-  int remainingPaddingSize;
+/// This is not the same as `_current.stream` for sparse files, which are
+/// reported as expanded through [TarEntry.contents].
+/// For that reason, we prefer to drain this stream when skipping a tar entry.
+/// When we know we're skipping data, there's no point expanding sparse holes.
+///
+/// Draining this stream will set the [TarReader._currentStream] field back to
+/// null. There can only be one content stream at the time.
+class _CurrentEntryStream extends Stream<List<int>> {
+  _EntryStreamState state = _EntryStreamState.preListen;
 
-  final EventSink<List<int>> out;
-  void Function() onDone;
+  final TarReader _reader;
+  final Stream<Uint8List> _source;
 
-  bool hadError = false;
-  bool isInContent = true;
+  final StreamController<List<int>> _listener = StreamController(sync: true);
+  // ignore: cancel_subscriptions
+  StreamSubscription<List<int>>? _sourceSubscription;
 
-  _OutgoingStreamGuard(this.remainingContentSize, this.out, this.onDone)
-      : remainingPaddingSize = _paddingFor(remainingContentSize);
+  int _remainingContentSize;
+  int _remainingPaddingSize;
+  bool _hadError = false;
+  bool _isInContent = true;
+
+  _CurrentEntryStream(this._reader, this._source, this._remainingContentSize)
+      : _remainingPaddingSize = _paddingFor(_remainingContentSize);
+
+  @override
+  StreamSubscription<List<int>> listen(void Function(List<int> event)? onData,
+      {Function? onError, void Function()? onDone, bool? cancelOnError}) {
+    // Make sure that this entry is still the current one: If users store the
+    // contents of a tar entry, then read more tar entries, and finally try to
+    // read the stream of the old contents, they'd get an exception about the
+    // stream already being listened to.
+    // This can be a bit confusing, so this check enables a better error UX.
+    if (_reader._currentStream != this) {
+      throw StateError(
+        'Tried listening to an outdated tar entry. \n'
+        'As all tar entries found by a reader are backed by a single source '
+        'stream, only the latest tar entry can be read. It looks like you '
+        'stored the results of `tarEntry.contents` somewhere, called '
+        '`reader.moveNext()` and then read the contents of the previous '
+        'entry.\n'
+        'For more details, including a discussion of workarounds, see '
+        'https://github.com/simolus3/tar/issues/18',
+      );
+    } else if (state != _EntryStreamState.preListen) {
+      throw StateError(
+        'A tar entry has been listened to multiple times. \n'
+        'As all tar entries are read from what\'s likely a single-'
+        'subscription stream, this is unsupported. If you didn\'t read a tar '
+        'entry multiple times yourself, perhaps you\'ve called `moveNext()` '
+        'before reading contents?',
+      );
+    }
+
+    // Now we have a listener, so
+    state = _EntryStreamState.subscriptionActive;
+    // ignore: cancel_subscriptions
+    final sub = _sourceSubscription = _source.listen(
+      _forwardData,
+      onError: _forwardError,
+      onDone: _forwardDone,
+    );
+
+    _listener
+      ..onPause = sub.pause
+      ..onResume = sub.resume
+      ..onCancel = () {
+        // Pause the source subscription. When reading the next entry, the tar
+        // reader will drain the remaining source stream.
+        sub.pause();
+        state = _EntryStreamState.cancelled;
+      };
+
+    return _listener.stream.listen(
+      onData,
+      onError: onError,
+      onDone: onDone,
+      cancelOnError: cancelOnError,
+    );
+  }
 
   static int _paddingFor(int contentSize) {
     final offsetInLastBlock = contentSize.toUnsigned(blockSizeLog2);
@@ -907,47 +954,59 @@
     return 0;
   }
 
-  @override
-  void add(Uint8List event) {
-    if (isInContent) {
-      if (event.length <= remainingContentSize) {
+  void _assertInStateForForwarding() {
+    assert(state == _EntryStreamState.subscriptionActive &&
+        _listener.hasListener &&
+        !_listener.isPaused);
+  }
+
+  void _forwardData(Uint8List event) {
+    _assertInStateForForwarding();
+
+    if (_isInContent) {
+      if (event.length <= _remainingContentSize) {
         // We can fully add this chunk as it consists entirely of data
-        out.add(event);
-        remainingContentSize -= event.length;
+        _listener.add(event);
+        _remainingContentSize -= event.length;
       } else {
         // We can add the first bytes as content, the others are padding that we
         // shouldn't emit
-        out.add(event.sublistView(0, remainingContentSize));
-        isInContent = false;
-        remainingPaddingSize -= event.length - remainingContentSize;
-        remainingContentSize = 0;
+        _listener.add(event.sublistView(0, _remainingContentSize));
+        _isInContent = false;
+        _remainingPaddingSize -= event.length - _remainingContentSize;
+        _remainingContentSize = 0;
       }
     } else {
       // Ok, the entire event is padding
-      remainingPaddingSize -= event.length;
+      _remainingPaddingSize -= event.length;
     }
 
     // The underlying stream comes from pkg:tar, so if we get too many bytes
     // that's a bug in this package.
-    assert(remainingPaddingSize >= 0, 'Stream emitted to many bytes');
+    assert(_remainingPaddingSize >= 0, 'Stream emitted to many bytes');
   }
 
-  @override
-  void addError(Object error, [StackTrace? stackTrace]) {
-    hadError = true;
-    out.addError(error, stackTrace);
+  void _forwardError(Object error, StackTrace trace) {
+    _assertInStateForForwarding();
+
+    _hadError = true;
+    _listener.addError(error, trace);
   }
 
-  @override
-  void close() {
+  void _forwardDone() {
+    _assertInStateForForwarding();
+
+    // Now that the source stream is done, reset the stream state on the reader.
+    state = _EntryStreamState.done;
+    _sourceSubscription = null;
+    _reader._currentStream = null;
+
     // If the stream stopped after an error, the user is already aware that
     // something is wrong.
-    if (remainingContentSize > 0 && !hadError) {
-      out.addError(
+    if (_remainingContentSize > 0 && !_hadError) {
+      _listener.addError(
           TarException('Unexpected end of tar file'), StackTrace.current);
     }
-
-    onDone();
-    out.close();
+    _listener.close();
   }
 }
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index e4451db..dbc7622 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -638,3 +638,63 @@
       key(entry.key, entry.value): value(entry.key, entry.value),
   };
 }
+
+/// Call [fn] retrying so long as [retryIf] return `true` for the exception
+/// thrown, up-to [maxAttempts] times.
+///
+/// Defaults to 8 attempts, sleeping as following after 1st, 2nd, 3rd, ...,
+/// 7th attempt:
+///  1. 400 ms +/- 25%
+///  2. 800 ms +/- 25%
+///  3. 1600 ms +/- 25%
+///  4. 3200 ms +/- 25%
+///  5. 6400 ms +/- 25%
+///  6. 12800 ms +/- 25%
+///  7. 25600 ms +/- 25%
+///
+/// ```dart
+/// final response = await retry(
+///   // Make a GET request
+///   () => http.get('https://google.com').timeout(Duration(seconds: 5)),
+///   // Retry on SocketException or TimeoutException
+///   retryIf: (e) => e is SocketException || e is TimeoutException,
+/// );
+/// print(response.body);
+/// ```
+///
+/// If no [retryIf] function is given this will retry any for any [Exception]
+/// thrown. To retry on an [Error], the error must be caught and _rethrown_
+/// as an [Exception].
+///
+/// See https://github.com/google/dart-neats/blob/master/retry/lib/retry.dart
+Future<T> retry<T>(
+  FutureOr<T> Function() fn, {
+  Duration delayFactor = const Duration(milliseconds: 200),
+  double randomizationFactor = 0.25,
+  Duration maxDelay = const Duration(seconds: 30),
+  int maxAttempts = 8,
+  FutureOr<bool> Function(Exception)? retryIf,
+  FutureOr<void> Function(Exception, int retryCount)? onRetry,
+}) async {
+  var attempt = 0;
+  // ignore: literal_only_boolean_expressions
+  while (true) {
+    attempt++; // first invocation is the first attempt
+    try {
+      return await fn();
+    } on Exception catch (e) {
+      if (attempt >= maxAttempts || (retryIf != null && !(await retryIf(e)))) {
+        rethrow;
+      }
+      if (onRetry != null) {
+        await onRetry(e, attempt);
+      }
+    }
+
+    // Sleep for a delay
+    final rf = randomizationFactor * (random.nextDouble() * 2 - 1) + 1;
+    final exp = math.min(attempt, 31); // prevent overflows.
+    final delay = delayFactor * math.pow(2.0, exp) * rf;
+    await Future.delayed(delay < maxDelay ? delay : maxDelay);
+  }
+}
diff --git a/lib/src/validator/dependency_override.dart b/lib/src/validator/dependency_override.dart
index b6a49a0..a16367a 100644
--- a/lib/src/validator/dependency_override.dart
+++ b/lib/src/validator/dependency_override.dart
@@ -16,10 +16,15 @@
     var overridden = MapKeySet(entrypoint.root.dependencyOverrides);
     var dev = MapKeySet(entrypoint.root.devDependencies);
     if (overridden.difference(dev).isNotEmpty) {
-      errors.add('Your pubspec.yaml must not override non-dev dependencies.\n'
-          'This ensures you test your package against the same versions of '
-          'its dependencies\n'
-          'that users will have when they use it.');
+      warnings.add('''
+Your pubspec.yaml is overriding non-dev dependencies.
+
+This indicates you are not testing your package against the same versions of its
+dependencies that users will have when they use it.
+
+This might be necessary for packages with cyclic dependencies.
+
+Please be extra careful when publising.''');
     }
     return Future.value();
   }
diff --git a/lib/src/validator/null_safety_mixed_mode.dart b/lib/src/validator/null_safety_mixed_mode.dart
index 31b755c..b17e0e5 100644
--- a/lib/src/validator/null_safety_mixed_mode.dart
+++ b/lib/src/validator/null_safety_mixed_mode.dart
@@ -6,6 +6,7 @@
 
 import 'package:path/path.dart' as p;
 
+import '../command_runner.dart';
 import '../null_safety_analysis.dart';
 import '../package_name.dart';
 import '../source/path.dart';
@@ -44,8 +45,8 @@
 We highly recommend that you wait until all of your dependencies have been
 migrated before publishing.
 
-Run `pub outdated --mode=null-safety` for more information about the state of
-dependencies.
+Run `$topLevelProgram pub outdated --mode=null-safety` for more information about the state
+of dependencies.
 
 See ${NullSafetyAnalysis.guideUrl}
 for more information about migrating.
diff --git a/pubspec.yaml b/pubspec.yaml
index e44e0e7..eb2983f 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -6,13 +6,13 @@
 dependencies:
   # Note: Pub's test infrastructure assumes that any dependencies used in tests
   # will be hosted dependencies.
-  analyzer: ^4.0.0
+  analyzer: ^5.1.0
   args: ^2.1.0
   async: ^2.6.1
   cli_util: ^0.3.5
   collection: ^1.15.0
   crypto: ^3.0.1
-  frontend_server_client: ^2.0.0
+  frontend_server_client: ^3.0.0
   http: ^0.13.3
   http_multi_server: ^3.0.1
   http_parser: ^4.0.1
@@ -31,6 +31,6 @@
 dev_dependencies:
   lints: ^2.0.0
   shelf_test_handler: ^2.0.0
-  test: ^1.17.3
+  test: ^1.21.5
   test_descriptor: ^2.0.0
   test_process: ^2.0.0
diff --git a/test/add/common/add_test.dart b/test/add/common/add_test.dart
index f1e76a7..25f9d8d 100644
--- a/test/add/common/add_test.dart
+++ b/test/add/common/add_test.dart
@@ -185,7 +185,7 @@
       await d.appDir({'foo': '1.2.3'}).validate();
     });
 
-    group('warns user to use pub upgrade if package exists', () {
+    group('notifies user about existing constraint', () {
       test('if package is added without a version constraint', () async {
         await servePackages()
           ..serve('foo', '1.2.3')
@@ -194,13 +194,13 @@
         await d.appDir({'foo': '1.2.2'}).create();
 
         await pubAdd(
-            args: ['foo'],
-            exitCode: exit_codes.DATA,
-            error:
-                contains('"foo" is already in "dependencies". Use "pub upgrade '
-                    'foo" to upgrade to a later version!'));
+          args: ['foo'],
+          output: contains(
+            '"foo" is already in "dependencies". Will try to update the constraint.',
+          ),
+        );
 
-        await d.appDir({'foo': '1.2.2'}).validate();
+        await d.appDir({'foo': '^1.2.3'}).validate();
       });
 
       test('if package is added with a specific version constraint', () async {
@@ -211,13 +211,13 @@
         await d.appDir({'foo': '1.2.2'}).create();
 
         await pubAdd(
-            args: ['foo:1.2.3'],
-            exitCode: exit_codes.DATA,
-            error:
-                contains('"foo" is already in "dependencies". Use "pub upgrade '
-                    'foo" to upgrade to a later version!'));
+          args: ['foo:1.2.3'],
+          output: contains(
+            '"foo" is already in "dependencies". Will try to update the constraint.',
+          ),
+        );
 
-        await d.appDir({'foo': '1.2.2'}).validate();
+        await d.appDir({'foo': '1.2.3'}).validate();
       });
 
       test('if package is added with a version constraint range', () async {
@@ -229,12 +229,10 @@
 
         await pubAdd(
             args: ['foo:>=1.2.2'],
-            exitCode: exit_codes.DATA,
-            error:
-                contains('"foo" is already in "dependencies". Use "pub upgrade '
-                    'foo" to upgrade to a later version!'));
+            output: contains(
+                '"foo" is already in "dependencies". Will try to update the constraint.'));
 
-        await d.appDir({'foo': '1.2.2'}).validate();
+        await d.appDir({'foo': '>=1.2.2'}).validate();
       });
     });
 
@@ -517,7 +515,7 @@
       ]).validate();
     });
 
-    group('warns user to use pub upgrade if package exists', () {
+    group('notifies user if package exists', () {
       test('if package is added without a version constraint', () async {
         await servePackages()
           ..serve('foo', '1.2.3')
@@ -532,15 +530,13 @@
 
         await pubAdd(
             args: ['foo', '--dev'],
-            exitCode: exit_codes.DATA,
-            error: contains(
-                '"foo" is already in "dev_dependencies". Use "pub upgrade '
-                'foo" to upgrade to a later version!'));
+            output: contains(
+                '"foo" is already in "dev_dependencies". Will try to update the constraint.'));
 
         await d.dir(appPath, [
           d.pubspec({
             'name': 'myapp',
-            'dev_dependencies': {'foo': '1.2.2'}
+            'dev_dependencies': {'foo': '^1.2.3'}
           })
         ]).validate();
       });
@@ -559,15 +555,13 @@
 
         await pubAdd(
             args: ['foo:1.2.3', '--dev'],
-            exitCode: exit_codes.DATA,
-            error: contains(
-                '"foo" is already in "dev_dependencies". Use "pub upgrade '
-                'foo" to upgrade to a later version!'));
+            output: contains(
+                '"foo" is already in "dev_dependencies". Will try to update the constraint.'));
 
         await d.dir(appPath, [
           d.pubspec({
             'name': 'myapp',
-            'dev_dependencies': {'foo': '1.2.2'}
+            'dev_dependencies': {'foo': '1.2.3'}
           })
         ]).validate();
       });
@@ -586,15 +580,13 @@
 
         await pubAdd(
             args: ['foo:>=1.2.2', '--dev'],
-            exitCode: exit_codes.DATA,
-            error: contains(
-                '"foo" is already in "dev_dependencies". Use "pub upgrade '
-                'foo" to upgrade to a later version!'));
+            output: contains(
+                '"foo" is already in "dev_dependencies". Will try to update the constraint.'));
 
         await d.dir(appPath, [
           d.pubspec({
             'name': 'myapp',
-            'dev_dependencies': {'foo': '1.2.2'}
+            'dev_dependencies': {'foo': '>=1.2.2'}
           })
         ]).validate();
       });
diff --git a/test/ascii_tree_test.dart b/test/ascii_tree_test.dart
index 5d82d49..a4b0163 100644
--- a/test/ascii_tree_test.dart
+++ b/test/ascii_tree_test.dart
@@ -3,240 +3,102 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:pub/src/ascii_tree.dart' as tree;
+import 'package:pub/src/package.dart';
+import 'package:pub/src/utils.dart';
 import 'package:test/test.dart';
 
+import 'descriptor.dart';
+import 'golden_file.dart';
+import 'test_pub.dart';
+
 /// Removes ansi color codes from [s].
 String stripColors(String s) {
   return s.replaceAll(RegExp('\u001b\\[.*?m'), '');
 }
 
 void main() {
-  group('tree.fromFiles', () {
-    test('no files', () {
-      expect(stripColors(tree.fromFiles([])), equals(''));
-    });
-
-    test('up to ten files in one directory are shown', () {
-      var files = [
-        'dir/a.dart',
-        'dir/b.dart',
-        'dir/c.dart',
-        'dir/d.dart',
-        'dir/e.dart',
-        'dir/f.dart',
-        'dir/g.dart',
-        'dir/h.dart',
-        'dir/i.dart',
-        'dir/j.dart'
-      ];
-      expect(stripColors(tree.fromFiles(files)), equals("""
-'-- dir
-    |-- a.dart
-    |-- b.dart
-    |-- c.dart
-    |-- d.dart
-    |-- e.dart
-    |-- f.dart
-    |-- g.dart
-    |-- h.dart
-    |-- i.dart
-    '-- j.dart
-"""));
-    });
-
-    test('files are elided if there are more than ten', () {
-      var files = [
-        'dir/a.dart',
-        'dir/b.dart',
-        'dir/c.dart',
-        'dir/d.dart',
-        'dir/e.dart',
-        'dir/f.dart',
-        'dir/g.dart',
-        'dir/h.dart',
-        'dir/i.dart',
-        'dir/j.dart',
-        'dir/k.dart'
-      ];
-      expect(stripColors(tree.fromFiles(files)), equals("""
-'-- dir
-    |-- a.dart
-    |-- b.dart
-    |-- c.dart
-    | (5 more...)
-    |-- i.dart
-    |-- j.dart
-    '-- k.dart
-"""));
-    });
-
-    test('files are not elided at the top level', () {
-      var files = [
-        'a.dart',
-        'b.dart',
-        'c.dart',
-        'd.dart',
-        'e.dart',
-        'f.dart',
-        'g.dart',
-        'h.dart',
-        'i.dart',
-        'j.dart',
-        'k.dart'
-      ];
-      expect(stripColors(tree.fromFiles(files)), equals("""
-|-- a.dart
-|-- b.dart
-|-- c.dart
-|-- d.dart
-|-- e.dart
-|-- f.dart
-|-- g.dart
-|-- h.dart
-|-- i.dart
-|-- j.dart
-'-- k.dart
-"""));
-    });
-
-    test('a complex example', () {
-      var files = [
-        'TODO',
-        'example/console_example.dart',
-        'example/main.dart',
-        'example/web copy/web_example.dart',
-        'test/absolute_test.dart',
-        'test/basename_test.dart',
-        'test/dirname_test.dart',
-        'test/extension_test.dart',
-        'test/is_absolute_test.dart',
-        'test/is_relative_test.dart',
-        'test/join_test.dart',
-        'test/normalize_test.dart',
-        'test/relative_test.dart',
-        'test/split_test.dart',
-        '.gitignore',
-        'README.md',
-        'lib/path.dart',
-        'pubspec.yaml',
-        'test/all_test.dart',
-        'test/path_posix_test.dart',
-        'test/path_windows_test.dart'
-      ];
-
-      expect(stripColors(tree.fromFiles(files)), equals("""
-|-- .gitignore
-|-- README.md
-|-- TODO
-|-- example
-|   |-- console_example.dart
-|   |-- main.dart
-|   '-- web copy
-|       '-- web_example.dart
-|-- lib
-|   '-- path.dart
-|-- pubspec.yaml
-'-- test
-    |-- absolute_test.dart
-    |-- all_test.dart
-    |-- basename_test.dart
-    | (7 more...)
-    |-- path_windows_test.dart
-    |-- relative_test.dart
-    '-- split_test.dart
-"""));
-    });
+  setUp(() {
+    forceColors = ForceColorOption.always;
   });
 
-  group('treeFromMap', () {
-    test('empty map', () {
-      expect(stripColors(tree.fromMap({})), equals(''));
-    });
-
-    test('a complex example', () {
-      var map = {
-        '.gitignore': <String, Map>{},
-        'README.md': <String, Map>{},
-        'TODO': <String, Map>{},
-        'example': {
-          'console_example.dart': <String, Map>{},
-          'main.dart': <String, Map>{},
-          'web copy': {'web_example.dart': <String, Map>{}},
-        },
-        'lib': {'path.dart': <String, Map>{}},
-        'pubspec.yaml': <String, Map>{},
-        'test': {
-          'absolute_test.dart': <String, Map>{},
-          'basename_test.dart': <String, Map>{},
-          'dirname_test.dart': <String, Map>{},
-          'extension_test.dart': <String, Map>{},
-          'is_absolute_test.dart': <String, Map>{},
-          'is_relative_test.dart': <String, Map>{},
-          'join_test.dart': <String, Map>{},
-          'normalize_test.dart': <String, Map>{},
-          'relative_test.dart': <String, Map>{},
-          'split_test.dart': <String, Map>{}
-        }
-      };
-
-      expect(stripColors(tree.fromMap(map)), equals("""
-|-- .gitignore
-|-- README.md
-|-- TODO
-|-- example
-|   |-- console_example.dart
-|   |-- main.dart
-|   '-- web copy
-|       '-- web_example.dart
-|-- lib
-|   '-- path.dart
-|-- pubspec.yaml
-'-- test
-    |-- absolute_test.dart
-    |-- basename_test.dart
-    |-- dirname_test.dart
-    |-- extension_test.dart
-    |-- is_absolute_test.dart
-    |-- is_relative_test.dart
-    |-- join_test.dart
-    |-- normalize_test.dart
-    |-- relative_test.dart
-    '-- split_test.dart
-"""));
-    });
+  tearDown(() {
+    forceColors = ForceColorOption.auto;
+  });
+  test('tree.fromFiles no files', () {
+    expect(tree.fromFiles([], showFileSizes: true), equals(''));
   });
 
-  test('does not elide children if showAllChildren is true', () {
+  List<int> bytes(int size) => List.filled(size, 0);
+  testWithGolden('tree.fromFiles a complex example', colors: true, (ctx) async {
+    await dir(appPath, [
+      libPubspec('app', '1.0.0'),
+      file('TODO', bytes(10)),
+      dir('example', [
+        file('console_example.dart', bytes(1000)),
+        file('main.dart', bytes(1024)),
+        dir('web copy', [
+          file('web_example.dart', bytes(1025)),
+        ]),
+      ]),
+      dir('test', [
+        file('absolute_test.dart', bytes(0)),
+        file('basename_test.dart', bytes(1 << 20)),
+        file('dirname_test.dart', bytes((1 << 20) + 1)),
+        file('extension_test.dart', bytes(2300)),
+        file('is_absolute_test.dart', bytes(2400)),
+        file('is_relative_test.dart', bytes((1 << 20) * 25)),
+        file('join_test.dart', bytes(1023)),
+        file('normalize_test.dart', bytes((1 << 20) - 1)),
+        file('relative_test.dart', bytes(100)),
+        file('split_test.dart', bytes(1)),
+        file('all_test.dart', bytes(100)),
+        file('path_posix_test.dart', bytes(100)),
+        file('path_windows_test.dart', bytes(100)),
+      ]),
+      file('.gitignore', bytes(100)),
+      file('README.md', bytes(100)),
+      dir('lib', [
+        file('path.dart', bytes(100)),
+      ]),
+    ]).create();
+    var files = Package.load(
+      null,
+      path(appPath),
+      (name) => throw UnimplementedError(),
+    ).listFiles();
+    ctx.expectNextSection(
+        tree.fromFiles(files, baseDir: path(appPath), showFileSizes: true));
+  });
+  test('tree.fromMap empty map', () {
+    expect(tree.fromMap({}), equals(''));
+  });
+
+  testWithGolden('tree.fromMap a complex example', colors: true, (ctx) {
     var map = {
-      'dir': {
-        'a.dart': <String, Map>{},
-        'b.dart': <String, Map>{},
-        'c.dart': <String, Map>{},
-        'd.dart': <String, Map>{},
-        'e.dart': <String, Map>{},
-        'f.dart': <String, Map>{},
-        'g.dart': <String, Map>{},
-        'h.dart': <String, Map>{},
-        'i.dart': <String, Map>{},
-        'j.dart': <String, Map>{},
-        'k.dart': <String, Map>{},
-        'l.dart': <String, Map>{},
+      '.gitignore': <String, Map>{},
+      'README.md': <String, Map>{},
+      'TODO': <String, Map>{},
+      'example': {
+        'console_example.dart': <String, Map>{},
+        'main.dart': <String, Map>{},
+        'web copy': {'web_example.dart': <String, Map>{}},
+      },
+      'lib': {'path.dart': <String, Map>{}},
+      'pubspec.yaml': <String, Map>{},
+      'test': {
+        'absolute_test.dart': <String, Map>{},
+        'basename_test.dart': <String, Map>{},
+        'dirname_test.dart': <String, Map>{},
+        'extension_test.dart': <String, Map>{},
+        'is_absolute_test.dart': <String, Map>{},
+        'is_relative_test.dart': <String, Map>{},
+        'join_test.dart': <String, Map>{},
+        'normalize_test.dart': <String, Map>{},
+        'relative_test.dart': <String, Map>{},
+        'split_test.dart': <String, Map>{}
       }
     };
-    expect(stripColors(tree.fromMap(map, showAllChildren: true)), equals("""
-'-- dir
-    |-- a.dart
-    |-- b.dart
-    |-- c.dart
-    |-- d.dart
-    |-- e.dart
-    |-- f.dart
-    |-- g.dart
-    |-- h.dart
-    |-- i.dart
-    |-- j.dart
-    |-- k.dart
-    '-- l.dart
-"""));
+
+    ctx.expectNextSection(tree.fromMap(map));
   });
 }
diff --git a/test/deps_test.dart b/test/deps_test.dart
index 7336f13..b4ded45 100644
--- a/test/deps_test.dart
+++ b/test/deps_test.dart
@@ -112,20 +112,20 @@
       await runPub(args: ['deps'], output: '''
           Dart SDK 0.1.2+3
           myapp 0.0.0
-          |-- from_path 1.2.3
-          |-- normal 1.2.3
-          |   |-- circular_a 1.2.3
-          |   |   '-- circular_b 1.2.3
-          |   |       '-- circular_a...
-          |   '-- transitive 1.2.3
-          |       '-- shared...
-          |-- overridden 2.0.0
-          |-- override_only 1.2.3
-          '-- unittest 1.2.3
-              |-- dev_only 1.2.3
-              '-- shared 1.2.3
-                  '-- other 1.0.0
-                      '-- myapp...
+          ├── from_path 1.2.3
+          ├── normal 1.2.3
+          │   ├── circular_a 1.2.3
+          │   │   └── circular_b 1.2.3
+          │   │       └── circular_a...
+          │   └── transitive 1.2.3
+          │       └── shared...
+          ├── overridden 2.0.0
+          ├── override_only 1.2.3
+          └── unittest 1.2.3
+              ├── dev_only 1.2.3
+              └── shared 1.2.3
+                  └── other 1.0.0
+                      └── myapp...
           ''');
     });
     test('in json form', () async {
@@ -333,17 +333,17 @@
       await runPub(args: ['deps', '--no-dev'], output: '''
           Dart SDK 0.1.2+3
           myapp 0.0.0
-          |-- from_path 1.2.3
-          |-- normal 1.2.3
-          |   |-- circular_a 1.2.3
-          |   |   '-- circular_b 1.2.3
-          |   |       '-- circular_a...
-          |   '-- transitive 1.2.3
-          |       '-- shared 1.2.3
-          |           '-- other 1.0.0
-          |               '-- myapp...
-          |-- overridden 2.0.0
-          '-- override_only 1.2.3
+          ├── from_path 1.2.3
+          ├── normal 1.2.3
+          │   ├── circular_a 1.2.3
+          │   │   └── circular_b 1.2.3
+          │   │       └── circular_a...
+          │   └── transitive 1.2.3
+          │       └── shared 1.2.3
+          │           └── other 1.0.0
+          │               └── myapp...
+          ├── overridden 2.0.0
+          └── override_only 1.2.3
           ''');
     });
   });
diff --git a/test/descriptor.dart b/test/descriptor.dart
index 9248ad4..669d8ef 100644
--- a/test/descriptor.dart
+++ b/test/descriptor.dart
@@ -33,7 +33,7 @@
 
 /// Describes a package that passes all validation.
 DirectoryDescriptor get validPackage => dir(appPath, [
-      libPubspec('test_pkg', '1.0.0', sdk: '>=1.8.0 <=2.0.0'),
+      libPubspec('test_pkg', '1.0.0', sdk: '>=0.1.2 <=0.2.0'),
       file('LICENSE', 'Eh, do what you want.'),
       file('README.md', "This package isn't real."),
       file('CHANGELOG.md', '# 1.0.0\nFirst version\n'),
@@ -188,11 +188,12 @@
 /// If [port] is passed, it's used as the port number of the local hosted server
 /// 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)])
-  ]);
+  return dir(hostedCachePath(port: port), contents);
 }
 
+String hostedCachePath({int? port}) =>
+    p.join(cachePath, 'hosted', 'localhost%58${port ?? globalServer.port}');
+
 /// Describes the file that contains the client's OAuth2
 /// credentials. The URL "/token" on [server] will be used as the token
 /// endpoint for refreshing the access token.
diff --git a/test/directory_option_test.dart b/test/directory_option_test.dart
index 65193bf..5a483d9 100644
--- a/test/directory_option_test.dart
+++ b/test/directory_option_test.dart
@@ -34,13 +34,13 @@
     await dir(appPath, [
       dir('bin', [
         file('app.dart', '''
-main() => print('Hi');    
+main() => print('Hi');
 ''')
       ]),
       dir('example', [
         pubspec({
           'name': 'example',
-          'environment': {'sdk': '>=1.2.0 <2.0.0'},
+          'environment': {'sdk': '>=0.1.2 <0.2.0'},
           'dependencies': {
             'test_pkg': {'path': '../'}
           }
@@ -49,7 +49,7 @@
       dir('example2', [
         pubspec({
           'name': 'example',
-          'environment': {'sdk': '>=1.2.0 <2.0.0'},
+          'environment': {'sdk': '>=0.1.2 <0.2.0'},
           'dependencies': {
             'myapp': {'path': '../'} // Wrong name of dependency
           }
@@ -82,7 +82,6 @@
       await ctx.run(
         cases[i],
         workingDirectory: sandbox,
-        environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'},
       );
     }
   });
diff --git a/test/embedding/embedding_test.dart b/test/embedding/embedding_test.dart
index 73370d7..9f74405 100644
--- a/test/embedding/embedding_test.dart
+++ b/test/embedding/embedding_test.dart
@@ -357,6 +357,18 @@
         RegExp(r'Writing \d+ characters', multiLine: true),
         r'Writing $N characters',
       )
+      .replaceAll(
+        RegExp(r'x-goog-hash(.*)$', multiLine: true),
+        r'x-goog-hash: $CHECKSUM_HEADER',
+      )
+      .replaceAll(
+        RegExp(
+            r'Computed checksum \d+ for foo 1.0.0 with expected CRC32C of '
+            r'\d+\.',
+            multiLine: true),
+        r'Computed checksum $CRC32C for foo 1.0.0 with expected CRC32C of '
+        r'$CRC32C.',
+      )
 
       /// TODO(sigurdm): This hack suppresses differences in stack-traces
       /// between dart 2.17 and 2.18. Remove when 2.18 is stable.
diff --git a/test/get/get_inside_cache_fails_test.dart b/test/get/get_inside_cache_fails_test.dart
new file mode 100644
index 0000000..a7a6b45
--- /dev/null
+++ b/test/get/get_inside_cache_fails_test.dart
@@ -0,0 +1,27 @@
+// 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:path/path.dart' as p;
+import 'package:test/test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+void main() {
+  test('`pub get` inside the cache fails gracefully', () async {
+    final server = await servePackages();
+    server.serve('foo', '1.0.0', pubspec: {
+      'name': 'foo',
+      'version': '1.0.0',
+      'environment': {'sdk': '>=0.1.2+3 <0.2.0'}
+    });
+    await d.appDir({'foo': 'any'}).create();
+
+    await pubGet();
+
+    await pubGet(
+        workingDirectory: p.join(d.sandbox, d.hostedCachePath(), 'foo-1.0.0'),
+        error: 'Cannot operate on packages inside the cache.');
+  });
+}
diff --git a/test/get/hosted/get_test.dart b/test/get/hosted/get_test.dart
index f0270a3..81d4845 100644
--- a/test/get/hosted/get_test.dart
+++ b/test/get/hosted/get_test.dart
@@ -12,10 +12,13 @@
 import '../../test_pub.dart';
 
 void main() {
-  test('gets a package from a pub server', () async {
+  test('gets a package from a pub server and validates its CRC32C checksum',
+      () async {
     final server = await servePackages();
     server.serve('foo', '1.2.3');
 
+    expect(await server.peekArchiveChecksumHeader('foo', '1.2.3'), isNotNull);
+
     await d.appDir({'foo': '1.2.3'}).create();
 
     await pubGet();
@@ -26,6 +29,62 @@
     ]).validate();
   });
 
+  group('gets a package from a pub server without validating its checksum', () {
+    late PackageServer server;
+
+    setUp(() async {
+      server = await servePackages()
+        ..serveChecksums = false
+        ..serve('foo', '1.2.3')
+        ..serve('bar', '1.2.3', headers: {
+          'x-goog-hash': ['']
+        })
+        ..serve('baz', '1.2.3', headers: {
+          'x-goog-hash': ['md5=loremipsum']
+        });
+    });
+
+    test('because of omitted checksum header', () async {
+      expect(await server.peekArchiveChecksumHeader('foo', '1.2.3'), isNull);
+
+      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();
+    });
+
+    test('because of empty checksum header', () async {
+      expect(await server.peekArchiveChecksumHeader('bar', '1.2.3'), '');
+
+      await d.appDir({'bar': '1.2.3'}).create();
+
+      await pubGet();
+
+      await d.cacheDir({'bar': '1.2.3'}).validate();
+      await d.appPackageConfigFile([
+        d.packageConfigEntry(name: 'bar', version: '1.2.3'),
+      ]).validate();
+    });
+
+    test('because of missing CRC32C in checksum header', () async {
+      expect(await server.peekArchiveChecksumHeader('baz', '1.2.3'),
+          'md5=loremipsum');
+
+      await d.appDir({'baz': '1.2.3'}).create();
+
+      await pubGet();
+
+      await d.cacheDir({'baz': '1.2.3'}).validate();
+      await d.appPackageConfigFile([
+        d.packageConfigEntry(name: 'baz', version: '1.2.3'),
+      ]).validate();
+    });
+  });
+
   test('URL encodes the package name', () async {
     await servePackages();
 
@@ -64,6 +123,148 @@
     ]).validate();
   });
 
+  test('recognizes and retries a package with a CRC32C checksum mismatch',
+      () async {
+    var server = await startPackageServer();
+
+    server.serve('foo', '1.2.3', headers: {
+      'x-goog-hash': PackageServer.composeChecksumHeader(crc32c: 3381945770)
+    });
+
+    await d.appDir({
+      'foo': {
+        'version': '1.2.3',
+        'hosted': {'name': 'foo', 'url': 'http://localhost:${server.port}'}
+      }
+    }).create();
+
+    await pubGet(
+      error: RegExp(
+          r'''Package archive for foo 1.2.3 downloaded from "(.+)" has '''
+          r'''"x-goog-hash: crc32c=(\d+)", which doesn't match the checksum '''
+          r'''of the archive downloaded\.'''),
+      silent: contains('Retry #2 because of checksum error'),
+      environment: {
+        'PUB_MAX_HTTP_RETRIES': '2',
+      },
+    );
+  });
+
+  group('recognizes bad checksum header and retries', () {
+    late PackageServer server;
+
+    setUp(() async {
+      server = await servePackages()
+        ..serve('foo', '1.2.3', headers: {
+          'x-goog-hash': ['crc32c=,md5=']
+        })
+        ..serve('bar', '1.2.3', headers: {
+          'x-goog-hash': ['crc32c=loremipsum,md5=loremipsum']
+        })
+        ..serve('baz', '1.2.3', headers: {
+          'x-goog-hash': ['crc32c=MTIzNDU=,md5=NTQzMjE=']
+        });
+    });
+
+    test('when the CRC32C checksum is empty', () async {
+      await d.appDir({
+        'foo': {
+          'version': '1.2.3',
+          'hosted': {'name': 'foo', 'url': 'http://localhost:${server.port}'}
+        }
+      }).create();
+
+      await pubGet(
+        exitCode: exit_codes.DATA,
+        error: contains(
+            'Package archive "foo-1.2.3.tar.gz" has a malformed CRC32C '
+            'checksum in its response headers'),
+        silent: contains('Retry #2 because of checksum error'),
+        environment: {
+          'PUB_MAX_HTTP_RETRIES': '2',
+        },
+      );
+    });
+
+    test('when the CRC32C checksum has bad encoding', () async {
+      await d.appDir({
+        'bar': {
+          'version': '1.2.3',
+          'hosted': {'name': 'bar', 'url': 'http://localhost:${server.port}'}
+        }
+      }).create();
+
+      await pubGet(
+        exitCode: exit_codes.DATA,
+        error: contains(
+            'Package archive "bar-1.2.3.tar.gz" has a malformed CRC32C '
+            'checksum in its response headers'),
+        silent: contains('Retry #2 because of checksum error'),
+        environment: {
+          'PUB_MAX_HTTP_RETRIES': '2',
+        },
+      );
+    });
+
+    test('when the CRC32C checksum is malformed', () async {
+      await d.appDir({
+        'baz': {
+          'version': '1.2.3',
+          'hosted': {'name': 'baz', 'url': 'http://localhost:${server.port}'}
+        }
+      }).create();
+
+      await pubGet(
+        exitCode: exit_codes.DATA,
+        error: contains(
+            'Package archive "baz-1.2.3.tar.gz" has a malformed CRC32C '
+            'checksum in its response headers'),
+        silent: contains('Retry #2 because of checksum error'),
+        environment: {
+          'PUB_MAX_HTTP_RETRIES': '2',
+        },
+      );
+    });
+  });
+
+  test('gets a package from a pub server that uses gzip response compression',
+      () async {
+    final server = await servePackages();
+    server.autoCompress = true;
+    server.serveChecksums = false;
+    server.serve('foo', '1.2.3');
+
+    expect(await server.peekArchiveChecksumHeader('foo', '1.2.3'), isNull);
+
+    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();
+  });
+
+  test(
+      'gets a package from a pub server that uses gzip response compression '
+      'and validates its CRC32C checksum', () async {
+    final server = await servePackages();
+    server.autoCompress = true;
+    server.serve('foo', '1.2.3');
+
+    expect(await server.peekArchiveChecksumHeader('foo', '1.2.3'), isNotNull);
+
+    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();
+  });
+
   group('categorizes dependency types in the lockfile', () {
     setUp(() async {
       await servePackages()
diff --git a/test/global/activate/custom_hosted_url_test.dart b/test/global/activate/custom_hosted_url_test.dart
index 8b2f0fc..1c0bc04 100644
--- a/test/global/activate/custom_hosted_url_test.dart
+++ b/test/global/activate/custom_hosted_url_test.dart
@@ -8,7 +8,7 @@
 
 void main() {
   test('activating a package from a custom pub server', () async {
-    // The default pub server (i.e. pub.dartlang.org).
+    // The default pub server (i.e. pub.dev).
     final server = await servePackages();
     server.serve('baz', '1.0.0');
 
diff --git a/test/global/run/runs_script_without_packages_file_test.dart b/test/global/run/runs_script_without_packages_file_test.dart
deleted file mode 100644
index dc225ba..0000000
--- a/test/global/run/runs_script_without_packages_file_test.dart
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2015, 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:path/path.dart' as p;
-import 'package:pub/src/io.dart';
-import 'package:test/test.dart';
-
-import '../../descriptor.dart' as d;
-import '../../test_pub.dart';
-
-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 runPub(args: ['global', 'activate', 'foo']);
-
-    // Mimic the global packages installed by pub <1.12, which didn't create a
-    // .packages file for global installs.
-    deleteEntry(p.join(d.sandbox, cachePath,
-        'global_packages/foo/.dart_tool/package_config.json'));
-
-    var pub = await pubRun(global: true, args: ['foo:script']);
-    expect(pub.stdout, emitsThrough('ok'));
-    await pub.shouldExit();
-  });
-
-  test(
-      'runs an unsnapshotted script without a .dart_tool/package_config.json file',
-      () async {
-    await d.dir('foo', [
-      d.libPubspec('foo', '1.0.0'),
-      d.dir('bin', [d.file('foo.dart', "main() => print('ok');")])
-    ]).create();
-
-    await runPub(args: ['global', 'activate', '--source', 'path', '../foo']);
-
-    deleteEntry(p.join(d.sandbox, cachePath,
-        'global_packages/foo/.dart_tool/package_config.json'));
-
-    var pub = await pubRun(global: true, args: ['foo']);
-    expect(pub.stdout, emitsThrough('ok'));
-    await pub.shouldExit();
-  });
-}
diff --git a/test/golden_file.dart b/test/golden_file.dart
index 9db8ad0..3dcbfb6 100644
--- a/test/golden_file.dart
+++ b/test/golden_file.dart
@@ -46,10 +46,15 @@
   late String _header;
   final _results = <String>[];
   late bool _shouldRegenerateGolden;
+  final bool colors;
   bool _generatedNewData = false; // track if new data is generated
   int _nextSectionIndex = 0;
 
-  GoldenTestContext._(this._currentTestFile, this._testName) {
+  GoldenTestContext._(
+    this._currentTestFile,
+    this._testName, {
+    required this.colors,
+  }) {
     final rel = p.relative(
       _currentTestFile.replaceAll(RegExp(r'\.dart$'), ''),
       from: p.join(p.current, 'test'),
@@ -59,8 +64,8 @@
       'testdata',
       'goldens',
       rel,
-      // Sanitize the name, and add .txt
-      '${_testName.replaceAll(RegExp(r'[<>:"/\|?*%#]'), '~')}.txt',
+      // Sanitize the name, and add .ans or .txt.
+      '${_testName.replaceAll(RegExp(r'[<>:"/\|?*%#]'), '~')}.${colors ? 'ans' : 'txt'}',
     );
     _goldenFile = File(_goldenFilePath);
     _header = '# GENERATED BY: ${p.relative(_currentTestFile)}\n\n';
@@ -184,10 +189,12 @@
       s.writeln('\$ cd $directory');
     }
     s.writeln('\$ tree');
-    s.writeln(stripColors(ascii_tree.fromFiles(
+    final tree = ascii_tree.fromFiles(
       listDir(target, recursive: true),
       baseDir: target,
-    )));
+      showFileSizes: false,
+    );
+    s.writeln(colors ? tree : stripColors(tree));
 
     _expectSection(sectionIndex, s.toString());
   }
@@ -203,11 +210,20 @@
 ///   `test/testdata/goldens/path/to/myfile_test/<name>.txt`
 /// , when `path/to/myfile_test.dart` is the `_test.dart` file from which this
 /// function is called.
+///
+/// If [colors] is `true` the file will be created with an `.ans` extension that
+/// indicates ANSI colors will be used.
+///
+/// Such a file can eg. be viewed in vscode with this plugin:
+/// https://marketplace.visualstudio.com/items?itemName=iliazeus.vscode-ansi
 void testWithGolden(
-  String name,
-  FutureOr<void> Function(GoldenTestContext ctx) fn,
-) {
-  final ctx = GoldenTestContext._(_findCurrentTestFilename(), name);
+    String name, FutureOr<void> Function(GoldenTestContext ctx) fn,
+    {bool colors = false}) {
+  final ctx = GoldenTestContext._(
+    _findCurrentTestFilename(),
+    name,
+    colors: colors,
+  );
   test(name, () async {
     ctx._readGoldenFile();
     await fn(ctx);
diff --git a/test/lish/archives_and_uploads_a_package_test.dart b/test/lish/archives_and_uploads_a_package_test.dart
index 41db57c..da7fdf7 100644
--- a/test/lish/archives_and_uploads_a_package_test.dart
+++ b/test/lish/archives_and_uploads_a_package_test.dart
@@ -15,10 +15,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('archives and uploads a package', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
@@ -39,6 +38,7 @@
 
   test('archives and uploads a package using token', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.tokensFile({
       'version': 1,
       'hosted': [
@@ -64,6 +64,7 @@
 
   test('publishes to hosted-url with path', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.tokensFile({
       'version': 1,
       'hosted': [
@@ -98,7 +99,7 @@
   test('with an empty Git submodule', () async {
     await d.git('empty').create();
 
-    var repo = d.git(appPath);
+    var repo = d.git(appPath, d.validPackage.contents);
     await repo.create();
 
     await repo.runGit(['submodule', 'add', '../empty', 'empty']);
diff --git a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
index 0f792d5..19b8761 100644
--- a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
+++ b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
@@ -10,10 +10,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test("cloud storage upload doesn't redirect", () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
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..85e55af 100644
--- a/test/lish/cloud_storage_upload_provides_an_error_test.dart
+++ b/test/lish/cloud_storage_upload_provides_an_error_test.dart
@@ -10,10 +10,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('cloud storage upload provides an error', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
diff --git a/test/lish/dot_folder_name_test.dart b/test/lish/dot_folder_name_test.dart
index 9f64839..d709f77 100644
--- a/test/lish/dot_folder_name_test.dart
+++ b/test/lish/dot_folder_name_test.dart
@@ -16,12 +16,11 @@
       d.dir('.vscode', [d.file('a')]),
       d.file('.pubignore', '!.vscode/')
     ]).create();
-
     await runPub(
       args: ['lish', '--dry-run'],
       output: contains('''
-|-- .vscode
-|   '-- a'''),
+├── .vscode
+│   └── a'''),
       exitCode: exit_codes.SUCCESS,
     );
   });
diff --git a/test/lish/preview_errors_if_private_test.dart b/test/lish/dry_run_errors_if_private_test.dart
similarity index 91%
rename from test/lish/preview_errors_if_private_test.dart
rename to test/lish/dry_run_errors_if_private_test.dart
index fb7160a..10dd739 100644
--- a/test/lish/preview_errors_if_private_test.dart
+++ b/test/lish/dry_run_errors_if_private_test.dart
@@ -10,7 +10,7 @@
 import '../test_pub.dart';
 
 void main() {
-  test('preview shows an error if the package is private', () async {
+  test('dry-run shows an error if the package is private', () async {
     var pkg = packageMap('test_pkg', '1.0.0');
     pkg['publish_to'] = 'none';
     await d.dir(appPath, [d.pubspec(pkg)]).create();
diff --git a/test/lish/dry_run_package_validation_has_a_warning_test.dart b/test/lish/dry_run_package_validation_has_a_warning_test.dart
new file mode 100644
index 0000000..1edd48d
--- /dev/null
+++ b/test/lish/dry_run_package_validation_has_a_warning_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2013, 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('dry-run package validation gives a warning', () async {
+    (await servePackages()).serve('foo', '1.0.0');
+    await d.validPackage.create();
+
+    var pkg =
+        packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=0.1.2 <0.2.0'});
+    pkg['dependencies'] = {'foo': 'any'};
+    await d.dir(appPath, [d.pubspec(pkg)]).create();
+
+    var pub = await startPublish(globalServer, args: ['--dry-run']);
+
+    await pub.shouldExit(exit_codes.DATA);
+    expect(
+      pub.stderr,
+      emitsThrough('Package has 1 warning.'),
+    );
+  });
+}
diff --git a/test/lish/preview_package_validation_has_no_warnings_test.dart b/test/lish/dry_run_package_validation_has_no_warnings_test.dart
similarity index 71%
rename from test/lish/preview_package_validation_has_no_warnings_test.dart
rename to test/lish/dry_run_package_validation_has_no_warnings_test.dart
index 179c648..13ed386 100644
--- a/test/lish/preview_package_validation_has_no_warnings_test.dart
+++ b/test/lish/dry_run_package_validation_has_no_warnings_test.dart
@@ -10,12 +10,9 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
-  test('preview package validation has no warnings', () async {
-    var pkg =
-        packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=1.8.0 <2.0.0'});
-    await d.dir(appPath, [d.pubspec(pkg)]).create();
+  test('--dry-run package validation on valid package has no warnings',
+      () async {
+    await d.validPackage.create();
 
     await servePackages();
     var pub = await startPublish(globalServer, args: ['--dry-run']);
diff --git a/test/lish/force_cannot_be_combined_with_dry_run_test.dart b/test/lish/force_cannot_be_combined_with_dry_run_test.dart
index 9d2233c..b82e7ce 100644
--- a/test/lish/force_cannot_be_combined_with_dry_run_test.dart
+++ b/test/lish/force_cannot_be_combined_with_dry_run_test.dart
@@ -9,9 +9,9 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('--force cannot be combined with --dry-run', () async {
+    await d.validPackage.create();
+
     await runPub(
       args: ['lish', '--force', '--dry-run'],
       error: contains('Cannot use both --force and --dry-run.'),
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..69c770a 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
@@ -2,6 +2,9 @@
 // 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';
 
@@ -9,24 +12,20 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('--force does not publish if there are errors', () async {
-    await d.dir(appPath, [
-      d.rawPubspec({
-        'name': 'test_pkg',
-        'homepage': 'http://pub.dartlang.org',
-        'version': '1.0.0',
-      }),
-    ]).create();
+    await servePackages();
+    await d.validPackage.create();
+    // It is an error to publish without a LICENSE file.
+    File(d.path(p.join(appPath, 'LICENSE'))).deleteSync();
 
     await servePackages();
     var pub = await startPublish(globalServer, args: ['--force']);
 
     await pub.shouldExit(exit_codes.DATA);
     expect(
-        pub.stderr,
-        emitsThrough('Sorry, your package is missing some '
-            "requirements and can't be published yet."));
+      pub.stderr,
+      emitsThrough(
+          "Sorry, your package is missing a requirement and can't be published yet."),
+    );
   });
 }
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..5b25f48 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
@@ -13,10 +13,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('--force publishes if there are no warnings or errors', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer, args: ['--force']);
 
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..41a115c 100644
--- a/test/lish/force_publishes_if_there_are_warnings_test.dart
+++ b/test/lish/force_publishes_if_there_are_warnings_test.dart
@@ -13,15 +13,15 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('--force publishes if there are warnings', () async {
+    await d.validPackage.create();
     var pkg =
-        packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=1.8.0 <2.0.0'});
+        packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=0.1.2 <0.2.0'});
     pkg['dependencies'] = {'foo': 'any'};
     await d.dir(appPath, [d.pubspec(pkg)]).create();
 
-    await servePackages();
+    (await servePackages()).serve('foo', '1.0.0');
+
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer, args: ['--force']);
 
@@ -35,15 +35,14 @@
     });
 
     await pub.shouldExit(exit_codes.SUCCESS);
+    final stderrLines = await pub.stderr.rest.toList();
     expect(
-      pub.stderr,
-      emitsThrough('Package validation found the following potential issue:'),
-    );
-    expect(
-        pub.stderr,
-        emitsLines(
-            '* Your dependency on "foo" should have a version constraint.\n'
-            '  Without a constraint, you\'re promising to support all future versions of "foo".'));
+        stderrLines,
+        allOf([
+          contains('Package validation found the following potential issue:'),
+          contains(
+              '* Your dependency on "foo" should have a version constraint. For example:'),
+        ]));
     expect(pub.stdout, emitsThrough('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..cb18e56 100644
--- a/test/lish/package_creation_provides_a_malformed_error_test.dart
+++ b/test/lish/package_creation_provides_a_malformed_error_test.dart
@@ -12,10 +12,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('package creation provides a malformed error', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
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..b65317c 100644
--- a/test/lish/package_creation_provides_a_malformed_success_test.dart
+++ b/test/lish/package_creation_provides_a_malformed_success_test.dart
@@ -12,10 +12,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('package creation provides a malformed success', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
diff --git a/test/lish/package_creation_provides_an_error_test.dart b/test/lish/package_creation_provides_an_error_test.dart
index f5ff128..a4fde1b 100644
--- a/test/lish/package_creation_provides_an_error_test.dart
+++ b/test/lish/package_creation_provides_an_error_test.dart
@@ -12,10 +12,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('package creation provides an error', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
diff --git a/test/lish/package_creation_provides_invalid_json_test.dart b/test/lish/package_creation_provides_invalid_json_test.dart
index 2cd6212..7181d8e 100644
--- a/test/lish/package_creation_provides_invalid_json_test.dart
+++ b/test/lish/package_creation_provides_invalid_json_test.dart
@@ -10,10 +10,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('package creation provides invalid JSON', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
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..92c74de 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
@@ -3,7 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:convert';
+import 'dart:io';
 
+import 'package:path/path.dart' as p;
 import 'package:pub/src/exit_codes.dart' as exit_codes;
 import 'package:shelf/shelf.dart' as shelf;
 import 'package:test/test.dart';
@@ -13,17 +15,16 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('package validation has a warning and continues', () async {
-    var pkg =
-        packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=1.8.0 <2.0.0'});
-    pkg['author'] = 'Natalie Weizenbaum';
-    await d.dir(appPath, [d.pubspec(pkg)]).create();
+    await servePackages();
+    await d.validPackage.create();
+    // Publishing without a README.md gives a warning.
+    File(d.path(p.join(appPath, 'README.md'))).deleteSync();
 
     await servePackages();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
+    expect(pub.stdout, emitsThrough(startsWith('Package has 1 warning.')));
     pub.stdin.writeln('y');
     handleUploadForm(globalServer);
     handleUpload(globalServer);
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..b552a25 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
@@ -9,13 +9,14 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('package validation has a warning and is canceled', () async {
+    await d.validPackage.create();
     var pkg =
-        packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=1.8.0 <2.0.0'});
+        packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=0.1.2 <0.2.0'});
     pkg['author'] = 'Natalie Weizenbaum';
-    await d.dir(appPath, [d.pubspec(pkg)]).create();
+    await d.dir(appPath, [
+      d.pubspec(pkg),
+    ]).create();
 
     await servePackages();
     var pub = await startPublish(globalServer);
diff --git a/test/lish/package_validation_has_an_error_test.dart b/test/lish/package_validation_has_an_error_test.dart
index 14c83c0..aa0e6f6 100644
--- a/test/lish/package_validation_has_an_error_test.dart
+++ b/test/lish/package_validation_has_an_error_test.dart
@@ -9,14 +9,13 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('package validation has an error', () async {
     await d.dir(appPath, [
       d.rawPubspec({
         'name': 'test_pkg',
-        'homepage': 'http://pub.dartlang.org',
+        'homepage': 'https://pub.dev',
         'version': '1.0.0',
+        'environment': {'sdk': '>=0.1.2 <0.2.0'}
       }),
     ]).create();
 
diff --git a/test/lish/preview_package_validation_has_a_warning_test.dart b/test/lish/preview_package_validation_has_a_warning_test.dart
deleted file mode 100644
index 69f59af..0000000
--- a/test/lish/preview_package_validation_has_a_warning_test.dart
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2013, 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() {
-  setUp(d.validPackage.create);
-
-  test('preview package validation has a warning', () async {
-    var pkg =
-        packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=1.8.0 <2.0.0'});
-    pkg['dependencies'] = {'foo': 'any'};
-    await d.dir(appPath, [d.pubspec(pkg)]).create();
-
-    await servePackages();
-    var pub = await startPublish(globalServer, args: ['--dry-run']);
-
-    await pub.shouldExit(exit_codes.DATA);
-    expect(
-      pub.stderr,
-      emitsThrough('Package validation found the following potential issue:'),
-    );
-    expect(
-        pub.stderr,
-        emitsLines(
-            '* Your dependency on "foo" should have a version constraint.\n'
-            '  Without a constraint, you\'re promising to support all future versions of "foo".\n'
-            '\n'
-            'Package has 1 warning.'));
-  });
-}
diff --git a/test/lish/requires_resolution_before_publishing_test.dart b/test/lish/requires_resolution_before_publishing_test.dart
new file mode 100644
index 0000000..e3294bc
--- /dev/null
+++ b/test/lish/requires_resolution_before_publishing_test.dart
@@ -0,0 +1,22 @@
+// 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('does not publish if no resolution can be found', () async {
+    await servePackages(); // No packages.
+    await d.validPackage.create();
+    await d.appDir({'foo': '1.0.0'}).create();
+    await runPub(
+      args: ['lish'],
+      error: contains("Because myapp depends on foo any which doesn't exist"),
+      exitCode: exit_codes.UNAVAILABLE,
+    );
+  });
+}
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..fcfdf14 100644
--- a/test/lish/server_arg_overrides_publish_to_url_test.dart
+++ b/test/lish/server_arg_overrides_publish_to_url_test.dart
@@ -18,7 +18,6 @@
     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),
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..8758bca 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
@@ -11,10 +11,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('upload form fields has a non-string value', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
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..dc41511 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
@@ -11,10 +11,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('upload form fields is not a map', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
diff --git a/test/lish/upload_form_is_missing_fields_test.dart b/test/lish/upload_form_is_missing_fields_test.dart
index b0032f8..e909c0a 100644
--- a/test/lish/upload_form_is_missing_fields_test.dart
+++ b/test/lish/upload_form_is_missing_fields_test.dart
@@ -11,10 +11,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('upload form is missing fields', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
diff --git a/test/lish/upload_form_is_missing_url_test.dart b/test/lish/upload_form_is_missing_url_test.dart
index eae43ea..418813f 100644
--- a/test/lish/upload_form_is_missing_url_test.dart
+++ b/test/lish/upload_form_is_missing_url_test.dart
@@ -11,10 +11,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('upload form is missing url', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
diff --git a/test/lish/upload_form_provides_an_error_test.dart b/test/lish/upload_form_provides_an_error_test.dart
index 35932b8..68a6c66 100644
--- a/test/lish/upload_form_provides_an_error_test.dart
+++ b/test/lish/upload_form_provides_an_error_test.dart
@@ -11,10 +11,9 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('upload form provides an error', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
diff --git a/test/lish/upload_form_provides_invalid_json_test.dart b/test/lish/upload_form_provides_invalid_json_test.dart
index a046755..73ffb9a 100644
--- a/test/lish/upload_form_provides_invalid_json_test.dart
+++ b/test/lish/upload_form_provides_invalid_json_test.dart
@@ -9,10 +9,10 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('upload form provides invalid JSON', () async {
     await servePackages();
+    await d.validPackage.create();
+    await servePackages();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
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..b37d24f 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
@@ -11,10 +11,9 @@
 import 'utils.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('upload form url is not a string', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.credentialsFile(globalServer, 'access token').create();
     var pub = await startPublish(globalServer);
 
diff --git a/test/lish/uses_publish_to_url_test.dart b/test/lish/uses_publish_to_url_test.dart
index 47496f7..d9408c4 100644
--- a/test/lish/uses_publish_to_url_test.dart
+++ b/test/lish/uses_publish_to_url_test.dart
@@ -14,7 +14,6 @@
     var pkg = packageMap('test_pkg', '1.0.0');
     pkg['publish_to'] = 'http://example.com';
     await d.dir(appPath, [d.pubspec(pkg)]).create();
-
     await runPub(
         args: ['lish', '--dry-run'],
         output: contains('Publishing test_pkg 1.0.0 to http://example.com'),
diff --git a/test/oauth2/logout_test.dart b/test/oauth2/logout_test.dart
index a12a652..fb95c73 100644
--- a/test/oauth2/logout_test.dart
+++ b/test/oauth2/logout_test.dart
@@ -16,8 +16,7 @@
             expiration: DateTime.now().add(Duration(hours: 1)))
         .create();
 
-    await runPub(
-        args: ['logout'], output: contains('Logging out of pub.dartlang.org.'));
+    await runPub(args: ['logout'], output: contains('Logging out of pub.dev.'));
 
     await d.dir(configPath, [d.nothing('pub-credentials.json')]).validate();
   });
@@ -48,7 +47,7 @@
       args: ['logout'],
       output: allOf(
         [
-          contains('Logging out of pub.dartlang.org.'),
+          contains('Logging out of pub.dev.'),
           contains('Also deleting legacy credentials at ')
         ],
       ),
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..fb63cde 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
@@ -13,9 +13,9 @@
   test(
       'with an expired credentials.json without a refresh token, '
       'authenticates again and saves credentials.json', () async {
+    await servePackages();
     await d.validPackage.create();
 
-    await servePackages();
     await d
         .credentialsFile(globalServer, 'access token',
             expiration: DateTime.now().subtract(Duration(hours: 1)))
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..2fdb7a4 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
@@ -14,7 +14,6 @@
       'with no credentials.json, authenticates and saves '
       'credentials.json', () async {
     await d.validPackage.create();
-
     await servePackages();
     var pub = await startPublish(globalServer);
     await confirmPublish(pub);
diff --git a/test/package_server.dart b/test/package_server.dart
index 6aaea68..b7587e7 100644
--- a/test/package_server.dart
+++ b/test/package_server.dart
@@ -5,8 +5,11 @@
 import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
+import 'dart:typed_data';
 
 import 'package:path/path.dart' as p;
+import 'package:pub/src/crc32c.dart';
+import 'package:pub/src/source/hosted.dart';
 import 'package:pub/src/third_party/tar/tar.dart';
 import 'package:pub_semver/pub_semver.dart';
 import 'package:shelf/shelf.dart' as shelf;
@@ -18,8 +21,8 @@
 import 'test_pub.dart';
 
 class PackageServer {
-  /// The inner [DescriptorServer] that this uses to serve its descriptors.
-  final shelf.Server _inner;
+  /// The inner [IOServer] that this uses to serve its descriptors.
+  final shelf_io.IOServer _inner;
 
   /// Handlers of requests. Last matching handler will be used.
   final List<_PatternAndHandler> _handlers = [];
@@ -27,6 +30,16 @@
   // A list of all the requests recieved up till now.
   final List<String> requestedPaths = <String>[];
 
+  /// Whether the [IOServer] should compress the content, if possible.
+  /// The default value is `false` (compression disabled).
+  /// See [HttpServer.autoCompress] for details.
+  bool get autoCompress => _inner.server.autoCompress;
+  set autoCompress(bool shouldAutoCompress) =>
+      _inner.server.autoCompress = shouldAutoCompress;
+
+  // Setting this to false will disable automatic calculation of checksums.
+  bool serveChecksums = true;
+
   PackageServer._(this._inner) {
     _inner.mount((request) {
       final path = request.url.path;
@@ -63,26 +76,30 @@
         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,
-        }));
+        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,
+            }),
+            headers: {
+              HttpHeaders.contentTypeHeader: 'application/vnd.pub.v2+json'
+            });
       },
     );
 
     server.handle(
       _downloadPattern,
-      (shelf.Request request) {
+      (shelf.Request request) async {
         final parts = request.url.pathSegments;
         assert(parts[0] == 'packages');
         final name = parts[1];
@@ -98,7 +115,21 @@
 
         for (final packageVersion in package.versions.values) {
           if (packageVersion.version == version) {
-            return shelf.Response.ok(packageVersion.contents());
+            final headers = packageVersion.headers ?? {};
+            headers[HttpHeaders.contentTypeHeader] ??= [
+              'application/octet-stream'
+            ];
+
+            // This gate enables tests to validate the CRC32C parser by
+            // passing in arbitrary values for the checksum header.
+            if (server.serveChecksums &&
+                !headers.containsKey(checksumHeaderName)) {
+              headers[checksumHeaderName] = composeChecksumHeader(
+                  crc32c: await packageVersion.computeArchiveCrc32c());
+            }
+
+            return shelf.Response.ok(packageVersion.contents(),
+                headers: headers);
           }
         }
         return shelf.Response.notFound('No version $version of $name');
@@ -178,7 +209,8 @@
   void serve(String name, String version,
       {Map<String, dynamic>? deps,
       Map<String, dynamic>? pubspec,
-      List<d.Descriptor>? contents}) {
+      List<d.Descriptor>? contents,
+      Map<String, List<String>>? headers}) {
     var pubspecFields = <String, dynamic>{'name': name, 'version': version};
     if (pubspec != null) pubspecFields.addAll(pubspec);
     if (deps != null) pubspecFields['dependencies'] = deps;
@@ -189,6 +221,7 @@
     var package = _packages.putIfAbsent(name, _ServedPackage.new);
     package.versions[version] = _ServedPackageVersion(
       pubspecFields,
+      headers: headers,
       contents: () {
         final entries = <TarEntry>[];
 
@@ -243,6 +276,37 @@
   void retractPackageVersion(String name, String version) {
     _packages[name]!.versions[version]!.isRetracted = true;
   }
+
+  Future<String?> peekArchiveChecksumHeader(String name, String version) async {
+    final v = _packages[name]!.versions[version]!;
+
+    // If the test configured an overriding header value.
+    var checksumHeader = v.headers?[checksumHeaderName];
+
+    // Otherwise, compute from package contents.
+    if (serveChecksums) {
+      checksumHeader ??=
+          composeChecksumHeader(crc32c: await v.computeArchiveCrc32c());
+    }
+
+    return checksumHeader?.join(',');
+  }
+
+  static List<String> composeChecksumHeader(
+      {int? crc32c, String? md5 = '5f4dcc3b5aa765d61d8327deb882cf99'}) {
+    List<String> header = [];
+
+    if (crc32c != null) {
+      final bytes = Uint8List(4)..buffer.asByteData().setUint32(0, crc32c);
+      header.add('crc32c=${base64.encode(bytes)}');
+    }
+
+    if (md5 != null) {
+      header.add('md5=${base64.encode(utf8.encode(md5))}');
+    }
+
+    return header;
+  }
 }
 
 class _ServedPackage {
@@ -255,11 +319,16 @@
 class _ServedPackageVersion {
   final Map pubspec;
   final Stream<List<int>> Function() contents;
+  final Map<String, List<String>>? headers;
   bool isRetracted = false;
 
   Version get version => Version.parse(pubspec['version']);
 
-  _ServedPackageVersion(this.pubspec, {required this.contents});
+  _ServedPackageVersion(this.pubspec, {required this.contents, this.headers});
+
+  Future<int> computeArchiveCrc32c() async {
+    return await Crc32c.computeByConsumingStream(contents());
+  }
 }
 
 class _PatternAndHandler {
diff --git a/test/pubspec_overrides_test.dart b/test/pubspec_overrides_test.dart
index 514d52f..9f48c23 100644
--- a/test/pubspec_overrides_test.dart
+++ b/test/pubspec_overrides_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:pub/src/exit_codes.dart' as exit_codes;
 import 'package:test/test.dart';
 
 import 'descriptor.dart' as d;
@@ -47,18 +46,4 @@
       ]).validate();
     });
   });
-
-  test('is ignored by publish command', () async {
-    await d.validPackage.create();
-    await d.dir(appPath, [
-      d.pubspecOverrides({
-        'dependency_overrides': {'lib': '1.0.0'}
-      }),
-    ]).create();
-
-    await runPub(
-      args: ['lish', '--dry-run'],
-      exitCode: exit_codes.SUCCESS,
-    );
-  });
 }
diff --git a/test/pubspec_test.dart b/test/pubspec_test.dart
index 1e9c8bd..2ccb30f 100644
--- a/test/pubspec_test.dart
+++ b/test/pubspec_test.dart
@@ -622,7 +622,7 @@
 
       test('throws on non-absolute URLs', () {
         expectPubspecException(
-            'publish_to: pub.dartlang.org', (pubspec) => pubspec.publishTo);
+            'publish_to: pub.dev', (pubspec) => pubspec.publishTo);
       });
     });
 
diff --git a/test/reformat_ranges_test.dart b/test/reformat_ranges_test.dart
index 9a88df6..d2c91ca 100644
--- a/test/reformat_ranges_test.dart
+++ b/test/reformat_ranges_test.dart
@@ -11,7 +11,7 @@
 
 void main() {
   final description = ResolvedHostedDescription(
-    HostedDescription('foo', 'https://pub.dartlang.org'),
+    HostedDescription('foo', 'https://pub.dev'),
   );
   test('reformatMax when max has a build identifier', () {
     expect(
diff --git a/test/test_pub.dart b/test/test_pub.dart
index 99f5655..be89bda 100644
--- a/test/test_pub.dart
+++ b/test/test_pub.dart
@@ -74,7 +74,7 @@
         orElse: () => null) as Map<String, dynamic>;
 
 /// The suffix appended to a built snapshot.
-final versionSuffix = testVersion;
+const versionSuffix = testVersion;
 
 /// Enum identifying a pub command that can be run with a well-defined success
 /// output.
@@ -182,6 +182,7 @@
   Iterable<String>? args,
   Object? output,
   Object? error,
+  Object? silent,
   Object? warning,
   int? exitCode,
   Map<String, String?>? environment,
@@ -193,6 +194,7 @@
       args: args,
       output: output,
       error: error,
+      silent: silent,
       warning: warning,
       exitCode: exitCode,
       environment: environment,
@@ -391,7 +393,7 @@
   // TODO(rnystrom): This is overly specific and inflexible regarding different
   // test packages. Should validate this a little more loosely.
   await expectLater(
-      pub.stdout, emits(startsWith('Publishing test_pkg 1.0.0 to ')));
+      pub.stdout, emitsThrough(startsWith('Publishing test_pkg 1.0.0 to ')));
   await expectLater(
       pub.stdout,
       emitsThrough(matches(
@@ -407,7 +409,7 @@
 /// sandbox.
 String _pathInSandbox(String relPath) => p.join(d.sandbox, relPath);
 
-String testVersion = '0.1.2+3';
+const String testVersion = '0.1.2+3';
 
 /// Gets the environment variables used to run pub in a test context.
 Map<String, String> getPubTestEnvironment([String? tokenEndpoint]) => {
@@ -681,7 +683,7 @@
   var package = <String, Object>{
     'name': name,
     'version': version,
-    'homepage': 'http://pub.dartlang.org',
+    'homepage': 'http://pub.dev',
     'description': 'A package, I guess.'
   };
 
@@ -691,7 +693,7 @@
   return package;
 }
 
-/// Returns a Map in the format used by the pub.dartlang.org API to represent a
+/// Returns a Map in the format used by the pub.dev API to represent a
 /// package version.
 ///
 /// [pubspec] is the parsed pubspec of the package version. If [full] is true,
@@ -946,8 +948,8 @@
 PackageServer get globalServer => _globalServer!;
 PackageServer? _globalServer;
 
-/// Creates an HTTP server that replicates the structure of pub.dartlang.org and
-/// makes it the current [globalServer].
+/// Creates an HTTP server that replicates the structure of pub.dev and makes it
+/// the current [globalServer].
 Future<PackageServer> servePackages() async {
   final server = await startPackageServer();
   _globalServer = server;
diff --git a/test/testdata/goldens/ascii_tree_test/tree.fromFiles a complex example.ans b/test/testdata/goldens/ascii_tree_test/tree.fromFiles a complex example.ans
new file mode 100644
index 0000000..7b913f0
--- /dev/null
+++ b/test/testdata/goldens/ascii_tree_test/tree.fromFiles a complex example.ans
@@ -0,0 +1,26 @@
+# GENERATED BY: test/ascii_tree_test.dart
+
+├── README.md (<1 KB)
+├── TODO (<1 KB)
+├── example
+│   ├── console_example.dart (<1 KB)
+│   ├── main.dart (1 KB)
+│   └── web copy
+│       └── web_example.dart (1 KB)
+├── lib
+│   └── path.dart (<1 KB)
+├── pubspec.yaml (<1 KB)
+└── test
+    ├── absolute_test.dart (<1 KB)
+    ├── all_test.dart (<1 KB)
+    ├── basename_test.dart (1 MB)
+    ├── dirname_test.dart (1 MB)
+    ├── extension_test.dart (2 KB)
+    ├── is_absolute_test.dart (2 KB)
+    ├── is_relative_test.dart (25 MB)
+    ├── join_test.dart (<1 KB)
+    ├── normalize_test.dart (1023 KB)
+    ├── path_posix_test.dart (<1 KB)
+    ├── path_windows_test.dart (<1 KB)
+    ├── relative_test.dart (<1 KB)
+    └── split_test.dart (<1 KB)
diff --git a/test/testdata/goldens/ascii_tree_test/tree.fromMap a complex example.ans b/test/testdata/goldens/ascii_tree_test/tree.fromMap a complex example.ans
new file mode 100644
index 0000000..0089c11
--- /dev/null
+++ b/test/testdata/goldens/ascii_tree_test/tree.fromMap a complex example.ans
@@ -0,0 +1,24 @@
+# GENERATED BY: test/ascii_tree_test.dart
+
+├── .gitignore
+├── README.md
+├── TODO
+├── example
+│   ├── console_example.dart
+│   ├── main.dart
+│   └── web copy
+│       └── web_example.dart
+├── lib
+│   └── path.dart
+├── pubspec.yaml
+└── test
+    ├── absolute_test.dart
+    ├── basename_test.dart
+    ├── dirname_test.dart
+    ├── extension_test.dart
+    ├── is_absolute_test.dart
+    ├── is_relative_test.dart
+    ├── join_test.dart
+    ├── normalize_test.dart
+    ├── relative_test.dart
+    └── split_test.dart
diff --git a/test/testdata/goldens/dependency_services/dependency_services_test/Can update a git package.txt b/test/testdata/goldens/dependency_services/dependency_services_test/Can update a git package.txt
index 1f90e4c..35de0ad 100644
--- a/test/testdata/goldens/dependency_services/dependency_services_test/Can update a git package.txt
+++ b/test/testdata/goldens/dependency_services/dependency_services_test/Can update a git package.txt
@@ -11,7 +11,7 @@
     description:
       path: "."
       ref: HEAD
-      resolved-ref: "92cdd4ac724a6da0db2a69ac149820aa220e8518"
+      resolved-ref: "5373af3230028f3e31e9ee39e326228db83710cb"
       url: "../bar.git"
     source: git
     version: "1.0.0"
@@ -20,7 +20,7 @@
     description:
       path: "."
       ref: HEAD
-      resolved-ref: "1ae220cc484311a7a1e2e31d1ccc6ea995acb6ba"
+      resolved-ref: "428f5dd6e627cb2384343eca6aed099f4f7d183d"
       url: "../foo.git"
     source: git
     version: "1.0.0"
@@ -34,7 +34,7 @@
   "dependencies": [
     {
       "name": "bar",
-      "version": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+      "version": "5373af3230028f3e31e9ee39e326228db83710cb",
       "kind": "direct",
       "constraint": "^1.0.0",
       "source": {
@@ -42,14 +42,14 @@
         "description": {
           "url": "../bar.git",
           "ref": "HEAD",
-          "resolved-ref": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+          "resolved-ref": "5373af3230028f3e31e9ee39e326228db83710cb",
           "path": "."
         }
       }
     },
     {
       "name": "foo",
-      "version": "1ae220cc484311a7a1e2e31d1ccc6ea995acb6ba",
+      "version": "428f5dd6e627cb2384343eca6aed099f4f7d183d",
       "kind": "direct",
       "constraint": "any",
       "source": {
@@ -57,7 +57,7 @@
         "description": {
           "url": "../foo.git",
           "ref": "HEAD",
-          "resolved-ref": "1ae220cc484311a7a1e2e31d1ccc6ea995acb6ba",
+          "resolved-ref": "428f5dd6e627cb2384343eca6aed099f4f7d183d",
           "path": "."
         }
       }
@@ -73,45 +73,45 @@
   "dependencies": [
     {
       "name": "bar",
-      "version": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+      "version": "5373af3230028f3e31e9ee39e326228db83710cb",
       "kind": "direct",
       "source": {
         "type": "git",
         "description": {
           "url": "../bar.git",
           "ref": "HEAD",
-          "resolved-ref": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+          "resolved-ref": "5373af3230028f3e31e9ee39e326228db83710cb",
           "path": "."
         }
       },
-      "latest": "cf473c33e39eeec4615bc2cde8bf68cbb10ad02c",
+      "latest": "40d0ffbfc376f2a796b0bbb928636c242285a01c",
       "constraint": "^1.0.0",
       "compatible": [],
       "singleBreaking": [
         {
           "name": "bar",
-          "version": "cf473c33e39eeec4615bc2cde8bf68cbb10ad02c",
+          "version": "40d0ffbfc376f2a796b0bbb928636c242285a01c",
           "kind": "direct",
           "source": {
             "type": "git",
             "description": {
               "url": "../bar.git",
               "ref": "HEAD",
-              "resolved-ref": "cf473c33e39eeec4615bc2cde8bf68cbb10ad02c",
+              "resolved-ref": "40d0ffbfc376f2a796b0bbb928636c242285a01c",
               "path": "."
             }
           },
           "constraintBumped": "^2.0.0",
           "constraintWidened": ">=1.0.0 <3.0.0",
           "constraintBumpedIfNeeded": "^2.0.0",
-          "previousVersion": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+          "previousVersion": "5373af3230028f3e31e9ee39e326228db83710cb",
           "previousConstraint": "^1.0.0",
           "previousSource": {
             "type": "git",
             "description": {
               "url": "../bar.git",
               "ref": "HEAD",
-              "resolved-ref": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+              "resolved-ref": "5373af3230028f3e31e9ee39e326228db83710cb",
               "path": "."
             }
           }
@@ -120,28 +120,28 @@
       "multiBreaking": [
         {
           "name": "bar",
-          "version": "cf473c33e39eeec4615bc2cde8bf68cbb10ad02c",
+          "version": "40d0ffbfc376f2a796b0bbb928636c242285a01c",
           "kind": "direct",
           "source": {
             "type": "git",
             "description": {
               "url": "../bar.git",
               "ref": "HEAD",
-              "resolved-ref": "cf473c33e39eeec4615bc2cde8bf68cbb10ad02c",
+              "resolved-ref": "40d0ffbfc376f2a796b0bbb928636c242285a01c",
               "path": "."
             }
           },
           "constraintBumped": "^2.0.0",
           "constraintWidened": ">=1.0.0 <3.0.0",
           "constraintBumpedIfNeeded": "^2.0.0",
-          "previousVersion": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+          "previousVersion": "5373af3230028f3e31e9ee39e326228db83710cb",
           "previousConstraint": "^1.0.0",
           "previousSource": {
             "type": "git",
             "description": {
               "url": "../bar.git",
               "ref": "HEAD",
-              "resolved-ref": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+              "resolved-ref": "5373af3230028f3e31e9ee39e326228db83710cb",
               "path": "."
             }
           }
@@ -150,46 +150,46 @@
     },
     {
       "name": "foo",
-      "version": "1ae220cc484311a7a1e2e31d1ccc6ea995acb6ba",
+      "version": "428f5dd6e627cb2384343eca6aed099f4f7d183d",
       "kind": "direct",
       "source": {
         "type": "git",
         "description": {
           "url": "../foo.git",
           "ref": "HEAD",
-          "resolved-ref": "1ae220cc484311a7a1e2e31d1ccc6ea995acb6ba",
+          "resolved-ref": "428f5dd6e627cb2384343eca6aed099f4f7d183d",
           "path": "."
         }
       },
-      "latest": "ad2d659389d4475f6c3a34282e2204160b753fd9",
+      "latest": "40c4eb4fb235961264ee9cdbdfa54ef7f6aa5199",
       "constraint": "any",
       "compatible": [],
       "singleBreaking": [],
       "multiBreaking": [
         {
           "name": "foo",
-          "version": "ad2d659389d4475f6c3a34282e2204160b753fd9",
+          "version": "40c4eb4fb235961264ee9cdbdfa54ef7f6aa5199",
           "kind": "direct",
           "source": {
             "type": "git",
             "description": {
               "url": "../foo.git",
               "ref": "HEAD",
-              "resolved-ref": "ad2d659389d4475f6c3a34282e2204160b753fd9",
+              "resolved-ref": "40c4eb4fb235961264ee9cdbdfa54ef7f6aa5199",
               "path": "."
             }
           },
           "constraintBumped": "^2.0.0",
           "constraintWidened": "any",
           "constraintBumpedIfNeeded": "any",
-          "previousVersion": "1ae220cc484311a7a1e2e31d1ccc6ea995acb6ba",
+          "previousVersion": "428f5dd6e627cb2384343eca6aed099f4f7d183d",
           "previousConstraint": "any",
           "previousSource": {
             "type": "git",
             "description": {
               "url": "../foo.git",
               "ref": "HEAD",
-              "resolved-ref": "1ae220cc484311a7a1e2e31d1ccc6ea995acb6ba",
+              "resolved-ref": "428f5dd6e627cb2384343eca6aed099f4f7d183d",
               "path": "."
             }
           }
@@ -202,7 +202,7 @@
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section apply
-$ echo '{"dependencyChanges":[{"name":"foo","version":"ad2d659389d4475f6c3a34282e2204160b753fd9"}]}' | dependency_services apply
+$ echo '{"dependencyChanges":[{"name":"foo","version":"40c4eb4fb235961264ee9cdbdfa54ef7f6aa5199"}]}' | dependency_services apply
 {"dependencies":[]}
 
 -------------------------------- END OF OUTPUT ---------------------------------
@@ -218,7 +218,7 @@
     description:
       path: "."
       ref: HEAD
-      resolved-ref: "92cdd4ac724a6da0db2a69ac149820aa220e8518"
+      resolved-ref: "5373af3230028f3e31e9ee39e326228db83710cb"
       url: "../bar.git"
     source: git
     version: "1.0.0"
@@ -227,7 +227,7 @@
     description:
       path: "."
       ref: HEAD
-      resolved-ref: ad2d659389d4475f6c3a34282e2204160b753fd9
+      resolved-ref: "40c4eb4fb235961264ee9cdbdfa54ef7f6aa5199"
       url: "../foo.git"
     source: git
     version: "2.0.0"
diff --git a/test/testdata/goldens/dependency_services/dependency_services_test/No pubspec.lock.txt b/test/testdata/goldens/dependency_services/dependency_services_test/No pubspec.lock.txt
index ca80a34..e5ab484 100644
--- a/test/testdata/goldens/dependency_services/dependency_services_test/No pubspec.lock.txt
+++ b/test/testdata/goldens/dependency_services/dependency_services_test/No pubspec.lock.txt
@@ -12,7 +12,7 @@
   "dependencies": [
     {
       "name": "bar",
-      "version": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+      "version": "5373af3230028f3e31e9ee39e326228db83710cb",
       "kind": "direct",
       "constraint": "any",
       "source": {
@@ -20,7 +20,7 @@
         "description": {
           "url": "../bar.git",
           "ref": "HEAD",
-          "resolved-ref": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+          "resolved-ref": "5373af3230028f3e31e9ee39e326228db83710cb",
           "path": "."
         }
       }
@@ -62,18 +62,18 @@
   "dependencies": [
     {
       "name": "bar",
-      "version": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+      "version": "5373af3230028f3e31e9ee39e326228db83710cb",
       "kind": "direct",
       "source": {
         "type": "git",
         "description": {
           "url": "../bar.git",
           "ref": "HEAD",
-          "resolved-ref": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+          "resolved-ref": "5373af3230028f3e31e9ee39e326228db83710cb",
           "path": "."
         }
       },
-      "latest": "92cdd4ac724a6da0db2a69ac149820aa220e8518",
+      "latest": "5373af3230028f3e31e9ee39e326228db83710cb",
       "constraint": "any",
       "compatible": [],
       "singleBreaking": [],
diff --git a/test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt b/test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt
index d8448df..4c8b2b9 100644
--- a/test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt
+++ b/test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt
@@ -2,20 +2,20 @@
 
 ## Section 0
 $ tree
-|-- bar
-|   |-- bin
-|   |   '-- qux.dart
-|   '-- pubspec.yaml
-|-- foo
-|   |-- bin
-|   |   |-- baz.dart
-|   |   '-- foo.dart
-|   '-- pubspec.yaml
-'-- myapp
-    |-- bin
-    |   '-- myapp.dart
-    |-- pubspec.lock
-    '-- pubspec.yaml
+├── bar
+│   ├── bin
+│   │   └── qux.dart
+│   └── pubspec.yaml
+├── foo
+│   ├── bin
+│   │   ├── baz.dart
+│   │   └── foo.dart
+│   └── pubspec.yaml
+└── myapp
+    ├── bin
+    │   └── myapp.dart
+    ├── pubspec.lock
+    └── pubspec.yaml
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
diff --git a/test/testdata/goldens/deps/executables_test/dev dependencies.txt b/test/testdata/goldens/deps/executables_test/dev dependencies.txt
index 2d72b44..8493d62 100644
--- a/test/testdata/goldens/deps/executables_test/dev dependencies.txt
+++ b/test/testdata/goldens/deps/executables_test/dev dependencies.txt
@@ -2,13 +2,13 @@
 
 ## Section 0
 $ tree
-|-- foo
-|   |-- bin
-|   |   '-- bar.dart
-|   '-- pubspec.yaml
-'-- myapp
-    |-- pubspec.lock
-    '-- pubspec.yaml
+├── foo
+│   ├── bin
+│   │   └── bar.dart
+│   └── pubspec.yaml
+└── myapp
+    ├── pubspec.lock
+    └── pubspec.yaml
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
diff --git a/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt b/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt
index a12d363..3b46fb0 100644
--- a/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt
+++ b/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt
@@ -2,12 +2,12 @@
 
 ## Section 0
 $ tree
-'-- myapp
-    |-- bin
-    |   |-- bar.dart
-    |   '-- foo.dart
-    |-- pubspec.lock
-    '-- pubspec.yaml
+└── myapp
+    ├── bin
+    │   ├── bar.dart
+    │   └── foo.dart
+    ├── pubspec.lock
+    └── pubspec.yaml
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
diff --git a/test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt b/test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt
index 75a1b33..b78f99f 100644
--- a/test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt
+++ b/test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt
@@ -2,13 +2,13 @@
 
 ## Section 0
 $ tree
-|-- foo
-|   |-- bin
-|   |   '-- bar.dart
-|   '-- pubspec.yaml
-'-- myapp
-    |-- pubspec.lock
-    '-- pubspec.yaml
+├── foo
+│   ├── bin
+│   │   └── bar.dart
+│   └── pubspec.yaml
+└── myapp
+    ├── pubspec.lock
+    └── pubspec.yaml
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
diff --git a/test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt b/test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt
index de70643..5d4cf00 100644
--- a/test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt
+++ b/test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt
@@ -2,17 +2,17 @@
 
 ## Section 0
 $ tree
-|-- baz
-|   |-- bin
-|   |   '-- qux.dart
-|   '-- pubspec.yaml
-|-- foo
-|   |-- bin
-|   |   '-- bar.dart
-|   '-- pubspec.yaml
-'-- myapp
-    |-- pubspec.lock
-    '-- pubspec.yaml
+├── baz
+│   ├── bin
+│   │   └── qux.dart
+│   └── pubspec.yaml
+├── foo
+│   ├── bin
+│   │   └── bar.dart
+│   └── pubspec.yaml
+└── myapp
+    ├── pubspec.lock
+    └── pubspec.yaml
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
diff --git a/test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt b/test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt
index 910210e..edb3098 100644
--- a/test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt
+++ b/test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt
@@ -2,18 +2,18 @@
 
 ## Section 0
 $ tree
-|-- foo-1.0
-|   |-- bin
-|   |   '-- bar.dart
-|   '-- pubspec.yaml
-|-- foo-2.0
-|   |-- bin
-|   |   |-- bar.dart
-|   |   '-- baz.dart
-|   '-- pubspec.yaml
-'-- myapp
-    |-- pubspec.lock
-    '-- pubspec.yaml
+├── foo-1.0
+│   ├── bin
+│   │   └── bar.dart
+│   └── pubspec.yaml
+├── foo-2.0
+│   ├── bin
+│   │   ├── bar.dart
+│   │   └── baz.dart
+│   └── pubspec.yaml
+└── myapp
+    ├── pubspec.lock
+    └── pubspec.yaml
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
diff --git a/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt b/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt
index 289f7c8..514e5ef 100644
--- a/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt
+++ b/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt
@@ -2,13 +2,13 @@
 
 ## Section 0
 $ tree
-'-- myapp
-    |-- bin
-    |   |-- foo.dart
-    |   '-- sub
-    |       '-- bar.dart
-    |-- pubspec.lock
-    '-- pubspec.yaml
+└── myapp
+    ├── bin
+    │   ├── foo.dart
+    │   └── sub
+    │       └── bar.dart
+    ├── pubspec.lock
+    └── pubspec.yaml
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
diff --git a/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt b/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt
index d4a2db3..8cf6076 100644
--- a/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt
+++ b/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt
@@ -2,12 +2,12 @@
 
 ## Section 0
 $ tree
-'-- myapp
-    |-- bin
-    |   |-- bar.sh
-    |   '-- foo.py
-    |-- pubspec.lock
-    '-- pubspec.yaml
+└── myapp
+    ├── bin
+    │   ├── bar.sh
+    │   └── foo.py
+    ├── pubspec.lock
+    └── pubspec.yaml
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
diff --git a/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt b/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt
index 9585341..577a0a5 100644
--- a/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt
+++ b/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt
@@ -53,7 +53,7 @@
 Resolving dependencies in myapp/example2...
 [STDERR] Error on line 1, column 9 of myapp/pubspec.yaml: "name" field doesn't match expected name "myapp".
 [STDERR]   ╷
-[STDERR] 1 │ {"name":"test_pkg","version":"1.0.0","homepage":"http://pub.dartlang.org","description":"A package, I guess.","environment":{"sdk":">=1.8.0 <=2.0.0"}, dependencies: { foo: ^1.0.0}}
+[STDERR] 1 │ {"name":"test_pkg","version":"1.0.0","homepage":"http://pub.dev","description":"A package, I guess.","environment":{"sdk":">=0.1.2 <=0.2.0"}, dependencies: { foo: ^1.0.0}}
 [STDERR]   │         ^^^^^^^^^^
 [STDERR]   ╵
 [EXIT CODE] 65
@@ -93,22 +93,30 @@
 
 ## Section 11
 $ pub publish -C myapp --dry-run
+Resolving dependencies in myapp...
+Got dependencies in myapp!
 Publishing test_pkg 1.0.0 to http://localhost:$PORT:
-|-- CHANGELOG.md
-|-- LICENSE
-|-- README.md
-|-- bin
-|   '-- app.dart
-|-- example
-|   '-- pubspec.yaml
-|-- example2
-|   '-- pubspec.yaml
-|-- lib
-|   '-- test_pkg.dart
-'-- pubspec.yaml
-The server may enforce additional checks.
-[STDERR] 
-[STDERR] Package has 0 warnings.
+├── CHANGELOG.md (<1 KB)
+├── LICENSE (<1 KB)
+├── README.md (<1 KB)
+├── bin
+│   └── app.dart (<1 KB)
+├── example
+│   └── pubspec.yaml (<1 KB)
+├── example2
+│   └── pubspec.yaml (<1 KB)
+├── lib
+│   └── test_pkg.dart (<1 KB)
+└── pubspec.yaml (<1 KB)
+[STDERR] Package validation found the following error:
+[STDERR] * Older versions of pub don't support ^ version constraints.
+[STDERR]   Make sure your SDK constraint excludes old versions:
+[STDERR]   
+[STDERR]   environment:
+[STDERR]     sdk: ">=1.8.0 <2.0.0"
+[STDERR] Sorry, your package is missing a requirement and can't be published yet.
+[STDERR] For more information, see: https://dart.dev/tools/pub/cmd/pub-lish.
+[EXIT CODE] 65
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
@@ -124,7 +132,7 @@
 
 ## Section 13
 $ pub deps -C myapp
-Dart SDK 1.12.0
+Dart SDK 0.1.2+3
 test_pkg 1.0.0
-'-- foo 1.0.0
+└── foo 1.0.0
 
diff --git a/test/testdata/goldens/embedding/embedding_test/--help.txt b/test/testdata/goldens/embedding/embedding_test/--help.txt
index ea8fd3f..13647a0 100644
--- a/test/testdata/goldens/embedding/embedding_test/--help.txt
+++ b/test/testdata/goldens/embedding/embedding_test/--help.txt
@@ -23,7 +23,7 @@
   login   Log into pub.dev.
   logout   Log out of pub.dev.
   outdated   Analyze your dependencies to find which ones can be upgraded.
-  publish   Publish the current package to pub.dartlang.org.
+  publish   Publish the current package to pub.dev.
   remove   Removes a dependency from the current package.
   token   Manage authentication tokens for hosted pub repositories.
   upgrade   Upgrade the current package's dependencies to latest versions.
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
index 14ea76f..dc09988 100644
--- 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
@@ -27,7 +27,7 @@
 [E]    | date: $TIME
 [E]    | content-length: 197
 [E]    | x-frame-options: SAMEORIGIN
-[E]    | content-type: text/plain; charset=utf-8
+[E]    | content-type: application/vnd.pub.v2+json
 [E]    | x-xss-protection: 1; mode=block
 [E]    | x-content-type-options: nosniff
 [E] IO  : Writing $N characters to text file $SANDBOX/cache/hosted/localhost%58$PORT/.cache/foo-versions.json.
@@ -49,13 +49,15 @@
 [E] IO  : HTTP response 200 OK for GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz
 [E]    | took: $TIME
 [E]    | x-powered-by: Dart with package:shelf
-[E]    | transfer-encoding: chunked
 [E]    | date: $TIME
+[E]    | transfer-encoding: chunked
+[E]    | x-goog-hash: $CHECKSUM_HEADER
 [E]    | x-frame-options: SAMEORIGIN
-[E]    | content-type: text/plain; charset=utf-8
+[E]    | content-type: application/octet-stream
 [E]    | x-xss-protection: 1; mode=block
 [E]    | x-content-type-options: nosniff
 [E] IO  : Creating $FILE from stream
+[E] FINE: Computed checksum $CRC32C for foo 1.0.0 with expected CRC32C of $CRC32C.
 [E] FINE: Created $FILE from stream
 [E] IO  : Created temp directory $DIR
 [E] IO  : Reading binary file $FILE.
@@ -163,7 +165,7 @@
    | date: $TIME
    | content-length: 197
    | x-frame-options: SAMEORIGIN
-   | content-type: text/plain; charset=utf-8
+   | content-type: application/vnd.pub.v2+json
    | x-xss-protection: 1; mode=block
    | x-content-type-options: nosniff
 IO  : Writing $N characters to text file $SANDBOX/cache/hosted/localhost%58$PORT/.cache/foo-versions.json.
@@ -187,13 +189,15 @@
 IO  : HTTP response 200 OK for GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz
    | took: $TIME
    | x-powered-by: Dart with package:shelf
-   | transfer-encoding: chunked
    | date: $TIME
+   | transfer-encoding: chunked
+   | x-goog-hash: $CHECKSUM_HEADER
    | x-frame-options: SAMEORIGIN
-   | content-type: text/plain; charset=utf-8
+   | content-type: application/octet-stream
    | x-xss-protection: 1; mode=block
    | x-content-type-options: nosniff
 IO  : Creating $FILE from stream
+FINE: Computed checksum $CRC32C for foo 1.0.0 with expected CRC32C of $CRC32C.
 FINE: Created $FILE from stream
 IO  : Created temp directory $DIR
 IO  : Reading binary file $FILE.
diff --git a/test/testdata/goldens/help_test/pub publish --help.txt b/test/testdata/goldens/help_test/pub publish --help.txt
index 2977db0..14e83e2 100644
--- a/test/testdata/goldens/help_test/pub publish --help.txt
+++ b/test/testdata/goldens/help_test/pub publish --help.txt
@@ -2,7 +2,7 @@
 
 ## Section 0
 $ pub publish --help
-Publish the current package to pub.dartlang.org.
+Publish the current package to pub.dev.
 
 Usage: pub publish [options]
 -h, --help               Print this usage information.
diff --git a/test/testdata/goldens/lish/many_files_test/displays all files.txt b/test/testdata/goldens/lish/many_files_test/displays all files.txt
index 09a01da..7171f66 100644
--- a/test/testdata/goldens/lish/many_files_test/displays all files.txt
+++ b/test/testdata/goldens/lish/many_files_test/displays all files.txt
@@ -1,32 +1,34 @@
 # GENERATED BY: test/lish/many_files_test.dart
 
+Resolving dependencies...
+Got dependencies!
 Publishing test_pkg 1.0.0 to http://localhost:$PORT:
-|-- CHANGELOG.md
-|-- LICENSE
-|-- README.md
-|-- lib
-|   |-- file_0.dart
-|   |-- file_1.dart
-|   |-- file_10.dart
-|   |-- file_11.dart
-|   |-- file_12.dart
-|   |-- file_13.dart
-|   |-- file_14.dart
-|   |-- file_15.dart
-|   |-- file_16.dart
-|   |-- file_17.dart
-|   |-- file_18.dart
-|   |-- file_19.dart
-|   |-- file_2.dart
-|   |-- file_3.dart
-|   |-- file_4.dart
-|   |-- file_5.dart
-|   |-- file_6.dart
-|   |-- file_7.dart
-|   |-- file_8.dart
-|   |-- file_9.dart
-|   '-- test_pkg.dart
-'-- pubspec.yaml
+├── CHANGELOG.md (<1 KB)
+├── LICENSE (<1 KB)
+├── README.md (<1 KB)
+├── lib
+│   ├── file_0.dart (<1 KB)
+│   ├── file_1.dart (<1 KB)
+│   ├── file_10.dart (<1 KB)
+│   ├── file_11.dart (<1 KB)
+│   ├── file_12.dart (<1 KB)
+│   ├── file_13.dart (<1 KB)
+│   ├── file_14.dart (<1 KB)
+│   ├── file_15.dart (<1 KB)
+│   ├── file_16.dart (<1 KB)
+│   ├── file_17.dart (<1 KB)
+│   ├── file_18.dart (<1 KB)
+│   ├── file_19.dart (<1 KB)
+│   ├── file_2.dart (<1 KB)
+│   ├── file_3.dart (<1 KB)
+│   ├── file_4.dart (<1 KB)
+│   ├── file_5.dart (<1 KB)
+│   ├── file_6.dart (<1 KB)
+│   ├── file_7.dart (<1 KB)
+│   ├── file_8.dart (<1 KB)
+│   ├── file_9.dart (<1 KB)
+│   └── test_pkg.dart (<1 KB)
+└── pubspec.yaml (<1 KB)
 
 Publishing is forever; packages cannot be unpublished.
 Policy details are available at https://pub.dev/policy
diff --git a/test/testdata/goldens/outdated/outdated_test/no lockfile.txt b/test/testdata/goldens/outdated/outdated_test/no lockfile.txt
index 87a8997..70ce88f 100644
--- a/test/testdata/goldens/outdated/outdated_test/no lockfile.txt
+++ b/test/testdata/goldens/outdated/outdated_test/no lockfile.txt
@@ -49,7 +49,7 @@
 foo           -        1.2.3       1.2.3       1.2.3   
 
 No pubspec.lock found. There are no Current versions.
-Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+Run `dart pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
 
 1 dependency is constrained to a version that is older than a resolvable version.
 To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
@@ -68,7 +68,7 @@
 foo           -        1.2.3       1.2.3       1.2.3   
 
 No pubspec.lock found. There are no Current versions.
-Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+Run `dart pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
 
 1 dependency is constrained to a version that is older than a resolvable version.
 To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
@@ -87,7 +87,7 @@
 foo           -        1.2.3       1.2.3       1.2.3   
 
 No pubspec.lock found. There are no Current versions.
-Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+Run `dart pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
 
 1 dependency is constrained to a version that is older than a resolvable version.
 To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
@@ -106,7 +106,7 @@
 foo           -        1.2.3       1.2.3       1.2.3   
 
 No pubspec.lock found. There are no Current versions.
-Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+Run `dart pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
 
 1 dependency is constrained to a version that is older than a resolvable version.
 To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
@@ -125,7 +125,7 @@
 foo           -        1.2.3       1.2.3       1.2.3   
 
 No pubspec.lock found. There are no Current versions.
-Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+Run `dart pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
 
 1 dependency is constrained to a version that is older than a resolvable version.
 To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
@@ -144,7 +144,7 @@
 foo           -        1.2.3       1.2.3       1.2.3   
 
 No pubspec.lock found. There are no Current versions.
-Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+Run `dart pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
 
 1 dependency is constrained to a version that is older than a resolvable version.
 To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
@@ -164,7 +164,7 @@
 foo           -        ✗1.2.3      ✗1.2.3      ✗1.2.3  
 
 No pubspec.lock found. There are no Current versions.
-Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+Run `dart pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
 
 1 dependency is constrained to a version that is older than a resolvable version.
 To update it, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
@@ -184,7 +184,7 @@
 foo           -        ✗1.2.3      ✗1.2.3      ✗1.2.3  
 
 No pubspec.lock found. There are no Current versions.
-Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+Run `dart pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
 
 1 dependency is constrained to a version that is older than a resolvable version.
 To update it, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
@@ -204,7 +204,7 @@
 foo           -        ✗1.2.3      ✗1.2.3      ✗1.2.3  
 
 No pubspec.lock found. There are no Current versions.
-Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+Run `dart pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
 
 1 dependency is constrained to a version that is older than a resolvable version.
 To update it, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
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/token_authentication_test.dart b/test/token/token_authentication_test.dart
index 350bca4..d0b89c9 100644
--- a/test/token/token_authentication_test.dart
+++ b/test/token/token_authentication_test.dart
@@ -9,10 +9,9 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('with a pre existing environment token authenticates', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.tokensFile({
       'version': 1,
       'hosted': [
@@ -33,6 +32,7 @@
 
   test('with a pre existing opaque token authenticates', () async {
     await servePackages();
+    await d.validPackage.create();
     await d.tokensFile({
       'version': 1,
       'hosted': [
diff --git a/test/token/when_receives_401_removes_token_test.dart b/test/token/when_receives_401_removes_token_test.dart
index add619b..6ab0700 100644
--- a/test/token/when_receives_401_removes_token_test.dart
+++ b/test/token/when_receives_401_removes_token_test.dart
@@ -9,10 +9,9 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('when receives 401 response removes saved token', () async {
     final server = await servePackages();
+    await d.validPackage.create();
     await d.tokensFile({
       'version': 1,
       'hosted': [
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 6db5538..3fef9a5 100644
--- a/test/token/when_receives_403_persists_saved_token_test.dart
+++ b/test/token/when_receives_403_persists_saved_token_test.dart
@@ -9,9 +9,8 @@
 import '../test_pub.dart';
 
 void main() {
-  setUp(d.validPackage.create);
-
   test('when receives 403 response persists saved token', () async {
+    await d.validPackage.create();
     final server = await servePackages();
     await d.tokensFile({
       'version': 1,
diff --git a/test/validator/dependency_override_test.dart b/test/validator/dependency_override_test.dart
index b801ad9..60af87d 100644
--- a/test/validator/dependency_override_test.dart
+++ b/test/validator/dependency_override_test.dart
@@ -36,7 +36,7 @@
         })
       ]).create();
 
-      await expectValidation(dependencyOverride, errors: isNotEmpty);
+      await expectValidation(dependencyOverride, warnings: isNotEmpty);
     });
 
     test('it has any non-dev dependency overrides', () async {
@@ -51,7 +51,7 @@
         })
       ]).create();
 
-      await expectValidation(dependencyOverride, errors: isNotEmpty);
+      await expectValidation(dependencyOverride, warnings: isNotEmpty);
     });
   });
 }
diff --git a/test/validator/dependency_test.dart b/test/validator/dependency_test.dart
index f90ed1d..69fc4a8 100644
--- a/test/validator/dependency_test.dart
+++ b/test/validator/dependency_test.dart
@@ -25,29 +25,38 @@
   ]);
 }
 
-Future<void> expectValidation({error, int exitCode = 0}) async {
+Future<void> expectValidation(
+    {error,
+    int exitCode = 0,
+    Map<String, String> environment = const {}}) async {
   await runPub(
     error: error ?? contains('Package has 0 warnings.'),
     args: ['publish', '--dry-run'],
     // workingDirectory: d.path(appPath),
     exitCode: exitCode,
+    environment: environment,
   );
 }
 
-Future<void> expectValidationWarning(error) async {
+Future<void> expectValidationWarning(error,
+    {Map<String, String> environment = const {}}) async {
   if (error is String) error = contains(error);
   await expectValidation(
-      error: allOf([error, contains('Package has 1 warning.')]),
-      exitCode: DATA);
+    error: allOf([error, contains('Package has 1 warning.')]),
+    exitCode: DATA,
+    environment: environment,
+  );
 }
 
-Future<void> expectValidationError(String text) async {
+Future<void> expectValidationError(String text,
+    {Map<String, String> environment = const {}}) async {
   await expectValidation(
       error: allOf([
         contains(text),
         contains('Package validation found the following error:')
       ]),
-      exitCode: DATA);
+      exitCode: DATA,
+      environment: environment);
 }
 
 Future<void> setUpDependency(dep,
@@ -56,6 +65,7 @@
   for (final version in hostedVersions) {
     server.serve('foo', version);
   }
+
   await package(deps: {'foo': dep}).create();
 }
 
@@ -63,212 +73,186 @@
   group('should consider a package valid if it', () {
     test('looks normal', () async {
       await package().create();
-      await expectValidation();
+      await expectValidation(environment: {'_PUB_TEST_SDK_VERSION': '1.18.0'});
     });
 
     test('has a ^ constraint with an appropriate SDK constraint', () async {
+      (await servePackages()).serve('foo', '1.2.3');
       await package(deps: {'foo': '^1.2.3'}).create();
-      await expectValidation();
+      await expectValidation(environment: {'_PUB_TEST_SDK_VERSION': '1.18.0'});
     });
 
     test('with a dependency on a pre-release while being one', () async {
+      (await servePackages()).serve('foo', '1.2.3-dev');
       await package(version: '1.0.0-dev', deps: {'foo': '^1.2.3-dev'}).create();
 
-      await expectValidation();
+      await expectValidation(environment: {'_PUB_TEST_SDK_VERSION': '1.18.0'});
     });
 
     test('has a git path dependency with an appropriate SDK constraint',
         () async {
       await servePackages();
+      await d.git('foo', [
+        d.dir('subdir', [d.libPubspec('foo', '1.0.0', sdk: '^2.0.0')]),
+      ]).create();
       await package(deps: {
         'foo': {
-          'git': {'url': 'git://github.com/dart-lang/foo', 'path': 'subdir'}
+          'git': {'url': '../foo', 'path': 'subdir'}
         }
       }, sdk: '>=2.0.0 <3.0.0')
           .create();
 
       // We should get a warning for using a git dependency, but not an error.
-      await expectValidationWarning('  foo: any');
+      await expectValidationWarning(
+          allOf([
+            contains('  foo: any'),
+          ]),
+          environment: {'_PUB_TEST_SDK_VERSION': '2.0.0'});
     });
 
     test('depends on Flutter from an SDK source', () async {
+      await d.dir('flutter', [d.file('version', '1.2.3')]).create();
+      await flutterPackage('flutter', sdk: '>=1.19.0 <2.0.0').create();
       await package(deps: {
         'flutter': {'sdk': 'flutter'}
       }, sdk: '>=1.19.0 <2.0.0')
           .create();
 
-      await expectValidation();
-    });
-
-    test(
-        'depends on a package from Flutter with an appropriate Dart SDK '
-        'constraint', () async {
-      await package(
-        deps: {
-          'foo': {'sdk': 'flutter', 'version': '>=1.2.3 <2.0.0'},
+      await expectValidation(
+        environment: {
+          '_PUB_TEST_SDK_VERSION': '1.19.0',
+          'FLUTTER_ROOT': path.join(d.sandbox, 'flutter')
         },
-        sdk: '>=1.19.0 <2.0.0',
-      ).create();
-
-      await expectValidation();
+      );
     });
 
     test(
-        'depends on a package from Fuchsia with an appropriate Dart SDK '
-        'constraint', () async {
-      await package(sdk: '>=2.0.0-dev.51.0 <2.0.0', deps: {
-        'foo': {'sdk': 'fuchsia', 'version': '>=1.2.3 <2.0.0'}
-      }).create();
-      await d.validPackage.create();
+      'depends on a package from Flutter with an appropriate Dart SDK constraint',
+      () async {
+        await d.dir('flutter', [d.file('version', '1.2.3')]).create();
+        await flutterPackage('foo', sdk: '^1.0.0').create();
+        await d.dir('flutter', [d.file('version', '1.2.3')]).create();
+        await package(
+          deps: {
+            'foo': {'sdk': 'flutter', 'version': '>=1.2.3 <2.0.0'},
+          },
+          sdk: '>=1.19.0 <2.0.0',
+        ).create();
 
-      await expectValidation();
-    });
+        await expectValidation(
+          environment: {
+            '_PUB_TEST_SDK_VERSION': '1.19.0',
+            'FLUTTER_ROOT': path.join(d.sandbox, 'flutter'),
+          },
+        );
+      },
+    );
+
+    test(
+      'depends on a package from Fuchsia with an appropriate Dart SDK constraint',
+      () async {
+        await fuschiaPackage('foo', sdk: '>=2.0.0 <3.0.0').create();
+        await package(sdk: '>=2.0.0 <3.0.0', deps: {
+          'foo': {'sdk': 'fuchsia', 'version': '>=1.2.3 <2.0.0'}
+        }).create();
+
+        await expectValidation(environment: {
+          'FUCHSIA_DART_SDK_ROOT': path.join(d.sandbox, 'fuchsia'),
+          '_PUB_TEST_SDK_VERSION': '2.12.0',
+        });
+      },
+    );
   });
 
   group('should consider a package invalid if it', () {
     setUp(package().create);
-    group('has a git dependency', () {
-      group('where a hosted version exists', () {
-        test('and should suggest the hosted primary version', () async {
-          await setUpDependency({'git': 'git://github.com/dart-lang/foo'},
-              hostedVersions: ['3.0.0-pre', '2.0.0', '1.0.0']);
-          await expectValidationWarning('  foo: ^2.0.0');
-        });
-
-        test(
-            'and should suggest the hosted prerelease version if '
-            "it's the only version available", () async {
-          await setUpDependency({'git': 'git://github.com/dart-lang/foo'},
-              hostedVersions: ['3.0.0-pre', '2.0.0-pre']);
-          await expectValidationWarning('  foo: ^3.0.0-pre');
-        });
-
-        test(
-            'and should suggest a tighter constraint if primary is '
-            'pre-1.0.0', () async {
-          await setUpDependency({'git': 'git://github.com/dart-lang/foo'},
-              hostedVersions: ['0.0.1', '0.0.2']);
-          await expectValidationWarning('  foo: ^0.0.2');
-        });
-      });
-
-      group('where no hosted version exists', () {
-        test("and should use the other source's version", () async {
-          await setUpDependency({
-            'git': 'git://github.com/dart-lang/foo',
-            'version': '>=1.0.0 <2.0.0'
-          });
-          await expectValidationWarning('  foo: ">=1.0.0 <2.0.0"');
-        });
-
-        test(
-            "and should use the other source's unquoted version if "
-            'concrete', () async {
-          await setUpDependency(
-              {'git': 'git://github.com/dart-lang/foo', 'version': '0.2.3'});
-          await expectValidationWarning('  foo: 0.2.3');
-        });
-      });
-    });
 
     group('has a path dependency', () {
       group('where a hosted version exists', () {
         test('and should suggest the hosted primary version', () async {
+          await d.dir('foo', [
+            d.libPubspec('foo', '1.2.3', sdk: 'any'),
+          ]).create();
           await setUpDependency({'path': path.join(d.sandbox, 'foo')},
               hostedVersions: ['3.0.0-pre', '2.0.0', '1.0.0']);
-          await expectValidationError('  foo: ^2.0.0');
+          await expectValidationError(
+            '  foo: ^2.0.0',
+            environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'},
+          );
         });
 
         test(
             'and should suggest the hosted prerelease version if '
             "it's the only version available", () async {
-          await setUpDependency({'path': path.join(d.sandbox, 'foo')},
-              hostedVersions: ['3.0.0-pre', '2.0.0-pre']);
-          await expectValidationError('  foo: ^3.0.0-pre');
+          await d.dir('foo', [
+            d.libPubspec('foo', '1.2.3', sdk: 'any'),
+          ]).create();
+          await setUpDependency(
+            {'path': path.join(d.sandbox, 'foo')},
+            hostedVersions: ['3.0.0-pre', '2.0.0-pre'],
+          );
+          await expectValidationError(
+            '  foo: ^3.0.0-pre',
+            environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'},
+          );
         });
 
         test(
             'and should suggest a tighter constraint if primary is '
             'pre-1.0.0', () async {
-          await setUpDependency({'path': path.join(d.sandbox, 'foo')},
-              hostedVersions: ['0.0.1', '0.0.2']);
-          await expectValidationError('  foo: ^0.0.2');
+          await d.dir('foo', [
+            d.libPubspec('foo', '1.2.3', sdk: 'any'),
+          ]).create();
+          await setUpDependency(
+            {'path': path.join(d.sandbox, 'foo')},
+            hostedVersions: ['0.0.1', '0.0.2'],
+          );
+          await expectValidationError(
+            '  foo: ^0.0.2',
+            environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'},
+          );
         });
       });
 
       group('where no hosted version exists', () {
         test("and should use the other source's version", () async {
+          await d.dir('foo', [
+            d.libPubspec('foo', '1.2.3', sdk: 'any'),
+          ]).create();
           await setUpDependency({
             'path': path.join(d.sandbox, 'foo'),
             'version': '>=1.0.0 <2.0.0'
           });
-          await expectValidationError('  foo: ">=1.0.0 <2.0.0"');
+          await expectValidationError(
+            '  foo: ">=1.0.0 <2.0.0"',
+            environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'},
+          );
         });
 
         test(
             "and should use the other source's unquoted version if "
             'concrete', () async {
+          await d.dir('foo', [
+            d.libPubspec('foo', '0.2.3', sdk: '^1.8.0'),
+          ]).create();
           await setUpDependency(
               {'path': path.join(d.sandbox, 'foo'), 'version': '0.2.3'});
-          await expectValidationError('  foo: 0.2.3');
+          await expectValidationError(
+            '  foo: 0.2.3',
+            environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'},
+          );
         });
       });
     });
 
     group('has an unconstrained dependency', () {
-      group('and it should not suggest a version', () {
-        test("if there's no lockfile", () async {
-          await d.dir(appPath, [
-            d.libPubspec('test_pkg', '1.0.0', deps: {'foo': 'any'})
-          ]).create();
-
-          await expectValidationWarning(isNot(contains('\n  foo:')));
-        });
-
-        test("if the lockfile doesn't have an entry for the dependency",
-            () async {
-          await d.dir(appPath, [
-            d.libPubspec('test_pkg', '1.0.0', deps: {'foo': 'any'}),
-            d.file(
-                'pubspec.lock',
-                jsonEncode({
-                  'packages': {
-                    'bar': {
-                      'version': '1.2.3',
-                      'source': 'hosted',
-                      'description': {
-                        'name': 'bar',
-                        'url': 'http://pub.dartlang.org'
-                      }
-                    }
-                  }
-                }))
-          ]).create();
-
-          await expectValidationWarning(isNot(contains('\n  foo:')));
-        });
-      });
-
       group('with a lockfile', () {
         test(
             'and it should suggest a constraint based on the locked '
             'version', () async {
+          (await servePackages()).serve('foo', '1.2.3');
           await d.dir(appPath, [
             d.libPubspec('test_pkg', '1.0.0', deps: {'foo': 'any'}),
-            d.file(
-                'pubspec.lock',
-                jsonEncode({
-                  'packages': {
-                    'foo': {
-                      'version': '1.2.3',
-                      'source': 'hosted',
-                      'description': {
-                        'name': 'foo',
-                        'url': 'http://pub.dartlang.org'
-                      }
-                    }
-                  }
-                }))
           ]).create();
 
           await expectValidationWarning('  foo: ^1.2.3');
@@ -277,6 +261,8 @@
         test(
             'and it should suggest a concrete constraint if the locked '
             'version is pre-1.0.0', () async {
+          (await servePackages()).serve('foo', '0.1.2');
+
           await d.dir(appPath, [
             d.libPubspec('test_pkg', '1.0.0', deps: {'foo': 'any'}),
             d.file(
@@ -286,10 +272,7 @@
                     'foo': {
                       'version': '0.1.2',
                       'source': 'hosted',
-                      'description': {
-                        'name': 'foo',
-                        'url': 'http://pub.dartlang.org'
-                      }
+                      'description': {'name': 'foo', 'url': 'https://pub.dev'}
                     }
                   }
                 }))
@@ -301,20 +284,24 @@
     });
 
     test('with a dependency on a pre-release without being one', () async {
+      (await servePackages()).serve('foo', '1.2.3-dev');
+
       await d.dir(appPath, [
         d.libPubspec(
           'test_pkg',
           '1.0.0',
           deps: {'foo': '^1.2.3-dev'},
-          sdk: '>=1.19.0 <2.0.0',
+          sdk: '>=1.8.0 <2.0.0',
         )
       ]).create();
 
-      await expectValidationWarning('Packages dependent on a pre-release');
+      await expectValidationWarning('Packages dependent on a pre-release',
+          environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'});
     });
     test(
         'with a single-version dependency and it should suggest a '
         'constraint based on the version', () async {
+      (await servePackages()).serve('foo', '1.2.3');
       await d.dir(appPath, [
         d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '1.2.3'})
       ]).create();
@@ -323,116 +310,69 @@
     });
 
     group('has a dependency without a lower bound', () {
-      group('and it should not suggest a version', () {
-        test("if there's no lockfile", () async {
-          await d.dir(appPath, [
-            d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '<3.0.0'})
-          ]).create();
+      test(
+          'and it should suggest a constraint based on the locked '
+          'version', () async {
+        (await servePackages()).serve('foo', '1.2.3');
 
-          await expectValidationWarning(isNot(contains('\n  foo:')));
-        });
+        await d.dir(appPath, [
+          d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '<3.0.0'}),
+          d.file(
+            'pubspec.lock',
+          )
+        ]).create();
 
-        test(
-            "if the lockfile doesn't have an entry for the "
-            'dependency', () async {
-          await d.dir(appPath, [
-            d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '<3.0.0'}),
-            d.file(
-                'pubspec.lock',
-                jsonEncode({
-                  'packages': {
-                    'bar': {
-                      'version': '1.2.3',
-                      'source': 'hosted',
-                      'description': {
-                        'name': 'bar',
-                        'url': 'http://pub.dartlang.org'
-                      }
-                    }
-                  }
-                }))
-          ]).create();
-
-          await expectValidationWarning(isNot(contains('\n  foo:')));
-        });
+        await expectValidationWarning('  foo: ">=1.2.3 <3.0.0"');
       });
 
-      group('with a lockfile', () {
-        test(
-            'and it should suggest a constraint based on the locked '
-            'version', () async {
-          await d.dir(appPath, [
-            d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '<3.0.0'}),
-            d.file(
-                'pubspec.lock',
-                jsonEncode({
-                  'packages': {
-                    'foo': {
-                      'version': '1.2.3',
-                      'source': 'hosted',
-                      'description': {
-                        'name': 'foo',
-                        'url': 'http://pub.dartlang.org'
-                      }
-                    }
+      test('and it should preserve the upper-bound operator', () async {
+        (await servePackages()).serve('foo', '1.2.3');
+        await d.dir(appPath, [
+          d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '<=3.0.0'}),
+          d.file(
+              'pubspec.lock',
+              jsonEncode({
+                'packages': {
+                  'foo': {
+                    'version': '1.2.3',
+                    'source': 'hosted',
+                    'description': {'name': 'foo', 'url': 'https://pub.dev'}
                   }
-                }))
-          ]).create();
+                }
+              }))
+        ]).create();
 
-          await expectValidationWarning('  foo: ">=1.2.3 <3.0.0"');
-        });
+        await expectValidationWarning('  foo: ">=1.2.3 <=3.0.0"');
+      });
 
-        test('and it should preserve the upper-bound operator', () async {
-          await d.dir(appPath, [
-            d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '<=3.0.0'}),
-            d.file(
-                'pubspec.lock',
-                jsonEncode({
-                  'packages': {
-                    'foo': {
-                      'version': '1.2.3',
-                      'source': 'hosted',
-                      'description': {
-                        'name': 'foo',
-                        'url': 'http://pub.dartlang.org'
-                      }
-                    }
+      test(
+          'and it should expand the suggested constraint if the '
+          'locked version matches the upper bound', () async {
+        (await servePackages()).serve('foo', '1.2.3');
+
+        await d.dir(appPath, [
+          d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '<=1.2.3'}),
+          d.file(
+              'pubspec.lock',
+              jsonEncode({
+                'packages': {
+                  'foo': {
+                    'version': '1.2.3',
+                    'source': 'hosted',
+                    'description': {'name': 'foo', 'url': 'https://pub.dev'}
                   }
-                }))
-          ]).create();
+                }
+              }))
+        ]).create();
 
-          await expectValidationWarning('  foo: ">=1.2.3 <=3.0.0"');
-        });
-
-        test(
-            'and it should expand the suggested constraint if the '
-            'locked version matches the upper bound', () async {
-          await d.dir(appPath, [
-            d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '<=1.2.3'}),
-            d.file(
-                'pubspec.lock',
-                jsonEncode({
-                  'packages': {
-                    'foo': {
-                      'version': '1.2.3',
-                      'source': 'hosted',
-                      'description': {
-                        'name': 'foo',
-                        'url': 'http://pub.dartlang.org'
-                      }
-                    }
-                  }
-                }))
-          ]).create();
-
-          await expectValidationWarning('  foo: ^1.2.3');
-        });
+        await expectValidationWarning('  foo: ^1.2.3');
       });
     });
 
     group('with a dependency without an upper bound', () {
       test('and it should suggest a constraint based on the lower bound',
           () async {
+        (await servePackages()).serve('foo', '1.2.3');
         await d.dir(appPath, [
           d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '>=1.2.3'})
         ]).create();
@@ -441,6 +381,7 @@
       });
 
       test('and it should preserve the lower-bound operator', () async {
+        (await servePackages()).serve('foo', '1.2.4');
         await d.dir(appPath, [
           d.libPubspec('test_pkg', '1.0.0', deps: {'foo': '>1.2.3'})
         ]).create();
@@ -450,21 +391,17 @@
     });
 
     group('has a ^ dependency', () {
-      test('without an SDK constraint', () async {
-        await d.dir(appPath, [
-          d.libPubspec('integration_pkg', '1.0.0', deps: {'foo': '^1.2.3'})
-        ]).create();
-
-        await expectValidationError('  sdk: ">=1.8.0 <2.0.0"');
-      });
-
       test('with a too-broad SDK constraint', () async {
+        (await servePackages()).serve('foo', '1.2.3');
         await d.dir(appPath, [
           d.libPubspec('test_pkg', '1.0.0',
               deps: {'foo': '^1.2.3'}, sdk: '>=1.5.0 <2.0.0')
         ]).create();
 
-        await expectValidationError('  sdk: ">=1.8.0 <2.0.0"');
+        await expectValidationError(
+          '  sdk: ">=1.8.0 <2.0.0"',
+          environment: {'_PUB_TEST_SDK_VERSION': '1.5.0'},
+        );
       });
     });
 
@@ -472,17 +409,22 @@
       test('without an SDK constraint', () async {
         // Ensure we don't report anything from the real pub.dev.
         await setUpDependency({});
+        await d.git('foo', [
+          d.dir('subdir', [d.libPubspec('foo', '1.0.0')]),
+        ]).create();
         await d.dir(appPath, [
           d.libPubspec('integration_pkg', '1.0.0', deps: {
             'foo': {
-              'git': {'url': 'git://github.com/dart-lang/foo', 'path': 'subdir'}
+              'git': {'url': d.path('foo'), 'path': 'subdir'}
             }
           })
         ]).create();
 
         await expectValidation(
           error: allOf(
-              contains('  sdk: ">=2.0.0 <3.0.0"'), contains('  foo: any')),
+            contains('  sdk: ">=2.0.0 <3.0.0"'),
+            contains('  foo: any'),
+          ),
           exitCode: DATA,
         );
       });
@@ -490,14 +432,15 @@
       test('with a too-broad SDK constraint', () async {
         // Ensure we don't report anything from the real pub.dev.
         await setUpDependency({});
+        await d.git('foo', [
+          d.dir(
+              'subdir', [d.libPubspec('foo', '1.0.0', sdk: '>=0.0.0 <3.0.0')]),
+        ]).create();
         await d.dir(appPath, [
           d.libPubspec('integration_pkg', '1.0.0',
               deps: {
                 'foo': {
-                  'git': {
-                    'url': 'git://github.com/dart-lang/foo',
-                    'path': 'subdir'
-                  }
+                  'git': {'url': d.path('foo'), 'path': 'subdir'}
                 }
               },
               sdk: '>=1.24.0 <3.0.0')
@@ -508,12 +451,14 @@
             contains('  sdk: ">=2.0.0 <3.0.0"'),
             contains('  foo: any'),
           ]),
+          environment: {'_PUB_TEST_SDK_VERSION': '1.24.0'},
           exitCode: DATA,
         );
       });
     });
 
     test('depends on Flutter from a non-SDK source', () async {
+      (await servePackages()).serve('flutter', '1.5.0');
       await d.dir(appPath, [
         d.libPubspec('test_pkg', '1.0.0', deps: {'flutter': '>=1.2.3 <2.0.0'})
       ]).create();
@@ -521,16 +466,10 @@
       await expectValidationError('sdk: >=1.2.3 <2.0.0');
     });
 
-    test('depends on a Flutter package from an unknown SDK', () async {
-      await package(deps: {
-        'foo': {'sdk': 'fblthp', 'version': '>=1.2.3 <2.0.0'}
-      }).create();
-
-      await expectValidationError('Unknown SDK "fblthp" for dependency "foo".');
-    });
-
     test('depends on a Flutter package with a too-broad SDK constraint',
         () async {
+      await d.dir('flutter', [d.file('version', '1.2.3')]).create();
+      await flutterPackage('foo', sdk: 'any').create();
       await package(
         deps: {
           'foo': {'sdk': 'flutter', 'version': '>=1.2.3 <2.0.0'}
@@ -538,35 +477,79 @@
         sdk: '>=1.18.0 <2.0.0',
       ).create();
 
-      await expectValidationError('sdk: ">=1.19.0 <2.0.0"');
+      await expectValidationError('sdk: ">=1.19.0 <2.0.0"', environment: {
+        '_PUB_TEST_SDK_VERSION': '1.19.0',
+        'FLUTTER_ROOT': path.join(d.sandbox, 'flutter'),
+      });
     });
 
     test('depends on a Flutter package with no SDK constraint', () async {
+      await d.dir('flutter', [d.file('version', '1.2.3')]).create();
+      await flutterPackage('foo', sdk: '>=0.0.0 <1.0.0').create();
       await package(sdk: '>=0.0.0 <=0.0.1', deps: {
         'foo': {'sdk': 'flutter', 'version': '>=1.2.3 <2.0.0'}
       }).create();
 
-      await expectValidationError('sdk: ">=1.19.0 <2.0.0"');
+      await expectValidationError(
+        'sdk: ">=1.19.0 <2.0.0"',
+        environment: {
+          '_PUB_TEST_SDK_VERSION': '0.0.0',
+          'FLUTTER_ROOT': path.join(d.sandbox, 'flutter'),
+        },
+      );
     });
 
     test('depends on a Fuchsia package with a too-broad SDK constraint',
         () async {
+      await fuschiaPackage('foo', sdk: '>=0.0.0 <3.0.0').create();
+
       await package(
-        sdk: '>=2.0.0-dev.50.0 <2.0.0',
+        sdk: '>=2.0.0-dev.50.0 <2.0.1',
         deps: {
           'foo': {'sdk': 'fuchsia', 'version': '>=1.2.3 <2.0.0'}
         },
       ).create();
 
-      await expectValidationError('sdk: ">=2.0.0 <3.0.0"');
+      await expectValidationError('sdk: ">=2.0.0 <2.0.1"', environment: {
+        'FUCHSIA_DART_SDK_ROOT': path.join(d.sandbox, 'fuchsia'),
+        '_PUB_TEST_SDK_VERSION': '2.0.1-dev.51.0',
+      });
     });
 
     test('depends on a Fuchsia package with no SDK constraint', () async {
+      await fuschiaPackage('foo').create();
       await package(sdk: '>=0.0.0 <1.0.0', deps: {
         'foo': {'sdk': 'fuchsia', 'version': '>=1.2.3 <2.0.0'}
       }).create();
 
-      await expectValidationError('sdk: ">=2.0.0 <3.0.0"');
+      await expectValidationError(
+        'sdk: ">=2.0.0 <3.0.0"',
+        environment: {'FUCHSIA_DART_SDK_ROOT': path.join(d.sandbox, 'fuchsia')},
+      );
     });
   });
 }
+
+d.Descriptor fuschiaPackage(String name,
+    {Map<String, String> deps = const {}, String? sdk}) {
+  return d.dir('fuchsia', [
+    d.dir('packages', [
+      d.dir(name, [
+        d.libDir(name, 'f(x) => 2 * x;'),
+        d.libPubspec(name, '1.5.0', deps: deps, sdk: sdk),
+      ]),
+    ]),
+  ]);
+}
+
+d.Descriptor flutterPackage(String name,
+    {Map<String, String> deps = const {}, String? sdk}) {
+  return d.dir('flutter', [
+    d.dir('packages', [
+      d.dir(name, [
+        d.libDir(name, 'f(x) => 2 * x;'),
+        d.libPubspec(name, '1.5.0', deps: deps, sdk: sdk),
+      ]),
+    ]),
+  ]);
+}
diff --git a/test/validator/flutter_constraint_test.dart b/test/validator/flutter_constraint_test.dart
index b7bdf7c..9e73ef6 100644
--- a/test/validator/flutter_constraint_test.dart
+++ b/test/validator/flutter_constraint_test.dart
@@ -11,17 +11,21 @@
   await runPub(
     error: error,
     args: ['publish', '--dry-run'],
-    environment: {'_PUB_TEST_SDK_VERSION': '2.12.0'},
+    environment: {
+      '_PUB_TEST_SDK_VERSION': '2.12.0',
+      'FLUTTER_ROOT': fakeFlutterRoot.io.path,
+    },
     workingDirectory: d.path(appPath),
     exitCode: exitCode,
   );
 }
 
+late d.DirectoryDescriptor fakeFlutterRoot;
+
 Future<void> setup({
   String? flutterConstraint,
 }) async {
-  final fakeFlutterRoot =
-      d.dir('fake_flutter_root', [d.file('version', '1.23.0')]);
+  fakeFlutterRoot = d.dir('fake_flutter_root', [d.file('version', '1.23.0')]);
   await fakeFlutterRoot.create();
   await d.validPackage.create();
   await d.dir(appPath, [
diff --git a/test/validator/gitignore_test.dart b/test/validator/gitignore_test.dart
index 3cd4a11..f4ec65c 100644
--- a/test/validator/gitignore_test.dart
+++ b/test/validator/gitignore_test.dart
@@ -20,7 +20,7 @@
   await runPub(
     error: error,
     args: ['publish', '--dry-run'],
-    environment: {'_PUB_TEST_SDK_VERSION': '2.12.0', ...environment},
+    environment: environment,
     workingDirectory: workingDirectory ?? d.path(appPath),
     exitCode: exitCode,
   );
@@ -35,8 +35,6 @@
       d.file('foo.txt'),
     ]).create();
 
-    await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'});
-
     await expectValidation(contains('Package has 0 warnings.'), 0);
 
     await d.dir('myapp', [
@@ -60,7 +58,7 @@
       d.file('foo.txt'),
     ]).create();
 
-    await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'});
+    await pubGet();
     await setUpFakeGitScript(bash: 'echo "Not git"', batch: 'echo "Not git"');
     await expectValidation(
         allOf([contains('Package has 0 warnings.')]), exit_codes.SUCCESS,
@@ -78,9 +76,7 @@
       ),
     ]).create();
     final packageRoot = p.join(d.sandbox, 'reporoot', 'myapp');
-    await pubGet(
-        environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'},
-        workingDirectory: packageRoot);
+    await pubGet(workingDirectory: packageRoot);
 
     await expectValidation(contains('Package has 0 warnings.'), 0,
         workingDirectory: packageRoot);
@@ -105,9 +101,7 @@
       ...d.validPackage.contents,
     ]).create();
     final packageRoot = p.join(d.sandbox, 'myapp');
-    await pubGet(
-        environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'},
-        workingDirectory: packageRoot);
+    await pubGet(workingDirectory: packageRoot);
 
     Link(p.join(packageRoot, '.abc', 'itself')).createSync(
       packageRoot,
diff --git a/test/validator/pubspec_field_test.dart b/test/validator/pubspec_field_test.dart
index 43db483..cd205ef 100644
--- a/test/validator/pubspec_field_test.dart
+++ b/test/validator/pubspec_field_test.dart
@@ -20,7 +20,7 @@
 
     test('has an HTTPS homepage URL', () async {
       var pkg = packageMap('test_pkg', '1.0.0');
-      pkg['homepage'] = 'https://pub.dartlang.org';
+      pkg['homepage'] = 'https://pub.dev';
       await d.dir(appPath, [d.pubspec(pkg)]).create();
 
       await expectValidation(pubspecField);
@@ -29,7 +29,7 @@
     test('has an HTTPS repository URL instead of homepage', () async {
       var pkg = packageMap('test_pkg', '1.0.0');
       pkg.remove('homepage');
-      pkg['repository'] = 'https://pub.dartlang.org';
+      pkg['repository'] = 'https://pub.dev';
       await d.dir(appPath, [d.pubspec(pkg)]).create();
 
       await expectValidation(pubspecField);
@@ -37,7 +37,7 @@
 
     test('has an HTTPS documentation URL', () async {
       var pkg = packageMap('test_pkg', '1.0.0');
-      pkg['documentation'] = 'https://pub.dartlang.org';
+      pkg['documentation'] = 'https://pub.dev';
       await d.dir(appPath, [d.pubspec(pkg)]).create();
 
       await expectValidation(pubspecField);
diff --git a/test/validator/readme_test.dart b/test/validator/readme_test.dart
index 17b0602..934feae 100644
--- a/test/validator/readme_test.dart
+++ b/test/validator/readme_test.dart
@@ -15,8 +15,6 @@
 Validator readme() => ReadmeValidator();
 
 void main() {
-  setUp(d.validPackage.create);
-
   group('should consider a package valid if it', () {
     test('looks normal', () async {
       await d.validPackage.create();
diff --git a/test/version_solver_test.dart b/test/version_solver_test.dart
index 128ed73..69489a3 100644
--- a/test/version_solver_test.dart
+++ b/test/version_solver_test.dart
@@ -2911,7 +2911,7 @@
     if (description is HostedDescription &&
         (description.url == SystemCache().hosted.defaultUrl)) {
       // If the dep uses the default hosted source, grab it from the test
-      // package server rather than pub.dartlang.org.
+      // package server rather than pub.dev.
       dep = cache.hosted
           .refFor(dep.name, url: globalServer.url)
           .withConstraint(dep.constraint);