Report failure if package is included twice in same workspace (#4211)
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index 861c9df..a9315fb 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -123,6 +123,7 @@
);
for (final package in root.transitiveWorkspace) {
if (identical(pubspecsMet.entries.first.value, package.pubspec)) {
+ validateWorkspaceGraph(root);
return (root: root, work: package);
}
}
diff --git a/lib/src/package.dart b/lib/src/package.dart
index ca6b3f6..e1c5208 100644
--- a/lib/src/package.dart
+++ b/lib/src/package.dart
@@ -359,3 +359,27 @@
).map(resolve).toList();
}
}
+
+/// Reports an error if the graph of the workspace rooted at [root] is not a
+/// tree.
+void validateWorkspaceGraph(Package root) {
+ final includedFrom = <String, String>{};
+ final stack = [root];
+
+ while (stack.isNotEmpty) {
+ final current = stack.removeLast();
+ for (final child in current.workspaceChildren) {
+ final previous = includedFrom[p.canonicalize(child.dir)];
+ if (previous != null) {
+ fail('''
+Packages can only be included in the workspace once.
+
+`${p.join(child.dir, 'pubspec.yaml')}` is included in the workspace, both from:
+* `${p.join(current.dir, 'pubspec.yaml')}` and
+* ${p.join(previous, 'pubspec.yaml')}.''');
+ }
+ includedFrom[p.canonicalize(child.dir)] = current.dir;
+ }
+ stack.addAll(current.workspaceChildren);
+ }
+}
diff --git a/test/workspace_test.dart b/test/workspace_test.dart
index 967c737..f78c514 100644
--- a/test/workspace_test.dart
+++ b/test/workspace_test.dart
@@ -719,6 +719,45 @@
expect(unmanagedPackageConfig.statSync().type, FileSystemEntityType.file);
});
+ test('Reports error if workspace doesn\'t form a tree.', () async {
+ await dir(appPath, [
+ libPubspec(
+ 'myapp',
+ '1.2.3',
+ sdk: '^3.7.0',
+ extras: {
+ 'workspace': ['pkgs/a', 'pkgs'],
+ },
+ ),
+ dir('pkgs', [
+ libPubspec(
+ 'a',
+ '1.1.1',
+ resolutionWorkspace: true,
+ extras: {
+ 'workspace': ['a'],
+ },
+ ),
+ dir(
+ 'a',
+ [
+ libPubspec('a', '1.1.1', resolutionWorkspace: true),
+ ],
+ ),
+ ]),
+ ]).create();
+ final s = p.separator;
+ await pubGet(
+ error: '''
+Packages can only be included in the workspace once.
+
+`.${s}pkgs${s}a${s}pubspec.yaml` is included in the workspace, both from:
+* `.${s}pkgs${s}pubspec.yaml` and
+* .${s}pubspec.yaml.''',
+ environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'},
+ );
+ });
+
test(
'Reports a failure if a workspace pubspec is not nested inside the parent dir',
() async {