diff --git a/compose/cli/main.py b/compose/cli/main.py index 56f6c0505..1fb62de69 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -496,19 +496,8 @@ class TopLevelCommand(Command): ) if not detached: - print("Attaching to", list_containers(to_attach)) - log_printer = LogPrinter(to_attach, attach_params={"logs": True}, monochrome=monochrome) - - try: - log_printer.run() - finally: - def handler(signal, frame): - project.kill(service_names=service_names) - sys.exit(0) - signal.signal(signal.SIGINT, handler) - - print("Gracefully stopping... (press Ctrl+C again to force)") - project.stop(service_names=service_names, timeout=timeout) + log_printer = build_log_printer(to_attach, service_names, monochrome) + attach_to_logs(project, log_printer, service_names, timeout) def migrate_to_labels(self, project, _options): """ @@ -551,5 +540,26 @@ class TopLevelCommand(Command): print(get_version_info('full')) +def build_log_printer(containers, service_names, monochrome): + return LogPrinter( + [c for c in containers if c.service in service_names], + attach_params={"logs": True}, + monochrome=monochrome) + + +def attach_to_logs(project, log_printer, service_names, timeout): + print("Attaching to", list_containers(log_printer.containers)) + try: + log_printer.run() + finally: + def handler(signal, frame): + project.kill(service_names=service_names) + sys.exit(0) + signal.signal(signal.SIGINT, handler) + + print("Gracefully stopping... (press Ctrl+C again to force)") + project.stop(service_names=service_names, timeout=timeout) + + def list_containers(containers): return ", ".join(c.name for c in containers) diff --git a/compose/container.py b/compose/container.py index 40aea98a4..6f88b41dc 100644 --- a/compose/container.py +++ b/compose/container.py @@ -62,9 +62,13 @@ class Container(object): def name(self): return self.dictionary['Name'][1:] + @property + def service(self): + return self.labels.get(LABEL_SERVICE) + @property def name_without_project(self): - return '{0}_{1}'.format(self.labels.get(LABEL_SERVICE), self.number) + return '{0}_{1}'.format(self.service, self.number) @property def number(self): diff --git a/tests/unit/cli/main_test.py b/tests/unit/cli/main_test.py new file mode 100644 index 000000000..817e8f49b --- /dev/null +++ b/tests/unit/cli/main_test.py @@ -0,0 +1,47 @@ +from __future__ import absolute_import + +from compose import container +from compose.cli.log_printer import LogPrinter +from compose.cli.main import attach_to_logs +from compose.cli.main import build_log_printer +from compose.project import Project +from tests import mock +from tests import unittest + + +def mock_container(service, number): + return mock.create_autospec( + container.Container, + service=service, + number=number, + name_without_project='{0}_{1}'.format(service, number)) + + +class CLIMainTestCase(unittest.TestCase): + + def test_build_log_printer(self): + containers = [ + mock_container('web', 1), + mock_container('web', 2), + mock_container('db', 1), + mock_container('other', 1), + mock_container('another', 1), + ] + service_names = ['web', 'db'] + log_printer = build_log_printer(containers, service_names, True) + self.assertEqual(log_printer.containers, containers[:3]) + + def test_attach_to_logs(self): + project = mock.create_autospec(Project) + log_printer = mock.create_autospec(LogPrinter, containers=[]) + service_names = ['web', 'db'] + timeout = 12 + + with mock.patch('compose.cli.main.signal', autospec=True) as mock_signal: + attach_to_logs(project, log_printer, service_names, timeout) + + mock_signal.signal.assert_called_once_with(mock_signal.SIGINT, mock.ANY) + log_printer.run.assert_called_once_with() + project.stop.assert_called_once_with( + service_names=service_names, + timeout=timeout)