[augeas-devel] Transform patch, v2

David Lutterkort lutter at redhat.com
Fri Aug 10 19:41:21 UTC 2012


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 */






More information about the augeas-devel mailing list