Handle overrides in workspaces (#4249)
diff --git a/lib/src/command/deps.dart b/lib/src/command/deps.dart
index 45b3343..a9d370d 100644
--- a/lib/src/command/deps.dart
+++ b/lib/src/command/deps.dart
@@ -211,7 +211,7 @@
}
await _outputCompactPackages(
'dependency overrides',
- root.dependencyOverrides.keys,
+ root.pubspec.dependencyOverrides.keys,
buffer,
);
}
@@ -268,7 +268,7 @@
}
await _outputListSection(
'dependency overrides',
- root.dependencyOverrides.keys,
+ root.pubspec.dependencyOverrides.keys,
buffer,
);
}
@@ -377,7 +377,7 @@
if (_includeDev) {
transitive.removeAll(root.devDependencies.keys);
}
- transitive.removeAll(root.dependencyOverrides.keys);
+ transitive.removeAll(root.pubspec.dependencyOverrides.keys);
}
return transitive;
}
@@ -391,7 +391,7 @@
final nonDevDependencies = [
for (final package in entrypoint.workspaceRoot.transitiveWorkspace) ...[
...package.dependencies.keys,
- ...package.dependencyOverrides.keys,
+ ...package.pubspec.dependencyOverrides.keys,
],
];
return nonDevDependencies
diff --git a/lib/src/command/upgrade.dart b/lib/src/command/upgrade.dart
index 1864aa2..40131f1 100644
--- a/lib/src/command/upgrade.dart
+++ b/lib/src/command/upgrade.dart
@@ -234,7 +234,7 @@
}
// Skip [dep] if it has a dependency_override.
- if (entrypoint.workspaceRoot.dependencyOverrides
+ if (entrypoint.workspaceRoot.pubspec.dependencyOverrides
.containsKey(dep.name)) {
dependencyOverriddenDeps.add(dep.name);
continue;
@@ -293,7 +293,7 @@
// If any of the packages to upgrade are dependency overrides, then we
// show a warning.
final toUpgradeOverrides = toUpgrade
- .where(entrypoint.workspaceRoot.dependencyOverrides.containsKey);
+ .where(entrypoint.workspaceRoot.allOverridesInWorkspace.containsKey);
if (toUpgradeOverrides.isNotEmpty) {
log.warning(
'Warning: dependency_overrides prevents upgrades for: '
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index e4507ce..96c9fe0 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -7,7 +7,6 @@
import 'dart:io';
import 'dart:math';
-import 'package:collection/collection.dart';
import 'package:path/path.dart' as p;
import 'package:pool/pool.dart';
import 'package:pub_semver/pub_semver.dart';
@@ -568,6 +567,7 @@
type,
workspaceRoot.dir,
workspaceRoot.pubspec,
+ workspaceRoot.allOverridesInWorkspace,
lockFile,
newLockFile,
result.availableVersions,
@@ -795,8 +795,6 @@
return false;
}
- final overrides = MapKeySet(root.dependencyOverrides);
-
// Check that uncached dependencies' pubspecs are also still satisfied,
// since they're mutable and may have changed since the last get.
for (var id in lockFile.packages.values) {
@@ -806,7 +804,8 @@
try {
if (cache.load(id).dependencies.values.every(
(dep) =>
- overrides.contains(dep.name) || isDependencyUpToDate(dep),
+ root.allOverridesInWorkspace.containsKey(dep.name) ||
+ isDependencyUpToDate(dep),
)) {
continue;
}
diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart
index cc89903..957884c 100644
--- a/lib/src/global_packages.dart
+++ b/lib/src/global_packages.dart
@@ -267,6 +267,7 @@
SolveType.get,
null,
root.pubspec,
+ root.pubspec.dependencyOverrides,
originalLockFile ?? LockFile.empty(),
lockFile,
result.availableVersions,
diff --git a/lib/src/package.dart b/lib/src/package.dart
index e8c97d6..8edf823 100644
--- a/lib/src/package.dart
+++ b/lib/src/package.dart
@@ -76,26 +76,32 @@
}
}
+ /// A collection of all overrides in the workspace.
+ ///
+ /// Should only be called on the workspace root.
+ ///
+ /// We only allow each package to be overridden once, so it is ok to collapse
+ /// the overrides into a single map.
+ late final Map<String, PackageRange> allOverridesInWorkspace = {
+ for (final package in transitiveWorkspace)
+ ...package.pubspec.dependencyOverrides,
+ };
+
/// The immediate dependencies this package specifies in its pubspec.
Map<String, PackageRange> get dependencies => pubspec.dependencies;
/// The immediate dev dependencies this package specifies in its pubspec.
Map<String, PackageRange> get devDependencies => pubspec.devDependencies;
- /// The dependency overrides this package specifies in its pubspec or pubspec
- /// overrides.
- Map<String, PackageRange> get dependencyOverrides =>
- pubspec.dependencyOverrides;
-
/// All immediate dependencies this package specifies.
///
- /// This includes regular, dev dependencies, and overrides.
+ /// This includes regular, dev dependencies, and overrides from this package.
Map<String, PackageRange> get immediateDependencies {
// Make sure to add overrides last so they replace normal dependencies.
return {}
..addAll(dependencies)
..addAll(devDependencies)
- ..addAll(dependencyOverrides);
+ ..addAll(pubspec.dependencyOverrides);
}
/// Returns a list of paths to all Dart executables in this package's bin
diff --git a/lib/src/solver/package_lister.dart b/lib/src/solver/package_lister.dart
index 5f48a28..c38d300 100644
--- a/lib/src/solver/package_lister.dart
+++ b/lib/src/solver/package_lister.dart
@@ -131,6 +131,7 @@
PackageLister.root(
Package package,
this._systemCache, {
+ required Set<String> overriddenPackages,
required Map<String, Version>? sdkOverrides,
}) : _ref = PackageRef.root(package),
// Treat the package as locked so we avoid the logic for finding the
@@ -138,8 +139,7 @@
// package.
_locked = PackageId.root(package),
_dependencyType = DependencyType.none,
- _overriddenPackages =
- Set.unmodifiable(package.dependencyOverrides.keys),
+ _overriddenPackages = overriddenPackages,
_isDowngrade = false,
_allowedRetractedVersion = null,
sdkOverrides = sdkOverrides ?? {},
diff --git a/lib/src/solver/report.dart b/lib/src/solver/report.dart
index 0736ce4..4d2aa9b 100644
--- a/lib/src/solver/report.dart
+++ b/lib/src/solver/report.dart
@@ -31,6 +31,7 @@
final LockFile _newLockFile;
final SystemCache _cache;
final bool _dryRun;
+ final Map<String, PackageRange> _overriddenPackages;
/// If quiet only a single summary line is output.
final bool _quiet;
@@ -52,6 +53,7 @@
this._type,
this._location,
this._rootPubspec,
+ this._overriddenPackages,
this._previousLockFile,
this._newLockFile,
this._availableVersions,
@@ -339,7 +341,7 @@
final oldId = _previousLockFile.packages[name];
final id = newId ?? oldId!;
- final isOverridden = _rootPubspec.dependencyOverrides.containsKey(id.name);
+ final isOverridden = _overriddenPackages.containsKey(id.name);
// If the package was previously a dependency but the dependency has
// changed in some way.
diff --git a/lib/src/solver/result.dart b/lib/src/solver/result.dart
index 36925e3..2d3ea06 100644
--- a/lib/src/solver/result.dart
+++ b/lib/src/solver/result.dart
@@ -20,6 +20,9 @@
/// reachable from the root.
final List<PackageId> packages;
+ /// Names of all dependency overrides in the workspace.
+ final Set<String> _overriddenPackages;
+
/// The root package of this resolution.
final Package _root;
@@ -81,9 +84,7 @@
// Don't factor in overridden dependencies' SDK constraints, because we'll
// accept those packages even if their constraints don't match.
final nonOverrides = pubspecs.values
- .where(
- (pubspec) => !_root.dependencyOverrides.containsKey(pubspec.name),
- )
+ .where((pubspec) => !_overriddenPackages.contains(pubspec.name))
.toList();
final sdkConstraints = <String, VersionConstraint>{};
@@ -101,7 +102,7 @@
},
mainDependencies: MapKeySet(_root.dependencies),
devDependencies: MapKeySet(_root.devDependencies),
- overriddenDependencies: MapKeySet(_root.dependencyOverrides),
+ overriddenDependencies: _overriddenPackages,
);
}
@@ -125,6 +126,7 @@
SolveResult(
this._root,
+ this._overriddenPackages,
this._previousLockFile,
this.packages,
this.pubspecs,
diff --git a/lib/src/solver/version_solver.dart b/lib/src/solver/version_solver.dart
index 7a007a7..89019c3 100644
--- a/lib/src/solver/version_solver.dart
+++ b/lib/src/solver/version_solver.dart
@@ -5,6 +5,7 @@
import 'dart:async';
import 'dart:math' as math;
+import 'package:collection/collection.dart';
import 'package:pub_semver/pub_semver.dart';
import '../exceptions.dart';
@@ -77,6 +78,11 @@
/// name anywhere in the dependency graph.
final Map<String, PackageRange> _dependencyOverrides;
+ /// Names of packages that are overridden in this resolution as a [Set] for
+ /// convenience.
+ late final Set<String> _overriddenPackages =
+ MapKeySet(_root.allOverridesInWorkspace);
+
/// The set of packages for which the lockfile should be ignored.
final Set<String> _unlock;
@@ -94,7 +100,7 @@
Iterable<String> unlock, {
Map<String, Version> sdkOverrides = const {},
}) : _sdkOverrides = sdkOverrides,
- _dependencyOverrides = _root.dependencyOverrides,
+ _dependencyOverrides = _root.allOverridesInWorkspace,
_unlock = {...unlock};
/// Prime the solver with [constraints].
@@ -470,6 +476,7 @@
return SolveResult(
_root,
+ _overriddenPackages,
_lockFile,
decisions,
pubspecs,
@@ -523,6 +530,7 @@
return PackageLister.root(
_rootPackages[ref.name]!,
_systemCache,
+ overriddenPackages: _overriddenPackages,
sdkOverrides: _sdkOverrides,
);
}
@@ -531,12 +539,12 @@
if (locked != null && locked.toRef() != ref) locked = null;
final overridden = <String>{
- ..._dependencyOverrides.keys,
+ ..._overriddenPackages,
// If the package is overridden, ignore its dependencies back onto the
// root package.
- if (_dependencyOverrides.containsKey(package.name)) ...[
+ if (_overriddenPackages.contains(package.name)) ...[
_root.name,
- ..._root.workspaceChildren.map((e) => e.name),
+ ..._root.transitiveWorkspace.map((e) => e.name),
],
};
diff --git a/lib/src/validator/dependency_override.dart b/lib/src/validator/dependency_override.dart
index afdb349..edefa8c 100644
--- a/lib/src/validator/dependency_override.dart
+++ b/lib/src/validator/dependency_override.dart
@@ -13,7 +13,8 @@
class DependencyOverrideValidator extends Validator {
@override
Future validate() {
- final overridden = MapKeySet(package.dependencyOverrides);
+ final overridden =
+ MapKeySet(context.entrypoint.workspaceRoot.allOverridesInWorkspace);
final dev = MapKeySet(package.devDependencies);
if (overridden.difference(dev).isNotEmpty) {
final overridesFile = package.pubspec.dependencyOverridesFromOverridesFile
diff --git a/test/workspace_test.dart b/test/workspace_test.dart
index 8ca27b9..0cd47de 100644
--- a/test/workspace_test.dart
+++ b/test/workspace_test.dart
@@ -1223,6 +1223,39 @@
`a${s}pubspec.yaml` and `b${s}pubspec.yaml` are both called "a".''',
);
});
+
+ test('overrides are applied', () async {
+ final server = await servePackages();
+ server.serve('foo', '1.0.0');
+ await dir('foo', [libPubspec('foo', '1.0.1')]).create();
+ await dir(appPath, [
+ libPubspec(
+ 'myapp',
+ '1.2.3',
+ deps: {'foo': '1.0.0'},
+ extras: {
+ 'workspace': ['a'],
+ },
+ sdk: '^3.5.0',
+ ),
+ dir('a', [
+ libPubspec(
+ 'a',
+ '1.0.0',
+ extras: {
+ 'dependency_overrides': {
+ 'foo': {'path': '../../foo'},
+ },
+ },
+ resolutionWorkspace: true,
+ ),
+ ]),
+ ]).create();
+ await pubGet(
+ environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'},
+ output: contains('! foo 1.0.1 from path ..${s}foo (overridden)'),
+ );
+ });
}
final s = p.separator;