Skip to content

Commit

Permalink
Unexpected config selector warning #1167
Browse files Browse the repository at this point in the history
  • Loading branch information
pditommaso committed Jun 8, 2019
1 parent c7e2a47 commit 52e70e3
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 26 deletions.
6 changes: 3 additions & 3 deletions modules/nextflow/src/main/groovy/nextflow/Session.groovy
Expand Up @@ -878,8 +878,8 @@ class Session implements ISession {
else if( key.startsWith('withName:') ) {
name = key.substring('withName:'.length())
}
if( name && !isValidProcessName(processNames, name, result) )
break
if( name )
checkValidProcessName(processNames, name, result)
}

return result
Expand All @@ -893,7 +893,7 @@ class Session implements ISession {
* @param errorMessage A list of strings used to return the error message to the caller
* @return {@code true} if the name specified belongs to the list of process names or {@code false} otherwise
*/
protected boolean isValidProcessName(Collection<String> processNames, String selector, List<String> errorMessage) {
protected boolean checkValidProcessName(Collection<String> processNames, String selector, List<String> errorMessage) {
final matches = processNames.any { name -> ProcessConfig.matchesSelector(name, selector) }
if( matches )
return true
Expand Down
Expand Up @@ -16,6 +16,8 @@

package nextflow.ast

import static org.codehaus.groovy.ast.tools.GeneralUtils.*

import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import nextflow.script.BaseScript
Expand All @@ -32,6 +34,7 @@ import nextflow.script.TokenVar
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.ClassCodeVisitorSupport
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.ConstructorNode
import org.codehaus.groovy.ast.MethodNode
import org.codehaus.groovy.ast.Parameter
import org.codehaus.groovy.ast.VariableScope
Expand Down Expand Up @@ -61,7 +64,6 @@ import org.codehaus.groovy.syntax.SyntaxException
import org.codehaus.groovy.syntax.Types
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.transform.GroovyASTTransformation
import static org.codehaus.groovy.ast.tools.GeneralUtils.constX
/**
* Implement some syntax sugars of Nextflow DSL scripting.
*
Expand Down Expand Up @@ -130,6 +132,62 @@ class NextflowDSLImpl implements ASTTransformation {
super.visitMethod(node)
}

/**
* Creates a statement that invokes the {@link nextflow.script.ScriptMeta#setProcessNames(java.util.List)} (java.util.List)} method
* used to initialize the script with metadata collected during script parsing
*
* @return The method invocation statement
*/
protected Statement makeSetProcessNamesStm() {
final names = new ListExpression()
for( String it: processNames ) {
names.addExpression(new ConstantExpression(it.toString()))
}

// the method list argument
final args = new ArgumentListExpression()
args.addExpression(names)

// some magic code
// this generates the invocation of the method:
// nextflow.script.ScriptMeta.get(this).setProcessNames(<list of process names>)
final scriptMeta = new PropertyExpression( new PropertyExpression(new VariableExpression('nextflow'),'script'), 'ScriptMeta')
final thiz = new ArgumentListExpression(); thiz.addExpression( new VariableExpression('this') )
final meta = new MethodCallExpression( scriptMeta, 'get', thiz )
final call = new MethodCallExpression( meta, 'setProcessNames', args)
final stm = new ExpressionStatement(call)
return stm
}

/**
* Add to constructor a method call to inject parsed metadata
*
* @param node
*/
protected void injectMetadata(ClassNode node) {
for( ConstructorNode constructor : node.getDeclaredConstructors() ) {
def code = constructor.getCode()
if( code instanceof BlockStatement ) {
code.addStatement(makeSetProcessNamesStm())
}
else if( code instanceof ExpressionStatement ) {
def expr = code
def block = new BlockStatement()
block.addStatement(expr)
block.addStatement(makeSetProcessNamesStm())
constructor.setCode(block)
}
else
throw new IllegalStateException("Invalid constructor expression: $code")
}
}

@Override
protected void visitObjectInitializerStatements(ClassNode node) {
if( node.getSuperClass().getName() == BaseScript.getName() )
injectMetadata(node)
super.visitObjectInitializerStatements(node)
}

@Override
void visitMethodCallExpression(MethodCallExpression methodCall) {
Expand Down
32 changes: 20 additions & 12 deletions modules/nextflow/src/main/groovy/nextflow/script/ScriptMeta.groovy
Expand Up @@ -75,6 +75,8 @@ class ScriptMeta {
/** Whenever it's a module script or the main script */
private boolean module

private List<String> processNames = Collections.emptyList()

Path getScriptPath() { scriptPath }

boolean isModule() { module }
Expand All @@ -99,6 +101,11 @@ class ScriptMeta {
this.module = val
}

@PackageScope
void setProcessNames(List<String> names) {
this.processNames = names
}

@PackageScope
static ScriptMeta register(BaseScript script) {
def meta = new ScriptMeta(script)
Expand Down Expand Up @@ -156,18 +163,19 @@ class ScriptMeta {
}

Set<String> getProcessNames() {
def result = new HashSet(definitions.size() + imports.size())
// local definitions
for( def item : definitions.values() ) {
if( item instanceof ProcessDef )
result.add(item.name)
}
// processes from imports
for( def item: imports.values() ) {
if( item instanceof ProcessDef )
result.add(item.name)
}
return result
new HashSet<String>(processNames)
// def result = new HashSet(definitions.size() + imports.size())
// // local definitions
// for( def item : definitions.values() ) {
// if( item instanceof ProcessDef )
// result.add(item.name)
// }
// // processes from imports
// for( def item: imports.values() ) {
// if( item instanceof ProcessDef )
// result.add(item.name)
// }
// return result
}

void addModule(BaseScript script, String name, String alias) {
Expand Down
Expand Up @@ -425,7 +425,7 @@ class SessionTest extends Specification {

when:
def error = []
session.isValidProcessName(NAMES, SELECTOR, error)
session.checkValidProcessName(NAMES, SELECTOR, error)
then:
error[0] == MSG

Expand Down
@@ -1,13 +1,11 @@
package nextflow.ast

import spock.lang.Specification

import groovy.transform.InheritConstructors
import nextflow.script.BaseScript
import nextflow.script.IncludeDef
import nextflow.script.ScriptMeta
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.MultipleCompilationErrorsException
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import spock.lang.Specification
/**
*
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
Expand Down Expand Up @@ -97,5 +95,29 @@ class NextflowDSLImplTest extends Specification {
}


def 'should set process name in the script meta' () {
given:
def config = new CompilerConfiguration()
config.setScriptBaseClass(BaseScript.class.name)
config.addCompilationCustomizers( new ASTTransformationCustomizer(NextflowDSL))

def SCRIPT = '''
process alpha {
/hello/
}
process beta {
/world/
}
'''

when:
def script = new GroovyShell(config).parse(SCRIPT)
then:
ScriptMeta.get(script).processNames == ['alpha','beta'] as Set
}


}
Expand Up @@ -43,9 +43,9 @@ class ScriptMetaTest extends Specification {
meta.getComponent('xxx') == null
meta.getComponent('yyy') == null

then:
meta.getProcessNames() as Set == ['proc1','proc2'] as Set

// then:
// meta.getProcessNames() as Set == ['proc1','proc2'] as Set
//
}

def 'should add imports' () {
Expand Down Expand Up @@ -102,8 +102,8 @@ class ScriptMetaTest extends Specification {
meta1.getComponent('my_process') instanceof ProcessDef
meta1.getComponent('my_process').name == 'my_process'

then:
meta1.getProcessNames() == ['proc1','proc2','my_process'] as Set
// then:
// meta1.getProcessNames() == ['proc1','proc2','my_process'] as Set
}


Expand Down

0 comments on commit 52e70e3

Please sign in to comment.