From b6b4a21ffb745c6357afb9cb7ee52ee422357740 Mon Sep 17 00:00:00 2001 From: Sigurd Meldgaard Date: Tue, 4 Jun 2024 23:34:36 +0200 Subject: [PATCH] Support for resolving package config and pubspec.lock in workspaces (#3684) Instead of expecting pubspec.lock and .dart_tool/package_config.json to reside in the same folder as pubspec.yaml, we visit each parent of the current directory until we find a .dart_tool/package_config.json, and expect pubspec.lock to exist next to that. Also invoke the generated scripts with an explicit packageConfig. This is to support running build_runner build in a workspace package, as implemented in dart-lang/pub#4127 --------- Co-authored-by: Jake Macdonald --- build_runner/CHANGELOG.md | 3 ++ .../src/build_script_generate/bootstrap.dart | 1 + build_runner_core/CHANGELOG.md | 1 + .../lib/src/package_graph/package_graph.dart | 33 ++++++++++++++--- .../workspace/.dart_tool/package_config.json | 23 ++++++++++++ .../test/fixtures/workspace/.gitignore | 5 +++ .../fixtures/workspace/pkgs/a/pubspec.yaml | 6 ++++ .../fixtures/workspace/pkgs/b/pubspec.yaml | 4 +++ .../test/fixtures/workspace/pubspec.lock | 5 +++ .../test/fixtures/workspace/pubspec.yaml | 6 ++++ .../package_graph/package_graph_test.dart | 36 +++++++++++++++++++ 11 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 build_runner_core/test/fixtures/workspace/.dart_tool/package_config.json create mode 100644 build_runner_core/test/fixtures/workspace/.gitignore create mode 100644 build_runner_core/test/fixtures/workspace/pkgs/a/pubspec.yaml create mode 100644 build_runner_core/test/fixtures/workspace/pkgs/b/pubspec.yaml create mode 100644 build_runner_core/test/fixtures/workspace/pubspec.lock create mode 100644 build_runner_core/test/fixtures/workspace/pubspec.yaml diff --git a/build_runner/CHANGELOG.md b/build_runner/CHANGELOG.md index ae4c52be8..36fb95919 100644 --- a/build_runner/CHANGELOG.md +++ b/build_runner/CHANGELOG.md @@ -1,5 +1,8 @@ ## 2.4.11-wip +- Explicitly pass the current isolates package config instead of assuming the + location, to support the upcoming pub workspaces feature. + ## 2.4.10 - Support version `1.x` and `2.x` of `shelf_web_socket` and `2.x` and `3.x` diff --git a/build_runner/lib/src/build_script_generate/bootstrap.dart b/build_runner/lib/src/build_script_generate/bootstrap.dart index c2c3e72d6..e8b3a24e1 100644 --- a/build_runner/lib/src/build_script_generate/bootstrap.dart +++ b/build_runner/lib/src/build_script_generate/bootstrap.dart @@ -164,6 +164,7 @@ Future _createKernelIfNeeded( 'lib/_internal/vm_platform_strong.dill', enabledExperiments: experiments, printIncrementalDependencies: false, + packagesJson: (await Isolate.packageConfig)!.toFilePath(), ); var hadOutput = false; diff --git a/build_runner_core/CHANGELOG.md b/build_runner_core/CHANGELOG.md index adaf28682..da8b8caee 100644 --- a/build_runner_core/CHANGELOG.md +++ b/build_runner_core/CHANGELOG.md @@ -1,5 +1,6 @@ ## 7.3.1-wip +- Support the upcoming pub workspaces feature. - Bump the min sdk to 3.4.0. - Remove some unnecessary casts and non-null assertions now that we have private field promotion. diff --git a/build_runner_core/lib/src/package_graph/package_graph.dart b/build_runner_core/lib/src/package_graph/package_graph.dart index 4f77ce496..3337fd156 100644 --- a/build_runner_core/lib/src/package_graph/package_graph.dart +++ b/build_runner_core/lib/src/package_graph/package_graph.dart @@ -78,14 +78,35 @@ class PackageGraph { 'pubspec.yaml.'); } - final packageConfig = - await findPackageConfig(Directory(packagePath), recurse: false); + // The path of the directory that contains .dart_tool/package_config.json. + // + // Should also contain `pubspec.lock`. + var rootDir = packagePath; + PackageConfig? packageConfig; + // Manually recurse through parent directories, to obtain the [rootDir] + // where a package config was found. It doesn't seem possible to obtain this + // directly with package:package_config. + while (true) { + packageConfig = + await findPackageConfig(Directory(rootDir), recurse: false); + File(p.join(rootDir, '.dart_tool', 'package_config.json')); + if (packageConfig != null) { + break; + } + final next = p.dirname(rootDir); + if (next == rootDir) { + // We have reached the file system root. + break; + } + rootDir = next; + } + if (packageConfig == null) { throw StateError( 'Unable to find package config for package at $packagePath.'); } - final dependencyTypes = _parseDependencyTypes(packagePath); + final dependencyTypes = _parseDependencyTypes(rootDir); final nodes = {}; // A consistent package order _should_ mean a consistent order of build @@ -94,11 +115,13 @@ class PackageGraph { final consistentlyOrderedPackages = packageConfig.packages.toList() ..sort((a, b) => a.name.compareTo(b.name)); for (final package in consistentlyOrderedPackages) { - var isRoot = package.name == rootPackageName; + final isRoot = package.name == rootPackageName; nodes[package.name] = PackageNode( package.name, package.root.toFilePath(), - isRoot ? DependencyType.path : dependencyTypes[package.name], + // If the package is missing from pubspec.lock, assume it is a path + // dependency. + dependencyTypes[package.name] ?? DependencyType.path, package.languageVersion, isRoot: isRoot); } diff --git a/build_runner_core/test/fixtures/workspace/.dart_tool/package_config.json b/build_runner_core/test/fixtures/workspace/.dart_tool/package_config.json new file mode 100644 index 000000000..32ecc9264 --- /dev/null +++ b/build_runner_core/test/fixtures/workspace/.dart_tool/package_config.json @@ -0,0 +1,23 @@ +{ + "configVersion": 2, + "packages": [ + { + "name": "workspace", + "rootUri": "../", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "a", + "rootUri": "../pkgs/a", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "b", + "rootUri": "../pkgs/b", + "packageUri": "lib/", + "languageVersion": "3.5" + } + ] +} diff --git a/build_runner_core/test/fixtures/workspace/.gitignore b/build_runner_core/test/fixtures/workspace/.gitignore new file mode 100644 index 000000000..f2132e3d7 --- /dev/null +++ b/build_runner_core/test/fixtures/workspace/.gitignore @@ -0,0 +1,5 @@ +# Take special care to include the .dart_tool/package_config.json +# +!.dart_tool +.dart_tool/* +!.dart_tool/package_config.json diff --git a/build_runner_core/test/fixtures/workspace/pkgs/a/pubspec.yaml b/build_runner_core/test/fixtures/workspace/pkgs/a/pubspec.yaml new file mode 100644 index 000000000..1677c6409 --- /dev/null +++ b/build_runner_core/test/fixtures/workspace/pkgs/a/pubspec.yaml @@ -0,0 +1,6 @@ +name: a +environment: + sdk: ^3.5.0-0 +resolution: workspace +dependencies: + b: diff --git a/build_runner_core/test/fixtures/workspace/pkgs/b/pubspec.yaml b/build_runner_core/test/fixtures/workspace/pkgs/b/pubspec.yaml new file mode 100644 index 000000000..c22a169a4 --- /dev/null +++ b/build_runner_core/test/fixtures/workspace/pkgs/b/pubspec.yaml @@ -0,0 +1,4 @@ +name: b +environment: + sdk: ^3.5.0-0 +resolution: workspace diff --git a/build_runner_core/test/fixtures/workspace/pubspec.lock b/build_runner_core/test/fixtures/workspace/pubspec.lock new file mode 100644 index 000000000..3630c37dc --- /dev/null +++ b/build_runner_core/test/fixtures/workspace/pubspec.lock @@ -0,0 +1,5 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: {} +sdks: + dart: ">=3.5.0-0 <4.0.0" diff --git a/build_runner_core/test/fixtures/workspace/pubspec.yaml b/build_runner_core/test/fixtures/workspace/pubspec.yaml new file mode 100644 index 000000000..97e18a7f5 --- /dev/null +++ b/build_runner_core/test/fixtures/workspace/pubspec.yaml @@ -0,0 +1,6 @@ +name: workspace +environment: + sdk: ^3.5.0-0 +workspace: + - pkgs/a + - pkgs/b diff --git a/build_runner_core/test/package_graph/package_graph_test.dart b/build_runner_core/test/package_graph/package_graph_test.dart index 16b168655..8dd429814 100644 --- a/build_runner_core/test/package_graph/package_graph_test.dart +++ b/build_runner_core/test/package_graph/package_graph_test.dart @@ -154,6 +154,42 @@ void main() { throwsA(anything)); }); }); + + group('workspace ', () { + var workspaceFixturePath = 'test/fixtures/workspace'; + + test('Loads all packages in workspace. Has correct root', () async { + Matcher packageNodeEquals(PackageNode node) => isA() + .having((c) => c.path, 'path', node.path) + .having((c) => c.dependencies, 'dependencies', + node.dependencies.map(packageNodeEquals)) + .having( + (c) => c.dependencyType, 'dependencyType', node.dependencyType); + + final graph = await PackageGraph.forPath('$workspaceFixturePath/pkgs/a'); + var a = PackageNode( + 'a', '$workspaceFixturePath/pkgs/a', DependencyType.path, null, + isRoot: true); + var b = PackageNode( + 'b', '$workspaceFixturePath/pkgs/b', DependencyType.path, null); + a.dependencies.add(b); + var workspace = PackageNode( + 'workspace', + workspaceFixturePath, + DependencyType.path, + null, + ); + + expect(graph.allPackages, { + 'a': packageNodeEquals(a), + 'b': packageNodeEquals(b), + 'workspace': packageNodeEquals(workspace), + r'$sdk': anything + }); + + expect(graph.root, packageNodeEquals(a)); + }); + }); } void expectPkg(PackageNode node, String name, String location,