浏览代码

Keep no-ansi parameter in the CLI scope

Signed-off-by: Joffrey F <[email protected]>
Joffrey F 8 年之前
父节点
当前提交
7882f1fb06
共有 7 个文件被更改,包括 50 次插入40 次删除
  1. 2 3
      compose/cli/command.py
  2. 7 0
      compose/cli/main.py
  3. 19 14
      compose/parallel.py
  4. 11 15
      compose/project.py
  5. 0 6
      compose/service.py
  6. 8 0
      tests/acceptance/cli_test.py
  7. 3 2
      tests/unit/parallel_test.py

+ 2 - 3
compose/cli/command.py

@@ -31,7 +31,6 @@ def project_from_options(project_dir, options):
         get_config_path_from_options(project_dir, options, environment),
         project_name=options.get('--project-name'),
         verbose=options.get('--verbose'),
-        noansi=options.get('--no-ansi'),
         host=host,
         tls_config=tls_config_from_options(options),
         environment=environment,
@@ -82,7 +81,7 @@ def get_client(environment, verbose=False, version=None, tls_config=None, host=N
 
 
 def get_project(project_dir, config_path=None, project_name=None, verbose=False,
-                noansi=False, host=None, tls_config=None, environment=None, override_dir=None):
+                host=None, tls_config=None, environment=None, override_dir=None):
     if not environment:
         environment = Environment.from_env_file(project_dir)
     config_details = config.find(project_dir, config_path, environment, override_dir)
@@ -101,7 +100,7 @@ def get_project(project_dir, config_path=None, project_name=None, verbose=False,
     )
 
     with errors.handle_connection_errors(client):
-        return Project.from_config(project_name, config_data, client, noansi=noansi)
+        return Project.from_config(project_name, config_data, client)
 
 
 def get_project_name(working_dir, project_name=None, environment=None):

+ 7 - 0
compose/cli/main.py

@@ -98,6 +98,7 @@ def dispatch():
 
     options, handler, command_options = dispatcher.parse(sys.argv[1:])
     setup_console_handler(console_handler, options.get('--verbose'))
+    setup_parallel_logger(options.get('--no-ansi'))
     return functools.partial(perform_command, options, handler, command_options)
 
 
@@ -127,6 +128,12 @@ def setup_logging():
     logging.getLogger("requests").propagate = False
 
 
+def setup_parallel_logger(noansi):
+    if noansi:
+        import compose.parallel
+        compose.parallel.ParallelStreamWriter.set_noansi()
+
+
 def setup_console_handler(handler, verbose):
     if handler.stream.isatty():
         format_class = ConsoleWarningFormatter

+ 19 - 14
compose/parallel.py

@@ -26,7 +26,7 @@ log = logging.getLogger(__name__)
 STOP = object()
 
 
-def parallel_execute(objects, func, get_name, msg, get_deps=None, limit=None, noansi=False):
+def parallel_execute(objects, func, get_name, msg, get_deps=None, limit=None):
     """Runs func on objects in parallel while ensuring that func is
     ran on object only after it is ran on all its dependencies.
 
@@ -36,7 +36,7 @@ def parallel_execute(objects, func, get_name, msg, get_deps=None, limit=None, no
     objects = list(objects)
     stream = get_output_stream(sys.stderr)
 
-    writer = ParallelStreamWriter(stream, msg, noansi)
+    writer = ParallelStreamWriter(stream, msg)
     for obj in objects:
         writer.add_object(get_name(obj))
     writer.write_initial()
@@ -221,12 +221,17 @@ class ParallelStreamWriter(object):
     to jump to the correct line, and write over the line.
     """
 
-    def __init__(self, stream, msg, noansi):
+    noansi = False
+
+    @classmethod
+    def set_noansi(cls, value=True):
+        cls.noansi = value
+
+    def __init__(self, stream, msg):
         self.stream = stream
         self.msg = msg
         self.lines = []
         self.width = 0
-        self.noansi = noansi
 
     def add_object(self, obj_index):
         self.lines.append(obj_index)
@@ -267,27 +272,27 @@ class ParallelStreamWriter(object):
             self._write_ansi(obj_index, status)
 
 
-def parallel_operation(containers, operation, options, message, noansi=False):
+def parallel_operation(containers, operation, options, message):
     parallel_execute(
         containers,
         operator.methodcaller(operation, **options),
         operator.attrgetter('name'),
         message,
-        noansi=noansi)
+    )
 
 
-def parallel_remove(containers, options, noansi=False):
+def parallel_remove(containers, options):
     stopped_containers = [c for c in containers if not c.is_running]
-    parallel_operation(stopped_containers, 'remove', options, 'Removing', noansi=noansi)
+    parallel_operation(stopped_containers, 'remove', options, 'Removing')
 
 
-def parallel_pause(containers, options, noansi=False):
-    parallel_operation(containers, 'pause', options, 'Pausing', noansi=noansi)
+def parallel_pause(containers, options):
+    parallel_operation(containers, 'pause', options, 'Pausing')
 
 
-def parallel_unpause(containers, options, noansi=False):
-    parallel_operation(containers, 'unpause', options, 'Unpausing', noansi=noansi)
+def parallel_unpause(containers, options):
+    parallel_operation(containers, 'unpause', options, 'Unpausing')
 
 
-def parallel_kill(containers, options, noansi=False):
-    parallel_operation(containers, 'kill', options, 'Killing', noansi=noansi)
+def parallel_kill(containers, options):
+    parallel_operation(containers, 'kill', options, 'Killing')

+ 11 - 15
compose/project.py

@@ -60,15 +60,13 @@ class Project(object):
     """
     A collection of services.
     """
-    def __init__(self, name, services, client, networks=None, volumes=None, config_version=None,
-                 noansi=False):
+    def __init__(self, name, services, client, networks=None, volumes=None, config_version=None):
         self.name = name
         self.services = services
         self.client = client
         self.volumes = volumes or ProjectVolumes({})
         self.networks = networks or ProjectNetworks({}, False)
         self.config_version = config_version
-        self.noansi = noansi
 
     def labels(self, one_off=OneOffFilter.exclude):
         labels = ['{0}={1}'.format(LABEL_PROJECT, self.name)]
@@ -77,7 +75,7 @@ class Project(object):
         return labels
 
     @classmethod
-    def from_config(cls, name, config_data, client, noansi=False):
+    def from_config(cls, name, config_data, client):
         """
         Construct a Project from a config.Config object.
         """
@@ -88,7 +86,7 @@ class Project(object):
             networks,
             use_networking)
         volumes = ProjectVolumes.from_config(name, config_data, client)
-        project = cls(name, [], client, project_networks, volumes, config_data.version, noansi=noansi)
+        project = cls(name, [], client, project_networks, volumes, config_data.version)
 
         for service_dict in config_data.services:
             service_dict = dict(service_dict)
@@ -128,7 +126,6 @@ class Project(object):
                     volumes_from=volumes_from,
                     secrets=secrets,
                     pid_mode=pid_mode,
-                    noansi=noansi,
                     **service_dict)
             )
 
@@ -274,7 +271,7 @@ class Project(object):
             operator.attrgetter('name'),
             'Starting',
             get_deps,
-            noansi=self.noansi)
+        )
 
         return containers
 
@@ -293,25 +290,25 @@ class Project(object):
             operator.attrgetter('name'),
             'Stopping',
             get_deps,
-            noansi=self.noansi)
+        )
 
     def pause(self, service_names=None, **options):
         containers = self.containers(service_names)
-        parallel.parallel_pause(reversed(containers), options, noansi=self.noansi)
+        parallel.parallel_pause(reversed(containers), options)
         return containers
 
     def unpause(self, service_names=None, **options):
         containers = self.containers(service_names)
-        parallel.parallel_unpause(containers, options, noansi=self.noansi)
+        parallel.parallel_unpause(containers, options)
         return containers
 
     def kill(self, service_names=None, **options):
-        parallel.parallel_kill(self.containers(service_names), options, noansi=self.noansi)
+        parallel.parallel_kill(self.containers(service_names), options)
 
     def remove_stopped(self, service_names=None, one_off=OneOffFilter.exclude, **options):
         parallel.parallel_remove(self.containers(
             service_names, stopped=True, one_off=one_off
-        ), options, noansi=self.noansi)
+        ), options)
 
     def down(self, remove_image_type, include_volumes, remove_orphans=False):
         self.stop(one_off=OneOffFilter.include)
@@ -337,7 +334,7 @@ class Project(object):
             self.build_container_operation_with_timeout_func('restart', options),
             operator.attrgetter('name'),
             'Restarting',
-            noansi=self.noansi)
+        )
         return containers
 
     def build(self, service_names=None, no_cache=False, pull=False, force_rm=False, build_args=None):
@@ -454,7 +451,6 @@ class Project(object):
             operator.attrgetter('name'),
             None,
             get_deps,
-            noansi=self.noansi,
         )
         if errors:
             raise ProjectError(
@@ -508,7 +504,7 @@ class Project(object):
                 operator.attrgetter('name'),
                 'Pulling',
                 limit=5,
-                noansi=self.noansi)
+            )
         else:
             for service in services:
                 service.pull(ignore_pull_failures, silent=silent)

+ 0 - 6
compose/service.py

@@ -158,7 +158,6 @@ class Service(object):
         secrets=None,
         scale=None,
         pid_mode=None,
-        noansi=False,
         **options
     ):
         self.name = name
@@ -172,7 +171,6 @@ class Service(object):
         self.networks = networks or {}
         self.secrets = secrets or []
         self.scale_num = scale or 1
-        self.noansi = noansi
         self.options = options
 
     def __repr__(self):
@@ -395,7 +393,6 @@ class Service(object):
                 lambda n: create_and_start(self, n),
                 lambda n: self.get_container_name(n),
                 "Creating",
-                noansi=self.noansi,
             )
             for error in errors.values():
                 raise OperationFailedError(error)
@@ -417,7 +414,6 @@ class Service(object):
                 recreate,
                 lambda c: c.name,
                 "Recreating",
-                noansi=self.noansi,
             )
             for error in errors.values():
                 raise OperationFailedError(error)
@@ -438,7 +434,6 @@ class Service(object):
                     lambda c: self.start_container_if_stopped(c, attach_logs=not detached),
                     lambda c: c.name,
                     "Starting",
-                    noansi=self.noansi,
                 )
 
                 for error in errors.values():
@@ -460,7 +455,6 @@ class Service(object):
             stop_and_remove,
             lambda c: c.name,
             "Stopping and removing",
-            noansi=self.noansi,
         )
 
     def execute_convergence_plan(self, plan, timeout=None, detached=False,

+ 8 - 0
tests/acceptance/cli_test.py

@@ -751,6 +751,14 @@ class CLITestCase(DockerClientTestCase):
             for service in services:
                 assert self.lookup(container, service.name)
 
+    @v2_only()
+    def test_up_no_ansi(self):
+        self.base_dir = 'tests/fixtures/v2-simple'
+        result = self.dispatch(['--no-ansi', 'up', '-d'], None)
+        assert "%c[2K\r" % 27 not in result.stderr
+        assert "%c[1A" % 27 not in result.stderr
+        assert "%c[1B" % 27 not in result.stderr
+
     @v2_only()
     def test_up_with_default_network_config(self):
         filename = 'default-network-config.yml'

+ 3 - 2
tests/unit/parallel_test.py

@@ -8,6 +8,7 @@ from docker.errors import APIError
 
 from compose.parallel import parallel_execute
 from compose.parallel import parallel_execute_iter
+from compose.parallel import ParallelStreamWriter
 from compose.parallel import UpstreamError
 
 
@@ -62,7 +63,7 @@ def test_parallel_execute_with_limit():
         limit=limit,
     )
 
-    assert results == tasks*[None]
+    assert results == tasks * [None]
     assert errors == {}
 
 
@@ -133,12 +134,12 @@ def test_parallel_execute_alignment(capsys):
 
 
 def test_parallel_execute_alignment_noansi(capsys):
+    ParallelStreamWriter.set_noansi()
     results, errors = parallel_execute(
         objects=["short", "a very long name"],
         func=lambda x: x,
         get_name=six.text_type,
         msg="Aligning",
-        noansi=True,
     )
 
     assert errors == {}