[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r23717: {arm} Parsing the tor man page to get descriptions for configurati (arm/trunk/src/util)
Author: atagar
Date: 2010-10-29 02:57:48 +0000 (Fri, 29 Oct 2010)
New Revision: 23717
Modified:
arm/trunk/src/util/torrc.py
Log:
Parsing the tor man page to get descriptions for configuration options.
Modified: arm/trunk/src/util/torrc.py
===================================================================
--- arm/trunk/src/util/torrc.py 2010-10-28 18:06:39 UTC (rev 23716)
+++ arm/trunk/src/util/torrc.py 2010-10-29 02:57:48 UTC (rev 23717)
@@ -31,7 +31,13 @@
# VAL_MISMATCH - the value doesn't match tor's current state
VAL_DUPLICATE, VAL_MISMATCH = range(1, 3)
+# descriptions of tor's configuration options fetched from its man page
+CONFIG_DESCRIPTIONS_LOCK = threading.RLock()
+CONFIG_DESCRIPTIONS = {}
+
TORRC = None # singleton torrc instance
+MAN_OPT_INDENT = 7 # indentation before options in the man page
+MAN_EX_INDENT = 15 # indentation used for man page examples
def loadConfig(config):
CONFIG["torrc.multiline"] = config.get("torrc.multiline", [])
@@ -156,6 +162,115 @@
return issuesFound
+def loadOptionDescriptions():
+ """
+ Fetches and parses descriptions for tor's configuration options from its man
+ page. This can be a somewhat lengthy call, and raises an IOError if issues
+ occure.
+ """
+
+ CONFIG_DESCRIPTIONS_LOCK.acquire()
+ CONFIG_DESCRIPTIONS.clear()
+
+ raisedExc = None
+ try:
+ manCallResults = sysTools.call("man tor")
+
+ lastOption, lastArg = None, None
+ lastDescription = ""
+ for line in manCallResults:
+ strippedLine = line.strip()
+
+ # we have content, but an indent less than an option (ignore line)
+ if strippedLine and not line.startswith(" " * MAN_OPT_INDENT): continue
+
+ # line starts with an indent equivilant to a new config option
+ isOptIndent = line.startswith(" " * MAN_OPT_INDENT) and line[MAN_OPT_INDENT] != " "
+
+ if isOptIndent:
+ # Most lines with this indent that aren't config options won't have
+ # any description set at this point (not a perfect filter, but cuts
+ # down on the noise).
+ strippedDescription = lastDescription.strip()
+ if lastOption and strippedDescription:
+ CONFIG_DESCRIPTIONS[lastOption] = (lastArg, strippedDescription)
+ lastDescription = ""
+
+ # parses the option and argument
+ line = line.strip()
+ divIndex = line.find(" ")
+ if divIndex != -1:
+ lastOption, lastArg = line[:divIndex], line[divIndex + 1:]
+ else:
+ # Appends the text to the running description. Empty lines and lines
+ # starting with a specific indentation are used for formatting, for
+ # instance the ExitPolicy and TestingTorNetwork entries.
+ if lastDescription and lastDescription[-1] != "\n":
+ lastDescription += " "
+
+ if not strippedLine:
+ lastDescription += "\n\n"
+ elif line.startswith(" " * MAN_EX_INDENT):
+ lastDescription += " %s\n" % strippedLine
+ else: lastDescription += strippedLine
+
+ except IOError, exc:
+ raisedExc = exc
+
+ CONFIG_DESCRIPTIONS_LOCK.release()
+ if raisedExc: raise raisedExc
+
+def isConfigDescriptionAvailable(option):
+ """
+ Returns if a description for the given configuration option has been loaded
+ or not.
+
+ Arguments:
+ option - tor config option
+ """
+
+ return option in CONFIG_DESCRIPTIONS
+
+def getConfigDescription(option):
+ """
+ Provides a tuple with arguments and description for the given tor
+ configuration option, fetched from its man page. This provides None if no
+ such option has been loaded. If the man page is in the process of being
+ loaded then this call blocks until it finishes.
+
+ Arguments:
+ option - tor config option
+ """
+
+ CONFIG_DESCRIPTIONS_LOCK.acquire()
+
+ if option in CONFIG_DESCRIPTIONS:
+ returnVal = CONFIG_DESCRIPTIONS[option]
+ else: returnVal = None
+
+ CONFIG_DESCRIPTIONS_LOCK.release()
+ return returnVal
+
+def _testConfigDescriptions():
+ """
+ Tester for the loadOptionDescriptions function, fetching the man page
+ contents and dumping its parsed results.
+ """
+
+ loadOptionDescriptions()
+ sortedOptions = CONFIG_DESCRIPTIONS.keys()
+ sortedOptions.sort()
+
+ for i in range(len(sortedOptions)):
+ option = sortedOptions[i]
+ argument, description = getConfigDescription(option)
+ optLabel = "OPTION: \"%s\"" % option
+ argLabel = "ARGUMENT: \"%s\"" % argument
+
+ print " %-45s %s" % (optLabel, argLabel)
+ print "\"%s\"" % description
+ if i != len(sortedOptions) - 1: print "-" * 80
+
def _parseConfValue(confArg):
"""
Converts size or time values to their lowest units (bytes or seconds) which