Special case global-run message for updated sdk (#4419)
diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart
index f491d69..16e2f17 100644
--- a/lib/src/global_packages.dart
+++ b/lib/src/global_packages.dart
@@ -28,6 +28,7 @@
import 'source/hosted.dart';
import 'source/path.dart';
import 'source/root.dart';
+import 'source/sdk.dart';
import 'system_cache.dart';
import 'utils.dart';
@@ -455,7 +456,16 @@
recompile: (exectuable) async {
final root = entrypoint.workspaceRoot;
final name = exectuable.package;
- // Resolve it and download its dependencies.
+
+ // When recompiling we re-resolve it and download its dependencies. This
+ // is mainly to protect from the case where the sdk was updated, and
+ // that causes some incompatibilities. (could be the new sdk is outside
+ // some package's environment constraint range, or that the sdk came
+ // with incompatible versions of sdk packages).
+ //
+ // We use --enforce-lockfile semantics, because we want upgrading
+ // globally activated packages to be conscious, and not a part of
+ // running them.
SolveResult result;
try {
result = await log.spinner(
@@ -474,14 +484,44 @@
result.packages.removeWhere((id) => id.name == 'pub global activate');
final newLockFile = await result.downloadCachedPackages(cache);
+ final report = SolveReport(
+ SolveType.get,
+ entrypoint.workspaceRoot.dir,
+ entrypoint.workspaceRoot.pubspec,
+ entrypoint.workspaceRoot.allOverridesInWorkspace,
+ entrypoint.lockFile,
+ newLockFile,
+ result.availableVersions,
+ cache,
+ dryRun: true,
+ enforceLockfile: true,
+ quiet: false,
+ );
+ await report.show(summary: true);
+
final sameVersions = entrypoint.lockFile.samePackageIds(newLockFile);
+
if (!sameVersions) {
- dataError('''
-The package `$name` as currently activated cannot resolve to the same packages.
+ if (newLockFile.packages.values.any((p) {
+ return p.source is SdkSource &&
+ p.version != entrypoint.lockFile.packages[p.name]?.version;
+ })) {
+ // More specific error message for the case of a version match with
+ // an sdk package.
+ dataError('''
+The current activation of `$name` is not compatible with your current SDK.
Try reactivating the package.
`$topLevelProgram pub global activate $name`
''');
+ } else {
+ dataError('''
+The current activation of `$name` cannot resolve to the same set of dependencies.
+
+Try reactivating the package.
+`$topLevelProgram pub global activate $name`
+''');
+ }
}
await recompile(exectuable);
_refreshBinStubs(entrypoint, executable);
diff --git a/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart b/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart
index dc308c7..01a03d6 100644
--- a/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart
+++ b/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart
@@ -48,6 +48,7 @@
// all output we see the precompilation messages as well.
expect(pub.stdout, emits('Resolving dependencies...'));
expect(pub.stdout, emits('Downloading packages...'));
+ expect(pub.stdout, emits(startsWith('No dependencies would change in ')));
expect(pub.stdout, emits('Building package executable...'));
expect(pub.stdout, emitsThrough('ok'));
await pub.shouldExit();
@@ -70,6 +71,102 @@
'foo',
'1.0.0',
deps: {
+ 'bar': 'any',
+ },
+ contents: [
+ d.dir('bin', [
+ d.file('foo.dart', 'import "package:bar/bar.dart"; main() => bar();'),
+ ]),
+ ],
+ );
+
+ server.serve(
+ 'bar',
+ '1.0.0',
+ contents: [
+ d.dir('lib', [
+ d.file('bar.dart', 'bar() => print("original");'),
+ ]),
+ ],
+ );
+
+ await runPub(
+ args: ['global', 'activate', 'foo'],
+ );
+
+ await runPub(
+ args: ['global', 'run', 'foo'],
+ output: 'original',
+ );
+
+ server.serve(
+ 'bar',
+ '1.0.0',
+ contents: [
+ d.dir('lib', [
+ d.file('foo.dart', 'foo() => print("updated");'),
+ ]),
+ ],
+ );
+
+ await runPub(
+ args: ['global', 'run', 'foo'],
+ environment: {
+ 'DART_ROOT': p.join(d.sandbox, 'dart'),
+ // Updated sdk version makes the old snapshot obsolete
+ '_PUB_TEST_SDK_VERSION': '3.2.1+4',
+ },
+ output: contains('~ bar 1.0.0 (was 1.0.0)'),
+ error: allOf(
+ contains(
+ 'The current activation of `foo` cannot resolve to the same set of '
+ 'dependencies.',
+ ),
+ contains(
+ "The existing content-hash from pubspec.lock doesn't match "
+ 'contents for:',
+ ),
+ contains('Try reactivating the package'),
+ ),
+ exitCode: DATA,
+ );
+
+ await d.dir('dart', [
+ d.dir('packages', [
+ d.dir('bar', [
+ // Doesn't fulfill constraint, but doesn't satisfy pubspec.lock.
+ d.libPubspec('bar', '2.0.0', deps: {}),
+ ]),
+ ]),
+ ]).create();
+ await runPub(
+ args: ['global', 'run', 'foo'],
+ environment: {
+ 'DART_ROOT': p.join(d.sandbox, 'dart'),
+ '_PUB_TEST_SDK_VERSION': '3.2.1+4',
+ },
+ error: allOf(
+ contains(
+ 'The existing content-hash from pubspec.lock doesn\'t match '
+ 'contents for:',
+ ),
+ contains(
+ 'The current activation of `foo` cannot resolve to the same '
+ 'set of dependencies.',
+ ),
+ contains('Try reactivating the package'),
+ ),
+ exitCode: DATA,
+ );
+ });
+
+ test('validate resolution before recompilation - updated sdk package',
+ () async {
+ final server = await servePackages();
+ server.serve(
+ 'foo',
+ '1.0.0',
+ deps: {
'bar': {'sdk': 'dart', 'version': '^1.0.0'},
},
contents: [
@@ -120,9 +217,12 @@
'DART_ROOT': p.join(d.sandbox, 'dart'),
'_PUB_TEST_SDK_VERSION': '3.2.1+4',
},
+ output: contains('> bar 1.2.0 from sdk dart (was 1.0.0 from sdk dart)'),
error: allOf(
- contains('The package `foo` as currently activated cannot resolve to '
- 'the same packages'),
+ contains(
+ 'The current activation of `foo` is not compatible with your '
+ 'current SDK.',
+ ),
contains('Try reactivating the package'),
),
exitCode: DATA,