Version 2.15.0-49.0.dev

Merge commit 'b54269e2551608a388f11eb6ccd21a7c41d9b529' into 'dev'
diff --git a/DEPS b/DEPS
index 5552294..ed209a5 100644
--- a/DEPS
+++ b/DEPS
@@ -140,7 +140,7 @@
   "pool_rev": "7abe634002a1ba8a0928eded086062f1307ccfae",
   "process_rev": "56ece43b53b64c63ae51ec184b76bd5360c28d0b",
   "protobuf_rev": "c1eb6cb51af39ccbaa1a8e19349546586a5c8e31",
-  "pub_rev": "9f2ddc02f066c68fb638ff65fbb73761ece23267",
+  "pub_rev": "cd7a43f2109f7e5eb22e73c7f4e15d25fd57598e",
   "pub_semver_rev": "f50d80ef10c4b2fa5f4c8878036a4d9342c0cc82",
   "resource_rev": "6b79867d0becf5395e5819a75720963b8298e9a7",
   "root_certificates_rev": "692f6d6488af68e0121317a9c2c9eb393eb0ee50",
diff --git a/codereview.settings b/codereview.settings
index fe2e4e9..e950dfc 100644
--- a/codereview.settings
+++ b/codereview.settings
@@ -3,3 +3,4 @@
 CODE_REVIEW_SERVER: https://dart-review.googlesource.com
 VIEW_VC: https://dart.googlesource.com/sdk/+
 CC_LIST: reviews@dartlang.org
+USE_PYTHON3: True
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index fefffae..c50d7d0 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -15,6 +15,7 @@
 import 'package:meta/meta.dart';
 import 'package:pedantic/pedantic.dart';
 import 'package:pub/pub.dart';
+
 import 'package:usage/usage.dart';
 
 import 'src/analytics.dart';
@@ -36,6 +37,15 @@
 /// analytics logic, it has been moved here.
 Future<void> runDartdev(List<String> args, SendPort port) async {
   VmInteropHandler.initialize(port);
+
+  // TODO(sigurdm): Remove when top-level pub is removed.
+  if (args[0] == '__deprecated_pub') {
+    // This is the entry-point supporting the top-level `pub` script.
+    // ignore: deprecated_member_use
+    VmInteropHandler.exit(await deprecatedpubCommand().run(args.skip(1)));
+    return;
+  }
+
   if (args.contains('run')) {
     // These flags have a format that can't be handled by package:args, so while
     // they are valid flags we'll assume the VM has verified them by this point.
diff --git a/pkg/dartdev/lib/src/commands/create.dart b/pkg/dartdev/lib/src/commands/create.dart
index da41f79..9819614 100644
--- a/pkg/dartdev/lib/src/commands/create.dart
+++ b/pkg/dartdev/lib/src/commands/create.dart
@@ -102,14 +102,11 @@
     );
 
     if (argResults['pub']) {
-      if (!Sdk.checkArtifactExists(sdk.pubSnapshot)) {
-        return 255;
-      }
       log.stdout('');
       var progress = log.progress('Running pub get');
       var process = await startDartProcess(
         sdk,
-        [sdk.pubSnapshot, 'get', '--no-precompile'],
+        ['pub', 'get'],
         cwd: dir,
       );
 
diff --git a/pkg/dartdev/lib/src/sdk.dart b/pkg/dartdev/lib/src/sdk.dart
index 833df09..dde3acf 100644
--- a/pkg/dartdev/lib/src/sdk.dart
+++ b/pkg/dartdev/lib/src/sdk.dart
@@ -78,13 +78,6 @@
         'devtools',
       );
 
-  String get pubSnapshot => path.absolute(
-        sdkPath,
-        'bin',
-        'snapshots',
-        'pub.dart.snapshot',
-      );
-
   static bool checkArtifactExists(String path) {
     if (!File(path).existsSync()) {
       log.stderr('Could not find $path. Have you built the full '
diff --git a/pkg/dartdev/test/analytics_test.dart b/pkg/dartdev/test/analytics_test.dart
index 83050f7..b3e1f8b 100644
--- a/pkg/dartdev/test/analytics_test.dart
+++ b/pkg/dartdev/test/analytics_test.dart
@@ -99,7 +99,8 @@
     });
     test('create', () {
       final p = project(logAnalytics: true);
-      final result = p.runSync(['create', '-tpackage-simple', 'name']);
+      final result =
+          p.runSync(['create', '--no-pub', '-tpackage-simple', 'name']);
       expect(extractAnalytics(result), [
         {
           'hitType': 'screenView',
@@ -113,7 +114,7 @@
             'label': null,
             'value': null,
             'cd1': '0',
-            'cd3': ' template ',
+            'cd3': ' pub template ',
           }
         },
         {
diff --git a/pkg/dartdev/test/sdk_test.dart b/pkg/dartdev/test/sdk_test.dart
index 2f0acab..34dbfc7 100644
--- a/pkg/dartdev/test/sdk_test.dart
+++ b/pkg/dartdev/test/sdk_test.dart
@@ -25,10 +25,6 @@
     expectFileExists(Sdk().analysisServerSnapshot);
   });
 
-  test('pub snapshot', () {
-    expectFileExists(Sdk().pubSnapshot);
-  });
-
   test('dds snapshot', () {
     expectFileExists(Sdk().ddsSnapshot);
   });
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 1e568ba..ea6bf68 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -1079,7 +1079,7 @@
 rs
 runnable
 s
-sand
+sandboxed
 sanitizing
 saw
 say
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 6ec4b57..89c8686 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -820,7 +820,7 @@
 rows
 runtimes
 rv
-sand
+sandboxed
 saves
 scans
 scheduler
diff --git a/pkg/front_end/tool/ast_model.dart b/pkg/front_end/tool/ast_model.dart
index a0708e4..ae209a2 100644
--- a/pkg/front_end/tool/ast_model.dart
+++ b/pkg/front_end/tool/ast_model.dart
@@ -505,17 +505,24 @@
 ///
 /// If [printDump] is `true`, a dump of the model printed to stdout.
 Future<AstModel> deriveAstModel(Uri repoDir, {bool printDump: false}) async {
+  bool errorsFound = false;
   CompilerOptions options = new CompilerOptions();
   options.sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
   options.packagesFileUri = computePackageConfig(repoDir);
   options.onDiagnostic = (DiagnosticMessage message) {
     printDiagnosticMessage(message, print);
+    if (message.severity == Severity.error) {
+      errorsFound = true;
+    }
   };
 
   InternalCompilerResult compilerResult = (await kernelForProgramInternal(
       astLibraryUri, options,
       retainDataForTesting: true,
       requireMain: false)) as InternalCompilerResult;
+  if (errorsFound) {
+    throw 'Errors found';
+  }
   ClassHierarchy classHierarchy = compilerResult.classHierarchy!;
   CoreTypes coreTypes = compilerResult.coreTypes!;
   TypeEnvironment typeEnvironment =
@@ -524,7 +531,6 @@
   Library astLibrary = compilerResult.component!.libraries
       .singleWhere((library) => library.importUri == astLibraryUri);
 
-  bool errorsFound = false;
   void reportError(String message) {
     print(message);
     errorsFound = true;
diff --git a/pkg/front_end/tool/generate_ast_coverage.dart b/pkg/front_end/tool/generate_ast_coverage.dart
index 423f2d6..cc2a6a9 100644
--- a/pkg/front_end/tool/generate_ast_coverage.dart
+++ b/pkg/front_end/tool/generate_ast_coverage.dart
@@ -30,6 +30,10 @@
   Map<String, Set<String>> nestedClassNames = {};
 
   @override
+  String get generatorCommand =>
+      'dart pkg/front_end/tool/generate_ast_coverage.dart';
+
+  @override
   String get returnType => 'void';
 
   @override
diff --git a/pkg/front_end/tool/generate_ast_equivalence.dart b/pkg/front_end/tool/generate_ast_equivalence.dart
index 83f689e..22af276 100644
--- a/pkg/front_end/tool/generate_ast_equivalence.dart
+++ b/pkg/front_end/tool/generate_ast_equivalence.dart
@@ -31,6 +31,10 @@
   EquivalenceVisitorStrategy();
 
   @override
+  String get generatorCommand =>
+      'dart pkg/front_end/tool/generate_ast_equivalence.dart';
+
+  @override
   String get argumentType => 'Node';
 
   @override
@@ -414,13 +418,7 @@
 
   void generateHeader(AstModel astModel, StringBuffer sb) {
     sb.writeln('''
-// Copyright (c) 2021, 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.
-
-// NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
-//
-// Run 'dart pkg/front_end/tool/generate_ast_equivalence.dart' to update.
+$preamble
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/src/printer.dart';
@@ -434,7 +432,7 @@
 /// current assumptions. The current state has two modes. In the asserting mode,
 /// the default, inequivalences are registered when found. In the non-asserting
 /// mode, inequivalences are _not_ registered. The latter is used to compute
-/// equivalences in sand boxed state, for instance to determine which elements
+/// equivalences in sandboxed state, for instance to determine which elements
 /// to pair when checking equivalence of two sets.
 class $visitorName$visitorTypeParameters
     implements Visitor1<$returnType, $argumentType> {
diff --git a/pkg/front_end/tool/visitor_generator.dart b/pkg/front_end/tool/visitor_generator.dart
index d4befb5..22bef62 100644
--- a/pkg/front_end/tool/visitor_generator.dart
+++ b/pkg/front_end/tool/visitor_generator.dart
@@ -84,6 +84,23 @@
 abstract class VisitorStrategy {
   const VisitorStrategy();
 
+  /// Preamble comment used in the generated file.
+  String get preamble => '''
+// Copyright (c) 2021, 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.
+
+// NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
+//
+// Run '$generatorCommand' to update.
+''';
+
+  /// The command used to generate the visitor.
+  ///
+  /// This is inserted in the [preamble] along with a comment that the file
+  /// is generated.
+  String get generatorCommand;
+
   /// Comment used as doc comment for the generated visitor class.
   String get visitorComment => '';
 
@@ -128,6 +145,8 @@
 
   void generateHeader(AstModel astModel, StringBuffer sb) {
     sb.writeln('''
+$preamble
+
 import 'package:kernel/ast.dart';
 
 $visitorComment
@@ -199,7 +218,7 @@
 }
 
 /// Strategy for creating an empty `Visitor<void>` implementation.
-class VoidVisitor0Strategy extends Visitor0Strategy {
+abstract class VoidVisitor0Strategy extends Visitor0Strategy {
   const VoidVisitor0Strategy();
 
   @override
@@ -312,7 +331,7 @@
 }
 
 /// Strategy for creating an empty `Visitor1<void,Null>` implementation.
-class VoidVisitor1Strategy extends Visitor1Strategy {
+abstract class VoidVisitor1Strategy extends Visitor1Strategy {
   const VoidVisitor1Strategy();
 
   @override
diff --git a/pkg/kernel/lib/src/coverage.dart b/pkg/kernel/lib/src/coverage.dart
index cfcd11d..01b9483 100644
--- a/pkg/kernel/lib/src/coverage.dart
+++ b/pkg/kernel/lib/src/coverage.dart
@@ -1,3 +1,11 @@
+// Copyright (c) 2021, 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.
+
+// NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
+//
+// Run 'dart pkg/front_end/tool/generate_ast_coverage.dart' to update.
+
 import 'package:kernel/ast.dart';
 
 /// Recursive visitor that collects kinds for all visited nodes.
diff --git a/pkg/kernel/lib/src/equivalence.dart b/pkg/kernel/lib/src/equivalence.dart
index 2f9fab4..a8edddb 100644
--- a/pkg/kernel/lib/src/equivalence.dart
+++ b/pkg/kernel/lib/src/equivalence.dart
@@ -18,7 +18,7 @@
 /// current assumptions. The current state has two modes. In the asserting mode,
 /// the default, inequivalences are registered when found. In the non-asserting
 /// mode, inequivalences are _not_ registered. The latter is used to compute
-/// equivalences in sand boxed state, for instance to determine which elements
+/// equivalences in sandboxed state, for instance to determine which elements
 /// to pair when checking equivalence of two sets.
 class EquivalenceVisitor implements Visitor1<bool, Node> {
   final EquivalenceStrategy strategy;
diff --git a/pkg/kernel/lib/src/union_find.dart b/pkg/kernel/lib/src/union_find.dart
index 4dffab0..bab7fc6 100644
--- a/pkg/kernel/lib/src/union_find.dart
+++ b/pkg/kernel/lib/src/union_find.dart
@@ -2,6 +2,10 @@
 // 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.
 
+/// Implementation of a union-find algorithm.
+///
+/// See https://en.wikipedia.org/wiki/Disjoint-set_data_structure
+
 import 'dart:collection';
 
 class UnionFindNode<T> {
@@ -46,6 +50,7 @@
 
   UnionFindNode<T> findNode(UnionFindNode<T> node) {
     if (node.parent != null) {
+      // Perform path compression by updating to the effective target.
       return node.parent = findNode(node.parent!);
     }
     return node;
diff --git a/pkg/kernel/test/equivalence_test.dart b/pkg/kernel/test/equivalence_test.dart
index de5ec47..f57f2a0 100644
--- a/pkg/kernel/test/equivalence_test.dart
+++ b/pkg/kernel/test/equivalence_test.dart
@@ -67,23 +67,22 @@
 '''),
   Test(component1, component2),
   Test(component1.libraries[0], component2.libraries[0]),
-  Test(component1.libraries[0], component2.libraries[0]),
   Test(component1.libraries[0], component2.libraries[1], inequivalence: '''
 Inequivalent nodes
-1: library file://uri1/
-2: library file://uri2/
+1: library import://uri1
+2: library import://uri2
 .root
 '''),
   Test(component1.libraries[1], component2.libraries[2], inequivalence: '''
 Inequivalent nodes
-1: library file://uri2/
-2: library file://uri3/
+1: library import://uri2
+2: library import://uri3
 .root
 '''),
   Test(component1.libraries[1], component2.libraries[3], inequivalence: '''
 Values file://uri2/ and file://uri3/ are not equivalent
 .root
- Library(library file://uri2/).fileUri
+ Library(library import://uri2).fileUri
 '''),
   Test(component1.libraries[0].procedures[0],
       component2.libraries[0].procedures[1],
@@ -173,31 +172,34 @@
 
 Component createComponent() {
   Component component = new Component();
-  Uri uri1 = Uri.parse('file://uri1');
-  Uri uri2 = Uri.parse('file://uri2');
-  Uri uri3 = Uri.parse('file://uri3');
-  Library library1 = new Library(uri1, fileUri: uri1);
+  Uri fileUri1 = Uri.parse('file://uri1');
+  Uri fileUri2 = Uri.parse('file://uri2');
+  Uri fileUri3 = Uri.parse('file://uri3');
+  Uri importUri1 = Uri.parse('import://uri1');
+  Uri importUri2 = Uri.parse('import://uri2');
+  Uri importUri3 = Uri.parse('import://uri3');
+  Library library1 = new Library(importUri1, fileUri: fileUri1);
   component.libraries.add(library1);
   Procedure procedure1foo = new Procedure(
       new Name('foo'), ProcedureKind.Method, new FunctionNode(null),
-      fileUri: uri1);
+      fileUri: fileUri1);
   library1.addProcedure(procedure1foo);
   Procedure procedure1bar = new Procedure(
       new Name('bar'), ProcedureKind.Method, new FunctionNode(null),
-      fileUri: uri1);
+      fileUri: fileUri1);
   library1.addProcedure(procedure1bar);
 
-  Library library2 = new Library(uri2, fileUri: uri2);
+  Library library2 = new Library(importUri2, fileUri: fileUri2);
   component.libraries.add(library2);
 
-  Library library3 = new Library(uri3, fileUri: uri2);
+  Library library3 = new Library(importUri3, fileUri: fileUri2);
   component.libraries.add(library3);
   Procedure procedure3foo = new Procedure(
       new Name('foo'), ProcedureKind.Method, new FunctionNode(null),
-      fileUri: uri1);
+      fileUri: fileUri1);
   library3.addProcedure(procedure3foo);
 
-  Library library4 = new Library(uri2, fileUri: uri3);
+  Library library4 = new Library(importUri2, fileUri: fileUri3);
   component.libraries.add(library4);
 
   return component;
diff --git a/pkg/test_runner/tool/update_static_error_tests.dart b/pkg/test_runner/tool/update_static_error_tests.dart
index 053dcbd..23be296 100644
--- a/pkg/test_runner/tool/update_static_error_tests.dart
+++ b/pkg/test_runner/tool/update_static_error_tests.dart
@@ -112,32 +112,27 @@
         parser, "Must provide at least one flag for an operation to perform.");
   }
 
-  if (results.rest.length != 1) {
-    _usageError(
-        parser, "Must provide a file path or glob for which tests to update.");
-  }
+  for (var result in results.rest) {
+    // Allow tests to be specified without the extension for compatibility with
+    // the regular test runner syntax.
+    if (!result.endsWith(".dart")) {
+      result += ".dart";
+    }
 
-  var result = results.rest.single;
+    // Allow tests to be specified either relative to the "tests" directory
+    // or relative to the current directory.
+    var root = result.startsWith("tests") ? "." : "tests";
+    var glob = Glob(result, recursive: true);
+    for (var entry in glob.listSync(root: root)) {
+      if (!entry.path.endsWith(".dart")) continue;
 
-  // Allow tests to be specified without the extension for compatibility with
-  // the regular test runner syntax.
-  if (!result.endsWith(".dart")) {
-    result += ".dart";
-  }
-
-  // Allow tests to be specified either relative to the "tests" directory
-  // or relative to the current directory.
-  var root = result.startsWith("tests") ? "." : "tests";
-  var glob = Glob(result, recursive: true);
-  for (var entry in glob.listSync(root: root)) {
-    if (!entry.path.endsWith(".dart")) continue;
-
-    if (entry is pkg_file.File) {
-      await _processFile(entry,
-          dryRun: dryRun,
-          includeContext: includeContext,
-          remove: removeSources,
-          insert: insertSources);
+      if (entry is pkg_file.File) {
+        await _processFile(entry,
+            dryRun: dryRun,
+            includeContext: includeContext,
+            remove: removeSources,
+            insert: insertSources);
+      }
     }
   }
 }
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 654967a..a505d5c 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -56,7 +56,6 @@
 # ........gen_kernel.dart.snapshot (if not on ia32)
 # ........kernel-service.dart.snapshot
 # ........kernel_worker.dart.snapshot
-# ........pub.dart.snapshot
 # ......resources/
 # ........dartdoc/
 # ...........packages
@@ -140,10 +139,6 @@
     "frontend_server",
     "../utils/kernel-service:frontend_server",
   ],
-  [
-    "pub",
-    "../utils/pub",
-  ],
 ]
 if (create_kernel_service_snapshot) {
   _platform_sdk_snapshots += [ [
diff --git a/sdk/bin/pub b/sdk/bin/pub
deleted file mode 100755
index 85ad5d6..0000000
--- a/sdk/bin/pub
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# Run pub.dart on the Dart VM. This script is only used when running pub from
-# within the Dart source repo. The shipped SDK instead uses "pub_sdk", which is
-# renamed to "pub" when the SDK is built.
-
-function follow_links() {
-  file="$1"
-  while [ -h "$file" ]; do
-    # On Mac OS, readlink -f doesn't work.
-    file="$(readlink "$file")"
-  done
-  echo "$file"
-}
-
-# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
-PROG_NAME="$(follow_links "$BASH_SOURCE")"
-
-# Handle the case where dart-sdk/bin has been symlinked to.
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-
-SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
-
-SNAPSHOT="$BIN_DIR/snapshots/pub.dart.snapshot"
-
-unset VM_OPTIONS
-declare -a VM_OPTIONS
-
-if [[ `uname` == 'Darwin' ]];
-then
-  OUT_DIR="$BIN_DIR"/../../xcodebuild/
-else
-  OUT_DIR="$BIN_DIR"/../../out/
-fi
-
-# Allow extra VM options to be passed in through an environment variable.
-if [[ $DART_VM_OPTIONS ]]; then
-  read -a OPTIONS <<< "$DART_VM_OPTIONS"
-  VM_OPTIONS+=("${OPTIONS[@]}")
-fi
-
-if [ -z "$DART_CONFIGURATION" ];
-then
-  DIRS=$( ls "$OUT_DIR" )
-  # list of possible configurations in decreasing desirability
-  CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
-    "ReleaseARM" "ReleaseARM64" "DebugARM" "DebugARM64" )
-  DART_CONFIGURATION="None"
-  for CONFIG in ${CONFIGS[*]}
-  do
-    for DIR in $DIRS;
-    do
-      if [ "$CONFIG" = "$DIR" ];
-      then
-        # choose most desirable configuration that is available and break
-        DART_CONFIGURATION="$DIR"
-        break 2
-      fi
-    done
-  done
-  if [ "$DART_CONFIGURATION" = "None" ]
-  then
-    echo "No valid dart configuration found in $OUT_DIR"
-    exit 1
-  fi
-fi
-
-if [[ `uname` == 'Darwin' ]];
-then
-  BUILD_DIR="$SDK_DIR/../xcodebuild/$DART_CONFIGURATION"
-else
-  BUILD_DIR="$SDK_DIR/../out/$DART_CONFIGURATION"
-fi
-
-# Use the Dart binary in the built SDK so pub can find the version file next
-# to it.
-DART="$BUILD_DIR/dart-sdk/bin/dart"
-
-# Run pub.
-PUB="$SDK_DIR/../third_party/pkg/pub/bin/pub.dart"
-exec "$DART" "--packages=$SDK_DIR/../.packages" "${VM_OPTIONS[@]}" "$PUB" "$@"
diff --git a/sdk/bin/pub_sdk b/sdk/bin/pub_sdk
index 4d29878..17ce14c 100755
--- a/sdk/bin/pub_sdk
+++ b/sdk/bin/pub_sdk
@@ -28,7 +28,7 @@
 
 # Handle the case where dart-sdk/bin has been symlinked to.
 BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-
+DART="$BIN_DIR/dart"
 
 unset VM_OPTIONS
 declare -a VM_OPTIONS
@@ -39,12 +39,9 @@
   VM_OPTIONS+=("${OPTIONS[@]}")
 fi
 
-# Run the pub snapshot.
-DART="$BIN_DIR/dart"
-if array_contains "--no-preview-dart-2" "${VM_OPTIONS[@]}"; then
-  echo "Pub no longer supports Dart 1"
-  exit -1
-else
-  SNAPSHOT="$BIN_DIR/snapshots/pub.dart.snapshot"
-  exec "$DART" "${VM_OPTIONS[@]}" "$SNAPSHOT" "$@"
+if [ -t 2 ]; then # Only print warning when run in terminal.
+  >&2 echo 'The top level `pub` command is deprecated. Use `dart pub` instead.'
 fi
+
+# Forward to the `dart __deprecatedpub` command.
+exec "$DART" "${VM_OPTIONS[@]}" __deprecated_pub "$@"
diff --git a/sdk/bin/pub_sdk.bat b/sdk/bin/pub_sdk.bat
index 2fe828b..e882aac 100644
--- a/sdk/bin/pub_sdk.bat
+++ b/sdk/bin/pub_sdk.bat
@@ -28,11 +28,8 @@
   )
 )
 
-if defined USING_DART_1 (
-  echo "Pub no longer supports Dart 1"
-) else (
-  "%BIN_DIR%\dart" %VM_OPTIONS% "%BIN_DIR%\snapshots\pub.dart.snapshot" %*
-)
+echo "The top level `pub.bat` command is deprecated. Use `dart pub` instead." 1>&2
+"%BIN_DIR%\dart" %VM_OPTIONS% __deprecated_pub %*
 
 endlocal
 
diff --git a/tools/VERSION b/tools/VERSION
index f249fa0..401980d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 48
+PRERELEASE 49
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/utils/pub/.gitignore b/utils/pub/.gitignore
deleted file mode 100644
index cfb192d..0000000
--- a/utils/pub/.gitignore
+++ /dev/null
@@ -1,21 +0,0 @@
-/Makefile
-/out
-/xcodebuild
-/*.Makefile
-/*.sln
-/*.target.mk
-/*.vcproj
-/*.vcxproj
-/*.vcxproj.filters
-/*.vcxproj.user
-/*.xcodeproj
-/Debug
-/DebugARM
-/DebugIA32
-/DebugSIMARM
-/DebugX64
-/Release
-/ReleaseARM
-/ReleaseIA32
-/ReleaseSIMARM
-/ReleaseX64
diff --git a/utils/pub/BUILD.gn b/utils/pub/BUILD.gn
deleted file mode 100644
index de93998..0000000
--- a/utils/pub/BUILD.gn
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-import("../application_snapshot.gni")
-
-application_snapshot("pub") {
-  main_dart = "../../third_party/pkg/pub/bin/pub.dart"
-
-  training_args = [ "--help" ]
-}