Skip to content

Commit 1f7b643

Browse files
committed
add projectDir in ModuleResolver and ResolveIncludeVisitor
Signed-off-by: jorgee <jorge.ejarque@seqera.io>
1 parent b3325ce commit 1f7b643

8 files changed

Lines changed: 41 additions & 21 deletions

File tree

modules/nextflow/src/main/groovy/nextflow/module/DefaultRemoteModuleResolver.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ import java.nio.file.Path
4545
class DefaultRemoteModuleResolver implements RemoteModuleResolver {
4646

4747
@Override
48-
Path resolve(String moduleName) {
49-
def baseDir = Global.session?.baseDir ?: Path.of('.').toAbsolutePath()
48+
Path resolve(String moduleName, Path projectDir) {
49+
final baseDir = projectDir ?: Path.of('.').toAbsolutePath()
5050
final config = Global.config ?: new ConfigBuilder().setBaseDir(baseDir).build()
5151
final registryConfig = config.navigate('registry') as RegistryConfig
5252

modules/nextflow/src/main/groovy/nextflow/script/IncludeDef.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ class IncludeDef {
181181
Path resolveRemoteModulePath(String moduleName) {
182182
// Use SPI to get the remote module resolver implementation
183183
def resolver = RemoteModuleResolverProvider.getInstance()
184-
return resolver.resolve(moduleName)
184+
return resolver.resolve(moduleName, session.baseDir)
185185
}
186186

187187
@PackageScope

modules/nextflow/src/main/groovy/nextflow/script/parser/v2/ScriptCompiler.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import groovy.lang.GroovyClassLoader;
3333
import groovy.lang.GroovyCodeSource;
3434
import com.google.common.hash.Hashing;
35+
import nextflow.Global;
3536
import nextflow.script.ast.RecordNode;
3637
import nextflow.script.ast.WorkflowNode;
3738
import nextflow.script.control.CallSiteCollector;
@@ -268,8 +269,9 @@ public void addPhaseOperation(IPrimaryClassNodeOperation op, int phase) {
268269

269270
private void analyze(SourceUnit source) {
270271
// on first pass, recursively add included modules to queue
272+
Path baseDir = Global.getSession() != null ? Global.getSession().getBaseDir() : null;
271273
if( entry == null ) {
272-
modules = new ModuleResolver(compiler).resolve(source, uri -> createSourceUnit(uri));
274+
modules = new ModuleResolver(compiler, baseDir).resolve(source, uri -> createSourceUnit(uri));
273275
for( var su : modules )
274276
addSource(su);
275277
entry = source;
@@ -283,7 +285,7 @@ private void analyze(SourceUnit source) {
283285
var cn = source.getAST().getClasses().get(0);
284286

285287
// perform strict syntax checking
286-
var includeResolver = new ResolveIncludeVisitor(source, compiler);
288+
var includeResolver = new ResolveIncludeVisitor(source, compiler, baseDir);
287289
includeResolver.visit();
288290
for( var error : includeResolver.getErrors() )
289291
source.getErrorCollector().addErrorAndContinue(error);

modules/nf-lang/src/main/java/nextflow/module/spi/FallbackRemoteModuleResolver.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,11 @@
3131
public class FallbackRemoteModuleResolver implements RemoteModuleResolver {
3232

3333
@Override
34-
public Path resolve(String moduleName) {
35-
// Use CWD-relative "modules" directory as a best-effort fallback when no
36-
// RemoteModuleResolver SPI implementation is available (e.g. running outside
37-
// a full Nextflow session).
38-
final Path baseDir = Path.of("modules").toAbsolutePath();
39-
final var resolved = baseDir.resolve(moduleName).normalize();
34+
public Path resolve(String moduleName, Path projectDir) {
35+
final Path modulesDir = (projectDir == null) ? projectDir.resolve("modules") : Path.of("modules").toAbsolutePath();
36+
final var resolved = modulesDir.resolve(moduleName).normalize();
4037
// Prevent path traversal outside the base directory
41-
if (!resolved.startsWith(baseDir.normalize())) {
38+
if (!resolved.startsWith(modulesDir.normalize())) {
4239
throw new IllegalStateException("Invalid module name '" + moduleName + "' - path escapes the modules directory");
4340
}
4441
if (!Files.exists(resolved)) {

modules/nf-lang/src/main/java/nextflow/module/spi/RemoteModuleResolver.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ public interface RemoteModuleResolver {
4747
* </ol>
4848
*
4949
* @param moduleName The module reference string (e.g., '@scope/name' or '@scope/name@version')
50+
* @param projectDir The base directory for the project (used to locate the modules directory)
5051
* @return Path to the resolved module's main.nf file
5152
* @throws IllegalArgumentException if the module reference is invalid or resolution fails
5253
*/
53-
Path resolve(String moduleName);
54+
Path resolve(String moduleName, Path projectDir);
5455

5556
/**
5657
* Get the priority of this resolver. Higher priority resolvers are tried first.

modules/nf-lang/src/main/java/nextflow/script/control/ModuleResolver.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,15 @@
3737
public class ModuleResolver {
3838

3939
private Compiler compiler;
40+
private Path projectDir;
4041

41-
public ModuleResolver(Compiler compiler) {
42+
public ModuleResolver(Compiler compiler, Path projectDir) {
4243
this.compiler = compiler;
44+
this.projectDir = projectDir;
45+
}
46+
47+
public ModuleResolver(Compiler compiler) {
48+
this(compiler, null);
4349
}
4450

4551
/**
@@ -75,7 +81,7 @@ private SourceUnit resolveInclude(IncludeNode node, SourceUnit sourceUnit, Funct
7581
return null;
7682

7783
var includeUri = isRemoteModule(source) ?
78-
RemoteModuleResolverProvider.getInstance().resolve(source).normalize().toUri() :
84+
RemoteModuleResolverProvider.getInstance().resolve(source, projectDir).normalize().toUri() :
7985
getIncludeUri(Path.of(sourceUnit.getSource().getURI()).getParent(), source);
8086
if( compiler.getSource(includeUri) != null )
8187
return null;

modules/nf-lang/src/main/java/nextflow/script/control/ResolveIncludeVisitor.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,22 @@ public class ResolveIncludeVisitor extends ScriptVisitorSupport {
5757

5858
private boolean changed;
5959

60-
public ResolveIncludeVisitor(SourceUnit sourceUnit, Compiler compiler, Set<URI> changedUris) {
60+
private Path projectDir;
61+
62+
public ResolveIncludeVisitor(SourceUnit sourceUnit, Compiler compiler, Set<URI> changedUris, Path projectDir) {
6163
this.sourceUnit = sourceUnit;
6264
this.uri = sourceUnit.getSource().getURI();
6365
this.compiler = compiler;
6466
this.changedUris = changedUris;
67+
this.projectDir = projectDir;
68+
}
69+
70+
public ResolveIncludeVisitor(SourceUnit sourceUnit, Compiler compiler, Path projectDir) {
71+
this(sourceUnit, compiler, null, projectDir);
6572
}
6673

6774
public ResolveIncludeVisitor(SourceUnit sourceUnit, Compiler compiler) {
68-
this(sourceUnit, compiler, null);
75+
this(sourceUnit, compiler, null, null);
6976
}
7077

7178
@Override
@@ -90,7 +97,7 @@ public void visitInclude(IncludeNode node) {
9097
URI includeUri;
9198
if( ModuleResolver.isRemoteModule(source) ) {
9299
try {
93-
includeUri = RemoteModuleResolverProvider.getInstance().resolve(source).normalize().toUri();
100+
includeUri = RemoteModuleResolverProvider.getInstance().resolve(source, projectDir).normalize().toUri();
94101
}
95102
catch( IllegalStateException e ) {
96103
addError(e.getMessage(), node);

modules/nf-lang/src/main/java/nextflow/script/control/ScriptParser.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package nextflow.script.control;
1717

1818
import java.io.File;
19+
import java.nio.file.Path;
1920
import java.util.ArrayList;
2021
import java.util.Collections;
2122

@@ -34,11 +35,17 @@
3435
public class ScriptParser {
3536

3637
private Compiler compiler;
38+
private Path projectDir;
3739

3840
public ScriptParser() {
41+
this(null);
42+
}
43+
44+
public ScriptParser(Path projectDir) {
3945
var config = getConfig();
4046
var classLoader = new GroovyClassLoader();
41-
compiler = new Compiler(config, classLoader);
47+
this.compiler = new Compiler(config, classLoader);
48+
this.projectDir = projectDir;
4249
}
4350

4451
public Compiler compiler() {
@@ -68,11 +75,11 @@ private void parse0(SourceUnit source) {
6875
public void analyze() {
6976
var sources = new ArrayList<>(compiler.getSources().values());
7077
for( var source : sources ) {
71-
new ModuleResolver(compiler()).resolve(source, (uri) -> compiler.createSourceUnit(new File(uri)));
78+
new ModuleResolver(compiler(), projectDir).resolve(source, (uri) -> compiler.createSourceUnit(new File(uri)));
7279
}
7380

7481
for( var source : compiler.getSources().values() ) {
75-
var includeResolver = new ResolveIncludeVisitor(source, compiler);
82+
var includeResolver = new ResolveIncludeVisitor(source, compiler, projectDir);
7683
includeResolver.visit();
7784
for( var error : includeResolver.getErrors() )
7885
source.getErrorCollector().addErrorAndContinue(error);

0 commit comments

Comments
 (0)