[augeas-devel] Recursive lens and "malformed node" error in put direction

Raphaël Pinson raphink at gmail.com
Wed Feb 16 10:11:06 UTC 2011


> One last thing you can try is turn entry into a regular lens, and see if
> the typechecker is happy with it or not. To do that, just remove any
> mention of 'entry' in the definition of the entry lens, and optionally
> change 'let rec' to 'let'.
>


OK. I've deactivated the recursive lens, and indeed there where quite
a few things augparse was not happy about. So I fixed these, and
reactivated the recursive lens once augparse was happy with it (The
lens is even uglier than before now ;-)).

It still fails with "Malformed child node 'APT'", and the following rm test:

   (* Test rm on recursive value *)
   test AptConf.entry put "APT { Clean-Installed \"true\"; }\n"
      after rm "/APT/Clean-Installed" = "APT {}\n"

returns:

  Syntax error in lens definition
  Failed to load tests/test_aptconf.aug
  tests/test_aptconf.aug:106.3-107.50:exception thrown in test
  tests/test_aptconf.aug:106.8-107.37:exception: Failed to match
    <<rec:{ /[A-Za-z][:A-Za-z-]*/ = /(([.0-9A-Z_a-z-]+))/ }>>
  with tree
    { "APT" }
    Lens: ./aptconf.aug:89.12-.38:
    Error encountered at path



Following are the lens and test file used (to be used with HEAD):


============== Lens =================
(*
Module: AptConf
  Parses /etc/apt/apt.conf and /etc/apt/apt.conf.d/*

Author: Raphael Pinson <raphink at gmail.com>

About: Reference
  This lens tries to keep as close as possible to `man 5 apt.conf`
where possible.

About: License
   This file is licenced under the LGPLv2+, like the rest of Augeas.

About: Lens Usage
   To be documented

About: Configuration files
   This lens applies to /etc/apt/apt.conf and /etc/apt/apt.conf.d/*.
See <filter>.
*)


module AptConf =
  autoload xfm

(************************************************************************
 * Group:                 USEFUL PRIMITIVES
 *************************************************************************)

(* View: eol
    And <Util.eol> end of line *)
let eol = Util.eol

(* View: empty
    A C-style empty line *)
let empty = Util.empty_c_style

(* View: indent
    An indentation *)
let indent = Util.indent

(* View: comment_simple
    A one-line comment, C-style *)
let comment_simple = Util.comment_c_style

(* View: comment_multi
    A multiline comment, C-style *)
let comment_multi = Util.comment_multiline

(* View: comment
    A comment, either <comment_simple> or <comment_multi> *)
let comment = comment_simple | comment_multi


(************************************************************************
 * Group:                 ENTRIES
 *************************************************************************)

(* View: name_re
    Regex for entry names *)
let name_re = /[A-Za-z][A-Za-z:-]*/


(* View: entry
    An apt.conf entry, recursive *)
let rec entry_noeol =
  let value =
     Util.del_str "\"" . store Rx.word
                       . Util.del_str "\";" in
  let opt_eol = del /[ \t\n]*/ "\n" in
  let long_eol = del /[ \t]*\n+/ "\n" in
  let list_elem = [ opt_eol . label "@elem" . value ] in
  let eol_comment = long_eol . comment in
  [ key name_re .
      (
        (Sep.space . value) |
        (
           del /[ \t\n]*\{/ " {" .
             ( empty |
                (
                  (opt_eol . entry_noeol) |
                  list_elem |
                  eol_comment
                )+
             )
           . del /[ \t\n]*\};?/ "\n};"
        )
      )
    ]

let entry = indent . entry_noeol . eol


(* View: include
    A file inclusion
    /!\ The manpage is not clear on the syntax *)
let include =
  [ indent . key "#include" . Sep.space
           . store Rx.fspath . eol ]


(* View: clear
    A list of variables to clear
    /!\ The manpage is not clear on the syntax *)
let clear =
  let name = [ label "name" . store name_re ] in
  [ indent . key "#clear" . Sep.space
           . Build.opt_list name Sep.space
           . eol ]


(************************************************************************
 * Group:                 LENS AND FILTER
 *************************************************************************)

(* View: lns
     The apt.conf lens *)
let lns = (empty|comment|entry|include|clear)*


(* Variable: filter *)
let filter = incl "/etc/apt/apt.conf"
    . incl "/etc/apt/apt.conf.d/*"
    . Util.stdexcl

let xfm = transform lns filter
============== /Lens =================


============== Test =================
module Test_aptconf =

  (* Test multiline C-style comments *)
  let comment_multiline = "/* This is a long
/* multiline
comment
*/
"

   test AptConf.comment get comment_multiline =
      { "#mcomment"
         { "1" = "This is a long" }
         { "2" = "/* multiline" }
         { "3" = "comment" } }


   (* Test empty multiline C-style comments *)
   let comment_multiline_empty = "/* */\n"

   test AptConf.empty get comment_multiline_empty = { }


   (* Test a simple entry *)
   let simple_entry = "APT::Clean-Installed \"true\";\n"

   test AptConf.entry get simple_entry =
      { "APT::Clean-Installed" = "true" }

   (* Test simple recursivity *)
   let simple_recursion = "APT { Clean-Installed \"true\"; };\n"

   test AptConf.entry get simple_recursion =
      { "APT" { "Clean-Installed" = "true" } }

   (* Test simple recursivity with several entries *)
   let simple_recursion_multi =
     "APT {
          Clean-Installed \"true\";
          Get::Assume-Yes \"true\";
      }\n"

   test AptConf.entry get simple_recursion_multi =
      { "APT"
         { "Clean-Installed" = "true" }
         { "Get::Assume-Yes" = "true" } }

   (* Test multiple recursivity *)
   let multiple_recursion =
     "APT { Get { Assume-Yes \"true\"; } };\n"

   test AptConf.entry get multiple_recursion =
      { "APT" { "Get" { "Assume-Yes" = "true" } } }

   (* Test simple list *)
   let simple_list = "DPKG::options { \"--force-confold\"; }\n"

   test AptConf.entry get simple_list =
      { "DPKG::options" { "@elem" = "--force-confold" } }


   (* Test recursive list *)
   let recursive_list =
     "DPKG {
          options {
              \"--force-confold\";
              \"--nocheck\";
          } };\n"

   test AptConf.entry get recursive_list =
      { "DPKG"
         { "options"
            { "@elem" = "--force-confold" }
            { "@elem" = "--nocheck" } } }

   (* Test empty group *)
   let empty_group =
    "APT\n{\n};\n"

   test AptConf.entry get empty_group = { "APT" {} }

   (* Test #include *)
   let include = "  #include /path/to/file\n"

   test AptConf.include get include =
      { "#include" = "/path/to/file" }

   (* Test #clear *)
   let clear = "#clear Dpkg::options Apt::Get::Assume-Yes\n"

   test AptConf.clear get clear =
      { "#clear"
         { "name" = "Dpkg::options" }
         { "name" = "Apt::Get::Assume-Yes" } }


   (* Test put simple value *)
   test AptConf.entry put "APT::Clean-Installed \"true\";\n"
      after set "/APT::Clean-Installed" "false" =
      "APT::Clean-Installed \"false\";\n"

   (* Test rm everything *)
   test AptConf.entry put "APT { Clean-Installed \"true\"; }\n"
      after rm "/APT" = ""

   (* Test rm on recursive value *)
   test AptConf.entry put "APT { Clean-Installed \"true\"; }\n"
      after rm "/APT/Clean-Installed" = "APT {}\n"

   (* Test put recursive value *)
   test AptConf.entry put "APT { Clean-Installed \"true\"; }\n"
      after set "/APT/Clean-Installed" "false" =
      "APT { Clean-Installed \"false\"; }\n"

   (* Test multiple lens *)
   let multiple_entries =
      "APT { Clean-Installed \"true\"; }\n
       APT::Clean-Installed \"true\";"

   test AptConf.lns get multiple_entries =
      { "APT" { "Clean-Installed" = "true" } }
      {}
      { "APT::Clean-Installed" = "true" }

   (* Test with full lens *)
   test AptConf.lns put "APT { Clean-Installed \"true\"; }\n"
      after set "/APT/Clean-Installed" "false" =
      "APT { Clean-Installed \"false\"; }\n"

============== /Test =================




More information about the augeas-devel mailing list