conf.py
author Tero Marttila <terom@fixme.fi>
Sun, 12 Jul 2009 00:43:36 +0300
changeset 6 57e8168ba8c4
parent 4 8b633782f02d
permissions -rw-r--r--
use FQDN for zone hosts
"""
    Generic configuration file output
"""

import os, os.path, tempfile, shutil

class ConfObject (object) :
    """
        An object that can be written to a ConfFile, as multiple lines of text.
    """

    def __init__ (self, comments=None) :
        """
            Initialize with the given list of comments. Comments that are None should be ignore.
        """
        
        # init the comments list
        self.comments = comments or []

    def add_comment (self, comment) :
        """
            Add a comment to be rendered in the output.
        """
        
        # add it
        self.comments.append(comment)

    def fmt_lines (self) :
        """
            Yield a series of lines to be output in the file
        """
        
        abstract

class File (ConfObject) :
    """
        A single configuration file on the filesystem.

        Configuration files are themselves ConfObject's, although this must be implemented in the inheriting class.
    """

    def __init__ (self, name, path, backup_suffix='.bak', mode=0644) :
        """
            Initialize the config file, but don't open it yet

            @param name the human-readable friendly name for the config file
            @param path the full filesystem path for the file
            @param backup_suffix rename the old file by adding this suffix when replacing it
            @param mode the permission bits for the new file
        """
  
        self.name = name
        self.path = path
        self.backup_suffix = backup_suffix
        self.mode = mode
    
    def write_file (self, file) :
        """
            Write out this config's stuff into the given file
        """

        writer = Writer(file)
        writer.write_obj(self)

    def write (self) :
        """
            Write out a new config file with this config's stuff using the following procedure:

                * lock the real file
                * open a new temporary file, and write out the objects into that, closing it
                * move the real file out of the way
                * move the temporary file into the real file's place
                * unlock the real file
        """

        # XXX: how to aquire the lock?
        # XXX: this needs checking over

        # open the new temporary file
        # XXX: ensure fd is closed
        tmp_fd, tmp_path = tempfile.mkstemp(prefix=self.name)

        # ...as a file
        tmp_file = os.fdopen(tmp_fd, "w")
        
        # fix the permissions
        os.chmod(tmp_path, self.mode)

        # write it
        self.write_file(tmp_file)

        # close it
        tmp_file.close()
        
        # move the old file out of the way
        if os.path.exists(self.path) :
            os.rename(self.path, self.path + self.backup_suffix)

        # move the new file in
        shutil.move(tmp_path, self.path)

class Writer (object) :
    """
        A conf.Writer is used to write out a new conf.File (as a temporary file)
    """

    def __init__ (self, file) :
        """
            @param file the temporary file object
        """

        self.file = file
    
    def write_line (self, line) :
        """
            Write a single line to the file
        """

        self.file.write("%s\n" % (line, ))
    
    def write_lines (self, lines) :
        """
            Write a series of lines into the file
        """

        for line in lines :
            self.write_line(line)

    def write_obj (self, obj) :
        """
            Write a single object to the file
        """
        
        # just write out all the lines
        self.write_lines(obj.fmt_lines())