[augeas-devel] [Interfaces] Draft lense

Free Ekanayaka free at 64studio.com
Wed Aug 20 17:03:13 UTC 2008


Hi Raphaël,

|--==> Raphaël Pinson writes:

[...]

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

I see.

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

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


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

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

  RP> which maps AcceptEnv like this

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

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


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

Yeah, I thought something like that too, but if you have a
configuration like:

auto lo eth0
auto eth1

it would generate a tree like:

{ "auto"
    { "1" = "lo" }
    { "2" = "eth0" } }
{ "auto"
    { "1" = "eth1" } }
    
which is closer to the actual configuration file, but probably less
parsable than:

{ "auto" = "lo" }
{ "auto" = "eth0" }
{ "auto" = "eth1" }

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

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

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

Smart idea, even the placement of the comments in the tree can result
a little bit odd sometimes. I've modified the lens accordingly and it
works (below you find the new version of the files). The only problem
is that I came across a weird bug which I believe is related with
Util.comment.

Basically I have to define my option lens like this:

let option = [  del /[ \t]*/ "   " . key  ( /[abcdefghijklmopqrstuvwxyz-]+/ - words ) . spc . value_to_eol . eol ]

instead of:

let option = [  del /[ \t]*/ "   " . key  ( /[a-z-]+/ - words ) . spc . value_to_eol . eol ]

Note that the former declaration is exactly the same as the latter,
but it excludes the letter "n", which of course makes the lens fail
with all options starting with a word containing "n". However the lens
works beautifully in all other cases.

If I don't exclude the "n" character and declare the option lens with
the regular [a-z-], I get this error:

lenses/interfaces.aug:27.3-.111:Failed to compile iface
lenses/interfaces.aug:27.82-.99:exception: overlapping lenses in tree union.put
    Example matched by both: 'comment/'
    First lens: lenses/interfaces.aug:24.16-.95
    Second lens: lenses/util.aug:21.4-22.55

lenses/interfaces.aug:28.3-.77:Failed to compile mapping
lenses/interfaces.aug:28.52-.67:exception: overlapping lenses in tree union.put
    Example matched by both: 'comment/'
    First lens: lenses/interfaces.aug:24.16-.95
    Second lens: lenses/util.aug:21.4-22.55

As far as I can tell this happens only with "n", Weird enough, isn't
it? :) It makes me think to something related with \n

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

Yes, I had figured out it :)

Ciao!

Free

============= 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 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 type (r:regexp) (t:string) = del r t . label t . spc . value_to_spc

   let words  = /(iface|auto|allow-[a-z-]+|mapping)/
   let option = [  del /[ \t]*/ "   " . key  ( /[abcdefghijklmopqrstuvwxyz-]+/ - words ) . spc . value_to_eol . eol ]

   let auto    = [ type /(allow-)?auto/ "auto" . eol . (comment|empty)* ]
   let iface   = [ type /iface/ "iface" . entry "family" . entry "method" . eol . (option | comment | empty)* ]
   let mapping = [ type /mapping/ "mapping" . eol . (option|comment|empty)* ]
   let hotplug = [ type /allow-hotplug/ "allow-hotplug" . eol . (comment|empty)* ]

   (* Define stanza *)
   let stanza = (iface | auto | mapping | hotplug)

   (* Define lens *)
   let lns = ( comment | empty )* . stanza*

   let filter = incl "/etc/network/interfaces"
              . Util.stdexcl

   let xfm = transform lns filter

============= test_interfaces.aug ==================

module Test_interfaces = 

    let conf ="# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
# The loopback network interface

auto lo
allow-hotplug eth1

iface lo inet loopback

mapping eth0
	script /usr/local/sbin/map-scheme
map HOME eth0-home
     map WORK eth0-work

iface eth0-home inet static
address 192.168.1.1
#     netmask 255.255.255.0
        up flush-mail

iface eth0-work inet dhcp

allow-auto eth1
iface eth1 inet dhcp
"

    test Interfaces.lns get conf =
        { "comment" = "This file describes the network interfaces available on your system"}
        { "comment" = "and how to activate them. For more information, see interfaces(5)." }
        { "comment" = "The loopback network interface" }
        {}
        { "auto" = "lo" }
        { "allow-hotplug" = "eth1" 
            {} }
        { "iface" = "lo"
            { "family" = "inet"}
            { "method" = "loopback"} {} }
        { "mapping" = "eth0"
            { "script" = "/usr/local/sbin/map-scheme"}
            { "map" = "HOME eth0-home"}
            { "map" = "WORK eth0-work"} 
            {} }
        { "iface" = "eth0-home"
            { "family" = "inet"}
            { "method" = "static"}
            { "address" = "192.168.1.1" }
            { "comment" = "netmask 255.255.255.0" }
            { "up" = "flush-mail" }
            {} }
        { "iface" = "eth0-work"
            { "family" = "inet"}
            { "method" = "dhcp"}
            {} }
        { "auto" = "eth1" }
        { "iface" = "eth1"
            { "family" = "inet"}
            { "method" = "dhcp"} }




More information about the augeas-devel mailing list