summaryrefslogtreecommitdiff
path: root/docs/source/docs/architecture/trees.rst
blob: 9f3bd1f7265d0181561645d9f82f8257c69f6e82 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
Trees
*****

Reconfigure operates with three types of data:

* Raw config text
* Syntax tree
* Data tree

.. _raw-config:

Config text 
===========

This is a raw content, as read from the config file. It is fed to :ref:`Parsers <parser>` to produce the :ref:`Syntax trees<node-tree>`.

.. _node-tree:

Syntax trees
==========

Syntax tree is an object tree built from :class:`reconfigure.nodes.Node` objects, representing the syntax structure of the file. This is very similar to Abstract Syntax Trees.

Syntax trees are produced by :ref:`Parser` classes.

Example::

    >>> text = open('/etc/samba/smb.conf').read()
    >>> text
    '#\n# Sample configuration file for the Samba suite for Debian GNU/Linux.\
    ...
    >>> from reconfigure.parsers import IniFileParser
    >>> parser = IniFileParser()
    >>> node_tree = parser.parse(text)
    >>> print node_tree
    (None)
            (global)
                    workgroup = WORKGROUP
                    server string = %h server (Samba, Ubuntu)
                    dns proxy = no
                    log file = /var/log/samba/log.%m
                    max log size = 1000
                    syslog = 0
                    panic action = /usr/share/samba/panic-action %d
                    encrypt passwords = true
                    passdb backend = tdbsam
                    obey pam restrictions = yes
                    unix password sync = yes
                    passwd program = /usr/bin/passwd %u
                    passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
                    pam password change = yes
                    map to guest = bad user
                    usershare allow guests = yes
            (printers)
                    comment = All Printers
                    browseable = no
                    path = /var/spool/samba
                    printable = yes
                    guest ok = no
                    read only = yes
                    create mask = 0700
    >>> node_tree
    <reconfigure.nodes.RootNode object at 0x219a150>
    >>> node_tree.children[0]
    <reconfigure.nodes.Node object at 0x219a950>
    >>> node_tree.children[0].name
    'global'
    >>> node_tree.children[0].children[0]
    <reconfigure.nodes.PropertyNode object at 0x219aa10>
    >>> node_tree.children[0].children[0].name
    'workgroup'
    >>> node_tree.children[0].children[0].value
    'WORKGROUP'

:class:`reconfigure.nodes.Node`  reference page contains more information on how to manipulate node trees.

Parsers work both ways - you can call ``stringify()`` and get the text representation back. Even more, you can feed the node tree to *another* parser and get the config in other format::

    >>> from reconfigure.parsers import JsonParser
    >>> json_parser = JsonParser()
    >>> json_parser.stringify(node_tree)
    >>> print json_parser.stringify(node_tree)
    {
        "global": {
            "encrypt passwords": "true", 
            "pam password change": "yes", 
            "passdb backend": "tdbsam", 
            "passwd program": "/usr/bin/passwd %u", 
            ...
        }, 
        "print$": {
            "comment": "Printer Drivers", 
            "path": "/var/lib/samba/printers", 
            "read only": "yes", 
            ...

Syntax trees might look useful to you, but they are not nearly as cool as :ref:`Data trees <data-tree>`

.. _data-tree:

Data trees
==========

Data tree represents the actual, meaningful ideas stored in the config. Straight to example::

    >>> from reconfigure.builders import BoundBuilder
    >>> from reconfigure.items.samba import SambaData
    >>> builder = BoundBuilder(SambaData)
    >>> data_tree = builder.build(node_tree)
    >>> data_tree
    {
        "global": {
            "server_string": "%h server (Samba, Ubuntu)", 
            "workgroup": "WORKGROUP", 
            "interfaces": "", 
            "bind_interfaces_only": true, 
            "security": "user", 
            "log_file": "/var/log/samba/log.%m"
        }, 
        "shares": [
            {
                "comment": "All Printers", 
                "browseable": false, 
                "create_mask": "0700", 
                "name": "printers", 
                "directory_mask": "0755", 
                "read_only": true, 
                "guest_ok": false, 
                "path": "/var/spool/samba"
            }, 
            {
                "comment": "Printer Drivers", 
                "browseable": true, 
                "create_mask": "0744", 
                "name": "print$", 
                "directory_mask": "0755", 
                "read_only": true, 
                "guest_ok": false, 
                "path": "/var/lib/samba/printers"
            }
        ]
    }

    >>> data_tree.shares
    <reconfigure.items.bound.BoundCollection object at 0x23d0610>
    >>> [_.path for _ in data_tree.shares]
    ['/var/spool/samba', '/var/lib/samba/printers']

Data trees may consist of any Python objects, but the common approach is to use :ref:`Bound data`

Data trees can be manipulated as you wish::

    >>> from reconfigure.items.samba import ShareData
    >>> share = ShareData()
    >>> share.path = '/home/user'
    >>> share.comment = 'New share'
    >>> data_tree.shares.append(share)
    >>> data_tree
    {
        ....
        "shares": [
        {
            "comment": "All Printers", 
            "browseable": false, 
            "create_mask": "0700", 
            "name": "printers", 
            "directory_mask": "0755", 
            "read_only": true, 
            "guest_ok": false, 
            "path": "/var/spool/samba"
        }, 
        {
            "comment": "Printer Drivers", 
            "browseable": true, 
            "create_mask": "0744", 
            "name": "print$", 
            "directory_mask": "0755", 
            "read_only": true, 
            "guest_ok": false, 
            "path": "/var/lib/samba/printers"
        }, 
        {
            "comment": "New share", 
            "browseable": true, 
            "create_mask": "0744", 
            "name": "share", 
            "directory_mask": "0755", 
            "read_only": true, 
            "guest_ok": false, 
            "path": "/home/user"
        }
    ]

After you're done with the modifications, the data tree must be converted back to the node tree::

    >>> node_tree = builder.unbuild(data_tree)