pvl/config/file.py
author Tero Marttila <terom@fixme.fi>
Sun, 12 Jul 2009 02:14:08 +0300
changeset 8 46d36bc33086
parent 7 pvl/config/conf.py@0f9cae2d7147
permissions -rw-r--r--
rename conf to file and start refactoring
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     1
"""
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     2
    Generic configuration file output
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     3
"""
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     4
1
2223ade4f259 continue the overengineering effort, we are now able to generate dhcpd.conf files
Tero Marttila <terom@fixme.fi>
parents: 0
diff changeset
     5
import os, os.path, tempfile, shutil
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     6
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
     7
class Item (object) :
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     8
    """
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
     9
        An object that can be represented as a series of lines of text.
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    10
        
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    11
        The structure of these objects/lines is not defined, but as a convenience, a method for prepending lines of
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    12
        comments is provided.
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    13
    """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    14
    
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    15
    # the prefix char for comments, must be defined
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    16
    COMMENT_PREFIX = None
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    17
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    18
    @classmethod
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    19
    def filter_comments (self, comments) :
3
ff98fa9b84ce implement comments properly
Tero Marttila <terom@fixme.fi>
parents: 1
diff changeset
    20
        """
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    21
            Return the filtered list of comments
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    22
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    23
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    24
        return [comment for comment in comments if comment]
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    25
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    26
    def __init__ (self, comments=()) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    27
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    28
            Initialize with the given list of comments, which will be filtered before use.
3
ff98fa9b84ce implement comments properly
Tero Marttila <terom@fixme.fi>
parents: 1
diff changeset
    29
        """
ff98fa9b84ce implement comments properly
Tero Marttila <terom@fixme.fi>
parents: 1
diff changeset
    30
        
ff98fa9b84ce implement comments properly
Tero Marttila <terom@fixme.fi>
parents: 1
diff changeset
    31
        # init the comments list
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    32
        self.comments = self.filter_comments(comments)
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    33
    
3
ff98fa9b84ce implement comments properly
Tero Marttila <terom@fixme.fi>
parents: 1
diff changeset
    34
    def add_comment (self, comment) :
ff98fa9b84ce implement comments properly
Tero Marttila <terom@fixme.fi>
parents: 1
diff changeset
    35
        """
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    36
            Add the given comment
3
ff98fa9b84ce implement comments properly
Tero Marttila <terom@fixme.fi>
parents: 1
diff changeset
    37
        """
ff98fa9b84ce implement comments properly
Tero Marttila <terom@fixme.fi>
parents: 1
diff changeset
    38
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    39
        self.comments += self.filter_comments([comment])
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    40
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    41
    def iter_comments (self) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    42
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    43
            Formats comments for output
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    44
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    45
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    46
        for comment in self.comments :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    47
            yield "%s %s" % (self.COMMENT_PREFIX, comment)
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    48
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    49
    def iter_lines (self, indent='\t') :
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    50
        """
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    51
            Yield a series of lines to be output in the file
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    52
        """
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    53
        
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    54
        abstract
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    55
    
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    56
    def render_lines (self, encoding=None, newline='\n', **opts) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    57
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    58
            Render lines as a series of objects, possibly encoded.
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    59
        """
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    60
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    61
        for line in self.iter_lines(**opts) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    62
            if encoding :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    63
                line = line.encode(encoding)
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    64
            
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    65
            elif encoding is False :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    66
                line = unicode(line)
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    67
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    68
            yield line + newline
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    69
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    70
    def render_unicode (self, **opts) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    71
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    72
            Render lines as a single unicode object
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    73
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    74
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    75
        return u''.join(self.render_lines(encoding=False, **opts))
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    76
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    77
    def render_str (self, encoding='utf-8', **opts) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    78
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    79
            Render lines as a single str object
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    80
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    81
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    82
        return ''.join(self.render_lines(encoding=encoding, **opts))
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    83
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    84
    def render_out (self, file, encoding='utf-8', **opts) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    85
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    86
            Render lines and write out to given file object
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    87
        """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    88
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    89
        for line in self.render_lines(encoding=encoding, **opts) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    90
            file.write(line)
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    91
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    92
class Contents (Item) :
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    93
    """
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    94
        A series of Items
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    95
    """
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    96
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    97
    def __init__ (self, *items) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    98
        self.items = items
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
    99
    
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   100
    def add_item (self, item) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   101
        self.items.append(item)
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   102
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   103
    def iter_lines (self, **opts) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   104
        for item in self.items :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   105
            for line in item.iter_lines(**opts) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   106
                yield line
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   107
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   108
class File (object) :
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   109
    """
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   110
        A configuration file on the filesystem.
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   111
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   112
        Configuration files can be written out with some given contents.
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   113
            
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   114
            
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   115
        XXX: better logic for backup file
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   116
    """
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   117
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   118
    def __init__ (self, name, path, backup_suffix='.bak', mode=0644) :
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   119
        """
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   120
            Initialize the config file, but don't open it yet
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   121
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   122
            @param name the human-readable friendly name for the config file
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   123
            @param path the full filesystem path for the file
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   124
            @param backup_suffix rename the old file by adding this suffix when replacing it
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   125
            @param mode the permission bits for the new file
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   126
        """
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   127
  
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   128
        self.name = name
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   129
        self.path = path
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   130
        self.backup_suffix = backup_suffix
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   131
        self.mode = mode
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   132
    
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   133
    def write (self, data) :
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   134
        """
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   135
            Write out a new config file with the given Item data using the following procedure:
4
8b633782f02d write bind_conf.py
Tero Marttila <terom@fixme.fi>
parents: 3
diff changeset
   136
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   137
                * lock the real file
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   138
                * open a new temporary file, and write out the objects into that, closing it
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   139
                * move the real file out of the way
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   140
                * move the temporary file into the real file's place
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   141
                * unlock the real file
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   142
        """
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   143
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   144
        # XXX: how to aquire the lock?
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   145
        # XXX: this needs checking over
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   146
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   147
        # open the new temporary file
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   148
        # XXX: ensure OS fd is closed
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   149
        tmp_fd, tmp_path = tempfile.mkstemp(prefix=self.name)
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   150
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   151
        # ...as a file
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   152
        tmp_file = os.fdopen(tmp_fd, "w")
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   153
        
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   154
        # fix the permissions
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   155
        os.chmod(tmp_path, self.mode)
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   156
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   157
        # write the Item out into the file
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   158
        data.render_out(tmp_file)
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   159
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   160
        # close it
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   161
        tmp_file.close()
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   162
        
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   163
        # move the old file out of the way
1
2223ade4f259 continue the overengineering effort, we are now able to generate dhcpd.conf files
Tero Marttila <terom@fixme.fi>
parents: 0
diff changeset
   164
        if os.path.exists(self.path) :
8
46d36bc33086 rename conf to file and start refactoring
Tero Marttila <terom@fixme.fi>
parents: 7
diff changeset
   165
            # XXX: use shutil.move?
1
2223ade4f259 continue the overengineering effort, we are now able to generate dhcpd.conf files
Tero Marttila <terom@fixme.fi>
parents: 0
diff changeset
   166
            os.rename(self.path, self.path + self.backup_suffix)
0
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   167
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   168
        # move the new file in
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   169
        shutil.move(tmp_path, self.path)
257003279747 initial code
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   170