在ant构建期间进行代码修改的最佳实践

时间:2011-05-12 16:27:13

标签: java ant build build-process

承认,这听起来并不是最佳做法,但让我解释一下。在构建期间,我们需要将构建号和系统版本粘贴到一个类中,该类的唯一目的是包含这些值并使它们可访问。

我们的第一个想法是使用系统属性,但由于部署环境的波动性(另一种说法是“系统管理员正在做奇怪的邪恶令人毛骨悚然的事情”),我们希望对它们进行硬编码。

基本上我看到了在蚂蚁中实现它的4种可能性:

  1. 对班级中的令牌使用<replace>

    这种方法的问题是文件被更改了,所以你必须在编译后用<replaceregexp>替换令牌......太丑了,我不想用正则表达式来触摸源代码。加上时间依赖性。

  2. 复制文件,复制副本,编译副本,删除副本

    一个人必须记住序列 - 必须先编译原始类才能被副本覆盖。时间依赖性也很难看。

  3. 复制文件,替换原件上的令牌,编译,用副本替换染色的原件

    相同的时间依赖性问题,除非嵌入在编译目标中。这也是丑陋的,因为我们所有的构建文件都使用相同的导入编译目标。

  4. 在构建脚本中从头开始创建文件/将文件存储在源路径之外

    由于没有时间依赖性,因此对前三个进行了改进,但编译器/ IDE非常不满意,因为它忽略了类。红色标记令人不安地丑陋。

  5. 您对替代方案有何看法?

    对此有什么最佳做法吗?

    我当然希望我错过了一个完美的方法。

    谢谢

    修改 我们最终使用清单将版本号和系统版本存储在Implementation-Version属性中,并且MyClass.class.getPackage().getImplementationVersion()。我发现这个解决方案是 this thread的答案之一,由andersoj发表在评论中

6 个答案:

答案 0 :(得分:10)

我认为更简单的方法是让您的Version.java类从JAR中包含的简单.properties文件中读取,并在Ant构建中的构建时生成此.properties文件。例如,只需生成:

build.number = 142
build.timestamp = 5/12/2011 12:31

built-in <buildnumber> task in Ant已经完成了一半(见第二个例子)。

答案 1 :(得分:2)

#2通常是我看到它完成的方式,除了你不准备编译的源应该与你准备好编译的源分开。这避免了你所谈论的时间问题,因为它只应编译一次。

这是一种在软件构建过程中始终显示的常见模式。

模式是: 从某些资源生成源,然后编译它。

这适用于从编译前的过滤源到为RMI,CORBA,Web服务等生成接口存根的许多内容......

将源复制到指定的“生成源”位置,并在副本文件上执行令牌替换以生成源,然后将生成的源编译到已编译的类目标。

编译顺序取决于您的其他来源是否依赖于生成的来源。

答案 2 :(得分:1)

我的解决方案是:

  1. 在课程中使用令牌:

    <replace dir="${source.dir}" includes="**/BuildInfo.*" summary="yes">
        <replacefilter  token="{{BUILD}}" value="${build}" />
        <replacefilter  token="{{BUILDDATE}}" value="${builddate}" />
    </replace>
    
  2. 此替换只应在构建系统执行的构建步骤中进行,而不应在IDE内的编译/调试会话中进行。

    构建系统设置不应该将更改的源代码提交回源存储库,因此这种方法不存在更改代码的问题。

    根据我的经验,当您将构建信息放在属性文件中时,它无效,因为管理员倾向于在升级时保留属性文件 - 替换安装后出来的属性文件。 (在属性文件中构建信息对我们来说是信息性的。如果属性文件与代码版本同步,它提供了在启动期间检查的机会。)

答案 3 :(得分:0)

我记得我们以一种不同的方式使用了第四种方法。您可以在创建release时将版本号传递给ant脚本.Ant脚本应该包含在发行版(config / properties文件)中,并且您的类应该从那里读取它可能使用属性文件或配置文件。

答案 4 :(得分:0)

我总是建议创建某种目录并将所有构建的代码放在那里。请勿触摸您签出的目录。我通常创建一个target目录,并在那里修改和构建所有文件。

如果没有太多* .java文件(或* .cpp文件),请将它们复制到target/source' and compile there. You can use the task with a`,以便在复制时使用内部版本号修改此文件一个文件

                                                                                    

<javac srcdir="${target.dir}/source"
    destdir="${target.dir}/classes"
    [yadda, yadda, yadda]
</java>

这样,您在签出的源目录中不做任何修改,因此没有人会不小心检查更改。另外,只需删除target目录即可执行 clean

如果有数千个(如果不是数百万个)*.java个文件,那么您可以将模板复制到target/source,然后在{$basedir}/sourcetarget/source中编译源代码。这样,你仍然没有弄清楚已检出的代码,并且有可能会有人意外地检查修改后的版本。而且,您只需删除clean即可完成target

答案 5 :(得分:0)

我正在寻找同一问题的解决方案,请阅读此链接:http://ant.apache.org/manual/Tasks/propertyfile.html我能够找到解决方案。

我使用netbeans,所以我只需要将这段代码添加到我的build.xml

<target name="-post-init">
    <property name="header" value="##Generated file - do not modify!"/>
        <propertyfile file="${src.dir}/version.prop" comment="${header}">
            <entry key="product.build.major" type="int"  value="1" />
            <entry key="product.build.minor" type="int"  default="0" operation="+" />
            <entry key="product.build.date"  type="date" value="now" />
    </propertyfile>
</target>

每次使用clean和build编译项目时,这将增加次要版本。因此,只要次要版本保持不动,您就可以保存以运行项目。

我只需要在运行时读取该文件。我希望这有帮助。