之前我发布了一个关于如何从命令行更改Maven项目版本的问题,这导致我遇到了一个新问题。
以前我能够获得版本号,因为版本存储为一个属性,很容易从命令行(bash)进行grep和解析。现在pom.xml <version>元素用于此,它不再是唯一的,因为所有依赖项(也许其他一些依赖项也使用它)。我认为,如果没有用于解析XML的外部工具或一些非常能感知上下文的sed命令,就无法用bash脚本获得当前版本号。
在我看来,最干净的解决方案是Maven发布这个版本信息。我想写一个自定义的maven插件检索不同的属性,但我想我应该先问这里。
那么,是否有任何简单的方法来获取${project的值。版本}到命令行?
解决方案
我必须手动cd到该目录,但这可以很容易地做到。在我的bash脚本我有:
version=`cd $project_loc && mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | sed -n -e '/^\[.*\]/ !{ /^[0-9]/ { p; q } }'`
这就得到了我可以改进的当前版本。Grepping可能更简单,但我认为我想尽可能健壮,所以我对以数字开头的第一行感到满意,并尝试将其作为版本号处理。
# Advances the last number of the given version string by one.
function advance_version () {
local v=$1
# Get the last number. First remove any suffixes (such as '-SNAPSHOT').
local cleaned=`echo $v | sed -e 's/[^0-9][^0-9]*$//'`
local last_num=`echo $cleaned | sed -e 's/[0-9]*\.//g'`
local next_num=$(($last_num+1))
# Finally replace the last number in version string with the new one.
echo $v | sed -e "s/[0-9][0-9]*\([^0-9]*\)$/$next_num/"
}
我通过调用:
new_version=$(advance_version $version)
在我的特拉维斯工作期间,我需要的正是这个要求,但有多个值。
我从这个解决方案开始,但当调用多次这是非常缓慢的(我需要5个表达式)。
我写了一个简单的maven插件来将pom.xml的值提取到.sh文件中。
https://github.com/famaridon/ci-tools-maven-plugin
mvn com.famaridon:ci-tools-maven-plugin:0.0.1-SNAPSHOT:environment -Dexpressions=project.artifactId,project.version,project.groupId,project.build.sourceEncoding
会产生:
#!/usr/bin/env bash
CI_TOOLS_PROJECT_ARTIFACTID='ci-tools-maven-plugin';
CI_TOOLS_PROJECT_VERSION='0.0.1-SNAPSHOT';
CI_TOOLS_PROJECT_GROUPID='com.famaridon';
CI_TOOLS_PROJECT_BUILD_SOURCEENCODING='UTF-8';
现在您可以简单地获取该文件的源代码
source .target/ci-tools-env.sh
玩得开心。
要么让mvn给出答案(正如大多数答案所建议的那样),要么从pom.xml中提取答案。第二种方法的唯一缺点是可以很容易地提取<version/>标记的值,但只有当它是文字时,即不是Maven属性时,它才有意义。我选择了这种方法,因为:
mvn太啰嗦了,我只是不喜欢过滤它的输出。
与读取pom.xml相比,启动mvn非常慢。
我总是在<version/>中使用文字值。
Mvn-version是一个ZSH shell脚本,它使用xmlstarlet读取pom.xml并打印项目的版本(如果存在)或父项目的版本(如果存在):
$ mvn-version .
1.0.0-SNAPSHOT
优点是它比运行mvn快得多:
$ time mvn-version .
1.1.0-SNAPSHOT
mvn-version . 0.01s user 0.01s system 75% cpu 0.019 total
$ time mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
> -Dexpression=project.version
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate 4.17s user 0.21s system 240% cpu 1.823 total
我的机器上的差异超过两个数量级。
如果您不介意将版本写入临时文件,那么还有另一种解决方案(不含grep/sed)适合我。(编辑:请参阅rjrjr的回答,这是一个更简单的解决方案,没有任何临时文件的麻烦)
我使用Exec Maven插件和echo二进制文件。与Maven Help Plugin相反,Exec Plugin允许输出重定向到文件,可以用来绕过grep/sed,甚至可以解析奇怪的东西,比如多行版本字符串(版本标记中带有CDATA块),至少在一定程度上是这样。
#!/usr/bin/env sh
MVN_VERSION=""
VERSION_FILE=$( mktemp mvn_project_version_XXXXX )
trap "rm -f -- \"$VERSION_FILE\"" INT EXIT
mvn -Dexec.executable="echo" \
-Dexec.args='${project.version}' \
-Dexec.outputFile="$VERSION_FILE" \
--non-recursive \
--batch-mode \
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec > /dev/null 2>&1 ||
{ echo "Maven invocation failed!" 1>&2; exit 1; }
# if you just care about the first line of the version, which will be
# sufficent for pretty much every use case I can imagine, you can use
# the read builtin
[ -s "$VERSION_FILE" ] && read -r MVN_VERSION < "$VERSION_FILE"
# Otherwise, you could use cat.
# Note that this still has issues when there are leading whitespaces
# in the multiline version string
#MVN_VERSION=$( cat "$VERSION_FILE" )
printf "Maven project version: %s\n" "$MVN_VERSION"