From 74d3d8f1bbe882a1c451ba8cc50db2aa2c087e1e Mon Sep 17 00:00:00 2001 From: Marcus Stoegbauer Date: Sat, 12 Jan 2013 22:04:52 +0000 Subject: [PATCH] Zwischenstand --- cfgfile.py | 64 +++++++++++++++ checks.py | 17 +++- userconfig.py | 216 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 254 insertions(+), 43 deletions(-) create mode 100644 cfgfile.py diff --git a/cfgfile.py b/cfgfile.py new file mode 100644 index 0000000..fc35265 --- /dev/null +++ b/cfgfile.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# $Id$ +# $URL$ + +""" +cfgfile.py + +Created by Marcus Stoegbauer on 2013-01-12. +Copyright (c) 2013 __MyCompanyName__. All rights reserved. +""" +from ConfigParser import ConfigParser + +class Conf(object): + confobj = ConfigParser() + cfgfile = '' + + def __init__(self, filename = None): + """if filename is set, open config file and initialize the ConfigParser + """ + if filename: + self.setfilename(filename) + # if filename + # def __init__ + + def setfilename(self, filename): + """initialize the ConfigParser + """ + if len(self.confobj.read(filename)) == 0 or self.confobj.read(filename)[0] != filename: + raise Exception('Cannot read config file ' + filename) + # if cannot read + self.cfgfile = filename + # def setfilename + + def get(self, section, option): + """returns the value of option in section + """ + if not self.cfgfile: + raise Exception('No config file set') + # if not cfgfile + return self.confobj.get(section, option) + # def get + + def set(self, section, option, value): + """docstring for update""" + self.confobj.set(section, option, value) + # def set + + + def getitems(self, section): + """returns all items in section + """ + if not self.cfgfile: + raise Exception('No config file set') + # if not cfgfile + return self.confobj.items(section) + # def getitems +# class Conf + + + def check(self, section, option): + """checks for option in section""" + return self.confobj.has_option(section, option) \ No newline at end of file diff --git a/checks.py b/checks.py index 15f77ab..8d5c38c 100644 --- a/checks.py +++ b/checks.py @@ -1,5 +1,9 @@ #!/usr/bin/env python # encoding: utf-8 +# +# $Id$ +# $URL$ + """ checks.py @@ -28,10 +32,19 @@ class checks(object): # for c return map(lambda k: (k[1],k[2]), sorted(classes, key=lambda k: k[0])) # def __classesForHost__ - + + def header(self): + """docstring for header""" + return (0, "", "header") + # def header + + def footer(self): + """docstring for footer""" + return (1000, "", "footer") + def all(self): """docstring for all""" - return (999, "", "all") + return (998, "", "all") # def all def arch(self): diff --git a/userconfig.py b/userconfig.py index 923e5db..8e4e77a 100755 --- a/userconfig.py +++ b/userconfig.py @@ -14,12 +14,28 @@ Copyright (c) 2013 __MyCompanyName__. All rights reserved. import sys import os import tempfile +import re +import getopt +# +import cfgfile from checks import checks classchecks = checks() -configdir = "../" +cfg = cfgfile.Conf() +verbose = 0 + hostclasses = classchecks.__classesForHost__() -verbose = 1 + +class Usage(Exception): + def __init__(self, msg): + self.msg = msg + + +help_message = """ +-h help +-d debug +-c userconfig.cfg config file +""" def debug(out, level=0): """docstring for debug""" @@ -31,28 +47,48 @@ def debug(out, level=0): # if verbose # def debug -def getDEST(directory): - """docstring for getDEST""" - f = open(directory+"/DEST") - destdir= f.read()[:-1] - if destdir == "$HOME": - destdir = os.environ['HOME'] - # if $HOME - if not destdir.endswith("/"): - destdir += "/" - # if not / - return destdir -# def getDEST +def error(out): + """Print error on stderr""" + print >> sys.stderr, str(out)+"\n" +# def error -def workconf(directory, destdir, depth=2): - """docstring for workconf""" +def getConfig(filename): + """reads filename as config, checks for DEST parameter and returns cfgfile object""" + try: + ret = cfgfile.Conf(filename) + except: + error("Error reading config file %s" % filename) + return False + # try + + # check for DEST parameter + if not ret.check("Main", "DEST"): + error("No DEST in config file %s" % filename) + return False + # if no DEST + + # replace $HOME with real home directory + if ret.get("Main", "DEST") == "$HOME": + ret.set("Main", "DEST", os.environ['HOME']) + # if $HOME + + # make sure DEST ends with / + if not ret.get("Main", "DEST").endswith("/"): + ret.set("Main", "DEST", ret.get("Main", "DEST")+"/") + # if not / + + return ret +# def getConfig + +def workconf(directory, depth=2): + """walks through directory, collecting all filenames, returns list of all filenames""" dirs = os.listdir(directory) ret = [] for d in dirs: name = directory+"/"+d if os.path.isdir(name): - # fixme: create name - workconf(name, destdir, depth+1) + # fixme: create name if it does not exist + workconf(name, depth+1) # if dir ret.append(name) debug("workconf: found file %s" % name, depth) @@ -61,30 +97,47 @@ def workconf(directory, destdir, depth=2): # def workconf def workdir(directory): - """docstring for work""" + """walks through all host classes, checking if the classes directory exists in directory + then collect all filenames within this directory and return a dict of all files for this + directory + """ debug("===============================", 1) - if not os.path.isfile(directory+"/DEST"): - debug("No DEST in %s, skipping." % directory, 1) - return + # skip directory if no CONFIGFILE present + if not os.path.isfile(directory+"/"+cfg.get("Main", "CONFIGFILE")): + debug("No %s in %s, skipping." % (cfg.get("Main", "CONFIGFILE"), directory), 1) + return {} # if not DEST - destdir = getDEST(directory) + + # get config file for directory + dirConfig = getConfig(directory+"/"+cfg.get("Main", "CONFIGFILE")) + if not dirConfig: + debug("Cannot read %s in %s, skipping." % (cfg.get("Main", "CONFIGFILE"), directory), 1) + return {} + # if not dirConfig + + destdir = dirConfig.get("Main","DEST") # destfiles is a dict of all files that will be created from the classes config # key is the destination filename, values are all classes filenames that are used to # build the file destfiles = {} - # Schritt 1: Dateien einlesen + + # walk through all know classes in directory and find filenames for h in hostclasses: + # build classes directory if h[0] != "": classdir = directory+"/"+h[0]+"_"+h[1] else: classdir = directory+"/"+h[1] # if all + + # if class directory exists if os.path.isdir(classdir): debug("workdir: %s" % classdir, 1) - tempfiles = workconf(classdir, destdir) - # tempfiles is a list of files within one classdir + # get list of files within this class directory + tempfiles = workconf(classdir) + # put files into dict for f in tempfiles: destname = destdir+os.path.basename(f) # destination filename if not destfiles.has_key(destname): @@ -94,29 +147,37 @@ def workdir(directory): # for tempfiles # if classdir # for hostclasses + debug("workdir: %s, Files: %s" % (directory, str(destfiles))) debug("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", 1) return destfiles # def work -def buildFile(destfile, classfiles): - """docstring for buildFile""" +def buildFile(classfiles, destfile): + """open all classfiles, assemble them and write the contents into a tempfile + returns the name of tempfile""" content = [] for f in classfiles: fp = open(f, "r") - content.append(fp.read()) + filecontent = fp.read() fp.close() + + # look for stamp in content, replace with real stamp + if re.search(re.escape(cfg.get("Main","STAMPREPLACE")), filecontent): + filecontent = re.sub(re.escape(cfg.get("Main","STAMPREPLACE")), cfg.get("Main","STAMP"), filecontent) + # if match + content.append(filecontent) # end f (tempfd, tempfilename) = tempfile.mkstemp(prefix=os.path.basename(destfile), dir="/tmp") - + fp = None try: fp = os.fdopen(tempfd, "w") except: - print "Cannot write to temporary file",tempfilename + error("Cannot write to temporary file %s" % tempfilename) os.remove(tempfilename) - sys.exit(1) + return False # try for block in content: @@ -124,22 +185,95 @@ def buildFile(destfile, classfiles): fp.write("\n") # for content fp.close() - # fixme: diff tempfilename destfile - # fixme: header marker for "is under userconfig control" - # fixme: if diff and not under userconfig control, backup destfile - # fixme: copy tempfilename to destfile - # fixme: remove tempfilename + + return tempfilename # def buildFile -def buildAllFiles(destfiles): - """docstring for buildFiles""" +def diff(fileA, fileB): + """diff fileA and fileB, returns True if files differ, False if they are the same""" + # FIXME: write + # FIXME: filter out comments? + # FIXME: COMMENTSTRING in config? + return False +# def diff + +def userConfigGenerated(filename): + """returns True if filename has been generated by userconfig, False else""" + # FIXME: write + return True +# def userConfigGenerated + +def backupFile(filename): + """make backup of filename, returns True if backup is successful, False else""" + # FIXME: write + return True +# def backupFile + +def copyFile(sourcefile, destfile): + """copy sourcefile to destfile, returns True if successful, False else""" + return True +# def copyFile + +def processAllFiles(destfiles): + """processes all files in destfiles, generate files from classes, compare and copy if necessary""" for df in destfiles.keys(): - buildFile(df, destfiles[df]) + # assemble file to tmp + tempfilename = buildFile(destfiles[df], df) + if not tempfilename: + debug("Error while creating temp file for %s, skipping." % df) + continue + # if not tempfilename + + # diff assembled file and config file + if diff(df, tempfilename): + if not userConfigGenerated(df): + # file not generated from userconfig -> back up + backupFile(df) + # if not userConfigGenerated + # copy tmp file to real location + copyFile(tempfilename, df) + # remove tmp + os.remove(tempfilename) + # if diff # for df # def buildAllFiles def main(): + configfile = "" + global verbose + + try: + try: + opts, args = getopt.getopt(sys.argv[1:], "hdc:v", ["help", "debug", "config="]) + except getopt.error, msg: + raise Usage(msg) + # try getopt + + for option, value in opts: + if option == "-v": + verbose = 1 + if option in ("-h", "--help"): + raise Usage(help_message) + if option in ("-d", "--debug"): + pass + if option in ("-c", "--config"): + configfile = value + # if + # for option, value + except Usage, err: + error(sys.argv[0].split("/")[-1] + ": " + str(err.msg)) + error("\t for help use --help") + return 2 + # try + + if configfile == "": + error( "No config file specified.") + return 2 + # if configfile + cfg.setfilename(configfile) + debug("Classes for host: %s" % hostclasses) + configdir = cfg.get("Main", "CONFIGDIR") for d in os.listdir(configdir): name = configdir+d if not os.path.isdir(name): @@ -151,7 +285,7 @@ def main(): else: debug("main: %s" % name) destfiles = workdir(name) - buildAllFiles(destfiles) + processAllFiles(destfiles) # if # for d # def main