On Tue, 2008-07-22 at 00:23 +0200, Kjetil Torgrim Homme wrote:
> I thought I'd try to enhance hosts.aug to recognise all syntactically
> correct /etc/hosts as an introduction to Augeas lenses.  This turned
> out to be harder than I thought it would be, even with the help of
> Raphaƫl Pinson and David Lutterkort on IRC :-)

If it's any consolation, handling of whitespace and comments is the most
difficult part of dealing with Augeas - there's a lot of subtelty, much
more than in the bits that directly map some part of inpuit into the
tree.

> The problem with the version in 0.2.2 (and Hg) is that it neither
> accepts leading white space nor comments after records, ie. this is
> valid, but Augeas fails silently if fed the file:
> 
> # This is a comment
>   127.0.0.1  localhost loghost # another comment
> 192.168.0.1  my-gw.local  
> ...
> First I tried to allow trailing comments by changing:
> 
>   let record = [ seq "host" . [ label "ipaddr" . store  word ] . sep_tab .
>                               [ label "canonical" . store word ] .
>                               [ label "alias" . sep_spc . store word ]*
>                  . comment ]
> 
> comment is a true superset of eol, after all.  This sort of works,
> since it allows "127.0.0.1 localhost# a comment", but will fail if you
> put whitespace in front of the comment.  So let's try:
> 
>   let record = [ seq "host" . [ label "ipaddr" . store  word ] . sep_tab .
>                               [ label "canonical" . store word ] .
>                               [ label "alias" . sep_spc . store word ]*
>                  . sep_spc? . comment ]
> 
> No -- it doesn't work, since the whitespace could be part of sep_spc
> or of comment, and ambiguity isn't allowed.  Let's revert the
> definition of record back to the original and change comment instead:
> 
>   let comment = [ del /[ \t]*(#.*)?\n/ "\n" ]
> 
> It can parse the file!  Nice.  OK, next task, allow leading whitespace:
> 
>   let record = [ sep_spc?
>                  . seq "host" . [ label "ipaddr" . store  word ] . sep_tab .
>                                 [ label "canonical" . store word ] .
>                                 [ label "alias" . sep_spc . store word ]*
>                  . comment ]

There's two subtle problems with the above:
      * Because 'comment' produces a tree node, whenever you create a
        new entry in the tree, you also have to have a node for the
        comment in the tree, no matter what. (This is the source of the
        'short split in concat' error you got)
      * sep_spc defaults to a single space " ", so that when you write
        the tree back to file, you often wind up with a leading space
        where there was none before

Attached is a patch (against hg HEAD) that does what you want.

Also, for trying out changes to lenses, I highly recommend using
augparse, and adding/expanding unit tests. For example, for your hosts
change, you could have run

        augparse -I lenses/ lenses/tests/test_hosts.aug
        
(assuming your changed Hosts module is in lenses/hosts.aug)

David

diff --git a/lenses/hosts.aug b/lenses/hosts.aug
--- a/lenses/hosts.aug
+++ b/lenses/hosts.aug
@@ -5,15 +5,17 @@
 
   let sep_tab = Util.del_ws_tab
   let sep_spc = Util.del_ws_spc
+  let opt_sep_spc = del /[ \t]*/ ""
 
   let eol = Util.del_str "\n"
 
-  let comment = [ del /(#.*|[ \t]*)\n/ "\n" ]
+  let del_comment = del /[ \t]*(#.*)?\n/ "\n"
+  let comment = [ del_comment ]
   let word = /[^# \n\t]+/
-  let record = [ seq "host" . [ label "ipaddr" . store  word ] . sep_tab .
+  let record = [ opt_sep_spc . seq "host" . [ label "ipaddr" . store  word ] . sep_tab .
                               [ label "canonical" . store word ] .
                               [ label "alias" . sep_spc . store word ]*
-                 . eol ]
+                 . del_comment ]
 
   let lns = ( comment | record ) *
 
diff --git a/lenses/tests/test_hosts.aug b/lenses/tests/test_hosts.aug
--- a/lenses/tests/test_hosts.aug
+++ b/lenses/tests/test_hosts.aug
@@ -51,6 +51,13 @@
           { "canonical" = "etch.example.com" } 
           { "alias" = "etch" } }
 
+  test Hosts.lns get "# Some comment
+  \t 127.0.0.1  localhost # my own machine\n \t \n" = 
+    {}
+    { "1" 
+      { "ipaddr" = "127.0.0.1" }
+      { "canonical" = "localhost" } }
+    {}
 
 (* Local Variables: *)
 (* mode: caml *)
_______________________________________________
augeas-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/augeas-devel

Reply via email to