Merge remote-tracking branch 'origin/cherry_pick_binstub_fix' into merge-cherry_pick_binstub_fix
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index bf82e2e..6a96ed7 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml
@@ -24,7 +24,7 @@ matrix: sdk: [dev] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} @@ -52,7 +52,7 @@ sdk: [dev] shard: [0, 1, 2, 3, 4, 5, 6] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }}
diff --git a/lib/src/ascii_tree.dart b/lib/src/ascii_tree.dart index f5c62fd..58e93f4 100644 --- a/lib/src/ascii_tree.dart +++ b/lib/src/ascii_tree.dart
@@ -84,7 +84,7 @@ } // Walk the map recursively and render to a string. - return fromMap(root); + return fromMap(root, startingAtTop: false); } /// Draws a tree from a nested map. Given a map like: @@ -108,9 +108,17 @@ /// barback /// /// Items with no children should have an empty map as the value. -String fromMap(Map<String, Map> map) { +/// +/// If [startingAtTop] is `false`, the tree will be shown as: +/// +/// |-- analyzer +/// | '-- args +/// | | '-- collection +/// ' '---logging +/// '---barback +String fromMap(Map<String, Map> map, {bool startingAtTop = true}) { var buffer = StringBuffer(); - _draw(buffer, '', null, map); + _draw(buffer, '', null, map, depth: startingAtTop ? 0 : 1); return buffer.toString(); } @@ -119,10 +127,11 @@ String prefix, bool isLastChild, String? name, + bool isRoot, ) { // Print lines. buffer.write(prefix); - if (name != null) { + if (!isRoot) { if (isLastChild) { buffer.write(log.gray(emoji('└── ', "'-- "))); } else { @@ -147,15 +156,16 @@ Map<String, Map> children, { bool showAllChildren = false, bool isLast = false, + required int depth, }) { // Don't draw a line for the root node. - if (name != null) _drawLine(buffer, prefix, isLast, name); + if (name != null) _drawLine(buffer, prefix, isLast, name, depth <= 1); // Recurse to the children. var childNames = ordered(children.keys); void drawChild(bool isLastChild, String child) { - var childPrefix = _getPrefix(name == null, isLast); + var childPrefix = _getPrefix(depth <= 1, isLast); _draw( buffer, '$prefix$childPrefix', @@ -163,6 +173,7 @@ children[child] as Map<String, Map>, showAllChildren: showAllChildren, isLast: isLastChild, + depth: depth + 1, ); }
diff --git a/lib/src/command/deps.dart b/lib/src/command/deps.dart index 404fa61..9258545 100644 --- a/lib/src/command/deps.dart +++ b/lib/src/command/deps.dart
@@ -89,7 +89,10 @@ usageException('Cannot combine --json and --style.'); } final visited = <String>[]; - final toVisit = [entrypoint.workspaceRoot.name]; + final workspacePackageNames = [ + ...entrypoint.workspaceRoot.transitiveWorkspace.map((p) => p.name), + ]; + final toVisit = [...workspacePackageNames]; final packagesJson = <dynamic>[]; final graph = await entrypoint.packageGraph; while (toVisit.isNotEmpty) { @@ -98,14 +101,15 @@ visited.add(current); final currentPackage = (await entrypoint.packageGraph).packages[current]!; - final next = (current == entrypoint.workspaceRoot.name - ? entrypoint.workspaceRoot.immediateDependencies + final isRoot = workspacePackageNames.contains(currentPackage.name); + final next = (isRoot + ? currentPackage.immediateDependencies : currentPackage.dependencies) .keys .toList(); final dependencyType = entrypoint.workspaceRoot.pubspec.dependencyType(current); - final kind = currentPackage == entrypoint.workspaceRoot + final kind = isRoot ? 'root' : (dependencyType == DependencyType.direct ? 'direct' @@ -159,8 +163,6 @@ buffer.writeln("${log.bold('${sdk.name} SDK')} ${sdk.version}"); } - buffer.writeln(_labelPackage(entrypoint.workspaceRoot)); - switch (argResults['style']) { case 'compact': await _outputCompact(buffer); @@ -187,24 +189,32 @@ Future<void> _outputCompact( StringBuffer buffer, ) async { - var root = entrypoint.workspaceRoot; - await _outputCompactPackages( - 'dependencies', - root.dependencies.keys, - buffer, - ); - if (_includeDev) { + var first = true; + for (final root in entrypoint.workspaceRoot.transitiveWorkspace) { + if (!first) { + buffer.write('\n'); + } + first = false; + + buffer.writeln(_labelPackage(root)); await _outputCompactPackages( - 'dev dependencies', - root.devDependencies.keys, + 'dependencies', + root.dependencies.keys, + buffer, + ); + if (_includeDev) { + await _outputCompactPackages( + 'dev dependencies', + root.devDependencies.keys, + buffer, + ); + } + await _outputCompactPackages( + 'dependency overrides', + root.dependencyOverrides.keys, buffer, ); } - await _outputCompactPackages( - 'dependency overrides', - root.dependencyOverrides.keys, - buffer, - ); var transitive = await _getTransitiveDependencies(); await _outputCompactPackages('transitive dependencies', transitive, buffer); @@ -240,20 +250,28 @@ /// For each dependency listed, *that* package's immediate dependencies are /// shown. Future<void> _outputList(StringBuffer buffer) async { - var root = entrypoint.workspaceRoot; - await _outputListSection('dependencies', root.dependencies.keys, buffer); - if (_includeDev) { + var first = true; + for (final root in entrypoint.workspaceRoot.transitiveWorkspace) { + if (!first) { + buffer.write('\n'); + } + first = false; + + buffer.writeln(_labelPackage(root)); + await _outputListSection('dependencies', root.dependencies.keys, buffer); + if (_includeDev) { + await _outputListSection( + 'dev dependencies', + root.devDependencies.keys, + buffer, + ); + } await _outputListSection( - 'dev dependencies', - root.devDependencies.keys, + 'dependency overrides', + root.dependencyOverrides.keys, buffer, ); } - await _outputListSection( - 'dependency overrides', - root.dependencyOverrides.keys, - buffer, - ); var transitive = await _getTransitiveDependencies(); if (transitive.isEmpty) return; @@ -301,57 +319,66 @@ // being added to the tree, and the parent map that will receive that // package. var toWalk = Queue<(Package, Map<String, Map>)>(); - var visited = <String>{entrypoint.workspaceRoot.name}; + var visited = <String>{}; // Start with the root dependencies. var packageTree = <String, Map>{}; + final workspacePackageNames = [ + ...entrypoint.workspaceRoot.transitiveWorkspace.map((p) => p.name), + ]; var immediateDependencies = entrypoint.workspaceRoot.immediateDependencies.keys.toSet(); if (!_includeDev) { immediateDependencies .removeAll(entrypoint.workspaceRoot.devDependencies.keys); } - for (var name in immediateDependencies) { + for (var name in workspacePackageNames) { toWalk.add((await _getPackage(name), packageTree)); } // Do a breadth-first walk to the dependency graph. while (toWalk.isNotEmpty) { - var pair = toWalk.removeFirst(); - var (package, map) = pair; + final (package, map) = toWalk.removeFirst(); - if (visited.contains(package.name)) { + if (!visited.add(package.name)) { map[log.gray('${package.name}...')] = <String, Map>{}; continue; } - visited.add(package.name); - // Populate the map with this package's dependencies. var childMap = <String, Map>{}; map[_labelPackage(package)] = childMap; - for (var dep in package.dependencies.values) { - toWalk.add((await _getPackage(dep.name), childMap)); + final isRoot = workspacePackageNames.contains(package.name); + final children = [ + ...isRoot + ? package.immediateDependencies.keys + : package.dependencies.keys, + ]; + if (!_includeDev) { + children.removeWhere(package.devDependencies.keys.contains); + } + for (var dep in children) { + toWalk.add((await _getPackage(dep), childMap)); } } - buffer.write(tree.fromMap(packageTree)); } String _labelPackage(Package package) => '${log.bold(package.name)} ${package.version}'; - /// Gets the names of the non-immediate dependencies of the root package. + /// Gets the names of the non-immediate dependencies of the workspace packages. Future<Set<String>> _getTransitiveDependencies() async { var transitive = await _getAllDependencies(); - var root = entrypoint.workspaceRoot; - transitive.remove(root.name); - transitive.removeAll(root.dependencies.keys); - if (_includeDev) { - transitive.removeAll(root.devDependencies.keys); + for (final root in entrypoint.workspaceRoot.transitiveWorkspace) { + transitive.remove(root.name); + transitive.removeAll(root.dependencies.keys); + if (_includeDev) { + transitive.removeAll(root.devDependencies.keys); + } + transitive.removeAll(root.dependencyOverrides.keys); } - transitive.removeAll(root.dependencyOverrides.keys); return transitive; } @@ -361,8 +388,12 @@ return graph.packages.keys.toSet(); } - var nonDevDependencies = entrypoint.workspaceRoot.dependencies.keys.toList() - ..addAll(entrypoint.workspaceRoot.dependencyOverrides.keys); + var nonDevDependencies = [ + for (final package in entrypoint.workspaceRoot.transitiveWorkspace) ...[ + ...package.dependencies.keys, + ...package.dependencyOverrides.keys, + ], + ]; return nonDevDependencies .expand(graph.transitiveDependencies) .map((package) => package.name) @@ -385,14 +416,14 @@ /// Outputs all executables reachable from [entrypoint]. Future<void> _outputExecutables(StringBuffer buffer) async { final graph = await entrypoint.packageGraph; - var packages = [ - entrypoint.workspaceRoot, - ...(_includeDev - ? entrypoint.workspaceRoot.immediateDependencies - : entrypoint.workspaceRoot.dependencies) - .keys - .map((name) => graph.packages[name]!), - ]; + final packages = { + for (final p in entrypoint.workspaceRoot.transitiveWorkspace) ...[ + graph.packages[p.name]!, + ...(_includeDev ? p.immediateDependencies : p.dependencies) + .keys + .map((name) => graph.packages[name]!), + ], + }; for (var package in packages) { var executables = package.executableNames;
diff --git a/pubspec.yaml b/pubspec.yaml index eb197db..3fe357c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml
@@ -11,7 +11,7 @@ collection: ^1.18.0 convert: ^3.1.1 crypto: ^3.0.3 - frontend_server_client: ^3.2.0 + frontend_server_client: ^4.0.0 http: ^1.1.2 http_multi_server: ^3.2.1 http_parser: ^4.0.2
diff --git a/test/ascii_tree_test.dart b/test/ascii_tree_test.dart index b406f72..115cbc6 100644 --- a/test/ascii_tree_test.dart +++ b/test/ascii_tree_test.dart
@@ -98,6 +98,6 @@ }, }; - ctx.expectNextSection(tree.fromMap(map)); + ctx.expectNextSection(tree.fromMap(map, startingAtTop: false)); }); }
diff --git a/test/workspace_test.dart b/test/workspace_test.dart index 1a98308..cfa4079 100644 --- a/test/workspace_test.dart +++ b/test/workspace_test.dart
@@ -355,6 +355,194 @@ ); }); + test('`pub deps` lists dependencies for all members of workspace', () async { + final server = await servePackages(); + server.serve( + 'foo', + '1.0.0', + deps: {'transitive': '^1.0.0'}, + contents: [ + dir('bin', [file('foomain.dart')]), + ], + ); + server.serve( + 'transitive', + '1.0.0', + contents: [ + dir('bin', [file('transitivemain.dart')]), + ], + ); + server.serve( + 'both', + '1.0.0', + contents: [ + dir('bin', [file('bothmain.dart')]), + ], + ); + + await dir(appPath, [ + libPubspec( + 'myapp', + '1.2.3', + extras: { + 'workspace': ['pkgs/a', 'pkgs/b'], + }, + deps: {'both': '^1.0.0', 'b': null}, + sdk: '^3.7.0', + ), + dir('bin', [file('myappmain.dart')]), + dir('pkgs', [ + dir('a', [ + libPubspec( + 'a', + '1.1.1', + deps: {'myapp': null, 'foo': '^1.0.0'}, + devDeps: {'both': '^1.0.0'}, + resolutionWorkspace: true, + ), + ]), + dir('bin', [file('amain.dart')]), + dir('b', [ + libPubspec( + 'b', + '1.1.1', + deps: {'myapp': null, 'both': '^1.0.0'}, + resolutionWorkspace: true, + ), + dir('bin', [file('bmain.dart')]), + ]), + ]), + ]).create(); + await runPub( + args: ['deps'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains( + ''' +Dart SDK 3.7.0 +a 1.1.1 +├── both... +├── foo 1.0.0 +│ └── transitive 1.0.0 +└── myapp... +b 1.1.1 +├── both... +└── myapp... +myapp 1.2.3 +├── b... +└── both 1.0.0''', + ), + ); + + await runPub( + args: ['deps', '--style=list', '--dev'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: ''' +Dart SDK 3.7.0 +myapp 1.2.3 + +dependencies: +- both 1.0.0 +- b 1.1.1 + - myapp any + - both ^1.0.0 + +b 1.1.1 + +dependencies: +- myapp 1.2.3 + - both ^1.0.0 + - b any +- both 1.0.0 + +a 1.1.1 + +dependencies: +- myapp 1.2.3 + - both ^1.0.0 + - b any +- foo 1.0.0 + - transitive ^1.0.0 + +dev dependencies: +- both 1.0.0 + +transitive dependencies: +- transitive 1.0.0''', + ); + + await runPub( + args: ['deps', '--style=list', '--no-dev'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: ''' +Dart SDK 3.7.0 +myapp 1.2.3 + +dependencies: +- both 1.0.0 +- b 1.1.1 + - myapp any + - both ^1.0.0 + +b 1.1.1 + +dependencies: +- myapp 1.2.3 + - both ^1.0.0 + - b any +- both 1.0.0 + +a 1.1.1 + +dependencies: +- myapp 1.2.3 + - both ^1.0.0 + - b any +- foo 1.0.0 + - transitive ^1.0.0 + +transitive dependencies: +- transitive 1.0.0''', + ); + await runPub( + args: ['deps', '--style=compact'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: ''' + Dart SDK 3.7.0 +myapp 1.2.3 + +dependencies: +- b 1.1.1 [myapp both] +- both 1.0.0 + +b 1.1.1 + +dependencies: +- both 1.0.0 +- myapp 1.2.3 [both b] + +a 1.1.1 + +dependencies: +- foo 1.0.0 [transitive] +- myapp 1.2.3 [both b] + +dev dependencies: +- both 1.0.0 + +transitive dependencies: +- transitive 1.0.0''', + ); + await runPub( + args: ['deps', '--executables'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: ''' +myapp:myappmain +both:bothmain +b:bmain +foo:foomain''', + ); + }); + test('`pub add` acts on the work package', () async { final server = await servePackages(); server.serve('foo', '1.0.0', sdk: '^3.7.0');