Skip to content

Commit 9c3d6e0

Browse files
committed
added "pub deps --executables" command to show all available executables
* removed "run --list" command * buffer is used to output executables * tests were adapted to verify --dev/--no-dev flag
1 parent 3d32057 commit 9c3d6e0

6 files changed

+314
-211
lines changed

lib/src/command/deps.dart

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,26 @@
44

55
import 'dart:collection';
66

7+
import 'package:analyzer/analyzer.dart' as analyzer;
8+
import 'package:path/path.dart' as p;
9+
710
import '../ascii_tree.dart' as tree;
811
import '../command.dart';
12+
import '../dart.dart';
913
import '../log.dart' as log;
1014
import '../package.dart';
1115
import '../utils.dart';
1216

17+
/// Returns `true` if [path] looks like a Dart entrypoint.
18+
bool _isDartExecutable(String path) {
19+
try {
20+
var unit = analyzer.parseDartFile(path, parseFunctionBodies: false);
21+
return isEntrypoint(unit);
22+
} on analyzer.AnalyzerErrorGroup {
23+
return false;
24+
}
25+
}
26+
1327
/// Handles the `deps` pub command.
1428
class DepsCommand extends PubCommand {
1529
String get name => "deps";
@@ -36,6 +50,9 @@ class DepsCommand extends PubCommand {
3650
negatable: true,
3751
help: "Whether to include dev dependencies.",
3852
defaultsTo: true);
53+
54+
argParser.addFlag("executables",
55+
negatable: false, help: "List all available executables.");
3956
}
4057

4158
void run() {
@@ -44,18 +61,22 @@ class DepsCommand extends PubCommand {
4461

4562
_buffer = new StringBuffer();
4663

47-
_buffer.writeln(_labelPackage(entrypoint.root));
48-
49-
switch (argResults["style"]) {
50-
case "compact":
51-
_outputCompact();
52-
break;
53-
case "list":
54-
_outputList();
55-
break;
56-
case "tree":
57-
_outputTree();
58-
break;
64+
if (argResults['executables']) {
65+
_outputExecutables();
66+
} else {
67+
_buffer.writeln(_labelPackage(entrypoint.root));
68+
69+
switch (argResults["style"]) {
70+
case "compact":
71+
_outputCompact();
72+
break;
73+
case "list":
74+
_outputList();
75+
break;
76+
case "tree":
77+
_outputTree();
78+
break;
79+
}
5980
}
6081

6182
log.message(_buffer);
@@ -231,4 +252,60 @@ class DepsCommand extends PubCommand {
231252
'was generated, please run "pub get" again.');
232253
return null;
233254
}
255+
256+
/// Outputs all executables reachable from [entrypoint].
257+
void _outputExecutables() {
258+
var packages = []
259+
..add(entrypoint.root)
260+
..addAll((_includeDev
261+
? entrypoint.root.immediateDependencies
262+
: entrypoint.root.dependencies)
263+
.map((dep) => entrypoint.packageGraph.packages[dep.name]));
264+
265+
for (var package in packages) {
266+
var executables = _getExecutablesFor(package);
267+
if (executables.isNotEmpty) {
268+
_buffer.writeln(_formatExecutables(package.name, executables.toList()));
269+
}
270+
}
271+
}
272+
273+
/// Lists all Dart files in the `bin` directory of the [package].
274+
///
275+
/// Returns file names without extensions.
276+
List<String> _getExecutablesFor(Package package) => package.executableIds
277+
.where((e) => _isDartExecutable(p.absolute(package.dir, e.path)))
278+
.map((e) => p.basenameWithoutExtension(e.path));
279+
280+
/// Returns formatted string that lists [executables] for the [packageName].
281+
/// Examples:
282+
///
283+
/// _formatExecutables('foo', ['foo']) // -> 'foo'
284+
/// _formatExecutables('foo', ['bar']) // -> 'foo:bar'
285+
/// _formatExecutables('foo', ['bar', 'foo']) // -> 'foo: foo, bar'
286+
///
287+
/// Note the leading space before first executable and sorting order in the
288+
/// last example.
289+
String _formatExecutables(String packageName, List<String> executables) {
290+
if (executables.length == 1) {
291+
// If executable matches the package name omit the name of executable in
292+
// the output.
293+
return executables.first != packageName
294+
? '${packageName}:${log.bold(executables.first)}'
295+
: log.bold(executables.first);
296+
}
297+
298+
// Sort executables to make executable that matches the package name to be
299+
// the first in the list.
300+
executables.sort((e1, e2) {
301+
if (e1 == packageName)
302+
return -1;
303+
else if (e2 == packageName)
304+
return 1;
305+
else
306+
return e1.compareTo(e2);
307+
});
308+
309+
return '${packageName}: ${executables.map(log.bold).join(', ')}';
310+
}
234311
}

lib/src/command/run.dart

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import 'package:path/path.dart' as p;
1010
import '../command.dart';
1111
import '../executable.dart';
1212
import '../io.dart';
13-
import '../log.dart' as log;
14-
import '../package.dart';
1513
import '../utils.dart';
1614

1715
/// Handles the `run` pub command.
@@ -24,20 +22,13 @@ class RunCommand extends PubCommand {
2422
RunCommand() {
2523
argParser.addFlag("checked",
2624
abbr: "c", help: "Enable runtime type checks and assertions.");
27-
argParser.addFlag('list', negatable: false,
28-
help: 'List all available executables.');
2925
argParser.addOption("mode",
3026
help: 'Mode to run transformers in.\n'
3127
'(defaults to "release" for dependencies, "debug" for '
3228
'entrypoint)');
3329
}
3430

3531
Future run() async {
36-
if (argResults['list']) {
37-
_listExecutables();
38-
return;
39-
}
40-
4132
if (argResults.rest.isEmpty) {
4233
usageException("Must specify an executable to run.");
4334
}
@@ -78,58 +69,4 @@ class RunCommand extends PubCommand {
7869
checked: argResults['checked'], mode: mode);
7970
await flushThenExit(exitCode);
8071
}
81-
82-
/// Lists all executables reachable from [entrypoint].
83-
void _listExecutables() {
84-
var packages = []
85-
..add(entrypoint.root)
86-
..addAll(entrypoint.root.immediateDependencies
87-
.map((dep) => entrypoint.packageGraph.packages[dep.name]));
88-
89-
packages.forEach((Package package) {
90-
var executables = _listExecutablesFor(package);
91-
if (executables.isNotEmpty) {
92-
log.message(_formatExecutables(package.name, executables.toList()));
93-
}
94-
});
95-
}
96-
97-
/// Lists all Dart files in the `bin` directory of the [package].
98-
///
99-
/// Returns file names without extensions.
100-
List<String> _listExecutablesFor(Package package) {
101-
return package
102-
.listFiles(beneath: 'bin', recursive: false)
103-
.where((executable) => p.extension(executable) == '.dart')
104-
.map(p.basenameWithoutExtension);
105-
}
106-
107-
/// Returns formatted string that lists [executables] for the [packageName].
108-
/// Examples:
109-
///
110-
/// _formatExecutables('foo', ['foo']) // -> 'foo'
111-
/// _formatExecutables('foo', ['bar']) // -> 'foo:bar'
112-
/// _formatExecutables('foo', ['bar', 'foo']) // -> 'foo: foo, bar'
113-
///
114-
/// Note the leading space before first executable and sorting order in the
115-
/// last example.
116-
String _formatExecutables(String packageName, List<String> executables) {
117-
if (executables.length == 1) {
118-
// If executable matches the package name omit the name of executable in
119-
// the output.
120-
return executables.first != packageName
121-
? '${log.bold(packageName)}:${executables.first}'
122-
: log.bold(packageName);
123-
} else {
124-
// Sort executables to make executable that matches the package name to be
125-
// the first in the list.
126-
executables.sort((e1, e2) {
127-
if (e1 == packageName) return -1;
128-
else if (e2 == packageName) return 1;
129-
else return e1.compareTo(e2);
130-
});
131-
132-
return '${log.bold(packageName)}: ${executables.join(', ')}';
133-
}
134-
}
13572
}

0 commit comments

Comments
 (0)