以编程方式替换 pom.xml 中的依赖版本?
Replace a dependency version in pom.xml programmatically?
假设我有一个 pom.xml 包含这样的父依赖项:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
</project>
有没有一种方法可以通过脚本以编程方式替换 1.0.0-SNAPSHOT
版本?
我的用例:
- 我有很多 pom.xml 文件需要更改
的父版本
- 我正在使用 git-xargs 跨多个存储库进行更改,因此我可以对每个 pom.xml 应用一个 bash 脚本来更改它。
例如,我可以执行以下操作,但这将更新 pom.xml 中出现的所有 1.0.0-SNAPSHOT
,我想将其限制为仅 some-parent
工件有一个版本 1.0.0-SNAPSHOT
:
git-xargs \
--branch-name test-branch \
--github-org <your-github-org> \
--commit-message "Update pom.xml" \
sed -i 's/1.0.0-SNAPSHOT/2.0.1/g' pom.xml
根据 git-xargs 文档,我可以使用任何类型的脚本来处理 pom.xml、bash、python、ruby等:https://github.com/gruntwork-io/git-xargs#how-to-supply-commands-or-scripts-to-run
更新:
以下 xmlstarlet 方法在一定程度上起作用:
if [[ $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:artifactId' pom.xml) == "some-parent" && $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:version' pom.xml) == "1.0.0-SNAPSHOT" ]]; then xmlstarlet edit -L -N my=http://maven.apache.org/POM/4.0.0 --update '//my:project/my:parent/my:version' --value '2.0.6' pom.xml; fi
xmlstarlet 正确更新了我想要的 xml 元素,但它也重新排序了顶部的 xsi:schemaLocation
、xmlns
和 xmlns:xsi
我的档案。
它更新自:
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
至:
<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/xsd/maven-4.0.0.xsd">
这对我不利。
虽然您可以将 --if
和 --else
用于 xmlstarlet sel
(例如参见 [=22=]),但我认为您不能将它们用于 xmlstarlet ed
.我几乎从不使用 xmlstarlet
,所以我不太确定。
这意味着您必须在 Bash...
内完成
$ if [[ $(xmlstarlet sel -t -v 'parent/version' pom.xml) == "1.0.0-SNAPSHOT" ]]
then xmlstarlet ed -O -u 'parent/version' -v 2.0.1 pom.xml
fi
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>2.0.1</version>
</parent>
与xidel:
$ xidel -s pom.xml -e '
if (parent/version = "1.0.0-SNAPSHOT")
then x:replace-nodes(parent/version/text(),"2.0.1")
else .
' --output-node-format=xml
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>2.0.1</version>
</parent>
如果您希望输出包含 XML 声明,对于 xmlstarlet
删除 -O
选项,对于 xidel
使用 --output-format=xml
代替。
这有效,结合使用了 xmlstarlet 和 mvn:
#! /usr/bin/env bash
if [[ $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:artifactId' pom.xml) == "some-parent" && \
$(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:version' pom.xml) == "4.0.0-SNAPSHOT" ]]; then
mvn versions:update-parent -DparentVersion=[4.0.0-661]
mvn versions:commit
fi
您应该避免使用 xml 作为纯文本文件,但如果您没有其他选择,您可以尝试一下。 sed
范围 (/starting-regex/,/ending-regex/{commands}
) 允许在特定上下文中限制您的替换。 IE。这条线:
sed -e '/<parent/,/\/parent/{/artifactId>some-parent/,/parent/{s/1.0.0-SNAPSHOT/2.0.0-SNAPSHOT/g}}'
将仅替换
你可以使用 xq.
只需将某个元素设置为新值就和
一样简单
xq -x '.project.parent.version = "2.0.1"' pom.xml
按条件设置为
xq -x '(.project.parent | select(
.artifactId == "some-parent" and .version == "1.0.0-SNAPSHOT"
)).version = "2.0.1"' pom.xml
输入样本数据,两者都会产生
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>2.0.1</version>
</parent>
</project>
如您所见,属性的 order 保持不变,但是 indentation 不同,尤其是您的 in-tag 换行符被吞掉了。此外,缺少 XML 声明(第一行),评论,如果存在于输入中。也许这对你也不可行,但请考虑
- 编辑逻辑结构(而不是其文本表示)较少error-prone,
- 所有这些问题(当然,缺少的注释除外)都可以使用 command-line 可用的众多 XML pretty-printers 之一轻松解决。 This 是一个 (non-exhaustive) 列表,列出了从这里到哪里去。
例如,让我们选择 tidy。
有了这个配置
xq -x '…' pom.xml |
tidy -xml -iq -utf8 --indent-with-tabs yes --indent-spaces 4 --tab-size 4 \
--indent-attributes yes --add-xml-decl yes
你会达到
<?xml version="1.0"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>2.0.1</version>
</parent>
</project>
就我所见,这仍然缺少 top-line 声明中的 encoding="UTF-8"
(整洁拒绝打印 obvious 声明),以及属性的缩进仍然减少了 1 个字符。如果这仍然是一个问题,请尝试与其他 pretty-printers 一起玩。很有可能您会找到适合完美收尾的那个。
假设我有一个 pom.xml 包含这样的父依赖项:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
</project>
有没有一种方法可以通过脚本以编程方式替换 1.0.0-SNAPSHOT
版本?
我的用例:
- 我有很多 pom.xml 文件需要更改 的父版本
- 我正在使用 git-xargs 跨多个存储库进行更改,因此我可以对每个 pom.xml 应用一个 bash 脚本来更改它。
例如,我可以执行以下操作,但这将更新 pom.xml 中出现的所有 1.0.0-SNAPSHOT
,我想将其限制为仅 some-parent
工件有一个版本 1.0.0-SNAPSHOT
:
git-xargs \
--branch-name test-branch \
--github-org <your-github-org> \
--commit-message "Update pom.xml" \
sed -i 's/1.0.0-SNAPSHOT/2.0.1/g' pom.xml
根据 git-xargs 文档,我可以使用任何类型的脚本来处理 pom.xml、bash、python、ruby等:https://github.com/gruntwork-io/git-xargs#how-to-supply-commands-or-scripts-to-run
更新:
以下 xmlstarlet 方法在一定程度上起作用:
if [[ $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:artifactId' pom.xml) == "some-parent" && $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:version' pom.xml) == "1.0.0-SNAPSHOT" ]]; then xmlstarlet edit -L -N my=http://maven.apache.org/POM/4.0.0 --update '//my:project/my:parent/my:version' --value '2.0.6' pom.xml; fi
xmlstarlet 正确更新了我想要的 xml 元素,但它也重新排序了顶部的 xsi:schemaLocation
、xmlns
和 xmlns:xsi
我的档案。
它更新自:
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
至:
<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/xsd/maven-4.0.0.xsd">
这对我不利。
虽然您可以将 --if
和 --else
用于 xmlstarlet sel
(例如参见 [=22=]),但我认为您不能将它们用于 xmlstarlet ed
.我几乎从不使用 xmlstarlet
,所以我不太确定。
这意味着您必须在 Bash...
$ if [[ $(xmlstarlet sel -t -v 'parent/version' pom.xml) == "1.0.0-SNAPSHOT" ]]
then xmlstarlet ed -O -u 'parent/version' -v 2.0.1 pom.xml
fi
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>2.0.1</version>
</parent>
与xidel:
$ xidel -s pom.xml -e '
if (parent/version = "1.0.0-SNAPSHOT")
then x:replace-nodes(parent/version/text(),"2.0.1")
else .
' --output-node-format=xml
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>2.0.1</version>
</parent>
如果您希望输出包含 XML 声明,对于 xmlstarlet
删除 -O
选项,对于 xidel
使用 --output-format=xml
代替。
这有效,结合使用了 xmlstarlet 和 mvn:
#! /usr/bin/env bash
if [[ $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:artifactId' pom.xml) == "some-parent" && \
$(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:version' pom.xml) == "4.0.0-SNAPSHOT" ]]; then
mvn versions:update-parent -DparentVersion=[4.0.0-661]
mvn versions:commit
fi
您应该避免使用 xml 作为纯文本文件,但如果您没有其他选择,您可以尝试一下。 sed
范围 (/starting-regex/,/ending-regex/{commands}
) 允许在特定上下文中限制您的替换。 IE。这条线:
sed -e '/<parent/,/\/parent/{/artifactId>some-parent/,/parent/{s/1.0.0-SNAPSHOT/2.0.0-SNAPSHOT/g}}'
将仅替换
你可以使用 xq.
只需将某个元素设置为新值就和
一样简单xq -x '.project.parent.version = "2.0.1"' pom.xml
按条件设置为
xq -x '(.project.parent | select(
.artifactId == "some-parent" and .version == "1.0.0-SNAPSHOT"
)).version = "2.0.1"' pom.xml
输入样本数据,两者都会产生
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>2.0.1</version>
</parent>
</project>
如您所见,属性的 order 保持不变,但是 indentation 不同,尤其是您的 in-tag 换行符被吞掉了。此外,缺少 XML 声明(第一行),评论,如果存在于输入中。也许这对你也不可行,但请考虑
- 编辑逻辑结构(而不是其文本表示)较少error-prone,
- 所有这些问题(当然,缺少的注释除外)都可以使用 command-line 可用的众多 XML pretty-printers 之一轻松解决。 This 是一个 (non-exhaustive) 列表,列出了从这里到哪里去。
例如,让我们选择 tidy。
有了这个配置
xq -x '…' pom.xml |
tidy -xml -iq -utf8 --indent-with-tabs yes --indent-spaces 4 --tab-size 4 \
--indent-attributes yes --add-xml-decl yes
你会达到
<?xml version="1.0"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>some-parent</artifactId>
<version>2.0.1</version>
</parent>
</project>
就我所见,这仍然缺少 top-line 声明中的 encoding="UTF-8"
(整洁拒绝打印 obvious 声明),以及属性的缩进仍然减少了 1 个字符。如果这仍然是一个问题,请尝试与其他 pretty-printers 一起玩。很有可能您会找到适合完美收尾的那个。