]> git.donarmstrong.com Git - lilypond.git/blob - scripts/auxiliar/ref_check.py
Build -- Add scripts/auxiliar/doc-section.sh
[lilypond.git] / scripts / auxiliar / ref_check.py
1
2 """
3 *** RefCheck
4
5 Flow
6   Read files
7     On @defManual manual refManual eg @defManual LM rlearning
8       Associate manual name 'manual' with reference @'refManual'{ ... }
9       Add 'refManual' to list of keywords
10     On @setManual manual set current manual name to 'manual'
11     On @include open and process new file
12     On @node add node to Nodes list with current manual name and current file name
13     On @ref add contents to References list with refManual, current manual name and current file name
14     On one of refManual keywords add contents to References list with ditto
15   Match refs and nodes
16     Process References list:
17       Check reference is contained in Nodes list with refManual in Nodes = refManual in References
18     Print results
19     
20 Known issues
21   Node names containing commas are only checked up to the comma
22   Spurious warnings "Xref should be internal" for files in /included
23
24 """
25
26
27 ##################################################
28 class CrossRefs:
29   """ Holds References and Nodes """
30   def __init__(self):
31     self.Manuals = {}
32     self.Nodes = {}
33     self.nodeNames = {}  # used to check for duplicates only
34     self.Refs = []
35     self.nodeCount = 0
36
37   def addManual(self, manualName, refManual):
38     self.Manuals[refManual] = manualName
39
40   def getRefManuals(self):
41     return self.Manuals.keys()
42
43   def getManualName(self, refManual):
44     return self.Manuals[refManual]
45
46   def addNode(self, nodeName, manualName, fileName):
47     global returnCode
48 #    print "Node: ", nodeName, " in ", manualName, " found in ", fileName
49     if manualName+"/"+nodeName in self.Nodes.keys():
50       print "Error: Duplicate nodename ",nodeName, " in ", fileName, " and ", self.Nodes[manualName+nodeName]
51       returnCode=1
52     self.Nodes[manualName + "/" + nodeName] = [manualName, fileName]
53     self.nodeNames[nodeName] = fileName
54
55   def addRef(self, toManualName, toHeading, inFileName):
56 #    if inFileName == "notation/vocal.itely":
57 #      print "Ref to ", toManualName, "/",toHeading, " found in ", inFileName
58     self.Refs.append([toManualName + "/" + toHeading, inFileName])
59
60   def check(self):
61     noErrors = True
62     for [refHeading, refFileName] in self.Refs:
63       try:
64         targetFileName = self.Nodes[refHeading]
65 #        if refFileName == "notation/vocal.itely":
66 #          print "ref to: ", refHeading, " in ", refFileName, " found in ", targetFileName
67       except KeyError:
68         noErrors = False
69         print "ref to: ", refHeading, " in ", refFileName, " not found"
70     if noErrors:
71       print " All references satisfied"
72     else:
73       returnCode=1
74
75 ##################################################
76 class File:
77   """ Process an included file """
78
79   # Class variables
80   CurrentManualName = ""
81   DefaultPath = ""
82   Excludes = []
83   Paths = {}
84
85   # Methods
86   def __init__(self, fileName):
87     self.fileName = fileName
88     try:
89       self.fullFileName = File.Paths[fileName] + fileName
90     except KeyError:
91       self.fullFileName = File.DefaultPath + fileName
92
93   def read(self, crossRefs):
94     """ Process File """
95
96     skip = False
97     myfile = open(self.fullFileName, 'r')
98     remainderLine = ""
99     lineNo = 0
100     for line in myfile:
101       lineNo += 1
102       words = line.split()
103       if len(words) > 0:
104         if words[0] == "@ignore" or words[0] == "@macro":
105           skip = True
106         if skip and len(words) > 1:
107           if words[0] == "@end" and (words[1].find("ignore") >= 0 or words[1].find("macro") >= 0):
108             skip = False
109
110         if not skip and words[0].find("@c") < 0:
111           if words[0].find("@defManual") >= 0:
112             # Manual definition found - extract manual name and refManual string
113             manualName = words[1]
114             refManual = words[2]
115             crossRefs.addManual(manualName, refManual)
116 #            print manualName, refManual
117
118           elif words[0].find("@defaultPath") >=0:
119             File.DefaultPath = words[1]
120
121           elif words[0].find("@path") >=0:
122             File.Paths[words[1]] = words[2]
123
124           elif words[0].find("@setManual") >= 0:
125             File.CurrentManualName = words[1]
126 #            print " Checking ", File.CurrentManualName
127
128           elif words[0].find("@exclude") >=0:
129             File.Excludes.append(words[1])
130
131           elif words[0].find("@include") >= 0:
132             if words[1] not in File.Excludes:
133               currentFileName = words[1]
134 #              print "  File: ", currentFileName
135               currentFile = File(currentFileName)
136               currentFile.read(crossRefs)
137
138           elif words[0] == "@node":
139             nodeName = line[6:-1]
140             crossRefs.addNode(nodeName, File.CurrentManualName, self.fileName)
141
142           # Find references
143
144           twoLines = remainderLine + ' ' + line.strip()
145           manualRefStrings = crossRefs.getRefManuals()
146           refFound = False
147           for manualRefString in manualRefStrings:
148             toManualName = crossRefs.getManualName(manualRefString)
149             actualToManualName = toManualName
150             if toManualName == "this":
151               toManualName = File.CurrentManualName
152             refString = "@" + manualRefString + "{"
153             refStart = twoLines.find(refString)
154             if refStart >= 0:
155               refFound = True
156               if actualToManualName == File.CurrentManualName:
157                 print "Warning: xref should be internal around line ", lineNo, " in ", self.fileName
158               twoLines = twoLines[refStart:]
159               refNodeStart = twoLines.find("{") + 1
160               # TODO Need to check here for nested {}
161               refNodeEnd = twoLines.find("}")
162               refNodeEndComma = twoLines.find(",")
163               if refNodeEndComma > 0:
164                 refNodeEnd = min(refNodeEnd, refNodeEndComma)
165               if refNodeEnd >= 0:
166                 crossRefs.addRef(toManualName, twoLines[refNodeStart:refNodeEnd], self.fileName)
167                 remainderLine=twoLines[refNodeEnd+1:]
168             if refFound:
169               refFound = False
170               break
171           if not refFound:
172               remainderLine = ""
173
174     myfile.close()
175     return
176
177 topFile = File("scripts/auxiliar/ref_check.tely") # TODO get from input params
178 print "RefCheck ver 0.1"
179 returnCode=0
180 crossRefs = CrossRefs()
181 topFile.read(crossRefs)
182 crossRefs.check()
183 if returnCode > 0:
184   print "Errors found: status code: ",returnCode