【问题标题】:Best practice for code modification during ant buildant build 期间代码修改的最佳实践
【发布时间】:2011-08-24 06:53:39
【问题描述】:

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

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

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

  1. 在类中的令牌上使用<replace>

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

  2. 拷贝文件,对拷贝进行替换,编译拷贝,删除拷贝

    必须注意顺序 - 必须先编译原始类才能被副本覆盖。时间依赖性也很丑陋。

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

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

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

    是对前三个的改进,因为没有时间依赖性,但是编译器/IDE 非常不满意,因为它忘记了类。红色标记丑得令人不安。

您对替代方案有何看法?

有没有这方面的最佳实践?

我当然希望我错过了一个完全理智的方法。

谢谢

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

【问题讨论】:

标签: java ant build build-process


【解决方案1】:

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

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

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

【讨论】:

  • 同意,这样做的另一个好处是浏览您的应用程序的 jar 文件,人们可以看到它的内部版本号。事实上,您可能需要考虑将这些内容放入 jar 的清单中。
  • 听起来不错,很有道理。我想我试图修改源本身是走错路了。
  • Ant 提供了一个“manifest”任务,用于将信息放入清单中——Java 提供了一个 Manifest 类,可以将信息取出。
  • @Andy Thomas-Cramer 谢谢你,我们最终使用了清单,但使用了 MyClass.class.getPackage().getImplementationVersion()。这是to this thread的答案之一
  • @kostja - 哦,对了,我忘记了,尽管过去使用过。
【解决方案2】:

#2 通常是我所看到的完成方式,除了您的未准备好编译的源代码应该与您准备编译的源代码位于不同的位置。这避免了您所说的时间问题,因为它应该只编译一次。

这是在软件构建过程中一直出现的常见模式。

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

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

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

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

【讨论】:

  • 感谢您的详细解答。这听起来也是一个干净而理智的解决方案。 +1
【解决方案3】:

我的解决办法是:

  1. 在类中的标记上使用:

    <replace dir="${source.dir}" includes="**/BuildInfo.*" summary="yes">
        <replacefilter  token="{{BUILD}}" value="${build}" />
        <replacefilter  token="{{BUILDDATE}}" value="${builddate}" />
    </replace>
    

这种替换应该只发生在您的构建系统执行的构建步骤中,绝不能发生在 IDE 内的编译/调试会话中。

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

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

【讨论】:

  • “构建系统设置不应将更改的源代码提交回源存储库...”。任何设计良好的构建系统都应该遵守这一点。 +1 更改只能朝一个方向进行,并且在清理时您应该只需要删除构建目标和中间构建工件(例如生成的源)。
  • 谢谢,这种方法的问题(这是我们的第一次尝试)是该类要么保持更改,并且由 VCS 显示为这样,并且不止一次已使用令牌签入替换...所以必须有某种回滚,要么是 1 中的 ,要么是 3 中的复制开关
  • 你是对的,考虑到我们的 CI 构建 - 签出、修改、构建、删除......令牌替换工作完美。但我们也希望能够在我们的开发机器上生成与发布相同的构建
  • @kostja, produce release-identical builds on our dev machines 这是一个危险的愿望,恕我直言,开发机器始终与受控构建系统不同,处于不断变化的状态。对于开发人员来说,{{BUILD}} 令牌显示为构建版本应该不是问题。测试(开发者除外)应始终基于您的构建系统构建的版本,而不是来自开发者的机器。
【解决方案4】:

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

【讨论】:

  • 就像 matt b 说的,还是我错过了什么?
  • 哦耶..我想我们几乎同时发帖
【解决方案5】:

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

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

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

这样,您不会在签出的源目录中进行任何修改,因此不会有人意外签入更改。另外,您只需删除target 目录即可清理

如果有数千个,如果不是数百万个*.java 文件,那么您可以将模板复制到target/source,然后在{$basedir}/sourcetarget/source 中编译源代码。这样,您仍然不会弄乱签出的代码,也不会留下有人意外签入修改版本的机会。而且,您仍然可以通过简单地删除 target 来创建 clean

【讨论】:

    【解决方案6】:

    我正在寻找相同问题的解决方案,阅读此链接: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 编译项目时增加次要版本。因此,您可以在次要版本保持静止时随时运行项目。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-31
      • 1970-01-01
      • 2015-09-10
      • 2011-03-26
      • 2012-01-13
      • 1970-01-01
      • 2011-06-20
      相关资源
      最近更新 更多