[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