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

后端 未结 5 1248
孤街浪徒
孤街浪徒 2021-02-12 03:33

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 a

相关标签:
5条回答
  • 2021-02-12 03:53

    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/src by the processSource task, which mirrors the standard processResources.
    2. 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
    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 filter with 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 $buildDir where 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 Sync rather than Copy so that files deleted from source are deleted from the filtered source as well (thanks, @Earthcomputer).
    0 讨论(0)
  • 2021-02-12 04:02

    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)
        }
    }
    
    0 讨论(0)
  • 2021-02-12 04:04

    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') }
    }
    
    0 讨论(0)
  • 2021-02-12 04:10

    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:

    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
    }
    
    0 讨论(0)
  • 2021-02-12 04:13

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

    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.

    0 讨论(0)
提交回复
热议问题