You could also make a larger use of common modules (Util, Rx, Sep, Build) to simply the lens. Here is my take for the lens:<br><br><br>module Gmetad =<br>   <br>autoload xfm<br><br>let quoted =<br>     let quote = Util.del_str "\""<br>
  in quote . store Rx.word. quote<br>   <br>let data_source =<br>     let host = [ label "host" . store Rx.word ]<br>  in Build.key_value_line "data_source" Sep.space<br>      (quoted . Sep.space<br>      . Build.opt_list host Sep.space)<br>
                 <br>     <br>let gridname = Build.key_value_line "gridname" Sep.space quoted <br><br>let lns  = (gridname | data_source | Util.empty)*<br><br>let filter = incl "/etc/gmetad.conf"<br>let xfm = transform lns filter<br>
<br><br><br><br>and for the test file:<br><br>module Test_gmetad =<br>   let conf = "gridname \"grid\"<br>data_source \"group_name\" ds1 ds2 <a href="http://ds3.example.com">ds3.example.com</a><br>
data_source \"group_other\" www1 www2 <a href="http://www3.example.com">www3.example.com</a><br>"<br>   test Gmetad.lns get  conf =<br>   { "gridname" = "grid" }<br>   { "data_source" = "group_name"<br>
     { "host" = "ds1" }<br>     { "host" = "ds2" }<br>     { "host" = "<a href="http://ds3.example.com">ds3.example.com</a>" } }<br>   { "data_source" = "group_other"<br>
     { "host" = "www1" }<br>     { "host" = "www2" }<br>     { "host" = "<a href="http://www3.example.com">www3.example.com</a>" } }<br><br><br><br>Raphaël<br><br>
<br><br><div class="gmail_quote">On Thu, May 31, 2012 at 4:57 PM, Raphaël Pinson <span dir="ltr"><<a href="mailto:raphael.pinson@camptocamp.com" target="_blank">raphael.pinson@camptocamp.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br><div class="gmail_quote"><div><div class="h5">On Thu, May 31, 2012 at 4:38 PM, Nathaniel Cook <span dir="ltr"><<a href="mailto:nvcook42@gmail.com" target="_blank">nvcook42@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

I have been working on writing a simplified lens for the ganglia<br>
gmetad.conf file. I have the lens working as I like but when I try to<br>
use augeas to add entries to the file I get errors on save if the file<br>
doesn't exist or is empty. It says it cannot parse the entire input:<br>
<br>
/augeas/files/etc/gmetad.conf/error = "parse_failed"<br>
/augeas/files/etc/gmetad.conf/error/pos = "0"<br>
/augeas/files/etc/gmetad.conf/error/line = "1"<br>
/augeas/files/etc/gmetad.conf/error/char = "0"<br>
/augeas/files/etc/gmetad.conf/error/lens =<br>
"/usr/share/augeas/lenses/gmetad.aug:22.12-.56:"<br>
/augeas/files/etc/gmetad.conf/error/message = "Get did not match entire input"<br>
<br>
<br>
Here is the lens:<br>
<br>
<br>
module Gmetad =<br>
    autoload xfm<br>
<br>
    let quote = Util.del_str "\""<br>
    let space = del /[ \t]+/ " "<br>
    let eol = Util.del_str "\n"<br>
    let empty =  del /[ \t]*/ "" . eol<br>
<br>
    let host = store /[a-zA-Z0-9._]+/<br>
    let hosts = ( space . [ seq "hosts" . host ] )+<br>
    let group = [ label "group" . quote . store /[a-zA-Z0-9._ ]+/ . quote ]<br>
    let data_source = [ counter "hosts" .  label "data_source" .<br>
Util.del_str "data_source" . space . group . [ label "hosts" . hosts ]<br>
]<br>
<br>
    let gridname = [ label "gridname" . Util.del_str "gridname" .<br>
space . quote . store /[a-zA-Z0-9._]+/ . quote ]<br>
<br>
    let lns  = (gridname . empty)* . (data_source . empty)*<br>
<br>
    let filter = incl "/etc/gmetad.conf"<br>
    let xfm = transform lns filter<br>
<br>
<br>
Here is the test module:<br>
<br>
module Test_gmetad =<br>
    let conf = "gridname \"grid\"<br>
data_source \"group_name\" ds1 ds2 <a href="http://ds3.example.com" target="_blank">ds3.example.com</a><br>
data_source \"group_other\" www1 www2 <a href="http://www3.example.com" target="_blank">www3.example.com</a><br>
"<br>
    test Gmetad.lns get  conf =<br>
    { "gridname" = "grid" }<br>
    { "data_source"<br>
            { "group" = "group_name" }<br>
            { "hosts"<br>
                { "1" = "ds1" }<br>
                { "2" = "ds2" }<br>
                { "3" = "<a href="http://ds3.example.com" target="_blank">ds3.example.com</a>" }<br>
            }<br>
    }<br>
    { "data_source"<br>
        { "group" = "group_other" }<br>
        { "hosts"<br>
            { "1" = "www1" }<br>
            { "2" = "www2" }<br>
            { "3" = "<a href="http://www3.example.com" target="_blank">www3.example.com</a>" }<br>
        }<br>
    }<br>
<br>
    let empty = ""<br>
<br>
    test Gmetad.lns get empty = ?<br>
<br></blockquote></div></div><div><br><br>An empty (or non existent) file is not an empty string, but a single carriage return. The test should thus be:<br><br>test Gmetad.lns get "\n" = ?<br><br>which fails since the lens cannot parse a single carriage return. This is the reason why it fails in augtool.<br>

<br><br>Doesn't this format not support empty lines? If it does, I'd advise to use Util.eol in gridname and data_source, and write lns as:<br><br>let lns = (gridname | data_source | Util.empty)*<br><br>or does the order strictly matter?<span class="HOEnZb"><font color="#888888"><br>

<br><br>Raphaël<br></font></span></div></div><br>
</blockquote></div><br>