find and replace versions in a specific block

Go To StackoverFlow.com

0

I have some pom files in my project with the following structure

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <parent>
             <artifactId>xparent</artifactId>
             <groupId>y</groupId>
             <version>2.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>someparent</artifactId>
     <version>x.x.x-needs_change</version>
     <packaging>pom</packaging>
     <name>some name</name>
     <description>some description</description>
     <url>myurl</url>

    <modules>
        <module>mymodules</module>
    </modules>

    <properties>
        <my.version>x.x.x-needs_change</my.version>
    </properties>

    <dependencies>
    <dependency>
    <groupId>hhhhh</groupId>
    <artifactId>hhhhh</artifactId>
    <version>x.x.x-should not change</version>
    </dependency>
   </dependencies>
</project>

I am using sed to give the current version as input and change it to a new version given. But I do not want to change version within dependency block. How do I do this?

I do not want to go the maven version plugin route. I have tried it and it does not suit my requirements.

I prefer sed / python script.

Thanks

2012-04-03 23:29
by user1164061


2

You could try:

sed -e '/<dependencies>/,/<\/dependencies>/ !{ 
       s!<version>[0-9.]\+</version>!<version>'"$NEWVERSION"'</version>!
       }' MY_FILE

The /<dependencies>/,/<\/dependencies>/ says "find all lines between <dependencies> and </dependencies>".

The ! after that says "perform the following actions everywhere but those lines (i.e. do this for all lines except between <dependencies> and </dependencies>)".

The s!<version>[0-9.]\+</version>!<version>'"$NEWVERSION"'</version>! says "replace <version>...</version> with <version>$NEWVERSION</version>, where $NEWVERSION is some environment variable that contains the new version number.

The farting around with the quotes ('"$NEWVERSION"') was because I wanted single quotes for the main part of the sed command (so I don't have to worry about the exclamation mark & backslashes), but I do want $NEWVERSION to be expanded.

Modify to suit your script.

2012-04-03 23:58
by mathematical.coffee
Nice, much cleaner than the version I came up with. Slight improvement would be to use s!\(<version>\)[0-9.]\+\(</version>\)!\1'"$NEWVERSION"'\2! to save a few characters - Andrew Clark 2012-04-04 00:03
I seriously think that the Do not use regex to parse html rule should be expanded to do not use sed to modify xml : - Kimvais 2012-04-04 07:32
Yeah, but for all people say "Don't do it!", it can be appropriate in some cases, depending on what control you have over the input (for example generated HTML/XML can be relied on to be well-formed as opposed to user input), whether the job is a once-off, who the code is for (I'm happy to use regex on my personal projects) and the time investment in a quickie with sed vs writing a script with a XML/HTML parser (especially if regex is second nature to you already) - mathematical.coffee 2012-04-04 23:37
@mathematical.coffee : It works. Really appreciate your hel - user1164061 2012-04-05 18:11


1

To parse and modify XML - you really should use a xml aware parser, such as lxml instead of text tools such as sed or awk

I assume that your POM files are indeed valid POM files, i.e. they have the enclosing <project> tag as well.

>>> t = """<project>
... <parent>
... <artifactID> </artifactID>
... <groupID> </groupID>
... <version>2.0.0</version>
... </parent>
... 
... <properties>
... <version>2.0.0</version>
... </properties>
... 
... <dependencies>
... <dependency>
... <version>2.0.0</version>
... </dependency>
... </dependencies></project>
... """
>>> from lxml import etree
>>> r = etree.fromstring(t)
>>> r.xpath("//parent/version")[0].text = "3.0"
>>> r.xpath("//properties/version")[0].text = "3.0"
>>> print(etree.tostring(r))
<project>
<parent>
<artifactID> </artifactID>
<groupID> </groupID>
<version>3.0</version>
</parent>

<properties>
<version>3.0</version>
</properties>

<dependencies>
<dependency>
<version>2.0.0</version>
</dependency>
</dependencies></project>
2012-04-04 07:23
by Kimvais
What if the input is a filename? I tried t = etree.parse(filenametoupdate) r=etree.tostring(t) r.xpath("//parent/version")[0].text = newversion r.xpath("//properties/version")[0].text = newversion but get an error AttributeError: 'str' object has no attribute 'xpath'. An mew to this. So I don't know how to fix thi - user1164061 2012-04-04 20:02
You only need to call .tostring() after you have updated the the versions, so you should call t.xpath() on the parsed tree not on the string - Kimvais 2012-04-05 05:09
Now I tried t = etree.parse(filenametoupdate) t.xpath("//parent/version")[0].text = newversion t.xpath("//properties/version")[0].text = newversion but I get IndexError: list index out of range. I also tried to expand //parent/version to /parent/artifactId/groupId/version but i still get the same erro - user1164061 2012-04-05 18:29
Can you please post a complete POM file somewhere - Kimvais 2012-04-05 20:10
I updated my question with the actual pom (minus all sensitive information). Can you please check it now? Sorry for the delay in replying. I was ooo - user1164061 2012-04-09 17:17
Hi, did you get a chance to check this - user1164061 2012-04-16 16:52


0

nawk '{
      a=$0;
      getline;
      if($0!~/depend/ && a!~/version/)
      {gsub(/2.0.0/,"1.0.0",$0);print a"\n"$0}
      else print a"\n"$0 
      }' file3

Below is the test:

pearl.302> cat file3
    <parent>
    <aritifactID> </artifactID>
    <groupID> </groupID>
    <version>2.0.0</version>
    </parent>

    <properties>
    <version>2.0.0</version>
    </properties>

    <dependencies>
    <dependency>
    <version>2.0.0</version>
    </dependency>
    </dependencies>
pearl.303> nawk '{a=$0;
                  getline;
                  if($0!~/depend/ && a!~/version/)
                  {gsub(/2.0.0/,"1.0.0",$0);print a"\n"$0}
                  else print a"\n"$0 }' file3
    <parent>
    <aritifactID> </artifactID>
    <groupID> </groupID>
    <version>1.0.0</version>
    </parent>

    <properties>
    <version>1.0.0</version>
    </properties>

    <dependencies>
    <dependency>
    <version>2.0.0</version>
    </dependency>
    </dependencies>
2012-04-04 07:09
by Vijay
That looks pretty fragile. What if there's a line between "version" and "depend" - glenn jackman 2012-04-04 13:06


0

awk -v change=1 -v newver=2.3.4 '
  change && /version/ {sub(/>[^<]+/, ">" newver)} 
  /<\/?dependencies>/ {change = !change} 
  {print}
'
2012-04-04 13:12
by glenn jackman