java 在构建之前替换文件中的令牌,但将令牌保留在源中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30038540/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:20:22  来源:igfitidea点击:

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

javagradle

提问by RAnders00

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

我想@VERSION@在构建之前用版本替换java 源文件中的令牌(Gradle 是我选择的构建系统)。

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.

在我当前的脚本中,ant.replace(file: 'src/main/java/randers/notenoughvocab/main/Reference.java', token: '@VERSION@', value: version)它替换了@VERSION@实际源文件中出现的 ,因此在构建后所有出现的模式都被版本替换,如果我更改版本,gradle 构建文件将不再在那里找到任何模式并且版本不会更新。

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

我的项目的项目布局(如果需要):
Screenshot of file layout taken from IntelliJ IDEA 14.1.2, Dark theme

采纳答案by Raffaele

You only need to replace @VERSION@tokens before releasing your software to the public. Here I defined a task compileForReleasethat accomplishes it:

您只需要@VERSION@在向公众发布您的软件之前替换令牌。在这里,我定义了一个compileForRelease完成它的任务:

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

task sourcesForRelease(type: Copy) {
    from 'src/main/java'
    into 'build/adjustedSrc'
    filter(ReplaceTokens, tokens: [VERSION: '2.3.1'])
}

task compileForRelease(type: JavaCompile, dependsOn: sourcesForRelease) {
    source = sourcesForRelease.destinationDir
    classpath = sourceSets.main.compileClasspath
    destinationDir = file('build/adjustedClasses')
}

I don't recommend messing with standard tasks defined by the Java plugin because that would add unnecessary overhead to each and every build.

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

回答by Opal

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.

警告:正如@Raffaele 过滤源代码的评论中所指出的那样,可能会导致严重的问题。此答案假设您很清楚自己在做什么,并且意识到可能发生的潜在问题。

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

问题在于java源文件没有被复制——它们只是被编译——就地。所以你需要:

  1. Before compilation - copy the file that contains @VERSION@
  2. Filter the file.
  3. Compile
  4. Restore original file.
  1. 编译前 - 复制包含的文件 @VERSION@
  2. 过滤文件。
  3. 编译
  4. 恢复原始文件。

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)
    }
}

回答by Aaron

I found existing answers somewhat unsatisfying, so here is my solution:

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

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
}

This addresses various concerns as follows:

这解决了以下各种问题:

  1. Unlike @Opal's answer, the main source remains unmolested; instead it is staged with modifications to $buildDir/srcby the processSourcetask, which mirrors the standard processResources.
  2. Unlike @Gregory Stachowiak's answer, sourceSets.main.java.srcDirsremains the default value and there is no sleight of hand in specifying a location that does not (yet) exist
  3. Unlike @Raffaele's answer, there is no separate task set for release vs other builds. I disagree that separating them is desirable; I think the added complexity is not worth it unless you have measured any performance hit and found it to be unacceptable. Before going with @Raffaele's solution I would even for instance prefer to limit the scope of the filterwith include/exclude patterns.
  4. Task dependencies are implicitly defined via outputs.
  5. All locations are taken from defaults and nothing is stringly typed. The only magic value here is src, the directory under $buildDirwhere the processed source files are put.
  6. (Edit: added 2019/1/12) Other answers do not properly handle situations where only the version has changed. Changing the version should, by itself, invalidate the task output. This is accomplished via inputs.property.
  7. (Edit 2019/5/20) Uses Syncrather than Copyso that files deleted from source are deleted from the filtered source as well (thanks, @Earthcomputer).
  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)。

回答by Gregory Stachowiak

I faced the same problem. And I was unable to find working solution. None of the examples I found worked. I believe it might to a fact, that I am new to Gradle and those examples omit some obvious pieces of code. So I looked into Gradle and found my own solution, that I'd like to share:

我遇到了同样的问题。我无法找到可行的解决方案。我发现的所有例子都没有奏效。我相信这可能是一个事实,即我是 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
}

回答by Vic Seedoubleyew

To complement other answers, I found this idiom more simple if there's only one value you are looking to change:

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

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