I am using SBT 0.13.16

I have a task that generates a file by calling the main method in the source. This task calculates the path to the file and passes it to the main method as an argument.

build.sbt:

 lazy val myTask = taskKey[Unit]("generates file by executing main method") myTask := Def.taskDyn { val file = (resourceManaged in Compile).value / "fileFromTask.txt" val path = file.getAbsolutePath Def.task { (runMain in Compile).toTask(s" com.company.Main $path").value } }.value assembly := (assembly dependsOn myTask).value resourceGenerators in Compile += Def.task { val file = (resourceManaged in Compile).value / "fileFromTask.txt" Seq(file) }.taskValue 

Main.scala:

 object Main extends App { val path = args(0) val file: Path = Paths.get( path ) Files.createDirectories(file.getParent) Files.write(file, "Hi! I am a simple text file".getBytes(StandardCharsets.UTF_8)) } 

I cannot understand why the sbt assembly command generates a file (I see it in the target\scala-2.12\resource_managed folder), but does not add it to the jar ?

BUT!
If you type sbt myTask assembly , then the file, as expected initially, will be added to the jar . But this is the same thing (in my opinion), which is just the sbt assembly . Why is that?

I noticed that if the file is generated in the task itself, and not in the main method, then the sbt assembly can also add it to the jar . Why?

    1 answer 1

    Because the sbt myTask assembly not the same as the sbt assembly .

    The fact is that the assebmly assebmly itself does not look into the target\scala-2.12\resource_managed folder, another task is responsible for this, and the assembly is executed after it. And despite the fact that you put myTask in front of assembly , myTask still comes after that other task.

    If you type in the sbt inspect assembly , you will see a list of other tasks on which assebmly depends and at the end of which it will begin its work:

     [info] Dependencies: [info] *:myTask [info] *:assembly::packageOptions [info] *:assembly::assemblyOption [info] *:assembly::streams [info] *:assembly::test [info] *:assembly::assembledMappings <--- Смотрим сюда :) [info] *:assembly::assemblyOutputPath 

    Those. Here is this line:

     assembly := (assembly dependsOn myTask).value 

    guarantees that myTask will run before assembly , but does not guarantee that myTask will run before other similar dependencies.

    Actually - *:assembly::assembledMappings also not involved in resources, but depends on another task, which also depends on others, and so on before copyResources . This task transfers resources from the target\scala-2.12\resource_managed folder to the target\scala-2.12\classes folder, from which the assembly then takes it.

    By the way, I don’t know a bug or a feature - if you call sbt copyResources , when the target\scala-2.12\resource_managed folders are sbt copyResources , the file is promised in the settings:

     resourceGenerators in Compile += Def.task { val file = (resourceManaged in Compile).value / "fileFromTask.txt" Seq(file) }.taskValue 

    then sbt, not finding the file , will create a folder with the same name ( fileFromTask.txt ) in the destination folder ( target\scala-2.12\classes ).

    In addition, our myTask myTask also depends on the copyResources copyResources , so when you myTask first time, it calls copyResources , which does not find fileFromTask.txt , then myTask itself is myTask which creates target\scala-2.12\resource_managed\main\fileFromTask.txt .

    • Thanks for the detailed answer. Is there a way to do myTask before anything that will cause assembly ? - Oleg