分发要包含在构建中的通用 ant 文件有哪些好方法?

发布于 2024-10-19 02:23:18 字数 308 浏览 7 评论 0原文

我在一个团队工作,我们生产许多小型应用程序,并在构建过程中使用 ANT。

我们希望以通用的方式容纳一些常用的指令。目前,我们需要将驱动器映射到公共位置,并且使用

<import file="${env.MAPPED_DRIVE}/common_directive.xml">

必须有更好的方法来分发公共ant文件以包含在许多项目中,而无需映射驱动器。您还有其他建议吗?

Import 是一个“顶级”指令,这意味着它无法在目标内部工作。因此,我不能简单地创建一个下载文件的目标,然后导入它。

I work in a group where we produce many small apps, and use ANT for our build processes.

We would like to have some of our commonly used directives housed in a common way. Currently, we require a mapped drive to a common location, and use

<import file="${env.MAPPED_DRIVE}/common_directive.xml">

There must be a better way to distribute a common ant file to include in many projects without having to map a drive. Do you have any other suggestions?

Import is a "top level" directive, which means it won't work inside of a target. Therefore, I cannot simply create a target that downloads the file, and then import it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

前事休说 2024-10-26 02:23:18

如果您使用 ANT 1.8+,您可以指定一个 URL 并托管通用的在网站上构建片段。

从 Ant 1.8.0 开始,该任务还可以
从 URL 导入资源

类路径资源(即 URL、
真的吗)。如果您需要知道是否
当前构建文件的源代码有
是您可以查阅的文件或 URL
属性 ant.file.type.projectname
(使用与上面相同的示例
ant.file.type.builddocs)其中之一
值为“file”或“url”。

If you are using ANT 1.8+, you could specify a URL and host the common build fragment on a website.

Since Ant 1.8.0 the task can also
import resources from URLs
or
classpath resources (which are URLs,
really). If you need to know whether
the current build file's source has
been a file or an URL you can consult
the property ant.file.type.projectname
(using the same example as above
ant.file.type.builddocs) which either
have the value "file" or "url".

深海里的那抹蓝 2024-10-26 02:23:18

我已经制定了一个解决方案,在目录中创建一个包含可重用构建脚本的 jar 文件,例如 com/example/ant/sharedbuild,该文件可以在 Ant 1.8 中导入:

<project>
    <import>
        <javaresource name="com/example/ant/sharedbuild/java.xml">
            <classpath location="../../../../target/ant-shared-build.jar" />
        </javaresource>
    </import>
</project>

在我的例子中,这定义了所有“公共”目标为项目进行基于 java 的构建。

语法有点冗长,尤其是当我添加越来越多的包含文件时(例如,添加创建 OSGi jar 的功能)。通过将包含 Macrodef 和 scriptdef 组合的 antlib.xml 添加到 jar 文件(与共享构建脚本位于同一目录中),构建文件现在看起来像这样(现在还创建了一个 OSGi jar 包):

<project xmlns:build="antlib:com.example.ant.sharedbuild">
    <taskdef uri="antlib:com.example.ant.sharedbuild"
             classpath="../../../../target/ant-shared-build.jar" />
    <build:build using="java, jar, bundle" />
</project>

不幸的是,我无法共享 Macrodef 或 scriptdef 中的代码,但实际上这并不难:用一点 JavaScript 来解析 using 属性并循环每个属性,从中派生文件名,然后导入。

我在硬盘上的固定位置(相对于我的项目)引用了 jar 文件。我认为我们可以做得更好。理想情况下,我想从中心位置获取(版本控制!)jar 文件。由于我们已经在使用 Ivy(带有 HTTP 存储库),我们可以在那里发布 jar 文件(同样带有版本)并直接从那里获取它:

<project xmlns:build="antlib:com.example.ant.sharedbuild">
    <property name="ant.shared.build.jar.file"
              location="${user.home}/ant/ant-shared-build-1.5.3.jar" />
    <get src="http://repo.example.com/.../ant-shared-build-1.5.3.jar"
         dest="${ant.shared.build.jar.file}"
         skipexisting="true" />
    <taskdef uri="antlib:com.example.ant.sharedbuild"
             classpath="${ant.shared.build.jar.file}" />
    <build:build using="java, jar, bundle" />
</project>

这样做有一些问题:

  1. 它再次变得冗长。
  2. 每个 build.xml 都会重复详细信息。
  3. 有很多重复的样板,尤其是版本号。

为了缓解这些问题,在每个包含 build.xml 的目录中,我还有一个 bootstrap.xml (名称并不重要)。然后,每个 build.xml 都包含此文件:

<project xmlns:build="antlib:com.example.ant.sharedbuild">
    <include file="bootstrap.xml" />
    <build:build using="java, jar, bundle" />
</project>

每个 bootstrap.xml 至少包含其父级的 bootstrap.xml:

<project>
    <include file="../bootstrap.xml" />
</project>

顶级 bootstrap.xml(根),然后执行获取 jar 文件并创建自定义的工作任务,如上所述:

<project>
    <property name="ant.shared.build.version"
              value="1.5.3" />
    <property name="ant.shared.build.jar.filename"
              value="ant-shared-build-${ant.shared.build.version}.jar" />
    <property name="ant.shared.build.jar.file"
              location="${user.home}/ant/${ant.shared.build.jar.filename}" />
    <get src="http://repo.example.com/.../${ant.shared.build.jar.filename}"
         dest="${ant.shared.build.jar.file}"
         skipexisting="true" />
    <taskdef uri="antlib:com.example.ant.sharedbuild"
             classpath="${ant.shared.build.jar.file}" />
</project>

虽然与问题没有直接关系,但我实际上正在将 Macrodef 和 scriptdef 重新加工成自定义 ant 任务,因为我希望能够支持如下所示的语法:

<project xmlns:build="antlib:com.example.ant.sharedbuild">
    <include file="bootstrap.xml" />
    <build:build>
        <using>
            <java />
            <bundle>
                <manifest>
                    Import-Package: *,org.joda.time;version="[1.6.0,1.6.0]"
                    Bundle-Activator: com.example.time.impl.Activator
                </manifest>
            </bundle>
        </using>
    </build:build>
</project>

我应该指出,只是创建可再发行的版本并不意味着它会有用。您仍然需要投入时间和精力来创建符合类似特征的设计的内聚的、模块化的、一致的实现。这一点更为重要,因为您需要跨项目、跨团队、跨组织边界等共享脚本。

总之,通过创建带有版本号的 jar 文件,该文件可以独立于特定文件位置或 SCM 工具进行分发我们可以获得真正共享但可复制的构建。

I've worked out a solution that creates a jar file containing our reusable build scripts in a directory, say com/example/ant/sharedbuild, which can be imported in Ant 1.8:

<project>
    <import>
        <javaresource name="com/example/ant/sharedbuild/java.xml">
            <classpath location="../../../../target/ant-shared-build.jar" />
        </javaresource>
    </import>
</project>

In my case this defines all of the "public" targets for the project to do a java-based build.

The syntax is a little verbose, especially as I add more and more include files (say, to add the ability to create an OSGi jar). By adding an antlib.xml that contains a combination of a macrodef and scriptdef to the jar file (in the same directory as the shared build scripts), the build file can now look like this (and now also creating an OSGi jar bundle):

<project xmlns:build="antlib:com.example.ant.sharedbuild">
    <taskdef uri="antlib:com.example.ant.sharedbuild"
             classpath="../../../../target/ant-shared-build.jar" />
    <build:build using="java, jar, bundle" />
</project>

Unfortunately, I can't share the code in the macrodef or scriptdef, but really it isn't hard: a little javascript to parse the using attribute and loop over each, derive a file name from it, and import.

I reference the jar file in a fixed location (relative to my project) on my hard drive. I think we can do better. Ideally, I'd like to fetch a (versioned!) jar file from a central location. Since we're already using Ivy (with an HTTP repository) we can publish the jar file there (again, with a version) and fetch it directly from there:

<project xmlns:build="antlib:com.example.ant.sharedbuild">
    <property name="ant.shared.build.jar.file"
              location="${user.home}/ant/ant-shared-build-1.5.3.jar" />
    <get src="http://repo.example.com/.../ant-shared-build-1.5.3.jar"
         dest="${ant.shared.build.jar.file}"
         skipexisting="true" />
    <taskdef uri="antlib:com.example.ant.sharedbuild"
             classpath="${ant.shared.build.jar.file}" />
    <build:build using="java, jar, bundle" />
</project>

There are some problems with this:

  1. It's getting verbose again.
  2. The verbosity is repeated for every build.xml.
  3. There's a lot of repeated boilerplate, especially the version number.

To mitigate these problems, in each directory containing a build.xml I also have a bootstrap.xml (the name doesn't really matter). Each build.xml then includes this file:

<project xmlns:build="antlib:com.example.ant.sharedbuild">
    <include file="bootstrap.xml" />
    <build:build using="java, jar, bundle" />
</project>

Each bootstrap.xml, at a minimum, includes it's parent's bootstrap.xml:

<project>
    <include file="../bootstrap.xml" />
</project>

The top-level bootstrap.xml (the root), then does the work of getting the jar file and creating the custom tasks, as above:

<project>
    <property name="ant.shared.build.version"
              value="1.5.3" />
    <property name="ant.shared.build.jar.filename"
              value="ant-shared-build-${ant.shared.build.version}.jar" />
    <property name="ant.shared.build.jar.file"
              location="${user.home}/ant/${ant.shared.build.jar.filename}" />
    <get src="http://repo.example.com/.../${ant.shared.build.jar.filename}"
         dest="${ant.shared.build.jar.file}"
         skipexisting="true" />
    <taskdef uri="antlib:com.example.ant.sharedbuild"
             classpath="${ant.shared.build.jar.file}" />
</project>

Though not directly related to the question, I'm actually reworking the macrodef and scriptdef into a custom ant task, because I want to be able to support a syntax that looks like this:

<project xmlns:build="antlib:com.example.ant.sharedbuild">
    <include file="bootstrap.xml" />
    <build:build>
        <using>
            <java />
            <bundle>
                <manifest>
                    Import-Package: *,org.joda.time;version="[1.6.0,1.6.0]"
                    Bundle-Activator: com.example.time.impl.Activator
                </manifest>
            </bundle>
        </using>
    </build:build>
</project>

I should point out that just creating a redistributable build doesn't mean it's going to be useful. You still need to put in the time and effort to create a cohesive, modular, consistent implementation in line with a design of similar characteristics. This is more important as you need to share scripts across projects, across teams, across organizational boundaries, etc.

In conclusion, by creating a jar file, with a version number, that can be distributed independent of a specific file location or an SCM tool we can get real shared but reproducible builds.

冧九 2024-10-26 02:23:18

Dominic Mitchell 关于 URL 引用的评论是一个坏主意,如果你想要可重复的构建,这让我思考......

如果您使用 SVN 进行版本控制,则需要考虑的另一个解决方案是创建 SVN 外部定义,指向 common_directive.xml

然后,只需使用 ANT 导入文件引用的相对路径即可。

有时构造一个
工作副本是由
不同结帐的数量。
对于
例如,您可能想要不同的
子目录来自不同的
存储库中的位置或者可能
来自不同的存储库
共。你当然可以设置
手动实现这样的场景——使用 svn
checkout 创建嵌套排序
您正在尝试的工作副本结构
来实现。但如果这个布局是
对于每个使用你的人来说都很重要
存储库,每个其他用户都需要
执行相同的结账
您执行的操作。

幸运的是,Subversion 提供了
支持外部定义。
外部定义是一个映射
URL 的本地目录 - 最好是
版本化的特定修订
目录。
在 Subversion 中,您声明
组中的外部定义使用
svn:externals 属性。你可以
使用以下命令创建或修改此属性
svn propset 或 svn propedit (请参阅
名为“操作的部分
属性
”)。它可以设置在任何
版本化目录及其值
描述了外部存储库
位置和客户端目录
该位置应该是
已签出。

svn:externals 的便利性
属性是一旦它被设置在
版本化目录,每个人
检查工作副本
目录还受益于
外部定义。
换句话说,
一旦一个人付出了努力
定义嵌套工作副本
结构,没有其他人必须
麻烦——Subversion 会在检查后
出原始工作副本,
还自动检查
外部工作副本。

Dominic Mitchell's comment about the URL reference being a bad idea if you want repeatable builds got me thinking...

Another solution to consider, if you are using SVN for version control, is to create an SVN Externals Definition that points to the common_directive.xml.

Then, just use a relative path for your ANT import file reference.

Sometimes it is useful to construct a
working copy that is made out of a
number of different checkouts.
For
example, you may want different
subdirectories to come from different
locations in a repository or perhaps
from different repositories
altogether. You could certainly set up
such a scenario by hand—using svn
checkout
to create the sort of nested
working copy structure you are trying
to achieve. But if this layout is
important for everyone who uses your
repository, every other user will need
to perform the same checkout
operations that you did.

Fortunately, Subversion provides
support for externals definitions. An
externals definition is a mapping of a
local directory to the URL—and ideally
a particular revision—of a versioned
directory.
In Subversion, you declare
externals definitions in groups using
the svn:externals property. You can
create or modify this property using
svn propset or svn propedit (see the
section called “Manipulating
Properties
”). It can be set on any
versioned directory, and its value
describes both the external repository
location and the client-side directory
to which that location should be
checked out.

The convenience of the svn:externals
property is that once it is set on a
versioned directory, everyone who
checks out a working copy with that
directory also gets the benefit of the
externals definition.
In other words,
once one person has made the effort to
define the nested working copy
structure, no one else has to
bother—Subversion will, after checking
out the original working copy,
automatically also check out the
external working copies.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文