3
Rg                 @   s   d Z ddlmZ ddlmZ ddlZddlZdd Zdd Zed	d
ddgZ	dd Z
dd ZdddZdd Zedkr|e  dS )a  
Utility to check ISC config grammar consistency. It detects statement names
which use different grammar depending on position in the configuration file.
E.g. "max-zone-ttl" in dnssec-policy uses '<duration>'
vs. '( unlimited | <duration> ) used in options.
    )
namedtuple)groupbyNc             C   s   i }x~| D ]v}|j d st|j|g jt| d| | kr
t| | d ||g }x&|j D ]\}}|j|g j| qbW q
W |S )av  Return mapping statement name to "path" where it is allowed.
    _top is placeholder name for the namesless topmost context.

    E.g. {
        'options: [('_top',)],
        'server': [('_top', 'view'), ('_top',)],
        'rate-limit': [('_top', 'options'), ('_top', 'view')],
        'slip': [('_top', 'options', 'rate-limit'), ('_top', 'view', 'rate-limit')]
    }
    __mapbody)
startswithAssertionError
setdefaultappendtuplestatement2blockitemsextend)grammarpathZ	key2placekeyZnested2blockZ
nested_keyZnested_path r   A/home/abuild/rpmbuild/BUILD/bind-9.18.33/doc/misc/checkgrammar.pyr      s    
r   c             C   sP   |d dkst t||g }x,|dd D ]}d| kr@| d } | | } q,W | S )zDescend into grammar dict using provided path
    and return final dict found there.

    Intermediate steps into "_mapbody" subkeys are done automatically.
    r   _top   Nr   )r   list)r   r   namestepr   r   r   get_statement_grammar4   s    r   	Statementr   r   
subgrammarc             C   sB   dd }g }t | |d} x$t| |D ]\}}|jt| q$W |S )zi
    Return groups of Statement tuples with identical grammars and flags.
    See itertools.groupby.
    c             S   s   t | jj S )N)sortedr   r   )	statementr   r   r   keyfuncL   s    z groupby_grammar.<locals>.keyfunc)r   )r   r   r	   r   )
statementsr   groups_keygroupr   r   r   groupby_grammarF   s    r"   c       	      C   s^   i }xT|j  D ]H\}}g }x*|D ]"}t| ||}|jt||| q W t|}|||< qW |S )zV
    Return map {statement name: [groups of [Statement]s with identical grammar].
    )r   r   r	   r   r"   )	Zwhole_grammarplacesoutZstatement_namepathsgrammarsr   Zstatement_grammarr   r   r   r   diff_statementsV   s    

r'   r   c             C   sh  dd }d| krZd| kst d| ks(t | d d }d| krR|dd	j| d  7 }|d
 S d}|d }| jdsd| kr|| d d 7 }|d7 }xt| d j |dD ]v\}}|jds|| |jd| 7 }t| d | |d d}nt| d | |d}|d dkr|d7 }||7 }qW | jds`||dd d 7 }d| kr`|dd	j| d  7 }|d
 S )zCPretty print a given grammar node in the same way as cfg_test wouldc             S   s   | \}}|dkrdS |S )z>Treat 'type' specially and always put it first, for zone typestype r   )itemr   r   r   r   r   sortkeyj   s    z pformat_grammar.<locals>.sortkeyZ_grammar_idr   ;_flagsz // z, 
r)   	Z_ignore_this_level z{
)r   _pprint_namer   )levelr   Nz};)r   joingetr   r   pformat_grammar)noder3   r+   r$   indentr   subnodeZinner_grammarr   r   r   r7   g   s6    


r7   c              C   s   t j } tj| }W dQ R X t|dg}x|t||j D ]j\}}t|dkr:td| d x>|D ]6}tddj	dd	 |D  td
t
|d jdd qdW t  q:W dS )z
    Ingest output from cfg_test --grammar and print out statements which use
    different grammar in different contexts.
    Nr   r   zstatement "z" is inconsistent across blocksz- path:z, c             s   s   | ]}d j |jV  qdS )z -> N)r5   r   ).0variantr   r   r   	<genexpr>   s    zmain.<locals>.<genexpr>r1   r   )r3   )	fileinputinputparsegrammarZparse_mapbodyr   r'   r   lenprintr5   r7   r   )Zfileinr   r#   Zstatementnamer   r!   r   r   r   main   s    

rC   __main__)r   )__doc__collectionsr   	itertoolsr   r>   r@   r   r   r   r"   r'   r7   rC   __name__r   r   r   r   <module>   s   
+