pvl/dhcp/config.py
author Tero Marttila <tero.marttila@aalto.fi>
Mon, 02 Mar 2015 12:59:17 +0200
changeset 685 668f934bb958
parent 682 60dbd952a15e
child 695 c60924eca185
permissions -rw-r--r--
pvl.dhcp.config: fix build_block() to handle top-level config Blocks
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
     1
import logging; log = logging.getLogger('pvl.dhcp.config')
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
     2
import shlex
673
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
     3
import string
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
     4
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
     5
# simplified model of lexer chars
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
     6
TOKEN_START = string.ascii_letters + string.digits + '-'
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
     7
TOKEN = TOKEN_START + '_'
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
     8
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
     9
# be far more lenient when parsing
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    10
TOKEN_EXTRA = TOKEN + ':.'
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    11
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    12
UNQUOTED_CONTEXT = set((
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    13
    ('host', ),
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    14
    ('fixed-address', ),
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    15
    ('next-server', ),
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    16
    ('hardware', 'ethernet'),
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    17
))
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    18
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    19
class DHCPConfigError(Exception):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    20
    def __init__ (self, parser, error, line=None):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    21
        self.parser = parser
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    22
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    23
        self.name = parser.name
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    24
        self.line = line
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    25
        self.error = error
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    26
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    27
    def __str__ (self):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    28
        return "{self.name}:{self.line}: {self.error}".format(self=self)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    29
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    30
def split (line) :
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    31
    """
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    32
        Split given line-data into raw tokens.
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    33
        
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    34
        >>> list(split('foo'))
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    35
        ['foo']
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    36
        >>> list(split('foo bar'))
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    37
        ['foo', 'bar']
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    38
        >>> list(split('foo;'))
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    39
        ['foo', ';']
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    40
        >>> list(split('"foo"'))
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    41
        ['foo']
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    42
        >>> list(split('foo "asdf quux" bar'))
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    43
        ['foo', 'asdf quux', 'bar']
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    44
        >>> list(split('foo "asdf quux"'))
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    45
        ['foo', 'asdf quux']
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    46
        >>> list(split('# nevermind'))
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    47
        []
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    48
        >>> list(split(''))
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    49
        []
673
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    50
        >>> list(split('next-server foo'))
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    51
        ['next-server', 'foo']
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    52
        >>> list(split('include "foo/bar.conf";'))
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    53
        ['include', 'foo/bar.conf', ';']
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    54
    """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    55
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    56
    if line is None:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    57
        raise TypeError(line)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    58
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    59
    lexer = shlex.shlex(line, posix=True)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    60
    lexer.commenters = '#'
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    61
    lexer.wordchars = TOKEN_EXTRA
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    62
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    63
    while True:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    64
        item = lexer.get_token()
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    65
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    66
        if item is None:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    67
            break
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    68
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    69
        yield item
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
    70
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    71
def quote (value, context=None):
673
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    72
    """
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    73
        Build a single field as part of a dhcp.conf line.
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    74
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    75
        >>> print quote('foo')
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    76
        foo
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    77
        >>> print quote('foo bar')
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    78
        "foo bar"
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    79
        >>> print quote('foo/bar.conf')
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    80
        "foo/bar.conf"
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    81
        >>> print quote(5)
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    82
        5
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    83
        >>> print quote('5')
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    84
        5
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    85
        >>> print quote('foo.bar')
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    86
        "foo.bar"
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    87
        >>> print quote('foo.bar', context=('host', ))
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    88
        foo.bar
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    89
        >>> print quote('192.0.2.1', context=('fixed-address', ))
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    90
        192.0.2.1
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    91
        >>> print quote('00:11:22:33:44:55', context=('hardware', 'ethernet'))
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    92
        00:11:22:33:44:55
673
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    93
    """
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    94
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    95
    if isinstance(value, int):
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
    96
        return str(value)
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    97
    elif context in UNQUOTED_CONTEXT:
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    98
        return str(value)
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
    99
    elif value[0] in TOKEN_START and all(c in TOKEN for c in value):
673
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
   100
        return str(value)
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
   101
    else:
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
   102
        # quoted
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
   103
        return '"{value}"'.format(value=value)
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
   104
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   105
class Block (object):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   106
    """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   107
        A block in a dhcp conf includes parameters and sub-blocks.
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   108
    """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   109
668
794f943c835d pvl.dhcp.config: Block(comment=...)
Tero Marttila <terom@paivola.fi>
parents: 666
diff changeset
   110
    def __init__ (self, key, items=None, blocks=None, comment=None):
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   111
        """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   112
            key: tuple      - name of block
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   113
        """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   114
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   115
        self.key = key
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   116
        self.items = items or [ ]
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   117
        self.blocks = blocks or [ ]
668
794f943c835d pvl.dhcp.config: Block(comment=...)
Tero Marttila <terom@paivola.fi>
parents: 666
diff changeset
   118
        self.comment = comment
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   119
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   120
    def __str__ (self):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   121
        return ' '.join(self.key)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   122
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   123
    def __repr__ (self):
682
60dbd952a15e pvl.dhcp.config: fix block stack to have .load() actually return the top-level block
Tero Marttila <terom@paivola.fi>
parents: 681
diff changeset
   124
        return "Block({self.key!r}, items={self.items!r}, blocks={self.blocks!r})".format(self=self)
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   125
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   126
class DHCPConfigParser (object):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   127
    """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   128
        Simple parser for ISC dhcpd conf files.
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   129
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   130
        Supports iterative parsing as required for following a dhcpd.leases file.
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   131
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   132
        Doesn't implement the full spec, but a useful approximation.
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   133
    """
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   134
256
63b285ceae41 pvl.dhcp.config: nested blocks
Tero Marttila <terom@paivola.fi>
parents: 255
diff changeset
   135
    @classmethod
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   136
    def load (cls, file, name=None):
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   137
        """
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   138
            Parse an complete file, returning the top-level Block.
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   139
673
0eda16e29613 pvl.dhcp.config: stricter quoting of e.g. include file paths
Tero Marttila <terom@paivola.fi>
parents: 668
diff changeset
   140
            >>> DHCPConfigParser.load(['foo;', 'bar {', '\tasdf "quux";', '}'], name='test')
682
60dbd952a15e pvl.dhcp.config: fix block stack to have .load() actually return the top-level block
Tero Marttila <terom@paivola.fi>
parents: 681
diff changeset
   141
            Block(None, items=[('foo',)], blocks=[Block(('bar',), items=[('asdf', 'quux')], blocks=[])])
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   142
        """
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   143
        
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   144
        if name is None:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   145
            name = file.name
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   146
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   147
        parser = cls(name=name)
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   148
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   149
        for lineno, line in enumerate(file, 1):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   150
            try:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   151
                for item in parser.parse_line(line):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   152
                    log.debug("%s", item)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   153
            except DHCPConfigError as error:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   154
                error.line = lineno
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   155
                raise
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   156
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   157
        if parser.token:
682
60dbd952a15e pvl.dhcp.config: fix block stack to have .load() actually return the top-level block
Tero Marttila <terom@paivola.fi>
parents: 681
diff changeset
   158
            raise DHCPConfError(parser, "Trailing data: {token}".format(token=parser.token), line=lineno)
60dbd952a15e pvl.dhcp.config: fix block stack to have .load() actually return the top-level block
Tero Marttila <terom@paivola.fi>
parents: 681
diff changeset
   159
        
60dbd952a15e pvl.dhcp.config: fix block stack to have .load() actually return the top-level block
Tero Marttila <terom@paivola.fi>
parents: 681
diff changeset
   160
        if parser.stack:
60dbd952a15e pvl.dhcp.config: fix block stack to have .load() actually return the top-level block
Tero Marttila <terom@paivola.fi>
parents: 681
diff changeset
   161
            raise DHCPConfError(parser, "Unterminated block: {stack}".format(stack=parser.stack), line=lineno)
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   162
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   163
        return parser.block 
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   164
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   165
    def __init__ (self, name=None):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   166
        self.name = name
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   167
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   168
        # lexer state
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   169
        self.token = []
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   170
        
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   171
        # parser state
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   172
        self.stack = []
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   173
        
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   174
        # top-level block
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   175
        self.block = Block(None)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   176
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   177
    def lex (self, line):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   178
        """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   179
            Lex one line of input into basic expressions:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   180
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   181
                open:   [...] {
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   182
                item:       [..];
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   183
                close:  [] }
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   184
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   185
            Yields (event, (...)) tokens.
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   186
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   187
            Raises DHCPConfError.
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   188
        """
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   189
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   190
        log.debug("%s", line)
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   191
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   192
        for word in split(line):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   193
            if word == '{':
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   194
                yield 'open', tuple(self.token)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   195
            
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   196
            elif word == ';':
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   197
                yield 'item', tuple(self.token)
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   198
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   199
            elif word == '}':
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   200
                if self.token:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   201
                    raise DHCPConfError(self, "Leading data on close: {token}".format(token=self.token))
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   202
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   203
                yield 'close', None
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   204
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   205
            else:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   206
                self.token.append(word)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   207
                continue
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   208
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   209
            self.token = [ ]
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   210
       
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   211
    def parse (self, tokens):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   212
        """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   213
            Parse given tokens, yielding any complete Blocks.
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   214
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   215
            Note that the Blocks yielded may be within some other Block which is still incomplete.
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   216
        """
256
63b285ceae41 pvl.dhcp.config: nested blocks
Tero Marttila <terom@paivola.fi>
parents: 255
diff changeset
   217
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   218
        for token, args in tokens:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   219
            if token == 'open':
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   220
                block = Block(args)
256
63b285ceae41 pvl.dhcp.config: nested blocks
Tero Marttila <terom@paivola.fi>
parents: 255
diff changeset
   221
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   222
                log.debug("open block: %s > %s", self.block, block)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   223
                
682
60dbd952a15e pvl.dhcp.config: fix block stack to have .load() actually return the top-level block
Tero Marttila <terom@paivola.fi>
parents: 681
diff changeset
   224
                self.stack.append(self.block)
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   225
                self.block.blocks.append(block)
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   226
                self.block = block
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   227
            
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   228
            # must be within block!
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   229
            elif token == 'item' :
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   230
                log.debug("block %s item: %s", self.block, args)
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   231
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   232
                self.block.items.append(args)
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   233
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   234
            elif token == 'close' :
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   235
                log.debug("close block: %s", self.block)
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   236
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   237
                block = self.block
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   238
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   239
                if self.stack:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   240
                    self.block = self.stack.pop()
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   241
                else:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   242
                    raise DHCPConfigError(self, "Mismatched block close: {block}".format(block=block))
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   243
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   244
                yield block
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   245
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   246
            else:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   247
                raise ValueError(token, args)
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   248
    
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   249
    def parse_line (self, line):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   250
        """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   251
            Lex and parse line tokens.
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   252
        """
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   253
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   254
        for block in self.parse(self.lex(line)):
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   255
            yield block
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   256
255
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   257
    def parse_lines (self, lines) :
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   258
        """
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   259
            Trivial wrapper around parse to parse multiple lines.
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   260
        """
d14eda12d966 split pvl.dhcp.config.DHCPConfigParser
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   261
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   262
        for line in lines:
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   263
            for block in self.parse_line(line) :
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   264
                yield block
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   265
    
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   266
def build_line (item, end, indent=0, context=None):
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   267
    """
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   268
        Build a structured line.
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   269
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   270
        >>> print build_line(('foo', ), ';')
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   271
        foo;
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   272
        >>> print build_line(('host', 'foo'), ' {')
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   273
        host foo {
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   274
        >>> print build_line(('foo', 'bar quux'), ';', indent=1)
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   275
            foo "bar quux";
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   276
    """
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   277
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   278
    return '    '*indent + ' '.join(quote(field, context=context) for field in item) + end
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   279
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   280
def build_item (item, **opts):
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   281
    """
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   282
        Build a single parameter line.
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   283
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   284
        >>> print build_item(('foo', ))
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   285
        foo;
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   286
    """
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   287
679
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   288
    return build_line(item, end=';',
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   289
        context     = item[:-1],
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   290
        **opts
31adba0f586d pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
Tero Marttila <terom@paivola.fi>
parents: 675
diff changeset
   291
    )
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   292
668
794f943c835d pvl.dhcp.config: Block(comment=...)
Tero Marttila <terom@paivola.fi>
parents: 666
diff changeset
   293
def build_block (block, indent=0):
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   294
    """
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   295
        Build a complete Block, recursively, yielding output lines.
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   296
681
3da02c7e5781 pvl.dhcp.config: fix build_block() doctests
Tero Marttila <terom@paivola.fi>
parents: 680
diff changeset
   297
        >>> for line in build_block(Block(('host', 'foo'), [('hardware', 'ethernet', '00:11:22:33:44:55')], comment="Testing")): print line
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   298
        # Testing
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   299
        host foo {
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   300
            hardware ethernet 00:11:22:33:44:55;
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   301
        }
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   302
        >>> for line in build_block(Block(('group', ), [('next-server', 'booter')], [ \
681
3da02c7e5781 pvl.dhcp.config: fix build_block() doctests
Tero Marttila <terom@paivola.fi>
parents: 680
diff changeset
   303
                    Block(('host', 'foo'), [('hardware', 'ethernet', '00:11:22:33:44:55')]) \
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   304
                ])): print line
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   305
        group {
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   306
            next-server booter;
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   307
        <BLANKLINE>
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   308
            host foo {
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   309
                hardware ethernet 00:11:22:33:44:55;
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   310
            }
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   311
        }
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   312
    """
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   313
668
794f943c835d pvl.dhcp.config: Block(comment=...)
Tero Marttila <terom@paivola.fi>
parents: 666
diff changeset
   314
    if block.comment:
794f943c835d pvl.dhcp.config: Block(comment=...)
Tero Marttila <terom@paivola.fi>
parents: 666
diff changeset
   315
        yield build_line((), end="# {comment}".format(comment=block.comment), indent=indent)
685
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   316
    
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   317
    if block.key:
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   318
        yield build_line(block.key, end=' {', indent=indent, context=block.key[0:1])
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   319
        indent += 1
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   320
    
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   321
    for item in block.items:
685
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   322
        yield build_item(item, indent=indent)
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   323
666
a8ddcbe894ff pvl.dhcp.config: refactor DHCPConfigParser to use shlex and yield Block objects, change build_block() to use Block; tests
Tero Marttila <terom@paivola.fi>
parents: 478
diff changeset
   324
    for subblock in block.blocks:
685
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   325
        if block.items:
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   326
            yield ''
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   327
685
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   328
        for line in build_block(subblock, indent=indent):
476
4b792c44cf05 pvl.dhcp.config: build configs
Tero Marttila <tero.marttila@aalto.fi>
parents: 256
diff changeset
   329
            yield line
685
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   330
    
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   331
    if block.key:
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   332
        indent -= 1
668f934bb958 pvl.dhcp.config: fix build_block() to handle top-level config Blocks
Tero Marttila <tero.marttila@aalto.fi>
parents: 682
diff changeset
   333
        yield build_line((), end='}', indent=indent)