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
Replace token in file before building, but keep token in sources
提问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:
我的项目的项目布局(如果需要):
采纳答案by Raffaele
You only need to replace @VERSION@
tokens before releasing your software to the public. Here I defined a task compileForRelease
that 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源文件没有被复制——它们只是被编译——就地。所以你需要:
- Before compilation - copy the file that contains
@VERSION@
- Filter the file.
- Compile
- Restore original file.
- 编译前 - 复制包含的文件
@VERSION@
- 过滤文件。
- 编译
- 恢复原始文件。
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:
这解决了以下各种问题:
- Unlike @Opal's answer, the main source remains unmolested; instead it is staged with modifications to
$buildDir/src
by theprocessSource
task, which mirrors the standardprocessResources
. - Unlike @Gregory Stachowiak's answer,
sourceSets.main.java.srcDirs
remains the default value and there is no sleight of hand in specifying a location that does not (yet) exist - 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
filter
with include/exclude patterns. - Task dependencies are implicitly defined via outputs.
- All locations are taken from defaults and nothing is stringly typed. The only magic value here is
src
, the directory under$buildDir
where the processed source files are put. - (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
. - (Edit 2019/5/20) Uses
Sync
rather thanCopy
so that files deleted from source are deleted from the filtered source as well (thanks, @Earthcomputer).
- 与@Opal 的回答不同,主要来源没有受到干扰;相反,它
$buildDir/src
根据processSource
任务进行修改,这反映了标准processResources
. - 与@Gregory Stachowiak 的答案不同,它
sourceSets.main.java.srcDirs
仍然是默认值,并且在指定(尚)不存在的位置时没有任何技巧 - 与@Raffaele 的回答不同,发布版本与其他版本没有单独的任务集。我不同意将它们分开是可取的;我认为增加的复杂性是不值得的,除非您测量了任何性能损失并发现它是不可接受的。在使用@Raffaele 的解决方案之前,我什至更愿意限制
filter
包含/排除模式的范围。 - 任务依赖是通过输出隐式定义的。
- 所有位置均取自默认值,并且没有任何字符串类型。这里唯一的神奇值是
src
,$buildDir
处理过的源文件所在的目录。 - (编辑:2019 年 1 月 12 日添加)其他答案无法正确处理仅版本更改的情况。更改版本本身应该会使任务输出无效。这是通过
inputs.property
. - (编辑 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') }
}