#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http:#www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from xml.dom.minidom import parse, parseString, Node from cStringIO import StringIO from stat import * from errno import * import os import os.path import filecmp #===================================================================================== # #===================================================================================== class Template: def __init__ (self, filename, handler): self.filename = filename self.handler = handler def expandLine (self, line, stream, object): cursor = 0 while 1: sub = line.find ("/*MGEN:", cursor) if sub == -1: stream.write (line[cursor:len (line)]) return subend = line.find("*/", sub) stream.write (line[cursor:sub]) cursor = subend + 2 tag = line[sub:subend] dotPos = tag.find (".") if dotPos == -1: raise ValueError ("Invalid tag: %s" % tag) tagObject = tag[7:dotPos] tagName = tag[dotPos + 1:len (tag)] self.handler (object, stream, tagObject, tagName) def expand (self, object): fd = open (self.filename) stream = StringIO () for line in fd: self.expandLine (line, stream, object) fd.close () return stream #===================================================================================== # #===================================================================================== class Generator: def createPath (self, path): exists = True try: mode = os.stat (path)[ST_MODE] except OSError, (err,text): if err == ENOENT: exists = False else: raise if exists and not S_ISDIR (mode): raise ValueError ("path is not directory: %s" % path) if not exists: pair = os.path.split (path) self.createPath (pair[0]) os.mkdir (path) def normalize (self, path): newpath = os.path.normcase (os.path.normpath (path)) self.createPath (newpath) return newpath + "/" def __init__ (self, destDir, templateDir): self.dest = self.normalize (destDir) self.input = self.normalize (templateDir) self.filelists = {} self.filelists["h"] = [] self.filelists["cpp"] = [] self.filelists["mk"] = [] self.templateFiles = [] def genDisclaimer (self, stream): stream.write ("// This source file was created by a code generator.\n") stream.write ("// Please do not edit.") def fileExt (self, path): dot = path.rfind (".") if dot == -1: return "" return path[dot + 1:] def writeIfChanged (self, stream, target, force=False): ext = self.fileExt (target) self.filelists[ext].append (target) tempFile = self.dest + "gen.tmp" fd = open (tempFile, "w") fd.write (stream.getvalue ()) fd.close () try: if not force and filecmp.cmp (target, tempFile): os.remove (tempFile) return except: pass try: os.remove (target) except: pass os.rename (tempFile, target) print "Generated:", target def targetClassFile (self, _class, templateFile): dot = templateFile.find(".") if dot == -1: raise ValueError ("Invalid template file name %s" % templateFile) extension = templateFile[dot:len (templateFile)] path = self.dest + _class.getName ().capitalize () + extension return path def targetMethodFile (self, method, templateFile): """ Return the file name for a method file """ dot = templateFile.rfind(".") if dot == -1: raise ValueError ("Invalid template file name %s" % templateFile) extension = templateFile[dot:] path = self.dest + "Args" + method.getFullName () + extension return path def substHandler (self, object, stream, tagObject, tag): if tagObject == "Root": obj = "self" else: obj = "object" # MUST be the same as the 2nd formal parameter call = obj + ".gen" + tag + "(stream)" eval (call) def makeClassFiles (self, templateFile, schema): """ Generate an expanded template per schema class """ classes = schema.getClasses () template = Template (self.input + templateFile, self.substHandler) self.templateFiles.append (templateFile) for _class in classes: target = self.targetClassFile (_class, templateFile) stream = template.expand (_class) self.writeIfChanged (stream, target) def makeMethodFiles (self, templateFile, schema): """ Generate an expanded template per method-with-arguments """ classes = schema.getClasses () template = Template (self.input + templateFile, self.substHandler) self.templateFiles.append (templateFile) for _class in classes: methods = _class.getMethods () for method in methods: if method.getArgCount () > 0: target = self.targetMethodFile (method, templateFile) stream = template.expand (method) self.writeIfChanged (stream, target) def makeMakeFile (self, target): stream = StringIO () stream.write ("# Generated makefile fragment.\n\n") stream.write ("mgen_generator=$(mgen_dir)/main.py \\\n") stream.write (" $(mgen_dir)/generate.py \\\n") stream.write (" $(mgen_dir)/schema.py \\\n") stream.write (" $(top_srcdir)/../specs/management-types.xml \\\n") stream.write (" $(top_srcdir)/../specs/management-schema.xml \\\n ") first = 1 for template in self.templateFiles: if first == 1: first = 0 else: stream.write (" \\\n ") stream.write ("$(mgen_dir)/templates/" + template) stream.write ("\n\nmgen_broker_cpp=") first = 1 for file in self.filelists["cpp"]: if first == 1: first = 0 else: stream.write (" \\\n ") stream.write (file.replace ("../src", ".")) stream.write ("\n\n") stream.write ("# Header file install rules.\n") stream.write ("qpid_managementdir = $(includedir)/qpid/management\n") stream.write ("dist_qpid_management_HEADERS = ") first = 1 for file in self.filelists["h"]: if first == 1: first = 0 else: stream.write (" \\\n ") stream.write (file.replace ("../src", ".")) stream.write ("\n\n") stream.write ("if GENERATE\n") stream.write ("$(srcdir)/managementgen.mk: $(mgen_generator)\n") stream.write ("\t$(mgen_cmd)\n") stream.write ("\n$(mgen_generator):\n") stream.write ("endif\n") self.writeIfChanged (stream, target, force=True)