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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 66 additions & 8 deletions modules/nf-core/deacon/index/main.nf
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
process DEACON_INDEX {
tag "$fasta"
tag "fasta - ${meta.id} - ${subcommand ?: 'build'}"

label 'process_low'

conda "${moduleDir}/environment.yml"
Expand All @@ -8,10 +9,12 @@ process DEACON_INDEX {
'biocontainers/deacon:0.13.2--h7ef3eeb_0' }"

input:
tuple val(meta), path(fasta)
tuple val(meta), path(reference) // reference fasta file (for build) or idx index (for set operations)
val(subcommand) // build, union, intersect or diff
tuple val(meta_set), path(set_genomes) // one (or more for union) idx indexes (or fasta files for diff)

output:
tuple val(meta), path("*.idx"), emit: index
tuple val(meta_out), path("*.idx"), emit: index
tuple val("${task.process}"), val('deacon'), eval('deacon --version | head -n1 | sed "s/deacon //g"'), emit: versions_deacon, topic: versions

when:
Expand All @@ -20,17 +23,72 @@ process DEACON_INDEX {
script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

// default to build if no subcommand is provided
subcommand = subcommand ?: "build"

// validate provided subcommand
def valid_subcommands = ['build', 'union', 'intersect', 'diff']
if (!(subcommand in valid_subcommands)) {
error "Invalid deacon index subcommand: '${subcommand}'. Must be one of: ${valid_subcommands.join(', ')}, or empty to default to `build`"
}

// create new meta map that stores utilised deacon index subcommand
meta_out = meta + [operation: subcommand]

// validate inputs based on subcommand
if (subcommand == 'build') {
if (set_genomes) {
error "Subcommand 'build' does not accept set_genomes input. Received: ${set_genomes}"
}
}
else {
// union, intersect, or diff require set_genomes input
if (!set_genomes) {
error "Subcommand '${subcommand}' requires set_genomes input (idx or fasta files)"
}

// create list of files (in case of a single file input)
def files_to_check = [set_genomes].flatten()

// union and intersect accept 1 or more idx files
if (subcommand == 'union' || subcommand == 'intersect') {
def non_idx = files_to_check.findAll { file -> !file.name.endsWith('.idx') }
if (non_idx) {
error "Subcommand '${subcommand}' requires .idx files. Found non-index files: ${non_idx.collect { it.name }.join(', ')}"
}
}

// diff accepts exactly 1 idx or fasta file
else if (subcommand == 'diff') {
def valid_exts = ['.idx', '.fa', '.fasta', '.fna']
def invalid_files = files_to_check.findAll { file ->
!valid_exts.any { ext -> file.name.endsWith(ext) }
}
if (invalid_files) {
error "Subcommand 'diff' requires .idx or fasta files (.fa, .fasta, .fna). Found invalid files: ${invalid_files.collect { it.name }.join(', ')}"
}

if (files_to_check.size() > 1) {
error "Subcommand 'diff' expects a single file for set operation. Received ${files_to_check.size()} files."
}
}
}

"""
deacon \\
index \\
build \\
--threads ${task.cpus} \\
$args \\
$fasta > ${prefix}.idx
${subcommand} \\
${subcommand == 'build' ? "--threads ${task.cpus}" : ""} \\
${args} \\
${subcommand == 'build' ? "${reference}" : "${reference} ${set_genomes}"} \\
> ${prefix}.idx
"""

stub:
def prefix = task.ext.prefix ?: "${fasta.baseName}"
def prefix = task.ext.prefix ?: "${meta.id}"
subcommand = subcommand ?: 'build'
meta_out = meta + [operation: subcommand]
"""
touch ${prefix}.idx
"""
Expand Down
42 changes: 35 additions & 7 deletions modules/nf-core/deacon/index/meta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,52 @@ tools:
doi: "10.1093/bioinformatics/btae004"
licence: ["MIT"]
identifier: "biotools:deacon"

input:
- - meta:
type: map
description: |
Groovy Map containing reference information.
e.g. [ id:'test', single_end:false ]
- fasta:
- reference:
type: file
description: Input genome fasta file
pattern: "*.{fasta,fasta.gz,fas,fas.gz,fa,fa.gz,fna,fna.gz}"
description: |
Main input file for deacon index
- For 'build': fasta genome file
- For 'union'/'intersect'/'diff': .idx index file
pattern: "*.{fasta,fasta.gz,fas,fas.gz,fa,fa.gz,fna,fna.gz,idx}"
ontologies:
- edam: "http://edamontology.org/data_2044" # Sequence
- edam: "http://edamontology.org/format_1929" # FASTA
- edam: "http://edamontology.org/data_3210" # Genome index
- subcommand:
type: string
description: |
Deacon index subcommand to execute: 'build' (default), 'union', 'intersect', or 'diff'.
- build: Index minimizers contained within a fastx file
- union: Combine multiple minimizer indexes (A ∪ B…)
- intersect: Intersect multiple minimizer indexes (A ∩ B…)
- diff: SSubtract minimizers in one index from another (A - B)
pattern: "build|union|intersect|diff"
- - meta_set:
type: map
description: |
Groovy Map containing metadata for set operation genome index/fasta files.
e.g. [ id:'genome' ]
- set_genomes:
type: file
description: |
Optional input for set operations (union/intersect/diff).
- For union/intersect: One or more .idx files to combine/intersect with the main reference index
- For diff: A single .idx or fasta file to subtract from the main reference index
- Not required for build
pattern: "*.{idx,fasta,fasta.gz,fas,fas.gz,fa,fa.gz,fna,fna.gz}"
ontologies:
- edam: "http://edamontology.org/data_3210" # Genome index
- edam: "http://edamontology.org/data_2044" # Sequence
- edam: "http://edamontology.org/format_1929" # FASTA

output:
index:
- - meta:
- - meta_out:
type: map
description: |
Groovy Map containing reference information.
Expand All @@ -55,7 +83,6 @@ output:
- deacon --version | head -n1 | sed "s/deacon //g":
type: eval
description: The expression to obtain the version of the tool

topics:
versions:
- - ${task.process}:
Expand All @@ -71,3 +98,4 @@ authors:
- "@mberacochea"
maintainers:
- "@mberacochea"
- "@pmoris"
6 changes: 6 additions & 0 deletions modules/nf-core/deacon/index/tests/main.nf.test
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ nextflow_process {
[ id:'test'],
file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)
]
input[1] = '' // should default to 'build'
input[2] = [[:], []] // empty tuple for optional set operation genome input
"""
}
}
Expand All @@ -44,6 +46,8 @@ nextflow_process {
[ id:'test'],
file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true)
]
input[1] = '' // should default to 'build'
input[2] = [[:], []] // empty tuple for optional set operation genome input
"""
}
}
Expand Down Expand Up @@ -71,6 +75,8 @@ nextflow_process {
[ id:'test'],
file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)
]
input[1] = '' // should default to 'build'
input[2] = [[:], []] // empty tuple for optional set operation genome input
"""
}
}
Expand Down
37 changes: 21 additions & 16 deletions modules/nf-core/deacon/index/tests/main.nf.test.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
[
[
{
"id": "test"
"id": "test",
"operation": "build"
},
"test.idx:md5,84e4985c91800686db9c9dca28fabd1a"
]
Expand All @@ -19,21 +20,22 @@
]
}
],
"timestamp": "2026-02-13T17:04:37.800900709",
"meta": {
"nf-test": "0.9.3",
"nf-test": "0.9.4",
"nextflow": "25.10.2"
},
"timestamp": "2026-02-12T12:49:12.213473021"
}
},
"index sarscov2 - fasta - stub": {
"content": [
{
"0": [
[
{
"id": "test"
"id": "test",
"operation": "build"
},
"genome.idx:md5,d41d8cd98f00b204e9800998ecf8427e"
"test.idx:md5,d41d8cd98f00b204e9800998ecf8427e"
]
],
"1": [
Expand All @@ -46,9 +48,10 @@
"index": [
[
{
"id": "test"
"id": "test",
"operation": "build"
},
"genome.idx:md5,d41d8cd98f00b204e9800998ecf8427e"
"test.idx:md5,d41d8cd98f00b204e9800998ecf8427e"
]
],
"versions_deacon": [
Expand All @@ -69,19 +72,20 @@
]
}
],
"timestamp": "2026-02-13T17:31:45.177093319",
"meta": {
"nf-test": "0.9.3",
"nf-test": "0.9.4",
"nextflow": "25.10.2"
},
"timestamp": "2026-02-12T12:49:26.132617722"
}
},
"index sarscov2 - fasta gzipped": {
"content": [
{
"0": [
[
{
"id": "test"
"id": "test",
"operation": "build"
},
"test.idx:md5,84e4985c91800686db9c9dca28fabd1a"
]
Expand All @@ -96,7 +100,8 @@
"index": [
[
{
"id": "test"
"id": "test",
"operation": "build"
},
"test.idx:md5,84e4985c91800686db9c9dca28fabd1a"
]
Expand All @@ -119,10 +124,10 @@
]
}
],
"timestamp": "2026-02-13T17:04:46.61203129",
"meta": {
"nf-test": "0.9.3",
"nf-test": "0.9.4",
"nextflow": "25.10.2"
},
"timestamp": "2026-02-12T12:49:19.142528704"
}
}
}
7 changes: 7 additions & 0 deletions modules/nf-core/deacon/index_diff/environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
channels:
- conda-forge
- bioconda
dependencies:
- bioconda::deacon=0.13.2
50 changes: 50 additions & 0 deletions modules/nf-core/deacon/index_diff/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
process DEACON_INDEX_DIFF {
tag "fasta"

label 'process_low'

conda "${moduleDir}/environment.yml"
container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ?
'https://depot.galaxyproject.org/singularity/deacon:0.13.2--h7ef3eeb_1':
'biocontainers/deacon:0.13.2--h7ef3eeb_0' }"

input:
tuple val(meta_index), path(index) // deacon .idx index file
tuple val(meta_genome), path(genome) // a single fasta or .idx file to subtract from the main index

output:
tuple val(meta_index), path("*.idx"), emit: index
tuple val("${task.process}"), val('deacon'), eval('deacon --version | head -n1 | sed "s/deacon //g"'), emit: versions_deacon, topic: versions

when:
task.ext.when == null || task.ext.when

script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta_index.id}"
// TODO: we could optionally construct a new prefix + meta_out.id based on the two input meta.ids, but just using the original id of the main index file seems more straightforward since it can always be modified in a custom config
// def prefix = task.ext.prefix ?: "${meta_index.id}_diff_${meta_genome.id}"
// def meta_out = meta_index + [ id: "${prefix}" ]
// def meta_out = meta.clone()
// meta_out.id = "${prefix}"

"""
deacon \\
index \\
diff \\
${args} \\
${index} \\
${genome} \\
> ${prefix}.idx
"""

stub:
def prefix = task.ext.prefix ?: "${meta_index.id}"
// TODO: we could optionally construct a new meta_out.id based on the two input meta.ids instead
// def prefix = task.ext.prefix ?: "${meta_index.id}_diff_${meta_genome.id}"
// def meta_out = meta.clone()
// meta_out.id = "${prefix}"
"""
touch ${prefix}.idx
"""
}
Loading
Loading