#!/usr/bin/env python # encoding: utf-8 # # $Id$ # $URL$ """ userconfig.py Created by Marcus Stoegbauer on 2013-01-10. 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() cfg = cfgfile.Conf() verbose = 0 hostclasses = classchecks.__classesForHost__() 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""" if verbose: if level > 0: print "*"*level,out else: print out # if verbose # def debug def error(out): """Print error on stderr""" print >> sys.stderr, str(out)+"\n" # def error 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 if it does not exist workconf(name, depth+1) # if dir ret.append(name) debug("workconf: found file %s" % name, depth) # for d return ret # def workconf def workdir(directory): """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) # 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 # 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 = {} # 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) # 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): destfiles[destname] = [] # if not destname, create key with empty list destfiles[destname].append(f) # append each file to dict # for tempfiles # if classdir # for hostclasses debug("workdir: %s, Files: %s" % (directory, str(destfiles))) debug("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", 1) return destfiles # def work 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") 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: error("Cannot write to temporary file %s" % tempfilename) os.remove(tempfilename) return False # try for block in content: fp.write(block) fp.write("\n") # for content fp.close() return tempfilename # def buildFile 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(): # 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): continue elif d.startswith(".svn"): continue elif os.path.isfile(name+"/.ignore"): continue else: debug("main: %s" % name) destfiles = workdir(name) processAllFiles(destfiles) # if # for d # def main if __name__ == '__main__': main()