Browse Source

Keep no-ansi parameter in the CLI scope

Signed-off-by: Joffrey F <[email protected]>
Joffrey F 8 years ago
parent
commit
7882f1fb06

+ 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),
         get_config_path_from_options(project_dir, options, environment),
         project_name=options.get('--project-name'),
         project_name=options.get('--project-name'),
         verbose=options.get('--verbose'),
         verbose=options.get('--verbose'),
-        noansi=options.get('--no-ansi'),
         host=host,
         host=host,
         tls_config=tls_config_from_options(options),
         tls_config=tls_config_from_options(options),
         environment=environment,
         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,
 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:
     if not environment:
         environment = Environment.from_env_file(project_dir)
         environment = Environment.from_env_file(project_dir)
     config_details = config.find(project_dir, config_path, environment, override_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):
     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):
 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:])
     options, handler, command_options = dispatcher.parse(sys.argv[1:])
     setup_console_handler(console_handler, options.get('--verbose'))
     setup_console_handler(console_handler, options.get('--verbose'))
+    setup_parallel_logger(options.get('--no-ansi'))
     return functools.partial(perform_command, options, handler, command_options)
     return functools.partial(perform_command, options, handler, command_options)
 
 
 
 
@@ -127,6 +128,12 @@ def setup_logging():
     logging.getLogger("requests").propagate = False
     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):
 def setup_console_handler(handler, verbose):
     if handler.stream.isatty():
     if handler.stream.isatty():
         format_class = ConsoleWarningFormatter
         format_class = ConsoleWarningFormatter

+ 19 - 14
compose/parallel.py

@@ -26,7 +26,7 @@ log = logging.getLogger(__name__)
 STOP = object()
 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
     """Runs func on objects in parallel while ensuring that func is
     ran on object only after it is ran on all its dependencies.
     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)
     objects = list(objects)
     stream = get_output_stream(sys.stderr)
     stream = get_output_stream(sys.stderr)
 
 
-    writer = ParallelStreamWriter(stream, msg, noansi)
+    writer = ParallelStreamWriter(stream, msg)
     for obj in objects:
     for obj in objects:
         writer.add_object(get_name(obj))
         writer.add_object(get_name(obj))
     writer.write_initial()
     writer.write_initial()
@@ -221,12 +221,17 @@ class ParallelStreamWriter(object):
     to jump to the correct line, and write over the line.
     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.stream = stream
         self.msg = msg
         self.msg = msg
         self.lines = []
         self.lines = []
         self.width = 0
         self.width = 0
-        self.noansi = noansi
 
 
     def add_object(self, obj_index):
     def add_object(self, obj_index):
         self.lines.append(obj_index)
         self.lines.append(obj_index)
@@ -267,27 +272,27 @@ class ParallelStreamWriter(object):
             self._write_ansi(obj_index, status)
             self._write_ansi(obj_index, status)
 
 
 
 
-def parallel_operation(containers, operation, options, message, noansi=False):
+def parallel_operation(containers, operation, options, message):
     parallel_execute(
     parallel_execute(
         containers,
         containers,
         operator.methodcaller(operation, **options),
         operator.methodcaller(operation, **options),
         operator.attrgetter('name'),
         operator.attrgetter('name'),
         message,
         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]
     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.
     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.name = name
         self.services = services
         self.services = services
         self.client = client
         self.client = client
         self.volumes = volumes or ProjectVolumes({})
         self.volumes = volumes or ProjectVolumes({})
         self.networks = networks or ProjectNetworks({}, False)
         self.networks = networks or ProjectNetworks({}, False)
         self.config_version = config_version
         self.config_version = config_version
-        self.noansi = noansi
 
 
     def labels(self, one_off=OneOffFilter.exclude):
     def labels(self, one_off=OneOffFilter.exclude):
         labels = ['{0}={1}'.format(LABEL_PROJECT, self.name)]
         labels = ['{0}={1}'.format(LABEL_PROJECT, self.name)]
@@ -77,7 +75,7 @@ class Project(object):
         return labels
         return labels
 
 
     @classmethod
     @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.
         Construct a Project from a config.Config object.
         """
         """
@@ -88,7 +86,7 @@ class Project(object):
             networks,
             networks,
             use_networking)
             use_networking)
         volumes = ProjectVolumes.from_config(name, config_data, client)
         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:
         for service_dict in config_data.services:
             service_dict = dict(service_dict)
             service_dict = dict(service_dict)
@@ -128,7 +126,6 @@ class Project(object):
                     volumes_from=volumes_from,
                     volumes_from=volumes_from,
                     secrets=secrets,
                     secrets=secrets,
                     pid_mode=pid_mode,
                     pid_mode=pid_mode,
-                    noansi=noansi,
                     **service_dict)
                     **service_dict)
             )
             )
 
 
@@ -274,7 +271,7 @@ class Project(object):
             operator.attrgetter('name'),
             operator.attrgetter('name'),
             'Starting',
             'Starting',
             get_deps,
             get_deps,
-            noansi=self.noansi)
+        )
 
 
         return containers
         return containers
 
 
@@ -293,25 +290,25 @@ class Project(object):
             operator.attrgetter('name'),
             operator.attrgetter('name'),
             'Stopping',
             'Stopping',
             get_deps,
             get_deps,
-            noansi=self.noansi)
+        )
 
 
     def pause(self, service_names=None, **options):
     def pause(self, service_names=None, **options):
         containers = self.containers(service_names)
         containers = self.containers(service_names)
-        parallel.parallel_pause(reversed(containers), options, noansi=self.noansi)
+        parallel.parallel_pause(reversed(containers), options)
         return containers
         return containers
 
 
     def unpause(self, service_names=None, **options):
     def unpause(self, service_names=None, **options):
         containers = self.containers(service_names)
         containers = self.containers(service_names)
-        parallel.parallel_unpause(containers, options, noansi=self.noansi)
+        parallel.parallel_unpause(containers, options)
         return containers
         return containers
 
 
     def kill(self, service_names=None, **options):
     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):
     def remove_stopped(self, service_names=None, one_off=OneOffFilter.exclude, **options):
         parallel.parallel_remove(self.containers(
         parallel.parallel_remove(self.containers(
             service_names, stopped=True, one_off=one_off
             service_names, stopped=True, one_off=one_off
-        ), options, noansi=self.noansi)
+        ), options)
 
 
     def down(self, remove_image_type, include_volumes, remove_orphans=False):
     def down(self, remove_image_type, include_volumes, remove_orphans=False):
         self.stop(one_off=OneOffFilter.include)
         self.stop(one_off=OneOffFilter.include)
@@ -337,7 +334,7 @@ class Project(object):
             self.build_container_operation_with_timeout_func('restart', options),
             self.build_container_operation_with_timeout_func('restart', options),
             operator.attrgetter('name'),
             operator.attrgetter('name'),
             'Restarting',
             'Restarting',
-            noansi=self.noansi)
+        )
         return containers
         return containers
 
 
     def build(self, service_names=None, no_cache=False, pull=False, force_rm=False, build_args=None):
     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'),
             operator.attrgetter('name'),
             None,
             None,
             get_deps,
             get_deps,
-            noansi=self.noansi,
         )
         )
         if errors:
         if errors:
             raise ProjectError(
             raise ProjectError(
@@ -508,7 +504,7 @@ class Project(object):
                 operator.attrgetter('name'),
                 operator.attrgetter('name'),
                 'Pulling',
                 'Pulling',
                 limit=5,
                 limit=5,
-                noansi=self.noansi)
+            )
         else:
         else:
             for service in services:
             for service in services:
                 service.pull(ignore_pull_failures, silent=silent)
                 service.pull(ignore_pull_failures, silent=silent)

+ 0 - 6
compose/service.py

@@ -158,7 +158,6 @@ class Service(object):
         secrets=None,
         secrets=None,
         scale=None,
         scale=None,
         pid_mode=None,
         pid_mode=None,
-        noansi=False,
         **options
         **options
     ):
     ):
         self.name = name
         self.name = name
@@ -172,7 +171,6 @@ class Service(object):
         self.networks = networks or {}
         self.networks = networks or {}
         self.secrets = secrets or []
         self.secrets = secrets or []
         self.scale_num = scale or 1
         self.scale_num = scale or 1
-        self.noansi = noansi
         self.options = options
         self.options = options
 
 
     def __repr__(self):
     def __repr__(self):
@@ -395,7 +393,6 @@ class Service(object):
                 lambda n: create_and_start(self, n),
                 lambda n: create_and_start(self, n),
                 lambda n: self.get_container_name(n),
                 lambda n: self.get_container_name(n),
                 "Creating",
                 "Creating",
-                noansi=self.noansi,
             )
             )
             for error in errors.values():
             for error in errors.values():
                 raise OperationFailedError(error)
                 raise OperationFailedError(error)
@@ -417,7 +414,6 @@ class Service(object):
                 recreate,
                 recreate,
                 lambda c: c.name,
                 lambda c: c.name,
                 "Recreating",
                 "Recreating",
-                noansi=self.noansi,
             )
             )
             for error in errors.values():
             for error in errors.values():
                 raise OperationFailedError(error)
                 raise OperationFailedError(error)
@@ -438,7 +434,6 @@ class Service(object):
                     lambda c: self.start_container_if_stopped(c, attach_logs=not detached),
                     lambda c: self.start_container_if_stopped(c, attach_logs=not detached),
                     lambda c: c.name,
                     lambda c: c.name,
                     "Starting",
                     "Starting",
-                    noansi=self.noansi,
                 )
                 )
 
 
                 for error in errors.values():
                 for error in errors.values():
@@ -460,7 +455,6 @@ class Service(object):
             stop_and_remove,
             stop_and_remove,
             lambda c: c.name,
             lambda c: c.name,
             "Stopping and removing",
             "Stopping and removing",
-            noansi=self.noansi,
         )
         )
 
 
     def execute_convergence_plan(self, plan, timeout=None, detached=False,
     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:
             for service in services:
                 assert self.lookup(container, service.name)
                 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()
     @v2_only()
     def test_up_with_default_network_config(self):
     def test_up_with_default_network_config(self):
         filename = 'default-network-config.yml'
         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
 from compose.parallel import parallel_execute_iter
 from compose.parallel import parallel_execute_iter
+from compose.parallel import ParallelStreamWriter
 from compose.parallel import UpstreamError
 from compose.parallel import UpstreamError
 
 
 
 
@@ -62,7 +63,7 @@ def test_parallel_execute_with_limit():
         limit=limit,
         limit=limit,
     )
     )
 
 
-    assert results == tasks*[None]
+    assert results == tasks * [None]
     assert errors == {}
     assert errors == {}
 
 
 
 
@@ -133,12 +134,12 @@ def test_parallel_execute_alignment(capsys):
 
 
 
 
 def test_parallel_execute_alignment_noansi(capsys):
 def test_parallel_execute_alignment_noansi(capsys):
+    ParallelStreamWriter.set_noansi()
     results, errors = parallel_execute(
     results, errors = parallel_execute(
         objects=["short", "a very long name"],
         objects=["short", "a very long name"],
         func=lambda x: x,
         func=lambda x: x,
         get_name=six.text_type,
         get_name=six.text_type,
         msg="Aligning",
         msg="Aligning",
-        noansi=True,
     )
     )
 
 
     assert errors == {}
     assert errors == {}