Explorar el Código

Fix the ncurses application layout so that it scales task and worker columns for larger displays in celeryev

Chris Rose hace 14 años
padre
commit
5fee1548dd
Se han modificado 3 ficheros con 90 adiciones y 13 borrados
  1. 33 12
      celery/events/cursesmon.py
  2. 56 0
      celery/tests/test_cursesmon.py
  3. 1 1
      celery/utils/__init__.py

+ 33 - 12
celery/events/cursesmon.py

@@ -7,11 +7,18 @@ import time
 from datetime import datetime
 from itertools import count
 from textwrap import wrap
+from math import ceil
 
 from celery import states
 from celery.app import app_or_default
 from celery.utils import abbr, abbrtask
 
+BORDER_SPACING = 4
+UUID_WIDTH = 36
+STATE_WIDTH = 8
+TIMESTAMP_WIDTH = 8
+MIN_WORKER_WIDTH = 15
+MIN_TASK_WIDTH = 16
 
 class CursesMonitor(object):
     keymap = {}
@@ -43,22 +50,36 @@ class CursesMonitor(object):
                           "L": self.selection_rate_limit}
         self.keymap = dict(default_keymap, **self.keymap)
 
-    def format_row(self, uuid, worker, task, timestamp, state):
-        my, mx = self.win.getmaxyx()
-        mx = mx - 3
-        uuid_max = 36
-        if mx < 88:
-            uuid_max = mx - 52 - 2
-        uuid = abbr(uuid, uuid_max).ljust(uuid_max)
-        worker = abbr(worker, 16).ljust(16)
-        task = abbrtask(task, 16).ljust(16)
-        state = abbr(state, 8).ljust(8)
-        timestamp = timestamp.ljust(8)
+    def format_row(self, uuid, task, worker, timestamp, state):
+        mx = self.display_width
+        detail_width = mx - 1 - STATE_WIDTH - 1 - TIMESTAMP_WIDTH # include spacing
+        uuid_space = detail_width - 1 - MIN_TASK_WIDTH - 1 - MIN_WORKER_WIDTH # include spacing
+
+        if uuid_space < UUID_WIDTH:
+            uuid_width = uuid_space
+        else:
+            uuid_width = UUID_WIDTH
+
+        detail_width = detail_width - uuid_width - 1
+        task_width = int(ceil(detail_width / 2.0))
+        worker_width = detail_width - task_width - 1
+
+        uuid = abbr(uuid, uuid_width).ljust(uuid_width)
+        worker = abbr(worker, worker_width).ljust(worker_width)
+        task = abbrtask(task, task_width).ljust(task_width)
+        state = abbr(state, STATE_WIDTH).ljust(STATE_WIDTH)
+        timestamp = timestamp.ljust(TIMESTAMP_WIDTH)
+
         row = "%s %s %s %s %s " % (uuid, worker, task, timestamp, state)
         if self.screen_width is None:
             self.screen_width = len(row[:mx])
         return row[:mx]
 
+    @property
+    def display_width(self):
+         _, mx = self.win.getmaxyx()
+         return mx - BORDER_SPACING
+
     def find_position(self):
         if not self.tasks:
             return 0
@@ -283,7 +304,7 @@ class CursesMonitor(object):
                     lineno = y()
                     win.addstr(lineno, x, line, attr)
                     if state_color:
-                        win.addstr(lineno, len(line) - len(task.state) + 1,
+                        win.addstr(lineno, len(line) - STATE_WIDTH + BORDER_SPACING - 1,
                                 task.state, state_color | attr)
                     if task.ready:
                         task.visited = time.time()

+ 56 - 0
celery/tests/test_cursesmon.py

@@ -0,0 +1,56 @@
+from celery.tests.utils import unittest
+
+from celery.events import cursesmon
+
+class MockWindow(object):
+
+    def getmaxyx(self):
+        return self.y, self.x
+
+class TestCursesDisplay(unittest.TestCase):
+
+    def setUp(self):
+        self.monitor = cursesmon.CursesMonitor(object())
+        self.win = MockWindow()
+        self.monitor.win = self.win
+
+    def test_format_row_with_default_widths(self):
+        self.win.x, self.win.y = 91, 24
+        row = self.monitor.format_row(
+            '783da208-77d0-40ca-b3d6-37dd6dbb55d3',
+            'task.task.task.task.task.task.task.task.task.tas',
+            'workerworkerworkerworkerworkerworkerworkerworker',
+            '21:13:20',
+            'SUCCESS')
+        self.assertEqual('783da208-77d0-40ca-b3d6-37dd6dbb55d3 workerworker... task.task.[.]tas 21:13:20 SUCCESS ',
+                         row)
+
+    def test_format_row_with_truncated_uuid(self):
+        self.win.x, self.win.y = 80, 24
+        row = self.monitor.format_row(
+            '783da208-77d0-40ca-b3d6-37dd6dbb55d3',
+            'task.task.task.task.task.task.task.task.task.tas',
+            'workerworkerworkerworkerworkerworkerworkerworker',
+            '21:13:20',
+            'SUCCESS')
+        self.assertEqual('783da208-77d0-40ca-b3d... workerworker... task.task.[.]tas 21:13:20 SUCCESS ',
+                         row)
+
+    def test_format_title_row(self):
+        self.win.x, self.win.y = 80, 24
+        row = self.monitor.format_row("UUID", "TASK",
+                                      "WORKER", "TIME", "STATE")
+        self.assertEqual('UUID                      WORKER          TASK             TIME     STATE   ',
+                         row)
+
+    def test_format_row_for_wide_screen_with_short_uuid(self):
+        self.win.x, self.win.y = 140, 24
+        row = self.monitor.format_row(
+            '783da208-77d0-40ca-b3d6-37dd6dbb55d3',
+            'task.task.task.task.task.task.task.task.task.tas',
+            'workerworkerworkerworkerworkerworkerworkerworker',
+            '21:13:20',
+            'SUCCESS')
+        self.assertEqual(136, len(row))
+        self.assertEqual('783da208-77d0-40ca-b3d6-37dd6dbb55d3 workerworkerworkerworkerworkerworker... task.task.task.task.task.task.task.[.]tas 21:13:20 SUCCESS ',
+                         row)

+ 1 - 1
celery/utils/__init__.py

@@ -306,7 +306,7 @@ def abbrtask(S, max):
         return "???"
     if len(S) > max:
         module, _, cls = rpartition(S, ".")
-        module = abbr(module, max - len(cls), False)
+        module = abbr(module, max - len(cls) - 3, False)
         return module + "[.]" + cls
     return S