diff --git a/compose/cli/main.py b/compose/cli/main.py index 5cec853db..37168f033 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -287,7 +287,7 @@ class TopLevelCommand(object): """ Validate and view the Compose file. - Usage: config [options] [-f KEY=VAL...] + Usage: config [options] Options: --resolve-image-digests Pin image tags to digests. @@ -295,7 +295,6 @@ class TopLevelCommand(object): anything. --services Print the service names, one per line. --volumes Print the volume names, one per line. - -f, --filter KEY=VAL Filter services by a property (can be used multiple times) """ @@ -310,15 +309,7 @@ class TopLevelCommand(object): return if options['--services']: - filters = build_filters(options.get('--filter')) - if filters: - if not self.project: - self.project = project_from_options('.', config_options) - services = filter_services(filters, self.project.services, self.project) - else: - services = [service['name'] for service in compose_config.services] - - print('\n'.join(services)) + print('\n'.join(service['name'] for service in compose_config.services)) return if options['--volumes']: @@ -608,38 +599,47 @@ class TopLevelCommand(object): """ List containers. - Usage: ps [options] [SERVICE...] + Usage: ps [options] [--filter KEY=VAL...] [SERVICE...] Options: - -q Only display IDs + -q Only display IDs + --services Display services + --filter KEY=VAL Filter services by a property (can be used multiple times) """ - 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(container.id) + if options['--services']: + filters = build_filters(options.get('--filter')) + services = self.project.services + if filters: + services = filter_services(filters, services, self.project) + print('\n'.join(service.name for service in services)) else: - headers = [ - 'Name', - 'Command', - 'State', - 'Ports', - ] - rows = [] - for container in containers: - command = container.human_readable_command - if len(command) > 30: - command = '%s ...' % command[:26] - rows.append([ - container.name, - command, - container.human_readable_state, - container.human_readable_ports, - ]) - print(Formatter().table(headers, rows)) + 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(container.id) + else: + headers = [ + 'Name', + 'Command', + 'State', + 'Ports', + ] + rows = [] + for container in containers: + command = container.human_readable_command + if len(command) > 30: + command = '%s ...' % command[:26] + rows.append([ + container.name, + command, + container.human_readable_state, + container.human_readable_ports, + ]) + print(Formatter().table(headers, rows)) def pull(self, options): """ @@ -1345,18 +1345,18 @@ def filter_services(filters, services, project): for status in filters[f]: if not has_container_with_state(containers, status): return False - elif f == 'option': - for option in filters[f]: - if option == 'image' or option == 'build': - if option not in service.options: + elif f == 'key': + for key in filters[f]: + if key == 'image' or key == 'build': + if key not in service.options: return False else: - raise UserError("Invalid option: %s" % option) + raise UserError("Invalid option: %s" % key) else: raise UserError("Invalid filter: %s" % f) return True - return [s.name for s in services if should_include(s)] + return filter(should_include, services) def build_filters(args): diff --git a/contrib/completion/bash/docker-compose b/contrib/completion/bash/docker-compose index 5885e686b..248ff9285 100644 --- a/contrib/completion/bash/docker-compose +++ b/contrib/completion/bash/docker-compose @@ -66,29 +66,29 @@ __docker_compose_services_all() { # All services that are defined by a Dockerfile reference __docker_compose_services_from_build() { - COMPREPLY=( $(compgen -W "$(__docker_compose_q config --services --filter "option=build")" -- "$cur") ) + COMPREPLY=( $(compgen -W "$(__docker_compose_q ps --services --filter "key=build")" -- "$cur") ) } # All services that are defined by an image __docker_compose_services_from_image() { - COMPREPLY=( $(compgen -W "$(__docker_compose_q config --services --filter "option=image")" -- "$cur") ) + COMPREPLY=( $(compgen -W "$(__docker_compose_q ps --services --filter "key=image")" -- "$cur") ) } # The services for which at least one paused container exists __docker_compose_services_paused() { - names=$(__docker_compose_q config --services --filter "status=paused") + names=$(__docker_compose_q ps --services --filter "status=paused") COMPREPLY=( $(compgen -W "$names" -- "$cur") ) } # The services for which at least one running container exists __docker_compose_services_running() { - names=$(__docker_compose_q config --services --filter "status=running") + names=$(__docker_compose_q ps --services --filter "status=running") COMPREPLY=( $(compgen -W "$names" -- "$cur") ) } # The services for which at least one stopped container exists __docker_compose_services_stopped() { - names=$(__docker_compose_q config --services --filter "status=stopped") + names=$(__docker_compose_q ps --services --filter "status=stopped") COMPREPLY=( $(compgen -W "$names" -- "$cur") ) } diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index a4c19afc5..d15d5c5fe 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -440,32 +440,6 @@ class CLITestCase(DockerClientTestCase): }, } - def test_config_services_filter_option(self): - self.base_dir = 'tests/fixtures/config-services-filter' - image = self.dispatch(['config', '--services', '--filter', 'option=image']) - build = self.dispatch(['config', '--services', '--filter', 'option=build']) - - self.assertIn('with_build', build.stdout) - self.assertNotIn('with_build', image.stdout) - self.assertIn('with_image', image.stdout) - self.assertNotIn('with_image', build.stdout) - - def test_config_services_filter_status(self): - self.base_dir = 'tests/fixtures/config-services-filter' - self.dispatch(['up', '-d']) - self.dispatch(['pause', 'with_image']) - paused = self.dispatch(['config', '--services', '--filter', 'status=paused']) - stopped = self.dispatch(['config', '--services', '--filter', 'status=stopped']) - running = self.dispatch(['config', '--services', '--filter', 'status=running', - '--filter', 'option=build']) - - self.assertNotIn('with_build', stopped.stdout) - self.assertNotIn('with_image', stopped.stdout) - self.assertNotIn('with_build', paused.stdout) - self.assertIn('with_image', paused.stdout) - self.assertIn('with_build', running.stdout) - self.assertNotIn('with_image', running.stdout) - def test_ps(self): self.project.get_service('simple').create_container() result = self.dispatch(['ps']) @@ -493,6 +467,35 @@ class CLITestCase(DockerClientTestCase): self.assertNotIn('multiplecomposefiles_another_1', result.stdout) self.assertIn('multiplecomposefiles_yetanother_1', result.stdout) + def test_ps_services_filter_option(self): + self.base_dir = 'tests/fixtures/ps-services-filter' + image = self.dispatch(['ps', '--services', '--filter', 'key=image']) + build = self.dispatch(['ps', '--services', '--filter', 'key=build']) + all_services = self.dispatch(['ps', '--services']) + + self.assertIn('with_build', all_services.stdout) + self.assertIn('with_image', all_services.stdout) + self.assertIn('with_build', build.stdout) + self.assertNotIn('with_build', image.stdout) + self.assertIn('with_image', image.stdout) + self.assertNotIn('with_image', build.stdout) + + def test_ps_services_filter_status(self): + self.base_dir = 'tests/fixtures/ps-services-filter' + self.dispatch(['up', '-d']) + self.dispatch(['pause', 'with_image']) + paused = self.dispatch(['ps', '--services', '--filter', 'status=paused']) + stopped = self.dispatch(['ps', '--services', '--filter', 'status=stopped']) + running = self.dispatch(['ps', '--services', '--filter', 'status=running', + '--filter', 'key=build']) + + self.assertNotIn('with_build', stopped.stdout) + self.assertNotIn('with_image', stopped.stdout) + self.assertNotIn('with_build', paused.stdout) + self.assertIn('with_image', paused.stdout) + self.assertIn('with_build', running.stdout) + self.assertNotIn('with_image', running.stdout) + def test_pull(self): result = self.dispatch(['pull']) assert sorted(result.stderr.split('\n'))[1:] == [ diff --git a/tests/fixtures/config-services-filter/docker-compose.yml b/tests/fixtures/ps-services-filter/docker-compose.yml similarity index 100% rename from tests/fixtures/config-services-filter/docker-compose.yml rename to tests/fixtures/ps-services-filter/docker-compose.yml