"""
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())