Browse Source

Cache process info used for completion between commands

Mike Naberezny 11 years ago
parent
commit
4aea127fd6
2 changed files with 32 additions and 2 deletions
  1. 12 2
      supervisor/supervisorctl.py
  2. 20 0
      supervisor/tests/test_supervisorctl.py

+ 12 - 2
supervisor/supervisorctl.py

@@ -102,6 +102,7 @@ class Controller(cmd.Cmd):
         self.prompt = self.options.prompt + '> '
         self.options.plugins = []
         self.vocab = ['help']
+        self._complete_info = None
         cmd.Cmd.__init__(self, completekey, stdin, stdout)
         for name, factory, kwargs in self.options.plugin_factories:
             plugin = factory(self, **kwargs)
@@ -132,6 +133,7 @@ class Controller(cmd.Cmd):
             return self.emptyline()
         if cmd is None:
             return self.default(line)
+        self._complete_info = None
         self.lastcmd = line
         if cmd == '':
             return self.default(line)
@@ -266,7 +268,7 @@ class Controller(cmd.Cmd):
     def _complete_groups(self, text):
         """Build a completion list of group names matching text"""
         groups = []
-        for info in self.get_supervisor().getAllProcessInfo():
+        for info in self._get_complete_info():
             if info['group'] not in groups:
                 groups.append(info['group'])
         return [ g + ' ' for g in groups if g.startswith(text) ]
@@ -274,13 +276,21 @@ class Controller(cmd.Cmd):
     def _complete_processes(self, text):
         """Build a completion list of process names matching text"""
         processes = []
-        for info in self.get_supervisor().getAllProcessInfo():
+        for info in self._get_complete_info():
             if ':' in text or info['name'] != info['group']:
                 processes.append('%s:%s' % (info['group'], info['name']))
             else:
                 processes.append(info['name'])
         return [ p + ' ' for p in processes if p.startswith(text) ]
 
+    def _get_complete_info(self):
+        """Get all process info used for completion.  We cache this between
+        commands to reduce XML-RPC calls because readline may call
+        complete() many times if the user hits tab only once."""
+        if self._complete_info is None:
+            self._complete_info = self.get_supervisor().getAllProcessInfo()
+        return self._complete_info
+
     def do_help(self, arg):
         if arg.strip() == 'help':
             self.help_help()

+ 20 - 0
supervisor/tests/test_supervisorctl.py

@@ -108,6 +108,14 @@ class ControllerTests(unittest.TestCase):
         self.assertEqual(controller.cmdqueue, [' help'])
         self.assertEqual(plugin.helped, True)
 
+    def test_onecmd_clears_completion_cache(self):
+        options = DummyClientOptions()
+        controller = self._makeOne(options)
+        controller.stdout = StringIO()
+        controller._complete_info = {}
+        controller.onecmd('help')
+        self.assertTrue(controller._complete_info is None)
+
     def test_complete_action_empty(self):
         options = DummyClientOptions()
         controller = self._makeOne(options)
@@ -215,6 +223,18 @@ class ControllerTests(unittest.TestCase):
         result = controller.complete('bad', 0, line='start bad')
         self.assertTrue(result is None)
 
+    def test_complete_caches_process_info(self):
+        options = DummyClientOptions()
+        controller = self._makeOne(options)
+        controller.stdout=StringIO()
+        controller.vocab = ['help', 'start']
+        result = controller.complete('', 0, line='start ')
+        self.assertFalse(result is None)
+        def f(*arg, **kw):
+            raise Exception("should not have called getAllProcessInfo")
+        controller.options._server.supervisor.getAllProcessInfo = f
+        controller.complete('', 1, line='start ')
+
     def test_complete_add_empty(self):
         options = DummyClientOptions()
         controller = self._makeOne(options)