# HG changeset patch # User Tero Marttila # Date 1247354048 -10800 # Node ID 46d36bc330868c3f7929ea85ae14ca20f08e8580 # Parent 0f9cae2d71479d0c0573d0e46f4fefd7170446e6 rename conf to file and start refactoring diff -r 0f9cae2d7147 -r 46d36bc33086 pvl/config/conf.py --- a/pvl/config/conf.py Sun Jul 12 00:51:08 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -""" - 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()) - diff -r 0f9cae2d7147 -r 46d36bc33086 pvl/config/file.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pvl/config/file.py Sun Jul 12 02:14:08 2009 +0300 @@ -0,0 +1,170 @@ +""" + Generic configuration file output +""" + +import os, os.path, tempfile, shutil + +class Item (object) : + """ + An object that can be represented as a series of lines of text. + + The structure of these objects/lines is not defined, but as a convenience, a method for prepending lines of + comments is provided. + """ + + # the prefix char for comments, must be defined + COMMENT_PREFIX = None + + @classmethod + def filter_comments (self, comments) : + """ + Return the filtered list of comments + """ + + return [comment for comment in comments if comment] + + def __init__ (self, comments=()) : + """ + Initialize with the given list of comments, which will be filtered before use. + """ + + # init the comments list + self.comments = self.filter_comments(comments) + + def add_comment (self, comment) : + """ + Add the given comment + """ + + self.comments += self.filter_comments([comment]) + + def iter_comments (self) : + """ + Formats comments for output + """ + + for comment in self.comments : + yield "%s %s" % (self.COMMENT_PREFIX, comment) + + def iter_lines (self, indent='\t') : + """ + Yield a series of lines to be output in the file + """ + + abstract + + def render_lines (self, encoding=None, newline='\n', **opts) : + """ + Render lines as a series of objects, possibly encoded. + """ + + for line in self.iter_lines(**opts) : + if encoding : + line = line.encode(encoding) + + elif encoding is False : + line = unicode(line) + + yield line + newline + + def render_unicode (self, **opts) : + """ + Render lines as a single unicode object + """ + + return u''.join(self.render_lines(encoding=False, **opts)) + + def render_str (self, encoding='utf-8', **opts) : + """ + Render lines as a single str object + """ + + return ''.join(self.render_lines(encoding=encoding, **opts)) + + def render_out (self, file, encoding='utf-8', **opts) : + """ + Render lines and write out to given file object + """ + + for line in self.render_lines(encoding=encoding, **opts) : + file.write(line) + +class Contents (Item) : + """ + A series of Items + """ + + def __init__ (self, *items) : + self.items = items + + def add_item (self, item) : + self.items.append(item) + + def iter_lines (self, **opts) : + for item in self.items : + for line in item.iter_lines(**opts) : + yield line + +class File (object) : + """ + A configuration file on the filesystem. + + Configuration files can be written out with some given contents. + + + XXX: better logic for backup file + """ + + 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 (self, data) : + """ + Write out a new config file with the given Item data 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 OS 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 the Item out into the file + data.render_out(tmp_file) + + # close it + tmp_file.close() + + # move the old file out of the way + if os.path.exists(self.path) : + # XXX: use shutil.move? + os.rename(self.path, self.path + self.backup_suffix) + + # move the new file in + shutil.move(tmp_path, self.path) +