[augeas-devel] [Interfaces] Draft lense

Raphaël Pinson raphink at gmail.com
Wed Aug 20 14:34:35 UTC 2008


On Wed, Aug 20, 2008 at 2:36 PM, Free Ekanayaka <free at 64studio.com> wrote:

>  RP> Nicolas Valcarcel (aka nxvl) was already working on this lens, so I'm
> sure
>  RP> he will be interested in it.
>
> Oh, I didn't now it. Is his work already committed somewhere? I would
> be glad to collaborate.



I think he has a bzr branch on Launchpad with his work. Haven't seen a
single line myself so far though.



>  >>(* Define a generic entry *)
>  >>>let entry (l:string) = [ spc . label l . value_to_spc ]
>  >>>
>  >>>(* Define a stanza type *)
>  >>>let type (t:string) = del t t . entry t
>  >>>
>  >>
>
>
>  RP> It seems to me that all this is equivalent to
>
>  RP> let entry (l:string) = [ key l . spc . value_to_spc ]
>
>
>  RP> Maybe you should use Util.indent instead of Util.del_opt_ws (aka spc
> for
>  RP> you) here, since Util.del_opt_ws will insert a space before new
> entries by
>  RP> default.
>
> If I simply replace Util.del_opt_ws with Util.indent, I get a series
> of errors like this one:
>
> lenses/interfaces.aug:26.3-.80:Failed to compile option
> lenses/interfaces.aug:26.18-.72:exception: ambiguous concatenation
>      'ifacA' can be split into
>      'ifa|=|cA'
>
>     and
>      'ifac|=|A'
>
>    First lens: lenses/interfaces.aug:26.18-.57
>    Second lens: lenses/interfaces.aug:9.22-.59
>
> Should I change something else too?
>


Sorry, my mistake. Util.del_ws_spc is for the spaces only, while you can put
Util.indent in the beginning of each entry. del_ws_spc deletes /[ \t]+/
while indent deletes /[ \t]*/.

In any case, you will probably end up using the \ trick instead for spc, and
indent in front of each entry.



> >>(* Define a iface stanza *)
>  >>>let option = [ spc . key /([a-z]|-)+/ . spc . value_to_eol . eol ]
>  >>>let iface = type "iface" . entry "family" . entry "method" . eol .
>  >>>option*
>  >>>
>  >>
>
>   RP> And there I see why you "have to" indent options. The best way around
> would
>  RP> probably be to specify the list of known options, or at least specify
> that
>  RP> options cannot be "iface", "family" or "method".
>
> I think the latter is better, because there are many options and even
> more can be added by packages like wireless-tools.
>

I agree with this. This is the way I took with php.aug aswell. One example
of the first case is dput.aug, since it has only few options.



>  >>(* Note that allow-auto and auto are synonims *)
>  >>>let allow_auto = type "allow-auto". (entry "allow-auto")* . eol
>  >>>
>  >>
>   RP> You could also have
>
>  RP> let type (r:regexp) (t:string) = del r t . entry
>
>  RP> And then
>
>  RP> let auto = type /(allow_)?auto/ "auto" (entry "auto")* . eol
>
>  RP> If these are stricly equivalent. This way, allow_auto and auto will be
>  RP> parsed equally, but the type will default to "auto".
>
> Yes, I had thought it too, but didn't find a way to do it. I tried
> your hint, but I'm getting an error like:
>
> lenses/interfaces.aug:21.46-.51:type error: expected string, regexp, lens,
> or filter but found string -> lens



I guess my definition of type is wrong. It should read

let type (r:regexp) (t:string) = del r t . entry t

since entry takes a string argument.



> RP> You don't have to number nodes like this. It actually makes it a bit
>  RP> confusing to parse
>
>  RP>         { "1"
>  RP>             { "auto" = "lo" }
>  RP>             { "auto" = "eth0" } }
>  RP>         { "2"
>  RP>             { "allow-hotplug" = "eth1" }}
>  RP>         {}
>  RP>         { "3"
>  RP>             { "iface" = "lo" }
>  RP>             { "family" = "inet"}
>  RP>             { "method" = "loopback"} }
>
>
>  RP> if more complicated than
>
>  RP>         { "auto" = "lo" }
>  RP>         { "auto" = "eth0" }
>  RP>         { "allow-hotplug" = "eth1" }
>  RP>         {}
>  RP>         {"iface"
>  RP>             { "name" = "lo" }
>  RP>             { "family" = "inet"}
>  RP>             { "method" = "loopback"} }
>
>
>  RP> which is much easier to parse with xpath. This means that iface could
> be
>  RP> rewritten as
>
>  RP> let iface = label "iface" . entry "name" . entry "family" . entry
> "method" .
>  RP> eol . option*
>
>  RP> and the same with other sections.
>
> Initially I planned to do it like you suggest (without seq), and it
> was easy to do for records like iface. However I'm having difficulties
> with the auto construct, which can accept more than one interface,
> like:
>
> auto lo eth0
>
> which I can't really turn to:
>
>  { "auto" = "lo" }
>  { "auto" = "eth0" } }
>
> I've tried with:
>
>   let entry (l:string) = [ spc . label l . value_to_spc ]
>    let auto  = del "auto" "auto" . (entry "auto")+ . eol
>
> but I get:
>
> lenses/interfaces.aug:31.13-.42:exception: ambiguous tree iteration
>      'auto/auto/' can be split into
>      'auto/|=|auto/'
>
>     and
>      'auto/auto/|=|'
>
> Note that using concatenation instead of repetition does work:
>
>   let auto  = del "auto" "auto" . entry "auto" . entry "auto" . eol
>
> but of course it hard-wires the number of parameters. I'm a bit
> confused here.
>


sshd.aug has a similar issue with "AcceptEnv" entries. David got around this
by using seq inside the entry instead of outside.

let array_entry (k:string) =
     let value = store /[^ \t\n]+/ in
     [ key k . [ sep . seq k . value]* . eol ]
let accept_env = array_entry "AcceptEnv"

which maps AcceptEnv like this

  let accept_env = "Protocol 2\nAcceptEnv LC_PAPER LC_NAME LC_ADDRESS
LC_TELEPHONE LC_MEASUREMENT \nAcceptEnv LC_IDENTIFICATION LC_ALL\n"

  test Sshd.lns get accept_env =
    { "Protocol" = "2" }
    { "AcceptEnv"
        { "1" = "LC_PAPER" }
        { "2" = "LC_NAME" }
        { "3" = "LC_ADDRESS" }
        { "4" = "LC_TELEPHONE" }
        { "5" = "LC_MEASUREMENT" } }
     { "AcceptEnv"
        { "6" = "LC_IDENTIFICATION" }
        { "7" = "LC_ALL" } }


This way, it doesn't affect the rest of the file, but still fixes the
mapping issue that you're facing.



> >>(* Define lens *)
>  >>>let lns = ( comment | stanza )*
>  >>
>  >>
>
>   RP> Have you tried putting comments in the middle of stanzas ?
>  RP> It seems to me that the option field could be a comment aswell.
>
> I did not try, it problably needs to be fixed.
>


I faced this issue in inifile.aug and bbhosts.aug (and more). You could get
around it with something like


let iface      = type "iface" . entry "family" . entry "method" . eol
                     . (option|comment|empty)*
let mapping = type "mapping" . eol
                     . (option|comment|empty)*

let stanza = iface
                | auto
                | allow_auto
                | allow_hotplug
                | mapping
let lns = (comment|empty)* . stanza*


Oh yes, forgot to tell you that you need Util.empty when yo use
Util.comment, since once comments are mapped, you still need to remove empty
lines.



Ciao


Raphaël
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/augeas-devel/attachments/20080820/258fc3f7/attachment.htm>


More information about the augeas-devel mailing list