Skip to content

Commit 30bfc43

Browse files
authored
Delete directories between workspace package and workspace root (#4446)
1 parent 3246cfe commit 30bfc43

File tree

4 files changed

+168
-27
lines changed

4 files changed

+168
-27
lines changed

lib/src/entrypoint.dart

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,15 +1335,45 @@ See https://dart.dev/go/sdk-constraint
13351335
/// Remove any `pubspec.lock` or `.dart_tool/package_config.json` files in
13361336
/// workspace packages that are not the root package.
13371337
///
1338+
/// Also remove from directories between the workspace package and the
1339+
/// workspace root, to prevent stray package configs from shadowing the shared
1340+
/// workspace package config.
1341+
///
13381342
/// This is to avoid surprises if a package is turned into a workspace member
13391343
/// but still has an old package config or lockfile.
13401344
void _removeStrayLockAndConfigFiles() {
1345+
final visited = <String>{
1346+
// By adding this to visited we will never go above the workspaceRoot.dir.
1347+
p.canonicalize(workspaceRoot.dir),
1348+
};
1349+
var deletedAny = false;
13411350
for (final package in workspaceRoot.transitiveWorkspace) {
13421351
if (package.pubspec.resolution == Resolution.workspace) {
1343-
deleteEntry(p.join(package.dir, 'pubspec.lock'));
1344-
deleteEntry(p.join(package.dir, '.dart_tool', 'package_config.json'));
1352+
for (final dir in parentDirs(package.dir)) {
1353+
if (!visited.add(p.canonicalize(dir))) {
1354+
// No reason to delete from the same directory twice.
1355+
break;
1356+
}
1357+
void deleteIfPresent(String path, String type) {
1358+
fileExists(path);
1359+
log.warning('Deleting old $type: `$path`.');
1360+
deleteEntry(path);
1361+
deletedAny = true;
1362+
}
1363+
1364+
deleteIfPresent(p.join(dir, 'pubspec.lock'), 'lock-file');
1365+
deleteIfPresent(
1366+
p.join(dir, '.dart_tool', 'package_config.json'),
1367+
'package config',
1368+
);
1369+
}
13451370
}
13461371
}
1372+
if (deletedAny) {
1373+
log.warning(
1374+
'See https://dart.dev/go/workspaces-stray-files for details.',
1375+
);
1376+
}
13471377
}
13481378

13491379
/// Returns a list of changes to constraints of workspace pubspecs updated to

lib/src/package.dart

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,12 @@ $symlinkResolvedDir => ${p.canonicalize(symlinkResolvedParent)}
435435
/// * If a package name occurs twice.
436436
/// * If two packages in the workspace override the same package name.
437437
/// * A workspace package is overridden.
438+
/// * A pubspec not included in the workspace exists in a directory
439+
/// between the root and a workspace package.
438440
void validateWorkspace(Package root) {
439441
if (root.workspaceChildren.isEmpty) return;
440442

443+
/// Maps the `p.canonicalize`d dir of each workspace-child to its parent.
441444
final includedFrom = <String, String>{};
442445
final stack = [root];
443446

@@ -500,6 +503,40 @@ Consider removing one of the overrides.
500503
Cannot override workspace packages.
501504
502505
Package `$override` at `${overriddenWorkspacePackage.presentationDir}` is overridden in `${package.pubspecPath}`.
506+
''');
507+
}
508+
}
509+
}
510+
511+
// Check for pubspec.yaml files between the root and any workspace package.
512+
final visited = <String>{
513+
// By adding this to visited we will never go above the workspaceRoot.dir.
514+
p.canonicalize(root.dir),
515+
};
516+
for (final package in root.transitiveWorkspace) {
517+
// Run through all parent directories until we meet another workspace
518+
// package.
519+
for (final dir in parentDirs(package.dir).skip(1)) {
520+
// Stop if we meet another package directory.
521+
if (includedFrom.containsKey(p.canonicalize(dir))) {
522+
break;
523+
}
524+
if (!visited.add(p.canonicalize(dir))) {
525+
// We have been here before.
526+
break;
527+
}
528+
final pubspecCandidate = p.join(dir, 'pubspec.yaml');
529+
if (fileExists(pubspecCandidate)) {
530+
fail('''
531+
The file `$pubspecCandidate` is located in a directory between the workspace root at
532+
`${root.dir}` and a workspace package at `${package.dir}`. But is not a member of the
533+
workspace.
534+
535+
This blocks the resolution of the package at `${package.dir}`.
536+
537+
Consider removing it.
538+
539+
See https://dart.dev/go/workspaces-stray-files for details.
503540
''');
504541
}
505542
}

pubspec.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,23 @@ packages:
55
dependency: transitive
66
description:
77
name: _fe_analyzer_shared
8-
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
8+
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
99
url: "https://pub.dev"
1010
source: hosted
11-
version: "73.0.0"
11+
version: "76.0.0"
1212
_macros:
1313
dependency: transitive
1414
description: dart
1515
source: sdk
16-
version: "0.3.2"
16+
version: "0.3.3"
1717
analyzer:
1818
dependency: "direct main"
1919
description:
2020
name: analyzer
21-
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
21+
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
2222
url: "https://pub.dev"
2323
source: hosted
24-
version: "6.8.0"
24+
version: "6.11.0"
2525
args:
2626
dependency: "direct main"
2727
description:
@@ -194,10 +194,10 @@ packages:
194194
dependency: transitive
195195
description:
196196
name: macros
197-
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
197+
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
198198
url: "https://pub.dev"
199199
source: hosted
200-
version: "0.1.2-main.4"
200+
version: "0.1.3-main.0"
201201
matcher:
202202
dependency: transitive
203203
description:

test/workspace_test.dart

Lines changed: 92 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,40 @@ foo:foomain''',
809809
);
810810
});
811811

812-
test('Removes lock files and package configs from workspace members',
812+
test('Reports error if pubspec inside workspace is not part of the workspace',
813+
() async {
814+
await dir(appPath, [
815+
libPubspec(
816+
'myapp',
817+
'1.2.3',
818+
extras: {
819+
'workspace': ['pkgs/a', 'pkgs/a/example'],
820+
},
821+
sdk: '^3.5.0',
822+
),
823+
dir('pkgs', [
824+
libPubspec('not_in_workspace', '1.0.0'),
825+
dir(
826+
'a',
827+
[
828+
libPubspec('a', '1.1.1', resolutionWorkspace: true),
829+
dir('example', [
830+
libPubspec('example', '0.0.0', resolutionWorkspace: true),
831+
]),
832+
],
833+
),
834+
]),
835+
]).create();
836+
await pubGet(
837+
environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'},
838+
error: contains(
839+
'The file `.${s}pkgs${s}pubspec.yaml` '
840+
'is located in a directory between the workspace root',
841+
),
842+
);
843+
});
844+
845+
test('Removes lock files and package configs from inside the workspace',
813846
() async {
814847
await dir(appPath, [
815848
libPubspec(
@@ -825,34 +858,75 @@ foo:foomain''',
825858
'a',
826859
[
827860
libPubspec('a', '1.1.1', resolutionWorkspace: true),
861+
dir('test_data', []),
828862
],
829863
),
830864
]),
831865
]).create();
866+
// Directories outside the workspace should not be affected.
867+
final outideWorkpace = sandbox;
868+
// Directories of worksace packages should be cleaned.
832869
final aDir = p.join(sandbox, appPath, 'pkgs', 'a');
870+
// Directories between workspace root and workspace packages should
871+
// be cleaned.
833872
final pkgsDir = p.join(sandbox, appPath, 'pkgs');
834-
final strayLockFile = File(p.join(aDir, 'pubspec.lock'));
835-
final strayPackageConfig =
836-
File(p.join(aDir, '.dart_tool', 'package_config.json'));
873+
// Directories inside a workspace package should not be cleaned.
874+
final inside = p.join(aDir, 'test_data');
837875

838-
final unmanagedLockFile = File(p.join(pkgsDir, 'pubspec.lock'));
839-
final unmanagedPackageConfig =
840-
File(p.join(pkgsDir, '.dart_tool', 'package_config.json'));
841-
strayPackageConfig.createSync(recursive: true);
842-
strayLockFile.createSync(recursive: true);
876+
void createLockFileAndPackageConfig(String dir) {
877+
File(p.join(dir, 'pubspec.lock')).createSync(recursive: true);
878+
File(p.join(dir, '.dart_tool', 'package_config.json'))
879+
.createSync(recursive: true);
880+
}
843881

844-
unmanagedPackageConfig.createSync(recursive: true);
845-
unmanagedLockFile.createSync(recursive: true);
882+
void validateLockFileAndPackageConfig(
883+
String dir,
884+
FileSystemEntityType state,
885+
) {
886+
expect(
887+
File(p.join(dir, 'pubspec.lock')).statSync().type,
888+
state,
889+
);
890+
expect(
891+
File(p.join(dir, '.dart_tool', 'package_config.json')).statSync().type,
892+
state,
893+
);
894+
}
846895

847-
await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'});
896+
createLockFileAndPackageConfig(sandbox);
897+
createLockFileAndPackageConfig(aDir);
898+
createLockFileAndPackageConfig(pkgsDir);
899+
createLockFileAndPackageConfig(inside);
848900

849-
expect(strayLockFile.statSync().type, FileSystemEntityType.notFound);
850-
expect(strayPackageConfig.statSync().type, FileSystemEntityType.notFound);
901+
await pubGet(
902+
environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'},
903+
warning: allOf(
904+
contains('Deleting old lock-file: `.${s}pkgs/a${s}pubspec.lock'),
905+
contains(
906+
'Deleting old package config: '
907+
'`.${s}pkgs/a$s.dart_tool${s}package_config.json`',
908+
),
909+
contains('Deleting old lock-file: `.${s}pkgs${s}pubspec.lock'),
910+
contains(
911+
'Deleting old package config: '
912+
'`.${s}pkgs$s.dart_tool${s}package_config.json`',
913+
),
914+
contains(
915+
'See https://dart.dev/go/workspaces-stray-files for details.',
916+
),
917+
),
918+
);
851919

852-
// We only delete stray files from directories that contain an actual
853-
// package.
854-
expect(unmanagedLockFile.statSync().type, FileSystemEntityType.file);
855-
expect(unmanagedPackageConfig.statSync().type, FileSystemEntityType.file);
920+
validateLockFileAndPackageConfig(
921+
outideWorkpace,
922+
FileSystemEntityType.file,
923+
);
924+
validateLockFileAndPackageConfig(aDir, FileSystemEntityType.notFound);
925+
validateLockFileAndPackageConfig(pkgsDir, FileSystemEntityType.notFound);
926+
validateLockFileAndPackageConfig(
927+
inside,
928+
FileSystemEntityType.file,
929+
);
856930
});
857931

858932
test('Reports error if workspace doesn\'t form a tree.', () async {

0 commit comments

Comments
 (0)