浏览代码

Add ability to list and filter services in `ps`
Also, rename --filter "option=..." to --filter "key=..."

Signed-off-by: Svyatoslav Ilinskiy <[email protected]>

Svyatoslav Ilinskiy 8 年之前
父节点
当前提交
be0b902631

+ 45 - 45
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):

+ 5 - 5
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") )
 }
 

+ 29 - 26
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:] == [

+ 0 - 0
tests/fixtures/config-services-filter/docker-compose.yml → tests/fixtures/ps-services-filter/docker-compose.yml