[augeas-devel] [PATCH] Sysconfig: new lens for a subdialect of shell

lutter at redhat.com lutter at redhat.com
Mon Jul 19 22:13:56 UTC 2010


From: David Lutterkort <lutter at redhat.com>

Using shell files with simple variable assignments is a very popular config
file format. The Shellvars lens doesn't serve those files perfectly well,
since it tries to preserve details important for general shell scripts that
are ignored by sysconfig files.

This lens is a variation on Shellvars that changes a few important aspects
of it:

  * Strip quotes from values when reading a file, and restore quotes as
    needed upon writing
  * Pretend there's no difference between single and double quotes (this
    assumption makes it possible to add quotes as needed solely based on
    syntax)
  * Do not support shell arrays or backticks; support for these could be
    restored by somebody sufficiently motivated, though neither of them
    should be used in a sysconfig file

The lens doesn't autoload any files yet, though we should consider moving
most of the files that Shellvars loads over to this lens.
---
 lenses/sysconfig.aug            |   60 +++++++++++++++++++++
 lenses/tests/test_sysconfig.aug |  110 +++++++++++++++++++++++++++++++++++++++
 tests/Makefile.am               |    1 +
 3 files changed, 171 insertions(+), 0 deletions(-)
 create mode 100644 lenses/sysconfig.aug
 create mode 100644 lenses/tests/test_sysconfig.aug

diff --git a/lenses/sysconfig.aug b/lenses/sysconfig.aug
new file mode 100644
index 0000000..9ee668e
--- /dev/null
+++ b/lenses/sysconfig.aug
@@ -0,0 +1,60 @@
+(* Variation of the Shellvars lens                                     *)
+(* Supports only what's needed to handle sysconfig files               *)
+(* Modified to strip quotes. In the put direction, add double quotes   *)
+(* around values that need them                                        *)
+(* To keep things simple, we also do not support shell variable arrays *)
+module Sysconfig =
+  let eol = Util.eol
+
+  let key_re = /[A-Za-z0-9_]+(\[[0-9]+\])?/ - "unset" - "export"
+  let eq = Util.del_str "="
+  let comment = Util.comment
+  let empty   = Util.empty
+  let xchgs   = Build.xchgs
+  let dels    = Util.del_str
+
+  let nothing = del /(""|'')?/ "" . value ""
+
+  (* Chars allowed in a bare string *)
+  let bchar = /[^ \t\n\"'\\]|\\\\./
+  let qchar = /["']/  (* " *)
+
+  (* We split the handling of right hand sides into a few cases:
+   *   bare  - strings that contain no spaces, optionally enclosed in
+   *           single or double quotes
+   *   dquot - strings that contain at least one space or apostrophe,
+   *           which must be enclosed in double quotes
+   *   squot - strings that contain an unescaped double quote
+   *)
+  let bare = del qchar? "" . store (bchar+) . del qchar? ""
+  let dquot =
+    del qchar "\"" . store (bchar* . /[ \t']/ . bchar*)+ . del qchar "\""
+  let squot =
+    dels "'" . store ((bchar|/[ \t]/)* . "\"" . (bchar|/[ \t]/)*)+ . dels "'"
+
+  let export = [ key "export" . Util.del_ws_spc ]
+  let kv (value:lens) = [ export? . key key_re . eq . value . eol ]
+  let assign = kv nothing | kv bare | kv dquot | kv squot
+
+  let var_action (name:string) =
+    [ xchgs name ("@" . name) . Util.del_ws_spc . store key_re . eol ]
+
+  let unset = var_action "unset"
+  let bare_export = var_action "export"
+
+  let source =
+    [
+      del /\.|source/ "." . label ".source" .
+      Util.del_ws_spc . store /[^= \t\n]+/ . eol
+    ]
+
+  let lns = (comment | empty | source | assign | unset | bare_export) *
+
+(*
+  Examples:
+
+  abc   -> abc -> abc
+  "abc" -> abc -> abc
+  "a b" -> a b -> "a b"
+  'a"b' -> a"b -> 'a"b'
+*)
diff --git a/lenses/tests/test_sysconfig.aug b/lenses/tests/test_sysconfig.aug
new file mode 100644
index 0000000..ef8abd4
--- /dev/null
+++ b/lenses/tests/test_sysconfig.aug
@@ -0,0 +1,110 @@
+(* Test for sysconfig lens *)
+module Test_sysconfig =
+
+  let eth_static = "# Intel Corporation PRO/100 VE Network Connection
+DEVICE=eth0
+BOOTPROTO=static
+BROADCAST=172.31.0.255
+HWADDR=ab:cd:ef:12:34:56
+export IPADDR=172.31.0.31
+#DHCP_HOSTNAME=host.example.com
+NETMASK=255.255.255.0
+NETWORK=172.31.0.0
+unset ONBOOT
+"
+  let empty_val = "EMPTY=\nDEVICE=eth0\n"
+
+  let key_brack = "SOME_KEY[1]=\nDEVICE=eth0\n"
+
+  test Sysconfig.lns get eth_static =
+    { "#comment" = "Intel Corporation PRO/100 VE Network Connection" }
+    { "DEVICE" = "eth0" }
+    { "BOOTPROTO" = "static" }
+    { "BROADCAST" = "172.31.0.255" }
+    { "HWADDR" = "ab:cd:ef:12:34:56" }
+    { "IPADDR" = "172.31.0.31"
+        { "export" } }
+    { "#comment" = "DHCP_HOSTNAME=host.example.com" }
+    { "NETMASK" = "255.255.255.0" }
+    { "NETWORK" = "172.31.0.0" }
+    { "@unset"   = "ONBOOT" }
+
+  test Sysconfig.lns put eth_static after
+      set "BOOTPROTO" "dhcp" ;
+      rm "IPADDR" ;
+      rm "BROADCAST" ;
+      rm "NETMASK" ;
+      rm "NETWORK"
+  = "# Intel Corporation PRO/100 VE Network Connection
+DEVICE=eth0
+BOOTPROTO=dhcp
+HWADDR=ab:cd:ef:12:34:56
+#DHCP_HOSTNAME=host.example.com
+unset ONBOOT
+"
+  test Sysconfig.lns get empty_val =
+    { "EMPTY" = "" } { "DEVICE" = "eth0" }
+
+  test Sysconfig.lns get key_brack =
+    { "SOME_KEY[1]" = "" } { "DEVICE" = "eth0" }
+
+  test Sysconfig.lns get "smartd_opts=\"-q never\"\n" =
+    { "smartd_opts" = "-q never" }
+
+  test Sysconfig.lns get "var=val  \n" = { "var" = "val" }
+
+  test Sysconfig.lns get ". /etc/java/java.conf\n" =
+    { ".source" = "/etc/java/java.conf" }
+
+  (* Quoted strings and other oddities *)
+  test Sysconfig.lns get "var=\"foo 'bar'\"\n" =
+    { "var" = "foo 'bar'" }
+
+  test Sysconfig.lns get "var=\"eth0\"\n" =
+    { "var" = "eth0" }
+
+  test Sysconfig.lns get "var='eth0'\n" =
+    { "var" = "eth0" }
+
+  test Sysconfig.lns get "var='Some \"funny\" value'\n" =
+    { "var" = "Some \"funny\" value" }
+
+  test Sysconfig.lns get "var=\"\\\"\"\n" =
+    { "var" = "\\\"" }
+
+  test Sysconfig.lns get "var=\\\"\n" =
+    { "var" = "\\\"" }
+
+  test Sysconfig.lns get "var=ab#c\n" =
+    { "var" = "ab#c" }
+
+  (* We don't handle backticks *)
+  test Sysconfig.lns get
+      "var=`grep nameserver /etc/resolv.conf | head -1`\n" = *
+
+  (* We don't handle comments at the end of a line yet *)
+  test Sysconfig.lns get "var=ab #c\n" = *
+
+  (* Bug 109: allow a bare export *)
+  test Sysconfig.lns get "export FOO\n" =
+  { "@export" = "FOO" }
+
+  (* Check we put quotes in when changes require them *)
+  test Sysconfig.lns put "var=\"v\"\n" after rm "/foo" =
+    "var=\"v\"\n"
+
+  test Sysconfig.lns put "var=v\n" after set "/var" "v w"=
+    "var=\"v w\"\n"
+
+  test Sysconfig.lns put "var='v'\n" after set "/var" "v w"=
+    "var='v w'\n"
+
+  test Sysconfig.lns put "var=v\n" after set "/var" "v'w"=
+    "var=\"v'w\"\n"
+
+  test Sysconfig.lns put "var=v\n" after set "/var" "v\"w"=
+    "var='v\"w'\n"
+
+(* Local Variables: *)
+(* mode: caml       *)
+(* End:             *)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3570c53..4bb1d15 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -73,6 +73,7 @@ lens_tests =			\
   lens-spacevars.sh		\
   lens-squid.sh			\
   lens-sshd.sh			\
+  lens-sysconfig.sh		\
   lens-sysctl.sh		\
   lens-vsftpd.sh		\
   lens-webmin.sh		\
-- 
1.7.1.1




More information about the augeas-devel mailing list