Build branch main with version main (219bd58)
Build pipeline: viash-hub.demultiplex.main-ks4jt
Source commit: 219bd5816e
Source message: Allow 'Undetermined' samples to be empty. (#50)
This commit is contained in:
18
CHANGELOG.md
18
CHANGELOG.md
@@ -1,3 +1,19 @@
|
||||
# demultiplex v0.3.12
|
||||
|
||||
## New features
|
||||
|
||||
* Add support for Nextflow versions version starting 25.xx.xx (PR #50).
|
||||
|
||||
## Bug fixes
|
||||
|
||||
* Allow FASTQ files for `Undetermined` to be empty (PR #50).
|
||||
|
||||
# demultiplex v0.3.11
|
||||
|
||||
## New features
|
||||
|
||||
* Output demultiplexer logs and metrics (PR #41).
|
||||
|
||||
# demultiplex v0.3.10
|
||||
|
||||
## Minor changes
|
||||
@@ -16,8 +32,6 @@
|
||||
|
||||
* Bump viash to 0.9.4, which adds support for nextflow versions starting major version 25.01 (PR #43 and #44).
|
||||
|
||||
* Output demultiplexer logs and metrics (PR #41).
|
||||
|
||||
# demultiplex v0.3.8
|
||||
|
||||
## Bug fixes
|
||||
|
||||
@@ -153,7 +153,7 @@ workflow:
|
||||
``` bash
|
||||
nextflow run \
|
||||
vsh/demultiplex \
|
||||
-r v0.3.9 \
|
||||
-r v0.3.11 \
|
||||
--help
|
||||
```
|
||||
|
||||
@@ -165,7 +165,7 @@ instance using the following:
|
||||
|
||||
``` bash
|
||||
nextflow run vsh/demultiplex \
|
||||
-revision v0.3.9 \
|
||||
-revision v0.3.11 \
|
||||
-main-script target/nextflow/workflows/runner/main.nf \
|
||||
--help
|
||||
```
|
||||
@@ -175,7 +175,7 @@ command:
|
||||
|
||||
``` bash
|
||||
nextflow run vsh/demultiplex \
|
||||
-r v0.3.9 \
|
||||
-r v0.3.11 \
|
||||
-main-script target/nextflow/runner/main.nf \
|
||||
--input "gs://viash-hub-resources/demultiplex/v3/demultiplex_htrnaseq_meta/SingleCell-RNA_P3_2" \
|
||||
--demultiplexer bclconvert \
|
||||
|
||||
@@ -129,7 +129,7 @@ You can check if everything is working by getting the `--help` for a workflow:
|
||||
```bash
|
||||
nextflow run \
|
||||
vsh/demultiplex \
|
||||
-r v0.3.9 \
|
||||
-r v0.3.11 \
|
||||
--help
|
||||
```
|
||||
|
||||
@@ -141,7 +141,7 @@ using the following:
|
||||
|
||||
``` bash
|
||||
nextflow run vsh/demultiplex \
|
||||
-revision v0.3.9 \
|
||||
-revision v0.3.11 \
|
||||
-main-script target/nextflow/workflows/runner/main.nf \
|
||||
--help
|
||||
```
|
||||
@@ -150,7 +150,7 @@ Having this project available locally, you can run the following command:
|
||||
|
||||
```bash
|
||||
nextflow run vsh/demultiplex \
|
||||
-r v0.3.9 \
|
||||
-r v0.3.11 \
|
||||
-main-script target/nextflow/runner/main.nf \
|
||||
--input "gs://viash-hub-resources/demultiplex/v3/demultiplex_htrnaseq_meta/SingleCell-RNA_P3_2" \
|
||||
--demultiplexer bclconvert \
|
||||
|
||||
@@ -30,6 +30,17 @@ resources:
|
||||
- type: nextflow_script
|
||||
path: main.nf
|
||||
entrypoint: run_wf
|
||||
test_resources:
|
||||
- type: nextflow_script
|
||||
path: test.nf
|
||||
entrypoint: test_gather_and_validate
|
||||
- type: nextflow_script
|
||||
path: test.nf
|
||||
entrypoint: test_undetermined_empty
|
||||
- type: nextflow_script
|
||||
path: test.nf
|
||||
entrypoint: test_without_index
|
||||
- path: test_data
|
||||
|
||||
runners:
|
||||
- type: nextflow
|
||||
|
||||
33
src/dataflow/gather_fastqs_and_validate/integration_tests.sh
Executable file
33
src/dataflow/gather_fastqs_and_validate/integration_tests.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
# get the root of the directory
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
|
||||
# ensure that the command below is run from the root of the repository
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
viash ns build --setup cb -q gather_fastqs_and_validate
|
||||
|
||||
nextflow run . \
|
||||
-main-script src/dataflow/gather_fastqs_and_validate/test.nf \
|
||||
-profile docker,no_publish,local \
|
||||
-entry test_gather_and_validate \
|
||||
-c src/config/labels.config \
|
||||
-resume
|
||||
|
||||
nextflow run . \
|
||||
-main-script src/dataflow/gather_fastqs_and_validate/test.nf \
|
||||
-profile docker,no_publish,local \
|
||||
-entry test_undetermined_empty \
|
||||
-c src/config/labels.config \
|
||||
-resume
|
||||
|
||||
nextflow run . \
|
||||
-main-script src/dataflow/gather_fastqs_and_validate/test.nf \
|
||||
-profile docker,no_publish,local \
|
||||
-entry test_without_index \
|
||||
-c src/config/labels.config \
|
||||
-resume
|
||||
|
||||
@@ -33,7 +33,8 @@ workflow run_wf {
|
||||
def sample_sheet = state.sample_sheet
|
||||
def start_parsing = false
|
||||
def sample_id_column_index = null
|
||||
def samples = ["Undetermined"]
|
||||
def undetermined_sample_name = "Undetermined"
|
||||
def samples = [undetermined_sample_name]
|
||||
def original_id = id
|
||||
|
||||
// Parse sample sheet for sample IDs
|
||||
@@ -92,8 +93,9 @@ workflow run_wf {
|
||||
processed_samples = samples.collect { sample_id ->
|
||||
def forward_regex = ~/^${sample_id}_S(\d+)_(L(\d+)_)?R1_(\d+)\.fastq\.gz$/
|
||||
def reverse_regex = ~/^${sample_id}_S(\d+)_(L(\d+)_)?R2_(\d+)\.fastq\.gz$/
|
||||
def forward_fastq = state.input.listFiles().findAll{it.isFile() && it.name ==~ forward_regex}
|
||||
def reverse_fastq = state.input.listFiles().findAll{it.isFile() && it.name ==~ reverse_regex}
|
||||
// Sort is needed here because multiple lanes (_L00*_) might be present and they need to be in the same order in both lists
|
||||
def forward_fastq = state.input.listFiles().findAll{it.isFile() && it.name ==~ forward_regex}.sort()
|
||||
def reverse_fastq = state.input.listFiles().findAll{it.isFile() && it.name ==~ reverse_regex}.sort()
|
||||
assert forward_fastq && !forward_fastq.isEmpty(): "No forward fastq files were found for sample ${sample_id}. " +
|
||||
"All fastq files in directory: ${allfastqs.collect{it.name}}"
|
||||
assert (reverse_fastq.isEmpty() || (forward_fastq.size() == reverse_fastq.size())):
|
||||
@@ -102,7 +104,7 @@ workflow run_wf {
|
||||
println "Found ${forward_fastq.size()} forward and ${reverse_fastq.size()} reverse " +
|
||||
"fastq files for sample ${sample_id}"
|
||||
|
||||
assert forward_fastq.every{!is_empty(it)} && reverse_fastq.every{!is_empty(it)}:
|
||||
assert sample_id == undetermined_sample_name || (forward_fastq.every{!is_empty(it)} && reverse_fastq.every{!is_empty(it)}):
|
||||
"A fastq file for sample '${sample_id}' appears to be empty!"
|
||||
def fastqs_state = [
|
||||
"fastq_forward": forward_fastq,
|
||||
|
||||
10
src/dataflow/gather_fastqs_and_validate/nextflow.config
Normal file
10
src/dataflow/gather_fastqs_and_validate/nextflow.config
Normal file
@@ -0,0 +1,10 @@
|
||||
manifest {
|
||||
nextflowVersion = '!>=20.12.1-edge'
|
||||
}
|
||||
|
||||
params {
|
||||
rootDir = java.nio.file.Paths.get("$projectDir/../../../").toAbsolutePath().normalize().toString()
|
||||
}
|
||||
|
||||
// include common settings
|
||||
includeConfig("${params.rootDir}/src/config/labels.config")
|
||||
86
src/dataflow/gather_fastqs_and_validate/test.nf
Normal file
86
src/dataflow/gather_fastqs_and_validate/test.nf
Normal file
@@ -0,0 +1,86 @@
|
||||
nextflow.enable.dsl=2
|
||||
|
||||
include { gather_fastqs_and_validate } from params.rootDir + "/target/nextflow/dataflow/gather_fastqs_and_validate/main.nf"
|
||||
|
||||
|
||||
workflow test_gather_and_validate {
|
||||
output_ch = Channel.fromList([
|
||||
[
|
||||
id: "run1",
|
||||
input: params.rootDir + "/src/dataflow/gather_fastqs_and_validate/test_data/fastqs",
|
||||
sample_sheet: params.rootDir + "/src/dataflow/gather_fastqs_and_validate/test_data/samplesheet.csv",
|
||||
]
|
||||
])
|
||||
| map { state -> [state.id, state]}
|
||||
| gather_fastqs_and_validate.run(toState: ["fastq_forward", "fastq_reverse"])
|
||||
|
||||
output_ch
|
||||
| toSortedList{a, b -> a[0] <=> b[0]}
|
||||
| view {"Output: $it"}
|
||||
| map {
|
||||
assert it.size() == 3: "Expected three fastq pairs"
|
||||
def first_pair = it[0][1]
|
||||
assert first_pair.fastq_forward.collect{it.name} == ["Undetermined_S1_R1_001.fastq.gz"]
|
||||
assert first_pair.fastq_reverse.collect{it.name} == ["Undetermined_S1_R2_001.fastq.gz"]
|
||||
def second_pair = it[1][1]
|
||||
assert second_pair.fastq_forward.collect{it.name} == ["sample1_S1_L001_R1_001.fastq.gz", "sample1_S1_L002_R1_001.fastq.gz"]
|
||||
assert second_pair.fastq_reverse.collect{it.name} == ["sample1_S1_L001_R2_001.fastq.gz", "sample1_S1_L002_R2_001.fastq.gz"]
|
||||
def undetermined_pair = it[2][1]
|
||||
assert undetermined_pair.fastq_forward.collect{it.name} == ["sample2_S1_L001_R1_001.fastq.gz"]
|
||||
assert undetermined_pair.fastq_reverse.collect{it.name} == ["sample2_S1_L001_R2_001.fastq.gz"]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
workflow test_undetermined_empty {
|
||||
output_ch = Channel.fromList([
|
||||
[
|
||||
id: "run1",
|
||||
input: params.rootDir + "/src/dataflow/gather_fastqs_and_validate/test_data/fastqs_undetermined_empty",
|
||||
sample_sheet: params.rootDir + "/src/dataflow/gather_fastqs_and_validate/test_data/samplesheet.csv",
|
||||
]
|
||||
])
|
||||
| map { state -> [state.id, state]}
|
||||
| gather_fastqs_and_validate.run(toState: ["fastq_forward", "fastq_reverse"])
|
||||
|
||||
output_ch
|
||||
| toSortedList{a, b -> a[0] <=> b[0]}
|
||||
| view {"Output: $it"}
|
||||
| map {
|
||||
assert it.size() == 3: "Expected three fastq pairs"
|
||||
def first_pair = it[0][1]
|
||||
assert first_pair.fastq_forward.collect{it.name} == ["Undetermined_S1_R1_001.fastq.gz"]
|
||||
assert first_pair.fastq_reverse.collect{it.name} == ["Undetermined_S1_R2_001.fastq.gz"]
|
||||
def second_pair = it[1][1]
|
||||
assert second_pair.fastq_forward.collect{it.name} == ["sample1_S1_L001_R1_001.fastq.gz", "sample1_S1_L002_R1_001.fastq.gz"]
|
||||
assert second_pair.fastq_reverse.collect{it.name} == ["sample1_S1_L001_R2_001.fastq.gz", "sample1_S1_L002_R2_001.fastq.gz"]
|
||||
def undetermined_pair = it[2][1]
|
||||
assert undetermined_pair.fastq_forward.collect{it.name} == ["sample2_S1_L001_R1_001.fastq.gz"]
|
||||
assert undetermined_pair.fastq_reverse.collect{it.name} == ["sample2_S1_L001_R2_001.fastq.gz"]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
workflow test_without_index {
|
||||
output_ch = Channel.fromList([
|
||||
[
|
||||
id: "run1",
|
||||
input: params.rootDir + "/src/dataflow/gather_fastqs_and_validate/test_data/fastqs_undetermined_empty",
|
||||
sample_sheet: params.rootDir + "/src/dataflow/gather_fastqs_and_validate/test_data/samplesheet_no_index.csv",
|
||||
]
|
||||
])
|
||||
| map { state -> [state.id, state]}
|
||||
| gather_fastqs_and_validate.run(toState: ["fastq_forward", "fastq_reverse"])
|
||||
|
||||
output_ch
|
||||
| toSortedList{a, b -> a[0] <=> b[0]}
|
||||
| view {"Output: $it"}
|
||||
| map {
|
||||
assert it.size() == 2: "Expected two fastq pairs"
|
||||
def first_pair = it[0][1]
|
||||
assert first_pair.fastq_forward.collect{it.name} == ["Undetermined_S1_R1_001.fastq.gz"]
|
||||
assert first_pair.fastq_reverse.collect{it.name} == ["Undetermined_S1_R2_001.fastq.gz"]
|
||||
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
[foo],,,,
|
||||
[somecontent],,,,
|
||||
bar,lorem,,,
|
||||
,,,,
|
||||
# Comment
|
||||
|
||||
[BCLConvert_Data],,,,
|
||||
Sample_ID,Index,Index2,,
|
||||
sample1,GTAGCCCTGT,GAGCATCTAT,,
|
||||
sample2,TCGGCTCTAC,CCGATGGTCT,,
|
||||
,,,,
|
||||
|
@@ -0,0 +1,10 @@
|
||||
[foo],,,,
|
||||
[somecontent],,,,
|
||||
bar,lorem,,,
|
||||
,,,,
|
||||
# Comment
|
||||
|
||||
[BCLConvert_Data],,,,
|
||||
Sample_ID,Index,Index2,,
|
||||
sample1,,,,
|
||||
,,,,
|
||||
|
@@ -101,7 +101,7 @@ repositories:
|
||||
- name: bb
|
||||
type: vsh
|
||||
repo: biobox
|
||||
tag: v0.3.0
|
||||
tag: v0.3.1
|
||||
|
||||
runners:
|
||||
- type: nextflow
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: "bases2fastq"
|
||||
version: "v0.3.0"
|
||||
version: "v0.3.1"
|
||||
authors:
|
||||
- name: "Dries Schaumont"
|
||||
roles:
|
||||
@@ -285,6 +285,9 @@ test_resources:
|
||||
is_executable: true
|
||||
info: null
|
||||
status: "enabled"
|
||||
scope:
|
||||
image: "public"
|
||||
target: "public"
|
||||
requirements:
|
||||
commands:
|
||||
- "ps"
|
||||
@@ -367,7 +370,7 @@ engines:
|
||||
id: "docker"
|
||||
image: "elembio/bases2fastq:2.1.0"
|
||||
target_registry: "images.viash-hub.com"
|
||||
target_tag: "v0.3.0"
|
||||
target_tag: "v0.3.1"
|
||||
namespace_separator: "/"
|
||||
setup:
|
||||
- type: "apt"
|
||||
@@ -393,23 +396,34 @@ build_info:
|
||||
engine: "docker|native"
|
||||
output: "target/nextflow/bases2fastq"
|
||||
executable: "target/nextflow/bases2fastq/main.nf"
|
||||
viash_version: "0.9.0"
|
||||
git_commit: "d86bd5cf62104af02caa852aacd352b1aa97ed60"
|
||||
git_remote: "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox"
|
||||
git_tag: "v0.2.0-29-gd86bd5c"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "98a5f3cc745525a65c10263d25cf414eb1093223"
|
||||
git_remote: "https://github.com/viash-hub/biobox"
|
||||
git_tag: "v0.3.0-8-g98a5f3c"
|
||||
package_config:
|
||||
name: "biobox"
|
||||
version: "v0.3.0"
|
||||
description: "A collection of bioinformatics tools for working with sequence data.\n"
|
||||
version: "v0.3.1"
|
||||
summary: "A curated collection of high-quality, standalone bioinformatics components\
|
||||
\ built with [Viash](https://viash.io).\n"
|
||||
description: "`biobox` offers a suite of reliable bioinformatics components, similar\
|
||||
\ to [nf-core/modules](https://github.com/nf-core/modules) and [snakemake-wrappers/bio](https://github.com/snakemake/snakemake-wrappers/tree/master/bio),\
|
||||
\ but built using the [Viash](https://viash.io) framework.\n\nThis approach emphasizes\
|
||||
\ **reusability**, **reproducibility**, and adherence to **best practices**. Key\
|
||||
\ features of `biobox` components include:\n\n* **Standalone & Nextflow Ready:**\
|
||||
\ Run components directly via the command line or seamlessly integrate them into\
|
||||
\ Nextflow workflows.\n* **High Quality Standards:**\n * Comprehensive documentation\
|
||||
\ for components and parameters.\n * Full exposure of underlying tool arguments.\n\
|
||||
\ * Containerized (Docker) for dependency management and reproducibility.\n\
|
||||
\ * Unit tested for verified functionality.\n"
|
||||
info: null
|
||||
viash_version: "0.9.0"
|
||||
viash_version: "0.9.4"
|
||||
source: "src"
|
||||
target: "target"
|
||||
config_mods:
|
||||
- ".requirements.commands := ['ps']\n"
|
||||
- ".engines += { type: \"native\" }"
|
||||
- ".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'"
|
||||
- ".engines[.type == 'docker'].target_tag := 'v0.3.0'"
|
||||
- ".engines[.type == 'docker'].target_tag := 'v0.3.1'"
|
||||
keywords:
|
||||
- "bioinformatics"
|
||||
- "modules"
|
||||
@@ -1,6 +1,6 @@
|
||||
// bases2fastq v0.3.0
|
||||
// bases2fastq v0.3.1
|
||||
//
|
||||
// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative
|
||||
// This wrapper script is auto-generated by viash 0.9.4 and is thus a derivative
|
||||
// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data
|
||||
// Intuitive.
|
||||
//
|
||||
@@ -85,64 +85,56 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
foundClass = "List[${e.foundClass}]"
|
||||
}
|
||||
} else if (par.type == "string") {
|
||||
// cast to string if need be
|
||||
// cast to string if need be. only cast if the value is a GString
|
||||
if (value instanceof GString) {
|
||||
value = value.toString()
|
||||
value = value as String
|
||||
}
|
||||
expectedClass = value instanceof String ? null : "String"
|
||||
} else if (par.type == "integer") {
|
||||
// cast to integer if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Integer) {
|
||||
try {
|
||||
value = value.toInteger()
|
||||
value = value as Integer
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Integer"
|
||||
}
|
||||
}
|
||||
if (value instanceof java.math.BigInteger) {
|
||||
value = value.intValue()
|
||||
}
|
||||
expectedClass = value instanceof Integer ? null : "Integer"
|
||||
} else if (par.type == "long") {
|
||||
// cast to long if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Long) {
|
||||
try {
|
||||
value = value.toLong()
|
||||
value = value as Long
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Long"
|
||||
}
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
value = value.toLong()
|
||||
}
|
||||
expectedClass = value instanceof Long ? null : "Long"
|
||||
} else if (par.type == "double") {
|
||||
// cast to double if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Double) {
|
||||
try {
|
||||
value = value.toDouble()
|
||||
value = value as Double
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Double"
|
||||
}
|
||||
}
|
||||
if (value instanceof java.math.BigDecimal) {
|
||||
value = value.doubleValue()
|
||||
} else if (par.type == "float") {
|
||||
// cast to float if need be
|
||||
if (value !instanceof Float) {
|
||||
try {
|
||||
value = value as Float
|
||||
} catch (NumberFormatException e) {
|
||||
expectedClass = "Float"
|
||||
}
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
value = value.toDouble()
|
||||
}
|
||||
expectedClass = value instanceof Double ? null : "Double"
|
||||
} else if (par.type == "boolean" | par.type == "boolean_true" | par.type == "boolean_false") {
|
||||
// cast to boolean if need be
|
||||
if (value instanceof String) {
|
||||
def valueLower = value.toLowerCase()
|
||||
if (valueLower == "true") {
|
||||
value = true
|
||||
} else if (valueLower == "false") {
|
||||
value = false
|
||||
if (value !instanceof Boolean) {
|
||||
try {
|
||||
value = value as Boolean
|
||||
} catch (Exception e) {
|
||||
expectedClass = "Boolean"
|
||||
}
|
||||
}
|
||||
expectedClass = value instanceof Boolean ? null : "Boolean"
|
||||
} else if (par.type == "file" && (par.direction == "input" || stage == "output")) {
|
||||
// cast to path if need be
|
||||
if (value instanceof String) {
|
||||
@@ -154,10 +146,13 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
expectedClass = value instanceof Path ? null : "Path"
|
||||
} else if (par.type == "file" && stage == "input" && par.direction == "output") {
|
||||
// cast to string if need be
|
||||
if (value instanceof GString) {
|
||||
value = value.toString()
|
||||
if (value !instanceof String) {
|
||||
try {
|
||||
value = value as String
|
||||
} catch (Exception e) {
|
||||
expectedClass = "String"
|
||||
}
|
||||
}
|
||||
expectedClass = value instanceof String ? null : "String"
|
||||
} else {
|
||||
// didn't find a match for par.type
|
||||
expectedClass = par.type
|
||||
@@ -176,7 +171,7 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
Map _processInputValues(Map inputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.required) {
|
||||
if (arg.required && arg.direction == "input") {
|
||||
assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing"
|
||||
}
|
||||
@@ -195,15 +190,8 @@ Map _processInputValues(Map inputs, Map config, String id, String key) {
|
||||
}
|
||||
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf'
|
||||
Map _processOutputValues(Map outputs, Map config, String id, String key) {
|
||||
Map _checkValidOutputArgument(Map outputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.direction == "output" && arg.required) {
|
||||
assert outputs.containsKey(arg.plainName) && outputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required output argument '${arg.plainName}' is missing"
|
||||
}
|
||||
}
|
||||
|
||||
outputs = outputs.collectEntries { name, value ->
|
||||
def par = config.allArguments.find { it.plainName == name && it.direction == "output" }
|
||||
assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid output argument"
|
||||
@@ -216,6 +204,16 @@ Map _processOutputValues(Map outputs, Map config, String id, String key) {
|
||||
return outputs
|
||||
}
|
||||
|
||||
void _checkAllRequiredOuputsPresent(Map outputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.direction == "output" && arg.required) {
|
||||
assert outputs.containsKey(arg.plainName) && outputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required output argument '${arg.plainName}' is missing"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf'
|
||||
class IDChecker {
|
||||
final def items = [] as Set
|
||||
@@ -1669,6 +1667,162 @@ def joinStates(Closure apply_) {
|
||||
}
|
||||
return joinStatesWf
|
||||
}
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishFiles.nf'
|
||||
def publishFiles(Map args) {
|
||||
def key_ = args.get("key")
|
||||
|
||||
assert key_ != null : "publishFiles: key must be specified"
|
||||
|
||||
workflow publishFilesWf {
|
||||
take: input_ch
|
||||
main:
|
||||
input_ch
|
||||
| map { tup ->
|
||||
def id_ = tup[0]
|
||||
def state_ = tup[1]
|
||||
|
||||
// the input files and the target output filenames
|
||||
def inputoutputFilenames_ = collectInputOutputPaths(state_, id_ + "." + key_).transpose()
|
||||
def inputFiles_ = inputoutputFilenames_[0]
|
||||
def outputFilenames_ = inputoutputFilenames_[1]
|
||||
|
||||
[id_, inputFiles_, outputFilenames_]
|
||||
}
|
||||
| publishFilesProc
|
||||
emit: input_ch
|
||||
}
|
||||
return publishFilesWf
|
||||
}
|
||||
|
||||
process publishFilesProc {
|
||||
// todo: check publishpath?
|
||||
publishDir path: "${getPublishDir()}/", mode: "copy"
|
||||
tag "$id"
|
||||
input:
|
||||
tuple val(id), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles)
|
||||
output:
|
||||
tuple val(id), path{outputFiles}
|
||||
script:
|
||||
def copyCommands = [
|
||||
inputFiles instanceof List ? inputFiles : [inputFiles],
|
||||
outputFiles instanceof List ? outputFiles : [outputFiles]
|
||||
]
|
||||
.transpose()
|
||||
.collectMany{infile, outfile ->
|
||||
if (infile.toString() != outfile.toString()) {
|
||||
[
|
||||
"[ -d \"\$(dirname '${outfile.toString()}')\" ] || mkdir -p \"\$(dirname '${outfile.toString()}')\"",
|
||||
"cp -r '${infile.toString()}' '${outfile.toString()}'"
|
||||
]
|
||||
} else {
|
||||
// no need to copy if infile is the same as outfile
|
||||
[]
|
||||
}
|
||||
}
|
||||
"""
|
||||
echo "Copying output files to destination folder"
|
||||
${copyCommands.join("\n ")}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
// this assumes that the state contains no other values other than those specified in the config
|
||||
def publishFilesByConfig(Map args) {
|
||||
def config = args.get("config")
|
||||
assert config != null : "publishFilesByConfig: config must be specified"
|
||||
|
||||
def key_ = args.get("key", config.name)
|
||||
assert key_ != null : "publishFilesByConfig: key must be specified"
|
||||
|
||||
workflow publishFilesSimpleWf {
|
||||
take: input_ch
|
||||
main:
|
||||
input_ch
|
||||
| map { tup ->
|
||||
def id_ = tup[0]
|
||||
def state_ = tup[1] // e.g. [output: new File("myoutput.h5ad"), k: 10]
|
||||
def origState_ = tup[2] // e.g. [output: '$id.$key.foo.h5ad']
|
||||
|
||||
|
||||
// the processed state is a list of [key, value, inputPath, outputFilename] tuples, where
|
||||
// - key is a String
|
||||
// - value is any object that can be serialized to a Yaml (so a String/Integer/Long/Double/Boolean, a List, a Map, or a Path)
|
||||
// - inputPath is a List[Path]
|
||||
// - outputFilename is a List[String]
|
||||
// - (inputPath, outputFilename) are the files that will be copied from src to dest (relative to the state.yaml)
|
||||
def processedState =
|
||||
config.allArguments
|
||||
.findAll { it.direction == "output" }
|
||||
.collectMany { par ->
|
||||
def plainName_ = par.plainName
|
||||
// if the state does not contain the key, it's an
|
||||
// optional argument for which the component did
|
||||
// not generate any output OR multiple channels were emitted
|
||||
// and the output was just not added to using the channel
|
||||
// that is now being parsed
|
||||
if (!state_.containsKey(plainName_)) {
|
||||
return []
|
||||
}
|
||||
def value = state_[plainName_]
|
||||
// if the parameter is not a file, it should be stored
|
||||
// in the state as-is, but is not something that needs
|
||||
// to be copied from the source path to the dest path
|
||||
if (par.type != "file") {
|
||||
return [[inputPath: [], outputFilename: []]]
|
||||
}
|
||||
// if the orig state does not contain this filename,
|
||||
// it's an optional argument for which the user specified
|
||||
// that it should not be returned as a state
|
||||
if (!origState_.containsKey(plainName_)) {
|
||||
return []
|
||||
}
|
||||
def filenameTemplate = origState_[plainName_]
|
||||
// if the pararameter is multiple: true, fetch the template
|
||||
if (par.multiple && filenameTemplate instanceof List) {
|
||||
filenameTemplate = filenameTemplate[0]
|
||||
}
|
||||
// instantiate the template
|
||||
def filename = filenameTemplate
|
||||
.replaceAll('\\$id', id_)
|
||||
.replaceAll('\\$\\{id\\}', id_)
|
||||
.replaceAll('\\$key', key_)
|
||||
.replaceAll('\\$\\{key\\}', key_)
|
||||
if (par.multiple) {
|
||||
// if the parameter is multiple: true, the filename
|
||||
// should contain a wildcard '*' that is replaced with
|
||||
// the index of the file
|
||||
assert filename.contains("*") : "Module '${key_}' id '${id_}': Multiple output files specified, but no wildcard '*' in the filename: ${filename}"
|
||||
def outputPerFile = value.withIndex().collect{ val, ix ->
|
||||
def filename_ix = filename.replace("*", ix.toString())
|
||||
def inputPath = val instanceof File ? val.toPath() : val
|
||||
[inputPath: inputPath, outputFilename: filename_ix]
|
||||
}
|
||||
def transposedOutputs = ["inputPath", "outputFilename"].collectEntries{ key ->
|
||||
[key, outputPerFile.collect{dic -> dic[key]}]
|
||||
}
|
||||
return [[key: plainName_] + transposedOutputs]
|
||||
} else {
|
||||
def value_ = java.nio.file.Paths.get(filename)
|
||||
def inputPath = value instanceof File ? value.toPath() : value
|
||||
return [[inputPath: [inputPath], outputFilename: [filename]]]
|
||||
}
|
||||
}
|
||||
|
||||
def inputPaths = processedState.collectMany{it.inputPath}
|
||||
def outputFilenames = processedState.collectMany{it.outputFilename}
|
||||
|
||||
|
||||
[id_, inputPaths, outputFilenames]
|
||||
}
|
||||
| publishFilesProc
|
||||
emit: input_ch
|
||||
}
|
||||
return publishFilesSimpleWf
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf'
|
||||
def collectFiles(obj) {
|
||||
if (obj instanceof java.io.File || obj instanceof Path) {
|
||||
@@ -1726,8 +1880,6 @@ def publishStates(Map args) {
|
||||
|
||||
// the input files and the target output filenames
|
||||
def inputoutputFilenames_ = collectInputOutputPaths(state_, id_ + "." + key_).transpose()
|
||||
def inputFiles_ = inputoutputFilenames_[0]
|
||||
def outputFilenames_ = inputoutputFilenames_[1]
|
||||
|
||||
def yamlFilename = yamlTemplate_
|
||||
.replaceAll('\\$id', id_)
|
||||
@@ -1740,7 +1892,7 @@ def publishStates(Map args) {
|
||||
// convert state to yaml blob
|
||||
def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename))
|
||||
|
||||
[id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_]
|
||||
[id_, yamlBlob_, yamlFilename]
|
||||
}
|
||||
| publishStatesProc
|
||||
emit: input_ch
|
||||
@@ -1752,33 +1904,17 @@ process publishStatesProc {
|
||||
publishDir path: "${getPublishDir()}/", mode: "copy"
|
||||
tag "$id"
|
||||
input:
|
||||
tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles)
|
||||
tuple val(id), val(yamlBlob), val(yamlFile)
|
||||
output:
|
||||
tuple val(id), path{[yamlFile] + outputFiles}
|
||||
tuple val(id), path{[yamlFile]}
|
||||
script:
|
||||
def copyCommands = [
|
||||
inputFiles instanceof List ? inputFiles : [inputFiles],
|
||||
outputFiles instanceof List ? outputFiles : [outputFiles]
|
||||
]
|
||||
.transpose()
|
||||
.collectMany{infile, outfile ->
|
||||
if (infile.toString() != outfile.toString()) {
|
||||
[
|
||||
"[ -d \"\$(dirname '${outfile.toString()}')\" ] || mkdir -p \"\$(dirname '${outfile.toString()}')\"",
|
||||
"cp -r '${infile.toString()}' '${outfile.toString()}'"
|
||||
]
|
||||
} else {
|
||||
// no need to copy if infile is the same as outfile
|
||||
[]
|
||||
}
|
||||
}
|
||||
"""
|
||||
mkdir -p "\$(dirname '${yamlFile}')"
|
||||
echo "Storing state as yaml"
|
||||
echo '${yamlBlob}' > '${yamlFile}'
|
||||
echo "Copying output files to destination folder"
|
||||
${copyCommands.join("\n ")}
|
||||
"""
|
||||
mkdir -p "\$(dirname '${yamlFile}')"
|
||||
echo "Storing state as yaml"
|
||||
cat > '${yamlFile}' << HERE
|
||||
${yamlBlob}
|
||||
HERE
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
@@ -1809,13 +1945,10 @@ def publishStatesByConfig(Map args) {
|
||||
.replaceAll('\\$\\{key\\}', key_)
|
||||
def yamlDir = java.nio.file.Paths.get(yamlFilename).getParent()
|
||||
|
||||
// the processed state is a list of [key, value, inputPath, outputFilename] tuples, where
|
||||
// the processed state is a list of [key, value] tuples, where
|
||||
// - key is a String
|
||||
// - value is any object that can be serialized to a Yaml (so a String/Integer/Long/Double/Boolean, a List, a Map, or a Path)
|
||||
// - inputPath is a List[Path]
|
||||
// - outputFilename is a List[String]
|
||||
// - (key, value) are the tuples that will be saved to the state.yaml file
|
||||
// - (inputPath, outputFilename) are the files that will be copied from src to dest (relative to the state.yaml)
|
||||
def processedState =
|
||||
config.allArguments
|
||||
.findAll { it.direction == "output" }
|
||||
@@ -1832,7 +1965,7 @@ def publishStatesByConfig(Map args) {
|
||||
// in the state as-is, but is not something that needs
|
||||
// to be copied from the source path to the dest path
|
||||
if (par.type != "file") {
|
||||
return [[key: plainName_, value: value, inputPath: [], outputFilename: []]]
|
||||
return [[key: plainName_, value: value]]
|
||||
}
|
||||
// if the orig state does not contain this filename,
|
||||
// it's an optional argument for which the user specified
|
||||
@@ -1863,13 +1996,9 @@ def publishStatesByConfig(Map args) {
|
||||
if (yamlDir != null) {
|
||||
value_ = yamlDir.relativize(value_)
|
||||
}
|
||||
def inputPath = val instanceof File ? val.toPath() : val
|
||||
[value: value_, inputPath: inputPath, outputFilename: filename_ix]
|
||||
return value_
|
||||
}
|
||||
def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key ->
|
||||
[key, outputPerFile.collect{dic -> dic[key]}]
|
||||
}
|
||||
return [[key: plainName_] + transposedOutputs]
|
||||
return [["key": plainName_, "value": outputPerFile]]
|
||||
} else {
|
||||
def value_ = java.nio.file.Paths.get(filename)
|
||||
// if id contains a slash
|
||||
@@ -1877,18 +2006,17 @@ def publishStatesByConfig(Map args) {
|
||||
value_ = yamlDir.relativize(value_)
|
||||
}
|
||||
def inputPath = value instanceof File ? value.toPath() : value
|
||||
return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]]
|
||||
return [["key": plainName_, value: value_]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def updatedState_ = processedState.collectEntries{[it.key, it.value]}
|
||||
def inputPaths = processedState.collectMany{it.inputPath}
|
||||
def outputFilenames = processedState.collectMany{it.outputFilename}
|
||||
|
||||
// convert state to yaml blob
|
||||
def yamlBlob_ = toTaggedYamlBlob([id: id_] + updatedState_)
|
||||
|
||||
[id_, yamlBlob_, yamlFilename, inputPaths, outputFilenames]
|
||||
[id_, yamlBlob_, yamlFilename]
|
||||
}
|
||||
| publishStatesProc
|
||||
emit: input_ch
|
||||
@@ -2562,6 +2690,7 @@ def _debug(workflowArgs, debugKey) {
|
||||
def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta)
|
||||
def key_ = workflowArgs["key"]
|
||||
def multipleArgs = meta.config.allArguments.findAll{ it.multiple }.collect{it.plainName}
|
||||
|
||||
workflow workflowInstance {
|
||||
take: input_
|
||||
@@ -2719,12 +2848,36 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
}
|
||||
|
||||
// TODO: move some of the _meta.join_id wrangling to the safeJoin() function.
|
||||
def chInitialOutput = chArgsWithDefaults
|
||||
def chInitialOutputMulti = chArgsWithDefaults
|
||||
| _debug(workflowArgs, "processed")
|
||||
// run workflow
|
||||
| innerWorkflowFactory(workflowArgs)
|
||||
// check output tuple
|
||||
| map { id_, output_ ->
|
||||
def chInitialOutputList = chInitialOutputMulti instanceof List ? chInitialOutputMulti : [chInitialOutputMulti]
|
||||
assert chInitialOutputList.size() > 0: "should have emitted at least one output channel"
|
||||
// Add a channel ID to the events, which designates the channel the event was emitted from as a running number
|
||||
// This number is used to sort the events later when the events are gathered from across the channels.
|
||||
def chInitialOutputListWithIndexedEvents = chInitialOutputList.withIndex().collect{channel, channelIndex ->
|
||||
def newChannel = channel
|
||||
| map {tuple ->
|
||||
assert tuple instanceof List :
|
||||
"Error in module '${key_}': element in output channel should be a tuple [id, data, ...otherargs...]\n" +
|
||||
" Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" +
|
||||
" Expected class: List. Found: tuple.getClass() is ${tuple.getClass()}"
|
||||
|
||||
def newEvent = [channelIndex] + tuple
|
||||
return newEvent
|
||||
}
|
||||
return newChannel
|
||||
}
|
||||
// Put the events into 1 channel, cover case where there is only one channel is emitted
|
||||
def chInitialOutput = chInitialOutputList.size() > 1 ? \
|
||||
chInitialOutputListWithIndexedEvents[0].mix(*chInitialOutputListWithIndexedEvents.tail()) : \
|
||||
chInitialOutputListWithIndexedEvents[0]
|
||||
def chInitialOutputProcessed = chInitialOutput
|
||||
| map { tuple ->
|
||||
def channelId = tuple[0]
|
||||
def id_ = tuple[1]
|
||||
def output_ = tuple[2]
|
||||
|
||||
// see if output map contains metadata
|
||||
def meta_ =
|
||||
@@ -2737,19 +2890,94 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
output_ = output_.findAll{k, v -> k != "_meta"}
|
||||
|
||||
// check value types
|
||||
output_ = _processOutputValues(output_, meta.config, id_, key_)
|
||||
output_ = _checkValidOutputArgument(output_, meta.config, id_, key_)
|
||||
|
||||
// simplify output if need be
|
||||
if (workflowArgs.auto.simplifyOutput && output_.size() == 1) {
|
||||
output_ = output_.values()[0]
|
||||
}
|
||||
|
||||
[join_id, id_, output_]
|
||||
[join_id, channelId, id_, output_]
|
||||
}
|
||||
// | view{"chInitialOutput: ${it.take(3)}"}
|
||||
|
||||
// join the output [prev_id, channel_id, new_id, output] with the previous state [prev_id, state, ...]
|
||||
def chPublishWithPreviousState = safeJoin(chInitialOutputProcessed, chRunFiltered, key_)
|
||||
// input tuple format: [join_id, channel_id, id, output, prev_state, ...]
|
||||
// output tuple format: [join_id, channel_id, id, new_state, ...]
|
||||
| map{ tup ->
|
||||
def new_state = workflowArgs.toState(tup.drop(2).take(3))
|
||||
tup.take(3) + [new_state] + tup.drop(5)
|
||||
}
|
||||
if (workflowArgs.auto.publish == "state") {
|
||||
def chPublishFiles = chPublishWithPreviousState
|
||||
// input tuple format: [join_id, channel_id, id, new_state, ...]
|
||||
// output tuple format: [join_id, channel_id, id, new_state]
|
||||
| map{ tup ->
|
||||
tup.take(4)
|
||||
}
|
||||
|
||||
safeJoin(chPublishFiles, chArgsWithDefaults, key_)
|
||||
// input tuple format: [join_id, channel_id, id, new_state, orig_state, ...]
|
||||
// output tuple format: [id, new_state, orig_state]
|
||||
| map { tup ->
|
||||
tup.drop(2).take(3)
|
||||
}
|
||||
| publishFilesByConfig(key: key_, config: meta.config)
|
||||
}
|
||||
// Join the state from the events that were emitted from different channels
|
||||
def chJoined = chInitialOutputProcessed
|
||||
| map {tuple ->
|
||||
def join_id = tuple[0]
|
||||
def channel_id = tuple[1]
|
||||
def id = tuple[2]
|
||||
def other = tuple.drop(3)
|
||||
// Below, groupTuple is used to join the events. To make sure resuming a workflow
|
||||
// keeps working, the output state must be deterministic. This means the state needs to be
|
||||
// sorted with groupTuple's has a 'sort' argument. This argument can be set to 'hash',
|
||||
// but hashing the state when it is large can be problematic in terms of performance.
|
||||
// Therefore, a custom comparator function is provided. We add the channel ID to the
|
||||
// states so that we can use the channel ID to sort the items.
|
||||
def stateWithChannelID = [[channel_id] * other.size(), other].transpose()
|
||||
// A comparator that is provided to groupTuple's 'sort' argument is applied
|
||||
// to all elements of the event tuple (that is not the 'id'). The comparator
|
||||
// closure that is used below expects the input to be List. So the join_id and
|
||||
// channel_id must also be wrapped in a list.
|
||||
[[join_id], [channel_id], id] + stateWithChannelID
|
||||
}
|
||||
| groupTuple(by: 2, sort: {a, b -> a[0] <=> b[0]}, size: chInitialOutputList.size(), remainder: true)
|
||||
| map {join_ids, _, id, statesWithChannelID ->
|
||||
// Remove the channel IDs from the states
|
||||
def states = statesWithChannelID.collect{it[1]}
|
||||
def newJoinId = join_ids.flatten().unique{a, b -> a <=> b}
|
||||
assert newJoinId.size() == 1: "Multiple events were emitted for '$id'."
|
||||
def newJoinIdUnique = newJoinId[0]
|
||||
|
||||
// Merge the states from the different channels
|
||||
def newState = states.inject([:]){ old_state, state_to_add ->
|
||||
return old_state + state_to_add.collectEntries{k, v ->
|
||||
if (!multipleArgs.contains(k)) {
|
||||
// if the key is not a multiple argument, we expect only one value
|
||||
if (old_state.containsKey(k)) {
|
||||
assert old_state[k] == v : "ID $id: multiple entries for argument $k were emitted."
|
||||
}
|
||||
[k, v]
|
||||
} else {
|
||||
// if the key is a multiple argument, append the different values into one list
|
||||
def prevValue = old_state.getOrDefault(k, [])
|
||||
def prevValueAsList = prevValue instanceof List ? prevValue : [prevValue]
|
||||
[k, prevValueAsList + v]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_checkAllRequiredOuputsPresent(newState, meta.config, id, key_)
|
||||
|
||||
// simplify output if need be
|
||||
if (workflowArgs.auto.simplifyOutput && newState.size() == 1) {
|
||||
newState = newState.values()[0]
|
||||
}
|
||||
|
||||
return [newJoinIdUnique, id, newState]
|
||||
}
|
||||
|
||||
// join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...]
|
||||
def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_)
|
||||
def chNewState = safeJoin(chJoined, chRunFiltered, key_)
|
||||
// input tuple format: [join_id, id, output, prev_state, ...]
|
||||
// output tuple format: [join_id, id, new_state, ...]
|
||||
| map{ tup ->
|
||||
@@ -2758,23 +2986,21 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
}
|
||||
|
||||
if (workflowArgs.auto.publish == "state") {
|
||||
def chPublish = chNewState
|
||||
def chPublishStates = chNewState
|
||||
// input tuple format: [join_id, id, new_state, ...]
|
||||
// output tuple format: [join_id, id, new_state]
|
||||
| map{ tup ->
|
||||
tup.take(3)
|
||||
}
|
||||
|
||||
safeJoin(chPublish, chArgsWithDefaults, key_)
|
||||
safeJoin(chPublishStates, chArgsWithDefaults, key_)
|
||||
// input tuple format: [join_id, id, new_state, orig_state, ...]
|
||||
// output tuple format: [id, new_state, orig_state]
|
||||
| map { tup ->
|
||||
tup.drop(1).take(3)
|
||||
}
|
||||
}
|
||||
| publishStatesByConfig(key: key_, config: meta.config)
|
||||
}
|
||||
|
||||
// remove join_id and meta
|
||||
chReturn = chNewState
|
||||
| map { tup ->
|
||||
// input tuple format: [join_id, id, new_state, ...]
|
||||
@@ -2808,7 +3034,7 @@ meta = [
|
||||
"resources_dir": moduleDir.toRealPath().normalize(),
|
||||
"config": processConfig(readJsonBlob('''{
|
||||
"name" : "bases2fastq",
|
||||
"version" : "v0.3.0",
|
||||
"version" : "v0.3.1",
|
||||
"authors" : [
|
||||
{
|
||||
"name" : "Dries Schaumont",
|
||||
@@ -3149,6 +3375,10 @@ meta = [
|
||||
}
|
||||
],
|
||||
"status" : "enabled",
|
||||
"scope" : {
|
||||
"image" : "public",
|
||||
"target" : "public"
|
||||
},
|
||||
"requirements" : {
|
||||
"commands" : [
|
||||
"ps"
|
||||
@@ -3245,7 +3475,7 @@ meta = [
|
||||
"id" : "docker",
|
||||
"image" : "elembio/bases2fastq:2.1.0",
|
||||
"target_registry" : "images.viash-hub.com",
|
||||
"target_tag" : "v0.3.0",
|
||||
"target_tag" : "v0.3.1",
|
||||
"namespace_separator" : "/",
|
||||
"setup" : [
|
||||
{
|
||||
@@ -3283,23 +3513,24 @@ meta = [
|
||||
"runner" : "nextflow",
|
||||
"engine" : "docker|native",
|
||||
"output" : "target/nextflow/bases2fastq",
|
||||
"viash_version" : "0.9.0",
|
||||
"git_commit" : "d86bd5cf62104af02caa852aacd352b1aa97ed60",
|
||||
"git_remote" : "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox",
|
||||
"git_tag" : "v0.2.0-29-gd86bd5c"
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "98a5f3cc745525a65c10263d25cf414eb1093223",
|
||||
"git_remote" : "https://github.com/viash-hub/biobox",
|
||||
"git_tag" : "v0.3.0-8-g98a5f3c"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "biobox",
|
||||
"version" : "v0.3.0",
|
||||
"description" : "A collection of bioinformatics tools for working with sequence data.\n",
|
||||
"viash_version" : "0.9.0",
|
||||
"version" : "v0.3.1",
|
||||
"summary" : "A curated collection of high-quality, standalone bioinformatics components built with [Viash](https://viash.io).\n",
|
||||
"description" : "`biobox` offers a suite of reliable bioinformatics components, similar to [nf-core/modules](https://github.com/nf-core/modules) and [snakemake-wrappers/bio](https://github.com/snakemake/snakemake-wrappers/tree/master/bio), but built using the [Viash](https://viash.io) framework.\n\nThis approach emphasizes **reusability**, **reproducibility**, and adherence to **best practices**. Key features of `biobox` components include:\n\n* **Standalone & Nextflow Ready:** Run components directly via the command line or seamlessly integrate them into Nextflow workflows.\n* **High Quality Standards:**\n * Comprehensive documentation for components and parameters.\n * Full exposure of underlying tool arguments.\n * Containerized (Docker) for dependency management and reproducibility.\n * Unit tested for verified functionality.\n",
|
||||
"viash_version" : "0.9.4",
|
||||
"source" : "src",
|
||||
"target" : "target",
|
||||
"config_mods" : [
|
||||
".requirements.commands := ['ps']\n",
|
||||
".engines += { type: \\"native\\" }",
|
||||
".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'",
|
||||
".engines[.type == 'docker'].target_tag := 'v0.3.0'"
|
||||
".engines[.type == 'docker'].target_tag := 'v0.3.1'"
|
||||
],
|
||||
"keywords" : [
|
||||
"bioinformatics",
|
||||
@@ -3816,7 +4047,7 @@ def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) {
|
||||
// create process from temp file
|
||||
def binding = new nextflow.script.ScriptBinding([:])
|
||||
def session = nextflow.Nextflow.getSession()
|
||||
def parser = new nextflow.script.ScriptParser(session)
|
||||
def parser = _getScriptLoader(session)
|
||||
.setModule(true)
|
||||
.setBinding(binding)
|
||||
def moduleScript = parser.runScript(tempFile)
|
||||
@@ -3830,6 +4061,27 @@ def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) {
|
||||
return scriptMeta.getProcess(procKey)
|
||||
}
|
||||
|
||||
// use Reflection to get a ScriptParser / ScriptLoader
|
||||
// <25.02.0-edge: new nextflow.script.ScriptParser(session)
|
||||
// >=25.02.0-edge: nextflow.script.ScriptLoaderFactory.create(session)
|
||||
def _getScriptLoader(nextflow.Session session) {
|
||||
// try using the old method
|
||||
try {
|
||||
Class<?> scriptParserClass = Class.forName('nextflow.script.ScriptParser')
|
||||
return scriptParserClass.getDeclaredConstructor(nextflow.Session).newInstance(session)
|
||||
} catch (ClassNotFoundException e) {
|
||||
// else try with the new method
|
||||
try {
|
||||
Class<?> scriptLoaderFactoryClass = Class.forName('nextflow.script.ScriptLoaderFactory')
|
||||
def createMethod = scriptLoaderFactoryClass.getDeclaredMethod('create', nextflow.Session)
|
||||
return createMethod.invoke(null, session) // null because create is static
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | java.lang.reflect.InvocationTargetException e2) {
|
||||
// Handle the case where neither class is found
|
||||
throw new Exception("Neither nextflow.script.ScriptParser nor nextflow.script.ScriptLoaderFactory could be found. Is this a compatible Nextflow version?", e2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// defaults
|
||||
meta["defaults"] = [
|
||||
// key to be used to trace the process and determine output names
|
||||
@@ -3843,7 +4095,7 @@ meta["defaults"] = [
|
||||
"container" : {
|
||||
"registry" : "images.viash-hub.com",
|
||||
"image" : "vsh/biobox/bases2fastq",
|
||||
"tag" : "v0.3.0"
|
||||
"tag" : "v0.3.1"
|
||||
},
|
||||
"tag" : "$id"
|
||||
}'''),
|
||||
@@ -2,7 +2,7 @@ manifest {
|
||||
name = 'bases2fastq'
|
||||
mainScript = 'main.nf'
|
||||
nextflowVersion = '!>=20.12.1-edge'
|
||||
version = 'v0.3.0'
|
||||
version = 'v0.3.1'
|
||||
description = 'Bases2Fastq demultiplexes sequencing data generated by Element Biosciences instruments and converts base calls into FASTQ files.\n'
|
||||
author = 'Dries Schaumont'
|
||||
}
|
||||
@@ -310,10 +310,10 @@
|
||||
"output_directory": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required, default: `$id.$key.output_directory.output_directory`, example: `fastq_dir`. Location to save output fastqs",
|
||||
"help_text": "Type: `file`, required, default: `$id.$key.output_directory.output_directory`, example: `fastq_dir`. Location to save output fastqs"
|
||||
"description": "Type: `file`, required, default: `$id.$key.output_directory`, example: `fastq_dir`. Location to save output fastqs",
|
||||
"help_text": "Type: `file`, required, default: `$id.$key.output_directory`, example: `fastq_dir`. Location to save output fastqs"
|
||||
,
|
||||
"default":"$id.$key.output_directory.output_directory"
|
||||
"default":"$id.$key.output_directory"
|
||||
}
|
||||
|
||||
|
||||
@@ -321,10 +321,10 @@
|
||||
"report": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id.$key.report.report`. Output location for the HTML report",
|
||||
"help_text": "Type: `file`, default: `$id.$key.report.report`. Output location for the HTML report"
|
||||
"description": "Type: `file`, default: `$id.$key.report`. Output location for the HTML report",
|
||||
"help_text": "Type: `file`, default: `$id.$key.report`. Output location for the HTML report"
|
||||
,
|
||||
"default":"$id.$key.report.report"
|
||||
"default":"$id.$key.report"
|
||||
}
|
||||
|
||||
|
||||
@@ -332,10 +332,10 @@
|
||||
"logs": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id.$key.logs.logs`, example: `logs_dir`. Directory containing log files",
|
||||
"help_text": "Type: `file`, default: `$id.$key.logs.logs`, example: `logs_dir`. Directory containing log files"
|
||||
"description": "Type: `file`, default: `$id.$key.logs`, example: `logs_dir`. Directory containing log files",
|
||||
"help_text": "Type: `file`, default: `$id.$key.logs`, example: `logs_dir`. Directory containing log files"
|
||||
,
|
||||
"default":"$id.$key.logs.logs"
|
||||
"default":"$id.$key.logs"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: "bcl_convert"
|
||||
version: "v0.3.0"
|
||||
version: "v0.3.1"
|
||||
authors:
|
||||
- name: "Toni Verbeiren"
|
||||
roles:
|
||||
@@ -290,6 +290,16 @@ argument_groups:
|
||||
direction: "output"
|
||||
multiple: false
|
||||
multiple_sep: ";"
|
||||
- type: "boolean"
|
||||
name: "--force"
|
||||
description: "Allow destination directory to already exist and overwrite files.\n"
|
||||
info: null
|
||||
example:
|
||||
- true
|
||||
required: false
|
||||
direction: "input"
|
||||
multiple: false
|
||||
multiple_sep: ";"
|
||||
resources:
|
||||
- type: "bash_script"
|
||||
path: "script.sh"
|
||||
@@ -303,6 +313,9 @@ test_resources:
|
||||
is_executable: true
|
||||
info: null
|
||||
status: "enabled"
|
||||
scope:
|
||||
image: "public"
|
||||
target: "public"
|
||||
requirements:
|
||||
commands:
|
||||
- "ps"
|
||||
@@ -386,7 +399,7 @@ engines:
|
||||
id: "docker"
|
||||
image: "debian:trixie-slim"
|
||||
target_registry: "images.viash-hub.com"
|
||||
target_tag: "v0.3.0"
|
||||
target_tag: "v0.3.1"
|
||||
namespace_separator: "/"
|
||||
setup:
|
||||
- type: "apt"
|
||||
@@ -417,23 +430,34 @@ build_info:
|
||||
engine: "docker|native"
|
||||
output: "target/nextflow/bcl_convert"
|
||||
executable: "target/nextflow/bcl_convert/main.nf"
|
||||
viash_version: "0.9.0"
|
||||
git_commit: "d86bd5cf62104af02caa852aacd352b1aa97ed60"
|
||||
git_remote: "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox"
|
||||
git_tag: "v0.2.0-29-gd86bd5c"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "98a5f3cc745525a65c10263d25cf414eb1093223"
|
||||
git_remote: "https://github.com/viash-hub/biobox"
|
||||
git_tag: "v0.3.0-8-g98a5f3c"
|
||||
package_config:
|
||||
name: "biobox"
|
||||
version: "v0.3.0"
|
||||
description: "A collection of bioinformatics tools for working with sequence data.\n"
|
||||
version: "v0.3.1"
|
||||
summary: "A curated collection of high-quality, standalone bioinformatics components\
|
||||
\ built with [Viash](https://viash.io).\n"
|
||||
description: "`biobox` offers a suite of reliable bioinformatics components, similar\
|
||||
\ to [nf-core/modules](https://github.com/nf-core/modules) and [snakemake-wrappers/bio](https://github.com/snakemake/snakemake-wrappers/tree/master/bio),\
|
||||
\ but built using the [Viash](https://viash.io) framework.\n\nThis approach emphasizes\
|
||||
\ **reusability**, **reproducibility**, and adherence to **best practices**. Key\
|
||||
\ features of `biobox` components include:\n\n* **Standalone & Nextflow Ready:**\
|
||||
\ Run components directly via the command line or seamlessly integrate them into\
|
||||
\ Nextflow workflows.\n* **High Quality Standards:**\n * Comprehensive documentation\
|
||||
\ for components and parameters.\n * Full exposure of underlying tool arguments.\n\
|
||||
\ * Containerized (Docker) for dependency management and reproducibility.\n\
|
||||
\ * Unit tested for verified functionality.\n"
|
||||
info: null
|
||||
viash_version: "0.9.0"
|
||||
viash_version: "0.9.4"
|
||||
source: "src"
|
||||
target: "target"
|
||||
config_mods:
|
||||
- ".requirements.commands := ['ps']\n"
|
||||
- ".engines += { type: \"native\" }"
|
||||
- ".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'"
|
||||
- ".engines[.type == 'docker'].target_tag := 'v0.3.0'"
|
||||
- ".engines[.type == 'docker'].target_tag := 'v0.3.1'"
|
||||
keywords:
|
||||
- "bioinformatics"
|
||||
- "modules"
|
||||
@@ -1,6 +1,6 @@
|
||||
// bcl_convert v0.3.0
|
||||
// bcl_convert v0.3.1
|
||||
//
|
||||
// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative
|
||||
// This wrapper script is auto-generated by viash 0.9.4 and is thus a derivative
|
||||
// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data
|
||||
// Intuitive.
|
||||
//
|
||||
@@ -86,64 +86,56 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
foundClass = "List[${e.foundClass}]"
|
||||
}
|
||||
} else if (par.type == "string") {
|
||||
// cast to string if need be
|
||||
// cast to string if need be. only cast if the value is a GString
|
||||
if (value instanceof GString) {
|
||||
value = value.toString()
|
||||
value = value as String
|
||||
}
|
||||
expectedClass = value instanceof String ? null : "String"
|
||||
} else if (par.type == "integer") {
|
||||
// cast to integer if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Integer) {
|
||||
try {
|
||||
value = value.toInteger()
|
||||
value = value as Integer
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Integer"
|
||||
}
|
||||
}
|
||||
if (value instanceof java.math.BigInteger) {
|
||||
value = value.intValue()
|
||||
}
|
||||
expectedClass = value instanceof Integer ? null : "Integer"
|
||||
} else if (par.type == "long") {
|
||||
// cast to long if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Long) {
|
||||
try {
|
||||
value = value.toLong()
|
||||
value = value as Long
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Long"
|
||||
}
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
value = value.toLong()
|
||||
}
|
||||
expectedClass = value instanceof Long ? null : "Long"
|
||||
} else if (par.type == "double") {
|
||||
// cast to double if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Double) {
|
||||
try {
|
||||
value = value.toDouble()
|
||||
value = value as Double
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Double"
|
||||
}
|
||||
}
|
||||
if (value instanceof java.math.BigDecimal) {
|
||||
value = value.doubleValue()
|
||||
} else if (par.type == "float") {
|
||||
// cast to float if need be
|
||||
if (value !instanceof Float) {
|
||||
try {
|
||||
value = value as Float
|
||||
} catch (NumberFormatException e) {
|
||||
expectedClass = "Float"
|
||||
}
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
value = value.toDouble()
|
||||
}
|
||||
expectedClass = value instanceof Double ? null : "Double"
|
||||
} else if (par.type == "boolean" | par.type == "boolean_true" | par.type == "boolean_false") {
|
||||
// cast to boolean if need be
|
||||
if (value instanceof String) {
|
||||
def valueLower = value.toLowerCase()
|
||||
if (valueLower == "true") {
|
||||
value = true
|
||||
} else if (valueLower == "false") {
|
||||
value = false
|
||||
if (value !instanceof Boolean) {
|
||||
try {
|
||||
value = value as Boolean
|
||||
} catch (Exception e) {
|
||||
expectedClass = "Boolean"
|
||||
}
|
||||
}
|
||||
expectedClass = value instanceof Boolean ? null : "Boolean"
|
||||
} else if (par.type == "file" && (par.direction == "input" || stage == "output")) {
|
||||
// cast to path if need be
|
||||
if (value instanceof String) {
|
||||
@@ -155,10 +147,13 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
expectedClass = value instanceof Path ? null : "Path"
|
||||
} else if (par.type == "file" && stage == "input" && par.direction == "output") {
|
||||
// cast to string if need be
|
||||
if (value instanceof GString) {
|
||||
value = value.toString()
|
||||
if (value !instanceof String) {
|
||||
try {
|
||||
value = value as String
|
||||
} catch (Exception e) {
|
||||
expectedClass = "String"
|
||||
}
|
||||
}
|
||||
expectedClass = value instanceof String ? null : "String"
|
||||
} else {
|
||||
// didn't find a match for par.type
|
||||
expectedClass = par.type
|
||||
@@ -177,7 +172,7 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
Map _processInputValues(Map inputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.required) {
|
||||
if (arg.required && arg.direction == "input") {
|
||||
assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing"
|
||||
}
|
||||
@@ -196,15 +191,8 @@ Map _processInputValues(Map inputs, Map config, String id, String key) {
|
||||
}
|
||||
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf'
|
||||
Map _processOutputValues(Map outputs, Map config, String id, String key) {
|
||||
Map _checkValidOutputArgument(Map outputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.direction == "output" && arg.required) {
|
||||
assert outputs.containsKey(arg.plainName) && outputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required output argument '${arg.plainName}' is missing"
|
||||
}
|
||||
}
|
||||
|
||||
outputs = outputs.collectEntries { name, value ->
|
||||
def par = config.allArguments.find { it.plainName == name && it.direction == "output" }
|
||||
assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid output argument"
|
||||
@@ -217,6 +205,16 @@ Map _processOutputValues(Map outputs, Map config, String id, String key) {
|
||||
return outputs
|
||||
}
|
||||
|
||||
void _checkAllRequiredOuputsPresent(Map outputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.direction == "output" && arg.required) {
|
||||
assert outputs.containsKey(arg.plainName) && outputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required output argument '${arg.plainName}' is missing"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf'
|
||||
class IDChecker {
|
||||
final def items = [] as Set
|
||||
@@ -1670,6 +1668,162 @@ def joinStates(Closure apply_) {
|
||||
}
|
||||
return joinStatesWf
|
||||
}
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishFiles.nf'
|
||||
def publishFiles(Map args) {
|
||||
def key_ = args.get("key")
|
||||
|
||||
assert key_ != null : "publishFiles: key must be specified"
|
||||
|
||||
workflow publishFilesWf {
|
||||
take: input_ch
|
||||
main:
|
||||
input_ch
|
||||
| map { tup ->
|
||||
def id_ = tup[0]
|
||||
def state_ = tup[1]
|
||||
|
||||
// the input files and the target output filenames
|
||||
def inputoutputFilenames_ = collectInputOutputPaths(state_, id_ + "." + key_).transpose()
|
||||
def inputFiles_ = inputoutputFilenames_[0]
|
||||
def outputFilenames_ = inputoutputFilenames_[1]
|
||||
|
||||
[id_, inputFiles_, outputFilenames_]
|
||||
}
|
||||
| publishFilesProc
|
||||
emit: input_ch
|
||||
}
|
||||
return publishFilesWf
|
||||
}
|
||||
|
||||
process publishFilesProc {
|
||||
// todo: check publishpath?
|
||||
publishDir path: "${getPublishDir()}/", mode: "copy"
|
||||
tag "$id"
|
||||
input:
|
||||
tuple val(id), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles)
|
||||
output:
|
||||
tuple val(id), path{outputFiles}
|
||||
script:
|
||||
def copyCommands = [
|
||||
inputFiles instanceof List ? inputFiles : [inputFiles],
|
||||
outputFiles instanceof List ? outputFiles : [outputFiles]
|
||||
]
|
||||
.transpose()
|
||||
.collectMany{infile, outfile ->
|
||||
if (infile.toString() != outfile.toString()) {
|
||||
[
|
||||
"[ -d \"\$(dirname '${outfile.toString()}')\" ] || mkdir -p \"\$(dirname '${outfile.toString()}')\"",
|
||||
"cp -r '${infile.toString()}' '${outfile.toString()}'"
|
||||
]
|
||||
} else {
|
||||
// no need to copy if infile is the same as outfile
|
||||
[]
|
||||
}
|
||||
}
|
||||
"""
|
||||
echo "Copying output files to destination folder"
|
||||
${copyCommands.join("\n ")}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
// this assumes that the state contains no other values other than those specified in the config
|
||||
def publishFilesByConfig(Map args) {
|
||||
def config = args.get("config")
|
||||
assert config != null : "publishFilesByConfig: config must be specified"
|
||||
|
||||
def key_ = args.get("key", config.name)
|
||||
assert key_ != null : "publishFilesByConfig: key must be specified"
|
||||
|
||||
workflow publishFilesSimpleWf {
|
||||
take: input_ch
|
||||
main:
|
||||
input_ch
|
||||
| map { tup ->
|
||||
def id_ = tup[0]
|
||||
def state_ = tup[1] // e.g. [output: new File("myoutput.h5ad"), k: 10]
|
||||
def origState_ = tup[2] // e.g. [output: '$id.$key.foo.h5ad']
|
||||
|
||||
|
||||
// the processed state is a list of [key, value, inputPath, outputFilename] tuples, where
|
||||
// - key is a String
|
||||
// - value is any object that can be serialized to a Yaml (so a String/Integer/Long/Double/Boolean, a List, a Map, or a Path)
|
||||
// - inputPath is a List[Path]
|
||||
// - outputFilename is a List[String]
|
||||
// - (inputPath, outputFilename) are the files that will be copied from src to dest (relative to the state.yaml)
|
||||
def processedState =
|
||||
config.allArguments
|
||||
.findAll { it.direction == "output" }
|
||||
.collectMany { par ->
|
||||
def plainName_ = par.plainName
|
||||
// if the state does not contain the key, it's an
|
||||
// optional argument for which the component did
|
||||
// not generate any output OR multiple channels were emitted
|
||||
// and the output was just not added to using the channel
|
||||
// that is now being parsed
|
||||
if (!state_.containsKey(plainName_)) {
|
||||
return []
|
||||
}
|
||||
def value = state_[plainName_]
|
||||
// if the parameter is not a file, it should be stored
|
||||
// in the state as-is, but is not something that needs
|
||||
// to be copied from the source path to the dest path
|
||||
if (par.type != "file") {
|
||||
return [[inputPath: [], outputFilename: []]]
|
||||
}
|
||||
// if the orig state does not contain this filename,
|
||||
// it's an optional argument for which the user specified
|
||||
// that it should not be returned as a state
|
||||
if (!origState_.containsKey(plainName_)) {
|
||||
return []
|
||||
}
|
||||
def filenameTemplate = origState_[plainName_]
|
||||
// if the pararameter is multiple: true, fetch the template
|
||||
if (par.multiple && filenameTemplate instanceof List) {
|
||||
filenameTemplate = filenameTemplate[0]
|
||||
}
|
||||
// instantiate the template
|
||||
def filename = filenameTemplate
|
||||
.replaceAll('\\$id', id_)
|
||||
.replaceAll('\\$\\{id\\}', id_)
|
||||
.replaceAll('\\$key', key_)
|
||||
.replaceAll('\\$\\{key\\}', key_)
|
||||
if (par.multiple) {
|
||||
// if the parameter is multiple: true, the filename
|
||||
// should contain a wildcard '*' that is replaced with
|
||||
// the index of the file
|
||||
assert filename.contains("*") : "Module '${key_}' id '${id_}': Multiple output files specified, but no wildcard '*' in the filename: ${filename}"
|
||||
def outputPerFile = value.withIndex().collect{ val, ix ->
|
||||
def filename_ix = filename.replace("*", ix.toString())
|
||||
def inputPath = val instanceof File ? val.toPath() : val
|
||||
[inputPath: inputPath, outputFilename: filename_ix]
|
||||
}
|
||||
def transposedOutputs = ["inputPath", "outputFilename"].collectEntries{ key ->
|
||||
[key, outputPerFile.collect{dic -> dic[key]}]
|
||||
}
|
||||
return [[key: plainName_] + transposedOutputs]
|
||||
} else {
|
||||
def value_ = java.nio.file.Paths.get(filename)
|
||||
def inputPath = value instanceof File ? value.toPath() : value
|
||||
return [[inputPath: [inputPath], outputFilename: [filename]]]
|
||||
}
|
||||
}
|
||||
|
||||
def inputPaths = processedState.collectMany{it.inputPath}
|
||||
def outputFilenames = processedState.collectMany{it.outputFilename}
|
||||
|
||||
|
||||
[id_, inputPaths, outputFilenames]
|
||||
}
|
||||
| publishFilesProc
|
||||
emit: input_ch
|
||||
}
|
||||
return publishFilesSimpleWf
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf'
|
||||
def collectFiles(obj) {
|
||||
if (obj instanceof java.io.File || obj instanceof Path) {
|
||||
@@ -1727,8 +1881,6 @@ def publishStates(Map args) {
|
||||
|
||||
// the input files and the target output filenames
|
||||
def inputoutputFilenames_ = collectInputOutputPaths(state_, id_ + "." + key_).transpose()
|
||||
def inputFiles_ = inputoutputFilenames_[0]
|
||||
def outputFilenames_ = inputoutputFilenames_[1]
|
||||
|
||||
def yamlFilename = yamlTemplate_
|
||||
.replaceAll('\\$id', id_)
|
||||
@@ -1741,7 +1893,7 @@ def publishStates(Map args) {
|
||||
// convert state to yaml blob
|
||||
def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename))
|
||||
|
||||
[id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_]
|
||||
[id_, yamlBlob_, yamlFilename]
|
||||
}
|
||||
| publishStatesProc
|
||||
emit: input_ch
|
||||
@@ -1753,33 +1905,17 @@ process publishStatesProc {
|
||||
publishDir path: "${getPublishDir()}/", mode: "copy"
|
||||
tag "$id"
|
||||
input:
|
||||
tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles)
|
||||
tuple val(id), val(yamlBlob), val(yamlFile)
|
||||
output:
|
||||
tuple val(id), path{[yamlFile] + outputFiles}
|
||||
tuple val(id), path{[yamlFile]}
|
||||
script:
|
||||
def copyCommands = [
|
||||
inputFiles instanceof List ? inputFiles : [inputFiles],
|
||||
outputFiles instanceof List ? outputFiles : [outputFiles]
|
||||
]
|
||||
.transpose()
|
||||
.collectMany{infile, outfile ->
|
||||
if (infile.toString() != outfile.toString()) {
|
||||
[
|
||||
"[ -d \"\$(dirname '${outfile.toString()}')\" ] || mkdir -p \"\$(dirname '${outfile.toString()}')\"",
|
||||
"cp -r '${infile.toString()}' '${outfile.toString()}'"
|
||||
]
|
||||
} else {
|
||||
// no need to copy if infile is the same as outfile
|
||||
[]
|
||||
}
|
||||
}
|
||||
"""
|
||||
mkdir -p "\$(dirname '${yamlFile}')"
|
||||
echo "Storing state as yaml"
|
||||
echo '${yamlBlob}' > '${yamlFile}'
|
||||
echo "Copying output files to destination folder"
|
||||
${copyCommands.join("\n ")}
|
||||
"""
|
||||
mkdir -p "\$(dirname '${yamlFile}')"
|
||||
echo "Storing state as yaml"
|
||||
cat > '${yamlFile}' << HERE
|
||||
${yamlBlob}
|
||||
HERE
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
@@ -1810,13 +1946,10 @@ def publishStatesByConfig(Map args) {
|
||||
.replaceAll('\\$\\{key\\}', key_)
|
||||
def yamlDir = java.nio.file.Paths.get(yamlFilename).getParent()
|
||||
|
||||
// the processed state is a list of [key, value, inputPath, outputFilename] tuples, where
|
||||
// the processed state is a list of [key, value] tuples, where
|
||||
// - key is a String
|
||||
// - value is any object that can be serialized to a Yaml (so a String/Integer/Long/Double/Boolean, a List, a Map, or a Path)
|
||||
// - inputPath is a List[Path]
|
||||
// - outputFilename is a List[String]
|
||||
// - (key, value) are the tuples that will be saved to the state.yaml file
|
||||
// - (inputPath, outputFilename) are the files that will be copied from src to dest (relative to the state.yaml)
|
||||
def processedState =
|
||||
config.allArguments
|
||||
.findAll { it.direction == "output" }
|
||||
@@ -1833,7 +1966,7 @@ def publishStatesByConfig(Map args) {
|
||||
// in the state as-is, but is not something that needs
|
||||
// to be copied from the source path to the dest path
|
||||
if (par.type != "file") {
|
||||
return [[key: plainName_, value: value, inputPath: [], outputFilename: []]]
|
||||
return [[key: plainName_, value: value]]
|
||||
}
|
||||
// if the orig state does not contain this filename,
|
||||
// it's an optional argument for which the user specified
|
||||
@@ -1864,13 +1997,9 @@ def publishStatesByConfig(Map args) {
|
||||
if (yamlDir != null) {
|
||||
value_ = yamlDir.relativize(value_)
|
||||
}
|
||||
def inputPath = val instanceof File ? val.toPath() : val
|
||||
[value: value_, inputPath: inputPath, outputFilename: filename_ix]
|
||||
return value_
|
||||
}
|
||||
def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key ->
|
||||
[key, outputPerFile.collect{dic -> dic[key]}]
|
||||
}
|
||||
return [[key: plainName_] + transposedOutputs]
|
||||
return [["key": plainName_, "value": outputPerFile]]
|
||||
} else {
|
||||
def value_ = java.nio.file.Paths.get(filename)
|
||||
// if id contains a slash
|
||||
@@ -1878,18 +2007,17 @@ def publishStatesByConfig(Map args) {
|
||||
value_ = yamlDir.relativize(value_)
|
||||
}
|
||||
def inputPath = value instanceof File ? value.toPath() : value
|
||||
return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]]
|
||||
return [["key": plainName_, value: value_]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def updatedState_ = processedState.collectEntries{[it.key, it.value]}
|
||||
def inputPaths = processedState.collectMany{it.inputPath}
|
||||
def outputFilenames = processedState.collectMany{it.outputFilename}
|
||||
|
||||
// convert state to yaml blob
|
||||
def yamlBlob_ = toTaggedYamlBlob([id: id_] + updatedState_)
|
||||
|
||||
[id_, yamlBlob_, yamlFilename, inputPaths, outputFilenames]
|
||||
[id_, yamlBlob_, yamlFilename]
|
||||
}
|
||||
| publishStatesProc
|
||||
emit: input_ch
|
||||
@@ -2563,6 +2691,7 @@ def _debug(workflowArgs, debugKey) {
|
||||
def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta)
|
||||
def key_ = workflowArgs["key"]
|
||||
def multipleArgs = meta.config.allArguments.findAll{ it.multiple }.collect{it.plainName}
|
||||
|
||||
workflow workflowInstance {
|
||||
take: input_
|
||||
@@ -2720,12 +2849,36 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
}
|
||||
|
||||
// TODO: move some of the _meta.join_id wrangling to the safeJoin() function.
|
||||
def chInitialOutput = chArgsWithDefaults
|
||||
def chInitialOutputMulti = chArgsWithDefaults
|
||||
| _debug(workflowArgs, "processed")
|
||||
// run workflow
|
||||
| innerWorkflowFactory(workflowArgs)
|
||||
// check output tuple
|
||||
| map { id_, output_ ->
|
||||
def chInitialOutputList = chInitialOutputMulti instanceof List ? chInitialOutputMulti : [chInitialOutputMulti]
|
||||
assert chInitialOutputList.size() > 0: "should have emitted at least one output channel"
|
||||
// Add a channel ID to the events, which designates the channel the event was emitted from as a running number
|
||||
// This number is used to sort the events later when the events are gathered from across the channels.
|
||||
def chInitialOutputListWithIndexedEvents = chInitialOutputList.withIndex().collect{channel, channelIndex ->
|
||||
def newChannel = channel
|
||||
| map {tuple ->
|
||||
assert tuple instanceof List :
|
||||
"Error in module '${key_}': element in output channel should be a tuple [id, data, ...otherargs...]\n" +
|
||||
" Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" +
|
||||
" Expected class: List. Found: tuple.getClass() is ${tuple.getClass()}"
|
||||
|
||||
def newEvent = [channelIndex] + tuple
|
||||
return newEvent
|
||||
}
|
||||
return newChannel
|
||||
}
|
||||
// Put the events into 1 channel, cover case where there is only one channel is emitted
|
||||
def chInitialOutput = chInitialOutputList.size() > 1 ? \
|
||||
chInitialOutputListWithIndexedEvents[0].mix(*chInitialOutputListWithIndexedEvents.tail()) : \
|
||||
chInitialOutputListWithIndexedEvents[0]
|
||||
def chInitialOutputProcessed = chInitialOutput
|
||||
| map { tuple ->
|
||||
def channelId = tuple[0]
|
||||
def id_ = tuple[1]
|
||||
def output_ = tuple[2]
|
||||
|
||||
// see if output map contains metadata
|
||||
def meta_ =
|
||||
@@ -2738,19 +2891,94 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
output_ = output_.findAll{k, v -> k != "_meta"}
|
||||
|
||||
// check value types
|
||||
output_ = _processOutputValues(output_, meta.config, id_, key_)
|
||||
output_ = _checkValidOutputArgument(output_, meta.config, id_, key_)
|
||||
|
||||
// simplify output if need be
|
||||
if (workflowArgs.auto.simplifyOutput && output_.size() == 1) {
|
||||
output_ = output_.values()[0]
|
||||
}
|
||||
|
||||
[join_id, id_, output_]
|
||||
[join_id, channelId, id_, output_]
|
||||
}
|
||||
// | view{"chInitialOutput: ${it.take(3)}"}
|
||||
|
||||
// join the output [prev_id, channel_id, new_id, output] with the previous state [prev_id, state, ...]
|
||||
def chPublishWithPreviousState = safeJoin(chInitialOutputProcessed, chRunFiltered, key_)
|
||||
// input tuple format: [join_id, channel_id, id, output, prev_state, ...]
|
||||
// output tuple format: [join_id, channel_id, id, new_state, ...]
|
||||
| map{ tup ->
|
||||
def new_state = workflowArgs.toState(tup.drop(2).take(3))
|
||||
tup.take(3) + [new_state] + tup.drop(5)
|
||||
}
|
||||
if (workflowArgs.auto.publish == "state") {
|
||||
def chPublishFiles = chPublishWithPreviousState
|
||||
// input tuple format: [join_id, channel_id, id, new_state, ...]
|
||||
// output tuple format: [join_id, channel_id, id, new_state]
|
||||
| map{ tup ->
|
||||
tup.take(4)
|
||||
}
|
||||
|
||||
safeJoin(chPublishFiles, chArgsWithDefaults, key_)
|
||||
// input tuple format: [join_id, channel_id, id, new_state, orig_state, ...]
|
||||
// output tuple format: [id, new_state, orig_state]
|
||||
| map { tup ->
|
||||
tup.drop(2).take(3)
|
||||
}
|
||||
| publishFilesByConfig(key: key_, config: meta.config)
|
||||
}
|
||||
// Join the state from the events that were emitted from different channels
|
||||
def chJoined = chInitialOutputProcessed
|
||||
| map {tuple ->
|
||||
def join_id = tuple[0]
|
||||
def channel_id = tuple[1]
|
||||
def id = tuple[2]
|
||||
def other = tuple.drop(3)
|
||||
// Below, groupTuple is used to join the events. To make sure resuming a workflow
|
||||
// keeps working, the output state must be deterministic. This means the state needs to be
|
||||
// sorted with groupTuple's has a 'sort' argument. This argument can be set to 'hash',
|
||||
// but hashing the state when it is large can be problematic in terms of performance.
|
||||
// Therefore, a custom comparator function is provided. We add the channel ID to the
|
||||
// states so that we can use the channel ID to sort the items.
|
||||
def stateWithChannelID = [[channel_id] * other.size(), other].transpose()
|
||||
// A comparator that is provided to groupTuple's 'sort' argument is applied
|
||||
// to all elements of the event tuple (that is not the 'id'). The comparator
|
||||
// closure that is used below expects the input to be List. So the join_id and
|
||||
// channel_id must also be wrapped in a list.
|
||||
[[join_id], [channel_id], id] + stateWithChannelID
|
||||
}
|
||||
| groupTuple(by: 2, sort: {a, b -> a[0] <=> b[0]}, size: chInitialOutputList.size(), remainder: true)
|
||||
| map {join_ids, _, id, statesWithChannelID ->
|
||||
// Remove the channel IDs from the states
|
||||
def states = statesWithChannelID.collect{it[1]}
|
||||
def newJoinId = join_ids.flatten().unique{a, b -> a <=> b}
|
||||
assert newJoinId.size() == 1: "Multiple events were emitted for '$id'."
|
||||
def newJoinIdUnique = newJoinId[0]
|
||||
|
||||
// Merge the states from the different channels
|
||||
def newState = states.inject([:]){ old_state, state_to_add ->
|
||||
return old_state + state_to_add.collectEntries{k, v ->
|
||||
if (!multipleArgs.contains(k)) {
|
||||
// if the key is not a multiple argument, we expect only one value
|
||||
if (old_state.containsKey(k)) {
|
||||
assert old_state[k] == v : "ID $id: multiple entries for argument $k were emitted."
|
||||
}
|
||||
[k, v]
|
||||
} else {
|
||||
// if the key is a multiple argument, append the different values into one list
|
||||
def prevValue = old_state.getOrDefault(k, [])
|
||||
def prevValueAsList = prevValue instanceof List ? prevValue : [prevValue]
|
||||
[k, prevValueAsList + v]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_checkAllRequiredOuputsPresent(newState, meta.config, id, key_)
|
||||
|
||||
// simplify output if need be
|
||||
if (workflowArgs.auto.simplifyOutput && newState.size() == 1) {
|
||||
newState = newState.values()[0]
|
||||
}
|
||||
|
||||
return [newJoinIdUnique, id, newState]
|
||||
}
|
||||
|
||||
// join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...]
|
||||
def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_)
|
||||
def chNewState = safeJoin(chJoined, chRunFiltered, key_)
|
||||
// input tuple format: [join_id, id, output, prev_state, ...]
|
||||
// output tuple format: [join_id, id, new_state, ...]
|
||||
| map{ tup ->
|
||||
@@ -2759,23 +2987,21 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
}
|
||||
|
||||
if (workflowArgs.auto.publish == "state") {
|
||||
def chPublish = chNewState
|
||||
def chPublishStates = chNewState
|
||||
// input tuple format: [join_id, id, new_state, ...]
|
||||
// output tuple format: [join_id, id, new_state]
|
||||
| map{ tup ->
|
||||
tup.take(3)
|
||||
}
|
||||
|
||||
safeJoin(chPublish, chArgsWithDefaults, key_)
|
||||
safeJoin(chPublishStates, chArgsWithDefaults, key_)
|
||||
// input tuple format: [join_id, id, new_state, orig_state, ...]
|
||||
// output tuple format: [id, new_state, orig_state]
|
||||
| map { tup ->
|
||||
tup.drop(1).take(3)
|
||||
}
|
||||
}
|
||||
| publishStatesByConfig(key: key_, config: meta.config)
|
||||
}
|
||||
|
||||
// remove join_id and meta
|
||||
chReturn = chNewState
|
||||
| map { tup ->
|
||||
// input tuple format: [join_id, id, new_state, ...]
|
||||
@@ -2809,7 +3035,7 @@ meta = [
|
||||
"resources_dir": moduleDir.toRealPath().normalize(),
|
||||
"config": processConfig(readJsonBlob('''{
|
||||
"name" : "bcl_convert",
|
||||
"version" : "v0.3.0",
|
||||
"version" : "v0.3.1",
|
||||
"authors" : [
|
||||
{
|
||||
"name" : "Toni Verbeiren",
|
||||
@@ -3172,6 +3398,18 @@ meta = [
|
||||
"direction" : "output",
|
||||
"multiple" : false,
|
||||
"multiple_sep" : ";"
|
||||
},
|
||||
{
|
||||
"type" : "boolean",
|
||||
"name" : "--force",
|
||||
"description" : "Allow destination directory to already exist and overwrite files.\n",
|
||||
"example" : [
|
||||
true
|
||||
],
|
||||
"required" : false,
|
||||
"direction" : "input",
|
||||
"multiple" : false,
|
||||
"multiple_sep" : ";"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3192,6 +3430,10 @@ meta = [
|
||||
}
|
||||
],
|
||||
"status" : "enabled",
|
||||
"scope" : {
|
||||
"image" : "public",
|
||||
"target" : "public"
|
||||
},
|
||||
"requirements" : {
|
||||
"commands" : [
|
||||
"ps"
|
||||
@@ -3289,7 +3531,7 @@ meta = [
|
||||
"id" : "docker",
|
||||
"image" : "debian:trixie-slim",
|
||||
"target_registry" : "images.viash-hub.com",
|
||||
"target_tag" : "v0.3.0",
|
||||
"target_tag" : "v0.3.1",
|
||||
"namespace_separator" : "/",
|
||||
"setup" : [
|
||||
{
|
||||
@@ -3328,23 +3570,24 @@ meta = [
|
||||
"runner" : "nextflow",
|
||||
"engine" : "docker|native",
|
||||
"output" : "target/nextflow/bcl_convert",
|
||||
"viash_version" : "0.9.0",
|
||||
"git_commit" : "d86bd5cf62104af02caa852aacd352b1aa97ed60",
|
||||
"git_remote" : "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox",
|
||||
"git_tag" : "v0.2.0-29-gd86bd5c"
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "98a5f3cc745525a65c10263d25cf414eb1093223",
|
||||
"git_remote" : "https://github.com/viash-hub/biobox",
|
||||
"git_tag" : "v0.3.0-8-g98a5f3c"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "biobox",
|
||||
"version" : "v0.3.0",
|
||||
"description" : "A collection of bioinformatics tools for working with sequence data.\n",
|
||||
"viash_version" : "0.9.0",
|
||||
"version" : "v0.3.1",
|
||||
"summary" : "A curated collection of high-quality, standalone bioinformatics components built with [Viash](https://viash.io).\n",
|
||||
"description" : "`biobox` offers a suite of reliable bioinformatics components, similar to [nf-core/modules](https://github.com/nf-core/modules) and [snakemake-wrappers/bio](https://github.com/snakemake/snakemake-wrappers/tree/master/bio), but built using the [Viash](https://viash.io) framework.\n\nThis approach emphasizes **reusability**, **reproducibility**, and adherence to **best practices**. Key features of `biobox` components include:\n\n* **Standalone & Nextflow Ready:** Run components directly via the command line or seamlessly integrate them into Nextflow workflows.\n* **High Quality Standards:**\n * Comprehensive documentation for components and parameters.\n * Full exposure of underlying tool arguments.\n * Containerized (Docker) for dependency management and reproducibility.\n * Unit tested for verified functionality.\n",
|
||||
"viash_version" : "0.9.4",
|
||||
"source" : "src",
|
||||
"target" : "target",
|
||||
"config_mods" : [
|
||||
".requirements.commands := ['ps']\n",
|
||||
".engines += { type: \\"native\\" }",
|
||||
".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'",
|
||||
".engines[.type == 'docker'].target_tag := 'v0.3.0'"
|
||||
".engines[.type == 'docker'].target_tag := 'v0.3.1'"
|
||||
],
|
||||
"keywords" : [
|
||||
"bioinformatics",
|
||||
@@ -3395,6 +3638,7 @@ $( if [ ! -z ${VIASH_PAR_BCL_SAMPLEPROJECT_SUBDIRECTORIES+x} ]; then echo "${VIA
|
||||
$( if [ ! -z ${VIASH_PAR_FASTQ_GZIP_COMPRESSION_LEVEL+x} ]; then echo "${VIASH_PAR_FASTQ_GZIP_COMPRESSION_LEVEL}" | sed "s#'#'\\"'\\"'#g;s#.*#par_fastq_gzip_compression_level='&'#" ; else echo "# par_fastq_gzip_compression_level="; fi )
|
||||
$( if [ ! -z ${VIASH_PAR_REPORTS+x} ]; then echo "${VIASH_PAR_REPORTS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_reports='&'#" ; else echo "# par_reports="; fi )
|
||||
$( if [ ! -z ${VIASH_PAR_LOGS+x} ]; then echo "${VIASH_PAR_LOGS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_logs='&'#" ; else echo "# par_logs="; fi )
|
||||
$( if [ ! -z ${VIASH_PAR_FORCE+x} ]; then echo "${VIASH_PAR_FORCE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_force='&'#" ; else echo "# par_force="; fi )
|
||||
$( if [ ! -z ${VIASH_META_NAME+x} ]; then echo "${VIASH_META_NAME}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_name='&'#" ; else echo "# meta_name="; fi )
|
||||
$( if [ ! -z ${VIASH_META_FUNCTIONALITY_NAME+x} ]; then echo "${VIASH_META_FUNCTIONALITY_NAME}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_functionality_name='&'#" ; else echo "# meta_functionality_name="; fi )
|
||||
$( if [ ! -z ${VIASH_META_RESOURCES_DIR+x} ]; then echo "${VIASH_META_RESOURCES_DIR}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_resources_dir='&'#" ; else echo "# meta_resources_dir="; fi )
|
||||
@@ -3419,9 +3663,13 @@ $( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}"
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
[[ "\\$par_force" == "false" ]] && unset par_force
|
||||
|
||||
|
||||
\\$(which bcl-convert) \\\\
|
||||
--bcl-input-directory "\\$par_bcl_input_directory" \\\\
|
||||
--output-directory "\\$par_output_directory" \\\\
|
||||
\\${par_force:+--force} \\\\
|
||||
\\${par_sample_sheet:+ --sample-sheet "\\$par_sample_sheet"} \\\\
|
||||
\\${par_run_info:+ --run-info "\\$par_run_info"} \\\\
|
||||
\\${par_bcl_only_lane:+ --bcl-only-lane "\\$par_bcl_only_lane"} \\\\
|
||||
@@ -3789,7 +4037,7 @@ def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) {
|
||||
// create process from temp file
|
||||
def binding = new nextflow.script.ScriptBinding([:])
|
||||
def session = nextflow.Nextflow.getSession()
|
||||
def parser = new nextflow.script.ScriptParser(session)
|
||||
def parser = _getScriptLoader(session)
|
||||
.setModule(true)
|
||||
.setBinding(binding)
|
||||
def moduleScript = parser.runScript(tempFile)
|
||||
@@ -3803,6 +4051,27 @@ def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) {
|
||||
return scriptMeta.getProcess(procKey)
|
||||
}
|
||||
|
||||
// use Reflection to get a ScriptParser / ScriptLoader
|
||||
// <25.02.0-edge: new nextflow.script.ScriptParser(session)
|
||||
// >=25.02.0-edge: nextflow.script.ScriptLoaderFactory.create(session)
|
||||
def _getScriptLoader(nextflow.Session session) {
|
||||
// try using the old method
|
||||
try {
|
||||
Class<?> scriptParserClass = Class.forName('nextflow.script.ScriptParser')
|
||||
return scriptParserClass.getDeclaredConstructor(nextflow.Session).newInstance(session)
|
||||
} catch (ClassNotFoundException e) {
|
||||
// else try with the new method
|
||||
try {
|
||||
Class<?> scriptLoaderFactoryClass = Class.forName('nextflow.script.ScriptLoaderFactory')
|
||||
def createMethod = scriptLoaderFactoryClass.getDeclaredMethod('create', nextflow.Session)
|
||||
return createMethod.invoke(null, session) // null because create is static
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | java.lang.reflect.InvocationTargetException e2) {
|
||||
// Handle the case where neither class is found
|
||||
throw new Exception("Neither nextflow.script.ScriptParser nor nextflow.script.ScriptLoaderFactory could be found. Is this a compatible Nextflow version?", e2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// defaults
|
||||
meta["defaults"] = [
|
||||
// key to be used to trace the process and determine output names
|
||||
@@ -3816,7 +4085,7 @@ meta["defaults"] = [
|
||||
"container" : {
|
||||
"registry" : "images.viash-hub.com",
|
||||
"image" : "vsh/biobox/bcl_convert",
|
||||
"tag" : "v0.3.0"
|
||||
"tag" : "v0.3.1"
|
||||
},
|
||||
"tag" : "$id"
|
||||
}'''),
|
||||
@@ -2,7 +2,7 @@ manifest {
|
||||
name = 'bcl_convert'
|
||||
mainScript = 'main.nf'
|
||||
nextflowVersion = '!>=20.12.1-edge'
|
||||
version = 'v0.3.0'
|
||||
version = 'v0.3.1'
|
||||
description = 'Convert bcl files to fastq files using bcl-convert.\nInformation about upgrading from bcl2fastq via\n[Upgrading from bcl2fastq to BCL Convert](https://emea.support.illumina.com/bulletins/2020/10/upgrading-from-bcl2fastq-to-bcl-convert.html)\nand [BCL Convert Compatible Products](https://support.illumina.com/sequencing/sequencing_software/bcl-convert/compatibility.html)\n'
|
||||
author = 'Toni Verbeiren, Dorien Roosen'
|
||||
}
|
||||
@@ -237,10 +237,10 @@
|
||||
"output_directory": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required, default: `$id.$key.output_directory.output_directory`, example: `fastq_dir`. Output directory containig fastq files",
|
||||
"help_text": "Type: `file`, required, default: `$id.$key.output_directory.output_directory`, example: `fastq_dir`. Output directory containig fastq files"
|
||||
"description": "Type: `file`, required, default: `$id.$key.output_directory`, example: `fastq_dir`. Output directory containig fastq files",
|
||||
"help_text": "Type: `file`, required, default: `$id.$key.output_directory`, example: `fastq_dir`. Output directory containig fastq files"
|
||||
,
|
||||
"default":"$id.$key.output_directory.output_directory"
|
||||
"default":"$id.$key.output_directory"
|
||||
}
|
||||
|
||||
|
||||
@@ -268,10 +268,10 @@
|
||||
"reports": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id.$key.reports.reports`, example: `reports_dir`. Reports directory",
|
||||
"help_text": "Type: `file`, default: `$id.$key.reports.reports`, example: `reports_dir`. Reports directory"
|
||||
"description": "Type: `file`, default: `$id.$key.reports`, example: `reports_dir`. Reports directory",
|
||||
"help_text": "Type: `file`, default: `$id.$key.reports`, example: `reports_dir`. Reports directory"
|
||||
,
|
||||
"default":"$id.$key.reports.reports"
|
||||
"default":"$id.$key.reports"
|
||||
}
|
||||
|
||||
|
||||
@@ -279,10 +279,20 @@
|
||||
"logs": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id.$key.logs.logs`, example: `logs_dir`. Reports directory",
|
||||
"help_text": "Type: `file`, default: `$id.$key.logs.logs`, example: `logs_dir`. Reports directory"
|
||||
"description": "Type: `file`, default: `$id.$key.logs`, example: `logs_dir`. Reports directory",
|
||||
"help_text": "Type: `file`, default: `$id.$key.logs`, example: `logs_dir`. Reports directory"
|
||||
,
|
||||
"default":"$id.$key.logs.logs"
|
||||
"default":"$id.$key.logs"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"force": {
|
||||
"type":
|
||||
"boolean",
|
||||
"description": "Type: `boolean`, example: `true`. Allow destination directory to already exist and overwrite files",
|
||||
"help_text": "Type: `boolean`, example: `true`. Allow destination directory to already exist and overwrite files.\n"
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: "falco"
|
||||
version: "v0.3.0"
|
||||
version: "v0.3.1"
|
||||
authors:
|
||||
- name: "Toni Verbeiren"
|
||||
roles:
|
||||
@@ -203,6 +203,9 @@ test_resources:
|
||||
is_executable: true
|
||||
info: null
|
||||
status: "enabled"
|
||||
scope:
|
||||
image: "public"
|
||||
target: "public"
|
||||
requirements:
|
||||
commands:
|
||||
- "ps"
|
||||
@@ -287,7 +290,7 @@ engines:
|
||||
id: "docker"
|
||||
image: "debian:trixie-slim"
|
||||
target_registry: "images.viash-hub.com"
|
||||
target_tag: "v0.3.0"
|
||||
target_tag: "v0.3.1"
|
||||
namespace_separator: "/"
|
||||
setup:
|
||||
- type: "apt"
|
||||
@@ -316,23 +319,34 @@ build_info:
|
||||
engine: "docker|native"
|
||||
output: "target/nextflow/falco"
|
||||
executable: "target/nextflow/falco/main.nf"
|
||||
viash_version: "0.9.0"
|
||||
git_commit: "d86bd5cf62104af02caa852aacd352b1aa97ed60"
|
||||
git_remote: "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox"
|
||||
git_tag: "v0.2.0-29-gd86bd5c"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "98a5f3cc745525a65c10263d25cf414eb1093223"
|
||||
git_remote: "https://github.com/viash-hub/biobox"
|
||||
git_tag: "v0.3.0-8-g98a5f3c"
|
||||
package_config:
|
||||
name: "biobox"
|
||||
version: "v0.3.0"
|
||||
description: "A collection of bioinformatics tools for working with sequence data.\n"
|
||||
version: "v0.3.1"
|
||||
summary: "A curated collection of high-quality, standalone bioinformatics components\
|
||||
\ built with [Viash](https://viash.io).\n"
|
||||
description: "`biobox` offers a suite of reliable bioinformatics components, similar\
|
||||
\ to [nf-core/modules](https://github.com/nf-core/modules) and [snakemake-wrappers/bio](https://github.com/snakemake/snakemake-wrappers/tree/master/bio),\
|
||||
\ but built using the [Viash](https://viash.io) framework.\n\nThis approach emphasizes\
|
||||
\ **reusability**, **reproducibility**, and adherence to **best practices**. Key\
|
||||
\ features of `biobox` components include:\n\n* **Standalone & Nextflow Ready:**\
|
||||
\ Run components directly via the command line or seamlessly integrate them into\
|
||||
\ Nextflow workflows.\n* **High Quality Standards:**\n * Comprehensive documentation\
|
||||
\ for components and parameters.\n * Full exposure of underlying tool arguments.\n\
|
||||
\ * Containerized (Docker) for dependency management and reproducibility.\n\
|
||||
\ * Unit tested for verified functionality.\n"
|
||||
info: null
|
||||
viash_version: "0.9.0"
|
||||
viash_version: "0.9.4"
|
||||
source: "src"
|
||||
target: "target"
|
||||
config_mods:
|
||||
- ".requirements.commands := ['ps']\n"
|
||||
- ".engines += { type: \"native\" }"
|
||||
- ".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'"
|
||||
- ".engines[.type == 'docker'].target_tag := 'v0.3.0'"
|
||||
- ".engines[.type == 'docker'].target_tag := 'v0.3.1'"
|
||||
keywords:
|
||||
- "bioinformatics"
|
||||
- "modules"
|
||||
@@ -1,6 +1,6 @@
|
||||
// falco v0.3.0
|
||||
// falco v0.3.1
|
||||
//
|
||||
// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative
|
||||
// This wrapper script is auto-generated by viash 0.9.4 and is thus a derivative
|
||||
// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data
|
||||
// Intuitive.
|
||||
//
|
||||
@@ -85,64 +85,56 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
foundClass = "List[${e.foundClass}]"
|
||||
}
|
||||
} else if (par.type == "string") {
|
||||
// cast to string if need be
|
||||
// cast to string if need be. only cast if the value is a GString
|
||||
if (value instanceof GString) {
|
||||
value = value.toString()
|
||||
value = value as String
|
||||
}
|
||||
expectedClass = value instanceof String ? null : "String"
|
||||
} else if (par.type == "integer") {
|
||||
// cast to integer if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Integer) {
|
||||
try {
|
||||
value = value.toInteger()
|
||||
value = value as Integer
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Integer"
|
||||
}
|
||||
}
|
||||
if (value instanceof java.math.BigInteger) {
|
||||
value = value.intValue()
|
||||
}
|
||||
expectedClass = value instanceof Integer ? null : "Integer"
|
||||
} else if (par.type == "long") {
|
||||
// cast to long if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Long) {
|
||||
try {
|
||||
value = value.toLong()
|
||||
value = value as Long
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Long"
|
||||
}
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
value = value.toLong()
|
||||
}
|
||||
expectedClass = value instanceof Long ? null : "Long"
|
||||
} else if (par.type == "double") {
|
||||
// cast to double if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Double) {
|
||||
try {
|
||||
value = value.toDouble()
|
||||
value = value as Double
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Double"
|
||||
}
|
||||
}
|
||||
if (value instanceof java.math.BigDecimal) {
|
||||
value = value.doubleValue()
|
||||
} else if (par.type == "float") {
|
||||
// cast to float if need be
|
||||
if (value !instanceof Float) {
|
||||
try {
|
||||
value = value as Float
|
||||
} catch (NumberFormatException e) {
|
||||
expectedClass = "Float"
|
||||
}
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
value = value.toDouble()
|
||||
}
|
||||
expectedClass = value instanceof Double ? null : "Double"
|
||||
} else if (par.type == "boolean" | par.type == "boolean_true" | par.type == "boolean_false") {
|
||||
// cast to boolean if need be
|
||||
if (value instanceof String) {
|
||||
def valueLower = value.toLowerCase()
|
||||
if (valueLower == "true") {
|
||||
value = true
|
||||
} else if (valueLower == "false") {
|
||||
value = false
|
||||
if (value !instanceof Boolean) {
|
||||
try {
|
||||
value = value as Boolean
|
||||
} catch (Exception e) {
|
||||
expectedClass = "Boolean"
|
||||
}
|
||||
}
|
||||
expectedClass = value instanceof Boolean ? null : "Boolean"
|
||||
} else if (par.type == "file" && (par.direction == "input" || stage == "output")) {
|
||||
// cast to path if need be
|
||||
if (value instanceof String) {
|
||||
@@ -154,10 +146,13 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
expectedClass = value instanceof Path ? null : "Path"
|
||||
} else if (par.type == "file" && stage == "input" && par.direction == "output") {
|
||||
// cast to string if need be
|
||||
if (value instanceof GString) {
|
||||
value = value.toString()
|
||||
if (value !instanceof String) {
|
||||
try {
|
||||
value = value as String
|
||||
} catch (Exception e) {
|
||||
expectedClass = "String"
|
||||
}
|
||||
}
|
||||
expectedClass = value instanceof String ? null : "String"
|
||||
} else {
|
||||
// didn't find a match for par.type
|
||||
expectedClass = par.type
|
||||
@@ -176,7 +171,7 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
Map _processInputValues(Map inputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.required) {
|
||||
if (arg.required && arg.direction == "input") {
|
||||
assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing"
|
||||
}
|
||||
@@ -195,15 +190,8 @@ Map _processInputValues(Map inputs, Map config, String id, String key) {
|
||||
}
|
||||
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf'
|
||||
Map _processOutputValues(Map outputs, Map config, String id, String key) {
|
||||
Map _checkValidOutputArgument(Map outputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.direction == "output" && arg.required) {
|
||||
assert outputs.containsKey(arg.plainName) && outputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required output argument '${arg.plainName}' is missing"
|
||||
}
|
||||
}
|
||||
|
||||
outputs = outputs.collectEntries { name, value ->
|
||||
def par = config.allArguments.find { it.plainName == name && it.direction == "output" }
|
||||
assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid output argument"
|
||||
@@ -216,6 +204,16 @@ Map _processOutputValues(Map outputs, Map config, String id, String key) {
|
||||
return outputs
|
||||
}
|
||||
|
||||
void _checkAllRequiredOuputsPresent(Map outputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.direction == "output" && arg.required) {
|
||||
assert outputs.containsKey(arg.plainName) && outputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required output argument '${arg.plainName}' is missing"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf'
|
||||
class IDChecker {
|
||||
final def items = [] as Set
|
||||
@@ -1669,6 +1667,162 @@ def joinStates(Closure apply_) {
|
||||
}
|
||||
return joinStatesWf
|
||||
}
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishFiles.nf'
|
||||
def publishFiles(Map args) {
|
||||
def key_ = args.get("key")
|
||||
|
||||
assert key_ != null : "publishFiles: key must be specified"
|
||||
|
||||
workflow publishFilesWf {
|
||||
take: input_ch
|
||||
main:
|
||||
input_ch
|
||||
| map { tup ->
|
||||
def id_ = tup[0]
|
||||
def state_ = tup[1]
|
||||
|
||||
// the input files and the target output filenames
|
||||
def inputoutputFilenames_ = collectInputOutputPaths(state_, id_ + "." + key_).transpose()
|
||||
def inputFiles_ = inputoutputFilenames_[0]
|
||||
def outputFilenames_ = inputoutputFilenames_[1]
|
||||
|
||||
[id_, inputFiles_, outputFilenames_]
|
||||
}
|
||||
| publishFilesProc
|
||||
emit: input_ch
|
||||
}
|
||||
return publishFilesWf
|
||||
}
|
||||
|
||||
process publishFilesProc {
|
||||
// todo: check publishpath?
|
||||
publishDir path: "${getPublishDir()}/", mode: "copy"
|
||||
tag "$id"
|
||||
input:
|
||||
tuple val(id), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles)
|
||||
output:
|
||||
tuple val(id), path{outputFiles}
|
||||
script:
|
||||
def copyCommands = [
|
||||
inputFiles instanceof List ? inputFiles : [inputFiles],
|
||||
outputFiles instanceof List ? outputFiles : [outputFiles]
|
||||
]
|
||||
.transpose()
|
||||
.collectMany{infile, outfile ->
|
||||
if (infile.toString() != outfile.toString()) {
|
||||
[
|
||||
"[ -d \"\$(dirname '${outfile.toString()}')\" ] || mkdir -p \"\$(dirname '${outfile.toString()}')\"",
|
||||
"cp -r '${infile.toString()}' '${outfile.toString()}'"
|
||||
]
|
||||
} else {
|
||||
// no need to copy if infile is the same as outfile
|
||||
[]
|
||||
}
|
||||
}
|
||||
"""
|
||||
echo "Copying output files to destination folder"
|
||||
${copyCommands.join("\n ")}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
// this assumes that the state contains no other values other than those specified in the config
|
||||
def publishFilesByConfig(Map args) {
|
||||
def config = args.get("config")
|
||||
assert config != null : "publishFilesByConfig: config must be specified"
|
||||
|
||||
def key_ = args.get("key", config.name)
|
||||
assert key_ != null : "publishFilesByConfig: key must be specified"
|
||||
|
||||
workflow publishFilesSimpleWf {
|
||||
take: input_ch
|
||||
main:
|
||||
input_ch
|
||||
| map { tup ->
|
||||
def id_ = tup[0]
|
||||
def state_ = tup[1] // e.g. [output: new File("myoutput.h5ad"), k: 10]
|
||||
def origState_ = tup[2] // e.g. [output: '$id.$key.foo.h5ad']
|
||||
|
||||
|
||||
// the processed state is a list of [key, value, inputPath, outputFilename] tuples, where
|
||||
// - key is a String
|
||||
// - value is any object that can be serialized to a Yaml (so a String/Integer/Long/Double/Boolean, a List, a Map, or a Path)
|
||||
// - inputPath is a List[Path]
|
||||
// - outputFilename is a List[String]
|
||||
// - (inputPath, outputFilename) are the files that will be copied from src to dest (relative to the state.yaml)
|
||||
def processedState =
|
||||
config.allArguments
|
||||
.findAll { it.direction == "output" }
|
||||
.collectMany { par ->
|
||||
def plainName_ = par.plainName
|
||||
// if the state does not contain the key, it's an
|
||||
// optional argument for which the component did
|
||||
// not generate any output OR multiple channels were emitted
|
||||
// and the output was just not added to using the channel
|
||||
// that is now being parsed
|
||||
if (!state_.containsKey(plainName_)) {
|
||||
return []
|
||||
}
|
||||
def value = state_[plainName_]
|
||||
// if the parameter is not a file, it should be stored
|
||||
// in the state as-is, but is not something that needs
|
||||
// to be copied from the source path to the dest path
|
||||
if (par.type != "file") {
|
||||
return [[inputPath: [], outputFilename: []]]
|
||||
}
|
||||
// if the orig state does not contain this filename,
|
||||
// it's an optional argument for which the user specified
|
||||
// that it should not be returned as a state
|
||||
if (!origState_.containsKey(plainName_)) {
|
||||
return []
|
||||
}
|
||||
def filenameTemplate = origState_[plainName_]
|
||||
// if the pararameter is multiple: true, fetch the template
|
||||
if (par.multiple && filenameTemplate instanceof List) {
|
||||
filenameTemplate = filenameTemplate[0]
|
||||
}
|
||||
// instantiate the template
|
||||
def filename = filenameTemplate
|
||||
.replaceAll('\\$id', id_)
|
||||
.replaceAll('\\$\\{id\\}', id_)
|
||||
.replaceAll('\\$key', key_)
|
||||
.replaceAll('\\$\\{key\\}', key_)
|
||||
if (par.multiple) {
|
||||
// if the parameter is multiple: true, the filename
|
||||
// should contain a wildcard '*' that is replaced with
|
||||
// the index of the file
|
||||
assert filename.contains("*") : "Module '${key_}' id '${id_}': Multiple output files specified, but no wildcard '*' in the filename: ${filename}"
|
||||
def outputPerFile = value.withIndex().collect{ val, ix ->
|
||||
def filename_ix = filename.replace("*", ix.toString())
|
||||
def inputPath = val instanceof File ? val.toPath() : val
|
||||
[inputPath: inputPath, outputFilename: filename_ix]
|
||||
}
|
||||
def transposedOutputs = ["inputPath", "outputFilename"].collectEntries{ key ->
|
||||
[key, outputPerFile.collect{dic -> dic[key]}]
|
||||
}
|
||||
return [[key: plainName_] + transposedOutputs]
|
||||
} else {
|
||||
def value_ = java.nio.file.Paths.get(filename)
|
||||
def inputPath = value instanceof File ? value.toPath() : value
|
||||
return [[inputPath: [inputPath], outputFilename: [filename]]]
|
||||
}
|
||||
}
|
||||
|
||||
def inputPaths = processedState.collectMany{it.inputPath}
|
||||
def outputFilenames = processedState.collectMany{it.outputFilename}
|
||||
|
||||
|
||||
[id_, inputPaths, outputFilenames]
|
||||
}
|
||||
| publishFilesProc
|
||||
emit: input_ch
|
||||
}
|
||||
return publishFilesSimpleWf
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf'
|
||||
def collectFiles(obj) {
|
||||
if (obj instanceof java.io.File || obj instanceof Path) {
|
||||
@@ -1726,8 +1880,6 @@ def publishStates(Map args) {
|
||||
|
||||
// the input files and the target output filenames
|
||||
def inputoutputFilenames_ = collectInputOutputPaths(state_, id_ + "." + key_).transpose()
|
||||
def inputFiles_ = inputoutputFilenames_[0]
|
||||
def outputFilenames_ = inputoutputFilenames_[1]
|
||||
|
||||
def yamlFilename = yamlTemplate_
|
||||
.replaceAll('\\$id', id_)
|
||||
@@ -1740,7 +1892,7 @@ def publishStates(Map args) {
|
||||
// convert state to yaml blob
|
||||
def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename))
|
||||
|
||||
[id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_]
|
||||
[id_, yamlBlob_, yamlFilename]
|
||||
}
|
||||
| publishStatesProc
|
||||
emit: input_ch
|
||||
@@ -1752,33 +1904,17 @@ process publishStatesProc {
|
||||
publishDir path: "${getPublishDir()}/", mode: "copy"
|
||||
tag "$id"
|
||||
input:
|
||||
tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles)
|
||||
tuple val(id), val(yamlBlob), val(yamlFile)
|
||||
output:
|
||||
tuple val(id), path{[yamlFile] + outputFiles}
|
||||
tuple val(id), path{[yamlFile]}
|
||||
script:
|
||||
def copyCommands = [
|
||||
inputFiles instanceof List ? inputFiles : [inputFiles],
|
||||
outputFiles instanceof List ? outputFiles : [outputFiles]
|
||||
]
|
||||
.transpose()
|
||||
.collectMany{infile, outfile ->
|
||||
if (infile.toString() != outfile.toString()) {
|
||||
[
|
||||
"[ -d \"\$(dirname '${outfile.toString()}')\" ] || mkdir -p \"\$(dirname '${outfile.toString()}')\"",
|
||||
"cp -r '${infile.toString()}' '${outfile.toString()}'"
|
||||
]
|
||||
} else {
|
||||
// no need to copy if infile is the same as outfile
|
||||
[]
|
||||
}
|
||||
}
|
||||
"""
|
||||
mkdir -p "\$(dirname '${yamlFile}')"
|
||||
echo "Storing state as yaml"
|
||||
echo '${yamlBlob}' > '${yamlFile}'
|
||||
echo "Copying output files to destination folder"
|
||||
${copyCommands.join("\n ")}
|
||||
"""
|
||||
mkdir -p "\$(dirname '${yamlFile}')"
|
||||
echo "Storing state as yaml"
|
||||
cat > '${yamlFile}' << HERE
|
||||
${yamlBlob}
|
||||
HERE
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
@@ -1809,13 +1945,10 @@ def publishStatesByConfig(Map args) {
|
||||
.replaceAll('\\$\\{key\\}', key_)
|
||||
def yamlDir = java.nio.file.Paths.get(yamlFilename).getParent()
|
||||
|
||||
// the processed state is a list of [key, value, inputPath, outputFilename] tuples, where
|
||||
// the processed state is a list of [key, value] tuples, where
|
||||
// - key is a String
|
||||
// - value is any object that can be serialized to a Yaml (so a String/Integer/Long/Double/Boolean, a List, a Map, or a Path)
|
||||
// - inputPath is a List[Path]
|
||||
// - outputFilename is a List[String]
|
||||
// - (key, value) are the tuples that will be saved to the state.yaml file
|
||||
// - (inputPath, outputFilename) are the files that will be copied from src to dest (relative to the state.yaml)
|
||||
def processedState =
|
||||
config.allArguments
|
||||
.findAll { it.direction == "output" }
|
||||
@@ -1832,7 +1965,7 @@ def publishStatesByConfig(Map args) {
|
||||
// in the state as-is, but is not something that needs
|
||||
// to be copied from the source path to the dest path
|
||||
if (par.type != "file") {
|
||||
return [[key: plainName_, value: value, inputPath: [], outputFilename: []]]
|
||||
return [[key: plainName_, value: value]]
|
||||
}
|
||||
// if the orig state does not contain this filename,
|
||||
// it's an optional argument for which the user specified
|
||||
@@ -1863,13 +1996,9 @@ def publishStatesByConfig(Map args) {
|
||||
if (yamlDir != null) {
|
||||
value_ = yamlDir.relativize(value_)
|
||||
}
|
||||
def inputPath = val instanceof File ? val.toPath() : val
|
||||
[value: value_, inputPath: inputPath, outputFilename: filename_ix]
|
||||
return value_
|
||||
}
|
||||
def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key ->
|
||||
[key, outputPerFile.collect{dic -> dic[key]}]
|
||||
}
|
||||
return [[key: plainName_] + transposedOutputs]
|
||||
return [["key": plainName_, "value": outputPerFile]]
|
||||
} else {
|
||||
def value_ = java.nio.file.Paths.get(filename)
|
||||
// if id contains a slash
|
||||
@@ -1877,18 +2006,17 @@ def publishStatesByConfig(Map args) {
|
||||
value_ = yamlDir.relativize(value_)
|
||||
}
|
||||
def inputPath = value instanceof File ? value.toPath() : value
|
||||
return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]]
|
||||
return [["key": plainName_, value: value_]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def updatedState_ = processedState.collectEntries{[it.key, it.value]}
|
||||
def inputPaths = processedState.collectMany{it.inputPath}
|
||||
def outputFilenames = processedState.collectMany{it.outputFilename}
|
||||
|
||||
// convert state to yaml blob
|
||||
def yamlBlob_ = toTaggedYamlBlob([id: id_] + updatedState_)
|
||||
|
||||
[id_, yamlBlob_, yamlFilename, inputPaths, outputFilenames]
|
||||
[id_, yamlBlob_, yamlFilename]
|
||||
}
|
||||
| publishStatesProc
|
||||
emit: input_ch
|
||||
@@ -2562,6 +2690,7 @@ def _debug(workflowArgs, debugKey) {
|
||||
def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta)
|
||||
def key_ = workflowArgs["key"]
|
||||
def multipleArgs = meta.config.allArguments.findAll{ it.multiple }.collect{it.plainName}
|
||||
|
||||
workflow workflowInstance {
|
||||
take: input_
|
||||
@@ -2719,12 +2848,36 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
}
|
||||
|
||||
// TODO: move some of the _meta.join_id wrangling to the safeJoin() function.
|
||||
def chInitialOutput = chArgsWithDefaults
|
||||
def chInitialOutputMulti = chArgsWithDefaults
|
||||
| _debug(workflowArgs, "processed")
|
||||
// run workflow
|
||||
| innerWorkflowFactory(workflowArgs)
|
||||
// check output tuple
|
||||
| map { id_, output_ ->
|
||||
def chInitialOutputList = chInitialOutputMulti instanceof List ? chInitialOutputMulti : [chInitialOutputMulti]
|
||||
assert chInitialOutputList.size() > 0: "should have emitted at least one output channel"
|
||||
// Add a channel ID to the events, which designates the channel the event was emitted from as a running number
|
||||
// This number is used to sort the events later when the events are gathered from across the channels.
|
||||
def chInitialOutputListWithIndexedEvents = chInitialOutputList.withIndex().collect{channel, channelIndex ->
|
||||
def newChannel = channel
|
||||
| map {tuple ->
|
||||
assert tuple instanceof List :
|
||||
"Error in module '${key_}': element in output channel should be a tuple [id, data, ...otherargs...]\n" +
|
||||
" Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" +
|
||||
" Expected class: List. Found: tuple.getClass() is ${tuple.getClass()}"
|
||||
|
||||
def newEvent = [channelIndex] + tuple
|
||||
return newEvent
|
||||
}
|
||||
return newChannel
|
||||
}
|
||||
// Put the events into 1 channel, cover case where there is only one channel is emitted
|
||||
def chInitialOutput = chInitialOutputList.size() > 1 ? \
|
||||
chInitialOutputListWithIndexedEvents[0].mix(*chInitialOutputListWithIndexedEvents.tail()) : \
|
||||
chInitialOutputListWithIndexedEvents[0]
|
||||
def chInitialOutputProcessed = chInitialOutput
|
||||
| map { tuple ->
|
||||
def channelId = tuple[0]
|
||||
def id_ = tuple[1]
|
||||
def output_ = tuple[2]
|
||||
|
||||
// see if output map contains metadata
|
||||
def meta_ =
|
||||
@@ -2737,19 +2890,94 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
output_ = output_.findAll{k, v -> k != "_meta"}
|
||||
|
||||
// check value types
|
||||
output_ = _processOutputValues(output_, meta.config, id_, key_)
|
||||
output_ = _checkValidOutputArgument(output_, meta.config, id_, key_)
|
||||
|
||||
// simplify output if need be
|
||||
if (workflowArgs.auto.simplifyOutput && output_.size() == 1) {
|
||||
output_ = output_.values()[0]
|
||||
}
|
||||
|
||||
[join_id, id_, output_]
|
||||
[join_id, channelId, id_, output_]
|
||||
}
|
||||
// | view{"chInitialOutput: ${it.take(3)}"}
|
||||
|
||||
// join the output [prev_id, channel_id, new_id, output] with the previous state [prev_id, state, ...]
|
||||
def chPublishWithPreviousState = safeJoin(chInitialOutputProcessed, chRunFiltered, key_)
|
||||
// input tuple format: [join_id, channel_id, id, output, prev_state, ...]
|
||||
// output tuple format: [join_id, channel_id, id, new_state, ...]
|
||||
| map{ tup ->
|
||||
def new_state = workflowArgs.toState(tup.drop(2).take(3))
|
||||
tup.take(3) + [new_state] + tup.drop(5)
|
||||
}
|
||||
if (workflowArgs.auto.publish == "state") {
|
||||
def chPublishFiles = chPublishWithPreviousState
|
||||
// input tuple format: [join_id, channel_id, id, new_state, ...]
|
||||
// output tuple format: [join_id, channel_id, id, new_state]
|
||||
| map{ tup ->
|
||||
tup.take(4)
|
||||
}
|
||||
|
||||
safeJoin(chPublishFiles, chArgsWithDefaults, key_)
|
||||
// input tuple format: [join_id, channel_id, id, new_state, orig_state, ...]
|
||||
// output tuple format: [id, new_state, orig_state]
|
||||
| map { tup ->
|
||||
tup.drop(2).take(3)
|
||||
}
|
||||
| publishFilesByConfig(key: key_, config: meta.config)
|
||||
}
|
||||
// Join the state from the events that were emitted from different channels
|
||||
def chJoined = chInitialOutputProcessed
|
||||
| map {tuple ->
|
||||
def join_id = tuple[0]
|
||||
def channel_id = tuple[1]
|
||||
def id = tuple[2]
|
||||
def other = tuple.drop(3)
|
||||
// Below, groupTuple is used to join the events. To make sure resuming a workflow
|
||||
// keeps working, the output state must be deterministic. This means the state needs to be
|
||||
// sorted with groupTuple's has a 'sort' argument. This argument can be set to 'hash',
|
||||
// but hashing the state when it is large can be problematic in terms of performance.
|
||||
// Therefore, a custom comparator function is provided. We add the channel ID to the
|
||||
// states so that we can use the channel ID to sort the items.
|
||||
def stateWithChannelID = [[channel_id] * other.size(), other].transpose()
|
||||
// A comparator that is provided to groupTuple's 'sort' argument is applied
|
||||
// to all elements of the event tuple (that is not the 'id'). The comparator
|
||||
// closure that is used below expects the input to be List. So the join_id and
|
||||
// channel_id must also be wrapped in a list.
|
||||
[[join_id], [channel_id], id] + stateWithChannelID
|
||||
}
|
||||
| groupTuple(by: 2, sort: {a, b -> a[0] <=> b[0]}, size: chInitialOutputList.size(), remainder: true)
|
||||
| map {join_ids, _, id, statesWithChannelID ->
|
||||
// Remove the channel IDs from the states
|
||||
def states = statesWithChannelID.collect{it[1]}
|
||||
def newJoinId = join_ids.flatten().unique{a, b -> a <=> b}
|
||||
assert newJoinId.size() == 1: "Multiple events were emitted for '$id'."
|
||||
def newJoinIdUnique = newJoinId[0]
|
||||
|
||||
// Merge the states from the different channels
|
||||
def newState = states.inject([:]){ old_state, state_to_add ->
|
||||
return old_state + state_to_add.collectEntries{k, v ->
|
||||
if (!multipleArgs.contains(k)) {
|
||||
// if the key is not a multiple argument, we expect only one value
|
||||
if (old_state.containsKey(k)) {
|
||||
assert old_state[k] == v : "ID $id: multiple entries for argument $k were emitted."
|
||||
}
|
||||
[k, v]
|
||||
} else {
|
||||
// if the key is a multiple argument, append the different values into one list
|
||||
def prevValue = old_state.getOrDefault(k, [])
|
||||
def prevValueAsList = prevValue instanceof List ? prevValue : [prevValue]
|
||||
[k, prevValueAsList + v]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_checkAllRequiredOuputsPresent(newState, meta.config, id, key_)
|
||||
|
||||
// simplify output if need be
|
||||
if (workflowArgs.auto.simplifyOutput && newState.size() == 1) {
|
||||
newState = newState.values()[0]
|
||||
}
|
||||
|
||||
return [newJoinIdUnique, id, newState]
|
||||
}
|
||||
|
||||
// join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...]
|
||||
def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_)
|
||||
def chNewState = safeJoin(chJoined, chRunFiltered, key_)
|
||||
// input tuple format: [join_id, id, output, prev_state, ...]
|
||||
// output tuple format: [join_id, id, new_state, ...]
|
||||
| map{ tup ->
|
||||
@@ -2758,23 +2986,21 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
}
|
||||
|
||||
if (workflowArgs.auto.publish == "state") {
|
||||
def chPublish = chNewState
|
||||
def chPublishStates = chNewState
|
||||
// input tuple format: [join_id, id, new_state, ...]
|
||||
// output tuple format: [join_id, id, new_state]
|
||||
| map{ tup ->
|
||||
tup.take(3)
|
||||
}
|
||||
|
||||
safeJoin(chPublish, chArgsWithDefaults, key_)
|
||||
safeJoin(chPublishStates, chArgsWithDefaults, key_)
|
||||
// input tuple format: [join_id, id, new_state, orig_state, ...]
|
||||
// output tuple format: [id, new_state, orig_state]
|
||||
| map { tup ->
|
||||
tup.drop(1).take(3)
|
||||
}
|
||||
}
|
||||
| publishStatesByConfig(key: key_, config: meta.config)
|
||||
}
|
||||
|
||||
// remove join_id and meta
|
||||
chReturn = chNewState
|
||||
| map { tup ->
|
||||
// input tuple format: [join_id, id, new_state, ...]
|
||||
@@ -2808,7 +3034,7 @@ meta = [
|
||||
"resources_dir": moduleDir.toRealPath().normalize(),
|
||||
"config": processConfig(readJsonBlob('''{
|
||||
"name" : "falco",
|
||||
"version" : "v0.3.0",
|
||||
"version" : "v0.3.1",
|
||||
"authors" : [
|
||||
{
|
||||
"name" : "Toni Verbeiren",
|
||||
@@ -3031,6 +3257,10 @@ meta = [
|
||||
}
|
||||
],
|
||||
"status" : "enabled",
|
||||
"scope" : {
|
||||
"image" : "public",
|
||||
"target" : "public"
|
||||
},
|
||||
"requirements" : {
|
||||
"commands" : [
|
||||
"ps"
|
||||
@@ -3131,7 +3361,7 @@ meta = [
|
||||
"id" : "docker",
|
||||
"image" : "debian:trixie-slim",
|
||||
"target_registry" : "images.viash-hub.com",
|
||||
"target_tag" : "v0.3.0",
|
||||
"target_tag" : "v0.3.1",
|
||||
"namespace_separator" : "/",
|
||||
"setup" : [
|
||||
{
|
||||
@@ -3169,23 +3399,24 @@ meta = [
|
||||
"runner" : "nextflow",
|
||||
"engine" : "docker|native",
|
||||
"output" : "target/nextflow/falco",
|
||||
"viash_version" : "0.9.0",
|
||||
"git_commit" : "d86bd5cf62104af02caa852aacd352b1aa97ed60",
|
||||
"git_remote" : "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox",
|
||||
"git_tag" : "v0.2.0-29-gd86bd5c"
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "98a5f3cc745525a65c10263d25cf414eb1093223",
|
||||
"git_remote" : "https://github.com/viash-hub/biobox",
|
||||
"git_tag" : "v0.3.0-8-g98a5f3c"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "biobox",
|
||||
"version" : "v0.3.0",
|
||||
"description" : "A collection of bioinformatics tools for working with sequence data.\n",
|
||||
"viash_version" : "0.9.0",
|
||||
"version" : "v0.3.1",
|
||||
"summary" : "A curated collection of high-quality, standalone bioinformatics components built with [Viash](https://viash.io).\n",
|
||||
"description" : "`biobox` offers a suite of reliable bioinformatics components, similar to [nf-core/modules](https://github.com/nf-core/modules) and [snakemake-wrappers/bio](https://github.com/snakemake/snakemake-wrappers/tree/master/bio), but built using the [Viash](https://viash.io) framework.\n\nThis approach emphasizes **reusability**, **reproducibility**, and adherence to **best practices**. Key features of `biobox` components include:\n\n* **Standalone & Nextflow Ready:** Run components directly via the command line or seamlessly integrate them into Nextflow workflows.\n* **High Quality Standards:**\n * Comprehensive documentation for components and parameters.\n * Full exposure of underlying tool arguments.\n * Containerized (Docker) for dependency management and reproducibility.\n * Unit tested for verified functionality.\n",
|
||||
"viash_version" : "0.9.4",
|
||||
"source" : "src",
|
||||
"target" : "target",
|
||||
"config_mods" : [
|
||||
".requirements.commands := ['ps']\n",
|
||||
".engines += { type: \\"native\\" }",
|
||||
".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'",
|
||||
".engines[.type == 'docker'].target_tag := 'v0.3.0'"
|
||||
".engines[.type == 'docker'].target_tag := 'v0.3.1'"
|
||||
],
|
||||
"keywords" : [
|
||||
"bioinformatics",
|
||||
@@ -3604,7 +3835,7 @@ def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) {
|
||||
// create process from temp file
|
||||
def binding = new nextflow.script.ScriptBinding([:])
|
||||
def session = nextflow.Nextflow.getSession()
|
||||
def parser = new nextflow.script.ScriptParser(session)
|
||||
def parser = _getScriptLoader(session)
|
||||
.setModule(true)
|
||||
.setBinding(binding)
|
||||
def moduleScript = parser.runScript(tempFile)
|
||||
@@ -3618,6 +3849,27 @@ def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) {
|
||||
return scriptMeta.getProcess(procKey)
|
||||
}
|
||||
|
||||
// use Reflection to get a ScriptParser / ScriptLoader
|
||||
// <25.02.0-edge: new nextflow.script.ScriptParser(session)
|
||||
// >=25.02.0-edge: nextflow.script.ScriptLoaderFactory.create(session)
|
||||
def _getScriptLoader(nextflow.Session session) {
|
||||
// try using the old method
|
||||
try {
|
||||
Class<?> scriptParserClass = Class.forName('nextflow.script.ScriptParser')
|
||||
return scriptParserClass.getDeclaredConstructor(nextflow.Session).newInstance(session)
|
||||
} catch (ClassNotFoundException e) {
|
||||
// else try with the new method
|
||||
try {
|
||||
Class<?> scriptLoaderFactoryClass = Class.forName('nextflow.script.ScriptLoaderFactory')
|
||||
def createMethod = scriptLoaderFactoryClass.getDeclaredMethod('create', nextflow.Session)
|
||||
return createMethod.invoke(null, session) // null because create is static
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | java.lang.reflect.InvocationTargetException e2) {
|
||||
// Handle the case where neither class is found
|
||||
throw new Exception("Neither nextflow.script.ScriptParser nor nextflow.script.ScriptLoaderFactory could be found. Is this a compatible Nextflow version?", e2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// defaults
|
||||
meta["defaults"] = [
|
||||
// key to be used to trace the process and determine output names
|
||||
@@ -3631,7 +3883,7 @@ meta["defaults"] = [
|
||||
"container" : {
|
||||
"registry" : "images.viash-hub.com",
|
||||
"image" : "vsh/biobox/falco",
|
||||
"tag" : "v0.3.0"
|
||||
"tag" : "v0.3.1"
|
||||
},
|
||||
"tag" : "$id"
|
||||
}'''),
|
||||
@@ -2,7 +2,7 @@ manifest {
|
||||
name = 'falco'
|
||||
mainScript = 'main.nf'
|
||||
nextflowVersion = '!>=20.12.1-edge'
|
||||
version = 'v0.3.0'
|
||||
version = 'v0.3.1'
|
||||
description = 'A C++ drop-in replacement of FastQC to assess the quality of sequence read data'
|
||||
author = 'Toni Verbeiren'
|
||||
}
|
||||
@@ -120,10 +120,10 @@
|
||||
"outdir": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required, default: `$id.$key.outdir.outdir`, example: `output`. Create all output files in the specified \noutput directory",
|
||||
"help_text": "Type: `file`, required, default: `$id.$key.outdir.outdir`, example: `output`. Create all output files in the specified \noutput directory. FALCO-SPECIFIC: If the \ndirectory does not exists, the program will \ncreate it.\n"
|
||||
"description": "Type: `file`, required, default: `$id.$key.outdir`, example: `output`. Create all output files in the specified \noutput directory",
|
||||
"help_text": "Type: `file`, required, default: `$id.$key.outdir`, example: `output`. Create all output files in the specified \noutput directory. FALCO-SPECIFIC: If the \ndirectory does not exists, the program will \ncreate it.\n"
|
||||
,
|
||||
"default":"$id.$key.outdir.outdir"
|
||||
"default":"$id.$key.outdir"
|
||||
}
|
||||
|
||||
|
||||
@@ -143,10 +143,10 @@
|
||||
"data_filename": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id.$key.data_filename.data_filename`. [Falco only] Specify filename for FastQC \ndata output (TXT)",
|
||||
"help_text": "Type: `file`, default: `$id.$key.data_filename.data_filename`. [Falco only] Specify filename for FastQC \ndata output (TXT). If not specified, it will \nbe called fastq_data.txt in either the input \nfile\u0027s directory or the one specified in the \n--output flag. Only available when running \nfalco with a single input.\n"
|
||||
"description": "Type: `file`, default: `$id.$key.data_filename`. [Falco only] Specify filename for FastQC \ndata output (TXT)",
|
||||
"help_text": "Type: `file`, default: `$id.$key.data_filename`. [Falco only] Specify filename for FastQC \ndata output (TXT). If not specified, it will \nbe called fastq_data.txt in either the input \nfile\u0027s directory or the one specified in the \n--output flag. Only available when running \nfalco with a single input.\n"
|
||||
,
|
||||
"default":"$id.$key.data_filename.data_filename"
|
||||
"default":"$id.$key.data_filename"
|
||||
}
|
||||
|
||||
|
||||
@@ -154,10 +154,10 @@
|
||||
"report_filename": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id.$key.report_filename.report_filename`. [Falco only] Specify filename for FastQC \nreport output (HTML)",
|
||||
"help_text": "Type: `file`, default: `$id.$key.report_filename.report_filename`. [Falco only] Specify filename for FastQC \nreport output (HTML). If not specified, it \nwill be called fastq_report.html in either \nthe input file\u0027s directory or the one \nspecified in the --output flag. Only \navailable when running falco with a single \ninput.\n"
|
||||
"description": "Type: `file`, default: `$id.$key.report_filename`. [Falco only] Specify filename for FastQC \nreport output (HTML)",
|
||||
"help_text": "Type: `file`, default: `$id.$key.report_filename`. [Falco only] Specify filename for FastQC \nreport output (HTML). If not specified, it \nwill be called fastq_report.html in either \nthe input file\u0027s directory or the one \nspecified in the --output flag. Only \navailable when running falco with a single \ninput.\n"
|
||||
,
|
||||
"default":"$id.$key.report_filename.report_filename"
|
||||
"default":"$id.$key.report_filename"
|
||||
}
|
||||
|
||||
|
||||
@@ -165,10 +165,10 @@
|
||||
"summary_filename": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id.$key.summary_filename.summary_filename`. [Falco only] Specify filename for the short \nsummary output (TXT)",
|
||||
"help_text": "Type: `file`, default: `$id.$key.summary_filename.summary_filename`. [Falco only] Specify filename for the short \nsummary output (TXT). If not specified, it \nwill be called fastq_report.html in either \nthe input file\u0027s directory or the one \nspecified in the --output flag. Only \navailable when running falco with a single \ninput.\n"
|
||||
"description": "Type: `file`, default: `$id.$key.summary_filename`. [Falco only] Specify filename for the short \nsummary output (TXT)",
|
||||
"help_text": "Type: `file`, default: `$id.$key.summary_filename`. [Falco only] Specify filename for the short \nsummary output (TXT). If not specified, it \nwill be called fastq_report.html in either \nthe input file\u0027s directory or the one \nspecified in the --output flag. Only \navailable when running falco with a single \ninput.\n"
|
||||
,
|
||||
"default":"$id.$key.summary_filename.summary_filename"
|
||||
"default":"$id.$key.summary_filename"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: "multiqc"
|
||||
version: "v0.3.0"
|
||||
version: "v0.3.1"
|
||||
authors:
|
||||
- name: "Dorien Roosen"
|
||||
roles:
|
||||
@@ -357,6 +357,9 @@ info:
|
||||
doi: "10.1093/bioinformatics/btw354"
|
||||
licence: "GPL v3 or later"
|
||||
status: "enabled"
|
||||
scope:
|
||||
image: "public"
|
||||
target: "public"
|
||||
requirements:
|
||||
commands:
|
||||
- "ps"
|
||||
@@ -433,7 +436,7 @@ engines:
|
||||
id: "docker"
|
||||
image: "quay.io/biocontainers/multiqc:1.21--pyhdfd78af_0"
|
||||
target_registry: "images.viash-hub.com"
|
||||
target_tag: "v0.3.0"
|
||||
target_tag: "v0.3.1"
|
||||
namespace_separator: "/"
|
||||
setup:
|
||||
- type: "docker"
|
||||
@@ -455,23 +458,34 @@ build_info:
|
||||
engine: "docker|native"
|
||||
output: "target/nextflow/multiqc"
|
||||
executable: "target/nextflow/multiqc/main.nf"
|
||||
viash_version: "0.9.0"
|
||||
git_commit: "d86bd5cf62104af02caa852aacd352b1aa97ed60"
|
||||
git_remote: "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox"
|
||||
git_tag: "v0.2.0-29-gd86bd5c"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "98a5f3cc745525a65c10263d25cf414eb1093223"
|
||||
git_remote: "https://github.com/viash-hub/biobox"
|
||||
git_tag: "v0.3.0-8-g98a5f3c"
|
||||
package_config:
|
||||
name: "biobox"
|
||||
version: "v0.3.0"
|
||||
description: "A collection of bioinformatics tools for working with sequence data.\n"
|
||||
version: "v0.3.1"
|
||||
summary: "A curated collection of high-quality, standalone bioinformatics components\
|
||||
\ built with [Viash](https://viash.io).\n"
|
||||
description: "`biobox` offers a suite of reliable bioinformatics components, similar\
|
||||
\ to [nf-core/modules](https://github.com/nf-core/modules) and [snakemake-wrappers/bio](https://github.com/snakemake/snakemake-wrappers/tree/master/bio),\
|
||||
\ but built using the [Viash](https://viash.io) framework.\n\nThis approach emphasizes\
|
||||
\ **reusability**, **reproducibility**, and adherence to **best practices**. Key\
|
||||
\ features of `biobox` components include:\n\n* **Standalone & Nextflow Ready:**\
|
||||
\ Run components directly via the command line or seamlessly integrate them into\
|
||||
\ Nextflow workflows.\n* **High Quality Standards:**\n * Comprehensive documentation\
|
||||
\ for components and parameters.\n * Full exposure of underlying tool arguments.\n\
|
||||
\ * Containerized (Docker) for dependency management and reproducibility.\n\
|
||||
\ * Unit tested for verified functionality.\n"
|
||||
info: null
|
||||
viash_version: "0.9.0"
|
||||
viash_version: "0.9.4"
|
||||
source: "src"
|
||||
target: "target"
|
||||
config_mods:
|
||||
- ".requirements.commands := ['ps']\n"
|
||||
- ".engines += { type: \"native\" }"
|
||||
- ".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'"
|
||||
- ".engines[.type == 'docker'].target_tag := 'v0.3.0'"
|
||||
- ".engines[.type == 'docker'].target_tag := 'v0.3.1'"
|
||||
keywords:
|
||||
- "bioinformatics"
|
||||
- "modules"
|
||||
@@ -1,6 +1,6 @@
|
||||
// multiqc v0.3.0
|
||||
// multiqc v0.3.1
|
||||
//
|
||||
// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative
|
||||
// This wrapper script is auto-generated by viash 0.9.4 and is thus a derivative
|
||||
// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data
|
||||
// Intuitive.
|
||||
//
|
||||
@@ -85,64 +85,56 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
foundClass = "List[${e.foundClass}]"
|
||||
}
|
||||
} else if (par.type == "string") {
|
||||
// cast to string if need be
|
||||
// cast to string if need be. only cast if the value is a GString
|
||||
if (value instanceof GString) {
|
||||
value = value.toString()
|
||||
value = value as String
|
||||
}
|
||||
expectedClass = value instanceof String ? null : "String"
|
||||
} else if (par.type == "integer") {
|
||||
// cast to integer if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Integer) {
|
||||
try {
|
||||
value = value.toInteger()
|
||||
value = value as Integer
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Integer"
|
||||
}
|
||||
}
|
||||
if (value instanceof java.math.BigInteger) {
|
||||
value = value.intValue()
|
||||
}
|
||||
expectedClass = value instanceof Integer ? null : "Integer"
|
||||
} else if (par.type == "long") {
|
||||
// cast to long if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Long) {
|
||||
try {
|
||||
value = value.toLong()
|
||||
value = value as Long
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Long"
|
||||
}
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
value = value.toLong()
|
||||
}
|
||||
expectedClass = value instanceof Long ? null : "Long"
|
||||
} else if (par.type == "double") {
|
||||
// cast to double if need be
|
||||
if (value instanceof String) {
|
||||
if (value !instanceof Double) {
|
||||
try {
|
||||
value = value.toDouble()
|
||||
value = value as Double
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing
|
||||
expectedClass = "Double"
|
||||
}
|
||||
}
|
||||
if (value instanceof java.math.BigDecimal) {
|
||||
value = value.doubleValue()
|
||||
} else if (par.type == "float") {
|
||||
// cast to float if need be
|
||||
if (value !instanceof Float) {
|
||||
try {
|
||||
value = value as Float
|
||||
} catch (NumberFormatException e) {
|
||||
expectedClass = "Float"
|
||||
}
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
value = value.toDouble()
|
||||
}
|
||||
expectedClass = value instanceof Double ? null : "Double"
|
||||
} else if (par.type == "boolean" | par.type == "boolean_true" | par.type == "boolean_false") {
|
||||
// cast to boolean if need be
|
||||
if (value instanceof String) {
|
||||
def valueLower = value.toLowerCase()
|
||||
if (valueLower == "true") {
|
||||
value = true
|
||||
} else if (valueLower == "false") {
|
||||
value = false
|
||||
if (value !instanceof Boolean) {
|
||||
try {
|
||||
value = value as Boolean
|
||||
} catch (Exception e) {
|
||||
expectedClass = "Boolean"
|
||||
}
|
||||
}
|
||||
expectedClass = value instanceof Boolean ? null : "Boolean"
|
||||
} else if (par.type == "file" && (par.direction == "input" || stage == "output")) {
|
||||
// cast to path if need be
|
||||
if (value instanceof String) {
|
||||
@@ -154,10 +146,13 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
expectedClass = value instanceof Path ? null : "Path"
|
||||
} else if (par.type == "file" && stage == "input" && par.direction == "output") {
|
||||
// cast to string if need be
|
||||
if (value instanceof GString) {
|
||||
value = value.toString()
|
||||
if (value !instanceof String) {
|
||||
try {
|
||||
value = value as String
|
||||
} catch (Exception e) {
|
||||
expectedClass = "String"
|
||||
}
|
||||
}
|
||||
expectedClass = value instanceof String ? null : "String"
|
||||
} else {
|
||||
// didn't find a match for par.type
|
||||
expectedClass = par.type
|
||||
@@ -176,7 +171,7 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
|
||||
Map _processInputValues(Map inputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.required) {
|
||||
if (arg.required && arg.direction == "input") {
|
||||
assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing"
|
||||
}
|
||||
@@ -195,15 +190,8 @@ Map _processInputValues(Map inputs, Map config, String id, String key) {
|
||||
}
|
||||
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf'
|
||||
Map _processOutputValues(Map outputs, Map config, String id, String key) {
|
||||
Map _checkValidOutputArgument(Map outputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.direction == "output" && arg.required) {
|
||||
assert outputs.containsKey(arg.plainName) && outputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required output argument '${arg.plainName}' is missing"
|
||||
}
|
||||
}
|
||||
|
||||
outputs = outputs.collectEntries { name, value ->
|
||||
def par = config.allArguments.find { it.plainName == name && it.direction == "output" }
|
||||
assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid output argument"
|
||||
@@ -216,6 +204,16 @@ Map _processOutputValues(Map outputs, Map config, String id, String key) {
|
||||
return outputs
|
||||
}
|
||||
|
||||
void _checkAllRequiredOuputsPresent(Map outputs, Map config, String id, String key) {
|
||||
if (!workflow.stubRun) {
|
||||
config.allArguments.each { arg ->
|
||||
if (arg.direction == "output" && arg.required) {
|
||||
assert outputs.containsKey(arg.plainName) && outputs.get(arg.plainName) != null :
|
||||
"Error in module '${key}' id '${id}': required output argument '${arg.plainName}' is missing"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf'
|
||||
class IDChecker {
|
||||
final def items = [] as Set
|
||||
@@ -1669,6 +1667,162 @@ def joinStates(Closure apply_) {
|
||||
}
|
||||
return joinStatesWf
|
||||
}
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishFiles.nf'
|
||||
def publishFiles(Map args) {
|
||||
def key_ = args.get("key")
|
||||
|
||||
assert key_ != null : "publishFiles: key must be specified"
|
||||
|
||||
workflow publishFilesWf {
|
||||
take: input_ch
|
||||
main:
|
||||
input_ch
|
||||
| map { tup ->
|
||||
def id_ = tup[0]
|
||||
def state_ = tup[1]
|
||||
|
||||
// the input files and the target output filenames
|
||||
def inputoutputFilenames_ = collectInputOutputPaths(state_, id_ + "." + key_).transpose()
|
||||
def inputFiles_ = inputoutputFilenames_[0]
|
||||
def outputFilenames_ = inputoutputFilenames_[1]
|
||||
|
||||
[id_, inputFiles_, outputFilenames_]
|
||||
}
|
||||
| publishFilesProc
|
||||
emit: input_ch
|
||||
}
|
||||
return publishFilesWf
|
||||
}
|
||||
|
||||
process publishFilesProc {
|
||||
// todo: check publishpath?
|
||||
publishDir path: "${getPublishDir()}/", mode: "copy"
|
||||
tag "$id"
|
||||
input:
|
||||
tuple val(id), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles)
|
||||
output:
|
||||
tuple val(id), path{outputFiles}
|
||||
script:
|
||||
def copyCommands = [
|
||||
inputFiles instanceof List ? inputFiles : [inputFiles],
|
||||
outputFiles instanceof List ? outputFiles : [outputFiles]
|
||||
]
|
||||
.transpose()
|
||||
.collectMany{infile, outfile ->
|
||||
if (infile.toString() != outfile.toString()) {
|
||||
[
|
||||
"[ -d \"\$(dirname '${outfile.toString()}')\" ] || mkdir -p \"\$(dirname '${outfile.toString()}')\"",
|
||||
"cp -r '${infile.toString()}' '${outfile.toString()}'"
|
||||
]
|
||||
} else {
|
||||
// no need to copy if infile is the same as outfile
|
||||
[]
|
||||
}
|
||||
}
|
||||
"""
|
||||
echo "Copying output files to destination folder"
|
||||
${copyCommands.join("\n ")}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
// this assumes that the state contains no other values other than those specified in the config
|
||||
def publishFilesByConfig(Map args) {
|
||||
def config = args.get("config")
|
||||
assert config != null : "publishFilesByConfig: config must be specified"
|
||||
|
||||
def key_ = args.get("key", config.name)
|
||||
assert key_ != null : "publishFilesByConfig: key must be specified"
|
||||
|
||||
workflow publishFilesSimpleWf {
|
||||
take: input_ch
|
||||
main:
|
||||
input_ch
|
||||
| map { tup ->
|
||||
def id_ = tup[0]
|
||||
def state_ = tup[1] // e.g. [output: new File("myoutput.h5ad"), k: 10]
|
||||
def origState_ = tup[2] // e.g. [output: '$id.$key.foo.h5ad']
|
||||
|
||||
|
||||
// the processed state is a list of [key, value, inputPath, outputFilename] tuples, where
|
||||
// - key is a String
|
||||
// - value is any object that can be serialized to a Yaml (so a String/Integer/Long/Double/Boolean, a List, a Map, or a Path)
|
||||
// - inputPath is a List[Path]
|
||||
// - outputFilename is a List[String]
|
||||
// - (inputPath, outputFilename) are the files that will be copied from src to dest (relative to the state.yaml)
|
||||
def processedState =
|
||||
config.allArguments
|
||||
.findAll { it.direction == "output" }
|
||||
.collectMany { par ->
|
||||
def plainName_ = par.plainName
|
||||
// if the state does not contain the key, it's an
|
||||
// optional argument for which the component did
|
||||
// not generate any output OR multiple channels were emitted
|
||||
// and the output was just not added to using the channel
|
||||
// that is now being parsed
|
||||
if (!state_.containsKey(plainName_)) {
|
||||
return []
|
||||
}
|
||||
def value = state_[plainName_]
|
||||
// if the parameter is not a file, it should be stored
|
||||
// in the state as-is, but is not something that needs
|
||||
// to be copied from the source path to the dest path
|
||||
if (par.type != "file") {
|
||||
return [[inputPath: [], outputFilename: []]]
|
||||
}
|
||||
// if the orig state does not contain this filename,
|
||||
// it's an optional argument for which the user specified
|
||||
// that it should not be returned as a state
|
||||
if (!origState_.containsKey(plainName_)) {
|
||||
return []
|
||||
}
|
||||
def filenameTemplate = origState_[plainName_]
|
||||
// if the pararameter is multiple: true, fetch the template
|
||||
if (par.multiple && filenameTemplate instanceof List) {
|
||||
filenameTemplate = filenameTemplate[0]
|
||||
}
|
||||
// instantiate the template
|
||||
def filename = filenameTemplate
|
||||
.replaceAll('\\$id', id_)
|
||||
.replaceAll('\\$\\{id\\}', id_)
|
||||
.replaceAll('\\$key', key_)
|
||||
.replaceAll('\\$\\{key\\}', key_)
|
||||
if (par.multiple) {
|
||||
// if the parameter is multiple: true, the filename
|
||||
// should contain a wildcard '*' that is replaced with
|
||||
// the index of the file
|
||||
assert filename.contains("*") : "Module '${key_}' id '${id_}': Multiple output files specified, but no wildcard '*' in the filename: ${filename}"
|
||||
def outputPerFile = value.withIndex().collect{ val, ix ->
|
||||
def filename_ix = filename.replace("*", ix.toString())
|
||||
def inputPath = val instanceof File ? val.toPath() : val
|
||||
[inputPath: inputPath, outputFilename: filename_ix]
|
||||
}
|
||||
def transposedOutputs = ["inputPath", "outputFilename"].collectEntries{ key ->
|
||||
[key, outputPerFile.collect{dic -> dic[key]}]
|
||||
}
|
||||
return [[key: plainName_] + transposedOutputs]
|
||||
} else {
|
||||
def value_ = java.nio.file.Paths.get(filename)
|
||||
def inputPath = value instanceof File ? value.toPath() : value
|
||||
return [[inputPath: [inputPath], outputFilename: [filename]]]
|
||||
}
|
||||
}
|
||||
|
||||
def inputPaths = processedState.collectMany{it.inputPath}
|
||||
def outputFilenames = processedState.collectMany{it.outputFilename}
|
||||
|
||||
|
||||
[id_, inputPaths, outputFilenames]
|
||||
}
|
||||
| publishFilesProc
|
||||
emit: input_ch
|
||||
}
|
||||
return publishFilesSimpleWf
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf'
|
||||
def collectFiles(obj) {
|
||||
if (obj instanceof java.io.File || obj instanceof Path) {
|
||||
@@ -1726,8 +1880,6 @@ def publishStates(Map args) {
|
||||
|
||||
// the input files and the target output filenames
|
||||
def inputoutputFilenames_ = collectInputOutputPaths(state_, id_ + "." + key_).transpose()
|
||||
def inputFiles_ = inputoutputFilenames_[0]
|
||||
def outputFilenames_ = inputoutputFilenames_[1]
|
||||
|
||||
def yamlFilename = yamlTemplate_
|
||||
.replaceAll('\\$id', id_)
|
||||
@@ -1740,7 +1892,7 @@ def publishStates(Map args) {
|
||||
// convert state to yaml blob
|
||||
def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename))
|
||||
|
||||
[id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_]
|
||||
[id_, yamlBlob_, yamlFilename]
|
||||
}
|
||||
| publishStatesProc
|
||||
emit: input_ch
|
||||
@@ -1752,33 +1904,17 @@ process publishStatesProc {
|
||||
publishDir path: "${getPublishDir()}/", mode: "copy"
|
||||
tag "$id"
|
||||
input:
|
||||
tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles)
|
||||
tuple val(id), val(yamlBlob), val(yamlFile)
|
||||
output:
|
||||
tuple val(id), path{[yamlFile] + outputFiles}
|
||||
tuple val(id), path{[yamlFile]}
|
||||
script:
|
||||
def copyCommands = [
|
||||
inputFiles instanceof List ? inputFiles : [inputFiles],
|
||||
outputFiles instanceof List ? outputFiles : [outputFiles]
|
||||
]
|
||||
.transpose()
|
||||
.collectMany{infile, outfile ->
|
||||
if (infile.toString() != outfile.toString()) {
|
||||
[
|
||||
"[ -d \"\$(dirname '${outfile.toString()}')\" ] || mkdir -p \"\$(dirname '${outfile.toString()}')\"",
|
||||
"cp -r '${infile.toString()}' '${outfile.toString()}'"
|
||||
]
|
||||
} else {
|
||||
// no need to copy if infile is the same as outfile
|
||||
[]
|
||||
}
|
||||
}
|
||||
"""
|
||||
mkdir -p "\$(dirname '${yamlFile}')"
|
||||
echo "Storing state as yaml"
|
||||
echo '${yamlBlob}' > '${yamlFile}'
|
||||
echo "Copying output files to destination folder"
|
||||
${copyCommands.join("\n ")}
|
||||
"""
|
||||
mkdir -p "\$(dirname '${yamlFile}')"
|
||||
echo "Storing state as yaml"
|
||||
cat > '${yamlFile}' << HERE
|
||||
${yamlBlob}
|
||||
HERE
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
@@ -1809,13 +1945,10 @@ def publishStatesByConfig(Map args) {
|
||||
.replaceAll('\\$\\{key\\}', key_)
|
||||
def yamlDir = java.nio.file.Paths.get(yamlFilename).getParent()
|
||||
|
||||
// the processed state is a list of [key, value, inputPath, outputFilename] tuples, where
|
||||
// the processed state is a list of [key, value] tuples, where
|
||||
// - key is a String
|
||||
// - value is any object that can be serialized to a Yaml (so a String/Integer/Long/Double/Boolean, a List, a Map, or a Path)
|
||||
// - inputPath is a List[Path]
|
||||
// - outputFilename is a List[String]
|
||||
// - (key, value) are the tuples that will be saved to the state.yaml file
|
||||
// - (inputPath, outputFilename) are the files that will be copied from src to dest (relative to the state.yaml)
|
||||
def processedState =
|
||||
config.allArguments
|
||||
.findAll { it.direction == "output" }
|
||||
@@ -1832,7 +1965,7 @@ def publishStatesByConfig(Map args) {
|
||||
// in the state as-is, but is not something that needs
|
||||
// to be copied from the source path to the dest path
|
||||
if (par.type != "file") {
|
||||
return [[key: plainName_, value: value, inputPath: [], outputFilename: []]]
|
||||
return [[key: plainName_, value: value]]
|
||||
}
|
||||
// if the orig state does not contain this filename,
|
||||
// it's an optional argument for which the user specified
|
||||
@@ -1863,13 +1996,9 @@ def publishStatesByConfig(Map args) {
|
||||
if (yamlDir != null) {
|
||||
value_ = yamlDir.relativize(value_)
|
||||
}
|
||||
def inputPath = val instanceof File ? val.toPath() : val
|
||||
[value: value_, inputPath: inputPath, outputFilename: filename_ix]
|
||||
return value_
|
||||
}
|
||||
def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key ->
|
||||
[key, outputPerFile.collect{dic -> dic[key]}]
|
||||
}
|
||||
return [[key: plainName_] + transposedOutputs]
|
||||
return [["key": plainName_, "value": outputPerFile]]
|
||||
} else {
|
||||
def value_ = java.nio.file.Paths.get(filename)
|
||||
// if id contains a slash
|
||||
@@ -1877,18 +2006,17 @@ def publishStatesByConfig(Map args) {
|
||||
value_ = yamlDir.relativize(value_)
|
||||
}
|
||||
def inputPath = value instanceof File ? value.toPath() : value
|
||||
return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]]
|
||||
return [["key": plainName_, value: value_]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def updatedState_ = processedState.collectEntries{[it.key, it.value]}
|
||||
def inputPaths = processedState.collectMany{it.inputPath}
|
||||
def outputFilenames = processedState.collectMany{it.outputFilename}
|
||||
|
||||
// convert state to yaml blob
|
||||
def yamlBlob_ = toTaggedYamlBlob([id: id_] + updatedState_)
|
||||
|
||||
[id_, yamlBlob_, yamlFilename, inputPaths, outputFilenames]
|
||||
[id_, yamlBlob_, yamlFilename]
|
||||
}
|
||||
| publishStatesProc
|
||||
emit: input_ch
|
||||
@@ -2562,6 +2690,7 @@ def _debug(workflowArgs, debugKey) {
|
||||
def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta)
|
||||
def key_ = workflowArgs["key"]
|
||||
def multipleArgs = meta.config.allArguments.findAll{ it.multiple }.collect{it.plainName}
|
||||
|
||||
workflow workflowInstance {
|
||||
take: input_
|
||||
@@ -2719,12 +2848,36 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
}
|
||||
|
||||
// TODO: move some of the _meta.join_id wrangling to the safeJoin() function.
|
||||
def chInitialOutput = chArgsWithDefaults
|
||||
def chInitialOutputMulti = chArgsWithDefaults
|
||||
| _debug(workflowArgs, "processed")
|
||||
// run workflow
|
||||
| innerWorkflowFactory(workflowArgs)
|
||||
// check output tuple
|
||||
| map { id_, output_ ->
|
||||
def chInitialOutputList = chInitialOutputMulti instanceof List ? chInitialOutputMulti : [chInitialOutputMulti]
|
||||
assert chInitialOutputList.size() > 0: "should have emitted at least one output channel"
|
||||
// Add a channel ID to the events, which designates the channel the event was emitted from as a running number
|
||||
// This number is used to sort the events later when the events are gathered from across the channels.
|
||||
def chInitialOutputListWithIndexedEvents = chInitialOutputList.withIndex().collect{channel, channelIndex ->
|
||||
def newChannel = channel
|
||||
| map {tuple ->
|
||||
assert tuple instanceof List :
|
||||
"Error in module '${key_}': element in output channel should be a tuple [id, data, ...otherargs...]\n" +
|
||||
" Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" +
|
||||
" Expected class: List. Found: tuple.getClass() is ${tuple.getClass()}"
|
||||
|
||||
def newEvent = [channelIndex] + tuple
|
||||
return newEvent
|
||||
}
|
||||
return newChannel
|
||||
}
|
||||
// Put the events into 1 channel, cover case where there is only one channel is emitted
|
||||
def chInitialOutput = chInitialOutputList.size() > 1 ? \
|
||||
chInitialOutputListWithIndexedEvents[0].mix(*chInitialOutputListWithIndexedEvents.tail()) : \
|
||||
chInitialOutputListWithIndexedEvents[0]
|
||||
def chInitialOutputProcessed = chInitialOutput
|
||||
| map { tuple ->
|
||||
def channelId = tuple[0]
|
||||
def id_ = tuple[1]
|
||||
def output_ = tuple[2]
|
||||
|
||||
// see if output map contains metadata
|
||||
def meta_ =
|
||||
@@ -2737,19 +2890,94 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
output_ = output_.findAll{k, v -> k != "_meta"}
|
||||
|
||||
// check value types
|
||||
output_ = _processOutputValues(output_, meta.config, id_, key_)
|
||||
output_ = _checkValidOutputArgument(output_, meta.config, id_, key_)
|
||||
|
||||
// simplify output if need be
|
||||
if (workflowArgs.auto.simplifyOutput && output_.size() == 1) {
|
||||
output_ = output_.values()[0]
|
||||
}
|
||||
|
||||
[join_id, id_, output_]
|
||||
[join_id, channelId, id_, output_]
|
||||
}
|
||||
// | view{"chInitialOutput: ${it.take(3)}"}
|
||||
|
||||
// join the output [prev_id, channel_id, new_id, output] with the previous state [prev_id, state, ...]
|
||||
def chPublishWithPreviousState = safeJoin(chInitialOutputProcessed, chRunFiltered, key_)
|
||||
// input tuple format: [join_id, channel_id, id, output, prev_state, ...]
|
||||
// output tuple format: [join_id, channel_id, id, new_state, ...]
|
||||
| map{ tup ->
|
||||
def new_state = workflowArgs.toState(tup.drop(2).take(3))
|
||||
tup.take(3) + [new_state] + tup.drop(5)
|
||||
}
|
||||
if (workflowArgs.auto.publish == "state") {
|
||||
def chPublishFiles = chPublishWithPreviousState
|
||||
// input tuple format: [join_id, channel_id, id, new_state, ...]
|
||||
// output tuple format: [join_id, channel_id, id, new_state]
|
||||
| map{ tup ->
|
||||
tup.take(4)
|
||||
}
|
||||
|
||||
safeJoin(chPublishFiles, chArgsWithDefaults, key_)
|
||||
// input tuple format: [join_id, channel_id, id, new_state, orig_state, ...]
|
||||
// output tuple format: [id, new_state, orig_state]
|
||||
| map { tup ->
|
||||
tup.drop(2).take(3)
|
||||
}
|
||||
| publishFilesByConfig(key: key_, config: meta.config)
|
||||
}
|
||||
// Join the state from the events that were emitted from different channels
|
||||
def chJoined = chInitialOutputProcessed
|
||||
| map {tuple ->
|
||||
def join_id = tuple[0]
|
||||
def channel_id = tuple[1]
|
||||
def id = tuple[2]
|
||||
def other = tuple.drop(3)
|
||||
// Below, groupTuple is used to join the events. To make sure resuming a workflow
|
||||
// keeps working, the output state must be deterministic. This means the state needs to be
|
||||
// sorted with groupTuple's has a 'sort' argument. This argument can be set to 'hash',
|
||||
// but hashing the state when it is large can be problematic in terms of performance.
|
||||
// Therefore, a custom comparator function is provided. We add the channel ID to the
|
||||
// states so that we can use the channel ID to sort the items.
|
||||
def stateWithChannelID = [[channel_id] * other.size(), other].transpose()
|
||||
// A comparator that is provided to groupTuple's 'sort' argument is applied
|
||||
// to all elements of the event tuple (that is not the 'id'). The comparator
|
||||
// closure that is used below expects the input to be List. So the join_id and
|
||||
// channel_id must also be wrapped in a list.
|
||||
[[join_id], [channel_id], id] + stateWithChannelID
|
||||
}
|
||||
| groupTuple(by: 2, sort: {a, b -> a[0] <=> b[0]}, size: chInitialOutputList.size(), remainder: true)
|
||||
| map {join_ids, _, id, statesWithChannelID ->
|
||||
// Remove the channel IDs from the states
|
||||
def states = statesWithChannelID.collect{it[1]}
|
||||
def newJoinId = join_ids.flatten().unique{a, b -> a <=> b}
|
||||
assert newJoinId.size() == 1: "Multiple events were emitted for '$id'."
|
||||
def newJoinIdUnique = newJoinId[0]
|
||||
|
||||
// Merge the states from the different channels
|
||||
def newState = states.inject([:]){ old_state, state_to_add ->
|
||||
return old_state + state_to_add.collectEntries{k, v ->
|
||||
if (!multipleArgs.contains(k)) {
|
||||
// if the key is not a multiple argument, we expect only one value
|
||||
if (old_state.containsKey(k)) {
|
||||
assert old_state[k] == v : "ID $id: multiple entries for argument $k were emitted."
|
||||
}
|
||||
[k, v]
|
||||
} else {
|
||||
// if the key is a multiple argument, append the different values into one list
|
||||
def prevValue = old_state.getOrDefault(k, [])
|
||||
def prevValueAsList = prevValue instanceof List ? prevValue : [prevValue]
|
||||
[k, prevValueAsList + v]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_checkAllRequiredOuputsPresent(newState, meta.config, id, key_)
|
||||
|
||||
// simplify output if need be
|
||||
if (workflowArgs.auto.simplifyOutput && newState.size() == 1) {
|
||||
newState = newState.values()[0]
|
||||
}
|
||||
|
||||
return [newJoinIdUnique, id, newState]
|
||||
}
|
||||
|
||||
// join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...]
|
||||
def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_)
|
||||
def chNewState = safeJoin(chJoined, chRunFiltered, key_)
|
||||
// input tuple format: [join_id, id, output, prev_state, ...]
|
||||
// output tuple format: [join_id, id, new_state, ...]
|
||||
| map{ tup ->
|
||||
@@ -2758,23 +2986,21 @@ def workflowFactory(Map args, Map defaultWfArgs, Map meta) {
|
||||
}
|
||||
|
||||
if (workflowArgs.auto.publish == "state") {
|
||||
def chPublish = chNewState
|
||||
def chPublishStates = chNewState
|
||||
// input tuple format: [join_id, id, new_state, ...]
|
||||
// output tuple format: [join_id, id, new_state]
|
||||
| map{ tup ->
|
||||
tup.take(3)
|
||||
}
|
||||
|
||||
safeJoin(chPublish, chArgsWithDefaults, key_)
|
||||
safeJoin(chPublishStates, chArgsWithDefaults, key_)
|
||||
// input tuple format: [join_id, id, new_state, orig_state, ...]
|
||||
// output tuple format: [id, new_state, orig_state]
|
||||
| map { tup ->
|
||||
tup.drop(1).take(3)
|
||||
}
|
||||
}
|
||||
| publishStatesByConfig(key: key_, config: meta.config)
|
||||
}
|
||||
|
||||
// remove join_id and meta
|
||||
chReturn = chNewState
|
||||
| map { tup ->
|
||||
// input tuple format: [join_id, id, new_state, ...]
|
||||
@@ -2808,7 +3034,7 @@ meta = [
|
||||
"resources_dir": moduleDir.toRealPath().normalize(),
|
||||
"config": processConfig(readJsonBlob('''{
|
||||
"name" : "multiqc",
|
||||
"version" : "v0.3.0",
|
||||
"version" : "v0.3.1",
|
||||
"authors" : [
|
||||
{
|
||||
"name" : "Dorien Roosen",
|
||||
@@ -3246,6 +3472,10 @@ meta = [
|
||||
"licence" : "GPL v3 or later"
|
||||
},
|
||||
"status" : "enabled",
|
||||
"scope" : {
|
||||
"image" : "public",
|
||||
"target" : "public"
|
||||
},
|
||||
"requirements" : {
|
||||
"commands" : [
|
||||
"ps"
|
||||
@@ -3335,7 +3565,7 @@ meta = [
|
||||
"id" : "docker",
|
||||
"image" : "quay.io/biocontainers/multiqc:1.21--pyhdfd78af_0",
|
||||
"target_registry" : "images.viash-hub.com",
|
||||
"target_tag" : "v0.3.0",
|
||||
"target_tag" : "v0.3.1",
|
||||
"namespace_separator" : "/",
|
||||
"setup" : [
|
||||
{
|
||||
@@ -3365,23 +3595,24 @@ meta = [
|
||||
"runner" : "nextflow",
|
||||
"engine" : "docker|native",
|
||||
"output" : "target/nextflow/multiqc",
|
||||
"viash_version" : "0.9.0",
|
||||
"git_commit" : "d86bd5cf62104af02caa852aacd352b1aa97ed60",
|
||||
"git_remote" : "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox",
|
||||
"git_tag" : "v0.2.0-29-gd86bd5c"
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "98a5f3cc745525a65c10263d25cf414eb1093223",
|
||||
"git_remote" : "https://github.com/viash-hub/biobox",
|
||||
"git_tag" : "v0.3.0-8-g98a5f3c"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "biobox",
|
||||
"version" : "v0.3.0",
|
||||
"description" : "A collection of bioinformatics tools for working with sequence data.\n",
|
||||
"viash_version" : "0.9.0",
|
||||
"version" : "v0.3.1",
|
||||
"summary" : "A curated collection of high-quality, standalone bioinformatics components built with [Viash](https://viash.io).\n",
|
||||
"description" : "`biobox` offers a suite of reliable bioinformatics components, similar to [nf-core/modules](https://github.com/nf-core/modules) and [snakemake-wrappers/bio](https://github.com/snakemake/snakemake-wrappers/tree/master/bio), but built using the [Viash](https://viash.io) framework.\n\nThis approach emphasizes **reusability**, **reproducibility**, and adherence to **best practices**. Key features of `biobox` components include:\n\n* **Standalone & Nextflow Ready:** Run components directly via the command line or seamlessly integrate them into Nextflow workflows.\n* **High Quality Standards:**\n * Comprehensive documentation for components and parameters.\n * Full exposure of underlying tool arguments.\n * Containerized (Docker) for dependency management and reproducibility.\n * Unit tested for verified functionality.\n",
|
||||
"viash_version" : "0.9.4",
|
||||
"source" : "src",
|
||||
"target" : "target",
|
||||
"config_mods" : [
|
||||
".requirements.commands := ['ps']\n",
|
||||
".engines += { type: \\"native\\" }",
|
||||
".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'",
|
||||
".engines[.type == 'docker'].target_tag := 'v0.3.0'"
|
||||
".engines[.type == 'docker'].target_tag := 'v0.3.1'"
|
||||
],
|
||||
"keywords" : [
|
||||
"bioinformatics",
|
||||
@@ -3935,7 +4166,7 @@ def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) {
|
||||
// create process from temp file
|
||||
def binding = new nextflow.script.ScriptBinding([:])
|
||||
def session = nextflow.Nextflow.getSession()
|
||||
def parser = new nextflow.script.ScriptParser(session)
|
||||
def parser = _getScriptLoader(session)
|
||||
.setModule(true)
|
||||
.setBinding(binding)
|
||||
def moduleScript = parser.runScript(tempFile)
|
||||
@@ -3949,6 +4180,27 @@ def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) {
|
||||
return scriptMeta.getProcess(procKey)
|
||||
}
|
||||
|
||||
// use Reflection to get a ScriptParser / ScriptLoader
|
||||
// <25.02.0-edge: new nextflow.script.ScriptParser(session)
|
||||
// >=25.02.0-edge: nextflow.script.ScriptLoaderFactory.create(session)
|
||||
def _getScriptLoader(nextflow.Session session) {
|
||||
// try using the old method
|
||||
try {
|
||||
Class<?> scriptParserClass = Class.forName('nextflow.script.ScriptParser')
|
||||
return scriptParserClass.getDeclaredConstructor(nextflow.Session).newInstance(session)
|
||||
} catch (ClassNotFoundException e) {
|
||||
// else try with the new method
|
||||
try {
|
||||
Class<?> scriptLoaderFactoryClass = Class.forName('nextflow.script.ScriptLoaderFactory')
|
||||
def createMethod = scriptLoaderFactoryClass.getDeclaredMethod('create', nextflow.Session)
|
||||
return createMethod.invoke(null, session) // null because create is static
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | java.lang.reflect.InvocationTargetException e2) {
|
||||
// Handle the case where neither class is found
|
||||
throw new Exception("Neither nextflow.script.ScriptParser nor nextflow.script.ScriptLoaderFactory could be found. Is this a compatible Nextflow version?", e2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// defaults
|
||||
meta["defaults"] = [
|
||||
// key to be used to trace the process and determine output names
|
||||
@@ -3962,7 +4214,7 @@ meta["defaults"] = [
|
||||
"container" : {
|
||||
"registry" : "images.viash-hub.com",
|
||||
"image" : "vsh/biobox/multiqc",
|
||||
"tag" : "v0.3.0"
|
||||
"tag" : "v0.3.1"
|
||||
},
|
||||
"tag" : "$id"
|
||||
}'''),
|
||||
@@ -2,7 +2,7 @@ manifest {
|
||||
name = 'multiqc'
|
||||
mainScript = 'main.nf'
|
||||
nextflowVersion = '!>=20.12.1-edge'
|
||||
version = 'v0.3.0'
|
||||
version = 'v0.3.1'
|
||||
description = 'MultiQC aggregates results from bioinformatics analyses across many samples into a single report.\nIt searches a given directory for analysis logs and compiles a HTML report. It\'s a general use tool, perfect for summarising the output from numerous bioinformatics tools.\n'
|
||||
author = 'Dorien Roosen'
|
||||
}
|
||||
@@ -48,10 +48,10 @@
|
||||
"output_data": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id.$key.output_data.output_data`, example: `multiqc_data`. Output directory for parsed data files",
|
||||
"help_text": "Type: `file`, default: `$id.$key.output_data.output_data`, example: `multiqc_data`. Output directory for parsed data files. If not provided, parsed data will not be published.\n"
|
||||
"description": "Type: `file`, default: `$id.$key.output_data`, example: `multiqc_data`. Output directory for parsed data files",
|
||||
"help_text": "Type: `file`, default: `$id.$key.output_data`, example: `multiqc_data`. Output directory for parsed data files. If not provided, parsed data will not be published.\n"
|
||||
,
|
||||
"default":"$id.$key.output_data.output_data"
|
||||
"default":"$id.$key.output_data"
|
||||
}
|
||||
|
||||
|
||||
@@ -59,10 +59,10 @@
|
||||
"output_plots": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id.$key.output_plots.output_plots`, example: `multiqc_plots`. Output directory for generated plots",
|
||||
"help_text": "Type: `file`, default: `$id.$key.output_plots.output_plots`, example: `multiqc_plots`. Output directory for generated plots. If not provided, plots will not be published.\n"
|
||||
"description": "Type: `file`, default: `$id.$key.output_plots`, example: `multiqc_plots`. Output directory for generated plots",
|
||||
"help_text": "Type: `file`, default: `$id.$key.output_plots`, example: `multiqc_plots`. Output directory for generated plots. If not provided, plots will not be published.\n"
|
||||
,
|
||||
"default":"$id.$key.output_plots.output_plots"
|
||||
"default":"$id.$key.output_plots"
|
||||
}
|
||||
|
||||
|
||||
@@ -157,9 +157,9 @@ build_info:
|
||||
output: "target/executable/io/interop_summary_to_csv"
|
||||
executable: "target/executable/io/interop_summary_to_csv/interop_summary_to_csv"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
package_config:
|
||||
name: "demultiplex"
|
||||
version: "main"
|
||||
|
||||
@@ -454,9 +454,9 @@ tar -C /tmp/ --no-same-owner --no-same-permissions -xvf /tmp/interop.tar.gz && \
|
||||
mv /tmp/interop-1.3.1-Linux-GNU/bin/index-summary /tmp/interop-1.3.1-Linux-GNU/bin/summary /usr/local/bin/
|
||||
|
||||
LABEL org.opencontainers.image.description="Companion container for running component io interop_summary_to_csv"
|
||||
LABEL org.opencontainers.image.created="2025-05-14T08:05:50Z"
|
||||
LABEL org.opencontainers.image.created="2025-05-26T10:28:13Z"
|
||||
LABEL org.opencontainers.image.source="https://github.com/viash-hub/demultiplex"
|
||||
LABEL org.opencontainers.image.revision="f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
LABEL org.opencontainers.image.revision="219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
LABEL org.opencontainers.image.version="main"
|
||||
|
||||
VIASHDOCKER
|
||||
|
||||
@@ -219,9 +219,9 @@ build_info:
|
||||
output: "target/executable/io/publish"
|
||||
executable: "target/executable/io/publish/publish"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
package_config:
|
||||
name: "demultiplex"
|
||||
version: "main"
|
||||
|
||||
@@ -450,9 +450,9 @@ RUN apt-get update && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
LABEL org.opencontainers.image.description="Companion container for running component io publish"
|
||||
LABEL org.opencontainers.image.created="2025-05-14T08:05:50Z"
|
||||
LABEL org.opencontainers.image.created="2025-05-26T10:28:13Z"
|
||||
LABEL org.opencontainers.image.source="https://github.com/viash-hub/demultiplex"
|
||||
LABEL org.opencontainers.image.revision="f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
LABEL org.opencontainers.image.revision="219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
LABEL org.opencontainers.image.version="main"
|
||||
|
||||
VIASHDOCKER
|
||||
|
||||
@@ -156,9 +156,9 @@ build_info:
|
||||
output: "target/executable/io/untar"
|
||||
executable: "target/executable/io/untar/untar"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
package_config:
|
||||
name: "demultiplex"
|
||||
version: "main"
|
||||
|
||||
@@ -450,9 +450,9 @@ RUN apt-get update && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
LABEL org.opencontainers.image.description="Companion container for running component io untar"
|
||||
LABEL org.opencontainers.image.created="2025-05-14T08:05:49Z"
|
||||
LABEL org.opencontainers.image.created="2025-05-26T10:28:12Z"
|
||||
LABEL org.opencontainers.image.source="https://github.com/viash-hub/demultiplex"
|
||||
LABEL org.opencontainers.image.revision="f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
LABEL org.opencontainers.image.revision="219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
LABEL org.opencontainers.image.version="main"
|
||||
|
||||
VIASHDOCKER
|
||||
|
||||
@@ -165,9 +165,9 @@ build_info:
|
||||
output: "target/nextflow/dataflow/combine_samples"
|
||||
executable: "target/nextflow/dataflow/combine_samples/main.nf"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
package_config:
|
||||
name: "demultiplex"
|
||||
version: "main"
|
||||
|
||||
@@ -3230,9 +3230,9 @@ meta = [
|
||||
"engine" : "native|native",
|
||||
"output" : "target/nextflow/dataflow/combine_samples",
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "f591b7849fe63b27602b2a759c1089d5dee1ecaa",
|
||||
"git_commit" : "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880",
|
||||
"git_remote" : "https://github.com/viash-hub/demultiplex",
|
||||
"git_tag" : "v0.1.1-28-gf591b78"
|
||||
"git_tag" : "v0.1.1-30-g219bd58"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "demultiplex",
|
||||
|
||||
@@ -1,147 +1,106 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "combine_samples",
|
||||
"description": "Combine fastq files from across samples into one event with a list of fastq files per orientation.",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
|
||||
|
||||
|
||||
"input arguments" : {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"id": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, required. ID of the new event",
|
||||
"help_text": "Type: `string`, required. ID of the new event"
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"forward_input": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: List of `file`, required, multiple_sep: `\";\"`. ",
|
||||
"help_text": "Type: List of `file`, required, multiple_sep: `\";\"`. "
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"reverse_input": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: List of `file`, multiple_sep: `\";\"`. ",
|
||||
"help_text": "Type: List of `file`, multiple_sep: `\";\"`. "
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"falco_dir": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. ",
|
||||
"help_text": "Type: `file`, required. "
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"output arguments" : {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"output_forward": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: List of `file`, required, default: `$id.$key.output_forward_*`, multiple_sep: `\";\"`. ",
|
||||
"help_text": "Type: List of `file`, required, default: `$id.$key.output_forward_*`, multiple_sep: `\";\"`. "
|
||||
,
|
||||
"default":"$id.$key.output_forward_*"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_reverse": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: List of `file`, default: `$id.$key.output_reverse_*`, multiple_sep: `\";\"`. ",
|
||||
"help_text": "Type: List of `file`, default: `$id.$key.output_reverse_*`, multiple_sep: `\";\"`. "
|
||||
,
|
||||
"default":"$id.$key.output_reverse_*"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_falco": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: List of `file`, required, default: `$id.$key.output_falco_*`, multiple_sep: `\";\"`. ",
|
||||
"help_text": "Type: List of `file`, required, default: `$id.$key.output_falco_*`, multiple_sep: `\";\"`. "
|
||||
,
|
||||
"default":"$id.$key.output_falco_*"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"nextflow input-output arguments" : {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
|
||||
|
||||
"publish_dir": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, required, example: `output/`. Path to an output directory",
|
||||
"help_text": "Type: `string`, required, example: `output/`. Path to an output directory."
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"param_list": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel",
|
||||
"help_text": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel. A `param_list` can either be a list of maps, a csv file, a json file, a yaml file, or simply a yaml blob.\n\n* A list of maps (as-is) where the keys of each map corresponds to the arguments of the pipeline. Example: in a `nextflow.config` file: `param_list: [ [\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027], [\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027] ]`.\n* A csv file should have column names which correspond to the different arguments of this pipeline. Example: `--param_list data.csv` with columns `id,input`.\n* A json or a yaml file should be a list of maps, each of which has keys corresponding to the arguments of the pipeline. Example: `--param_list data.json` with contents `[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]`.\n* A yaml blob can also be passed directly as a string. Example: `--param_list \"[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]\"`.\n\nWhen passing a csv, json or yaml file, relative path names are relativized to the location of the parameter file. No relativation is performed when `param_list` is a list of maps (as-is) or a yaml blob.",
|
||||
"hidden": true
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/input arguments"
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "combine_samples",
|
||||
"description": "Combine fastq files from across samples into one event with a list of fastq files per orientation.",
|
||||
"type": "object",
|
||||
"$defs": {
|
||||
"input arguments": {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "ID of the new event",
|
||||
"help_text": "Type: `string`, multiple: `False`, required. "
|
||||
},
|
||||
"forward_input": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `True`, required, direction: `input`. "
|
||||
},
|
||||
"reverse_input": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `True`, direction: `input`. "
|
||||
},
|
||||
"falco_dir": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/output arguments"
|
||||
"output arguments": {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"output_forward": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `True`, required, default: `\"$id.$key.output_forward_*\"`, direction: `output`. ",
|
||||
"default": "$id.$key.output_forward_*"
|
||||
},
|
||||
"output_reverse": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `True`, default: `\"$id.$key.output_reverse_*\"`, direction: `output`. ",
|
||||
"default": "$id.$key.output_reverse_*"
|
||||
},
|
||||
"output_falco": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `True`, required, default: `\"$id.$key.output_falco_*\"`, direction: `output`. ",
|
||||
"default": "$id.$key.output_falco_*"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/nextflow input-output arguments"
|
||||
"nextflow input-output arguments": {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
"publish_dir": {
|
||||
"type": "string",
|
||||
"description": "Path to an output directory.",
|
||||
"help_text": "Type: `string`, multiple: `False`, required, example: `\"output/\"`. "
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/input arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/output arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/nextflow input-output arguments"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -54,6 +54,21 @@ resources:
|
||||
dest: "nextflow_labels.config"
|
||||
description: "From a directory containing fastq files, gather the files per sample\
|
||||
\ \nand validate according to the contents of the sample sheet.\n"
|
||||
test_resources:
|
||||
- type: "nextflow_script"
|
||||
path: "test.nf"
|
||||
is_executable: true
|
||||
entrypoint: "test_gather_and_validate"
|
||||
- type: "nextflow_script"
|
||||
path: "test.nf"
|
||||
is_executable: true
|
||||
entrypoint: "test_undetermined_empty"
|
||||
- type: "nextflow_script"
|
||||
path: "test.nf"
|
||||
is_executable: true
|
||||
entrypoint: "test_without_index"
|
||||
- type: "file"
|
||||
path: "test_data"
|
||||
info: null
|
||||
status: "enabled"
|
||||
scope:
|
||||
@@ -141,9 +156,9 @@ build_info:
|
||||
output: "target/nextflow/dataflow/gather_fastqs_and_validate"
|
||||
executable: "target/nextflow/dataflow/gather_fastqs_and_validate/main.nf"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
package_config:
|
||||
name: "demultiplex"
|
||||
version: "main"
|
||||
|
||||
@@ -3101,6 +3101,30 @@ meta = [
|
||||
}
|
||||
],
|
||||
"description" : "From a directory containing fastq files, gather the files per sample \nand validate according to the contents of the sample sheet.\n",
|
||||
"test_resources" : [
|
||||
{
|
||||
"type" : "nextflow_script",
|
||||
"path" : "test.nf",
|
||||
"is_executable" : true,
|
||||
"entrypoint" : "test_gather_and_validate"
|
||||
},
|
||||
{
|
||||
"type" : "nextflow_script",
|
||||
"path" : "test.nf",
|
||||
"is_executable" : true,
|
||||
"entrypoint" : "test_undetermined_empty"
|
||||
},
|
||||
{
|
||||
"type" : "nextflow_script",
|
||||
"path" : "test.nf",
|
||||
"is_executable" : true,
|
||||
"entrypoint" : "test_without_index"
|
||||
},
|
||||
{
|
||||
"type" : "file",
|
||||
"path" : "test_data"
|
||||
}
|
||||
],
|
||||
"status" : "enabled",
|
||||
"scope" : {
|
||||
"image" : "public",
|
||||
@@ -3203,9 +3227,9 @@ meta = [
|
||||
"engine" : "native|native",
|
||||
"output" : "target/nextflow/dataflow/gather_fastqs_and_validate",
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "f591b7849fe63b27602b2a759c1089d5dee1ecaa",
|
||||
"git_commit" : "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880",
|
||||
"git_remote" : "https://github.com/viash-hub/demultiplex",
|
||||
"git_tag" : "v0.1.1-28-gf591b78"
|
||||
"git_tag" : "v0.1.1-30-g219bd58"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "demultiplex",
|
||||
@@ -3284,7 +3308,8 @@ workflow run_wf {
|
||||
def sample_sheet = state.sample_sheet
|
||||
def start_parsing = false
|
||||
def sample_id_column_index = null
|
||||
def samples = ["Undetermined"]
|
||||
def undetermined_sample_name = "Undetermined"
|
||||
def samples = [undetermined_sample_name]
|
||||
def original_id = id
|
||||
|
||||
// Parse sample sheet for sample IDs
|
||||
@@ -3343,8 +3368,9 @@ workflow run_wf {
|
||||
processed_samples = samples.collect { sample_id ->
|
||||
def forward_regex = ~/^${sample_id}_S(\d+)_(L(\d+)_)?R1_(\d+)\.fastq\.gz$/
|
||||
def reverse_regex = ~/^${sample_id}_S(\d+)_(L(\d+)_)?R2_(\d+)\.fastq\.gz$/
|
||||
def forward_fastq = state.input.listFiles().findAll{it.isFile() && it.name ==~ forward_regex}
|
||||
def reverse_fastq = state.input.listFiles().findAll{it.isFile() && it.name ==~ reverse_regex}
|
||||
// Sort is needed here because multiple lanes (_L00*_) might be present and they need to be in the same order in both lists
|
||||
def forward_fastq = state.input.listFiles().findAll{it.isFile() && it.name ==~ forward_regex}.sort()
|
||||
def reverse_fastq = state.input.listFiles().findAll{it.isFile() && it.name ==~ reverse_regex}.sort()
|
||||
assert forward_fastq && !forward_fastq.isEmpty(): "No forward fastq files were found for sample ${sample_id}. " +
|
||||
"All fastq files in directory: ${allfastqs.collect{it.name}}"
|
||||
assert (reverse_fastq.isEmpty() || (forward_fastq.size() == reverse_fastq.size())):
|
||||
@@ -3353,7 +3379,7 @@ workflow run_wf {
|
||||
println "Found ${forward_fastq.size()} forward and ${reverse_fastq.size()} reverse " +
|
||||
"fastq files for sample ${sample_id}"
|
||||
|
||||
assert forward_fastq.every{!is_empty(it)} && reverse_fastq.every{!is_empty(it)}:
|
||||
assert sample_id == undetermined_sample_name || (forward_fastq.every{!is_empty(it)} && reverse_fastq.every{!is_empty(it)}):
|
||||
"A fastq file for sample '${sample_id}' appears to be empty!"
|
||||
def fastqs_state = [
|
||||
"fastq_forward": forward_fastq,
|
||||
|
||||
@@ -1,116 +1,79 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "gather_fastqs_and_validate",
|
||||
"description": "From a directory containing fastq files, gather the files per sample \nand validate according to the contents of the sample sheet.\n",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
|
||||
|
||||
|
||||
"input arguments" : {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"input": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. Directory containing ",
|
||||
"help_text": "Type: `file`, required. Directory containing .fastq files"
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"sample_sheet": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. Sample sheet",
|
||||
"help_text": "Type: `file`, required. Sample sheet"
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"output arguments" : {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"fastq_forward": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: List of `file`, required, default: `$id.$key.fastq_forward_*`, multiple_sep: `\";\"`. ",
|
||||
"help_text": "Type: List of `file`, required, default: `$id.$key.fastq_forward_*`, multiple_sep: `\";\"`. "
|
||||
,
|
||||
"default":"$id.$key.fastq_forward_*"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"fastq_reverse": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: List of `file`, default: `$id.$key.fastq_reverse_*`, multiple_sep: `\";\"`. ",
|
||||
"help_text": "Type: List of `file`, default: `$id.$key.fastq_reverse_*`, multiple_sep: `\";\"`. "
|
||||
,
|
||||
"default":"$id.$key.fastq_reverse_*"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"nextflow input-output arguments" : {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
|
||||
|
||||
"publish_dir": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, required, example: `output/`. Path to an output directory",
|
||||
"help_text": "Type: `string`, required, example: `output/`. Path to an output directory."
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"param_list": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel",
|
||||
"help_text": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel. A `param_list` can either be a list of maps, a csv file, a json file, a yaml file, or simply a yaml blob.\n\n* A list of maps (as-is) where the keys of each map corresponds to the arguments of the pipeline. Example: in a `nextflow.config` file: `param_list: [ [\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027], [\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027] ]`.\n* A csv file should have column names which correspond to the different arguments of this pipeline. Example: `--param_list data.csv` with columns `id,input`.\n* A json or a yaml file should be a list of maps, each of which has keys corresponding to the arguments of the pipeline. Example: `--param_list data.json` with contents `[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]`.\n* A yaml blob can also be passed directly as a string. Example: `--param_list \"[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]\"`.\n\nWhen passing a csv, json or yaml file, relative path names are relativized to the location of the parameter file. No relativation is performed when `param_list` is a list of maps (as-is) or a yaml blob.",
|
||||
"hidden": true
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/input arguments"
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "gather_fastqs_and_validate",
|
||||
"description": "From a directory containing fastq files, gather the files per sample \nand validate according to the contents of the sample sheet.\n",
|
||||
"type": "object",
|
||||
"$defs": {
|
||||
"input arguments": {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Directory containing .fastq files",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
},
|
||||
"sample_sheet": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Sample sheet",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/output arguments"
|
||||
"output arguments": {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"fastq_forward": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `True`, required, default: `\"$id.$key.fastq_forward_*\"`, direction: `output`. ",
|
||||
"default": "$id.$key.fastq_forward_*"
|
||||
},
|
||||
"fastq_reverse": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `True`, default: `\"$id.$key.fastq_reverse_*\"`, direction: `output`. ",
|
||||
"default": "$id.$key.fastq_reverse_*"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/nextflow input-output arguments"
|
||||
"nextflow input-output arguments": {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
"publish_dir": {
|
||||
"type": "string",
|
||||
"description": "Path to an output directory.",
|
||||
"help_text": "Type: `string`, multiple: `False`, required, example: `\"output/\"`. "
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/input arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/output arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/nextflow input-output arguments"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -158,27 +158,27 @@ dependencies:
|
||||
repository:
|
||||
type: "vsh"
|
||||
repo: "biobox"
|
||||
tag: "v0.3.0"
|
||||
tag: "v0.3.1"
|
||||
- name: "bases2fastq"
|
||||
repository:
|
||||
type: "vsh"
|
||||
repo: "biobox"
|
||||
tag: "v0.3.0"
|
||||
tag: "v0.3.1"
|
||||
- name: "falco"
|
||||
repository:
|
||||
type: "vsh"
|
||||
repo: "biobox"
|
||||
tag: "v0.3.0"
|
||||
tag: "v0.3.1"
|
||||
- name: "multiqc"
|
||||
repository:
|
||||
type: "vsh"
|
||||
repo: "biobox"
|
||||
tag: "v0.3.0"
|
||||
tag: "v0.3.1"
|
||||
repositories:
|
||||
- type: "vsh"
|
||||
name: "bb"
|
||||
repo: "biobox"
|
||||
tag: "v0.3.0"
|
||||
tag: "v0.3.1"
|
||||
license: "MIT"
|
||||
links:
|
||||
repository: "https://github.com/viash-hub/demultiplex"
|
||||
@@ -258,18 +258,18 @@ build_info:
|
||||
output: "target/nextflow/demultiplex"
|
||||
executable: "target/nextflow/demultiplex/main.nf"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
dependencies:
|
||||
- "target/nextflow/io/untar"
|
||||
- "target/nextflow/dataflow/gather_fastqs_and_validate"
|
||||
- "target/nextflow/io/interop_summary_to_csv"
|
||||
- "target/nextflow/dataflow/combine_samples"
|
||||
- "target/dependencies/vsh/vsh/biobox/v0.3.0/nextflow/bcl_convert"
|
||||
- "target/dependencies/vsh/vsh/biobox/v0.3.0/nextflow/bases2fastq"
|
||||
- "target/dependencies/vsh/vsh/biobox/v0.3.0/nextflow/falco"
|
||||
- "target/dependencies/vsh/vsh/biobox/v0.3.0/nextflow/multiqc"
|
||||
- "target/dependencies/vsh/vsh/biobox/v0.3.1/nextflow/bcl_convert"
|
||||
- "target/dependencies/vsh/vsh/biobox/v0.3.1/nextflow/bases2fastq"
|
||||
- "target/dependencies/vsh/vsh/biobox/v0.3.1/nextflow/falco"
|
||||
- "target/dependencies/vsh/vsh/biobox/v0.3.1/nextflow/multiqc"
|
||||
package_config:
|
||||
name: "demultiplex"
|
||||
version: "main"
|
||||
|
||||
@@ -3235,7 +3235,7 @@ meta = [
|
||||
"repository" : {
|
||||
"type" : "vsh",
|
||||
"repo" : "biobox",
|
||||
"tag" : "v0.3.0"
|
||||
"tag" : "v0.3.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -3243,7 +3243,7 @@ meta = [
|
||||
"repository" : {
|
||||
"type" : "vsh",
|
||||
"repo" : "biobox",
|
||||
"tag" : "v0.3.0"
|
||||
"tag" : "v0.3.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -3251,7 +3251,7 @@ meta = [
|
||||
"repository" : {
|
||||
"type" : "vsh",
|
||||
"repo" : "biobox",
|
||||
"tag" : "v0.3.0"
|
||||
"tag" : "v0.3.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -3259,7 +3259,7 @@ meta = [
|
||||
"repository" : {
|
||||
"type" : "vsh",
|
||||
"repo" : "biobox",
|
||||
"tag" : "v0.3.0"
|
||||
"tag" : "v0.3.1"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -3268,7 +3268,7 @@ meta = [
|
||||
"type" : "vsh",
|
||||
"name" : "bb",
|
||||
"repo" : "biobox",
|
||||
"tag" : "v0.3.0"
|
||||
"tag" : "v0.3.1"
|
||||
}
|
||||
],
|
||||
"license" : "MIT",
|
||||
@@ -3363,9 +3363,9 @@ meta = [
|
||||
"engine" : "native|native",
|
||||
"output" : "target/nextflow/demultiplex",
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "f591b7849fe63b27602b2a759c1089d5dee1ecaa",
|
||||
"git_commit" : "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880",
|
||||
"git_remote" : "https://github.com/viash-hub/demultiplex",
|
||||
"git_tag" : "v0.1.1-28-gf591b78"
|
||||
"git_tag" : "v0.1.1-30-g219bd58"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "demultiplex",
|
||||
@@ -3410,10 +3410,10 @@ include { untar } from "${meta.resources_dir}/../../nextflow/io/untar/main.nf"
|
||||
include { gather_fastqs_and_validate } from "${meta.resources_dir}/../../nextflow/dataflow/gather_fastqs_and_validate/main.nf"
|
||||
include { interop_summary_to_csv } from "${meta.resources_dir}/../../nextflow/io/interop_summary_to_csv/main.nf"
|
||||
include { combine_samples } from "${meta.resources_dir}/../../nextflow/dataflow/combine_samples/main.nf"
|
||||
include { bcl_convert } from "${meta.root_dir}/dependencies/vsh/vsh/biobox/v0.3.0/nextflow/bcl_convert/main.nf"
|
||||
include { bases2fastq } from "${meta.root_dir}/dependencies/vsh/vsh/biobox/v0.3.0/nextflow/bases2fastq/main.nf"
|
||||
include { falco } from "${meta.root_dir}/dependencies/vsh/vsh/biobox/v0.3.0/nextflow/falco/main.nf"
|
||||
include { multiqc } from "${meta.root_dir}/dependencies/vsh/vsh/biobox/v0.3.0/nextflow/multiqc/main.nf"
|
||||
include { bcl_convert } from "${meta.root_dir}/dependencies/vsh/vsh/biobox/v0.3.1/nextflow/bcl_convert/main.nf"
|
||||
include { bases2fastq } from "${meta.root_dir}/dependencies/vsh/vsh/biobox/v0.3.1/nextflow/bases2fastq/main.nf"
|
||||
include { falco } from "${meta.root_dir}/dependencies/vsh/vsh/biobox/v0.3.1/nextflow/falco/main.nf"
|
||||
include { multiqc } from "${meta.root_dir}/dependencies/vsh/vsh/biobox/v0.3.1/nextflow/multiqc/main.nf"
|
||||
|
||||
// inner workflow
|
||||
// user-provided Nextflow code
|
||||
|
||||
@@ -1,196 +1,128 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "demultiplex",
|
||||
"description": "Demultiplexing of raw sequencing data",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
|
||||
|
||||
|
||||
"input arguments" : {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"id": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`. Unique identifier for the run",
|
||||
"help_text": "Type: `string`. Unique identifier for the run"
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"input": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. Directory containing raw sequencing data",
|
||||
"help_text": "Type: `file`, required. Directory containing raw sequencing data"
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"run_information": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`. CSV file containing sample information, which will be used as \ninput for the demultiplexer",
|
||||
"help_text": "Type: `file`. CSV file containing sample information, which will be used as \ninput for the demultiplexer. Canonically called \u0027SampleSheet.csv\u0027 (Illumina)\nor \u0027RunManifest.csv\u0027 (Element Biosciences). If not specified,\nwill try to autodetect the sample sheet in the input directory.\nRequires --demultiplexer to be set.\n"
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"demultiplexer": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, choices: ``bases2fastq`, `bclconvert``. Demultiplexer to use, choice depends on the provider\nof the instrument that was used to generate the data",
|
||||
"help_text": "Type: `string`, choices: ``bases2fastq`, `bclconvert``. Demultiplexer to use, choice depends on the provider\nof the instrument that was used to generate the data.\nWhen not using --sample_sheet, specifying this argument is not\nrequired.\n",
|
||||
"enum": ["bases2fastq", "bclconvert"]
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"output arguments" : {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"output": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id/fastq`. Directory to write fastq data to",
|
||||
"help_text": "Type: `file`, default: `$id/fastq`. Directory to write fastq data to"
|
||||
,
|
||||
"default":"$id/fastq"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_falco": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: List of `file`, default: `$id/qc/fastqc`, multiple_sep: `\";\"`. Directory to write falco output to",
|
||||
"help_text": "Type: List of `file`, default: `$id/qc/fastqc`, multiple_sep: `\";\"`. Directory to write falco output to"
|
||||
,
|
||||
"default":"$id/qc/fastqc"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_multiqc": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `$id/qc/multiqc_report.html`. Directory to write falco output to",
|
||||
"help_text": "Type: `file`, default: `$id/qc/multiqc_report.html`. Directory to write falco output to"
|
||||
,
|
||||
"default":"$id/qc/multiqc_report.html"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_run_information": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required, default: `$id/run_information.csv`. ",
|
||||
"help_text": "Type: `file`, required, default: `$id/run_information.csv`. "
|
||||
,
|
||||
"default":"$id/run_information.csv"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"demultiplexer_logs": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required, default: `$id/demultiplexer_logs`. ",
|
||||
"help_text": "Type: `file`, required, default: `$id/demultiplexer_logs`. "
|
||||
,
|
||||
"default":"$id/demultiplexer_logs"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"other arguments" : {
|
||||
"title": "Other arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"skip_copycomplete_check": {
|
||||
"type":
|
||||
"boolean",
|
||||
"description": "Type: `boolean_true`, default: `false`. Disable the check for the presence of a \"CopyComplete",
|
||||
"help_text": "Type: `boolean_true`, default: `false`. Disable the check for the presence of a \"CopyComplete.txt\" file in input\ndirectory in case of Illumina data.\n"
|
||||
,
|
||||
"default":false
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"nextflow input-output arguments" : {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
|
||||
|
||||
"publish_dir": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, required, example: `output/`. Path to an output directory",
|
||||
"help_text": "Type: `string`, required, example: `output/`. Path to an output directory."
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"param_list": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel",
|
||||
"help_text": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel. A `param_list` can either be a list of maps, a csv file, a json file, a yaml file, or simply a yaml blob.\n\n* A list of maps (as-is) where the keys of each map corresponds to the arguments of the pipeline. Example: in a `nextflow.config` file: `param_list: [ [\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027], [\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027] ]`.\n* A csv file should have column names which correspond to the different arguments of this pipeline. Example: `--param_list data.csv` with columns `id,input`.\n* A json or a yaml file should be a list of maps, each of which has keys corresponding to the arguments of the pipeline. Example: `--param_list data.json` with contents `[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]`.\n* A yaml blob can also be passed directly as a string. Example: `--param_list \"[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]\"`.\n\nWhen passing a csv, json or yaml file, relative path names are relativized to the location of the parameter file. No relativation is performed when `param_list` is a list of maps (as-is) or a yaml blob.",
|
||||
"hidden": true
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/input arguments"
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "demultiplex",
|
||||
"description": "Demultiplexing of raw sequencing data",
|
||||
"type": "object",
|
||||
"$defs": {
|
||||
"input arguments": {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique identifier for the run",
|
||||
"help_text": "Type: `string`, multiple: `False`. "
|
||||
},
|
||||
"input": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Directory containing raw sequencing data",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
},
|
||||
"run_information": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "CSV file containing sample information, which will be used as \ninput for the demultiplexer",
|
||||
"help_text": "Type: `file`, multiple: `False`, direction: `input`. "
|
||||
},
|
||||
"demultiplexer": {
|
||||
"type": "string",
|
||||
"description": "Demultiplexer to use, choice depends on the provider\nof the instrument that was used to generate the data.\nWhen not using --sample_sheet, specifying this argument is not\nrequired.\n",
|
||||
"help_text": "Type: `string`, multiple: `False`, choices: ``bases2fastq`, `bclconvert``. ",
|
||||
"enum": [
|
||||
"bases2fastq",
|
||||
"bclconvert"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/output arguments"
|
||||
"output arguments": {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"output": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "Directory to write fastq data to",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"$id/fastq\"`, direction: `output`. ",
|
||||
"default": "$id/fastq"
|
||||
},
|
||||
"output_falco": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": "path",
|
||||
"description": "Directory to write falco output to",
|
||||
"help_text": "Type: `file`, multiple: `True`, default: `[\"$id/qc/fastqc\"]`, direction: `output`. ",
|
||||
"default": [
|
||||
"$id/qc/fastqc"
|
||||
]
|
||||
},
|
||||
"output_multiqc": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "Directory to write falco output to",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"$id/qc/multiqc_report.html\"`, direction: `output`. ",
|
||||
"default": "$id/qc/multiqc_report.html"
|
||||
},
|
||||
"output_run_information": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, default: `\"$id/run_information.csv\"`, direction: `output`. ",
|
||||
"default": "$id/run_information.csv"
|
||||
},
|
||||
"demultiplexer_logs": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, default: `\"$id/demultiplexer_logs\"`, direction: `output`. ",
|
||||
"default": "$id/demultiplexer_logs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/other arguments"
|
||||
"other arguments": {
|
||||
"title": "Other arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"skip_copycomplete_check": {
|
||||
"type": "boolean",
|
||||
"description": "Disable the check for the presence of a \"CopyComplete.txt\" file in input\ndirectory in case of Illumina data.\n",
|
||||
"help_text": "Type: `boolean_true`, multiple: `False`, default: `false`. ",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/nextflow input-output arguments"
|
||||
"nextflow input-output arguments": {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
"publish_dir": {
|
||||
"type": "string",
|
||||
"description": "Path to an output directory.",
|
||||
"help_text": "Type: `string`, multiple: `False`, required, example: `\"output/\"`. "
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/input arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/output arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/other arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/nextflow input-output arguments"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -157,9 +157,9 @@ build_info:
|
||||
output: "target/nextflow/io/interop_summary_to_csv"
|
||||
executable: "target/nextflow/io/interop_summary_to_csv/main.nf"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
package_config:
|
||||
name: "demultiplex"
|
||||
version: "main"
|
||||
|
||||
@@ -3228,9 +3228,9 @@ meta = [
|
||||
"engine" : "docker|native",
|
||||
"output" : "target/nextflow/io/interop_summary_to_csv",
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "f591b7849fe63b27602b2a759c1089d5dee1ecaa",
|
||||
"git_commit" : "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880",
|
||||
"git_remote" : "https://github.com/viash-hub/demultiplex",
|
||||
"git_tag" : "v0.1.1-28-gf591b78"
|
||||
"git_tag" : "v0.1.1-30-g219bd58"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "demultiplex",
|
||||
|
||||
@@ -1,106 +1,66 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "interop_summary_to_csv",
|
||||
"description": "No description",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
|
||||
|
||||
|
||||
"input arguments" : {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"input": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. Sequencing run folder (*not* InterOp folder)",
|
||||
"help_text": "Type: `file`, required. Sequencing run folder (*not* InterOp folder)."
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"output arguments" : {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"output_run_summary": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required, default: `$id.$key.output_run_summary`. ",
|
||||
"help_text": "Type: `file`, required, default: `$id.$key.output_run_summary`. "
|
||||
,
|
||||
"default":"$id.$key.output_run_summary"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_index_summary": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required, default: `$id.$key.output_index_summary`. ",
|
||||
"help_text": "Type: `file`, required, default: `$id.$key.output_index_summary`. "
|
||||
,
|
||||
"default":"$id.$key.output_index_summary"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"nextflow input-output arguments" : {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
|
||||
|
||||
"publish_dir": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, required, example: `output/`. Path to an output directory",
|
||||
"help_text": "Type: `string`, required, example: `output/`. Path to an output directory."
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"param_list": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel",
|
||||
"help_text": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel. A `param_list` can either be a list of maps, a csv file, a json file, a yaml file, or simply a yaml blob.\n\n* A list of maps (as-is) where the keys of each map corresponds to the arguments of the pipeline. Example: in a `nextflow.config` file: `param_list: [ [\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027], [\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027] ]`.\n* A csv file should have column names which correspond to the different arguments of this pipeline. Example: `--param_list data.csv` with columns `id,input`.\n* A json or a yaml file should be a list of maps, each of which has keys corresponding to the arguments of the pipeline. Example: `--param_list data.json` with contents `[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]`.\n* A yaml blob can also be passed directly as a string. Example: `--param_list \"[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]\"`.\n\nWhen passing a csv, json or yaml file, relative path names are relativized to the location of the parameter file. No relativation is performed when `param_list` is a list of maps (as-is) or a yaml blob.",
|
||||
"hidden": true
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/input arguments"
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "interop_summary_to_csv",
|
||||
"description": "No description",
|
||||
"type": "object",
|
||||
"$defs": {
|
||||
"input arguments": {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Sequencing run folder (*not* InterOp folder).",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/output arguments"
|
||||
"output arguments": {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"output_run_summary": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, default: `\"$id.$key.output_run_summary\"`, direction: `output`. ",
|
||||
"default": "$id.$key.output_run_summary"
|
||||
},
|
||||
"output_index_summary": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, default: `\"$id.$key.output_index_summary\"`, direction: `output`. ",
|
||||
"default": "$id.$key.output_index_summary"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/nextflow input-output arguments"
|
||||
"nextflow input-output arguments": {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
"publish_dir": {
|
||||
"type": "string",
|
||||
"description": "Path to an output directory.",
|
||||
"help_text": "Type: `string`, multiple: `False`, required, example: `\"output/\"`. "
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/input arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/output arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/nextflow input-output arguments"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -219,9 +219,9 @@ build_info:
|
||||
output: "target/nextflow/io/publish"
|
||||
executable: "target/nextflow/io/publish/main.nf"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
package_config:
|
||||
name: "demultiplex"
|
||||
version: "main"
|
||||
|
||||
@@ -3297,9 +3297,9 @@ meta = [
|
||||
"engine" : "docker|native",
|
||||
"output" : "target/nextflow/io/publish",
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "f591b7849fe63b27602b2a759c1089d5dee1ecaa",
|
||||
"git_commit" : "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880",
|
||||
"git_remote" : "https://github.com/viash-hub/demultiplex",
|
||||
"git_tag" : "v0.1.1-28-gf591b78"
|
||||
"git_tag" : "v0.1.1-30-g219bd58"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "demultiplex",
|
||||
|
||||
@@ -1,179 +1,118 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "publish",
|
||||
"description": "Publish the processed results of the run",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
|
||||
|
||||
|
||||
"input arguments" : {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"input": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. Directory to write fastq data to",
|
||||
"help_text": "Type: `file`, required. Directory to write fastq data to"
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"input_falco": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: List of `file`, required, multiple_sep: `\";\"`. Directory to write falco output to",
|
||||
"help_text": "Type: List of `file`, required, multiple_sep: `\";\"`. Directory to write falco output to"
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"input_multiqc": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. Location where to write the MultiQC report to",
|
||||
"help_text": "Type: `file`, required. Location where to write the MultiQC report to."
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"input_run_information": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. Location where to write the run information to",
|
||||
"help_text": "Type: `file`, required. Location where to write the run information to."
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"input_demultiplexer_logs": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. ",
|
||||
"help_text": "Type: `file`, required. "
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"output arguments" : {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"output": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `fastq`. ",
|
||||
"help_text": "Type: `file`, default: `fastq`. "
|
||||
,
|
||||
"default":"fastq"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_falco": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `qc/fastqc`. ",
|
||||
"help_text": "Type: `file`, default: `qc/fastqc`. "
|
||||
,
|
||||
"default":"qc/fastqc"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_multiqc": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `qc/multiqc_report.html`. ",
|
||||
"help_text": "Type: `file`, default: `qc/multiqc_report.html`. "
|
||||
,
|
||||
"default":"qc/multiqc_report.html"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_run_information": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `run_information.csv`. ",
|
||||
"help_text": "Type: `file`, default: `run_information.csv`. "
|
||||
,
|
||||
"default":"run_information.csv"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"output_demultiplexer_logs": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `demultiplexer_logs`. ",
|
||||
"help_text": "Type: `file`, default: `demultiplexer_logs`. "
|
||||
,
|
||||
"default":"demultiplexer_logs"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"nextflow input-output arguments" : {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
|
||||
|
||||
"publish_dir": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, required, example: `output/`. Path to an output directory",
|
||||
"help_text": "Type: `string`, required, example: `output/`. Path to an output directory."
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"param_list": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel",
|
||||
"help_text": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel. A `param_list` can either be a list of maps, a csv file, a json file, a yaml file, or simply a yaml blob.\n\n* A list of maps (as-is) where the keys of each map corresponds to the arguments of the pipeline. Example: in a `nextflow.config` file: `param_list: [ [\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027], [\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027] ]`.\n* A csv file should have column names which correspond to the different arguments of this pipeline. Example: `--param_list data.csv` with columns `id,input`.\n* A json or a yaml file should be a list of maps, each of which has keys corresponding to the arguments of the pipeline. Example: `--param_list data.json` with contents `[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]`.\n* A yaml blob can also be passed directly as a string. Example: `--param_list \"[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]\"`.\n\nWhen passing a csv, json or yaml file, relative path names are relativized to the location of the parameter file. No relativation is performed when `param_list` is a list of maps (as-is) or a yaml blob.",
|
||||
"hidden": true
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/input arguments"
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "publish",
|
||||
"description": "Publish the processed results of the run",
|
||||
"type": "object",
|
||||
"$defs": {
|
||||
"input arguments": {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Directory to write fastq data to",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
},
|
||||
"input_falco": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Directory to write falco output to",
|
||||
"help_text": "Type: `file`, multiple: `True`, required, direction: `input`. "
|
||||
},
|
||||
"input_multiqc": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Location where to write the MultiQC report to.",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
},
|
||||
"input_run_information": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Location where to write the run information to.",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
},
|
||||
"input_demultiplexer_logs": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/output arguments"
|
||||
"output arguments": {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"output": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"fastq\"`, direction: `output`. ",
|
||||
"default": "fastq"
|
||||
},
|
||||
"output_falco": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"qc/fastqc\"`, direction: `output`. ",
|
||||
"default": "qc/fastqc"
|
||||
},
|
||||
"output_multiqc": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"qc/multiqc_report.html\"`, direction: `output`. ",
|
||||
"default": "qc/multiqc_report.html"
|
||||
},
|
||||
"output_run_information": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"run_information.csv\"`, direction: `output`. ",
|
||||
"default": "run_information.csv"
|
||||
},
|
||||
"output_demultiplexer_logs": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"demultiplexer_logs\"`, direction: `output`. ",
|
||||
"default": "demultiplexer_logs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/nextflow input-output arguments"
|
||||
"nextflow input-output arguments": {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
"publish_dir": {
|
||||
"type": "string",
|
||||
"description": "Path to an output directory.",
|
||||
"help_text": "Type: `string`, multiple: `False`, required, example: `\"output/\"`. "
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/input arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/output arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/nextflow input-output arguments"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -156,9 +156,9 @@ build_info:
|
||||
output: "target/nextflow/io/untar"
|
||||
executable: "target/nextflow/io/untar/main.nf"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
package_config:
|
||||
name: "demultiplex"
|
||||
version: "main"
|
||||
|
||||
@@ -3227,9 +3227,9 @@ meta = [
|
||||
"engine" : "docker|native",
|
||||
"output" : "target/nextflow/io/untar",
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "f591b7849fe63b27602b2a759c1089d5dee1ecaa",
|
||||
"git_commit" : "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880",
|
||||
"git_remote" : "https://github.com/viash-hub/demultiplex",
|
||||
"git_tag" : "v0.1.1-28-gf591b78"
|
||||
"git_tag" : "v0.1.1-30-g219bd58"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "demultiplex",
|
||||
|
||||
@@ -1,119 +1,74 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "untar",
|
||||
"description": "Unpack a .tar file. When the contents of the .tar file is just a single directory,\nput the contents of the directory into the output folder instead of that directory.\n",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
|
||||
|
||||
|
||||
"input arguments" : {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"input": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. Tarball file to be unpacked",
|
||||
"help_text": "Type: `file`, required. Tarball file to be unpacked."
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"output arguments" : {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"output": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required, default: `$id.$key.output`. Directory to write the contents of the ",
|
||||
"help_text": "Type: `file`, required, default: `$id.$key.output`. Directory to write the contents of the .tar file to."
|
||||
,
|
||||
"default":"$id.$key.output"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"other arguments" : {
|
||||
"title": "Other arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"exclude": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, example: `docs/figures`. Prevents any file or member whose name matches the shell wildcard (pattern) from being extracted",
|
||||
"help_text": "Type: `string`, example: `docs/figures`. Prevents any file or member whose name matches the shell wildcard (pattern) from being extracted."
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"nextflow input-output arguments" : {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
|
||||
|
||||
"publish_dir": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, required, example: `output/`. Path to an output directory",
|
||||
"help_text": "Type: `string`, required, example: `output/`. Path to an output directory."
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"param_list": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel",
|
||||
"help_text": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel. A `param_list` can either be a list of maps, a csv file, a json file, a yaml file, or simply a yaml blob.\n\n* A list of maps (as-is) where the keys of each map corresponds to the arguments of the pipeline. Example: in a `nextflow.config` file: `param_list: [ [\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027], [\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027] ]`.\n* A csv file should have column names which correspond to the different arguments of this pipeline. Example: `--param_list data.csv` with columns `id,input`.\n* A json or a yaml file should be a list of maps, each of which has keys corresponding to the arguments of the pipeline. Example: `--param_list data.json` with contents `[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]`.\n* A yaml blob can also be passed directly as a string. Example: `--param_list \"[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]\"`.\n\nWhen passing a csv, json or yaml file, relative path names are relativized to the location of the parameter file. No relativation is performed when `param_list` is a list of maps (as-is) or a yaml blob.",
|
||||
"hidden": true
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/input arguments"
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "untar",
|
||||
"description": "Unpack a .tar file. When the contents of the .tar file is just a single directory,\nput the contents of the directory into the output folder instead of that directory.\n",
|
||||
"type": "object",
|
||||
"$defs": {
|
||||
"input arguments": {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Tarball file to be unpacked.",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/output arguments"
|
||||
"output arguments": {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"output": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "Directory to write the contents of the .tar file to.",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, default: `\"$id.$key.output\"`, direction: `output`. ",
|
||||
"default": "$id.$key.output"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/other arguments"
|
||||
"other arguments": {
|
||||
"title": "Other arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"exclude": {
|
||||
"type": "string",
|
||||
"description": "Prevents any file or member whose name matches the shell wildcard (pattern) from being extracted.",
|
||||
"help_text": "Type: `string`, multiple: `False`, example: `\"docs/figures\"`. "
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/nextflow input-output arguments"
|
||||
"nextflow input-output arguments": {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
"publish_dir": {
|
||||
"type": "string",
|
||||
"description": "Path to an output directory.",
|
||||
"help_text": "Type: `string`, multiple: `False`, required, example: `\"output/\"`. "
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/input arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/output arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/other arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/nextflow input-output arguments"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -206,9 +206,9 @@ build_info:
|
||||
output: "target/nextflow/runner"
|
||||
executable: "target/nextflow/runner/main.nf"
|
||||
viash_version: "0.9.4"
|
||||
git_commit: "f591b7849fe63b27602b2a759c1089d5dee1ecaa"
|
||||
git_commit: "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880"
|
||||
git_remote: "https://github.com/viash-hub/demultiplex"
|
||||
git_tag: "v0.1.1-28-gf591b78"
|
||||
git_tag: "v0.1.1-30-g219bd58"
|
||||
dependencies:
|
||||
- "target/nextflow/demultiplex"
|
||||
- "target/nextflow/io/publish"
|
||||
|
||||
@@ -3283,9 +3283,9 @@ meta = [
|
||||
"engine" : "native|native",
|
||||
"output" : "target/nextflow/runner",
|
||||
"viash_version" : "0.9.4",
|
||||
"git_commit" : "f591b7849fe63b27602b2a759c1089d5dee1ecaa",
|
||||
"git_commit" : "219bd5816e7e6a6c80b4d6f6c1d21b3ffe53c880",
|
||||
"git_remote" : "https://github.com/viash-hub/demultiplex",
|
||||
"git_tag" : "v0.1.1-28-gf591b78"
|
||||
"git_tag" : "v0.1.1-30-g219bd58"
|
||||
},
|
||||
"package_config" : {
|
||||
"name" : "demultiplex",
|
||||
|
||||
@@ -1,200 +1,127 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "runner",
|
||||
"description": "Runner for demultiplexing of raw sequencing data",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
|
||||
|
||||
|
||||
"input arguments" : {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"input": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, required. Base directory of the canonical form `s3://\u003cbucket\u003e/\u003cpath\u003e/\u003cRunID\u003e/`",
|
||||
"help_text": "Type: `file`, required. Base directory of the canonical form `s3://\u003cbucket\u003e/\u003cpath\u003e/\u003cRunID\u003e/`.\nA tarball (tar.gz, .tgz, .tar) containing run information can be provided in which\ncase the RunID is set to the name of the tarball without the extension.\n"
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"run_information": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`. CSV file containing sample information, which will be used as \ninput for the demultiplexer",
|
||||
"help_text": "Type: `file`. CSV file containing sample information, which will be used as \ninput for the demultiplexer. Canonically called \u0027SampleSheet.csv\u0027 (Illumina)\nor \u0027RunManifest.csv\u0027 (Element Biosciences). If not specified,\nwill try to autodetect the sample sheet in the input directory.\nRequires --demultiplexer to be set.\n"
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"demultiplexer": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, choices: ``bases2fastq`, `bclconvert``. Demultiplexer to use, choice depends on the provider\nof the instrument that was used to generate the data",
|
||||
"help_text": "Type: `string`, choices: ``bases2fastq`, `bclconvert``. Demultiplexer to use, choice depends on the provider\nof the instrument that was used to generate the data.\nWhen not using --sample_sheet, specifying this argument is not\nrequired.\n",
|
||||
"enum": ["bases2fastq", "bclconvert"]
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"annotation flags" : {
|
||||
"title": "Annotation flags",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"plain_output": {
|
||||
"type":
|
||||
"boolean",
|
||||
"description": "Type: `boolean_true`, default: `false`. Flag to indicate that the output should be stored directly under $publish_dir rather than\nunder a subdirectory structure runID/\u003cdate_time\u003e_demultiplex_\u003cversion\u003e/",
|
||||
"help_text": "Type: `boolean_true`, default: `false`. Flag to indicate that the output should be stored directly under $publish_dir rather than\nunder a subdirectory structure runID/\u003cdate_time\u003e_demultiplex_\u003cversion\u003e/.\n"
|
||||
,
|
||||
"default":false
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"output arguments" : {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"fastq_output": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `fastq`. ",
|
||||
"help_text": "Type: `file`, default: `fastq`. "
|
||||
,
|
||||
"default":"fastq"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"falco_output": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `qc/fastqc`. ",
|
||||
"help_text": "Type: `file`, default: `qc/fastqc`. "
|
||||
,
|
||||
"default":"qc/fastqc"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"multiqc_output": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `qc/multiqc_report.html`. ",
|
||||
"help_text": "Type: `file`, default: `qc/multiqc_report.html`. "
|
||||
,
|
||||
"default":"qc/multiqc_report.html"
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"demultiplexer_logs": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `file`, default: `demultiplexer_logs`. ",
|
||||
"help_text": "Type: `file`, default: `demultiplexer_logs`. "
|
||||
,
|
||||
"default":"demultiplexer_logs"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"other arguments" : {
|
||||
"title": "Other arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
|
||||
|
||||
"skip_copycomplete_check": {
|
||||
"type":
|
||||
"boolean",
|
||||
"description": "Type: `boolean_true`, default: `false`. Disable the check for the presence of a \"CopyComplete",
|
||||
"help_text": "Type: `boolean_true`, default: `false`. Disable the check for the presence of a \"CopyComplete.txt\" file in input\ndirectory in case of Illumina data.\n"
|
||||
,
|
||||
"default":false
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"nextflow input-output arguments" : {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
|
||||
|
||||
"publish_dir": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, required, example: `output/`. Path to an output directory",
|
||||
"help_text": "Type: `string`, required, example: `output/`. Path to an output directory."
|
||||
|
||||
}
|
||||
|
||||
|
||||
,
|
||||
"param_list": {
|
||||
"type":
|
||||
"string",
|
||||
"description": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel",
|
||||
"help_text": "Type: `string`, example: `my_params.yaml`. Allows inputting multiple parameter sets to initialise a Nextflow channel. A `param_list` can either be a list of maps, a csv file, a json file, a yaml file, or simply a yaml blob.\n\n* A list of maps (as-is) where the keys of each map corresponds to the arguments of the pipeline. Example: in a `nextflow.config` file: `param_list: [ [\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027], [\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027] ]`.\n* A csv file should have column names which correspond to the different arguments of this pipeline. Example: `--param_list data.csv` with columns `id,input`.\n* A json or a yaml file should be a list of maps, each of which has keys corresponding to the arguments of the pipeline. Example: `--param_list data.json` with contents `[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]`.\n* A yaml blob can also be passed directly as a string. Example: `--param_list \"[ {\u0027id\u0027: \u0027foo\u0027, \u0027input\u0027: \u0027foo.txt\u0027}, {\u0027id\u0027: \u0027bar\u0027, \u0027input\u0027: \u0027bar.txt\u0027} ]\"`.\n\nWhen passing a csv, json or yaml file, relative path names are relativized to the location of the parameter file. No relativation is performed when `param_list` is a list of maps (as-is) or a yaml blob.",
|
||||
"hidden": true
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/input arguments"
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "runner",
|
||||
"description": "Runner for demultiplexing of raw sequencing data",
|
||||
"type": "object",
|
||||
"$defs": {
|
||||
"input arguments": {
|
||||
"title": "Input arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"exists": true,
|
||||
"description": "Base directory of the canonical form `s3://<bucket>/<path>/<RunID>/`.\nA tarball (tar.gz, .tgz, .tar) containing run information can be provided in which\ncase the RunID is set to the name of the tarball without the extension.\n",
|
||||
"help_text": "Type: `file`, multiple: `False`, required, direction: `input`. "
|
||||
},
|
||||
"run_information": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "CSV file containing sample information, which will be used as \ninput for the demultiplexer",
|
||||
"help_text": "Type: `file`, multiple: `False`, direction: `input`. "
|
||||
},
|
||||
"demultiplexer": {
|
||||
"type": "string",
|
||||
"description": "Demultiplexer to use, choice depends on the provider\nof the instrument that was used to generate the data.\nWhen not using --sample_sheet, specifying this argument is not\nrequired.\n",
|
||||
"help_text": "Type: `string`, multiple: `False`, choices: ``bases2fastq`, `bclconvert``. ",
|
||||
"enum": [
|
||||
"bases2fastq",
|
||||
"bclconvert"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/annotation flags"
|
||||
"annotation flags": {
|
||||
"title": "Annotation flags",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"plain_output": {
|
||||
"type": "boolean",
|
||||
"description": "Flag to indicate that the output should be stored directly under $publish_dir rather than\nunder a subdirectory structure runID/<date_time>_demultiplex_<version>/.\n",
|
||||
"help_text": "Type: `boolean_true`, multiple: `False`, default: `false`. ",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/output arguments"
|
||||
"output arguments": {
|
||||
"title": "Output arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"fastq_output": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"fastq\"`, direction: `output`. ",
|
||||
"default": "fastq"
|
||||
},
|
||||
"falco_output": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"qc/fastqc\"`, direction: `output`. ",
|
||||
"default": "qc/fastqc"
|
||||
},
|
||||
"multiqc_output": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"qc/multiqc_report.html\"`, direction: `output`. ",
|
||||
"default": "qc/multiqc_report.html"
|
||||
},
|
||||
"demultiplexer_logs": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "",
|
||||
"help_text": "Type: `file`, multiple: `False`, default: `\"demultiplexer_logs\"`, direction: `output`. ",
|
||||
"default": "demultiplexer_logs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/other arguments"
|
||||
"other arguments": {
|
||||
"title": "Other arguments",
|
||||
"type": "object",
|
||||
"description": "No description",
|
||||
"properties": {
|
||||
"skip_copycomplete_check": {
|
||||
"type": "boolean",
|
||||
"description": "Disable the check for the presence of a \"CopyComplete.txt\" file in input\ndirectory in case of Illumina data.\n",
|
||||
"help_text": "Type: `boolean_true`, multiple: `False`, default: `false`. ",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$ref": "#/definitions/nextflow input-output arguments"
|
||||
"nextflow input-output arguments": {
|
||||
"title": "Nextflow input-output arguments",
|
||||
"type": "object",
|
||||
"description": "Input/output parameters for Nextflow itself. Please note that both publishDir and publish_dir are supported but at least one has to be configured.",
|
||||
"properties": {
|
||||
"publish_dir": {
|
||||
"type": "string",
|
||||
"description": "Path to an output directory.",
|
||||
"help_text": "Type: `string`, multiple: `False`, required, example: `\"output/\"`. "
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/input arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/annotation flags"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/output arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/other arguments"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/nextflow input-output arguments"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user