This is a rework of the previous patch which adds:

 - an aug_transform API call
 - a transform command for aug_srun
 - a -t|--transform option to augtool

This is the second version, with the following changes:

 - rebased on master;
 - augeas.c, augtool.c: do not use malloc(), use xasprintf() and catch errors;
 - augtool.c: move all transforms to add_transforms();
 - change syntax of --transform|-t to make aug_srun syntax.

---
 src/augeas.c           |   62 +++++++++++++++++++++++++++++
 src/augeas.h           |   14 +++++++
 src/augeas_sym.version |    1 +
 src/augrun.c           |   46 +++++++++++++++++++++
 src/augtool.c          |  104 +++++++++++++++++++++++++++++++++---------------
 tests/run.tests        |   23 +++++++++++
 tests/test-api.c       |   46 +++++++++++++++++++++
 7 files changed, 263 insertions(+), 33 deletions(-)

diff --git a/src/augeas.c b/src/augeas.c
index a2ffa03..8ad1a91 100644
--- a/src/augeas.c
+++ b/src/augeas.c
@@ -1761,6 +1761,68 @@ int aug_to_xml(const struct augeas *aug, const char 
*pathin,
     return -1;
 }
 
+int aug_transform(struct augeas *aug, const char *lens, const char *file, int 
excl) {
+    int r = 0;
+    char *filter;
+    char *lenspath;
+    char *inclpath;
+    char *lenslenspath;
+    char *lensname = NULL;
+
+    api_entry(aug);
+
+    ARG_CHECK(STREQ("", lens), aug, "aug_transform: LENS must not be empty");
+    ARG_CHECK(STREQ("", file), aug, "aug_transform: FILE must not be empty");
+
+    r = ALLOC_N(filter, 5);
+    ERR_THROW(r < 0, aug, AUG_ENOMEM, NULL);
+    if (excl)
+        strcpy(filter, "excl");
+    else
+        strcpy(filter, "incl");
+
+    r = xasprintf(&lenspath, "/augeas/load/%s", lens);
+    ERR_THROW(r < 0, aug, AUG_ENOMEM, NULL);
+
+    r = xasprintf(&inclpath, "%s/%s[. = '%s']", lenspath, filter, file);
+    ERR_THROW(r < 0, aug, AUG_ENOMEM, NULL);
+
+    r = xasprintf(&lenslenspath, "%s/lens", lenspath);
+    ERR_THROW(r < 0, aug, AUG_ENOMEM, NULL);
+
+    if (strchr(lens, '.')) {
+       r = xasprintf(&lensname, "%s", lensname);
+        ERR_THROW(r < 0, aug, AUG_ENOMEM, NULL);
+    } else {
+       r = xasprintf(&lensname, "%s.lns", lens);
+        ERR_THROW(r < 0, aug, AUG_ENOMEM, NULL);
+    }
+
+    if (aug_match(aug, lenslenspath, NULL) == 0)
+        r = aug_set(aug, lenslenspath, lensname);
+        ERR_BAIL(aug);
+
+    r = aug_set(aug, inclpath, file);
+    ERR_BAIL(aug);
+
+    free(filter);
+    free(lenspath);
+    free(inclpath);
+    free(lenslenspath);
+    free(lensname);
+    api_exit(aug);
+
+    return r;
+ error:
+    free(filter);
+    free(lenspath);
+    free(inclpath);
+    free(lenslenspath);
+    free(lensname);
+    api_exit(aug);
+    return -1;
+}
+
 int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
     struct pathx *p;
     int result;
diff --git a/src/augeas.h b/src/augeas.h
index 7f7ac14..00e4c9f 100644
--- a/src/augeas.h
+++ b/src/augeas.h
@@ -362,6 +362,20 @@ int aug_to_xml(const augeas *aug, const char *path, 
xmlNode **xmldoc,
                unsigned int flags);
 
 /*
+ * Function: aug_transform
+ *
+ * Add a transform for FILE using LENS.
+ * EXCL specifies if this the file is to be included (0)
+ * or excluded (1) from the LENS. 
+ * The LENS maybe be a module name or a full lens name.
+ * If a module name is given, then lns will be the lens assumed.
+ *
+ * Returns:
+ * 1 on success, -1 on failure
+ */
+int aug_transform(augeas *aug, const char *lens, const char *file, int excl);
+
+/*
  * Function: aug_srun
  *
  * Run one or more newline-separated commands. The output of the commands
diff --git a/src/augeas_sym.version b/src/augeas_sym.version
index eb53941..c56d443 100644
--- a/src/augeas_sym.version
+++ b/src/augeas_sym.version
@@ -57,4 +57,5 @@ AUGEAS_0.16.0 {
       aug_text_store;
       aug_text_retrieve;
       aug_rename;
+      aug_transform;
 } AUGEAS_0.15.0;
diff --git a/src/augrun.c b/src/augrun.c
index 78ef414..58c9100 100644
--- a/src/augrun.c
+++ b/src/augrun.c
@@ -942,6 +942,51 @@ static const struct command_def cmd_dump_xml_def = {
     .help = "Export entries in the tree as XML. If PATH is given, printing 
starts there,\n otherwise the whole tree is printed. If FILENAME is given, the 
XML is saved\n to the given file."
 };
 
+static void cmd_transform(struct command *cmd) {
+    const char *lens = arg_value(cmd, "lens");
+    const char *filter = arg_value(cmd, "filter");
+    const char *file = arg_value(cmd, "file");
+    int r, excl = 0;
+
+    if (STREQ("excl", filter))
+        excl = 1;
+    else if (STREQ("incl", filter))
+        excl = 0;
+    else
+        ERR_REPORT(cmd, AUG_ECMDRUN,
+                   "FILTER must be \"incl\" or \"excl\"");
+
+    r = aug_transform(cmd->aug, lens, file, excl);
+    if (r < 0)
+        ERR_REPORT(cmd, AUG_ECMDRUN,
+                   "Adding transform for %s on lens %s failed", lens, file);
+}
+
+static const struct command_opt_def cmd_transform_opts[] = {
+    { .type = CMD_PATH, .name = "lens", .optional = false,
+      .help = "the lens to use" },
+    { .type = CMD_PATH, .name = "filter", .optional = false,
+      .help = "the type of filter, either \"incl\" or \"excl\"" },
+    { .type = CMD_PATH, .name = "file", .optional = false,
+      .help = "the file to associate to the lens" },
+    CMD_OPT_DEF_LAST
+};
+
+static const char const cmd_transform_help[] =
+    "Add a transform for FILE using LENS. The LENS may be a module name or a\n"
+    " full lens name.  If a module name is given, then \"lns\" will be the 
lens\n"
+    " assumed.  The FILTER must be either \"incl\" or \"excl\".  If the filter 
is\n"
+    " \"incl\",  the FILE will be parsed by the LENS.  If the filter is 
\"excl\",\n"
+    " the FILE will be excluded from the LENS. FILE may contain wildcards." ;
+
+static const struct command_def cmd_transform_def = {
+    .name = "transform",
+    .opts = cmd_transform_opts,
+    .handler = cmd_transform,
+    .synopsis = "add a transform",
+    .help = cmd_transform_help
+};
+
 static void cmd_save(struct command *cmd) {
     int r;
     r = aug_save(cmd->aug);
@@ -1132,6 +1177,7 @@ static const struct command_def const *commands[] = {
     &cmd_store_def,
     &cmd_retrieve_def,
     &cmd_touch_def,
+    &cmd_transform_def,
     &cmd_help_def,
     &cmd_def_last
 };
diff --git a/src/augtool.c b/src/augtool.c
index bb0becc..f2c2c92 100644
--- a/src/augtool.c
+++ b/src/augtool.c
@@ -44,6 +44,8 @@ static const char *const progname = "augtool";
 static unsigned int flags = AUG_NONE;
 const char *root = NULL;
 char *loadpath = NULL;
+char *transforms = NULL;
+size_t transformslen = 0;
 const char *inputfile = NULL;
 int echo_commands = 0;         /* Gets also changed in main_loop */
 bool print_version = false;
@@ -168,7 +170,8 @@ static char *readline_command_generator(const char *text, 
int state) {
         "quit", "clear", "defnode", "defvar",
         "get", "ins", "load", "ls", "match",
         "mv", "rename", "print", "dump-xml", "rm", "save", "set", "setm",
-        "clearm", "span", "store", "retrieve", "help", NULL };
+        "clearm", "span", "store", "retrieve", "transform",
+        "help", NULL };
 
     static int current = 0;
     const char *name;
@@ -266,22 +269,25 @@ static void usage(void) {
     fprintf(stderr, "Run '%s help' to get a list of possible commands.\n",
             progname);
     fprintf(stderr, "\nOptions:\n\n");
-    fprintf(stderr, "  -c, --typecheck    typecheck lenses\n");
-    fprintf(stderr, "  -b, --backup       preserve originals of modified files 
with\n"
-                    "                     extension '.augsave'\n");
-    fprintf(stderr, "  -n, --new          save changes in files with extension 
'.augnew',\n"
-                    "                     leave original unchanged\n");
-    fprintf(stderr, "  -r, --root ROOT    use ROOT as the root of the 
filesystem\n");
-    fprintf(stderr, "  -I, --include DIR  search DIR for modules; can be given 
mutiple times\n");
-    fprintf(stderr, "  -e, --echo         echo commands when reading from a 
file\n");
-    fprintf(stderr, "  -f, --file FILE    read commands from FILE\n");
-    fprintf(stderr, "  -s, --autosave     automatically save at the end of 
instructions\n");
-    fprintf(stderr, "  -i, --interactive  run an interactive shell after 
evaluating the commands in STDIN and FILE\n");
-    fprintf(stderr, "  -S, --nostdinc     do not search the builtin default 
directories for modules\n");
-    fprintf(stderr, "  -L, --noload       do not load any files into the tree 
on startup\n");
-    fprintf(stderr, "  -A, --noautoload   do not autoload modules from the 
search path\n");
-    fprintf(stderr, "  --span             load span positions for nodes 
related to a file\n");
-    fprintf(stderr, "  --version          print version information and 
exit.\n");
+    fprintf(stderr, "  -c, --typecheck            typecheck lenses\n");
+    fprintf(stderr, "  -b, --backup               preserve originals of 
modified files with\n"
+                    "                             extension '.augsave'\n");
+    fprintf(stderr, "  -n, --new                  save changes in files with 
extension '.augnew',\n"
+                    "                             leave original unchanged\n");
+    fprintf(stderr, "  -r, --root ROOT            use ROOT as the root of the 
filesystem\n");
+    fprintf(stderr, "  -I, --include DIR          search DIR for modules; can 
be given mutiple times\n");
+    fprintf(stderr, "  -t, --transform LENS=FILE  add a transform for FILE 
using LENS\n");
+    fprintf(stderr, "  -e, --echo                 echo commands when reading 
from a file\n");
+    fprintf(stderr, "  -f, --file FILE            read commands from FILE\n");
+    fprintf(stderr, "  -s, --autosave             automatically save at the 
end of instructions\n");
+    fprintf(stderr, "  -i, --interactive          run an interactive shell 
after evaluating\n"
+                    "                             the commands in STDIN and 
FILE\n");
+    fprintf(stderr, "  -S, --nostdinc             do not search the builtin 
default directories\n"
+                    "                             for modules\n");
+    fprintf(stderr, "  -L, --noload               do not load any files into 
the tree on startup\n");
+    fprintf(stderr, "  -A, --noautoload           do not autoload modules from 
the search path\n");
+    fprintf(stderr, "  --span                     load span positions for 
nodes related to a file\n");
+    fprintf(stderr, "  --version                  print version information 
and exit.\n");
 
     exit(EXIT_FAILURE);
 }
@@ -294,26 +300,27 @@ static void parse_opts(int argc, char **argv) {
         VAL_SPAN = VAL_VERSION + 1
     };
     struct option options[] = {
-        { "help",      0, 0, 'h' },
-        { "typecheck", 0, 0, 'c' },
-        { "backup",    0, 0, 'b' },
-        { "new",       0, 0, 'n' },
-        { "root",      1, 0, 'r' },
-        { "include",   1, 0, 'I' },
-        { "echo",      0, 0, 'e' },
-        { "file",      1, 0, 'f' },
-        { "autosave",  0, 0, 's' },
-        { "interactive",  0, 0, 'i' },
-        { "nostdinc",  0, 0, 'S' },
-        { "noload",    0, 0, 'L' },
-        { "noautoload", 0, 0, 'A' },
-        { "span",      0, 0, VAL_SPAN },
-        { "version",   0, 0, VAL_VERSION },
+        { "help",        0, 0, 'h' },
+        { "typecheck",   0, 0, 'c' },
+        { "backup",      0, 0, 'b' },
+        { "new",         0, 0, 'n' },
+        { "root",        1, 0, 'r' },
+        { "include",     1, 0, 'I' },
+        { "transform",   1, 0, 't' },
+        { "echo",        0, 0, 'e' },
+        { "file",        1, 0, 'f' },
+        { "autosave",    0, 0, 's' },
+        { "interactive", 0, 0, 'i' },
+        { "nostdinc",    0, 0, 'S' },
+        { "noload",      0, 0, 'L' },
+        { "noautoload",  0, 0, 'A' },
+        { "span",        0, 0, VAL_SPAN },
+        { "version",     0, 0, VAL_VERSION },
         { 0, 0, 0, 0}
     };
     int idx;
 
-    while ((opt = getopt_long(argc, argv, "hnbcr:I:ef:siSLA", options, &idx)) 
!= -1) {
+    while ((opt = getopt_long(argc, argv, "hnbcr:I:t:ef:siSLA", options, 
&idx)) != -1) {
         switch(opt) {
         case 'c':
             flags |= AUG_TYPE_CHECK;
@@ -333,6 +340,9 @@ static void parse_opts(int argc, char **argv) {
         case 'I':
             argz_add(&loadpath, &loadpathlen, optarg);
             break;
+        case 't':
+            argz_add(&transforms, &transformslen, optarg);
+            break;
         case 'e':
             echo_commands = 1;
             break;
@@ -537,6 +547,33 @@ static int run_args(int argc, char **argv) {
     return (code == 0 || code == -2) ? 0 : -1;
 }
 
+static void add_transforms(char *ts, size_t tslen) {
+    char *command;
+    int r;
+    char *t = NULL;
+    bool added_transform = false;
+
+    while ((t = argz_next(ts, tslen, t))) {
+        r = xasprintf(&command, "transform %s", t);
+        if (r < 0)
+            fprintf(stderr, "error: Failed to add transform %s: could not 
allocate memory\n", t);
+
+        r = aug_srun(aug, stdout, command);
+        if (r < 0)
+            fprintf(stderr, "error: Failed to add transform %s: %s\n", t, 
aug_error_message(aug));
+
+       added_transform = true;
+    }
+   
+    if (added_transform) {
+        r = aug_load(aug);
+        if (r < 0)
+            fprintf(stderr, "error: Failed to load with new transforms: %s\n", 
aug_error_message(aug));
+    }
+
+    free(command);
+}
+
 int main(int argc, char **argv) {
     int r;
 
@@ -551,6 +588,7 @@ int main(int argc, char **argv) {
             print_aug_error();
         exit(EXIT_FAILURE);
     }
+    add_transforms(transforms, transformslen);
     if (print_version) {
         print_version_info();
         return EXIT_SUCCESS;
diff --git a/tests/run.tests b/tests/run.tests
index 55effdb..7567004 100644
--- a/tests/run.tests
+++ b/tests/run.tests
@@ -340,6 +340,29 @@ test get-bad-pathx -1 EPATHX
   get /files[]
 
 #
+# test transform
+#
+test transform-1 3
+  transform Test incl /tmp/bar
+  get /augeas/load/Test/lens
+  get /augeas/load/Test/incl
+prints
+  /augeas/load/Test/lens = Test.lns
+  /augeas/load/Test/incl = /tmp/bar
+
+test transform-2 4
+  transform Bar incl /tmp/foo/*
+  transform Bar incl /tmp/bar/*
+  transform Bar excl /tmp/foo/baz
+  print /augeas/load/Bar
+prints
+  /augeas/load/Bar
+  /augeas/load/Bar/lens = "Bar.lns"
+  /augeas/load/Bar/incl[1] = "/tmp/foo/*"
+  /augeas/load/Bar/incl[2] = "/tmp/bar/*"
+  /augeas/load/Bar/excl = "/tmp/foo/baz"
+
+#
 # test print
 #
 test print-save 1
diff --git a/tests/test-api.c b/tests/test-api.c
index e74a6db..555582a 100644
--- a/tests/test-api.c
+++ b/tests/test-api.c
@@ -483,6 +483,52 @@ static void testToXml(CuTest *tc) {
     aug_close(aug);
 }
 
+static void testTransform(CuTest *tc) {
+    struct augeas *aug;
+    int r;
+    const char *v;
+
+    aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_MODL_AUTOLOAD);
+
+    r = aug_transform(aug, "Passwd", "/etc/passwd", 0);
+    CuAssertRetSuccess(tc, r);
+
+    r = aug_get(aug, "/augeas/load/Passwd/incl", &v);
+    CuAssertRetSuccess(tc, r);
+    CuAssertStrEquals(tc, "/etc/passwd", v);
+
+    r = aug_get(aug, "/augeas/load/Passwd/lens", &v);
+    CuAssertRetSuccess(tc, r);
+    CuAssertStrEquals(tc, "Passwd.lns", v);
+
+    r = aug_transform(aug, "Shellvars.lns_norec", "/etc/sysconfig/grub", 0);
+    CuAssertRetSuccess(tc, r);
+
+    r = aug_transform(aug, "Shellvars.lns_norec", "/etc/sysconfig/*", 0);
+    CuAssertRetSuccess(tc, r);
+
+    r = aug_transform(aug, "Shellvars.lns_norec", "/etc/sysconfig/network", 1);
+    CuAssertRetSuccess(tc, r);
+
+    r = aug_get(aug, "/augeas/load/Shellvars.lns_norec/incl[1]", &v);
+    CuAssertRetSuccess(tc, r);
+    CuAssertStrEquals(tc, "/etc/sysconfig/grub", v);
+
+    r = aug_get(aug, "/augeas/load/Shellvars.lns_norec/incl[2]", &v);
+    CuAssertRetSuccess(tc, r);
+    CuAssertStrEquals(tc, "/etc/sysconfig/*", v);
+
+    r = aug_get(aug, "/augeas/load/Shellvars.lns_norec/excl", &v);
+    CuAssertRetSuccess(tc, r);
+    CuAssertStrEquals(tc, "/etc/sysconfig/network", v);
+
+    r = aug_get(aug, "/augeas/load/Shellvars.lns_norec/lens", &v);
+    CuAssertRetSuccess(tc, r);
+    CuAssertStrEquals(tc, "Shellvars.lns_norec", v);
+
+    aug_close(aug);
+}
+
 static void testTextStore(CuTest *tc) {
     static const char *const hosts = "192.168.0.1 rtr.example.com router\n";
     /* Not acceptable for Hosts.lns - missing canonical and \n */
-- 
1.7.9.5

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

Reply via email to