[augeas-devel] Re: [Interfaces] Draft lense

Raphaël Pinson raphink at gmail.com
Fri Aug 22 06:55:29 UTC 2008


On Thu, Aug 21, 2008 at 11:42 PM, Free Ekanayaka <free at 64studio.com> wrote:

> Hi Raphaël,
>
> |--==> Raphaël Pinson writes:
>
>   RP> Let's see...
>
>  RP> The expected tree for 'auto\\\nA# A\n' is
>
>  RP> { "auto"
>  RP>    { "1" = "A"
>  RP>       { "comment" = "A" } } }
>
>  RP> and this is what the first lens does alright (btw David if you read
> this, I
>  RP> think it would be great if lens conflicts would print the tree
> generated by
>  RP> the lenses, it would greatly help to understand the issue).
>  RP> But it seems that a second lens does
>
>  RP> { "auto"
>  RP>    { "1" = "A# A" } }
>
>  RP> '#' is not a valid character in an iface name, but we have:
>
>  RP> let value_to_spc = store /[^\\ \t\n]+/
>  RP> let array (r:regexp) (t:string) = del r t . label t . counter t . [
> spc .
>  RP> seq t . value_to_spc ]+
>
>
>  RP> See the issue? Just turning your value_to_spc in to a [^\\# \t\n]
> should fix
>  RP> this.
>
> Thanks for explanation, very clear. Excluding "#" from the characters
> of the stored value fixed the issue, so that single-line entries work now
> perfectly.
>
> However if I try to support trailing comments with multi-line entries
> like:
>
> let mapping = [ type "mapping" . (comment|eol) . (option|comment|empty)* ]
>
> I'm getting another error:
>
> lenses/interfaces.aug:30.3-.71:Failed to compile mapping
> lenses/interfaces.aug:30.19-.69:exception: ambiguous tree concatenation
>      '#comment/' can be split into
>      '|=|#comment/'
>
>     and
>      '#comment/|=|'
>
>    First lens: lenses/interfaces.aug:30.19-.49
>    Second lens: lenses/interfaces.aug:30.52-.69
>
> and I can't figure out why.
>


Yes, lens debugging messages are quite hard to understand. I banged my head
with them too, and I think they are definitely something that could be
improved.

I'm going to try and explain what this means.


>
> Do the messages "ambiguous tree concatenation" and "ambiguous
> concatenation" actually differ?



In this case, the ambiguity is in the tree concatenation. The problem is not
met when parsing the input, but when generating the tree. "|=|" is the
position of the parser when the error is met.

The error says that the lens at interfaces.aug:30-3-.71 failed to compile
(i.e. line 30, position 3 to 71), which is the "mapping" lens. This lens is
defined as

let mapping = [ type "mapping" . (comment|eol) . (option|comment|empty)* ]

Now augeas says that in this lens, a tree with a '#comment/' node (the /
shows that we're talking about the tree, not about parsing) can be split
either before '#comment' ('|=|#comment/') or after ('#comment/|=|'). Let's
see... what is a '#comment/' node in the "mapping" lens?

{ "mapping"
   { "comment" = "whatever" } }

This is a comment in a mapping node. What would this look like in the
conffile?

mapping # whatever

or maybe

mapping
    # whatever


Both these possiblity will lead to the same tree, which means that the tree
is not enough to determine how to create the conffile. I honestly had not
thought of this conflict when I suggested there could be comments right
after "mapping" or "iface" headers. I'm guessing this is one of the reasons
why David first chose to ignore comments: since the "official" parser is
(likely to be) imperative, it removes comments, empty lines and backslashes
before even looking at what's in the file, while we have to consider all
these in the regexp we write.

I don't really see how to easily solve this problem, since both positions
for the comment are possible (right after "mapping", or on the next line).
Quite obviously, the problem only appears if the first line met after
"mapping" is a comment. So... we could try something like this (I have no
idea if this will work properly):

let mapping = [ type "mapping" .
                     ( (eol . empty*) | ((eol . empty*)? . comment) ) .
                     option .
                     (option|comment|empty)* ]

This assumes that there is at least one mandatory option (not sure this is
the case). My assumption here is that "mapping" is either followed by an eol
and any amount of empty lines followed by a first option, or by an optional
eol and any amount of empty lines followed by a comment. I suppose that this
would match both a trailing comment and a newline comment that would come
before the first option. There would be no ambiguity in this case, and the
default would be to place this first comment on the same line as "mapping".
Again, I have not tested and cannot garantee that it will work. Another
option would be to give up on comments and ignore them altogether for this
lens (but I really think comments in trees are a nice addition :) ).


Ciao


Raphaël



================ interfaces.aug ======================
>
> (* Intefraces module for Augeas               *)
> (* Author: Free Ekanayaka <free at 64studio.com> *)
>
> module Interfaces =
>   autoload xfm
>
>   (* Define useful primitives *)
> (*   let eol          = Util.eol*)
> let eol = del "\n" "\n"
>    let value_to_eol = store /([^\\# \t\n].*[^\\ \t\n]|[^\\ \t\n])/
>    let value_to_spc = store /[^\\# \t\n]+/
>    let spc = del /([ \t]+|[ \t]*\\\\\n[ \t]*)/ " "
>
>   (* Define comment *)
>   let comment = Util.comment
>   let empty   = Util.empty
>
>   (* Define a generic entry *)
>   let entry (l:string) = [ spc . label l . value_to_spc ]
>
>   (* Define stanzas *)
>    let array (r:regexp) (t:string) = del r t . label t . counter t . [ spc
> . seq t . value_to_spc ]+
>    let type (t:string) = del t t . label t . spc . value_to_spc
>
>   let words  = /(iface|auto|allow-[a-z-]+|mapping)/
>   let option = [  del /[ \t]*/ "   " . key  ( /[a-z-]+/ - words ) . spc .
> value_to_eol . eol ]
>
>    let auto = [ array /(allow-)?auto/ "auto" . (comment|eol) ]
>    let hotplug = [ type "allow-hotplug" . (comment|eol) ]
>    let iface   = [ type "iface" . entry "family" . entry "method" . eol .
> (option | comment | empty)* ]
>    let mapping = [ type "mapping" . (comment|eol) . (option|comment|empty)*
> ]
>
>    let s_entry = (auto | hotplug) . (comment|empty)*
>   let m_entry = iface | mapping
>
>   (* Define lens *)
>    let lns = (comment|empty)* . (m_entry | s_entry)*
>
>   let filter = incl "/etc/network/interfaces"
>              . Util.stdexcl
>
>   let xfm = transform lns filter
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/augeas-devel/attachments/20080822/cf228a0e/attachment.htm>


More information about the augeas-devel mailing list