scala - 如何在不同机器上重用已编译的源代码

标签 scala sbt

为了加快我们的开发工作流程,我们拆分测试并在多个代理上并行运行每个部分。然而,编译测试源似乎需要大部分时间用于测试步骤。

为了避免这种情况,我们使用 sbt test:compile 预编译测试。并使用已编译的目标构建一个 docker 镜像。

稍后,此镜像在每个代理中用于运行测试。但是,即使存在已编译的类,它似乎也会重新编译测试和应用程序源。

有没有办法让 sbt 使用现有的编译目标?

更新:提供更多背景信息

这个问题与 scala 和 sbt 严格相关(因此是 sbt 标签)。

我们的 CI 过程分为多个阶段。它大致是这样的。

  • 阶段 1:使用 SBT 使用 sbt compile 将 Scala 项目编译成 java bitcode我们使用 sbt test:compile 在同一测试中编译测试源目标捆绑在 docker 镜像中并推送到远程存储库,
  • 第 2 阶段:我们使用多个代理来并行拆分和运行测试。
    测试从构建的 docker 镜像运行,因此环境是
    相同的。但是,正在运行 sbt test甚至导致项目重新编译
    通过编译的bitcode存在。

  • 为了说明这一点,我基本上想在一台机器上编译并在另一台机器上运行已编译的测试源,而无需重新编译

    更新

    我不认为 https://stackoverflow.com/a/37440714/8261是同样的问题,因为与它不同,我不安装卷或在主机上构建。一切都在 docker 中编译和运行,但分为两个构建阶段。因此,文件修改时间和路径保持不变。

    调试输出有这样的东西
    Initial source changes: 
        removed:Set()
        added: Set()
        modified: Set()
    Invalidated products: Set(/app/target/scala-2.12/classes/Class1.class, /app/target/scala-2.12/classes/graph/Class2.class, ...)
    External API changes: API Changes: Set()
    Modified binary dependencies: Set()
    Initial directly invalidated classes: Set()
    
    Sources indirectly invalidated by:
        product: Set(/app/Class4.scala, /app/Class5.scala, ...)
        binary dep: Set()
        external source: Set()
    All initially invalidated classes: Set()
    All initially invalidated sources:Set(/app/Class4.scala, /app/Class5.scala, ...)
    Recompiling all 304 sources: invalidated sources (266) exceeded 50.0% of all sources
    Compiling 302 Scala sources and 2 Java sources to /app/target/scala-2.12/classes ...
    

    它没有初始源更改,但产品已失效。

    更新:重现的最小项目

    我创建了一个最小的 sbt 项目来重现该问题。
    https://github.com/pulasthibandara/sbt-docker-recomplile

    如您所见,除了在新步骤(新容器)的第二阶段运行之外,构建阶段之间没有任何变化。

    最佳答案

    虽然 https://stackoverflow.com/a/37440714/8261指向正确的方向,根本问题和解决方案是不同的。

    问题

    当 SBT 在 docker 构建的不同阶段运行时,它似乎会重新编译所有内容。这是因为 docker 会压缩在每个阶段创建的图像,从而从源中去除 lastModifiedDate 的毫秒部分。

    SBT 在确定源是否已更改时取决于 lastModifiedDate,并且由于其不同(毫秒部分),构建会触发完整的重新编译。

    解决方案

  • java 8:
    设置 -Dsbt.io.jdktimestamps=true当按照 https://github.com/sbt/sbt/issues/4168#issuecomment-417655678 中的建议运行 SBT 时解决此问题。
  • 较新:
    遵循 https://github.com/sbt/sbt/issues/4168#issuecomment-417658294 中的推荐

  • 我通过设置 SBT_OPTS 解决了这个问题docker 文件中的 env 变量,例如
    ENV SBT_OPTS="${SBT_OPTS} -Dsbt.io.jdktimestamps=true"
    

    test project已使用此解决方法进行更新。

    关于scala - 如何在不同机器上重用已编译的源代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54068316/

    相关文章:

    scala - 了解 GenericTraversableTemplate 和其他 Scala 集合内部结构

    scala - 如何在 sbt 中只运行一个测试?

    java - 如何在案例类中重用类参数?

    linux - 如何让 sbt 使用我本地存储库中的 jar?

    scala - 具有隐式转换的类型类中的堆栈溢出

    scala - 扩展函数缺少参数类型 - 它取决于什么?

    scala - 在 Akka 中设置日志记录级别

    java - 无法使用 Scala 从 Cassandra DB 的原始数据类型映射读取数据

    scala - Play 应用程序中用于测试的资源目录

    scala - 创建两个模块的 IntelliJ "SBT project import"