rename conf to file and start refactoring
authorTero Marttila <terom@fixme.fi>
Sun, 12 Jul 2009 02:14:08 +0300
changeset 8 46d36bc33086
parent 7 0f9cae2d7147
child 9 2156906bfbf1
rename conf to file and start refactoring
pvl/config/conf.py
pvl/config/file.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())
-
--- /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)
+