Add missing await (and make downstream async) (#3949)

diff --git a/lib/src/command/deps.dart b/lib/src/command/deps.dart
index 73f482c..e082b14 100644
--- a/lib/src/command/deps.dart
+++ b/lib/src/command/deps.dart
@@ -93,11 +93,13 @@
       final visited = <String>[];
       final toVisit = [entrypoint.root.name];
       final packagesJson = <dynamic>[];
+      final graph = await entrypoint.packageGraph;
       while (toVisit.isNotEmpty) {
         final current = toVisit.removeLast();
         if (visited.contains(current)) continue;
         visited.add(current);
-        final currentPackage = entrypoint.packageGraph.packages[current]!;
+        final currentPackage =
+            (await entrypoint.packageGraph).packages[current]!;
         final next = (current == entrypoint.root.name
                 ? entrypoint.root.immediateDependencies
                 : currentPackage.dependencies)
@@ -126,7 +128,7 @@
         for (final package in [
           entrypoint.root,
           ...entrypoint.root.immediateDependencies.keys
-              .map((name) => entrypoint.packageGraph.packages[name]),
+              .map((name) => graph.packages[name]),
         ])
           ...package!.executableNames.map(
             (name) => package == entrypoint.root
@@ -151,7 +153,7 @@
       );
     } else {
       if (argResults.flag('executables')) {
-        _outputExecutables(buffer);
+        await _outputExecutables(buffer);
       } else {
         for (var sdk in sdks.values) {
           if (!sdk.isAvailable) continue;
@@ -162,13 +164,13 @@
 
         switch (argResults['style']) {
           case 'compact':
-            _outputCompact(buffer);
+            await _outputCompact(buffer);
             break;
           case 'list':
-            _outputList(buffer);
+            await _outputList(buffer);
             break;
           case 'tree':
-            _outputTree(buffer);
+            await _outputTree(buffer);
             break;
         }
       }
@@ -183,40 +185,44 @@
   /// For each dependency listed, *that* package's immediate dependencies are
   /// shown. Unlike [_outputList], this prints all of these dependencies on one
   /// line.
-  void _outputCompact(
+  Future<void> _outputCompact(
     StringBuffer buffer,
-  ) {
+  ) async {
     var root = entrypoint.root;
-    _outputCompactPackages('dependencies', root.dependencies.keys, buffer);
+    await _outputCompactPackages(
+      'dependencies',
+      root.dependencies.keys,
+      buffer,
+    );
     if (_includeDev) {
-      _outputCompactPackages(
+      await _outputCompactPackages(
         'dev dependencies',
         root.devDependencies.keys,
         buffer,
       );
     }
-    _outputCompactPackages(
+    await _outputCompactPackages(
       'dependency overrides',
       root.dependencyOverrides.keys,
       buffer,
     );
 
-    var transitive = _getTransitiveDependencies();
-    _outputCompactPackages('transitive dependencies', transitive, buffer);
+    var transitive = await _getTransitiveDependencies();
+    await _outputCompactPackages('transitive dependencies', transitive, buffer);
   }
 
   /// Outputs one section of packages in the compact output.
-  void _outputCompactPackages(
+  Future<void> _outputCompactPackages(
     String section,
     Iterable<String> names,
     StringBuffer buffer,
-  ) {
+  ) async {
     if (names.isEmpty) return;
 
     buffer.writeln();
     buffer.writeln('$section:');
     for (var name in ordered(names)) {
-      var package = _getPackage(name);
+      var package = await _getPackage(name);
 
       buffer.write('- ${_labelPackage(package)}');
       if (package.dependencies.isEmpty) {
@@ -234,37 +240,45 @@
   ///
   /// For each dependency listed, *that* package's immediate dependencies are
   /// shown.
-  void _outputList(StringBuffer buffer) {
+  Future<void> _outputList(StringBuffer buffer) async {
     var root = entrypoint.root;
-    _outputListSection('dependencies', root.dependencies.keys, buffer);
+    await _outputListSection('dependencies', root.dependencies.keys, buffer);
     if (_includeDev) {
-      _outputListSection('dev dependencies', root.devDependencies.keys, buffer);
+      await _outputListSection(
+        'dev dependencies',
+        root.devDependencies.keys,
+        buffer,
+      );
     }
-    _outputListSection(
+    await _outputListSection(
       'dependency overrides',
       root.dependencyOverrides.keys,
       buffer,
     );
 
-    var transitive = _getTransitiveDependencies();
+    var transitive = await _getTransitiveDependencies();
     if (transitive.isEmpty) return;
 
-    _outputListSection('transitive dependencies', ordered(transitive), buffer);
+    await _outputListSection(
+      'transitive dependencies',
+      ordered(transitive),
+      buffer,
+    );
   }
 
   /// Outputs one section of packages in the list output.
-  void _outputListSection(
+  Future<void> _outputListSection(
     String name,
     Iterable<String> deps,
     StringBuffer buffer,
-  ) {
+  ) async {
     if (deps.isEmpty) return;
 
     buffer.writeln();
     buffer.writeln('$name:');
 
     for (var name in deps) {
-      var package = _getPackage(name);
+      var package = await _getPackage(name);
       buffer.writeln('- ${_labelPackage(package)}');
 
       for (var dep in package.dependencies.values) {
@@ -279,9 +293,9 @@
   /// dependency), later ones are not traversed. This is done in breadth-first
   /// fashion so that a package will always be expanded at the shallowest
   /// depth that it appears at.
-  void _outputTree(
+  Future<void> _outputTree(
     StringBuffer buffer,
-  ) {
+  ) async {
     // The work list for the breadth-first traversal. It contains the package
     // being added to the tree, and the parent map that will receive that
     // package.
@@ -296,7 +310,7 @@
       immediateDependencies.removeAll(entrypoint.root.devDependencies.keys);
     }
     for (var name in immediateDependencies) {
-      toWalk.add(Pair(_getPackage(name), packageTree));
+      toWalk.add(Pair(await _getPackage(name), packageTree));
     }
 
     // Do a breadth-first walk to the dependency graph.
@@ -317,7 +331,7 @@
       map[_labelPackage(package)] = childMap;
 
       for (var dep in package.dependencies.values) {
-        toWalk.add(Pair(_getPackage(dep.name), childMap));
+        toWalk.add(Pair(await _getPackage(dep.name), childMap));
       }
     }
 
@@ -328,8 +342,8 @@
       '${log.bold(package.name)} ${package.version}';
 
   /// Gets the names of the non-immediate dependencies of the root package.
-  Set<String> _getTransitiveDependencies() {
-    var transitive = _getAllDependencies();
+  Future<Set<String>> _getTransitiveDependencies() async {
+    var transitive = await _getAllDependencies();
     var root = entrypoint.root;
     transitive.remove(root.name);
     transitive.removeAll(root.dependencies.keys);
@@ -340,13 +354,16 @@
     return transitive;
   }
 
-  Set<String> _getAllDependencies() {
-    if (_includeDev) return entrypoint.packageGraph.packages.keys.toSet();
+  Future<Set<String>> _getAllDependencies() async {
+    final graph = await entrypoint.packageGraph;
+    if (_includeDev) {
+      return graph.packages.keys.toSet();
+    }
 
     var nonDevDependencies = entrypoint.root.dependencies.keys.toList()
       ..addAll(entrypoint.root.dependencyOverrides.keys);
     return nonDevDependencies
-        .expand((name) => entrypoint.packageGraph.transitiveDependencies(name))
+        .expand(graph.transitiveDependencies)
         .map((package) => package.name)
         .toSet();
   }
@@ -357,22 +374,23 @@
   /// It's very unlikely that the lockfile won't be up-to-date with the pubspec,
   /// but it's possible, since [Entrypoint.assertUpToDate]'s modification time
   /// check can return a false negative. This fails gracefully if that happens.
-  Package _getPackage(String name) {
-    var package = entrypoint.packageGraph.packages[name];
+  Future<Package> _getPackage(String name) async {
+    var package = (await entrypoint.packageGraph).packages[name];
     if (package != null) return package;
     dataError('The pubspec.yaml file has changed since the pubspec.lock file '
         'was generated, please run "$topLevelProgram pub get" again.');
   }
 
   /// Outputs all executables reachable from [entrypoint].
-  void _outputExecutables(StringBuffer buffer) {
+  Future<void> _outputExecutables(StringBuffer buffer) async {
+    final graph = await entrypoint.packageGraph;
     var packages = [
       entrypoint.root,
       ...(_includeDev
               ? entrypoint.root.immediateDependencies
               : entrypoint.root.dependencies)
           .keys
-          .map((name) => entrypoint.packageGraph.packages[name]!),
+          .map((name) => graph.packages[name]!),
     ];
 
     for (var package in packages) {
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index b38589d..ca4d6a7 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -167,10 +167,14 @@
   ///
   /// Throws a [DataError] if the `.dart_tool/package_config.json` file isn't
   /// up-to-date relative to the pubspec and the lockfile.
-  PackageGraph get packageGraph => _packageGraph ??= _createPackageGraph();
+  Future<PackageGraph> get packageGraph =>
+      _packageGraph ??= _createPackageGraph();
 
-  PackageGraph _createPackageGraph() {
-    ensureUpToDate(); // TODO, really?
+  Future<PackageGraph> _createPackageGraph() async {
+    // TODO(sigurdm): consider having [ensureUptoDate] and [AcquireDependencies]
+    // return the package-graph, such it by construction will always made from an
+    // up-to-date package-config.
+    await ensureUpToDate();
     var packages = {
       for (var packageEntry in packageConfig.nonInjectedPackages)
         packageEntry.name: Package.load(
@@ -184,7 +188,7 @@
     return PackageGraph(this, packages);
   }
 
-  PackageGraph? _packageGraph;
+  Future<PackageGraph>? _packageGraph;
 
   /// Where the lock file and package configurations are to be found.
   ///
@@ -275,7 +279,8 @@
     SolveResult? solveResult,
   }) : rootDir = _root.dir {
     if (solveResult != null) {
-      _packageGraph = PackageGraph.fromSolveResult(this, solveResult);
+      _packageGraph =
+          Future.value(PackageGraph.fromSolveResult(this, solveResult));
     }
   }
 
@@ -421,7 +426,7 @@
 
       /// Build a package graph from the version solver results so we don't
       /// have to reload and reparse all the pubspecs.
-      _packageGraph = PackageGraph.fromSolveResult(this, result);
+      _packageGraph = Future.value(PackageGraph.fromSolveResult(this, result));
 
       await writePackageConfigFile();
 
@@ -429,7 +434,7 @@
         if (precompile) {
           await precompileExecutables();
         } else {
-          _deleteExecutableSnapshots(changed: result.changedPackages);
+          await _deleteExecutableSnapshots(changed: result.changedPackages);
         }
       } catch (error, stackTrace) {
         // Just log exceptions here. Since the method is just about acquiring
@@ -446,7 +451,7 @@
   ///
   /// Except globally activated packages they should precompile executables from
   /// the package itself if they are immutable.
-  List<Executable> get _builtExecutables {
+  Future<List<Executable>> get _builtExecutables async {
     if (isGlobal) {
       if (isCached) {
         return root.executablePaths
@@ -456,8 +461,9 @@
         return <Executable>[];
       }
     }
+    final graph = await packageGraph;
     final r = root.immediateDependencies.keys.expand((packageName) {
-      final package = packageGraph.packages[packageName]!;
+      final package = graph.packages[packageName]!;
       return package.executablePaths
           .map((path) => Executable(packageName, path));
     }).toList();
@@ -466,7 +472,7 @@
 
   /// Precompiles all [_builtExecutables].
   Future<void> precompileExecutables() async {
-    final executables = _builtExecutables;
+    final executables = await _builtExecutables;
 
     if (executables.isEmpty) return;
 
@@ -524,7 +530,7 @@
     final package = executable.package;
 
     await dart.precompile(
-      executablePath: resolveExecutable(executable),
+      executablePath: await resolveExecutable(executable),
       outputPath: pathOfExecutable(executable),
       incrementalDillPath: incrementalDillPathOfExecutable(executable),
       packageConfigPath: packageConfigPath,
@@ -572,9 +578,9 @@
   }
 
   /// The absolute path of [executable] resolved relative to [this].
-  String resolveExecutable(Executable executable) {
+  Future<String> resolveExecutable(Executable executable) async {
     return p.join(
-      packageGraph.packages[executable.package]!.dir,
+      (await packageGraph).packages[executable.package]!.dir,
       executable.relativePath,
     );
   }
@@ -583,7 +589,7 @@
   ///
   /// If [changed] is passed, only dependencies whose contents might be changed
   /// if one of the given packages changes will have their executables deleted.
-  void _deleteExecutableSnapshots({Iterable<String>? changed}) {
+  Future<void> _deleteExecutableSnapshots({Iterable<String>? changed}) async {
     if (!dirExists(_snapshotPath)) return;
 
     // If we don't know what changed, we can't safely re-use any snapshots.
@@ -603,15 +609,15 @@
       deleteEntry(_snapshotPath);
       return;
     }
+    final graph = await packageGraph;
 
     // Clean out any outdated snapshots.
     for (var entry in listDir(_snapshotPath)) {
       if (!dirExists(entry)) continue;
-
       var package = p.basename(entry);
-      if (!packageGraph.packages.containsKey(package) ||
-          packageGraph.isPackageMutable(package) ||
-          packageGraph
+      if (!graph.packages.containsKey(package) ||
+          graph.isPackageMutable(package) ||
+          graph
               .transitiveDependencies(package)
               .any((dep) => changedDeps.contains(dep.name))) {
         deleteEntry(entry);
diff --git a/lib/src/executable.dart b/lib/src/executable.dart
index 5789665..b54397f 100644
--- a/lib/src/executable.dart
+++ b/lib/src/executable.dart
@@ -57,7 +57,7 @@
   // entrypoint itself.
   if (entrypoint.root.name != executable.package &&
       !entrypoint.root.immediateDependencies.containsKey(package)) {
-    if (entrypoint.packageGraph.packages.containsKey(package)) {
+    if ((await entrypoint.packageGraph).packages.containsKey(package)) {
       dataError('Package "$package" is not an immediate dependency.\n'
           'Cannot run executables in transitive dependencies.');
     } else {
@@ -76,7 +76,7 @@
   // later invocation.
   var useSnapshot = vmArgs.isEmpty;
 
-  var executablePath = entrypoint.resolveExecutable(executable);
+  var executablePath = await entrypoint.resolveExecutable(executable);
   if (!fileExists(executablePath)) {
     var message =
         'Could not find ${log.bold(p.normalize(executable.relativePath))}';
@@ -93,7 +93,7 @@
     await entrypoint.ensureUpToDate();
 
     if (!fileExists(snapshotPath) ||
-        entrypoint.packageGraph.isPackageMutable(package)) {
+        (await entrypoint.packageGraph).isPackageMutable(package)) {
       await recompile(executable);
     }
     executablePath = snapshotPath;
@@ -349,7 +349,7 @@
   }
   final executable = Executable(package, p.join('bin', '$command.dart'));
 
-  final path = entrypoint.resolveExecutable(executable);
+  final path = await entrypoint.resolveExecutable(executable);
   if (!fileExists(path)) {
     throw CommandResolutionFailedException._(
       'Could not find `bin${p.separator}$command.dart` in package `$package`.',
@@ -366,7 +366,7 @@
   } else {
     final snapshotPath = entrypoint.pathOfExecutable(executable);
     if (!fileExists(snapshotPath) ||
-        entrypoint.packageGraph.isPackageMutable(package)) {
+        (await entrypoint.packageGraph).isPackageMutable(package)) {
       try {
         await errorsOnlyUnlessTerminal(
           () => entrypoint.precompileExecutable(