Is it possible to publish a file to Maven if its location is not known at configuration time?

I am trying to publish a file to a maven repository. The location of the file is not known at configuration time, so I set up a fileTree to find it by pattern. This pattern is set as the output of the task. The problem is that MavenPublication does not seem to support lazy values for artifacts, so it cannot take the singleFile from the outputs of the task that generates it.

Here’s a full example:

import java.nio.file.Files
import java.nio.file.Path

group 'test'
version '1.0-SNAPSHOT'

// generates 3 files. assume that the location is not known,
// but we need to get a file that matches a certain pattern
def genTask = project.task("createSomeFiles") {
    Path buildPath = project.getBuildDir().toPath()
    List<Path> paths = [
            "unknown_file_name_skip.txt",
            "not_needed_file_name.skip",
            "unknown_file_name.txt"]
            .collect { buildPath.resolve(it) }
    outputs.files project.fileTree(
            dir: project.buildDir,
            include: "**/*.txt",
            exclude: "**/*skip*.txt")
    doLast {
        Files.createDirectories(buildPath)
        paths.each {
            if (Files.exists(it)) {
                Files.delete(it)
            }
            Files.createFile(it)
        }
    }
}

// prints the file location correctly ("build/unknown_file_name.txt")
project.task("printOutputs", dependsOn: genTask) {
    doLast {
        println genTask.outputs.files.singleFile
    }
}

project.apply plugin: 'maven-publish'

project.publishing {
    publications {
        maven(MavenPublication) {
            // 1) does not work: not an archive task
            artifact source: project.tasks.createSomeFiles
            // 2) does not work: singleFile evaluates at configuration time (expected)
            artifact source: project.tasks.createSomeFiles.outputs.files.singleFile
            // 3) does not work: closure STILL evaluated at configuration time
            artifact source: {project.tasks.createSomeFiles.outputs.files.singleFile}
            // 4) does not work: same as above but with different syntax
            artifact({ project.tasks.createSomeFiles.outputs.files.singleFile })
        }
    }
    repositories {
        maven {
            url "$project.rootDir/repo"
        }
    }
}

Publications contain 4 cases that I have tried:

  1. Specifying the task as a source does not work, because it is expected to be an ArchiveTask. I cannot make the createSomeFiles task an archive task, because it also requires the name to be known at configuration time.
  2. Specifying the singleFile as source does not work, because the file is not known at configuration phase.
  3. This is the case I expected to work. The source is set up as a closure, which should, in theory, be lazily initialized when it is actually needed. Instead, it is read at configuration phase and we get the same error, that we got in the previous case:
    "> Expected task ‘createSomeFiles’ output files to contain exactly one file, however, it contains no files."
  4. This is the same closure-based solution but with different syntax. The result is the same.

Am I missing something here or is it impossible to publish a file if its name is not known during configuration?

Thanks.

One way to achieve what you are after is to add an action to the task producing the file (see addLast) that calls singleFile() on the file tree and then copies/renames that file to a known location that you can reference.

Keep in mind that if you move the file, you may break the UP-TO-DATE check.

Thanks for the reply.

But this does not really solve the issue, because it forces me to publish it with a predefined name, as well as creating a copy of a file, which can be quite big.

It’s pretty strange that there is no “proper” way of doing this.

A Maven repo is not a filesystem - it has structure based on the notion of artifacts with well known coordinates. Gradle allows you to choose what to publish, but you can not break the artifact naming convention if you want your artifact to be well behaved [*]. As such, it is a bad fit if you just want to publish a random file. (You may easily use some http library if you need to upload directly.)

[*] there are workarounds, such as using ad-hoc classifiers, etc, but that is leading to even more complications down the road.

To turn the question around - how are you planing to use that file?