Skip to content

Commit

Permalink
Special case global-run message for updated sdk (#4419)
Browse files Browse the repository at this point in the history
  • Loading branch information
sigurdm authored Nov 5, 2024
1 parent afdd62c commit 8c2e621
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 5 deletions.
46 changes: 43 additions & 3 deletions lib/src/global_packages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import 'source/git.dart';
import 'source/hosted.dart';
import 'source/path.dart';
import 'source/root.dart';
import 'source/sdk.dart';
import 'system_cache.dart';
import 'utils.dart';

Expand Down Expand Up @@ -455,7 +456,16 @@ try:
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(
Expand All @@ -474,14 +484,44 @@ Try reactivating the package.
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);
Expand Down
104 changes: 102 additions & 2 deletions test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ void main() {
// 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();
Expand All @@ -66,6 +67,102 @@ void main() {

test('validate resolution before recompilation', () async {
final server = await servePackages();
server.serve(
'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',
Expand Down Expand Up @@ -120,9 +217,12 @@ void main() {
'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,
Expand Down

0 comments on commit 8c2e621

Please sign in to comment.