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