On Sun, 2010-03-14 at 10:48 +0100, Frederik Wagner wrote:
> On Fri, Feb 26, 2010 at 12:43 AM, David Lutterkort <[email protected]> wrote:
> > On Thu, 2010-02-25 at 19:19 +0100, Frederik Wagner wrote:
> >> Hi .*,
> >>
> >> I would like to append definitions for the console to _all_ kernel
> >> lines ins the grub configuration. Is there a way to do that without
> >> knowing howmany entries there are? E.g. using something like:
> >>
> >> augtool> set /files/boot/grub/menu.lst/title[*]/kernel/console[1] ttyS0
> >> or
> >> augtool> set /files/boot/grub/menu.lst/*/kernel/console[1] ttyS1
> >>
> >> I.e. so every title entry containing a kernel line would get
> >> "console=..." parameters appended.
> >> It is not working like I wrote, but there hopefully is away (btw. I'm
> >> using augeas normally through puppet!).
> 
> Hi David,
> 
> > There's actually no way to do that through the API in one call - you can
> > do it, e.g. in Ruby with something like
> >
> >        aug.match("/files/boot/grub/menu.lst/*/kernel/console").each do
> >        |p|
> >          aug.set(p, "ttyS1")
> >        end
> >
> > It would not be very hard to add a aug_set_all call to the API (it would
> > be a slight variation on aug_set in augeas.c) If you feel up to it, I'd
> > happily take a patch ;)
> 
> while playing around in the code, it os actually quite simple as long
> the node (in the example '../console') exists. When the node or the
> path to the node does not exists (there might be kernel settings which
> do not yet have a 'console' parameter), the match won't find them and
> the aug_set() will not create the node.

Aah, yes, you are right - I only thought about it in terms of already
existing nodes. In that case, it would be best to have the user tell you
which part of the path should already exist, and what part to set. In
Rubyesque pseudo code, something like

        def setm(base, child, value)
          aug.match(base).each do |p|
            aug.set(p + b, value)
          end
        end
        
Attached is a completely untested patch that should include the guts of
a 'set multiple' nodes API call. It does a slight variation on the
above: inside the match loop, it checks if there already are one or more
nodes matching p+b; if so, it sets each of them, if not it creates a new
one.

What's missing is exposing this call in augtool and the language
bindings - for puppet, that would mean to enhance ruby-augeas.

> The way to do this - as far as I understand - would be to somehow
> delete the last node in the path/pattern (the node which value hast to
> be set), match for the resulting patj and do a set on each match+node
> to set.  But for this I'm lost in the code, I don't want to introduce
> arbitrary string manipulation in augeas.c ;-)
> I'm anyway not sure, if the result would allow for all matching
> operation, e.g. matches on the last part of the path, like
> "/file/some/path/*[somematch]"

I agree with your analysis - and that it would be way too complicated to
get right in a language binding.

> Including this in ruby or the ruby API seems more simple, but since I
> would like to use it in puppet, I don't want to make a change in all
> the interfaces for a 'dirty hack'.

Let me know how much you can do with this patch. Would be great if you
could enhance it with a test or two, either by exposing it in augtool
and writing a shell script that tests it, or with a test written in C.
Once we have that, I'll commit all that.

David
>From a2bf6a84c2c52b64b9fad1c01e9f166f480a5944 Mon Sep 17 00:00:00 2001
From: David Lutterkort <[email protected]>
Date: Mon, 15 Mar 2010 17:07:06 -0700
Subject: [PATCH] Add aug_setm to API

  * src/augeas.h (aug_setm): new public API call
  * src/augeas.c (aug_setm): implement setting multiple nodes
  * src/augeas_sym.version: export symbol aug_setm
---
 src/augeas.c           |   49 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/augeas.h           |   12 +++++++++++
 src/augeas_sym.version |    5 ++++
 3 files changed, 66 insertions(+), 0 deletions(-)

diff --git a/src/augeas.c b/src/augeas.c
index c910017..91bebc6 100644
--- a/src/augeas.c
+++ b/src/augeas.c
@@ -600,6 +600,55 @@ int aug_set(struct augeas *aug, const char *path, const char *value) {
     return -1;
 }
 
+int aug_setm(struct augeas *aug, const char *base,
+             const char *sub, const char *value) {
+    struct pathx *bx = NULL, *sx = NULL;
+    struct error *err = err_of_aug(aug);
+    struct tree *bt, *st;
+    int result, r;
+
+    api_entry(aug);
+
+    bx = parse_user_pathx(aug, true, base);
+    ERR_BAIL(aug);
+
+    for (bt = pathx_first(bx); bt != NULL; bt = pathx_next(bx)) {
+        if (sub != NULL) {
+            /* Handle subnodes of BT */
+            pathx_parse(bt, err, sub, true, aug->symtab, &sx);
+            ERR_BAIL(aug);
+            if (pathx_first(sx) != NULL) {
+                /* Change existing subnodes matching SUB */
+                for (st = pathx_first(sx); st != NULL; st = pathx_next(sx)) {
+                    r = tree_set_value(st, value);
+                    ERR_NOMEM(r < 0, aug);
+                }
+            } else {
+                /* Create a new subnode matching SUB */
+                r = pathx_expand_tree(sx, &st);
+                if (r == -1)
+                    goto error;
+                r = tree_set_value(st, value);
+                ERR_NOMEM(r < 0, aug);
+            }
+            free_pathx(sx);
+            sx = NULL;
+        } else {
+            /* Set nodes matching BT directly */
+            r = tree_set_value(bt, value);
+            ERR_NOMEM(r < 0, aug);
+        }
+    }
+
+    result = 0;
+ done:
+    api_exit(aug);
+    return result;
+ error:
+    result = -1;
+    goto done;
+}
+
 int tree_insert(struct pathx *p, const char *label, int before) {
     struct tree *new = NULL, *match;
 
diff --git a/src/augeas.h b/src/augeas.h
index 514578b..c512742 100644
--- a/src/augeas.h
+++ b/src/augeas.h
@@ -137,6 +137,18 @@ int aug_get(const augeas *aug, const char *path, const char **value);
  */
 int aug_set(augeas *aug, const char *path, const char *value);
 
+/* Function: aug_setm
+ *
+ * Set the value of multiple nodes in one operation. Find or create a node
+ * matching SUB by interpreting SUB as a path expression relative to each
+ * node matching BASE. SUB may be NULL, in which case all the nodes
+ * matching BASE will be modified.
+ *
+ * Returns:
+ * number of modified nodes on success, -1 on error
+ */
+int aug_setm(augeas *aug, const char *base, const char *sub, const char *value);
+
 /* Function: aug_insert
  *
  * Create a new sibling LABEL for PATH by inserting into the tree just
diff --git a/src/augeas_sym.version b/src/augeas_sym.version
index 0014f68..542f5fa 100644
--- a/src/augeas_sym.version
+++ b/src/augeas_sym.version
@@ -29,3 +29,8 @@ AUGEAS_0.10.0 {
       aug_error_minor_message;
       aug_error_details;
 } AUGEAS_0.8.0;
+
+AUGEAS_0.11.0 {
+    global:
+      aug_setm;
+} AUGEAS_0.10.0;
-- 
1.6.6.1

_______________________________________________
augeas-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/augeas-devel

Reply via email to