[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