Skip to content

Commit 64ca1ba

Browse files
authored
Teach pub deps to show deps of all workspace packages (#4198)
1 parent 3f0df78 commit 64ca1ba

File tree

4 files changed

+294
-64
lines changed

4 files changed

+294
-64
lines changed

lib/src/ascii_tree.dart

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ String fromFiles(
8484
}
8585

8686
// Walk the map recursively and render to a string.
87-
return fromMap(root);
87+
return fromMap(root, startingAtTop: false);
8888
}
8989

9090
/// Draws a tree from a nested map. Given a map like:
@@ -108,9 +108,17 @@ String fromFiles(
108108
/// barback
109109
///
110110
/// Items with no children should have an empty map as the value.
111-
String fromMap(Map<String, Map> map) {
111+
///
112+
/// If [startingAtTop] is `false`, the tree will be shown as:
113+
///
114+
/// |-- analyzer
115+
/// | '-- args
116+
/// | | '-- collection
117+
/// ' '---logging
118+
/// '---barback
119+
String fromMap(Map<String, Map> map, {bool startingAtTop = true}) {
112120
var buffer = StringBuffer();
113-
_draw(buffer, '', null, map);
121+
_draw(buffer, '', null, map, depth: startingAtTop ? 0 : 1);
114122
return buffer.toString();
115123
}
116124

@@ -119,10 +127,11 @@ void _drawLine(
119127
String prefix,
120128
bool isLastChild,
121129
String? name,
130+
bool isRoot,
122131
) {
123132
// Print lines.
124133
buffer.write(prefix);
125-
if (name != null) {
134+
if (!isRoot) {
126135
if (isLastChild) {
127136
buffer.write(log.gray(emoji('└── ', "'-- ")));
128137
} else {
@@ -147,22 +156,24 @@ void _draw(
147156
Map<String, Map> children, {
148157
bool showAllChildren = false,
149158
bool isLast = false,
159+
required int depth,
150160
}) {
151161
// Don't draw a line for the root node.
152-
if (name != null) _drawLine(buffer, prefix, isLast, name);
162+
if (name != null) _drawLine(buffer, prefix, isLast, name, depth <= 1);
153163

154164
// Recurse to the children.
155165
var childNames = ordered(children.keys);
156166

157167
void drawChild(bool isLastChild, String child) {
158-
var childPrefix = _getPrefix(name == null, isLast);
168+
var childPrefix = _getPrefix(depth <= 1, isLast);
159169
_draw(
160170
buffer,
161171
'$prefix$childPrefix',
162172
child,
163173
children[child] as Map<String, Map>,
164174
showAllChildren: showAllChildren,
165175
isLast: isLastChild,
176+
depth: depth + 1,
166177
);
167178
}
168179

lib/src/command/deps.dart

Lines changed: 88 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ class DepsCommand extends PubCommand {
8989
usageException('Cannot combine --json and --style.');
9090
}
9191
final visited = <String>[];
92-
final toVisit = [entrypoint.workspaceRoot.name];
92+
final workspacePackageNames = [
93+
...entrypoint.workspaceRoot.transitiveWorkspace.map((p) => p.name),
94+
];
95+
final toVisit = [...workspacePackageNames];
9396
final packagesJson = <dynamic>[];
9497
final graph = await entrypoint.packageGraph;
9598
while (toVisit.isNotEmpty) {
@@ -98,14 +101,15 @@ class DepsCommand extends PubCommand {
98101
visited.add(current);
99102
final currentPackage =
100103
(await entrypoint.packageGraph).packages[current]!;
101-
final next = (current == entrypoint.workspaceRoot.name
102-
? entrypoint.workspaceRoot.immediateDependencies
104+
final isRoot = workspacePackageNames.contains(currentPackage.name);
105+
final next = (isRoot
106+
? currentPackage.immediateDependencies
103107
: currentPackage.dependencies)
104108
.keys
105109
.toList();
106110
final dependencyType =
107111
entrypoint.workspaceRoot.pubspec.dependencyType(current);
108-
final kind = currentPackage == entrypoint.workspaceRoot
112+
final kind = isRoot
109113
? 'root'
110114
: (dependencyType == DependencyType.direct
111115
? 'direct'
@@ -159,8 +163,6 @@ class DepsCommand extends PubCommand {
159163
buffer.writeln("${log.bold('${sdk.name} SDK')} ${sdk.version}");
160164
}
161165

162-
buffer.writeln(_labelPackage(entrypoint.workspaceRoot));
163-
164166
switch (argResults['style']) {
165167
case 'compact':
166168
await _outputCompact(buffer);
@@ -187,24 +189,32 @@ class DepsCommand extends PubCommand {
187189
Future<void> _outputCompact(
188190
StringBuffer buffer,
189191
) async {
190-
var root = entrypoint.workspaceRoot;
191-
await _outputCompactPackages(
192-
'dependencies',
193-
root.dependencies.keys,
194-
buffer,
195-
);
196-
if (_includeDev) {
192+
var first = true;
193+
for (final root in entrypoint.workspaceRoot.transitiveWorkspace) {
194+
if (!first) {
195+
buffer.write('\n');
196+
}
197+
first = false;
198+
199+
buffer.writeln(_labelPackage(root));
200+
await _outputCompactPackages(
201+
'dependencies',
202+
root.dependencies.keys,
203+
buffer,
204+
);
205+
if (_includeDev) {
206+
await _outputCompactPackages(
207+
'dev dependencies',
208+
root.devDependencies.keys,
209+
buffer,
210+
);
211+
}
197212
await _outputCompactPackages(
198-
'dev dependencies',
199-
root.devDependencies.keys,
213+
'dependency overrides',
214+
root.dependencyOverrides.keys,
200215
buffer,
201216
);
202217
}
203-
await _outputCompactPackages(
204-
'dependency overrides',
205-
root.dependencyOverrides.keys,
206-
buffer,
207-
);
208218

209219
var transitive = await _getTransitiveDependencies();
210220
await _outputCompactPackages('transitive dependencies', transitive, buffer);
@@ -240,20 +250,28 @@ class DepsCommand extends PubCommand {
240250
/// For each dependency listed, *that* package's immediate dependencies are
241251
/// shown.
242252
Future<void> _outputList(StringBuffer buffer) async {
243-
var root = entrypoint.workspaceRoot;
244-
await _outputListSection('dependencies', root.dependencies.keys, buffer);
245-
if (_includeDev) {
253+
var first = true;
254+
for (final root in entrypoint.workspaceRoot.transitiveWorkspace) {
255+
if (!first) {
256+
buffer.write('\n');
257+
}
258+
first = false;
259+
260+
buffer.writeln(_labelPackage(root));
261+
await _outputListSection('dependencies', root.dependencies.keys, buffer);
262+
if (_includeDev) {
263+
await _outputListSection(
264+
'dev dependencies',
265+
root.devDependencies.keys,
266+
buffer,
267+
);
268+
}
246269
await _outputListSection(
247-
'dev dependencies',
248-
root.devDependencies.keys,
270+
'dependency overrides',
271+
root.dependencyOverrides.keys,
249272
buffer,
250273
);
251274
}
252-
await _outputListSection(
253-
'dependency overrides',
254-
root.dependencyOverrides.keys,
255-
buffer,
256-
);
257275

258276
var transitive = await _getTransitiveDependencies();
259277
if (transitive.isEmpty) return;
@@ -301,57 +319,66 @@ class DepsCommand extends PubCommand {
301319
// being added to the tree, and the parent map that will receive that
302320
// package.
303321
var toWalk = Queue<(Package, Map<String, Map>)>();
304-
var visited = <String>{entrypoint.workspaceRoot.name};
322+
var visited = <String>{};
305323

306324
// Start with the root dependencies.
307325
var packageTree = <String, Map>{};
326+
final workspacePackageNames = [
327+
...entrypoint.workspaceRoot.transitiveWorkspace.map((p) => p.name),
328+
];
308329
var immediateDependencies =
309330
entrypoint.workspaceRoot.immediateDependencies.keys.toSet();
310331
if (!_includeDev) {
311332
immediateDependencies
312333
.removeAll(entrypoint.workspaceRoot.devDependencies.keys);
313334
}
314-
for (var name in immediateDependencies) {
335+
for (var name in workspacePackageNames) {
315336
toWalk.add((await _getPackage(name), packageTree));
316337
}
317338

318339
// Do a breadth-first walk to the dependency graph.
319340
while (toWalk.isNotEmpty) {
320-
var pair = toWalk.removeFirst();
321-
var (package, map) = pair;
341+
final (package, map) = toWalk.removeFirst();
322342

323-
if (visited.contains(package.name)) {
343+
if (!visited.add(package.name)) {
324344
map[log.gray('${package.name}...')] = <String, Map>{};
325345
continue;
326346
}
327347

328-
visited.add(package.name);
329-
330348
// Populate the map with this package's dependencies.
331349
var childMap = <String, Map>{};
332350
map[_labelPackage(package)] = childMap;
333351

334-
for (var dep in package.dependencies.values) {
335-
toWalk.add((await _getPackage(dep.name), childMap));
352+
final isRoot = workspacePackageNames.contains(package.name);
353+
final children = [
354+
...isRoot
355+
? package.immediateDependencies.keys
356+
: package.dependencies.keys,
357+
];
358+
if (!_includeDev) {
359+
children.removeWhere(package.devDependencies.keys.contains);
360+
}
361+
for (var dep in children) {
362+
toWalk.add((await _getPackage(dep), childMap));
336363
}
337364
}
338-
339365
buffer.write(tree.fromMap(packageTree));
340366
}
341367

342368
String _labelPackage(Package package) =>
343369
'${log.bold(package.name)} ${package.version}';
344370

345-
/// Gets the names of the non-immediate dependencies of the root package.
371+
/// Gets the names of the non-immediate dependencies of the workspace packages.
346372
Future<Set<String>> _getTransitiveDependencies() async {
347373
var transitive = await _getAllDependencies();
348-
var root = entrypoint.workspaceRoot;
349-
transitive.remove(root.name);
350-
transitive.removeAll(root.dependencies.keys);
351-
if (_includeDev) {
352-
transitive.removeAll(root.devDependencies.keys);
374+
for (final root in entrypoint.workspaceRoot.transitiveWorkspace) {
375+
transitive.remove(root.name);
376+
transitive.removeAll(root.dependencies.keys);
377+
if (_includeDev) {
378+
transitive.removeAll(root.devDependencies.keys);
379+
}
380+
transitive.removeAll(root.dependencyOverrides.keys);
353381
}
354-
transitive.removeAll(root.dependencyOverrides.keys);
355382
return transitive;
356383
}
357384

@@ -361,8 +388,12 @@ class DepsCommand extends PubCommand {
361388
return graph.packages.keys.toSet();
362389
}
363390

364-
var nonDevDependencies = entrypoint.workspaceRoot.dependencies.keys.toList()
365-
..addAll(entrypoint.workspaceRoot.dependencyOverrides.keys);
391+
var nonDevDependencies = [
392+
for (final package in entrypoint.workspaceRoot.transitiveWorkspace) ...[
393+
...package.dependencies.keys,
394+
...package.dependencyOverrides.keys,
395+
],
396+
];
366397
return nonDevDependencies
367398
.expand(graph.transitiveDependencies)
368399
.map((package) => package.name)
@@ -385,14 +416,14 @@ class DepsCommand extends PubCommand {
385416
/// Outputs all executables reachable from [entrypoint].
386417
Future<void> _outputExecutables(StringBuffer buffer) async {
387418
final graph = await entrypoint.packageGraph;
388-
var packages = [
389-
entrypoint.workspaceRoot,
390-
...(_includeDev
391-
? entrypoint.workspaceRoot.immediateDependencies
392-
: entrypoint.workspaceRoot.dependencies)
393-
.keys
394-
.map((name) => graph.packages[name]!),
395-
];
419+
final packages = {
420+
for (final p in entrypoint.workspaceRoot.transitiveWorkspace) ...[
421+
graph.packages[p.name]!,
422+
...(_includeDev ? p.immediateDependencies : p.dependencies)
423+
.keys
424+
.map((name) => graph.packages[name]!),
425+
],
426+
};
396427

397428
for (var package in packages) {
398429
var executables = package.executableNames;

test/ascii_tree_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,6 @@ void main() {
9898
},
9999
};
100100

101-
ctx.expectNextSection(tree.fromMap(map));
101+
ctx.expectNextSection(tree.fromMap(map, startingAtTop: false));
102102
});
103103
}

0 commit comments

Comments
 (0)