commit 32b44dc3f9fcea7e5dd19a9cade9f2f947f32672 Author: Damian Johnson atagar@torproject.org Date: Sat Aug 26 15:32:51 2017 -0700
Fetch manual information on demand
Fetching just the manual information we need, when we need it. Rather than loading the whole manual this now retrieves information from the sqlite manual cache. This should mean slightly faster startup and reduced memory usage. However, this no longer parses the local man page (so information cannot be more up-to-date than stem's cache).
We can re-introduce usage of local man pages later if this becomes something folks care about. --- nyx/panel/config.py | 97 +++++++++++++++++++++++++++++++++------------------- test/panel/config.py | 7 ++-- 2 files changed, 64 insertions(+), 40 deletions(-)
diff --git a/nyx/panel/config.py b/nyx/panel/config.py index 07a04b0..db04dbb 100644 --- a/nyx/panel/config.py +++ b/nyx/panel/config.py @@ -7,7 +7,6 @@ and the resulting configuration files saved. """
import curses -import os
import nyx.curses import nyx.panel @@ -17,9 +16,9 @@ import stem.control import stem.manual import stem.util.connection
+from nyx import tor_controller, input_prompt, show_message from nyx.curses import WHITE, NORMAL, BOLD, HIGHLIGHT from nyx.menu import MenuItem, Submenu -from nyx import tor_controller, data_directory, input_prompt, show_message
from stem.util import conf, enum, log, str_tools
@@ -50,14 +49,16 @@ class ConfigEntry(object):
:var str name: name of the configuration option :var str value_type: type of value - :var stem.manual.ConfigOption manual: manual information about the option """
- def __init__(self, name, value_type, manual): + def __init__(self, name, value_type): self.name = name self.value_type = value_type - self.manual = manual.config_options.get(name, stem.manual.ConfigOption(name)) - self._index = list(manual.config_options.keys()).index(name) if name in manual.config_options else 99999 + self._category = None + self._usage = None + self._summary = None + self._description = None + self._position = None
def value(self): """ @@ -98,7 +99,7 @@ class ConfigEntry(object): """
if attr == SortAttr.CATEGORY: - return self.manual.category + return self.category elif attr == SortAttr.NAME: return self.name elif attr == SortAttr.VALUE: @@ -106,16 +107,59 @@ class ConfigEntry(object): elif attr == SortAttr.VALUE_TYPE: return self.value_type elif attr == SortAttr.USAGE: - return self.manual.usage + return self.usage elif attr == SortAttr.SUMMARY: - return self.manual.summary + return self.summary elif attr == SortAttr.DESCRIPTION: - return self.manual.description + return self.description elif attr == SortAttr.MAN_PAGE_ENTRY: - return self._index + return self.position elif attr == SortAttr.IS_SET: return not self.is_set()
+ @property + def category(self): + if not self._category: + self._fetch_attr() + + return self._category + + @property + def usage(self): + if not self._usage: + self._fetch_attr() + + return self._usage + + @property + def summary(self): + if not self._summary: + self._fetch_attr() + + return self._summary + + @property + def description(self): + if not self._description: + self._fetch_attr() + + return self._description + + @property + def position(self): + if not self._position: + self._fetch_attr() + + return self._position + + def _fetch_attr(self): + result = stem.manual.query('SELECT category, usage, summary, description, position FROM torrc WHERE key=?', self.name.upper()).fetchone() + + if result: + self._category, self._usage, self._summary, self._description, self._position = result + else: + log.info("No manual information found for '%s'" % self.name) +
class ConfigPanel(nyx.panel.Panel): """ @@ -130,23 +174,6 @@ class ConfigPanel(nyx.panel.Panel): self._sort_order = CONFIG['config_order'] self._show_all = False # show all options, or just the important ones
- cached_manual_path = data_directory('manual') - - if cached_manual_path: - if os.path.exists(cached_manual_path): - manual = stem.manual.Manual.from_cache(cached_manual_path) - else: - try: - manual = stem.manual.Manual.from_man() - - try: - manual.save(cached_manual_path) - except IOError as exc: - log.debug("Unable to cache manual information to '%s'. This is fine, but means starting Nyx takes a little longer than usual: " % (cached_manual_path, exc)) - except IOError as exc: - log.debug("Unable to use 'man tor' to get information about config options (%s), using bundled information instead" % exc) - manual = stem.manual.Manual.from_cache() - try: for line in tor_controller().get_info('config/names').splitlines(): # Lines of the form "<option> <type>[ <documentation>]". Documentation @@ -165,7 +192,7 @@ class ConfigPanel(nyx.panel.Panel): elif value_type == 'Virtual' and not CONFIG['show_virtual_options']: continue
- self._contents.append(ConfigEntry(name, value_type, manual)) + self._contents.append(ConfigEntry(name, value_type))
self._contents = sorted(self._contents, key = lambda entry: [entry.sort_value(field) for field in self._sort_order]) except stem.ControllerError as exc: @@ -302,13 +329,13 @@ def _draw_line(subwindow, x, y, entry, is_selected, value_width, description_wid Show an individual configuration line. """
- attr = [CONFIG['attr.config.category_color'].get(entry.manual.category, WHITE)] + attr = [CONFIG['attr.config.category_color'].get(entry.category, WHITE)] attr.append(BOLD if entry.is_set() else NORMAL) attr.append(HIGHLIGHT if is_selected else NORMAL)
option_label = str_tools.crop(entry.name, NAME_WIDTH).ljust(NAME_WIDTH + 1) value_label = str_tools.crop(entry.value(), value_width).ljust(value_width + 1) - summary_label = str_tools.crop(entry.manual.summary, description_width).ljust(description_width) + summary_label = str_tools.crop(entry.summary, description_width).ljust(description_width)
subwindow.addstr(x, y, option_label + value_label + summary_label, *attr)
@@ -318,14 +345,14 @@ def _draw_selection_details(subwindow, selected): Shows details of the currently selected option. """
- attr = ', '.join(('custom' if selected.is_set() else 'default', selected.value_type, 'usage: %s' % selected.manual.usage)) - selected_color = CONFIG['attr.config.category_color'].get(selected.manual.category, WHITE) + attr = ', '.join(('custom' if selected.is_set() else 'default', selected.value_type, 'usage: %s' % selected.usage)) + selected_color = CONFIG['attr.config.category_color'].get(selected.category, WHITE) subwindow.box(0, 0, subwindow.width, DETAILS_HEIGHT)
- subwindow.addstr(2, 1, '%s (%s Option)' % (selected.name, selected.manual.category), selected_color, BOLD) + subwindow.addstr(2, 1, '%s (%s Option)' % (selected.name, selected.category), selected_color, BOLD) subwindow.addstr(2, 2, 'Value: %s (%s)' % (selected.value(), str_tools.crop(attr, max(0, subwindow.width - len(selected.value()) - 13))), selected_color, BOLD)
- description = 'Description: %s' % selected.manual.description + description = 'Description: %s' % selected.description
for i in range(DETAILS_HEIGHT - 4): if not description: diff --git a/test/panel/config.py b/test/panel/config.py index 0289406..99bbaec 100644 --- a/test/panel/config.py +++ b/test/panel/config.py @@ -4,7 +4,6 @@ Unit tests for nyx.panel.config.
import unittest
-import stem.manual import nyx.panel.config import test
@@ -32,8 +31,7 @@ class TestConfigPanel(unittest.TestCase): tor_controller_mock().get_info.return_value = True tor_controller_mock().get_conf.return_value = ['9051']
- manual = stem.manual.Manual.from_cache() - entry = nyx.panel.config.ConfigEntry('ControlPort', 'LineList', manual) + entry = nyx.panel.config.ConfigEntry('ControlPort', 'LineList')
rendered = test.render(nyx.panel.config._draw_line, 0, 0, entry, False, 10, 35) self.assertEqual(EXPECTED_LINE, rendered.content) @@ -44,8 +42,7 @@ class TestConfigPanel(unittest.TestCase): tor_controller_mock().get_info.return_value = True tor_controller_mock().get_conf.return_value = ['9051']
- manual = stem.manual.Manual.from_cache() - selected = nyx.panel.config.ConfigEntry('ControlPort', 'LineList', manual) + selected = nyx.panel.config.ConfigEntry('ControlPort', 'LineList')
rendered = test.render(nyx.panel.config._draw_selection_details, selected) self.assertEqual(EXPECTED_DETAIL_DIALOG, rendered.content)
tor-commits@lists.torproject.org