Skip to content

Commit 0030712

Browse files
authored
Simplify package loading. (#4277)
1 parent 20c27dc commit 0030712

File tree

6 files changed

+67
-70
lines changed

6 files changed

+67
-70
lines changed

build_runner/lib/src/build_plan/package_graph.dart

Lines changed: 43 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:convert';
56
import 'dart:io';
67

78
import 'package:build/build.dart';
89
import 'package:built_collection/built_collection.dart';
10+
import 'package:meta/meta.dart';
911
import 'package:package_config/package_config.dart';
1012
import 'package:path/path.dart' as p;
1113
import 'package:yaml/yaml.dart';
1214

1315
import '../constants.dart';
1416
import '../io/asset_path_provider.dart';
15-
import '../logging/build_log.dart';
1617

1718
/// The SDK package, we filter this to the core libs and dev compiler
1819
/// resources.
@@ -65,67 +66,53 @@ class PackageGraph implements AssetPathProvider {
6566
return PackageGraph._(root, allPackages);
6667
}
6768

68-
/// Creates a [PackageGraph] for the package whose top level directory lives
69-
/// at [packagePath] (no trailing slash).
69+
/// Loads the package graph for the package at absolute path [packagePath].
70+
///
71+
/// Assumes `pubspec.yaml` exists and has a name, as this is checked by
72+
/// `dart run`.
73+
@visibleForTesting
7074
static Future<PackageGraph> forPath(String packagePath) async {
71-
buildLog.debug('forPath $packagePath');
72-
73-
/// Read in the pubspec file and parse it as yaml.
74-
final pubspec = File(p.join(packagePath, 'pubspec.yaml'));
75-
if (!pubspec.existsSync()) {
76-
throw StateError(
77-
'Unable to generate package graph, no `pubspec.yaml` found. '
78-
'This program must be ran from the root directory of your package.',
79-
);
80-
}
81-
final rootPubspec = _pubspecForPath(packagePath);
82-
final rootPackageName = rootPubspec['name'] as String?;
83-
if (rootPackageName == null) {
84-
throw StateError(
85-
'The current package has no name, please add one to the '
86-
'pubspec.yaml.',
87-
);
88-
}
89-
90-
// The path of the directory that contains .dart_tool/package_config.json.
91-
//
92-
// Should also contain `pubspec.lock`.
93-
var rootDir = packagePath;
94-
PackageConfig? packageConfig;
95-
// Manually recurse through parent directories, to obtain the [rootDir]
96-
// where a package config was found. It doesn't seem possible to obtain this
97-
// directly with package:package_config.
98-
while (true) {
99-
packageConfig = await findPackageConfig(
100-
Directory(rootDir),
101-
recurse: false,
75+
var packageConfigFile = File(
76+
p.join(packagePath, '.dart_tool', 'package_config.json'),
77+
);
78+
String? workspacePath;
79+
if (!packageConfigFile.existsSync()) {
80+
final workspaceRefFile = File(
81+
p.join(packagePath, '.dart_tool', 'pub', 'workspace_ref.json'),
10282
);
103-
if (packageConfig != null) {
104-
break;
105-
}
106-
final next = p.dirname(rootDir);
107-
if (next == rootDir) {
108-
// We have reached the file system root.
109-
break;
83+
if (workspaceRefFile.existsSync()) {
84+
final workspaceRef =
85+
(json.decode(workspaceRefFile.readAsStringSync())
86+
as Map<String, Object?>)['workspaceRoot']
87+
as String;
88+
workspacePath = p.canonicalize(
89+
p.join(p.dirname(workspaceRefFile.path), workspaceRef),
90+
);
91+
packageConfigFile = File(
92+
p.join(workspacePath, '.dart_tool', 'package_config.json'),
93+
);
11094
}
111-
rootDir = next;
11295
}
11396

114-
if (packageConfig == null) {
115-
throw StateError(
116-
'Unable to find package config for package at $packagePath.',
117-
);
97+
if (!packageConfigFile.existsSync()) {
98+
throw StateError('Failed to find package_config.json.');
11899
}
119-
final dependencyTypes = _parseDependencyTypes(rootDir);
100+
101+
final packageConfig = await loadPackageConfig(packageConfigFile);
120102

121103
final nodes = <String, PackageNode>{};
122-
// A consistent package order _should_ mean a consistent order of build
123-
// phases. It's not a guarantee, but also not required for correctness, only
124-
// an optimization.
125-
final consistentlyOrderedPackages =
104+
final packages =
126105
packageConfig.packages.toList()
127106
..sort((a, b) => a.name.compareTo(b.name));
128-
for (final package in consistentlyOrderedPackages) {
107+
108+
final rootPubspec = _pubspecForPath(packagePath);
109+
final rootPackageName = rootPubspec['name']! as String;
110+
final pubspecLockFile = File(
111+
p.join(workspacePath ?? packagePath, 'pubspec.lock'),
112+
);
113+
final dependencyTypes = _parseDependencyTypes(pubspecLockFile);
114+
115+
for (final package in packages) {
129116
final isRoot = package.name == rootPackageName;
130117
nodes[package.name] = PackageNode(
131118
package.name,
@@ -137,6 +124,7 @@ class PackageGraph implements AssetPathProvider {
137124
isRoot: isRoot,
138125
);
139126
}
127+
140128
PackageNode packageNode(String package, {String? parent}) {
141129
final node = nodes[package];
142130
if (node == null) {
@@ -270,16 +258,9 @@ enum DependencyType { github, path, hosted }
270258

271259
/// Parse the `pubspec.lock` file and return a Map from package name to the type
272260
/// of dependency.
273-
Map<String, DependencyType> _parseDependencyTypes(String rootPackagePath) {
274-
final pubspecLock = File(p.join(rootPackagePath, 'pubspec.lock'));
275-
if (!pubspecLock.existsSync()) {
276-
throw StateError(
277-
'Unable to generate package graph, no `pubspec.lock` found. '
278-
'This program must be ran from the root directory of your package.',
279-
);
280-
}
261+
Map<String, DependencyType> _parseDependencyTypes(File pubspecLockFile) {
281262
final dependencyTypes = <String, DependencyType>{};
282-
final dependencies = loadYaml(pubspecLock.readAsStringSync()) as YamlMap;
263+
final dependencies = loadYaml(pubspecLockFile.readAsStringSync()) as YamlMap;
283264
final packages = dependencies['packages'] as YamlMap;
284265
for (final packageName in packages.keys) {
285266
final source = (packages[packageName] as YamlMap)['source'];
@@ -303,7 +284,7 @@ DependencyType _dependencyTypeFromSource(String source) {
303284
throw ArgumentError('Unable to determine dependency type:\n$source');
304285
}
305286

306-
/// Read the pubspec for each package in [packages] and finds it's
287+
/// Read the pubspec for each package in [packages] and finds its
307288
/// dependencies.
308289
Map<String, List<String>> _parsePackageDependencies(
309290
Iterable<Package> packages,

build_runner/test/build_plan/package_graph_test.dart

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ void main() {
3333
});
3434

3535
group('basic package ', () {
36-
final basicPkgPath = 'test/fixtures/basic_pkg/';
36+
final basicPkgPath = p.absolute('test/fixtures/basic_pkg/');
3737

3838
setUp(() async {
3939
graph = await PackageGraph.forPath(basicPkgPath);
@@ -82,7 +82,7 @@ void main() {
8282
});
8383

8484
group('package with dev dependencies', () {
85-
final withDevDepsPkgPath = 'test/fixtures/with_dev_deps';
85+
final withDevDepsPkgPath = p.absolute('test/fixtures/with_dev_deps');
8686

8787
setUp(() async {
8888
graph = await PackageGraph.forPath(withDevDepsPkgPath);
@@ -131,7 +131,7 @@ void main() {
131131
});
132132

133133
group('package with flutter dependencies', () {
134-
final withFlutterDeps = 'test/fixtures/flutter_pkg';
134+
final withFlutterDeps = p.absolute('test/fixtures/flutter_pkg');
135135

136136
setUp(() async {
137137
graph = await PackageGraph.forPath(withFlutterDeps);
@@ -172,23 +172,25 @@ void main() {
172172

173173
test('missing pubspec throws on create', () {
174174
expect(
175-
() => PackageGraph.forPath(p.join('test', 'fixtures', 'no_pubspec')),
175+
() => PackageGraph.forPath(
176+
p.absolute(p.join('test', 'fixtures', 'no_pubspec')),
177+
),
176178
throwsA(anything),
177179
);
178180
});
179181

180182
test('missing .dart_tool/package_config.json file throws on create', () {
181183
expect(
182184
() => PackageGraph.forPath(
183-
p.join('test', 'fixtures', 'no_packages_file'),
185+
p.absolute(p.join('test', 'fixtures', 'no_packages_file')),
184186
),
185187
throwsA(anything),
186188
);
187189
});
188190
});
189191

190192
group('workspace ', () {
191-
final workspaceFixturePath = 'test/fixtures/workspace';
193+
final workspaceFixturePath = p.absolute('test/fixtures/workspace');
192194

193195
test('Loads all packages in workspace. Has correct root', () async {
194196
Matcher packageNodeEquals(PackageNode node) => isA<PackageNode>()
@@ -204,7 +206,9 @@ void main() {
204206
node.dependencyType,
205207
);
206208

207-
final graph = await PackageGraph.forPath('$workspaceFixturePath/pkgs/a');
209+
final graph = await PackageGraph.forPath(
210+
p.absolute('$workspaceFixturePath/pkgs/a'),
211+
);
208212
final a = PackageNode(
209213
'a',
210214
'$workspaceFixturePath/pkgs/a',
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"workspaceRoot": "../.."
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"workspaceRoot": "../../../.."
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"workspaceRoot": "../../../.."
3+
}

build_runner/test/io/reader_writer_test.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,17 @@ import 'package:build_runner/src/build_plan/package_graph.dart';
1010
import 'package:build_runner/src/io/reader_writer.dart';
1111
import 'package:glob/glob.dart';
1212
import 'package:path/path.dart' as path;
13+
import 'package:path/path.dart' as p;
1314
import 'package:test/test.dart';
1415

1516
import '../common/common.dart';
1617

1718
final newLine = Platform.isWindows ? '\r\n' : '\n';
1819

1920
void main() async {
20-
final packageGraph = await PackageGraph.forPath('test/fixtures/basic_pkg');
21+
final packageGraph = await PackageGraph.forPath(
22+
p.absolute('test/fixtures/basic_pkg'),
23+
);
2124

2225
group('ReaderWriter', () {
2326
final readerWriter = ReaderWriter(packageGraph);

0 commit comments

Comments
 (0)