]> rtime.felk.cvut.cz Git - omk.git/blob - omkbuild.py
Development continues :)
[omk.git] / omkbuild.py
1 #!/usr/bin/env python
2 """
3 This script has two main functions:
4
5   1) Combine several snippets to form Makefile.rules file
6   2) Split Makefile.rules file to the originnal snippets
7
8 Snippet syntax:
9
10   snippet ::= legal? documentation rules
11   
12   legal ::= comment* empty-comment empty-comment
13   documentation := comment*
14   rules ::= text
15   
16   comment ::= '#' text
17   empty-comment ::= '#'
18   text ::= [^#] ...
19
20  Makefile.rules policies:
21
22    * All the parts of the Makefile.rules are ordered in the same order
23      as they are in snippets i.e. copyrights, documentations and rules.
24
25    * On the first line of each part of the Makefile.rules, there is
26      special mart of the form #OMK@<snippet file name><EOL>. This mark
27      is used for splitting Makefile.rules back to the original
28      snippets.
29
30 """
31
32 from optparse import OptionParser
33 import os
34 import sys
35 import string
36 import re
37
38 class Snippet:
39     def __init__(self, fname = None):
40         """Initializes the snippet and if fname is given, reads it
41         from file"""
42         self.name = ""
43         self.legal = []
44         self.doc = []
45         self.code = []
46         if fname: self.readFromFile(fname)
47         
48     def readFromFile(self, fname):
49         """Loads snippet from file."""
50         self.name = fname
51         f = open(fname, "r")
52         
53         self.readLines(f.readlines())
54          
55         f.close
56
57     def readLines(self, lines):
58         """Parses the snippet given in the list and stores it in
59         self."""
60         currentPart = self.legal
61         counter = 0
62
63         for line in lines:
64             if currentPart == self.legal:
65                 if line.strip() == "#": counter += 1
66                 else: counter = 0
67                 if counter == 2: currentPart = self.doc
68             if line[0] != "#": currentPart = self.code
69
70             currentPart.append(line)
71
72         if not self.doc:
73             self.doc = self.legal
74             self.legal = []
75
76     def asLines(self):
77         lines = []
78         for type in ['legal', 'doc', 'code']:
79             for line in self.__dict__[type]:
80                 lines.append(line)
81         return lines
82
83     def __str__(self):
84         s = ""
85         lines = self.asLines()
86         for l in lines: s += l
87         return s
88
89     def __repr__(self):
90         s = "<Snippet: %s>" % self.name
91         return s
92
93     def __cmp__(self, other):
94         ret = self.name.__cmp__(other.name)
95         if ret != 0: return ret
96         ret = self.legal.__cmp__(other.legal)
97         if ret != 0: return ret
98         ret = self.doc.__cmp__(other.doc)
99         if ret != 0: return ret
100         ret = self.code.__cmp__(other.code)
101         return ret
102
103 def parseCommandLine():
104     parser = OptionParser(usage = """
105     %prog [-o FILE] snippet1 snippet2 ...      build Makefile.rules from snippets
106     %prog [-o - ] -s Makfile.rules
107     """)
108     parser.add_option("-s", "--split",
109                       action="store", dest="split", default=False, metavar="RULES",
110                       help="Split given Makefile.rules to the original snippets")
111     parser.add_option("-o", "--output",
112                       action="store", dest="output", default=False, metavar="RULES",
113                       help="Output built Makefile.rules to file RULES")
114     (options, args) = parser.parse_args()
115     return options, args
116
117 def splitToSnippets(rules):
118     """Split rules to the original snippets. The output is dictinary
119     of lists of lines"""
120
121     snipBegin = re.compile("^(.*)#OMK@(.*)$")
122     snipDict = dict()
123     currentLinesList = None
124
125     for line in rules:
126         match = snipBegin.match(line)
127         if match:
128             line = match.group(1).rstrip() + "\n"
129             snipName = match.group(2)
130             if not snipName in snipDict:
131                 snipDict[snipName] = []
132             currentLinesList = snipDict[snipName]
133
134         currentLinesList.append(line);
135     return snipDict
136
137 def convertSnipDict(snipDict):
138     """Takes dictionary of snippets, where each snippet is a lists of
139     lines, as the input argument and returns dictionary of snippets objects"""
140     outDict = dict()
141
142     for s in snipDict:
143         snip = Snippet()
144         snip.name = s
145         snip.readLines(snipDict[s])
146         outDict[s] = snip
147     return outDict
148
149 def readSnippets(fnames):
150     """Reads the snippets from several files and retuns them as a
151     dictionaly indexed by file name."""
152     snipDict = dict()
153         
154     for fn in fnames:
155         snipDict[fn] = Snippet(fn)
156
157     return snipDict
158
159     
160 def combineRules(snippets):
161     """Combine all snippents from the snippets dictionary to one list
162     of lines."""
163
164     rules = list()
165
166     for type in ['legal', 'doc', 'code']:
167         for s in snippets:
168             snip = snippets[s]
169             if len(snip.__dict__[type]) == 0: continue
170             firstLine = string.rstrip(snip.__dict__[type][0])
171             rules.append(firstLine.ljust(60)+" #OMK@%s\n"%snip.name)
172             rules.extend(snip.__dict__[type][1:]);
173     return rules
174
175 def assertSameSnippets(d1, d2):
176     theSame = d1==d2
177     if not theSame:
178         # Generate an error message
179         for s in d1:
180             if (d1[s] != d2[s]):
181                 sys.stderr.write("Consistency error: ")
182                 s1 = d1[s]
183                 s2 = d2[s]
184                 for i in range(len(s1)):
185                     if s1[i] != s2[i]:
186                         sys.stderr.write("snippet %s, line %d differs!\n")
187                 
188     return theSame
189
190 def buildRules(fnames, output):
191     snipDict = readSnippets(fnames)
192     rules = combineRules(snipDict)
193     snipDict2 = convertSnipDict(splitToSnippets(rules))
194
195     if assertSameSnippets(snipDict, snipDict2) == False:
196         sys.exit(1)
197         
198
199     if output: f = open(output,"w+")
200     else:
201         f = sys.stdout
202
203     f.writelines(rules)
204
205     f.close()
206
207 def splitRules(rulesFN, output):
208     pass
209
210 def main():
211     (options, args) = parseCommandLine()
212     if options.split:
213         splitRules(options.split, options.output)
214     else:
215         buildRules(args, options.output)
216
217
218 if __name__ == "__main__":    main()