diff --git a/lib/src/command/global.dart b/lib/src/command/global.dart index 8c2105ca6ef019568f37584970d7f3687d94d8a1..c1b17302f6fd0a2e627a4c943f2b8b01651d2d78 100644 --- a/lib/src/command/global.dart +++ b/lib/src/command/global.dart @@ -7,6 +7,7 @@ library pub.command.global; import '../command.dart'; import 'global_activate.dart'; import 'global_deactivate.dart'; +import 'global_list.dart'; import 'global_run.dart'; /// Handles the `global` pub command. @@ -17,6 +18,7 @@ class GlobalCommand extends PubCommand { final subcommands = { "activate": new GlobalActivateCommand(), "deactivate": new GlobalDeactivateCommand(), + "list": new GlobalListCommand(), "run": new GlobalRunCommand() }; } diff --git a/lib/src/command/global_list.dart b/lib/src/command/global_list.dart new file mode 100644 index 0000000000000000000000000000000000000000..c498b42545ba87e2c1ae911866cda2036145b927 --- /dev/null +++ b/lib/src/command/global_list.dart @@ -0,0 +1,21 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// 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. + +library pub.command.global_list; + +import 'dart:async'; + +import '../command.dart'; + +/// Handles the `global list` pub command. +class GlobalListCommand extends PubCommand { + bool get allowTrailingOptions => false; + String get description => 'List globally activated packages.'; + String get usage => 'pub global list'; + + Future onRun() { + globals.listActivePackages(); + return null; + } +} diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart index d762507354f30642062949cdae9e8ac54893b8e6..bbb289a50e740578e00f8e128e92d1fb09d31c51 100644 --- a/lib/src/global_packages.dart +++ b/lib/src/global_packages.dart @@ -147,40 +147,29 @@ class GlobalPackages { lockFile.serialize(cache.rootDir, cache.sources)); var id = lockFile.packages[package]; - if (id.source == "git") { - var url = GitSource.urlFromDescription(id.description); - log.message('Activated ${log.bold(id.name)} ${id.version} from Git ' - 'repository "$url".'); - } else if (id.source == "path") { - var path = PathSource.pathFromDescription(id.description); - log.message('Activated ${log.bold(id.name)} ${id.version} at path ' - '"$path".'); - } else { - log.message("Activated ${log.bold(id.name)} ${id.version}."); - } + log.message('Activated ${_formatPackage(id)}.'); // TODO(rnystrom): Look in "bin" and display list of binaries that // user can run. } /// Shows the user the currently active package with [name], if any. - void _describeActive(String package) { + void _describeActive(String name) { try { - var lockFile = new LockFile.load(_getLockFilePath(package), - cache.sources); - var id = lockFile.packages[package]; + var lockFile = new LockFile.load(_getLockFilePath(name), cache.sources); + var id = lockFile.packages[name]; - if (id.source == "git") { + if (id.source == 'git') { var url = GitSource.urlFromDescription(id.description); - log.message('Package ${log.bold(id.name)} is currently active from ' - 'Git repository "${url}".'); - } else if (id.source == "path") { + log.message('Package ${log.bold(name)} is currently active from Git ' + 'repository "${url}".'); + } else if (id.source == 'path') { var path = PathSource.pathFromDescription(id.description); - log.message('Package ${log.bold(package)} is currently active at ' - 'path "$path".'); + log.message('Package ${log.bold(name)} is currently active at path ' + '"$path".'); } else { - log.message("Package ${log.bold(package)} is currently active at " - "version ${log.bold(id.version)}."); + log.message('Package ${log.bold(name)} is currently active at version ' + '${log.bold(id.version)}.'); } } on IOException catch (error) { // If we couldn't read the lock file, it's not activated. @@ -190,7 +179,7 @@ class GlobalPackages { /// Deactivates a previously-activated package named [name]. /// - /// If [logDeletion] is true, displays to the user when a package is + /// If [logDeactivate] is true, displays to the user when a package is /// deactivated. Otherwise, deactivates silently. /// /// Returns `false` if no package with [name] was currently active. @@ -204,16 +193,7 @@ class GlobalPackages { deleteEntry(lockFilePath); if (logDeactivate) { - if (id.source == "git") { - var url = GitSource.urlFromDescription(id.description); - log.message('Deactivated package ${log.bold(name)} from Git repository ' - '"$url".'); - } else if (id.source == "path") { - var path = PathSource.pathFromDescription(id.description); - log.message('Deactivated package ${log.bold(name)} at path "$path".'); - } else { - log.message("Deactivated package ${log.bold(name)} ${id.version}."); - } + log.message('Deactivated package ${_formatPackage(id)}.'); } return true; @@ -258,4 +238,38 @@ class GlobalPackages { /// Gets the path to the lock file for an activated cached package with /// [name]. String _getLockFilePath(name) => p.join(_directory, name + ".lock"); + + /// Shows to the user formatted list of globally activated packages. + void listActivePackages() { + if (!dirExists(_directory)) return; + + // Loads lock [file] and returns [PackageId] of the activated package. + loadPackageId(file) { + var name = p.basenameWithoutExtension(file); + var lockFile = new LockFile.load(p.join(_directory, file), cache.sources); + return lockFile.packages[name]; + } + + var packages = listDir(_directory, includeDirs: false) + .where((file) => p.extension(file) == '.lock') + .map(loadPackageId) + .toList(); + + packages + ..sort((id1, id2) => id1.name.compareTo(id2.name)) + ..forEach((id) => log.message(_formatPackage(id))); + } + + /// Returns formatted string representing the package [id]. + String _formatPackage(PackageId id) { + if (id.source == 'git') { + var url = GitSource.urlFromDescription(id.description); + return '${log.bold(id.name)} ${id.version} from Git repository "$url"'; + } else if (id.source == 'path') { + var path = PathSource.pathFromDescription(id.description); + return '${log.bold(id.name)} ${id.version} at path "$path"'; + } else { + return '${log.bold(id.name)} ${id.version}'; + } + } } diff --git a/test/global/deactivate/git_package_test.dart b/test/global/deactivate/git_package_test.dart index cc191913b5cb662dec824b80a8e03dbd6f3edcf2..3d14d91eee11ca28741fa1d365914f0ccf224395 100644 --- a/test/global/deactivate/git_package_test.dart +++ b/test/global/deactivate/git_package_test.dart @@ -20,6 +20,6 @@ main() { schedulePub(args: ["global", "activate", "-sgit", "../foo.git"]); schedulePub(args: ["global", "deactivate", "foo"], - output: 'Deactivated package foo from Git repository "../foo.git".'); + output: 'Deactivated package foo 1.0.0 from Git repository "../foo.git".'); }); } diff --git a/test/global/deactivate/path_package_test.dart b/test/global/deactivate/path_package_test.dart index 90047f613d5fed347edf8070f484f8aa08dbe77f..3241efc47f6245c474efed8463f1b70cb136b3c7 100644 --- a/test/global/deactivate/path_package_test.dart +++ b/test/global/deactivate/path_package_test.dart @@ -22,6 +22,6 @@ main() { var path = canonicalize(p.join(sandboxDir, "foo")); schedulePub(args: ["global", "deactivate", "foo"], - output: 'Deactivated package foo at path "$path".'); + output: 'Deactivated package foo 1.0.0 at path "$path".'); }); } diff --git a/test/global/list_test.dart b/test/global/list_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..6286c722d481ac36374e87704bd233324b6eca00 --- /dev/null +++ b/test/global/list_test.dart @@ -0,0 +1,76 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// 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:path/path.dart' as p; + +import '../../lib/src/io.dart'; +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +main() { + initConfig(); + + integration('lists an activated hosted package', () { + servePackages([ + packageMap('foo', '1.0.0') + ]); + + schedulePub(args: ['global', 'activate', 'foo']); + + schedulePub(args: ['global', 'list'], output: 'foo 1.0.0'); + }); + + integration('lists an activated Git package', () { + ensureGit(); + + d.git('foo.git', [ + d.libPubspec('foo', '1.0.0'), + d.dir('bin', [ + d.file('foo.dart', 'main() => print("ok");') + ]) + ]).create(); + + schedulePub(args: ['global', 'activate', '-sgit', '../foo.git']); + + schedulePub(args: ['global', 'list'], + output: 'foo 1.0.0 from Git repository "../foo.git"'); + }); + + integration('lists an activated Path package', () { + d.dir('foo', [ + d.libPubspec('foo', '1.0.0'), + d.dir('bin', [ + d.file('foo.dart', 'main() => print("ok");') + ]) + ]).create(); + + schedulePub(args: ['global', 'activate', '-spath', '../foo']); + + var path = canonicalize(p.join(sandboxDir, 'foo')); + schedulePub(args: ['global', 'list'], + output: 'foo 1.0.0 at path "$path"'); + }); + + integration('lists activated packages in alphabetical order', () { + servePackages([ + packageMap('aaa', '1.0.0'), + packageMap('bbb', '1.0.0'), + packageMap('ccc', '1.0.0') + ]); + + schedulePub(args: ['global', 'activate', 'ccc']); + schedulePub(args: ['global', 'activate', 'aaa']); + schedulePub(args: ['global', 'activate', 'bbb']); + + schedulePub(args: ['global', 'list'], output: ''' +aaa 1.0.0 +bbb 1.0.0 +ccc 1.0.0 +'''); + }); + + integration('lists nothing when no packages activated', () { + schedulePub(args: ['global', 'list'], output: '\n'); + }); +}