Skip to content

Commit 196e631

Browse files
committed
Fix module binaries PATH not injected on nextflow module run (#7087)
When a module is launched directly via `nextflow module run`, the module main.nf is loaded as the entry script, so `ScriptMeta.isModule()` is false and `TaskProcessor.getModuleBundle()` was returning null, causing the `resources/usr/bin` directory not to be added to the task PATH. Switch the gate from `isModule()` to `getScriptPath()` so the bundle is resolved whenever the owner script has a known path. This makes the behavior of `nextflow module run` consistent with `nextflow run` plus include. The feature remains opt-in via `nextflow.enable.moduleBinaries`. Signed-off-by: Paolo Di Tommaso <paolo.ditommaso@gmail.com>
1 parent 656ff4e commit 196e631

2 files changed

Lines changed: 41 additions & 1 deletion

File tree

modules/nextflow/src/main/groovy/nextflow/processor/TaskProcessor.groovy

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1569,7 +1569,11 @@ class TaskProcessor {
15691569
ResourcesBundle getModuleBundle() {
15701570
final script = this.getOwnerScript()
15711571
final meta = ScriptMeta.get(script)
1572-
return meta?.isModule() ? meta.getModuleBundle() : null
1572+
// Resolve the resources bundle whenever the owner script has a known path,
1573+
// not only when it was loaded as an included module. This allows module
1574+
// binaries to be picked up also when a module is launched directly as the
1575+
// entry script via `nextflow module run` -- see #7087
1576+
return meta?.getScriptPath() ? meta.getModuleBundle() : null
15731577
}
15741578

15751579
@Memoized

modules/nextflow/src/test/groovy/nextflow/processor/TaskProcessorTest.groovy

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import nextflow.script.BaseScript
3535
import nextflow.script.BodyDef
3636
import nextflow.script.ProcessConfig
3737
import nextflow.script.ProcessConfigV1
38+
import nextflow.script.ScriptMeta
3839
import nextflow.script.ScriptType
3940
import nextflow.script.bundle.ResourcesBundle
4041
import nextflow.script.params.FileInParam
@@ -100,6 +101,41 @@ class TaskProcessorTest extends Specification {
100101

101102
}
102103

104+
def 'should resolve module bundle when script path is set regardless of isModule' () {
105+
given:
106+
def folder = Files.createTempDirectory('test')
107+
def mod = folder.resolve('mod1'); mod.mkdir()
108+
def bin = mod.resolve('resources/usr/bin'); bin.mkdirs()
109+
def scriptPath = mod.resolve('main.nf'); Files.createFile(scriptPath)
110+
Files.createFile(bin.resolve('echo.sh'))
111+
and:
112+
def script = Mock(BaseScript)
113+
def meta = Mock(ScriptMeta) {
114+
getScriptPath() >> scriptPath
115+
// Simulate the failing case: script is loaded as the entry, not as an included module
116+
isModule() >> false
117+
getModuleBundle() >> ResourcesBundle.scan(mod.resolve('resources'))
118+
}
119+
and:
120+
def session = Mock(Session) { getConfig() >> [:] }
121+
def executor = Mock(Executor) {}
122+
def processor = Spy(TaskProcessor, constructorArgs: [[session:session, executor:executor]])
123+
processor.getOwnerScript() >> script
124+
125+
when:
126+
ResourcesBundle bundle
127+
GroovyMock(ScriptMeta, global: true)
128+
ScriptMeta.get(script) >> meta
129+
bundle = processor.getModuleBundle()
130+
131+
then:
132+
bundle != null
133+
bundle.getBinDirs() == [bin]
134+
135+
cleanup:
136+
folder?.deleteDir()
137+
}
138+
103139
@Unroll
104140
def 'should add module bin paths to task env' () {
105141
given:

0 commit comments

Comments
 (0)