5

我有一个使用 Ant 构建的客户端和服务器。客户端依赖于首先构建的服务器才能构建。除了捆绑在客户端中的服务器 ear 文件之外,我拥有所有必需的库。

我创建了 3 个 ant 文件build.xmlbuild-client.xmlbuild-server.xml. (单击任何文件名以查看它们)这些文件包含在其中,build-client.xml以便它可以从中运行目标。build-server.xmlbuild.xml

我遇到的问题是basedir变量从构建文件更改为构建文件。build-client.xml因此,如果我从basedir 变量中运行目标,build.xml则相对于build.xml.

如何在 Ant 脚本中多次更改 basedir 变量?

另外,查看这些构建文件,您是否发现了一种更好的方法来做我想做的事情?现在我在想我必须将客户端战争和服务器耳朵放在同一个位置,然后才能制作最终的捆绑耳朵。我对此的想法可能是有缺陷的,因为这些脚本看起来不必要地复杂。

4

3 回答 3

5

任务的ant 文档<import>您提供了有关如何完成此任务的信息。

根据导入的文件解析文件

假设您的名为 importing.xml 的主构建文件导入了一个构建文件 imports.xml,它位于文件系统的任何位置,imported.xml 从imported.properties 读取一组属性:

<!-- importing.xml -->
<project name="importing" basedir="." default="...">
  <import file="${path_to_imported}/imported.xml"/>
</project>

<!-- imported.xml -->
<project name="imported" basedir="." default="...">
  <property file="imported.properties"/>
</project>

basedir然而,这个片段将根据 importing.xml解析imported.properties ,因为basedirAnt 忽略了imported.xml。使用imported.properties的正确方法是:

<!-- imported.xml -->
<project name="imported" basedir="." default="...">
  <dirname property="imported.basedir" file="${ant.file.imported}"/>
  <property file="${imported.basedir}/imported.properties"/>
</project>

如上所述,${ant.file.imported}它存储了构建脚本的路径,它定义了名为imported 的项目(简而言之,它存储了imported.xml 的路径)并<dirname>获取其目录。此技术还允许将imported.xml 用作独立文件(无需在其他项目中导入)。

基本上,您不能真正使用${basedir}变量,也不能真正使用basedir="./../GrahamsProjClient"项目标签中的属性,而是可以构造它:

<!-- build-client.xml -->
<project name="GPClient" default="dist" >

  <dirname property="client.root.dir" file="${ant.file.GPClient}"/>
  <property name="real.basedir" value="${client.root.dir}/../GrahamsProjClient"/>

  <!-- Then from then on, replace ${basedir} with ${real.basedir} -->
  ...
</project>

您可以对 build-server.xml 执行相同操作,唯一需要注意的是项目名称${ant.file.[project name]}<dirname />.

于 2012-10-10T00:58:32.053 回答
3

我的正常规则是不要使用<ant><subant>在正常的构建过程中,因为它会破坏依赖项检查。我们让一个开发人员将 build.xml 分解为七个单独的构建文件,并且由于不断调用<ant>任务来执行其他构建文件中的内容,他最多执行了 14 次相同的目标。然后,他想知道为什么他的构建需要这么长时间。将七个构建文件重新组合成一个文件,build.xml并使用depends参数<target>将构建缩短到不到两分钟。

但是,在这种情况下,您拥有的实际上是两个独立的项目,并且build.xml您使用一个来调用这两个独立的项目。在这种情况下,最好使用<ant>and<subant>调用而不是<import>.

  • 这些调用不会干扰${basedir}.
  • 这些调用允许您指定要包含在这些单独文件中的属性和资源。(可能的答案是没有)。
  • 多个目标共享同一个名称没有问题。客户端构建中的编译目标不会与_compile_服务器构建中的目标重叠。

Subant 更强大,但实现起来更棘手。使用 Subant,您可以让它搜索 build.xml 文件。大多数时候使用<ant>只是更容易,做你想做的事。


我真正推荐的是使用 Ivy 来处理依赖问题。Ivy 不仅可以处理客户端中的服务器依赖项,还可以处理所有第三方 jar 依赖项。不再在项目中存储 jarfile。当您将 jar 文件存储在项目中时,您会丢失有关其实际版本和历史记录的信息。你在你的项目中看到一个commons-io.jar,你不知道它是什么版本,或者即使它是官方的`commons-io.jar,或者你的开发人员在某个点上把它弄脏了。

问题是 Ivy 需要做一些工作来实现。您需要使用 Ivy 存储库管理器,例如NexusArtifactoryArchiva。(实际上,这些是 Maven 存储库管理器,但 Ivy 与它们配合得非常好。)

然后,您需要将其ivy.jar导入您的项目并让该ivysettings.xml文件指向您的Maven Ivy 存储库服务器。

如果您使用 Subversion 作为您的版本控制系统,您可以执行以下操作:

  • 创建一个包含 ivy.jar 的 Ivy 项目和一个为您设置所有内容的 XML 文件。我在Github上有一个,你可以看看。XML 文件称为ivy.tasks.xml.
  • 然后在你的项目中,使用svn:externals来导入这个项目。
  • 在您的build.xml中,您需要做两件事:
    • <project>在您的实体中添加 Ivy 命名空间。
    • 使用该<import>任务导入具有所有设置的 Ivy XML 文件。

优点是更改您的 Ivy 项目会自动更改所有与 Ivy 交互的项目。例如,如果您更改了 Ivy 服务器的 URL,或者您需要重新定义 Ivy 缓存目录。

这样做后,您只需创建一个ivy.xml定义依赖项的文件,并使用<ivy:cachepath><ivy:retrieve>检索您需要的第三方 jar。这将包括您的客户需要的服务器 jar。

于 2012-10-10T02:39:11.640 回答
0

我注意到 ant 的一件事是我无法像我想要的那样改变变量

解决方案是让 ant 从命令行为您想要执行的每个目标运行,而不是执行命令行语句,例如

ant target1 target2

或者

<target name="target1">
   <antcall target="target2">
</target>

我不得不从命令行按顺序执行目标调用 ant target1 ant target2

所以我选择将这些 ant 调用放在一个 python 脚本中,它只是进行os.system("");调用,我的命令行语句将在引号内。bash 也可以这样做

这是 ant 为每个目标使用正确变量的唯一方法,如果这些变量具有相同的名称

于 2012-10-09T22:00:54.990 回答