ACK. I pushed a variation of this patch, using tree_child_cr & friends
to set up the tree entries rather than xasprintf etc. It also now
correctly handles setting a transform Foo.lns /files (i.e., the
transform node has the .lns stripped from its name)

David

On Thu, 2012-08-09 at 15:27 +0200, Raphaël Pinson wrote:
> 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 */



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

Reply via email to