Skip to content

Commit 9280b59

Browse files
jorgeebentsherman
andauthored
Refactor lineage annotations as list (#6022)
Signed-off-by: jorgee <[email protected]> Signed-off-by: Jorge Ejarque <[email protected]> Signed-off-by: Ben Sherman <[email protected]> Co-authored-by: Ben Sherman <[email protected]>
1 parent b0191fa commit 9280b59

22 files changed

+143
-167
lines changed

docs/workflow.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -627,9 +627,6 @@ See [Output directives](#output-directives) for the list of available index dire
627627

628628
The following directives are available for each output in the output block:
629629

630-
`annotations`
631-
: Specify annotations to be be applied to every published file. Can be a map or a closure that returns a map.
632-
633630
`index`
634631
: Create an index file which will contain a record of each published value.
635632

@@ -638,12 +635,18 @@ The following directives are available for each output in the output block:
638635
`header`
639636
: When `true`, the keys of the first record are used as the column names (default: `false`). Can also be a list of column names. Only used for CSV files.
640637

638+
`labels`
639+
: Specify labels to be applied to the index file as a list of strings.
640+
641641
`path`
642642
: The name of the index file relative to the base output directory (required). Can be a CSV, JSON, or YAML file.
643643

644644
`sep`
645645
: The character used to separate values (default: `','`). Only used for CSV files.
646646

647+
`labels`
648+
: Specify labels to be applied to every published file. Can be a list of strings or a closure that returns a list.
649+
647650
`path`
648651
: Specify the publish path relative to the output directory (default: `'.'`). Can be a path, a closure that defines a custom directory for each published value, or a closure that publishes individual files using the `>>` operator.
649652

modules/nextflow/src/main/groovy/nextflow/extension/PublishOp.groovy

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import groovy.util.logging.Slf4j
2323
import groovyx.gpars.dataflow.DataflowReadChannel
2424
import nextflow.Session
2525
import nextflow.exception.ScriptRuntimeException
26-
import nextflow.file.FileHelper
2726
import nextflow.processor.PublishDir
2827
import nextflow.trace.event.FilePublishEvent
2928
import nextflow.trace.event.WorkflowOutputEvent
@@ -100,7 +99,7 @@ class PublishOp {
10099
overrides.saveAs = targetResolver
101100
else
102101
overrides.path = targetResolver
103-
overrides.annotations = getAnnotations(publishOpts.annotations, value)
102+
overrides.labels = getLabels(publishOpts.labels, value)
104103

105104
final publisher = PublishDir.create(publishOpts + overrides)
106105

@@ -190,22 +189,27 @@ class PublishOp {
190189
}
191190

192191
/**
193-
* Get or resolve the annotations of a workflow output.
192+
* Get or resolve the labels of a workflow output.
194193
*
195-
* @param annotations Map | Closure<Map>
194+
* @param labels List | Closure<List>
196195
* @param value
197196
*/
198-
protected static Map getAnnotations(annotations, value) {
199-
if( annotations == null )
200-
return [:]
201-
if( annotations instanceof Map )
202-
return annotations
203-
if( annotations instanceof Closure ) {
204-
final result = annotations.call(value)
205-
if( result instanceof Map )
206-
return result
197+
protected static List<String> getLabels(labels, value) {
198+
if( labels == null )
199+
return []
200+
if( labels instanceof List<String> )
201+
return labels
202+
if( labels instanceof Closure ) {
203+
try {
204+
final result = labels.call(value)
205+
if( result instanceof List<String> )
206+
return result
207+
} catch (Throwable e) {
208+
log.warn("Exception while evaluating dynamic `labels` directive for value '$value' -- ${e.getMessage()}")
209+
return []
210+
}
207211
}
208-
throw new ScriptRuntimeException("Invalid output `annotations` directive -- it should be either a Map or a closure that returns a Map")
212+
throw new ScriptRuntimeException("Invalid output `labels` directive -- it should be either a List or a closure that returns a List")
209213
}
210214

211215
/**
@@ -238,7 +242,7 @@ class PublishOp {
238242
else {
239243
log.warn "Invalid extension '${ext}' for index file '${indexPath}' -- should be CSV, JSON, or YAML"
240244
}
241-
session.notifyFilePublish(new FilePublishEvent(null, indexPath))
245+
session.notifyFilePublish(new FilePublishEvent(null, indexPath, indexOpts.labels))
242246
}
243247

244248
log.trace "Publish operator complete"
@@ -365,13 +369,16 @@ class PublishOp {
365369
static class IndexOpts {
366370
Path path
367371
def /* boolean | List<String> */ header = false
372+
List<String> labels
368373
String sep = ','
369374

370375
IndexOpts(Path targetDir, Map opts) {
371376
this.path = targetDir.resolve(opts.path as String)
372377

373378
if( opts.header != null )
374379
this.header = opts.header
380+
if( opts.labels )
381+
this.labels = opts.labels as List<String>
375382
if( opts.sep )
376383
this.sep = opts.sep as String
377384
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ class PublishDir {
111111
private def tags
112112

113113
/**
114-
* Annotations to be associated to the target file
114+
* Labels to be associated to the target file
115115
*/
116-
private Map annotations
116+
private List<String> labels
117117

118118
/**
119119
* The content type of the file. Currently only supported by AWS S3.
@@ -217,8 +217,8 @@ class PublishDir {
217217
if( params.tags != null )
218218
result.tags = params.tags
219219

220-
if( params.annotations != null )
221-
result.annotations = params.annotations as Map
220+
if( params.labels != null )
221+
result.labels = params.labels as List<String>
222222

223223
if( params.contentType instanceof Boolean )
224224
result.contentType = params.contentType
@@ -590,7 +590,7 @@ class PublishDir {
590590
}
591591

592592
protected void notifyFilePublish(Path destination, Path source=null) {
593-
session.notifyFilePublish(new FilePublishEvent(source, destination, annotations))
593+
session.notifyFilePublish(new FilePublishEvent(source, destination, labels))
594594
}
595595

596596
}

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,6 @@ class OutputDsl {
108108

109109
private Map opts = [:]
110110

111-
void annotations(Map value) {
112-
setOption('annotations', value)
113-
}
114-
115-
void annotations(Closure value) {
116-
setOption('annotations', value)
117-
}
118-
119111
void contentType(String value) {
120112
setOption('contentType', value)
121113
}
@@ -141,6 +133,14 @@ class OutputDsl {
141133
setOption('index', dsl.getOptions())
142134
}
143135

136+
void labels(List<String> value) {
137+
setOption('labels', value)
138+
}
139+
140+
void labels(Closure value) {
141+
setOption('labels', value)
142+
}
143+
144144
void mode(String value) {
145145
setOption('mode', value)
146146
}
@@ -194,6 +194,10 @@ class OutputDsl {
194194
setOption('header', value)
195195
}
196196

197+
void labels(List<String> value) {
198+
setOption('labels', value)
199+
}
200+
197201
void path(String value) {
198202
setOption('path', value)
199203
}

modules/nextflow/src/main/groovy/nextflow/trace/event/FilePublishEvent.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class FilePublishEvent {
3838
*/
3939
Path target
4040
/**
41-
* Annotations associated with the published file.
41+
* Labels associated with the published file.
4242
*/
43-
Map<String,String> annotations
43+
List<String> labels
4444
}

modules/nextflow/src/test/groovy/nextflow/script/OutputDslTest.groovy

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ class OutputDslTest extends Specification {
8484
"${outputDir}/barbar/file2.txt"
8585
""".stripIndent()
8686
and:
87-
1 * session.notifyFilePublish(new FilePublishEvent(file1, outputDir.resolve('foo/file1.txt'), [:]))
88-
1 * session.notifyFilePublish(new FilePublishEvent(file2, outputDir.resolve('barbar/file2.txt'), [:]))
87+
1 * session.notifyFilePublish(new FilePublishEvent(file1, outputDir.resolve('foo/file1.txt'), []))
88+
1 * session.notifyFilePublish(new FilePublishEvent(file2, outputDir.resolve('barbar/file2.txt'), []))
8989
1 * session.notifyWorkflowOutput(new WorkflowOutputEvent('foo', [outputDir.resolve('foo/file1.txt')], null))
9090
1 * session.notifyWorkflowOutput(new WorkflowOutputEvent('bar', [outputDir.resolve('barbar/file2.txt')], outputDir.resolve('index.csv')))
9191
1 * session.notifyFilePublish(new FilePublishEvent(null, outputDir.resolve('index.csv'), null))
@@ -125,7 +125,7 @@ class OutputDslTest extends Specification {
125125
then:
126126
outputDir.resolve('file1.txt').text == 'Hello'
127127
and:
128-
1 * session.notifyFilePublish(new FilePublishEvent(file1, outputDir.resolve('file1.txt'), [:]))
128+
1 * session.notifyFilePublish(new FilePublishEvent(file1, outputDir.resolve('file1.txt'), []))
129129
1 * session.notifyWorkflowOutput(new WorkflowOutputEvent('foo', [outputDir.resolve('file1.txt')], null))
130130

131131
cleanup:
@@ -149,6 +149,7 @@ class OutputDslTest extends Specification {
149149
dsl2.overwrite(true)
150150
dsl2.storageClass('someClass')
151151
dsl2.tags([foo:'1',bar:'2'])
152+
dsl2.labels(['label'])
152153
then:
153154
dsl2.getOptions() == [
154155
contentType:'simple/text',
@@ -157,7 +158,8 @@ class OutputDslTest extends Specification {
157158
mode: 'someMode',
158159
overwrite: true,
159160
storageClass: 'someClass',
160-
tags: [foo:'1',bar:'2']
161+
tags: [foo:'1',bar:'2'],
162+
labels: ['label']
161163
]
162164
}
163165

@@ -173,11 +175,13 @@ class OutputDslTest extends Specification {
173175
dsl2.header(true)
174176
dsl2.path('path')
175177
dsl2.sep(',')
178+
dsl2.labels(['label'])
176179
then:
177180
dsl2.getOptions() == [
178181
header: true,
179182
path: 'path',
180-
sep: ','
183+
sep: ',',
184+
labels: ['label']
181185
]
182186
}
183187

modules/nf-lang/src/main/java/nextflow/script/dsl/OutputDsl.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ public interface OutputDsl extends DslScope {
3939
""")
4040
Map<String,Object> getParams();
4141

42-
@Description("""
43-
Specify annotations to be be applied to every published file. Can be a map or a closure that returns a map.
44-
""")
45-
/* Map | Closure */
46-
void annotations(Object value);
47-
4842
@Description("""
4943
*Currently only supported for S3.*
5044
@@ -68,6 +62,12 @@ Enable or disable publishing (default: `true`).
6862
""")
6963
void index(Closure closure);
7064

65+
@Description("""
66+
Specify labels to be be applied to every published file.
67+
""")
68+
/* List | Closure */
69+
void labels(Object value);
70+
7171
@Description("""
7272
The file publishing method (default: `'symlink'`).
7373
""")
@@ -106,6 +106,11 @@ interface IndexDsl extends DslScope {
106106
/* List<String> | Boolean */
107107
void header(Object value);
108108

109+
@Description("""
110+
Specify labels to be applied to the index file.
111+
""")
112+
void labels(List<String> value);
113+
109114
@Description("""
110115
Closure which defines how to transform each published value into a CSV record. The closure should return a list or map. By default, no transformation is applied.
111116
""")

modules/nf-lineage/src/main/nextflow/lineage/DefaultLinStore.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class DefaultLinStore implements LinStore {
101101
return searchAllFiles(params)
102102
}
103103

104-
private Map<String, LinSerializable> searchAllFiles(Map<String,String> params) {
104+
private Map<String, LinSerializable> searchAllFiles(Map<String,List<String>> params) {
105105
final results = new HashMap<String, LinSerializable>()
106106

107107
Files.walkFileTree(location, new FileVisitor<Path>() {

modules/nf-lineage/src/main/nextflow/lineage/LinObserver.groovy

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import java.time.OffsetDateTime
2626
import groovy.transform.CompileStatic
2727
import groovy.util.logging.Slf4j
2828
import nextflow.Session
29-
import nextflow.lineage.model.Annotation
3029
import nextflow.lineage.model.Checksum
3130
import nextflow.lineage.model.FileOutput
3231
import nextflow.lineage.model.DataPath
@@ -37,7 +36,6 @@ import nextflow.lineage.model.WorkflowOutput
3736
import nextflow.lineage.model.WorkflowRun
3837
import nextflow.file.FileHelper
3938
import nextflow.file.FileHolder
40-
import nextflow.processor.TaskHandler
4139
import nextflow.processor.TaskRun
4240
import nextflow.script.ScriptMeta
4341
import nextflow.script.params.BaseParam
@@ -55,7 +53,6 @@ import nextflow.script.params.StdOutParam
5553
import nextflow.script.params.ValueInParam
5654
import nextflow.script.params.ValueOutParam
5755
import nextflow.trace.TraceObserverV2
58-
import nextflow.trace.TraceRecord
5956
import nextflow.trace.event.FilePublishEvent
6057
import nextflow.trace.event.TaskEvent
6158
import nextflow.trace.event.WorkflowOutputEvent
@@ -362,21 +359,13 @@ class LinObserver implements TraceObserverV2 {
362359
attrs.size(),
363360
LinUtils.toDate(attrs?.creationTime()),
364361
LinUtils.toDate(attrs?.lastModifiedTime()),
365-
convertAnnotations(event.annotations))
362+
event.labels)
366363
store.save(key, value)
367364
} catch (Throwable e) {
368365
log.warn("Unexpected error storing published file '${event.target.toUriString()}' for workflow '${executionHash}'", e)
369366
}
370367
}
371368

372-
private static List<Annotation> convertAnnotations(Map annotations){
373-
if( !annotations )
374-
return null
375-
final converted = new LinkedList<Annotation>()
376-
annotations.forEach { Object key, Object value -> converted.add(new Annotation(key.toString(), value)) }
377-
return converted
378-
}
379-
380369
String getSourceReference(Path source){
381370
final hash = FileHelper.getTaskHashFromPath(source, session.workDir)
382371
if (hash) {

modules/nf-lineage/src/main/nextflow/lineage/LinPropertyValidator.groovy

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
package nextflow.lineage
1818

1919
import groovy.transform.CompileStatic
20-
import nextflow.lineage.model.Annotation
2120
import nextflow.lineage.model.Checksum
2221
import nextflow.lineage.model.DataPath
22+
import nextflow.lineage.model.FileOutput
2323
import nextflow.lineage.model.Parameter
2424
import nextflow.lineage.model.TaskOutput
2525
import nextflow.lineage.model.TaskRun
@@ -36,10 +36,9 @@ import nextflow.lineage.model.WorkflowRun
3636
class LinPropertyValidator {
3737

3838
private static final List<Class> LIN_MODEL_CLASSES = [
39-
Annotation,
4039
Checksum,
41-
DataOutput,
4240
DataPath,
41+
FileOutput,
4342
Parameter,
4443
TaskOutput,
4544
TaskRun,
@@ -71,8 +70,8 @@ class LinPropertyValidator {
7170
}
7271
}
7372

74-
void validateQueryParams(Map<String, String> params) {
75-
for( String key : params.keySet() ) {
73+
void validateQueryParams(Collection<String> keys) {
74+
for( final key : keys ) {
7675
validate(key.tokenize('.'))
7776
}
7877
}

0 commit comments

Comments
 (0)