Home | 簡體中文 | 繁體中文 | 雜文 | 知乎專欄 | Github | OSChina 博客 | 雲社區 | 雲棲社區 | Facebook | Linkedin | 視頻教程 | 打賞(Donations) | About
知乎專欄多維度架構 | 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者”

第 2 章 Build Tools

目錄

2.1. Apache Ant
2.1.1. 安裝 ant
2.1.1.1. 1.8
2.1.1.2. 1.10.1
2.1.2. ANT
2.1.2.1. ant.project.name
2.1.2.2. 定義
2.1.3. Project
2.1.3.1. property
2.1.3.2. ant
2.1.3.3. environment
2.1.4. path
2.1.5. copy
2.1.6. javac
2.1.7. condition
2.1.8. exec
2.1.8.1. sshexec
2.1.9. if
2.1.10. macrodef
2.1.10.1. Git
2.1.10.2. Rsync
2.1.10.3. SSH
2.1.10.4. maven
2.1.11. Javascript
2.1.12. mail
2.1.13. basename
2.1.14. FAQ
2.1.14.1. warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
2.1.14.2. 調試 exec
2.2. Apache Ivy
2.2.1. Ivy Install
2.2.1.1. source code
2.2.1.2. apt-get
2.2.2. Test example
2.3. Apache Maven
2.3.1. 安裝 Maven
2.3.1.1. CentOS 8 安裝 Maven
2.3.1.2. Ubuntu
2.3.1.3. 源碼安裝
2.3.2. Maven 命令
2.3.2.1. 參數
2.3.2.2. -s 指定 settings.xml 檔案
2.3.2.3. help
2.3.2.4. archetype:create
2.3.2.5. clean
2.3.2.6. compile
2.3.2.6.1. 多綫程編譯
2.3.2.7. 編譯測試代碼
2.3.2.8. test
2.3.2.9. package
2.3.2.10. install
2.3.2.10.1. install-file
2.3.2.11. war
2.3.2.12. exec
2.3.2.13. dependency
2.3.2.13.1. build-classpath
2.3.2.13.2. dependency:tree 顯示包依賴樹
2.3.2.13.3. copy-dependencies 導出依賴包
2.3.2.13.4. analyze 查看未被使用的包
2.3.2.13.5. sources 下載源碼
2.3.2.14. jar
2.3.2.15. 構建裝配Maven Assembly
2.3.2.16. 加密密碼
2.3.2.17. help:describe
2.3.3. Maven 倉庫
2.3.4. pom.xml
2.3.4.1. properties
2.3.4.1.1. java.version
2.3.4.2. repositories 倉庫配置
2.3.4.2.1. 預設倉庫
2.3.4.2.2. 阿里雲倉庫
2.3.4.3. dependencies
2.3.4.4. dependencyManagement
2.3.4.5. build
2.3.4.5.1. finalName
2.3.4.5.2. sourceDirectory
2.3.4.5.3. resources 檔案處理
2.3.4.6. plugins
2.3.4.6.1. 跳過Unit test
2.3.4.6.2. maven-shade-plugin
2.3.5. Maven Module
2.3.5.1. Parent
2.3.5.2. 公共項目 common
2.3.5.3. 常規項目
2.3.5.4. 現在測試效果
2.3.6. 依賴管理
2.3.6.1. 創建依賴模組
2.3.6.2. 引用依賴管理
2.3.7. plugins
2.3.7.1. maven-compiler-plugin
2.3.7.2. maven-war-plugin
2.3.7.3. maven-antrun-plugin
2.3.7.4. maven-install-plugin
2.3.7.5. maven-surefire-plugin
2.3.7.6. maven-deploy-plugin
2.3.7.7. maven-jar-plugin
2.3.7.8. maven-dependency-plugin
2.3.7.9. spring-boot-maven-plugin
2.3.7.10. tomcat8-maven-plugin
2.4. Gradle 5
2.4.1. 安裝 Gradle
2.4.1.1. CentOS
2.4.1.2. Mac
2.4.2. Example
2.4.3. gradle 命令
2.4.3.1. tasks 列出任務
2.4.4. build.gradle
2.4.4.1. repositories
2.4.4.2. dependencies
2.4.4.3. jar
2.4.5. gradle.properties
2.4.5.1. 列出 properties
2.4.5.2. 自定義 gradle.properties
2.4.5.3.
2.4.5.4. System.properties
2.5. JitPack - Easy to use package repository for Git
2.6. Artifactory
2.6.1. Artifactory Web UI
2.6.2. build.gradle

2.1. Apache Ant

http://ant.apache.org/

2.1.1. 安裝 ant

2.1.1.1. 1.8

cd /usr/local/src
wget http://mirror.bjtu.edu.cn/apache//ant/binaries/apache-ant-1.8.1-bin.tar.gz
tar zxvf apache-ant-1.8.1-bin.tar.gz
mv apache-ant-1.8.1 /usr/local/
cd ..
ln -s apache-ant-1.8.1 apache-ant
			
ANT_HOME=/usr/local/apache-ant
export CLASSPATH=$CLASSPATH:$ANT_HOME/lib
			

2.1.1.2. 1.10.1

Netkiller OSCM 一鍵安裝

curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/java/ant/apache-ant-1.10.1.sh | bash
			

2.1.2. ANT

2.1.2.1. ant.project.name

ant.project.name 一般式定義在

			
<project name="www.netkiller.cn" default="compile" basedir="." xmlns:if="ant:if">
<echo>${ant.project.name}</echo>
			
			

我們希望從命令行傳遞這個值

			
<project default="compile" basedir="." xmlns:if="ant:if">
<echo>${ant.project.name}</echo>
			
			

你需要將 project 中的定義去掉才能從命令行傳遞

			
ant -Dant.project.name=www.netkiller.cn -f build.xml
			
			

你也可以從 build.properties 檔案定義 ant.project.name

			
MacBook-Pro:deployment neo$ cat build.properties 
ant.project.name=www.netkiller.cn			
			
			
			
ant -f build.xml -propertyfile build.properties	
			
			

2.1.2.2. 定義

			
			
			

2.1.3. Project

		
<description>project Name</description>
		
		

2.1.3.1. property

在 build.xml 中定義 property

			
<property name="src" value="src"/>
<property name="dest" value="classes"/>
<property name="hello" value="hello.jar"/>		
			
			

引用 properties 檔案

			
<property file="build.properties" />
<propety resource="build.properties"/>
			
			

設置系統的環境變數為首碼

			
<property environment="env"/> 
<property name="tomcat.home" value="${env.CATALINA_HOME}"/> 
			
			

命令行傳值,使用-D參數是會覆蓋build.xml中的先前定義的變數

			
$ ant --help | grep property
  -D<property>=<value>   use value for given property
  -propertyfile <name>   load all properties from file with -D
  

	 		
			

2.1.3.2. ant

Project name

			
${ant.project.name}
			
			

2.1.3.3. environment

			
<property environment="env"/>
<echo message="JAVA_HOME is set to = ${env.JAVA_HOME}" />			
			
			

2.1.4. path

定義

		
	<path id="classpath">  
        <fileset dir="${env.JAVA_HOME}/lib">  
            <include name="*.jar" />  
        </fileset>  
        <fileset dir="${env.CATALINA_HOME}/lib">  
            <include name="*.jar" />  
        </fileset>  
        <fileset dir="WebRoot/WEB-INF/lib" includes="*.jar"/>
    </path>    
		
		

引用

		
	<javac srcdir="${src.dir}" destdir="${classes.dir}" source="1.5" target="1.5">  
		<classpath refid="classpath" />  
	</javac>		
		
		

		
    <classpath>
		<path refid="classpath"/>
    </classpath>		
		
		

2.1.5. copy

複製目錄

		
	<copy todir="${basedir}/WebContent"> 
		<fileset dir="${basedir}/WebRoot" includes="**/*"/>
	</copy>	    
		
		

複製指定副檔名檔案

		
	<copy todir="${dest}">  
		<fileset dir="${src}">  
			<include name="**/*.xml" />  
			<include name="**/*.properties" />  
		</fileset>
	</copy> 	
		
		

2.1.6. javac

		
	<path id="classpath">
		<fileset dir="${env.JAVA_HOME}/lib">
			<include name="*.jar" />
		</fileset>
		<fileset dir="${env.CATALINA_HOME}/lib">
			<include name="*.jar" />
		</fileset>
		<fileset dir="${project.dir}/WebRoot/WEB-INF/lib" includes="*.jar" />
	</path>

	<javac srcdir="${project.src}" destdir="${project.build}/WEB-INF/classes" debug="true" listfiles="true">
			<classpath refid="classpath" />
			<include name="**/*.java"/>
			<exclude name="**/*.xml"/>
			<exclude name="**/*.properties"/>
	</javac>
		
		

listfiles 顯示編譯檔案列表

debug 顯示調試信息,編譯錯誤信息

2.1.7. condition

		
<?xml version="1.0"?>
<project name="test" default="doFoo" basedir=".">
  <property name="directory" value="/www/directory"/>

  <target name="doFoo" depends="dir.check" if="dir.exists">
    <echo>${directory} exists</echo>
  </target>

  <target name="doBar" depends="dir.check" unless="dir.exists">
    <echo>${directory} missing"</echo>
  </target>

  <target name="dir.check">
    <condition property="dir.exists">
      <available file="${directory}" type="dir"/>
    </condition>
  </target>
</project>		
		
		

2.1.8. exec

		
<project name="{{ name }}" default="help" basedir=".">
  
  <property name="username" value="{{ username }}"/>
  <property name="host" value="{{ host }}"/>
  <property name="dir" value="/srv/{{ path }}/"/>

  <tstamp>
    <format property="TODAY_UK" pattern="yyyyMMddhhmmss" locale="en,UK"/>
  </tstamp>

  <target name="help" description="show available commands" >
    <exec executable="ant" dir="." failonerror="true">
      <arg value="-p"/>
    </exec>
  </target>
  
  <target name="deploy-to" description="show where we are deploying to" >
    <echo>${username}@${host}:${dir}</echo>
  </target>

  <target name="deploy" description="deploy usng rsync" >
    <exec executable="rsync" dir="." failonerror="true">
      <arg value="-r"/>
      <arg value="."/>
      <arg value="${username}@${host}:${dir}"/>
      <arg value="--exclude-from=rsync.excludes"/>
      <arg value="-v"/>
    </exec>
  </target>

  <target name="deploy-test" description="test deploy usng rsync with the dry run flag set" >
    <exec executable="rsync" dir="." failonerror="true">
      <arg value="-r"/>
      <arg value="."/>
      <arg value="${username}@${host}:${dir}"/>
      <arg value="--exclude-from=rsync.excludes"/>
      <arg value="--dry-run"/>
      <arg value="-v"/>
    </exec>
  </target>

  <target name="backup" description="backup site" >
    <exec executable="scp" dir="." failonerror="true">
      <arg value="-r"/>
      <arg value="${username}@${host}:${dir}"/>
      <arg value="backups/${TODAY_UK}"/>
    </exec>
  </target>

</project>		
		
		

2.1.8.1. sshexec

			
<sshexec host="${remove}" keyfile="~/.ssh/id_rsa" command="/srv/apache-tomcat/bin/catalina.sh stop -force" />			
			
			

2.1.9. if

		
		
<if>
  <available file="my_directory" type="dir" />
  <then>
    <echo message="Directory exists" />
  </then>
  <else>
    <echo message="Directory does not exist" />
  </else>
</if>		
		
		
		

Ant 1.9.x 新增 xmlns:if="ant:if"

		
<project name="tryit"
 xmlns:if="ant:if"
 xmlns:unless="ant:unless"
>
 <exec executable="java">
   <arg line="-X" if:true="${showextendedparams}"/>
   <arg line="-version" unless:true="${showextendedparams}"/>
 </exec>
 <condition property="onmac">
   <os family="mac"/>
 </condition>
 <echo if:set="onmac">running on MacOS</echo>
 <echo unless:set="onmac">not running on MacOS</echo>
</project>


<!DOCTYPE project>
<project xmlns:if="ant:if" xmlns:unless="ant:unless">
  <property unless:set="property" name="property.is.set" value="false"/>
  <property if:set="property" name="property.is.set" value="true"/>
  <echo>${property.is.set}</echo>
</project>
		
		

2.1.10. macrodef

arg value 與 arg line

arg line 可以處理參數的空格, 而arg value則不能. arg line 可以處理空參數, arg value傳遞空參數會報錯.

		
<exec executable = "sh" dir = "@{dir}">
	<arg line = "ls -l /var/log" />
</exec>


<exec executable = "ls" dir = "@{dir}">
	<arg value = "-l" />
	<arg value = "/var/log" />
</exec>
		
		
		
        <macrodef name="mvn">
                <attribute name="options" default="" />
                <attribute name="goal" default="" />
                <attribute name="phase" default=" " />
                <attribute name="dir" default="" />
                <element name="args" optional="false" />
                <sequential>
                        <exec executable="mvn" dir="@{dir}" >
                                <arg value="@{options}" />
                                <arg value="@{goal}" />
                                <arg value="@{phase}" />
                        </exec>
                </sequential>
        </macrodef>

<!-- 執行下面宏將會出錯,你必須傳遞options,phase參數 -->
<mvn goal="package" dir="${project.dir}"/>
<!-- 將vale改為line後正常 -->
		<exec executable="mvn" dir="@{dir}" >
                                <arg line="@{options}" />
                                <arg line="@{goal}" />
                                <arg line="@{phase}" />
        </exec>
		
		
		

運行方式sequential為順序執行, parallel為並行執行。

2.1.10.1. Git

			
<macrodef name = "git">
    <attribute name = "command" />
    <attribute name = "dir" default = "" />
    <element name = "args" optional = "true" />
    <sequential>
        <echo message = "git @{command}" />
        <exec executable = "git" dir = "@{dir}">
            <arg value = "@{command}" />
            <args/>
        </exec>
    </sequential>
</macrodef>
<macrodef name = "git-clone-pull">
    <attribute name = "repository" />
    <attribute name = "dest" />
    <sequential>
        <git command = "clone">
            <args>
                <arg value = "@{repository}" />
                <arg value = "@{dest}" />
            </args>
        </git>
        <git command = "pull" dir = "@{dest}" />
    </sequential>
</macrodef>
			
			
			
<git command = "clone">
    <args>
        <arg value = "git://github.com/280north/ojunit.git" />
        <arg value = "ojunit" />
    </args>
</git>

<git command = "pull" dir = "repository_path" />		

<git-clone-pull repository="git://github.com/280north/ojunit.git" dest="ojunit" />	
			
			

2.1.10.2. Rsync

			
			
	<macrodef name="rsync">
		<attribute name="option" default="auzv" />
		<attribute name="src" default="" />
		<attribute name="dest" default="" />
		<element name="args" optional="true" />
		<sequential>
			<exec executable="rsync">
				<arg value="@{option}" />
				<arg value="@{src}" />
				<arg value="@{dest}" />
				<args />
			</exec>
		</sequential>
	</macrodef>			
			
			
			
			
	<target name="deploy" depends="compile">
		<rsync option="-auzv" src="${project.dest}" dest="${remote}:${destination}">
			<args>
				<arg value="-P" />
			</args>
		</rsync>
	</target>			
			
			

2.1.10.3. SSH

			
	<macrodef name="ssh">
		<attribute name="host" />
		<attribute name="command" />
		<attribute name="keyfile" default="~/.ssh/id_rsa" />
		<element name="args" optional="true" />
		<sequential>
			<exec executable="ssh">
				<arg value="@{host}" />
				<!-- arg value="-i @{keyfile}" / -->
				<args />
				<arg value="@{command}" />
			</exec>
		</sequential>
	</macrodef>
			
			
			
	<target name="stop" depends="">
		<!-- ssh host="${remote}" command="/srv/apache-tomcat/bin/catalina.sh stop -force" keyfile="~/.ssh/id_rsa" / -->
		<ssh host="${remote}" command="/srv/apache-tomcat/bin/shutdown.sh" />
	</target>
	<target name="start" depends="">
		<ssh host="${remote}" command="/srv/apache-tomcat/bin/startup.sh" keyfile="~/.ssh/id_rsa" />
	</target>		
			
			

2.1.10.4. maven

			
        <macrodef name="mvn">
                <attribute name="options" default="" />
                <attribute name="goal" default="" />
                <attribute name="phase" default=" " />
                <attribute name="dir" default="" />
                <element name="args" optional="false" />
                <sequential>
                        <exec executable="mvn" dir="@{dir}" >
                                <arg line="@{options}" />
                                <arg value="@{goal}" />
                                <arg line="@{phase}" />
                        </exec>
                </sequential>
        </macrodef>			
			
			

2.1.11. Javascript

		

$ cat build.xml 
<project name="Attachments" default="print">
    <property name="numAttachments" value="20" />
    <target name="generate">
        <script language="javascript"><![CDATA[
            var list = '1';
            var limit = project.getProperty( "numAttachments" );
            for (var i=2;i<limit;i++)
            { 
                list = list + ',' + i;
            }
            project.setNewProperty("list", list);            
		print(list);
        ]] >
        </script>    
    </target>
</project>

		
		
		
$ ant generate
Buildfile: /www/testing/build.xml

generate:
   [script] 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19

BUILD SUCCESSFUL
Total time: 0 seconds
		
		

2.1.12. mail

https://ant.apache.org/manual/Tasks/mail.html

		
cp ~/.m2/repository/com/sun/mail/javax.mail/1.5.6/javax.mail-1.5.6.jar /srv/apache-ant-1.9.6/lib
cp /www/.m2/repository/com/sun/mail/javax.mail/1.5.6/javax.mail-1.5.6.jar /srv/apache-ant-1.10.1/lib/
		
		

Examples

		
<mail from="me"
      tolist="you"
      subject="Results of nightly build"
      files="build.log"/>
Sends an email from me to you with a subject of Results of nightly build and includes the contents of the file build.log in the body of the message.

<mail mailhost="smtp.myisp.com" mailport="1025" subject="Test build">
  <from address="config@myisp.com"/>
  <replyto address="me@myisp.com"/>
  <to address="all@xyz.com"/>
  <message>The ${buildname} nightly build has completed</message>
  <attachments>
    <fileset dir="dist">
      <include name="**/*.zip"/>
    </fileset>
  </attachments>
</mail>
		
		

2.1.13. basename

		
<basename property="jar.filename" file="${lib.jarfile}"/>
will set jar.filename to myjar.jar, if lib.jarfile is defined as either a full-path filename (eg., /usr/local/lib/myjar.jar), a relative-path filename (eg., lib/myjar.jar), or a simple filename (eg., myjar.jar).
<basename property="cmdname" file="D:/usr/local/foo.exe"
          suffix=".exe"/>
will set cmdname to foo.
<property environment="env"/>
<basename property="temp.dirname" file="${env.TEMP}"/>
			
		
		

2.1.14. FAQ

2.1.14.1. warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds

includeantruntime="false"

			
<target name="compile" depends="init">
   <javac includeantruntime="false" srcdir="${src}" destdir="${dest}"/>
</target>
			
			

or

			
<property name="build.sysclasspath" value="last"/>
			
			

2.1.14.2. 調試 exec

將 executable="echo" 設置成 echo 是一種不錯的調試手段

			
        <macrodef name="gulp">
                <attribute name="stage" default=""/>
                <attribute name="src" default=""/>
                <attribute name="dir" default="" />
                <sequential>
                        <exec vmlauncher="false" executable="echo" dir="@{dir}" osfamily="unix">
                                <arg line="--stage @{stage} --src @{src}"/>
                                <!-- arg value="stage @{stage}" / -->
                        </exec>
                </sequential>
        </macrodef>

        <target name="gulp">
                <gulp stage="${git.branch}" src="cn" dir="."/>
        </target>