diff --git a/cli/dcoscli/package/main.py b/cli/dcoscli/package/main.py index c3421e7..3a9cdb7 100644 --- a/cli/dcoscli/package/main.py +++ b/cli/dcoscli/package/main.py @@ -315,8 +315,7 @@ def _list(): emitter.publish(error) return 1 - for name, version in installed: - emitter.publish('{} [{}]'.format(name, version)) + emitter.publish(installed) return 0 diff --git a/cli/tests/integrations/cli/test_package.py b/cli/tests/integrations/cli/test_package.py index a928fbe..a0e672a 100644 --- a/cli/tests/integrations/cli/test_package.py +++ b/cli/tests/integrations/cli/test_package.py @@ -234,7 +234,7 @@ def test_list(): returncode, stdout, stderr = exec_command(['dcos', 'package', 'list']) assert returncode == 0 - assert stdout == b'' + assert stdout == b'[]\n' assert stderr == b'' returncode, stdout, stderr = exec_command( @@ -251,7 +251,27 @@ def test_list(): returncode, stdout, stderr = exec_command(['dcos', 'package', 'list']) assert returncode == 0 - assert stdout == b'mesos-dns [alpha]\n' + assert stdout == b"""\ +[ + { + "appId": "/mesos-dns", + "description": "DNS-based service discovery for Mesos.", + "maintainer": "support@mesosphere.io", + "name": "mesos-dns", + "packageSource": "git://github.com/mesosphere/universe.git", + "postInstallNotes": "Please refer to the tutorial instructions for \ +further setup requirements: http://mesosphere.github.io/mesos-dns/docs\ +/tutorial-gce.html", + "registryVersion": "0.1.0-alpha", + "scm": "https://github.com/mesosphere/mesos-dns.git", + "tags": [ + "mesosphere" + ], + "version": "alpha", + "website": "http://mesosphere.github.io/mesos-dns" + } +] +""" assert stderr == b'' diff --git a/dcos/api/emitting.py b/dcos/api/emitting.py index 4205700..864fe27 100644 --- a/dcos/api/emitting.py +++ b/dcos/api/emitting.py @@ -5,6 +5,7 @@ import collections import json import os import pydoc +import re import sys import pager @@ -105,6 +106,9 @@ def _process_json(event, pager_command): json_output = json.dumps(event, sort_keys=True, indent=2) + # Strip trailing whitespace + json_output = re.sub(r'\s+$', '', json_output, 0, re.M) + force_colors = False # TODO(CD): Introduce a --colors flag if not sys.stdout.isatty(): diff --git a/dcos/api/package.py b/dcos/api/package.py index 50461c1..a213de9 100644 --- a/dcos/api/package.py +++ b/dcos/api/package.py @@ -204,22 +204,44 @@ The app ids of the installed package instances are: [{}].""".format( init_client.remove_app(app['id'], force=True) -def list_installed_packages(init_client): +def list_installed_packages(init_client, result_predicate=lambda x: True): """ :param init_client: The program to use to list packages :type init_client: object - :rtype: ((str, str), Error) + :param result_predicate: The predicate to use to filter results + :type result_predicate: function(dict): bool + :rtype: (list of dict, Error) """ apps, error = init_client.get_apps() if error is not None: return (None, error) - pkgs = [(a['labels'][PACKAGE_NAME_KEY], a['labels'][PACKAGE_VERSION_KEY]) - for a in apps - if (a.get('labels') is not None and - a.get('labels').get(PACKAGE_NAME_KEY) is not None and - a.get('labels').get(PACKAGE_VERSION_KEY) is not None)] + encoded_pkgs = [(a['id'], a['labels']) + for a in apps + if a.get('labels', {}).get(PACKAGE_METADATA_KEY)] + + def decode_and_add_context(pair): + app_id, labels = pair + encoded = labels.get(PACKAGE_METADATA_KEY, {}) + source = labels.get(PACKAGE_SOURCE_KEY) + registry_version = labels.get(PACKAGE_REGISTRY_VERSION_KEY) + + decoded = base64.b64decode(six.b(encoded)).decode() + decoded_json, error = util.load_jsons(decoded) + if error is None: + decoded_json['appId'] = app_id + decoded_json['packageSource'] = source + decoded_json['registryVersion'] = registry_version + return (decoded_json, error) + + decoded_pkgs = [decode_and_add_context(encoded) + for encoded in encoded_pkgs] + + # Filter elements that failed to parse correctly as JSON, + # or do not match the supplied predicate + pkgs = [pair[0] for pair in decoded_pkgs + if pair[1] is None and result_predicate(pair[0])] return (pkgs, None)