From 33f510b3409a55fd7a4e9050853e14cbd853d18e Mon Sep 17 00:00:00 2001 From: Jesus Tinoco <jesus.rodriguez.tinoco@gmail.com> Date: Sat, 11 Jun 2016 01:12:02 +0200 Subject: [PATCH] 3501 - Add a new command option (images) Signed-off-by: Jesus Rodriguez Tinoco <jesus.rodriguez.tinoco@gmail.com> --- compose/cli/main.py | 38 ++++++++++++++++++++++++++ contrib/completion/bash/docker-compose | 10 +++++++ tests/acceptance/cli_test.py | 27 ++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/compose/cli/main.py b/compose/cli/main.py index a7aec945e..ba053e233 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -175,6 +175,7 @@ class TopLevelCommand(object): events Receive real time events from containers exec Execute a command in a running container help Get help on a command + images List images kill Kill containers logs View output from containers pause Pause services @@ -481,6 +482,43 @@ class TopLevelCommand(object): print(getdoc(subject)) + def images(self, options): + """ + List images. + Usage: images [options] [SERVICE...] + + Options: + -q Only display IDs + """ + containers = sorted( + self.project.containers(service_names=options['SERVICE'], stopped=True) + + self.project.containers(service_names=options['SERVICE'], one_off=OneOffFilter.only), + key=attrgetter('name')) + + if options['-q']: + for container in containers: + print(str.split(str(container.image), ':')[1]) + else: + headers = [ + 'Repository', + 'Tag', + 'Image Id', + 'Size' + ] + rows = [] + for container in containers: + image_config = container.image_config + repo_tags = str.split(str(image_config['RepoTags'][0]), ':') + image_id = str.split(str(container.image), ':')[1][0:12] + size = round(int(image_config['Size'])/float(1 << 20), 1) + rows.append([ + repo_tags[0], + repo_tags[1], + image_id, + size + ]) + print(Formatter().table(headers, rows)) + def kill(self, options): """ Force stop service containers. diff --git a/contrib/completion/bash/docker-compose b/contrib/completion/bash/docker-compose index f4b9342f3..fa099eac4 100644 --- a/contrib/completion/bash/docker-compose +++ b/contrib/completion/bash/docker-compose @@ -220,6 +220,16 @@ _docker_compose_help() { COMPREPLY=( $( compgen -W "${commands[*]}" -- "$cur" ) ) } +_docker_compose_images() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help -q" -- "$cur" ) ) + ;; + *) + __docker_compose_services_all + ;; + esac +} _docker_compose_kill() { case "$prev" in diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index cc7bc5dfe..26baf3377 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -1986,3 +1986,30 @@ class CLITestCase(DockerClientTestCase): result = wait_on_process(proc, returncode=1) assert 'exitcodefrom_another_1 exited with code 1' in result.stdout + + def test_images(self): + self.project.get_service('simple').create_container() + result = self.dispatch(['images']) + assert 'simplecomposefile_simple' in result.stdout + + def test_images_default_composefile(self): + self.base_dir = 'tests/fixtures/multiple-composefiles' + self.dispatch(['up', '-d']) + result = self.dispatch(['images']) + + self.assertIn('multiplecomposefiles_simple', result.stdout) + self.assertIn('multiplecomposefiles_another', result.stdout) + self.assertNotIn('multiplecomposefiles_yetanother', result.stdout) + + def test_images_alternate_composefile(self): + config_path = os.path.abspath( + 'tests/fixtures/multiple-composefiles/compose2.yml') + self._project = get_project(self.base_dir, [config_path]) + + self.base_dir = 'tests/fixtures/multiple-composefiles' + self.dispatch(['-f', 'compose2.yml', 'up', '-d']) + result = self.dispatch(['-f', 'compose2.yml', 'images']) + + self.assertNotIn('multiplecomposefiles_simple', result.stdout) + self.assertNotIn('multiplecomposefiles_another', result.stdout) + self.assertIn('multiplecomposefiles_yetanother', result.stdout)