Replace token in file before building, but keep token in sources

时间:2015-05-04 19:37:19

标签: java gradle

I want to replace a @VERSION@ token in a java source file with a version before building (Gradle is my build system of choice).

In my current script ant.replace(file: 'src/main/java/randers/notenoughvocab/main/Reference.java', token: '@VERSION@', value: version) it replaces the occurrences of @VERSION@ in the actual source file, so after a build all occurrences of the pattern have been replaced by the version and if I change the version the the gradle build file it will no longer find any patterns in there and the version will not update.

I have also seen a task here, but I do not get what values need to be applied for my specific project.

The project layout for my project, if that is needed:
Screenshot of file layout taken from IntelliJ IDEA 14.1.2, Dark theme

My gradle build file: View on github

5 个答案:

答案 0 :(得分:15)

在向公众发布软件之前,您只需要替换\\\*|([^\\]?\*) 令牌。在这里,我定义了一个完成它的任务@VERSION@

compileForRelease

我不建议搞乱Java插件定义的标准任务,因为这会给每个版本增加不必要的开销。

答案 1 :(得分:6)

WARNING: As indicated in comments by @Raffaele filtering source code may result in serious problems. This answer assumes that you know well what are you doing and are conscious about potential problems that may occur.

The problem is in the fact that java source files are not copied - they're compiled only - in place. So you need to:

  1. Before compilation - copy the file that contains @VERSION@
  2. Filter the file.
  3. Compile
  4. Restore original file.

Not sure about paths but the following piece of code should be helpful:

apply plugin: 'java'

version = '0.0.1'
group = 'randers.notenoughvocab'
archivesBaseName = 'NotEnoughVocab'

def versionFile = 'src/main/java/randers/notenoughvocab/main/Reference.java'
def tempDir = 'build/tmp/sourcesCache'
def versionFileName = 'Reference.java'

compileJava.doFirst {
    copy {
        from(versionFile)
        into(tempDir)
    }
    ant.replace(file: versionFile, token: '@VERSION@', value: version)
}

compileJava.doLast {
    copy {
        from(tempDir + '/' + versionFileName)
        into(project.file(versionFile).parent)
    }
}

答案 2 :(得分:3)

我遇到了同样的问题。我无法找到有效的解决方案。我找到的所有例子都没有奏效。我相信这可能是事实,我是Gradle的新手,这些例子省略了一些明显的代码。所以我调查了Gradle并找到了自己的解决方案,我想分享一下:

import org.apache.tools.ant.filters.ReplaceTokens

// Change compiler source directory
sourceSets {
    main {
        java {
            srcDirs = ['build/src/main/java']
        }
    }
}

// Prepare sources for compilation
task prepareSources(type: Copy) {
    from('src/main/java')
    into('build/src/main/java')
    filter(ReplaceTokens, tokens: [pluginVersion: version])
}

// Prepare sources, before compile
compileJava {
    dependsOn prepareSources
}

答案 3 :(得分:2)

我发现现有答案有些不令人满意,所以这是我的解决方案:

import org.apache.tools.ant.filters.ReplaceTokens

task processSource(type: Sync) {
    from sourceSets.main.java
    inputs.property 'version', version
    filter(ReplaceTokens, tokens: [VERSION: version])
    into "$buildDir/src"
}

compileJava {
    source = processSource.outputs
}

这解决了以下各种问题:

  1. 与@Opal的答案不同,主要来源仍然不受干扰;相反,它是通过$buildDir/src任务对processSource的修改来分阶段进行的,该任务反映了标准processResources
  2. 与@Gregory Stachowiak的答案不同,sourceSets.main.java.srcDirs仍然是默认值,并且可以轻松地指定尚不存在的位置
  3. 与@Raffaele的答案不同,没有针对发布版本与其他内部版本的单独任务集。我不同意将它们分开是可取的。我认为增加的复杂性是不值得的,除非您测量了任何性能损失,并认为这是不可接受的。例如,在使用@Raffaele的解决方案之前,我什至更喜欢使用包含/排除模式来限制filter的范围。
  4. 任务依赖项是通过输出隐式定义的。
  5. 所有位置均取自默认值,且未键入任何字符串。这里唯一的魔力值是src$buildDir下的目录,已处理的源文件放置在该目录下。
  6. (编辑:已添加2019/1/12)其他答案不能正确处理仅更改版本的情况。更改版本本身应该会使任务输出无效。这是通过inputs.property完成的。
  7. (编辑2019/5/20)使用Sync而不是Copy,以便从源中删除的文件也从已过滤的源中删除(感谢@Earthcomputer)。

答案 4 :(得分:1)

为了补充其他答案,如果您只想改变一个值,我发现这个成语更简单:

task generateSources(type: Copy) {
    from 'src/main/java'
    into 'build/src/main/java'
    filter { line -> line.replaceAll('xxx', 'aaa') }
}