]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/auxiliar/ref_check.py
Imported Upstream version 2.14.2
[lilypond.git] / scripts / auxiliar / ref_check.py
diff --git a/scripts/auxiliar/ref_check.py b/scripts/auxiliar/ref_check.py
new file mode 100755 (executable)
index 0000000..ec6f6b6
--- /dev/null
@@ -0,0 +1,188 @@
+
+"""
+*** 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][1]
+      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
+    try:
+      myfile = open(self.fullFileName, 'r')
+    except IOError:
+      print "File ", self.fullFileName, " referenced in ", File.CurrentManualName, " but not found"
+      return
+    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] != "@c":
+          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: should xref 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