Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 42 additions & 44 deletions docs/reference/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ The `disk` directive allows you to define how much local disk storage the proces

```nextflow
process hello {
disk '2 GB'
disk 2.GB

script:
"""
Expand Down Expand Up @@ -692,17 +692,17 @@ The `errorStrategy` directive allows you to define how the process manages an er

The following error strategies are available:

`terminate` (default)
`'terminate'` (default)
: When a task fails, terminate the pipeline immediately and report an error. Pending and running jobs are killed.

`finish`
`'finish'`
: When a task fails, wait for submitted and running tasks to finish and then terminate the pipeline, reporting an error.

`ignore`
`'ignore'`
: When a task fails, ignore it and continue the pipeline execution. If the `workflow.failOnIgnore` config option is set to `true`, the pipeline will report an error (i.e. return a non-zero exit code) upon completion. Otherwise, the pipeline will complete successfully.
: See the {ref}`stdlib-namespaces-workflow` namespace for more information.

`retry`
`'retry'`
: When a task fails, retry it.

When setting the `errorStrategy` directive to `ignore` the process doesn't stop on an error condition, it just reports a message notifying you of the error event.
Expand Down Expand Up @@ -908,34 +908,6 @@ process hello {

See also: [cpus](#cpus) and [memory](#memory).

(process-maxsubmitawait)=

### maxSubmitAwait

The `maxSubmitAwait` directive allows you to specify how long a task can remain in submission queue without being executed.
Elapsed this time the task execution will fail.

When used along with `retry` error strategy, it can be useful to re-schedule the task to a difference queue or
resource requirement. For example:

```nextflow
process hello {
errorStrategy 'retry'
maxSubmitAwait '10 mins'
maxRetries 3
queue "${task.submitAttempt==1 ? 'spot-compute' : 'on-demand-compute'}"

script:
"""
your_command --here
"""
}
```

In the above example the task is submitted to the `spot-compute` on the first attempt (`task.submitAttempt==1`). If the
task execution does not start in the 10 minutes, a failure is reported and a new submission is attempted using the
queue named `on-demand-compute`.

(process-maxerrors)=

### maxErrors
Expand Down Expand Up @@ -1003,6 +975,34 @@ There is a subtle but important difference between `maxRetries` and the `maxErro

See also: [errorStrategy](#errorstrategy) and [maxErrors](#maxerrors).

(process-maxsubmitawait)=

### maxSubmitAwait

The `maxSubmitAwait` directive allows you to specify how long a task can remain in submission queue without being executed.
Elapsed this time the task execution will fail.

When used along with `retry` error strategy, it can be useful to re-schedule the task to a difference queue or
resource requirement. For example:

```nextflow
process hello {
errorStrategy 'retry'
maxSubmitAwait 10.m
maxRetries 3
queue "${task.submitAttempt==1 ? 'spot-compute' : 'on-demand-compute'}"

script:
"""
your_command --here
"""
}
```

In the above example the task is submitted to the `spot-compute` on the first attempt (`task.submitAttempt==1`). If the
task execution does not start in the 10 minutes, a failure is reported and a new submission is attempted using the
queue named `on-demand-compute`.

(process-memory)=

### memory
Expand All @@ -1011,7 +1011,7 @@ The `memory` directive allows you to define how much memory the process is allow

```nextflow
process hello {
memory '2 GB'
memory 2.GB

script:
"""
Expand Down Expand Up @@ -1746,7 +1746,7 @@ The `time` directive allows you to define how long a process is allowed to run.

```nextflow
process hello {
time '1h'
time 1.h

script:
"""
Expand All @@ -1757,15 +1757,13 @@ process hello {

The following time unit suffixes can be used when specifying the duration value:

| Unit | Description |
| ------------------------------- | ------------ |
| `ms`, `milli`, `millis` | Milliseconds |
| `s`, `sec`, `second`, `seconds` | Seconds |
| `m`, `min`, `minute`, `minutes` | Minutes |
| `h`, `hour`, `hours` | Hours |
| `d`, `day`, `days` | Days |

Multiple units can be used in a single declaration, for example: `'1day 6hours 3minutes 30seconds'`
| Unit | Description |
| ---- | ------------ |
| `ms` | Milliseconds |
| `s` | Seconds |
| `m` | Minutes |
| `h` | Hours |
| `d` | Days |

See {ref}`stdlib-types-duration` for more information.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import nextflow.script.control.ResolveIncludeVisitor;
import nextflow.script.control.ScriptResolveVisitor;
import nextflow.script.control.ScriptToGroovyVisitor;
import nextflow.script.control.StripTypesVisitor;
import nextflow.script.control.TypeCheckingVisitor;
import nextflow.script.parser.ScriptParserPluginFactory;
import org.codehaus.groovy.ast.ASTNode;
Expand Down Expand Up @@ -290,6 +291,7 @@ private void analyze(SourceUnit source) {

// convert to Groovy
new ScriptToGroovyVisitor(source).visit();
new StripTypesVisitor(source).visitClass(cn);
new PathCompareVisitor(source).visitClass(cn);
new OpCriteriaVisitor(source).visitClass(cn);
new GStringToStringVisitor(source).visitClass(cn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,26 @@ class ScriptLoaderV2Test extends Dsl2Spec {
noExceptionThrown()
}

def 'should strip unsupported type annotations' () {

given:
def session = new Session()
def parser = new ScriptLoaderV2(session)

def TEXT = '''
// strip cast type
['1', '1.fastq', '2.fastq'] as Tuple<String,String,String>

// strip type annotation in variable declaration
def ch: Channel = channel.empty()
'''

when:
parser.parse(TEXT)
parser.runScript()

then:
noExceptionThrown()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,11 @@ private void checkMethodCall(MethodCallExpression node) {
if( !node.isImplicitThis() )
return;
var name = node.getMethodAsString();
var defNode = vsc.findDslFunction(name, node);
if( defNode != null )
node.putNodeMetaData(ASTNodeMarker.METHOD_TARGET, defNode);
var methods = vsc.findDslFunction(name, node);
if( methods.size() == 1 )
node.putNodeMetaData(ASTNodeMarker.METHOD_TARGET, methods.get(0));
else if( !methods.isEmpty() )
node.putNodeMetaData(ASTNodeMarker.METHOD_OVERLOADS, methods);
else if( !KEYWORDS.contains(name) )
vsc.addError("`" + name + "` is not defined", node.getMethod());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public enum ASTNodeMarker {
// denotes that an assignment is an implicit declaration
IMPLICIT_DECLARATION,

// the inferred return type of a closure expression
INFERRED_RETURN_TYPE,

// the inferred type of an expression
INFERRED_TYPE,

Expand All @@ -39,6 +42,9 @@ public enum ASTNodeMarker {
// the verbatim text of a Groovy-style type annotation (ClassNode)
LEGACY_TYPE,

// the list of candidate MethodNode's for a MethodCallExpression
METHOD_OVERLOADS,

// the MethodNode targeted by a MethodCallExpression
METHOD_TARGET,

Expand All @@ -48,6 +54,9 @@ public enum ASTNodeMarker {
// denotes a nullable type annotation (ClassNode)
NULLABLE,

// the FieldNode targeted by a PropertyExpression
PROPERTY_TARGET,

// the starting quote sequence of a string literal or gstring expression
QUOTE_CHAR,

Expand Down
40 changes: 40 additions & 0 deletions modules/nf-lang/src/main/java/nextflow/script/ast/ASTUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

import groovy.transform.NamedParams;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.AnnotatedNode;
Expand All @@ -30,9 +33,12 @@
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.PropertyNode;
import org.codehaus.groovy.ast.Variable;
import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ClosureExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.ListExpression;
import org.codehaus.groovy.ast.expr.MapExpression;
import org.codehaus.groovy.ast.expr.MapEntryExpression;
import org.codehaus.groovy.ast.expr.MethodCall;
Expand Down Expand Up @@ -145,6 +151,40 @@ public static List<MapEntryExpression> asNamedArgs(MethodCall call) {
: Collections.emptyList();
}

/**
* Given a parameter with a @NamedParams annotation,
* return the map of named params.
*
* @param parameter
*/
public static Map<String, AnnotationNode> asNamedParams(Parameter parameter) {
var namedParams = new LinkedHashMap<String, AnnotationNode>();
parameter.getAnnotations().stream()
.filter(an -> an.getClassNode().getName().equals(NamedParams.class.getName()))
.flatMap(an -> {
var value = an.getMember("value");
return value instanceof ListExpression le
? le.getExpressions().stream()
: Stream.empty();
})
.forEach((value) -> {
if( !(value instanceof AnnotationConstantExpression) )
return;
var ace = (AnnotationConstantExpression) value;
var namedParam = (AnnotationNode) ace.getValue();
var name = namedParam.getMember("value").getText();
namedParams.put(name, namedParam);
});
return namedParams;
}

public static Parameter asNamedParam(AnnotationNode node) {
var name = node.getMember("value").getText();
var typeX = (ClassExpression) node.getMember("type");
var type = typeX != null ? typeX.getType() : ClassHelper.dynamicType();
return new Parameter(type, name);
}

public static VariableExpression asVarX(Statement statement) {
return statement instanceof ExpressionStatement es ? asVarX(es.getExpression()) : null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,20 @@
*/
package nextflow.script.ast;

import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.stmt.Statement;

/**
* An output declaration.
*
* @author Ben Sherman <[email protected]>
*/
public class OutputNode extends ASTNode {
public final String name;
public final ClassNode type;
public class OutputNode extends Parameter {
public final Statement body;

public OutputNode(String name, ClassNode type, Statement body) {
this.name = name;
this.type = type;
super(type, name);
this.body = body;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,30 +69,28 @@ private static ClassNode dummyReturnType(Statement block) {
if( outputs.size() == 1 ) {
var first = outputs.get(0);
var output = ((ExpressionStatement) first).getExpression();
if( outputName(output) == null )
if( outputTarget(output) == null )
return output.getType();
}
var cn = new ClassNode(Record.class);
outputs.stream()
.map(stmt -> ((ExpressionStatement) stmt).getExpression())
.map(output -> outputName(output))
.filter(name -> name != null)
.forEach((name) -> {
var type = ClassHelper.dynamicType();
var fn = new FieldNode(name, Modifier.PUBLIC, type, cn, null);
.map(output -> outputTarget(output))
.filter(target -> target != null)
.forEach((target) -> {
var fn = new FieldNode(target.getName(), Modifier.PUBLIC, target.getType(), cn, null);
fn.setDeclaringClass(cn);
cn.addField(fn);
});
return cn;
}

private static String outputName(Expression output) {
private static VariableExpression outputTarget(Expression output) {
if( output instanceof VariableExpression ve ) {
return ve.getName();
return ve;
}
else if( output instanceof AssignmentExpression ae ) {
var target = (VariableExpression)ae.getLeftExpression();
return target.getName();
if( output instanceof AssignmentExpression ae ) {
return (VariableExpression)ae.getLeftExpression();
}
return null;
}
Expand Down
Loading