augeas icon indicating copy to clipboard operation
augeas copied to clipboard

Append new line if not exist using Simplelines.lns

Open nicutor opened this issue 7 years ago • 9 comments

Hi,

I have a file in this format:

# comment sample 1
# comment sample 2
line 1 value # comment line 1
line 2 value # comment line 2
Include /some/file
Include /some/other/file

I am trying to append a new line at the end of file if that line doesn't already exist using Simplelines and I don't know what I am missing.

Can you please give me an example of how to do this? I am using the right lens?

Thank you!

nicutor avatar Jun 02 '18 23:06 nicutor

Best to show what you've tried and what you got.

MatthewHannigan avatar Jun 03 '18 01:06 MatthewHannigan

Hi @MatthewHannigan,

I found this tutorial https://github.com/hercules-team/augeas/wiki/Adding-nodes-to-the-tree and i was able to add a new line using this:

# augtool -At "Simplelines.lns incl /root/tmp"
augtool> print /files/root/tmp
/files/root/tmp
/files/root/tmp/#comment[1] = "comment sample 1"
/files/root/tmp/#comment[2] = "comment sample 2"
/files/root/tmp/1 = "line 1 value # comment line 1"
/files/root/tmp/2 = "line 2 value # comment line 2"
augtool> ins 01 before /files/root/tmp/1
augtool> set /files/root/tmp/01 'Include /some/file'
augtool> print /files/root/tmp
/files/root/tmp
/files/root/tmp/#comment[1] = "comment sample 1"
/files/root/tmp/#comment[2] = "comment sample 2"
/files/root/tmp/01 = "Include /some/file"
/files/root/tmp/1 = "line 1 value # comment line 1"
/files/root/tmp/2 = "line 2 value # comment line 2"
augtool> save
Saved 1 file(s)
augtool> quit

# cat /root/tmp
# comment sample 1
# comment sample 2
Include /some/file
line 1 value # comment line 1
line 2 value # comment line 2

Now I am trying to use the 'match' method to find if the line is already there:

augtool> match /files/root/tmp/*[. = 'Include']
  (no matches)
augtool> match /files/root/tmp/*[. =~ 'Include']
error: Invalid path expression
error: type error
/files/root/tmp/*[. =~ 'Include']|=|
augtool>

What I am trying to do is, to add some 'Include /path/to/some/files' lines on the file, but only if the line is not already there, no matter at what position.

The match function will return a code so I can use it on this chef resource: https://supermarket.chef.io/cookbooks/augeas For example:

augeas 'add_included_files' do
  changes ['ins 01 before /files/root/tmp/1', 'set /files/root/tmp/01 Include /some/file']
  lens 'Simplelines.lns'
  incl '/root/tmp'
  run_if  "match /files/root/tmp/*[. != 'Include /some/file']"
end

Can you please guide me how to use the matc function, or to tell me another way to check if a line is not already on a file?

Thank you very much.

nicutor avatar Jun 03 '18 18:06 nicutor

You are very close ! If this was about returning a successful match if the line Include /some/file was there, you could write

    run_if  "match /files/root/tmp/*[. = 'Include /some/file']"

But that's reversed from what you want: you want to run if there is no node with Include /some/file. If there was a run_unless in Chef, you'd be done. We therefore need to find a way to match if the line is not there, which is unfortunately a little more involved.

The construct /files/root/tmp/*[ . = 'Include /some/file'] loops over all nodes underneath /files/root/tmp and returns those that match the condition in [ ... ]. The construct /files/root/tmp/*[ . != 'Include /some/file'] is not the negation of this: that expression matches all nodes whose content is not Include /some/file, and so you'll get matches as long as there are lines other than Include /some/file in the file.

One way to resolve this is to do the following:

    run_if "match /files/root/tmp[count(*[. = 'Include /some/file']) = 0]"

The argument to count is a list of nodes; in this case, we count all the nodes underneath /files/root/tmp that have Include /some/file and produce a match when that count is 0. The match is /files/root/tmp, but that doesn't matter since we are only interested in whether something matches at all or not for run_if.

BTW, your changes will stick the new line into the beginning of the file. If you want to append them, you'd do

    changes ['ins 01 after /files/root/tmp/*[last()]', 'set /files/root/tmp/01 Include /some/file']

lutter avatar Jun 05 '18 03:06 lutter

One other small thing: in newer versions of Augeas (since 1.10), you can write ['something'] as a shorthand for [. = 'something'] - but that's merely cosmetic.

lutter avatar Jun 05 '18 03:06 lutter

Thank you @lutter !

Your command runs fine for me. I still have issues to use that on chef resource.

I've opened an issue on their side: https://github.com/nhuff/chef-augeas/issues/12 and hope somebody will guide me in the right direction.

nicutor avatar Jun 05 '18 15:06 nicutor

I just looked through the Chef code, and from reading the code (i.e., I haven't tried to run anything ;) ), it looks like you can actually check for the size of a match. IOW, something like this should work, too:

    run_if "match /files/root/tmp/*[ . = 'Include /some/file'] size == 0"

lutter avatar Jun 05 '18 16:06 lutter

Hi @lutter, many thanks! This is it, everything works now.

Now, if you don't mind, I will like to know how to combine all of these in a single augtool command. I mean to not enter on augtool shell at all. If this is possible.. I will like to use this in future from command line too, instead of using sed/perl or something else.

augeas 'include_some_file' do
  changes ['ins 01 before /files/root/tmp/1', 'set /files/root/tmp/01 Include /some/file']
  lens 'Simplelines.lns'
  incl '/root/tmp'
  run_if  "match /files/root/tmp/*[. = 'Include /some/file'] size == 0"
end

Thank you very much again for your help.

nicutor avatar Jun 05 '18 19:06 nicutor

You can't do it straightup in augtool since that has no if statement. But you can do it as a shell script: this gist shows how that could be done.

Since using augtool in the if statement in that script is sorta brittle, I created PR #563 to do this kind of check with augmatch - but that's of course not yet in a released version of augeas.

lutter avatar Jun 07 '18 22:06 lutter

See also: #68

georgehansper avatar Jul 24 '20 01:07 georgehansper