X-Git-Url: http://rtime.felk.cvut.cz/gitweb/omk.git/blobdiff_plain/1b1387493fefd2da060bafd3086f77e7f3097666..75a9abff74dfbdd3103e115c19f4a5f0cc9cb0af:/omkbuild.py diff --git a/omkbuild.py b/omkbuild.py index facccc2..b1c0a12 100755 --- a/omkbuild.py +++ b/omkbuild.py @@ -23,17 +23,22 @@ Snippet syntax: 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 mark of the form #OMK@. This mark - is used for splitting modified Makefile.rules back to the - original snippets. If starts with __, it is - ignored during splitting. + special mark of the form: + + #OMK:[@] + + This mark is used for splitting modified Makefile.rules back to + the original snippets. If starts with __, it + is ignored during splitting. + + * Toplevel snippet has name in the forb Makefile.rules.* and no + other (included) snippet has such name. """ from optparse import OptionParser import os import os.path import sys -import string import re rulesDir = "rules" @@ -103,11 +108,15 @@ class Snippet: if currentPart == self.legal: if line.strip() == "#": counter += 1 else: counter = 0 - if counter == 2: currentPart = self.doc if line[0] != "#": currentPart = self.code currentPart.append(line) + if counter == 2: + currentPart = self.doc + counter = 0 + + if not self.doc: self.doc = self.legal self.legal = LineList() @@ -126,15 +135,15 @@ class Snippet: s = "" % self.name return s - def __cmp__(self, other): - ret = cmp(self.name, other.name) - if ret != 0: return ret - ret = cmp(self.legal, other.legal) - if ret != 0: return ret - ret = cmp(self.doc, other.doc) - if ret != 0: return ret - ret = cmp(self.code, other.code) - return ret + def __eq__(self, other): + return \ + self.name == other.name and \ + self.legal == other.legal and \ + self.doc == other.doc and \ + self.code == other.code + + def __ne__(self, other): + return not self == other def __getitem__(self, key): return { @@ -169,8 +178,11 @@ class Snippets: def __iter__(self): return iter(self._order) - def __cmp__(self, other): - return cmp(self._snippets, other._snippets) + def __eq__(self, other): + return self._snippets == other._snippets + + def __ne__(self, other): + return not self == other def loadFromFiles(self, fnames): """Reads the snippets from several files and adds them to itself.""" @@ -195,24 +207,71 @@ class Snippets: s += snip.getDiff(other[snip.name]) return s +# Include directoves matching this r.e. will be replaced by this script +reInclude = re.compile("^include ([^ ]*) #omkbuild") + class MakefileRules(LineList): def __init__(self): self.snippets = Snippets() self.rules = LineList() - def combine(self): - """Combine self.snippets and produces self.rules""" + def _includeSnippets(self, filename, baseFileName="", onlyLoadSnippets=False): + """Recursively traverses snippets according to include + directives. If onlyLoadSnippets is True, self.rules is not + modified ...""" + + if onlyLoadSnippets: + if filename in self.snippets: + sys.stderr.write("Error: Snippet included more than once\n") + # This is not allowed becouse it would cause problems + # during spliting + sys.exit(1) + self.snippets += Snippet(filename) + + lines = self.snippets[filename]['code'] + + addMarker = 1 # The first line of the snippet should be marked + for line in lines: + match = reInclude.match(line) + if match: + # Include other snippet + self._includeSnippets(match.group(1).strip(),\ + filename, + onlyLoadSnippets) + addMarker = 2 # The next line after include should be marked + else: + # Add this line to rules + if addMarker: + if addMarker==1: + line = line.rstrip().ljust(80)+" #OMK:%s@%s\n"%(filename,baseFileName) + elif addMarker==2: + line = line.rstrip().ljust(80)+" #OMK:%s\n"%(filename) + addMarker = 0 + if not onlyLoadSnippets: + self.rules += [line] + + def combineFrom(self, topLevelSnippet, onlyCheck=False): + """Produces self.rules from the topLevelSnippet and all + snippets included directly or indirectly from it.""" self.rules = LineList() - for type in ['legal', 'doc', 'code']: + if not onlyCheck: + self._includeSnippets(topLevelSnippet, onlyLoadSnippets=True) + + # Append legal and doc parts + for type in ['legal', 'doc']: for snip in self.snippets: lines = snip[type] if len(lines) == 0: continue - firstLine = string.rstrip(lines[0]) - self.rules += [firstLine.ljust(60)+" #OMK@%s\n"%snip.name] + firstLine = lines[0].rstrip() + self.rules += [firstLine.ljust(80)+" #OMK:%s\n"%snip.name] self.rules += lines[1:] #self.rules += ['a'] # test error + # Append code parts + self._includeSnippets(topLevelSnippet) + + def split(self): """Split self.rules to the original snippets in self.snippets.""" self.snippets = Snippets() @@ -222,7 +281,7 @@ class MakefileRules(LineList): def _getSnipDicts(self): """Split self.rules to the original snippets, which are returened as dictionary of LineLists.""" - snipBegin = re.compile("^(.*)#OMK@(.*)$") + snipBegin = re.compile("^(.*)#OMK:([^@]*)(?:@(.*))?\n$") snipDict = dict() currentLinesList = None @@ -231,6 +290,11 @@ class MakefileRules(LineList): if match: line = match.group(1).rstrip() + "\n" snipName = match.group(2) + includedFrom = match.group(3) + if includedFrom: + if not includedFrom in snipDict: snipDict[includedFrom] = LineList() + snipDict[includedFrom].append("include %s #omkbuild\n" % snipName); + if not snipName in snipDict: snipDict[snipName] = LineList() currentLinesList = snipDict[snipName] @@ -243,7 +307,7 @@ class MakefileRules(LineList): def parseCommandLine(): parser = OptionParser(usage = """ - %prog [-o FILE] snippet1 snippet2 ... build Makefile.rules from snippets + %prog [-o FILE] top-level-snippet build Makefile.rules from the top-level-snippet and included ones %prog [-o - ] -s Makfile.rules """) parser.add_option("-s", "--split", @@ -252,19 +316,15 @@ def parseCommandLine(): parser.add_option("-o", "--output", action="store", dest="output", default=False, metavar="RULES", help="Write Makefile.rules to file RULES") - parser.add_option("-a", "--all", - action="store_true", dest="all", - help="Rebuild all rules acording to rulesdef.py") (options, args) = parser.parse_args() + if len(args) > 1: + parser.print_help() + sys.exit(1) return options, args -def buildRules(fnames, output, name): +def buildRules(topLevelSnippet, output): rules = MakefileRules() - snip_rule_type = Snippet(name="__type") - snip_rule_type.addCodeLine("OMK_RULES_TYPE=%s\n" % name) - rules.snippets += snip_rule_type - rules.snippets.loadFromFiles(fnames) - rules.combine() + rules.combineFrom(topLevelSnippet) rulesCheck = MakefileRules() rulesCheck.rules = rules.rules @@ -276,7 +336,10 @@ def buildRules(fnames, output, name): sys.stderr.write(diff) sys.exit(1) - if output: f = open(output,"w+") + if output: + try: os.makedirs(os.path.dirname(output)) + except: pass + f = open(output,"w+") else: f = sys.stdout f.writelines(rules.rules) f.close() @@ -288,10 +351,19 @@ def splitRules(rulesFN, output): rulesCheck = MakefileRules() rulesCheck.snippets = rules.snippets - rulesCheck.combine() + + topLevelSnippet = None + for snip in rules.snippets: + if snip.name.startswith("Makefile.rules."): + topLevelSnippet = snip.name + if not topLevelSnippet: + sys.stderr.write("No toplevel snippet (Makefile.rules.*) found\n") + sys.exit(1) + + rulesCheck.combineFrom(topLevelSnippet, onlyCheck=True) # The comparsion is not that simple. The order of rules might be - # different. + # different. FIXME: Is this still true? # if rules.rules != rulesCheck.rules: # sys.stderr.write("Consistency error:\n") # diff = rules.rules.getDiff(rulesCheck.rules) @@ -301,30 +373,19 @@ def splitRules(rulesFN, output): for snip in rules.snippets: if snip.name[0:2] == "__": continue - print snip.name + print(snip.name) f = None if output == "-": f = sys.stdout else: f = open(snip.name, "w+") f.writelines(snip.asLinesList()) f.close() -def buildAllRules(): - import rulesdef - os.chdir(snippetsDir) - for rules in rulesdef.rules: - print 'Building rules: %s' % rules - outputDir = os.path.join(sys.path[0], rulesDir, rules) - if not os.path.isdir(outputDir): os.makedirs(outputDir) - buildRules(rulesdef.rules[rules], os.path.join(outputDir, 'Makefile.rules'), rules) - def main(): (options, args) = parseCommandLine() - if options.all: - buildAllRules() - elif options.split: + if options.split: splitRules(options.split, options.output) else: - buildRules(args, options.output) + buildRules(args[0], options.output) if __name__ == "__main__": main()