diff --git a/cli/dcoscli/config/main.py b/cli/dcoscli/config/main.py index 3e27595..ee3d48d 100644 --- a/cli/dcoscli/config/main.py +++ b/cli/dcoscli/config/main.py @@ -379,7 +379,7 @@ def _get_config_schema(command): 'dcoscli', 'data/config-schema/core.json').decode('utf-8')) - executable = subcommand.command_executables(command, util.dcos_path()) + executable = subcommand.command_executables(command) return subcommand.config_schema(executable) diff --git a/cli/dcoscli/help/main.py b/cli/dcoscli/help/main.py index e51fef8..94347f0 100644 --- a/cli/dcoscli/help/main.py +++ b/cli/dcoscli/help/main.py @@ -59,7 +59,7 @@ def _help(show_info): directory = util.dcos_path() logger.debug("DCOS Path: {!r}".format(directory)) - paths = subcommand.list_paths(directory) + paths = subcommand.list_paths() with ThreadPoolExecutor(max_workers=len(paths)) as executor: results = executor.map(subcommand.documentation, paths) commands_message = options.make_command_summary_string(sorted(results)) diff --git a/cli/dcoscli/main.py b/cli/dcoscli/main.py index 457ade8..0268f39 100644 --- a/cli/dcoscli/main.py +++ b/cli/dcoscli/main.py @@ -81,7 +81,7 @@ def _main(): if not command: command = "help" - executable = subcommand.command_executables(command, util.dcos_path()) + executable = subcommand.command_executables(command) subproc = Popen([executable, command] + args[''], stderr=PIPE) diff --git a/cli/dcoscli/package/main.py b/cli/dcoscli/package/main.py index 94a30ab..7fca5b9 100644 --- a/cli/dcoscli/package/main.py +++ b/cli/dcoscli/package/main.py @@ -45,6 +45,7 @@ Configuration: ] """ import json +import os import sys import dcoscli @@ -348,6 +349,16 @@ def _install(package_name, options_path, app_id, cli, app, yes): subcommand.install(pkg, pkg_version, options) + subcommand_paths = subcommand.get_package_commands(package_name) + new_commands = [os.path.basename(p).replace('-', ' ', 1) + for p in subcommand_paths] + + if new_commands: + commands = ', '.join(new_commands) + plural = "s" if len(new_commands) > 1 else "" + emitter.publish("New command{} available: {}".format(plural, + commands)) + post_install_notes = pkg.package_json(pkg_version).get('postInstallNotes') if post_install_notes: emitter.publish(post_install_notes) diff --git a/cli/tests/integrations/test_package.py b/cli/tests/integrations/test_package.py index e355993..61110ee 100644 --- a/cli/tests/integrations/test_package.py +++ b/cli/tests/integrations/test_package.py @@ -537,6 +537,7 @@ def test_uninstall_multiple_apps(): b'Installing package [helloworld] version [0.1.0] ' + b'with app id [/helloworld-1]\n' b'Installing CLI subcommand for package [helloworld]\n' + b'New command available: dcos helloworld\n' b'A sample post-installation message\n') _install_helloworld(['--yes', '--app-id=/helloworld-1'], @@ -546,6 +547,7 @@ def test_uninstall_multiple_apps(): b'Installing package [helloworld] version [0.1.0] ' + b'with app id [/helloworld-2]\n' b'Installing CLI subcommand for package [helloworld]\n' + b'New command available: dcos helloworld\n' b'A sample post-installation message\n') _install_helloworld(['--yes', '--app-id=/helloworld-2'], @@ -594,6 +596,7 @@ def test_install_yes(): b'Continue installing? [yes/no] ' b'Installing package [helloworld] version [0.1.0]\n' b'Installing CLI subcommand for package [helloworld]\n' + b'New command available: dcos helloworld\n' b'A sample post-installation message\n') _uninstall_helloworld() @@ -642,6 +645,7 @@ version-1.x.zip", stdout = (b"A sample pre-installation message\n" b"Installing CLI subcommand for package [helloworld]\n" + b'New command available: dcos helloworld\n' b"A sample post-installation message\n") _install_helloworld(args=['--cli', '--yes'], stdout=stdout) @@ -762,6 +766,7 @@ def _install_helloworld( stdout=b'A sample pre-installation message\n' b'Installing package [helloworld] version [0.1.0]\n' b'Installing CLI subcommand for package [helloworld]\n' + b'New command available: dcos helloworld\n' b'A sample post-installation message\n', returncode=0, stdin=None): @@ -826,6 +831,7 @@ def _helloworld(): stdout = b'''A sample pre-installation message Installing package [helloworld] version [0.1.0] Installing CLI subcommand for package [helloworld] +New command available: dcos helloworld A sample post-installation message ''' return _package('helloworld', diff --git a/dcos/package.py b/dcos/package.py index 577f8b7..c40595b 100644 --- a/dcos/package.py +++ b/dcos/package.py @@ -374,7 +374,7 @@ def installed_subcommands(): """ return [subcommand.InstalledSubcommand(name) for name in - subcommand.distributions(util.dcos_path())] + subcommand.distributions()] def installed_apps(init_client, endpoints=False): diff --git a/dcos/subcommand.py b/dcos/subcommand.py index 78a0845..c01dcdf 100644 --- a/dcos/subcommand.py +++ b/dcos/subcommand.py @@ -11,20 +11,18 @@ from dcos.errors import DCOSException logger = util.get_logger(__name__) -def command_executables(subcommand, dcos_path): +def command_executables(subcommand): """List the real path to executable dcos program for specified subcommand. :param subcommand: name of subcommand. E.g. marathon :type subcommand: str - :param dcos_path: path to the dcos cli directory - :type dcos_path: str :returns: the dcos program path :rtype: str """ executables = [ command_path - for command_path in list_paths(dcos_path) + for command_path in list_paths() if noun(command_path) == subcommand ] @@ -39,15 +37,38 @@ def command_executables(subcommand, dcos_path): return executables[0] -def list_paths(dcos_path): +def get_package_commands(package_name): + """List the real path(s) to executables for a specific dcos subcommand + + :param package_name: package name + :type package_name: str + :returns: list of all the dcos program paths in package + :rtype: [str] + """ + bin_dir = os.path.join(package_dir(package_name), + constants.DCOS_SUBCOMMAND_VIRTUALENV_SUBDIR, + BIN_DIRECTORY) + + executables = [] + for filename in os.listdir(bin_dir): + path = os.path.join(bin_dir, filename) + + if (filename.startswith(constants.DCOS_COMMAND_PREFIX) and + _is_executable(path)): + + executables.append(path) + + return executables + + +def list_paths(): """List the real path to executable dcos subcommand programs. - :param dcos_path: path to the dcos cli directory - :type dcos_path: str :returns: list of all the dcos program paths - :rtype: list of str + :rtype: [str] """ + dcos_path = util.dcos_path() # Let's get all the default subcommands binpath = os.path.join(dcos_path, BIN_DIRECTORY) commands = [ @@ -58,18 +79,8 @@ def list_paths(dcos_path): ] subcommands = [] - for package in distributions(dcos_path): - bin_dir = os.path.join(package_dir(package), - constants.DCOS_SUBCOMMAND_VIRTUALENV_SUBDIR, - BIN_DIRECTORY) - - for filename in os.listdir(bin_dir): - path = os.path.join(bin_dir, filename) - - if (filename.startswith(constants.DCOS_COMMAND_PREFIX) and - _is_executable(path)): - - subcommands.append(path) + for package in distributions(): + subcommands += get_package_commands(package) return commands + subcommands @@ -86,11 +97,9 @@ def _is_executable(path): not util.is_windows_platform() or path.endswith('.exe')) -def distributions(dcos_path): +def distributions(): """List all of the installed subcommand packages - :param dcos_path: path to the dcos cli directory - :type dcos_path: str :returns: a list of packages :rtype: list of str """