在上一个教程中,你已经看到如何处理两个简单项目之间的依赖。
这个教程将引导你完成在一个更加复杂的环境下的ivy使用。这个教程的所有源文件在ivy发行包的src/example/multi-project下可以得到。
1) 上下文
这里是这个教程涉及到得项目的概况:
* version 帮助通过版本列表来标识模块
* list 获取目录下的文件列表(递归地)
* size 获取目录下的所有文件或者一个文件集合的总大小
* find 在一个给定目录或者文件列表之间查找匹配给定名称的文件
* sizewhere 给出在一个目录下配置名称的文件的总大小
* console 通过简单的控制台应用提供入口给所有其他模块特性
可以肯定的是这不是旨在展示如何开发一个复杂的应用或者提供高级算法的指示。
而是给出一个简单的理解,关于ant + ivy如何使用来开发一个被分割为多个模块的应用。
现在,这是这些模块如何关联到其他模块:
黄色的模块是在这个教程中要讲述的模块,而蓝色的模块是外部依赖(我们将在这个教程中看到如何生成这个图形)。
如你所见,我们在这里有一个优美关联的彼此相互依赖的模块,每个都依赖其他的最新版本。
2) 示例文件
这个教程的源文件可以在ivy发行包的src/example/multi-project下找到。在这个目录中,你将发现下面的文件:
* build.xml
这是根构建文件,将被所有模块用来调用target,按照他们的依赖的顺序(例如,确保在一个模块的构建通常在任何依赖它的模块之
前)
* common
o common.xml
每个项目的build.xml都会导入的通用构建文件。这个构建定义了被所有项目使用的target。
o build.properties
对所有项目通用的一些属性
* projects
包含所有模块,每个模块一个目录,每个目录下
o ivy.xml
模块的ivy文件,描述它的对其他模块和/或外部模块的依赖。
例如:
<ivy-module version="1.0">
<info
organisation="org.apache.ivy.example"
module="find"
status="integration"/>
<configurations>
<conf name="core"/>
<conf name="standalone" extends="core"/>
</configurations>
<publications>
<artifact name="find" type="jar" conf="core" />
</publications>
<dependencies>
<dependency name="version" rev="latest.integration" conf="core->default" />
<dependency name="list" rev="latest.integration" conf="core" />
<dependency org="commons-collections" name="commons-collections" rev="3.1" conf="core->default" />
<dependency org="commons-cli" name="commons-cli" rev="1.0" conf="standalone->default" />
</dependencies>
</ivy-module>
o build.xml
项目的构建文件,主要由一个common构建文件和一个项目特殊属性文件的导入组成:
<project name="find" default="compile">
<property file="build.properties"/>
<import file="${common.dir}/common.xml"/>
</project>
o build.properties
模块特殊属性 + 查找通用构建文件的属性
projects.dir = ${basedir}/..
wkspace.dir = ${projects.dir}/..
common.dir = ${wkspace.dir}/common
o src
源文件目录,有所有java源文件
注意这里不展示通常的软件开发的良好实践,尤其是你将发现在这些例子中没有任何单元测试,即使我们认为单元测试非常重要。但是这不是这个教程的目标。
现在你对结构有一点更多的了解了,让我们看一下这个教程最重要的部分:通用构建文件。实际上,你已经看到,所有模块的构建文件都仅仅是导入这个通用构建文件,并在他们的ivy文件(你应该开始熟悉)中定义他们的依赖。
因此,这里是这个通用构建文件的一些方面:
1. ivy 设置
<!-- setup ivy default configuration with some custom info -->
<property name="ivy.local.default.root" value="${repository.dir}/local"/>
<property name="ivy.shared.default.root" value="${repository.dir}/shared"/>
<!-- here is how we would have configured ivy if we had our own ivysettings file
<ivy:settings file="${common.dir}/ivysettings.xml" id="ivy.instance" />
-->
这个声明只为ivy配置了两个属性: 本地仓库的位置和共享仓库的位置。这是仅为这里进行的配置,因为ivy默认是配置为在团队环境下工作(关于这个的详情请看默认配置教程)。可以肯定的是在实际环境中共享仓库位置将会是在团队共享目录(或者在一个更加复杂的仓库中,再次查看默认设置教程来了解如何使用实际上不同的东西)。你可以从注释中看到如果默认设置不符合你的目标时如何进行设置。
2. 解析依赖
<target name="resolve" depends="clean-lib, load-ivy" description="--> resolve and retrieve dependencies with ivy">
<mkdir dir="${lib.dir}"/> <!-- not usually necessary, ivy creates the directory IF there are dependencies -->
<!-- the call to resolve is not mandatory, retrieve makes an implicit call if we don't -->
<ivy:resolve file="${ivy.file}"/>
<ivy:retrieve pattern="${lib.dir}/[artifact].[ext]" />
</target>
你应该开始熟悉这种ivy的使用方法。我们显式调用resolve来使用ivy文件配置(默认就足够了),然后调用retrieve来从缓存中复制解析的依赖制品到本地lib目录(不带版本号),在IDE中这样使用非常简单,当制品版本更改时IDE配置不会改变。
3. ivy-new-version
<target name="ivy-new-version" depends="load-ivy" unless="ivy.new.revision">
<!-- default module version prefix value -->
<property name="module.version.prefix" value="${module.version.target}-dev-b" />
<!-- asks to ivy an available version number -->
<ivy:info file="${ivy.file}" />
<ivy:buildnumber
organisation="${ivy.organisation}" module="${ivy.module}"
revision="${module.version.prefix}" defaultBuildNumber="1" revSep=""/>
</target>
这个target使用ivy来查找模块的新版本。为了获取关于我们正在处理的模块的详情,我们直接使用在ivy文件中通过ivy:info任务找到的信息。然后buildnumber 任务用来获取一个新的版本,基于我们通过属性设置前缀,默认它将会是1.0-dev-b(在通用构建属性文件中看一下module.version.target的默认值)。每个被这个通用构建文件构建的模块都可以很容易的通过在它的模块特有的build.properties中设置一个不同的module.version.target,或者设置覆盖module.version.prefix.来覆盖这个。为了获取新的修订版本,ivy扫描仓库来获取最新的带有给定前缀的可用版本,并在这个版本上增加1.
4. publish
<target name="publish" depends="clean-build, jar" description="--> publish this project in the ivy repository">
<ivy:publish artifactspattern="${build.dir}/[artifact].[ext]"
resolver="shared"
pubrevision="${version}"
status="release"
/>
<echo message="project ${ant.project.name} released with version ${version}" />
</target>
这个target在共享仓库中发布模块,使用在version属性中找到的修订版本,这是在其他target中设置的(在上面我们已经看到是基于ivy-new-version)。当模块到达一个特定的里程碑时,或者任何你想团队可以从模块的一个新版本中获益的时它可以被使用。
5. publish-local
<target name="publish-local" depends="local-version, jar" description="--> publish this project in the local ivy
repository">
<ivy:publish artifactspattern="${build.dir}/[artifact].[ext]"
resolver="local"
pubrevision="${version}"
pubdate="${now}"
status="integration"
forcedeliver="true"
/>
<echo message="project ${ant.project.name} published locally with version ${version}" />
</target>
这个和publish任务非常相像,除了这个是在本地仓库中发布修订版本,这仅仅在你的环境下使用不会打扰团队。当你在一个模块中修改一些东西并且想在其他模块中从这些修改中获益,你可以简单的调用在这个模块中调研用publish-local,然后你的其他模块的下一次构建将自动得到这个本地版本。
6. clean-local
<target name="clean-local" description="--> cleans the local repository for the current module">
<delete dir="${ivy.local.default.root}/${ant.project.name}"/>
</target>
这个target在当你不想再使用你的本地版本时使用,例如当你发型一个新的版本到整个团队时,或者抛弃你的本地修改并想从团队的新版本中获益时。
7. report
<target name="report" depends="resolve" description="--> generates a report of dependencies">
<ivy:report todir="${build.dir}"/>
</target>
同时生成html报告和图形报告。
例如,为了生成类似这个教程开头展示的那样的图形,你仅仅需要遵循这里给出的说明,graphml文件你将在这里找到
projects/console/build/
在项目的控制台调用report之后,就这样,你得到了所有你的应用的依赖的清晰的概况。
3) Playing with the projects
你可以使用正规ant命令来玩这个教程。在这个教程的基础目录(src/example/multi-project)下开始,运行ant -p:
Buildfile: build.xml
Main targets:
clean clean tutorial: delete repository, ivy cache, and all projects
clean-all clean all projects
publish-all compile, jar and publish all projects in the right order
这里给出你可以在这里做什么的注意。为了确认所有你的模块在你的仓库中都至少发布了一个版本(被依赖于其他模块的模块构建要求),你可以运行ant publish-all (
这里是示例的日志)。
你将可以看到ivy在所有模块上调用publish target,按照依赖的顺序,因此被依赖的总是在依赖它的前面构建和发布。随意修改一个模块的源文件(例如修改一个方法名称)和使用这个方法的模块,然后调用publish-all看被依赖的是如何首先编译,发布,然后依赖它的模块可以得到它并成功编译。
然后你可以进入示例项目目录的其中一个(如 projects/find for instance),并运行ant -p:
Buildfile: build.xml
Main targets:
clean --> clean the project
clean-build --> clean the project built files
clean-lib --> clean the project libraries directory (dependencies)
clean-local --> cleans the local repository for the current module
compile --> compile the project
jar --> make a jar file for this project
publish --> publish this project in the ivy repository
publish-local --> publish this project in the local ivy repository
report --> generates a report of dependencies
resolve --> resolve and retrieve dependencies with ivy
run --> compile and run the project
Default target: compile
你可以看到可用的target,感谢common.xml构建文件的导入。通过调用resolve, publish玩这个项目,并且当你在其他项目中同样做后
看发生了什么。举例来说一个有趣的事情是修改项目的依赖:如果现在模块版本依赖于一个新的通用类库,你将看到一旦这个版本的项目被发布,所有其他依赖于版本的项目都将得到这个类库作为他们间接依赖的一部分。非常简单!如果一个项目引入一些新变化导致依赖于它的项目不稳定,你可以非常简单的修改依赖它的项目的依赖,从latest.integration 到一个固定的稳定版本(可能是这个修改之前的最后版本)。现在保持你的模块可控式非常容易的!
你将非常熟悉使用ivy进行多项目开发,我们希望你能欣赏它的能力和弹性!这些教程仅仅是你的ivy旅程的开始,游览
参考文档来学习关于这些特性的更多内容,加入
邮件列表来分享你的经验并在社区中提问。浏览源文件,打开jira问题,提交补丁,加入并帮助ivy成为最好的依赖管理工具!