]> git.donarmstrong.com Git - lilypond.git/commitdiff
Docs: add py script to check cross-references
authorTrevor Daniels <t.daniels@treda.co.uk>
Wed, 18 Aug 2010 11:59:43 +0000 (12:59 +0100)
committerTrevor Daniels <t.daniels@treda.co.uk>
Wed, 18 Aug 2010 11:59:43 +0000 (12:59 +0100)
 - for use by doc editors to check cross-references
   in the doc tree are correct

 - run at top level of git repository

 - see comments for known issues

 - files to be checked/excluded are in ref_check.tely

scripts/auxiliar/ref_check.py [new file with mode: 0644]
scripts/auxiliar/ref_check.tely [new file with mode: 0644]

diff --git a/scripts/auxiliar/ref_check.py b/scripts/auxiliar/ref_check.py
new file mode 100644 (file)
index 0000000..8050272
--- /dev/null
@@ -0,0 +1,184 @@
+
+"""
+*** RefCheck
+
+Flow
+  Read files
+    On @defManual manual refManual eg @defManual LM rlearning
+      Associate manual name 'manual' with reference @'refManual'{ ... }
+      Add 'refManual' to list of keywords
+    On @setManual manual set current manual name to 'manual'
+    On @include open and process new file
+    On @node add node to Nodes list with current manual name and current file name
+    On @ref add contents to References list with refManual, current manual name and current file name
+    On one of refManual keywords add contents to References list with ditto
+  Match refs and nodes
+    Process References list:
+      Check reference is contained in Nodes list with refManual in Nodes = refManual in References
+    Print results
+    
+Known issues
+  Node names containing commas are only checked up to the comma
+  Spurious warnings "Xref should be internal" for files in /included
+
+"""
+
+
+##################################################
+class CrossRefs:
+  """ Holds References and Nodes """
+  def __init__(self):
+    self.Manuals = {}
+    self.Nodes = {}
+    self.nodeNames = {}  # used to check for duplicates only
+    self.Refs = []
+    self.nodeCount = 0
+
+  def addManual(self, manualName, refManual):
+    self.Manuals[refManual] = manualName
+
+  def getRefManuals(self):
+    return self.Manuals.keys()
+
+  def getManualName(self, refManual):
+    return self.Manuals[refManual]
+
+  def addNode(self, nodeName, manualName, fileName):
+    global returnCode
+#    print "Node: ", nodeName, " in ", manualName, " found in ", fileName
+    if manualName+"/"+nodeName in self.Nodes.keys():
+      print "Error: Duplicate nodename ",nodeName, " in ", fileName, " and ", self.Nodes[manualName+nodeName]
+      returnCode=1
+    self.Nodes[manualName + "/" + nodeName] = [manualName, fileName]
+    self.nodeNames[nodeName] = fileName
+
+  def addRef(self, toManualName, toHeading, inFileName):
+#    if inFileName == "notation/vocal.itely":
+#      print "Ref to ", toManualName, "/",toHeading, " found in ", inFileName
+    self.Refs.append([toManualName + "/" + toHeading, inFileName])
+
+  def check(self):
+    noErrors = True
+    for [refHeading, refFileName] in self.Refs:
+      try:
+        targetFileName = self.Nodes[refHeading]
+#        if refFileName == "notation/vocal.itely":
+#          print "ref to: ", refHeading, " in ", refFileName, " found in ", targetFileName
+      except KeyError:
+        noErrors = False
+        print "ref to: ", refHeading, " in ", refFileName, " not found"
+    if noErrors:
+      print " All references satisfied"
+    else:
+      returnCode=1
+
+##################################################
+class File:
+  """ Process an included file """
+
+  # Class variables
+  CurrentManualName = ""
+  DefaultPath = ""
+  Excludes = []
+  Paths = {}
+
+  # Methods
+  def __init__(self, fileName):
+    self.fileName = fileName
+    try:
+      self.fullFileName = File.Paths[fileName] + fileName
+    except KeyError:
+      self.fullFileName = File.DefaultPath + fileName
+
+  def read(self, crossRefs):
+    """ Process File """
+
+    skip = False
+    myfile = open(self.fullFileName, 'r')
+    remainderLine = ""
+    lineNo = 0
+    for line in myfile:
+      lineNo += 1
+      words = line.split()
+      if len(words) > 0:
+        if words[0] == "@ignore" or words[0] == "@macro":
+          skip = True
+        if skip and len(words) > 1:
+          if words[0] == "@end" and (words[1].find("ignore") >= 0 or words[1].find("macro") >= 0):
+            skip = False
+
+        if not skip and words[0].find("@c") < 0:
+          if words[0].find("@defManual") >= 0:
+            # Manual definition found - extract manual name and refManual string
+            manualName = words[1]
+            refManual = words[2]
+            crossRefs.addManual(manualName, refManual)
+#            print manualName, refManual
+
+          elif words[0].find("@defaultPath") >=0:
+            File.DefaultPath = words[1]
+
+          elif words[0].find("@path") >=0:
+            File.Paths[words[1]] = words[2]
+
+          elif words[0].find("@setManual") >= 0:
+            File.CurrentManualName = words[1]
+#            print " Checking ", File.CurrentManualName
+
+          elif words[0].find("@exclude") >=0:
+            File.Excludes.append(words[1])
+
+          elif words[0].find("@include") >= 0:
+            if words[1] not in File.Excludes:
+              currentFileName = words[1]
+#              print "  File: ", currentFileName
+              currentFile = File(currentFileName)
+              currentFile.read(crossRefs)
+
+          elif words[0] == "@node":
+            nodeName = line[6:-1]
+            crossRefs.addNode(nodeName, File.CurrentManualName, self.fileName)
+
+          # Find references
+
+          twoLines = remainderLine + ' ' + line.strip()
+          manualRefStrings = crossRefs.getRefManuals()
+          refFound = False
+          for manualRefString in manualRefStrings:
+            toManualName = crossRefs.getManualName(manualRefString)
+            actualToManualName = toManualName
+            if toManualName == "this":
+              toManualName = File.CurrentManualName
+            refString = "@" + manualRefString + "{"
+            refStart = twoLines.find(refString)
+            if refStart >= 0:
+              refFound = True
+              if actualToManualName == File.CurrentManualName:
+                print "Warning: xref should be internal around line ", lineNo, " in ", self.fileName
+              twoLines = twoLines[refStart:]
+              refNodeStart = twoLines.find("{") + 1
+              # TODO Need to check here for nested {}
+              refNodeEnd = twoLines.find("}")
+              refNodeEndComma = twoLines.find(",")
+              if refNodeEndComma > 0:
+                refNodeEnd = min(refNodeEnd, refNodeEndComma)
+              if refNodeEnd >= 0:
+                crossRefs.addRef(toManualName, twoLines[refNodeStart:refNodeEnd], self.fileName)
+                remainderLine=twoLines[refNodeEnd+1:]
+            if refFound:
+              refFound = False
+              break
+          if not refFound:
+              remainderLine = ""
+
+    myfile.close()
+    return
+
+topFile = File("scripts/auxiliar/ref_check.tely") # TODO get from input params
+print "RefCheck ver 0.1"
+returnCode=0
+crossRefs = CrossRefs()
+topFile.read(crossRefs)
+crossRefs.check()
+if returnCode > 0:
+  print "Errors found: status code: ",returnCode
\ No newline at end of file
diff --git a/scripts/auxiliar/ref_check.tely b/scripts/auxiliar/ref_check.tely
new file mode 100644 (file)
index 0000000..960f092
--- /dev/null
@@ -0,0 +1,71 @@
+
+Manual names and reference keywords:
+(refs to IR not checked)
+@defManual this ref
+@defManual CH rchanges
+@defManual EL rextend
+@defManual WE rgeneral
+@defManual ES ressay
+@defManual LM rlearning
+@defManual MG rgloss
+@defManual NR ruser
+@defManual AU rprogram
+@defManual CG rcontrib
+
+Files to be excluded (not available in git):
+@exclude colorado.itexi
+@exclude computer-notation.itexi
+@exclude context-properties.tely
+@exclude engravingbib.itexi
+@exclude identifiers.tely
+@exclude layout-properties.tely
+@exclude macros.itexi
+@exclude markup-commands.tely
+@exclude markup-list-commands.tely
+@exclude scheme-functions.tely
+@exclude type-predicates.tely
+@exclude version.itexi
+@exclude weblinks.itexi
+
+@defaultPath Documentation/
+
+Learning Manual
+@setManual LM
+@include learning.tely
+
+Music Glossary
+@setManual MG
+@include music-glossary.tely
+
+Notation Reference
+@setManual NR
+@include notation.tely
+Dummy nodes to satisfy refs to text markup
+@node Text markup commands
+@node Font
+@node Align
+@node Graphic
+@node Instrument Specific Markup
+@node Music
+@node Text markup list commands
+
+Application Usage
+@setManual AU
+@include usage.tely
+
+Contributors Guide
+@setManual CG
+@include contributor.texi
+
+Extending Lilypond
+@setManual EL
+@include extending.tely
+
+Essay
+@setManual ES
+@include essay.tely
+
+General (web)
+@setManual WE
+@include web.texi
+