Skip to content

Commit

Permalink
Add function modified() to select nodes which are marked as dirty
Browse files Browse the repository at this point in the history
  • Loading branch information
George Hansper authored and lutter committed Aug 31, 2020
1 parent a42eea9 commit eb04250
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 30 deletions.
63 changes: 34 additions & 29 deletions src/augeas.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ static const char *const static_nodes[][2] = {
{ AUGEAS_META_PATHX_FUNC "/glob", NULL },
{ AUGEAS_META_PATHX_FUNC "/label", NULL },
{ AUGEAS_META_PATHX_FUNC "/last", NULL },
{ AUGEAS_META_PATHX_FUNC "/modified", NULL },
{ AUGEAS_META_PATHX_FUNC "/position", NULL },
{ AUGEAS_META_PATHX_FUNC "/regexp", NULL }
};
Expand All @@ -84,18 +85,21 @@ static const char *const errcodes[] = {
};

static void tree_mark_dirty(struct tree *tree) {
do {
tree->dirty = 1;
tree = tree->parent;
} while (tree != tree->parent && !tree->dirty);
tree->dirty = 1;
while (tree != tree->parent ) {
if ( tree->file ) {
tree->dirty = 1;
break;
}
tree = tree->parent;
}
}

void tree_clean(struct tree *tree) {
if (tree->dirty) {
list_for_each(c, tree->children)
tree_clean(c);
}
if ( tree->file && ! tree->dirty )
return;
list_for_each(c, tree->children)
tree_clean(c);
tree->dirty = 0;
}

Expand Down Expand Up @@ -691,10 +695,9 @@ static void tree_mark_files(struct tree *tree) {
static void tree_rm_dirty_files(struct augeas *aug, struct tree *tree) {
struct tree *p;

if (!tree->dirty)
if (tree->file && !tree->dirty) {
return;

if (tree->file && ((p = tree_child(tree, "path")) != NULL)) {
} else if (tree->file && tree->dirty && ((p = tree_child(tree, "path")) != NULL)) {
tree_unlink(aug, tree_fpath(aug, p->value));
tree_unlink(aug, tree);
} else {
Expand All @@ -709,7 +712,7 @@ static void tree_rm_dirty_files(struct augeas *aug, struct tree *tree) {

static void tree_rm_dirty_leaves(struct augeas *aug, struct tree *tree,
struct tree *protect) {
if (! tree->dirty)
if (tree->file && !tree->dirty)
return;

struct tree *c = tree->children;
Expand Down Expand Up @@ -1491,19 +1494,23 @@ static int tree_save(struct augeas *aug, struct tree *tree,
return -1;

list_for_each(t, tree) {
if (t->dirty) {
if (t->file && ! t->dirty) {
continue;
} else {
char *tpath = NULL;
struct tree *transform = NULL;
if (asprintf(&tpath, "%s/%s", path, t->label) == -1) {
result = -1;
continue;
}
list_for_each(xfm, load->children) {
if (transform_applies(xfm, tpath)) {
if (transform == NULL || transform == xfm) {
transform = xfm;
} else {
result = check_save_dup(aug, tpath, transform, xfm);
if ( t->dirty ) {
list_for_each(xfm, load->children) {
if (transform_applies(xfm, tpath)) {
if (transform == NULL || transform == xfm) {
transform = xfm;
} else {
result = check_save_dup(aug, tpath, transform, xfm);
}
}
}
}
Expand Down Expand Up @@ -1554,7 +1561,7 @@ static int unlink_removed_files(struct augeas *aug,

int result = 0;

if (! files->dirty)
if (files->file)
return 0;

for (struct tree *tm = meta->children; tm != NULL;) {
Expand All @@ -1576,7 +1583,7 @@ static int unlink_removed_files(struct augeas *aug,
result = -1;
}
free_pathx(px);
} else if (tf->dirty && ! tree_child(tm, "path")) {
} else if (! tree_child(tm, "path")) {
if (unlink_removed_files(aug, tf, tm) < 0)
result = -1;
}
Expand Down Expand Up @@ -1605,15 +1612,13 @@ int aug_save(struct augeas *aug) {
list_for_each(xfm, load->children)
transform_validate(aug, xfm);

if (files->dirty) {
if (tree_save(aug, files->children, AUGEAS_FILES_TREE) == -1)
ret = -1;
if (tree_save(aug, files->children, AUGEAS_FILES_TREE) == -1)
ret = -1;

/* Remove files whose entire subtree was removed. */
if (meta_files != NULL) {
if (unlink_removed_files(aug, files, meta_files) < 0)
ret = -1;
}
/* Remove files whose entire subtree was removed. */
if (meta_files != NULL) {
if (unlink_removed_files(aug, files, meta_files) < 0)
ret = -1;
}
if (!(aug->flags & AUG_SAVE_NOOP)) {
tree_clean(aug->origin);
Expand Down
9 changes: 9 additions & 0 deletions src/pathx.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ static void func_regexp_flag(struct state *state, int nargs);
static void func_glob(struct state *state, int nargs);
static void func_int(struct state *state, int nargs);
static void func_not(struct state *state, int nargs);
static void func_modified(struct state *state, int nargs);

static const enum type arg_types_nodeset[] = { T_NODESET };
static const enum type arg_types_string[] = { T_STRING };
Expand Down Expand Up @@ -341,6 +342,8 @@ static const struct func builtin_funcs[] = {
.arg_types = arg_types_nodeset, .impl = func_int, .pure = false },
{ .name = "int", .arity = 1, .type = T_NUMBER,
.arg_types = arg_types_bool, .impl = func_int, .pure = false },
{ .name = "modified", .arity = 0, .type = T_BOOLEAN,
.arg_types = NULL, .impl = func_modified, .pure = false },
{ .name = "not", .arity = 1, .type = T_BOOLEAN,
.arg_types = arg_types_bool, .impl = func_not, .pure = true }
};
Expand Down Expand Up @@ -724,6 +727,12 @@ static void func_int(struct state *state, int nargs) {
push_value(vind, state);
}

static void func_modified(struct state *state, int nargs) {
ensure_arity(0, 0);

push_boolean_value(state->ctx->dirty , state);
}

static void func_not(struct state *state, int nargs) {
ensure_arity(1, 1);
RET_ON_ERROR;
Expand Down
3 changes: 2 additions & 1 deletion tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ check_SCRIPTS = \
test-save-empty.sh test-bug-1.sh test-idempotent.sh test-preserve.sh \
test-events-saved.sh test-save-mode.sh test-unlink-error.sh \
test-augtool-empty-line.sh test-augtool-modify-root.sh \
test-span-rec-lens.sh test-nonwritable.sh test-augmatch.sh
test-span-rec-lens.sh test-nonwritable.sh test-augmatch.sh \
test-function-modified.sh

EXTRA_DIST = \
test-augtool root lens-test-1 \
Expand Down
47 changes: 47 additions & 0 deletions tests/test-function-modified.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/sh

# Test that changing the value of a node causes the function modified() to return true

root=$abs_top_builddir/build/test-function-modified
hosts=$root/etc/hosts

rm -rf $root
mkdir -p $(dirname $hosts)

cat <<EOF > $hosts
127.0.0.1 localhost
::1 localhost6
EOF

touch -r $0 $hosts

augtool --nostdinc -r $root -I $abs_top_srcdir/lenses > /dev/null <<EOF >$root/output.1
set /files/etc/hosts/1/ipaddr 127.0.0.4
match /files/etc/hosts//*[modified()]
EOF

[ "$(cat $root/output.1)" = '/files/etc/hosts/1/ipaddr = 127.0.0.4' ] || exit 1

# An empty value should return true, even if none of the child nodes are modified
augtool --nostdinc -r $root -I $abs_top_srcdir/lenses > /dev/null <<EOF >$root/output.2
set /files/etc/hosts/1 x
set /files/etc/hosts/1
match /files/etc/hosts//*[modified()]
EOF

[ "$(cat $root/output.2)" = '/files/etc/hosts/1 = (none)' ] || exit 1

# Test that changing a value does not change the parent node
# Test that adding a new node also marks the (new) parent node.
augtool --nostdinc -r $root -I $abs_top_srcdir/lenses > /dev/null <<EOF >$root/output.3
set /files/etc/hosts/1/ipaddr 127.1.1.1
set /files/etc/hosts/3/ipaddr 127.3.3.3
match /files/etc/hosts//*[modified()]
EOF

diff -q $root/output.3 - <<EOF || exit 1
/files/etc/hosts/3 = (none)
/files/etc/hosts/1/ipaddr = 127.1.1.1
/files/etc/hosts/3/ipaddr = 127.3.3.3
EOF

0 comments on commit eb04250

Please sign in to comment.