maven-2 생성 - Maven 프로젝트 버전을 bash 명령 행으로 가져 오는 방법




리눅스 빌드 (19)

나는 여기에 다른 답변을 사용할 때 부작용에 빠지기 때문에 여기 또 다른 대안이있다.

version=$(printf 'VER\t${project.version}' | mvn help:evaluate | grep '^VER' | cut -f2)

이전 Maven 프로젝트 vesion을 커맨드 라인 에서 새로운 문제 로 바꾸는 방법에 대한 질문을했습니다.

이전 버전에서는 grep 및 명령 행 (bash)에서 구문 분석하기 쉬운 특성으로 버전이 저장되었으므로 버전 번호를 얻을 수있었습니다. 이제는 pom.xml 요소가이 용도로 사용되었으므로 더 이상 모든 종속성과 일부 다른 것들이 이것을 사용하므로 고유하지 않습니다. 나는 xml을 파싱하거나 매우 context-aware sed 명령을 구문 분석하기위한 외부 도구 없이 bash 스크립트로 현재 버전 번호를 얻는 방법이 없다고 생각한다.

저의 의견에 가장 깨끗한 해결책은 Maven이이 버전 정보를 나눠 주도록하는 것입니다. 다른 속성을 검색하기위한 커스텀 메이븐 플러그인을 작성할 생각 이었지만 여기서 먼저 물어볼 것이라고 생각했습니다.

그래서, ${project.version} 의 값을 명령 행으로 가져 오는 쉬운 방법이 있습니까? 미리 감사드립니다.

해결책

도움을 주셔서 감사합니다. 수동으로 디렉토리로 이동해야했지만 쉽게 할 수 있습니다. 내 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)

희망이 사람을 도움이됩니다.


나는 약간의 가짜 Downloaded: 라인이 원래의 할당을 깨고 출력에 들어오는 것을 알아 차렸다. 여기에 내가 정착 한 필터가있다. 도움이되기를 바랍니다!

version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n')

편집하다

100 % 확신 할 수는 없지만 Jenkins의 포스트 빌드 스크립트를 통해이를 실행하면 출력이 [INFO]version 으로 나오고 있습니다 (예 : [INFO]0.3.2 .

출력물을 파일에 버리고 BASH의 첫 번째 필터를 통해 직접 실행 했으므로 Jenkins에서 무슨 일이 벌어지고 있는지 확실하지 않습니다.

젠킨스에서 100 % 얻으려면 후속 sed 필터를 추가했습니다. 여기 내 최신의

version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n' | sed -E 's/\[.*\]//g')

편집하다

마지막으로 여기에서 한 가지 메모를 해 /r/n0.3.2 tr여전히 /r/n0.3.2 와 같은 결과를 /r/n0.3.2 (Jenkins를 경유했을 때만). awkawk 문제는 사라졌습니다! 나의 최종 결과

mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version \
| egrep -v '^\[|Downloading:' | sed 's/[^0-9\.]//g' | awk 1 ORS=''

이렇게하면 로그 항목을 출력에서 ​​제거 할 필요가 없습니다.

mvn -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive exec:exec -q

임시 파일에 버전을 쓰는 것을 꺼려한다면 grep / sed가없는 다른 해결책이 나와 잘 작동합니다. ( 편집 : 어떤 임시 파일 번거 로움없이 훨씬 간단한 솔루션 rjrjr의 답변 을 참조하십시오)

echo 바이너리와 함께 Exec Maven Plugin 을 사용합니다. Maven 도움말 플러그인과는 달리, Exec 플러그인은 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"

나는 나를 위해 올바른 균형을 발견했다. mvn package 후 maven-archiver 플러그인은 다음과 같은 내용으로 target/maven-archiver/pom.properties 을 생성합니다.

version=0.0.1-SNAPSHOT
groupId=somegroup
artifactId=someArtifact

나는 그것을 실행하기 위해 bash만을 사용하고있다.

. ./target/maven-archiver/pom.properties

그때

echo $version
0.0.1-SNAPSHOT

물론이 파일을 실행하는 것은 전혀 안전하지 않지만 실행을 perl 또는 bash 스크립트로 쉽게 변환하여 해당 파일의 환경 변수를 읽고 설정할 수 있습니다.


당신은 mvn 에게 답을 주거나 (대부분의 대답이 제시하는 것처럼) pom.xml 에서 대답을 추출합니다. 두 번째 접근법의 유일한 단점은 <version/> 태그의 값을 매우 쉽게 추출 할 수 있지만 리터럴 , 즉 Maven 속성이 아닌 경우에만 의미가 있다는 것입니다. 어쨌든 다음과 같은 이유로이 방법을 선택했습니다.

  • mvnmvn 표시하는 방법이며 출력을 필터링하는 것을 좋아하지 않습니다.
  • mvn 시작하는 것은 pom.xml 을 읽는 것과 비교할 때 매우 느립니다.
  • 나는 항상 <version/> 에서 리터럴 값을 사용한다.

mvn-versionxmlstarlet 을 사용하여 pom.xml 을 읽고 프로젝트 버전 (존재하는 경우) 또는 상위 프로젝트 버전 (존재하는 경우)을 인쇄하는 zsh 쉘 스크립트입니다.

$ 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

내 기계의 차이는 2 배 이상입니다.


Maven Help Plugin 은 어떻게 든 이것을 이미 제안하고 있습니다 :

  • help:evaluate 은 대화 형 모드에서 사용자가 지정한 Maven 표현식을 평가합니다.

다음은 ${project.version} 을 얻기 위해 명령 행에서 호출하는 방법입니다.

mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
    -Dexpression=project.version

mvn help:evaluate -Dexpression=project.version | sed -e 1h -e '2,3{H;g}' -e '/\[INFO\] BUILD SUCCESS/ q' -e '1,2d' -e '{N;D}' | sed -e '1q'

나는 최근에 maven 출력에서 project.version 을 추출하기 위해 구현 한 작은 sed 필터 개선을 추가하고 있습니다.


Exec 출력 플러그인은 EnvInject 플러그인을 통해 출력을 파일로 리디렉션하고 작업 환경에 다시 주입 할 수 있기 때문에 출력 파싱없이 작동합니다.


이것은 나를 위해, 오프라인 및 mvn에 의존하지 않고 일했습니다.

VERSION=$(grep --max-count=1 '<version>' <your_path>/pom.xml | awk -F '>' '{ print $2 }' | awk -F '<' '{ print $1 }')
echo $VERSION

가장 큰 대답은 제 의견으로는 꽤 쓰레기입니다. 여러분은 maven 콘솔 출력을 해킹하기 위해 grep을 사용해야합니다. 왜 직장에 맞는 도구를 사용하지 않습니까? xpath 구문을 사용하는 것이 XML 데이터 구조에 액세스하기위한 의도 된 방법이므로 버전 번호를 검색하는 가장 좋은 방법입니다. 아래 표현식은 요소의 "로컬 이름"을 사용하여 pom을 탐색합니다. 즉 xml에 존재하거나 존재하지 않을 수있는 네임 스페이스 선언을 무시합니다.

xmllint --xpath "//*[local-name()='project']/*[local-name()='version']/text()" pom.xml


최근에이 정확한 문제를 해결하는 릴리스 후보 메이븐 플러그인을 개발하여 해킹 셸 스크립트에 의존하지 않고 maven-help-plugin 의 출력을 구문 분석 할 필요가 없도록했습니다.

예를 들어 Maven 프로젝트 버전을 터미널에 인쇄하려면 다음을 실행하십시오.

mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version

maven-help-plugin 과 유사한 출력을줍니다 :

[INFO] Detected version: '1.0.0-SNAPSHOT'
1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

그러나 임의의 출력 형식을 지정할 수도 있습니다 (버전이 TeamCity 와 같은 CI 서버에 의해 로그에서 선택 될 수 있도록).

mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
   -DoutputTemplate="##teamcity[setParameter name='env.PROJECT_VERSION' value='{{ version }}']"

어떤 결과 :

[INFO] Detected version: '1.0.0-SNAPSHOT'
##teamcity[setParameter name='env.PROJECT_VERSION' value='1.0.0-SNAPSHOT']
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Jenkins 와 같은 CI 서버가 사용할 수 있도록 출력을 파일에 저장하려면 다음을 수행하십시오.

mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
   -DoutputTemplate="PROJECT_VERSION={{ version }}" \
   -DoutputUri="file://\${project.basedir}/version.properties"

결과 version.properties 파일은 다음과 같습니다.

PROJECT_VERSION=1.0.0-SNAPSHOT

위의 모든 것 외에도 Release Candidate 에서는 POM에 정의한 API 버전에 따라 프로젝트 버전 (CI 서버에서 수행 할 수있는 작업)을 설정할 수 있습니다.

Maven 라이프 사이클의 일부로 사용되는 Release Candidate의 예제를 보려면 다른 오픈 소스 프로젝트 인 Build Monitor for Jenkinspom.xml 을 살펴보십시오.


python -c "import xml.etree.ElementTree as ET; \
  print(ET.parse(open('pom.xml')).getroot().find( \
  '{http://maven.apache.org/POM/4.0.0}version').text)"

당신이 파이썬 2.5 이상을 가지고있는 한, 이것이 효과가있다. 그것보다 낮은 버전을 가지고 있다면 python-lxml 설치하고 가져 오기를 lxml.etree로 변경하십시오. 이 방법은 빠르며 추가 플러그인을 다운로드 할 필요가 없습니다. 또한 구문 분석 할 필요가있는 것과 같이 xmllint로 유효성을 검사하지 않는 잘못된 형식의 pom.xml 파일에서도 작동합니다. Mac 및 Linux에서 테스트되었습니다.


Exec Maven Plugin을 사용한 Tom의 솔루션은 훨씬 뛰어 났지만 필요 이상으로 복잡합니다. 나에게 그것은 간단하다.

set -o errexit

MVN_VERSION=$(mvn -q \
    -Dexec.executable=echo \
    -Dexec.args='${project.version}' \
    --non-recursive \
    exec:exec)

VERSION=$(head -50 pom.xml | awk -F'>' '/SNAPSHOT/ {print $2}' | awk -F'<' '{print $1}')

이것은 내가 버전 번호를 얻는데 사용했던 것입니다. 그렇게하는 것이 더 좋은 방법 일 것이라고 생각했습니다.


mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['

Maven 바닥 글은 꽤 표준 적입니다.

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.609s
[INFO] Finished at: Wed May 21 18:02:38 MSK 2014
[INFO] Final Memory: 17M/736M
[INFO] ------------------------------------------------------------------------

따라서 다음 코드를 사용할 수 있습니다.

> version=$(mvn help:evaluate -Dexpression=project.version | tail -8 | head -1)
> echo $version

이것이 도움이된다면 Dunno. 주석으로 코드 서식을 지정하는 방법을 모르므로 응답으로 게시 됨 (도움?)

무료 파스칼 컴파일러를 찾을 수 있다면, 이것을 컴파일하거나 이메일을 보내서 & nbsp; 하나를 파헤 치거나 exe 메일을 보내거나 어딘가에 게시 할 수 있습니다. 적어도 코드가 작동하고 필요한 알고리즘을 보여주기 때문에 코드를 게시합니다.

program Whence (input,output);
  Uses Dos, my_funk;
  Const program_version = '1.00';
        program_date    = '17 March 1994';
  VAR   path_str          : string;
        command_name      : NameStr;
        command_extension : ExtStr;
        command_directory : DirStr;
        search_dir        : DirStr;
        result            : DirStr;


  procedure Check_for (file_name : string);
    { check existance of the passed parameter. If exists, then state so   }
    { and exit.                                                           }
  begin
    if Fsearch(file_name,'') <> '' then
    begin
      WriteLn('Dos command = ',Fexpand(file_name));
      Halt(0);    { structured ? whaddayamean structured ? }
    end;
  end;

  function Get_next_dir : DirStr;
    { Returns the next directory from the path variable, truncating the   }
    { variable every time. Implicit input (but not passed as parameter)   }
    { is, therefore, path_str                                             }
    var  semic_pos  : Byte;

  begin
      semic_pos  := Pos(';',path_str);
      if (semic_pos = 0) then
      begin
        Get_next_dir := '';
        Exit;
      end;

      result       := Copy(Path_str,1,(semic_pos - 1));  { return result   }
      { hmm! although *I* never reference a Root drive (my directory tree) }
      { is 1/2 way structured), some network logon software which I run    }
      { does (it adds Z:\ to the path). This means that I have to allow    }
      { path entries with & without a terminating backslash. I'll delete   }
      { anysuch here since I always add one in the main program below.     }
      if (Copy(result,(Length(result)),1) = '\') then
         Delete(result,Length(result),1);

      path_str     := Copy(path_str,(semic_pos + 1),
                                 (length(path_str) - semic_pos));
      Get_next_dir := result;
  end;  { of function get_next_dir }

begin
  { the following is a kludge which makes the function Get_next_dir easier  }
  { to implement. By appending a semi-colon to the end of the path         }
  { Get_next_dir doesn't need to handle the special case of the last entry }
  { which normally doesn't have a semic afterwards. It may be a kludge,    }
  { but it's a documented kludge (you might even call it a refinement).    }
  path_str := GetEnv('Path') + ';';

  if (paramCount = 0) then
  begin
    WriteLn('Whence : V',program_version,' from ',program_date);
    Writeln;
    WriteLn('Usage  : WHENCE command[.extension]');
    WriteLn;
    WriteLn('Whence is a ''find file''type utility witha difference');
    Writeln('There are are already more than enough of those   :-)');
    Write  ('Use Whence when you''re not sure where a command which you ');
    WriteLn('want to invoke');
    WriteLn('actually resides.');
    Write  ('If you intend to invoke the command with an extension e.g ');
    Writeln('"my_cmd.exe param"');
    Write  ('then invoke Whence with the same extension e.g ');
    WriteLn('"Whence my_cmd.exe"');
    Write  ('otherwise a simple "Whence my_cmd" will suffice; Whence will ');
    Write  ('then search the current directory and each directory in the ');
    Write  ('for My_cmd.com, then My_cmd.exe and lastly for my_cmd.bat, ');
    Write  ('just as DOS does');
    Halt(0);
  end;

  Fsplit(paramStr(1),command_directory,command_name,command_extension);
  if (command_directory <> '') then
  begin
WriteLn('directory detected *',command_directory,'*');
    Halt(0);
  end;

  if (command_extension <> '') then
  begin
    path_str := Fsearch(paramstr(1),'');    { current directory }
    if   (path_str <> '') then WriteLn('Dos command = "',Fexpand(path_str),'"')
    else
    begin
      path_str := Fsearch(paramstr(1),GetEnv('path'));
      if (path_str <> '') then WriteLn('Dos command = "',Fexpand(path_str),'"')
                          else Writeln('command not found in path.');
    end;
  end
  else
  begin
    { O.K, the way it works, DOS looks for a command firstly in the current  }
    { directory, then in each directory in the Path. If no extension is      }
    { given and several commands of the same name exist, then .COM has       }
    { priority over .EXE, has priority over .BAT                             }

    Check_for(paramstr(1) + '.com');     { won't return if file is found }
    Check_for(paramstr(1) + '.exe');
    Check_for(paramstr(1) + '.bat');


    { not in current directory, search thru path .... }

    search_dir := Get_next_dir;

    while (search_dir <> '') do
    begin
       Check_for(search_dir + '\' + paramstr(1) + '.com');
       Check_for(search_dir + '\' + paramstr(1) + '.exe');
       Check_for(search_dir + '\' + paramstr(1) + '.bat');
       search_dir := Get_next_dir;
    end;


    WriteLn('DOS command not found : ',paramstr(1));
  end;
end.




maven-2 command-line