]> rtime.felk.cvut.cz Git - omk.git/blobdiff - omkbuild.py
omkbuild.py: Makefile.rules are constructed by replacing include directives in snippets
[omk.git] / omkbuild.py
index 7f01c3b5064478d5164891bbb52902c6e7095188..68e555eb32d256afcc9f31f15cdec650113f2b93 100755 (executable)
@@ -23,10 +23,16 @@ 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@<snippet file name><EOL>. This mark
-     is used for splitting modified Makefile.rules back to the
-     original snippets. If <snippet file name> starts with __, it is
-     ignored during splitting.
+     special mark of the form:
+
+       #OMK:<snippet file name>[@<included from snippet>]<EOL>
+
+     This mark is used for splitting modified Makefile.rules back to
+     the original snippets. If <snippet file name> 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
@@ -199,24 +205,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 = string.rstrip(line).ljust(80)+" #OMK:%s@%s\n"%(filename,baseFileName)
+                    elif addMarker==2:
+                        line = string.rstrip(line).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]
+                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()
@@ -226,7 +279,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
 
@@ -235,6 +288,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]
@@ -247,7 +305,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",
@@ -256,19 +314,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
@@ -292,10 +346,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)
@@ -312,23 +375,12 @@ def splitRules(rulesFN, output):
         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()