import os import sys import re import inspect import urllib import io validExtensions = (".cpp", ".h", ".js", ".md") # specify the paths in which docublocks are searched. note that js/apps/* must not be included because it contains js/apps/system/ # and that path also contains copies of some files present in js/ anyway. searchMDPaths = [ "Manual", "AQL", "HTTP", "Cookbook", "Drivers" ] searchPaths = [ ["Documentation/Books/Manual/", False], ["Documentation/Books/AQL/", False], ["Documentation/Books/HTTP/", False], ["Documentation/Books/Cookbook/", False], ["Documentation/Books/Drivers/", False], ["Documentation/DocuBlocks/", True] ] fullSuccess = True def file_content(filepath, forceDokuBlockContent): """ Fetches and formats file's content to perform the required operation. """ infile = io.open(filepath, 'r', encoding='utf-8', newline=None) filelines = tuple(infile) infile.close() comment_indexes = [] comments = [] _start = None docublockname = "" for line in enumerate(filelines): if "@startDocuBlock" in line[1]: docublockname = line[1] # in the unprocessed md files we have non-terminated startDocuBlocks, else it is an error: if ((_start != None) and (not searchMDPaths[0] in filepath) and (not searchMDPaths[1] in filepath) and (not searchMDPaths[2] in filepath) and (not searchMDPaths[3] in filepath) and (not searchMDPaths[4] in filepath)): print "next startDocuBlock found without endDocuBlock in between in file %s [%s]" %(filepath, line) raise Exception _start = line[0] if "@endDocuBlock" in line[1]: docublockname = "" try: _end = line[0] + 1 comment_indexes.append([_start, _end]) _start = None except NameError: print "endDocuBlock without previous startDocublock seen while analyzing file %s [%s]" %(filepath, line) raise Exception if len(docublockname) != 0 and forceDokuBlockContent: print "no endDocuBlock found while analyzing file %s [%s]" %(filepath, docublockname) raise Exception for index in comment_indexes: comments.append(filelines[index[0]: index[1]]) return comments def example_content(filepath, fh, tag, blockType, placeIntoFilePath): """ Fetches an example file and inserts it using code """ first = True aqlResult = False lastline = None longText = u"" longLines = 0 short = "" shortLines = 0 shortable = False showdots = True CURL_STATE_CMD = 1 CURL_STATE_HEADER = 2 CURL_STATE_BODY = 3 curlState = CURL_STATE_CMD AQL_STATE_QUERY = 1 AQL_STATE_BINDV = 2 AQL_STATE_RESULT = 3 aqlState = AQL_STATE_QUERY blockCount = 0; # read in the context, split into long and short infile = io.open(filepath, 'r', encoding='utf-8', newline=None) for line in infile: stripped_line = re.sub('<[^<]+?>', '', line) # remove HTML tags if first: if blockType == "arangosh" and not stripped_line.startswith("arangosh>"): raise Exception ("mismatching blocktype - expecting 'arangosh' to start with 'arangosh>' - in %s while inspecting %s - referenced via %s have '%s'" %(filepath, tag, placeIntoFilePath, line)) # HACK: highlight.js may add HTML to the prefix # shell> curl ... if blockType == "curl" and not stripped_line.startswith("shell> curl"): raise Exception("mismatching blocktype - expecting 'curl' to start with 'shell> curl' in %s while inspecting %s - referenced via %s have '%s'" %(filepath, tag, placeIntoFilePath, line)) first = False if blockType == "arangosh": if stripped_line.startswith("arangosh>") or stripped_line.startswith("........>"): if lastline != None: # short = short + lastline # shortLines = shortLines + 1 lastline = None short += line shortLines += 1 showdots = True else: if showdots: if lastline == None: # lastline = line shortable = True showdots = False lastline = None else: # short = short + "~~~hidden~~~\n" # shortLines = shortLines + 1 shortable = True showdots = False lastline = None if blockType == "curl": if stripped_line.startswith("shell> curl"): curlState = CURL_STATE_CMD elif curlState == CURL_STATE_CMD and line.startswith("HTTP/"): curlState = CURL_STATE_HEADER elif curlState == CURL_STATE_HEADER and line.startswith("{"): curlState = CURL_STATE_BODY if curlState == CURL_STATE_CMD or curlState == CURL_STATE_HEADER: short = short + line shortLines += 1 else: shortable = True if blockType == "AQL" or blockType == "EXPLAIN": if line.startswith("@Q"): # query part blockCount = 0 aqlState = AQL_STATE_QUERY if blockType == "EXPLAIN": short += "Explain Query:\n
\n"
          longText += "Explain Query:\n
\n"
        else:
          short += "Query:\n
\n"
          longText += "Query:\n
\n"
        continue # skip this line - it is only here for this.
      elif line.startswith("@B"): # bind values part
        short += "
\nBind Values:\n
\n"
        longText += "
\nBind Values:\n
\n"
        blockCount = 0
        aqlState = AQL_STATE_BINDV
        continue # skip this line - it is only here for this.
      elif line.startswith("@R"): # result part
        shortable = True
        if blockType == "EXPLAIN":
          longText += "
\nExplain output:\n
\n"
        else:
          longText += "
\nQuery results:\n
\n"
        blockCount = 0
        aqlState = AQL_STATE_RESULT
        continue # skip this line - it is only here for this.

      if aqlState == AQL_STATE_QUERY or aqlState == AQL_STATE_BINDV:
        short = short + line
        shortLines += 1

      blockCount += 1

    longText += line
    longLines += 1

  if lastline != None:
    short += lastline
    shortLines += 1

  infile.close()

  if longLines - shortLines < 5:
    shortable = False
  # python3: urllib.parse.quote_plus

  # write example
  fh.write(unicode("\n"))

  utag = urllib.quote_plus(tag) + '_container'
  ustr = u"\uE9CB"
  anchor = u""

  longTag = "%s_long" % tag
  shortTag = "%s_short" % tag
  shortToggle = "$('#%s').hide(); $('#%s').show();" % (shortTag, longTag)
  longToggle = "$('#%s').hide(); $('#%s').show(); window.location.hash='%s';" % (longTag, shortTag, utag)

  fh.write(unicode("
\n" % utag)) fh.write(unicode(anchor)) if shortable: fh.write(unicode("
\n" % longTag)) else: fh.write(unicode("
\n" % longTag)) if blockType != "AQL" and blockType != "EXPLAIN": fh.write(unicode("
\n"))
  fh.write(unicode("%s" % longText))
  fh.write(unicode("
\n")) if shortable: hideText="" if blockType == "arangosh": hideText = u"Hide execution results" elif blockType == "curl": hideText = u"Hide response body" elif blockType == "AQL": hideText = u"Hide query result" elif blockType == "EXPLAIN": hideText = u"Hide explain output" else: hideText = u"Hide" fh.write(unicode('
%s
' % ( utag, longToggle, hideText ))) fh.write(unicode("
\n")) if shortable: fh.write(unicode("
\n" % (shortTag, shortToggle))) if blockType != "AQL" and blockType != "EXPLAIN": fh.write(unicode("
\n"))
    fh.write(unicode("%s" % short))

    if blockType == "arangosh":
      fh.write(unicode("
Show execution results
\n")) elif blockType == "curl": fh.write(unicode("
Show response body
\n")) elif blockType == "AQL": fh.write(unicode("
Show query result
\n")) elif blockType == "EXPLAIN": fh.write(unicode("
Show explain output
\n")) else: fh.write(unicode("
Show
\n")) fh.write(unicode("\n")) fh.write(unicode("\n")) fh.write(unicode("\n")) def fetch_comments(dirpath, forceDokuBlockContent): """ Fetches comments from files and writes to a file in required format. """ global fullSuccess global validExtensions comments_filename = "allComments.txt" fh = io.open(comments_filename, "a", encoding="utf-8", newline="") shouldIgnoreLine = False for root, directories, files in os.walk(dirpath): for filename in files: if filename.endswith(validExtensions) and (filename.find("#") < 0): filepath = os.path.join(root, filename) file_comments = file_content(filepath, forceDokuBlockContent) for comment in file_comments: fh.write(unicode("\n\n" % filepath)) explain = False for _com in comment: if "@EXPLAIN{TRUE}" in _com: explain = True for _com in comment: _text = re.sub(r"//(/)+\s*\n", "
\n", _com) # place in temporary brs... _text = re.sub(r"///+(\s+\s+)([-\*\d])", r" \2", _text) _text = re.sub(r"///\s", "", _text) _text = _text.strip("\n") if _text: if not shouldIgnoreLine: if ("@startDocuBlock" in _text) or \ ("@endDocuBlock" in _text): fh.write(unicode("%s\n\n" % _text)) elif ("@EXAMPLE_ARANGOSH_OUTPUT" in _text or \ "@EXAMPLE_ARANGOSH_RUN" in _text or \ "@EXAMPLE_AQL" in _text): blockType="" if "@EXAMPLE_ARANGOSH_OUTPUT" in _text: blockType = "arangosh" elif "@EXAMPLE_ARANGOSH_RUN" in _text: blockType = "curl" elif "@EXAMPLE_AQL" in _text: if explain: blockType = "EXPLAIN" else: blockType = "AQL" shouldIgnoreLine = True try: _filename = re.search("{(.*)}", _text).group(1) except Exception as x: print "failed to match file name in %s while parsing %s " % (_text, filepath) raise x dirpath = os.path.abspath(os.path.join(os.path.dirname( __file__ ), os.pardir, "Examples", _filename + ".generated")) if os.path.isfile(dirpath): example_content(dirpath, fh, _filename, blockType, filepath) else: fullSuccess = False print "Could not find the generated example for " + _filename + " found in " + filepath else: fh.write(unicode("%s\n" % _text)) elif ("@END_EXAMPLE_ARANGOSH_OUTPUT" in _text or \ "@END_EXAMPLE_ARANGOSH_RUN" in _text or \ "@END_EXAMPLE_AQL" in _text): shouldIgnoreLine = False else: fh.write(unicode("\n")) fh.close() if __name__ == "__main__": errorsFile = io.open("../../lib/Basics/errors.dat", "r", encoding="utf-8", newline=None) commentsFile = io.open("allComments.txt", "w", encoding="utf-8", newline="") commentsFile.write(unicode("@startDocuBlock errorCodes \n")) for line in errorsFile: commentsFile.write(unicode(line + "\n")) commentsFile.write(unicode("@endDocuBlock \n")) commentsFile.close() errorsFile.close() for i in searchPaths: print "Searching for docublocks in " + i[0] + ": " dirpath = os.path.abspath(os.path.join(os.path.dirname( __file__ ), os.pardir,"ArangoDB/../../"+i[0])) fetch_comments(dirpath, i[1]) os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'templates')) if not fullSuccess: sys.exit(1)