#!/usr/bin/env python
+"""
+This script has two main functions:
+
+ 1) Combine several snippets to form Makefile.rules file
+ 2) Split Makefile.rules file to the originnal snippets
+
+Snippet syntax:
+
+ snippet ::= legal? documentation rules
+
+ legal ::= comment* empty-comment empty-comment
+ documentation := comment*
+ rules ::= text
+
+ comment ::= '#' text
+ empty-comment ::= '#'
+ text ::= [^#] ...
+
+ Makefile.rules policies:
+
+ * All the parts of the Makefile.rules are ordered in the same order
+ as they are in snippets i.e. copyrights, documentations and rules.
+
+ * On the first line of each part of the Makefile.rules, there is
+ special mart of the form #OMK@<snippet file name><EOL>. This mark
+ is used for splitting Makefile.rules back to the original
+ snippets.
+
+"""
from optparse import OptionParser
import os
import sys
import string
+import re
class Snippet:
-
- def __init__(self, fname):
+ def __init__(self, fname = None):
+ """Initializes the snippet and if fname is given, reads it
+ from file"""
self.name = ""
self.legal = []
self.doc = []
self.code = []
- self.read(fname)
-
- def read(self, fname):
+ if fname: self.readFromFile(fname)
+
+ def readFromFile(self, fname):
+ """Loads snippet from file."""
self.name = fname
f = open(fname, "r")
- current = self.legal
+
+ self.readLines(f.readlines())
+
+ f.close
+
+ def readLines(self, lines):
+ """Parses the snippet given in the list and stores it in
+ self."""
+ currentPart = self.legal
counter = 0
- for line in f:
- if current == self.legal:
+
+ for line in lines:
+ if currentPart == self.legal:
if line.strip() == "#": counter += 1
- else:
- if counter == 2: current = self.doc
- counter = 0
- if line[0] != "#": current = self.code
-
- current.append(line)
+ else: counter = 0
+ if counter == 2: currentPart = self.doc
+ if line[0] != "#": currentPart = self.code
+
+ currentPart.append(line)
if not self.doc:
self.doc = self.legal
self.legal = []
-
- f.close
+
+ def asLines(self):
+ lines = []
+ for type in ['legal', 'doc', 'code']:
+ for line in self.__dict__[type]:
+ lines.append(line)
+ return lines
def __str__(self):
- s = "Snippet: %s\n" % self.name
- s += " Legal: %d lines\n" % len(self.legal)
- s += " Doc: %d lines\n" % len(self.doc)
- s += " Code: %d lines\n" % len(self.code)
+ s = ""
+ lines = self.asLines()
+ for l in lines: s += l
return s
+ def __repr__(self):
+ s = "<Snippet: %s>" % self.name
+ return s
+
+ def __cmp__(self, other):
+ ret = self.name.__cmp__(other.name)
+ if ret != 0: return ret
+ ret = self.legal.__cmp__(other.legal)
+ if ret != 0: return ret
+ ret = self.doc.__cmp__(other.doc)
+ if ret != 0: return ret
+ ret = self.code.__cmp__(other.code)
+ return ret
def parseCommandLine():
parser = OptionParser(usage = """
%prog [-o FILE] snippet1 snippet2 ... build Makefile.rules from snippets
- %prog --split Makfile.rules
+ %prog [-o - ] -s Makfile.rules
""")
parser.add_option("-s", "--split",
action="store", dest="split", default=False, metavar="RULES",
(options, args) = parser.parse_args()
return options, args
-def splitRules(rules):
- pass
+def splitToSnippets(rules):
+ """Split rules to the original snippets. The output is dictinary
+ of lists of lines"""
-def buildRules(snippets, output):
- if output:
- f = open(output, "w+")
- else:
- f = sys.stdout
+ snipBegin = re.compile("^(.*)#OMK@(.*)$")
+ snipDict = dict()
+ currentLinesList = None
+
+ for line in rules:
+ match = snipBegin.match(line)
+ if match:
+ line = match.group(1).rstrip() + "\n"
+ snipName = match.group(2)
+ if not snipName in snipDict:
+ snipDict[snipName] = []
+ currentLinesList = snipDict[snipName]
+
+ currentLinesList.append(line);
+ return snipDict
+
+def convertSnipDict(snipDict):
+ """Takes dictionary of snippets, where each snippet is a lists of
+ lines, as the input argument and returns dictionary of snippets objects"""
+ outDict = dict()
- parts = []
+ for s in snipDict:
+ snip = Snippet()
+ snip.name = s
+ snip.readLines(snipDict[s])
+ outDict[s] = snip
+ return outDict
+
+def readSnippets(fnames):
+ """Reads the snippets from several files and retuns them as a
+ dictionaly indexed by file name."""
+ snipDict = dict()
- for snip in snippets:
- parts.append(Snippet(snip))
+ for fn in fnames:
+ snipDict[fn] = Snippet(fn)
+
+ return snipDict
+
+
+def combineRules(snippets):
+ """Combine all snippents from the snippets dictionary to one list
+ of lines."""
+
+ rules = list()
for type in ['legal', 'doc', 'code']:
- for snip in parts:
+ for s in snippets:
+ snip = snippets[s]
if len(snip.__dict__[type]) == 0: continue
firstLine = string.rstrip(snip.__dict__[type][0])
- f.write(firstLine.ljust(60)+" #@omk@%s\n"%snip.name)
- f.writelines(snip.__dict__[type][1:])
+ rules.append(firstLine.ljust(60)+" #OMK@%s\n"%snip.name)
+ rules.extend(snip.__dict__[type][1:]);
+ return rules
+
+def assertSameSnippets(d1, d2):
+ theSame = d1==d2
+ if not theSame:
+ # Generate an error message
+ for s in d1:
+ if (d1[s] != d2[s]):
+ sys.stderr.write("Consistency error: ")
+ s1 = d1[s]
+ s2 = d2[s]
+ for i in range(len(s1)):
+ if s1[i] != s2[i]:
+ sys.stderr.write("snippet %s, line %d differs!\n")
+
+ return theSame
+
+def buildRules(fnames, output):
+ snipDict = readSnippets(fnames)
+ rules = combineRules(snipDict)
+ snipDict2 = convertSnipDict(splitToSnippets(rules))
+
+ if assertSameSnippets(snipDict, snipDict2) == False:
+ sys.exit(1)
+
+
+ if output: f = open(output,"w+")
+ else:
+ f = sys.stdout
+
+ f.writelines(rules)
+
f.close()
+def splitRules(rulesFN, output):
+ pass
+
def main():
(options, args) = parseCommandLine()
if options.split:
- splitRules(options.split)
+ splitRules(options.split, options.output)
else:
buildRules(args, options.output)