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' ;
56import 'dart:io' ;
67
78import 'package:build/build.dart' ;
89import 'package:built_collection/built_collection.dart' ;
10+ import 'package:meta/meta.dart' ;
911import 'package:package_config/package_config.dart' ;
1012import 'package:path/path.dart' as p;
1113import 'package:yaml/yaml.dart' ;
1214
1315import '../constants.dart' ;
1416import '../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.
308289Map <String , List <String >> _parsePackageDependencies (
309290 Iterable <Package > packages,
0 commit comments