From 056a8c9ace35be434699bf9edba05760fcb9283c Mon Sep 17 00:00:00 2001 From: Sigurd Meldgaard Date: Tue, 16 Mar 2021 16:06:02 +0100 Subject: [PATCH] pub deps --json (#2896) --- lib/src/command/deps.dart | 140 +++++--- lib/src/package.dart | 3 + test/deps/executables_test.dart | 329 +++++++----------- test/deps/goldens/dart_executables.txt | 36 ++ test/deps/goldens/dev_dependencies.txt | 45 +++ test/deps/goldens/formatting.txt | 67 ++++ test/deps/goldens/from_dependency.txt | 45 +++ test/deps/goldens/non_dart_executables.txt | 31 ++ .../goldens/nothing_in_sub_drectories.txt | 36 ++ test/deps/goldens/only_immediate.txt | 58 +++ test/deps/goldens/overrides.txt | 51 +++ test/deps_test.dart | 122 +++++++ 12 files changed, 724 insertions(+), 239 deletions(-) create mode 100644 test/deps/goldens/dart_executables.txt create mode 100644 test/deps/goldens/dev_dependencies.txt create mode 100644 test/deps/goldens/formatting.txt create mode 100644 test/deps/goldens/from_dependency.txt create mode 100644 test/deps/goldens/non_dart_executables.txt create mode 100644 test/deps/goldens/nothing_in_sub_drectories.txt create mode 100644 test/deps/goldens/only_immediate.txt create mode 100644 test/deps/goldens/overrides.txt diff --git a/lib/src/command/deps.dart b/lib/src/command/deps.dart index 98e68a30f..d061b960f 100644 --- a/lib/src/command/deps.dart +++ b/lib/src/command/deps.dart @@ -3,8 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:collection'; - -import 'package:path/path.dart' as p; +import 'dart:convert'; import '../ascii_tree.dart' as tree; import '../command.dart'; @@ -53,6 +52,10 @@ class DepsCommand extends PubCommand { argParser.addFlag('executables', negatable: false, help: 'List all available executables.'); + argParser.addFlag('json', + negatable: false, + help: 'Output dependency information in a json format.'); + argParser.addOption('directory', abbr: 'C', help: 'Run this in the directory.', valueHelp: 'dir'); } @@ -64,26 +67,98 @@ class DepsCommand extends PubCommand { _buffer = StringBuffer(); - if (argResults['executables']) { - _outputExecutables(); - } else { - for (var sdk in sdks.values) { - if (!sdk.isAvailable) continue; - _buffer.writeln("${log.bold('${sdk.name} SDK')} ${sdk.version}"); + if (argResults['json']) { + if (argResults.wasParsed('dev')) { + usageException( + 'Cannot combine --json and --dev.\nThe json output contains the dependency type in the output.'); } - - _buffer.writeln(_labelPackage(entrypoint.root)); - - switch (argResults['style']) { - case 'compact': - _outputCompact(); - break; - case 'list': - _outputList(); - break; - case 'tree': - _outputTree(); - break; + if (argResults.wasParsed('executables')) { + usageException( + 'Cannot combine --json and --executables.\nThe json output always lists available executables.'); + } + if (argResults.wasParsed('style')) { + usageException('Cannot combine --json and --style.'); + } + final visited = []; + final toVisit = [entrypoint.root.name]; + final packagesJson = []; + while (toVisit.isNotEmpty) { + final current = toVisit.removeLast(); + if (visited.contains(current)) continue; + visited.add(current); + final currentPackage = entrypoint.packageGraph.packages[current]; + final next = (current == entrypoint.root.name + ? entrypoint.root.immediateDependencies + : currentPackage.dependencies) + .keys + .toList(); + final dependencyType = entrypoint.root.dependencyType(current); + final kind = currentPackage == entrypoint.root + ? 'root' + : (dependencyType == DependencyType.direct + ? 'direct' + : (dependencyType == DependencyType.dev + ? 'dev' + : 'transitive')); + final source = + entrypoint.packageGraph.lockFile.packages[current]?.source?.name ?? + 'root'; + packagesJson.add({ + 'name': current, + 'version': currentPackage.version.toString(), + 'kind': kind, + 'source': source, + 'dependencies': next + }); + toVisit.addAll(next); + } + var executables = [ + for (final package in [ + entrypoint.root, + ...entrypoint.root.immediateDependencies.keys + .map((name) => entrypoint.packageGraph.packages[name]) + ]) + ...package.executableNames.map((name) => package == entrypoint.root + ? ':$name' + : (package.name == name ? name : '${package.name}:$name')) + ]; + + _buffer.writeln( + JsonEncoder.withIndent(' ').convert( + { + 'root': entrypoint.root.name, + 'packages': packagesJson, + 'sdks': [ + for (var sdk in sdks.values) + if (sdk.version != null) + {'name': sdk.name, 'version': sdk.version.toString()} + ], + 'executables': executables + }, + ), + ); + } else { + if (argResults['executables']) { + _outputExecutables(); + } else { + for (var sdk in sdks.values) { + if (!sdk.isAvailable) continue; + _buffer.writeln("${log.bold('${sdk.name} SDK')} ${sdk.version}"); + } + + _buffer.writeln(_labelPackage(entrypoint.root)); + + switch (argResults['style']) { + case 'compact': + _outputCompact(); + break; + case 'list': + _outputList(); + break; + case 'tree': + _outputTree(); + break; + } } } @@ -268,34 +343,13 @@ class DepsCommand extends PubCommand { ]; for (var package in packages) { - var executables = _getExecutablesFor(package); + var executables = package.executableNames; if (executables.isNotEmpty) { _buffer.writeln(_formatExecutables(package.name, executables.toList())); } } } - /// Returns `true` if [path] looks like a Dart entrypoint. - bool _isDartExecutable(String path) { - try { - var unit = analysisContextManager.parse(path); - return isEntrypoint(unit); - } on AnalyzerErrorGroup { - return false; - } - } - - /// Lists all Dart files in the `bin` directory of the [package]. - /// - /// Returns file names without extensions. - Iterable _getExecutablesFor(Package package) { - var packagePath = p.normalize(p.absolute(package.dir)); - analysisContextManager.createContextsForDirectory(packagePath); - return package.executablePaths - .where((e) => _isDartExecutable(p.absolute(package.dir, e))) - .map(p.basenameWithoutExtension); - } - /// Returns formatted string that lists [executables] for the [packageName]. /// Examples: /// diff --git a/lib/src/package.dart b/lib/src/package.dart index 55ce4feed..88a290974 100644 --- a/lib/src/package.dart +++ b/lib/src/package.dart @@ -84,6 +84,9 @@ class Package { .toList(); } + List get executableNames => + executablePaths.map(p.basenameWithoutExtension).toList(); + /// Returns the path to the README file at the root of the entrypoint, or null /// if no README file is found. /// diff --git a/test/deps/executables_test.dart b/test/deps/executables_test.dart index 933189f62..88b1a8874 100644 --- a/test/deps/executables_test.dart +++ b/test/deps/executables_test.dart @@ -2,226 +2,163 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:pub/src/ascii_tree.dart' as tree; +import 'package:pub/src/io.dart'; import 'package:test/test.dart'; import '../descriptor.dart' as d; +import '../golden_file.dart'; import '../test_pub.dart'; const _validMain = 'main() {}'; +const _invalidMain = 'main() {'; + +Future variations(String name) async { + final buffer = StringBuffer(); + buffer.writeln( + tree.fromFiles(listDir(d.sandbox, recursive: true), baseDir: d.sandbox)); + + await pubGet(); + await runPubIntoBuffer(['deps', '--executables'], buffer); + await runPubIntoBuffer(['deps', '--executables', '--dev'], buffer); + // The json ouput also lists the exectuables. + await runPubIntoBuffer(['deps', '--json'], buffer); + // The easiest way to update the golden files is to delete them and rerun the + // test. + expectMatchesGoldenFile(buffer.toString(), 'test/deps/goldens/$name.txt'); +} void main() { - Future Function() _testExecutablesOutput(output, {bool dev = true}) => - () async { - await pubGet(); - await runPub( - args: ['deps', '--executables', if (dev) '--dev' else '--no-dev'], - output: output); - }; - - Future Function() _testAllDepsOutput(output) => - _testExecutablesOutput(output); - Future Function() _testNonDevDepsOutput(output) => - _testExecutablesOutput(output, dev: false); - - group('lists nothing when no executables found', () { - setUp(() async { - await d.dir(appPath, [d.appPubspec()]).create(); - }); - - test('all dependencies', _testAllDepsOutput('\n')); - test('non-dev dependencies', _testNonDevDepsOutput('\n')); + test('skips non-Dart executables', () async { + await d.dir(appPath, [ + d.appPubspec(), + d.dir('bin', [d.file('foo.py'), d.file('bar.sh')]) + ]).create(); + await variations('non_dart_executables'); }); - group('skips non-Dart executables', () { - setUp(() async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [d.file('foo.py'), d.file('bar.sh')]) - ]).create(); - }); - - test('all dependencies', _testAllDepsOutput('\n')); - test('non-dev dependencies', _testNonDevDepsOutput('\n')); + test('lists Dart executables, even without entrypoints', () async { + await d.dir(appPath, [ + d.appPubspec(), + d.dir( + 'bin', + [d.file('foo.dart', _validMain), d.file('bar.dart', _invalidMain)], + ) + ]).create(); + await variations('dart_executables'); }); - group('skips Dart executables which are not parsable', () { - setUp(() async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [d.file('foo.dart', 'main() {')]) - ]).create(); - }); - - test('all dependencies', _testAllDepsOutput('\n')); - test('non-dev dependencies', _testNonDevDepsOutput('\n')); + test('skips executables in sub directories', () async { + await d.dir(appPath, [ + d.appPubspec(), + d.dir('bin', [ + d.file('foo.dart', _validMain), + d.dir('sub', [d.file('bar.dart', _validMain)]) + ]) + ]).create(); + await variations('nothing_in_sub_drectories'); }); - group('skips Dart executables without entrypoints', () { - setUp(() async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir( - 'bin', [d.file('foo.dart'), d.file('bar.dart', 'main(x, y, z) {}')]) - ]).create(); - }); - - test('all dependencies', _testAllDepsOutput('\n')); - test('non-dev dependencies', _testNonDevDepsOutput('\n')); - }); + test('lists executables from a dependency', () async { + await d.dir('foo', [ + d.libPubspec('foo', '1.0.0'), + d.dir('bin', [d.file('bar.dart', _validMain)]) + ]).create(); - group('lists valid Dart executables with entrypoints', () { - setUp(() async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', - [d.file('foo.dart', _validMain), d.file('bar.dart', _validMain)]) - ]).create(); - }); - - test('all dependencies', _testAllDepsOutput('myapp: bar, foo')); - test('non-dev dependencies', _testNonDevDepsOutput('myapp: bar, foo')); - }); + await d.dir(appPath, [ + d.appPubspec({ + 'foo': {'path': '../foo'} + }) + ]).create(); - group('skips executables in sub directories', () { - setUp(() async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [ - d.file('foo.dart', _validMain), - d.dir('sub', [d.file('bar.dart', _validMain)]) - ]) - ]).create(); - }); - - test('all dependencies', _testAllDepsOutput('myapp:foo')); - test('non-dev dependencies', _testNonDevDepsOutput('myapp:foo')); + await variations('from_dependency'); }); - group('lists executables from a dependency', () { - setUp(() async { - await d.dir('foo', [ - d.libPubspec('foo', '1.0.0'), - d.dir('bin', [d.file('bar.dart', _validMain)]) - ]).create(); - - await d.dir(appPath, [ - d.appPubspec({ - 'foo': {'path': '../foo'} - }) - ]).create(); - }); - - test('all dependencies', _testAllDepsOutput('foo:bar')); - test('non-dev dependencies', _testNonDevDepsOutput('foo:bar')); + test('lists executables only from immediate dependencies', () async { + await d.dir(appPath, [ + d.appPubspec({ + 'foo': {'path': '../foo'} + }) + ]).create(); + + await d.dir('foo', [ + d.libPubspec('foo', '1.0.0', deps: { + 'baz': {'path': '../baz'} + }), + d.dir('bin', [d.file('bar.dart', _validMain)]) + ]).create(); + + await d.dir('baz', [ + d.libPubspec('baz', '1.0.0'), + d.dir('bin', [d.file('qux.dart', _validMain)]) + ]).create(); + + await variations('only_immediate'); }); - group('lists executables only from immediate dependencies', () { - setUp(() async { - await d.dir(appPath, [ - d.appPubspec({ - 'foo': {'path': '../foo'} - }) - ]).create(); - - await d.dir('foo', [ - d.libPubspec('foo', '1.0.0', deps: { - 'baz': {'path': '../baz'} - }), - d.dir('bin', [d.file('bar.dart', _validMain)]) - ]).create(); - - await d.dir('baz', [ - d.libPubspec('baz', '1.0.0'), - d.dir('bin', [d.file('qux.dart', _validMain)]) - ]).create(); - }); - - test('all dependencies', _testAllDepsOutput('foo:bar')); - test('non-dev dependencies', _testNonDevDepsOutput('foo:bar')); + test('applies formatting before printing executables', () async { + await d.dir(appPath, [ + d.appPubspec({ + 'foo': {'path': '../foo'}, + 'bar': {'path': '../bar'} + }), + d.dir('bin', [d.file('myapp.dart', _validMain)]) + ]).create(); + + await d.dir('foo', [ + d.libPubspec('foo', '1.0.0'), + d.dir('bin', + [d.file('baz.dart', _validMain), d.file('foo.dart', _validMain)]) + ]).create(); + + await d.dir('bar', [ + d.libPubspec('bar', '1.0.0'), + d.dir('bin', [d.file('qux.dart', _validMain)]) + ]).create(); + + await variations('formatting'); }); - group('applies formatting before printing executables', () { - setUp(() async { - await d.dir(appPath, [ - d.appPubspec({ - 'foo': {'path': '../foo'}, - 'bar': {'path': '../bar'} - }), - d.dir('bin', [d.file('myapp.dart', _validMain)]) - ]).create(); - - await d.dir('foo', [ - d.libPubspec('foo', '1.0.0'), - d.dir('bin', - [d.file('baz.dart', _validMain), d.file('foo.dart', _validMain)]) - ]).create(); - - await d.dir('bar', [ - d.libPubspec('bar', '1.0.0'), - d.dir('bin', [d.file('qux.dart', _validMain)]) - ]).create(); - }); - - test('all dependencies', _testAllDepsOutput(''' - myapp - foo: foo, baz - bar:qux''')); - test('non-dev dependencies', _testNonDevDepsOutput(''' - myapp - foo: foo, baz - bar:qux''')); - }); + test('dev dependencies', () async { + await d.dir('foo', [ + d.libPubspec('foo', '1.0.0'), + d.dir('bin', [d.file('bar.dart', _validMain)]) + ]).create(); - group('dev dependencies', () { - setUp(() async { - await d.dir('foo', [ - d.libPubspec('foo', '1.0.0'), - d.dir('bin', [d.file('bar.dart', _validMain)]) - ]).create(); - - await d.dir(appPath, [ - d.pubspec({ - 'name': 'myapp', - 'dev_dependencies': { - 'foo': {'path': '../foo'} - } - }) - ]).create(); - }); - - test('are listed if --dev flag is set', _testAllDepsOutput('foo:bar')); - test('are skipped if --no-dev flag is set', _testNonDevDepsOutput('\n')); + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'dev_dependencies': { + 'foo': {'path': '../foo'} + } + }) + ]).create(); + await variations('dev_dependencies'); }); - group('overriden dependencies executables', () { - setUp(() async { - await d.dir('foo-1.0', [ - d.libPubspec('foo', '1.0.0'), - d.dir('bin', [d.file('bar.dart', _validMain)]) - ]).create(); - - await d.dir('foo-2.0', [ - d.libPubspec('foo', '2.0.0'), - d.dir('bin', - [d.file('bar.dart', _validMain), d.file('baz.dart', _validMain)]) - ]).create(); - - await d.dir(appPath, [ - d.pubspec({ - 'name': 'myapp', - 'dependencies': { - 'foo': {'path': '../foo-1.0'} - }, - 'dependency_overrides': { - 'foo': {'path': '../foo-2.0'} - } - }) - ]).create(); - }); - - test( - 'are listed if --dev flag is set', _testAllDepsOutput('foo: bar, baz')); - test('are listed if --no-dev flag is set', - _testNonDevDepsOutput('foo: bar, baz')); + test('overriden dependencies executables', () async { + await d.dir('foo-1.0', [ + d.libPubspec('foo', '1.0.0'), + d.dir('bin', [d.file('bar.dart', _validMain)]) + ]).create(); + + await d.dir('foo-2.0', [ + d.libPubspec('foo', '2.0.0'), + d.dir('bin', + [d.file('bar.dart', _validMain), d.file('baz.dart', _validMain)]) + ]).create(); + + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'dependencies': { + 'foo': {'path': '../foo-1.0'} + }, + 'dependency_overrides': { + 'foo': {'path': '../foo-2.0'} + } + }) + ]).create(); + await variations('overrides'); }); } diff --git a/test/deps/goldens/dart_executables.txt b/test/deps/goldens/dart_executables.txt new file mode 100644 index 000000000..9284ceb2a --- /dev/null +++ b/test/deps/goldens/dart_executables.txt @@ -0,0 +1,36 @@ +'-- myapp + |-- bin + | |-- bar.dart + | '-- foo.dart + '-- pubspec.yaml + +$ pub deps --executables +myapp: bar, foo + +$ pub deps --executables --dev +myapp: bar, foo + +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [ + ":bar", + ":foo" + ] +} + diff --git a/test/deps/goldens/dev_dependencies.txt b/test/deps/goldens/dev_dependencies.txt new file mode 100644 index 000000000..3fb677c1d --- /dev/null +++ b/test/deps/goldens/dev_dependencies.txt @@ -0,0 +1,45 @@ +|-- foo +| |-- bin +| | '-- bar.dart +| '-- pubspec.yaml +'-- myapp + '-- pubspec.yaml + +$ pub deps --executables +foo:bar + +$ pub deps --executables --dev +foo:bar + +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [ + "foo" + ] + }, + { + "name": "foo", + "version": "1.0.0", + "kind": "dev", + "source": "path", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [ + "foo:bar" + ] +} + diff --git a/test/deps/goldens/formatting.txt b/test/deps/goldens/formatting.txt new file mode 100644 index 000000000..ff5aec96b --- /dev/null +++ b/test/deps/goldens/formatting.txt @@ -0,0 +1,67 @@ +|-- bar +| |-- bin +| | '-- qux.dart +| '-- pubspec.yaml +|-- foo +| |-- bin +| | |-- baz.dart +| | '-- foo.dart +| '-- pubspec.yaml +'-- myapp + |-- bin + | '-- myapp.dart + '-- pubspec.yaml + +$ pub deps --executables +myapp +foo: foo, baz +bar:qux + +$ pub deps --executables --dev +myapp +foo: foo, baz +bar:qux + +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [ + "foo", + "bar" + ] + }, + { + "name": "bar", + "version": "1.0.0", + "kind": "direct", + "source": "path", + "dependencies": [] + }, + { + "name": "foo", + "version": "1.0.0", + "kind": "direct", + "source": "path", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [ + ":myapp", + "foo:baz", + "foo", + "bar:qux" + ] +} + diff --git a/test/deps/goldens/from_dependency.txt b/test/deps/goldens/from_dependency.txt new file mode 100644 index 000000000..30836e551 --- /dev/null +++ b/test/deps/goldens/from_dependency.txt @@ -0,0 +1,45 @@ +|-- foo +| |-- bin +| | '-- bar.dart +| '-- pubspec.yaml +'-- myapp + '-- pubspec.yaml + +$ pub deps --executables +foo:bar + +$ pub deps --executables --dev +foo:bar + +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [ + "foo" + ] + }, + { + "name": "foo", + "version": "1.0.0", + "kind": "direct", + "source": "path", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [ + "foo:bar" + ] +} + diff --git a/test/deps/goldens/non_dart_executables.txt b/test/deps/goldens/non_dart_executables.txt new file mode 100644 index 000000000..646e21eb3 --- /dev/null +++ b/test/deps/goldens/non_dart_executables.txt @@ -0,0 +1,31 @@ +'-- myapp + |-- bin + | |-- bar.sh + | '-- foo.py + '-- pubspec.yaml + +$ pub deps --executables + +$ pub deps --executables --dev + +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [] +} + diff --git a/test/deps/goldens/nothing_in_sub_drectories.txt b/test/deps/goldens/nothing_in_sub_drectories.txt new file mode 100644 index 000000000..db3c77c52 --- /dev/null +++ b/test/deps/goldens/nothing_in_sub_drectories.txt @@ -0,0 +1,36 @@ +'-- myapp + |-- bin + | |-- foo.dart + | '-- sub + | '-- bar.dart + '-- pubspec.yaml + +$ pub deps --executables +myapp:foo + +$ pub deps --executables --dev +myapp:foo + +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [ + ":foo" + ] +} + diff --git a/test/deps/goldens/only_immediate.txt b/test/deps/goldens/only_immediate.txt new file mode 100644 index 000000000..5e429257c --- /dev/null +++ b/test/deps/goldens/only_immediate.txt @@ -0,0 +1,58 @@ +|-- baz +| |-- bin +| | '-- qux.dart +| '-- pubspec.yaml +|-- foo +| |-- bin +| | '-- bar.dart +| '-- pubspec.yaml +'-- myapp + '-- pubspec.yaml + +$ pub deps --executables +foo:bar + +$ pub deps --executables --dev +foo:bar + +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [ + "foo" + ] + }, + { + "name": "foo", + "version": "1.0.0", + "kind": "direct", + "source": "path", + "dependencies": [ + "baz" + ] + }, + { + "name": "baz", + "version": "1.0.0", + "kind": "transitive", + "source": "path", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [ + "foo:bar" + ] +} + diff --git a/test/deps/goldens/overrides.txt b/test/deps/goldens/overrides.txt new file mode 100644 index 000000000..ab76e7996 --- /dev/null +++ b/test/deps/goldens/overrides.txt @@ -0,0 +1,51 @@ +|-- foo-1.0 +| |-- bin +| | '-- bar.dart +| '-- pubspec.yaml +|-- foo-2.0 +| |-- bin +| | |-- bar.dart +| | '-- baz.dart +| '-- pubspec.yaml +'-- myapp + '-- pubspec.yaml + +$ pub deps --executables +foo: bar, baz + +$ pub deps --executables --dev +foo: bar, baz + +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [ + "foo" + ] + }, + { + "name": "foo", + "version": "2.0.0", + "kind": "direct", + "source": "path", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [ + "foo:bar", + "foo:baz" + ] +} + diff --git a/test/deps_test.dart b/test/deps_test.dart index d1ab44d6a..207e8e739 100644 --- a/test/deps_test.dart +++ b/test/deps_test.dart @@ -130,6 +130,128 @@ void main() { '-- myapp... '''); }); + test('in json form', () async { + await pubGet(); + await runPub(args: ['deps', '--json'], output: ''' +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [ + "normal", + "overridden", + "from_path", + "unittest", + "override_only" + ] + }, + { + "name": "override_only", + "version": "1.2.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [] + }, + { + "name": "unittest", + "version": "1.2.3", + "kind": "dev", + "source": "hosted", + "dependencies": [ + "shared", + "dev_only" + ] + }, + { + "name": "dev_only", + "version": "1.2.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [] + }, + { + "name": "shared", + "version": "1.2.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "other" + ] + }, + { + "name": "other", + "version": "1.0.0", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "myapp" + ] + }, + { + "name": "from_path", + "version": "1.2.3", + "kind": "direct", + "source": "path", + "dependencies": [] + }, + { + "name": "overridden", + "version": "2.0.0", + "kind": "direct", + "source": "hosted", + "dependencies": [] + }, + { + "name": "normal", + "version": "1.2.3", + "kind": "direct", + "source": "hosted", + "dependencies": [ + "transitive", + "circular_a" + ] + }, + { + "name": "circular_a", + "version": "1.2.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "circular_b" + ] + }, + { + "name": "circular_b", + "version": "1.2.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "circular_a" + ] + }, + { + "name": "transitive", + "version": "1.2.3", + "kind": "transitive", + "source": "hosted", + "dependencies": [ + "shared" + ] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [] +}'''); + }); test('with the Flutter SDK, if applicable', () async { await pubGet();