From a7b0d33a321ac5de7907304788aad233cbf4b806 Mon Sep 17 00:00:00 2001 From: CI Date: Sat, 26 Oct 2024 19:02:37 +0000 Subject: [PATCH] Build branch main with version main (aa43543) Build pipeline: viash-hub.biobox.main-2k68h Source commit: https://github.com/viash-hub/biobox/commit/aa43543e1fb609901d09b7a9f0c5e72707cb47a4 Source message: Rseqc innerdistance (#159) * initial commit dedup * Revert "initial commit dedup" This reverts commit 38f586bec0ac9e4312b016e29c3aa0bd53f292b2. * full component with two tests * fix default values * adjust argument names and container image --------- Co-authored-by: Robrecht Cannoodt --- CHANGELOG.md | 24 +- .../config.vsh.yaml | 105 + .../help.txt | 85 + .../script.sh | 22 + .../test.sh | 36 + .../test_data/1_truncated.gff | 123 + .../test_data/kill_list.txt | 3 + .../test_data/script.sh | 13 + .../test_data/test_output.gff | 113 + .../agat_sp_merge_annotations/config.vsh.yaml | 67 + src/agat/agat_sp_merge_annotations/help.txt | 64 + src/agat/agat_sp_merge_annotations/script.sh | 19 + src/agat/agat_sp_merge_annotations/test.sh | 56 + .../test_data/agat_sp_merge_annotations_1.gff | 13 + .../test_data/agat_sp_merge_annotations_2.gff | 3 + .../test_data/file1.gff | 14 + .../test_data/file2.gff | 12 + .../test_data/fileA.gff | 2 + .../test_data/fileB.gff | 2 + .../test_data/script.sh | 15 + .../bedtools_bamtobed/config.vsh.yaml | 118 + src/bedtools/bedtools_bamtobed/help.txt | 43 + src/bedtools/bedtools_bamtobed/script.sh | 39 + src/bedtools/bedtools_bamtobed/test.sh | 183 + .../bedtools_bamtobed/test_data/example.bam | Bin 0 -> 334 bytes .../bedtools_bamtobed/test_data/example.sam | 3 + src/rseqc/rseqc_bamstat/config.vsh.yaml | 59 + src/rseqc/rseqc_bamstat/help.txt | 18 + src/rseqc/rseqc_bamstat/script.sh | 9 + src/rseqc/rseqc_bamstat/test.sh | 49 + .../rseqc_bamstat/test_data/ref_output.txt | 22 + .../test_data/ref_output_mapq.txt | 22 + src/rseqc/rseqc_bamstat/test_data/sample.bam | Bin 0 -> 9240 bytes .../rseqc_inferexperiment/config.vsh.yaml | 76 + src/rseqc/rseqc_inferexperiment/help.txt | 21 + src/rseqc/rseqc_inferexperiment/script.sh | 10 + src/rseqc/rseqc_inferexperiment/test.sh | 72 + .../test_data/sample.bam | Bin 0 -> 5595 bytes .../test_data/test.bed12 | 4 + .../test_data/test.paired_end.sorted.bam | Bin 0 -> 19725 bytes .../rseqc_inner_distance/config.vsh.yaml | 116 + src/rseqc/rseqc_inner_distance/help.txt | 43 + src/rseqc/rseqc_inner_distance/script.sh | 25 + src/rseqc/rseqc_inner_distance/test.sh | 77 + .../rseqc_inner_distance/test_data/test.bed12 | 4 + .../test_data/test.paired_end.sorted.bam | Bin 0 -> 10205 bytes .../test_data/test1.inner_distance.txt | 49 + .../test_data/test1.inner_distance_freq.txt | 100 + .../test_data/test2.inner_distance.txt | 4 + .../test_data/test2.inner_distance_freq.txt | 100 + .../agat_convert_bed2gff/.config.vsh.yaml | 6 +- .../agat_convert_bed2gff/agat_convert_bed2gff | 4 +- .../agat_convert_embl2gff/.config.vsh.yaml | 6 +- .../agat_convert_embl2gff | 4 +- .../agat_convert_genscan2gff/.config.vsh.yaml | 6 +- .../agat_convert_genscan2gff | 4 +- .../agat_convert_sp_gff2gtf/.config.vsh.yaml | 6 +- .../agat_convert_sp_gff2gtf | 4 +- .../agat_convert_sp_gff2tsv/.config.vsh.yaml | 6 +- .../agat_convert_sp_gff2tsv | 4 +- .../agat_convert_sp_gxf2gxf/.config.vsh.yaml | 6 +- .../agat_convert_sp_gxf2gxf | 4 +- .../agat/agat_sp_add_introns/.config.vsh.yaml | 6 +- .../agat_sp_add_introns/agat_sp_add_introns | 4 +- .../.config.vsh.yaml | 263 ++ .../agat_sp_filter_feature_from_kill_list | 1312 ++++++ .../.config.vsh.yaml | 211 + .../agat_sp_merge_annotations | 1187 ++++++ .../agat/agat_sp_statistics/.config.vsh.yaml | 6 +- .../agat_sp_statistics/agat_sp_statistics | 4 +- target/executable/arriba/.config.vsh.yaml | 6 +- target/executable/arriba/arriba | 4 +- .../bbmap/bbmap_bbsplit/.config.vsh.yaml | 6 +- .../bbmap/bbmap_bbsplit/bbmap_bbsplit | 4 +- .../bcftools_annotate/.config.vsh.yaml | 6 +- .../bcftools_annotate/bcftools_annotate | 4 +- .../bcftools/bcftools_concat/.config.vsh.yaml | 6 +- .../bcftools/bcftools_concat/bcftools_concat | 4 +- .../bcftools/bcftools_norm/.config.vsh.yaml | 6 +- .../bcftools/bcftools_norm/bcftools_norm | 4 +- .../bcftools/bcftools_sort/.config.vsh.yaml | 6 +- .../bcftools/bcftools_sort/bcftools_sort | 4 +- .../bcftools/bcftools_stats/.config.vsh.yaml | 6 +- .../bcftools/bcftools_stats/bcftools_stats | 4 +- .../executable/bcl_convert/.config.vsh.yaml | 6 +- target/executable/bcl_convert/bcl_convert | 4 +- .../.config.vsh.yaml | 6 +- .../bd_rhapsody_make_reference | 4 +- .../.config.vsh.yaml | 6 +- .../bd_rhapsody_sequence_analysis | 4 +- .../bedtools_bamtobed/.config.vsh.yaml | 262 ++ .../bedtools_bamtobed/bedtools_bamtobed | 1313 ++++++ .../bedtools_bamtofastq/.config.vsh.yaml | 6 +- .../bedtools_bamtofastq/bedtools_bamtofastq | 4 +- .../bedtools_bed12tobed6/.config.vsh.yaml | 6 +- .../bedtools_bed12tobed6/bedtools_bed12tobed6 | 4 +- .../bedtools_bedtobam/.config.vsh.yaml | 6 +- .../bedtools_bedtobam/bedtools_bedtobam | 4 +- .../bedtools_genomecov/.config.vsh.yaml | 6 +- .../bedtools_genomecov/bedtools_genomecov | 4 +- .../bedtools_getfasta/.config.vsh.yaml | 6 +- .../bedtools_getfasta/bedtools_getfasta | 4 +- .../bedtools_groupby/.config.vsh.yaml | 6 +- .../bedtools_groupby/bedtools_groupby | 4 +- .../bedtools_intersect/.config.vsh.yaml | 6 +- .../bedtools_intersect/bedtools_intersect | 4 +- .../bedtools/bedtools_links/.config.vsh.yaml | 6 +- .../bedtools/bedtools_links/bedtools_links | 4 +- .../bedtools/bedtools_merge/.config.vsh.yaml | 6 +- .../bedtools/bedtools_merge/bedtools_merge | 4 +- .../bedtools/bedtools_sort/.config.vsh.yaml | 6 +- .../bedtools/bedtools_sort/bedtools_sort | 4 +- .../busco_download_datasets/.config.vsh.yaml | 6 +- .../busco_download_datasets | 4 +- .../busco_list_datasets/.config.vsh.yaml | 6 +- .../busco_list_datasets/busco_list_datasets | 4 +- .../busco/busco_run/.config.vsh.yaml | 6 +- target/executable/busco/busco_run/busco_run | 4 +- target/executable/cutadapt/.config.vsh.yaml | 6 +- target/executable/cutadapt/cutadapt | 4 +- target/executable/falco/.config.vsh.yaml | 6 +- target/executable/falco/falco | 4 +- target/executable/fastp/.config.vsh.yaml | 6 +- target/executable/fastp/fastp | 4 +- target/executable/fastqc/.config.vsh.yaml | 6 +- target/executable/fastqc/fastqc | 4 +- .../executable/featurecounts/.config.vsh.yaml | 6 +- target/executable/featurecounts/featurecounts | 4 +- .../executable/fq_subsample/.config.vsh.yaml | 6 +- target/executable/fq_subsample/fq_subsample | 4 +- target/executable/gffread/.config.vsh.yaml | 6 +- target/executable/gffread/gffread | 4 +- .../kallisto/kallisto_index/.config.vsh.yaml | 6 +- .../kallisto/kallisto_index/kallisto_index | 4 +- .../kallisto/kallisto_quant/.config.vsh.yaml | 6 +- .../kallisto/kallisto_quant/kallisto_quant | 4 +- .../lofreq/lofreq_call/.config.vsh.yaml | 6 +- .../executable/lofreq/lofreq_call/lofreq_call | 4 +- .../lofreq/lofreq_indelqual/.config.vsh.yaml | 6 +- .../lofreq/lofreq_indelqual/lofreq_indelqual | 4 +- target/executable/multiqc/.config.vsh.yaml | 6 +- target/executable/multiqc/multiqc | 4 +- target/executable/nanoplot/.config.vsh.yaml | 6 +- target/executable/nanoplot/nanoplot | 4 +- target/executable/pear/.config.vsh.yaml | 6 +- target/executable/pear/pear | 4 +- .../qualimap/qualimap_rnaseq/.config.vsh.yaml | 6 +- .../qualimap/qualimap_rnaseq/qualimap_rnaseq | 4 +- .../.config.vsh.yaml | 6 +- .../rsem_calculate_expression | 4 +- .../rsem_prepare_reference/.config.vsh.yaml | 6 +- .../rsem_prepare_reference | 4 +- .../rseqc/rseqc_bamstat/.config.vsh.yaml | 202 + .../rseqc/rseqc_bamstat/rseqc_bamstat | 1119 +++++ .../rseqc_inferexperiment/.config.vsh.yaml | 228 + .../rseqc_inferexperiment | 1192 ++++++ .../rseqc_inner_distance/.config.vsh.yaml | 321 ++ .../rseqc_inner_distance/rseqc_inner_distance | 1449 +++++++ .../salmon/salmon_index/.config.vsh.yaml | 6 +- .../salmon/salmon_index/salmon_index | 4 +- .../salmon/salmon_quant/.config.vsh.yaml | 6 +- .../salmon/salmon_quant/salmon_quant | 4 +- .../samtools_collate/.config.vsh.yaml | 6 +- .../samtools_collate/samtools_collate | 4 +- .../samtools/samtools_faidx/.config.vsh.yaml | 6 +- .../samtools/samtools_faidx/samtools_faidx | 4 +- .../samtools/samtools_fasta/.config.vsh.yaml | 6 +- .../samtools/samtools_fasta/samtools_fasta | 4 +- .../samtools/samtools_fastq/.config.vsh.yaml | 6 +- .../samtools/samtools_fastq/samtools_fastq | 4 +- .../samtools_flagstat/.config.vsh.yaml | 6 +- .../samtools_flagstat/samtools_flagstat | 4 +- .../samtools_idxstats/.config.vsh.yaml | 6 +- .../samtools_idxstats/samtools_idxstats | 4 +- .../samtools/samtools_index/.config.vsh.yaml | 6 +- .../samtools/samtools_index/samtools_index | 4 +- .../samtools/samtools_sort/.config.vsh.yaml | 6 +- .../samtools/samtools_sort/samtools_sort | 4 +- .../samtools/samtools_stats/.config.vsh.yaml | 6 +- .../samtools/samtools_stats/samtools_stats | 4 +- .../samtools/samtools_view/.config.vsh.yaml | 6 +- .../samtools/samtools_view/samtools_view | 4 +- .../seqtk/seqtk_sample/.config.vsh.yaml | 6 +- .../seqtk/seqtk_sample/seqtk_sample | 4 +- .../seqtk/seqtk_subseq/.config.vsh.yaml | 6 +- .../seqtk/seqtk_subseq/seqtk_subseq | 4 +- target/executable/snpeff/.config.vsh.yaml | 6 +- target/executable/snpeff/snpeff | 4 +- target/executable/sortmerna/.config.vsh.yaml | 6 +- target/executable/sortmerna/sortmerna | 4 +- .../star/star_align_reads/.config.vsh.yaml | 6 +- .../star/star_align_reads/star_align_reads | 4 +- .../star_genome_generate/.config.vsh.yaml | 6 +- .../star_genome_generate/star_genome_generate | 4 +- target/executable/trimgalore/.config.vsh.yaml | 6 +- target/executable/trimgalore/trimgalore | 4 +- .../umi_tools_dedup/.config.vsh.yaml | 6 +- .../umi_tools/umi_tools_dedup/umi_tools_dedup | 4 +- .../umi_tools_extract/.config.vsh.yaml | 6 +- .../umi_tools_extract/umi_tools_extract | 4 +- .../umi_tools_prepareforrsem/.config.vsh.yaml | 6 +- .../umi_tools_prepareforrsem | 4 +- .../agat_convert_bed2gff/.config.vsh.yaml | 6 +- .../agat/agat_convert_bed2gff/main.nf | 6 +- .../agat_convert_embl2gff/.config.vsh.yaml | 6 +- .../agat/agat_convert_embl2gff/main.nf | 6 +- .../agat_convert_genscan2gff/.config.vsh.yaml | 6 +- .../agat/agat_convert_genscan2gff/main.nf | 6 +- .../agat_convert_sp_gff2gtf/.config.vsh.yaml | 6 +- .../agat/agat_convert_sp_gff2gtf/main.nf | 6 +- .../agat_convert_sp_gff2tsv/.config.vsh.yaml | 6 +- .../agat/agat_convert_sp_gff2tsv/main.nf | 6 +- .../agat_convert_sp_gxf2gxf/.config.vsh.yaml | 6 +- .../agat/agat_convert_sp_gxf2gxf/main.nf | 6 +- .../agat/agat_sp_add_introns/.config.vsh.yaml | 6 +- .../nextflow/agat/agat_sp_add_introns/main.nf | 6 +- .../.config.vsh.yaml | 263 ++ .../main.nf | 3669 ++++++++++++++++ .../nextflow.config | 126 + .../nextflow_schema.json | 160 + .../.config.vsh.yaml | 211 + .../agat/agat_sp_merge_annotations/main.nf | 3612 ++++++++++++++++ .../agat_sp_merge_annotations/nextflow.config | 126 + .../nextflow_schema.json | 119 + .../agat/agat_sp_statistics/.config.vsh.yaml | 6 +- .../nextflow/agat/agat_sp_statistics/main.nf | 6 +- target/nextflow/arriba/.config.vsh.yaml | 6 +- target/nextflow/arriba/main.nf | 6 +- .../bbmap/bbmap_bbsplit/.config.vsh.yaml | 6 +- target/nextflow/bbmap/bbmap_bbsplit/main.nf | 6 +- .../bcftools_annotate/.config.vsh.yaml | 6 +- .../bcftools/bcftools_annotate/main.nf | 6 +- .../bcftools/bcftools_concat/.config.vsh.yaml | 6 +- .../nextflow/bcftools/bcftools_concat/main.nf | 6 +- .../bcftools/bcftools_norm/.config.vsh.yaml | 6 +- .../nextflow/bcftools/bcftools_norm/main.nf | 6 +- .../bcftools/bcftools_sort/.config.vsh.yaml | 6 +- .../nextflow/bcftools/bcftools_sort/main.nf | 6 +- .../bcftools/bcftools_stats/.config.vsh.yaml | 6 +- .../nextflow/bcftools/bcftools_stats/main.nf | 6 +- target/nextflow/bcl_convert/.config.vsh.yaml | 6 +- target/nextflow/bcl_convert/main.nf | 6 +- .../.config.vsh.yaml | 6 +- .../bd_rhapsody_make_reference/main.nf | 6 +- .../.config.vsh.yaml | 6 +- .../bd_rhapsody_sequence_analysis/main.nf | 6 +- .../bedtools_bamtobed/.config.vsh.yaml | 262 ++ .../bedtools/bedtools_bamtobed/main.nf | 3694 ++++++++++++++++ .../bedtools_bamtobed/nextflow.config | 126 + .../bedtools_bamtobed/nextflow_schema.json | 206 + .../bedtools_bamtofastq/.config.vsh.yaml | 6 +- .../bedtools/bedtools_bamtofastq/main.nf | 6 +- .../bedtools_bed12tobed6/.config.vsh.yaml | 6 +- .../bedtools/bedtools_bed12tobed6/main.nf | 6 +- .../bedtools_bedtobam/.config.vsh.yaml | 6 +- .../bedtools/bedtools_bedtobam/main.nf | 6 +- .../bedtools_genomecov/.config.vsh.yaml | 6 +- .../bedtools/bedtools_genomecov/main.nf | 6 +- .../bedtools_getfasta/.config.vsh.yaml | 6 +- .../bedtools/bedtools_getfasta/main.nf | 6 +- .../bedtools_groupby/.config.vsh.yaml | 6 +- .../bedtools/bedtools_groupby/main.nf | 6 +- .../bedtools_intersect/.config.vsh.yaml | 6 +- .../bedtools/bedtools_intersect/main.nf | 6 +- .../bedtools/bedtools_links/.config.vsh.yaml | 6 +- .../nextflow/bedtools/bedtools_links/main.nf | 6 +- .../bedtools/bedtools_merge/.config.vsh.yaml | 6 +- .../nextflow/bedtools/bedtools_merge/main.nf | 6 +- .../bedtools/bedtools_sort/.config.vsh.yaml | 6 +- .../nextflow/bedtools/bedtools_sort/main.nf | 6 +- .../busco_download_datasets/.config.vsh.yaml | 6 +- .../busco/busco_download_datasets/main.nf | 6 +- .../busco_list_datasets/.config.vsh.yaml | 6 +- .../busco/busco_list_datasets/main.nf | 6 +- .../nextflow/busco/busco_run/.config.vsh.yaml | 6 +- target/nextflow/busco/busco_run/main.nf | 6 +- target/nextflow/cutadapt/.config.vsh.yaml | 6 +- target/nextflow/cutadapt/main.nf | 6 +- target/nextflow/falco/.config.vsh.yaml | 6 +- target/nextflow/falco/main.nf | 6 +- target/nextflow/fastp/.config.vsh.yaml | 6 +- target/nextflow/fastp/main.nf | 6 +- target/nextflow/fastqc/.config.vsh.yaml | 6 +- target/nextflow/fastqc/main.nf | 6 +- .../nextflow/featurecounts/.config.vsh.yaml | 6 +- target/nextflow/featurecounts/main.nf | 6 +- target/nextflow/fq_subsample/.config.vsh.yaml | 6 +- target/nextflow/fq_subsample/main.nf | 6 +- target/nextflow/gffread/.config.vsh.yaml | 6 +- target/nextflow/gffread/main.nf | 6 +- .../kallisto/kallisto_index/.config.vsh.yaml | 6 +- .../nextflow/kallisto/kallisto_index/main.nf | 6 +- .../kallisto/kallisto_quant/.config.vsh.yaml | 6 +- .../nextflow/kallisto/kallisto_quant/main.nf | 6 +- .../lofreq/lofreq_call/.config.vsh.yaml | 6 +- target/nextflow/lofreq/lofreq_call/main.nf | 6 +- .../lofreq/lofreq_indelqual/.config.vsh.yaml | 6 +- .../nextflow/lofreq/lofreq_indelqual/main.nf | 6 +- target/nextflow/multiqc/.config.vsh.yaml | 6 +- target/nextflow/multiqc/main.nf | 6 +- target/nextflow/nanoplot/.config.vsh.yaml | 6 +- target/nextflow/nanoplot/main.nf | 6 +- target/nextflow/pear/.config.vsh.yaml | 6 +- target/nextflow/pear/main.nf | 6 +- .../qualimap/qualimap_rnaseq/.config.vsh.yaml | 6 +- .../nextflow/qualimap/qualimap_rnaseq/main.nf | 6 +- .../.config.vsh.yaml | 6 +- .../rsem/rsem_calculate_expression/main.nf | 6 +- .../rsem_prepare_reference/.config.vsh.yaml | 6 +- .../rsem/rsem_prepare_reference/main.nf | 6 +- .../rseqc/rseqc_bamstat/.config.vsh.yaml | 202 + target/nextflow/rseqc/rseqc_bamstat/main.nf | 3594 ++++++++++++++++ .../rseqc/rseqc_bamstat/nextflow.config | 126 + .../rseqc/rseqc_bamstat/nextflow_schema.json | 105 + .../rseqc_inferexperiment/.config.vsh.yaml | 228 + .../rseqc/rseqc_inferexperiment/main.nf | 3630 ++++++++++++++++ .../rseqc_inferexperiment/nextflow.config | 126 + .../nextflow_schema.json | 139 + .../rseqc_inner_distance/.config.vsh.yaml | 321 ++ .../rseqc/rseqc_inner_distance/main.nf | 3753 +++++++++++++++++ .../rseqc_inner_distance/nextflow.config | 126 + .../rseqc_inner_distance/nextflow_schema.json | 209 + .../salmon/salmon_index/.config.vsh.yaml | 6 +- target/nextflow/salmon/salmon_index/main.nf | 6 +- .../salmon/salmon_quant/.config.vsh.yaml | 6 +- target/nextflow/salmon/salmon_quant/main.nf | 6 +- .../samtools_collate/.config.vsh.yaml | 6 +- .../samtools/samtools_collate/main.nf | 6 +- .../samtools/samtools_faidx/.config.vsh.yaml | 6 +- .../nextflow/samtools/samtools_faidx/main.nf | 6 +- .../samtools/samtools_fasta/.config.vsh.yaml | 6 +- .../nextflow/samtools/samtools_fasta/main.nf | 6 +- .../samtools/samtools_fastq/.config.vsh.yaml | 6 +- .../nextflow/samtools/samtools_fastq/main.nf | 6 +- .../samtools_flagstat/.config.vsh.yaml | 6 +- .../samtools/samtools_flagstat/main.nf | 6 +- .../samtools_idxstats/.config.vsh.yaml | 6 +- .../samtools/samtools_idxstats/main.nf | 6 +- .../samtools/samtools_index/.config.vsh.yaml | 6 +- .../nextflow/samtools/samtools_index/main.nf | 6 +- .../samtools/samtools_sort/.config.vsh.yaml | 6 +- .../nextflow/samtools/samtools_sort/main.nf | 6 +- .../samtools/samtools_stats/.config.vsh.yaml | 6 +- .../nextflow/samtools/samtools_stats/main.nf | 6 +- .../samtools/samtools_view/.config.vsh.yaml | 6 +- .../nextflow/samtools/samtools_view/main.nf | 6 +- .../seqtk/seqtk_sample/.config.vsh.yaml | 6 +- target/nextflow/seqtk/seqtk_sample/main.nf | 6 +- .../seqtk/seqtk_subseq/.config.vsh.yaml | 6 +- target/nextflow/seqtk/seqtk_subseq/main.nf | 6 +- target/nextflow/snpeff/.config.vsh.yaml | 6 +- target/nextflow/snpeff/main.nf | 6 +- target/nextflow/sortmerna/.config.vsh.yaml | 6 +- target/nextflow/sortmerna/main.nf | 6 +- .../star/star_align_reads/.config.vsh.yaml | 6 +- target/nextflow/star/star_align_reads/main.nf | 6 +- .../star_genome_generate/.config.vsh.yaml | 6 +- .../star/star_genome_generate/main.nf | 6 +- target/nextflow/trimgalore/.config.vsh.yaml | 6 +- target/nextflow/trimgalore/main.nf | 6 +- .../umi_tools_dedup/.config.vsh.yaml | 6 +- .../umi_tools/umi_tools_dedup/main.nf | 6 +- .../umi_tools_extract/.config.vsh.yaml | 6 +- .../umi_tools/umi_tools_extract/main.nf | 6 +- .../umi_tools_prepareforrsem/.config.vsh.yaml | 6 +- .../umi_tools_prepareforrsem/main.nf | 6 +- 366 files changed, 37009 insertions(+), 780 deletions(-) create mode 100644 src/agat/agat_sp_filter_feature_from_kill_list/config.vsh.yaml create mode 100644 src/agat/agat_sp_filter_feature_from_kill_list/help.txt create mode 100644 src/agat/agat_sp_filter_feature_from_kill_list/script.sh create mode 100644 src/agat/agat_sp_filter_feature_from_kill_list/test.sh create mode 100644 src/agat/agat_sp_filter_feature_from_kill_list/test_data/1_truncated.gff create mode 100644 src/agat/agat_sp_filter_feature_from_kill_list/test_data/kill_list.txt create mode 100755 src/agat/agat_sp_filter_feature_from_kill_list/test_data/script.sh create mode 100644 src/agat/agat_sp_filter_feature_from_kill_list/test_data/test_output.gff create mode 100644 src/agat/agat_sp_merge_annotations/config.vsh.yaml create mode 100644 src/agat/agat_sp_merge_annotations/help.txt create mode 100644 src/agat/agat_sp_merge_annotations/script.sh create mode 100644 src/agat/agat_sp_merge_annotations/test.sh create mode 100644 src/agat/agat_sp_merge_annotations/test_data/agat_sp_merge_annotations_1.gff create mode 100644 src/agat/agat_sp_merge_annotations/test_data/agat_sp_merge_annotations_2.gff create mode 100644 src/agat/agat_sp_merge_annotations/test_data/file1.gff create mode 100644 src/agat/agat_sp_merge_annotations/test_data/file2.gff create mode 100644 src/agat/agat_sp_merge_annotations/test_data/fileA.gff create mode 100644 src/agat/agat_sp_merge_annotations/test_data/fileB.gff create mode 100755 src/agat/agat_sp_merge_annotations/test_data/script.sh create mode 100644 src/bedtools/bedtools_bamtobed/config.vsh.yaml create mode 100644 src/bedtools/bedtools_bamtobed/help.txt create mode 100644 src/bedtools/bedtools_bamtobed/script.sh create mode 100644 src/bedtools/bedtools_bamtobed/test.sh create mode 100644 src/bedtools/bedtools_bamtobed/test_data/example.bam create mode 100644 src/bedtools/bedtools_bamtobed/test_data/example.sam create mode 100644 src/rseqc/rseqc_bamstat/config.vsh.yaml create mode 100644 src/rseqc/rseqc_bamstat/help.txt create mode 100644 src/rseqc/rseqc_bamstat/script.sh create mode 100644 src/rseqc/rseqc_bamstat/test.sh create mode 100644 src/rseqc/rseqc_bamstat/test_data/ref_output.txt create mode 100644 src/rseqc/rseqc_bamstat/test_data/ref_output_mapq.txt create mode 100644 src/rseqc/rseqc_bamstat/test_data/sample.bam create mode 100644 src/rseqc/rseqc_inferexperiment/config.vsh.yaml create mode 100644 src/rseqc/rseqc_inferexperiment/help.txt create mode 100644 src/rseqc/rseqc_inferexperiment/script.sh create mode 100644 src/rseqc/rseqc_inferexperiment/test.sh create mode 100644 src/rseqc/rseqc_inferexperiment/test_data/sample.bam create mode 100644 src/rseqc/rseqc_inferexperiment/test_data/test.bed12 create mode 100644 src/rseqc/rseqc_inferexperiment/test_data/test.paired_end.sorted.bam create mode 100644 src/rseqc/rseqc_inner_distance/config.vsh.yaml create mode 100644 src/rseqc/rseqc_inner_distance/help.txt create mode 100644 src/rseqc/rseqc_inner_distance/script.sh create mode 100644 src/rseqc/rseqc_inner_distance/test.sh create mode 100644 src/rseqc/rseqc_inner_distance/test_data/test.bed12 create mode 100644 src/rseqc/rseqc_inner_distance/test_data/test.paired_end.sorted.bam create mode 100644 src/rseqc/rseqc_inner_distance/test_data/test1.inner_distance.txt create mode 100644 src/rseqc/rseqc_inner_distance/test_data/test1.inner_distance_freq.txt create mode 100644 src/rseqc/rseqc_inner_distance/test_data/test2.inner_distance.txt create mode 100644 src/rseqc/rseqc_inner_distance/test_data/test2.inner_distance_freq.txt create mode 100644 target/executable/agat/agat_sp_filter_feature_from_kill_list/.config.vsh.yaml create mode 100755 target/executable/agat/agat_sp_filter_feature_from_kill_list/agat_sp_filter_feature_from_kill_list create mode 100644 target/executable/agat/agat_sp_merge_annotations/.config.vsh.yaml create mode 100755 target/executable/agat/agat_sp_merge_annotations/agat_sp_merge_annotations create mode 100644 target/executable/bedtools/bedtools_bamtobed/.config.vsh.yaml create mode 100755 target/executable/bedtools/bedtools_bamtobed/bedtools_bamtobed create mode 100644 target/executable/rseqc/rseqc_bamstat/.config.vsh.yaml create mode 100755 target/executable/rseqc/rseqc_bamstat/rseqc_bamstat create mode 100644 target/executable/rseqc/rseqc_inferexperiment/.config.vsh.yaml create mode 100755 target/executable/rseqc/rseqc_inferexperiment/rseqc_inferexperiment create mode 100644 target/executable/rseqc/rseqc_inner_distance/.config.vsh.yaml create mode 100755 target/executable/rseqc/rseqc_inner_distance/rseqc_inner_distance create mode 100644 target/nextflow/agat/agat_sp_filter_feature_from_kill_list/.config.vsh.yaml create mode 100644 target/nextflow/agat/agat_sp_filter_feature_from_kill_list/main.nf create mode 100644 target/nextflow/agat/agat_sp_filter_feature_from_kill_list/nextflow.config create mode 100644 target/nextflow/agat/agat_sp_filter_feature_from_kill_list/nextflow_schema.json create mode 100644 target/nextflow/agat/agat_sp_merge_annotations/.config.vsh.yaml create mode 100644 target/nextflow/agat/agat_sp_merge_annotations/main.nf create mode 100644 target/nextflow/agat/agat_sp_merge_annotations/nextflow.config create mode 100644 target/nextflow/agat/agat_sp_merge_annotations/nextflow_schema.json create mode 100644 target/nextflow/bedtools/bedtools_bamtobed/.config.vsh.yaml create mode 100644 target/nextflow/bedtools/bedtools_bamtobed/main.nf create mode 100644 target/nextflow/bedtools/bedtools_bamtobed/nextflow.config create mode 100644 target/nextflow/bedtools/bedtools_bamtobed/nextflow_schema.json create mode 100644 target/nextflow/rseqc/rseqc_bamstat/.config.vsh.yaml create mode 100644 target/nextflow/rseqc/rseqc_bamstat/main.nf create mode 100644 target/nextflow/rseqc/rseqc_bamstat/nextflow.config create mode 100644 target/nextflow/rseqc/rseqc_bamstat/nextflow_schema.json create mode 100644 target/nextflow/rseqc/rseqc_inferexperiment/.config.vsh.yaml create mode 100644 target/nextflow/rseqc/rseqc_inferexperiment/main.nf create mode 100644 target/nextflow/rseqc/rseqc_inferexperiment/nextflow.config create mode 100644 target/nextflow/rseqc/rseqc_inferexperiment/nextflow_schema.json create mode 100644 target/nextflow/rseqc/rseqc_inner_distance/.config.vsh.yaml create mode 100644 target/nextflow/rseqc/rseqc_inner_distance/main.nf create mode 100644 target/nextflow/rseqc/rseqc_inner_distance/nextflow.config create mode 100644 target/nextflow/rseqc/rseqc_inner_distance/nextflow_schema.json diff --git a/CHANGELOG.md b/CHANGELOG.md index a8cfc83a..0e32edb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,26 +4,30 @@ * `agat`: - `agat/agat_convert_genscan2gff`: convert a genscan file into a GFF file (PR #100). - - `agat_sp_statistics`: provides exhaustive statistics of a gft/gff file (PR #107). - + - `agat/agat_sp_add_introns`: add intron features to gtf/gff file without intron features (PR #104). + - `agat/agat_sp_filter_feature_from_kill_list`: remove features in a GFF file based on a kill list (PR #105). + - `agat/agat_sp_merge_annotations`: merge different gff annotation files in one (PR #106). + - `agat/agat_sp_statistics`: provides exhaustive statistics of a gft/gff file (PR #107). * `bd_rhapsody/bd_rhapsody_sequence_analysis`: BD Rhapsody Sequence Analysis CWL pipeline (PR #96). +* `bedtools`: + - `bedtools/bedtools_bamtobed`: Converts BAM alignments to BED6 or BEDPE format (PR #109). + * `rsem/rsem_calculate_expression`: Calculate expression levels (PR #93). +* `rseqc`: + - `rseqc/rseqc_inner_distance`: Calculate inner distance between read pairs (PR #159). + - `rseqc/rseqc_inferexperiment`: Infer strandedness from sequencing reads (PR #158). + - `rseqc/bam_stat`: Generate statistics from a bam file (PR #155). + * `nanoplot`: Plotting tool for long read sequencing data and alignments (PR #95). -* `agat`: - - `agat/agat_sp_add_introns`: add intron features to gtf/gff file without intron features (PR #104). - - -## BREAKING CHANGES +## BUG FIXES * `falco`: Fix a typo in the `--reverse_complement` argument (PR #157). -## BUG FIXES - -* `cutadapt`: fix the the non-functional `action` parameter (PR #161). +* `cutadapt`: Fix the the non-functional `action` parameter (PR #161). ## MINOR CHANGES diff --git a/src/agat/agat_sp_filter_feature_from_kill_list/config.vsh.yaml b/src/agat/agat_sp_filter_feature_from_kill_list/config.vsh.yaml new file mode 100644 index 00000000..0608ad4d --- /dev/null +++ b/src/agat/agat_sp_filter_feature_from_kill_list/config.vsh.yaml @@ -0,0 +1,105 @@ +name: agat_sp_filter_feature_from_kill_list +namespace: agat +description: | + Remove features based on a kill list. The default behaviour is to look at the features's ID. + If the feature has an ID (case insensitive) listed among the kill list it will be removed. + Removing a level1 or level2 feature will automatically remove all linked subfeatures, and + removing all children of a feature will automatically remove this feature too. +keywords: [gene annotations, filtering, gff] +links: + homepage: https://github.com/NBISweden/AGAT + documentation: https://agat.readthedocs.io/en/latest/tools/agat_sp_filter_feature_from_kill_list.html + issue_tracker: https://github.com/NBISweden/AGAT/issues + repository: https://github.com/NBISweden/AGAT +references: + doi: 10.5281/zenodo.3552717 +license: GPL-3.0 +requirements: + - commands: [agat] +authors: + - __merge__: /src/_authors/leila_paquay.yaml + roles: [ author, maintainer ] + +argument_groups: + - name: Inputs + arguments: + - name: --gff + alternatives: [-f, --ref, --reffile] + description: Input GFF3 file that will be read. + type: file + required: true + - name: --kill_list + alternatives: [--kl] + description: Text file containing the kill list. One value per line. + type: file + required: true + example: kill_list.txt + - name: Outputs + arguments: + - name: --output + alternatives: [-o, --out] + description: | + Path to the output GFF file that contains filtered features. + type: file + direction: output + required: true + - name: Arguments + arguments: + - name: --type + alternatives: [-p, -l] + description: | + Primary tag option, case insensitive, list. Allow to specify the feature types that + will be handled. + + You can specify a specific feature by giving its primary tag name (column 3) as: + + * cds + * Gene + * mRNA + + You can specify directly all the feature of a particular + level: + + * level2=mRNA,ncRNA,tRNA,etc + * level3=CDS,exon,UTR,etc. + + By default all features are taken into account. Fill the option with the value "all" will + have the same behaviour. + type: string + multiple: true + - name: --attribute + alternatives: [-a] + description: | + Attribute tag to specify the attribute to analyse. Case sensitive. Default: ID + type: string + example: ID + - name: --config + alternatives: [-c] + description: | + AGAT config file. By default AGAT takes the original agat_config.yaml shipped with AGAT. + The `--config` option gives you the possibility to use your own AGAT config file (located + elsewhere or named differently). + type: file + example: custom_agat_config.yaml + - name: --verbose + alternatives: [-v] + description: Verbose option for debugging purpose. + type: boolean_true +resources: + - type: bash_script + path: script.sh +test_resources: + - type: bash_script + path: test.sh + - type: file + path: test_data +engines: + - type: docker + image: quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0 + setup: + - type: docker + run: | + agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.txt +runners: + - type: executable + - type: nextflow \ No newline at end of file diff --git a/src/agat/agat_sp_filter_feature_from_kill_list/help.txt b/src/agat/agat_sp_filter_feature_from_kill_list/help.txt new file mode 100644 index 00000000..b0087916 --- /dev/null +++ b/src/agat/agat_sp_filter_feature_from_kill_list/help.txt @@ -0,0 +1,85 @@ +```sh +agat_sp_filter_feature_from_kill_list.pl --help +``` + + ------------------------------------------------------------------------------ +| Another GFF Analysis Toolkit (AGAT) - Version: v1.4.0 | +| https://github.com/NBISweden/AGAT | +| National Bioinformatics Infrastructure Sweden (NBIS) - www.nbis.se | + ------------------------------------------------------------------------------ + + +Name: + agat_sp_filter_feature_from_kill_list.pl + +Description: + The script aims to remove features based on a kill list. The default + behaviour is to look at the features's ID. If the feature has an ID + (case insensitive) listed among the kill list it will be removed. /!\ + Removing a level1 or level2 feature will automatically remove all linked + subfeatures, and removing all children of a feature will automatically + remove this feature too. + +Usage: + agat_sp_filter_feature_from_kill_list.pl --gff infile.gff --kill_list file.txt [ --output outfile ] + agat_sp_filter_feature_from_kill_list.pl --help + +Options: + -f, --reffile, --gff or -ref + Input GFF3 file that will be read + + -p, --type or -l + primary tag option, case insensitive, list. Allow to specied the + feature types that will be handled. You can specified a specific + feature by given its primary tag name (column 3) as: cds, Gene, + MrNa You can specify directly all the feature of a particular + level: level2=mRNA,ncRNA,tRNA,etc level3=CDS,exon,UTR,etc By + default all feature are taking into account. fill the option by + the value "all" will have the same behaviour. + + --kl or --kill_list + Kill list. One value per line. + + -a or --attribute + Attribute tag to specify the attribute to analyse. Case + sensitive. Default: ID + + -o or --output + Output GFF file. If no output file is specified, the output will + be written to STDOUT. + + -v Verbose option for debugging purpose. + + -c or --config + String - Input agat config file. By default AGAT takes as input + agat_config.yaml file from the working directory if any, + otherwise it takes the orignal agat_config.yaml shipped with + AGAT. To get the agat_config.yaml locally type: "agat config + --expose". The --config option gives you the possibility to use + your own AGAT config file (located elsewhere or named + differently). + + -h or --help + Display this helpful text. + +Feedback: + Did you find a bug?: + Do not hesitate to report bugs to help us keep track of the bugs and + their resolution. Please use the GitHub issue tracking system available + at this address: + + https://github.com/NBISweden/AGAT/issues + + Ensure that the bug was not already reported by searching under Issues. + If you're unable to find an (open) issue addressing the problem, open a new one. + Try as much as possible to include in the issue when relevant: + - a clear description, + - as much relevant information as possible, + - the command used, + - a data sample, + - an explanation of the expected behaviour that is not occurring. + + Do you want to contribute?: + You are very welcome, visit this address for the Contributing + guidelines: + https://github.com/NBISweden/AGAT/blob/master/CONTRIBUTING.md \ No newline at end of file diff --git a/src/agat/agat_sp_filter_feature_from_kill_list/script.sh b/src/agat/agat_sp_filter_feature_from_kill_list/script.sh new file mode 100644 index 00000000..6779b857 --- /dev/null +++ b/src/agat/agat_sp_filter_feature_from_kill_list/script.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -eo pipefail + +## VIASH START +## VIASH END + +# unset flags +[[ "$par_verbose" == "false" ]] && unset par_verbose + +# convert par_type to comma separated list +par_type=$(echo $par_type | tr ';' ',') + +# run agat_sp_filter_feature_from_kill_list +agat_sp_filter_feature_from_kill_list.pl \ + --gff "$par_gff" \ + --kill_list "$par_kill_list" \ + --output "$par_output" \ + ${par_type:+--type "${par_type}"} \ + ${par_attribute:+--attribute "${par_attribute}"} \ + ${par_config:+--config "${par_config}"} \ + ${par_verbose:+-v} diff --git a/src/agat/agat_sp_filter_feature_from_kill_list/test.sh b/src/agat/agat_sp_filter_feature_from_kill_list/test.sh new file mode 100644 index 00000000..d9d775d5 --- /dev/null +++ b/src/agat/agat_sp_filter_feature_from_kill_list/test.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +set -eo pipefail + +## VIASH START +## VIASH END + +test_dir="${meta_resources_dir}/test_data" + +# create temporary directory and clean up on exit +TMPDIR=$(mktemp -d "$meta_temp_dir/$meta_functionality_name-XXXXXX") +function clean_up { + [[ -d "$TMPDIR" ]] && rm -rf "$TMPDIR" +} +#trap clean_up EXIT + +echo "> Run $meta_name with test data" +"$meta_executable" \ + --gff "$test_dir/1_truncated.gff" \ + --kill_list "$test_dir/kill_list.txt" \ + --output "$TMPDIR/output.gff" + +echo ">> Checking output" +[ ! -f "$TMPDIR/output.gff" ] && echo "Output file output.gff does not exist" && exit 1 + +echo ">> Check if output is empty" +[ ! -s "$TMPDIR/output.gff" ] && echo "Output file output.gff is empty" && exit 1 + +echo ">> Check if output matches expected output" +diff "$TMPDIR/output.gff" "$test_dir/test_output.gff" +if [ $? -ne 0 ]; then + echo "Output file output.gff does not match expected output" + exit 1 +fi + +echo "> Test successful" \ No newline at end of file diff --git a/src/agat/agat_sp_filter_feature_from_kill_list/test_data/1_truncated.gff b/src/agat/agat_sp_filter_feature_from_kill_list/test_data/1_truncated.gff new file mode 100644 index 00000000..e0fb6bce --- /dev/null +++ b/src/agat/agat_sp_filter_feature_from_kill_list/test_data/1_truncated.gff @@ -0,0 +1,123 @@ +##gff-version 3 +##sequence-region 1 1 43270923 +#!genome-build RAP-DB IRGSP-1.0 +#!genome-version IRGSP-1.0 +#!genome-date 2015-10 +#!genome-build-accession GCA_001433935.1 +1 RAP-DB chromosome 1 43270923 . . . ID=chromosome:1;Alias=Chr1,AP014957.1,NC_029256.1 +### +1 irgsp repeat_region 2000 2100 . + . ID=fakeRepeat1 +### +1 irgsp gene 2983 10815 . + . ID=gene:Os01g0100100;biotype=protein_coding;description=RabGAP/TBC domain containing protein. (Os01t0100100-01);gene_id=Os01g0100100;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 2983 10815 . + . ID=transcript:Os01t0100100-01;Parent=gene:Os01g0100100;biotype=protein_coding;transcript_id=Os01t0100100-01 +1 irgsp exon 2983 3268 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon1;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100100-01.exon1;rank=1 +1 irgsp five_prime_UTR 2983 3268 . + . Parent=transcript:Os01t0100100-01 +1 irgsp five_prime_UTR 3354 3448 . + . Parent=transcript:Os01t0100100-01 +1 irgsp exon 3354 3616 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon2;constitutive=1;ensembl_end_phase=0;ensembl_phase=-1;exon_id=Os01t0100100-01.exon2;rank=2 +1 irgsp CDS 3449 3616 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp exon 4357 4455 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon3;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Os01t0100100-01.exon3;rank=3 +1 irgsp CDS 4357 4455 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp exon 5457 5560 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon4;constitutive=1;ensembl_end_phase=2;ensembl_phase=0;exon_id=Os01t0100100-01.exon4;rank=4 +1 irgsp CDS 5457 5560 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp exon 7136 7944 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon5;constitutive=1;ensembl_end_phase=1;ensembl_phase=2;exon_id=Os01t0100100-01.exon5;rank=5 +1 irgsp CDS 7136 7944 . + 1 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp exon 8028 8150 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon6;constitutive=1;ensembl_end_phase=1;ensembl_phase=1;exon_id=Os01t0100100-01.exon6;rank=6 +1 irgsp CDS 8028 8150 . + 2 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp exon 8232 8320 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon7;constitutive=1;ensembl_end_phase=0;ensembl_phase=1;exon_id=Os01t0100100-01.exon7;rank=7 +1 irgsp CDS 8232 8320 . + 2 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp exon 8408 8608 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon8;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Os01t0100100-01.exon8;rank=8 +1 irgsp CDS 8408 8608 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp exon 9210 9615 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon9;constitutive=1;ensembl_end_phase=1;ensembl_phase=0;exon_id=Os01t0100100-01.exon9;rank=9 +1 irgsp CDS 9210 9615 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp exon 10102 10187 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon10;constitutive=1;ensembl_end_phase=0;ensembl_phase=1;exon_id=Os01t0100100-01.exon10;rank=10 +1 irgsp CDS 10102 10187 . + 2 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 10274 10297 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp exon 10274 10430 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon11;constitutive=1;ensembl_end_phase=-1;ensembl_phase=0;exon_id=Os01t0100100-01.exon11;rank=11 +1 irgsp three_prime_UTR 10298 10430 . + . Parent=transcript:Os01t0100100-01 +1 irgsp exon 10504 10815 . + . Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon12;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100100-01.exon12;rank=12 +1 irgsp three_prime_UTR 10504 10815 . + . Parent=transcript:Os01t0100100-01 +### +1 irgsp gene 11218 12435 . + . ID=gene:Os01g0100200;biotype=protein_coding;description=Conserved hypothetical protein. (Os01t0100200-01);gene_id=Os01g0100200;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 11218 12435 . + . ID=transcript:Os01t0100200-01;Parent=gene:Os01g0100200;biotype=protein_coding;transcript_id=Os01t0100200-01 +1 irgsp five_prime_UTR 11218 11797 . + . Parent=transcript:Os01t0100200-01 +1 irgsp exon 11218 12060 . + . Parent=transcript:Os01t0100200-01;Name=Os01t0100200-01.exon1;constitutive=1;ensembl_end_phase=2;ensembl_phase=-1;exon_id=Os01t0100200-01.exon1;rank=1 +1 irgsp CDS 11798 12060 . + 0 ID=CDS:Os01t0100200-01;Parent=transcript:Os01t0100200-01;protein_id=Os01t0100200-01 +1 irgsp CDS 12152 12317 . + 1 ID=CDS:Os01t0100200-01;Parent=transcript:Os01t0100200-01;protein_id=Os01t0100200-01 +1 irgsp exon 12152 12435 . + . Parent=transcript:Os01t0100200-01;Name=Os01t0100200-01.exon2;constitutive=1;ensembl_end_phase=-1;ensembl_phase=2;exon_id=Os01t0100200-01.exon2;rank=2 +1 irgsp three_prime_UTR 12318 12435 . + . Parent=transcript:Os01t0100200-01 +### +1 irgsp gene 11372 12284 . - . ID=gene:Os01g0100300;biotype=protein_coding;description=Cytochrome P450 domain containing protein. (Os01t0100300-00);gene_id=Os01g0100300;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 11372 12284 . - . ID=transcript:Os01t0100300-00;Parent=gene:Os01g0100300;biotype=protein_coding;transcript_id=Os01t0100300-00 +1 irgsp exon 11372 12042 . - . Parent=transcript:Os01t0100300-00;Name=Os01t0100300-00.exon2;constitutive=1;ensembl_end_phase=0;ensembl_phase=1;exon_id=Os01t0100300-00.exon2;rank=2 +1 irgsp CDS 11372 12042 . - 2 ID=CDS:Os01t0100300-00;Parent=transcript:Os01t0100300-00;protein_id=Os01t0100300-00 +1 irgsp exon 12146 12284 . - . Parent=transcript:Os01t0100300-00;Name=Os01t0100300-00.exon1;constitutive=1;ensembl_end_phase=1;ensembl_phase=0;exon_id=Os01t0100300-00.exon1;rank=1 +1 irgsp CDS 12146 12284 . - 0 ID=CDS:Os01t0100300-00;Parent=transcript:Os01t0100300-00;protein_id=Os01t0100300-00 +### +1 irgsp gene 12721 15685 . + . ID=gene:Os01g0100400;biotype=protein_coding;description=Similar to Pectinesterase-like protein. (Os01t0100400-01);gene_id=Os01g0100400;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 12721 15685 . + . ID=transcript:Os01t0100400-01;Parent=gene:Os01g0100400;biotype=protein_coding;transcript_id=Os01t0100400-01 +1 irgsp five_prime_UTR 12721 12773 . + . Parent=transcript:Os01t0100400-01 +1 irgsp exon 12721 13813 . + . Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon1;constitutive=1;ensembl_end_phase=2;ensembl_phase=-1;exon_id=Os01t0100400-01.exon1;rank=1 +1 irgsp CDS 12774 13813 . + 0 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp exon 13906 14271 . + . Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon2;constitutive=1;ensembl_end_phase=2;ensembl_phase=2;exon_id=Os01t0100400-01.exon2;rank=2 +1 irgsp CDS 13906 14271 . + 1 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp exon 14359 14437 . + . Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon3;constitutive=1;ensembl_end_phase=0;ensembl_phase=2;exon_id=Os01t0100400-01.exon3;rank=3 +1 irgsp CDS 14359 14437 . + 1 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp exon 14969 15171 . + . Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon4;constitutive=1;ensembl_end_phase=2;ensembl_phase=0;exon_id=Os01t0100400-01.exon4;rank=4 +1 irgsp CDS 14969 15171 . + 0 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp CDS 15266 15359 . + 1 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp exon 15266 15685 . + . Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon5;constitutive=1;ensembl_end_phase=-1;ensembl_phase=2;exon_id=Os01t0100400-01.exon5;rank=5 +1 irgsp three_prime_UTR 15360 15685 . + . Parent=transcript:Os01t0100400-01 +### +1 irgsp gene 12808 13978 . - . ID=gene:Os01g0100466;biotype=protein_coding;description=Hypothetical protein. (Os01t0100466-00);gene_id=Os01g0100466;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 12808 13978 . - . ID=transcript:Os01t0100466-00;Parent=gene:Os01g0100466;biotype=protein_coding;transcript_id=Os01t0100466-00 +1 irgsp three_prime_UTR 12808 12868 . - . Parent=transcript:Os01t0100466-00 +1 irgsp exon 12808 13782 . - . Parent=transcript:Os01t0100466-00;Name=Os01t0100466-00.exon2;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100466-00.exon2;rank=2 +1 irgsp CDS 12869 13102 . - 0 ID=CDS:Os01t0100466-00;Parent=transcript:Os01t0100466-00;protein_id=Os01t0100466-00 +1 irgsp five_prime_UTR 13103 13782 . - . Parent=transcript:Os01t0100466-00 +1 irgsp exon 13880 13978 . - . Parent=transcript:Os01t0100466-00;Name=Os01t0100466-00.exon1;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100466-00.exon1;rank=1 +1 irgsp five_prime_UTR 13880 13978 . - . Parent=transcript:Os01t0100466-00 +### +1 irgsp gene 16399 20144 . + . ID=gene:Os01g0100500;biotype=protein_coding;description=Immunoglobulin-like domain containing protein. (Os01t0100500-01);gene_id=Os01g0100500;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 16399 20144 . + . ID=transcript:Os01t0100500-01;Parent=gene:Os01g0100500;biotype=protein_coding;transcript_id=Os01t0100500-01 +1 irgsp five_prime_UTR 16399 16598 . + . Parent=transcript:Os01t0100500-01 +1 irgsp exon 16399 16976 . + . Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon1;constitutive=1;ensembl_end_phase=0;ensembl_phase=-1;exon_id=Os01t0100500-01.exon1;rank=1 +1 irgsp CDS 16599 16976 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp exon 17383 17474 . + . Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon2;constitutive=1;ensembl_end_phase=2;ensembl_phase=0;exon_id=Os01t0100500-01.exon2;rank=2 +1 irgsp CDS 17383 17474 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp exon 17558 18258 . + . Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon3;constitutive=1;ensembl_end_phase=1;ensembl_phase=2;exon_id=Os01t0100500-01.exon3;rank=3 +1 irgsp CDS 17558 18258 . + 1 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp exon 18501 18571 . + . Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon4;constitutive=1;ensembl_end_phase=0;ensembl_phase=1;exon_id=Os01t0100500-01.exon4;rank=4 +1 irgsp CDS 18501 18571 . + 2 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp exon 18968 19057 . + . Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon5;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Os01t0100500-01.exon5;rank=5 +1 irgsp CDS 18968 19057 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp exon 19142 19321 . + . Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon6;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Os01t0100500-01.exon6;rank=6 +1 irgsp CDS 19142 19321 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp CDS 19531 19593 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp exon 19531 19629 . + . Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon7;constitutive=1;ensembl_end_phase=-1;ensembl_phase=0;exon_id=Os01t0100500-01.exon7;rank=7 +1 irgsp three_prime_UTR 19594 19629 . + . Parent=transcript:Os01t0100500-01 +1 irgsp exon 19734 20144 . + . Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon8;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100500-01.exon8;rank=8 +1 irgsp three_prime_UTR 19734 20144 . + . Parent=transcript:Os01t0100500-01 +### +1 irgsp gene 22841 26892 . + . ID=gene:Os01g0100600;biotype=protein_coding;description=Single-stranded nucleic acid binding R3H domain containing protein. (Os01t0100600-01);gene_id=Os01g0100600;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 22841 26892 . + . ID=transcript:Os01t0100600-01;Parent=gene:Os01g0100600;biotype=protein_coding;transcript_id=Os01t0100600-01 +1 irgsp five_prime_UTR 22841 23231 . + . Parent=transcript:Os01t0100600-01 +1 irgsp exon 22841 23281 . + . Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon1;constitutive=1;ensembl_end_phase=2;ensembl_phase=-1;exon_id=Os01t0100600-01.exon1;rank=1 +1 irgsp CDS 23232 23281 . + 0 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp exon 23572 23847 . + . Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon2;constitutive=1;ensembl_end_phase=2;ensembl_phase=2;exon_id=Os01t0100600-01.exon2;rank=2 +1 irgsp CDS 23572 23847 . + 1 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp exon 23962 24033 . + . Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon3;constitutive=1;ensembl_end_phase=2;ensembl_phase=2;exon_id=Os01t0100600-01.exon3;rank=3 +1 irgsp CDS 23962 24033 . + 1 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp exon 24492 24577 . + . Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon4;constitutive=1;ensembl_end_phase=1;ensembl_phase=2;exon_id=Os01t0100600-01.exon4;rank=4 +1 irgsp CDS 24492 24577 . + 1 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp exon 25445 25519 . + . Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon5;constitutive=1;ensembl_end_phase=1;ensembl_phase=1;exon_id=Os01t0100600-01.exon5;rank=5 +1 irgsp CDS 25445 25519 . + 2 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp CDS 25883 26391 . + 2 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp exon 25883 26892 . + . Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon6;constitutive=1;ensembl_end_phase=-1;ensembl_phase=1;exon_id=Os01t0100600-01.exon6;rank=6 +1 irgsp three_prime_UTR 26392 26892 . + . Parent=transcript:Os01t0100600-01 +### +1 irgsp gene 25861 26424 . - . ID=gene:Os01g0100650;biotype=protein_coding;description=Hypothetical gene. (Os01t0100650-00);gene_id=Os01g0100650;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 25861 26424 . - . ID=transcript:Os01t0100650-00;Parent=gene:Os01g0100650;biotype=protein_coding;transcript_id=Os01t0100650-00 +1 irgsp three_prime_UTR 25861 26039 . - . Parent=transcript:Os01t0100650-00 +1 irgsp exon 25861 26424 . - . Parent=transcript:Os01t0100650-00;Name=Os01t0100650-00.exon1;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100650-00.exon1;rank=1 +1 irgsp CDS 26040 26423 . - 0 ID=CDS:Os01t0100650-00;Parent=transcript:Os01t0100650-00;protein_id=Os01t0100650-00 +1 irgsp five_prime_UTR 26424 26424 . - . Parent=transcript:Os01t0100650-00 diff --git a/src/agat/agat_sp_filter_feature_from_kill_list/test_data/kill_list.txt b/src/agat/agat_sp_filter_feature_from_kill_list/test_data/kill_list.txt new file mode 100644 index 00000000..a9d72f89 --- /dev/null +++ b/src/agat/agat_sp_filter_feature_from_kill_list/test_data/kill_list.txt @@ -0,0 +1,3 @@ +gene:Os01g0100700 +CDS:Os01t0100650-00 +transcript:Os01t0102700-01 diff --git a/src/agat/agat_sp_filter_feature_from_kill_list/test_data/script.sh b/src/agat/agat_sp_filter_feature_from_kill_list/test_data/script.sh new file mode 100755 index 00000000..6f9d1584 --- /dev/null +++ b/src/agat/agat_sp_filter_feature_from_kill_list/test_data/script.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# clone repo +if [ ! -d /tmp/agat_source ]; then + git clone --depth 1 --single-branch --branch master https://github.com/NBISweden/AGAT /tmp/agat_source +fi + +# copy test data +cp -r /tmp/agat_source/t/scripts_output/in/1.gff src/agat/agat_sp_filter_feature_from_kill_list/test_data +cp -r /tmp/agat_source/t/scripts_output/out/agat_sp_filter_feature_from_kill_list_1.gff src/agat/agat_sp_filter_feature_from_kill_list/test_data +cp -r /tmp/agat_source/t/scripts_output/in/kill_list.txt src/agat/agat_sp_filter_feature_from_kill_list/test_data + +head -n 123 src/agat/agat_sp_filter_feature_from_kill_list/test_data/1.gff > src/agat/agat_sp_filter_feature_from_kill_list/test_data/1_truncated.gff \ No newline at end of file diff --git a/src/agat/agat_sp_filter_feature_from_kill_list/test_data/test_output.gff b/src/agat/agat_sp_filter_feature_from_kill_list/test_data/test_output.gff new file mode 100644 index 00000000..47838fe7 --- /dev/null +++ b/src/agat/agat_sp_filter_feature_from_kill_list/test_data/test_output.gff @@ -0,0 +1,113 @@ +##gff-version 3 +##sequence-region 1 1 43270923 +#!genome-build RAP-DB IRGSP-1.0 +#!genome-version IRGSP-1.0 +#!genome-date 2015-10 +#!genome-build-accession GCA_001433935.1 +1 RAP-DB chromosome 1 43270923 . . . ID=chromosome:1;Alias=Chr1,AP014957.1,NC_029256.1 +1 irgsp repeat_region 2000 2100 . + . ID=fakeRepeat1 +1 irgsp gene 2983 10815 . + . ID=gene:Os01g0100100;biotype=protein_coding;description=RabGAP/TBC domain containing protein. (Os01t0100100-01);gene_id=Os01g0100100;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 2983 10815 . + . ID=transcript:Os01t0100100-01;Parent=gene:Os01g0100100;biotype=protein_coding;transcript_id=Os01t0100100-01 +1 irgsp exon 2983 3268 . + . ID=Os01t0100100-01.exon1;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon1;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100100-01.exon1;rank=1 +1 irgsp exon 3354 3616 . + . ID=Os01t0100100-01.exon2;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon2;constitutive=1;ensembl_end_phase=0;ensembl_phase=-1;exon_id=Os01t0100100-01.exon2;rank=2 +1 irgsp exon 4357 4455 . + . ID=Os01t0100100-01.exon3;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon3;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Os01t0100100-01.exon3;rank=3 +1 irgsp exon 5457 5560 . + . ID=Os01t0100100-01.exon4;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon4;constitutive=1;ensembl_end_phase=2;ensembl_phase=0;exon_id=Os01t0100100-01.exon4;rank=4 +1 irgsp exon 7136 7944 . + . ID=Os01t0100100-01.exon5;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon5;constitutive=1;ensembl_end_phase=1;ensembl_phase=2;exon_id=Os01t0100100-01.exon5;rank=5 +1 irgsp exon 8028 8150 . + . ID=Os01t0100100-01.exon6;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon6;constitutive=1;ensembl_end_phase=1;ensembl_phase=1;exon_id=Os01t0100100-01.exon6;rank=6 +1 irgsp exon 8232 8320 . + . ID=Os01t0100100-01.exon7;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon7;constitutive=1;ensembl_end_phase=0;ensembl_phase=1;exon_id=Os01t0100100-01.exon7;rank=7 +1 irgsp exon 8408 8608 . + . ID=Os01t0100100-01.exon8;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon8;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Os01t0100100-01.exon8;rank=8 +1 irgsp exon 9210 9615 . + . ID=Os01t0100100-01.exon9;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon9;constitutive=1;ensembl_end_phase=1;ensembl_phase=0;exon_id=Os01t0100100-01.exon9;rank=9 +1 irgsp exon 10102 10187 . + . ID=Os01t0100100-01.exon10;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon10;constitutive=1;ensembl_end_phase=0;ensembl_phase=1;exon_id=Os01t0100100-01.exon10;rank=10 +1 irgsp exon 10274 10430 . + . ID=Os01t0100100-01.exon11;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon11;constitutive=1;ensembl_end_phase=-1;ensembl_phase=0;exon_id=Os01t0100100-01.exon11;rank=11 +1 irgsp exon 10504 10815 . + . ID=Os01t0100100-01.exon12;Parent=transcript:Os01t0100100-01;Name=Os01t0100100-01.exon12;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100100-01.exon12;rank=12 +1 irgsp CDS 3449 3616 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 4357 4455 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 5457 5560 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 7136 7944 . + 1 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 8028 8150 . + 2 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 8232 8320 . + 2 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 8408 8608 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 9210 9615 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 10102 10187 . + 2 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp CDS 10274 10297 . + 0 ID=CDS:Os01t0100100-01;Parent=transcript:Os01t0100100-01;protein_id=Os01t0100100-01 +1 irgsp five_prime_UTR 2983 3268 . + . ID=agat-five_prime_utr-1;Parent=transcript:Os01t0100100-01 +1 irgsp five_prime_UTR 3354 3448 . + . ID=agat-five_prime_utr-2;Parent=transcript:Os01t0100100-01 +1 irgsp three_prime_UTR 10298 10430 . + . ID=agat-three_prime_utr-1;Parent=transcript:Os01t0100100-01 +1 irgsp three_prime_UTR 10504 10815 . + . ID=agat-three_prime_utr-2;Parent=transcript:Os01t0100100-01 +1 irgsp gene 11218 12435 . + . ID=gene:Os01g0100200;biotype=protein_coding;description=Conserved hypothetical protein. (Os01t0100200-01);gene_id=Os01g0100200;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 11218 12435 . + . ID=transcript:Os01t0100200-01;Parent=gene:Os01g0100200;biotype=protein_coding;transcript_id=Os01t0100200-01 +1 irgsp exon 11218 12060 . + . ID=Os01t0100200-01.exon1;Parent=transcript:Os01t0100200-01;Name=Os01t0100200-01.exon1;constitutive=1;ensembl_end_phase=2;ensembl_phase=-1;exon_id=Os01t0100200-01.exon1;rank=1 +1 irgsp exon 12152 12435 . + . ID=Os01t0100200-01.exon2;Parent=transcript:Os01t0100200-01;Name=Os01t0100200-01.exon2;constitutive=1;ensembl_end_phase=-1;ensembl_phase=2;exon_id=Os01t0100200-01.exon2;rank=2 +1 irgsp CDS 11798 12060 . + 0 ID=CDS:Os01t0100200-01;Parent=transcript:Os01t0100200-01;protein_id=Os01t0100200-01 +1 irgsp CDS 12152 12317 . + 1 ID=CDS:Os01t0100200-01;Parent=transcript:Os01t0100200-01;protein_id=Os01t0100200-01 +1 irgsp five_prime_UTR 11218 11797 . + . ID=agat-five_prime_utr-3;Parent=transcript:Os01t0100200-01 +1 irgsp three_prime_UTR 12318 12435 . + . ID=agat-three_prime_utr-3;Parent=transcript:Os01t0100200-01 +1 irgsp gene 11372 12284 . - . ID=gene:Os01g0100300;biotype=protein_coding;description=Cytochrome P450 domain containing protein. (Os01t0100300-00);gene_id=Os01g0100300;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 11372 12284 . - . ID=transcript:Os01t0100300-00;Parent=gene:Os01g0100300;biotype=protein_coding;transcript_id=Os01t0100300-00 +1 irgsp exon 11372 12042 . - . ID=Os01t0100300-00.exon2;Parent=transcript:Os01t0100300-00;Name=Os01t0100300-00.exon2;constitutive=1;ensembl_end_phase=0;ensembl_phase=1;exon_id=Os01t0100300-00.exon2;rank=2 +1 irgsp exon 12146 12284 . - . ID=Os01t0100300-00.exon1;Parent=transcript:Os01t0100300-00;Name=Os01t0100300-00.exon1;constitutive=1;ensembl_end_phase=1;ensembl_phase=0;exon_id=Os01t0100300-00.exon1;rank=1 +1 irgsp CDS 11372 12042 . - 2 ID=CDS:Os01t0100300-00;Parent=transcript:Os01t0100300-00;protein_id=Os01t0100300-00 +1 irgsp CDS 12146 12284 . - 0 ID=CDS:Os01t0100300-00;Parent=transcript:Os01t0100300-00;protein_id=Os01t0100300-00 +1 irgsp gene 12721 15685 . + . ID=gene:Os01g0100400;biotype=protein_coding;description=Similar to Pectinesterase-like protein. (Os01t0100400-01);gene_id=Os01g0100400;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 12721 15685 . + . ID=transcript:Os01t0100400-01;Parent=gene:Os01g0100400;biotype=protein_coding;transcript_id=Os01t0100400-01 +1 irgsp exon 12721 13813 . + . ID=Os01t0100400-01.exon1;Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon1;constitutive=1;ensembl_end_phase=2;ensembl_phase=-1;exon_id=Os01t0100400-01.exon1;rank=1 +1 irgsp exon 13906 14271 . + . ID=Os01t0100400-01.exon2;Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon2;constitutive=1;ensembl_end_phase=2;ensembl_phase=2;exon_id=Os01t0100400-01.exon2;rank=2 +1 irgsp exon 14359 14437 . + . ID=Os01t0100400-01.exon3;Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon3;constitutive=1;ensembl_end_phase=0;ensembl_phase=2;exon_id=Os01t0100400-01.exon3;rank=3 +1 irgsp exon 14969 15171 . + . ID=Os01t0100400-01.exon4;Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon4;constitutive=1;ensembl_end_phase=2;ensembl_phase=0;exon_id=Os01t0100400-01.exon4;rank=4 +1 irgsp exon 15266 15685 . + . ID=Os01t0100400-01.exon5;Parent=transcript:Os01t0100400-01;Name=Os01t0100400-01.exon5;constitutive=1;ensembl_end_phase=-1;ensembl_phase=2;exon_id=Os01t0100400-01.exon5;rank=5 +1 irgsp CDS 12774 13813 . + 0 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp CDS 13906 14271 . + 1 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp CDS 14359 14437 . + 1 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp CDS 14969 15171 . + 0 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp CDS 15266 15359 . + 1 ID=CDS:Os01t0100400-01;Parent=transcript:Os01t0100400-01;protein_id=Os01t0100400-01 +1 irgsp five_prime_UTR 12721 12773 . + . ID=agat-five_prime_utr-4;Parent=transcript:Os01t0100400-01 +1 irgsp three_prime_UTR 15360 15685 . + . ID=agat-three_prime_utr-4;Parent=transcript:Os01t0100400-01 +1 irgsp gene 12808 13978 . - . ID=gene:Os01g0100466;biotype=protein_coding;description=Hypothetical protein. (Os01t0100466-00);gene_id=Os01g0100466;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 12808 13978 . - . ID=transcript:Os01t0100466-00;Parent=gene:Os01g0100466;biotype=protein_coding;transcript_id=Os01t0100466-00 +1 irgsp exon 12808 13782 . - . ID=Os01t0100466-00.exon2;Parent=transcript:Os01t0100466-00;Name=Os01t0100466-00.exon2;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100466-00.exon2;rank=2 +1 irgsp exon 13880 13978 . - . ID=Os01t0100466-00.exon1;Parent=transcript:Os01t0100466-00;Name=Os01t0100466-00.exon1;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100466-00.exon1;rank=1 +1 irgsp CDS 12869 13102 . - 0 ID=CDS:Os01t0100466-00;Parent=transcript:Os01t0100466-00;protein_id=Os01t0100466-00 +1 irgsp five_prime_UTR 13103 13782 . - . ID=agat-five_prime_utr-5;Parent=transcript:Os01t0100466-00 +1 irgsp five_prime_UTR 13880 13978 . - . ID=agat-five_prime_utr-6;Parent=transcript:Os01t0100466-00 +1 irgsp three_prime_UTR 12808 12868 . - . ID=agat-three_prime_utr-5;Parent=transcript:Os01t0100466-00 +1 irgsp gene 16399 20144 . + . ID=gene:Os01g0100500;biotype=protein_coding;description=Immunoglobulin-like domain containing protein. (Os01t0100500-01);gene_id=Os01g0100500;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 16399 20144 . + . ID=transcript:Os01t0100500-01;Parent=gene:Os01g0100500;biotype=protein_coding;transcript_id=Os01t0100500-01 +1 irgsp exon 16399 16976 . + . ID=Os01t0100500-01.exon1;Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon1;constitutive=1;ensembl_end_phase=0;ensembl_phase=-1;exon_id=Os01t0100500-01.exon1;rank=1 +1 irgsp exon 17383 17474 . + . ID=Os01t0100500-01.exon2;Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon2;constitutive=1;ensembl_end_phase=2;ensembl_phase=0;exon_id=Os01t0100500-01.exon2;rank=2 +1 irgsp exon 17558 18258 . + . ID=Os01t0100500-01.exon3;Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon3;constitutive=1;ensembl_end_phase=1;ensembl_phase=2;exon_id=Os01t0100500-01.exon3;rank=3 +1 irgsp exon 18501 18571 . + . ID=Os01t0100500-01.exon4;Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon4;constitutive=1;ensembl_end_phase=0;ensembl_phase=1;exon_id=Os01t0100500-01.exon4;rank=4 +1 irgsp exon 18968 19057 . + . ID=Os01t0100500-01.exon5;Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon5;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Os01t0100500-01.exon5;rank=5 +1 irgsp exon 19142 19321 . + . ID=Os01t0100500-01.exon6;Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon6;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Os01t0100500-01.exon6;rank=6 +1 irgsp exon 19531 19629 . + . ID=Os01t0100500-01.exon7;Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon7;constitutive=1;ensembl_end_phase=-1;ensembl_phase=0;exon_id=Os01t0100500-01.exon7;rank=7 +1 irgsp exon 19734 20144 . + . ID=Os01t0100500-01.exon8;Parent=transcript:Os01t0100500-01;Name=Os01t0100500-01.exon8;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100500-01.exon8;rank=8 +1 irgsp CDS 16599 16976 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp CDS 17383 17474 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp CDS 17558 18258 . + 1 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp CDS 18501 18571 . + 2 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp CDS 18968 19057 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp CDS 19142 19321 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp CDS 19531 19593 . + 0 ID=CDS:Os01t0100500-01;Parent=transcript:Os01t0100500-01;protein_id=Os01t0100500-01 +1 irgsp five_prime_UTR 16399 16598 . + . ID=agat-five_prime_utr-7;Parent=transcript:Os01t0100500-01 +1 irgsp three_prime_UTR 19594 19629 . + . ID=agat-three_prime_utr-6;Parent=transcript:Os01t0100500-01 +1 irgsp three_prime_UTR 19734 20144 . + . ID=agat-three_prime_utr-7;Parent=transcript:Os01t0100500-01 +1 irgsp gene 22841 26892 . + . ID=gene:Os01g0100600;biotype=protein_coding;description=Single-stranded nucleic acid binding R3H domain containing protein. (Os01t0100600-01);gene_id=Os01g0100600;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 22841 26892 . + . ID=transcript:Os01t0100600-01;Parent=gene:Os01g0100600;biotype=protein_coding;transcript_id=Os01t0100600-01 +1 irgsp exon 22841 23281 . + . ID=Os01t0100600-01.exon1;Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon1;constitutive=1;ensembl_end_phase=2;ensembl_phase=-1;exon_id=Os01t0100600-01.exon1;rank=1 +1 irgsp exon 23572 23847 . + . ID=Os01t0100600-01.exon2;Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon2;constitutive=1;ensembl_end_phase=2;ensembl_phase=2;exon_id=Os01t0100600-01.exon2;rank=2 +1 irgsp exon 23962 24033 . + . ID=Os01t0100600-01.exon3;Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon3;constitutive=1;ensembl_end_phase=2;ensembl_phase=2;exon_id=Os01t0100600-01.exon3;rank=3 +1 irgsp exon 24492 24577 . + . ID=Os01t0100600-01.exon4;Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon4;constitutive=1;ensembl_end_phase=1;ensembl_phase=2;exon_id=Os01t0100600-01.exon4;rank=4 +1 irgsp exon 25445 25519 . + . ID=Os01t0100600-01.exon5;Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon5;constitutive=1;ensembl_end_phase=1;ensembl_phase=1;exon_id=Os01t0100600-01.exon5;rank=5 +1 irgsp exon 25883 26892 . + . ID=Os01t0100600-01.exon6;Parent=transcript:Os01t0100600-01;Name=Os01t0100600-01.exon6;constitutive=1;ensembl_end_phase=-1;ensembl_phase=1;exon_id=Os01t0100600-01.exon6;rank=6 +1 irgsp CDS 23232 23281 . + 0 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp CDS 23572 23847 . + 1 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp CDS 23962 24033 . + 1 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp CDS 24492 24577 . + 1 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp CDS 25445 25519 . + 2 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp CDS 25883 26391 . + 2 ID=CDS:Os01t0100600-01;Parent=transcript:Os01t0100600-01;protein_id=Os01t0100600-01 +1 irgsp five_prime_UTR 22841 23231 . + . ID=agat-five_prime_utr-8;Parent=transcript:Os01t0100600-01 +1 irgsp three_prime_UTR 26392 26892 . + . ID=agat-three_prime_utr-8;Parent=transcript:Os01t0100600-01 +1 irgsp gene 25861 26424 . - . ID=gene:Os01g0100650;biotype=protein_coding;description=Hypothetical gene. (Os01t0100650-00);gene_id=Os01g0100650;logic_name=irgspv1.0-20170804-genes +1 irgsp mRNA 25861 26424 . - . ID=transcript:Os01t0100650-00;Parent=gene:Os01g0100650;biotype=protein_coding;transcript_id=Os01t0100650-00 +1 irgsp exon 25861 26424 . - . ID=Os01t0100650-00.exon1;Parent=transcript:Os01t0100650-00;Name=Os01t0100650-00.exon1;constitutive=1;ensembl_end_phase=-1;ensembl_phase=-1;exon_id=Os01t0100650-00.exon1;rank=1 +1 irgsp five_prime_UTR 26424 26424 . - . ID=agat-five_prime_utr-9;Parent=transcript:Os01t0100650-00 +1 irgsp three_prime_UTR 25861 26039 . - . ID=agat-three_prime_utr-9;Parent=transcript:Os01t0100650-00 diff --git a/src/agat/agat_sp_merge_annotations/config.vsh.yaml b/src/agat/agat_sp_merge_annotations/config.vsh.yaml new file mode 100644 index 00000000..bc47921a --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/config.vsh.yaml @@ -0,0 +1,67 @@ +name: agat_sp_merge_annotations +namespace: agat +description: | + Merge different gff annotation files into one. It uses the AGAT parser that takes care of + duplicated names and fixes other oddities met in those files. +keywords: [gene annotations, merge, gff] +links: + homepage: https://github.com/NBISweden/AGAT + documentation: https://agat.readthedocs.io/en/latest/tools/agat_sp_merge_annotations.html + issue_tracker: https://github.com/NBISweden/AGAT/issues + repository: https://github.com/NBISweden/AGAT +references: + doi: 10.5281/zenodo.3552717 +license: GPL-3.0 +requirements: + commands: [agat] +authors: + - __merge__: /src/_authors/leila_paquay.yaml + roles: [ author, maintainer ] +argument_groups: + - name: Inputs + arguments: + - name: --gff + alternatives: [-f] + description: | + Input GTF/GFF file(s). + type: file + multiple: true + required: true + example: input1.gff;input2.gff + - name: Outputs + arguments: + - name: --output + alternatives: [-o, --out] + description: Output gff3 file where the gene incriminated will be writen. + type: file + direction: output + required: true + example: output.gff + - name: Arguments + arguments: + - name: --config + alternatives: [-c] + description: | + AGAT config file. By default AGAT takes the original agat_config.yaml shipped with AGAT. + The `--config` option gives you the possibility to use your own AGAT config file (located + elsewhere or named differently). + type: file + example: custom_agat_config.yaml +resources: + - type: bash_script + path: script.sh +test_resources: + - type: bash_script + path: test.sh + - type: file + path: test_data +engines: + - type: docker + image: quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0 + setup: + - type: docker + run: | + agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.txt +runners: + - type: executable + - type: nextflow \ No newline at end of file diff --git a/src/agat/agat_sp_merge_annotations/help.txt b/src/agat/agat_sp_merge_annotations/help.txt new file mode 100644 index 00000000..2a17e7e4 --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/help.txt @@ -0,0 +1,64 @@ +```sh +agat_sp_merge_annotations.pl --help +``` + + ------------------------------------------------------------------------------ +| Another GFF Analysis Toolkit (AGAT) - Version: v1.4.0 | +| https://github.com/NBISweden/AGAT | +| National Bioinformatics Infrastructure Sweden (NBIS) - www.nbis.se | + ------------------------------------------------------------------------------ + + +Name: + agat_sp_merge_annotations.pl + +Description: + This script merge different gff annotation files in one. It uses the + AGAT parser that takes care of duplicated names and fixes other oddities + met in those files. + +Usage: + agat_sp_merge_annotations.pl --gff infile1 --gff infile2 --out outFile + agat_sp_merge_annotations.pl --help + +Options: + --gff or -f + Input GTF/GFF file(s). You can specify as much file you want + like so: -f file1 -f file2 -f file3 + + --out, --output or -o + Output gff3 file where the gene incriminated will be write. + + -c or --config + String - Input agat config file. By default AGAT takes as input + agat_config.yaml file from the working directory if any, + otherwise it takes the orignal agat_config.yaml shipped with + AGAT. To get the agat_config.yaml locally type: "agat config + --expose". The --config option gives you the possibility to use + your own AGAT config file (located elsewhere or named + differently). + + --help or -h + Display this helpful text. + +Feedback: + Did you find a bug?: + Do not hesitate to report bugs to help us keep track of the bugs and + their resolution. Please use the GitHub issue tracking system available + at this address: + + https://github.com/NBISweden/AGAT/issues + + Ensure that the bug was not already reported by searching under Issues. + If you're unable to find an (open) issue addressing the problem, open a new one. + Try as much as possible to include in the issue when relevant: + - a clear description, + - as much relevant information as possible, + - the command used, + - a data sample, + - an explanation of the expected behaviour that is not occurring. + + Do you want to contribute?: + You are very welcome, visit this address for the Contributing + guidelines: + https://github.com/NBISweden/AGAT/blob/master/CONTRIBUTING.md diff --git a/src/agat/agat_sp_merge_annotations/script.sh b/src/agat/agat_sp_merge_annotations/script.sh new file mode 100644 index 00000000..5703745a --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/script.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -eo pipefail + +## VIASH START +## VIASH END + +# Convert a list of file names to multiple -gff arguments +input_files="" +IFS=";" read -ra file_names <<< "$par_gff" +for file in "${file_names[@]}"; do + input_files+="--gff $file " +done + +# run agat_sp_merge_annotations +agat_sp_merge_annotations.pl \ + $input_files \ + -o "$par_output" \ + ${par_config:+--config "${par_config}"} diff --git a/src/agat/agat_sp_merge_annotations/test.sh b/src/agat/agat_sp_merge_annotations/test.sh new file mode 100644 index 00000000..7b882717 --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/test.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +set -eo pipefail + +## VIASH START +## VIASH END + +test_dir="${meta_resources_dir}/test_data" + +# create temporary directory and clean up on exit +TMPDIR=$(mktemp -d "$meta_temp_dir/$meta_functionality_name-XXXXXX") +function clean_up { + [[ -d "$TMPDIR" ]] && rm -rf "$TMPDIR" +} +trap clean_up EXIT + +echo "> Run $meta_name with test data 1" +"$meta_executable" \ + --gff "$test_dir/file1.gff;$test_dir/file2.gff" \ + --output "$TMPDIR/output.gff" + +echo ">> Checking output" +[ ! -f "$TMPDIR/output.gff" ] && echo "Output file output.gff does not exist" && exit 1 + +echo ">> Check if output is empty" +[ ! -s "$TMPDIR/output.gff" ] && echo "Output file output.gff is empty" && exit 1 + +echo ">> Check if output matches expected output" +diff "$TMPDIR/output.gff" "$test_dir/agat_sp_merge_annotations_1.gff" +if [ $? -ne 0 ]; then + echo "Output file output.gff does not match expected output" + exit 1 +fi + +echo ">> cleanup" +rm -rf "$TMPDIR/output.gff" + +echo "> Run $meta_name with test data 2" +"$meta_executable" \ + --gff "$test_dir/fileA.gff;$test_dir/fileB.gff" \ + --output "$TMPDIR/output.gff" + +echo ">> Checking output" +[ ! -f "$TMPDIR/output.gff" ] && echo "Output file output.gff does not exist" && exit 1 + +echo ">> Check if output is empty" +[ ! -s "$TMPDIR/output.gff" ] && echo "Output file output.gff is empty" && exit 1 + +echo ">> Check if output matches expected output" +diff "$TMPDIR/output.gff" "$test_dir/agat_sp_merge_annotations_2.gff" +if [ $? -ne 0 ]; then + echo "Output file output.gff does not match expected output" + exit 1 +fi + +echo "> Test successful" \ No newline at end of file diff --git a/src/agat/agat_sp_merge_annotations/test_data/agat_sp_merge_annotations_1.gff b/src/agat/agat_sp_merge_annotations/test_data/agat_sp_merge_annotations_1.gff new file mode 100644 index 00000000..5f68f1f3 --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/test_data/agat_sp_merge_annotations_1.gff @@ -0,0 +1,13 @@ +##gff-version 3 +chr10 BestRefSeq gene 123237824 123357992 . - . ID=gene-FGFR2;ontology=G0222 +chr10 BestRefSeq mRNA 123237824 123357992 . - . ID=rna-NM_022970.3;Parent=gene-FGFR2;ontology=G0222;merged_ID=IDmodified-mrna-1;merged_Ontology=G0333;merged_Parent=IDmodified-gene-1 +chr10 BestRefSeq exon 123237824 123239535 . - . ID=exon-NM_022970.3-18;Parent=rna-NM_022970.3 +chr10 BestRefSeq exon 123243212 123243317 . - . ID=exon-NM_022970.3-17;Parent=rna-NM_022970.3 +chr10 BestRefSeq exon 123353223 123353481 . - . ID=exon-NM_022970.3-2;Parent=rna-NM_022970.3 +chr10 BestRefSeq exon 123357476 123357992 . - . ID=exon-NM_022970.3-1;Parent=rna-NM_022970.3 +chr10 BestRefSeq CDS 123239371 123239535 . - 0 ID=cds-NP_075259.4;Parent=rna-NM_022970.3 +chr10 BestRefSeq CDS 123243212 123243317 . - 1 ID=cds-NP_075259.4;Parent=rna-NM_022970.3 +chr10 BestRefSeq CDS 123353223 123353331 . - 0 ID=cds-NP_075259.4;Parent=rna-NM_022970.3 +chr10 BestRefSeq five_prime_UTR 123353332 123353481 . - . ID=agat-five_prime_utr-54403;Parent=rna-NM_022970.3 +chr10 BestRefSeq five_prime_UTR 123357476 123357992 . - . ID=agat-five_prime_utr-54403;Parent=rna-NM_022970.3 +chr10 BestRefSeq three_prime_UTR 123237824 123239370 . - . ID=agat-three_prime_utr-54427;Parent=rna-NM_022970.3 diff --git a/src/agat/agat_sp_merge_annotations/test_data/agat_sp_merge_annotations_2.gff b/src/agat/agat_sp_merge_annotations/test_data/agat_sp_merge_annotations_2.gff new file mode 100644 index 00000000..1c3846b2 --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/test_data/agat_sp_merge_annotations_2.gff @@ -0,0 +1,3 @@ +##gff-version 3 +chr1 AUGUSTUS gene 1000424 1039237 . + . ID=A +chr1 AUGUSTUS mRNA 1000424 1039237 . + . ID=A.t1;Parent=A;merged_ID=B.t1;merged_Parent=B diff --git a/src/agat/agat_sp_merge_annotations/test_data/file1.gff b/src/agat/agat_sp_merge_annotations/test_data/file1.gff new file mode 100644 index 00000000..d822ebfa --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/test_data/file1.gff @@ -0,0 +1,14 @@ +chr10 BestRefSeq gene 123237824 123357992 . - . ID=gene-FGFR2;Ontology=G0222; +chr10 BestRefSeq mRNA 123237824 123357992 . - . ID=rna-NM_022970.3;Parent=gene-FGFR2;Ontology=G0222; +chr10 BestRefSeq exon 123237824 123239535 . - . ID=exon-NM_022970.3-18;Parent=rna-NM_022970.3; +chr10 BestRefSeq exon 123243212 123243317 . - . ID=exon-NM_022970.3-17;Parent=rna-NM_022970.3; +chr10 BestRefSeq exon 123353223 123353481 . - . ID=exon-NM_022970.3-2;Parent=rna-NM_022970.3; +chr10 BestRefSeq exon 123357476 123357992 . - . ID=exon-NM_022970.3-1;Parent=rna-NM_022970.3; +chr10 BestRefSeq CDS 123239371 123239535 . - 0 ID=cds-NP_075259.4;Parent=rna-NM_022970.3; +chr10 BestRefSeq CDS 123243212 123243317 . - 1 ID=cds-NP_075259.4;Parent=rna-NM_022970.3; +chr10 BestRefSeq CDS 123353223 123353331 . - 0 ID=cds-NP_075259.4;Parent=rna-NM_022970.3; +chr10 BestRefSeq five_prime_UTR 123353332 123353481 . - . ID=agat-five_prime_utr-54403;Parent=rna-NM_022970.3; +chr10 BestRefSeq five_prime_UTR 123357476 123357992 . - . ID=agat-five_prime_utr-54403;Parent=rna-NM_022970.3; +chr10 BestRefSeq three_prime_UTR 123237824 123239370 . - . ID=agat-three_prime_utr-54427;Parent=rna-NM_022970.3; + + \ No newline at end of file diff --git a/src/agat/agat_sp_merge_annotations/test_data/file2.gff b/src/agat/agat_sp_merge_annotations/test_data/file2.gff new file mode 100644 index 00000000..f072e1b3 --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/test_data/file2.gff @@ -0,0 +1,12 @@ +chr10 BestRefSeq gene 123237824 123357992 . - . ID=gene-FGFR2;Ontology=G0222; +chr10 BestRefSeq mRNA 123237824 123357992 . - . ID=rna-NM_022970.3;Parent=gene-FGFR2;Ontology=G0333; +chr10 BestRefSeq exon 123237824 123239535 . - . ID=exon-NM_022970.3-18;Parent=rna-NM_022970.3; +chr10 BestRefSeq exon 123243212 123243317 . - . ID=exon-NM_022970.3-17;Parent=rna-NM_022970.3; +chr10 BestRefSeq exon 123353223 123353481 . - . ID=exon-NM_022970.3-2;Parent=rna-NM_022970.3; +chr10 BestRefSeq exon 123357476 123357992 . - . ID=exon-NM_022970.3-1;Parent=rna-NM_022970.3; +chr10 BestRefSeq CDS 123239371 123239535 . - 0 ID=cds-NP_075259.4;Parent=rna-NM_022970.3; +chr10 BestRefSeq CDS 123243212 123243317 . - 1 ID=cds-NP_075259.4;Parent=rna-NM_022970.3; +chr10 BestRefSeq CDS 123353223 123353331 . - 0 ID=cds-NP_075259.4;Parent=rna-NM_022970.3; +chr10 BestRefSeq five_prime_UTR 123353332 123353481 . - . ID=agat-five_prime_utr-54403;Parent=rna-NM_022970.3; +chr10 BestRefSeq five_prime_UTR 123357476 123357992 . - . ID=agat-five_prime_utr-54403;Parent=rna-NM_022970.3; +chr10 BestRefSeq three_prime_UTR 123237824 123239370 . - . ID=agat-three_prime_utr-54427;Parent=rna-NM_022970.3; \ No newline at end of file diff --git a/src/agat/agat_sp_merge_annotations/test_data/fileA.gff b/src/agat/agat_sp_merge_annotations/test_data/fileA.gff new file mode 100644 index 00000000..03b2d16d --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/test_data/fileA.gff @@ -0,0 +1,2 @@ +chr1 AUGUSTUS gene 1000424 1039237 . + . ID=A; +chr1 AUGUSTUS mRNA 1000424 1039237 . + . ID=A.t1;Parent=A; diff --git a/src/agat/agat_sp_merge_annotations/test_data/fileB.gff b/src/agat/agat_sp_merge_annotations/test_data/fileB.gff new file mode 100644 index 00000000..e796e5f0 --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/test_data/fileB.gff @@ -0,0 +1,2 @@ +chr1 AUGUSTUS gene 1000424 1039237 . + . ID=B; +chr1 AUGUSTUS mRNA 1000424 1039237 . + . ID=B.t1;Parent=B; diff --git a/src/agat/agat_sp_merge_annotations/test_data/script.sh b/src/agat/agat_sp_merge_annotations/test_data/script.sh new file mode 100755 index 00000000..0d3acae7 --- /dev/null +++ b/src/agat/agat_sp_merge_annotations/test_data/script.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# clone repo +if [ ! -d /tmp/agat_source ]; then + git clone --depth 1 --single-branch --branch master https://github.com/NBISweden/AGAT /tmp/agat_source +fi + +# copy test data +cp -r /tmp/agat_source/t/scripts_output/in/agat_sp_merge_annotations/file1.gff src/agat/agat_sp_merge_annotations/test_data +cp -r /tmp/agat_source/t/scripts_output/in/agat_sp_merge_annotations/file2.gff src/agat/agat_sp_merge_annotations/test_data +cp -r /tmp/agat_source/t/scripts_output/out/agat_sp_merge_annotations_1.gff src/agat/agat_sp_merge_annotations/test_data + +cp -r /tmp/agat_source/t/scripts_output/in/agat_sp_merge_annotations/fileA.gff src/agat/agat_sp_merge_annotations/test_data +cp -r /tmp/agat_source/t/scripts_output/in/agat_sp_merge_annotations/fileB.gff src/agat/agat_sp_merge_annotations/test_data +cp -r /tmp/agat_source/t/scripts_output/out/agat_sp_merge_annotations_2.gff src/agat/agat_sp_merge_annotations/test_data \ No newline at end of file diff --git a/src/bedtools/bedtools_bamtobed/config.vsh.yaml b/src/bedtools/bedtools_bamtobed/config.vsh.yaml new file mode 100644 index 00000000..22ef8b44 --- /dev/null +++ b/src/bedtools/bedtools_bamtobed/config.vsh.yaml @@ -0,0 +1,118 @@ +name: bedtools_bamtobed +namespace: bedtools +description: Converts BAM alignments to BED6 or BEDPE format. +keywords: [Converts, BAM, BED, BED6, BEDPE] +links: + documentation: https://bedtools.readthedocs.io/en/latest/content/tools/bamtobed.html + repository: https://github.com/arq5x/bedtools2 + homepage: https://bedtools.readthedocs.io/en/latest/# + issue_tracker: https://github.com/arq5x/bedtools2/issues +references: + doi: 10.1093/bioinformatics/btq033 +license: MIT +requirements: + commands: [bedtools] +authors: + - __merge__: /src/_authors/theodoro_gasperin.yaml + roles: [ author, maintainer ] + +argument_groups: + - name: Inputs + arguments: + - name: --input + alternatives: -i + type: file + description: Input BAM file. + required: true + + - name: Outputs + arguments: + - name: --output + alternatives: -o + required: true + type: file + direction: output + description: Output BED file. + + - name: Options + arguments: + - name: --bedpe + type: boolean_true + description: | + Write BEDPE format. Requires BAM to be grouped or sorted by query. + + - name: --mate1 + type: boolean_true + description: | + When writing BEDPE (-bedpe) format, always report mate one as the first BEDPE "block". + + - name: --bed12 + type: boolean_true + description: | + Write "blocked" BED format (aka "BED12"). Forces -split. + See http://genome-test.cse.ucsc.edu/FAQ/FAQformat#format1 + + - name: --split + type: boolean_true + description: | + Report "split" BAM alignments as separate BED entries. + Splits only on N CIGAR operations. + + - name: --splitD + type: boolean_true + description: | + Split alignments based on N and D CIGAR operators. + Forces -split. + + - name: --edit_distance + alternatives: -ed + type: boolean_true + description: | + Use BAM edit distance (NM tag) for BED score. + - Default for BED is to use mapping quality. + - Default for BEDPE is to use the minimum of + the two mapping qualities for the pair. + - When -ed is used with -bedpe, the total edit + distance from the two mates is reported. + + - name: --tag + type: string + description: | + Use other NUMERIC BAM alignment tag for BED score. + Default for BED is to use mapping quality. Disallowed with BEDPE output. + example: "SM" + + - name: --color + type: string + description: | + An R,G,B string for the color used with BED12 format. + Default is (255,0,0). + example: "250,250,250" + + - name: --cigar + type: boolean_true + description: | + Add the CIGAR string to the BED entry as a 7th column. + +resources: + - type: bash_script + path: script.sh + +test_resources: + - type: bash_script + path: test.sh + - path: test_data + +engines: + - type: docker + image: debian:stable-slim + setup: + - type: apt + packages: [bedtools, procps] + - type: docker + run: | + echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var/software_versions.txt + +runners: + - type: executable + - type: nextflow \ No newline at end of file diff --git a/src/bedtools/bedtools_bamtobed/help.txt b/src/bedtools/bedtools_bamtobed/help.txt new file mode 100644 index 00000000..0cfc23a2 --- /dev/null +++ b/src/bedtools/bedtools_bamtobed/help.txt @@ -0,0 +1,43 @@ +```bash +bedtools bamtobed +``` + +Tool: bedtools bamtobed (aka bamToBed) +Version: v2.30.0 +Summary: Converts BAM alignments to BED6 or BEDPE format. + +Usage: bedtools bamtobed [OPTIONS] -i + +Options: + -bedpe Write BEDPE format. + - Requires BAM to be grouped or sorted by query. + + -mate1 When writing BEDPE (-bedpe) format, + always report mate one as the first BEDPE "block". + + -bed12 Write "blocked" BED format (aka "BED12"). Forces -split. + + http://genome-test.cse.ucsc.edu/FAQ/FAQformat#format1 + + -split Report "split" BAM alignments as separate BED entries. + Splits only on N CIGAR operations. + + -splitD Split alignments based on N and D CIGAR operators. + Forces -split. + + -ed Use BAM edit distance (NM tag) for BED score. + - Default for BED is to use mapping quality. + - Default for BEDPE is to use the minimum of + the two mapping qualities for the pair. + - When -ed is used with -bedpe, the total edit + distance from the two mates is reported. + + -tag Use other NUMERIC BAM alignment tag for BED score. + - Default for BED is to use mapping quality. + Disallowed with BEDPE output. + + -color An R,G,B string for the color used with BED12 format. + Default is (255,0,0). + + -cigar Add the CIGAR string to the BED entry as a 7th column. + diff --git a/src/bedtools/bedtools_bamtobed/script.sh b/src/bedtools/bedtools_bamtobed/script.sh new file mode 100644 index 00000000..10c4cef4 --- /dev/null +++ b/src/bedtools/bedtools_bamtobed/script.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_bedpe + par_mate1 + par_bed12 + par_split + par_splitD + par_edit_distance + par_tag + par_color + par_cigar +) + +for par in ${unset_if_false[@]}; do + test_val="${!par}" + [[ "$test_val" == "false" ]] && unset $par +done + +# Execute bedtools sort with the provided arguments +bedtools bamtobed \ + ${par_bedpe:+-bedpe} \ + ${par_mate1:+-mate1} \ + ${par_bed12:+-bed12} \ + ${par_split:+-split} \ + ${par_splitD:+-splitD} \ + ${par_edit_distance:+-ed} \ + ${par_tag:+-tag "$par_tag"} \ + ${par_cigar:+-cigar} \ + ${par_color:+-color "$par_color"} \ + -i "$par_input" \ + > "$par_output" + diff --git a/src/bedtools/bedtools_bamtobed/test.sh b/src/bedtools/bedtools_bamtobed/test.sh new file mode 100644 index 00000000..3ea8b59d --- /dev/null +++ b/src/bedtools/bedtools_bamtobed/test.sh @@ -0,0 +1,183 @@ +#!/bin/bash + +# exit on error +set -eo pipefail + +# directory of the bam file +test_data="$meta_resources_dir/test_data" + +############################################# +# helper functions +assert_file_exists() { + [ -f "$1" ] || { echo "File '$1' does not exist" && exit 1; } +} +assert_file_not_empty() { + [ -s "$1" ] || { echo "File '$1' is empty but shouldn't be" && exit 1; } +} +assert_file_contains() { + grep -q "$2" "$1" || { echo "File '$1' does not contain '$2'" && exit 1; } +} +assert_identical_content() { + diff -a "$2" "$1" \ + || (echo "Files are not identical!" && exit 1) +} +############################################# + +echo "Creating Test Data..." +TMPDIR=$(mktemp -d "$meta_temp_dir/XXXXXX") +function clean_up { + [[ -d "$TMPDIR" ]] && rm -r "$TMPDIR" +} +trap clean_up EXIT + +# Generate expected files for comparison +printf "chr2:172936693-172938111\t128\t228\tmy_read/1\t60\t+\nchr2:172936693-172938111\t428\t528\tmy_read/2\t60\t-\n" > "$TMPDIR/expected.bed" +printf "chr2:172936693-172938111\t128\t228\tchr2:172936693-172938111\t428\t528\tmy_read\t60\t+\t-\n" > "$TMPDIR/expected.bedpe" +printf "chr2:172936693-172938111\t128\t228\tmy_read/1\t60\t+\t128\t228\t255,0,0\t1\t100\t0\nchr2:172936693-172938111\t428\t528\tmy_read/2\t60\t-\t428\t528\t255,0,0\t1\t100\t0\n" > "$TMPDIR/expected.bed12" +printf "chr2:172936693-172938111\t128\t228\tmy_read/1\t0\t+\nchr2:172936693-172938111\t428\t528\tmy_read/2\t0\t-\n" > "$TMPDIR/expected_ed.bed" +printf "chr2:172936693-172938111\t128\t228\tmy_read/1\t60\t+\t128\t228\t250,250,250\t1\t100\t0\nchr2:172936693-172938111\t428\t528\tmy_read/2\t60\t-\t428\t528\t250,250,250\t1\t100\t0\n" > "$TMPDIR/expected_color.bed12" +printf "chr2:172936693-172938111\t128\t228\tmy_read/1\t60\t+\t100M\nchr2:172936693-172938111\t428\t528\tmy_read/2\t60\t-\t100M\n" > "$TMPDIR/expected_cigar.bed" +printf "chr2:172936693-172938111\t128\t228\tmy_read/1\t85\t+\nchr2:172936693-172938111\t428\t528\tmy_read/2\t85\t-\n" > "$TMPDIR/expected_tag.bed" + + +# Test 1: +mkdir "$TMPDIR/test1" && pushd "$TMPDIR/test1" > /dev/null + +echo "> Run bedtools bamtobed on BAM file" +"$meta_executable" \ + --input "$test_data/example.bam" \ + --output "output.bed" \ + +# checks +assert_file_exists "output.bed" +assert_file_not_empty "output.bed" +assert_identical_content "output.bed" "../expected.bed" +echo "- test1 succeeded -" + +popd > /dev/null + +# Test 2: +mkdir "$TMPDIR/test2" && pushd "$TMPDIR/test2" > /dev/null + +echo "> Run bedtools bamtobed on BAM file with -bedpe" +"$meta_executable" \ + --input "$test_data/example.bam" \ + --output "output.bedpe" \ + --bedpe + +# checks +assert_file_exists "output.bedpe" +assert_file_not_empty "output.bedpe" +assert_identical_content "output.bedpe" "../expected.bedpe" +echo "- test2 succeeded -" + +popd > /dev/null + +# Test 3: +mkdir "$TMPDIR/test3" && pushd "$TMPDIR/test3" > /dev/null + +echo "> Run bedtools bamtobed on BAM file with -bed12" +"$meta_executable" \ + --input "$test_data/example.bam" \ + --output "output.bed12" \ + --bed12 + +# checks +assert_file_exists "output.bed12" +assert_file_not_empty "output.bed12" +assert_identical_content "output.bed12" "../expected.bed12" +echo "- test3 succeeded -" + +popd > /dev/null + +# Test 4: +mkdir "$TMPDIR/test4" && pushd "$TMPDIR/test4" > /dev/null + +echo "> Run bedtools bamtobed on BAM file with -ed" +"$meta_executable" \ + --input "$test_data/example.bam" \ + --output "output_ed.bed" \ + --edit_distance + +# checks +assert_file_exists "output_ed.bed" +assert_file_not_empty "output_ed.bed" +assert_identical_content "output_ed.bed" "../expected_ed.bed" +echo "- test4 succeeded -" + +popd > /dev/null + +# Test 5: +mkdir "$TMPDIR/test5" && pushd "$TMPDIR/test5" > /dev/null + +echo "> Run bedtools bamtobed on BAM file with -color" +"$meta_executable" \ + --input "$test_data/example.bam" \ + --output "output_color.bed12" \ + --bed12 \ + --color "250,250,250" \ + +# checks +assert_file_exists "output_color.bed12" +assert_file_not_empty "output_color.bed12" +assert_identical_content "output_color.bed12" "../expected_color.bed12" +echo "- test5 succeeded -" + +popd > /dev/null + +# Test 6: +mkdir "$TMPDIR/test6" && pushd "$TMPDIR/test6" > /dev/null + +echo "> Run bedtools bamtobed on BAM file with -cigar" +"$meta_executable" \ + --input "$test_data/example.bam" \ + --output "output_cigar.bed" \ + --cigar + +# checks +assert_file_exists "output_cigar.bed" +assert_file_not_empty "output_cigar.bed" +assert_identical_content "output_cigar.bed" "../expected_cigar.bed" +echo "- test6 succeeded -" + +popd > /dev/null + +# Test 7: +mkdir "$TMPDIR/test7" && pushd "$TMPDIR/test7" > /dev/null + +echo "> Run bedtools bamtobed on BAM file with -tag" +"$meta_executable" \ + --input "$test_data/example.bam" \ + --output "output_tag.bed" \ + --tag "XT" + +# checks +assert_file_exists "output_tag.bed" +assert_file_not_empty "output_tag.bed" +assert_identical_content "output_tag.bed" "../expected_tag.bed" +echo "- test7 succeeded -" + +popd > /dev/null + +# Test 8: +mkdir "$TMPDIR/test8" && pushd "$TMPDIR/test8" > /dev/null + +echo "> Run bedtools bamtobed on BAM file with other options" +"$meta_executable" \ + --input "$test_data/example.bam" \ + --output "output.bed" \ + --bedpe \ + --mate1 \ + --split \ + --splitD \ + +# checks +assert_file_exists "output.bed" +assert_file_not_empty "output.bed" +assert_identical_content "output.bed" "../expected.bedpe" +echo "- test8 succeeded -" + +popd > /dev/null + +echo "---- All tests succeeded! ----" +exit 0 diff --git a/src/bedtools/bedtools_bamtobed/test_data/example.bam b/src/bedtools/bedtools_bamtobed/test_data/example.bam new file mode 100644 index 0000000000000000000000000000000000000000..ffc075ab83a83a98ed1edbf88b26cc27ad8946c6 GIT binary patch literal 334 zcmb2|=3rp}f&Xj_PR>jWAq>SuUsA6mBqS7Y@IB%Aw%O~PhS4S?6Z1_bX2zRMuCZ>` z;o;@Ato^fw$CpQUheTtRYNNz-r#8JXHa3Ry>s4lk0?m>~GxQF_-U<7&m>dP#pU;|5 z)~CHK)-&PMX8(zQnRkjz7tzu&Q_9lpm^;_nXXDZb**~)OH9hZA+GbYw!F2!1eU^u& z=6?J8db>^n+vnS58VqGOpQde!^LhT^FPno$sK1R;RVb&i_o5|>-LG;Kg??MHCx&;~ ziZww?R#r16X1LX_ZFYQZ=WBLl9Y-y@V*W$>-;Wo3eOwoN_@m-GsXhDI /var/software_versions.txt +runners: +- type: executable +- type: nextflow diff --git a/src/rseqc/rseqc_bamstat/help.txt b/src/rseqc/rseqc_bamstat/help.txt new file mode 100644 index 00000000..b4e9c1d9 --- /dev/null +++ b/src/rseqc/rseqc_bamstat/help.txt @@ -0,0 +1,18 @@ +``` +bam_stat.py -h +``` + +Usage: bam_stat.py [options] + +Summarizing mapping statistics of a BAM or SAM file. + + + +Options: + --version show program's version number and exit + -h, --help show this help message and exit + -i INPUT_FILE, --input-file=INPUT_FILE + Alignment file in BAM or SAM format. + -q MAP_QUAL, --mapq=MAP_QUAL + Minimum mapping quality (phred scaled) to determine + "uniquely mapped" reads. default=30 \ No newline at end of file diff --git a/src/rseqc/rseqc_bamstat/script.sh b/src/rseqc/rseqc_bamstat/script.sh new file mode 100644 index 00000000..32927bb6 --- /dev/null +++ b/src/rseqc/rseqc_bamstat/script.sh @@ -0,0 +1,9 @@ +#!/bin/bash + + +set -eo pipefail + +bam_stat.py \ + --input-file "${par_input_file}" \ + ${par_mapq:+--mapq "${par_mapq}"} \ +> $par_output diff --git a/src/rseqc/rseqc_bamstat/test.sh b/src/rseqc/rseqc_bamstat/test.sh new file mode 100644 index 00000000..f9180da8 --- /dev/null +++ b/src/rseqc/rseqc_bamstat/test.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# define input and output for script + +input_bam="sample.bam" +output_summary="mapping_quality.txt" + +# run executable and tests +echo "> Running $meta_functionality_name." + +"$meta_executable" \ + --input_file "$meta_resources_dir/test_data/$input_bam" \ + --output "$output_summary" + +exit_code=$? +[[ $exit_code != 0 ]] && echo "Non zero exit code: $exit_code" && exit 1 + +echo ">> Checking whether output is present" +[ ! -f "$output_summary" ] && echo "$output_summary file missing" && exit 1 +[ ! -s "$output_summary" ] && echo "$output_summary file is empty" && exit 1 + +echo ">> Checking whether output is correct" +diff "$meta_resources_dir/test_data/ref_output.txt" "$meta_resources_dir/$output_summary" || { echo "Output is not correct"; exit 1; } + +############################################################################# + +echo ">>> Test 2: Test with non-default mapping quality threshold" + +output_summary="mapping_quality_mapq_50.txt" + +# run executable and tests +echo "> Running $meta_functionality_name." + +"$meta_executable" \ + --input_file "$meta_resources_dir/test_data/$input_bam" \ + --output "$output_summary" \ + --mapq 50 + +exit_code=$? +[[ $exit_code != 0 ]] && echo "Non zero exit code: $exit_code" && exit 1 + +echo ">> Checking whether output is present" +[ ! -f "$output_summary" ] && echo "$output_summary file missing" && exit 1 +[ ! -s "$output_summary" ] && echo "$output_summary file is empty" && exit 1 + +echo ">> Checking whether output is correct" +diff "$meta_resources_dir/test_data/ref_output_mapq.txt" "$meta_resources_dir/$output_summary" || { echo "Output is not correct"; exit 1; } + +exit 0 \ No newline at end of file diff --git a/src/rseqc/rseqc_bamstat/test_data/ref_output.txt b/src/rseqc/rseqc_bamstat/test_data/ref_output.txt new file mode 100644 index 00000000..6b939096 --- /dev/null +++ b/src/rseqc/rseqc_bamstat/test_data/ref_output.txt @@ -0,0 +1,22 @@ + +#================================================== +#All numbers are READ count +#================================================== + +Total records: 90 + +QC failed: 0 +Optical/PCR duplicate: 0 +Non primary hits 0 +Unmapped reads: 1 +mapq < mapq_cut (non-unique): 0 + +mapq >= mapq_cut (unique): 89 +Read-1: 45 +Read-2: 44 +Reads map to '+': 44 +Reads map to '-': 45 +Non-splice reads: 89 +Splice reads: 0 +Reads mapped in proper pairs: 88 +Proper-paired reads map to different chrom:0 diff --git a/src/rseqc/rseqc_bamstat/test_data/ref_output_mapq.txt b/src/rseqc/rseqc_bamstat/test_data/ref_output_mapq.txt new file mode 100644 index 00000000..be8af62f --- /dev/null +++ b/src/rseqc/rseqc_bamstat/test_data/ref_output_mapq.txt @@ -0,0 +1,22 @@ + +#================================================== +#All numbers are READ count +#================================================== + +Total records: 90 + +QC failed: 0 +Optical/PCR duplicate: 0 +Non primary hits 0 +Unmapped reads: 1 +mapq < mapq_cut (non-unique): 6 + +mapq >= mapq_cut (unique): 83 +Read-1: 42 +Read-2: 41 +Reads map to '+': 44 +Reads map to '-': 39 +Non-splice reads: 83 +Splice reads: 0 +Reads mapped in proper pairs: 83 +Proper-paired reads map to different chrom:0 diff --git a/src/rseqc/rseqc_bamstat/test_data/sample.bam b/src/rseqc/rseqc_bamstat/test_data/sample.bam new file mode 100644 index 0000000000000000000000000000000000000000..ed1e24333ba1df0efa75401d7928b790038b762a GIT binary patch literal 9240 zcmV+zBROL8JfAYa&X{eo2(a(4x#KL{xo6|RWh#{l`wJHF zG8Rb+UCXZ?!F*E?$@6n6fpc!H+qhDcO4CJy-SVtVlLK9pDosel z^VV|IVoooa6FAt@UQ4X!YKCDo!o4C#m$XQ}ed3qd%|$c%r+O@P;z%eEf)+$#Wrc{9c#{alYgOlCnfm%W=X~d! zs@iTVGOxdj-^rtIU|Z4C(Z?hEx*yk`!=JBv?6Je0qtnxa)9ZVuM@J{o+wO}ZDY@i{ zNHkM@r&wASRVrEE2`+k7w4%|h)x9peP8ChXi#{!iUbb3yW!rUiStqSbd7GxC&htF3 z;>y4B;a!~3IId*$CC@8+UmVjLb8AdD+xK*dhUq)HKgMktE@zqfNpyFPvAl{G=1+P@ ze^*9d@g76;ag5*%?tS0x*>AjW?<{)k^*^~A{m2{7w(6TV%dNlqj=%OVe*V9`_HVuG zEPCSIXD@xvd(NVtesBGzcfSwUo(piZSl*1@9F6!czWd$pE@Ao6yQ8QCD5BLY5oyAT zqUsCQr&^UtYnFC>Q&&nHT+67#+DzWaZ`&G(*hzGqLq!BMBbBZ`=r?h^xbp2OI8r_|Zq zJvceuG2BVgx=~$Q@)RVg%DR_HS7^m_+SFAlRKpZ6HLp{y`=m~osu`0>A)8cnoh&Pr zh(c8=6_Vxjialon>P)^Hm_`4s9M3aiLY@yJD{k{w^34BrS(aNYX`J5Y^t-A6<+np9 zBXH-{#2v!MVYvvn^Xjc1c3}R>0Or%tCmfg`zcY$%ZcV{FI6gf+iQWq^xk%EU>srXR zWObw4Le#yGDyg+D(j*aWQiz1{wCGx;S=rUB=S_z@ld5jpLKdPDysLOpZ0F`xEgXP` zWck9rH;gi-X3f=s?(H@+w}VF+Yz@D2e2MX0j)B;H+TWg=5p$DaZRKDzhMg_wQf|4N z(QS`aZJ&Iaic>kOwkmBQbO15)Y7vW|y;pQI(JhWimjNTfJeEp3VreIobJ`2aDrLI9ffTyGsjUq^S-S9fm zAgU~?nsvQOlDYw3bz^2%#b)w`AOw?hR@uUFGPnLZvs|Pv3r|%?uzUtXUipcCZ8q_< z-=5Cpx;sU~?#01E}U=vtXWw?#_mZNX9h?dnjZhy15ZDDu^1mpHZ{$~_>?>^e`}M_xPKxv ze6V=MU1Q|+!Q%JtvH~Oo^W@<0V9x}L8F=Lsyks4Csct%f57xX%@JDyUA!Qjjc=tT8 zMS{$IYeR<>bYM_y@9?2B_M|h9g5rn$u@oANz#((bO-!+1n!r(+`;2ajP0*n`2+n^L z!g&Yae8>iipLo>4`9J{YLtEc=(7hpm^DV*HTV{rSbb7eEAAJ`7ZDy=>k~A7IK}*%j zn)h|Ddf6A9s(Mx=Y6R@|y<*2F%=#^J=l1FIo!h4;bKbE5GMw|T&g}83b3Xr{{i2ZY zhLdB?Z&@?vJHt8ur@%zKC}^V5l>T@Y$E?}pba&T4O?5J93ZW|U*QBy)Qe7~YR+UD_ z!0;E&j~Zo7QG8)Ng;6~2-@PzSV?pn2cqZ|^L|b@)vkzc0@4D}2J!|g`Ci8*UI3KY6 zk}*1c#7!o_*hglG+u`xa-fr~Sd!wikoTVDt1_8KEWuj7Dl}gc^Y9+ctLNjXEcq$Q^ zHPeh0qHVb1I^}iOrV^s3kQXL%ew*&8mIJ&09I*S@c{t*0!V%v(-5QZ%yEYvCd^95Z z)3a2~qW3R>UMVHWortPqY0|+RB0m#Ia#fS^M)f>Nm{y2G9Tzp1LKY=cZJ}!|Yskd9 zgI{HQo8k{;993@9&)kI8+=i3PIKV7+j?SgO14wa*f^n3YduJoj;u3gT;t_Z|A$SkY zz}pJIdvNP7JMjMI1Iyv(+DoJ8HPi63zjJ!9yJNynogyn~iARd3eNrT%QytF-hKqCAw3{eUq|Jbc#YjLQtl<>nT*#sj|6>OGp+r0gHoTzz}8wt_1vX?*>0K zYJeeN=f$YDg8Os(lRZ8V@r?9gT#60xpappBS?zA~w7H9Dw%wwmfyl5JW zIaVYr7C!H^UU7!zDsjXn;^@D6CdNQBdIO81UyI%mj73w&xW9LBa&#C$)*zcp;MfQZ zRhK;yI@B0CP_D+?sxAsClt>usdtE5rS+{NJXPvtFM>{=3zTfH=%Ot}fnyX2R4O@)F zq&rE6=N5D;m~3&%pl0Sx^YjAROsgW2ym>UbbEic{C&;xorR1G7nMcZCU!sRY>KYVT zFeJHXSewN}Vw896*H=x*KJFlx&%ou(1nIoJmln;B;|L9p4GsQ}QN zt$=fOWWmS`2wo@JpF)UQikSkJ7lBT4$M&Pv3h5J>F*xVLjzX5aq`rCf1(4+X`7ip? z)m=gG{DK$I_iitHu*bKTs-FADkUyse%m#8<%C7Bdpb8~~TBeo^VYAho2?h&nMT-I! zY%)*#j)DL5;JPJ`ycQrc)M z#~4>#t87s&cg1px#>JpqgVW{<9?EAo)lUAxq;}%<){n7eZ}km~Jv7x@2Sq8l0567zZ86xVAPQ4I7$ErhBt1T z)p@NDpZ^*AnDU`?nNx_h?=pLXuQb3!Z{EFix#F3lJ;f5bvjE~f*oT*c076Lxwu|N6D%GU**@6z$H~d3<`Zb8O3`=y(-fiZ2>6zbL8# zVyk7mD|lTt3W<3)J#D z!nQ%0&{IDxL7Ko>$r2<7EkukKxPn}@mR_Md1GK^*cFl%($PB6p1k2xD`hlDqjyyLv zqxrIxRp&oQm$`X;5k=2Tg~{O#`anlEvtntAS~9d;(m?eKtrT=yuhUYBE|G{jvPIz} zB^?OUW>iICxOIf%!3<%<>%&DKD;LOJUrO`=JM;=>N^IJlHwhvoiCx zLCN@SiakCZ%O_-9LCnnc;RbJ+Pd%so*8t3KUM`UPr1<#(%#RH+lgN57vu{gGl9`o4 z%bO)A3n!dI4Z(Knjyj&5R1|R-}>drg{J*esH)3XA#_!`|6JElsYWGxyjDASK9fF2bY%`eF9_uXJ+Te`^P&r zj(6-r!0{PysEkqVKIzInP4FirMdshWsBYIQUOl`a5-lzB0GQ9LYwsFH#)+#}*p(O1^QFHv+l~S{oce)2$bpq)Q?TJ1J z)OyhYOX}fscv(~t(KtZ>%0_D){248g3G}wFKnK)XkIvPDmnY^kn~3?+2{FInaQn3Z z%cr9^24ioW6Z2^Qu9_ z^!KJ5xP2(iCX;6)xmV0~r8mv5;t#wh*aJ#Gvj(MmLzKKv{o-F7xit9HS47bZGcFzO z?(d%%pNd)=HCvz~(RV?Ll+>z9Q{+de1QTj0D|mwPlBmlRr8`;l9eSqB={5p{QAM^5DK5O8G!9L%rw?^Cu%R9ihe-MrM-Z5jG#j?fKr|!ik`WY^0 z-ifwHf=ObZdSCS7G%mnBR7mSaa#|vbZZlVKQRtHL)GiTU*mdK6wUYH!rbI`JIOE(2 zCkv6yul-W>CG}~0S*D3>7QQ-uI^>7Ge&E!6@x{<_3B>ye#P9sy=T@ynzkd+(ul(NS z^~6tMY!gzCD%VKa z3v@O37rf+H4qS7^TP&mW{T;v_TrMnW{q4S*d zit%}JIGKG`g+IBXLrMa%V zWtL>ybt86m9tby4JJUQQaK4#zSMweI#{=w@c&=||dsF}W-?vNPq2tjKv8l99PvAbJX&-*UvMACC=Dp9iSR9u5J9GaKsuif`!H_K(=RWM1ggy4r$&mA&txfq+2Mg$MooN{Mt%2QwdFeP)1l zEY%UzFPlmv2WzxtVSO*jq!JYn+9Pxx1$#uHu9LcjVv-7lJ*6P$Q~ZMdWNDeeMbz*S zsk}v6iB{AvvSBe-W&|SSQ)Xo$Z6L6u%)Qvjja14)O5+2roEMwuWfwmZtL<%}O_1E0 z7x~=-ajpG1tak#|2ME^x`SxE~wGjM)t>1GH{!w81KkCLRnEv0MvGwHe^yn!1HuBv$ ze!AP=g6n|`1{5ktDX88Z> zFZmhX9i%BA_OXKe*u2C`y!nG^tZ=@~E+QN4i1kn_94#7j4AHqkoTU;Q8a29>1zI{F z1w$g&aRivIZ)mM}S{Jp@x&Wh^TQ*Ih#bS8gM3SK;VAsK#ydt*$+1$j5<;-s895dh8 zN^V;z9#$4E2XrUA{WrmDVMZ3Nzj)6jW5qK8IlLXdE+El|XLe`_^DNw2Np^_en{X7# zjfLfh-3yyrc-)e^$}KpzgO)c=(k(m=X7PExiYd1+wU7MJJ6A3*f6OuE-->0&{nl3@ zIh#ho)BWRvy}js7cOyN!BQk5|H4@jZk?2L2FbuQs0Y(A!i{uQxyF(7!B7s1)Rr5B% z-AvWEp-~M(`kN*#I?}j8otImeb==E0+j3)E`CW`5QS6G<*wq-an3kZDpRy$fvs210 z%(Tn;Ghd)uUM-Q=H_!ff>bPGPp!!X(Exsw1mG50Z_1{e$%<1mw(ebWPzUYH0po88N z+WWNRkR#G5hIFFW$Q%#>p=njkk&cNr1;7FgE~LD)L;`7ss;Q%(V8Y2ome1vRHD6XT z&8C7sgRFHiemu~__RYP`LXUfX$d!G1lknv$`&9(oT=){eub[Ji7oy)t%b zQ6OJ~FKlUL1((H*05UhF#Z+76PL$=h!&FBjddCKN6?POp{Bpm^ zb$H}YM1RLk@UMJ-6#dEUk)IqL9Ka*tkx%D=vQJm0DaJVEJsQdheK&;)9H=4j8(|e1 zlPiG=kz1Grensbkik}5ciL-pv|qOD5>Apw<1?eY?D z70d#@hPE^SIw=*J=c%UE`W5i1i+nMz_s!e}dbj=Atwu3fNjxl3G0QT?9l`^!@v!M< za{R>TgY3K6$rQ`c)bs3jH^sgOS1uF$&j9nFLo3iRyolJC|j~UUz^*Y*ub(_Fxyc_bYQT&ul=kNS>sonXTDuV*^?4uwBHCU%qjZhwD@qS?*aL1iqo85E}c^ zyL@;+o|^^G)M0T#%*wlW255?{S2#4kJaF^r=>5?+_Wn6H_jZntkE5sH2457ImrD}z zOI{A_c)pF0FnZ5C5I%qIivF|bCkVMf7$Wq+Ip1y*LgpW9#MFW^NqXng9=8G`b0u28 zlq$}r{ljpBW$;>rmpthfcG$Cs5PH=bgu+Pr{OcV;-K$6c_A!Uh*D&_Vtr>@oj`j{u zqaBkeg+^5?u4lh;O@H8(gRcLluO7|O>-x`N z>|f8#@n{cCd?W1Fp(7H(NSvm0Y*kk%D3qqCsq#hZ@o5b@LN>aoTA(l{+FSW$bNH*i z{NIxW?HwB-7R!G<5%ZsK()DcRZrxuG@btmr>lpj|5}wC9`>uVZW!j7M;*0s2egwE^%9Con|YQ35JH{d=xg^c>*K=V_ZLhts< z?$u`oG{+>K82cl0S2(isMPn%XRN>?BrniP#gg3OQ#}5dzB0tY(x8>o&9T=}w zZgV3$@1C&pja#FWyf(|?$(erRg*l$aahekEi-J(&u3o1NZ5x($6LXM|8;&jfAqROr z^qQQ$F%`COWsfCnyvD~)9zcHnr74~lXa}Y%&Hd{ELA|+?3wZ4kK?ifctdC4MV^kvN zv~yU~T|%~i8-){Nx;9vwGyg1CArMVT*dKf75hsiEi*D`7Y`K%??$n}uvRE)5=gGvvgQTaEYw z%x(?zK*YEjf)?e4057u(d}4Q$k^gN{6N_aweAM1%ma?0y*>83qmRVzT5!=!-f%%&& z+f~2w$zOeR#lFx725Nrj`e^H(ngsA`=G3%c+Rb9?K}#)Y%7F&vHWakb(Q0VLp4lLQ z{(qX7Q|>G}u9;`35gd7y<$)_TQ?{686Z2eOl5x&rX$k-Q6O**%H#bG1cx5Ci9$D5& z4`b|~%#X9&-`hXjw~>gYZNY>DC_F8}Oq6i?5{e0B<)Wc-jc9s0k^|ikv3HLON1vyA>j*Ur4;RaVra5y)XIy7qJF~5 zqyV}p94b#Gl)#Hj&F2WMxC}!5#JocGx$}=F{M=;r2UgmIv;W6)^L!Drzk*M{_{*CU z%|2T*`#ZwfdzHMiyR4Gmjj?|=d-h0)Pj>8f0`v%VN@pjaOC}QZU3m+u;z}|E&!lY% zgi6sB3BFGxLa0uA!~=-Dx~NebgS;zSWGyUV#@D;#!iZLTn3u2F+fu?}VTWRS1Y2z7 zu{$fx+(0Y2+&cN#AM)wWcCx2r(NZ6?-!pSv8Dl%9zF-c*%3aMr^QU`$5Kum{P9@(x zQOUlPcoKm5qyzIYjQy)Qm?UV@W>LzJ?X8c80;q z%(=q-b9n{Hi?i}iZu0T>tPGlu?=FiF3ZzfIFvD{Unz}=vM5Vti6D=CFL%A$!6b=AU zS3(stS+Nw|VWmV})o9i=vdY4LV7YYH`gO3RFp2>x3n^AW_wVHq$K% zfvISUqGO$4lLgmaWX`1P+)`I6){z!tX(kkAc`y>&nzXG_TS1%I2;%E!7m~NvR;CNT zw6|=jgfW{DE5I{pIm#u7A)HF7@M?6Xq=bWGsjPac8MG*%CPkg9Qh|ghz0%=jT69!7 zAYqGsAM#z6q}!F{mizxD*ew>Oupj%VoG-FL&1bV6E+eeN@Z_|q3ng~Tk0ieWo{#vm z^#?qkh*UI=sX0IQcTY}EqZ{|q`URGlg~-tTbmAMu5>!{Y>@{trM1_E~9a3CaaFNus znN*~zZNXD$A_)yR9Nf8Ts_UGa1vv{BcjVRVK;GcP=PsnmOz?gG9I|`Y__lkekhw() zA!HwzQ}FgeHU%V~OlI9H`2R7))kR|QDnfdeJp{otZq@zp{?aDM z-TmV|pk_)?morQtDbWLI+qz%{FQ6B@PSPGeg?Mp}_Pd%WSz4@RU)gBk@gUA^#nm-G zJ&w*PP;}kexYO+AlNyv)(*Hex(<|w3?JZYG_YZask(7~=zCB3NxgG13^a_*9SG-#d zZCLgT?#*Vm1;@O(7nu1AS5wm8S`kkO-nY+<*+OaJ$!&pAw0+ua`-9v}o7cb^hZ9|X z7aR$*;dS0R<_)9X(tqJWhs0(1|u zVR%d4a@3rApFoEKZD6FPtwJiO%SdQA4@@M{mU!q ut*y&d@Ba*Ga5RY+ZU6uuiwFb&00000{{{d;LjnLB00RI30000000006cpcXO literal 0 HcmV?d00001 diff --git a/src/rseqc/rseqc_inferexperiment/config.vsh.yaml b/src/rseqc/rseqc_inferexperiment/config.vsh.yaml new file mode 100644 index 00000000..184f2c10 --- /dev/null +++ b/src/rseqc/rseqc_inferexperiment/config.vsh.yaml @@ -0,0 +1,76 @@ +name: "rseqc_inferexperiment" +namespace: "rseqc" +description: | + Infer strandedness from sequencing reads +links: + homepage: https://rseqc.sourceforge.net/ + documentation: https://rseqc.sourceforge.net/#infer-experiment-py + issue_tracker: https://github.com/MonashBioinformaticsPlatform/RSeQC/issues + repository: https://github.com/MonashBioinformaticsPlatform/RSeQC +references: + doi: 10.1093/bioinformatics/bts356 +license: GPL-3.0 +authors: + - __merge__: /src/_authors/emma_rousseau.yaml + roles: [ author, maintainer ] + +argument_groups: +- name: "Input" + arguments: + - name: "--input_file" + alternatives: ["-i"] + type: file + required: true + description: input alignment file in BAM or SAM format + - name: "--refgene" + alternatives: ["-r"] + type: file + required: true + description: Reference gene model in bed format + +- name: "Output" + arguments: + - name: "--output" + type: file + direction: output + required: true + description: Output file (txt) of strandness report. + example: $id.strandedness.txt + +- name: "Options" + arguments: + - name: "--sample_size" + alternatives: ["-s"] + type: integer + description: | + Number of reads sampled from SAM/BAM file. Default: 200000 + example: 200000 + - name: "--mapq" + alternatives: ["-q"] + type: integer + description: | + Minimum mapping quality (phred scaled) to determine uniquely mapped reads. Default: 30 + example: 30 + +resources: + - type: bash_script + path: script.sh + +test_resources: + - type: bash_script + path: test.sh + - path: test_data + +engines: +- type: docker + image: python:3.10 + setup: + - type: python + packages: [ RSeQC ] + - type: docker + run: | + echo "RSeQC - infer_experiment.py: $(infer_experiment.py --version | cut -d' ' -f2)" > /var/software_versions.txt + +runners: +- type: executable +- type: nextflow diff --git a/src/rseqc/rseqc_inferexperiment/help.txt b/src/rseqc/rseqc_inferexperiment/help.txt new file mode 100644 index 00000000..f19aa318 --- /dev/null +++ b/src/rseqc/rseqc_inferexperiment/help.txt @@ -0,0 +1,21 @@ +``` +infer_eperiment.py --help +``` + +Usage: infer_experiment.py [options] + + +Options: + --version show program's version number and exit + -h, --help show this help message and exit + -i INPUT_FILE, --input-file=INPUT_FILE + Input alignment file in SAM or BAM format + -r REFGENE_BED, --refgene=REFGENE_BED + Reference gene model in bed fomat. + -s SAMPLE_SIZE, --sample-size=SAMPLE_SIZE + Number of reads sampled from SAM/BAM file. + default=200000 + -q MAP_QUAL, --mapq=MAP_QUAL + Minimum mapping quality (phred scaled) for an + alignment to be considered as "uniquely mapped". + default=30 \ No newline at end of file diff --git a/src/rseqc/rseqc_inferexperiment/script.sh b/src/rseqc/rseqc_inferexperiment/script.sh new file mode 100644 index 00000000..c425b6f3 --- /dev/null +++ b/src/rseqc/rseqc_inferexperiment/script.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -eo pipefail + +infer_experiment.py \ + -i $par_input_file \ + -r $par_refgene \ + ${par_sample_size:+-s "${par_sample_size}"} \ + ${par_mapq:+-q "${par_mapq}"} \ +> $par_output diff --git a/src/rseqc/rseqc_inferexperiment/test.sh b/src/rseqc/rseqc_inferexperiment/test.sh new file mode 100644 index 00000000..ff2e870c --- /dev/null +++ b/src/rseqc/rseqc_inferexperiment/test.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# define input and output for script +input_bam="$meta_resources_dir/test_data/sample.bam" +input_bed="$meta_resources_dir/test_data/test.bed12" +output="strandedness.txt" + +echo ">>> Prepare test output data" + +cat > "$meta_resources_dir/test_data/strandedness.txt" < "$meta_resources_dir/test_data/strandedness2.txt" <>> Test 1: Test with default parameters" + +"$meta_executable" \ + --input_file "$input_bam" \ + --refgene "$input_bed" \ + --output "$output" + +exit_code=$? +[[ $exit_code != 0 ]] && echo "Non zero exit code: $exit_code" && exit 1 + +echo ">> Checking whether output can be found and has content" + +[ ! -f "$output" ] && echo "$output is missing" && exit 1 +[ ! -s "$output" ] && echo "$output is empty" && exit 1 + + +echo ">> Checking whether output is correct" +diff "$output" "$meta_resources_dir/test_data/strandedness.txt" || { echo "Output is not correct"; exit 1; } + +rm "$output" + +################################################################################ + +echo ">>> Test 2: Test with non-default sample size and map quality" + +"$meta_executable" \ + --input_file "$input_bam" \ + --refgene "$input_bed" \ + --output "$output" \ + --sample_size 150000 \ + --mapq 90 + +exit_code=$? +[[ $exit_code != 0 ]] && echo "Non zero exit code: $exit_code" && exit 1 + +echo ">> Checking whether output can be found and has content" + +[ ! -f "$output" ] && echo "$output is missing" && exit 1 +[ ! -s "$output" ] && echo "$output is empty" && exit 1 + +echo ">> Checking whether output is correct" +diff "$output" "$meta_resources_dir/test_data/strandedness2.txt" || { echo "Output is not correct"; exit 1; } + + +echo "All tests passed" + +exit 0 \ No newline at end of file diff --git a/src/rseqc/rseqc_inferexperiment/test_data/sample.bam b/src/rseqc/rseqc_inferexperiment/test_data/sample.bam new file mode 100644 index 0000000000000000000000000000000000000000..9b8d417c8cc1651725269c13a1c915b08b2e4d38 GIT binary patch literal 5595 zcmV<16(s5(iwFb&00000{{{d;LjnM80fmy^PQox0#*25wm)Hxe<5ULHs|`qyWSi3o zw@dd2T*6jd8#LbgV7{4Qz@|9#?rYEK@9TGR#ROL8JfAYa&X{eo2(a(4x#KL{xo6|RWh#{l`wJHF zG8Rb+UCXZ?!F*E?$@6n6fpc!H+qhDcO4CJy-SVtVlLK9pDosel z^VV|IVoooa6FAt@UQ4X!YKCDo!o4C#m$XQ}ed3qd%|$c%r*HxdBm&7DZ#=Cd+dEI8Pof!w+ z#1ig(@BVGm@@DP?C)H@kgK8v|NUTC=YcQ=?Xd!#t;wB9uwoRaZNs0X+SP=ZsekfS6 zMub8lhF6J*p+uB)~wY+wnCIP&-1iOt9azYS(?!} zu4MF*=arwArgY+_rZm}~(C%0tGx}K>z2Y20bUQ|H zg1Jxb9Dn7>bH~X;Kl95w$y22W6MN?NonT8u#T3HKedsZ`UYR)w)bR$gH>9R6R6{a#mX`a)OM$U|=GkG^K zi~emK&og2|o)04%ro}6H7JpopD32fyWXx8?%$-Y&T--?6bodB2g^ts3lTEn!KO-J`FfS&* zlC1dpmA9r~dTzc3$7Z#yK|X+Iv{sEFNM+r~npqH47gf!>-Y`}-;Hz!i>Z;T&-Vuag z3eGB922SSQUuT|+^sZKmPi3-R~Irx35PI{r#})RcL$*V}CvK zZ+m-3ySt7<9p^2ptg4w1O4ia8bx~T2RWoTCCK${W1BGl`X8M95C`wx@&1@+dJf4z0 zD_PqC8SmZ(pEQ23tJC>o4^&9U)TmZuqDvWtJkLDm#N4IK+grE+7lwFIEwePT6vKe> zt5?UN2b(PbT5wu#V)!Qx#vt|D&?7T>+m3y?9Ghr4^b=UlLu zfmcq!V^;!C*rrpsv6c_`Nv~8ZvdQk`C#!&_Xap`AHjLo;*9{^{UbOZ z8I3(MGxYtVy`A&PH{jo9##%GhSi}UYO{;6!*S+a=Uv#GGdBMyIu2wSXe;NF!Q`Qv4m)=u2#S?z-rE?lfI``q3 z#P=F);RTLAjm3QQ)=x#&-ZEOur{5cVz}7of(dn767>2QDW{KP0!Qr``NP3mX?2q1kfFd7;`y8fk^ByH;q3o_Q~ zcptF))I1!?D}*DtI9jZb;yXSZeKuJk`iWVp=F$6epjT=Qax+zRT(A!A5c!!xl4}|v z8`De1xHX7Fom92dN*5(JZDDJxYskd9gJ0!xi{cMu998bq&)kL9+=r9QIlwFpjxMCX z14!u@1?MQUaONY?@+$E3#3S&w$KaivfwvfecXsh}0leS5eLei#c}J4GcN%`qZy)XM zY`gGN3uGlN@yJNgvx2G4bcj23h13ou1PP(UHF+1#Y-f=Bva)AZpisaFN@2U6LRBq{ z&s9P~vh)d9Iw}SXVRpoo5r4wj;D=TkU_shlNG}F#i?Hkc#<}<(!yA^0&<CM=oNLLrQI3~n0P z3|yCNM9GZR2>Bdkml_#PgESnXQ&){v%mrxt{vaQb&RMsAp=2yu(o!jv%Y(wsRv_kM zf1YMhlVhgO>9RCS2VtHDH5EnEs+i+N!g3k&PVW_GXl@cmd?JqiAu=%qn#uhk#H5*|!*dV17fil5H-HcA1CZurJlaA$1LkEEv*KHM|y9arphhN;rPiYHJO0SxyemDw=J(3r=l0 zrqeP~zXt!nQn%vFCkQ?}a}@wuvlno|jyxEd10m`}|0#s1rIZ7ts_YthN^yuCE@!UJk>@qKsi7tf zGLWt*xIhq)l9iAks2LY+hinB^Qhr+8@@u#%Z; z5X4y5(RBDJI4h1$gO$ot+G(r6m{47-d{HhB#d43v>7cvTN&pCk7p|MtMXiut{vQ9B@}YE@Q;79vnV%3V4KUG*H!ZHNI2`rX zt9+fDgz8S&S+)<#CxzA*+Shy zyCPi#N%;&+gnmi}M!k$HfjOiCRkg7?cr8aD=M2qF?7VZr&WPr3+__#Ry+I_&&WxQ0 zM~B-7zD$aaSJ4T)SjhaMs0xU!mdmb?b)i8)q^SnADy7l)GH4k=!GOD(afO;yk4iEL z+`?KCW7og5vO2P{*Npl73OHXmC1E>E^tC;pDNjUGY($fgo7YJR;g@FIT%ifo3fPq5 zNJd3tZQXHQk_p$n64olz@;bt{L7LE0KaC+xki6s!$w3PdV->C-SFLqa=)nNJFi1nQ zAssSG8-m^@SOH*O8w~ao~zR#?<5U3?X%drNk zUs+?I+j=WXtvaR=b##lui69*a)8%z?qA8^9QhN5-m z^In&4ta>3%+PriUn0x}}@nQvBq~;$bD}e8w#`FMYPJ0DT3l;J$isQ;S1D?_=y+ zGftjAcXV)+JO~&I7-yjnrVRsbsJtSQz*HytVM!ndQp^I zHNC)%N{hmDTbJWxdOaeEPvsold^#9HH|4ka&>QfK%tsS|$$!nT+}++g=Vj(~gObbZ6nkPimQTpIftXq7!wudtpL$OJ+W^e(TwNfKN%8jw zFh4iQOd{*<%)UJ_NoH0CEpN_H7G_dH4Z(Knjyj&5HWYC<_t;;<26IGuS!tFuKcV=Z>#4I6XJX&aV|aWJ#)rgh#aM&~w&xbs>)( zHNQJ0ZiQNgPHu3WZnz3Vt~DH)7MYcAXsVBZ#0QV};4DXT@>t#Rozj5icTTeNt&Mhm z;q3ZWqvtU8A2T~YIDfG1<9NqU1)Q7#hsqe$?pas%g5f(QMecWBR@duDHxHi>iPpAx z0L)7p+npcyw}WvWioD zmDNKzK?Upkz`Tm{#p&`!8x4-XI9c5}@508b`-?eKu6A{C17|jQ64~Y_G`y0BnFypGj6@pP4?p{hghibLW$ne(5O!p5&{D48L4487)BvWiSSHEk8t*sHXhmKhc0UsLs$!`n=>V#^vO9& zZ%$E4M<~5HL227_V2sl5PC0P>P?{|!&sOB#u-c8@G`|*q5Iw;;p!CTrpmfU^rRYeIQPUhGvM|9*9xrt%})F8tQ587T>v@uk&O*h*nQ-p5=g?QS%$I4{d`5m9NdC*bJeSWJc;jH7FY3h#H^TA;FzyeM6}~sj z80WEUarOCIa7RDG1E>{IWH4oTw*+(U)5ZnUH=vgkHT0~duZsT6*T_|oqi zkGqw;uW}_i+QgaWK{$Dce109bs;{X}-^+4MWVi7(@G~Gk^z}zhEf!xK9oIm-jX-?! zKVRRp7yY(D%>U%O*Y^`YkFl-Al#qw}+ee{C--`xJ>`*$kEm5sPJ+l#LG#iktu^i?D_5z(z-I;=;11(fdokTHCGq2JR*JRKzkZzjjUdLs*wF1>>9>Mv8 zlf-;B5%W=iKL76ZvK&GD##>WPdN^I8IYERO(-Z9^9A2-{t+2=_o4%!Oi^kT-LE#V? zxF|ckrCH2&=sdIDa5+y7C#%n@aZxg#34$xYoL1`?pYn*@{J}{b`a35b`dH)q+j2c? z|NWmxl3$#1^8k(PeP4fXBs^eAt!OJu(IM+BdbmQ4h7aw7zyv(i9z^?O)1IxA-e`EJi6)9#3W;p8GyV=xzAd=wIU}qsF;)l@;UI9U|l+ zHKU~y!hbrYWdQG zszHdV8Jq=5b6xk8+mh|~jri3?Ai_fZO7k&+^OH$;ZN4LZJiy+F=ark;(bRwMr`GFp zH>xB#J7wqL!S>NPpB@z)nWg4!58Bz<@DA}?p?^^q#?TH6rD*R(V_B(~|LYds%f4fs zV!foc5|Y%GQqwL<#Bnf~A(2imR3Y4sHiu<#W*#3xwE^{fG~`Rhc?>%)VNYXpa^$>u zaZ-LX2J`O4#Tl4qMy<t@=zlO&Ixxdu?RDr}`iuO*s9R-r;i zjdcXCV(VHeb>nSgAocd2Tpfncg$Mnc zjS}fH9n5@y_0j)0<6ix!}N;&(C?;)C*fR!l zUf@6UCl@7yi>Tovgno*&678s8X2WK#%n3xur_9Sj`U3(_$~=ml+)1TuOljN@%6X}a zUVif#u%k(?;;y7yld}{NIu3|3Vn6VEVs3 zW9#AG(f)q&2J+oGezxn;Rd46`J(Y)@!0u0|hW}1yr+z5+$-BRl#=UfohGFBFSNLu+ zmiVDr@#pwytnk0u$5=srY+m9e-h6KwD}rzHo5)sn#Cxa}i53kyhUnZN z&QggDjT&3)0xcbof+LaZBmzv=H?&t=)J3hVEx@SeDW9g$W-&Z(BFWGa@cUq0UXl8L zJ~s(sIrD$axypP~FS&iCc-UFE9?*mEj&DZC(v2)bfAQw4j1`wg z<~6vrlI##)C*i2rg{9|*|6ADH!xOgLRbj)qAN0Hll5QDsaGTHbO-y+TOMB*nk8j*w p{{Oo8K`a)JK=Dru*J>A=#?%j0$#VU>-}@qS=ED7V zKXGaH#F+=a@9x)KeEi_C2QN)-I{yHE;gN?QefW`!Z=9Za;6>f>OJ8*N^xS0UJ0IWM zoSfOeue~w;&Wk@Vo;^N>ht2MK@Zu8}?|SIs?1_ta%`QGZJ9zBP)4N`{Z(g%LnQU!t zZEbFyo4m$cxIdk}dGea?zx3#1k34*E?x9C74j=KK-u2+4-D6%eIfoa|eg6+0({b8% z%mbQTeB_D89(%(K2GkutFgLi#xe1Od-ygsE;Y)8Bf9HkQjoSxbe8Z#XW)~kBKK0yW z_}un**>h))J^sY_J0I&F`^Jk8KYr;!dirCJKXK{7bFaJj$kN-dyZFdWD@9SO9g!Ai$zg9|HUufTHoH=+uS=h-P_*YEna)3 zD4df{GR-0n-Ucp=s)Xa-YN>rtjjkhaqK~DuLDiL1UMS^V6QeB~YfWibKa^Mt*SNn7>_IJx4H@k*mV^;(=ptF%Www$S65f7wQ*Igt>KfP_jq-6 zbzH5E@FyI>?^=V;F?5GN1Fo#XZyL`g`~Q44Jt$uM!dFa+7u|obVlK?el?N|9^owu% z!{yHQFJdS|j9ge>n=0taRiTc-oQJ=3bwohGz}Dath6rtKJRYx&*Ty3l-0HX* zjd6_aKZ0yrAsp#TBSdC#z}K1!`|o`4(nHstx#@Xnyf<{?-GAr3iFEumMZs~n2QBG* z@tUIe<~-?4CY!rE>qt9Hm^#>|lp^w`Dvfu{su*|_wW)*-H4n0k(g+znGmHnrxns)J zB3SFnDln}=6@+$t42{Ov4w0y#f0i1Ie7yYncnv6FoNsk_4I6wP$O@0w*2aV-T!-T^ z{Hv4pQBLVfOIt~% z&LW!Q3dt$4R5c#aF;Wz=8nJ5vJ@f4vb|0^f*H+i6wbiw81%x?X8;{pkkrau==>d2J zJ0aB~bnpP+;I$Fl8WSzUYgq-#{Pd6&D}eK(&F^PcytM~swUTM`i!Gc#+0rJ^>&iSU z_G$A(Nb#s`Q)&}xS85$ZP>~6)y{oycgJnW{Sp%tz*MLTd8{rt+DiBMxHl~5Y$cd!j z9I0u%nnV#&6WnNt5jv+sAUF7*PL`4^KBeuC?Ig6x=4kW(?a?8Dd7*f9(b4Na|HeF+ zM4O+xz9^!LMrmf6COD_-0FX*kOT%Iv8>cG6tq+Wu+65MC99;#n83}F;1$YuxYokPy z$n8j7X@H4bljtW!G1rhS#|u>7eJ^A*5OhX@Qhux{hZ(Lgx|Jy*mZEfvs zZXyj?&Kp)mZI}>R8X1&PWsHVJCPU2xlMyZ`*)%M8#bUHFmfEpcO6Hl-(zB8^HZVrw zEe&J-#de3o*PcjWwNDyJ{1GREJ_MRX%0nTBw}4skdDw3aH7DtdYP7bRsdQ}(E zj)pRr-{{d$1`_~&-hd%HFawj0#YQp1V&GhR78)aM$z%*JdLEhd%1I@-i;64JM8gDQ zLI>ICC>twStfaPDmeqI-1k4yL05B#-tE16s64^*NtD__VTU|hGMFdH7nM7e#jS`v} zf8tocbzF@{bQc?<)}4;Jx0LDf*N!tZZkjVRva)#Ab)DwT%HmJ1BLk!l=I-X!<`k91 z0K9S@Ja!a#BGy)yOd46Ul1Y0$Aw?9}O80S(7Xh+#N~(hlx(aL-?2%O`Y7;^UhPqR^TG`L%VGil@9a(IRC3YoY$BOvuBX9c-cJ(&RcqLK4axe3A%fG zaK5s44UYS8ZtrbPHi{2jUlapoHH_8KggUy=I3vCB!8@;Ps61CJbbwvGwwmZ^HaU3Z zP`Lg2;ll0L=f=EF3bH@upBwPw<&OFAKl_T1NQ`qZo=p#4dBm8n?T`6?@3BZW3hJU` zrN0>HF=CrB^tQE$(K=Qu9V(F5U}YJwx|m>1DAA6oR>z|xN71qdEj}Viffi5tyFrnS zS4VJ6>KTmh1+rZ+7Y^R~;H8J&aOUr2s=cur%)wjlPBP%^&7F37dm0S8xxnN8WMgY* zcRDFPbYoG}T5=H$_l;9VI2J^#$`D{oCTOc1V>;HX6wU`0dE{K_rj|iQA&qT>3$;`3 z#Ke4(PABO@Y(Ka_KW3AIzc(QMnLI)r$(6m84kRs1JQD%>2C{CR_k;EA1FpqqQWhh&-HqofQtaU^*(sF4ZvIJfp^==eF?nB zZdp`6w|+}e0BQEX+gRV*oUEhzF@l-c038J>JX1{DU=?Skszne+No5pwAYC|%HVErk z=~)y)HVmK?(Rxr-Mg*FxqzMU#Ku``DkX9`A2RlbUBJV_<4V+b|kyn)N0SQOCE460sr?g4YFgH|lA^9}uLMM%_DS4jBm}wDZvzL*g8u zxy(4?bH>ppG9|7S1uyR9Me*~+rQS7YeKe<=yW3lZG*X+uoN@q0Fr|-7geq7Ot%*!j zMk%L*W}JH;Rgjj%HjZROLLL9;WY2)?C%c6x2`LE1iqm4G7Bn%TC)nXQM}&^3I?y?V zsNuL_oY{cJVO2mRFYlP{&|v}7X%Ovo>7;cy^AKEmrhRnA)=?TJqm#PkMnuhH%~X`m z2i>?BgRKJxffqIOjuxCxNE0wQ!|6Sl$>!bY&l33UY(U?5 zc2R=8>gt!JjOHaZ@(ZKC9wJH{H_gqk~TSkR(kLPukm z2qjZSN#`6_+Lcw~MbCh~8tsTDii z&h72Jovq@j8;Syi6u1JF=7GuD)rQqE2*zx!xZo^G$x0r1*;v)s$Yc{a`TY8S`62D_ zJ}3D$wAtj~wF4;jKRJ)YnI2tzat?^+l3CFQ;$8D*#gzha(lL#e_Cnvv@mORAI}V6G zgMBhfD`2LfN&}`FxWW^Iq5tiqgAdL$qGp1NpdDk@LU$cOSaIcDl$uByZL35v$-4%V zN}A}Svz*ZA54m@I;&$kl#zQC<*=y)K`5SY-lWcFjlrKuF&+wvn#=O0?xxKZyMbmw* z!J>Dnwvq+weB@F4s2NjbV1`TZ&#_W!rGsvwb`H!lucZ%0NzGwF!b-uSkL>(aEiPv-5dgeMSZi-s{xkU(@& zI;Dk^r7OAgs&pn;BcfDg44gqvrG4}<2*IprxQna_(J2sOG`2iKaLKLp)-vdFzt7_3 zY;hdk^W-fN=K#%R)Y(V#&KAw@zqJ$o8O>`%QA`HZxwE&szC&)($eFT&GZk6sm8z78 zw&Bt$X_N~_aS?+pnRYRlVCo>P(~LRBwQ|yPX~4i$F@iC6GUB|vmP7;{=lOkm1#Z%d zYZr!4w<4PISTw~_Gy%DxpA-=Oy#Z}@XlfRuQCf3rgQ#OPmb(&I*mx~s)QuGuu&t$I z9@f*CZJ6XGXV%FkIv%xjEHuivY@sIxB*TDKMbTDEGlQ#1h&8)Z(N`NiL>Y$m9At>#96s6OaIl+Z%f`|g_Kp_|h zFA9$~DlTgUo)RBx#*EbgUHD5!b(*&10mnQxIjzyJfKya*C=iyoMEQHif!Uu}-MO;A z(gBxA^B)x*z<12+^aSP@Vg*hLRTV7gaUGEP!5L6S)>tc89ip_H#*CvL^|&(WZkk?V z!+FSI)U>4a`knMEtu|kPv06FQ@j9zka>T{IXkk1kek#HEt9bs)($;b?75@lQ&Ew{FDObN{ybKY6bR3kjsF+^#C7pmmC_QD0GolwD&^JK}G zh(xZufy)4AfH)mYsvG9F=sqCnl6+rXhuLKR!$U0ZI70W_(en3iju!d*8MhV1|2@ER zbA4+{X699clFP%eJY~z%vDWCplm2n~iFQI?TBdKdVi&(Oo9uu7bc#Grih&5TS(MF8 zAlA(Re-mMXnOTKk8E3UqOiC@B;=)*1@w6_0#^I_AT3Km$WVLLZicW{1MG#Ku#z|L- z5UkRY@w2!Xw1&PAT&_zNJ1*^@9{`MYV(;WKMT(*xiR)W2Knr!bWy7;Ot-4qT>YhKA z@%e|3n-ur?{9McDK!;geWcg!#ytqjVU>OA=-(bbHuyd)Y& zX(cy_PP|O=bd8pVsbwD@K4pMQ?-XBDYq!E;aj#E`ry`lqV)^;w`26frK0klkVyMwi z-&Pd=cEIO58$0Wy$1Oh*aB={gtt0sEnJv9wPBEAi;oqKzcI7P--JmUD__^B&)3(hf z`=466-1%L9_VRm{@cA=Z!UW(lpJ&1ZfW?3?2}~eN0c#sB)>7~$XjmFz!fRzDXTp{) z@Nvvehy2~K@|lF&&$n2{hC z^HE=hp>MXuH}wE_)^`oPIPabxUN6vK|J`$=o016YkM4gMQp#yZmjgJvzZ7Ypch&T6Nn6O3yXSd?0%cbfk0b_jFhS!_!%SzGqC{zmRgzmtfKhFfR?r<8ymYQQ>72E*kZYi(peLj36&5$ zTBSLlCb*JJmQI^e_^6%oHb@a77l9es#8Q?L_$6BJ# z(pPBtj!cFWztcq>;)D{-GYC{n9uH(;Sh#}an6>fRXgtD2tQ06ao9zG5&^W&bR~@|xm8@ehg)-)jaGM_4vRQ9N~HQE)%NB{HEK&zJ#YAJ)F0Nw}_^QCu5S zI|(7O!g?7>7g>l>P>A@5;>L5d63Hrb(LoUBD%n$s5!YybokP_T-~m-)fGj`=fv<@^ z6Y})Rx|f4Tm)7XL zsHL-3n-CiywaSQCi^y1rLDrF5C%KJYDjp-NT*-oAOe@B@vqABojL-&F5=DQS*^TQ& zZM;nIV;f-FyW4lmb-$QS`~3jUuODa3ugw|r*#Ld&+ZNq&0P&aR-Es*|oM_G=!b0#s zcG7C+osKSgp=#ei*kXt#DifSxnh9w`G|-DhtCV9taM>G2Zr!NRYHzU_4-A6CTK>-X z_^wM@rp>P(w?f}HK+D$0`8#Dtn;Fa>`CCQtcjjqxXLoyRoBZ#!jM|m36dgrSHdv;7 zh@5lfAr8VB%Xz@~8>#AOZ3G=-q~$C|$4t;ZSXL{`2k}eDXh)BAKzhU8<6(IA+T5-5 z57sf#+6H}Q`I?_Ro6OFh(qo)ghXA=unwir9;eR?$nh8zdbY>&3%fLCeE(EQD2{kO7 zc^189s&r*E!g}!90n$816Sc8CxJFeqkJd2b!8K>?lNgdsaU(Rk3`80zjkIUWXAHXY zB`w`Ms>`7b?B?-OJda+?&aD2!-`>qNvnsz%7sYM!)VaH}zBi@mk>XBi#~U95ghX;H zqSLlyMuh+o7Ft8>MIBkG8D+O{FTG_}GcRFTsd1`-sj1B-;`neR=6n{3y6^?0^Ns?O zDbUhf?%sVbUm}+=O)>G6QD86LrlqzUR*st=^})Pj<-!2WYkNzVpZfNq_`l}uqTQ|S zt?5p2_67*uDT>!#dl{fQtzzYbcTzbSb+8;3)>()ty(JI)gssCTfrjZEEmNoWK&KeH zlLA=4lLE&WD}#nUhW%jd`6^mS=!XGxXOsQkT52L4vVu8oVf|DKYv-y1sK0gIL`tw0 zD+KEs!AvTh#2lf+NYFFQtaY*B(z~FT48dt9v=cT+E=uM#GpcmLJqflFMAVOHxCjy& zh@;gtv=c$*jgpm=L>>qVFqJxI6I{b-9cB1YNFN4^qg9%SvZY)ww-SZ-X&Jpy)P}HL zYc9-g0a*X|;(L|_g5R?8*#zNNdaVCF=~|_W;>`nU-QC*T-Y&j$T~Q42i`Gl6njwC` z*BA+mDOBzMXlDbrVSrf5Qltz<0ED2x>y*5Kga$oklY^HIoIm?N_TZ(5{vY#ud4$*Z zrYS#`bp^;V8sI$L{Q11DNV1KB$T~jaUNlh#qoS5IW6@f0u|?KI<5aC==>+GRS;=g) zzJ^$FVU*D^Dr;Sh!VSZ@AgU0Eq+JrAI9QxltkQopH%Z3w8YOeKl8wSYaTx&;JCgj$ zlrUZ}ys5PZRW_0+?PIBUJ6czKsz)4|51-#7q8}UZArZ{yt}TiZ_^^No&ZBYE>^z3T zVRS1B5Q;&ikUNkoG*lcskr9oMtUqv-U{v8UN_q0ZOAo#MyI;RFy!^$9Qhr4*3hq}w zrzp=u&Vh}AcHW&8)VqS3f7Nqw-pKXiJ>qX1=y5|(dZ_Epry~*D8&IB#rGO}R3 zw2iYiK**sK(ghxZ_c4aZWz8XELb{UaMnn~KqmP zcCMXAy!ttdx&frXhvs!d;&_1bXoRejHo7`C(efIi(HslLs3zE`m8@jsN^u`q;1Scg z(OO7$D8xl$7JF_OwucZBrkF-cgKmM%Kgn5@IJ~`_C=c&~@T+ zf8maf*FoY#``tT8`uFkN+1T4yFN&uDuSbY31~)peJ^&)imo}aHj-og-c>4qn=sww4>0r!0=opkV zAqLO5WVHl`khamna(NlG4kZt+j*!wI8}D2wgBB5@^(z;pQQ&`};etItOCl-#IYp!3 ztc1o)Gh)ikK#`LWqT`(OGgp2h9kfTiTixf}K@!&g@;Kdh+tM(>|MNSF;?_iI8BDka z$2~A7>yypxy$xCs*HYHHb~ZFY))q9OY+@rNn4Mb0;K9Ct^dY0Ib-@MYg$8qtJFLo~ zYG!x{F3^g2k~m<9=J^VF5)cE*<4ER2GEFlm*~my|=|QP3ON$V-R6t@CBe!98Noy9c zghml=XyxL3U^dy0r;BWxLo+4A_R)O(AQ`rYW^)zMOhsyNgy>Hj!R#4>U?_DcMR5SO zI8&xs06BQ*ZbEB>G(A*&saLv{zQ1skCzzcKRI}-R?6LVw58S)GEZdo0c~(O6qb+T| zxA?)Ly9UQ|XinF6c6N%Vo>mlB1ZE<}6SiY|F5J#2&I3p|%_awr4k&K_%ZEnv?|*p? zp`-}=2>tybyR{FsB|$A-H0w{ zDguO_a|A+tP5R{*CWP#roqYSrgwUt&EQ;F)6%N+7x2Ics#X8QE`b=eltz9DoM3lk; zVDM0pq>9cl8>It>hK@oiQOa0K+tfZv=3!9*%2FlC-;O=Ec|_WSwj~Cdw=c7NOQ_~+ zsEhIUTF8Z@?KVp60_SUZd*%r!fCGdlH7R7%*WXJ94_Jrn1N1>yc z=3tx(C|hM!h%wa4faeS1@gWA?#kzDcYA=~?XbMk*{_Ab|_hb>67#5cU7CX--`~T!P zyPhx2*8QhFJhQU+{X2`|w-)f+S>H&@SJ4^IY8AZ-q0!noskL?5JMOePxmHQ{676*CnWvsmO(`uB=AawuNxGB{DMu6j zQ506Y#Em92rb>b3hrbmnanRqe2DO^t6#S9Vqws-6S3;_C-Tc*iq*d zW2n6d&dJ)r@)e1>Eb9_#bkc9x_cM2`{b8F_4p6MpT2r!b(8Jc7l_Y{C z;g_Cqcsl~y@c_>gEC-6E?Ed>b0?q6WBH+0T1lqFuX=NmnoPLgsLUUfMNU#%MXR zE-7oQ`A4+623470C57g;tziNjnS*YTm#HubayJUWOrAu!^k7sr)SaG&EzN{FI7w`* zX7c=n(q43<@-Pzru)m1Be^Li#t0Ql}9X%d)}EOs<#f;=?yhA)s)PqAN%*dP2qbzE3i-lXv*qbRv}+UtX#OKzRC^=1Hl>U`&M)Or0<>U`A_>ipnc3$De* zsbf@H)-eT0qMpdQCW$aq@7erGObADL>9O}YXx+uMj?zlb-1?Fwi<r}wjf~+)LGFN)Y2!}#N99D^~a;4zTamZ|9l3Qy6DlH0S%!OMmovJW4cJ-7eixzTTuY11G5&kWh~3P#_5r&qltcEZuG z9WnZA`lHWQ^7>@aN`7Qg6z?0n`|0*%cb(D+tYJ|=?F8nzX3^EMDSec|aiJq?Y9&3? z_+yR>=A@~k@Y)8YxltzgXzNfm3@U$cl=W$HfkrD8^Gfd-!y>@>K$l>Gfu1Zha#O7| z>;REmDNY_{cqqJ6Z6~Ud1))Be?}b7f!sC6kjjbMvL~e( zOS&^ZXKUAJ=G$zt|Nfy&LeKsoGD){e6JQ%U7XaSx8E|ES5|!qapr=jXEL2fwr#aPA z=zD8O2%|3{4U}$l2rP{KsCz_H) zT?fykQ${kViEqmgYwjv8q=k&vy0Y9U#dIB^us+xy*42?a1sR&GIZx&WIS>%NJgDqL zNWpb^pyQ<&EVkwM4*SO3Qwh%#D9w3iO|HN7NRL1tE;?cQiXnlL;C#moMR7Smo&|3x zO=dBbnhFpDUNEaC!H7#KBtqLj>{Q)7acK%y$m3659{3{pYQTYz#NM3#{P>}M)%}lW zPBqg-bL_vIE)+(XY)p42yJX&4?!0r#z^)6bj8@oaoia+54$`2R2+YbTd32Ep6B%cv zW6m@#SRNZ^qtLZdmRrr|0Ii7#p?Lj(QYO&_K{m6yBVV0gr)Ji^S@=}vQ3pMvs zWGR}sCoym5t+9+JU^nDcz<7|%-^Y_R(lNy~li*5ioQ9f`t_~#^uJYhBXq>E>G9r|r zWKr<|#ml0$;5h)pR@aWzkVtzLd2y8YOP~}BbnK@>r4VzSN@LLq$PnfP>v&Su%|rQqc)(ZyK+c7EROk@t687?#N}Diz|})Mf%^yfxtY_k zMkdI&$ROetqDpzNJXqBz$&_`fY*?+NY@`y*>(~Ta%PK^xEf1v)CB)$?uOJ&rm?wMg zpO)no2RU9Kv6Iqr_vMqeY)LQj`pLZa7dI9~r{5@w|8cdGeMbOBTD9i@eCI;Z4;EYHu&IlUBy}{XS^(-NCazS41q@mo9nsY6mz9h zJlfjH^E5*yia-k)7v3?kXsxH8J2B82l83Zb_4h$Ns`WV_Gy40Ei)OlMX*AQ>&CYPl zjQ;%1qJTX<=8%M%G-QZ7X-aJy8zG^TF{Oa~DjzBl7hY%+ zl#&%BkXKC%m9;Fb(k*Au+~zSM`dZRDDUmy*=$!Vroh#zzMXjqRy{(q2;b=D5|G?>H z%vq-cc6r8}bvj_YGo(zy6LfkAhBZ+(8f)Zxrpwy!Qr1yfRR>vf=536OH#XKya3ZL> zw6KeVtsA8pD4VNI@K$mf1=!WeGS7LAxQ$^RJPncH%KJJlwuBDmSrRJkw@%b>H^dQ= z<_C_`={GIa>3_1-iOfuzU)?H-_YX*OYh!nBo4h%yl8rJY?4Aiuom$3##ciWCN=4XY z$LZj?#9c8Us8PD;85Eo6!Ag*rg0WH==VCkO&aSZbAK(RHAi(qkj!o4Xmo)0v&2ZX- z{)H5;Ow-bA9YK(CFEnK~*?;#iRs>nSmn+u~w7b1kL4X}ic)A5-!1!guEyD;;3~#t% z7rFFVYkIC7Su)&|{BuUkTA>ouh(zRjBZ>2}Z zc`o#v*>wNiN2#DQOJm&MvfT;JjOItSi{j6R)VVdC>=Bw$x~g)nf=bK{6lsOS8Y<{8 zE*!XWgRE7kn5+W?i!}juB#8p|vh$t=%XH&{jMaRd=96jm%WZ2zSi9r?)kK?re7d3= zd4=YEEt*}ur(&llzBEL0dotPBp%og?Jy4NETN6rI!#)uZ5*DoGflFs#J2nZaKM-Rl zP4rEWQ8~p*UaQ90M#M6}0@mTH@r!M-Uy21C_8Xk%zWG+qM(79mP_QyA;w;oET2>^Y z59S@M-~=+vIw%WHAlKW5j83G95z3bdosZH*h1=q2DIM1Vln`wy0>h*IP1aJ3Jf#HT zc(b4+ZYIMJLz(apx1>w+!_2x@(6Wv6$H(dPzp>PI2SUu&W@dFD*t0`Ci8#@AKP70Y zsbTvQWvo&GBI}KIoQX1WN!gp^>85gFsI`+vD3cAf1*{I$+`XQQcbD{Eg61C`$Lim* zRB+z7x40Pl{=K5u9ypP9);G6ysUVDTtWui8^juk?YaY4dEJQemfKXOemO&0YGuk^S zT%@hltg#Um$ymdn_>Ped%Hrmk(2||4GJ`_vN=4Eo$Yn=$lvGgLH7jO3#whT1{fq(> zDKfXcKua0qEuh_vFsxy8Y(bd*yz-9LB?rjeI@}m!uP8n;n5ZW-QK_p&f*&bpscI9Y z(cF0p@!wo=7DAAD`><#sqAA)SnT5)DA#xLJ10GLVJFcL*8;+WMIfN_)v}2tXC}W4! zg!8IQl7G~j))86)O?etEnq+A8T6=xr68%8SHf?sb2%^$`UeAzxv>%hpM0c=5v>%U43;9tdw@u2kVCha`Ebd z)rmbcDJcy%PsfSRNQuOk8N0Mt5e@{kI*pmCsE}xAJ+)0F{3C9F=~;6vamdRJymjzBQrj49f)g#~L9V zY}NxA0!BkDaScVPc_kp!5b77ht|(9m(?y6&;ZiB5EDNOsmqrQO|16=>D{sqSr=x^r zhj`wOk(PJxHkB3o&C}&UXG8oGEt(yb0>aw^Doto&@{onSB@Kkz!A_m9)47EhWAI06 zqhQi4oUB!3w&og2h1N<5p|rFP_DOBDbEV?kGxy}epfm6F<1O%9j z5+M*7llEssw`HCzrmxK=`%fKbIrhu_+|jZ+0C(#;5ocy~0C?aI%3xw5)|Fz&ba`9(l4>e-1AI%vD3lR;bU1ZO#$?mu-D ztM?bo?ray#KGTwB=SP3jeo?H?&uXUYu+J0~2)-IHf)X>1&DoG?W6w-uu<2|XH`Rp0 zKD1>YI(L#QJaIj}0D2Y_Sj5nuHWmhJ3XQ7~l%}8;hasi3*)38!)>2E4f{D$yteh^P zpe^my12psc+I~^|(va7;H}@v%$m=HtQymFrRC$xW)&Y^`c=!(|aD8(dPkVNVE)&1r=*;Om&h%Y5mr9C0;(N$J}X4q21X~^`YN{+{m-Z{=Yk&v+`T}Xrko& z$>L2#N3Jg(O3p-@P{ZFEdkQpphvt)zO-=#aNIRI3nv+E~$my|i&|5PTlH?@S;?S%rO z@uTzZh%5$iGn6A~N5CqA4IWk?SoAE^N`}ZH$^66IZ^U&FMPVQYI1COruyS37> zXht*kWZ=yMLQ8D>Jk!+xURLYJq!i z8z1mwQxs5GY!0~Ht;uA9@c~3a)^ZtYQ$n6!1kIo-rDE;46R^>lU`jCOJcIOdD>!WX z&7Et!GAhKuj?B)#2tw9FY9ckH7k!C0V?@)f`W2IwZ5^ zxU(sW|9Pl6wkEqNUH^CxOTl2l@CXonQ$<@26RMW8S+AX@FSYjZ^t1Qd$fra|<|}|G zP6&UkpF4AkoakoJN_?~_ihnaib7y;FopPeD3_xvQiI(#aM40n5&i}}*)g8SnUF*xj zVZ+O5&6>(hO95DOs-M9pU{LF#Tm_CZi?dCfz+I?Z%wCr#XF$Yh_AnS>}6^rRZ4FK_kS+$*ZZ2DD*TBw$`3U~@#VpboKChk)_01t zn38=gBbX(Oz-lg;;7qF8L*+1b7L%9A9%xAz-6X3cN{u3)Nvb?SvredMGair7^iTHv zDwaE>a;_t=I{+|Bt%8l1&_|EU%UH=BrVg~)j8jycd902qcq;J2XNLSBfgdhC{qxUV zq61|svq9fwqqePM(GUps1W?@FibNCS4$SI~-oH9#|Izz?O3K;H2* z*lc!=1cw~VLW~l&;C7zZPnZRsvOqwTsnw92v!>AJThx}X4`IRLf4R`<+yGWMY!iRQ@|$kJN| z44>pCOvaAq{MU%!F95me=P8FYY+d&zTxJL=KW&MG(nh)Br|x(2!N zc{^k*iHp-KB36Q-JEn*S^ef;o%*9aaj_^`)iG zfc)7ZzZ0N1e{jJ|=>a394O6w}K3WzWQzklTgN7ZEg<`@r%IR237JQIGa18}jMZ~pa z;iF;XjibdLs)k0xOH-#T;0O%j@)m)9Yl*b~<8oSJ^d)c}?HJAUIeEb%eg5hTisG3= z`rKJx-=V<61yEwit$+ebio+#sn6yka+{4Cm(F!Ll^E@<>%hEykJA9U2gj|m9WbLH= zQd>a2wGQZF5}D~er8k-4OJu74-mRC)RJq~aA{!uZb&&TxO6%gbJvz#yDBX! z_75M&?l&)GcVO)-Ju`KJ2>8NKdiL1;F&<@CX%NLCN|oe;7!v6FKed-Y$X{RS2Eb+!l~Ld5w;3%LS&`0L0hglq-nwSSf!K9 zDHEf=;@UcW$6nXEw={PtQG2K3@@vQ!@*AB^W;d=}Uii(wdf}qw)y#*qrWc zQ*N7TqJ(|IvF2x4tc;*Yi*RVm5aeg+0tUo)(3iM<}6kq*U=D7B2CC*y)4`W#DW?og(-um6r{&!IbMTG zcWI#$Rd*f{h0ws*!Iz7~3;x}X-;p-a)r&+5`^D1!rnsRanV0mqv@n_*8JzHIR_9Go zLUJi#>LUty>Q-p}d<$i_sB+)EMe$t&oxVBQ+MSTltYZ+-DDSXBR0xc@hHF#TT-)GX z2vTqe`wTjIrR%70OO7(cMtSL7Y-EI>2rZev936B@d#K0xb3d{I>V2XkhIZe$=2)RQ zTI%ooXG`Gxx-E)78w$|Z%{|Hya)=8O#Bj%D_&@~D^KCZ?H4+kORp_es3-8Kynkxos>;s6*<}BBE^phb z-(P~}{r48d%?rf2v%XFKkIR8g8rX;rl8dlvK;yXPOtc2)5+sM05^J}2@_ZZ%F=Pmr zJSQQSrT{r+f-ciPJSG<@z7=5gubeI^A*1=(C1_rMZ&7@3fi`#dc8NAm$<7rl5e3*( zTFIt~kqgU8r&!HO+C(f3C}B0>6~yG zUdcz@mDEVMEH<>(hMc}^W#i1!jUs>!Gn(1h1bW?HKoe;bH;TACIy62wNUHG)E2XL6 z>L*c)Vsapjm`D{O6T7L(cpeYT63o-|1Rwmv0+HFv-u6zdJs;i}w5-$Lb6hxWzXa~M z4V1X&-o-$Pm)*Ni%xAi}0l9C*ld$tmFJ5+MKd?6zFgdT-x^=W1asb2 zT9(Xpc4;!#{XIb2owaOHd}RU9R=Y3d=W58$N0OxtJQyuQw|GPQpyt^ngk#X=c}ZB3 z9W%%O8Kv~|B)~840MQXcrvJ*2JTY$JyZ-Fu_bfqEwkd}%Yni?yPY?uynp2tSKXeT- z{V(586j#LN8BgZCmMPPNG*gy}G=px(*$sFAOaFLTTRo<4|9-D!To>5>wgKDsh3RcA zmA?JHOr@PL{rC43#a|AD>DF|T_chV5n!zJ(Y62VZ)KRh!EsLx%3Zk41>?9MI<;q4a zRb-C)5TWL5Wj8$^37;vmyfI;MG~Y81KTPsRXenHXWzi*=wo6lB%n zm#UoNZap~)9}BnRuSKs1t>05#39eFu)%4%?(Y(%Fm|X{Ge&shlbI+0l&g)t<|NVW7 zJP!z8KcLbcno?;SJ%=q{WD}wZ&d30XoQ}aJ5nRL04$n&IZ*U1s^c25F zShYzDxN1-DgkDrftC=H>PC4awmk11{UMJ<|;baTGK*)r}j!4BfNtxJj7K>hV7n^ z5XmiDVkDVU=ka{SAKW1r&0yRfZP{)+sEH1l8FiWnFdI@OU^^(!nQ=t#oR6_&utR1O zOIbUog7=}}P?Sb9(?G6Fscq??XaEwfgUz){9$*U|rkrG^(T$9;Nko%J)#?+%H;q0y zhkAIVUiovO9dh{utuHa3b@E)pysqJ2)-4ldP4p`-Td3JL-QHT?-Jv}RrDU;$2~jM0 zj10E4HP-6VX-vzOTG!EO2GdbxqKd&uXBw#bl$a5t_lNo!*vb7cu=!1;|bL1ATir`*hrl_3FYR5^b%AM$i%>` zg0Q99tEOf=7-nJ}q;t|a7P&G(f=Qrj>s+1KFv-bwlb**E`l#GosM#VaC+H2*?Mt>^!s9*s0r*!7_x3|SbfG&ULbUO`ax_s3u z7MFwH`--CY%n-?)&FLOV%@THQ(;W0MRFz}WS|y|6kn|ND#48938Y+OAfep)iD5F=L z#ZU_YnGr@o`HMOXUB}~-I4Kr;X4W6~2$mr0i(NFxim6=xd?$GoR&??!0}%mA1^~3$%H(4$3P; zK!;go<`p8K*V~6^5^drN(WwCAJQ@=xnjt>#a0dw@3Czdov%9GI4 ztNn2m0nJc;?6?)8zLBX{Upk;(jrP_v@)7SUHYbKROKwVKRknd9|P1_kyhzoYr!D%f|zZw4NS#ljkd8$C;jq< zANRMXb{IhI_0^?!lT>>8YFyqtUDdIQ zHFKdBF~SZV;HR=!0i+CD^I6qMp>1GFaK<<Ik_EuN3#M${*MJ!wG;k+rRp^GVR3 zs#Muz?(2*08XV8zy1TQrwOu@QLs8U0Lpn$m zLqLzT<4qYk>7cC+w zqtQkL#iDUdG`_2DJU5i%Fuq2R35P**=l z8=Mpd)`Fq7EQHjQF(|H$bVjSF#CfVglZMj{wxhp{_V_5cyPGFz$MnwH@=s6aYR@qq z#X%<-GoC+iP!zWe0uJ}KHug3sq0QEw34?naO9u(T71Iu)x}X*>^HC`o3=fXSz-rb6 zCY3NjbFV!ZCb6nC4~iRCnk#n?FZ(jF{*sp7#To|Lli)}@N5L0xk8i5eG@HzdV^fCu z5uE4R70T~DSgdsQO9urm(3Cc-wU}Lcz+dXAR^Fl@anYw6ANYYgS2KNzQ7m zbg5lsU~xUTriwL>5Sb98GIbqGmWt_TebCLj=hr3joP2d{G+M**6RC(kR8vcf$buh_M(rBq+;&6Pr}EtI+Q0dEOA6P0 z)vk0zIE;7)V*TdFGQuiVp2I?dd7s1 zjpDB6-Ye0}{h zIw%q)5?N8bHF9iFy_B^SVwe#{!ozrk1YJ5vF-E}Q6nC)Nmy#bChQ!qymk~R`Z(mcQY^!KmL z`Ml>$kG%YsdmP@zy;;SxXVZh%_L2DH;q`|;nHN@PJ*vo}9Y!s4tn?AQxJrvs!W691-b8C_%Y&|&JGJIq?0dww53!0{8J5qwb2wPGd%*2S zB$3>{GKXZMsXmgA3~B1G1If;!qaVr7lT6hGl;-+g2}dsXRrSkWzwIa_`^$j0xBl6$ ze?QUWHN`>kn%=dS4ry|0XMMU}y!LwXf-9_oTPrS%6gEZ+@hQwY8NJqxhAkwOWjYES zY;g2Pju-#-r6W3ZLyyM`hqCDx=ZD`n8h&wZ^cyhxpPU>0KO54~m5u(m0bG8|Zy!dl zju`zl{n1yMiyrPw&;LAg(ZfaYLxXoenNIh1){DQ2PkDbEeBBkYK! zSZqukD^*)7R1>%tHU?cwE`04&BSW3YAX9Q5m;p$6HKPq>OT7|bz>id+8%u4&V=*kb zS2Yj6z6OQR*2Z8*08VciQpwj3&1BjC`t5z3k{2Ja$=BR~N)k?Ax^kSLTpVt=h9Q_V z=o$_UD+3T1jUDGc_w&FeaMFxZ%<;=^!XGHcA`E zxv!lLLFg!z=1PbV;_`sYJ_d_zby16D%A;@LI@nz7K?`-#13-2(lZW{atQwPp2|{6E zDQz~{|BcH_l?3Fn8J^Jugw2rdIy9vb5TY&{A%ldOwhD|z=|Q>GJV>T=rFpcbj?Qye zGGncExLb*EIyxp;8EYSP1A*1m2%TxL3{$RQOgaS+cOlma zwcI-2+;J^^KilNTqS+JmvpZKt3C+Dni{jSXi8h}|Xnx|+qWIGRZB94$wx`qLJaTd1 z7Iv79QOKyg0YD*k4GKcBV9Js)FJZe+UREmdCN{y8x->CGrPJIQcke~)fUB|A7*%^r zGaVcsI1*BkXt+w(=?Hs+n4{YF6rN2tXvG{SO{3Z5;No!R{HqUMdg!SiU4PyZv-DU0 zum{4e&n7avzv#ev`hd(5Fdx0HC@KjtRgG`T63V}n5TLJX3(?ZN(pqW7WuwmGpNK{7 zu=XShs`N6`EG$(p?Y(G<+iztOek*Iax#3-FE*!k|!AlRl<$w9MCBr*->nGAszTUp~ zdkfpU25oM5J9}G`4b1flm5+@r%i2SkFcoUnFjGb*ed$fZSyS1v6*kG=k%p0C*J0ZY zEE5hT>(Y!PjWmbF)6ij9)8Vk5c<|Cg|M>s7<9Umg+rbk*+aFf(-MlD%xM+?a7WjUJ zDy3+cErs-!qK@b*k^Y1nmfml&WN|7G9aaL4#`UN+X2k%2W)@_9pPgF==3@ zUE!6Gjcec0p(=p{cuSR3Xg9Z>fTD#3>YOP#$u<=JXm${#lLVw)P|>T9(oF#~+{Sx0 z+5h6{@{`}5ko%6u@;m?eVyky;;hk^oZfxxql84H(CaSXLM93vTs~jW8A9+sj<)J*z zQ)bG;pe-L0iLXL}P5XAUa~=O4EF1jt)){=n-viEI7E4_T*qOw7B^~EV3I!BtN+v_? zG_RPcAv?%OZ<}C^wop6@cC)pmGr`ITuiiBb|44AlVtPInbi^!`?AW1e=xWUAp%IsE)C7QypBjD)mVYbQ*@P2>fwm-OM$z<$? zcCq4>k1aaa|C`5(;(ZI;va`9lMdcw+%nT7WE7HR7(3DVM%4lD@U~AZ>mP3XxL~$)+ zm!1vTe)KPNt)-Z3BjtRlj*#*h)x9P|3+;pyc$fO6UieCe8>TPwt@jP6b8Q?KNSbUw zWuGueq^Auv8%ZDV2^-lU)m1&JV=dJ|?dPUeMrbI~1DoVQD7&d@sa$BlooO0V>%g2U zaUUR{s#MxJZA}NYODphd;^G$2XWAPKt2z^Cz=??>DMpJbk7hZP8-bOu>g03_dA||E z4@J+lc^irK``&lYl4O3q^35I@-nvH~mrF%QuCG{t5=rv`@Mz9s=NeWacGaQSou^%x zXul=cwglxXE+$YNaOCb3vz9C)!YRe^qfW&=bA}+Kk{=0#IeNM#*-8KP#?Rif%udR> z>@OZ))MYo%isBas+_|x_JKdrRMGBHf0{2lvon~cXfXoqHGR|VnAhgodB50!(_oCK} zdsz#vloGX&P3@dxRg9I6zQ2}mHCleuv5!m^Kx*_?& /var/software_versions.txt +runners: +- type: executable +- type: nextflow \ No newline at end of file diff --git a/src/rseqc/rseqc_inner_distance/help.txt b/src/rseqc/rseqc_inner_distance/help.txt new file mode 100644 index 00000000..18f97bb6 --- /dev/null +++ b/src/rseqc/rseqc_inner_distance/help.txt @@ -0,0 +1,43 @@ +``` +inner_distance.py --help +``` + +Usage: inner_distance.py [options] + +Calculate the inner distance (insert size) of RNA-seq fragments. + + RNA fragment + _________________||_________________ +| | +| | +||||||||||------------------|||||||||| + read_1 insert_size read_2 + +fragment size = read_1 + insert_size + read_2 + + + +Options: + --version show program's version number and exit + -h, --help show this help message and exit + -i INPUT_FILE, --input-file=INPUT_FILE + Alignment file in BAM or SAM format. + -o OUTPUT_PREFIX, --out-prefix=OUTPUT_PREFIX + Prefix of output files(s) + -r REF_GENE, --refgene=REF_GENE + Reference gene model in BED format. + -k SAMPLESIZE, --sample-size=SAMPLESIZE + Number of read-pairs used to estimate inner distance. + default=1000000 + -l LOWER_BOUND_SIZE, --lower-bound=LOWER_BOUND_SIZE + Lower bound of inner distance (bp). This option is + used for ploting histograme. default=-250 + -u UPPER_BOUND_SIZE, --upper-bound=UPPER_BOUND_SIZE + Upper bound of inner distance (bp). This option is + used for plotting histogram. default=250 + -s STEP_SIZE, --step=STEP_SIZE + Step size (bp) of histograme. This option is used for + plotting histogram. default=5 + -q MAP_QUAL, --mapq=MAP_QUAL + Minimum mapping quality (phred scaled) for an + alignment to be called "uniquely mapped". default=30 \ No newline at end of file diff --git a/src/rseqc/rseqc_inner_distance/script.sh b/src/rseqc/rseqc_inner_distance/script.sh new file mode 100644 index 00000000..fe00c590 --- /dev/null +++ b/src/rseqc/rseqc_inner_distance/script.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -exo pipefail + + +inner_distance.py \ + -i $par_input_file \ + -r $par_refgene \ + -o $par_output_prefix \ + ${par_sample_size:+-k "${par_sample_size}"} \ + ${par_lower_bound:+-l "${par_lower_bound}"} \ + ${par_upper_bound:+-u "${par_upper_bound}"} \ + ${par_step:+-s "${par_step}"} \ + ${par_mapq:+-q "${par_mapq}"} \ +> stdout.txt + +if [[ -n $par_output_stats ]]; then head -n 2 stdout.txt > $par_output_stats; fi + + +[[ -n "$par_output_dist" && -f "$par_output_prefix.inner_distance.txt" ]] && mv $par_output_prefix.inner_distance.txt $par_output_dist +[[ -n "$par_output_plot" && -f "$par_output_prefix.inner_distance_plot.pdf" ]] && mv $par_output_prefix.inner_distance_plot.pdf $par_output_plot +[[ -n "$par_output_plot_r" && -f "$par_output_prefix.inner_distance_plot.r" ]] && mv $par_output_prefix.inner_distance_plot.r $par_output_plot_r +[[ -n "$par_output_freq" && -f "$par_output_prefix.inner_distance_freq.txt" ]] && mv $par_output_prefix.inner_distance_freq.txt $par_output_freq + +exit 0 \ No newline at end of file diff --git a/src/rseqc/rseqc_inner_distance/test.sh b/src/rseqc/rseqc_inner_distance/test.sh new file mode 100644 index 00000000..927a69a9 --- /dev/null +++ b/src/rseqc/rseqc_inner_distance/test.sh @@ -0,0 +1,77 @@ +#!/bin/bash + + +# define input and output for script +input_bam="$meta_resources_dir/test_data/test.paired_end.sorted.bam" +input_bed="$meta_resources_dir/test_data/test.bed12" + +output_stats="inner_distance_stats.txt" +output_dist="inner_distance.txt" +output_plot="inner_distance_plot.pdf" +output_plot_r="inner_distance_plot.r" +output_freq="inner_distance_freq.txt" + +# Run executable +echo "> Running $meta_functionality_name" + +"$meta_executable" \ + --input_file $input_bam \ + --refgene $input_bed \ + --output_prefix "test" \ + --output_stats $output_stats \ + --output_dist $output_dist \ + --output_plot $output_plot \ + --output_plot_r $output_plot_r \ + --output_freq $output_freq + +exit_code=$? +[[ $exit_code != 0 ]] && echo "Non zero exit code: $exit_code" && exit 1 + +echo ">> Check whether output is present and not empty" + +[[ -f "$output_stats" ]] || { echo "$output_stats was not created"; exit 1; } +[[ -s "$output_stats" ]] || { echo "$output_stats is empty"; exit 1; } +[[ -f "$output_dist" ]] || { echo "$output_dist was not created"; exit 1; } +[[ -s "$output_dist" ]] || { echo "$output_dist is empty"; exit 1; } +[[ -f "$output_plot" ]] || { echo "$output_plot was not created"; exit 1; } +[[ -s "$output_plot" ]] || { echo "$output_plot is empty"; exit 1; } +[[ -f "$output_plot_r" ]] || { echo "$output_plot_r was not created"; exit 1; } +[[ -s "$output_plot_r" ]] || { echo "$output_plot_r is empty"; exit 1; } +[[ -f "$output_freq" ]] || { echo "$output_freq was created"; exit 1; } +[[ -s "$output_freq" ]] || { echo "$output_freq is empty"; exit 1; } + +echo ">> Check whether output is correct" +diff "$output_freq" "$meta_resources_dir/test_data/test1.inner_distance_freq.txt" || { echo "Output is not correct"; exit 1; } +diff "$output_dist" "$meta_resources_dir/test_data/test1.inner_distance.txt" || { echo "Output is not correct"; exit 1; } + +# clean up +rm "$output_stats" "$output_dist" "$output_plot" "$output_plot_r" "$output_freq" +################################################################################ + +echo "> Running $meta_functionality_name with non-default parameters and default output file names" +"$meta_executable" \ + --input_file $input_bam \ + --refgene $input_bed \ + --output_prefix "test" \ + --sample_size 4 \ + --mapq 10 + +exit_code=$? +[[ $exit_code != 0 ]] && echo "Non zero exit code: $exit_code" && exit 1 + +echo ">> Check whether output is present and not empty" + +[[ -f "test.inner_distance.txt" ]] || { echo "test.inner_distance.txt was not created"; exit 1; } +[[ -s "test.inner_distance.txt" ]] || { echo "test.inner_distance.txt is empty"; exit 1; } +[[ -f "test.inner_distance_plot.pdf" ]] || { echo "test.inner_distance_plot.pdf was not created"; exit 1; } +[[ -s "test.inner_distance_plot.pdf" ]] || { echo "test.inner_distance_plot.pdf is empty"; exit 1; } +[[ -f "test.inner_distance_plot.r" ]] || { echo "test.inner_distance_plot.r was not created"; exit 1; } +[[ -s "test.inner_distance_plot.r" ]] || { echo "test.inner_distance_plot.r is empty"; exit 1; } +[[ -f "test.inner_distance_freq.txt" ]] || { echo "test.inner_distance_freq.txt was created"; exit 1; } +[[ -s "test.inner_distance_freq.txt" ]] || { echo "test.inner_distance_freq.txt is empty"; exit 1; } + +echo ">> Check whether output is correct" +diff "test.inner_distance_freq.txt" "$meta_resources_dir/test_data/test2.inner_distance_freq.txt" || { echo "Output is not correct"; exit 1; } +diff "test.inner_distance.txt" "$meta_resources_dir/test_data/test2.inner_distance.txt" || { echo "Output is not correct"; exit 1; } + +exit 0 \ No newline at end of file diff --git a/src/rseqc/rseqc_inner_distance/test_data/test.bed12 b/src/rseqc/rseqc_inner_distance/test_data/test.bed12 new file mode 100644 index 00000000..33a46951 --- /dev/null +++ b/src/rseqc/rseqc_inner_distance/test_data/test.bed12 @@ -0,0 +1,4 @@ +MT192765.1 1242 1264 nCoV-2019_5_LEFT 1 + 1242 1264 0 2 10,12, 0,10, +MT192765.1 1573 1595 nCoV-2019_6_LEFT 2 + 1573 1595 0 2 7,15, 0,7, +MT192765.1 1623 1651 nCoV-2019_5_RIGHT 1 - 1623 1651 0 2 14,14, 0,14, +MT192765.1 1942 1964 nCoV-2019_6_RIGHT 2 - 1942 1964 0 2 11,11 0,11, diff --git a/src/rseqc/rseqc_inner_distance/test_data/test.paired_end.sorted.bam b/src/rseqc/rseqc_inner_distance/test_data/test.paired_end.sorted.bam new file mode 100644 index 0000000000000000000000000000000000000000..8b215e12d1a932f1619cf7ded7e172141f45d479 GIT binary patch literal 10205 zcmV<3CnDG%iwFb&00000{{{d;LjnMD0fmy^PQox0hpTtRm)Hxe<5ULHD+VM;vd!s) z+ok&hE@3OK4I1x#Sl_~Iz@|9l?zE@j$SUWjh*u-d8%zMC+9d0b3kPX^@EAz)ObM}( zWuT_^euV=9Rjy-S+oj2yru(5*gZU;Wl4qw>0;k-%ZsST(C`}g)cFWTuiT89-s3ayK z&sy7Ii=3X56WHr%w89S7C{uiWCPTDz#3XP$C+s z&xA^#5*26?p+YG#h&GCa0JXTSQ0t}~%fLyPigm5zveTlGwPB6vOwqPl)Fl^PDnzFmW7?u=+p4INMy0$-)57F=9+z<$ zj=X;qXEcs88GXz1(p?wF^uS&k)5Y#FouXlSM%TxgWP8Ja_}gFtl=xiw;0cI48;D`;qu&$*o!P{OAn(J>})}&a>wPIMv0kU znTujcaDK7*Y7oV{M{t%~ft%0vaDK4oCh>J^DvD!no(m~vB={>UU8_P$ooZo{l*vxj ztOd1`RN|FHl{_PkIBBHE_K1lr`0pl8Gk27t=a~b@tD-!B+>%p#$?;^oD5Q>u*0l1=Df!87MZROa<}*Jgt59hbtQz0Hxqa4UYr!q2mj(Jvz z*;AR5H~#{h=iAn9q+m6u=~ae|RR41DHDD0HzTz1TYbhu|zi& zZwr8^mFXBT?S$eYWy%O9(grv~?ZJ%jMjGCk2V@N9$-&{lo;4OT@QNvT$vW^-Q@0W?tazQ^M|;I1&4jf|lG?x~7^NFk@viE0 zr#jK(|ef+b7OeZl9RUdB+*Z@tl8SCXbh$^Vxs)bs-T1C&!#$ zzh=%ikLUacBM}KsK^+aE^d~br=ENqatJ@mhRI8F&NL`Y?CNHZZuM6VR=)(Fj5d4ML zqt>$~E52}=!g@UZ?_OA?v7pD!Jd^XiL|bTqtMA5S-g?I`2G-s_n#{Xj?sdTS3kK`- zem|K6WAC2@ZimMwd%Mx6Z;zr{a+VtSHZZ_dsuG==ve265RB71?1)tGC##05;Y?xt8 z$fo9+o0L~=lPWkpLYupISYld@*f%M<#H2_RBm`w@+Kx zVCPn*!}ZSkTQlWvo;6Q#7Q3i2cH@Ba8rzza@qrnh_l)p-VCzS>2JGg+3Ss=Ysb2DU zl5b?Vfv_qG*%+nw>YzGdR$8S|yR>b%W5IIV}=8Nvgdr6mOM{JW>Yvk{uLMTO-MW zA;o3Qs?zEJ!QHUf&Ny=cf{V^<27u=5 z95^pW4vfr#5d1{)|0;=$YkjpfR!E82$Gsz% zf=nh_rX^fyQ^BX!kV8l*UJGlA6jsxvS8l97m~TEc{e|;Pm_6ql=w~jbz;5+$KHS6k zRP>f;7<{{uPa=A~IJ2cJ*# zeJ07HSE6otqFdF$n}^~D*F=H*FoWhtykBsMs0Q^1sT8?q9sDm1T_qV6BwCIX0F2?4 z8zyzZSBTGkjk`^GpSsM+#JWeByC7s5Afnf9-MUzEIQUy%W6R_ujK4MYw>+Li&K`{l z{u3wCagMBTs(7Iam{n20%Wq*xInsNYC3K|#;vLwGXrXH0yCPf!N!bicn0^WdMzxG} zVD_OvS+2|uUgq%RoT0gjop(>z8PNP2cQ2<&Z%U(RcgD`+)03TJmnKEUOSCDz8MygE zlmgCH!+0xrB@`%#FjXU0B^Byk8YLrmFyO9Am_*L1LnfIVTwx43V>dpvG91}hYlirK z0M2Dj$+7J(bh$mC$v2{zu0)fNo99Uh;V;a%IiLxz6|hOk5R9g^F;&Y{K_XmrGBrjb zm)8=uHNu3B>S+nW1kMVUAUJ5?#2AS)h*c{UJajLB&M}C6u_5jwgK`4F^0N!ykTcCu z;O1sDU$ipo{Oxp^n-46a=;^6ra=3#!(2|-3!A`X z6ELrC4ZsCz{=;Yh`2ML)_h9DKD{x+@5O0wkm)Z(HB?Azy!o^N;6CmZxN2D~p#Yif% zFyme<<1ln_c+Y*Sf;C@)vD`W{@rrY;hwb32;N^6_y0jT9_6x->5{Sl0iLos)b5z(vE?(2=H{5ih{|yOYuUfQlZ=Jvp5;w z2utEZIZHPe4tmo~@onDM1{@>v(FMTrGjlBOUt@dj@8$dV7R&N|?>$lUzh_t;>>Tbn zH}i%;$@mSjJs}*+CuCef%*@x}dTp6cHK+S)0Or>(X2?TO{9F&_2YWY@$a*l7Z%0gW zGfRzggX8*Q^UGp~C`op3;bE;>)SOjSUdcm6&2^`QR;Y!qeUqGTuaxsE_bj&>eHdf^b0+7< z`^P)Zj<@Vw!0{Py$c$0$K52_CP4JU~BKx;5${TgWtA{sOqNO$ufcf;wa_5iy_t!nN zLeB5)iTUAs200JJB!JTyF&&shOc-w}8`nH#jh0jzO43e>isNTnD8m}wnhtPP30!yh zo~VPsTNf>`q#8blmPHm3g%cQ{Y>?JopHYj<$lneb=n=KnqjP!V6^QxtCStyDLd>su z+iY zoR3VWH)=Gv`jN@(_M8eE&+cE(nR3zDg$B-SawoFYcc}kP8fNOKP>gWH`z@=WNz9fpC zpKQv;~sMrEO5_K1ZNJ*v3G(~)bOfaFAGQkt1mt<9>NZl#XwWytHV2Mi+ zw-+4wJII;l-l=znIPMFY-f}x2MwPcRL`$*Hr`ead@?9Qk%AwYr^_Sb4C#mSnXFRM3 z=e9kEzOqHWh<)=J>2)Ca$Mf`DJ}cmjjeWjVZ4I~)mN$WM{~#Lhy=lfchh>AaPu`AK zbTeE~ypv6b0F#`3s(sPHXxR+gnpYo*eC*`Wk(g)?i|b)Uj!ZY9;cSb&5i>2FYr}kS=1-;ao6dl2W0n zTp?r^sEn#s3x*1GDl4iarsFX4f`Yi@2K58+stfJ+aawLEK{dLL;QX^q&U`j;=7R(J zMJU`{6gVP3@6GRfNJE9$j!s`^O6$TMy-8IyRvC$rDWaZ)m$IRtB9j>~0?&v^uH{@JDq{oRuaeaLbC$6`5ZfA3$8qMx2} z^B9HfBbR@#IW%BFrD&6C(IV;;9aJGh!H4=FZ~}E9+keAFZBUve8v__oLV_wqEu_Os zYSFS;|5ARw$*-wcj6$Y7Jea+C?&=u6w&A`9{TkjGInM11W{g91h>#1^43bU=|JIb6 z9!-+;1PS=M(0~uICW1^P*=s7CbtrL2l!%ZHL53Xwrzs)L3VN+Sm-BPC$SAsJ%FdJH zozp!R9tnoXQn983?M$Uv3;Qimzo>-P)L|hd^o8to`!boj zaod=;GWj^+7WZddf-3e6ER;#1$F^6d^!-7U)uPpB)Zo62eKS{P9YnZKnR5$i0f8fB9-N)rx=PuY(s+SS=f&1~x#mY=wYzLA z6Xb5qll=aM_|pCy)|&zAT?Fel-}LLN8o}?{`XdkF{~L+^Px`SEqW^bhY&|(VJvxfM zgLrq2pJ_W()tfnfkLSJ<*e;>!|64yhc0;)f-rcD<^wL=x`o=Nm;oFNb#h;obf3Cg{ zGyFf*7s3p09fc|H3$}vv*gVBcy!rOjR(Rd!n#cw@Vja8{juH(jhN#@Y&QgjEg&I>S zfszhL!4Sx`90sQCYU&kFD^W>f1Q=C6?!pvm7Q_7}lJq43*9U9kirD>gv59wzX0_O_K%{X`G?T%i|YS+{+icbYonGRg7bzxQ^A>=NPh>T2M((xs-!l zDdie7U0Z(^5>(6G5_xs)>Yq#%_lriTem(dWUzf|C?=3*}-%SF(*#@vilJQ3usP z2em1b_o?NO!_sMnaH2Da9AE+A)9Q*N9Ft87fF%lC2zjYR0%3-(sG^`D!pV8s=kmOq zx0OtzsnO3-)Vdg6KJtg%sorSP+T>7#9@hMjD*MDH$Ct0HR}pY?$Cm(pQQ0Rp>9RW}x-8g+ zH@tM&Hjozh^wc(Zi6=PMBZPDT_*z5QTZU+?MI}I2m1w|XDR>DdSiquy-pttL+}2z0 zerV=Gq(vT%Ebo`=SuE``TJNJxSm};94iY|i&;$EP4J_6G83=n;U(|Zr5PLj7e*Ylr z@9=nj{(h(Z$9Nv^pYHEO(f5(8!_h_k4`~8anqe}fDH4izX>Fe1$Q39-%Su{sx1-Ru zk{xtqx)d~A?ugGA&j)AC{T6WS&GS_9GiO#yu0HcequGaYLU6ALr4P&m)*(Xf6*C=b zadk>*JeG8V;u6Epu2Q+yfi; zi+(2CPYgQ9J(}%Iv20BP&whWC?Yn1Xo8W%}n0L<#;xzW5*^if$(L!t+4SfX0}p;f?&hEHn1{4J2aQxt+O0L6I{=3<>~6Et_G z)TFVu%of9r&}?oXntqcSJ42gK!_@3-?P42e$a0VEBKG_Wg`0fbr@F}U!19sd>njRl zVPATb_cthTQvgjfPEN>KdiUlLnsVzU9?dWI+hYtGHRo#W%<=t-!->jLv) zK|+4P(<3>aFC!$3-aa>k&z;%PfAzTuLf#OL5qi&@Z#M`b`^Q>mYC(}CJqlru@4(1> ziZ--T#rd>;I9^~mIu_$ofpiNu99TpMy>tyiV@vwnD?LK(%Le`SL66W^Fm~V8j6+99 zdxxjdj*XPYLRD$RpbZk(2(zgGs5{z`q%`nCTLbuz(2ypDPgQV~4BMve3{N^LDww=C ztgFeeGBgT61Q&C<^u}9}I3F8?Jodtw^?Akqdp@oTy49u2`Rx1F)CcbC{rZ3UvOye! zU;inL{j0e+9_^usZyoz}=*UDea!ym)wyG5x9!f1L%6w5jKJ}o(WTTpDBobq?c|5;p z41d`p{GM!7-f_=eOl>{Qy2y>r33$h0fdt9Ijahx!%nG4Y-bWA)~rD(ERu& z)4RR0diALu%^`><#{R@y6%OpYZVY9YYP=lU^zl9y5d>|j@kfMN5ufL?%kpt!Pw=(# z@?zuw?hWs?MY}EgM#D5%VY@w;Wr9 zO%C$BuQhr9#%9>Yojs1Q@fsaFxdHjvr>1zGqa2v76!))=2pYtlRKP2i2-=JLMRjDt z8KV?ArM?sqN9C(VL+ z@1Do;u$hFv4O2@$v=@1Letc8u|F%i#KLmk4{lH+?Lvi)J82j8@d7hjcpB%dCYMXY3 zbzO?^H=!Ctswyr}W}(tbgHX9e%uG$EaEUrFk(wxI88*CZozPwg2(6JvK+f4m%x?Eb zS69irW%fPLJrU!wH(C@I0=&#M_{4rIqwr-z6NhEiztml3TiI>Y92UFxZPplF#4fc= zVE)d^a@FsB>^B}-u`cwko|^A{V374dO#=Akb80#;-D0uzprsBp?Lh-`Ycg7>Xw}rQ zXBSAI{+}jxmpg}!FXmZljJCYW@{uaFQ+AkT6Y*T1lJUx7sfB<3ib>e=JDV&~ywVbh z2bcY%`!V)U=G$5B@9iJ%J4?jUMlh)W3Qr3#6DgdofX9TivZyItBkPW~9!Ik5AIP3*jNB|9Ho!Ol-TxRhGl z-96kr-gl+j3-PakW`NE#Re_utijZ2c7MLRQ%o|yqU5J|xp3TBDBJ04*ETl3<{zJ(8 z4{tE|W_B}@RVzv!ShF&8sCInn!DYXbFur5X&H>Lg_`tbGL{7Woaa2NTc>A=gQ3~w< zjG3ZxDD46Ql^`U(r`sXMbS23?kL#o~8*Sh?UH(2#C$7E|SvjiWja{qx)$!yeoUuaZ zfi)Xy4SuKDS?1@XyHWJkS-`$`cyhSoHn43;S5`>pssaW+5wuYeqbhMLRFN{J7_DrA zbJPNIT8~Fdb11Jt8y!_i2kqO!C;?e@ku6oGj{MmUq&u^s=iKd#Ipp5GxeM=``LpyK ze&<~q{m#25fPUA5_t_rM$D*Gdjs5Ig;7?BX4)>y*_7dTV5DL0bm0HuvCx#-ML9SfX zWc3qXBm(HBP^dgr@C2?iG@m21;xq{L+IfcTGiPs4_?gM<51eZ=p8Y?bi|2LB{t`O< z{6`Qcntirr_BV}ZAH3w9-DNNNZ5aFL?A{|JKG|{02~Z<6DeawrDw#}BcjXPFifhGS zJd>stFqN_u37#hkCe)-I>;as-N>s>=!M!UQL@g{~R@eLB!aA*PGp~@dcd3NM!VSf4 z3%1y~$9}IgdjWNF`9AqLZ1U;%c5=I9QLB$#@0t0kjFlamU$7ft+PD?w>?gXuTT&$=3sE)&Qw2kXmYSLz7>t-YK8d z{Nm~5tE<9*@?&$IB-iL9*&EGAc9)Y21n*DIq|!rajpp^BCo7Ezr9^mwu_W(vUwucb zo8hQ4bME2(g&d>c#Y_3eHtG1=RvOJmcbAGXV4&lnusdZg$4&2S>yYzIb^r5(QUU+ zA@fZNW60h;r{Il+Yzjy|nasLl^mz<%c^+H5ijaY2_X4tat%L0531p!|^h1<&Qwb)xfWO$biq`OH*o!lKzsor#OU+vD$OZ|Id*|F` zTz&B~;OLbCS=X(NE6rX!$w38A`oE3f44(8i_LeiG`v*IR2+GKlzA;GBz8&j5=@lZE zuXwZ?+Hu-%bZs`fY_!drKfugixtu5cjTQEU;C<6vm>rbXp4<=^Wz(hgcG$?xmU%6# z@pz)kk49Uh(|=Sh=P&+#PbpRLagl5Y3NB>iR*>bRw@Qq(o^Uo-+~ z1o%COhM_Ha!;y3Dq-k_p^AeXzTvfC%;ygtW3eh%{XZ83f{nLxw@+7^T*#zNg^RZ;4 z)*r!>-rBlc_Wn)#%c`@(*uR;{`oZqr$^L2h^qcEK5%tarnfw%a)%@H$?gT^@YpVd?qNi*2p-SGES^0zE@J6CwQLGjaE5?%0h8S&4F7 zf>Z=j_*Ben8zetbJnl5o`lW%hjXX25TAUnoZnS1d={E|=3m9`%Ak0HNt@sreA%_qy zvpc=JB4lXxDtq3>Wx2Z8HbFES0ePNdECE5#Kf0-#>CTniOxp*8;}`_}VT}F3oR_pG zjdR42XDDRbw1yUxCP)$z{mM?4Ey^CCo6^vs(2yL(<+4l)p=FnLDUuID@RAmgmyN;I z;HAqm$LE`@f0nPiY^+k_ksgji%`^6O>8wxn_`5Yp@Bq(GUMyk`HvQoq&ky!CoiIM0 zGt=QoHeI9Y(HN9H>>l}WD2uvc1Nzu}$IJ9*mpc-VV zfNj@u=4O%EQjVveoA|=T!SS?{)tBwg*d{3USGbPZ3$KT;pN6=w)coWon||j?oBplC z<(T_VG4`?f=Y{Q`oF2JsjwpE}s)9Z}lae|$q}Xn53tWYOG*=12#*T6OsTkDM$d&05 z+H4+LmXpRz6A-pi%Jeb!Xpyq}%6yl0o|SVK%J0^=3QothGs5*=t-6>fb9$wZjuxZV z6yW)hd9TQQvqjEqBI>~e5q2)%84AdR@oVQF8Rqb`?G4urBdfv78miN+ptSqj#eTI> zwg~%ClX;34zE0P#x3}Lym>maB4%_W`470(MpQ#;2OAdP9)GN-H0?m)CGeLK(>~a5v zqvaI?e~7VfFMXQb-tMVGlXF#;N|m$|b3>c7(!-i|&_R(?Q7RYGE_9h7hNNaO2)nF= zN$qFZbscKW2|P~CO*!4C`Nr*~x9Z5|u$~zR5Srh-*rpqyLi5q1LDoZsCOU?{IY;wo z7e1$}(2(t+9Z4k0nNXMXIT6$nrr~~S##Kch$Hr;tk8-T+8bBvt%L@<^3AQFRNK7JP zzsR!KMJh_kd;(W*@%#$evxE6zVWS}rRPUGG`?Y(Ps* z+o60(=unGLM%a(Vk)St|nz;{Pu>zj^&o{|@kGxwFWak?crITjo7}{1Q`!IGN9GKLNBIi literal 0 HcmV?d00001 diff --git a/src/rseqc/rseqc_inner_distance/test_data/test1.inner_distance.txt b/src/rseqc/rseqc_inner_distance/test_data/test1.inner_distance.txt new file mode 100644 index 00000000..e5f09f8f --- /dev/null +++ b/src/rseqc/rseqc_inner_distance/test_data/test1.inner_distance.txt @@ -0,0 +1,49 @@ +ERR5069949.29668 -4 sameTranscript=No,dist=genomic +ERR5069949.114870 -45 sameTranscript=No,dist=genomic +ERR5069949.147998 94 sameTranscript=No,dist=genomic +ERR5069949.155944 -105 sameTranscript=No,dist=genomic +ERR5069949.184542 49 sameTranscript=No,dist=genomic +ERR5069949.169513 -92 sameTranscript=No,dist=genomic +ERR5069949.257821 -139 sameTranscript=No,dist=genomic +ERR5069949.309410 13 sameTranscript=No,dist=genomic +ERR5069949.376959 -66 sameTranscript=No,dist=genomic +ERR5069949.366975 -106 sameTranscript=No,dist=genomic +ERR5069949.465452 -19 sameTranscript=No,dist=genomic +ERR5069949.479807 5 sameTranscript=No,dist=genomic +ERR5069949.501486 -82 sameTranscript=No,dist=genomic +ERR5069949.532979 -96 sameTranscript=No,dist=genomic +ERR5069949.540529 -61 sameTranscript=No,dist=genomic +ERR5069949.573706 -63 sameTranscript=No,dist=genomic +ERR5069949.576388 -77 sameTranscript=No,dist=genomic +ERR5069949.611123 -125 sameTranscript=No,dist=genomic +ERR5069949.651338 -33 sameTranscript=No,dist=genomic +ERR5069949.686090 -29 sameTranscript=No,dist=genomic +ERR5069949.786562 42 sameTranscript=No,dist=genomic +ERR5069949.870926 -22 sameTranscript=No,dist=genomic +ERR5069949.856527 -69 sameTranscript=No,dist=genomic +ERR5069949.885966 -32 sameTranscript=No,dist=genomic +ERR5069949.937422 18 sameTranscript=No,dist=genomic +ERR5069949.919671 -116 sameTranscript=No,dist=genomic +ERR5069949.973930 -79 sameTranscript=No,dist=genomic +ERR5069949.986441 -22 sameTranscript=No,dist=genomic +ERR5069949.1014693 -150 sameTranscript=No,dist=genomic +ERR5069949.1020777 -122 sameTranscript=No,dist=genomic +ERR5069949.1066259 -4 sameTranscript=No,dist=genomic +ERR5069949.1062611 -124 sameTranscript=No,dist=genomic +ERR5069949.1067032 -103 sameTranscript=No,dist=genomic +ERR5069949.1088785 -101 sameTranscript=No,dist=genomic +ERR5069949.1132353 -142 sameTranscript=No,dist=genomic +ERR5069949.1151736 -55 sameTranscript=No,dist=genomic +ERR5069949.1258508 62 sameTranscript=No,dist=genomic +ERR5069949.1189252 -98 sameTranscript=No,dist=genomic +ERR5069949.1261808 -88 sameTranscript=No,dist=genomic +ERR5069949.1246538 -122 sameTranscript=No,dist=genomic +ERR5069949.1328186 -64 sameTranscript=No,dist=genomic +ERR5069949.1331889 -132 sameTranscript=No,dist=genomic +ERR5069949.1372331 -29 sameTranscript=No,dist=genomic +ERR5069949.1340552 -140 sameTranscript=No,dist=genomic +ERR5069949.1412839 -117 sameTranscript=No,dist=genomic +ERR5069949.1476386 -98 sameTranscript=No,dist=genomic +ERR5069949.1538968 -133 sameTranscript=No,dist=genomic +ERR5069949.1552198 -67 sameTranscript=No,dist=genomic +ERR5069949.1561137 -59 sameTranscript=No,dist=genomic diff --git a/src/rseqc/rseqc_inner_distance/test_data/test1.inner_distance_freq.txt b/src/rseqc/rseqc_inner_distance/test_data/test1.inner_distance_freq.txt new file mode 100644 index 00000000..908326ff --- /dev/null +++ b/src/rseqc/rseqc_inner_distance/test_data/test1.inner_distance_freq.txt @@ -0,0 +1,100 @@ +-250 -245 0 +-245 -240 0 +-240 -235 0 +-235 -230 0 +-230 -225 0 +-225 -220 0 +-220 -215 0 +-215 -210 0 +-210 -205 0 +-205 -200 0 +-200 -195 0 +-195 -190 0 +-190 -185 0 +-185 -180 0 +-180 -175 0 +-175 -170 0 +-170 -165 0 +-165 -160 0 +-160 -155 0 +-155 -150 1 +-150 -145 0 +-145 -140 2 +-140 -135 1 +-135 -130 2 +-130 -125 1 +-125 -120 3 +-120 -115 2 +-115 -110 0 +-110 -105 2 +-105 -100 2 +-100 -95 3 +-95 -90 1 +-90 -85 1 +-85 -80 1 +-80 -75 2 +-75 -70 0 +-70 -65 3 +-65 -60 3 +-60 -55 2 +-55 -50 0 +-50 -45 1 +-45 -40 0 +-40 -35 0 +-35 -30 2 +-30 -25 2 +-25 -20 2 +-20 -15 1 +-15 -10 0 +-10 -5 0 +-5 0 2 +0 5 1 +5 10 0 +10 15 1 +15 20 1 +20 25 0 +25 30 0 +30 35 0 +35 40 0 +40 45 1 +45 50 1 +50 55 0 +55 60 0 +60 65 1 +65 70 0 +70 75 0 +75 80 0 +80 85 0 +85 90 0 +90 95 1 +95 100 0 +100 105 0 +105 110 0 +110 115 0 +115 120 0 +120 125 0 +125 130 0 +130 135 0 +135 140 0 +140 145 0 +145 150 0 +150 155 0 +155 160 0 +160 165 0 +165 170 0 +170 175 0 +175 180 0 +180 185 0 +185 190 0 +190 195 0 +195 200 0 +200 205 0 +205 210 0 +210 215 0 +215 220 0 +220 225 0 +225 230 0 +230 235 0 +235 240 0 +240 245 0 +245 250 0 diff --git a/src/rseqc/rseqc_inner_distance/test_data/test2.inner_distance.txt b/src/rseqc/rseqc_inner_distance/test_data/test2.inner_distance.txt new file mode 100644 index 00000000..a1930c9e --- /dev/null +++ b/src/rseqc/rseqc_inner_distance/test_data/test2.inner_distance.txt @@ -0,0 +1,4 @@ +ERR5069949.29668 -4 sameTranscript=No,dist=genomic +ERR5069949.114870 -45 sameTranscript=No,dist=genomic +ERR5069949.147998 94 sameTranscript=No,dist=genomic +ERR5069949.155944 -105 sameTranscript=No,dist=genomic diff --git a/src/rseqc/rseqc_inner_distance/test_data/test2.inner_distance_freq.txt b/src/rseqc/rseqc_inner_distance/test_data/test2.inner_distance_freq.txt new file mode 100644 index 00000000..021311a2 --- /dev/null +++ b/src/rseqc/rseqc_inner_distance/test_data/test2.inner_distance_freq.txt @@ -0,0 +1,100 @@ +-250 -245 0 +-245 -240 0 +-240 -235 0 +-235 -230 0 +-230 -225 0 +-225 -220 0 +-220 -215 0 +-215 -210 0 +-210 -205 0 +-205 -200 0 +-200 -195 0 +-195 -190 0 +-190 -185 0 +-185 -180 0 +-180 -175 0 +-175 -170 0 +-170 -165 0 +-165 -160 0 +-160 -155 0 +-155 -150 0 +-150 -145 0 +-145 -140 0 +-140 -135 0 +-135 -130 0 +-130 -125 0 +-125 -120 0 +-120 -115 0 +-115 -110 0 +-110 -105 1 +-105 -100 0 +-100 -95 0 +-95 -90 0 +-90 -85 0 +-85 -80 0 +-80 -75 0 +-75 -70 0 +-70 -65 0 +-65 -60 0 +-60 -55 0 +-55 -50 0 +-50 -45 1 +-45 -40 0 +-40 -35 0 +-35 -30 0 +-30 -25 0 +-25 -20 0 +-20 -15 0 +-15 -10 0 +-10 -5 0 +-5 0 1 +0 5 0 +5 10 0 +10 15 0 +15 20 0 +20 25 0 +25 30 0 +30 35 0 +35 40 0 +40 45 0 +45 50 0 +50 55 0 +55 60 0 +60 65 0 +65 70 0 +70 75 0 +75 80 0 +80 85 0 +85 90 0 +90 95 1 +95 100 0 +100 105 0 +105 110 0 +110 115 0 +115 120 0 +120 125 0 +125 130 0 +130 135 0 +135 140 0 +140 145 0 +145 150 0 +150 155 0 +155 160 0 +160 165 0 +165 170 0 +170 175 0 +175 180 0 +180 185 0 +185 190 0 +190 195 0 +195 200 0 +200 205 0 +205 210 0 +210 215 0 +215 220 0 +220 225 0 +225 230 0 +230 235 0 +235 240 0 +240 245 0 +245 250 0 diff --git a/target/executable/agat/agat_convert_bed2gff/.config.vsh.yaml b/target/executable/agat/agat_convert_bed2gff/.config.vsh.yaml index 306ee9a1..4540e724 100644 --- a/target/executable/agat/agat_convert_bed2gff/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_bed2gff/.config.vsh.yaml @@ -235,9 +235,9 @@ build_info: output: "target/executable/agat/agat_convert_bed2gff" executable: "target/executable/agat/agat_convert_bed2gff/agat_convert_bed2gff" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/agat/agat_convert_bed2gff/agat_convert_bed2gff b/target/executable/agat/agat_convert_bed2gff/agat_convert_bed2gff index fb78ac59..76c95753 100755 --- a/target/executable/agat/agat_convert_bed2gff/agat_convert_bed2gff +++ b/target/executable/agat/agat_convert_bed2gff/agat_convert_bed2gff @@ -515,9 +515,9 @@ RUN agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.t LABEL org.opencontainers.image.authors="Leïla Paquay" LABEL org.opencontainers.image.description="Companion container for running component agat agat_convert_bed2gff" -LABEL org.opencontainers.image.created="2024-10-26T13:11:21Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:10Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/agat/agat_convert_embl2gff/.config.vsh.yaml b/target/executable/agat/agat_convert_embl2gff/.config.vsh.yaml index 5202afa3..b0ee8c35 100644 --- a/target/executable/agat/agat_convert_embl2gff/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_embl2gff/.config.vsh.yaml @@ -225,9 +225,9 @@ build_info: output: "target/executable/agat/agat_convert_embl2gff" executable: "target/executable/agat/agat_convert_embl2gff/agat_convert_embl2gff" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/agat/agat_convert_embl2gff/agat_convert_embl2gff b/target/executable/agat/agat_convert_embl2gff/agat_convert_embl2gff index b049fdca..87ddfc02 100755 --- a/target/executable/agat/agat_convert_embl2gff/agat_convert_embl2gff +++ b/target/executable/agat/agat_convert_embl2gff/agat_convert_embl2gff @@ -505,9 +505,9 @@ RUN agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.t LABEL org.opencontainers.image.authors="Leïla Paquay" LABEL org.opencontainers.image.description="Companion container for running component agat agat_convert_embl2gff" -LABEL org.opencontainers.image.created="2024-10-26T13:11:20Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:08Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/agat/agat_convert_genscan2gff/.config.vsh.yaml b/target/executable/agat/agat_convert_genscan2gff/.config.vsh.yaml index a75c4832..41b019a6 100644 --- a/target/executable/agat/agat_convert_genscan2gff/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_genscan2gff/.config.vsh.yaml @@ -230,9 +230,9 @@ build_info: output: "target/executable/agat/agat_convert_genscan2gff" executable: "target/executable/agat/agat_convert_genscan2gff/agat_convert_genscan2gff" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/agat/agat_convert_genscan2gff/agat_convert_genscan2gff b/target/executable/agat/agat_convert_genscan2gff/agat_convert_genscan2gff index 90ae4d54..a87f36f8 100755 --- a/target/executable/agat/agat_convert_genscan2gff/agat_convert_genscan2gff +++ b/target/executable/agat/agat_convert_genscan2gff/agat_convert_genscan2gff @@ -514,9 +514,9 @@ RUN agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.t LABEL org.opencontainers.image.authors="Leïla Paquay" LABEL org.opencontainers.image.description="Companion container for running component agat agat_convert_genscan2gff" -LABEL org.opencontainers.image.created="2024-10-26T13:11:19Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:07Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml b/target/executable/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml index 3c3b21b5..05425917 100644 --- a/target/executable/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml @@ -228,9 +228,9 @@ build_info: output: "target/executable/agat/agat_convert_sp_gff2gtf" executable: "target/executable/agat/agat_convert_sp_gff2gtf/agat_convert_sp_gff2gtf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/agat/agat_convert_sp_gff2gtf/agat_convert_sp_gff2gtf b/target/executable/agat/agat_convert_sp_gff2gtf/agat_convert_sp_gff2gtf index b5b5c2cc..71c963e9 100755 --- a/target/executable/agat/agat_convert_sp_gff2gtf/agat_convert_sp_gff2gtf +++ b/target/executable/agat/agat_convert_sp_gff2gtf/agat_convert_sp_gff2gtf @@ -519,9 +519,9 @@ RUN agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.t LABEL org.opencontainers.image.authors="Leïla Paquay" LABEL org.opencontainers.image.description="Companion container for running component agat agat_convert_sp_gff2gtf" -LABEL org.opencontainers.image.created="2024-10-26T13:11:21Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:09Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml b/target/executable/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml index 10eaf2ea..df3445ed 100644 --- a/target/executable/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml @@ -188,9 +188,9 @@ build_info: output: "target/executable/agat/agat_convert_sp_gff2tsv" executable: "target/executable/agat/agat_convert_sp_gff2tsv/agat_convert_sp_gff2tsv" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/agat/agat_convert_sp_gff2tsv/agat_convert_sp_gff2tsv b/target/executable/agat/agat_convert_sp_gff2tsv/agat_convert_sp_gff2tsv index 0ac462fa..0749315f 100755 --- a/target/executable/agat/agat_convert_sp_gff2tsv/agat_convert_sp_gff2tsv +++ b/target/executable/agat/agat_convert_sp_gff2tsv/agat_convert_sp_gff2tsv @@ -484,9 +484,9 @@ RUN agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.t LABEL org.opencontainers.image.authors="Leïla Paquay" LABEL org.opencontainers.image.description="Companion container for running component agat agat_convert_sp_gff2tsv" -LABEL org.opencontainers.image.created="2024-10-26T13:11:20Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:08Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml b/target/executable/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml index ce34425f..ddb3ec05 100644 --- a/target/executable/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml @@ -195,9 +195,9 @@ build_info: output: "target/executable/agat/agat_convert_sp_gxf2gxf" executable: "target/executable/agat/agat_convert_sp_gxf2gxf/agat_convert_sp_gxf2gxf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/agat/agat_convert_sp_gxf2gxf/agat_convert_sp_gxf2gxf b/target/executable/agat/agat_convert_sp_gxf2gxf/agat_convert_sp_gxf2gxf index 14f0a337..62a728fd 100755 --- a/target/executable/agat/agat_convert_sp_gxf2gxf/agat_convert_sp_gxf2gxf +++ b/target/executable/agat/agat_convert_sp_gxf2gxf/agat_convert_sp_gxf2gxf @@ -493,9 +493,9 @@ RUN agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.t LABEL org.opencontainers.image.authors="Leïla Paquay" LABEL org.opencontainers.image.description="Companion container for running component agat agat_convert_sp_gxf2gxf" -LABEL org.opencontainers.image.created="2024-10-26T13:11:19Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:07Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/agat/agat_sp_add_introns/.config.vsh.yaml b/target/executable/agat/agat_sp_add_introns/.config.vsh.yaml index 8b19da23..1bb83d2d 100644 --- a/target/executable/agat/agat_sp_add_introns/.config.vsh.yaml +++ b/target/executable/agat/agat_sp_add_introns/.config.vsh.yaml @@ -186,9 +186,9 @@ build_info: output: "target/executable/agat/agat_sp_add_introns" executable: "target/executable/agat/agat_sp_add_introns/agat_sp_add_introns" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/agat/agat_sp_add_introns/agat_sp_add_introns b/target/executable/agat/agat_sp_add_introns/agat_sp_add_introns index 5a030580..9acefe5b 100755 --- a/target/executable/agat/agat_sp_add_introns/agat_sp_add_introns +++ b/target/executable/agat/agat_sp_add_introns/agat_sp_add_introns @@ -479,9 +479,9 @@ RUN agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.t LABEL org.opencontainers.image.authors="Leïla Paquay" LABEL org.opencontainers.image.description="Companion container for running component agat agat_sp_add_introns" -LABEL org.opencontainers.image.created="2024-10-26T13:11:20Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:09Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/agat/agat_sp_filter_feature_from_kill_list/.config.vsh.yaml b/target/executable/agat/agat_sp_filter_feature_from_kill_list/.config.vsh.yaml new file mode 100644 index 00000000..f248e314 --- /dev/null +++ b/target/executable/agat/agat_sp_filter_feature_from_kill_list/.config.vsh.yaml @@ -0,0 +1,263 @@ +name: "agat_sp_filter_feature_from_kill_list" +namespace: "agat" +version: "main" +authors: +- name: "Leïla Paquay" + roles: + - "author" + - "maintainer" + info: + links: + email: "leila@data-intuitive.com" + github: "Leila011" + linkedin: "leilapaquay" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Software Developer" +argument_groups: +- name: "Inputs" + arguments: + - type: "file" + name: "--gff" + alternatives: + - "-f" + - "--ref" + - "--reffile" + description: "Input GFF3 file that will be read." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--kill_list" + alternatives: + - "--kl" + description: "Text file containing the kill list. One value per line." + info: null + example: + - "kill_list.txt" + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + - "--out" + description: "Path to the output GFF file that contains filtered features. \n" + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Arguments" + arguments: + - type: "string" + name: "--type" + alternatives: + - "-p" + - "-l" + description: "Primary tag option, case insensitive, list. Allow to specify the\ + \ feature types that \nwill be handled. \n\nYou can specify a specific feature\ + \ by giving its primary tag name (column 3) as: \n\n * cds\n * Gene\n * mRNA\n\ + \ \nYou can specify directly all the feature of a particular\nlevel: \n\n \ + \ * level2=mRNA,ncRNA,tRNA,etc \n * level3=CDS,exon,UTR,etc. \n\nBy default\ + \ all features are taken into account. Fill the option with the value \"all\"\ + \ will \nhave the same behaviour.\n" + info: null + required: false + direction: "input" + multiple: true + multiple_sep: ";" + - type: "string" + name: "--attribute" + alternatives: + - "-a" + description: "Attribute tag to specify the attribute to analyse. Case sensitive.\ + \ Default: ID\n" + info: null + example: + - "ID" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--config" + alternatives: + - "-c" + description: "AGAT config file. By default AGAT takes the original agat_config.yaml\ + \ shipped with AGAT.\nThe `--config` option gives you the possibility to use\ + \ your own AGAT config file (located \nelsewhere or named differently).\n" + info: null + example: + - "custom_agat_config.yaml" + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--verbose" + alternatives: + - "-v" + description: "Verbose option for debugging purpose." + info: null + direction: "input" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Remove features based on a kill list. The default behaviour is to look\ + \ at the features's ID. \nIf the feature has an ID (case insensitive) listed among\ + \ the kill list it will be removed.\nRemoving a level1 or level2 feature will automatically\ + \ remove all linked subfeatures, and \nremoving all children of a feature will automatically\ + \ remove this feature too.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "gene annotations" +- "filtering" +- "gff" +license: "GPL-3.0" +references: + doi: + - "10.5281/zenodo.3552717" +links: + repository: "https://github.com/NBISweden/AGAT" + homepage: "https://github.com/NBISweden/AGAT" + documentation: "https://agat.readthedocs.io/en/latest/tools/agat_sp_filter_feature_from_kill_list.html" + issue_tracker: "https://github.com/NBISweden/AGAT/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "docker" + run: + - "agat --version | sed 's/AGAT\\s\\(.*\\)/agat: \"\\1\"/' > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/agat/agat_sp_filter_feature_from_kill_list/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/agat/agat_sp_filter_feature_from_kill_list" + executable: "target/executable/agat/agat_sp_filter_feature_from_kill_list/agat_sp_filter_feature_from_kill_list" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/executable/agat/agat_sp_filter_feature_from_kill_list/agat_sp_filter_feature_from_kill_list b/target/executable/agat/agat_sp_filter_feature_from_kill_list/agat_sp_filter_feature_from_kill_list new file mode 100755 index 00000000..2cfc8821 --- /dev/null +++ b/target/executable/agat/agat_sp_filter_feature_from_kill_list/agat_sp_filter_feature_from_kill_list @@ -0,0 +1,1312 @@ +#!/usr/bin/env bash + +# agat_sp_filter_feature_from_kill_list main +# +# This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +# work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +# Intuitive. +# +# The component may contain files which fall under a different license. The +# authors of this component should specify the license in the header of such +# files, or include a separate license file detailing the licenses of all included +# files. +# +# Component authors: +# * Leïla Paquay (author, maintainer) + +set -e + +if [ -z "$VIASH_TEMP" ]; then + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMP} + VIASH_TEMP=${VIASH_TEMP:-$TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TMP} + VIASH_TEMP=${VIASH_TEMP:-$TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TEMP} + VIASH_TEMP=${VIASH_TEMP:-/tmp} +fi + +# define helper functions +# ViashQuote: put quotes around non flag values +# $1 : unquoted string +# return : possibly quoted string +# examples: +# ViashQuote --foo # returns --foo +# ViashQuote bar # returns 'bar' +# Viashquote --foo=bar # returns --foo='bar' +function ViashQuote { + if [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+=.+$ ]]; then + echo "$1" | sed "s#=\(.*\)#='\1'#" + elif [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+$ ]]; then + echo "$1" + else + echo "'$1'" + fi +} +# ViashRemoveFlags: Remove leading flag +# $1 : string with a possible leading flag +# return : string without possible leading flag +# examples: +# ViashRemoveFlags --foo=bar # returns bar +function ViashRemoveFlags { + echo "$1" | sed 's/^--*[a-zA-Z0-9_\-]*=//' +} +# ViashSourceDir: return the path of a bash file, following symlinks +# usage : ViashSourceDir ${BASH_SOURCE[0]} +# $1 : Should always be set to ${BASH_SOURCE[0]} +# returns : The absolute path of the bash file +function ViashSourceDir { + local source="$1" + while [ -h "$source" ]; do + local dir="$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd )" + source="$(readlink "$source")" + [[ $source != /* ]] && source="$dir/$source" + done + cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd +} +# ViashFindTargetDir: return the path of the '.build.yaml' file, following symlinks +# usage : ViashFindTargetDir 'ScriptPath' +# $1 : The location from where to start the upward search +# returns : The absolute path of the '.build.yaml' file +function ViashFindTargetDir { + local source="$1" + while [[ "$source" != "" && ! -e "$source/.build.yaml" ]]; do + source=${source%/*} + done + echo $source +} +# see https://en.wikipedia.org/wiki/Syslog#Severity_level +VIASH_LOGCODE_EMERGENCY=0 +VIASH_LOGCODE_ALERT=1 +VIASH_LOGCODE_CRITICAL=2 +VIASH_LOGCODE_ERROR=3 +VIASH_LOGCODE_WARNING=4 +VIASH_LOGCODE_NOTICE=5 +VIASH_LOGCODE_INFO=6 +VIASH_LOGCODE_DEBUG=7 +VIASH_VERBOSITY=$VIASH_LOGCODE_NOTICE + +# ViashLog: Log events depending on the verbosity level +# usage: ViashLog 1 alert Oh no something went wrong! +# $1: required verbosity level +# $2: display tag +# $3+: messages to display +# stdout: Your input, prepended by '[$2] '. +function ViashLog { + local required_level="$1" + local display_tag="$2" + shift 2 + if [ $VIASH_VERBOSITY -ge $required_level ]; then + >&2 echo "[$display_tag]" "$@" + fi +} + +# ViashEmergency: log events when the system is unstable +# usage: ViashEmergency Oh no something went wrong. +# stdout: Your input, prepended by '[emergency] '. +function ViashEmergency { + ViashLog $VIASH_LOGCODE_EMERGENCY emergency "$@" +} + +# ViashAlert: log events when actions must be taken immediately (e.g. corrupted system database) +# usage: ViashAlert Oh no something went wrong. +# stdout: Your input, prepended by '[alert] '. +function ViashAlert { + ViashLog $VIASH_LOGCODE_ALERT alert "$@" +} + +# ViashCritical: log events when a critical condition occurs +# usage: ViashCritical Oh no something went wrong. +# stdout: Your input, prepended by '[critical] '. +function ViashCritical { + ViashLog $VIASH_LOGCODE_CRITICAL critical "$@" +} + +# ViashError: log events when an error condition occurs +# usage: ViashError Oh no something went wrong. +# stdout: Your input, prepended by '[error] '. +function ViashError { + ViashLog $VIASH_LOGCODE_ERROR error "$@" +} + +# ViashWarning: log potentially abnormal events +# usage: ViashWarning Something may have gone wrong. +# stdout: Your input, prepended by '[warning] '. +function ViashWarning { + ViashLog $VIASH_LOGCODE_WARNING warning "$@" +} + +# ViashNotice: log significant but normal events +# usage: ViashNotice This just happened. +# stdout: Your input, prepended by '[notice] '. +function ViashNotice { + ViashLog $VIASH_LOGCODE_NOTICE notice "$@" +} + +# ViashInfo: log normal events +# usage: ViashInfo This just happened. +# stdout: Your input, prepended by '[info] '. +function ViashInfo { + ViashLog $VIASH_LOGCODE_INFO info "$@" +} + +# ViashDebug: log all events, for debugging purposes +# usage: ViashDebug This just happened. +# stdout: Your input, prepended by '[debug] '. +function ViashDebug { + ViashLog $VIASH_LOGCODE_DEBUG debug "$@" +} + +# find source folder of this component +VIASH_META_RESOURCES_DIR=`ViashSourceDir ${BASH_SOURCE[0]}` + +# find the root of the built components & dependencies +VIASH_TARGET_DIR=`ViashFindTargetDir $VIASH_META_RESOURCES_DIR` + +# define meta fields +VIASH_META_NAME="agat_sp_filter_feature_from_kill_list" +VIASH_META_FUNCTIONALITY_NAME="agat_sp_filter_feature_from_kill_list" +VIASH_META_EXECUTABLE="$VIASH_META_RESOURCES_DIR/$VIASH_META_NAME" +VIASH_META_CONFIG="$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" +VIASH_META_TEMP_DIR="$VIASH_TEMP" + + +# ViashHelp: Display helpful explanation about this executable +function ViashHelp { + echo "agat_sp_filter_feature_from_kill_list main" + echo "" + echo "Remove features based on a kill list. The default behaviour is to look at the" + echo "features's ID." + echo "If the feature has an ID (case insensitive) listed among the kill list it will" + echo "be removed." + echo "Removing a level1 or level2 feature will automatically remove all linked" + echo "subfeatures, and" + echo "removing all children of a feature will automatically remove this feature too." + echo "" + echo "Inputs:" + echo " -f, --ref, --reffile, --gff" + echo " type: file, required parameter, file must exist" + echo " Input GFF3 file that will be read." + echo "" + echo " --kl, --kill_list" + echo " type: file, required parameter, file must exist" + echo " example: kill_list.txt" + echo " Text file containing the kill list. One value per line." + echo "" + echo "Outputs:" + echo " -o, --out, --output" + echo " type: file, required parameter, output, file must exist" + echo " Path to the output GFF file that contains filtered features." + echo "" + echo "Arguments:" + echo " -p, -l, --type" + echo " type: string, multiple values allowed" + echo " Primary tag option, case insensitive, list. Allow to specify the feature" + echo " types that" + echo " will be handled." + echo " You can specify a specific feature by giving its primary tag name" + echo " (column 3) as:" + echo " * cds" + echo " * Gene" + echo " * mRNA" + echo " You can specify directly all the feature of a particular" + echo " level:" + echo " * level2=mRNA,ncRNA,tRNA,etc" + echo " * level3=CDS,exon,UTR,etc." + echo " By default all features are taken into account. Fill the option with the" + echo " value \"all\" will" + echo " have the same behaviour." + echo "" + echo " -a, --attribute" + echo " type: string" + echo " example: ID" + echo " Attribute tag to specify the attribute to analyse. Case sensitive." + echo " Default: ID" + echo "" + echo " -c, --config" + echo " type: file, file must exist" + echo " example: custom_agat_config.yaml" + echo " AGAT config file. By default AGAT takes the original agat_config.yaml" + echo " shipped with AGAT." + echo " The \`--config\` option gives you the possibility to use your own AGAT" + echo " config file (located" + echo " elsewhere or named differently)." + echo "" + echo " -v, --verbose" + echo " type: boolean_true" + echo " Verbose option for debugging purpose." +} + +# initialise variables +VIASH_MODE='run' +VIASH_ENGINE_ID='docker' + +######## Helper functions for setting up Docker images for viash ######## +# expects: ViashDockerBuild + +# ViashDockerInstallationCheck: check whether Docker is installed correctly +# +# examples: +# ViashDockerInstallationCheck +function ViashDockerInstallationCheck { + ViashDebug "Checking whether Docker is installed" + if [ ! command -v docker &> /dev/null ]; then + ViashCritical "Docker doesn't seem to be installed. See 'https://docs.docker.com/get-docker/' for instructions." + exit 1 + fi + + ViashDebug "Checking whether the Docker daemon is running" + local save=$-; set +e + local docker_version=$(docker version --format '{{.Client.APIVersion}}' 2> /dev/null) + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashCritical "Docker daemon does not seem to be running. Try one of the following:" + ViashCritical "- Try running 'dockerd' in the command line" + ViashCritical "- See https://docs.docker.com/config/daemon/" + exit 1 + fi +} + +# ViashDockerRemoteTagCheck: check whether a Docker image is available +# on a remote. Assumes `docker login` has been performed, if relevant. +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerRemoteTagCheck python:latest +# echo $? # returns '0' +# ViashDockerRemoteTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerRemoteTagCheck { + docker manifest inspect $1 > /dev/null 2> /dev/null +} + +# ViashDockerLocalTagCheck: check whether a Docker image is available locally +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# docker pull python:latest +# ViashDockerLocalTagCheck python:latest +# echo $? # returns '0' +# ViashDockerLocalTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerLocalTagCheck { + [ -n "$(docker images -q $1)" ] +} + +# ViashDockerPull: pull a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPull python:latest +# echo $? # returns '0' +# ViashDockerPull sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPull { + ViashNotice "Checking if Docker image is available at '$1'" + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker pull $1 && return 0 || return 1 + else + local save=$-; set +e + docker pull $1 2> /dev/null > /dev/null + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashWarning "Could not pull from '$1'. Docker image doesn't exist or is not accessible." + fi + return $out + fi +} + +# ViashDockerPush: push a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPush python:latest +# echo $? # returns '0' +# ViashDockerPush sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPush { + ViashNotice "Pushing image to '$1'" + local save=$-; set +e + local out + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker push $1 + out=$? + else + docker push $1 2> /dev/null > /dev/null + out=$? + fi + [[ $save =~ e ]] && set -e + if [ $out -eq 0 ]; then + ViashNotice "Container '$1' push succeeded." + else + ViashError "Container '$1' push errored. You might not be logged in or have the necessary permissions." + fi + return $out +} + +# ViashDockerPullElseBuild: pull a Docker image, else build it +# +# $1 : image identifier with format `[registry/]image[:tag]` +# ViashDockerBuild : a Bash function which builds a docker image, takes image identifier as argument. +# examples: +# ViashDockerPullElseBuild mynewcomponent +function ViashDockerPullElseBuild { + local save=$-; set +e + ViashDockerPull $1 + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashDockerBuild $@ + fi +} + +# ViashDockerSetup: create a Docker image, according to specified docker setup strategy +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $2 : docker setup strategy, see DockerSetupStrategy.scala +# examples: +# ViashDockerSetup mynewcomponent alwaysbuild +function ViashDockerSetup { + local image_id="$1" + local setup_strategy="$2" + if [ "$setup_strategy" == "alwaysbuild" -o "$setup_strategy" == "build" -o "$setup_strategy" == "b" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspull" -o "$setup_strategy" == "pull" -o "$setup_strategy" == "p" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "alwayspullelsebuild" -o "$setup_strategy" == "pullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspullelsecachedbuild" -o "$setup_strategy" == "pullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayscachedbuild" -o "$setup_strategy" == "cachedbuild" -o "$setup_strategy" == "cb" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [[ "$setup_strategy" =~ ^ifneedbe ]]; then + local save=$-; set +e + ViashDockerLocalTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashInfo "Image $image_id already exists" + elif [ "$setup_strategy" == "ifneedbebuild" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbecachedbuild" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepull" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "ifneedbepullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi + elif [ "$setup_strategy" == "push" -o "$setup_strategy" == "forcepush" -o "$setup_strategy" == "alwayspush" ]; then + ViashDockerPush "$image_id" + elif [ "$setup_strategy" == "pushifnotpresent" -o "$setup_strategy" == "gentlepush" -o "$setup_strategy" == "maybepush" ]; then + local save=$-; set +e + ViashDockerRemoteTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashNotice "Container '$image_id' exists, doing nothing." + else + ViashNotice "Container '$image_id' does not yet exist." + ViashDockerPush "$image_id" + fi + elif [ "$setup_strategy" == "donothing" -o "$setup_strategy" == "meh" ]; then + ViashNotice "Skipping setup." + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi +} + +# ViashDockerCheckCommands: Check whether a docker container has the required commands +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $@ : commands to verify being present +# examples: +# ViashDockerCheckCommands bash:4.0 bash ps foo +function ViashDockerCheckCommands { + local image_id="$1" + shift 1 + local commands="$@" + local save=$-; set +e + local missing # mark 'missing' as local in advance, otherwise the exit code of the command will be missing and always be '0' + missing=$(docker run --rm --entrypoint=sh "$image_id" -c "for command in $commands; do command -v \$command >/dev/null 2>&1; if [ \$? -ne 0 ]; then echo \$command; exit 1; fi; done") + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -ne 0 ]; then + ViashError "Docker container '$image_id' does not contain command '$missing'." + exit 1 + fi +} + +# ViashDockerBuild: build a docker image +# $1 : image identifier with format `[registry/]image[:tag]` +# $... : additional arguments to pass to docker build +# $VIASH_META_TEMP_DIR : temporary directory to store dockerfile & optional resources in +# $VIASH_META_NAME : name of the component +# $VIASH_META_RESOURCES_DIR : directory containing the resources +# $VIASH_VERBOSITY : verbosity level +# exit code $? : whether or not the image was built successfully +function ViashDockerBuild { + local image_id="$1" + shift 1 + + # create temporary directory to store dockerfile & optional resources in + local tmpdir=$(mktemp -d "$VIASH_META_TEMP_DIR/dockerbuild-$VIASH_META_NAME-XXXXXX") + local dockerfile="$tmpdir/Dockerfile" + function clean_up { + rm -rf "$tmpdir" + } + trap clean_up EXIT + + # store dockerfile and resources + ViashDockerfile "$VIASH_ENGINE_ID" > "$dockerfile" + + # generate the build command + local docker_build_cmd="docker build -t '$image_id' $@ '$VIASH_META_RESOURCES_DIR' -f '$dockerfile'" + + # build the container + ViashNotice "Building container '$image_id' with Dockerfile" + ViashInfo "$docker_build_cmd" + local save=$-; set +e + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + eval $docker_build_cmd + else + eval $docker_build_cmd &> "$tmpdir/docker_build.log" + fi + + # check exit code + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashError "Error occurred while building container '$image_id'" + if [ $VIASH_VERBOSITY -lt $VIASH_LOGCODE_INFO ]; then + ViashError "Transcript: --------------------------------" + cat "$tmpdir/docker_build.log" + ViashError "End of transcript --------------------------" + fi + exit 1 + fi +} + +######## End of helper functions for setting up Docker images for viash ######## + +# ViashDockerFile: print the dockerfile to stdout +# $1 : engine identifier +# return : dockerfile required to run this component +# examples: +# ViashDockerFile +function ViashDockerfile { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + cat << 'VIASHDOCKER' +FROM quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0 +ENTRYPOINT [] +RUN agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.txt + +LABEL org.opencontainers.image.authors="Leïla Paquay" +LABEL org.opencontainers.image.description="Companion container for running component agat agat_sp_filter_feature_from_kill_list" +LABEL org.opencontainers.image.created="2024-10-26T18:44:08Z" +LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" +LABEL org.opencontainers.image.version="main" + +VIASHDOCKER + fi +} + +# ViashDockerBuildArgs: return the arguments to pass to docker build +# $1 : engine identifier +# return : arguments to pass to docker build +function ViashDockerBuildArgs { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + echo "" + fi +} + +# ViashAbsolutePath: generate absolute path from relative path +# borrowed from https://stackoverflow.com/a/21951256 +# $1 : relative filename +# return : absolute path +# examples: +# ViashAbsolutePath some_file.txt # returns /path/to/some_file.txt +# ViashAbsolutePath /foo/bar/.. # returns /foo +function ViashAbsolutePath { + local thePath + local parr + local outp + local len + if [[ ! "$1" =~ ^/ ]]; then + thePath="$PWD/$1" + else + thePath="$1" + fi + echo "$thePath" | ( + IFS=/ + read -a parr + declare -a outp + for i in "${parr[@]}"; do + case "$i" in + ''|.) continue ;; + ..) + len=${#outp[@]} + if ((len==0)); then + continue + else + unset outp[$((len-1))] + fi + ;; + *) + len=${#outp[@]} + outp[$len]="$i" + ;; + esac + done + echo /"${outp[*]}" + ) +} +# ViashDockerAutodetectMount: auto configuring docker mounts from parameters +# $1 : The parameter value +# returns : New parameter +# $VIASH_DIRECTORY_MOUNTS : Added another parameter to be passed to docker +# $VIASH_DOCKER_AUTOMOUNT_PREFIX : The prefix to be used for the automounts +# examples: +# ViashDockerAutodetectMount /path/to/bar # returns '/viash_automount/path/to/bar' +# ViashDockerAutodetectMountArg /path/to/bar # returns '--volume="/path/to:/viash_automount/path/to"' +function ViashDockerAutodetectMount { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + if [ -z "$base_name" ]; then + echo "$mount_target" + else + echo "$mount_target/$base_name" + fi +} +function ViashDockerAutodetectMountArg { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + ViashDebug "ViashDockerAutodetectMountArg $1 -> $mount_source -> $mount_target" + echo "--volume=\"$mount_source:$mount_target\"" +} +function ViashDockerStripAutomount { + local abs_path=$(ViashAbsolutePath "$1") + echo "${abs_path#$VIASH_DOCKER_AUTOMOUNT_PREFIX}" +} +# initialise variables +VIASH_DIRECTORY_MOUNTS=() + +# configure default docker automount prefix if it is unset +if [ -z "${VIASH_DOCKER_AUTOMOUNT_PREFIX+x}" ]; then + VIASH_DOCKER_AUTOMOUNT_PREFIX="/viash_automount" +fi + +# initialise docker variables +VIASH_DOCKER_RUN_ARGS=(-i --rm) + +# initialise array +VIASH_POSITIONAL_ARGS='' + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + ViashHelp + exit + ;; + ---v|---verbose) + let "VIASH_VERBOSITY=VIASH_VERBOSITY+1" + shift 1 + ;; + ---verbosity) + VIASH_VERBOSITY="$2" + shift 2 + ;; + ---verbosity=*) + VIASH_VERBOSITY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + --version) + echo "agat_sp_filter_feature_from_kill_list main" + exit + ;; + --gff) + [ -n "$VIASH_PAR_GFF" ] && ViashError Bad arguments for option \'--gff\': \'$VIASH_PAR_GFF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_GFF="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --gff. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --gff=*) + [ -n "$VIASH_PAR_GFF" ] && ViashError Bad arguments for option \'--gff=*\': \'$VIASH_PAR_GFF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_GFF=$(ViashRemoveFlags "$1") + shift 1 + ;; + -f) + [ -n "$VIASH_PAR_GFF" ] && ViashError Bad arguments for option \'-f\': \'$VIASH_PAR_GFF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_GFF="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -f. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --ref) + [ -n "$VIASH_PAR_GFF" ] && ViashError Bad arguments for option \'--ref\': \'$VIASH_PAR_GFF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_GFF="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --ref. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --reffile) + [ -n "$VIASH_PAR_GFF" ] && ViashError Bad arguments for option \'--reffile\': \'$VIASH_PAR_GFF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_GFF="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --reffile. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --kill_list) + [ -n "$VIASH_PAR_KILL_LIST" ] && ViashError Bad arguments for option \'--kill_list\': \'$VIASH_PAR_KILL_LIST\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_KILL_LIST="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --kill_list. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --kill_list=*) + [ -n "$VIASH_PAR_KILL_LIST" ] && ViashError Bad arguments for option \'--kill_list=*\': \'$VIASH_PAR_KILL_LIST\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_KILL_LIST=$(ViashRemoveFlags "$1") + shift 1 + ;; + --kl) + [ -n "$VIASH_PAR_KILL_LIST" ] && ViashError Bad arguments for option \'--kl\': \'$VIASH_PAR_KILL_LIST\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_KILL_LIST="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --kl. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output=*) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output=*\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT=$(ViashRemoveFlags "$1") + shift 1 + ;; + -o) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'-o\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -o. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --out) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--out\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --out. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --type) + if [ -z "$VIASH_PAR_TYPE" ]; then + VIASH_PAR_TYPE="$2" + else + VIASH_PAR_TYPE="$VIASH_PAR_TYPE;""$2" + fi + [ $# -lt 2 ] && ViashError Not enough arguments passed to --type. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --type=*) + if [ -z "$VIASH_PAR_TYPE" ]; then + VIASH_PAR_TYPE=$(ViashRemoveFlags "$1") + else + VIASH_PAR_TYPE="$VIASH_PAR_TYPE;"$(ViashRemoveFlags "$1") + fi + shift 1 + ;; + -p) + if [ -z "$VIASH_PAR_TYPE" ]; then + VIASH_PAR_TYPE="$2" + else + VIASH_PAR_TYPE="$VIASH_PAR_TYPE;""$2" + fi + [ $# -lt 2 ] && ViashError Not enough arguments passed to -p. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + -l) + if [ -z "$VIASH_PAR_TYPE" ]; then + VIASH_PAR_TYPE="$2" + else + VIASH_PAR_TYPE="$VIASH_PAR_TYPE;""$2" + fi + [ $# -lt 2 ] && ViashError Not enough arguments passed to -l. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --attribute) + [ -n "$VIASH_PAR_ATTRIBUTE" ] && ViashError Bad arguments for option \'--attribute\': \'$VIASH_PAR_ATTRIBUTE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ATTRIBUTE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --attribute. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --attribute=*) + [ -n "$VIASH_PAR_ATTRIBUTE" ] && ViashError Bad arguments for option \'--attribute=*\': \'$VIASH_PAR_ATTRIBUTE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ATTRIBUTE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -a) + [ -n "$VIASH_PAR_ATTRIBUTE" ] && ViashError Bad arguments for option \'-a\': \'$VIASH_PAR_ATTRIBUTE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ATTRIBUTE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -a. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --config) + [ -n "$VIASH_PAR_CONFIG" ] && ViashError Bad arguments for option \'--config\': \'$VIASH_PAR_CONFIG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CONFIG="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --config. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --config=*) + [ -n "$VIASH_PAR_CONFIG" ] && ViashError Bad arguments for option \'--config=*\': \'$VIASH_PAR_CONFIG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CONFIG=$(ViashRemoveFlags "$1") + shift 1 + ;; + -c) + [ -n "$VIASH_PAR_CONFIG" ] && ViashError Bad arguments for option \'-c\': \'$VIASH_PAR_CONFIG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CONFIG="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -c. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --verbose) + [ -n "$VIASH_PAR_VERBOSE" ] && ViashError Bad arguments for option \'--verbose\': \'$VIASH_PAR_VERBOSE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_VERBOSE=true + shift 1 + ;; + -v) + [ -n "$VIASH_PAR_VERBOSE" ] && ViashError Bad arguments for option \'-v\': \'$VIASH_PAR_VERBOSE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_VERBOSE=true + shift 1 + ;; + ---engine) + VIASH_ENGINE_ID="$2" + shift 2 + ;; + ---engine=*) + VIASH_ENGINE_ID="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---setup) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$2" + shift 2 + ;; + ---setup=*) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---dockerfile) + VIASH_MODE='dockerfile' + shift 1 + ;; + ---docker_run_args) + VIASH_DOCKER_RUN_ARGS+=("$2") + shift 2 + ;; + ---docker_run_args=*) + VIASH_DOCKER_RUN_ARGS+=("$(ViashRemoveFlags "$1")") + shift 1 + ;; + ---docker_image_id) + VIASH_MODE='docker_image_id' + shift 1 + ;; + ---debug) + VIASH_MODE='debug' + shift 1 + ;; + ---cpus) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---cpus. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---cpus=*) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus=*\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS=$(ViashRemoveFlags "$1") + shift 1 + ;; + ---memory) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---memory. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---memory=*) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory=*\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY=$(ViashRemoveFlags "$1") + shift 1 + ;; + *) # positional arg or unknown option + # since the positional args will be eval'd, can we always quote, instead of using ViashQuote + VIASH_POSITIONAL_ARGS="$VIASH_POSITIONAL_ARGS '$1'" + [[ $1 == -* ]] && ViashWarning $1 looks like a parameter but is not a defined parameter and will instead be treated as a positional argument. Use "--help" to get more information on the parameters. + shift # past argument + ;; + esac +done + +# parse positional parameters +eval set -- $VIASH_POSITIONAL_ARGS + + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + VIASH_ENGINE_TYPE='native' +elif [ "$VIASH_ENGINE_ID" == "docker" ] ; then + VIASH_ENGINE_TYPE='docker' +else + ViashError "Engine '$VIASH_ENGINE_ID' is not recognized. Options are: docker, native." + exit 1 +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # check if docker is installed properly + ViashDockerInstallationCheck + + # determine docker image id + if [[ "$VIASH_ENGINE_ID" == 'docker' ]]; then + VIASH_DOCKER_IMAGE_ID='images.viash-hub.com/vsh/biobox/agat/agat_sp_filter_feature_from_kill_list:main' + fi + + # print dockerfile + if [ "$VIASH_MODE" == "dockerfile" ]; then + ViashDockerfile "$VIASH_ENGINE_ID" + exit 0 + + elif [ "$VIASH_MODE" == "docker_image_id" ]; then + echo "$VIASH_DOCKER_IMAGE_ID" + exit 0 + + # enter docker container + elif [[ "$VIASH_MODE" == "debug" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} -v '$(pwd)':/pwd --workdir /pwd -t $VIASH_DOCKER_IMAGE_ID" + ViashNotice "+ $VIASH_CMD" + eval $VIASH_CMD + exit + + # build docker image + elif [ "$VIASH_MODE" == "setup" ]; then + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" "$VIASH_SETUP_STRATEGY" + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' + exit 0 + fi + + # check if docker image exists + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" ifneedbepullelsecachedbuild + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' +fi + +# setting computational defaults + +# helper function for parsing memory strings +function ViashMemoryAsBytes { + local memory=`echo "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'` + local memory_regex='^([0-9]+)([kmgtp]i?b?|b)$' + if [[ $memory =~ $memory_regex ]]; then + local number=${memory/[^0-9]*/} + local symbol=${memory/*[0-9]/} + + case $symbol in + b) memory_b=$number ;; + kb|k) memory_b=$(( $number * 1000 )) ;; + mb|m) memory_b=$(( $number * 1000 * 1000 )) ;; + gb|g) memory_b=$(( $number * 1000 * 1000 * 1000 )) ;; + tb|t) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 )) ;; + pb|p) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 * 1000 )) ;; + kib|ki) memory_b=$(( $number * 1024 )) ;; + mib|mi) memory_b=$(( $number * 1024 * 1024 )) ;; + gib|gi) memory_b=$(( $number * 1024 * 1024 * 1024 )) ;; + tib|ti) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 )) ;; + pib|pi) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 * 1024 )) ;; + esac + echo "$memory_b" + fi +} +# compute memory in different units +if [ ! -z ${VIASH_META_MEMORY+x} ]; then + VIASH_META_MEMORY_B=`ViashMemoryAsBytes $VIASH_META_MEMORY` + # do not define other variables if memory_b is an empty string + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_META_MEMORY_KB=$(( ($VIASH_META_MEMORY_B+999) / 1000 )) + VIASH_META_MEMORY_MB=$(( ($VIASH_META_MEMORY_KB+999) / 1000 )) + VIASH_META_MEMORY_GB=$(( ($VIASH_META_MEMORY_MB+999) / 1000 )) + VIASH_META_MEMORY_TB=$(( ($VIASH_META_MEMORY_GB+999) / 1000 )) + VIASH_META_MEMORY_PB=$(( ($VIASH_META_MEMORY_TB+999) / 1000 )) + VIASH_META_MEMORY_KIB=$(( ($VIASH_META_MEMORY_B+1023) / 1024 )) + VIASH_META_MEMORY_MIB=$(( ($VIASH_META_MEMORY_KIB+1023) / 1024 )) + VIASH_META_MEMORY_GIB=$(( ($VIASH_META_MEMORY_MIB+1023) / 1024 )) + VIASH_META_MEMORY_TIB=$(( ($VIASH_META_MEMORY_GIB+1023) / 1024 )) + VIASH_META_MEMORY_PIB=$(( ($VIASH_META_MEMORY_TIB+1023) / 1024 )) + else + # unset memory if string is empty + unset $VIASH_META_MEMORY_B + fi +fi +# unset nproc if string is empty +if [ -z "$VIASH_META_CPUS" ]; then + unset $VIASH_META_CPUS +fi + + +# check whether required parameters exist +if [ -z ${VIASH_PAR_GFF+x} ]; then + ViashError '--gff' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_PAR_KILL_LIST+x} ]; then + ViashError '--kill_list' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_PAR_OUTPUT+x} ]; then + ViashError '--output' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_NAME+x} ]; then + ViashError 'name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_FUNCTIONALITY_NAME+x} ]; then + ViashError 'functionality_name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_RESOURCES_DIR+x} ]; then + ViashError 'resources_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_EXECUTABLE+x} ]; then + ViashError 'executable' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_CONFIG+x} ]; then + ViashError 'config' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_TEMP_DIR+x} ]; then + ViashError 'temp_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi + +# filling in defaults +if [ -z ${VIASH_PAR_VERBOSE+x} ]; then + VIASH_PAR_VERBOSE="false" +fi + +# check whether required files exist +if [ ! -z "$VIASH_PAR_GFF" ] && [ ! -e "$VIASH_PAR_GFF" ]; then + ViashError "Input file '$VIASH_PAR_GFF' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_KILL_LIST" ] && [ ! -e "$VIASH_PAR_KILL_LIST" ]; then + ViashError "Input file '$VIASH_PAR_KILL_LIST' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_CONFIG" ] && [ ! -e "$VIASH_PAR_CONFIG" ]; then + ViashError "Input file '$VIASH_PAR_CONFIG' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_PAR_VERBOSE" ]]; then + if ! [[ "$VIASH_PAR_VERBOSE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--verbose' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_CPUS" ]]; then + if ! [[ "$VIASH_META_CPUS" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'cpus' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_B" ]]; then + if ! [[ "$VIASH_META_MEMORY_B" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_b' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi + +# create parent directories of output files, if so desired +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT")" +fi + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + if [ "$VIASH_MODE" == "run" ]; then + VIASH_CMD="bash" + else + ViashError "Engine '$VIASH_ENGINE_ID' does not support mode '$VIASH_MODE'." + exit 1 + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # detect volumes from file arguments + VIASH_CHOWN_VARS=() +if [ ! -z "$VIASH_PAR_GFF" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_GFF")" ) + VIASH_PAR_GFF=$(ViashDockerAutodetectMount "$VIASH_PAR_GFF") +fi +if [ ! -z "$VIASH_PAR_KILL_LIST" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_KILL_LIST")" ) + VIASH_PAR_KILL_LIST=$(ViashDockerAutodetectMount "$VIASH_PAR_KILL_LIST") +fi +if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT")" ) + VIASH_PAR_OUTPUT=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT" ) +fi +if [ ! -z "$VIASH_PAR_CONFIG" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_CONFIG")" ) + VIASH_PAR_CONFIG=$(ViashDockerAutodetectMount "$VIASH_PAR_CONFIG") +fi +if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_RESOURCES_DIR")" ) + VIASH_META_RESOURCES_DIR=$(ViashDockerAutodetectMount "$VIASH_META_RESOURCES_DIR") +fi +if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_EXECUTABLE")" ) + VIASH_META_EXECUTABLE=$(ViashDockerAutodetectMount "$VIASH_META_EXECUTABLE") +fi +if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_CONFIG")" ) + VIASH_META_CONFIG=$(ViashDockerAutodetectMount "$VIASH_META_CONFIG") +fi +if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_TEMP_DIR")" ) + VIASH_META_TEMP_DIR=$(ViashDockerAutodetectMount "$VIASH_META_TEMP_DIR") +fi + + # get unique mounts + VIASH_UNIQUE_MOUNTS=($(for val in "${VIASH_DIRECTORY_MOUNTS[@]}"; do echo "$val"; done | sort -u)) +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # change file ownership + function ViashPerformChown { + if (( ${#VIASH_CHOWN_VARS[@]} )); then + set +e + VIASH_CMD="docker run --entrypoint=bash --rm ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID -c 'chown $(id -u):$(id -g) --silent --recursive ${VIASH_CHOWN_VARS[@]}'" + ViashDebug "+ $VIASH_CMD" + eval $VIASH_CMD + set -e + fi + } + trap ViashPerformChown EXIT +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # helper function for filling in extra docker args + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_DOCKER_RUN_ARGS+=("--memory=${VIASH_META_MEMORY_B}") + fi + if [ ! -z "$VIASH_META_CPUS" ]; then + VIASH_DOCKER_RUN_ARGS+=("--cpus=${VIASH_META_CPUS}") + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID" +fi + + +# set dependency paths + + +ViashDebug "Running command: $(echo $VIASH_CMD)" +cat << VIASHEOF | eval $VIASH_CMD +set -e +tempscript=\$(mktemp "$VIASH_META_TEMP_DIR/viash-run-agat_sp_filter_feature_from_kill_list-XXXXXX").sh +function clean_up { + rm "\$tempscript" +} +function interrupt { + echo -e "\nCTRL-C Pressed..." + exit 1 +} +trap clean_up EXIT +trap interrupt INT SIGINT +cat > "\$tempscript" << 'VIASHMAIN' +#!/bin/bash + +set -eo pipefail + +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_GFF+x} ]; then echo "${VIASH_PAR_GFF}" | sed "s#'#'\"'\"'#g;s#.*#par_gff='&'#" ; else echo "# par_gff="; fi ) +$( if [ ! -z ${VIASH_PAR_KILL_LIST+x} ]; then echo "${VIASH_PAR_KILL_LIST}" | sed "s#'#'\"'\"'#g;s#.*#par_kill_list='&'#" ; else echo "# par_kill_list="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\"'\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; fi ) +$( if [ ! -z ${VIASH_PAR_TYPE+x} ]; then echo "${VIASH_PAR_TYPE}" | sed "s#'#'\"'\"'#g;s#.*#par_type='&'#" ; else echo "# par_type="; fi ) +$( if [ ! -z ${VIASH_PAR_ATTRIBUTE+x} ]; then echo "${VIASH_PAR_ATTRIBUTE}" | sed "s#'#'\"'\"'#g;s#.*#par_attribute='&'#" ; else echo "# par_attribute="; fi ) +$( if [ ! -z ${VIASH_PAR_CONFIG+x} ]; then echo "${VIASH_PAR_CONFIG}" | sed "s#'#'\"'\"'#g;s#.*#par_config='&'#" ; else echo "# par_config="; fi ) +$( if [ ! -z ${VIASH_PAR_VERBOSE+x} ]; then echo "${VIASH_PAR_VERBOSE}" | sed "s#'#'\"'\"'#g;s#.*#par_verbose='&'#" ; else echo "# par_verbose="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\"'\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\"'\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\"'\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\"'\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END + +# unset flags +[[ "\$par_verbose" == "false" ]] && unset par_verbose + +# convert par_type to comma separated list +par_type=\$(echo \$par_type | tr ';' ',') + +# run agat_sp_filter_feature_from_kill_list +agat_sp_filter_feature_from_kill_list.pl \\ + --gff "\$par_gff" \\ + --kill_list "\$par_kill_list" \\ + --output "\$par_output" \\ + \${par_type:+--type "\${par_type}"} \\ + \${par_attribute:+--attribute "\${par_attribute}"} \\ + \${par_config:+--config "\${par_config}"} \\ + \${par_verbose:+-v} +VIASHMAIN +bash "\$tempscript" & +wait "\$!" + +VIASHEOF + + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # strip viash automount from file paths + + if [ ! -z "$VIASH_PAR_GFF" ]; then + VIASH_PAR_GFF=$(ViashDockerStripAutomount "$VIASH_PAR_GFF") + fi + if [ ! -z "$VIASH_PAR_KILL_LIST" ]; then + VIASH_PAR_KILL_LIST=$(ViashDockerStripAutomount "$VIASH_PAR_KILL_LIST") + fi + if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_PAR_OUTPUT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT") + fi + if [ ! -z "$VIASH_PAR_CONFIG" ]; then + VIASH_PAR_CONFIG=$(ViashDockerStripAutomount "$VIASH_PAR_CONFIG") + fi + if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_META_RESOURCES_DIR=$(ViashDockerStripAutomount "$VIASH_META_RESOURCES_DIR") + fi + if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_META_EXECUTABLE=$(ViashDockerStripAutomount "$VIASH_META_EXECUTABLE") + fi + if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_META_CONFIG=$(ViashDockerStripAutomount "$VIASH_META_CONFIG") + fi + if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_META_TEMP_DIR=$(ViashDockerStripAutomount "$VIASH_META_TEMP_DIR") + fi +fi + + +# check whether required files exist +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -e "$VIASH_PAR_OUTPUT" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT' does not exist." + exit 1 +fi + + +exit 0 diff --git a/target/executable/agat/agat_sp_merge_annotations/.config.vsh.yaml b/target/executable/agat/agat_sp_merge_annotations/.config.vsh.yaml new file mode 100644 index 00000000..b460de98 --- /dev/null +++ b/target/executable/agat/agat_sp_merge_annotations/.config.vsh.yaml @@ -0,0 +1,211 @@ +name: "agat_sp_merge_annotations" +namespace: "agat" +version: "main" +authors: +- name: "Leïla Paquay" + roles: + - "author" + - "maintainer" + info: + links: + email: "leila@data-intuitive.com" + github: "Leila011" + linkedin: "leilapaquay" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Software Developer" +argument_groups: +- name: "Inputs" + arguments: + - type: "file" + name: "--gff" + alternatives: + - "-f" + description: "Input GTF/GFF file(s).\n" + info: null + example: + - "input1.gff;input2.gff" + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: true + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + - "--out" + description: "Output gff3 file where the gene incriminated will be writen." + info: null + example: + - "output.gff" + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Arguments" + arguments: + - type: "file" + name: "--config" + alternatives: + - "-c" + description: "AGAT config file. By default AGAT takes the original agat_config.yaml\ + \ shipped with AGAT. \nThe `--config` option gives you the possibility to use\ + \ your own AGAT config file (located\nelsewhere or named differently).\n" + info: null + example: + - "custom_agat_config.yaml" + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Merge different gff annotation files into one. It uses the AGAT parser\ + \ that takes care of\nduplicated names and fixes other oddities met in those files.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "gene annotations" +- "merge" +- "gff" +license: "GPL-3.0" +references: + doi: + - "10.5281/zenodo.3552717" +links: + repository: "https://github.com/NBISweden/AGAT" + homepage: "https://github.com/NBISweden/AGAT" + documentation: "https://agat.readthedocs.io/en/latest/tools/agat_sp_merge_annotations.html" + issue_tracker: "https://github.com/NBISweden/AGAT/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "docker" + run: + - "agat --version | sed 's/AGAT\\s\\(.*\\)/agat: \"\\1\"/' > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/agat/agat_sp_merge_annotations/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/agat/agat_sp_merge_annotations" + executable: "target/executable/agat/agat_sp_merge_annotations/agat_sp_merge_annotations" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/executable/agat/agat_sp_merge_annotations/agat_sp_merge_annotations b/target/executable/agat/agat_sp_merge_annotations/agat_sp_merge_annotations new file mode 100755 index 00000000..c0e43395 --- /dev/null +++ b/target/executable/agat/agat_sp_merge_annotations/agat_sp_merge_annotations @@ -0,0 +1,1187 @@ +#!/usr/bin/env bash + +# agat_sp_merge_annotations main +# +# This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +# work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +# Intuitive. +# +# The component may contain files which fall under a different license. The +# authors of this component should specify the license in the header of such +# files, or include a separate license file detailing the licenses of all included +# files. +# +# Component authors: +# * Leïla Paquay (author, maintainer) + +set -e + +if [ -z "$VIASH_TEMP" ]; then + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMP} + VIASH_TEMP=${VIASH_TEMP:-$TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TMP} + VIASH_TEMP=${VIASH_TEMP:-$TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TEMP} + VIASH_TEMP=${VIASH_TEMP:-/tmp} +fi + +# define helper functions +# ViashQuote: put quotes around non flag values +# $1 : unquoted string +# return : possibly quoted string +# examples: +# ViashQuote --foo # returns --foo +# ViashQuote bar # returns 'bar' +# Viashquote --foo=bar # returns --foo='bar' +function ViashQuote { + if [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+=.+$ ]]; then + echo "$1" | sed "s#=\(.*\)#='\1'#" + elif [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+$ ]]; then + echo "$1" + else + echo "'$1'" + fi +} +# ViashRemoveFlags: Remove leading flag +# $1 : string with a possible leading flag +# return : string without possible leading flag +# examples: +# ViashRemoveFlags --foo=bar # returns bar +function ViashRemoveFlags { + echo "$1" | sed 's/^--*[a-zA-Z0-9_\-]*=//' +} +# ViashSourceDir: return the path of a bash file, following symlinks +# usage : ViashSourceDir ${BASH_SOURCE[0]} +# $1 : Should always be set to ${BASH_SOURCE[0]} +# returns : The absolute path of the bash file +function ViashSourceDir { + local source="$1" + while [ -h "$source" ]; do + local dir="$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd )" + source="$(readlink "$source")" + [[ $source != /* ]] && source="$dir/$source" + done + cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd +} +# ViashFindTargetDir: return the path of the '.build.yaml' file, following symlinks +# usage : ViashFindTargetDir 'ScriptPath' +# $1 : The location from where to start the upward search +# returns : The absolute path of the '.build.yaml' file +function ViashFindTargetDir { + local source="$1" + while [[ "$source" != "" && ! -e "$source/.build.yaml" ]]; do + source=${source%/*} + done + echo $source +} +# see https://en.wikipedia.org/wiki/Syslog#Severity_level +VIASH_LOGCODE_EMERGENCY=0 +VIASH_LOGCODE_ALERT=1 +VIASH_LOGCODE_CRITICAL=2 +VIASH_LOGCODE_ERROR=3 +VIASH_LOGCODE_WARNING=4 +VIASH_LOGCODE_NOTICE=5 +VIASH_LOGCODE_INFO=6 +VIASH_LOGCODE_DEBUG=7 +VIASH_VERBOSITY=$VIASH_LOGCODE_NOTICE + +# ViashLog: Log events depending on the verbosity level +# usage: ViashLog 1 alert Oh no something went wrong! +# $1: required verbosity level +# $2: display tag +# $3+: messages to display +# stdout: Your input, prepended by '[$2] '. +function ViashLog { + local required_level="$1" + local display_tag="$2" + shift 2 + if [ $VIASH_VERBOSITY -ge $required_level ]; then + >&2 echo "[$display_tag]" "$@" + fi +} + +# ViashEmergency: log events when the system is unstable +# usage: ViashEmergency Oh no something went wrong. +# stdout: Your input, prepended by '[emergency] '. +function ViashEmergency { + ViashLog $VIASH_LOGCODE_EMERGENCY emergency "$@" +} + +# ViashAlert: log events when actions must be taken immediately (e.g. corrupted system database) +# usage: ViashAlert Oh no something went wrong. +# stdout: Your input, prepended by '[alert] '. +function ViashAlert { + ViashLog $VIASH_LOGCODE_ALERT alert "$@" +} + +# ViashCritical: log events when a critical condition occurs +# usage: ViashCritical Oh no something went wrong. +# stdout: Your input, prepended by '[critical] '. +function ViashCritical { + ViashLog $VIASH_LOGCODE_CRITICAL critical "$@" +} + +# ViashError: log events when an error condition occurs +# usage: ViashError Oh no something went wrong. +# stdout: Your input, prepended by '[error] '. +function ViashError { + ViashLog $VIASH_LOGCODE_ERROR error "$@" +} + +# ViashWarning: log potentially abnormal events +# usage: ViashWarning Something may have gone wrong. +# stdout: Your input, prepended by '[warning] '. +function ViashWarning { + ViashLog $VIASH_LOGCODE_WARNING warning "$@" +} + +# ViashNotice: log significant but normal events +# usage: ViashNotice This just happened. +# stdout: Your input, prepended by '[notice] '. +function ViashNotice { + ViashLog $VIASH_LOGCODE_NOTICE notice "$@" +} + +# ViashInfo: log normal events +# usage: ViashInfo This just happened. +# stdout: Your input, prepended by '[info] '. +function ViashInfo { + ViashLog $VIASH_LOGCODE_INFO info "$@" +} + +# ViashDebug: log all events, for debugging purposes +# usage: ViashDebug This just happened. +# stdout: Your input, prepended by '[debug] '. +function ViashDebug { + ViashLog $VIASH_LOGCODE_DEBUG debug "$@" +} + +# find source folder of this component +VIASH_META_RESOURCES_DIR=`ViashSourceDir ${BASH_SOURCE[0]}` + +# find the root of the built components & dependencies +VIASH_TARGET_DIR=`ViashFindTargetDir $VIASH_META_RESOURCES_DIR` + +# define meta fields +VIASH_META_NAME="agat_sp_merge_annotations" +VIASH_META_FUNCTIONALITY_NAME="agat_sp_merge_annotations" +VIASH_META_EXECUTABLE="$VIASH_META_RESOURCES_DIR/$VIASH_META_NAME" +VIASH_META_CONFIG="$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" +VIASH_META_TEMP_DIR="$VIASH_TEMP" + + +# ViashHelp: Display helpful explanation about this executable +function ViashHelp { + echo "agat_sp_merge_annotations main" + echo "" + echo "Merge different gff annotation files into one. It uses the AGAT parser that" + echo "takes care of" + echo "duplicated names and fixes other oddities met in those files." + echo "" + echo "Inputs:" + echo " -f, --gff" + echo " type: file, required parameter, multiple values allowed, file must exist" + echo " example: input1.gff;input2.gff" + echo " Input GTF/GFF file(s)." + echo "" + echo "Outputs:" + echo " -o, --out, --output" + echo " type: file, required parameter, output, file must exist" + echo " example: output.gff" + echo " Output gff3 file where the gene incriminated will be writen." + echo "" + echo "Arguments:" + echo " -c, --config" + echo " type: file, file must exist" + echo " example: custom_agat_config.yaml" + echo " AGAT config file. By default AGAT takes the original agat_config.yaml" + echo " shipped with AGAT." + echo " The \`--config\` option gives you the possibility to use your own AGAT" + echo " config file (located" + echo " elsewhere or named differently)." +} + +# initialise variables +VIASH_MODE='run' +VIASH_ENGINE_ID='docker' + +######## Helper functions for setting up Docker images for viash ######## +# expects: ViashDockerBuild + +# ViashDockerInstallationCheck: check whether Docker is installed correctly +# +# examples: +# ViashDockerInstallationCheck +function ViashDockerInstallationCheck { + ViashDebug "Checking whether Docker is installed" + if [ ! command -v docker &> /dev/null ]; then + ViashCritical "Docker doesn't seem to be installed. See 'https://docs.docker.com/get-docker/' for instructions." + exit 1 + fi + + ViashDebug "Checking whether the Docker daemon is running" + local save=$-; set +e + local docker_version=$(docker version --format '{{.Client.APIVersion}}' 2> /dev/null) + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashCritical "Docker daemon does not seem to be running. Try one of the following:" + ViashCritical "- Try running 'dockerd' in the command line" + ViashCritical "- See https://docs.docker.com/config/daemon/" + exit 1 + fi +} + +# ViashDockerRemoteTagCheck: check whether a Docker image is available +# on a remote. Assumes `docker login` has been performed, if relevant. +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerRemoteTagCheck python:latest +# echo $? # returns '0' +# ViashDockerRemoteTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerRemoteTagCheck { + docker manifest inspect $1 > /dev/null 2> /dev/null +} + +# ViashDockerLocalTagCheck: check whether a Docker image is available locally +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# docker pull python:latest +# ViashDockerLocalTagCheck python:latest +# echo $? # returns '0' +# ViashDockerLocalTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerLocalTagCheck { + [ -n "$(docker images -q $1)" ] +} + +# ViashDockerPull: pull a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPull python:latest +# echo $? # returns '0' +# ViashDockerPull sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPull { + ViashNotice "Checking if Docker image is available at '$1'" + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker pull $1 && return 0 || return 1 + else + local save=$-; set +e + docker pull $1 2> /dev/null > /dev/null + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashWarning "Could not pull from '$1'. Docker image doesn't exist or is not accessible." + fi + return $out + fi +} + +# ViashDockerPush: push a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPush python:latest +# echo $? # returns '0' +# ViashDockerPush sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPush { + ViashNotice "Pushing image to '$1'" + local save=$-; set +e + local out + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker push $1 + out=$? + else + docker push $1 2> /dev/null > /dev/null + out=$? + fi + [[ $save =~ e ]] && set -e + if [ $out -eq 0 ]; then + ViashNotice "Container '$1' push succeeded." + else + ViashError "Container '$1' push errored. You might not be logged in or have the necessary permissions." + fi + return $out +} + +# ViashDockerPullElseBuild: pull a Docker image, else build it +# +# $1 : image identifier with format `[registry/]image[:tag]` +# ViashDockerBuild : a Bash function which builds a docker image, takes image identifier as argument. +# examples: +# ViashDockerPullElseBuild mynewcomponent +function ViashDockerPullElseBuild { + local save=$-; set +e + ViashDockerPull $1 + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashDockerBuild $@ + fi +} + +# ViashDockerSetup: create a Docker image, according to specified docker setup strategy +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $2 : docker setup strategy, see DockerSetupStrategy.scala +# examples: +# ViashDockerSetup mynewcomponent alwaysbuild +function ViashDockerSetup { + local image_id="$1" + local setup_strategy="$2" + if [ "$setup_strategy" == "alwaysbuild" -o "$setup_strategy" == "build" -o "$setup_strategy" == "b" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspull" -o "$setup_strategy" == "pull" -o "$setup_strategy" == "p" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "alwayspullelsebuild" -o "$setup_strategy" == "pullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspullelsecachedbuild" -o "$setup_strategy" == "pullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayscachedbuild" -o "$setup_strategy" == "cachedbuild" -o "$setup_strategy" == "cb" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [[ "$setup_strategy" =~ ^ifneedbe ]]; then + local save=$-; set +e + ViashDockerLocalTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashInfo "Image $image_id already exists" + elif [ "$setup_strategy" == "ifneedbebuild" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbecachedbuild" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepull" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "ifneedbepullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi + elif [ "$setup_strategy" == "push" -o "$setup_strategy" == "forcepush" -o "$setup_strategy" == "alwayspush" ]; then + ViashDockerPush "$image_id" + elif [ "$setup_strategy" == "pushifnotpresent" -o "$setup_strategy" == "gentlepush" -o "$setup_strategy" == "maybepush" ]; then + local save=$-; set +e + ViashDockerRemoteTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashNotice "Container '$image_id' exists, doing nothing." + else + ViashNotice "Container '$image_id' does not yet exist." + ViashDockerPush "$image_id" + fi + elif [ "$setup_strategy" == "donothing" -o "$setup_strategy" == "meh" ]; then + ViashNotice "Skipping setup." + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi +} + +# ViashDockerCheckCommands: Check whether a docker container has the required commands +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $@ : commands to verify being present +# examples: +# ViashDockerCheckCommands bash:4.0 bash ps foo +function ViashDockerCheckCommands { + local image_id="$1" + shift 1 + local commands="$@" + local save=$-; set +e + local missing # mark 'missing' as local in advance, otherwise the exit code of the command will be missing and always be '0' + missing=$(docker run --rm --entrypoint=sh "$image_id" -c "for command in $commands; do command -v \$command >/dev/null 2>&1; if [ \$? -ne 0 ]; then echo \$command; exit 1; fi; done") + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -ne 0 ]; then + ViashError "Docker container '$image_id' does not contain command '$missing'." + exit 1 + fi +} + +# ViashDockerBuild: build a docker image +# $1 : image identifier with format `[registry/]image[:tag]` +# $... : additional arguments to pass to docker build +# $VIASH_META_TEMP_DIR : temporary directory to store dockerfile & optional resources in +# $VIASH_META_NAME : name of the component +# $VIASH_META_RESOURCES_DIR : directory containing the resources +# $VIASH_VERBOSITY : verbosity level +# exit code $? : whether or not the image was built successfully +function ViashDockerBuild { + local image_id="$1" + shift 1 + + # create temporary directory to store dockerfile & optional resources in + local tmpdir=$(mktemp -d "$VIASH_META_TEMP_DIR/dockerbuild-$VIASH_META_NAME-XXXXXX") + local dockerfile="$tmpdir/Dockerfile" + function clean_up { + rm -rf "$tmpdir" + } + trap clean_up EXIT + + # store dockerfile and resources + ViashDockerfile "$VIASH_ENGINE_ID" > "$dockerfile" + + # generate the build command + local docker_build_cmd="docker build -t '$image_id' $@ '$VIASH_META_RESOURCES_DIR' -f '$dockerfile'" + + # build the container + ViashNotice "Building container '$image_id' with Dockerfile" + ViashInfo "$docker_build_cmd" + local save=$-; set +e + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + eval $docker_build_cmd + else + eval $docker_build_cmd &> "$tmpdir/docker_build.log" + fi + + # check exit code + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashError "Error occurred while building container '$image_id'" + if [ $VIASH_VERBOSITY -lt $VIASH_LOGCODE_INFO ]; then + ViashError "Transcript: --------------------------------" + cat "$tmpdir/docker_build.log" + ViashError "End of transcript --------------------------" + fi + exit 1 + fi +} + +######## End of helper functions for setting up Docker images for viash ######## + +# ViashDockerFile: print the dockerfile to stdout +# $1 : engine identifier +# return : dockerfile required to run this component +# examples: +# ViashDockerFile +function ViashDockerfile { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + cat << 'VIASHDOCKER' +FROM quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0 +ENTRYPOINT [] +RUN agat --version | sed 's/AGAT\s\(.*\)/agat: "\1"/' > /var/software_versions.txt + +LABEL org.opencontainers.image.authors="Leïla Paquay" +LABEL org.opencontainers.image.description="Companion container for running component agat agat_sp_merge_annotations" +LABEL org.opencontainers.image.created="2024-10-26T18:44:08Z" +LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" +LABEL org.opencontainers.image.version="main" + +VIASHDOCKER + fi +} + +# ViashDockerBuildArgs: return the arguments to pass to docker build +# $1 : engine identifier +# return : arguments to pass to docker build +function ViashDockerBuildArgs { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + echo "" + fi +} + +# ViashAbsolutePath: generate absolute path from relative path +# borrowed from https://stackoverflow.com/a/21951256 +# $1 : relative filename +# return : absolute path +# examples: +# ViashAbsolutePath some_file.txt # returns /path/to/some_file.txt +# ViashAbsolutePath /foo/bar/.. # returns /foo +function ViashAbsolutePath { + local thePath + local parr + local outp + local len + if [[ ! "$1" =~ ^/ ]]; then + thePath="$PWD/$1" + else + thePath="$1" + fi + echo "$thePath" | ( + IFS=/ + read -a parr + declare -a outp + for i in "${parr[@]}"; do + case "$i" in + ''|.) continue ;; + ..) + len=${#outp[@]} + if ((len==0)); then + continue + else + unset outp[$((len-1))] + fi + ;; + *) + len=${#outp[@]} + outp[$len]="$i" + ;; + esac + done + echo /"${outp[*]}" + ) +} +# ViashDockerAutodetectMount: auto configuring docker mounts from parameters +# $1 : The parameter value +# returns : New parameter +# $VIASH_DIRECTORY_MOUNTS : Added another parameter to be passed to docker +# $VIASH_DOCKER_AUTOMOUNT_PREFIX : The prefix to be used for the automounts +# examples: +# ViashDockerAutodetectMount /path/to/bar # returns '/viash_automount/path/to/bar' +# ViashDockerAutodetectMountArg /path/to/bar # returns '--volume="/path/to:/viash_automount/path/to"' +function ViashDockerAutodetectMount { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + if [ -z "$base_name" ]; then + echo "$mount_target" + else + echo "$mount_target/$base_name" + fi +} +function ViashDockerAutodetectMountArg { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + ViashDebug "ViashDockerAutodetectMountArg $1 -> $mount_source -> $mount_target" + echo "--volume=\"$mount_source:$mount_target\"" +} +function ViashDockerStripAutomount { + local abs_path=$(ViashAbsolutePath "$1") + echo "${abs_path#$VIASH_DOCKER_AUTOMOUNT_PREFIX}" +} +# initialise variables +VIASH_DIRECTORY_MOUNTS=() + +# configure default docker automount prefix if it is unset +if [ -z "${VIASH_DOCKER_AUTOMOUNT_PREFIX+x}" ]; then + VIASH_DOCKER_AUTOMOUNT_PREFIX="/viash_automount" +fi + +# initialise docker variables +VIASH_DOCKER_RUN_ARGS=(-i --rm) + +# initialise array +VIASH_POSITIONAL_ARGS='' + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + ViashHelp + exit + ;; + ---v|---verbose) + let "VIASH_VERBOSITY=VIASH_VERBOSITY+1" + shift 1 + ;; + ---verbosity) + VIASH_VERBOSITY="$2" + shift 2 + ;; + ---verbosity=*) + VIASH_VERBOSITY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + --version) + echo "agat_sp_merge_annotations main" + exit + ;; + --gff) + if [ -z "$VIASH_PAR_GFF" ]; then + VIASH_PAR_GFF="$2" + else + VIASH_PAR_GFF="$VIASH_PAR_GFF;""$2" + fi + [ $# -lt 2 ] && ViashError Not enough arguments passed to --gff. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --gff=*) + if [ -z "$VIASH_PAR_GFF" ]; then + VIASH_PAR_GFF=$(ViashRemoveFlags "$1") + else + VIASH_PAR_GFF="$VIASH_PAR_GFF;"$(ViashRemoveFlags "$1") + fi + shift 1 + ;; + -f) + if [ -z "$VIASH_PAR_GFF" ]; then + VIASH_PAR_GFF="$2" + else + VIASH_PAR_GFF="$VIASH_PAR_GFF;""$2" + fi + [ $# -lt 2 ] && ViashError Not enough arguments passed to -f. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output=*) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output=*\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT=$(ViashRemoveFlags "$1") + shift 1 + ;; + -o) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'-o\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -o. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --out) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--out\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --out. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --config) + [ -n "$VIASH_PAR_CONFIG" ] && ViashError Bad arguments for option \'--config\': \'$VIASH_PAR_CONFIG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CONFIG="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --config. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --config=*) + [ -n "$VIASH_PAR_CONFIG" ] && ViashError Bad arguments for option \'--config=*\': \'$VIASH_PAR_CONFIG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CONFIG=$(ViashRemoveFlags "$1") + shift 1 + ;; + -c) + [ -n "$VIASH_PAR_CONFIG" ] && ViashError Bad arguments for option \'-c\': \'$VIASH_PAR_CONFIG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CONFIG="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -c. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---engine) + VIASH_ENGINE_ID="$2" + shift 2 + ;; + ---engine=*) + VIASH_ENGINE_ID="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---setup) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$2" + shift 2 + ;; + ---setup=*) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---dockerfile) + VIASH_MODE='dockerfile' + shift 1 + ;; + ---docker_run_args) + VIASH_DOCKER_RUN_ARGS+=("$2") + shift 2 + ;; + ---docker_run_args=*) + VIASH_DOCKER_RUN_ARGS+=("$(ViashRemoveFlags "$1")") + shift 1 + ;; + ---docker_image_id) + VIASH_MODE='docker_image_id' + shift 1 + ;; + ---debug) + VIASH_MODE='debug' + shift 1 + ;; + ---cpus) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---cpus. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---cpus=*) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus=*\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS=$(ViashRemoveFlags "$1") + shift 1 + ;; + ---memory) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---memory. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---memory=*) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory=*\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY=$(ViashRemoveFlags "$1") + shift 1 + ;; + *) # positional arg or unknown option + # since the positional args will be eval'd, can we always quote, instead of using ViashQuote + VIASH_POSITIONAL_ARGS="$VIASH_POSITIONAL_ARGS '$1'" + [[ $1 == -* ]] && ViashWarning $1 looks like a parameter but is not a defined parameter and will instead be treated as a positional argument. Use "--help" to get more information on the parameters. + shift # past argument + ;; + esac +done + +# parse positional parameters +eval set -- $VIASH_POSITIONAL_ARGS + + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + VIASH_ENGINE_TYPE='native' +elif [ "$VIASH_ENGINE_ID" == "docker" ] ; then + VIASH_ENGINE_TYPE='docker' +else + ViashError "Engine '$VIASH_ENGINE_ID' is not recognized. Options are: docker, native." + exit 1 +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # check if docker is installed properly + ViashDockerInstallationCheck + + # determine docker image id + if [[ "$VIASH_ENGINE_ID" == 'docker' ]]; then + VIASH_DOCKER_IMAGE_ID='images.viash-hub.com/vsh/biobox/agat/agat_sp_merge_annotations:main' + fi + + # print dockerfile + if [ "$VIASH_MODE" == "dockerfile" ]; then + ViashDockerfile "$VIASH_ENGINE_ID" + exit 0 + + elif [ "$VIASH_MODE" == "docker_image_id" ]; then + echo "$VIASH_DOCKER_IMAGE_ID" + exit 0 + + # enter docker container + elif [[ "$VIASH_MODE" == "debug" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} -v '$(pwd)':/pwd --workdir /pwd -t $VIASH_DOCKER_IMAGE_ID" + ViashNotice "+ $VIASH_CMD" + eval $VIASH_CMD + exit + + # build docker image + elif [ "$VIASH_MODE" == "setup" ]; then + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" "$VIASH_SETUP_STRATEGY" + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' + exit 0 + fi + + # check if docker image exists + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" ifneedbepullelsecachedbuild + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' +fi + +# setting computational defaults + +# helper function for parsing memory strings +function ViashMemoryAsBytes { + local memory=`echo "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'` + local memory_regex='^([0-9]+)([kmgtp]i?b?|b)$' + if [[ $memory =~ $memory_regex ]]; then + local number=${memory/[^0-9]*/} + local symbol=${memory/*[0-9]/} + + case $symbol in + b) memory_b=$number ;; + kb|k) memory_b=$(( $number * 1000 )) ;; + mb|m) memory_b=$(( $number * 1000 * 1000 )) ;; + gb|g) memory_b=$(( $number * 1000 * 1000 * 1000 )) ;; + tb|t) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 )) ;; + pb|p) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 * 1000 )) ;; + kib|ki) memory_b=$(( $number * 1024 )) ;; + mib|mi) memory_b=$(( $number * 1024 * 1024 )) ;; + gib|gi) memory_b=$(( $number * 1024 * 1024 * 1024 )) ;; + tib|ti) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 )) ;; + pib|pi) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 * 1024 )) ;; + esac + echo "$memory_b" + fi +} +# compute memory in different units +if [ ! -z ${VIASH_META_MEMORY+x} ]; then + VIASH_META_MEMORY_B=`ViashMemoryAsBytes $VIASH_META_MEMORY` + # do not define other variables if memory_b is an empty string + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_META_MEMORY_KB=$(( ($VIASH_META_MEMORY_B+999) / 1000 )) + VIASH_META_MEMORY_MB=$(( ($VIASH_META_MEMORY_KB+999) / 1000 )) + VIASH_META_MEMORY_GB=$(( ($VIASH_META_MEMORY_MB+999) / 1000 )) + VIASH_META_MEMORY_TB=$(( ($VIASH_META_MEMORY_GB+999) / 1000 )) + VIASH_META_MEMORY_PB=$(( ($VIASH_META_MEMORY_TB+999) / 1000 )) + VIASH_META_MEMORY_KIB=$(( ($VIASH_META_MEMORY_B+1023) / 1024 )) + VIASH_META_MEMORY_MIB=$(( ($VIASH_META_MEMORY_KIB+1023) / 1024 )) + VIASH_META_MEMORY_GIB=$(( ($VIASH_META_MEMORY_MIB+1023) / 1024 )) + VIASH_META_MEMORY_TIB=$(( ($VIASH_META_MEMORY_GIB+1023) / 1024 )) + VIASH_META_MEMORY_PIB=$(( ($VIASH_META_MEMORY_TIB+1023) / 1024 )) + else + # unset memory if string is empty + unset $VIASH_META_MEMORY_B + fi +fi +# unset nproc if string is empty +if [ -z "$VIASH_META_CPUS" ]; then + unset $VIASH_META_CPUS +fi + + +# check whether required parameters exist +if [ -z ${VIASH_PAR_GFF+x} ]; then + ViashError '--gff' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_PAR_OUTPUT+x} ]; then + ViashError '--output' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_NAME+x} ]; then + ViashError 'name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_FUNCTIONALITY_NAME+x} ]; then + ViashError 'functionality_name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_RESOURCES_DIR+x} ]; then + ViashError 'resources_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_EXECUTABLE+x} ]; then + ViashError 'executable' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_CONFIG+x} ]; then + ViashError 'config' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_TEMP_DIR+x} ]; then + ViashError 'temp_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi + +# check whether required files exist +if [ ! -z "$VIASH_PAR_GFF" ]; then + IFS=';' + set -f + for file in $VIASH_PAR_GFF; do + unset IFS + if [ ! -e "$file" ]; then + ViashError "Input file '$file' does not exist." + exit 1 + fi + done + set +f +fi +if [ ! -z "$VIASH_PAR_CONFIG" ] && [ ! -e "$VIASH_PAR_CONFIG" ]; then + ViashError "Input file '$VIASH_PAR_CONFIG' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_META_CPUS" ]]; then + if ! [[ "$VIASH_META_CPUS" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'cpus' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_B" ]]; then + if ! [[ "$VIASH_META_MEMORY_B" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_b' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi + +# create parent directories of output files, if so desired +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT")" +fi + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + if [ "$VIASH_MODE" == "run" ]; then + VIASH_CMD="bash" + else + ViashError "Engine '$VIASH_ENGINE_ID' does not support mode '$VIASH_MODE'." + exit 1 + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # detect volumes from file arguments + VIASH_CHOWN_VARS=() +if [ ! -z "$VIASH_PAR_GFF" ]; then + VIASH_TEST_GFF=() + IFS=';' + for var in $VIASH_PAR_GFF; do + unset IFS + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$var")" ) + var=$(ViashDockerAutodetectMount "$var") + VIASH_TEST_GFF+=( "$var" ) + done + VIASH_PAR_GFF=$(IFS=';' ; echo "${VIASH_TEST_GFF[*]}") +fi +if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT")" ) + VIASH_PAR_OUTPUT=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT" ) +fi +if [ ! -z "$VIASH_PAR_CONFIG" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_CONFIG")" ) + VIASH_PAR_CONFIG=$(ViashDockerAutodetectMount "$VIASH_PAR_CONFIG") +fi +if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_RESOURCES_DIR")" ) + VIASH_META_RESOURCES_DIR=$(ViashDockerAutodetectMount "$VIASH_META_RESOURCES_DIR") +fi +if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_EXECUTABLE")" ) + VIASH_META_EXECUTABLE=$(ViashDockerAutodetectMount "$VIASH_META_EXECUTABLE") +fi +if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_CONFIG")" ) + VIASH_META_CONFIG=$(ViashDockerAutodetectMount "$VIASH_META_CONFIG") +fi +if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_TEMP_DIR")" ) + VIASH_META_TEMP_DIR=$(ViashDockerAutodetectMount "$VIASH_META_TEMP_DIR") +fi + + # get unique mounts + VIASH_UNIQUE_MOUNTS=($(for val in "${VIASH_DIRECTORY_MOUNTS[@]}"; do echo "$val"; done | sort -u)) +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # change file ownership + function ViashPerformChown { + if (( ${#VIASH_CHOWN_VARS[@]} )); then + set +e + VIASH_CMD="docker run --entrypoint=bash --rm ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID -c 'chown $(id -u):$(id -g) --silent --recursive ${VIASH_CHOWN_VARS[@]}'" + ViashDebug "+ $VIASH_CMD" + eval $VIASH_CMD + set -e + fi + } + trap ViashPerformChown EXIT +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # helper function for filling in extra docker args + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_DOCKER_RUN_ARGS+=("--memory=${VIASH_META_MEMORY_B}") + fi + if [ ! -z "$VIASH_META_CPUS" ]; then + VIASH_DOCKER_RUN_ARGS+=("--cpus=${VIASH_META_CPUS}") + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID" +fi + + +# set dependency paths + + +ViashDebug "Running command: $(echo $VIASH_CMD)" +cat << VIASHEOF | eval $VIASH_CMD +set -e +tempscript=\$(mktemp "$VIASH_META_TEMP_DIR/viash-run-agat_sp_merge_annotations-XXXXXX").sh +function clean_up { + rm "\$tempscript" +} +function interrupt { + echo -e "\nCTRL-C Pressed..." + exit 1 +} +trap clean_up EXIT +trap interrupt INT SIGINT +cat > "\$tempscript" << 'VIASHMAIN' +#!/bin/bash + +set -eo pipefail + +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_GFF+x} ]; then echo "${VIASH_PAR_GFF}" | sed "s#'#'\"'\"'#g;s#.*#par_gff='&'#" ; else echo "# par_gff="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\"'\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; fi ) +$( if [ ! -z ${VIASH_PAR_CONFIG+x} ]; then echo "${VIASH_PAR_CONFIG}" | sed "s#'#'\"'\"'#g;s#.*#par_config='&'#" ; else echo "# par_config="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\"'\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\"'\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\"'\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\"'\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END + +# Convert a list of file names to multiple -gff arguments +input_files="" +IFS=";" read -ra file_names <<< "\$par_gff" +for file in "\${file_names[@]}"; do + input_files+="--gff \$file " +done + +# run agat_sp_merge_annotations +agat_sp_merge_annotations.pl \\ + \$input_files \\ + -o "\$par_output" \\ + \${par_config:+--config "\${par_config}"} +VIASHMAIN +bash "\$tempscript" & +wait "\$!" + +VIASHEOF + + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # strip viash automount from file paths + + if [ ! -z "$VIASH_PAR_GFF" ]; then + unset VIASH_TEST_GFF + IFS=';' + for var in $VIASH_PAR_GFF; do + unset IFS + if [ -z "$VIASH_TEST_GFF" ]; then + VIASH_TEST_GFF="$(ViashDockerStripAutomount "$var")" + else + VIASH_TEST_GFF="$VIASH_TEST_GFF;""$(ViashDockerStripAutomount "$var")" + fi + done + VIASH_PAR_GFF="$VIASH_TEST_GFF" + fi + if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_PAR_OUTPUT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT") + fi + if [ ! -z "$VIASH_PAR_CONFIG" ]; then + VIASH_PAR_CONFIG=$(ViashDockerStripAutomount "$VIASH_PAR_CONFIG") + fi + if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_META_RESOURCES_DIR=$(ViashDockerStripAutomount "$VIASH_META_RESOURCES_DIR") + fi + if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_META_EXECUTABLE=$(ViashDockerStripAutomount "$VIASH_META_EXECUTABLE") + fi + if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_META_CONFIG=$(ViashDockerStripAutomount "$VIASH_META_CONFIG") + fi + if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_META_TEMP_DIR=$(ViashDockerStripAutomount "$VIASH_META_TEMP_DIR") + fi +fi + + +# check whether required files exist +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -e "$VIASH_PAR_OUTPUT" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT' does not exist." + exit 1 +fi + + +exit 0 diff --git a/target/executable/agat/agat_sp_statistics/.config.vsh.yaml b/target/executable/agat/agat_sp_statistics/.config.vsh.yaml index d0a5e433..349b3d36 100644 --- a/target/executable/agat/agat_sp_statistics/.config.vsh.yaml +++ b/target/executable/agat/agat_sp_statistics/.config.vsh.yaml @@ -231,9 +231,9 @@ build_info: output: "target/executable/agat/agat_sp_statistics" executable: "target/executable/agat/agat_sp_statistics/agat_sp_statistics" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/agat/agat_sp_statistics/agat_sp_statistics b/target/executable/agat/agat_sp_statistics/agat_sp_statistics index b8c0572e..eeac3fca 100755 --- a/target/executable/agat/agat_sp_statistics/agat_sp_statistics +++ b/target/executable/agat/agat_sp_statistics/agat_sp_statistics @@ -507,9 +507,9 @@ RUN agat --version | sed 's/.*v\.//; s/\s.*//' | sed 's/^/AGAT: /' > /var/softwa LABEL org.opencontainers.image.authors="Leïla Paquay" LABEL org.opencontainers.image.description="Companion container for running component agat agat_sp_statistics" -LABEL org.opencontainers.image.created="2024-10-26T13:11:20Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:09Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/arriba/.config.vsh.yaml b/target/executable/arriba/.config.vsh.yaml index 4c6038ff..a034357e 100644 --- a/target/executable/arriba/.config.vsh.yaml +++ b/target/executable/arriba/.config.vsh.yaml @@ -706,9 +706,9 @@ build_info: output: "target/executable/arriba" executable: "target/executable/arriba/arriba" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/arriba/arriba b/target/executable/arriba/arriba index 2bfca067..b957fcd6 100755 --- a/target/executable/arriba/arriba +++ b/target/executable/arriba/arriba @@ -754,9 +754,9 @@ RUN arriba -h | grep 'Version:' 2>&1 | sed 's/Version:\s\(.*\)/arriba: "\1"/' > LABEL org.opencontainers.image.authors="Robrecht Cannoodt" LABEL org.opencontainers.image.description="Companion container for running component arriba" -LABEL org.opencontainers.image.created="2024-10-26T13:11:21Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:10Z" LABEL org.opencontainers.image.source="https://github.com/suhrig/arriba" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bbmap/bbmap_bbsplit/.config.vsh.yaml b/target/executable/bbmap/bbmap_bbsplit/.config.vsh.yaml index 6a2c5c50..6586c1e4 100644 --- a/target/executable/bbmap/bbmap_bbsplit/.config.vsh.yaml +++ b/target/executable/bbmap/bbmap_bbsplit/.config.vsh.yaml @@ -359,9 +359,9 @@ build_info: output: "target/executable/bbmap/bbmap_bbsplit" executable: "target/executable/bbmap/bbmap_bbsplit/bbmap_bbsplit" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bbmap/bbmap_bbsplit/bbmap_bbsplit b/target/executable/bbmap/bbmap_bbsplit/bbmap_bbsplit index 52083431..fc42d009 100755 --- a/target/executable/bbmap/bbmap_bbsplit/bbmap_bbsplit +++ b/target/executable/bbmap/bbmap_bbsplit/bbmap_bbsplit @@ -600,9 +600,9 @@ cp -r bbmap/* /usr/local/bin RUN bbsplit.sh --version 2>&1 | awk '/BBMap version/{print "BBMAP:", $NF}' > /var/software_versions.txt LABEL org.opencontainers.image.description="Companion container for running component bbmap bbmap_bbsplit" -LABEL org.opencontainers.image.created="2024-10-26T13:11:24Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:12Z" LABEL org.opencontainers.image.source="https://github.com/BioInfoTools/BBMap/blob/master/sh/bbsplit.sh" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bcftools/bcftools_annotate/.config.vsh.yaml b/target/executable/bcftools/bcftools_annotate/.config.vsh.yaml index 5dcd2f17..5228e868 100644 --- a/target/executable/bcftools/bcftools_annotate/.config.vsh.yaml +++ b/target/executable/bcftools/bcftools_annotate/.config.vsh.yaml @@ -469,9 +469,9 @@ build_info: output: "target/executable/bcftools/bcftools_annotate" executable: "target/executable/bcftools/bcftools_annotate/bcftools_annotate" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bcftools/bcftools_annotate/bcftools_annotate b/target/executable/bcftools/bcftools_annotate/bcftools_annotate index 8d54a340..1158f3e3 100755 --- a/target/executable/bcftools/bcftools_annotate/bcftools_annotate +++ b/target/executable/bcftools/bcftools_annotate/bcftools_annotate @@ -650,9 +650,9 @@ RUN echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftoo LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bcftools bcftools_annotate" -LABEL org.opencontainers.image.created="2024-10-26T13:11:12Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:00Z" LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bcftools/bcftools_concat/.config.vsh.yaml b/target/executable/bcftools/bcftools_concat/.config.vsh.yaml index 39aaf690..ade51af9 100644 --- a/target/executable/bcftools/bcftools_concat/.config.vsh.yaml +++ b/target/executable/bcftools/bcftools_concat/.config.vsh.yaml @@ -335,9 +335,9 @@ build_info: output: "target/executable/bcftools/bcftools_concat" executable: "target/executable/bcftools/bcftools_concat/bcftools_concat" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bcftools/bcftools_concat/bcftools_concat b/target/executable/bcftools/bcftools_concat/bcftools_concat index 63ae35cb..b49da971 100755 --- a/target/executable/bcftools/bcftools_concat/bcftools_concat +++ b/target/executable/bcftools/bcftools_concat/bcftools_concat @@ -566,9 +566,9 @@ RUN echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftoo LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bcftools bcftools_concat" -LABEL org.opencontainers.image.created="2024-10-26T13:11:13Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:01Z" LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bcftools/bcftools_norm/.config.vsh.yaml b/target/executable/bcftools/bcftools_norm/.config.vsh.yaml index e1b53f7e..b71f853d 100644 --- a/target/executable/bcftools/bcftools_norm/.config.vsh.yaml +++ b/target/executable/bcftools/bcftools_norm/.config.vsh.yaml @@ -416,9 +416,9 @@ build_info: output: "target/executable/bcftools/bcftools_norm" executable: "target/executable/bcftools/bcftools_norm/bcftools_norm" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bcftools/bcftools_norm/bcftools_norm b/target/executable/bcftools/bcftools_norm/bcftools_norm index 8f1661d2..7544eb41 100755 --- a/target/executable/bcftools/bcftools_norm/bcftools_norm +++ b/target/executable/bcftools/bcftools_norm/bcftools_norm @@ -589,9 +589,9 @@ RUN echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftoo LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bcftools bcftools_norm" -LABEL org.opencontainers.image.created="2024-10-26T13:11:14Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:02Z" LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bcftools/bcftools_sort/.config.vsh.yaml b/target/executable/bcftools/bcftools_sort/.config.vsh.yaml index 95bb973f..388a563e 100644 --- a/target/executable/bcftools/bcftools_sort/.config.vsh.yaml +++ b/target/executable/bcftools/bcftools_sort/.config.vsh.yaml @@ -185,9 +185,9 @@ build_info: output: "target/executable/bcftools/bcftools_sort" executable: "target/executable/bcftools/bcftools_sort/bcftools_sort" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bcftools/bcftools_sort/bcftools_sort b/target/executable/bcftools/bcftools_sort/bcftools_sort index 54c82d1e..9b2f72e5 100755 --- a/target/executable/bcftools/bcftools_sort/bcftools_sort +++ b/target/executable/bcftools/bcftools_sort/bcftools_sort @@ -483,9 +483,9 @@ RUN echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftoo LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bcftools bcftools_sort" -LABEL org.opencontainers.image.created="2024-10-26T13:11:14Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:02Z" LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bcftools/bcftools_stats/.config.vsh.yaml b/target/executable/bcftools/bcftools_stats/.config.vsh.yaml index cf6ffceb..7216a9f9 100644 --- a/target/executable/bcftools/bcftools_stats/.config.vsh.yaml +++ b/target/executable/bcftools/bcftools_stats/.config.vsh.yaml @@ -458,9 +458,9 @@ build_info: output: "target/executable/bcftools/bcftools_stats" executable: "target/executable/bcftools/bcftools_stats/bcftools_stats" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bcftools/bcftools_stats/bcftools_stats b/target/executable/bcftools/bcftools_stats/bcftools_stats index d9e1da31..d9ebd0d9 100755 --- a/target/executable/bcftools/bcftools_stats/bcftools_stats +++ b/target/executable/bcftools/bcftools_stats/bcftools_stats @@ -626,9 +626,9 @@ RUN echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftoo LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bcftools bcftools_stats" -LABEL org.opencontainers.image.created="2024-10-26T13:11:13Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:01Z" LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bcl_convert/.config.vsh.yaml b/target/executable/bcl_convert/.config.vsh.yaml index dbefed7e..b31b4646 100644 --- a/target/executable/bcl_convert/.config.vsh.yaml +++ b/target/executable/bcl_convert/.config.vsh.yaml @@ -418,9 +418,9 @@ build_info: output: "target/executable/bcl_convert" executable: "target/executable/bcl_convert/bcl_convert" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bcl_convert/bcl_convert b/target/executable/bcl_convert/bcl_convert index b262e57b..6eddf272 100755 --- a/target/executable/bcl_convert/bcl_convert +++ b/target/executable/bcl_convert/bcl_convert @@ -599,9 +599,9 @@ RUN echo "bcl-convert: \"$(bcl-convert -V 2>&1 >/dev/null | sed -n '/Version/ s/ LABEL org.opencontainers.image.authors="Toni Verbeiren, Dorien Roosen" LABEL org.opencontainers.image.description="Companion container for running component bcl_convert" -LABEL org.opencontainers.image.created="2024-10-26T13:11:19Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:07Z" LABEL org.opencontainers.image.source="https://github.com/viash-hub/biobox" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bd_rhapsody/bd_rhapsody_make_reference/.config.vsh.yaml b/target/executable/bd_rhapsody/bd_rhapsody_make_reference/.config.vsh.yaml index 8bcf1fcb..d501da67 100644 --- a/target/executable/bd_rhapsody/bd_rhapsody_make_reference/.config.vsh.yaml +++ b/target/executable/bd_rhapsody/bd_rhapsody_make_reference/.config.vsh.yaml @@ -274,9 +274,9 @@ build_info: output: "target/executable/bd_rhapsody/bd_rhapsody_make_reference" executable: "target/executable/bd_rhapsody/bd_rhapsody_make_reference/bd_rhapsody_make_reference" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bd_rhapsody/bd_rhapsody_make_reference/bd_rhapsody_make_reference b/target/executable/bd_rhapsody/bd_rhapsody_make_reference/bd_rhapsody_make_reference index 732fa212..5cb72ebb 100755 --- a/target/executable/bd_rhapsody/bd_rhapsody_make_reference/bd_rhapsody_make_reference +++ b/target/executable/bd_rhapsody/bd_rhapsody_make_reference/bd_rhapsody_make_reference @@ -554,9 +554,9 @@ RUN VERSION=$(ls -v /var/bd_rhapsody_cwl | grep '^v' | sed 's#v##' | tail -1) RUN echo "bdgenomics/rhapsody: \"$VERSION\"" > /var/software_versions.txt LABEL org.opencontainers.image.authors="Robrecht Cannoodt, Weiwei Schultz" LABEL org.opencontainers.image.description="Companion container for running component bd_rhapsody bd_rhapsody_make_reference" -LABEL org.opencontainers.image.created="2024-10-26T13:11:16Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:03Z" LABEL org.opencontainers.image.source="https://bitbucket.org/CRSwDev/cwl/src/master/v2.2.1/Extra_Utilities/" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis/.config.vsh.yaml b/target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis/.config.vsh.yaml index fa967a06..75eb0e02 100644 --- a/target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis/.config.vsh.yaml +++ b/target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis/.config.vsh.yaml @@ -1115,9 +1115,9 @@ build_info: output: "target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis" executable: "target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis/bd_rhapsody_sequence_analysis" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis/bd_rhapsody_sequence_analysis b/target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis/bd_rhapsody_sequence_analysis index b3228441..a91508ab 100755 --- a/target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis/bd_rhapsody_sequence_analysis +++ b/target/executable/bd_rhapsody/bd_rhapsody_sequence_analysis/bd_rhapsody_sequence_analysis @@ -954,9 +954,9 @@ RUN VERSION=$(ls -v /var/bd_rhapsody_cwl | grep '^v' | sed 's#v##' | tail -1) RUN echo "bdgenomics/rhapsody: \"$VERSION\"" > /var/software_versions.txt LABEL org.opencontainers.image.authors="Robrecht Cannoodt, Weiwei Schultz" LABEL org.opencontainers.image.description="Companion container for running component bd_rhapsody bd_rhapsody_sequence_analysis" -LABEL org.opencontainers.image.created="2024-10-26T13:11:16Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:03Z" LABEL org.opencontainers.image.source="https://bitbucket.org/CRSwDev/cwl/src/master/v2.2.1" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_bamtobed/.config.vsh.yaml b/target/executable/bedtools/bedtools_bamtobed/.config.vsh.yaml new file mode 100644 index 00000000..c495fa2f --- /dev/null +++ b/target/executable/bedtools/bedtools_bamtobed/.config.vsh.yaml @@ -0,0 +1,262 @@ +name: "bedtools_bamtobed" +namespace: "bedtools" +version: "main" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + - "maintainer" + info: + links: + email: "theodorogtc@gmail.com" + github: "tgaspe" + linkedin: "theodoro-gasperin-terra-camargo" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Bioinformatician" +argument_groups: +- name: "Inputs" + arguments: + - type: "file" + name: "--input" + alternatives: + - "-i" + description: "Input BAM file." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + description: "Output BED file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "boolean_true" + name: "--bedpe" + description: "Write BEDPE format. Requires BAM to be grouped or sorted by query.\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--mate1" + description: "When writing BEDPE (-bedpe) format, always report mate one as the\ + \ first BEDPE \"block\".\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--bed12" + description: "Write \"blocked\" BED format (aka \"BED12\"). Forces -split.\nSee\ + \ http://genome-test.cse.ucsc.edu/FAQ/FAQformat#format1\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--split" + description: "Report \"split\" BAM alignments as separate BED entries.\nSplits\ + \ only on N CIGAR operations.\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--splitD" + description: "Split alignments based on N and D CIGAR operators.\nForces -split.\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--edit_distance" + alternatives: + - "-ed" + description: "Use BAM edit distance (NM tag) for BED score.\n- Default for BED\ + \ is to use mapping quality.\n- Default for BEDPE is to use the minimum of\n\ + \ the two mapping qualities for the pair.\n- When -ed is used with -bedpe,\ + \ the total edit\n distance from the two mates is reported.\n" + info: null + direction: "input" + - type: "string" + name: "--tag" + description: "Use other NUMERIC BAM alignment tag for BED score.\nDefault for\ + \ BED is to use mapping quality. Disallowed with BEDPE output.\n" + info: null + example: + - "SM" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--color" + description: "An R,G,B string for the color used with BED12 format.\nDefault is\ + \ (255,0,0).\n" + info: null + example: + - "250,250,250" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--cigar" + description: "Add the CIGAR string to the BED entry as a 7th column.\n" + info: null + direction: "input" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Converts BAM alignments to BED6 or BEDPE format." +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Converts" +- "BAM" +- "BED" +- "BED6" +- "BEDPE" +license: "MIT" +references: + doi: + - "10.1093/bioinformatics/btq033" +links: + repository: "https://github.com/arq5x/bedtools2" + homepage: "https://bedtools.readthedocs.io/en/latest/#" + documentation: "https://bedtools.readthedocs.io/en/latest/content/tools/bamtobed.html" + issue_tracker: "https://github.com/arq5x/bedtools2/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "debian:stable-slim" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bedtools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bedtools: \\\"$(bedtools --version | sed -n 's/^bedtools //p')\\\"\"\ + \ > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bedtools/bedtools_bamtobed/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/bedtools/bedtools_bamtobed" + executable: "target/executable/bedtools/bedtools_bamtobed/bedtools_bamtobed" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/executable/bedtools/bedtools_bamtobed/bedtools_bamtobed b/target/executable/bedtools/bedtools_bamtobed/bedtools_bamtobed new file mode 100755 index 00000000..8ddc020e --- /dev/null +++ b/target/executable/bedtools/bedtools_bamtobed/bedtools_bamtobed @@ -0,0 +1,1313 @@ +#!/usr/bin/env bash + +# bedtools_bamtobed main +# +# This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +# work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +# Intuitive. +# +# The component may contain files which fall under a different license. The +# authors of this component should specify the license in the header of such +# files, or include a separate license file detailing the licenses of all included +# files. +# +# Component authors: +# * Theodoro Gasperin Terra Camargo (author, maintainer) + +set -e + +if [ -z "$VIASH_TEMP" ]; then + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMP} + VIASH_TEMP=${VIASH_TEMP:-$TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TMP} + VIASH_TEMP=${VIASH_TEMP:-$TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TEMP} + VIASH_TEMP=${VIASH_TEMP:-/tmp} +fi + +# define helper functions +# ViashQuote: put quotes around non flag values +# $1 : unquoted string +# return : possibly quoted string +# examples: +# ViashQuote --foo # returns --foo +# ViashQuote bar # returns 'bar' +# Viashquote --foo=bar # returns --foo='bar' +function ViashQuote { + if [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+=.+$ ]]; then + echo "$1" | sed "s#=\(.*\)#='\1'#" + elif [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+$ ]]; then + echo "$1" + else + echo "'$1'" + fi +} +# ViashRemoveFlags: Remove leading flag +# $1 : string with a possible leading flag +# return : string without possible leading flag +# examples: +# ViashRemoveFlags --foo=bar # returns bar +function ViashRemoveFlags { + echo "$1" | sed 's/^--*[a-zA-Z0-9_\-]*=//' +} +# ViashSourceDir: return the path of a bash file, following symlinks +# usage : ViashSourceDir ${BASH_SOURCE[0]} +# $1 : Should always be set to ${BASH_SOURCE[0]} +# returns : The absolute path of the bash file +function ViashSourceDir { + local source="$1" + while [ -h "$source" ]; do + local dir="$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd )" + source="$(readlink "$source")" + [[ $source != /* ]] && source="$dir/$source" + done + cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd +} +# ViashFindTargetDir: return the path of the '.build.yaml' file, following symlinks +# usage : ViashFindTargetDir 'ScriptPath' +# $1 : The location from where to start the upward search +# returns : The absolute path of the '.build.yaml' file +function ViashFindTargetDir { + local source="$1" + while [[ "$source" != "" && ! -e "$source/.build.yaml" ]]; do + source=${source%/*} + done + echo $source +} +# see https://en.wikipedia.org/wiki/Syslog#Severity_level +VIASH_LOGCODE_EMERGENCY=0 +VIASH_LOGCODE_ALERT=1 +VIASH_LOGCODE_CRITICAL=2 +VIASH_LOGCODE_ERROR=3 +VIASH_LOGCODE_WARNING=4 +VIASH_LOGCODE_NOTICE=5 +VIASH_LOGCODE_INFO=6 +VIASH_LOGCODE_DEBUG=7 +VIASH_VERBOSITY=$VIASH_LOGCODE_NOTICE + +# ViashLog: Log events depending on the verbosity level +# usage: ViashLog 1 alert Oh no something went wrong! +# $1: required verbosity level +# $2: display tag +# $3+: messages to display +# stdout: Your input, prepended by '[$2] '. +function ViashLog { + local required_level="$1" + local display_tag="$2" + shift 2 + if [ $VIASH_VERBOSITY -ge $required_level ]; then + >&2 echo "[$display_tag]" "$@" + fi +} + +# ViashEmergency: log events when the system is unstable +# usage: ViashEmergency Oh no something went wrong. +# stdout: Your input, prepended by '[emergency] '. +function ViashEmergency { + ViashLog $VIASH_LOGCODE_EMERGENCY emergency "$@" +} + +# ViashAlert: log events when actions must be taken immediately (e.g. corrupted system database) +# usage: ViashAlert Oh no something went wrong. +# stdout: Your input, prepended by '[alert] '. +function ViashAlert { + ViashLog $VIASH_LOGCODE_ALERT alert "$@" +} + +# ViashCritical: log events when a critical condition occurs +# usage: ViashCritical Oh no something went wrong. +# stdout: Your input, prepended by '[critical] '. +function ViashCritical { + ViashLog $VIASH_LOGCODE_CRITICAL critical "$@" +} + +# ViashError: log events when an error condition occurs +# usage: ViashError Oh no something went wrong. +# stdout: Your input, prepended by '[error] '. +function ViashError { + ViashLog $VIASH_LOGCODE_ERROR error "$@" +} + +# ViashWarning: log potentially abnormal events +# usage: ViashWarning Something may have gone wrong. +# stdout: Your input, prepended by '[warning] '. +function ViashWarning { + ViashLog $VIASH_LOGCODE_WARNING warning "$@" +} + +# ViashNotice: log significant but normal events +# usage: ViashNotice This just happened. +# stdout: Your input, prepended by '[notice] '. +function ViashNotice { + ViashLog $VIASH_LOGCODE_NOTICE notice "$@" +} + +# ViashInfo: log normal events +# usage: ViashInfo This just happened. +# stdout: Your input, prepended by '[info] '. +function ViashInfo { + ViashLog $VIASH_LOGCODE_INFO info "$@" +} + +# ViashDebug: log all events, for debugging purposes +# usage: ViashDebug This just happened. +# stdout: Your input, prepended by '[debug] '. +function ViashDebug { + ViashLog $VIASH_LOGCODE_DEBUG debug "$@" +} + +# find source folder of this component +VIASH_META_RESOURCES_DIR=`ViashSourceDir ${BASH_SOURCE[0]}` + +# find the root of the built components & dependencies +VIASH_TARGET_DIR=`ViashFindTargetDir $VIASH_META_RESOURCES_DIR` + +# define meta fields +VIASH_META_NAME="bedtools_bamtobed" +VIASH_META_FUNCTIONALITY_NAME="bedtools_bamtobed" +VIASH_META_EXECUTABLE="$VIASH_META_RESOURCES_DIR/$VIASH_META_NAME" +VIASH_META_CONFIG="$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" +VIASH_META_TEMP_DIR="$VIASH_TEMP" + + +# ViashHelp: Display helpful explanation about this executable +function ViashHelp { + echo "bedtools_bamtobed main" + echo "" + echo "Converts BAM alignments to BED6 or BEDPE format." + echo "" + echo "Inputs:" + echo " -i, --input" + echo " type: file, required parameter, file must exist" + echo " Input BAM file." + echo "" + echo "Outputs:" + echo " -o, --output" + echo " type: file, required parameter, output, file must exist" + echo " Output BED file." + echo "" + echo "Options:" + echo " --bedpe" + echo " type: boolean_true" + echo " Write BEDPE format. Requires BAM to be grouped or sorted by query." + echo "" + echo " --mate1" + echo " type: boolean_true" + echo " When writing BEDPE (-bedpe) format, always report mate one as the first" + echo " BEDPE \"block\"." + echo "" + echo " --bed12" + echo " type: boolean_true" + echo " Write \"blocked\" BED format (aka \"BED12\"). Forces -split." + echo " See http://genome-test.cse.ucsc.edu/FAQ/FAQformat#format1" + echo "" + echo " --split" + echo " type: boolean_true" + echo " Report \"split\" BAM alignments as separate BED entries." + echo " Splits only on N CIGAR operations." + echo "" + echo " --splitD" + echo " type: boolean_true" + echo " Split alignments based on N and D CIGAR operators." + echo " Forces -split." + echo "" + echo " -ed, --edit_distance" + echo " type: boolean_true" + echo " Use BAM edit distance (NM tag) for BED score." + echo " - Default for BED is to use mapping quality." + echo " - Default for BEDPE is to use the minimum of" + echo " the two mapping qualities for the pair." + echo " - When -ed is used with -bedpe, the total edit" + echo " distance from the two mates is reported." + echo "" + echo " --tag" + echo " type: string" + echo " example: SM" + echo " Use other NUMERIC BAM alignment tag for BED score." + echo " Default for BED is to use mapping quality. Disallowed with BEDPE output." + echo "" + echo " --color" + echo " type: string" + echo " example: 250,250,250" + echo " An R,G,B string for the color used with BED12 format." + echo " Default is (255,0,0)." + echo "" + echo " --cigar" + echo " type: boolean_true" + echo " Add the CIGAR string to the BED entry as a 7th column." +} + +# initialise variables +VIASH_MODE='run' +VIASH_ENGINE_ID='docker' + +######## Helper functions for setting up Docker images for viash ######## +# expects: ViashDockerBuild + +# ViashDockerInstallationCheck: check whether Docker is installed correctly +# +# examples: +# ViashDockerInstallationCheck +function ViashDockerInstallationCheck { + ViashDebug "Checking whether Docker is installed" + if [ ! command -v docker &> /dev/null ]; then + ViashCritical "Docker doesn't seem to be installed. See 'https://docs.docker.com/get-docker/' for instructions." + exit 1 + fi + + ViashDebug "Checking whether the Docker daemon is running" + local save=$-; set +e + local docker_version=$(docker version --format '{{.Client.APIVersion}}' 2> /dev/null) + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashCritical "Docker daemon does not seem to be running. Try one of the following:" + ViashCritical "- Try running 'dockerd' in the command line" + ViashCritical "- See https://docs.docker.com/config/daemon/" + exit 1 + fi +} + +# ViashDockerRemoteTagCheck: check whether a Docker image is available +# on a remote. Assumes `docker login` has been performed, if relevant. +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerRemoteTagCheck python:latest +# echo $? # returns '0' +# ViashDockerRemoteTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerRemoteTagCheck { + docker manifest inspect $1 > /dev/null 2> /dev/null +} + +# ViashDockerLocalTagCheck: check whether a Docker image is available locally +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# docker pull python:latest +# ViashDockerLocalTagCheck python:latest +# echo $? # returns '0' +# ViashDockerLocalTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerLocalTagCheck { + [ -n "$(docker images -q $1)" ] +} + +# ViashDockerPull: pull a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPull python:latest +# echo $? # returns '0' +# ViashDockerPull sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPull { + ViashNotice "Checking if Docker image is available at '$1'" + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker pull $1 && return 0 || return 1 + else + local save=$-; set +e + docker pull $1 2> /dev/null > /dev/null + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashWarning "Could not pull from '$1'. Docker image doesn't exist or is not accessible." + fi + return $out + fi +} + +# ViashDockerPush: push a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPush python:latest +# echo $? # returns '0' +# ViashDockerPush sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPush { + ViashNotice "Pushing image to '$1'" + local save=$-; set +e + local out + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker push $1 + out=$? + else + docker push $1 2> /dev/null > /dev/null + out=$? + fi + [[ $save =~ e ]] && set -e + if [ $out -eq 0 ]; then + ViashNotice "Container '$1' push succeeded." + else + ViashError "Container '$1' push errored. You might not be logged in or have the necessary permissions." + fi + return $out +} + +# ViashDockerPullElseBuild: pull a Docker image, else build it +# +# $1 : image identifier with format `[registry/]image[:tag]` +# ViashDockerBuild : a Bash function which builds a docker image, takes image identifier as argument. +# examples: +# ViashDockerPullElseBuild mynewcomponent +function ViashDockerPullElseBuild { + local save=$-; set +e + ViashDockerPull $1 + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashDockerBuild $@ + fi +} + +# ViashDockerSetup: create a Docker image, according to specified docker setup strategy +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $2 : docker setup strategy, see DockerSetupStrategy.scala +# examples: +# ViashDockerSetup mynewcomponent alwaysbuild +function ViashDockerSetup { + local image_id="$1" + local setup_strategy="$2" + if [ "$setup_strategy" == "alwaysbuild" -o "$setup_strategy" == "build" -o "$setup_strategy" == "b" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspull" -o "$setup_strategy" == "pull" -o "$setup_strategy" == "p" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "alwayspullelsebuild" -o "$setup_strategy" == "pullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspullelsecachedbuild" -o "$setup_strategy" == "pullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayscachedbuild" -o "$setup_strategy" == "cachedbuild" -o "$setup_strategy" == "cb" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [[ "$setup_strategy" =~ ^ifneedbe ]]; then + local save=$-; set +e + ViashDockerLocalTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashInfo "Image $image_id already exists" + elif [ "$setup_strategy" == "ifneedbebuild" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbecachedbuild" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepull" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "ifneedbepullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi + elif [ "$setup_strategy" == "push" -o "$setup_strategy" == "forcepush" -o "$setup_strategy" == "alwayspush" ]; then + ViashDockerPush "$image_id" + elif [ "$setup_strategy" == "pushifnotpresent" -o "$setup_strategy" == "gentlepush" -o "$setup_strategy" == "maybepush" ]; then + local save=$-; set +e + ViashDockerRemoteTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashNotice "Container '$image_id' exists, doing nothing." + else + ViashNotice "Container '$image_id' does not yet exist." + ViashDockerPush "$image_id" + fi + elif [ "$setup_strategy" == "donothing" -o "$setup_strategy" == "meh" ]; then + ViashNotice "Skipping setup." + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi +} + +# ViashDockerCheckCommands: Check whether a docker container has the required commands +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $@ : commands to verify being present +# examples: +# ViashDockerCheckCommands bash:4.0 bash ps foo +function ViashDockerCheckCommands { + local image_id="$1" + shift 1 + local commands="$@" + local save=$-; set +e + local missing # mark 'missing' as local in advance, otherwise the exit code of the command will be missing and always be '0' + missing=$(docker run --rm --entrypoint=sh "$image_id" -c "for command in $commands; do command -v \$command >/dev/null 2>&1; if [ \$? -ne 0 ]; then echo \$command; exit 1; fi; done") + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -ne 0 ]; then + ViashError "Docker container '$image_id' does not contain command '$missing'." + exit 1 + fi +} + +# ViashDockerBuild: build a docker image +# $1 : image identifier with format `[registry/]image[:tag]` +# $... : additional arguments to pass to docker build +# $VIASH_META_TEMP_DIR : temporary directory to store dockerfile & optional resources in +# $VIASH_META_NAME : name of the component +# $VIASH_META_RESOURCES_DIR : directory containing the resources +# $VIASH_VERBOSITY : verbosity level +# exit code $? : whether or not the image was built successfully +function ViashDockerBuild { + local image_id="$1" + shift 1 + + # create temporary directory to store dockerfile & optional resources in + local tmpdir=$(mktemp -d "$VIASH_META_TEMP_DIR/dockerbuild-$VIASH_META_NAME-XXXXXX") + local dockerfile="$tmpdir/Dockerfile" + function clean_up { + rm -rf "$tmpdir" + } + trap clean_up EXIT + + # store dockerfile and resources + ViashDockerfile "$VIASH_ENGINE_ID" > "$dockerfile" + + # generate the build command + local docker_build_cmd="docker build -t '$image_id' $@ '$VIASH_META_RESOURCES_DIR' -f '$dockerfile'" + + # build the container + ViashNotice "Building container '$image_id' with Dockerfile" + ViashInfo "$docker_build_cmd" + local save=$-; set +e + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + eval $docker_build_cmd + else + eval $docker_build_cmd &> "$tmpdir/docker_build.log" + fi + + # check exit code + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashError "Error occurred while building container '$image_id'" + if [ $VIASH_VERBOSITY -lt $VIASH_LOGCODE_INFO ]; then + ViashError "Transcript: --------------------------------" + cat "$tmpdir/docker_build.log" + ViashError "End of transcript --------------------------" + fi + exit 1 + fi +} + +######## End of helper functions for setting up Docker images for viash ######## + +# ViashDockerFile: print the dockerfile to stdout +# $1 : engine identifier +# return : dockerfile required to run this component +# examples: +# ViashDockerFile +function ViashDockerfile { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + cat << 'VIASHDOCKER' +FROM debian:stable-slim +ENTRYPOINT [] +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y bedtools procps && \ + rm -rf /var/lib/apt/lists/* + +RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var/software_versions.txt + +LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" +LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_bamtobed" +LABEL org.opencontainers.image.created="2024-10-26T18:44:08Z" +LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" +LABEL org.opencontainers.image.version="main" + +VIASHDOCKER + fi +} + +# ViashDockerBuildArgs: return the arguments to pass to docker build +# $1 : engine identifier +# return : arguments to pass to docker build +function ViashDockerBuildArgs { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + echo "" + fi +} + +# ViashAbsolutePath: generate absolute path from relative path +# borrowed from https://stackoverflow.com/a/21951256 +# $1 : relative filename +# return : absolute path +# examples: +# ViashAbsolutePath some_file.txt # returns /path/to/some_file.txt +# ViashAbsolutePath /foo/bar/.. # returns /foo +function ViashAbsolutePath { + local thePath + local parr + local outp + local len + if [[ ! "$1" =~ ^/ ]]; then + thePath="$PWD/$1" + else + thePath="$1" + fi + echo "$thePath" | ( + IFS=/ + read -a parr + declare -a outp + for i in "${parr[@]}"; do + case "$i" in + ''|.) continue ;; + ..) + len=${#outp[@]} + if ((len==0)); then + continue + else + unset outp[$((len-1))] + fi + ;; + *) + len=${#outp[@]} + outp[$len]="$i" + ;; + esac + done + echo /"${outp[*]}" + ) +} +# ViashDockerAutodetectMount: auto configuring docker mounts from parameters +# $1 : The parameter value +# returns : New parameter +# $VIASH_DIRECTORY_MOUNTS : Added another parameter to be passed to docker +# $VIASH_DOCKER_AUTOMOUNT_PREFIX : The prefix to be used for the automounts +# examples: +# ViashDockerAutodetectMount /path/to/bar # returns '/viash_automount/path/to/bar' +# ViashDockerAutodetectMountArg /path/to/bar # returns '--volume="/path/to:/viash_automount/path/to"' +function ViashDockerAutodetectMount { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + if [ -z "$base_name" ]; then + echo "$mount_target" + else + echo "$mount_target/$base_name" + fi +} +function ViashDockerAutodetectMountArg { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + ViashDebug "ViashDockerAutodetectMountArg $1 -> $mount_source -> $mount_target" + echo "--volume=\"$mount_source:$mount_target\"" +} +function ViashDockerStripAutomount { + local abs_path=$(ViashAbsolutePath "$1") + echo "${abs_path#$VIASH_DOCKER_AUTOMOUNT_PREFIX}" +} +# initialise variables +VIASH_DIRECTORY_MOUNTS=() + +# configure default docker automount prefix if it is unset +if [ -z "${VIASH_DOCKER_AUTOMOUNT_PREFIX+x}" ]; then + VIASH_DOCKER_AUTOMOUNT_PREFIX="/viash_automount" +fi + +# initialise docker variables +VIASH_DOCKER_RUN_ARGS=(-i --rm) + +# initialise array +VIASH_POSITIONAL_ARGS='' + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + ViashHelp + exit + ;; + ---v|---verbose) + let "VIASH_VERBOSITY=VIASH_VERBOSITY+1" + shift 1 + ;; + ---verbosity) + VIASH_VERBOSITY="$2" + shift 2 + ;; + ---verbosity=*) + VIASH_VERBOSITY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + --version) + echo "bedtools_bamtobed main" + exit + ;; + --input) + [ -n "$VIASH_PAR_INPUT" ] && ViashError Bad arguments for option \'--input\': \'$VIASH_PAR_INPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --input. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --input=*) + [ -n "$VIASH_PAR_INPUT" ] && ViashError Bad arguments for option \'--input=*\': \'$VIASH_PAR_INPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT=$(ViashRemoveFlags "$1") + shift 1 + ;; + -i) + [ -n "$VIASH_PAR_INPUT" ] && ViashError Bad arguments for option \'-i\': \'$VIASH_PAR_INPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -i. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output=*) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output=*\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT=$(ViashRemoveFlags "$1") + shift 1 + ;; + -o) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'-o\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -o. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --bedpe) + [ -n "$VIASH_PAR_BEDPE" ] && ViashError Bad arguments for option \'--bedpe\': \'$VIASH_PAR_BEDPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_BEDPE=true + shift 1 + ;; + --mate1) + [ -n "$VIASH_PAR_MATE1" ] && ViashError Bad arguments for option \'--mate1\': \'$VIASH_PAR_MATE1\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MATE1=true + shift 1 + ;; + --bed12) + [ -n "$VIASH_PAR_BED12" ] && ViashError Bad arguments for option \'--bed12\': \'$VIASH_PAR_BED12\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_BED12=true + shift 1 + ;; + --split) + [ -n "$VIASH_PAR_SPLIT" ] && ViashError Bad arguments for option \'--split\': \'$VIASH_PAR_SPLIT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SPLIT=true + shift 1 + ;; + --splitD) + [ -n "$VIASH_PAR_SPLITD" ] && ViashError Bad arguments for option \'--splitD\': \'$VIASH_PAR_SPLITD\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SPLITD=true + shift 1 + ;; + --edit_distance) + [ -n "$VIASH_PAR_EDIT_DISTANCE" ] && ViashError Bad arguments for option \'--edit_distance\': \'$VIASH_PAR_EDIT_DISTANCE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EDIT_DISTANCE=true + shift 1 + ;; + -ed) + [ -n "$VIASH_PAR_EDIT_DISTANCE" ] && ViashError Bad arguments for option \'-ed\': \'$VIASH_PAR_EDIT_DISTANCE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EDIT_DISTANCE=true + shift 1 + ;; + --tag) + [ -n "$VIASH_PAR_TAG" ] && ViashError Bad arguments for option \'--tag\': \'$VIASH_PAR_TAG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TAG="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --tag. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --tag=*) + [ -n "$VIASH_PAR_TAG" ] && ViashError Bad arguments for option \'--tag=*\': \'$VIASH_PAR_TAG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TAG=$(ViashRemoveFlags "$1") + shift 1 + ;; + --color) + [ -n "$VIASH_PAR_COLOR" ] && ViashError Bad arguments for option \'--color\': \'$VIASH_PAR_COLOR\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLOR="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --color. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --color=*) + [ -n "$VIASH_PAR_COLOR" ] && ViashError Bad arguments for option \'--color=*\': \'$VIASH_PAR_COLOR\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLOR=$(ViashRemoveFlags "$1") + shift 1 + ;; + --cigar) + [ -n "$VIASH_PAR_CIGAR" ] && ViashError Bad arguments for option \'--cigar\': \'$VIASH_PAR_CIGAR\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CIGAR=true + shift 1 + ;; + ---engine) + VIASH_ENGINE_ID="$2" + shift 2 + ;; + ---engine=*) + VIASH_ENGINE_ID="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---setup) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$2" + shift 2 + ;; + ---setup=*) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---dockerfile) + VIASH_MODE='dockerfile' + shift 1 + ;; + ---docker_run_args) + VIASH_DOCKER_RUN_ARGS+=("$2") + shift 2 + ;; + ---docker_run_args=*) + VIASH_DOCKER_RUN_ARGS+=("$(ViashRemoveFlags "$1")") + shift 1 + ;; + ---docker_image_id) + VIASH_MODE='docker_image_id' + shift 1 + ;; + ---debug) + VIASH_MODE='debug' + shift 1 + ;; + ---cpus) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---cpus. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---cpus=*) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus=*\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS=$(ViashRemoveFlags "$1") + shift 1 + ;; + ---memory) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---memory. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---memory=*) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory=*\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY=$(ViashRemoveFlags "$1") + shift 1 + ;; + *) # positional arg or unknown option + # since the positional args will be eval'd, can we always quote, instead of using ViashQuote + VIASH_POSITIONAL_ARGS="$VIASH_POSITIONAL_ARGS '$1'" + [[ $1 == -* ]] && ViashWarning $1 looks like a parameter but is not a defined parameter and will instead be treated as a positional argument. Use "--help" to get more information on the parameters. + shift # past argument + ;; + esac +done + +# parse positional parameters +eval set -- $VIASH_POSITIONAL_ARGS + + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + VIASH_ENGINE_TYPE='native' +elif [ "$VIASH_ENGINE_ID" == "docker" ] ; then + VIASH_ENGINE_TYPE='docker' +else + ViashError "Engine '$VIASH_ENGINE_ID' is not recognized. Options are: docker, native." + exit 1 +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # check if docker is installed properly + ViashDockerInstallationCheck + + # determine docker image id + if [[ "$VIASH_ENGINE_ID" == 'docker' ]]; then + VIASH_DOCKER_IMAGE_ID='images.viash-hub.com/vsh/biobox/bedtools/bedtools_bamtobed:main' + fi + + # print dockerfile + if [ "$VIASH_MODE" == "dockerfile" ]; then + ViashDockerfile "$VIASH_ENGINE_ID" + exit 0 + + elif [ "$VIASH_MODE" == "docker_image_id" ]; then + echo "$VIASH_DOCKER_IMAGE_ID" + exit 0 + + # enter docker container + elif [[ "$VIASH_MODE" == "debug" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} -v '$(pwd)':/pwd --workdir /pwd -t $VIASH_DOCKER_IMAGE_ID" + ViashNotice "+ $VIASH_CMD" + eval $VIASH_CMD + exit + + # build docker image + elif [ "$VIASH_MODE" == "setup" ]; then + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" "$VIASH_SETUP_STRATEGY" + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' + exit 0 + fi + + # check if docker image exists + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" ifneedbepullelsecachedbuild + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' +fi + +# setting computational defaults + +# helper function for parsing memory strings +function ViashMemoryAsBytes { + local memory=`echo "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'` + local memory_regex='^([0-9]+)([kmgtp]i?b?|b)$' + if [[ $memory =~ $memory_regex ]]; then + local number=${memory/[^0-9]*/} + local symbol=${memory/*[0-9]/} + + case $symbol in + b) memory_b=$number ;; + kb|k) memory_b=$(( $number * 1000 )) ;; + mb|m) memory_b=$(( $number * 1000 * 1000 )) ;; + gb|g) memory_b=$(( $number * 1000 * 1000 * 1000 )) ;; + tb|t) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 )) ;; + pb|p) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 * 1000 )) ;; + kib|ki) memory_b=$(( $number * 1024 )) ;; + mib|mi) memory_b=$(( $number * 1024 * 1024 )) ;; + gib|gi) memory_b=$(( $number * 1024 * 1024 * 1024 )) ;; + tib|ti) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 )) ;; + pib|pi) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 * 1024 )) ;; + esac + echo "$memory_b" + fi +} +# compute memory in different units +if [ ! -z ${VIASH_META_MEMORY+x} ]; then + VIASH_META_MEMORY_B=`ViashMemoryAsBytes $VIASH_META_MEMORY` + # do not define other variables if memory_b is an empty string + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_META_MEMORY_KB=$(( ($VIASH_META_MEMORY_B+999) / 1000 )) + VIASH_META_MEMORY_MB=$(( ($VIASH_META_MEMORY_KB+999) / 1000 )) + VIASH_META_MEMORY_GB=$(( ($VIASH_META_MEMORY_MB+999) / 1000 )) + VIASH_META_MEMORY_TB=$(( ($VIASH_META_MEMORY_GB+999) / 1000 )) + VIASH_META_MEMORY_PB=$(( ($VIASH_META_MEMORY_TB+999) / 1000 )) + VIASH_META_MEMORY_KIB=$(( ($VIASH_META_MEMORY_B+1023) / 1024 )) + VIASH_META_MEMORY_MIB=$(( ($VIASH_META_MEMORY_KIB+1023) / 1024 )) + VIASH_META_MEMORY_GIB=$(( ($VIASH_META_MEMORY_MIB+1023) / 1024 )) + VIASH_META_MEMORY_TIB=$(( ($VIASH_META_MEMORY_GIB+1023) / 1024 )) + VIASH_META_MEMORY_PIB=$(( ($VIASH_META_MEMORY_TIB+1023) / 1024 )) + else + # unset memory if string is empty + unset $VIASH_META_MEMORY_B + fi +fi +# unset nproc if string is empty +if [ -z "$VIASH_META_CPUS" ]; then + unset $VIASH_META_CPUS +fi + + +# check whether required parameters exist +if [ -z ${VIASH_PAR_INPUT+x} ]; then + ViashError '--input' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_PAR_OUTPUT+x} ]; then + ViashError '--output' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_NAME+x} ]; then + ViashError 'name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_FUNCTIONALITY_NAME+x} ]; then + ViashError 'functionality_name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_RESOURCES_DIR+x} ]; then + ViashError 'resources_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_EXECUTABLE+x} ]; then + ViashError 'executable' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_CONFIG+x} ]; then + ViashError 'config' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_TEMP_DIR+x} ]; then + ViashError 'temp_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi + +# filling in defaults +if [ -z ${VIASH_PAR_BEDPE+x} ]; then + VIASH_PAR_BEDPE="false" +fi +if [ -z ${VIASH_PAR_MATE1+x} ]; then + VIASH_PAR_MATE1="false" +fi +if [ -z ${VIASH_PAR_BED12+x} ]; then + VIASH_PAR_BED12="false" +fi +if [ -z ${VIASH_PAR_SPLIT+x} ]; then + VIASH_PAR_SPLIT="false" +fi +if [ -z ${VIASH_PAR_SPLITD+x} ]; then + VIASH_PAR_SPLITD="false" +fi +if [ -z ${VIASH_PAR_EDIT_DISTANCE+x} ]; then + VIASH_PAR_EDIT_DISTANCE="false" +fi +if [ -z ${VIASH_PAR_CIGAR+x} ]; then + VIASH_PAR_CIGAR="false" +fi + +# check whether required files exist +if [ ! -z "$VIASH_PAR_INPUT" ] && [ ! -e "$VIASH_PAR_INPUT" ]; then + ViashError "Input file '$VIASH_PAR_INPUT' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_PAR_BEDPE" ]]; then + if ! [[ "$VIASH_PAR_BEDPE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--bedpe' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_MATE1" ]]; then + if ! [[ "$VIASH_PAR_MATE1" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--mate1' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_BED12" ]]; then + if ! [[ "$VIASH_PAR_BED12" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--bed12' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_SPLIT" ]]; then + if ! [[ "$VIASH_PAR_SPLIT" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--split' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_SPLITD" ]]; then + if ! [[ "$VIASH_PAR_SPLITD" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--splitD' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_EDIT_DISTANCE" ]]; then + if ! [[ "$VIASH_PAR_EDIT_DISTANCE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--edit_distance' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_CIGAR" ]]; then + if ! [[ "$VIASH_PAR_CIGAR" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--cigar' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_CPUS" ]]; then + if ! [[ "$VIASH_META_CPUS" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'cpus' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_B" ]]; then + if ! [[ "$VIASH_META_MEMORY_B" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_b' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi + +# create parent directories of output files, if so desired +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT")" +fi + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + if [ "$VIASH_MODE" == "run" ]; then + VIASH_CMD="bash" + else + ViashError "Engine '$VIASH_ENGINE_ID' does not support mode '$VIASH_MODE'." + exit 1 + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # detect volumes from file arguments + VIASH_CHOWN_VARS=() +if [ ! -z "$VIASH_PAR_INPUT" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_INPUT")" ) + VIASH_PAR_INPUT=$(ViashDockerAutodetectMount "$VIASH_PAR_INPUT") +fi +if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT")" ) + VIASH_PAR_OUTPUT=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT" ) +fi +if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_RESOURCES_DIR")" ) + VIASH_META_RESOURCES_DIR=$(ViashDockerAutodetectMount "$VIASH_META_RESOURCES_DIR") +fi +if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_EXECUTABLE")" ) + VIASH_META_EXECUTABLE=$(ViashDockerAutodetectMount "$VIASH_META_EXECUTABLE") +fi +if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_CONFIG")" ) + VIASH_META_CONFIG=$(ViashDockerAutodetectMount "$VIASH_META_CONFIG") +fi +if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_TEMP_DIR")" ) + VIASH_META_TEMP_DIR=$(ViashDockerAutodetectMount "$VIASH_META_TEMP_DIR") +fi + + # get unique mounts + VIASH_UNIQUE_MOUNTS=($(for val in "${VIASH_DIRECTORY_MOUNTS[@]}"; do echo "$val"; done | sort -u)) +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # change file ownership + function ViashPerformChown { + if (( ${#VIASH_CHOWN_VARS[@]} )); then + set +e + VIASH_CMD="docker run --entrypoint=bash --rm ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID -c 'chown $(id -u):$(id -g) --silent --recursive ${VIASH_CHOWN_VARS[@]}'" + ViashDebug "+ $VIASH_CMD" + eval $VIASH_CMD + set -e + fi + } + trap ViashPerformChown EXIT +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # helper function for filling in extra docker args + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_DOCKER_RUN_ARGS+=("--memory=${VIASH_META_MEMORY_B}") + fi + if [ ! -z "$VIASH_META_CPUS" ]; then + VIASH_DOCKER_RUN_ARGS+=("--cpus=${VIASH_META_CPUS}") + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID" +fi + + +# set dependency paths + + +ViashDebug "Running command: $(echo $VIASH_CMD)" +cat << VIASHEOF | eval $VIASH_CMD +set -e +tempscript=\$(mktemp "$VIASH_META_TEMP_DIR/viash-run-bedtools_bamtobed-XXXXXX").sh +function clean_up { + rm "\$tempscript" +} +function interrupt { + echo -e "\nCTRL-C Pressed..." + exit 1 +} +trap clean_up EXIT +trap interrupt INT SIGINT +cat > "\$tempscript" << 'VIASHMAIN' +#!/bin/bash + +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_INPUT+x} ]; then echo "${VIASH_PAR_INPUT}" | sed "s#'#'\"'\"'#g;s#.*#par_input='&'#" ; else echo "# par_input="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\"'\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; fi ) +$( if [ ! -z ${VIASH_PAR_BEDPE+x} ]; then echo "${VIASH_PAR_BEDPE}" | sed "s#'#'\"'\"'#g;s#.*#par_bedpe='&'#" ; else echo "# par_bedpe="; fi ) +$( if [ ! -z ${VIASH_PAR_MATE1+x} ]; then echo "${VIASH_PAR_MATE1}" | sed "s#'#'\"'\"'#g;s#.*#par_mate1='&'#" ; else echo "# par_mate1="; fi ) +$( if [ ! -z ${VIASH_PAR_BED12+x} ]; then echo "${VIASH_PAR_BED12}" | sed "s#'#'\"'\"'#g;s#.*#par_bed12='&'#" ; else echo "# par_bed12="; fi ) +$( if [ ! -z ${VIASH_PAR_SPLIT+x} ]; then echo "${VIASH_PAR_SPLIT}" | sed "s#'#'\"'\"'#g;s#.*#par_split='&'#" ; else echo "# par_split="; fi ) +$( if [ ! -z ${VIASH_PAR_SPLITD+x} ]; then echo "${VIASH_PAR_SPLITD}" | sed "s#'#'\"'\"'#g;s#.*#par_splitD='&'#" ; else echo "# par_splitD="; fi ) +$( if [ ! -z ${VIASH_PAR_EDIT_DISTANCE+x} ]; then echo "${VIASH_PAR_EDIT_DISTANCE}" | sed "s#'#'\"'\"'#g;s#.*#par_edit_distance='&'#" ; else echo "# par_edit_distance="; fi ) +$( if [ ! -z ${VIASH_PAR_TAG+x} ]; then echo "${VIASH_PAR_TAG}" | sed "s#'#'\"'\"'#g;s#.*#par_tag='&'#" ; else echo "# par_tag="; fi ) +$( if [ ! -z ${VIASH_PAR_COLOR+x} ]; then echo "${VIASH_PAR_COLOR}" | sed "s#'#'\"'\"'#g;s#.*#par_color='&'#" ; else echo "# par_color="; fi ) +$( if [ ! -z ${VIASH_PAR_CIGAR+x} ]; then echo "${VIASH_PAR_CIGAR}" | sed "s#'#'\"'\"'#g;s#.*#par_cigar='&'#" ; else echo "# par_cigar="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\"'\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\"'\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\"'\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\"'\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END + +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_bedpe + par_mate1 + par_bed12 + par_split + par_splitD + par_edit_distance + par_tag + par_color + par_cigar +) + +for par in \${unset_if_false[@]}; do + test_val="\${!par}" + [[ "\$test_val" == "false" ]] && unset \$par +done + +# Execute bedtools sort with the provided arguments +bedtools bamtobed \\ + \${par_bedpe:+-bedpe} \\ + \${par_mate1:+-mate1} \\ + \${par_bed12:+-bed12} \\ + \${par_split:+-split} \\ + \${par_splitD:+-splitD} \\ + \${par_edit_distance:+-ed} \\ + \${par_tag:+-tag "\$par_tag"} \\ + \${par_cigar:+-cigar} \\ + \${par_color:+-color "\$par_color"} \\ + -i "\$par_input" \\ + > "\$par_output" +VIASHMAIN +bash "\$tempscript" & +wait "\$!" + +VIASHEOF + + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # strip viash automount from file paths + + if [ ! -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT=$(ViashDockerStripAutomount "$VIASH_PAR_INPUT") + fi + if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_PAR_OUTPUT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT") + fi + if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_META_RESOURCES_DIR=$(ViashDockerStripAutomount "$VIASH_META_RESOURCES_DIR") + fi + if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_META_EXECUTABLE=$(ViashDockerStripAutomount "$VIASH_META_EXECUTABLE") + fi + if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_META_CONFIG=$(ViashDockerStripAutomount "$VIASH_META_CONFIG") + fi + if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_META_TEMP_DIR=$(ViashDockerStripAutomount "$VIASH_META_TEMP_DIR") + fi +fi + + +# check whether required files exist +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -e "$VIASH_PAR_OUTPUT" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT' does not exist." + exit 1 +fi + + +exit 0 diff --git a/target/executable/bedtools/bedtools_bamtofastq/.config.vsh.yaml b/target/executable/bedtools/bedtools_bamtofastq/.config.vsh.yaml index 69a0daa4..0acf32cf 100644 --- a/target/executable/bedtools/bedtools_bamtofastq/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_bamtofastq/.config.vsh.yaml @@ -187,9 +187,9 @@ build_info: output: "target/executable/bedtools/bedtools_bamtofastq" executable: "target/executable/bedtools/bedtools_bamtofastq/bedtools_bamtofastq" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_bamtofastq/bedtools_bamtofastq b/target/executable/bedtools/bedtools_bamtofastq/bedtools_bamtofastq index 0b372aee..b8e89008 100755 --- a/target/executable/bedtools/bedtools_bamtofastq/bedtools_bamtofastq +++ b/target/executable/bedtools/bedtools_bamtofastq/bedtools_bamtofastq @@ -483,9 +483,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_bamtofastq" -LABEL org.opencontainers.image.created="2024-10-26T13:11:20Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:07Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_bed12tobed6/.config.vsh.yaml b/target/executable/bedtools/bedtools_bed12tobed6/.config.vsh.yaml index 19e18392..c4457466 100644 --- a/target/executable/bedtools/bedtools_bed12tobed6/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_bed12tobed6/.config.vsh.yaml @@ -176,9 +176,9 @@ build_info: output: "target/executable/bedtools/bedtools_bed12tobed6" executable: "target/executable/bedtools/bedtools_bed12tobed6/bedtools_bed12tobed6" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_bed12tobed6/bedtools_bed12tobed6 b/target/executable/bedtools/bedtools_bed12tobed6/bedtools_bed12tobed6 index 89c98e2d..3f0c611a 100755 --- a/target/executable/bedtools/bedtools_bed12tobed6/bedtools_bed12tobed6 +++ b/target/executable/bedtools/bedtools_bed12tobed6/bedtools_bed12tobed6 @@ -480,9 +480,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_bed12tobed6" -LABEL org.opencontainers.image.created="2024-10-26T13:11:21Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:09Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_bedtobam/.config.vsh.yaml b/target/executable/bedtools/bedtools_bedtobam/.config.vsh.yaml index b4f824a4..6d533216 100644 --- a/target/executable/bedtools/bedtools_bedtobam/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_bedtobam/.config.vsh.yaml @@ -214,9 +214,9 @@ build_info: output: "target/executable/bedtools/bedtools_bedtobam" executable: "target/executable/bedtools/bedtools_bedtobam/bedtools_bedtobam" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_bedtobam/bedtools_bedtobam b/target/executable/bedtools/bedtools_bedtobam/bedtools_bedtobam index cad7c621..a2f4a727 100755 --- a/target/executable/bedtools/bedtools_bedtobam/bedtools_bedtobam +++ b/target/executable/bedtools/bedtools_bedtobam/bedtools_bedtobam @@ -496,9 +496,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_bedtobam" -LABEL org.opencontainers.image.created="2024-10-26T13:11:22Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:10Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_genomecov/.config.vsh.yaml b/target/executable/bedtools/bedtools_genomecov/.config.vsh.yaml index 0fa1fd43..d841906d 100644 --- a/target/executable/bedtools/bedtools_genomecov/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_genomecov/.config.vsh.yaml @@ -337,9 +337,9 @@ build_info: output: "target/executable/bedtools/bedtools_genomecov" executable: "target/executable/bedtools/bedtools_genomecov/bedtools_genomecov" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_genomecov/bedtools_genomecov b/target/executable/bedtools/bedtools_genomecov/bedtools_genomecov index 397c9a3e..79221112 100755 --- a/target/executable/bedtools/bedtools_genomecov/bedtools_genomecov +++ b/target/executable/bedtools/bedtools_genomecov/bedtools_genomecov @@ -591,9 +591,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_genomecov" -LABEL org.opencontainers.image.created="2024-10-26T13:11:20Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:08Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_getfasta/.config.vsh.yaml b/target/executable/bedtools/bedtools_getfasta/.config.vsh.yaml index 0ec92d14..8fbf68b1 100644 --- a/target/executable/bedtools/bedtools_getfasta/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_getfasta/.config.vsh.yaml @@ -232,9 +232,9 @@ build_info: output: "target/executable/bedtools/bedtools_getfasta" executable: "target/executable/bedtools/bedtools_getfasta/bedtools_getfasta" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_getfasta/bedtools_getfasta b/target/executable/bedtools/bedtools_getfasta/bedtools_getfasta index ce3a254a..da484e58 100755 --- a/target/executable/bedtools/bedtools_getfasta/bedtools_getfasta +++ b/target/executable/bedtools/bedtools_getfasta/bedtools_getfasta @@ -526,9 +526,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Dries Schaumont" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_getfasta" -LABEL org.opencontainers.image.created="2024-10-26T13:11:22Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:10Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_groupby/.config.vsh.yaml b/target/executable/bedtools/bedtools_groupby/.config.vsh.yaml index 32f4fafd..fc195ac1 100644 --- a/target/executable/bedtools/bedtools_groupby/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_groupby/.config.vsh.yaml @@ -273,9 +273,9 @@ build_info: output: "target/executable/bedtools/bedtools_groupby" executable: "target/executable/bedtools/bedtools_groupby/bedtools_groupby" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_groupby/bedtools_groupby b/target/executable/bedtools/bedtools_groupby/bedtools_groupby index dc5c2c25..1f7a0a68 100755 --- a/target/executable/bedtools/bedtools_groupby/bedtools_groupby +++ b/target/executable/bedtools/bedtools_groupby/bedtools_groupby @@ -552,9 +552,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_groupby" -LABEL org.opencontainers.image.created="2024-10-26T13:11:21Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:09Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_intersect/.config.vsh.yaml b/target/executable/bedtools/bedtools_intersect/.config.vsh.yaml index 3ed95f00..df9afc62 100644 --- a/target/executable/bedtools/bedtools_intersect/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_intersect/.config.vsh.yaml @@ -410,9 +410,9 @@ build_info: output: "target/executable/bedtools/bedtools_intersect" executable: "target/executable/bedtools/bedtools_intersect/bedtools_intersect" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_intersect/bedtools_intersect b/target/executable/bedtools/bedtools_intersect/bedtools_intersect index 22cd99db..c399dec1 100755 --- a/target/executable/bedtools/bedtools_intersect/bedtools_intersect +++ b/target/executable/bedtools/bedtools_intersect/bedtools_intersect @@ -633,9 +633,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_intersect" -LABEL org.opencontainers.image.created="2024-10-26T13:11:19Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:07Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_links/.config.vsh.yaml b/target/executable/bedtools/bedtools_links/.config.vsh.yaml index 29640690..9b28fd8a 100644 --- a/target/executable/bedtools/bedtools_links/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_links/.config.vsh.yaml @@ -210,9 +210,9 @@ build_info: output: "target/executable/bedtools/bedtools_links" executable: "target/executable/bedtools/bedtools_links/bedtools_links" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_links/bedtools_links b/target/executable/bedtools/bedtools_links/bedtools_links index 0b7c6cfb..cb3cc188 100755 --- a/target/executable/bedtools/bedtools_links/bedtools_links +++ b/target/executable/bedtools/bedtools_links/bedtools_links @@ -500,9 +500,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_links" -LABEL org.opencontainers.image.created="2024-10-26T13:11:20Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:08Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_merge/.config.vsh.yaml b/target/executable/bedtools/bedtools_merge/.config.vsh.yaml index 3e9d409c..fc36f972 100644 --- a/target/executable/bedtools/bedtools_merge/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_merge/.config.vsh.yaml @@ -279,9 +279,9 @@ build_info: output: "target/executable/bedtools/bedtools_merge" executable: "target/executable/bedtools/bedtools_merge/bedtools_merge" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_merge/bedtools_merge b/target/executable/bedtools/bedtools_merge/bedtools_merge index 5a66fd02..069f45df 100755 --- a/target/executable/bedtools/bedtools_merge/bedtools_merge +++ b/target/executable/bedtools/bedtools_merge/bedtools_merge @@ -558,9 +558,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_merge" -LABEL org.opencontainers.image.created="2024-10-26T13:11:21Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:09Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_sort/.config.vsh.yaml b/target/executable/bedtools/bedtools_sort/.config.vsh.yaml index 18e53863..dc23e354 100644 --- a/target/executable/bedtools/bedtools_sort/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_sort/.config.vsh.yaml @@ -222,9 +222,9 @@ build_info: output: "target/executable/bedtools/bedtools_sort" executable: "target/executable/bedtools/bedtools_sort/bedtools_sort" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/bedtools/bedtools_sort/bedtools_sort b/target/executable/bedtools/bedtools_sort/bedtools_sort index 12bcfbee..6f25ffc7 100755 --- a/target/executable/bedtools/bedtools_sort/bedtools_sort +++ b/target/executable/bedtools/bedtools_sort/bedtools_sort @@ -509,9 +509,9 @@ RUN echo "bedtools: \"$(bedtools --version | sed -n 's/^bedtools //p')\"" > /var LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component bedtools bedtools_sort" -LABEL org.opencontainers.image.created="2024-10-26T13:11:19Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:07Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/busco/busco_download_datasets/.config.vsh.yaml b/target/executable/busco/busco_download_datasets/.config.vsh.yaml index 51570e50..bc7976b2 100644 --- a/target/executable/busco/busco_download_datasets/.config.vsh.yaml +++ b/target/executable/busco/busco_download_datasets/.config.vsh.yaml @@ -158,9 +158,9 @@ build_info: output: "target/executable/busco/busco_download_datasets" executable: "target/executable/busco/busco_download_datasets/busco_download_datasets" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/busco/busco_download_datasets/busco_download_datasets b/target/executable/busco/busco_download_datasets/busco_download_datasets index 5a6c03a2..a33a4232 100755 --- a/target/executable/busco/busco_download_datasets/busco_download_datasets +++ b/target/executable/busco/busco_download_datasets/busco_download_datasets @@ -475,9 +475,9 @@ RUN busco --version | sed 's/BUSCO\s\(.*\)/busco: "\1"/' > /var/software_version LABEL org.opencontainers.image.authors="Dorien Roosen" LABEL org.opencontainers.image.description="Companion container for running component busco busco_download_datasets" -LABEL org.opencontainers.image.created="2024-10-26T13:11:18Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:06Z" LABEL org.opencontainers.image.source="https://gitlab.com/ezlab/busco" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/busco/busco_list_datasets/.config.vsh.yaml b/target/executable/busco/busco_list_datasets/.config.vsh.yaml index 67ad64c8..efa8a7e9 100644 --- a/target/executable/busco/busco_list_datasets/.config.vsh.yaml +++ b/target/executable/busco/busco_list_datasets/.config.vsh.yaml @@ -145,9 +145,9 @@ build_info: output: "target/executable/busco/busco_list_datasets" executable: "target/executable/busco/busco_list_datasets/busco_list_datasets" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/busco/busco_list_datasets/busco_list_datasets b/target/executable/busco/busco_list_datasets/busco_list_datasets index a0e95e17..5f7fe70d 100755 --- a/target/executable/busco/busco_list_datasets/busco_list_datasets +++ b/target/executable/busco/busco_list_datasets/busco_list_datasets @@ -465,9 +465,9 @@ RUN busco --version | sed 's/BUSCO\s\(.*\)/busco: "\1"/' > /var/software_version LABEL org.opencontainers.image.authors="Dorien Roosen" LABEL org.opencontainers.image.description="Companion container for running component busco busco_list_datasets" -LABEL org.opencontainers.image.created="2024-10-26T13:11:18Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:06Z" LABEL org.opencontainers.image.source="https://gitlab.com/ezlab/busco" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/busco/busco_run/.config.vsh.yaml b/target/executable/busco/busco_run/.config.vsh.yaml index 6dc36832..241e6c2b 100644 --- a/target/executable/busco/busco_run/.config.vsh.yaml +++ b/target/executable/busco/busco_run/.config.vsh.yaml @@ -423,9 +423,9 @@ build_info: output: "target/executable/busco/busco_run" executable: "target/executable/busco/busco_run/busco_run" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/busco/busco_run/busco_run b/target/executable/busco/busco_run/busco_run index bd0d4082..33a95e82 100755 --- a/target/executable/busco/busco_run/busco_run +++ b/target/executable/busco/busco_run/busco_run @@ -632,9 +632,9 @@ RUN busco --version | sed 's/BUSCO\s\(.*\)/busco: "\1"/' > /var/software_version LABEL org.opencontainers.image.authors="Dorien Roosen" LABEL org.opencontainers.image.description="Companion container for running component busco busco_run" -LABEL org.opencontainers.image.created="2024-10-26T13:11:18Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:06Z" LABEL org.opencontainers.image.source="https://gitlab.com/ezlab/busco" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/cutadapt/.config.vsh.yaml b/target/executable/cutadapt/.config.vsh.yaml index 38ebf207..ffb10c02 100644 --- a/target/executable/cutadapt/.config.vsh.yaml +++ b/target/executable/cutadapt/.config.vsh.yaml @@ -740,9 +740,9 @@ build_info: output: "target/executable/cutadapt" executable: "target/executable/cutadapt/cutadapt" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/cutadapt/cutadapt b/target/executable/cutadapt/cutadapt index 835cd6c4..d9462971 100755 --- a/target/executable/cutadapt/cutadapt +++ b/target/executable/cutadapt/cutadapt @@ -831,9 +831,9 @@ RUN cutadapt --version | sed 's/\(.*\)/cutadapt: "\1"/' > /var/software_versions LABEL org.opencontainers.image.authors="Toni Verbeiren" LABEL org.opencontainers.image.description="Companion container for running component cutadapt" -LABEL org.opencontainers.image.created="2024-10-26T13:11:09Z" +LABEL org.opencontainers.image.created="2024-10-26T18:43:58Z" LABEL org.opencontainers.image.source="https://github.com/marcelm/cutadapt" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/falco/.config.vsh.yaml b/target/executable/falco/.config.vsh.yaml index 494b0e4c..2cd5897c 100644 --- a/target/executable/falco/.config.vsh.yaml +++ b/target/executable/falco/.config.vsh.yaml @@ -317,9 +317,9 @@ build_info: output: "target/executable/falco" executable: "target/executable/falco/falco" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/falco/falco b/target/executable/falco/falco index 7d377050..c12bd439 100755 --- a/target/executable/falco/falco +++ b/target/executable/falco/falco @@ -589,9 +589,9 @@ RUN echo "falco: \"$(falco -v | sed -n 's/^falco //p')\"" > /var/software_versio LABEL org.opencontainers.image.authors="Toni Verbeiren" LABEL org.opencontainers.image.description="Companion container for running component falco" -LABEL org.opencontainers.image.created="2024-10-26T13:11:11Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:00Z" LABEL org.opencontainers.image.source="https://github.com/smithlabcode/falco" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/fastp/.config.vsh.yaml b/target/executable/fastp/.config.vsh.yaml index dfb037a6..67a2ddfc 100644 --- a/target/executable/fastp/.config.vsh.yaml +++ b/target/executable/fastp/.config.vsh.yaml @@ -1083,9 +1083,9 @@ build_info: output: "target/executable/fastp" executable: "target/executable/fastp/fastp" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/fastp/fastp b/target/executable/fastp/fastp index 28df9eca..08fc63a3 100755 --- a/target/executable/fastp/fastp +++ b/target/executable/fastp/fastp @@ -1028,9 +1028,9 @@ RUN fastp --version 2>&1 | sed 's# #: "#;s#$#"#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Robrecht Cannoodt" LABEL org.opencontainers.image.description="Companion container for running component fastp" -LABEL org.opencontainers.image.created="2024-10-26T13:11:15Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:03Z" LABEL org.opencontainers.image.source="https://github.com/OpenGene/fastp" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/fastqc/.config.vsh.yaml b/target/executable/fastqc/.config.vsh.yaml index 6cc331bd..76a69d20 100644 --- a/target/executable/fastqc/.config.vsh.yaml +++ b/target/executable/fastqc/.config.vsh.yaml @@ -340,9 +340,9 @@ build_info: output: "target/executable/fastqc" executable: "target/executable/fastqc/fastqc" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/fastqc/fastqc b/target/executable/fastqc/fastqc index f647813a..6922494f 100755 --- a/target/executable/fastqc/fastqc +++ b/target/executable/fastqc/fastqc @@ -601,9 +601,9 @@ RUN echo "fastqc: $(fastqc --version | sed -n 's/^FastQC //p')" > /var/software_ LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component fastqc" -LABEL org.opencontainers.image.created="2024-10-26T13:11:16Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:04Z" LABEL org.opencontainers.image.source="https://github.com/s-andrews/FastQC" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/featurecounts/.config.vsh.yaml b/target/executable/featurecounts/.config.vsh.yaml index 6b60deb6..59e70f22 100644 --- a/target/executable/featurecounts/.config.vsh.yaml +++ b/target/executable/featurecounts/.config.vsh.yaml @@ -645,9 +645,9 @@ build_info: output: "target/executable/featurecounts" executable: "target/executable/featurecounts/featurecounts" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/featurecounts/featurecounts b/target/executable/featurecounts/featurecounts index 2fcdf889..952763b5 100755 --- a/target/executable/featurecounts/featurecounts +++ b/target/executable/featurecounts/featurecounts @@ -754,9 +754,9 @@ RUN featureCounts -v 2>&1 | sed 's/featureCounts v\([0-9.]*\)/featureCounts: \1/ LABEL org.opencontainers.image.authors="Sai Nirmayi Yasa" LABEL org.opencontainers.image.description="Companion container for running component featurecounts" -LABEL org.opencontainers.image.created="2024-10-26T13:11:12Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:00Z" LABEL org.opencontainers.image.source="https://github.com/ShiLab-Bioinformatics/subread" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/fq_subsample/.config.vsh.yaml b/target/executable/fq_subsample/.config.vsh.yaml index 8ee93f02..d4eb2bfe 100644 --- a/target/executable/fq_subsample/.config.vsh.yaml +++ b/target/executable/fq_subsample/.config.vsh.yaml @@ -190,9 +190,9 @@ build_info: output: "target/executable/fq_subsample" executable: "target/executable/fq_subsample/fq_subsample" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/fq_subsample/fq_subsample b/target/executable/fq_subsample/fq_subsample index 5123ea27..e88955eb 100755 --- a/target/executable/fq_subsample/fq_subsample +++ b/target/executable/fq_subsample/fq_subsample @@ -493,9 +493,9 @@ mv target/release/fq /usr/local/bin/ && \ cd / && rm -rf /fq LABEL org.opencontainers.image.description="Companion container for running component fq_subsample" -LABEL org.opencontainers.image.created="2024-10-26T13:11:12Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:00Z" LABEL org.opencontainers.image.source="https://github.com/stjude-rust-labs/fq" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/gffread/.config.vsh.yaml b/target/executable/gffread/.config.vsh.yaml index ef6a6b98..95b23697 100644 --- a/target/executable/gffread/.config.vsh.yaml +++ b/target/executable/gffread/.config.vsh.yaml @@ -685,9 +685,9 @@ build_info: output: "target/executable/gffread" executable: "target/executable/gffread/gffread" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/gffread/gffread b/target/executable/gffread/gffread index 305d5ea4..d6ebb00d 100755 --- a/target/executable/gffread/gffread +++ b/target/executable/gffread/gffread @@ -807,9 +807,9 @@ RUN echo "gffread: \"$(gffread --version 2>&1)\"" > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component gffread" -LABEL org.opencontainers.image.created="2024-10-26T13:11:16Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:04Z" LABEL org.opencontainers.image.source="https://github.com/gpertea/gffread" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/kallisto/kallisto_index/.config.vsh.yaml b/target/executable/kallisto/kallisto_index/.config.vsh.yaml index 70155d2b..60157212 100644 --- a/target/executable/kallisto/kallisto_index/.config.vsh.yaml +++ b/target/executable/kallisto/kallisto_index/.config.vsh.yaml @@ -218,9 +218,9 @@ build_info: output: "target/executable/kallisto/kallisto_index" executable: "target/executable/kallisto/kallisto_index/kallisto_index" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/kallisto/kallisto_index/kallisto_index b/target/executable/kallisto/kallisto_index/kallisto_index index 92586614..b01f9560 100755 --- a/target/executable/kallisto/kallisto_index/kallisto_index +++ b/target/executable/kallisto/kallisto_index/kallisto_index @@ -506,9 +506,9 @@ tar -xzf kallisto_linux-v0.50.1.tar.gz && \ mv kallisto/kallisto /usr/local/bin/ LABEL org.opencontainers.image.description="Companion container for running component kallisto kallisto_index" -LABEL org.opencontainers.image.created="2024-10-26T13:11:22Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:10Z" LABEL org.opencontainers.image.source="https://github.com/pachterlab/kallisto" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/kallisto/kallisto_quant/.config.vsh.yaml b/target/executable/kallisto/kallisto_quant/.config.vsh.yaml index 51855177..73593726 100644 --- a/target/executable/kallisto/kallisto_quant/.config.vsh.yaml +++ b/target/executable/kallisto/kallisto_quant/.config.vsh.yaml @@ -234,9 +234,9 @@ build_info: output: "target/executable/kallisto/kallisto_quant" executable: "target/executable/kallisto/kallisto_quant/kallisto_quant" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/kallisto/kallisto_quant/kallisto_quant b/target/executable/kallisto/kallisto_quant/kallisto_quant index 5112ec5e..f0f06367 100755 --- a/target/executable/kallisto/kallisto_quant/kallisto_quant +++ b/target/executable/kallisto/kallisto_quant/kallisto_quant @@ -518,9 +518,9 @@ mv kallisto/kallisto /usr/local/bin/ RUN echo "kallisto: $(kallisto version | sed 's/kallisto, version //')" > /var/software_versions.txt LABEL org.opencontainers.image.description="Companion container for running component kallisto kallisto_quant" -LABEL org.opencontainers.image.created="2024-10-26T13:11:22Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:11Z" LABEL org.opencontainers.image.source="https://github.com/pachterlab/kallisto" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/lofreq/lofreq_call/.config.vsh.yaml b/target/executable/lofreq/lofreq_call/.config.vsh.yaml index 9bb79963..42f277fa 100644 --- a/target/executable/lofreq/lofreq_call/.config.vsh.yaml +++ b/target/executable/lofreq/lofreq_call/.config.vsh.yaml @@ -507,9 +507,9 @@ build_info: output: "target/executable/lofreq/lofreq_call" executable: "target/executable/lofreq/lofreq_call/lofreq_call" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/lofreq/lofreq_call/lofreq_call b/target/executable/lofreq/lofreq_call/lofreq_call index 5a411a76..9f97fbab 100755 --- a/target/executable/lofreq/lofreq_call/lofreq_call +++ b/target/executable/lofreq/lofreq_call/lofreq_call @@ -656,9 +656,9 @@ echo "lofreq: $version" > /var/software_versions.txt LABEL org.opencontainers.image.authors="Kai Waldrant" LABEL org.opencontainers.image.description="Companion container for running component lofreq lofreq_call" -LABEL org.opencontainers.image.created="2024-10-26T13:11:23Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:11Z" LABEL org.opencontainers.image.source="https://github.com/viash-hub/biobox" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/lofreq/lofreq_indelqual/.config.vsh.yaml b/target/executable/lofreq/lofreq_indelqual/.config.vsh.yaml index efef3cd7..f7a06d09 100644 --- a/target/executable/lofreq/lofreq_indelqual/.config.vsh.yaml +++ b/target/executable/lofreq/lofreq_indelqual/.config.vsh.yaml @@ -215,9 +215,9 @@ build_info: output: "target/executable/lofreq/lofreq_indelqual" executable: "target/executable/lofreq/lofreq_indelqual/lofreq_indelqual" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/lofreq/lofreq_indelqual/lofreq_indelqual b/target/executable/lofreq/lofreq_indelqual/lofreq_indelqual index ed1d85e5..990b7153 100755 --- a/target/executable/lofreq/lofreq_indelqual/lofreq_indelqual +++ b/target/executable/lofreq/lofreq_indelqual/lofreq_indelqual @@ -501,9 +501,9 @@ echo "lofreq: $version" > /var/software_versions.txt LABEL org.opencontainers.image.authors="Kai Waldrant" LABEL org.opencontainers.image.description="Companion container for running component lofreq lofreq_indelqual" -LABEL org.opencontainers.image.created="2024-10-26T13:11:23Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:12Z" LABEL org.opencontainers.image.source="https://github.com/viash-hub/biobox" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/multiqc/.config.vsh.yaml b/target/executable/multiqc/.config.vsh.yaml index 5bb5de07..42ddb186 100644 --- a/target/executable/multiqc/.config.vsh.yaml +++ b/target/executable/multiqc/.config.vsh.yaml @@ -456,9 +456,9 @@ build_info: output: "target/executable/multiqc" executable: "target/executable/multiqc/multiqc" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/multiqc/multiqc b/target/executable/multiqc/multiqc index 168effb8..55deff3b 100755 --- a/target/executable/multiqc/multiqc +++ b/target/executable/multiqc/multiqc @@ -637,9 +637,9 @@ RUN multiqc --version | sed 's/multiqc, version\s\(.*\)/multiqc: "\1"/' > /var/s LABEL org.opencontainers.image.authors="Dorien Roosen" LABEL org.opencontainers.image.description="Companion container for running component multiqc" -LABEL org.opencontainers.image.created="2024-10-26T13:11:18Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:05Z" LABEL org.opencontainers.image.source="https://github.com/viash-hub/biobox" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/nanoplot/.config.vsh.yaml b/target/executable/nanoplot/.config.vsh.yaml index 155935e4..99130c27 100644 --- a/target/executable/nanoplot/.config.vsh.yaml +++ b/target/executable/nanoplot/.config.vsh.yaml @@ -492,9 +492,9 @@ build_info: output: "target/executable/nanoplot" executable: "target/executable/nanoplot/nanoplot" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/nanoplot/nanoplot b/target/executable/nanoplot/nanoplot index ed0f4c3e..3477c545 100755 --- a/target/executable/nanoplot/nanoplot +++ b/target/executable/nanoplot/nanoplot @@ -661,9 +661,9 @@ RUN version=$(NanoPlot --version) && \ echo "$version" > /var/software_versions.txt LABEL org.opencontainers.image.description="Companion container for running component nanoplot" -LABEL org.opencontainers.image.created="2024-10-26T13:11:18Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:05Z" LABEL org.opencontainers.image.source="https://github.com/wdecoster/NanoPlot" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/pear/.config.vsh.yaml b/target/executable/pear/.config.vsh.yaml index cf0008d5..82e6e3e3 100644 --- a/target/executable/pear/.config.vsh.yaml +++ b/target/executable/pear/.config.vsh.yaml @@ -398,9 +398,9 @@ build_info: output: "target/executable/pear" executable: "target/executable/pear/pear" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/pear/pear b/target/executable/pear/pear index b0728d72..c2891765 100755 --- a/target/executable/pear/pear +++ b/target/executable/pear/pear @@ -597,9 +597,9 @@ echo "pear: $version" > /var/software_versions.txt LABEL org.opencontainers.image.authors="Kai Waldrant" LABEL org.opencontainers.image.description="Companion container for running component pear" -LABEL org.opencontainers.image.created="2024-10-26T13:11:08Z" +LABEL org.opencontainers.image.created="2024-10-26T18:43:57Z" LABEL org.opencontainers.image.source="https://github.com/tseemann/PEAR" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/qualimap/qualimap_rnaseq/.config.vsh.yaml b/target/executable/qualimap/qualimap_rnaseq/.config.vsh.yaml index 6fde6c8a..dfafc8c2 100644 --- a/target/executable/qualimap/qualimap_rnaseq/.config.vsh.yaml +++ b/target/executable/qualimap/qualimap_rnaseq/.config.vsh.yaml @@ -264,9 +264,9 @@ build_info: output: "target/executable/qualimap/qualimap_rnaseq" executable: "target/executable/qualimap/qualimap_rnaseq/qualimap_rnaseq" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/qualimap/qualimap_rnaseq/qualimap_rnaseq b/target/executable/qualimap/qualimap_rnaseq/qualimap_rnaseq index a6dba41b..e276cdf7 100755 --- a/target/executable/qualimap/qualimap_rnaseq/qualimap_rnaseq +++ b/target/executable/qualimap/qualimap_rnaseq/qualimap_rnaseq @@ -527,9 +527,9 @@ RUN echo QualiMap: $(qualimap 2>&1 | grep QualiMap | sed 's/^.*QualiMap//') > /v LABEL org.opencontainers.image.authors="Dorien Roosen" LABEL org.opencontainers.image.description="Companion container for running component qualimap qualimap_rnaseq" -LABEL org.opencontainers.image.created="2024-10-26T13:11:13Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:00Z" LABEL org.opencontainers.image.source="https://bitbucket.org/kokonech/qualimap/commits/branch/master" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/rsem/rsem_calculate_expression/.config.vsh.yaml b/target/executable/rsem/rsem_calculate_expression/.config.vsh.yaml index c733c026..e8b5f602 100644 --- a/target/executable/rsem/rsem_calculate_expression/.config.vsh.yaml +++ b/target/executable/rsem/rsem_calculate_expression/.config.vsh.yaml @@ -852,9 +852,9 @@ build_info: output: "target/executable/rsem/rsem_calculate_expression" executable: "target/executable/rsem/rsem_calculate_expression/rsem_calculate_expression" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/rsem/rsem_calculate_expression/rsem_calculate_expression b/target/executable/rsem/rsem_calculate_expression/rsem_calculate_expression index 8134770e..84ca3bfd 100755 --- a/target/executable/rsem/rsem_calculate_expression/rsem_calculate_expression +++ b/target/executable/rsem/rsem_calculate_expression/rsem_calculate_expression @@ -991,9 +991,9 @@ echo "bowtie: `bowtie --version | grep -oP 'bowtie-align-s version \K\d+\.\d+\.\ echo "HISAT2: `hisat2 --version | grep -oP 'hisat2-align-s version \K\d+\.\d+\.\d+'`" >> /var/software_versions.txt LABEL org.opencontainers.image.description="Companion container for running component rsem rsem_calculate_expression" -LABEL org.opencontainers.image.created="2024-10-26T13:11:11Z" +LABEL org.opencontainers.image.created="2024-10-26T18:43:59Z" LABEL org.opencontainers.image.source="https://github.com/deweylab/RSEM" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/rsem/rsem_prepare_reference/.config.vsh.yaml b/target/executable/rsem/rsem_prepare_reference/.config.vsh.yaml index 55c195e0..fb530b60 100644 --- a/target/executable/rsem/rsem_prepare_reference/.config.vsh.yaml +++ b/target/executable/rsem/rsem_prepare_reference/.config.vsh.yaml @@ -416,9 +416,9 @@ build_info: output: "target/executable/rsem/rsem_prepare_reference" executable: "target/executable/rsem/rsem_prepare_reference/rsem_prepare_reference" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/rsem/rsem_prepare_reference/rsem_prepare_reference b/target/executable/rsem/rsem_prepare_reference/rsem_prepare_reference index 1b3b4987..672a7028 100755 --- a/target/executable/rsem/rsem_prepare_reference/rsem_prepare_reference +++ b/target/executable/rsem/rsem_prepare_reference/rsem_prepare_reference @@ -656,9 +656,9 @@ echo "HISAT2: `hisat2 --version | grep -oP 'hisat2-align-s version \K\d+\.\d+\.\ LABEL org.opencontainers.image.authors="Sai Nirmayi Yasa" LABEL org.opencontainers.image.description="Companion container for running component rsem rsem_prepare_reference" -LABEL org.opencontainers.image.created="2024-10-26T13:11:10Z" +LABEL org.opencontainers.image.created="2024-10-26T18:43:59Z" LABEL org.opencontainers.image.source="https://github.com/deweylab/RSEM" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/rseqc/rseqc_bamstat/.config.vsh.yaml b/target/executable/rseqc/rseqc_bamstat/.config.vsh.yaml new file mode 100644 index 00000000..850fe78d --- /dev/null +++ b/target/executable/rseqc/rseqc_bamstat/.config.vsh.yaml @@ -0,0 +1,202 @@ +name: "rseqc_bamstat" +namespace: "rseqc" +version: "main" +authors: +- name: "Emma Rousseau" + roles: + - "author" + - "maintainer" + info: + links: + email: "emma@data-intuitive.com" + github: "emmarousseau" + linkedin: "emmarousseau1" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Bioinformatician" +argument_groups: +- name: "Input" + arguments: + - type: "file" + name: "--input_file" + alternatives: + - "-i" + description: "Input alignment file in BAM or SAM format." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--mapq" + alternatives: + - "-q" + description: "Minimum mapping quality (phred scaled) to determine uniquely mapped\ + \ reads. Default: '30'.\n" + info: null + example: + - 30 + required: false + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Output" + arguments: + - type: "file" + name: "--output" + description: "Output file (txt) with mapping quality statistics." + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Generate statistics from a bam file." +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "rnaseq" +- "genomics" +license: "GPL-3.0" +references: + doi: + - "10.1093/bioinformatics/bts356" +links: + repository: "https://github.com/MonashBioinformaticsPlatform/RSeQC" + homepage: "https://rseqc.sourceforge.net/" + documentation: "https://rseqc.sourceforge.net/#bam-stat-py" + issue_tracker: "https://github.com/MonashBioinformaticsPlatform/RSeQC/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "python:3.10" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "python" + user: false + packages: + - "RSeQC" + upgrade: true + - type: "docker" + run: + - "echo \"RSeQC bam_stat.py: $(bam_stat.py --version | cut -d' ' -f2-)\" > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/rseqc/rseqc_bamstat/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/rseqc/rseqc_bamstat" + executable: "target/executable/rseqc/rseqc_bamstat/rseqc_bamstat" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/executable/rseqc/rseqc_bamstat/rseqc_bamstat b/target/executable/rseqc/rseqc_bamstat/rseqc_bamstat new file mode 100755 index 00000000..c2fb8028 --- /dev/null +++ b/target/executable/rseqc/rseqc_bamstat/rseqc_bamstat @@ -0,0 +1,1119 @@ +#!/usr/bin/env bash + +# rseqc_bamstat main +# +# This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +# work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +# Intuitive. +# +# The component may contain files which fall under a different license. The +# authors of this component should specify the license in the header of such +# files, or include a separate license file detailing the licenses of all included +# files. +# +# Component authors: +# * Emma Rousseau (author, maintainer) + +set -e + +if [ -z "$VIASH_TEMP" ]; then + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMP} + VIASH_TEMP=${VIASH_TEMP:-$TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TMP} + VIASH_TEMP=${VIASH_TEMP:-$TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TEMP} + VIASH_TEMP=${VIASH_TEMP:-/tmp} +fi + +# define helper functions +# ViashQuote: put quotes around non flag values +# $1 : unquoted string +# return : possibly quoted string +# examples: +# ViashQuote --foo # returns --foo +# ViashQuote bar # returns 'bar' +# Viashquote --foo=bar # returns --foo='bar' +function ViashQuote { + if [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+=.+$ ]]; then + echo "$1" | sed "s#=\(.*\)#='\1'#" + elif [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+$ ]]; then + echo "$1" + else + echo "'$1'" + fi +} +# ViashRemoveFlags: Remove leading flag +# $1 : string with a possible leading flag +# return : string without possible leading flag +# examples: +# ViashRemoveFlags --foo=bar # returns bar +function ViashRemoveFlags { + echo "$1" | sed 's/^--*[a-zA-Z0-9_\-]*=//' +} +# ViashSourceDir: return the path of a bash file, following symlinks +# usage : ViashSourceDir ${BASH_SOURCE[0]} +# $1 : Should always be set to ${BASH_SOURCE[0]} +# returns : The absolute path of the bash file +function ViashSourceDir { + local source="$1" + while [ -h "$source" ]; do + local dir="$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd )" + source="$(readlink "$source")" + [[ $source != /* ]] && source="$dir/$source" + done + cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd +} +# ViashFindTargetDir: return the path of the '.build.yaml' file, following symlinks +# usage : ViashFindTargetDir 'ScriptPath' +# $1 : The location from where to start the upward search +# returns : The absolute path of the '.build.yaml' file +function ViashFindTargetDir { + local source="$1" + while [[ "$source" != "" && ! -e "$source/.build.yaml" ]]; do + source=${source%/*} + done + echo $source +} +# see https://en.wikipedia.org/wiki/Syslog#Severity_level +VIASH_LOGCODE_EMERGENCY=0 +VIASH_LOGCODE_ALERT=1 +VIASH_LOGCODE_CRITICAL=2 +VIASH_LOGCODE_ERROR=3 +VIASH_LOGCODE_WARNING=4 +VIASH_LOGCODE_NOTICE=5 +VIASH_LOGCODE_INFO=6 +VIASH_LOGCODE_DEBUG=7 +VIASH_VERBOSITY=$VIASH_LOGCODE_NOTICE + +# ViashLog: Log events depending on the verbosity level +# usage: ViashLog 1 alert Oh no something went wrong! +# $1: required verbosity level +# $2: display tag +# $3+: messages to display +# stdout: Your input, prepended by '[$2] '. +function ViashLog { + local required_level="$1" + local display_tag="$2" + shift 2 + if [ $VIASH_VERBOSITY -ge $required_level ]; then + >&2 echo "[$display_tag]" "$@" + fi +} + +# ViashEmergency: log events when the system is unstable +# usage: ViashEmergency Oh no something went wrong. +# stdout: Your input, prepended by '[emergency] '. +function ViashEmergency { + ViashLog $VIASH_LOGCODE_EMERGENCY emergency "$@" +} + +# ViashAlert: log events when actions must be taken immediately (e.g. corrupted system database) +# usage: ViashAlert Oh no something went wrong. +# stdout: Your input, prepended by '[alert] '. +function ViashAlert { + ViashLog $VIASH_LOGCODE_ALERT alert "$@" +} + +# ViashCritical: log events when a critical condition occurs +# usage: ViashCritical Oh no something went wrong. +# stdout: Your input, prepended by '[critical] '. +function ViashCritical { + ViashLog $VIASH_LOGCODE_CRITICAL critical "$@" +} + +# ViashError: log events when an error condition occurs +# usage: ViashError Oh no something went wrong. +# stdout: Your input, prepended by '[error] '. +function ViashError { + ViashLog $VIASH_LOGCODE_ERROR error "$@" +} + +# ViashWarning: log potentially abnormal events +# usage: ViashWarning Something may have gone wrong. +# stdout: Your input, prepended by '[warning] '. +function ViashWarning { + ViashLog $VIASH_LOGCODE_WARNING warning "$@" +} + +# ViashNotice: log significant but normal events +# usage: ViashNotice This just happened. +# stdout: Your input, prepended by '[notice] '. +function ViashNotice { + ViashLog $VIASH_LOGCODE_NOTICE notice "$@" +} + +# ViashInfo: log normal events +# usage: ViashInfo This just happened. +# stdout: Your input, prepended by '[info] '. +function ViashInfo { + ViashLog $VIASH_LOGCODE_INFO info "$@" +} + +# ViashDebug: log all events, for debugging purposes +# usage: ViashDebug This just happened. +# stdout: Your input, prepended by '[debug] '. +function ViashDebug { + ViashLog $VIASH_LOGCODE_DEBUG debug "$@" +} + +# find source folder of this component +VIASH_META_RESOURCES_DIR=`ViashSourceDir ${BASH_SOURCE[0]}` + +# find the root of the built components & dependencies +VIASH_TARGET_DIR=`ViashFindTargetDir $VIASH_META_RESOURCES_DIR` + +# define meta fields +VIASH_META_NAME="rseqc_bamstat" +VIASH_META_FUNCTIONALITY_NAME="rseqc_bamstat" +VIASH_META_EXECUTABLE="$VIASH_META_RESOURCES_DIR/$VIASH_META_NAME" +VIASH_META_CONFIG="$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" +VIASH_META_TEMP_DIR="$VIASH_TEMP" + + +# ViashHelp: Display helpful explanation about this executable +function ViashHelp { + echo "rseqc_bamstat main" + echo "" + echo "Generate statistics from a bam file." + echo "" + echo "Input:" + echo " -i, --input_file" + echo " type: file, required parameter, file must exist" + echo " Input alignment file in BAM or SAM format." + echo "" + echo " -q, --mapq" + echo " type: integer" + echo " example: 30" + echo " Minimum mapping quality (phred scaled) to determine uniquely mapped" + echo " reads. Default: '30'." + echo "" + echo "Output:" + echo " --output" + echo " type: file, output, file must exist" + echo " Output file (txt) with mapping quality statistics." +} + +# initialise variables +VIASH_MODE='run' +VIASH_ENGINE_ID='docker' + +######## Helper functions for setting up Docker images for viash ######## +# expects: ViashDockerBuild + +# ViashDockerInstallationCheck: check whether Docker is installed correctly +# +# examples: +# ViashDockerInstallationCheck +function ViashDockerInstallationCheck { + ViashDebug "Checking whether Docker is installed" + if [ ! command -v docker &> /dev/null ]; then + ViashCritical "Docker doesn't seem to be installed. See 'https://docs.docker.com/get-docker/' for instructions." + exit 1 + fi + + ViashDebug "Checking whether the Docker daemon is running" + local save=$-; set +e + local docker_version=$(docker version --format '{{.Client.APIVersion}}' 2> /dev/null) + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashCritical "Docker daemon does not seem to be running. Try one of the following:" + ViashCritical "- Try running 'dockerd' in the command line" + ViashCritical "- See https://docs.docker.com/config/daemon/" + exit 1 + fi +} + +# ViashDockerRemoteTagCheck: check whether a Docker image is available +# on a remote. Assumes `docker login` has been performed, if relevant. +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerRemoteTagCheck python:latest +# echo $? # returns '0' +# ViashDockerRemoteTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerRemoteTagCheck { + docker manifest inspect $1 > /dev/null 2> /dev/null +} + +# ViashDockerLocalTagCheck: check whether a Docker image is available locally +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# docker pull python:latest +# ViashDockerLocalTagCheck python:latest +# echo $? # returns '0' +# ViashDockerLocalTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerLocalTagCheck { + [ -n "$(docker images -q $1)" ] +} + +# ViashDockerPull: pull a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPull python:latest +# echo $? # returns '0' +# ViashDockerPull sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPull { + ViashNotice "Checking if Docker image is available at '$1'" + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker pull $1 && return 0 || return 1 + else + local save=$-; set +e + docker pull $1 2> /dev/null > /dev/null + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashWarning "Could not pull from '$1'. Docker image doesn't exist or is not accessible." + fi + return $out + fi +} + +# ViashDockerPush: push a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPush python:latest +# echo $? # returns '0' +# ViashDockerPush sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPush { + ViashNotice "Pushing image to '$1'" + local save=$-; set +e + local out + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker push $1 + out=$? + else + docker push $1 2> /dev/null > /dev/null + out=$? + fi + [[ $save =~ e ]] && set -e + if [ $out -eq 0 ]; then + ViashNotice "Container '$1' push succeeded." + else + ViashError "Container '$1' push errored. You might not be logged in or have the necessary permissions." + fi + return $out +} + +# ViashDockerPullElseBuild: pull a Docker image, else build it +# +# $1 : image identifier with format `[registry/]image[:tag]` +# ViashDockerBuild : a Bash function which builds a docker image, takes image identifier as argument. +# examples: +# ViashDockerPullElseBuild mynewcomponent +function ViashDockerPullElseBuild { + local save=$-; set +e + ViashDockerPull $1 + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashDockerBuild $@ + fi +} + +# ViashDockerSetup: create a Docker image, according to specified docker setup strategy +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $2 : docker setup strategy, see DockerSetupStrategy.scala +# examples: +# ViashDockerSetup mynewcomponent alwaysbuild +function ViashDockerSetup { + local image_id="$1" + local setup_strategy="$2" + if [ "$setup_strategy" == "alwaysbuild" -o "$setup_strategy" == "build" -o "$setup_strategy" == "b" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspull" -o "$setup_strategy" == "pull" -o "$setup_strategy" == "p" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "alwayspullelsebuild" -o "$setup_strategy" == "pullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspullelsecachedbuild" -o "$setup_strategy" == "pullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayscachedbuild" -o "$setup_strategy" == "cachedbuild" -o "$setup_strategy" == "cb" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [[ "$setup_strategy" =~ ^ifneedbe ]]; then + local save=$-; set +e + ViashDockerLocalTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashInfo "Image $image_id already exists" + elif [ "$setup_strategy" == "ifneedbebuild" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbecachedbuild" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepull" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "ifneedbepullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi + elif [ "$setup_strategy" == "push" -o "$setup_strategy" == "forcepush" -o "$setup_strategy" == "alwayspush" ]; then + ViashDockerPush "$image_id" + elif [ "$setup_strategy" == "pushifnotpresent" -o "$setup_strategy" == "gentlepush" -o "$setup_strategy" == "maybepush" ]; then + local save=$-; set +e + ViashDockerRemoteTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashNotice "Container '$image_id' exists, doing nothing." + else + ViashNotice "Container '$image_id' does not yet exist." + ViashDockerPush "$image_id" + fi + elif [ "$setup_strategy" == "donothing" -o "$setup_strategy" == "meh" ]; then + ViashNotice "Skipping setup." + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi +} + +# ViashDockerCheckCommands: Check whether a docker container has the required commands +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $@ : commands to verify being present +# examples: +# ViashDockerCheckCommands bash:4.0 bash ps foo +function ViashDockerCheckCommands { + local image_id="$1" + shift 1 + local commands="$@" + local save=$-; set +e + local missing # mark 'missing' as local in advance, otherwise the exit code of the command will be missing and always be '0' + missing=$(docker run --rm --entrypoint=sh "$image_id" -c "for command in $commands; do command -v \$command >/dev/null 2>&1; if [ \$? -ne 0 ]; then echo \$command; exit 1; fi; done") + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -ne 0 ]; then + ViashError "Docker container '$image_id' does not contain command '$missing'." + exit 1 + fi +} + +# ViashDockerBuild: build a docker image +# $1 : image identifier with format `[registry/]image[:tag]` +# $... : additional arguments to pass to docker build +# $VIASH_META_TEMP_DIR : temporary directory to store dockerfile & optional resources in +# $VIASH_META_NAME : name of the component +# $VIASH_META_RESOURCES_DIR : directory containing the resources +# $VIASH_VERBOSITY : verbosity level +# exit code $? : whether or not the image was built successfully +function ViashDockerBuild { + local image_id="$1" + shift 1 + + # create temporary directory to store dockerfile & optional resources in + local tmpdir=$(mktemp -d "$VIASH_META_TEMP_DIR/dockerbuild-$VIASH_META_NAME-XXXXXX") + local dockerfile="$tmpdir/Dockerfile" + function clean_up { + rm -rf "$tmpdir" + } + trap clean_up EXIT + + # store dockerfile and resources + ViashDockerfile "$VIASH_ENGINE_ID" > "$dockerfile" + + # generate the build command + local docker_build_cmd="docker build -t '$image_id' $@ '$VIASH_META_RESOURCES_DIR' -f '$dockerfile'" + + # build the container + ViashNotice "Building container '$image_id' with Dockerfile" + ViashInfo "$docker_build_cmd" + local save=$-; set +e + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + eval $docker_build_cmd + else + eval $docker_build_cmd &> "$tmpdir/docker_build.log" + fi + + # check exit code + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashError "Error occurred while building container '$image_id'" + if [ $VIASH_VERBOSITY -lt $VIASH_LOGCODE_INFO ]; then + ViashError "Transcript: --------------------------------" + cat "$tmpdir/docker_build.log" + ViashError "End of transcript --------------------------" + fi + exit 1 + fi +} + +######## End of helper functions for setting up Docker images for viash ######## + +# ViashDockerFile: print the dockerfile to stdout +# $1 : engine identifier +# return : dockerfile required to run this component +# examples: +# ViashDockerFile +function ViashDockerfile { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + cat << 'VIASHDOCKER' +FROM python:3.10 +ENTRYPOINT [] +RUN pip install --upgrade pip && \ + pip install --upgrade --no-cache-dir "RSeQC" + +RUN echo "RSeQC bam_stat.py: $(bam_stat.py --version | cut -d' ' -f2-)" > /var/software_versions.txt + +LABEL org.opencontainers.image.authors="Emma Rousseau" +LABEL org.opencontainers.image.description="Companion container for running component rseqc rseqc_bamstat" +LABEL org.opencontainers.image.created="2024-10-26T18:44:06Z" +LABEL org.opencontainers.image.source="https://github.com/MonashBioinformaticsPlatform/RSeQC" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" +LABEL org.opencontainers.image.version="main" + +VIASHDOCKER + fi +} + +# ViashDockerBuildArgs: return the arguments to pass to docker build +# $1 : engine identifier +# return : arguments to pass to docker build +function ViashDockerBuildArgs { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + echo "" + fi +} + +# ViashAbsolutePath: generate absolute path from relative path +# borrowed from https://stackoverflow.com/a/21951256 +# $1 : relative filename +# return : absolute path +# examples: +# ViashAbsolutePath some_file.txt # returns /path/to/some_file.txt +# ViashAbsolutePath /foo/bar/.. # returns /foo +function ViashAbsolutePath { + local thePath + local parr + local outp + local len + if [[ ! "$1" =~ ^/ ]]; then + thePath="$PWD/$1" + else + thePath="$1" + fi + echo "$thePath" | ( + IFS=/ + read -a parr + declare -a outp + for i in "${parr[@]}"; do + case "$i" in + ''|.) continue ;; + ..) + len=${#outp[@]} + if ((len==0)); then + continue + else + unset outp[$((len-1))] + fi + ;; + *) + len=${#outp[@]} + outp[$len]="$i" + ;; + esac + done + echo /"${outp[*]}" + ) +} +# ViashDockerAutodetectMount: auto configuring docker mounts from parameters +# $1 : The parameter value +# returns : New parameter +# $VIASH_DIRECTORY_MOUNTS : Added another parameter to be passed to docker +# $VIASH_DOCKER_AUTOMOUNT_PREFIX : The prefix to be used for the automounts +# examples: +# ViashDockerAutodetectMount /path/to/bar # returns '/viash_automount/path/to/bar' +# ViashDockerAutodetectMountArg /path/to/bar # returns '--volume="/path/to:/viash_automount/path/to"' +function ViashDockerAutodetectMount { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + if [ -z "$base_name" ]; then + echo "$mount_target" + else + echo "$mount_target/$base_name" + fi +} +function ViashDockerAutodetectMountArg { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + ViashDebug "ViashDockerAutodetectMountArg $1 -> $mount_source -> $mount_target" + echo "--volume=\"$mount_source:$mount_target\"" +} +function ViashDockerStripAutomount { + local abs_path=$(ViashAbsolutePath "$1") + echo "${abs_path#$VIASH_DOCKER_AUTOMOUNT_PREFIX}" +} +# initialise variables +VIASH_DIRECTORY_MOUNTS=() + +# configure default docker automount prefix if it is unset +if [ -z "${VIASH_DOCKER_AUTOMOUNT_PREFIX+x}" ]; then + VIASH_DOCKER_AUTOMOUNT_PREFIX="/viash_automount" +fi + +# initialise docker variables +VIASH_DOCKER_RUN_ARGS=(-i --rm) + +# initialise array +VIASH_POSITIONAL_ARGS='' + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + ViashHelp + exit + ;; + ---v|---verbose) + let "VIASH_VERBOSITY=VIASH_VERBOSITY+1" + shift 1 + ;; + ---verbosity) + VIASH_VERBOSITY="$2" + shift 2 + ;; + ---verbosity=*) + VIASH_VERBOSITY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + --version) + echo "rseqc_bamstat main" + exit + ;; + --input_file) + [ -n "$VIASH_PAR_INPUT_FILE" ] && ViashError Bad arguments for option \'--input_file\': \'$VIASH_PAR_INPUT_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --input_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --input_file=*) + [ -n "$VIASH_PAR_INPUT_FILE" ] && ViashError Bad arguments for option \'--input_file=*\': \'$VIASH_PAR_INPUT_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -i) + [ -n "$VIASH_PAR_INPUT_FILE" ] && ViashError Bad arguments for option \'-i\': \'$VIASH_PAR_INPUT_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -i. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --mapq) + [ -n "$VIASH_PAR_MAPQ" ] && ViashError Bad arguments for option \'--mapq\': \'$VIASH_PAR_MAPQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MAPQ="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --mapq. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --mapq=*) + [ -n "$VIASH_PAR_MAPQ" ] && ViashError Bad arguments for option \'--mapq=*\': \'$VIASH_PAR_MAPQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MAPQ=$(ViashRemoveFlags "$1") + shift 1 + ;; + -q) + [ -n "$VIASH_PAR_MAPQ" ] && ViashError Bad arguments for option \'-q\': \'$VIASH_PAR_MAPQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MAPQ="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -q. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output=*) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output=*\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT=$(ViashRemoveFlags "$1") + shift 1 + ;; + ---engine) + VIASH_ENGINE_ID="$2" + shift 2 + ;; + ---engine=*) + VIASH_ENGINE_ID="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---setup) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$2" + shift 2 + ;; + ---setup=*) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---dockerfile) + VIASH_MODE='dockerfile' + shift 1 + ;; + ---docker_run_args) + VIASH_DOCKER_RUN_ARGS+=("$2") + shift 2 + ;; + ---docker_run_args=*) + VIASH_DOCKER_RUN_ARGS+=("$(ViashRemoveFlags "$1")") + shift 1 + ;; + ---docker_image_id) + VIASH_MODE='docker_image_id' + shift 1 + ;; + ---debug) + VIASH_MODE='debug' + shift 1 + ;; + ---cpus) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---cpus. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---cpus=*) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus=*\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS=$(ViashRemoveFlags "$1") + shift 1 + ;; + ---memory) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---memory. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---memory=*) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory=*\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY=$(ViashRemoveFlags "$1") + shift 1 + ;; + *) # positional arg or unknown option + # since the positional args will be eval'd, can we always quote, instead of using ViashQuote + VIASH_POSITIONAL_ARGS="$VIASH_POSITIONAL_ARGS '$1'" + [[ $1 == -* ]] && ViashWarning $1 looks like a parameter but is not a defined parameter and will instead be treated as a positional argument. Use "--help" to get more information on the parameters. + shift # past argument + ;; + esac +done + +# parse positional parameters +eval set -- $VIASH_POSITIONAL_ARGS + + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + VIASH_ENGINE_TYPE='native' +elif [ "$VIASH_ENGINE_ID" == "docker" ] ; then + VIASH_ENGINE_TYPE='docker' +else + ViashError "Engine '$VIASH_ENGINE_ID' is not recognized. Options are: docker, native." + exit 1 +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # check if docker is installed properly + ViashDockerInstallationCheck + + # determine docker image id + if [[ "$VIASH_ENGINE_ID" == 'docker' ]]; then + VIASH_DOCKER_IMAGE_ID='images.viash-hub.com/vsh/biobox/rseqc/rseqc_bamstat:main' + fi + + # print dockerfile + if [ "$VIASH_MODE" == "dockerfile" ]; then + ViashDockerfile "$VIASH_ENGINE_ID" + exit 0 + + elif [ "$VIASH_MODE" == "docker_image_id" ]; then + echo "$VIASH_DOCKER_IMAGE_ID" + exit 0 + + # enter docker container + elif [[ "$VIASH_MODE" == "debug" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} -v '$(pwd)':/pwd --workdir /pwd -t $VIASH_DOCKER_IMAGE_ID" + ViashNotice "+ $VIASH_CMD" + eval $VIASH_CMD + exit + + # build docker image + elif [ "$VIASH_MODE" == "setup" ]; then + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" "$VIASH_SETUP_STRATEGY" + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' + exit 0 + fi + + # check if docker image exists + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" ifneedbepullelsecachedbuild + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' +fi + +# setting computational defaults + +# helper function for parsing memory strings +function ViashMemoryAsBytes { + local memory=`echo "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'` + local memory_regex='^([0-9]+)([kmgtp]i?b?|b)$' + if [[ $memory =~ $memory_regex ]]; then + local number=${memory/[^0-9]*/} + local symbol=${memory/*[0-9]/} + + case $symbol in + b) memory_b=$number ;; + kb|k) memory_b=$(( $number * 1000 )) ;; + mb|m) memory_b=$(( $number * 1000 * 1000 )) ;; + gb|g) memory_b=$(( $number * 1000 * 1000 * 1000 )) ;; + tb|t) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 )) ;; + pb|p) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 * 1000 )) ;; + kib|ki) memory_b=$(( $number * 1024 )) ;; + mib|mi) memory_b=$(( $number * 1024 * 1024 )) ;; + gib|gi) memory_b=$(( $number * 1024 * 1024 * 1024 )) ;; + tib|ti) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 )) ;; + pib|pi) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 * 1024 )) ;; + esac + echo "$memory_b" + fi +} +# compute memory in different units +if [ ! -z ${VIASH_META_MEMORY+x} ]; then + VIASH_META_MEMORY_B=`ViashMemoryAsBytes $VIASH_META_MEMORY` + # do not define other variables if memory_b is an empty string + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_META_MEMORY_KB=$(( ($VIASH_META_MEMORY_B+999) / 1000 )) + VIASH_META_MEMORY_MB=$(( ($VIASH_META_MEMORY_KB+999) / 1000 )) + VIASH_META_MEMORY_GB=$(( ($VIASH_META_MEMORY_MB+999) / 1000 )) + VIASH_META_MEMORY_TB=$(( ($VIASH_META_MEMORY_GB+999) / 1000 )) + VIASH_META_MEMORY_PB=$(( ($VIASH_META_MEMORY_TB+999) / 1000 )) + VIASH_META_MEMORY_KIB=$(( ($VIASH_META_MEMORY_B+1023) / 1024 )) + VIASH_META_MEMORY_MIB=$(( ($VIASH_META_MEMORY_KIB+1023) / 1024 )) + VIASH_META_MEMORY_GIB=$(( ($VIASH_META_MEMORY_MIB+1023) / 1024 )) + VIASH_META_MEMORY_TIB=$(( ($VIASH_META_MEMORY_GIB+1023) / 1024 )) + VIASH_META_MEMORY_PIB=$(( ($VIASH_META_MEMORY_TIB+1023) / 1024 )) + else + # unset memory if string is empty + unset $VIASH_META_MEMORY_B + fi +fi +# unset nproc if string is empty +if [ -z "$VIASH_META_CPUS" ]; then + unset $VIASH_META_CPUS +fi + + +# check whether required parameters exist +if [ -z ${VIASH_PAR_INPUT_FILE+x} ]; then + ViashError '--input_file' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_NAME+x} ]; then + ViashError 'name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_FUNCTIONALITY_NAME+x} ]; then + ViashError 'functionality_name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_RESOURCES_DIR+x} ]; then + ViashError 'resources_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_EXECUTABLE+x} ]; then + ViashError 'executable' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_CONFIG+x} ]; then + ViashError 'config' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_TEMP_DIR+x} ]; then + ViashError 'temp_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi + +# check whether required files exist +if [ ! -z "$VIASH_PAR_INPUT_FILE" ] && [ ! -e "$VIASH_PAR_INPUT_FILE" ]; then + ViashError "Input file '$VIASH_PAR_INPUT_FILE' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_PAR_MAPQ" ]]; then + if ! [[ "$VIASH_PAR_MAPQ" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--mapq' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_CPUS" ]]; then + if ! [[ "$VIASH_META_CPUS" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'cpus' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_B" ]]; then + if ! [[ "$VIASH_META_MEMORY_B" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_b' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi + +# create parent directories of output files, if so desired +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT")" +fi + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + if [ "$VIASH_MODE" == "run" ]; then + VIASH_CMD="bash" + else + ViashError "Engine '$VIASH_ENGINE_ID' does not support mode '$VIASH_MODE'." + exit 1 + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # detect volumes from file arguments + VIASH_CHOWN_VARS=() +if [ ! -z "$VIASH_PAR_INPUT_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_INPUT_FILE")" ) + VIASH_PAR_INPUT_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_INPUT_FILE") +fi +if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT")" ) + VIASH_PAR_OUTPUT=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT" ) +fi +if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_RESOURCES_DIR")" ) + VIASH_META_RESOURCES_DIR=$(ViashDockerAutodetectMount "$VIASH_META_RESOURCES_DIR") +fi +if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_EXECUTABLE")" ) + VIASH_META_EXECUTABLE=$(ViashDockerAutodetectMount "$VIASH_META_EXECUTABLE") +fi +if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_CONFIG")" ) + VIASH_META_CONFIG=$(ViashDockerAutodetectMount "$VIASH_META_CONFIG") +fi +if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_TEMP_DIR")" ) + VIASH_META_TEMP_DIR=$(ViashDockerAutodetectMount "$VIASH_META_TEMP_DIR") +fi + + # get unique mounts + VIASH_UNIQUE_MOUNTS=($(for val in "${VIASH_DIRECTORY_MOUNTS[@]}"; do echo "$val"; done | sort -u)) +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # change file ownership + function ViashPerformChown { + if (( ${#VIASH_CHOWN_VARS[@]} )); then + set +e + VIASH_CMD="docker run --entrypoint=bash --rm ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID -c 'chown $(id -u):$(id -g) --silent --recursive ${VIASH_CHOWN_VARS[@]}'" + ViashDebug "+ $VIASH_CMD" + eval $VIASH_CMD + set -e + fi + } + trap ViashPerformChown EXIT +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # helper function for filling in extra docker args + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_DOCKER_RUN_ARGS+=("--memory=${VIASH_META_MEMORY_B}") + fi + if [ ! -z "$VIASH_META_CPUS" ]; then + VIASH_DOCKER_RUN_ARGS+=("--cpus=${VIASH_META_CPUS}") + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID" +fi + + +# set dependency paths + + +ViashDebug "Running command: $(echo $VIASH_CMD)" +cat << VIASHEOF | eval $VIASH_CMD +set -e +tempscript=\$(mktemp "$VIASH_META_TEMP_DIR/viash-run-rseqc_bamstat-XXXXXX").sh +function clean_up { + rm "\$tempscript" +} +function interrupt { + echo -e "\nCTRL-C Pressed..." + exit 1 +} +trap clean_up EXIT +trap interrupt INT SIGINT +cat > "\$tempscript" << 'VIASHMAIN' +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_INPUT_FILE+x} ]; then echo "${VIASH_PAR_INPUT_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_input_file='&'#" ; else echo "# par_input_file="; fi ) +$( if [ ! -z ${VIASH_PAR_MAPQ+x} ]; then echo "${VIASH_PAR_MAPQ}" | sed "s#'#'\"'\"'#g;s#.*#par_mapq='&'#" ; else echo "# par_mapq="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\"'\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\"'\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\"'\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\"'\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\"'\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END +#!/bin/bash + + +set -eo pipefail + +bam_stat.py \\ + --input-file "\${par_input_file}" \\ + \${par_mapq:+--mapq "\${par_mapq}"} \\ +> \$par_output +VIASHMAIN +bash "\$tempscript" & +wait "\$!" + +VIASHEOF + + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # strip viash automount from file paths + + if [ ! -z "$VIASH_PAR_INPUT_FILE" ]; then + VIASH_PAR_INPUT_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_INPUT_FILE") + fi + if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_PAR_OUTPUT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT") + fi + if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_META_RESOURCES_DIR=$(ViashDockerStripAutomount "$VIASH_META_RESOURCES_DIR") + fi + if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_META_EXECUTABLE=$(ViashDockerStripAutomount "$VIASH_META_EXECUTABLE") + fi + if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_META_CONFIG=$(ViashDockerStripAutomount "$VIASH_META_CONFIG") + fi + if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_META_TEMP_DIR=$(ViashDockerStripAutomount "$VIASH_META_TEMP_DIR") + fi +fi + + +# check whether required files exist +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -e "$VIASH_PAR_OUTPUT" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT' does not exist." + exit 1 +fi + + +exit 0 diff --git a/target/executable/rseqc/rseqc_inferexperiment/.config.vsh.yaml b/target/executable/rseqc/rseqc_inferexperiment/.config.vsh.yaml new file mode 100644 index 00000000..c2be895c --- /dev/null +++ b/target/executable/rseqc/rseqc_inferexperiment/.config.vsh.yaml @@ -0,0 +1,228 @@ +name: "rseqc_inferexperiment" +namespace: "rseqc" +version: "main" +authors: +- name: "Emma Rousseau" + roles: + - "author" + - "maintainer" + info: + links: + email: "emma@data-intuitive.com" + github: "emmarousseau" + linkedin: "emmarousseau1" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Bioinformatician" +argument_groups: +- name: "Input" + arguments: + - type: "file" + name: "--input_file" + alternatives: + - "-i" + description: "input alignment file in BAM or SAM format" + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--refgene" + alternatives: + - "-r" + description: "Reference gene model in bed format" + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Output" + arguments: + - type: "file" + name: "--output" + description: "Output file (txt) of strandness report." + info: null + example: + - "$id.strandedness.txt" + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "integer" + name: "--sample_size" + alternatives: + - "-s" + description: "Number of reads sampled from SAM/BAM file. Default: 200000\n" + info: null + example: + - 200000 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--mapq" + alternatives: + - "-q" + description: "Minimum mapping quality (phred scaled) to determine uniquely mapped\ + \ reads. Default: 30\n" + info: null + example: + - 30 + required: false + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Infer strandedness from sequencing reads\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +license: "GPL-3.0" +references: + doi: + - "10.1093/bioinformatics/bts356" +links: + repository: "https://github.com/MonashBioinformaticsPlatform/RSeQC" + homepage: "https://rseqc.sourceforge.net/" + documentation: "https://rseqc.sourceforge.net/#infer-experiment-py" + issue_tracker: "https://github.com/MonashBioinformaticsPlatform/RSeQC/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "python:3.10" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "python" + user: false + packages: + - "RSeQC" + upgrade: true + - type: "docker" + run: + - "echo \"RSeQC - infer_experiment.py: $(infer_experiment.py --version | cut -d'\ + \ ' -f2)\" > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/rseqc/rseqc_inferexperiment/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/rseqc/rseqc_inferexperiment" + executable: "target/executable/rseqc/rseqc_inferexperiment/rseqc_inferexperiment" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/executable/rseqc/rseqc_inferexperiment/rseqc_inferexperiment b/target/executable/rseqc/rseqc_inferexperiment/rseqc_inferexperiment new file mode 100755 index 00000000..f9f4c8ed --- /dev/null +++ b/target/executable/rseqc/rseqc_inferexperiment/rseqc_inferexperiment @@ -0,0 +1,1192 @@ +#!/usr/bin/env bash + +# rseqc_inferexperiment main +# +# This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +# work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +# Intuitive. +# +# The component may contain files which fall under a different license. The +# authors of this component should specify the license in the header of such +# files, or include a separate license file detailing the licenses of all included +# files. +# +# Component authors: +# * Emma Rousseau (author, maintainer) + +set -e + +if [ -z "$VIASH_TEMP" ]; then + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMP} + VIASH_TEMP=${VIASH_TEMP:-$TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TMP} + VIASH_TEMP=${VIASH_TEMP:-$TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TEMP} + VIASH_TEMP=${VIASH_TEMP:-/tmp} +fi + +# define helper functions +# ViashQuote: put quotes around non flag values +# $1 : unquoted string +# return : possibly quoted string +# examples: +# ViashQuote --foo # returns --foo +# ViashQuote bar # returns 'bar' +# Viashquote --foo=bar # returns --foo='bar' +function ViashQuote { + if [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+=.+$ ]]; then + echo "$1" | sed "s#=\(.*\)#='\1'#" + elif [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+$ ]]; then + echo "$1" + else + echo "'$1'" + fi +} +# ViashRemoveFlags: Remove leading flag +# $1 : string with a possible leading flag +# return : string without possible leading flag +# examples: +# ViashRemoveFlags --foo=bar # returns bar +function ViashRemoveFlags { + echo "$1" | sed 's/^--*[a-zA-Z0-9_\-]*=//' +} +# ViashSourceDir: return the path of a bash file, following symlinks +# usage : ViashSourceDir ${BASH_SOURCE[0]} +# $1 : Should always be set to ${BASH_SOURCE[0]} +# returns : The absolute path of the bash file +function ViashSourceDir { + local source="$1" + while [ -h "$source" ]; do + local dir="$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd )" + source="$(readlink "$source")" + [[ $source != /* ]] && source="$dir/$source" + done + cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd +} +# ViashFindTargetDir: return the path of the '.build.yaml' file, following symlinks +# usage : ViashFindTargetDir 'ScriptPath' +# $1 : The location from where to start the upward search +# returns : The absolute path of the '.build.yaml' file +function ViashFindTargetDir { + local source="$1" + while [[ "$source" != "" && ! -e "$source/.build.yaml" ]]; do + source=${source%/*} + done + echo $source +} +# see https://en.wikipedia.org/wiki/Syslog#Severity_level +VIASH_LOGCODE_EMERGENCY=0 +VIASH_LOGCODE_ALERT=1 +VIASH_LOGCODE_CRITICAL=2 +VIASH_LOGCODE_ERROR=3 +VIASH_LOGCODE_WARNING=4 +VIASH_LOGCODE_NOTICE=5 +VIASH_LOGCODE_INFO=6 +VIASH_LOGCODE_DEBUG=7 +VIASH_VERBOSITY=$VIASH_LOGCODE_NOTICE + +# ViashLog: Log events depending on the verbosity level +# usage: ViashLog 1 alert Oh no something went wrong! +# $1: required verbosity level +# $2: display tag +# $3+: messages to display +# stdout: Your input, prepended by '[$2] '. +function ViashLog { + local required_level="$1" + local display_tag="$2" + shift 2 + if [ $VIASH_VERBOSITY -ge $required_level ]; then + >&2 echo "[$display_tag]" "$@" + fi +} + +# ViashEmergency: log events when the system is unstable +# usage: ViashEmergency Oh no something went wrong. +# stdout: Your input, prepended by '[emergency] '. +function ViashEmergency { + ViashLog $VIASH_LOGCODE_EMERGENCY emergency "$@" +} + +# ViashAlert: log events when actions must be taken immediately (e.g. corrupted system database) +# usage: ViashAlert Oh no something went wrong. +# stdout: Your input, prepended by '[alert] '. +function ViashAlert { + ViashLog $VIASH_LOGCODE_ALERT alert "$@" +} + +# ViashCritical: log events when a critical condition occurs +# usage: ViashCritical Oh no something went wrong. +# stdout: Your input, prepended by '[critical] '. +function ViashCritical { + ViashLog $VIASH_LOGCODE_CRITICAL critical "$@" +} + +# ViashError: log events when an error condition occurs +# usage: ViashError Oh no something went wrong. +# stdout: Your input, prepended by '[error] '. +function ViashError { + ViashLog $VIASH_LOGCODE_ERROR error "$@" +} + +# ViashWarning: log potentially abnormal events +# usage: ViashWarning Something may have gone wrong. +# stdout: Your input, prepended by '[warning] '. +function ViashWarning { + ViashLog $VIASH_LOGCODE_WARNING warning "$@" +} + +# ViashNotice: log significant but normal events +# usage: ViashNotice This just happened. +# stdout: Your input, prepended by '[notice] '. +function ViashNotice { + ViashLog $VIASH_LOGCODE_NOTICE notice "$@" +} + +# ViashInfo: log normal events +# usage: ViashInfo This just happened. +# stdout: Your input, prepended by '[info] '. +function ViashInfo { + ViashLog $VIASH_LOGCODE_INFO info "$@" +} + +# ViashDebug: log all events, for debugging purposes +# usage: ViashDebug This just happened. +# stdout: Your input, prepended by '[debug] '. +function ViashDebug { + ViashLog $VIASH_LOGCODE_DEBUG debug "$@" +} + +# find source folder of this component +VIASH_META_RESOURCES_DIR=`ViashSourceDir ${BASH_SOURCE[0]}` + +# find the root of the built components & dependencies +VIASH_TARGET_DIR=`ViashFindTargetDir $VIASH_META_RESOURCES_DIR` + +# define meta fields +VIASH_META_NAME="rseqc_inferexperiment" +VIASH_META_FUNCTIONALITY_NAME="rseqc_inferexperiment" +VIASH_META_EXECUTABLE="$VIASH_META_RESOURCES_DIR/$VIASH_META_NAME" +VIASH_META_CONFIG="$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" +VIASH_META_TEMP_DIR="$VIASH_TEMP" + + +# ViashHelp: Display helpful explanation about this executable +function ViashHelp { + echo "rseqc_inferexperiment main" + echo "" + echo "Infer strandedness from sequencing reads" + echo "" + echo "Input:" + echo " -i, --input_file" + echo " type: file, required parameter, file must exist" + echo " input alignment file in BAM or SAM format" + echo "" + echo " -r, --refgene" + echo " type: file, required parameter, file must exist" + echo " Reference gene model in bed format" + echo "" + echo "Output:" + echo " --output" + echo " type: file, required parameter, output, file must exist" + echo " example: \$id.strandedness.txt" + echo " Output file (txt) of strandness report." + echo "" + echo "Options:" + echo " -s, --sample_size" + echo " type: integer" + echo " example: 200000" + echo " Number of reads sampled from SAM/BAM file. Default: 200000" + echo "" + echo " -q, --mapq" + echo " type: integer" + echo " example: 30" + echo " Minimum mapping quality (phred scaled) to determine uniquely mapped" + echo " reads. Default: 30" +} + +# initialise variables +VIASH_MODE='run' +VIASH_ENGINE_ID='docker' + +######## Helper functions for setting up Docker images for viash ######## +# expects: ViashDockerBuild + +# ViashDockerInstallationCheck: check whether Docker is installed correctly +# +# examples: +# ViashDockerInstallationCheck +function ViashDockerInstallationCheck { + ViashDebug "Checking whether Docker is installed" + if [ ! command -v docker &> /dev/null ]; then + ViashCritical "Docker doesn't seem to be installed. See 'https://docs.docker.com/get-docker/' for instructions." + exit 1 + fi + + ViashDebug "Checking whether the Docker daemon is running" + local save=$-; set +e + local docker_version=$(docker version --format '{{.Client.APIVersion}}' 2> /dev/null) + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashCritical "Docker daemon does not seem to be running. Try one of the following:" + ViashCritical "- Try running 'dockerd' in the command line" + ViashCritical "- See https://docs.docker.com/config/daemon/" + exit 1 + fi +} + +# ViashDockerRemoteTagCheck: check whether a Docker image is available +# on a remote. Assumes `docker login` has been performed, if relevant. +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerRemoteTagCheck python:latest +# echo $? # returns '0' +# ViashDockerRemoteTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerRemoteTagCheck { + docker manifest inspect $1 > /dev/null 2> /dev/null +} + +# ViashDockerLocalTagCheck: check whether a Docker image is available locally +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# docker pull python:latest +# ViashDockerLocalTagCheck python:latest +# echo $? # returns '0' +# ViashDockerLocalTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerLocalTagCheck { + [ -n "$(docker images -q $1)" ] +} + +# ViashDockerPull: pull a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPull python:latest +# echo $? # returns '0' +# ViashDockerPull sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPull { + ViashNotice "Checking if Docker image is available at '$1'" + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker pull $1 && return 0 || return 1 + else + local save=$-; set +e + docker pull $1 2> /dev/null > /dev/null + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashWarning "Could not pull from '$1'. Docker image doesn't exist or is not accessible." + fi + return $out + fi +} + +# ViashDockerPush: push a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPush python:latest +# echo $? # returns '0' +# ViashDockerPush sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPush { + ViashNotice "Pushing image to '$1'" + local save=$-; set +e + local out + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker push $1 + out=$? + else + docker push $1 2> /dev/null > /dev/null + out=$? + fi + [[ $save =~ e ]] && set -e + if [ $out -eq 0 ]; then + ViashNotice "Container '$1' push succeeded." + else + ViashError "Container '$1' push errored. You might not be logged in or have the necessary permissions." + fi + return $out +} + +# ViashDockerPullElseBuild: pull a Docker image, else build it +# +# $1 : image identifier with format `[registry/]image[:tag]` +# ViashDockerBuild : a Bash function which builds a docker image, takes image identifier as argument. +# examples: +# ViashDockerPullElseBuild mynewcomponent +function ViashDockerPullElseBuild { + local save=$-; set +e + ViashDockerPull $1 + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashDockerBuild $@ + fi +} + +# ViashDockerSetup: create a Docker image, according to specified docker setup strategy +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $2 : docker setup strategy, see DockerSetupStrategy.scala +# examples: +# ViashDockerSetup mynewcomponent alwaysbuild +function ViashDockerSetup { + local image_id="$1" + local setup_strategy="$2" + if [ "$setup_strategy" == "alwaysbuild" -o "$setup_strategy" == "build" -o "$setup_strategy" == "b" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspull" -o "$setup_strategy" == "pull" -o "$setup_strategy" == "p" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "alwayspullelsebuild" -o "$setup_strategy" == "pullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspullelsecachedbuild" -o "$setup_strategy" == "pullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayscachedbuild" -o "$setup_strategy" == "cachedbuild" -o "$setup_strategy" == "cb" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [[ "$setup_strategy" =~ ^ifneedbe ]]; then + local save=$-; set +e + ViashDockerLocalTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashInfo "Image $image_id already exists" + elif [ "$setup_strategy" == "ifneedbebuild" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbecachedbuild" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepull" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "ifneedbepullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi + elif [ "$setup_strategy" == "push" -o "$setup_strategy" == "forcepush" -o "$setup_strategy" == "alwayspush" ]; then + ViashDockerPush "$image_id" + elif [ "$setup_strategy" == "pushifnotpresent" -o "$setup_strategy" == "gentlepush" -o "$setup_strategy" == "maybepush" ]; then + local save=$-; set +e + ViashDockerRemoteTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashNotice "Container '$image_id' exists, doing nothing." + else + ViashNotice "Container '$image_id' does not yet exist." + ViashDockerPush "$image_id" + fi + elif [ "$setup_strategy" == "donothing" -o "$setup_strategy" == "meh" ]; then + ViashNotice "Skipping setup." + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi +} + +# ViashDockerCheckCommands: Check whether a docker container has the required commands +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $@ : commands to verify being present +# examples: +# ViashDockerCheckCommands bash:4.0 bash ps foo +function ViashDockerCheckCommands { + local image_id="$1" + shift 1 + local commands="$@" + local save=$-; set +e + local missing # mark 'missing' as local in advance, otherwise the exit code of the command will be missing and always be '0' + missing=$(docker run --rm --entrypoint=sh "$image_id" -c "for command in $commands; do command -v \$command >/dev/null 2>&1; if [ \$? -ne 0 ]; then echo \$command; exit 1; fi; done") + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -ne 0 ]; then + ViashError "Docker container '$image_id' does not contain command '$missing'." + exit 1 + fi +} + +# ViashDockerBuild: build a docker image +# $1 : image identifier with format `[registry/]image[:tag]` +# $... : additional arguments to pass to docker build +# $VIASH_META_TEMP_DIR : temporary directory to store dockerfile & optional resources in +# $VIASH_META_NAME : name of the component +# $VIASH_META_RESOURCES_DIR : directory containing the resources +# $VIASH_VERBOSITY : verbosity level +# exit code $? : whether or not the image was built successfully +function ViashDockerBuild { + local image_id="$1" + shift 1 + + # create temporary directory to store dockerfile & optional resources in + local tmpdir=$(mktemp -d "$VIASH_META_TEMP_DIR/dockerbuild-$VIASH_META_NAME-XXXXXX") + local dockerfile="$tmpdir/Dockerfile" + function clean_up { + rm -rf "$tmpdir" + } + trap clean_up EXIT + + # store dockerfile and resources + ViashDockerfile "$VIASH_ENGINE_ID" > "$dockerfile" + + # generate the build command + local docker_build_cmd="docker build -t '$image_id' $@ '$VIASH_META_RESOURCES_DIR' -f '$dockerfile'" + + # build the container + ViashNotice "Building container '$image_id' with Dockerfile" + ViashInfo "$docker_build_cmd" + local save=$-; set +e + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + eval $docker_build_cmd + else + eval $docker_build_cmd &> "$tmpdir/docker_build.log" + fi + + # check exit code + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashError "Error occurred while building container '$image_id'" + if [ $VIASH_VERBOSITY -lt $VIASH_LOGCODE_INFO ]; then + ViashError "Transcript: --------------------------------" + cat "$tmpdir/docker_build.log" + ViashError "End of transcript --------------------------" + fi + exit 1 + fi +} + +######## End of helper functions for setting up Docker images for viash ######## + +# ViashDockerFile: print the dockerfile to stdout +# $1 : engine identifier +# return : dockerfile required to run this component +# examples: +# ViashDockerFile +function ViashDockerfile { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + cat << 'VIASHDOCKER' +FROM python:3.10 +ENTRYPOINT [] +RUN pip install --upgrade pip && \ + pip install --upgrade --no-cache-dir "RSeQC" + +RUN echo "RSeQC - infer_experiment.py: $(infer_experiment.py --version | cut -d' ' -f2)" > /var/software_versions.txt + +LABEL org.opencontainers.image.authors="Emma Rousseau" +LABEL org.opencontainers.image.description="Companion container for running component rseqc rseqc_inferexperiment" +LABEL org.opencontainers.image.created="2024-10-26T18:44:06Z" +LABEL org.opencontainers.image.source="https://github.com/MonashBioinformaticsPlatform/RSeQC" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" +LABEL org.opencontainers.image.version="main" + +VIASHDOCKER + fi +} + +# ViashDockerBuildArgs: return the arguments to pass to docker build +# $1 : engine identifier +# return : arguments to pass to docker build +function ViashDockerBuildArgs { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + echo "" + fi +} + +# ViashAbsolutePath: generate absolute path from relative path +# borrowed from https://stackoverflow.com/a/21951256 +# $1 : relative filename +# return : absolute path +# examples: +# ViashAbsolutePath some_file.txt # returns /path/to/some_file.txt +# ViashAbsolutePath /foo/bar/.. # returns /foo +function ViashAbsolutePath { + local thePath + local parr + local outp + local len + if [[ ! "$1" =~ ^/ ]]; then + thePath="$PWD/$1" + else + thePath="$1" + fi + echo "$thePath" | ( + IFS=/ + read -a parr + declare -a outp + for i in "${parr[@]}"; do + case "$i" in + ''|.) continue ;; + ..) + len=${#outp[@]} + if ((len==0)); then + continue + else + unset outp[$((len-1))] + fi + ;; + *) + len=${#outp[@]} + outp[$len]="$i" + ;; + esac + done + echo /"${outp[*]}" + ) +} +# ViashDockerAutodetectMount: auto configuring docker mounts from parameters +# $1 : The parameter value +# returns : New parameter +# $VIASH_DIRECTORY_MOUNTS : Added another parameter to be passed to docker +# $VIASH_DOCKER_AUTOMOUNT_PREFIX : The prefix to be used for the automounts +# examples: +# ViashDockerAutodetectMount /path/to/bar # returns '/viash_automount/path/to/bar' +# ViashDockerAutodetectMountArg /path/to/bar # returns '--volume="/path/to:/viash_automount/path/to"' +function ViashDockerAutodetectMount { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + if [ -z "$base_name" ]; then + echo "$mount_target" + else + echo "$mount_target/$base_name" + fi +} +function ViashDockerAutodetectMountArg { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + ViashDebug "ViashDockerAutodetectMountArg $1 -> $mount_source -> $mount_target" + echo "--volume=\"$mount_source:$mount_target\"" +} +function ViashDockerStripAutomount { + local abs_path=$(ViashAbsolutePath "$1") + echo "${abs_path#$VIASH_DOCKER_AUTOMOUNT_PREFIX}" +} +# initialise variables +VIASH_DIRECTORY_MOUNTS=() + +# configure default docker automount prefix if it is unset +if [ -z "${VIASH_DOCKER_AUTOMOUNT_PREFIX+x}" ]; then + VIASH_DOCKER_AUTOMOUNT_PREFIX="/viash_automount" +fi + +# initialise docker variables +VIASH_DOCKER_RUN_ARGS=(-i --rm) + +# initialise array +VIASH_POSITIONAL_ARGS='' + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + ViashHelp + exit + ;; + ---v|---verbose) + let "VIASH_VERBOSITY=VIASH_VERBOSITY+1" + shift 1 + ;; + ---verbosity) + VIASH_VERBOSITY="$2" + shift 2 + ;; + ---verbosity=*) + VIASH_VERBOSITY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + --version) + echo "rseqc_inferexperiment main" + exit + ;; + --input_file) + [ -n "$VIASH_PAR_INPUT_FILE" ] && ViashError Bad arguments for option \'--input_file\': \'$VIASH_PAR_INPUT_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --input_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --input_file=*) + [ -n "$VIASH_PAR_INPUT_FILE" ] && ViashError Bad arguments for option \'--input_file=*\': \'$VIASH_PAR_INPUT_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -i) + [ -n "$VIASH_PAR_INPUT_FILE" ] && ViashError Bad arguments for option \'-i\': \'$VIASH_PAR_INPUT_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -i. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --refgene) + [ -n "$VIASH_PAR_REFGENE" ] && ViashError Bad arguments for option \'--refgene\': \'$VIASH_PAR_REFGENE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REFGENE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --refgene. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --refgene=*) + [ -n "$VIASH_PAR_REFGENE" ] && ViashError Bad arguments for option \'--refgene=*\': \'$VIASH_PAR_REFGENE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REFGENE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -r) + [ -n "$VIASH_PAR_REFGENE" ] && ViashError Bad arguments for option \'-r\': \'$VIASH_PAR_REFGENE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REFGENE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -r. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output=*) + [ -n "$VIASH_PAR_OUTPUT" ] && ViashError Bad arguments for option \'--output=*\': \'$VIASH_PAR_OUTPUT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT=$(ViashRemoveFlags "$1") + shift 1 + ;; + --sample_size) + [ -n "$VIASH_PAR_SAMPLE_SIZE" ] && ViashError Bad arguments for option \'--sample_size\': \'$VIASH_PAR_SAMPLE_SIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLE_SIZE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --sample_size. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --sample_size=*) + [ -n "$VIASH_PAR_SAMPLE_SIZE" ] && ViashError Bad arguments for option \'--sample_size=*\': \'$VIASH_PAR_SAMPLE_SIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLE_SIZE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -s) + [ -n "$VIASH_PAR_SAMPLE_SIZE" ] && ViashError Bad arguments for option \'-s\': \'$VIASH_PAR_SAMPLE_SIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLE_SIZE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -s. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --mapq) + [ -n "$VIASH_PAR_MAPQ" ] && ViashError Bad arguments for option \'--mapq\': \'$VIASH_PAR_MAPQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MAPQ="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --mapq. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --mapq=*) + [ -n "$VIASH_PAR_MAPQ" ] && ViashError Bad arguments for option \'--mapq=*\': \'$VIASH_PAR_MAPQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MAPQ=$(ViashRemoveFlags "$1") + shift 1 + ;; + -q) + [ -n "$VIASH_PAR_MAPQ" ] && ViashError Bad arguments for option \'-q\': \'$VIASH_PAR_MAPQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MAPQ="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -q. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---engine) + VIASH_ENGINE_ID="$2" + shift 2 + ;; + ---engine=*) + VIASH_ENGINE_ID="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---setup) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$2" + shift 2 + ;; + ---setup=*) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---dockerfile) + VIASH_MODE='dockerfile' + shift 1 + ;; + ---docker_run_args) + VIASH_DOCKER_RUN_ARGS+=("$2") + shift 2 + ;; + ---docker_run_args=*) + VIASH_DOCKER_RUN_ARGS+=("$(ViashRemoveFlags "$1")") + shift 1 + ;; + ---docker_image_id) + VIASH_MODE='docker_image_id' + shift 1 + ;; + ---debug) + VIASH_MODE='debug' + shift 1 + ;; + ---cpus) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---cpus. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---cpus=*) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus=*\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS=$(ViashRemoveFlags "$1") + shift 1 + ;; + ---memory) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---memory. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---memory=*) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory=*\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY=$(ViashRemoveFlags "$1") + shift 1 + ;; + *) # positional arg or unknown option + # since the positional args will be eval'd, can we always quote, instead of using ViashQuote + VIASH_POSITIONAL_ARGS="$VIASH_POSITIONAL_ARGS '$1'" + [[ $1 == -* ]] && ViashWarning $1 looks like a parameter but is not a defined parameter and will instead be treated as a positional argument. Use "--help" to get more information on the parameters. + shift # past argument + ;; + esac +done + +# parse positional parameters +eval set -- $VIASH_POSITIONAL_ARGS + + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + VIASH_ENGINE_TYPE='native' +elif [ "$VIASH_ENGINE_ID" == "docker" ] ; then + VIASH_ENGINE_TYPE='docker' +else + ViashError "Engine '$VIASH_ENGINE_ID' is not recognized. Options are: docker, native." + exit 1 +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # check if docker is installed properly + ViashDockerInstallationCheck + + # determine docker image id + if [[ "$VIASH_ENGINE_ID" == 'docker' ]]; then + VIASH_DOCKER_IMAGE_ID='images.viash-hub.com/vsh/biobox/rseqc/rseqc_inferexperiment:main' + fi + + # print dockerfile + if [ "$VIASH_MODE" == "dockerfile" ]; then + ViashDockerfile "$VIASH_ENGINE_ID" + exit 0 + + elif [ "$VIASH_MODE" == "docker_image_id" ]; then + echo "$VIASH_DOCKER_IMAGE_ID" + exit 0 + + # enter docker container + elif [[ "$VIASH_MODE" == "debug" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} -v '$(pwd)':/pwd --workdir /pwd -t $VIASH_DOCKER_IMAGE_ID" + ViashNotice "+ $VIASH_CMD" + eval $VIASH_CMD + exit + + # build docker image + elif [ "$VIASH_MODE" == "setup" ]; then + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" "$VIASH_SETUP_STRATEGY" + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' + exit 0 + fi + + # check if docker image exists + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" ifneedbepullelsecachedbuild + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' +fi + +# setting computational defaults + +# helper function for parsing memory strings +function ViashMemoryAsBytes { + local memory=`echo "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'` + local memory_regex='^([0-9]+)([kmgtp]i?b?|b)$' + if [[ $memory =~ $memory_regex ]]; then + local number=${memory/[^0-9]*/} + local symbol=${memory/*[0-9]/} + + case $symbol in + b) memory_b=$number ;; + kb|k) memory_b=$(( $number * 1000 )) ;; + mb|m) memory_b=$(( $number * 1000 * 1000 )) ;; + gb|g) memory_b=$(( $number * 1000 * 1000 * 1000 )) ;; + tb|t) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 )) ;; + pb|p) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 * 1000 )) ;; + kib|ki) memory_b=$(( $number * 1024 )) ;; + mib|mi) memory_b=$(( $number * 1024 * 1024 )) ;; + gib|gi) memory_b=$(( $number * 1024 * 1024 * 1024 )) ;; + tib|ti) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 )) ;; + pib|pi) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 * 1024 )) ;; + esac + echo "$memory_b" + fi +} +# compute memory in different units +if [ ! -z ${VIASH_META_MEMORY+x} ]; then + VIASH_META_MEMORY_B=`ViashMemoryAsBytes $VIASH_META_MEMORY` + # do not define other variables if memory_b is an empty string + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_META_MEMORY_KB=$(( ($VIASH_META_MEMORY_B+999) / 1000 )) + VIASH_META_MEMORY_MB=$(( ($VIASH_META_MEMORY_KB+999) / 1000 )) + VIASH_META_MEMORY_GB=$(( ($VIASH_META_MEMORY_MB+999) / 1000 )) + VIASH_META_MEMORY_TB=$(( ($VIASH_META_MEMORY_GB+999) / 1000 )) + VIASH_META_MEMORY_PB=$(( ($VIASH_META_MEMORY_TB+999) / 1000 )) + VIASH_META_MEMORY_KIB=$(( ($VIASH_META_MEMORY_B+1023) / 1024 )) + VIASH_META_MEMORY_MIB=$(( ($VIASH_META_MEMORY_KIB+1023) / 1024 )) + VIASH_META_MEMORY_GIB=$(( ($VIASH_META_MEMORY_MIB+1023) / 1024 )) + VIASH_META_MEMORY_TIB=$(( ($VIASH_META_MEMORY_GIB+1023) / 1024 )) + VIASH_META_MEMORY_PIB=$(( ($VIASH_META_MEMORY_TIB+1023) / 1024 )) + else + # unset memory if string is empty + unset $VIASH_META_MEMORY_B + fi +fi +# unset nproc if string is empty +if [ -z "$VIASH_META_CPUS" ]; then + unset $VIASH_META_CPUS +fi + + +# check whether required parameters exist +if [ -z ${VIASH_PAR_INPUT_FILE+x} ]; then + ViashError '--input_file' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_PAR_REFGENE+x} ]; then + ViashError '--refgene' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_PAR_OUTPUT+x} ]; then + ViashError '--output' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_NAME+x} ]; then + ViashError 'name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_FUNCTIONALITY_NAME+x} ]; then + ViashError 'functionality_name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_RESOURCES_DIR+x} ]; then + ViashError 'resources_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_EXECUTABLE+x} ]; then + ViashError 'executable' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_CONFIG+x} ]; then + ViashError 'config' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_TEMP_DIR+x} ]; then + ViashError 'temp_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi + +# check whether required files exist +if [ ! -z "$VIASH_PAR_INPUT_FILE" ] && [ ! -e "$VIASH_PAR_INPUT_FILE" ]; then + ViashError "Input file '$VIASH_PAR_INPUT_FILE' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_REFGENE" ] && [ ! -e "$VIASH_PAR_REFGENE" ]; then + ViashError "Input file '$VIASH_PAR_REFGENE' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_PAR_SAMPLE_SIZE" ]]; then + if ! [[ "$VIASH_PAR_SAMPLE_SIZE" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--sample_size' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_MAPQ" ]]; then + if ! [[ "$VIASH_PAR_MAPQ" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--mapq' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_CPUS" ]]; then + if ! [[ "$VIASH_META_CPUS" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'cpus' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_B" ]]; then + if ! [[ "$VIASH_META_MEMORY_B" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_b' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi + +# create parent directories of output files, if so desired +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT")" +fi + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + if [ "$VIASH_MODE" == "run" ]; then + VIASH_CMD="bash" + else + ViashError "Engine '$VIASH_ENGINE_ID' does not support mode '$VIASH_MODE'." + exit 1 + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # detect volumes from file arguments + VIASH_CHOWN_VARS=() +if [ ! -z "$VIASH_PAR_INPUT_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_INPUT_FILE")" ) + VIASH_PAR_INPUT_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_INPUT_FILE") +fi +if [ ! -z "$VIASH_PAR_REFGENE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_REFGENE")" ) + VIASH_PAR_REFGENE=$(ViashDockerAutodetectMount "$VIASH_PAR_REFGENE") +fi +if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT")" ) + VIASH_PAR_OUTPUT=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT" ) +fi +if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_RESOURCES_DIR")" ) + VIASH_META_RESOURCES_DIR=$(ViashDockerAutodetectMount "$VIASH_META_RESOURCES_DIR") +fi +if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_EXECUTABLE")" ) + VIASH_META_EXECUTABLE=$(ViashDockerAutodetectMount "$VIASH_META_EXECUTABLE") +fi +if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_CONFIG")" ) + VIASH_META_CONFIG=$(ViashDockerAutodetectMount "$VIASH_META_CONFIG") +fi +if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_TEMP_DIR")" ) + VIASH_META_TEMP_DIR=$(ViashDockerAutodetectMount "$VIASH_META_TEMP_DIR") +fi + + # get unique mounts + VIASH_UNIQUE_MOUNTS=($(for val in "${VIASH_DIRECTORY_MOUNTS[@]}"; do echo "$val"; done | sort -u)) +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # change file ownership + function ViashPerformChown { + if (( ${#VIASH_CHOWN_VARS[@]} )); then + set +e + VIASH_CMD="docker run --entrypoint=bash --rm ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID -c 'chown $(id -u):$(id -g) --silent --recursive ${VIASH_CHOWN_VARS[@]}'" + ViashDebug "+ $VIASH_CMD" + eval $VIASH_CMD + set -e + fi + } + trap ViashPerformChown EXIT +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # helper function for filling in extra docker args + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_DOCKER_RUN_ARGS+=("--memory=${VIASH_META_MEMORY_B}") + fi + if [ ! -z "$VIASH_META_CPUS" ]; then + VIASH_DOCKER_RUN_ARGS+=("--cpus=${VIASH_META_CPUS}") + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID" +fi + + +# set dependency paths + + +ViashDebug "Running command: $(echo $VIASH_CMD)" +cat << VIASHEOF | eval $VIASH_CMD +set -e +tempscript=\$(mktemp "$VIASH_META_TEMP_DIR/viash-run-rseqc_inferexperiment-XXXXXX").sh +function clean_up { + rm "\$tempscript" +} +function interrupt { + echo -e "\nCTRL-C Pressed..." + exit 1 +} +trap clean_up EXIT +trap interrupt INT SIGINT +cat > "\$tempscript" << 'VIASHMAIN' +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_INPUT_FILE+x} ]; then echo "${VIASH_PAR_INPUT_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_input_file='&'#" ; else echo "# par_input_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REFGENE+x} ]; then echo "${VIASH_PAR_REFGENE}" | sed "s#'#'\"'\"'#g;s#.*#par_refgene='&'#" ; else echo "# par_refgene="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\"'\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLE_SIZE+x} ]; then echo "${VIASH_PAR_SAMPLE_SIZE}" | sed "s#'#'\"'\"'#g;s#.*#par_sample_size='&'#" ; else echo "# par_sample_size="; fi ) +$( if [ ! -z ${VIASH_PAR_MAPQ+x} ]; then echo "${VIASH_PAR_MAPQ}" | sed "s#'#'\"'\"'#g;s#.*#par_mapq='&'#" ; else echo "# par_mapq="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\"'\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\"'\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\"'\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\"'\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END +#!/bin/bash + +set -eo pipefail + +infer_experiment.py \\ + -i \$par_input_file \\ + -r \$par_refgene \\ + \${par_sample_size:+-s "\${par_sample_size}"} \\ + \${par_mapq:+-q "\${par_mapq}"} \\ +> \$par_output +VIASHMAIN +bash "\$tempscript" & +wait "\$!" + +VIASHEOF + + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # strip viash automount from file paths + + if [ ! -z "$VIASH_PAR_INPUT_FILE" ]; then + VIASH_PAR_INPUT_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_INPUT_FILE") + fi + if [ ! -z "$VIASH_PAR_REFGENE" ]; then + VIASH_PAR_REFGENE=$(ViashDockerStripAutomount "$VIASH_PAR_REFGENE") + fi + if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_PAR_OUTPUT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT") + fi + if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_META_RESOURCES_DIR=$(ViashDockerStripAutomount "$VIASH_META_RESOURCES_DIR") + fi + if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_META_EXECUTABLE=$(ViashDockerStripAutomount "$VIASH_META_EXECUTABLE") + fi + if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_META_CONFIG=$(ViashDockerStripAutomount "$VIASH_META_CONFIG") + fi + if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_META_TEMP_DIR=$(ViashDockerStripAutomount "$VIASH_META_TEMP_DIR") + fi +fi + + +# check whether required files exist +if [ ! -z "$VIASH_PAR_OUTPUT" ] && [ ! -e "$VIASH_PAR_OUTPUT" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT' does not exist." + exit 1 +fi + + +exit 0 diff --git a/target/executable/rseqc/rseqc_inner_distance/.config.vsh.yaml b/target/executable/rseqc/rseqc_inner_distance/.config.vsh.yaml new file mode 100644 index 00000000..bc547d2e --- /dev/null +++ b/target/executable/rseqc/rseqc_inner_distance/.config.vsh.yaml @@ -0,0 +1,321 @@ +name: "rseqc_inner_distance" +namespace: "rseqc" +version: "main" +authors: +- name: "Emma Rousseau" + roles: + - "author" + - "maintainer" + info: + links: + email: "emma@data-intuitive.com" + github: "emmarousseau" + linkedin: "emmarousseau1" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Bioinformatician" +argument_groups: +- name: "Input" + arguments: + - type: "file" + name: "--input_file" + alternatives: + - "-i" + description: "input alignment file in BAM or SAM format" + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--refgene" + alternatives: + - "-r" + description: "Reference gene model in bed format" + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--sample_size" + alternatives: + - "-k" + description: "Numer of reads sampled from SAM/BAM file, default = 1000000." + info: null + example: + - 1000000 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--mapq" + alternatives: + - "-q" + description: "Minimum mapping quality (phred scaled) to determine uniquely mapped\ + \ reads, default=30." + info: null + example: + - 30 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--lower_bound" + alternatives: + - "-l" + description: "Lower bound of inner distance (bp). This option is used for ploting\ + \ histograme, default=-250." + info: null + example: + - -250 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--upper_bound" + alternatives: + - "-u" + description: "Upper bound of inner distance (bp). This option is used for ploting\ + \ histograme, default=250." + info: null + example: + - 250 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--step" + alternatives: + - "-s" + description: "Step size (bp) of histograme. This option is used for plotting histogram,\ + \ default=5." + info: null + example: + - 5 + required: false + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Output" + arguments: + - type: "string" + name: "--output_prefix" + alternatives: + - "-o" + description: "Rrefix of output files." + info: null + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_stats" + description: "output file (txt) with summary statistics of inner distances of\ + \ paired reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_dist" + description: "output file (txt) with inner distances of all paired reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_freq" + description: "output file (txt) with frequencies of inner distances of all paired\ + \ reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_plot" + description: "output file (pdf) with histogram plot of of inner distances of all\ + \ paired reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_plot_r" + description: "output file (R) with script of histogram plot of of inner distances\ + \ of all paired reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Calculate inner distance between read pairs.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +license: "GPL-3.0" +references: + doi: + - "10.1093/bioinformatics/bts356" +links: + repository: "https://github.com/MonashBioinformaticsPlatform/RSeQC" + homepage: "https://rseqc.sourceforge.net/" + documentation: "https://rseqc.sourceforge.net/#inner-distance-py" + issue_tracker: "https://github.com/MonashBioinformaticsPlatform/RSeQC/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "python:3.10" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "r-base" + interactive: false + - type: "python" + user: false + packages: + - "RSeQC" + upgrade: true + - type: "docker" + run: + - "echo \"RSeQC - inner_distance.py: $(inner_distance.py --version | cut -d' '\ + \ -f2)\" > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/rseqc/rseqc_inner_distance/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/rseqc/rseqc_inner_distance" + executable: "target/executable/rseqc/rseqc_inner_distance/rseqc_inner_distance" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/executable/rseqc/rseqc_inner_distance/rseqc_inner_distance b/target/executable/rseqc/rseqc_inner_distance/rseqc_inner_distance new file mode 100755 index 00000000..098d90bc --- /dev/null +++ b/target/executable/rseqc/rseqc_inner_distance/rseqc_inner_distance @@ -0,0 +1,1449 @@ +#!/usr/bin/env bash + +# rseqc_inner_distance main +# +# This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +# work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +# Intuitive. +# +# The component may contain files which fall under a different license. The +# authors of this component should specify the license in the header of such +# files, or include a separate license file detailing the licenses of all included +# files. +# +# Component authors: +# * Emma Rousseau (author, maintainer) + +set -e + +if [ -z "$VIASH_TEMP" ]; then + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMP} + VIASH_TEMP=${VIASH_TEMP:-$TMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TMP} + VIASH_TEMP=${VIASH_TEMP:-$TEMPDIR} + VIASH_TEMP=${VIASH_TEMP:-$TEMP} + VIASH_TEMP=${VIASH_TEMP:-/tmp} +fi + +# define helper functions +# ViashQuote: put quotes around non flag values +# $1 : unquoted string +# return : possibly quoted string +# examples: +# ViashQuote --foo # returns --foo +# ViashQuote bar # returns 'bar' +# Viashquote --foo=bar # returns --foo='bar' +function ViashQuote { + if [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+=.+$ ]]; then + echo "$1" | sed "s#=\(.*\)#='\1'#" + elif [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+$ ]]; then + echo "$1" + else + echo "'$1'" + fi +} +# ViashRemoveFlags: Remove leading flag +# $1 : string with a possible leading flag +# return : string without possible leading flag +# examples: +# ViashRemoveFlags --foo=bar # returns bar +function ViashRemoveFlags { + echo "$1" | sed 's/^--*[a-zA-Z0-9_\-]*=//' +} +# ViashSourceDir: return the path of a bash file, following symlinks +# usage : ViashSourceDir ${BASH_SOURCE[0]} +# $1 : Should always be set to ${BASH_SOURCE[0]} +# returns : The absolute path of the bash file +function ViashSourceDir { + local source="$1" + while [ -h "$source" ]; do + local dir="$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd )" + source="$(readlink "$source")" + [[ $source != /* ]] && source="$dir/$source" + done + cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd +} +# ViashFindTargetDir: return the path of the '.build.yaml' file, following symlinks +# usage : ViashFindTargetDir 'ScriptPath' +# $1 : The location from where to start the upward search +# returns : The absolute path of the '.build.yaml' file +function ViashFindTargetDir { + local source="$1" + while [[ "$source" != "" && ! -e "$source/.build.yaml" ]]; do + source=${source%/*} + done + echo $source +} +# see https://en.wikipedia.org/wiki/Syslog#Severity_level +VIASH_LOGCODE_EMERGENCY=0 +VIASH_LOGCODE_ALERT=1 +VIASH_LOGCODE_CRITICAL=2 +VIASH_LOGCODE_ERROR=3 +VIASH_LOGCODE_WARNING=4 +VIASH_LOGCODE_NOTICE=5 +VIASH_LOGCODE_INFO=6 +VIASH_LOGCODE_DEBUG=7 +VIASH_VERBOSITY=$VIASH_LOGCODE_NOTICE + +# ViashLog: Log events depending on the verbosity level +# usage: ViashLog 1 alert Oh no something went wrong! +# $1: required verbosity level +# $2: display tag +# $3+: messages to display +# stdout: Your input, prepended by '[$2] '. +function ViashLog { + local required_level="$1" + local display_tag="$2" + shift 2 + if [ $VIASH_VERBOSITY -ge $required_level ]; then + >&2 echo "[$display_tag]" "$@" + fi +} + +# ViashEmergency: log events when the system is unstable +# usage: ViashEmergency Oh no something went wrong. +# stdout: Your input, prepended by '[emergency] '. +function ViashEmergency { + ViashLog $VIASH_LOGCODE_EMERGENCY emergency "$@" +} + +# ViashAlert: log events when actions must be taken immediately (e.g. corrupted system database) +# usage: ViashAlert Oh no something went wrong. +# stdout: Your input, prepended by '[alert] '. +function ViashAlert { + ViashLog $VIASH_LOGCODE_ALERT alert "$@" +} + +# ViashCritical: log events when a critical condition occurs +# usage: ViashCritical Oh no something went wrong. +# stdout: Your input, prepended by '[critical] '. +function ViashCritical { + ViashLog $VIASH_LOGCODE_CRITICAL critical "$@" +} + +# ViashError: log events when an error condition occurs +# usage: ViashError Oh no something went wrong. +# stdout: Your input, prepended by '[error] '. +function ViashError { + ViashLog $VIASH_LOGCODE_ERROR error "$@" +} + +# ViashWarning: log potentially abnormal events +# usage: ViashWarning Something may have gone wrong. +# stdout: Your input, prepended by '[warning] '. +function ViashWarning { + ViashLog $VIASH_LOGCODE_WARNING warning "$@" +} + +# ViashNotice: log significant but normal events +# usage: ViashNotice This just happened. +# stdout: Your input, prepended by '[notice] '. +function ViashNotice { + ViashLog $VIASH_LOGCODE_NOTICE notice "$@" +} + +# ViashInfo: log normal events +# usage: ViashInfo This just happened. +# stdout: Your input, prepended by '[info] '. +function ViashInfo { + ViashLog $VIASH_LOGCODE_INFO info "$@" +} + +# ViashDebug: log all events, for debugging purposes +# usage: ViashDebug This just happened. +# stdout: Your input, prepended by '[debug] '. +function ViashDebug { + ViashLog $VIASH_LOGCODE_DEBUG debug "$@" +} + +# find source folder of this component +VIASH_META_RESOURCES_DIR=`ViashSourceDir ${BASH_SOURCE[0]}` + +# find the root of the built components & dependencies +VIASH_TARGET_DIR=`ViashFindTargetDir $VIASH_META_RESOURCES_DIR` + +# define meta fields +VIASH_META_NAME="rseqc_inner_distance" +VIASH_META_FUNCTIONALITY_NAME="rseqc_inner_distance" +VIASH_META_EXECUTABLE="$VIASH_META_RESOURCES_DIR/$VIASH_META_NAME" +VIASH_META_CONFIG="$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" +VIASH_META_TEMP_DIR="$VIASH_TEMP" + + +# ViashHelp: Display helpful explanation about this executable +function ViashHelp { + echo "rseqc_inner_distance main" + echo "" + echo "Calculate inner distance between read pairs." + echo "" + echo "Input:" + echo " -i, --input_file" + echo " type: file, required parameter, file must exist" + echo " input alignment file in BAM or SAM format" + echo "" + echo " -r, --refgene" + echo " type: file, required parameter, file must exist" + echo " Reference gene model in bed format" + echo "" + echo " -k, --sample_size" + echo " type: integer" + echo " example: 1000000" + echo " Numer of reads sampled from SAM/BAM file, default = 1000000." + echo "" + echo " -q, --mapq" + echo " type: integer" + echo " example: 30" + echo " Minimum mapping quality (phred scaled) to determine uniquely mapped" + echo " reads, default=30." + echo "" + echo " -l, --lower_bound" + echo " type: integer" + echo " example: -250" + echo " Lower bound of inner distance (bp). This option is used for ploting" + echo " histograme, default=-250." + echo "" + echo " -u, --upper_bound" + echo " type: integer" + echo " example: 250" + echo " Upper bound of inner distance (bp). This option is used for ploting" + echo " histograme, default=250." + echo "" + echo " -s, --step" + echo " type: integer" + echo " example: 5" + echo " Step size (bp) of histograme. This option is used for plotting" + echo " histogram, default=5." + echo "" + echo "Output:" + echo " -o, --output_prefix" + echo " type: string, required parameter" + echo " Rrefix of output files." + echo "" + echo " --output_stats" + echo " type: file, output, file must exist" + echo " output file (txt) with summary statistics of inner distances of paired" + echo " reads" + echo "" + echo " --output_dist" + echo " type: file, output, file must exist" + echo " output file (txt) with inner distances of all paired reads" + echo "" + echo " --output_freq" + echo " type: file, output, file must exist" + echo " output file (txt) with frequencies of inner distances of all paired" + echo " reads" + echo "" + echo " --output_plot" + echo " type: file, output, file must exist" + echo " output file (pdf) with histogram plot of of inner distances of all" + echo " paired reads" + echo "" + echo " --output_plot_r" + echo " type: file, output, file must exist" + echo " output file (R) with script of histogram plot of of inner distances of" + echo " all paired reads" +} + +# initialise variables +VIASH_MODE='run' +VIASH_ENGINE_ID='docker' + +######## Helper functions for setting up Docker images for viash ######## +# expects: ViashDockerBuild + +# ViashDockerInstallationCheck: check whether Docker is installed correctly +# +# examples: +# ViashDockerInstallationCheck +function ViashDockerInstallationCheck { + ViashDebug "Checking whether Docker is installed" + if [ ! command -v docker &> /dev/null ]; then + ViashCritical "Docker doesn't seem to be installed. See 'https://docs.docker.com/get-docker/' for instructions." + exit 1 + fi + + ViashDebug "Checking whether the Docker daemon is running" + local save=$-; set +e + local docker_version=$(docker version --format '{{.Client.APIVersion}}' 2> /dev/null) + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashCritical "Docker daemon does not seem to be running. Try one of the following:" + ViashCritical "- Try running 'dockerd' in the command line" + ViashCritical "- See https://docs.docker.com/config/daemon/" + exit 1 + fi +} + +# ViashDockerRemoteTagCheck: check whether a Docker image is available +# on a remote. Assumes `docker login` has been performed, if relevant. +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerRemoteTagCheck python:latest +# echo $? # returns '0' +# ViashDockerRemoteTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerRemoteTagCheck { + docker manifest inspect $1 > /dev/null 2> /dev/null +} + +# ViashDockerLocalTagCheck: check whether a Docker image is available locally +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# docker pull python:latest +# ViashDockerLocalTagCheck python:latest +# echo $? # returns '0' +# ViashDockerLocalTagCheck sdaizudceahifu +# echo $? # returns '1' +function ViashDockerLocalTagCheck { + [ -n "$(docker images -q $1)" ] +} + +# ViashDockerPull: pull a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPull python:latest +# echo $? # returns '0' +# ViashDockerPull sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPull { + ViashNotice "Checking if Docker image is available at '$1'" + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker pull $1 && return 0 || return 1 + else + local save=$-; set +e + docker pull $1 2> /dev/null > /dev/null + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashWarning "Could not pull from '$1'. Docker image doesn't exist or is not accessible." + fi + return $out + fi +} + +# ViashDockerPush: push a Docker image +# +# $1 : image identifier with format `[registry/]image[:tag]` +# exit code $? : whether or not the image was found +# examples: +# ViashDockerPush python:latest +# echo $? # returns '0' +# ViashDockerPush sdaizudceahifu +# echo $? # returns '1' +function ViashDockerPush { + ViashNotice "Pushing image to '$1'" + local save=$-; set +e + local out + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + docker push $1 + out=$? + else + docker push $1 2> /dev/null > /dev/null + out=$? + fi + [[ $save =~ e ]] && set -e + if [ $out -eq 0 ]; then + ViashNotice "Container '$1' push succeeded." + else + ViashError "Container '$1' push errored. You might not be logged in or have the necessary permissions." + fi + return $out +} + +# ViashDockerPullElseBuild: pull a Docker image, else build it +# +# $1 : image identifier with format `[registry/]image[:tag]` +# ViashDockerBuild : a Bash function which builds a docker image, takes image identifier as argument. +# examples: +# ViashDockerPullElseBuild mynewcomponent +function ViashDockerPullElseBuild { + local save=$-; set +e + ViashDockerPull $1 + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashDockerBuild $@ + fi +} + +# ViashDockerSetup: create a Docker image, according to specified docker setup strategy +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $2 : docker setup strategy, see DockerSetupStrategy.scala +# examples: +# ViashDockerSetup mynewcomponent alwaysbuild +function ViashDockerSetup { + local image_id="$1" + local setup_strategy="$2" + if [ "$setup_strategy" == "alwaysbuild" -o "$setup_strategy" == "build" -o "$setup_strategy" == "b" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspull" -o "$setup_strategy" == "pull" -o "$setup_strategy" == "p" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "alwayspullelsebuild" -o "$setup_strategy" == "pullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayspullelsecachedbuild" -o "$setup_strategy" == "pullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "alwayscachedbuild" -o "$setup_strategy" == "cachedbuild" -o "$setup_strategy" == "cb" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [[ "$setup_strategy" =~ ^ifneedbe ]]; then + local save=$-; set +e + ViashDockerLocalTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashInfo "Image $image_id already exists" + elif [ "$setup_strategy" == "ifneedbebuild" ]; then + ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbecachedbuild" ]; then + ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepull" ]; then + ViashDockerPull $image_id + elif [ "$setup_strategy" == "ifneedbepullelsebuild" ]; then + ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id") + elif [ "$setup_strategy" == "ifneedbepullelsecachedbuild" ]; then + ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id") + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi + elif [ "$setup_strategy" == "push" -o "$setup_strategy" == "forcepush" -o "$setup_strategy" == "alwayspush" ]; then + ViashDockerPush "$image_id" + elif [ "$setup_strategy" == "pushifnotpresent" -o "$setup_strategy" == "gentlepush" -o "$setup_strategy" == "maybepush" ]; then + local save=$-; set +e + ViashDockerRemoteTagCheck $image_id + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -eq 0 ]; then + ViashNotice "Container '$image_id' exists, doing nothing." + else + ViashNotice "Container '$image_id' does not yet exist." + ViashDockerPush "$image_id" + fi + elif [ "$setup_strategy" == "donothing" -o "$setup_strategy" == "meh" ]; then + ViashNotice "Skipping setup." + else + ViashError "Unrecognised Docker strategy: $setup_strategy" + exit 1 + fi +} + +# ViashDockerCheckCommands: Check whether a docker container has the required commands +# +# $1 : image identifier with format `[registry/]image[:tag]` +# $@ : commands to verify being present +# examples: +# ViashDockerCheckCommands bash:4.0 bash ps foo +function ViashDockerCheckCommands { + local image_id="$1" + shift 1 + local commands="$@" + local save=$-; set +e + local missing # mark 'missing' as local in advance, otherwise the exit code of the command will be missing and always be '0' + missing=$(docker run --rm --entrypoint=sh "$image_id" -c "for command in $commands; do command -v \$command >/dev/null 2>&1; if [ \$? -ne 0 ]; then echo \$command; exit 1; fi; done") + local outCheck=$? + [[ $save =~ e ]] && set -e + if [ $outCheck -ne 0 ]; then + ViashError "Docker container '$image_id' does not contain command '$missing'." + exit 1 + fi +} + +# ViashDockerBuild: build a docker image +# $1 : image identifier with format `[registry/]image[:tag]` +# $... : additional arguments to pass to docker build +# $VIASH_META_TEMP_DIR : temporary directory to store dockerfile & optional resources in +# $VIASH_META_NAME : name of the component +# $VIASH_META_RESOURCES_DIR : directory containing the resources +# $VIASH_VERBOSITY : verbosity level +# exit code $? : whether or not the image was built successfully +function ViashDockerBuild { + local image_id="$1" + shift 1 + + # create temporary directory to store dockerfile & optional resources in + local tmpdir=$(mktemp -d "$VIASH_META_TEMP_DIR/dockerbuild-$VIASH_META_NAME-XXXXXX") + local dockerfile="$tmpdir/Dockerfile" + function clean_up { + rm -rf "$tmpdir" + } + trap clean_up EXIT + + # store dockerfile and resources + ViashDockerfile "$VIASH_ENGINE_ID" > "$dockerfile" + + # generate the build command + local docker_build_cmd="docker build -t '$image_id' $@ '$VIASH_META_RESOURCES_DIR' -f '$dockerfile'" + + # build the container + ViashNotice "Building container '$image_id' with Dockerfile" + ViashInfo "$docker_build_cmd" + local save=$-; set +e + if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then + eval $docker_build_cmd + else + eval $docker_build_cmd &> "$tmpdir/docker_build.log" + fi + + # check exit code + local out=$? + [[ $save =~ e ]] && set -e + if [ $out -ne 0 ]; then + ViashError "Error occurred while building container '$image_id'" + if [ $VIASH_VERBOSITY -lt $VIASH_LOGCODE_INFO ]; then + ViashError "Transcript: --------------------------------" + cat "$tmpdir/docker_build.log" + ViashError "End of transcript --------------------------" + fi + exit 1 + fi +} + +######## End of helper functions for setting up Docker images for viash ######## + +# ViashDockerFile: print the dockerfile to stdout +# $1 : engine identifier +# return : dockerfile required to run this component +# examples: +# ViashDockerFile +function ViashDockerfile { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + cat << 'VIASHDOCKER' +FROM python:3.10 +ENTRYPOINT [] +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y r-base && \ + rm -rf /var/lib/apt/lists/* + +RUN pip install --upgrade pip && \ + pip install --upgrade --no-cache-dir "RSeQC" + +RUN echo "RSeQC - inner_distance.py: $(inner_distance.py --version | cut -d' ' -f2)" > /var/software_versions.txt + +LABEL org.opencontainers.image.authors="Emma Rousseau" +LABEL org.opencontainers.image.description="Companion container for running component rseqc rseqc_inner_distance" +LABEL org.opencontainers.image.created="2024-10-26T18:44:06Z" +LABEL org.opencontainers.image.source="https://github.com/MonashBioinformaticsPlatform/RSeQC" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" +LABEL org.opencontainers.image.version="main" + +VIASHDOCKER + fi +} + +# ViashDockerBuildArgs: return the arguments to pass to docker build +# $1 : engine identifier +# return : arguments to pass to docker build +function ViashDockerBuildArgs { + local engine_id="$1" + + if [[ "$engine_id" == "docker" ]]; then + echo "" + fi +} + +# ViashAbsolutePath: generate absolute path from relative path +# borrowed from https://stackoverflow.com/a/21951256 +# $1 : relative filename +# return : absolute path +# examples: +# ViashAbsolutePath some_file.txt # returns /path/to/some_file.txt +# ViashAbsolutePath /foo/bar/.. # returns /foo +function ViashAbsolutePath { + local thePath + local parr + local outp + local len + if [[ ! "$1" =~ ^/ ]]; then + thePath="$PWD/$1" + else + thePath="$1" + fi + echo "$thePath" | ( + IFS=/ + read -a parr + declare -a outp + for i in "${parr[@]}"; do + case "$i" in + ''|.) continue ;; + ..) + len=${#outp[@]} + if ((len==0)); then + continue + else + unset outp[$((len-1))] + fi + ;; + *) + len=${#outp[@]} + outp[$len]="$i" + ;; + esac + done + echo /"${outp[*]}" + ) +} +# ViashDockerAutodetectMount: auto configuring docker mounts from parameters +# $1 : The parameter value +# returns : New parameter +# $VIASH_DIRECTORY_MOUNTS : Added another parameter to be passed to docker +# $VIASH_DOCKER_AUTOMOUNT_PREFIX : The prefix to be used for the automounts +# examples: +# ViashDockerAutodetectMount /path/to/bar # returns '/viash_automount/path/to/bar' +# ViashDockerAutodetectMountArg /path/to/bar # returns '--volume="/path/to:/viash_automount/path/to"' +function ViashDockerAutodetectMount { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + if [ -z "$base_name" ]; then + echo "$mount_target" + else + echo "$mount_target/$base_name" + fi +} +function ViashDockerAutodetectMountArg { + local abs_path=$(ViashAbsolutePath "$1") + local mount_source + local base_name + if [ -d "$abs_path" ]; then + mount_source="$abs_path" + base_name="" + else + mount_source=`dirname "$abs_path"` + base_name=`basename "$abs_path"` + fi + local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source" + ViashDebug "ViashDockerAutodetectMountArg $1 -> $mount_source -> $mount_target" + echo "--volume=\"$mount_source:$mount_target\"" +} +function ViashDockerStripAutomount { + local abs_path=$(ViashAbsolutePath "$1") + echo "${abs_path#$VIASH_DOCKER_AUTOMOUNT_PREFIX}" +} +# initialise variables +VIASH_DIRECTORY_MOUNTS=() + +# configure default docker automount prefix if it is unset +if [ -z "${VIASH_DOCKER_AUTOMOUNT_PREFIX+x}" ]; then + VIASH_DOCKER_AUTOMOUNT_PREFIX="/viash_automount" +fi + +# initialise docker variables +VIASH_DOCKER_RUN_ARGS=(-i --rm) + +# initialise array +VIASH_POSITIONAL_ARGS='' + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + ViashHelp + exit + ;; + ---v|---verbose) + let "VIASH_VERBOSITY=VIASH_VERBOSITY+1" + shift 1 + ;; + ---verbosity) + VIASH_VERBOSITY="$2" + shift 2 + ;; + ---verbosity=*) + VIASH_VERBOSITY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + --version) + echo "rseqc_inner_distance main" + exit + ;; + --input_file) + [ -n "$VIASH_PAR_INPUT_FILE" ] && ViashError Bad arguments for option \'--input_file\': \'$VIASH_PAR_INPUT_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --input_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --input_file=*) + [ -n "$VIASH_PAR_INPUT_FILE" ] && ViashError Bad arguments for option \'--input_file=*\': \'$VIASH_PAR_INPUT_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -i) + [ -n "$VIASH_PAR_INPUT_FILE" ] && ViashError Bad arguments for option \'-i\': \'$VIASH_PAR_INPUT_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INPUT_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -i. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --refgene) + [ -n "$VIASH_PAR_REFGENE" ] && ViashError Bad arguments for option \'--refgene\': \'$VIASH_PAR_REFGENE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REFGENE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --refgene. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --refgene=*) + [ -n "$VIASH_PAR_REFGENE" ] && ViashError Bad arguments for option \'--refgene=*\': \'$VIASH_PAR_REFGENE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REFGENE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -r) + [ -n "$VIASH_PAR_REFGENE" ] && ViashError Bad arguments for option \'-r\': \'$VIASH_PAR_REFGENE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REFGENE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -r. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --sample_size) + [ -n "$VIASH_PAR_SAMPLE_SIZE" ] && ViashError Bad arguments for option \'--sample_size\': \'$VIASH_PAR_SAMPLE_SIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLE_SIZE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --sample_size. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --sample_size=*) + [ -n "$VIASH_PAR_SAMPLE_SIZE" ] && ViashError Bad arguments for option \'--sample_size=*\': \'$VIASH_PAR_SAMPLE_SIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLE_SIZE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -k) + [ -n "$VIASH_PAR_SAMPLE_SIZE" ] && ViashError Bad arguments for option \'-k\': \'$VIASH_PAR_SAMPLE_SIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLE_SIZE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -k. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --mapq) + [ -n "$VIASH_PAR_MAPQ" ] && ViashError Bad arguments for option \'--mapq\': \'$VIASH_PAR_MAPQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MAPQ="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --mapq. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --mapq=*) + [ -n "$VIASH_PAR_MAPQ" ] && ViashError Bad arguments for option \'--mapq=*\': \'$VIASH_PAR_MAPQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MAPQ=$(ViashRemoveFlags "$1") + shift 1 + ;; + -q) + [ -n "$VIASH_PAR_MAPQ" ] && ViashError Bad arguments for option \'-q\': \'$VIASH_PAR_MAPQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MAPQ="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -q. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --lower_bound) + [ -n "$VIASH_PAR_LOWER_BOUND" ] && ViashError Bad arguments for option \'--lower_bound\': \'$VIASH_PAR_LOWER_BOUND\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_LOWER_BOUND="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --lower_bound. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --lower_bound=*) + [ -n "$VIASH_PAR_LOWER_BOUND" ] && ViashError Bad arguments for option \'--lower_bound=*\': \'$VIASH_PAR_LOWER_BOUND\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_LOWER_BOUND=$(ViashRemoveFlags "$1") + shift 1 + ;; + -l) + [ -n "$VIASH_PAR_LOWER_BOUND" ] && ViashError Bad arguments for option \'-l\': \'$VIASH_PAR_LOWER_BOUND\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_LOWER_BOUND="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -l. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --upper_bound) + [ -n "$VIASH_PAR_UPPER_BOUND" ] && ViashError Bad arguments for option \'--upper_bound\': \'$VIASH_PAR_UPPER_BOUND\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_UPPER_BOUND="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --upper_bound. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --upper_bound=*) + [ -n "$VIASH_PAR_UPPER_BOUND" ] && ViashError Bad arguments for option \'--upper_bound=*\': \'$VIASH_PAR_UPPER_BOUND\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_UPPER_BOUND=$(ViashRemoveFlags "$1") + shift 1 + ;; + -u) + [ -n "$VIASH_PAR_UPPER_BOUND" ] && ViashError Bad arguments for option \'-u\': \'$VIASH_PAR_UPPER_BOUND\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_UPPER_BOUND="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -u. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --step) + [ -n "$VIASH_PAR_STEP" ] && ViashError Bad arguments for option \'--step\': \'$VIASH_PAR_STEP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_STEP="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --step. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --step=*) + [ -n "$VIASH_PAR_STEP" ] && ViashError Bad arguments for option \'--step=*\': \'$VIASH_PAR_STEP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_STEP=$(ViashRemoveFlags "$1") + shift 1 + ;; + -s) + [ -n "$VIASH_PAR_STEP" ] && ViashError Bad arguments for option \'-s\': \'$VIASH_PAR_STEP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_STEP="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -s. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_prefix) + [ -n "$VIASH_PAR_OUTPUT_PREFIX" ] && ViashError Bad arguments for option \'--output_prefix\': \'$VIASH_PAR_OUTPUT_PREFIX\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_PREFIX="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_prefix. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_prefix=*) + [ -n "$VIASH_PAR_OUTPUT_PREFIX" ] && ViashError Bad arguments for option \'--output_prefix=*\': \'$VIASH_PAR_OUTPUT_PREFIX\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_PREFIX=$(ViashRemoveFlags "$1") + shift 1 + ;; + -o) + [ -n "$VIASH_PAR_OUTPUT_PREFIX" ] && ViashError Bad arguments for option \'-o\': \'$VIASH_PAR_OUTPUT_PREFIX\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_PREFIX="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -o. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_stats) + [ -n "$VIASH_PAR_OUTPUT_STATS" ] && ViashError Bad arguments for option \'--output_stats\': \'$VIASH_PAR_OUTPUT_STATS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_STATS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_stats. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_stats=*) + [ -n "$VIASH_PAR_OUTPUT_STATS" ] && ViashError Bad arguments for option \'--output_stats=*\': \'$VIASH_PAR_OUTPUT_STATS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_STATS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --output_dist) + [ -n "$VIASH_PAR_OUTPUT_DIST" ] && ViashError Bad arguments for option \'--output_dist\': \'$VIASH_PAR_OUTPUT_DIST\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_DIST="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_dist. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_dist=*) + [ -n "$VIASH_PAR_OUTPUT_DIST" ] && ViashError Bad arguments for option \'--output_dist=*\': \'$VIASH_PAR_OUTPUT_DIST\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_DIST=$(ViashRemoveFlags "$1") + shift 1 + ;; + --output_freq) + [ -n "$VIASH_PAR_OUTPUT_FREQ" ] && ViashError Bad arguments for option \'--output_freq\': \'$VIASH_PAR_OUTPUT_FREQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_FREQ="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_freq. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_freq=*) + [ -n "$VIASH_PAR_OUTPUT_FREQ" ] && ViashError Bad arguments for option \'--output_freq=*\': \'$VIASH_PAR_OUTPUT_FREQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_FREQ=$(ViashRemoveFlags "$1") + shift 1 + ;; + --output_plot) + [ -n "$VIASH_PAR_OUTPUT_PLOT" ] && ViashError Bad arguments for option \'--output_plot\': \'$VIASH_PAR_OUTPUT_PLOT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_PLOT="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_plot. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_plot=*) + [ -n "$VIASH_PAR_OUTPUT_PLOT" ] && ViashError Bad arguments for option \'--output_plot=*\': \'$VIASH_PAR_OUTPUT_PLOT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_PLOT=$(ViashRemoveFlags "$1") + shift 1 + ;; + --output_plot_r) + [ -n "$VIASH_PAR_OUTPUT_PLOT_R" ] && ViashError Bad arguments for option \'--output_plot_r\': \'$VIASH_PAR_OUTPUT_PLOT_R\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_PLOT_R="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_plot_r. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_plot_r=*) + [ -n "$VIASH_PAR_OUTPUT_PLOT_R" ] && ViashError Bad arguments for option \'--output_plot_r=*\': \'$VIASH_PAR_OUTPUT_PLOT_R\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_PLOT_R=$(ViashRemoveFlags "$1") + shift 1 + ;; + ---engine) + VIASH_ENGINE_ID="$2" + shift 2 + ;; + ---engine=*) + VIASH_ENGINE_ID="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---setup) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$2" + shift 2 + ;; + ---setup=*) + VIASH_MODE='setup' + VIASH_SETUP_STRATEGY="$(ViashRemoveFlags "$1")" + shift 1 + ;; + ---dockerfile) + VIASH_MODE='dockerfile' + shift 1 + ;; + ---docker_run_args) + VIASH_DOCKER_RUN_ARGS+=("$2") + shift 2 + ;; + ---docker_run_args=*) + VIASH_DOCKER_RUN_ARGS+=("$(ViashRemoveFlags "$1")") + shift 1 + ;; + ---docker_image_id) + VIASH_MODE='docker_image_id' + shift 1 + ;; + ---debug) + VIASH_MODE='debug' + shift 1 + ;; + ---cpus) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---cpus. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---cpus=*) + [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus=*\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_CPUS=$(ViashRemoveFlags "$1") + shift 1 + ;; + ---memory) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to ---memory. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + ---memory=*) + [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory=*\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_META_MEMORY=$(ViashRemoveFlags "$1") + shift 1 + ;; + *) # positional arg or unknown option + # since the positional args will be eval'd, can we always quote, instead of using ViashQuote + VIASH_POSITIONAL_ARGS="$VIASH_POSITIONAL_ARGS '$1'" + [[ $1 == -* ]] && ViashWarning $1 looks like a parameter but is not a defined parameter and will instead be treated as a positional argument. Use "--help" to get more information on the parameters. + shift # past argument + ;; + esac +done + +# parse positional parameters +eval set -- $VIASH_POSITIONAL_ARGS + + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + VIASH_ENGINE_TYPE='native' +elif [ "$VIASH_ENGINE_ID" == "docker" ] ; then + VIASH_ENGINE_TYPE='docker' +else + ViashError "Engine '$VIASH_ENGINE_ID' is not recognized. Options are: docker, native." + exit 1 +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # check if docker is installed properly + ViashDockerInstallationCheck + + # determine docker image id + if [[ "$VIASH_ENGINE_ID" == 'docker' ]]; then + VIASH_DOCKER_IMAGE_ID='images.viash-hub.com/vsh/biobox/rseqc/rseqc_inner_distance:main' + fi + + # print dockerfile + if [ "$VIASH_MODE" == "dockerfile" ]; then + ViashDockerfile "$VIASH_ENGINE_ID" + exit 0 + + elif [ "$VIASH_MODE" == "docker_image_id" ]; then + echo "$VIASH_DOCKER_IMAGE_ID" + exit 0 + + # enter docker container + elif [[ "$VIASH_MODE" == "debug" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} -v '$(pwd)':/pwd --workdir /pwd -t $VIASH_DOCKER_IMAGE_ID" + ViashNotice "+ $VIASH_CMD" + eval $VIASH_CMD + exit + + # build docker image + elif [ "$VIASH_MODE" == "setup" ]; then + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" "$VIASH_SETUP_STRATEGY" + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' + exit 0 + fi + + # check if docker image exists + ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" ifneedbepullelsecachedbuild + ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash' +fi + +# setting computational defaults + +# helper function for parsing memory strings +function ViashMemoryAsBytes { + local memory=`echo "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'` + local memory_regex='^([0-9]+)([kmgtp]i?b?|b)$' + if [[ $memory =~ $memory_regex ]]; then + local number=${memory/[^0-9]*/} + local symbol=${memory/*[0-9]/} + + case $symbol in + b) memory_b=$number ;; + kb|k) memory_b=$(( $number * 1000 )) ;; + mb|m) memory_b=$(( $number * 1000 * 1000 )) ;; + gb|g) memory_b=$(( $number * 1000 * 1000 * 1000 )) ;; + tb|t) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 )) ;; + pb|p) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 * 1000 )) ;; + kib|ki) memory_b=$(( $number * 1024 )) ;; + mib|mi) memory_b=$(( $number * 1024 * 1024 )) ;; + gib|gi) memory_b=$(( $number * 1024 * 1024 * 1024 )) ;; + tib|ti) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 )) ;; + pib|pi) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 * 1024 )) ;; + esac + echo "$memory_b" + fi +} +# compute memory in different units +if [ ! -z ${VIASH_META_MEMORY+x} ]; then + VIASH_META_MEMORY_B=`ViashMemoryAsBytes $VIASH_META_MEMORY` + # do not define other variables if memory_b is an empty string + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_META_MEMORY_KB=$(( ($VIASH_META_MEMORY_B+999) / 1000 )) + VIASH_META_MEMORY_MB=$(( ($VIASH_META_MEMORY_KB+999) / 1000 )) + VIASH_META_MEMORY_GB=$(( ($VIASH_META_MEMORY_MB+999) / 1000 )) + VIASH_META_MEMORY_TB=$(( ($VIASH_META_MEMORY_GB+999) / 1000 )) + VIASH_META_MEMORY_PB=$(( ($VIASH_META_MEMORY_TB+999) / 1000 )) + VIASH_META_MEMORY_KIB=$(( ($VIASH_META_MEMORY_B+1023) / 1024 )) + VIASH_META_MEMORY_MIB=$(( ($VIASH_META_MEMORY_KIB+1023) / 1024 )) + VIASH_META_MEMORY_GIB=$(( ($VIASH_META_MEMORY_MIB+1023) / 1024 )) + VIASH_META_MEMORY_TIB=$(( ($VIASH_META_MEMORY_GIB+1023) / 1024 )) + VIASH_META_MEMORY_PIB=$(( ($VIASH_META_MEMORY_TIB+1023) / 1024 )) + else + # unset memory if string is empty + unset $VIASH_META_MEMORY_B + fi +fi +# unset nproc if string is empty +if [ -z "$VIASH_META_CPUS" ]; then + unset $VIASH_META_CPUS +fi + + +# check whether required parameters exist +if [ -z ${VIASH_PAR_INPUT_FILE+x} ]; then + ViashError '--input_file' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_PAR_REFGENE+x} ]; then + ViashError '--refgene' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_PAR_OUTPUT_PREFIX+x} ]; then + ViashError '--output_prefix' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_NAME+x} ]; then + ViashError 'name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_FUNCTIONALITY_NAME+x} ]; then + ViashError 'functionality_name' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_RESOURCES_DIR+x} ]; then + ViashError 'resources_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_EXECUTABLE+x} ]; then + ViashError 'executable' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_CONFIG+x} ]; then + ViashError 'config' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi +if [ -z ${VIASH_META_TEMP_DIR+x} ]; then + ViashError 'temp_dir' is a required argument. Use "--help" to get more information on the parameters. + exit 1 +fi + +# check whether required files exist +if [ ! -z "$VIASH_PAR_INPUT_FILE" ] && [ ! -e "$VIASH_PAR_INPUT_FILE" ]; then + ViashError "Input file '$VIASH_PAR_INPUT_FILE' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_REFGENE" ] && [ ! -e "$VIASH_PAR_REFGENE" ]; then + ViashError "Input file '$VIASH_PAR_REFGENE' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_PAR_SAMPLE_SIZE" ]]; then + if ! [[ "$VIASH_PAR_SAMPLE_SIZE" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--sample_size' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_MAPQ" ]]; then + if ! [[ "$VIASH_PAR_MAPQ" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--mapq' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_LOWER_BOUND" ]]; then + if ! [[ "$VIASH_PAR_LOWER_BOUND" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--lower_bound' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_UPPER_BOUND" ]]; then + if ! [[ "$VIASH_PAR_UPPER_BOUND" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--upper_bound' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_STEP" ]]; then + if ! [[ "$VIASH_PAR_STEP" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--step' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_CPUS" ]]; then + if ! [[ "$VIASH_META_CPUS" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'cpus' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_B" ]]; then + if ! [[ "$VIASH_META_MEMORY_B" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_b' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pb' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_KIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_KIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_kib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_MIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_MIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_mib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_GIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_GIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_gib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_TIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_TIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_tib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_META_MEMORY_PIB" ]]; then + if ! [[ "$VIASH_META_MEMORY_PIB" =~ ^[-+]?[0-9]+$ ]]; then + ViashError 'memory_pib' has to be a long. Use "--help" to get more information on the parameters. + exit 1 + fi +fi + +# create parent directories of output files, if so desired +if [ ! -z "$VIASH_PAR_OUTPUT_STATS" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT_STATS")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT_STATS")" +fi +if [ ! -z "$VIASH_PAR_OUTPUT_DIST" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT_DIST")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT_DIST")" +fi +if [ ! -z "$VIASH_PAR_OUTPUT_FREQ" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT_FREQ")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT_FREQ")" +fi +if [ ! -z "$VIASH_PAR_OUTPUT_PLOT" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT_PLOT")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT_PLOT")" +fi +if [ ! -z "$VIASH_PAR_OUTPUT_PLOT_R" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT_PLOT_R")" ]; then + mkdir -p "$(dirname "$VIASH_PAR_OUTPUT_PLOT_R")" +fi + +if [ "$VIASH_ENGINE_ID" == "native" ] ; then + if [ "$VIASH_MODE" == "run" ]; then + VIASH_CMD="bash" + else + ViashError "Engine '$VIASH_ENGINE_ID' does not support mode '$VIASH_MODE'." + exit 1 + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # detect volumes from file arguments + VIASH_CHOWN_VARS=() +if [ ! -z "$VIASH_PAR_INPUT_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_INPUT_FILE")" ) + VIASH_PAR_INPUT_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_INPUT_FILE") +fi +if [ ! -z "$VIASH_PAR_REFGENE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_REFGENE")" ) + VIASH_PAR_REFGENE=$(ViashDockerAutodetectMount "$VIASH_PAR_REFGENE") +fi +if [ ! -z "$VIASH_PAR_OUTPUT_STATS" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT_STATS")" ) + VIASH_PAR_OUTPUT_STATS=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT_STATS") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT_STATS" ) +fi +if [ ! -z "$VIASH_PAR_OUTPUT_DIST" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT_DIST")" ) + VIASH_PAR_OUTPUT_DIST=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT_DIST") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT_DIST" ) +fi +if [ ! -z "$VIASH_PAR_OUTPUT_FREQ" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT_FREQ")" ) + VIASH_PAR_OUTPUT_FREQ=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT_FREQ") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT_FREQ" ) +fi +if [ ! -z "$VIASH_PAR_OUTPUT_PLOT" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT_PLOT")" ) + VIASH_PAR_OUTPUT_PLOT=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT_PLOT") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT_PLOT" ) +fi +if [ ! -z "$VIASH_PAR_OUTPUT_PLOT_R" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT_PLOT_R")" ) + VIASH_PAR_OUTPUT_PLOT_R=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT_PLOT_R") + VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT_PLOT_R" ) +fi +if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_RESOURCES_DIR")" ) + VIASH_META_RESOURCES_DIR=$(ViashDockerAutodetectMount "$VIASH_META_RESOURCES_DIR") +fi +if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_EXECUTABLE")" ) + VIASH_META_EXECUTABLE=$(ViashDockerAutodetectMount "$VIASH_META_EXECUTABLE") +fi +if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_CONFIG")" ) + VIASH_META_CONFIG=$(ViashDockerAutodetectMount "$VIASH_META_CONFIG") +fi +if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_TEMP_DIR")" ) + VIASH_META_TEMP_DIR=$(ViashDockerAutodetectMount "$VIASH_META_TEMP_DIR") +fi + + # get unique mounts + VIASH_UNIQUE_MOUNTS=($(for val in "${VIASH_DIRECTORY_MOUNTS[@]}"; do echo "$val"; done | sort -u)) +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # change file ownership + function ViashPerformChown { + if (( ${#VIASH_CHOWN_VARS[@]} )); then + set +e + VIASH_CMD="docker run --entrypoint=bash --rm ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID -c 'chown $(id -u):$(id -g) --silent --recursive ${VIASH_CHOWN_VARS[@]}'" + ViashDebug "+ $VIASH_CMD" + eval $VIASH_CMD + set -e + fi + } + trap ViashPerformChown EXIT +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # helper function for filling in extra docker args + if [ ! -z "$VIASH_META_MEMORY_B" ]; then + VIASH_DOCKER_RUN_ARGS+=("--memory=${VIASH_META_MEMORY_B}") + fi + if [ ! -z "$VIASH_META_CPUS" ]; then + VIASH_DOCKER_RUN_ARGS+=("--cpus=${VIASH_META_CPUS}") + fi +fi + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID" +fi + + +# set dependency paths + + +ViashDebug "Running command: $(echo $VIASH_CMD)" +cat << VIASHEOF | eval $VIASH_CMD +set -e +tempscript=\$(mktemp "$VIASH_META_TEMP_DIR/viash-run-rseqc_inner_distance-XXXXXX").sh +function clean_up { + rm "\$tempscript" +} +function interrupt { + echo -e "\nCTRL-C Pressed..." + exit 1 +} +trap clean_up EXIT +trap interrupt INT SIGINT +cat > "\$tempscript" << 'VIASHMAIN' +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_INPUT_FILE+x} ]; then echo "${VIASH_PAR_INPUT_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_input_file='&'#" ; else echo "# par_input_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REFGENE+x} ]; then echo "${VIASH_PAR_REFGENE}" | sed "s#'#'\"'\"'#g;s#.*#par_refgene='&'#" ; else echo "# par_refgene="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLE_SIZE+x} ]; then echo "${VIASH_PAR_SAMPLE_SIZE}" | sed "s#'#'\"'\"'#g;s#.*#par_sample_size='&'#" ; else echo "# par_sample_size="; fi ) +$( if [ ! -z ${VIASH_PAR_MAPQ+x} ]; then echo "${VIASH_PAR_MAPQ}" | sed "s#'#'\"'\"'#g;s#.*#par_mapq='&'#" ; else echo "# par_mapq="; fi ) +$( if [ ! -z ${VIASH_PAR_LOWER_BOUND+x} ]; then echo "${VIASH_PAR_LOWER_BOUND}" | sed "s#'#'\"'\"'#g;s#.*#par_lower_bound='&'#" ; else echo "# par_lower_bound="; fi ) +$( if [ ! -z ${VIASH_PAR_UPPER_BOUND+x} ]; then echo "${VIASH_PAR_UPPER_BOUND}" | sed "s#'#'\"'\"'#g;s#.*#par_upper_bound='&'#" ; else echo "# par_upper_bound="; fi ) +$( if [ ! -z ${VIASH_PAR_STEP+x} ]; then echo "${VIASH_PAR_STEP}" | sed "s#'#'\"'\"'#g;s#.*#par_step='&'#" ; else echo "# par_step="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_PREFIX+x} ]; then echo "${VIASH_PAR_OUTPUT_PREFIX}" | sed "s#'#'\"'\"'#g;s#.*#par_output_prefix='&'#" ; else echo "# par_output_prefix="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_STATS+x} ]; then echo "${VIASH_PAR_OUTPUT_STATS}" | sed "s#'#'\"'\"'#g;s#.*#par_output_stats='&'#" ; else echo "# par_output_stats="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_DIST+x} ]; then echo "${VIASH_PAR_OUTPUT_DIST}" | sed "s#'#'\"'\"'#g;s#.*#par_output_dist='&'#" ; else echo "# par_output_dist="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_FREQ+x} ]; then echo "${VIASH_PAR_OUTPUT_FREQ}" | sed "s#'#'\"'\"'#g;s#.*#par_output_freq='&'#" ; else echo "# par_output_freq="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_PLOT+x} ]; then echo "${VIASH_PAR_OUTPUT_PLOT}" | sed "s#'#'\"'\"'#g;s#.*#par_output_plot='&'#" ; else echo "# par_output_plot="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_PLOT_R+x} ]; then echo "${VIASH_PAR_OUTPUT_PLOT_R}" | sed "s#'#'\"'\"'#g;s#.*#par_output_plot_r='&'#" ; else echo "# par_output_plot_r="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\"'\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\"'\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\"'\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\"'\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\"'\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END +#!/bin/bash + +set -exo pipefail + + +inner_distance.py \\ + -i \$par_input_file \\ + -r \$par_refgene \\ + -o \$par_output_prefix \\ + \${par_sample_size:+-k "\${par_sample_size}"} \\ + \${par_lower_bound:+-l "\${par_lower_bound}"} \\ + \${par_upper_bound:+-u "\${par_upper_bound}"} \\ + \${par_step:+-s "\${par_step}"} \\ + \${par_mapq:+-q "\${par_mapq}"} \\ +> stdout.txt + +if [[ -n \$par_output_stats ]]; then head -n 2 stdout.txt > \$par_output_stats; fi + + +[[ -n "\$par_output_dist" && -f "\$par_output_prefix.inner_distance.txt" ]] && mv \$par_output_prefix.inner_distance.txt \$par_output_dist +[[ -n "\$par_output_plot" && -f "\$par_output_prefix.inner_distance_plot.pdf" ]] && mv \$par_output_prefix.inner_distance_plot.pdf \$par_output_plot +[[ -n "\$par_output_plot_r" && -f "\$par_output_prefix.inner_distance_plot.r" ]] && mv \$par_output_prefix.inner_distance_plot.r \$par_output_plot_r +[[ -n "\$par_output_freq" && -f "\$par_output_prefix.inner_distance_freq.txt" ]] && mv \$par_output_prefix.inner_distance_freq.txt \$par_output_freq + +exit 0 +VIASHMAIN +bash "\$tempscript" & +wait "\$!" + +VIASHEOF + + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # strip viash automount from file paths + + if [ ! -z "$VIASH_PAR_INPUT_FILE" ]; then + VIASH_PAR_INPUT_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_INPUT_FILE") + fi + if [ ! -z "$VIASH_PAR_REFGENE" ]; then + VIASH_PAR_REFGENE=$(ViashDockerStripAutomount "$VIASH_PAR_REFGENE") + fi + if [ ! -z "$VIASH_PAR_OUTPUT_STATS" ]; then + VIASH_PAR_OUTPUT_STATS=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT_STATS") + fi + if [ ! -z "$VIASH_PAR_OUTPUT_DIST" ]; then + VIASH_PAR_OUTPUT_DIST=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT_DIST") + fi + if [ ! -z "$VIASH_PAR_OUTPUT_FREQ" ]; then + VIASH_PAR_OUTPUT_FREQ=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT_FREQ") + fi + if [ ! -z "$VIASH_PAR_OUTPUT_PLOT" ]; then + VIASH_PAR_OUTPUT_PLOT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT_PLOT") + fi + if [ ! -z "$VIASH_PAR_OUTPUT_PLOT_R" ]; then + VIASH_PAR_OUTPUT_PLOT_R=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT_PLOT_R") + fi + if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then + VIASH_META_RESOURCES_DIR=$(ViashDockerStripAutomount "$VIASH_META_RESOURCES_DIR") + fi + if [ ! -z "$VIASH_META_EXECUTABLE" ]; then + VIASH_META_EXECUTABLE=$(ViashDockerStripAutomount "$VIASH_META_EXECUTABLE") + fi + if [ ! -z "$VIASH_META_CONFIG" ]; then + VIASH_META_CONFIG=$(ViashDockerStripAutomount "$VIASH_META_CONFIG") + fi + if [ ! -z "$VIASH_META_TEMP_DIR" ]; then + VIASH_META_TEMP_DIR=$(ViashDockerStripAutomount "$VIASH_META_TEMP_DIR") + fi +fi + + +# check whether required files exist +if [ ! -z "$VIASH_PAR_OUTPUT_STATS" ] && [ ! -e "$VIASH_PAR_OUTPUT_STATS" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT_STATS' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_OUTPUT_DIST" ] && [ ! -e "$VIASH_PAR_OUTPUT_DIST" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT_DIST' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_OUTPUT_FREQ" ] && [ ! -e "$VIASH_PAR_OUTPUT_FREQ" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT_FREQ' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_OUTPUT_PLOT" ] && [ ! -e "$VIASH_PAR_OUTPUT_PLOT" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT_PLOT' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_OUTPUT_PLOT_R" ] && [ ! -e "$VIASH_PAR_OUTPUT_PLOT_R" ]; then + ViashError "Output file '$VIASH_PAR_OUTPUT_PLOT_R' does not exist." + exit 1 +fi + + +exit 0 diff --git a/target/executable/salmon/salmon_index/.config.vsh.yaml b/target/executable/salmon/salmon_index/.config.vsh.yaml index 7712414d..d4ff9c33 100644 --- a/target/executable/salmon/salmon_index/.config.vsh.yaml +++ b/target/executable/salmon/salmon_index/.config.vsh.yaml @@ -277,9 +277,9 @@ build_info: output: "target/executable/salmon/salmon_index" executable: "target/executable/salmon/salmon_index/salmon_index" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/salmon/salmon_index/salmon_index b/target/executable/salmon/salmon_index/salmon_index index d3202ec5..8ff5c23c 100755 --- a/target/executable/salmon/salmon_index/salmon_index +++ b/target/executable/salmon/salmon_index/salmon_index @@ -546,9 +546,9 @@ RUN salmon index -v 2>&1 | sed 's/salmon \([0-9.]*\)/salmon: \1/' > /var/softwar LABEL org.opencontainers.image.authors="Sai Nirmayi Yasa" LABEL org.opencontainers.image.description="Companion container for running component salmon salmon_index" -LABEL org.opencontainers.image.created="2024-10-26T13:11:17Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:05Z" LABEL org.opencontainers.image.source="https://github.com/COMBINE-lab/salmon" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/salmon/salmon_quant/.config.vsh.yaml b/target/executable/salmon/salmon_quant/.config.vsh.yaml index dd56ab36..a9d3fa34 100644 --- a/target/executable/salmon/salmon_quant/.config.vsh.yaml +++ b/target/executable/salmon/salmon_quant/.config.vsh.yaml @@ -1173,9 +1173,9 @@ build_info: output: "target/executable/salmon/salmon_quant" executable: "target/executable/salmon/salmon_quant/salmon_quant" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/salmon/salmon_quant/salmon_quant b/target/executable/salmon/salmon_quant/salmon_quant index ae600470..60877576 100755 --- a/target/executable/salmon/salmon_quant/salmon_quant +++ b/target/executable/salmon/salmon_quant/salmon_quant @@ -1168,9 +1168,9 @@ RUN salmon index -v 2>&1 | sed 's/salmon \([0-9.]*\)/salmon: \1/' > /var/softwar LABEL org.opencontainers.image.authors="Sai Nirmayi Yasa" LABEL org.opencontainers.image.description="Companion container for running component salmon salmon_quant" -LABEL org.opencontainers.image.created="2024-10-26T13:11:17Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:05Z" LABEL org.opencontainers.image.source="https://github.com/COMBINE-lab/salmon" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_collate/.config.vsh.yaml b/target/executable/samtools/samtools_collate/.config.vsh.yaml index 73e7c4ad..067ca194 100644 --- a/target/executable/samtools/samtools_collate/.config.vsh.yaml +++ b/target/executable/samtools/samtools_collate/.config.vsh.yaml @@ -264,9 +264,9 @@ build_info: output: "target/executable/samtools/samtools_collate" executable: "target/executable/samtools/samtools_collate/samtools_collate" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_collate/samtools_collate b/target/executable/samtools/samtools_collate/samtools_collate index 75d985fe..6e0693d1 100755 --- a/target/executable/samtools/samtools_collate/samtools_collate +++ b/target/executable/samtools/samtools_collate/samtools_collate @@ -519,9 +519,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_collate" -LABEL org.opencontainers.image.created="2024-10-26T13:11:10Z" +LABEL org.opencontainers.image.created="2024-10-26T18:43:57Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_faidx/.config.vsh.yaml b/target/executable/samtools/samtools_faidx/.config.vsh.yaml index 7b2b03d8..35641919 100644 --- a/target/executable/samtools/samtools_faidx/.config.vsh.yaml +++ b/target/executable/samtools/samtools_faidx/.config.vsh.yaml @@ -243,9 +243,9 @@ build_info: output: "target/executable/samtools/samtools_faidx" executable: "target/executable/samtools/samtools_faidx/samtools_faidx" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_faidx/samtools_faidx b/target/executable/samtools/samtools_faidx/samtools_faidx index c71964f1..685ac3ba 100755 --- a/target/executable/samtools/samtools_faidx/samtools_faidx +++ b/target/executable/samtools/samtools_faidx/samtools_faidx @@ -512,9 +512,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_faidx" -LABEL org.opencontainers.image.created="2024-10-26T13:11:09Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:12Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_fasta/.config.vsh.yaml b/target/executable/samtools/samtools_fasta/.config.vsh.yaml index 0b6b957e..763a7d28 100644 --- a/target/executable/samtools/samtools_fasta/.config.vsh.yaml +++ b/target/executable/samtools/samtools_fasta/.config.vsh.yaml @@ -433,9 +433,9 @@ build_info: output: "target/executable/samtools/samtools_fasta" executable: "target/executable/samtools/samtools_fasta/samtools_fasta" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_fasta/samtools_fasta b/target/executable/samtools/samtools_fasta/samtools_fasta index 5896a136..523ba5b8 100755 --- a/target/executable/samtools/samtools_fasta/samtools_fasta +++ b/target/executable/samtools/samtools_fasta/samtools_fasta @@ -625,9 +625,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_fasta" -LABEL org.opencontainers.image.created="2024-10-26T13:11:10Z" +LABEL org.opencontainers.image.created="2024-10-26T18:43:58Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_fastq/.config.vsh.yaml b/target/executable/samtools/samtools_fastq/.config.vsh.yaml index 9cbbb07f..8c4eb310 100644 --- a/target/executable/samtools/samtools_fastq/.config.vsh.yaml +++ b/target/executable/samtools/samtools_fastq/.config.vsh.yaml @@ -433,9 +433,9 @@ build_info: output: "target/executable/samtools/samtools_fastq" executable: "target/executable/samtools/samtools_fastq/samtools_fastq" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_fastq/samtools_fastq b/target/executable/samtools/samtools_fastq/samtools_fastq index 1e202ba3..771d7d84 100755 --- a/target/executable/samtools/samtools_fastq/samtools_fastq +++ b/target/executable/samtools/samtools_fastq/samtools_fastq @@ -626,9 +626,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_fastq" -LABEL org.opencontainers.image.created="2024-10-26T13:11:11Z" +LABEL org.opencontainers.image.created="2024-10-26T18:43:59Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_flagstat/.config.vsh.yaml b/target/executable/samtools/samtools_flagstat/.config.vsh.yaml index c7ec1f54..34f6fd16 100644 --- a/target/executable/samtools/samtools_flagstat/.config.vsh.yaml +++ b/target/executable/samtools/samtools_flagstat/.config.vsh.yaml @@ -173,9 +173,9 @@ build_info: output: "target/executable/samtools/samtools_flagstat" executable: "target/executable/samtools/samtools_flagstat/samtools_flagstat" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_flagstat/samtools_flagstat b/target/executable/samtools/samtools_flagstat/samtools_flagstat index 5402a7e1..0d5928fe 100755 --- a/target/executable/samtools/samtools_flagstat/samtools_flagstat +++ b/target/executable/samtools/samtools_flagstat/samtools_flagstat @@ -474,9 +474,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_flagstat" -LABEL org.opencontainers.image.created="2024-10-26T13:11:23Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:11Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_idxstats/.config.vsh.yaml b/target/executable/samtools/samtools_idxstats/.config.vsh.yaml index 48af23a9..2ecdffa7 100644 --- a/target/executable/samtools/samtools_idxstats/.config.vsh.yaml +++ b/target/executable/samtools/samtools_idxstats/.config.vsh.yaml @@ -183,9 +183,9 @@ build_info: output: "target/executable/samtools/samtools_idxstats" executable: "target/executable/samtools/samtools_idxstats/samtools_idxstats" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_idxstats/samtools_idxstats b/target/executable/samtools/samtools_idxstats/samtools_idxstats index e10cbca4..a083bf56 100755 --- a/target/executable/samtools/samtools_idxstats/samtools_idxstats +++ b/target/executable/samtools/samtools_idxstats/samtools_idxstats @@ -478,9 +478,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_idxstats" -LABEL org.opencontainers.image.created="2024-10-26T13:11:23Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:11Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_index/.config.vsh.yaml b/target/executable/samtools/samtools_index/.config.vsh.yaml index 1c5a00d1..9d77a155 100644 --- a/target/executable/samtools/samtools_index/.config.vsh.yaml +++ b/target/executable/samtools/samtools_index/.config.vsh.yaml @@ -189,9 +189,9 @@ build_info: output: "target/executable/samtools/samtools_index" executable: "target/executable/samtools/samtools_index/samtools_index" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_index/samtools_index b/target/executable/samtools/samtools_index/samtools_index index 46a5ce1f..ea207921 100755 --- a/target/executable/samtools/samtools_index/samtools_index +++ b/target/executable/samtools/samtools_index/samtools_index @@ -485,9 +485,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_index" -LABEL org.opencontainers.image.created="2024-10-26T13:11:23Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:11Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_sort/.config.vsh.yaml b/target/executable/samtools/samtools_sort/.config.vsh.yaml index 85987c2d..5fdab70a 100644 --- a/target/executable/samtools/samtools_sort/.config.vsh.yaml +++ b/target/executable/samtools/samtools_sort/.config.vsh.yaml @@ -332,9 +332,9 @@ build_info: output: "target/executable/samtools/samtools_sort" executable: "target/executable/samtools/samtools_sort/samtools_sort" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_sort/samtools_sort b/target/executable/samtools/samtools_sort/samtools_sort index 1d53a19b..7359bc89 100755 --- a/target/executable/samtools/samtools_sort/samtools_sort +++ b/target/executable/samtools/samtools_sort/samtools_sort @@ -556,9 +556,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_sort" -LABEL org.opencontainers.image.created="2024-10-26T13:11:11Z" +LABEL org.opencontainers.image.created="2024-10-26T18:43:58Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_stats/.config.vsh.yaml b/target/executable/samtools/samtools_stats/.config.vsh.yaml index d60035f3..04c9c623 100644 --- a/target/executable/samtools/samtools_stats/.config.vsh.yaml +++ b/target/executable/samtools/samtools_stats/.config.vsh.yaml @@ -401,9 +401,9 @@ build_info: output: "target/executable/samtools/samtools_stats" executable: "target/executable/samtools/samtools_stats/samtools_stats" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_stats/samtools_stats b/target/executable/samtools/samtools_stats/samtools_stats index 616c2c36..5ee10440 100755 --- a/target/executable/samtools/samtools_stats/samtools_stats +++ b/target/executable/samtools/samtools_stats/samtools_stats @@ -575,9 +575,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_stats" -LABEL org.opencontainers.image.created="2024-10-26T13:11:22Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:10Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/samtools/samtools_view/.config.vsh.yaml b/target/executable/samtools/samtools_view/.config.vsh.yaml index fc68fb02..8eac778f 100644 --- a/target/executable/samtools/samtools_view/.config.vsh.yaml +++ b/target/executable/samtools/samtools_view/.config.vsh.yaml @@ -665,9 +665,9 @@ build_info: output: "target/executable/samtools/samtools_view" executable: "target/executable/samtools/samtools_view/samtools_view" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/samtools/samtools_view/samtools_view b/target/executable/samtools/samtools_view/samtools_view index 5c2e4650..dcac1e7b 100755 --- a/target/executable/samtools/samtools_view/samtools_view +++ b/target/executable/samtools/samtools_view/samtools_view @@ -825,9 +825,9 @@ sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component samtools samtools_view" -LABEL org.opencontainers.image.created="2024-10-26T13:11:08Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:11Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/seqtk/seqtk_sample/.config.vsh.yaml b/target/executable/seqtk/seqtk_sample/.config.vsh.yaml index 8dc51304..8ac08ff4 100644 --- a/target/executable/seqtk/seqtk_sample/.config.vsh.yaml +++ b/target/executable/seqtk/seqtk_sample/.config.vsh.yaml @@ -173,9 +173,9 @@ build_info: output: "target/executable/seqtk/seqtk_sample" executable: "target/executable/seqtk/seqtk_sample/seqtk_sample" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/seqtk/seqtk_sample/seqtk_sample b/target/executable/seqtk/seqtk_sample/seqtk_sample index 85fa5dac..56dd3e1e 100755 --- a/target/executable/seqtk/seqtk_sample/seqtk_sample +++ b/target/executable/seqtk/seqtk_sample/seqtk_sample @@ -481,9 +481,9 @@ FROM quay.io/biocontainers/seqtk:1.4--he4a0461_2 ENTRYPOINT [] LABEL org.opencontainers.image.authors="Jakub Majercik" LABEL org.opencontainers.image.description="Companion container for running component seqtk seqtk_sample" -LABEL org.opencontainers.image.created="2024-10-26T13:11:23Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:12Z" LABEL org.opencontainers.image.source="https://github.com/lh3/seqtk/tree/v1.4" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/seqtk/seqtk_subseq/.config.vsh.yaml b/target/executable/seqtk/seqtk_subseq/.config.vsh.yaml index df8f14f3..f99e0ea2 100644 --- a/target/executable/seqtk/seqtk_subseq/.config.vsh.yaml +++ b/target/executable/seqtk/seqtk_subseq/.config.vsh.yaml @@ -196,9 +196,9 @@ build_info: output: "target/executable/seqtk/seqtk_subseq" executable: "target/executable/seqtk/seqtk_subseq/seqtk_subseq" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/seqtk/seqtk_subseq/seqtk_subseq b/target/executable/seqtk/seqtk_subseq/seqtk_subseq index 2b312b09..0f6c7136 100755 --- a/target/executable/seqtk/seqtk_subseq/seqtk_subseq +++ b/target/executable/seqtk/seqtk_subseq/seqtk_subseq @@ -491,9 +491,9 @@ RUN echo $(echo $(seqtk 2>&1) | sed -n 's/.*\(Version: [^ ]*\).*/\1/p') > /var/s LABEL org.opencontainers.image.authors="Theodoro Gasperin Terra Camargo" LABEL org.opencontainers.image.description="Companion container for running component seqtk seqtk_subseq" -LABEL org.opencontainers.image.created="2024-10-26T13:11:24Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:12Z" LABEL org.opencontainers.image.source="https://github.com/lh3/seqtk/tree/v1.4" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/snpeff/.config.vsh.yaml b/target/executable/snpeff/.config.vsh.yaml index b768e894..059b8b1a 100644 --- a/target/executable/snpeff/.config.vsh.yaml +++ b/target/executable/snpeff/.config.vsh.yaml @@ -628,9 +628,9 @@ build_info: output: "target/executable/snpeff" executable: "target/executable/snpeff/snpeff" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/snpeff/snpeff b/target/executable/snpeff/snpeff index a2ef4445..cf8c7502 100755 --- a/target/executable/snpeff/snpeff +++ b/target/executable/snpeff/snpeff @@ -756,9 +756,9 @@ version_trimmed=$(echo "$version" | awk '{print $1, $2}') && \ echo "$version_trimmed" > /var/software_versions.txt LABEL org.opencontainers.image.description="Companion container for running component snpeff" -LABEL org.opencontainers.image.created="2024-10-26T13:11:15Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:02Z" LABEL org.opencontainers.image.source="https://github.com/pcingola/SnpEff" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/sortmerna/.config.vsh.yaml b/target/executable/sortmerna/.config.vsh.yaml index eba5efce..c877c452 100644 --- a/target/executable/sortmerna/.config.vsh.yaml +++ b/target/executable/sortmerna/.config.vsh.yaml @@ -591,9 +591,9 @@ build_info: output: "target/executable/sortmerna" executable: "target/executable/sortmerna/sortmerna" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/sortmerna/sortmerna b/target/executable/sortmerna/sortmerna index f915619d..0aaed3ab 100755 --- a/target/executable/sortmerna/sortmerna +++ b/target/executable/sortmerna/sortmerna @@ -744,9 +744,9 @@ wget --no-check-certificate https://github.com/sortmerna/sortmerna/releases/down bash sortmerna-4.3.6-Linux.sh --skip-license LABEL org.opencontainers.image.description="Companion container for running component sortmerna" -LABEL org.opencontainers.image.created="2024-10-26T13:11:12Z" +LABEL org.opencontainers.image.created="2024-10-26T18:43:59Z" LABEL org.opencontainers.image.source="https://github.com/sortmerna/sortmerna" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/star/star_align_reads/.config.vsh.yaml b/target/executable/star/star_align_reads/.config.vsh.yaml index 406a6889..248068f2 100644 --- a/target/executable/star/star_align_reads/.config.vsh.yaml +++ b/target/executable/star/star_align_reads/.config.vsh.yaml @@ -2663,9 +2663,9 @@ build_info: output: "target/executable/star/star_align_reads" executable: "target/executable/star/star_align_reads/star_align_reads" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/star/star_align_reads/star_align_reads b/target/executable/star/star_align_reads/star_align_reads index 3872c2ed..161c928b 100755 --- a/target/executable/star/star_align_reads/star_align_reads +++ b/target/executable/star/star_align_reads/star_align_reads @@ -1920,9 +1920,9 @@ RUN STAR --version | sed 's#\(.*\)#star: "\1"#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Angela Oliveira Pisco, Robrecht Cannoodt" LABEL org.opencontainers.image.description="Companion container for running component star star_align_reads" -LABEL org.opencontainers.image.created="2024-10-26T13:11:13Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:01Z" LABEL org.opencontainers.image.source="https://github.com/alexdobin/STAR" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/star/star_genome_generate/.config.vsh.yaml b/target/executable/star/star_genome_generate/.config.vsh.yaml index 0e2b1ca0..15375b6d 100644 --- a/target/executable/star/star_genome_generate/.config.vsh.yaml +++ b/target/executable/star/star_genome_generate/.config.vsh.yaml @@ -333,9 +333,9 @@ build_info: output: "target/executable/star/star_genome_generate" executable: "target/executable/star/star_genome_generate/star_genome_generate" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/star/star_genome_generate/star_genome_generate b/target/executable/star/star_genome_generate/star_genome_generate index 89e124d5..44422fdd 100755 --- a/target/executable/star/star_genome_generate/star_genome_generate +++ b/target/executable/star/star_genome_generate/star_genome_generate @@ -577,9 +577,9 @@ RUN STAR --version | sed 's#\(.*\)#star: "\1"#' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Sai Nirmayi Yasa" LABEL org.opencontainers.image.description="Companion container for running component star star_genome_generate" -LABEL org.opencontainers.image.created="2024-10-26T13:11:13Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:00Z" LABEL org.opencontainers.image.source="https://github.com/alexdobin/STAR" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/trimgalore/.config.vsh.yaml b/target/executable/trimgalore/.config.vsh.yaml index 56595b98..f2d9d3c4 100644 --- a/target/executable/trimgalore/.config.vsh.yaml +++ b/target/executable/trimgalore/.config.vsh.yaml @@ -770,9 +770,9 @@ build_info: output: "target/executable/trimgalore" executable: "target/executable/trimgalore/trimgalore" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/trimgalore/trimgalore b/target/executable/trimgalore/trimgalore index ec3482b0..b599ba42 100755 --- a/target/executable/trimgalore/trimgalore +++ b/target/executable/trimgalore/trimgalore @@ -881,9 +881,9 @@ RUN echo "TrimGalore: `trim_galore --version | sed -n 's/.*version\s\+\([0-9]\+\ LABEL org.opencontainers.image.authors="Sai Nirmayi Yasa" LABEL org.opencontainers.image.description="Companion container for running component trimgalore" -LABEL org.opencontainers.image.created="2024-10-26T13:11:17Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:04Z" LABEL org.opencontainers.image.source="https://github.com/FelixKrueger/TrimGalore" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/umi_tools/umi_tools_dedup/.config.vsh.yaml b/target/executable/umi_tools/umi_tools_dedup/.config.vsh.yaml index 3e4323e0..be52b591 100644 --- a/target/executable/umi_tools/umi_tools_dedup/.config.vsh.yaml +++ b/target/executable/umi_tools/umi_tools_dedup/.config.vsh.yaml @@ -611,9 +611,9 @@ build_info: output: "target/executable/umi_tools/umi_tools_dedup" executable: "target/executable/umi_tools/umi_tools_dedup/umi_tools_dedup" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/umi_tools/umi_tools_dedup/umi_tools_dedup b/target/executable/umi_tools/umi_tools_dedup/umi_tools_dedup index 72986d59..e3a53492 100755 --- a/target/executable/umi_tools/umi_tools_dedup/umi_tools_dedup +++ b/target/executable/umi_tools/umi_tools_dedup/umi_tools_dedup @@ -770,9 +770,9 @@ RUN umi_tools -v | sed 's/ version//g' > /var/software_versions.txt LABEL org.opencontainers.image.authors="Emma Rousseau" LABEL org.opencontainers.image.description="Companion container for running component umi_tools umi_tools_dedup" -LABEL org.opencontainers.image.created="2024-10-26T13:11:15Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:03Z" LABEL org.opencontainers.image.source="https://github.com/CGATOxford/UMI-tools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/umi_tools/umi_tools_extract/.config.vsh.yaml b/target/executable/umi_tools/umi_tools_extract/.config.vsh.yaml index 3337ecf1..232beff1 100644 --- a/target/executable/umi_tools/umi_tools_extract/.config.vsh.yaml +++ b/target/executable/umi_tools/umi_tools_extract/.config.vsh.yaml @@ -449,9 +449,9 @@ build_info: output: "target/executable/umi_tools/umi_tools_extract" executable: "target/executable/umi_tools/umi_tools_extract/umi_tools_extract" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/umi_tools/umi_tools_extract/umi_tools_extract b/target/executable/umi_tools/umi_tools_extract/umi_tools_extract index 2783ccee..c95662ec 100755 --- a/target/executable/umi_tools/umi_tools_extract/umi_tools_extract +++ b/target/executable/umi_tools/umi_tools_extract/umi_tools_extract @@ -637,9 +637,9 @@ ENTRYPOINT [] RUN umi_tools -v | sed 's/ version//g' > /var/software_versions.txt LABEL org.opencontainers.image.description="Companion container for running component umi_tools umi_tools_extract" -LABEL org.opencontainers.image.created="2024-10-26T13:11:14Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:02Z" LABEL org.opencontainers.image.source="https://github.com/CGATOxford/UMI-tools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/executable/umi_tools/umi_tools_prepareforrsem/.config.vsh.yaml b/target/executable/umi_tools/umi_tools_prepareforrsem/.config.vsh.yaml index 3a5953a6..ade1ff8b 100644 --- a/target/executable/umi_tools/umi_tools_prepareforrsem/.config.vsh.yaml +++ b/target/executable/umi_tools/umi_tools_prepareforrsem/.config.vsh.yaml @@ -256,9 +256,9 @@ build_info: output: "target/executable/umi_tools/umi_tools_prepareforrsem" executable: "target/executable/umi_tools/umi_tools_prepareforrsem/umi_tools_prepareforrsem" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/executable/umi_tools/umi_tools_prepareforrsem/umi_tools_prepareforrsem b/target/executable/umi_tools/umi_tools_prepareforrsem/umi_tools_prepareforrsem index ce36601f..a2d13fca 100755 --- a/target/executable/umi_tools/umi_tools_prepareforrsem/umi_tools_prepareforrsem +++ b/target/executable/umi_tools/umi_tools_prepareforrsem/umi_tools_prepareforrsem @@ -519,9 +519,9 @@ ENTRYPOINT [] RUN umi_tools -v | sed 's/ version//g' > /var/software_versions.txt LABEL org.opencontainers.image.description="Companion container for running component umi_tools umi_tools_prepareforrsem" -LABEL org.opencontainers.image.created="2024-10-26T13:11:15Z" +LABEL org.opencontainers.image.created="2024-10-26T18:44:03Z" LABEL org.opencontainers.image.source="https://github.com/CGATOxford/UMI-tools" -LABEL org.opencontainers.image.revision="52f44f5049606ac655154cf54ed53fa76b49896f" +LABEL org.opencontainers.image.revision="aa43543e1fb609901d09b7a9f0c5e72707cb47a4" LABEL org.opencontainers.image.version="main" VIASHDOCKER diff --git a/target/nextflow/agat/agat_convert_bed2gff/.config.vsh.yaml b/target/nextflow/agat/agat_convert_bed2gff/.config.vsh.yaml index 5a504fbb..74d95755 100644 --- a/target/nextflow/agat/agat_convert_bed2gff/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_bed2gff/.config.vsh.yaml @@ -235,9 +235,9 @@ build_info: output: "target/nextflow/agat/agat_convert_bed2gff" executable: "target/nextflow/agat/agat_convert_bed2gff/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/agat/agat_convert_bed2gff/main.nf b/target/nextflow/agat/agat_convert_bed2gff/main.nf index fd90156a..070e7441 100644 --- a/target/nextflow/agat/agat_convert_bed2gff/main.nf +++ b/target/nextflow/agat/agat_convert_bed2gff/main.nf @@ -3092,9 +3092,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_bed2gff", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/agat/agat_convert_embl2gff/.config.vsh.yaml b/target/nextflow/agat/agat_convert_embl2gff/.config.vsh.yaml index a8179014..ed155150 100644 --- a/target/nextflow/agat/agat_convert_embl2gff/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_embl2gff/.config.vsh.yaml @@ -225,9 +225,9 @@ build_info: output: "target/nextflow/agat/agat_convert_embl2gff" executable: "target/nextflow/agat/agat_convert_embl2gff/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/agat/agat_convert_embl2gff/main.nf b/target/nextflow/agat/agat_convert_embl2gff/main.nf index 5f822e39..e5405e5a 100644 --- a/target/nextflow/agat/agat_convert_embl2gff/main.nf +++ b/target/nextflow/agat/agat_convert_embl2gff/main.nf @@ -3085,9 +3085,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_embl2gff", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/agat/agat_convert_genscan2gff/.config.vsh.yaml b/target/nextflow/agat/agat_convert_genscan2gff/.config.vsh.yaml index 59b91b2c..029ab91f 100644 --- a/target/nextflow/agat/agat_convert_genscan2gff/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_genscan2gff/.config.vsh.yaml @@ -230,9 +230,9 @@ build_info: output: "target/nextflow/agat/agat_convert_genscan2gff" executable: "target/nextflow/agat/agat_convert_genscan2gff/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/agat/agat_convert_genscan2gff/main.nf b/target/nextflow/agat/agat_convert_genscan2gff/main.nf index 53486c7b..94c235c2 100644 --- a/target/nextflow/agat/agat_convert_genscan2gff/main.nf +++ b/target/nextflow/agat/agat_convert_genscan2gff/main.nf @@ -3087,9 +3087,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_genscan2gff", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml b/target/nextflow/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml index 002de914..1e529b2d 100644 --- a/target/nextflow/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml @@ -228,9 +228,9 @@ build_info: output: "target/nextflow/agat/agat_convert_sp_gff2gtf" executable: "target/nextflow/agat/agat_convert_sp_gff2gtf/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/agat/agat_convert_sp_gff2gtf/main.nf b/target/nextflow/agat/agat_convert_sp_gff2gtf/main.nf index 22541ce6..3886681e 100644 --- a/target/nextflow/agat/agat_convert_sp_gff2gtf/main.nf +++ b/target/nextflow/agat/agat_convert_sp_gff2gtf/main.nf @@ -3068,9 +3068,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_sp_gff2gtf", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml b/target/nextflow/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml index d51d52ee..626202b6 100644 --- a/target/nextflow/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml @@ -188,9 +188,9 @@ build_info: output: "target/nextflow/agat/agat_convert_sp_gff2tsv" executable: "target/nextflow/agat/agat_convert_sp_gff2tsv/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/agat/agat_convert_sp_gff2tsv/main.nf b/target/nextflow/agat/agat_convert_sp_gff2tsv/main.nf index d7e23757..f173da04 100644 --- a/target/nextflow/agat/agat_convert_sp_gff2tsv/main.nf +++ b/target/nextflow/agat/agat_convert_sp_gff2tsv/main.nf @@ -3046,9 +3046,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_sp_gff2tsv", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml b/target/nextflow/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml index bfa89c8d..08454fd5 100644 --- a/target/nextflow/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml @@ -195,9 +195,9 @@ build_info: output: "target/nextflow/agat/agat_convert_sp_gxf2gxf" executable: "target/nextflow/agat/agat_convert_sp_gxf2gxf/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/agat/agat_convert_sp_gxf2gxf/main.nf b/target/nextflow/agat/agat_convert_sp_gxf2gxf/main.nf index 8a9f2276..9483023f 100644 --- a/target/nextflow/agat/agat_convert_sp_gxf2gxf/main.nf +++ b/target/nextflow/agat/agat_convert_sp_gxf2gxf/main.nf @@ -3046,9 +3046,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_sp_gxf2gxf", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/agat/agat_sp_add_introns/.config.vsh.yaml b/target/nextflow/agat/agat_sp_add_introns/.config.vsh.yaml index ecd1c859..83a50490 100644 --- a/target/nextflow/agat/agat_sp_add_introns/.config.vsh.yaml +++ b/target/nextflow/agat/agat_sp_add_introns/.config.vsh.yaml @@ -186,9 +186,9 @@ build_info: output: "target/nextflow/agat/agat_sp_add_introns" executable: "target/nextflow/agat/agat_sp_add_introns/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/agat/agat_sp_add_introns/main.nf b/target/nextflow/agat/agat_sp_add_introns/main.nf index e7cc1aba..6aa25e0d 100644 --- a/target/nextflow/agat/agat_sp_add_introns/main.nf +++ b/target/nextflow/agat/agat_sp_add_introns/main.nf @@ -3049,9 +3049,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_sp_add_introns", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/.config.vsh.yaml b/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/.config.vsh.yaml new file mode 100644 index 00000000..dd47e0a0 --- /dev/null +++ b/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/.config.vsh.yaml @@ -0,0 +1,263 @@ +name: "agat_sp_filter_feature_from_kill_list" +namespace: "agat" +version: "main" +authors: +- name: "Leïla Paquay" + roles: + - "author" + - "maintainer" + info: + links: + email: "leila@data-intuitive.com" + github: "Leila011" + linkedin: "leilapaquay" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Software Developer" +argument_groups: +- name: "Inputs" + arguments: + - type: "file" + name: "--gff" + alternatives: + - "-f" + - "--ref" + - "--reffile" + description: "Input GFF3 file that will be read." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--kill_list" + alternatives: + - "--kl" + description: "Text file containing the kill list. One value per line." + info: null + example: + - "kill_list.txt" + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + - "--out" + description: "Path to the output GFF file that contains filtered features. \n" + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Arguments" + arguments: + - type: "string" + name: "--type" + alternatives: + - "-p" + - "-l" + description: "Primary tag option, case insensitive, list. Allow to specify the\ + \ feature types that \nwill be handled. \n\nYou can specify a specific feature\ + \ by giving its primary tag name (column 3) as: \n\n * cds\n * Gene\n * mRNA\n\ + \ \nYou can specify directly all the feature of a particular\nlevel: \n\n \ + \ * level2=mRNA,ncRNA,tRNA,etc \n * level3=CDS,exon,UTR,etc. \n\nBy default\ + \ all features are taken into account. Fill the option with the value \"all\"\ + \ will \nhave the same behaviour.\n" + info: null + required: false + direction: "input" + multiple: true + multiple_sep: ";" + - type: "string" + name: "--attribute" + alternatives: + - "-a" + description: "Attribute tag to specify the attribute to analyse. Case sensitive.\ + \ Default: ID\n" + info: null + example: + - "ID" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--config" + alternatives: + - "-c" + description: "AGAT config file. By default AGAT takes the original agat_config.yaml\ + \ shipped with AGAT.\nThe `--config` option gives you the possibility to use\ + \ your own AGAT config file (located \nelsewhere or named differently).\n" + info: null + example: + - "custom_agat_config.yaml" + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--verbose" + alternatives: + - "-v" + description: "Verbose option for debugging purpose." + info: null + direction: "input" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Remove features based on a kill list. The default behaviour is to look\ + \ at the features's ID. \nIf the feature has an ID (case insensitive) listed among\ + \ the kill list it will be removed.\nRemoving a level1 or level2 feature will automatically\ + \ remove all linked subfeatures, and \nremoving all children of a feature will automatically\ + \ remove this feature too.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "gene annotations" +- "filtering" +- "gff" +license: "GPL-3.0" +references: + doi: + - "10.5281/zenodo.3552717" +links: + repository: "https://github.com/NBISweden/AGAT" + homepage: "https://github.com/NBISweden/AGAT" + documentation: "https://agat.readthedocs.io/en/latest/tools/agat_sp_filter_feature_from_kill_list.html" + issue_tracker: "https://github.com/NBISweden/AGAT/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "docker" + run: + - "agat --version | sed 's/AGAT\\s\\(.*\\)/agat: \"\\1\"/' > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/agat/agat_sp_filter_feature_from_kill_list/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/agat/agat_sp_filter_feature_from_kill_list" + executable: "target/nextflow/agat/agat_sp_filter_feature_from_kill_list/main.nf" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/main.nf b/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/main.nf new file mode 100644 index 00000000..42366c01 --- /dev/null +++ b/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/main.nf @@ -0,0 +1,3669 @@ +// agat_sp_filter_feature_from_kill_list main +// +// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +// Intuitive. +// +// The component may contain files which fall under a different license. The +// authors of this component should specify the license in the header of such +// files, or include a separate license file detailing the licenses of all included +// files. +// +// Component authors: +// * Leïla Paquay (author, maintainer) + +//////////////////////////// +// VDSL3 helper functions // +//////////////////////////// + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_checkArgumentType.nf' +class UnexpectedArgumentTypeException extends Exception { + String errorIdentifier + String stage + String plainName + String expectedClass + String foundClass + + // ${key ? " in module '$key'" : ""}${id ? " id '$id'" : ""} + UnexpectedArgumentTypeException(String errorIdentifier, String stage, String plainName, String expectedClass, String foundClass) { + super("Error${errorIdentifier ? " $errorIdentifier" : ""}:${stage ? " $stage" : "" } argument '${plainName}' has the wrong type. " + + "Expected type: ${expectedClass}. Found type: ${foundClass}") + this.errorIdentifier = errorIdentifier + this.stage = stage + this.plainName = plainName + this.expectedClass = expectedClass + this.foundClass = foundClass + } +} + +/** + * Checks if the given value is of the expected type. If not, an exception is thrown. + * + * @param stage The stage of the argument (input or output) + * @param par The parameter definition + * @param value The value to check + * @param errorIdentifier The identifier to use in the error message + * @return The value, if it is of the expected type + * @throws UnexpectedArgumentTypeException If the value is not of the expected type +*/ +def _checkArgumentType(String stage, Map par, Object value, String errorIdentifier) { + // expectedClass will only be != null if value is not of the expected type + def expectedClass = null + def foundClass = null + + // todo: split if need be + + if (!par.required && value == null) { + expectedClass = null + } else if (par.multiple) { + if (value !instanceof Collection) { + value = [value] + } + + // split strings + value = value.collectMany{ val -> + if (val instanceof String) { + // collect() to ensure that the result is a List and not simply an array + val.split(par.multiple_sep).collect() + } else { + [val] + } + } + + // process globs + if (par.type == "file" && par.direction == "input") { + value = value.collect{ it instanceof String ? file(it, hidden: true) : it }.flatten() + } + + // check types of elements in list + try { + value = value.collect { listVal -> + _checkArgumentType(stage, par + [multiple: false], listVal, errorIdentifier) + } + } catch (UnexpectedArgumentTypeException e) { + expectedClass = "List[${e.expectedClass}]" + foundClass = "List[${e.foundClass}]" + } + } else if (par.type == "string") { + // cast to string if need be + if (value instanceof GString) { + value = value.toString() + } + expectedClass = value instanceof String ? null : "String" + } else if (par.type == "integer") { + // cast to integer if need be + if (value instanceof String) { + try { + value = value.toInteger() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toLong() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toDouble() + } catch (NumberFormatException e) { + // do nothing + } + } + if (value instanceof java.math.BigDecimal) { + value = value.doubleValue() + } + 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 + } + } + 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) { + value = file(value, hidden: true) + } + if (value instanceof File) { + value = value.toPath() + } + 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() + } + expectedClass = value instanceof String ? null : "String" + } else { + // didn't find a match for par.type + expectedClass = par.type + } + + if (expectedClass != null) { + if (foundClass == null) { + foundClass = value.getClass().getName() + } + throw new UnexpectedArgumentTypeException(errorIdentifier, stage, par.plainName, expectedClass, foundClass) + } + + return value +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processInputValues.nf' +Map _processInputValues(Map inputs, Map config, String id, String key) { + if (!workflow.stubRun) { + config.allArguments.each { arg -> + if (arg.required) { + assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null : + "Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing" + } + } + + inputs = inputs.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid input argument" + + value = _checkArgumentType("input", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return inputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf' +Map _processOutputValues(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" + + value = _checkArgumentType("output", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return outputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf' +class IDChecker { + final def items = [] as Set + + @groovy.transform.WithWriteLock + boolean observe(String item) { + if (items.contains(item)) { + return false + } else { + items << item + return true + } + } + + @groovy.transform.WithReadLock + boolean contains(String item) { + return items.contains(item) + } + + @groovy.transform.WithReadLock + Set getItems() { + return items.clone() + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_checkUniqueIds.nf' + +/** + * Check if the ids are unique across parameter sets + * + * @param parameterSets a list of parameter sets. + */ +private void _checkUniqueIds(List>> parameterSets) { + def ppIds = parameterSets.collect{it[0]} + assert ppIds.size() == ppIds.unique().size() : "All argument sets should have unique ids. Detected ids: $ppIds" +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_getChild.nf' + +// helper functions for reading params from file // +def _getChild(parent, child) { + if (child.contains("://") || java.nio.file.Paths.get(child).isAbsolute()) { + child + } else { + def parentAbsolute = java.nio.file.Paths.get(parent).toAbsolutePath().toString() + parentAbsolute.replaceAll('/[^/]*$', "/") + child + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_parseParamList.nf' +/** + * Figure out the param list format based on the file extension + * + * @param param_list A String containing the path to the parameter list file. + * + * @return A String containing the format of the parameter list file. + */ +def _paramListGuessFormat(param_list) { + if (param_list !instanceof String) { + "asis" + } else if (param_list.endsWith(".csv")) { + "csv" + } else if (param_list.endsWith(".json") || param_list.endsWith(".jsn")) { + "json" + } else if (param_list.endsWith(".yaml") || param_list.endsWith(".yml")) { + "yaml" + } else { + "yaml_blob" + } +} + + +/** + * Read the param list + * + * @param param_list One of the following: + * - A String containing the path to the parameter list file (csv, json or yaml), + * - A yaml blob of a list of maps (yaml_blob), + * - Or a groovy list of maps (asis). + * @param config A Map of the Viash configuration. + * + * @return A List of Maps containing the parameters. + */ +def _parseParamList(param_list, Map config) { + // first determine format by extension + def paramListFormat = _paramListGuessFormat(param_list) + + def paramListPath = (paramListFormat != "asis" && paramListFormat != "yaml_blob") ? + file(param_list, hidden: true) : + null + + // get the correct parser function for the detected params_list format + def paramSets = [] + if (paramListFormat == "asis") { + paramSets = param_list + } else if (paramListFormat == "yaml_blob") { + paramSets = readYamlBlob(param_list) + } else if (paramListFormat == "yaml") { + paramSets = readYaml(paramListPath) + } else if (paramListFormat == "json") { + paramSets = readJson(paramListPath) + } else if (paramListFormat == "csv") { + paramSets = readCsv(paramListPath) + } else { + error "Format of provided --param_list not recognised.\n" + + "Found: '$paramListFormat'.\n" + + "Expected: a csv file, a json file, a yaml file,\n" + + "a yaml blob or a groovy list of maps." + } + + // data checks + assert paramSets instanceof List: "--param_list should contain a list of maps" + for (value in paramSets) { + assert value instanceof Map: "--param_list should contain a list of maps" + } + + // id is argument + def idIsArgument = config.allArguments.any{it.plainName == "id"} + + // Reformat from List to List> by adding the ID as first element of a Tuple2 + paramSets = paramSets.collect({ data -> + def id = data.id + if (!idIsArgument) { + data = data.findAll{k, v -> k != "id"} + } + [id, data] + }) + + // Split parameters with 'multiple: true' + paramSets = paramSets.collect({ id, data -> + data = _splitParams(data, config) + [id, data] + }) + + // The paths of input files inside a param_list file may have been specified relatively to the + // location of the param_list file. These paths must be made absolute. + if (paramListPath) { + paramSets = paramSets.collect({ id, data -> + def new_data = data.collectEntries{ parName, parValue -> + def par = config.allArguments.find{it.plainName == parName} + if (par && par.type == "file" && par.direction == "input") { + if (parValue instanceof Collection) { + parValue = parValue.collectMany{path -> + def x = _resolveSiblingIfNotAbsolute(path, paramListPath) + x instanceof Collection ? x : [x] + } + } else { + parValue = _resolveSiblingIfNotAbsolute(parValue, paramListPath) + } + } + [parName, parValue] + } + [id, new_data] + }) + } + + return paramSets +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_splitParams.nf' +/** + * Split parameters for arguments that accept multiple values using their separator + * + * @param paramList A Map containing parameters to split. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A Map of parameters where the parameter values have been split into a list using + * their seperator. + */ +Map _splitParams(Map parValues, Map config){ + def parsedParamValues = parValues.collectEntries { parName, parValue -> + def parameterSettings = config.allArguments.find({it.plainName == parName}) + + if (!parameterSettings) { + // if argument is not found, do not alter + return [parName, parValue] + } + if (parameterSettings.multiple) { // Check if parameter can accept multiple values + if (parValue instanceof Collection) { + parValue = parValue.collect{it instanceof String ? it.split(parameterSettings.multiple_sep) : it } + } else if (parValue instanceof String) { + parValue = parValue.split(parameterSettings.multiple_sep) + } else if (parValue == null) { + parValue = [] + } else { + parValue = [ parValue ] + } + parValue = parValue.flatten() + } + // For all parameters check if multiple values are only passed for + // arguments that allow it. Quietly simplify lists of length 1. + if (!parameterSettings.multiple && parValue instanceof Collection) { + assert parValue.size() == 1 : + "Error: argument ${parName} has too many values.\n" + + " Expected amount: 1. Found: ${parValue.size()}" + parValue = parValue[0] + } + [parName, parValue] + } + return parsedParamValues +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/channelFromParams.nf' +/** + * Parse nextflow parameters based on settings defined in a viash config. + * Return a list of parameter sets, each parameter set corresponding to + * an event in a nextflow channel. The output from this function can be used + * with Channel.fromList to create a nextflow channel with Vdsl3 formatted + * events. + * + * This function performs: + * - A filtering of the params which can be found in the config file. + * - Process the params_list argument which allows a user to to initialise + * a Vsdl3 channel with multiple parameter sets. Possible formats are + * csv, json, yaml, or simply a yaml_blob. A csv should have column names + * which correspond to the different arguments of this pipeline. A json or a yaml + * file should be a list of maps, each of which has keys corresponding to the + * arguments of the pipeline. A yaml blob can also be passed directly as a parameter. + * When passing a csv, json or yaml, relative path names are relativized to the + * location of the parameter file. + * - Combine the parameter sets into a vdsl3 Channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A list of parameters with the first element of the event being + * the event ID and the second element containing a map of the parsed parameters. + */ + +private List>> _paramsToParamSets(Map params, Map config){ + // todo: fetch key from run args + def key_ = config.name + + /* parse regular parameters (not in param_list) */ + /*************************************************/ + def globalParams = config.allArguments + .findAll { params.containsKey(it.plainName) } + .collectEntries { [ it.plainName, params[it.plainName] ] } + def globalID = params.get("id", null) + + /* process params_list arguments */ + /*********************************/ + def paramList = params.containsKey("param_list") && params.param_list != null ? + params.param_list : [] + // if (paramList instanceof String) { + // paramList = [paramList] + // } + // def paramSets = paramList.collectMany{ _parseParamList(it, config) } + // TODO: be able to process param_list when it is a list of strings + def paramSets = _parseParamList(paramList, config) + if (paramSets.isEmpty()) { + paramSets = [[null, [:]]] + } + + /* combine arguments into channel */ + /**********************************/ + def processedParams = paramSets.indexed().collect{ index, tup -> + // Process ID + def id = tup[0] ?: globalID + + if (workflow.stubRun && !id) { + // if stub run, explicitly add an id if missing + id = "stub${index}" + } + assert id != null: "Each parameter set should have at least an 'id'" + + // Process params + def parValues = globalParams + tup[1] + // // Remove parameters which are null, if the default is also null + // parValues = parValues.collectEntries{paramName, paramValue -> + // parameterSettings = config.functionality.allArguments.find({it.plainName == paramName}) + // if ( paramValue != null || parameterSettings.get("default", null) != null ) { + // [paramName, paramValue] + // } + // } + parValues = parValues.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key_}' id '${id}': '${name}' is not a valid input argument" + + if (par == null) { + return [:] + } + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + + [ name, value ] + } + + [id, parValues] + } + + // Check if ids (first element of each list) is unique + _checkUniqueIds(processedParams) + return processedParams +} + +/** + * Parse nextflow parameters based on settings defined in a viash config + * and return a nextflow channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A nextflow Channel with events. Events are formatted as a tuple that contains + * first contains the ID of the event and as second element holds a parameter map. + * + * + */ +def channelFromParams(Map params, Map config) { + def processedParams = _paramsToParamSets(params, config) + return Channel.fromList(processedParams) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/checkUniqueIds.nf' +def checkUniqueIds(Map args) { + def stopOnError = args.stopOnError == null ? args.stopOnError : true + + def idChecker = new IDChecker() + + return filter { tup -> + if (!idChecker.observe(tup[0])) { + if (stopOnError) { + error "Duplicate id: ${tup[0]}" + } else { + log.warn "Duplicate id: ${tup[0]}, removing duplicate entry" + return false + } + } + return true + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/preprocessInputs.nf' +// This helper file will be deprecated soon +preprocessInputsDeprecationWarningPrinted = false + +def preprocessInputsDeprecationWarning() { + if (!preprocessInputsDeprecationWarningPrinted) { + preprocessInputsDeprecationWarningPrinted = true + System.err.println("Warning: preprocessInputs() is deprecated and will be removed in Viash 0.9.0.") + } +} + +/** + * Generate a nextflow Workflow that allows processing a channel of + * Vdsl3 formatted events and apply a Viash config to them: + * - Gather default parameters from the Viash config and make + * sure that they are correctly formatted (see applyConfig method). + * - Format the input parameters (also using the applyConfig method). + * - Apply the default parameter to the input parameters. + * - Do some assertions: + * ~ Check if the event IDs in the channel are unique. + * + * The events in the channel are formatted as tuples, with the + * first element of the tuples being a unique id of the parameter set, + * and the second element containg the the parameters themselves. + * Optional extra elements of the tuples will be passed to the output as is. + * + * @param args A map that must contain a 'config' key that points + * to a parsed config (see readConfig()). Optionally, a + * 'key' key can be provided which can be used to create a unique + * name for the workflow process. + * + * @return A workflow that allows processing a channel of Vdsl3 formatted events + * and apply a Viash config to them. + */ +def preprocessInputs(Map args) { + preprocessInputsDeprecationWarning() + + def config = args.config + assert config instanceof Map : + "Error in preprocessInputs: config must be a map. " + + "Expected class: Map. Found: config.getClass() is ${config.getClass()}" + def key_ = args.key ?: config.name + + // Get different parameter types (used throughout this function) + def defaultArgs = config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + map { tup -> + def id = tup[0] + def data = tup[1] + def passthrough = tup.drop(2) + + def new_data = (defaultArgs + data).collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + + if (par != null) { + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + } + + [ name, value ] + } + + [ id, new_data ] + passthrough + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runComponents.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component config. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component config. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component config. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component config. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runComponents(Map args) { + log.warn("runComponents is deprecated, use runEach instead") + assert args.components: "runComponents should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runComponents" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def id_ = args.id + + workflow runComponentsWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def comp_config = comp_.config + + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_config) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + // def new_id = id_(tup[0], tup[1], comp_config) + def new_id = tup[0] + if (id_ instanceof String) { + new_id = id_ + } else if (id_ instanceof Closure) { + new_id = id_(new_id, tup[1], comp_config) + } + [new_id] + tup.drop(1) + } + : filter_ch + def data_ch = id_ch | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_config) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_config) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + post_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runComponentsWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runEach.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component itself. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component itself. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component itself. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component itself. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runEach(Map args) { + assert args.components: "runEach should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runEach" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def runIf_ = args.runIf + def id_ = args.id + + assert !runIf_ || runIf_ instanceof Closure: "runEach: must pass a Closure to runIf." + + workflow runEachWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + def new_id = id_ + if (new_id instanceof Closure) { + new_id = new_id(tup[0], tup[1], comp_) + } + assert new_id instanceof String : "Error in runEach: id should be a String or a Closure that returns a String. Expected: id instanceof String. Found: ${new_id.getClass()}" + [new_id] + tup.drop(1) + } + : filter_ch + def chPassthrough = null + def chRun = null + if (runIf_) { + def idRunIfBranch = id_ch.branch{ tup -> + run: runIf_(tup[0], tup[1], comp_) + passthrough: true + } + chPassthrough = idRunIfBranch.passthrough + chRun = idRunIfBranch.run + } else { + chRun = id_ch + chPassthrough = Channel.empty() + } + def data_ch = chRun | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + def return_ch = post_ch + | concat(chPassthrough) + + return_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runEachWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/safeJoin.nf' +/** + * Join sourceChannel to targetChannel + * + * This function joins the sourceChannel to the targetChannel. + * However, each id in the targetChannel must be present in the + * sourceChannel. If _meta.join_id exists in the targetChannel, that is + * used as an id instead. If the id doesn't match any id in the sourceChannel, + * an error is thrown. + */ + +def safeJoin(targetChannel, sourceChannel, key) { + def sourceIDs = new IDChecker() + + def sourceCheck = sourceChannel + | map { tup -> + sourceIDs.observe(tup[0]) + tup + } + def targetCheck = targetChannel + | map { tup -> + def id = tup[0] + + if (!sourceIDs.contains(id)) { + error ( + "Error in module '${key}' when merging output with original state.\n" + + " Reason: output with id '${id}' could not be joined with source channel.\n" + + " If the IDs in the output channel differ from the input channel,\n" + + " please set `tup[1]._meta.join_id to the original ID.\n" + + " Original IDs in input channel: ['${sourceIDs.getItems().join("', '")}'].\n" + + " Unexpected ID in the output channel: '${id}'.\n" + + " Example input event: [\"id\", [input: file(...)]],\n" + + " Example output event: [\"newid\", [output: file(...), _meta: [join_id: \"id\"]]]" + ) + } + // TODO: add link to our documentation on how to fix this + + tup + } + + sourceCheck.cross(targetChannel) + | map{ left, right -> + right + left.drop(1) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/_processArgument.nf' +def _processArgument(arg) { + arg.multiple = arg.multiple != null ? arg.multiple : false + arg.required = arg.required != null ? arg.required : false + arg.direction = arg.direction != null ? arg.direction : "input" + arg.multiple_sep = arg.multiple_sep != null ? arg.multiple_sep : ";" + arg.plainName = arg.name.replaceAll("^-*", "") + + if (arg.type == "file") { + arg.must_exist = arg.must_exist != null ? arg.must_exist : true + arg.create_parent = arg.create_parent != null ? arg.create_parent : true + } + + // add default values to output files which haven't already got a default + if (arg.type == "file" && arg.direction == "output" && arg.default == null) { + def mult = arg.multiple ? "_*" : "" + def extSearch = "" + if (arg.default != null) { + extSearch = arg.default + } else if (arg.example != null) { + extSearch = arg.example + } + if (extSearch instanceof List) { + extSearch = extSearch[0] + } + def extSearchResult = extSearch.find("\\.[^\\.]+\$") + def ext = extSearchResult != null ? extSearchResult : "" + arg.default = "\$id.\$key.${arg.plainName}${mult}${ext}" + if (arg.multiple) { + arg.default = [arg.default] + } + } + + if (!arg.multiple) { + if (arg.default != null && arg.default instanceof List) { + arg.default = arg.default[0] + } + if (arg.example != null && arg.example instanceof List) { + arg.example = arg.example[0] + } + } + + if (arg.type == "boolean_true") { + arg.default = false + } + if (arg.type == "boolean_false") { + arg.default = true + } + + arg +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/addGlobalParams.nf' +def addGlobalArguments(config) { + def localConfig = [ + "argument_groups": [ + [ + "name": "Nextflow input-output arguments", + "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.", + "arguments" : [ + [ + 'name': '--publish_dir', + 'required': true, + 'type': 'string', + 'description': 'Path to an output directory.', + 'example': 'output/', + 'multiple': false + ], + [ + 'name': '--param_list', + 'required': false, + 'type': 'string', + 'description': '''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. + | + |* 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: [ ['id': 'foo', 'input': 'foo.txt'], ['id': 'bar', 'input': 'bar.txt'] ]`. + |* 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`. + |* 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 `[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]`. + |* A yaml blob can also be passed directly as a string. Example: `--param_list "[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]"`. + | + |When 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.'''.stripMargin(), + 'example': 'my_params.yaml', + 'multiple': false, + 'hidden': true + ] + // TODO: allow multiple: true in param_list? + // TODO: allow to specify a --param_list_regex to filter the param_list? + // TODO: allow to specify a --param_list_from_state to remap entries in the param_list? + ] + ] + ] + ] + + return processConfig(_mergeMap(config, localConfig)) +} + +def _mergeMap(Map lhs, Map rhs) { + return rhs.inject(lhs.clone()) { map, entry -> + if (map[entry.key] instanceof Map && entry.value instanceof Map) { + map[entry.key] = _mergeMap(map[entry.key], entry.value) + } else if (map[entry.key] instanceof Collection && entry.value instanceof Collection) { + map[entry.key] += entry.value + } else { + map[entry.key] = entry.value + } + return map + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/generateHelp.nf' +def _generateArgumentHelp(param) { + // alternatives are not supported + // def names = param.alternatives ::: List(param.name) + + def unnamedProps = [ + ["required parameter", param.required], + ["multiple values allowed", param.multiple], + ["output", param.direction.toLowerCase() == "output"], + ["file must exist", param.type == "file" && param.must_exist] + ].findAll{it[1]}.collect{it[0]} + + def dflt = null + if (param.default != null) { + if (param.default instanceof List) { + dflt = param.default.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + dflt = param.default.toString() + } + } + def example = null + if (param.example != null) { + if (param.example instanceof List) { + example = param.example.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + example = param.example.toString() + } + } + def min = param.min?.toString() + def max = param.max?.toString() + + def escapeChoice = { choice -> + def s1 = choice.replaceAll("\\n", "\\\\n") + def s2 = s1.replaceAll("\"", """\\\"""") + s2.contains(",") || s2 != choice ? "\"" + s2 + "\"" : s2 + } + def choices = param.choices == null ? + null : + "[ " + param.choices.collect{escapeChoice(it.toString())}.join(", ") + " ]" + + def namedPropsStr = [ + ["type", ([param.type] + unnamedProps).join(", ")], + ["default", dflt], + ["example", example], + ["choices", choices], + ["min", min], + ["max", max] + ] + .findAll{it[1]} + .collect{"\n " + it[0] + ": " + it[1].replaceAll("\n", "\\n")} + .join("") + + def descStr = param.description == null ? + "" : + _paragraphWrap("\n" + param.description.trim(), 80 - 8).join("\n ") + + "\n --" + param.plainName + + namedPropsStr + + descStr +} + +// Based on Helper.generateHelp() in Helper.scala +def _generateHelp(config) { + def fun = config + + // PART 1: NAME AND VERSION + def nameStr = fun.name + + (fun.version == null ? "" : " " + fun.version) + + // PART 2: DESCRIPTION + def descrStr = fun.description == null ? + "" : + "\n\n" + _paragraphWrap(fun.description.trim(), 80).join("\n") + + // PART 3: Usage + def usageStr = fun.usage == null ? + "" : + "\n\nUsage:\n" + fun.usage.trim() + + // PART 4: Options + def argGroupStrs = fun.allArgumentGroups.collect{argGroup -> + def name = argGroup.name + def descriptionStr = argGroup.description == null ? + "" : + "\n " + _paragraphWrap(argGroup.description.trim(), 80-4).join("\n ") + "\n" + def arguments = argGroup.arguments.collect{arg -> + arg instanceof String ? fun.allArguments.find{it.plainName == arg} : arg + }.findAll{it != null} + def argumentStrs = arguments.collect{param -> _generateArgumentHelp(param)} + + "\n\n$name:" + + descriptionStr + + argumentStrs.join("\n") + } + + // FINAL: combine + def out = nameStr + + descrStr + + usageStr + + argGroupStrs.join("") + + return out +} + +// based on Format._paragraphWrap +def _paragraphWrap(str, maxLength) { + def outLines = [] + str.split("\n").each{par -> + def words = par.split("\\s").toList() + + def word = null + def line = words.pop() + while(!words.isEmpty()) { + word = words.pop() + if (line.length() + word.length() + 1 <= maxLength) { + line = line + " " + word + } else { + outLines.add(line) + line = word + } + } + if (words.isEmpty()) { + outLines.add(line) + } + } + return outLines +} + +def helpMessage(config) { + if (params.containsKey("help") && params.help) { + def mergedConfig = addGlobalArguments(config) + def helpStr = _generateHelp(mergedConfig) + println(helpStr) + exit 0 + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/processConfig.nf' +def processConfig(config) { + // set defaults for arguments + config.arguments = + (config.arguments ?: []).collect{_processArgument(it)} + + // set defaults for argument_group arguments + config.argument_groups = + (config.argument_groups ?: []).collect{grp -> + grp.arguments = (grp.arguments ?: []).collect{_processArgument(it)} + grp + } + + // create combined arguments list + config.allArguments = + config.arguments + + config.argument_groups.collectMany{it.arguments} + + // add missing argument groups (based on Functionality::allArgumentGroups()) + def argGroups = config.argument_groups + if (argGroups.any{it.name.toLowerCase() == "arguments"}) { + argGroups = argGroups.collect{ grp -> + if (grp.name.toLowerCase() == "arguments") { + grp = grp + [ + arguments: grp.arguments + config.arguments + ] + } + grp + } + } else { + argGroups = argGroups + [ + name: "Arguments", + arguments: config.arguments + ] + } + config.allArgumentGroups = argGroups + + config +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/readConfig.nf' + +def readConfig(file) { + def config = readYaml(file ?: moduleDir.resolve("config.vsh.yaml")) + processConfig(config) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_resolveSiblingIfNotAbsolute.nf' +/** + * Resolve a path relative to the current file. + * + * @param str The path to resolve, as a String. + * @param parentPath The path to resolve relative to, as a Path. + * + * @return The path that may have been resovled, as a Path. + */ +def _resolveSiblingIfNotAbsolute(str, parentPath) { + if (str !instanceof String) { + return str + } + if (!_stringIsAbsolutePath(str)) { + return parentPath.resolveSibling(str) + } else { + return file(str, hidden: true) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_stringIsAbsolutePath.nf' +/** + * Check whether a path as a string is absolute. + * + * In the past, we tried using `file(., relative: true).isAbsolute()`, + * but the 'relative' option was added in 22.10.0. + * + * @param path The path to check, as a String. + * + * @return Whether the path is absolute, as a boolean. + */ +def _stringIsAbsolutePath(path) { + def _resolve_URL_PROTOCOL = ~/^([a-zA-Z][a-zA-Z0-9]*:)?\\/.+/ + + assert path instanceof String + return _resolve_URL_PROTOCOL.matcher(path).matches() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/collectTraces.nf' +class CustomTraceObserver implements nextflow.trace.TraceObserver { + List traces + + CustomTraceObserver(List traces) { + this.traces = traces + } + + @Override + void onProcessComplete(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } + + @Override + void onProcessCached(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } +} + +def collectTraces() { + def traces = Collections.synchronizedList([]) + + // add custom trace observer which stores traces in the traces object + session.observers.add(new CustomTraceObserver(traces)) + + traces +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/deepClone.nf' +/** + * Performs a deep clone of the given object. + * @param x an object + */ +def deepClone(x) { + iterateMap(x, {it instanceof Cloneable ? it.clone() : it}) +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getPublishDir.nf' +def getPublishDir() { + return params.containsKey("publish_dir") ? params.publish_dir : + params.containsKey("publishDir") ? params.publishDir : + null +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getRootDir.nf' + +// Recurse upwards until we find a '.build.yaml' file +def _findBuildYamlFile(pathPossiblySymlink) { + def path = pathPossiblySymlink.toRealPath() + def child = path.resolve(".build.yaml") + if (java.nio.file.Files.isDirectory(path) && java.nio.file.Files.exists(child)) { + return child + } else { + def parent = path.getParent() + if (parent == null) { + return null + } else { + return _findBuildYamlFile(parent) + } + } +} + +// get the root of the target folder +def getRootDir() { + def dir = _findBuildYamlFile(meta.resources_dir) + assert dir != null: "Could not find .build.yaml in the folder structure" + dir.getParent() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/iterateMap.nf' +/** + * Recursively apply a function over the leaves of an object. + * @param obj The object to iterate over. + * @param fun The function to apply to each value. + * @return The object with the function applied to each value. + */ +def iterateMap(obj, fun) { + if (obj instanceof List && obj !instanceof String) { + return obj.collect{item -> + iterateMap(item, fun) + } + } else if (obj instanceof Map) { + return obj.collectEntries{key, item -> + [key.toString(), iterateMap(item, fun)] + } + } else { + return fun(obj) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/niceView.nf' +/** + * A view for printing the event of each channel as a YAML blob. + * This is useful for debugging. + */ +def niceView() { + workflow niceViewWf { + take: input + main: + output = input + | view{toYamlBlob(it)} + emit: output + } + return niceViewWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readCsv.nf' + +def readCsv(file_path) { + def output = [] + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + + // todo: allow escaped quotes in string + // todo: allow single quotes? + def splitRegex = java.util.regex.Pattern.compile(''',(?=(?:[^"]*"[^"]*")*[^"]*$)''') + def removeQuote = java.util.regex.Pattern.compile('''"(.*)"''') + + def br = java.nio.file.Files.newBufferedReader(inputFile) + + def row = -1 + def header = null + while (br.ready() && header == null) { + def line = br.readLine() + row++ + if (!line.startsWith("#")) { + header = splitRegex.split(line, -1).collect{field -> + m = removeQuote.matcher(field) + m.find() ? m.replaceFirst('$1') : field + } + } + } + assert header != null: "CSV file should contain a header" + + while (br.ready()) { + def line = br.readLine() + row++ + if (line == null) { + br.close() + break + } + + if (!line.startsWith("#")) { + def predata = splitRegex.split(line, -1) + def data = predata.collect{field -> + if (field == "") { + return null + } + def m = removeQuote.matcher(field) + if (m.find()) { + return m.replaceFirst('$1') + } else { + return field + } + } + assert header.size() == data.size(): "Row $row should contain the same number as fields as the header" + + def dataMap = [header, data].transpose().collectEntries().findAll{it.value != null} + output.add(dataMap) + } + } + + output +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJson.nf' +def readJson(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parse(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJsonBlob.nf' +def readJsonBlob(str) { + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parseText(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readTaggedYaml.nf' +// Custom constructor to modify how certain objects are parsed from YAML +class CustomConstructor extends org.yaml.snakeyaml.constructor.Constructor { + Path root + + class ConstructPath extends org.yaml.snakeyaml.constructor.AbstractConstruct { + public Object construct(org.yaml.snakeyaml.nodes.Node node) { + String filename = (String) constructScalar(node); + if (root != null) { + return root.resolve(filename); + } + return java.nio.file.Paths.get(filename); + } + } + + CustomConstructor(org.yaml.snakeyaml.LoaderOptions options, Path root) { + super(options) + this.root = root + // Handling !file tag and parse it back to a File type + this.yamlConstructors.put(new org.yaml.snakeyaml.nodes.Tag("!file"), new ConstructPath()) + } +} + +def readTaggedYaml(Path path) { + def options = new org.yaml.snakeyaml.LoaderOptions() + def constructor = new CustomConstructor(options, path.getParent()) + def yaml = new org.yaml.snakeyaml.Yaml(constructor) + return yaml.load(path.text) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYaml.nf' +def readYaml(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYamlBlob.nf' +def readYamlBlob(str) { + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toJsonBlob.nf' +String toJsonBlob(data) { + return groovy.json.JsonOutput.toJson(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toTaggedYamlBlob.nf' +// Custom representer to modify how certain objects are represented in YAML +class CustomRepresenter extends org.yaml.snakeyaml.representer.Representer { + Path relativizer + + class RepresentPath implements org.yaml.snakeyaml.representer.Represent { + public String getFileName(Object obj) { + if (obj instanceof File) { + obj = ((File) obj).toPath(); + } + if (obj !instanceof Path) { + throw new IllegalArgumentException("Object: " + obj + " is not a Path or File"); + } + def path = (Path) obj; + + if (relativizer != null) { + return relativizer.relativize(path).toString() + } else { + return path.toString() + } + } + + public org.yaml.snakeyaml.nodes.Node representData(Object data) { + String filename = getFileName(data); + def tag = new org.yaml.snakeyaml.nodes.Tag("!file"); + return representScalar(tag, filename); + } + } + CustomRepresenter(org.yaml.snakeyaml.DumperOptions options, Path relativizer) { + super(options) + this.relativizer = relativizer + this.representers.put(sun.nio.fs.UnixPath, new RepresentPath()) + this.representers.put(Path, new RepresentPath()) + this.representers.put(File, new RepresentPath()) + } +} + +String toTaggedYamlBlob(data) { + return toRelativeTaggedYamlBlob(data, null) +} +String toRelativeTaggedYamlBlob(data, Path relativizer) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + def representer = new CustomRepresenter(options, relativizer) + def yaml = new org.yaml.snakeyaml.Yaml(representer, options) + return yaml.dump(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toYamlBlob.nf' +String toYamlBlob(data) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + options.setPrettyFlow(true) + def yaml = new org.yaml.snakeyaml.Yaml(options) + def cleanData = iterateMap(data, { it instanceof Path ? it.toString() : it }) + return yaml.dump(cleanData) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeJson.nf' +void writeJson(data, file) { + assert data: "writeJson: data should not be null" + assert file: "writeJson: file should not be null" + file.write(toJsonBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeYaml.nf' +void writeYaml(data, file) { + assert data: "writeYaml: data should not be null" + assert file: "writeYaml: file should not be null" + file.write(toYamlBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/findStates.nf' +def findStates(Map params, Map config) { + def auto_config = deepClone(config) + def auto_params = deepClone(params) + + auto_config = auto_config.clone() + // override arguments + auto_config.argument_groups = [] + auto_config.arguments = [ + [ + type: "string", + name: "--id", + description: "A dummy identifier", + required: false + ], + [ + type: "file", + name: "--input_states", + example: "/path/to/input/directory/**/state.yaml", + description: "Path to input directory containing the datasets to be integrated.", + required: true, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--filter", + example: "foo/.*/state.yaml", + description: "Regex to filter state files by path.", + required: false + ], + // to do: make this a yaml blob? + [ + type: "string", + name: "--rename_keys", + example: ["newKey1:oldKey1", "newKey2:oldKey2"], + description: "Rename keys in the detected input files. This is useful if the input files do not match the set of input arguments of the workflow.", + required: false, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--settings", + example: '{"output_dataset": "dataset.h5ad", "k": 10}', + description: "Global arguments as a JSON glob to be passed to all components.", + required: false + ] + ] + if (!(auto_params.containsKey("id"))) { + auto_params["id"] = "auto" + } + + // run auto config through processConfig once more + auto_config = processConfig(auto_config) + + workflow findStatesWf { + helpMessage(auto_config) + + output_ch = + channelFromParams(auto_params, auto_config) + | flatMap { autoId, args -> + + def globalSettings = args.settings ? readYamlBlob(args.settings) : [:] + + // look for state files in input dir + def stateFiles = args.input_states + + // filter state files by regex + if (args.filter) { + stateFiles = stateFiles.findAll{ stateFile -> + def stateFileStr = stateFile.toString() + def matcher = stateFileStr =~ args.filter + matcher.matches()} + } + + // read in states + def states = stateFiles.collect { stateFile -> + def state_ = readTaggedYaml(stateFile) + [state_.id, state_] + } + + // construct renameMap + if (args.rename_keys) { + def renameMap = args.rename_keys.collectEntries{renameString -> + def split = renameString.split(":") + assert split.size() == 2: "Argument 'rename_keys' should be of the form 'newKey:oldKey', or 'newKey:oldKey;newKey:oldKey' in case of multiple values" + split + } + + // rename keys in state, only let states through which have all keys + // also add global settings + states = states.collectMany{id, state -> + def newState = [:] + + for (key in renameMap.keySet()) { + def origKey = renameMap[key] + if (!(state.containsKey(origKey))) { + return [] + } + newState[key] = state[origKey] + } + + [[id, globalSettings + newState]] + } + } + + states + } + emit: + output_ch + } + + return findStatesWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/joinStates.nf' +def joinStates(Closure apply_) { + workflow joinStatesWf { + take: input_ch + main: + output_ch = input_ch + | toSortedList + | filter{ it.size() > 0 } + | map{ tups -> + def ids = tups.collect{it[0]} + def states = tups.collect{it[1]} + apply_(ids, states) + } + + emit: output_ch + } + return joinStatesWf +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf' +def collectFiles(obj) { + if (obj instanceof java.io.File || obj instanceof Path) { + return [obj] + } else if (obj instanceof List && obj !instanceof String) { + return obj.collectMany{item -> + collectFiles(item) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectFiles(item) + } + } else { + return [] + } +} + +/** + * Recurse through a state and collect all input files and their target output filenames. + * @param obj The state to recurse through. + * @param prefix The prefix to prepend to the output filenames. + */ +def collectInputOutputPaths(obj, prefix) { + if (obj instanceof File || obj instanceof Path) { + def path = obj instanceof Path ? obj : obj.toPath() + def ext = path.getFileName().toString().find("\\.[^\\.]+\$") ?: "" + def newFilename = prefix + ext + return [[obj, newFilename]] + } else if (obj instanceof List && obj !instanceof String) { + return obj.withIndex().collectMany{item, ix -> + collectInputOutputPaths(item, prefix + "_" + ix) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectInputOutputPaths(item, prefix + "." + key) + } + } else { + return [] + } +} + +def publishStates(Map args) { + def key_ = args.get("key") + def yamlTemplate_ = args.get("output_state", args.get("outputState", '$id.$key.state.yaml')) + + assert key_ != null : "publishStates: key must be specified" + + workflow publishStatesWf { + 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] + + def yamlFilename = yamlTemplate_ + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .replaceAll('\\$\\{key\\}', key_) + + // TODO: do the pathnames in state_ match up with the outputFilenames_? + + // convert state to yaml blob + def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename)) + + [id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_] + } + | publishStatesProc + emit: input_ch + } + return publishStatesWf +} +process publishStatesProc { + // todo: check publishpath? + publishDir path: "${getPublishDir()}/", mode: "copy" + tag "$id" + input: + tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles) + output: + tuple val(id), path{[yamlFile] + 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 + [] + } + } + """ +mkdir -p "\$(dirname '${yamlFile}')" +echo "Storing state as yaml" +echo '${yamlBlob}' > '${yamlFile}' +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 publishStatesByConfig(Map args) { + def config = args.get("config") + assert config != null : "publishStatesByConfig: config must be specified" + + def key_ = args.get("key", config.name) + assert key_ != null : "publishStatesByConfig: key must be specified" + + workflow publishStatesSimpleWf { + 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'] + + // TODO: allow overriding the state.yaml template + // TODO TODO: if auto.publish == "state", add output_state as an argument + def yamlTemplate = params.containsKey("output_state") ? params.output_state : '$id.$key.state.yaml' + def yamlFilename = yamlTemplate + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .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 + // - 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" } + .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 + 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 [[key: plainName_, value: value, 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 value_ = java.nio.file.Paths.get(filename_ix) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = val instanceof File ? val.toPath() : val + [value: value_, inputPath: inputPath, outputFilename: filename_ix] + } + def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key -> + [key, outputPerFile.collect{dic -> dic[key]}] + } + return [[key: plainName_] + transposedOutputs] + } else { + def value_ = java.nio.file.Paths.get(filename) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = value instanceof File ? value.toPath() : value + return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]] + } + } + + 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] + } + | publishStatesProc + emit: input_ch + } + return publishStatesSimpleWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/setState.nf' +def setState(fun) { + assert fun instanceof Closure || fun instanceof Map || fun instanceof List : + "Error in setState: Expected process argument to be a Closure, a Map, or a List. Found: class ${fun.getClass()}" + + // if fun is a List, convert to map + if (fun instanceof List) { + // check whether fun is a list[string] + assert fun.every{it instanceof CharSequence} : "Error in setState: argument is a List, but not all elements are Strings" + fun = fun.collectEntries{[it, it]} + } + + // if fun is a map, convert to closure + if (fun instanceof Map) { + // check whether fun is a map[string, string] + assert fun.values().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all values are Strings" + assert fun.keySet().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all keys are Strings" + def funMap = fun.clone() + // turn the map into a closure to be used later on + fun = { id_, state_ -> + assert state_ instanceof Map : "Error in setState: the state is not a Map" + funMap.collectMany{newkey, origkey -> + if (state_.containsKey(origkey)) { + [[newkey, state_[origkey]]] + } else { + [] + } + }.collectEntries() + } + } + + map { tup -> + def id = tup[0] + def state = tup[1] + def unfilteredState = fun(id, state) + def newState = unfilteredState.findAll{key, val -> val != null} + [id, newState] + tup.drop(2) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processAuto.nf' +// TODO: unit test processAuto +def processAuto(Map auto) { + // remove null values + auto = auto.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = ["simplifyInput", "simplifyOutput", "transcript", "publish"] + def unexpectedKeys = auto.keySet() - expectedKeys + assert unexpectedKeys.isEmpty(), "unexpected keys in auto: '${unexpectedKeys.join("', '")}'" + + // check auto.simplifyInput + assert auto.simplifyInput instanceof Boolean, "auto.simplifyInput must be a boolean" + + // check auto.simplifyOutput + assert auto.simplifyOutput instanceof Boolean, "auto.simplifyOutput must be a boolean" + + // check auto.transcript + assert auto.transcript instanceof Boolean, "auto.transcript must be a boolean" + + // check auto.publish + assert auto.publish instanceof Boolean || auto.publish == "state", "auto.publish must be a boolean or 'state'" + + return auto.subMap(expectedKeys) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processDirectives.nf' +def assertMapKeys(map, expectedKeys, requiredKeys, mapName) { + assert map instanceof Map : "Expected argument '$mapName' to be a Map. Found: class ${map.getClass()}" + map.forEach { key, val -> + assert key in expectedKeys : "Unexpected key '$key' in ${mapName ? mapName + " " : ""}map" + } + requiredKeys.forEach { requiredKey -> + assert map.containsKey(requiredKey) : "Missing required key '$key' in ${mapName ? mapName + " " : ""}map" + } +} + +// TODO: unit test processDirectives +def processDirectives(Map drctv) { + // remove null values + drctv = drctv.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = [ + "accelerator", "afterScript", "beforeScript", "cache", "conda", "container", "containerOptions", "cpus", "disk", "echo", "errorStrategy", "executor", "machineType", "maxErrors", "maxForks", "maxRetries", "memory", "module", "penv", "pod", "publishDir", "queue", "label", "scratch", "storeDir", "stageInMode", "stageOutMode", "tag", "time" + ] + def unexpectedKeys = drctv.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Unexpected keys in process directive: '${unexpectedKeys.join("', '")}'" + + /* DIRECTIVE accelerator + accepted examples: + - [ limit: 4, type: "nvidia-tesla-k80" ] + */ + if (drctv.containsKey("accelerator")) { + assertMapKeys(drctv["accelerator"], ["type", "limit", "request", "runtime"], [], "accelerator") + } + + /* DIRECTIVE afterScript + accepted examples: + - "source /cluster/bin/cleanup" + */ + if (drctv.containsKey("afterScript")) { + assert drctv["afterScript"] instanceof CharSequence + } + + /* DIRECTIVE beforeScript + accepted examples: + - "source /cluster/bin/setup" + */ + if (drctv.containsKey("beforeScript")) { + assert drctv["beforeScript"] instanceof CharSequence + } + + /* DIRECTIVE cache + accepted examples: + - true + - false + - "deep" + - "lenient" + */ + if (drctv.containsKey("cache")) { + assert drctv["cache"] instanceof CharSequence || drctv["cache"] instanceof Boolean + if (drctv["cache"] instanceof CharSequence) { + assert drctv["cache"] in ["deep", "lenient"] : "Unexpected value for cache" + } + } + + /* DIRECTIVE conda + accepted examples: + - "bwa=0.7.15" + - "bwa=0.7.15 fastqc=0.11.5" + - ["bwa=0.7.15", "fastqc=0.11.5"] + */ + if (drctv.containsKey("conda")) { + if (drctv["conda"] instanceof List) { + drctv["conda"] = drctv["conda"].join(" ") + } + assert drctv["conda"] instanceof CharSequence + } + + /* DIRECTIVE container + accepted examples: + - "foo/bar:tag" + - [ registry: "reg", image: "im", tag: "ta" ] + is transformed to "reg/im:ta" + - [ image: "im" ] + is transformed to "im:latest" + */ + if (drctv.containsKey("container")) { + assert drctv["container"] instanceof Map || drctv["container"] instanceof CharSequence + if (drctv["container"] instanceof Map) { + def m = drctv["container"] + assertMapKeys(m, [ "registry", "image", "tag" ], ["image"], "container") + def part1 = + System.getenv('OVERRIDE_CONTAINER_REGISTRY') ? System.getenv('OVERRIDE_CONTAINER_REGISTRY') + "/" : + params.containsKey("override_container_registry") ? params["override_container_registry"] + "/" : // todo: remove? + m.registry ? m.registry + "/" : + "" + def part2 = m.image + def part3 = m.tag ? ":" + m.tag : ":latest" + drctv["container"] = part1 + part2 + part3 + } + } + + /* DIRECTIVE containerOptions + accepted examples: + - "--foo bar" + - ["--foo bar", "-f b"] + */ + if (drctv.containsKey("containerOptions")) { + if (drctv["containerOptions"] instanceof List) { + drctv["containerOptions"] = drctv["containerOptions"].join(" ") + } + assert drctv["containerOptions"] instanceof CharSequence + } + + /* DIRECTIVE cpus + accepted examples: + - 1 + - 10 + */ + if (drctv.containsKey("cpus")) { + assert drctv["cpus"] instanceof Integer + } + + /* DIRECTIVE disk + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("disk")) { + assert drctv["disk"] instanceof CharSequence + // assert drctv["disk"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE echo + accepted examples: + - true + - false + */ + if (drctv.containsKey("echo")) { + assert drctv["echo"] instanceof Boolean + } + + /* DIRECTIVE errorStrategy + accepted examples: + - "terminate" + - "finish" + */ + if (drctv.containsKey("errorStrategy")) { + assert drctv["errorStrategy"] instanceof CharSequence + assert drctv["errorStrategy"] in ["terminate", "finish", "ignore", "retry"] : "Unexpected value for errorStrategy" + } + + /* DIRECTIVE executor + accepted examples: + - "local" + - "sge" + */ + if (drctv.containsKey("executor")) { + assert drctv["executor"] instanceof CharSequence + assert drctv["executor"] in ["local", "sge", "uge", "lsf", "slurm", "pbs", "pbspro", "moab", "condor", "nqsii", "ignite", "k8s", "awsbatch", "google-pipelines"] : "Unexpected value for executor" + } + + /* DIRECTIVE machineType + accepted examples: + - "n1-highmem-8" + */ + if (drctv.containsKey("machineType")) { + assert drctv["machineType"] instanceof CharSequence + } + + /* DIRECTIVE maxErrors + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxErrors")) { + assert drctv["maxErrors"] instanceof Integer + } + + /* DIRECTIVE maxForks + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxForks")) { + assert drctv["maxForks"] instanceof Integer + } + + /* DIRECTIVE maxRetries + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxRetries")) { + assert drctv["maxRetries"] instanceof Integer + } + + /* DIRECTIVE memory + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("memory")) { + assert drctv["memory"] instanceof CharSequence + // assert drctv["memory"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE module + accepted examples: + - "ncbi-blast/2.2.27" + - "ncbi-blast/2.2.27:t_coffee/10.0" + - ["ncbi-blast/2.2.27", "t_coffee/10.0"] + */ + if (drctv.containsKey("module")) { + if (drctv["module"] instanceof List) { + drctv["module"] = drctv["module"].join(":") + } + assert drctv["module"] instanceof CharSequence + } + + /* DIRECTIVE penv + accepted examples: + - "smp" + */ + if (drctv.containsKey("penv")) { + assert drctv["penv"] instanceof CharSequence + } + + /* DIRECTIVE pod + accepted examples: + - [ label: "key", value: "val" ] + - [ annotation: "key", value: "val" ] + - [ env: "key", value: "val" ] + - [ [label: "l", value: "v"], [env: "e", value: "v"]] + */ + if (drctv.containsKey("pod")) { + if (drctv["pod"] instanceof Map) { + drctv["pod"] = [ drctv["pod"] ] + } + assert drctv["pod"] instanceof List + drctv["pod"].forEach { pod -> + assert pod instanceof Map + // TODO: should more checks be added? + // See https://www.nextflow.io/docs/latest/process.html?highlight=directives#pod + // e.g. does it contain 'label' and 'value', or 'annotation' and 'value', or ...? + } + } + + /* DIRECTIVE publishDir + accepted examples: + - [] + - [ [ path: "foo", enabled: true ], [ path: "bar", enabled: false ] ] + - "/path/to/dir" + is transformed to [[ path: "/path/to/dir" ]] + - [ path: "/path/to/dir", mode: "cache" ] + is transformed to [[ path: "/path/to/dir", mode: "cache" ]] + */ + // TODO: should we also look at params["publishDir"]? + if (drctv.containsKey("publishDir")) { + def pblsh = drctv["publishDir"] + + // check different options + assert pblsh instanceof List || pblsh instanceof Map || pblsh instanceof CharSequence + + // turn into list if not already so + // for some reason, 'if (!pblsh instanceof List) pblsh = [ pblsh ]' doesn't work. + pblsh = pblsh instanceof List ? pblsh : [ pblsh ] + + // check elements of publishDir + pblsh = pblsh.collect{ elem -> + // turn into map if not already so + elem = elem instanceof CharSequence ? [ path: elem ] : elem + + // check types and keys + assert elem instanceof Map : "Expected publish argument '$elem' to be a String or a Map. Found: class ${elem.getClass()}" + assertMapKeys(elem, [ "path", "mode", "overwrite", "pattern", "saveAs", "enabled" ], ["path"], "publishDir") + + // check elements in map + assert elem.containsKey("path") + assert elem["path"] instanceof CharSequence + if (elem.containsKey("mode")) { + assert elem["mode"] instanceof CharSequence + assert elem["mode"] in [ "symlink", "rellink", "link", "copy", "copyNoFollow", "move" ] + } + if (elem.containsKey("overwrite")) { + assert elem["overwrite"] instanceof Boolean + } + if (elem.containsKey("pattern")) { + assert elem["pattern"] instanceof CharSequence + } + if (elem.containsKey("saveAs")) { + assert elem["saveAs"] instanceof CharSequence //: "saveAs as a Closure is currently not supported. Surround your closure with single quotes to get the desired effect. Example: '\{ foo \}'" + } + if (elem.containsKey("enabled")) { + assert elem["enabled"] instanceof Boolean + } + + // return final result + elem + } + // store final directive + drctv["publishDir"] = pblsh + } + + /* DIRECTIVE queue + accepted examples: + - "long" + - "short,long" + - ["short", "long"] + */ + if (drctv.containsKey("queue")) { + if (drctv["queue"] instanceof List) { + drctv["queue"] = drctv["queue"].join(",") + } + assert drctv["queue"] instanceof CharSequence + } + + /* DIRECTIVE label + accepted examples: + - "big_mem" + - "big_cpu" + - ["big_mem", "big_cpu"] + */ + if (drctv.containsKey("label")) { + if (drctv["label"] instanceof CharSequence) { + drctv["label"] = [ drctv["label"] ] + } + assert drctv["label"] instanceof List + drctv["label"].forEach { label -> + assert label instanceof CharSequence + // assert label.matches("[a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?") + // ^ does not allow closures + } + } + + /* DIRECTIVE scratch + accepted examples: + - true + - "/path/to/scratch" + - '$MY_PATH_TO_SCRATCH' + - "ram-disk" + */ + if (drctv.containsKey("scratch")) { + assert drctv["scratch"] == true || drctv["scratch"] instanceof CharSequence + } + + /* DIRECTIVE storeDir + accepted examples: + - "/path/to/storeDir" + */ + if (drctv.containsKey("storeDir")) { + assert drctv["storeDir"] instanceof CharSequence + } + + /* DIRECTIVE stageInMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageInMode")) { + assert drctv["stageInMode"] instanceof CharSequence + assert drctv["stageInMode"] in ["copy", "link", "symlink", "rellink"] + } + + /* DIRECTIVE stageOutMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageOutMode")) { + assert drctv["stageOutMode"] instanceof CharSequence + assert drctv["stageOutMode"] in ["copy", "move", "rsync"] + } + + /* DIRECTIVE tag + accepted examples: + - "foo" + - '$id' + */ + if (drctv.containsKey("tag")) { + assert drctv["tag"] instanceof CharSequence + } + + /* DIRECTIVE time + accepted examples: + - "1h" + - "2days" + - "1day 6hours 3minutes 30seconds" + */ + if (drctv.containsKey("time")) { + assert drctv["time"] instanceof CharSequence + // todo: validation regex? + } + + return drctv +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processWorkflowArgs.nf' +def processWorkflowArgs(Map args, Map defaultWfArgs, Map meta) { + // override defaults with args + def workflowArgs = defaultWfArgs + args + + // check whether 'key' exists + assert workflowArgs.containsKey("key") : "Error in module '${meta.config.name}': key is a required argument" + + // if 'key' is a closure, apply it to the original key + if (workflowArgs["key"] instanceof Closure) { + workflowArgs["key"] = workflowArgs["key"](meta.config.name) + } + def key = workflowArgs["key"] + assert key instanceof CharSequence : "Expected process argument 'key' to be a String. Found: class ${key.getClass()}" + assert key ==~ /^[a-zA-Z_]\w*$/ : "Error in module '$key': Expected process argument 'key' to consist of only letters, digits or underscores. Found: ${key}" + + // check for any unexpected keys + def expectedKeys = ["key", "directives", "auto", "map", "mapId", "mapData", "mapPassthrough", "filter", "runIf", "fromState", "toState", "args", "renameKeys", "debug"] + def unexpectedKeys = workflowArgs.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Error in module '$key': unexpected arguments to the '.run()' function: '${unexpectedKeys.join("', '")}'" + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("directives") : "Error in module '$key': directives is a required argument" + assert workflowArgs["directives"] instanceof Map : "Error in module '$key': Expected process argument 'directives' to be a Map. Found: class ${workflowArgs['directives'].getClass()}" + workflowArgs["directives"] = processDirectives(defaultWfArgs.directives + workflowArgs["directives"]) + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("auto") : "Error in module '$key': auto is a required argument" + assert workflowArgs["auto"] instanceof Map : "Error in module '$key': Expected process argument 'auto' to be a Map. Found: class ${workflowArgs['auto'].getClass()}" + workflowArgs["auto"] = processAuto(defaultWfArgs.auto + workflowArgs["auto"]) + + // auto define publish, if so desired + if (workflowArgs.auto.publish == true && (workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : [:]).isEmpty()) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.publish is true, params.publish_dir needs to be defined.\n" + + // " Example: params.publish_dir = \"./output/\"" + def publishDir = getPublishDir() + + if (publishDir != null) { + workflowArgs.directives.publishDir = [[ + path: publishDir, + saveAs: "{ it.startsWith('.') ? null : it }", // don't publish hidden files, by default + mode: "copy" + ]] + } + } + + // auto define transcript, if so desired + if (workflowArgs.auto.transcript == true) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("transcriptsDir") || params.containsKey("transcripts_dir") || params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.transcript is true, either params.transcripts_dir or params.publish_dir needs to be defined.\n" + + // " Example: params.transcripts_dir = \"./transcripts/\"" + def transcriptsDir = + params.containsKey("transcripts_dir") ? params.transcripts_dir : + params.containsKey("transcriptsDir") ? params.transcriptsDir : + params.containsKey("publish_dir") ? params.publish_dir + "/_transcripts" : + params.containsKey("publishDir") ? params.publishDir + "/_transcripts" : + null + if (transcriptsDir != null) { + def timestamp = nextflow.Nextflow.getSession().getWorkflowMetadata().start.format('yyyy-MM-dd_HH-mm-ss') + def transcriptsPublishDir = [ + path: "$transcriptsDir/$timestamp/\${task.process.replaceAll(':', '-')}/\${id}/", + saveAs: "{ it.startsWith('.') ? it.replaceAll('^.', '') : null }", + mode: "copy" + ] + def publishDirs = workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : null ? workflowArgs.directives.publishDir : [] + workflowArgs.directives.publishDir = publishDirs + transcriptsPublishDir + } + } + + // if this is a stubrun, remove certain directives? + if (workflow.stubRun) { + workflowArgs.directives.keySet().removeAll(["publishDir", "cpus", "memory", "label"]) + } + + for (nam in ["map", "mapId", "mapData", "mapPassthrough", "filter", "runIf"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam]) { + assert workflowArgs[nam] instanceof Closure : "Error in module '$key': Expected process argument '$nam' to be null or a Closure. Found: class ${workflowArgs[nam].getClass()}" + } + } + + // TODO: should functions like 'map', 'mapId', 'mapData', 'mapPassthrough' be deprecated as well? + for (nam in ["map", "mapData", "mapPassthrough", "renameKeys"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam] != null) { + log.warn "module '$key': workflow argument '$nam' is deprecated and will be removed in Viash 0.9.0. Please use 'fromState' and 'toState' instead." + } + } + + // check fromState + workflowArgs["fromState"] = _processFromState(workflowArgs.get("fromState"), key, meta.config) + + // check toState + workflowArgs["toState"] = _processToState(workflowArgs.get("toState"), key, meta.config) + + // return output + return workflowArgs +} + +def _processFromState(fromState, key_, config_) { + assert fromState == null || fromState instanceof Closure || fromState instanceof Map || fromState instanceof List : + "Error in module '$key_': Expected process argument 'fromState' to be null, a Closure, a Map, or a List. Found: class ${fromState.getClass()}" + if (fromState == null) { + return null + } + + // if fromState is a List, convert to map + if (fromState instanceof List) { + // check whether fromstate is a list[string] + assert fromState.every{it instanceof CharSequence} : "Error in module '$key_': fromState is a List, but not all elements are Strings" + fromState = fromState.collectEntries{[it, it]} + } + + // if fromState is a map, convert to closure + if (fromState instanceof Map) { + // check whether fromstate is a map[string, string] + assert fromState.values().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all values are Strings" + assert fromState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all keys are Strings" + def fromStateMap = fromState.clone() + def requiredInputNames = meta.config.allArguments.findAll{it.required && it.direction == "Input"}.collect{it.plainName} + // turn the map into a closure to be used later on + fromState = { it -> + def state = it[1] + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def data = fromStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (state.containsKey(origkey)) { + [[newkey, state[origkey]]] + } else if (!requiredInputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': fromState key '$origkey' not found in current state") + } + }.collectEntries() + data + } + } + + return fromState +} + +def _processToState(toState, key_, config_) { + if (toState == null) { + toState = { tup -> tup[1] } + } + + // toState should be a closure, map[string, string], or list[string] + assert toState instanceof Closure || toState instanceof Map || toState instanceof List : + "Error in module '$key_': Expected process argument 'toState' to be a Closure, a Map, or a List. Found: class ${toState.getClass()}" + + // if toState is a List, convert to map + if (toState instanceof List) { + // check whether toState is a list[string] + assert toState.every{it instanceof CharSequence} : "Error in module '$key_': toState is a List, but not all elements are Strings" + toState = toState.collectEntries{[it, it]} + } + + // if toState is a map, convert to closure + if (toState instanceof Map) { + // check whether toState is a map[string, string] + assert toState.values().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all values are Strings" + assert toState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all keys are Strings" + def toStateMap = toState.clone() + def requiredOutputNames = config_.allArguments.findAll{it.required && it.direction == "Output"}.collect{it.plainName} + // turn the map into a closure to be used later on + toState = { it -> + def output = it[1] + def state = it[2] + assert output instanceof Map : "Error in module '$key_': the output is not a Map" + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def extraEntries = toStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (output.containsKey(origkey)) { + [[newkey, output[origkey]]] + } else if (!requiredOutputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': toState key '$origkey' not found in current output") + } + }.collectEntries() + state + extraEntries + } + } + + return toState +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/workflowFactory.nf' +def _debug(workflowArgs, debugKey) { + if (workflowArgs.debug) { + view { "process '${workflowArgs.key}' $debugKey tuple: $it" } + } else { + map { it } + } +} + +// depends on: innerWorkflowFactory +def workflowFactory(Map args, Map defaultWfArgs, Map meta) { + def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta) + def key_ = workflowArgs["key"] + + workflow workflowInstance { + take: input_ + + main: + def chModified = input_ + | checkUniqueIds([:]) + | _debug(workflowArgs, "input") + | map { tuple -> + tuple = deepClone(tuple) + + if (workflowArgs.map) { + tuple = workflowArgs.map(tuple) + } + if (workflowArgs.mapId) { + tuple[0] = workflowArgs.mapId(tuple[0]) + } + if (workflowArgs.mapData) { + tuple[1] = workflowArgs.mapData(tuple[1]) + } + if (workflowArgs.mapPassthrough) { + tuple = tuple.take(2) + workflowArgs.mapPassthrough(tuple.drop(2)) + } + + // check tuple + assert tuple instanceof List : + "Error in module '${key_}': element in 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()}" + assert tuple.size() >= 2 : + "Error in module '${key_}': expected length of tuple in input channel to be two or greater.\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: tuple.size() == ${tuple.size()}" + + // check id field + if (tuple[0] instanceof GString) { + tuple[0] = tuple[0].toString() + } + assert tuple[0] instanceof CharSequence : + "Error in module '${key_}': first element of tuple in channel should be a String\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: ${tuple[0]}" + + // match file to input file + if (workflowArgs.auto.simplifyInput && (tuple[1] instanceof Path || tuple[1] instanceof List)) { + def inputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + + assert inputFiles.size() == 1 : + "Error in module '${key_}' id '${tuple[0]}'.\n" + + " Anonymous file inputs are only allowed when the process has exactly one file input.\n" + + " Expected: inputFiles.size() == 1. Found: inputFiles.size() is ${inputFiles.size()}" + + tuple[1] = [[ inputFiles[0].plainName, tuple[1] ]].collectEntries() + } + + // check data field + assert tuple[1] instanceof Map : + "Error in module '${key_}' id '${tuple[0]}': second element of tuple in channel should be a Map\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // rename keys of data field in tuple + if (workflowArgs.renameKeys) { + assert workflowArgs.renameKeys instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class: Map. Found: renameKeys.getClass() is ${workflowArgs.renameKeys.getClass()}" + assert tuple[1] instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // TODO: allow renameKeys to be a function? + workflowArgs.renameKeys.each { newKey, oldKey -> + assert newKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of newKey: String. Found: newKey.getClass() is ${newKey.getClass()}" + assert oldKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of oldKey: String. Found: oldKey.getClass() is ${oldKey.getClass()}" + assert tuple[1].containsKey(oldKey) : + "Error renaming data keys in module '${key}' id '${tuple[0]}'.\n" + + " Key '$oldKey' is missing in the data map. tuple[1].keySet() is '${tuple[1].keySet()}'" + tuple[1].put(newKey, tuple[1][oldKey]) + } + tuple[1].keySet().removeAll(workflowArgs.renameKeys.collect{ newKey, oldKey -> oldKey }) + } + tuple + } + + + def chRun = null + def chPassthrough = null + if (workflowArgs.runIf) { + def runIfBranch = chModified.branch{ tup -> + run: workflowArgs.runIf(tup[0], tup[1]) + passthrough: true + } + chRun = runIfBranch.run + chPassthrough = runIfBranch.passthrough + } else { + chRun = chModified + chPassthrough = Channel.empty() + } + + def chRunFiltered = workflowArgs.filter ? + chRun | filter{workflowArgs.filter(it)} : + chRun + + def chArgs = workflowArgs.fromState ? + chRunFiltered | map{ + def new_data = workflowArgs.fromState(it.take(2)) + [it[0], new_data] + } : + chRunFiltered | map {tup -> tup.take(2)} + + // fill in defaults + def chArgsWithDefaults = chArgs + | map { tuple -> + def id_ = tuple[0] + def data_ = tuple[1] + + // TODO: could move fromState to here + + // fetch default params from functionality + def defaultArgs = meta.config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + // fetch overrides in params + def paramArgs = meta.config.allArguments + .findAll { par -> + def argKey = key_ + "__" + par.plainName + params.containsKey(argKey) + } + .collectEntries { [ it.plainName, params[key_ + "__" + it.plainName] ] } + + // fetch overrides in data + def dataArgs = meta.config.allArguments + .findAll { data_.containsKey(it.plainName) } + .collectEntries { [ it.plainName, data_[it.plainName] ] } + + // combine params + def combinedArgs = defaultArgs + paramArgs + workflowArgs.args + dataArgs + + // remove arguments with explicit null values + combinedArgs + .removeAll{_, val -> val == null || val == "viash_no_value" || val == "force_null"} + + combinedArgs = _processInputValues(combinedArgs, meta.config, id_, key_) + + [id_, combinedArgs] + tuple.drop(2) + } + + // TODO: move some of the _meta.join_id wrangling to the safeJoin() function. + def chInitialOutput = chArgsWithDefaults + | _debug(workflowArgs, "processed") + // run workflow + | innerWorkflowFactory(workflowArgs) + // check output tuple + | map { id_, output_ -> + + // see if output map contains metadata + def meta_ = + output_ instanceof Map && output_.containsKey("_meta") ? + output_["_meta"] : + [:] + def join_id = meta_.join_id ?: id_ + + // remove metadata + output_ = output_.findAll{k, v -> k != "_meta"} + + // check value types + output_ = _processOutputValues(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_] + } + // | view{"chInitialOutput: ${it.take(3)}"} + + // join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...] + def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_) + // input tuple format: [join_id, id, output, prev_state, ...] + // output tuple format: [join_id, id, new_state, ...] + | map{ tup -> + def new_state = workflowArgs.toState(tup.drop(1).take(3)) + tup.take(2) + [new_state] + tup.drop(4) + } + + if (workflowArgs.auto.publish == "state") { + def chPublish = 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_) + // 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, ...] + // output tuple format: [id, new_state, ...] + tup.drop(1) + } + | _debug(workflowArgs, "output") + | concat(chPassthrough) + + emit: chReturn + } + + def wf = workflowInstance.cloneWithName(key_) + + // add factory function + wf.metaClass.run = { runArgs -> + workflowFactory(runArgs, workflowArgs, meta) + } + // add config to module for later introspection + wf.metaClass.config = meta.config + + return wf +} + +nextflow.enable.dsl=2 + +// START COMPONENT-SPECIFIC CODE + +// create meta object +meta = [ + "resources_dir": moduleDir.toRealPath().normalize(), + "config": processConfig(readJsonBlob('''{ + "name" : "agat_sp_filter_feature_from_kill_list", + "namespace" : "agat", + "version" : "main", + "authors" : [ + { + "name" : "Leïla Paquay", + "roles" : [ + "author", + "maintainer" + ], + "info" : { + "links" : { + "email" : "leila@data-intuitive.com", + "github" : "Leila011", + "linkedin" : "leilapaquay" + }, + "organizations" : [ + { + "name" : "Data Intuitive", + "href" : "https://www.data-intuitive.com", + "role" : "Software Developer" + } + ] + } + } + ], + "argument_groups" : [ + { + "name" : "Inputs", + "arguments" : [ + { + "type" : "file", + "name" : "--gff", + "alternatives" : [ + "-f", + "--ref", + "--reffile" + ], + "description" : "Input GFF3 file that will be read.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--kill_list", + "alternatives" : [ + "--kl" + ], + "description" : "Text file containing the kill list. One value per line.", + "example" : [ + "kill_list.txt" + ], + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Outputs", + "arguments" : [ + { + "type" : "file", + "name" : "--output", + "alternatives" : [ + "-o", + "--out" + ], + "description" : "Path to the output GFF file that contains filtered features. \n", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Arguments", + "arguments" : [ + { + "type" : "string", + "name" : "--type", + "alternatives" : [ + "-p", + "-l" + ], + "description" : "Primary tag option, case insensitive, list. Allow to specify the feature types that \nwill be handled. \n\nYou can specify a specific feature by giving its primary tag name (column 3) as: \n\n * cds\n * Gene\n * mRNA\n \nYou can specify directly all the feature of a particular\nlevel: \n\n * level2=mRNA,ncRNA,tRNA,etc \n * level3=CDS,exon,UTR,etc. \n\nBy default all features are taken into account. Fill the option with the value \\"all\\" will \nhave the same behaviour.\n", + "required" : false, + "direction" : "input", + "multiple" : true, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--attribute", + "alternatives" : [ + "-a" + ], + "description" : "Attribute tag to specify the attribute to analyse. Case sensitive. Default: ID\n", + "example" : [ + "ID" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--config", + "alternatives" : [ + "-c" + ], + "description" : "AGAT config file. By default AGAT takes the original agat_config.yaml shipped with AGAT.\nThe `--config` option gives you the possibility to use your own AGAT config file (located \nelsewhere or named differently).\n", + "example" : [ + "custom_agat_config.yaml" + ], + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--verbose", + "alternatives" : [ + "-v" + ], + "description" : "Verbose option for debugging purpose.", + "direction" : "input" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Remove features based on a kill list. The default behaviour is to look at the features's ID. \nIf the feature has an ID (case insensitive) listed among the kill list it will be removed.\nRemoving a level1 or level2 feature will automatically remove all linked subfeatures, and \nremoving all children of a feature will automatically remove this feature too.\n", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + }, + { + "type" : "file", + "path" : "test_data" + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "keywords" : [ + "gene annotations", + "filtering", + "gff" + ], + "license" : "GPL-3.0", + "references" : { + "doi" : [ + "10.5281/zenodo.3552717" + ] + }, + "links" : { + "repository" : "https://github.com/NBISweden/AGAT", + "homepage" : "https://github.com/NBISweden/AGAT", + "documentation" : "https://agat.readthedocs.io/en/latest/tools/agat_sp_filter_feature_from_kill_list.html", + "issue_tracker" : "https://github.com/NBISweden/AGAT/issues" + }, + "runners" : [ + { + "type" : "executable", + "id" : "executable", + "docker_setup_strategy" : "ifneedbepullelsecachedbuild" + }, + { + "type" : "nextflow", + "id" : "nextflow", + "directives" : { + "tag" : "$id" + }, + "auto" : { + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false + }, + "config" : { + "labels" : { + "mem1gb" : "memory = 1000000000.B", + "mem2gb" : "memory = 2000000000.B", + "mem5gb" : "memory = 5000000000.B", + "mem10gb" : "memory = 10000000000.B", + "mem20gb" : "memory = 20000000000.B", + "mem50gb" : "memory = 50000000000.B", + "mem100gb" : "memory = 100000000000.B", + "mem200gb" : "memory = 200000000000.B", + "mem500gb" : "memory = 500000000000.B", + "mem1tb" : "memory = 1000000000000.B", + "mem2tb" : "memory = 2000000000000.B", + "mem5tb" : "memory = 5000000000000.B", + "mem10tb" : "memory = 10000000000000.B", + "mem20tb" : "memory = 20000000000000.B", + "mem50tb" : "memory = 50000000000000.B", + "mem100tb" : "memory = 100000000000000.B", + "mem200tb" : "memory = 200000000000000.B", + "mem500tb" : "memory = 500000000000000.B", + "mem1gib" : "memory = 1073741824.B", + "mem2gib" : "memory = 2147483648.B", + "mem4gib" : "memory = 4294967296.B", + "mem8gib" : "memory = 8589934592.B", + "mem16gib" : "memory = 17179869184.B", + "mem32gib" : "memory = 34359738368.B", + "mem64gib" : "memory = 68719476736.B", + "mem128gib" : "memory = 137438953472.B", + "mem256gib" : "memory = 274877906944.B", + "mem512gib" : "memory = 549755813888.B", + "mem1tib" : "memory = 1099511627776.B", + "mem2tib" : "memory = 2199023255552.B", + "mem4tib" : "memory = 4398046511104.B", + "mem8tib" : "memory = 8796093022208.B", + "mem16tib" : "memory = 17592186044416.B", + "mem32tib" : "memory = 35184372088832.B", + "mem64tib" : "memory = 70368744177664.B", + "mem128tib" : "memory = 140737488355328.B", + "mem256tib" : "memory = 281474976710656.B", + "mem512tib" : "memory = 562949953421312.B", + "cpu1" : "cpus = 1", + "cpu2" : "cpus = 2", + "cpu5" : "cpus = 5", + "cpu10" : "cpus = 10", + "cpu20" : "cpus = 20", + "cpu50" : "cpus = 50", + "cpu100" : "cpus = 100", + "cpu200" : "cpus = 200", + "cpu500" : "cpus = 500", + "cpu1000" : "cpus = 1000" + } + }, + "debug" : false, + "container" : "docker" + } + ], + "engines" : [ + { + "type" : "docker", + "id" : "docker", + "image" : "quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0", + "target_registry" : "images.viash-hub.com", + "target_tag" : "main", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "docker", + "run" : [ + "agat --version | sed 's/AGAT\\\\s\\\\(.*\\\\)/agat: \\"\\\\1\\"/' > /var/software_versions.txt\n" + ] + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/agat/agat_sp_filter_feature_from_kill_list/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/agat/agat_sp_filter_feature_from_kill_list", + "viash_version" : "0.9.0", + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" + }, + "package_config" : { + "name" : "biobox", + "version" : "main", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0", + "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 := 'main'" + ], + "keywords" : [ + "bioinformatics", + "modules", + "sequencing" + ], + "license" : "MIT", + "organization" : "vsh", + "links" : { + "repository" : "https://github.com/viash-hub/biobox", + "issue_tracker" : "https://github.com/viash-hub/biobox/issues" + } + } +}''')) +] + +// resolve dependencies dependencies (if any) + + +// inner workflow +// inner workflow hook +def innerWorkflowFactory(args) { + def rawScript = '''set -e +tempscript=".viash_script.sh" +cat > "$tempscript" << VIASHMAIN +#!/bin/bash + +set -eo pipefail + +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_GFF+x} ]; then echo "${VIASH_PAR_GFF}" | sed "s#'#'\\"'\\"'#g;s#.*#par_gff='&'#" ; else echo "# par_gff="; fi ) +$( if [ ! -z ${VIASH_PAR_KILL_LIST+x} ]; then echo "${VIASH_PAR_KILL_LIST}" | sed "s#'#'\\"'\\"'#g;s#.*#par_kill_list='&'#" ; else echo "# par_kill_list="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; fi ) +$( if [ ! -z ${VIASH_PAR_TYPE+x} ]; then echo "${VIASH_PAR_TYPE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_type='&'#" ; else echo "# par_type="; fi ) +$( if [ ! -z ${VIASH_PAR_ATTRIBUTE+x} ]; then echo "${VIASH_PAR_ATTRIBUTE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_attribute='&'#" ; else echo "# par_attribute="; fi ) +$( if [ ! -z ${VIASH_PAR_CONFIG+x} ]; then echo "${VIASH_PAR_CONFIG}" | sed "s#'#'\\"'\\"'#g;s#.*#par_config='&'#" ; else echo "# par_config="; fi ) +$( if [ ! -z ${VIASH_PAR_VERBOSE+x} ]; then echo "${VIASH_PAR_VERBOSE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_verbose='&'#" ; else echo "# par_verbose="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END + +# unset flags +[[ "\\$par_verbose" == "false" ]] && unset par_verbose + +# convert par_type to comma separated list +par_type=\\$(echo \\$par_type | tr ';' ',') + +# run agat_sp_filter_feature_from_kill_list +agat_sp_filter_feature_from_kill_list.pl \\\\ + --gff "\\$par_gff" \\\\ + --kill_list "\\$par_kill_list" \\\\ + --output "\\$par_output" \\\\ + \\${par_type:+--type "\\${par_type}"} \\\\ + \\${par_attribute:+--attribute "\\${par_attribute}"} \\\\ + \\${par_config:+--config "\\${par_config}"} \\\\ + \\${par_verbose:+-v} +VIASHMAIN +bash "$tempscript" +''' + + return vdsl3WorkflowFactory(args, meta, rawScript) +} + + + +/** + * Generate a workflow for VDSL3 modules. + * + * This function is called by the workflowFactory() function. + * + * Input channel: [id, input_map] + * Output channel: [id, output_map] + * + * Internally, this workflow will convert the input channel + * to a format which the Nextflow module will be able to handle. + */ +def vdsl3WorkflowFactory(Map args, Map meta, String rawScript) { + def key = args["key"] + def processObj = null + + workflow processWf { + take: input_ + main: + + if (processObj == null) { + processObj = _vdsl3ProcessFactory(args, meta, rawScript) + } + + output_ = input_ + | map { tuple -> + def id = tuple[0] + def data_ = tuple[1] + + if (workflow.stubRun) { + // add id if missing + data_ = [id: 'stub'] + data_ + } + + // process input files separately + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { par -> + def val = data_.containsKey(par.plainName) ? data_[par.plainName] : [] + def inputFiles = [] + if (val == null) { + inputFiles = [] + } else if (val instanceof List) { + inputFiles = val + } else if (val instanceof Path) { + inputFiles = [ val ] + } else { + inputFiles = [] + } + if (!workflow.stubRun) { + // throw error when an input file doesn't exist + inputFiles.each{ file -> + assert file.exists() : + "Error in module '${key}' id '${id}' argument '${par.plainName}'.\n" + + " Required input file does not exist.\n" + + " Path: '$file'.\n" + + " Expected input file to exist" + } + } + inputFiles + } + + // remove input files + def argsExclInputFiles = meta.config.allArguments + .findAll { (it.type != "file" || it.direction != "input") && data_.containsKey(it.plainName) } + .collectEntries { par -> + def parName = par.plainName + def val = data_[parName] + if (par.multiple && val instanceof Collection) { + val = val.join(par.multiple_sep) + } + if (par.direction == "output" && par.type == "file") { + val = val + .replaceAll('\\$id', id) + .replaceAll('\\$\\{id\\}', id) + .replaceAll('\\$key', key) + .replaceAll('\\$\\{key\\}', key) + } + [parName, val] + } + + [ id ] + inputPaths + [ argsExclInputFiles, meta.resources_dir ] + } + | processObj + | map { output -> + def outputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .indexed() + .collectEntries{ index, par -> + def out = output[index + 1] + // strip dummy '.exitcode' file from output (see nextflow-io/nextflow#2678) + if (!out instanceof List || out.size() <= 1) { + if (par.multiple) { + out = [] + } else { + assert !par.required : + "Error in module '${key}' id '${output[0]}' argument '${par.plainName}'.\n" + + " Required output file is missing" + out = null + } + } else if (out.size() == 2 && !par.multiple) { + out = out[1] + } else { + out = out.drop(1) + } + [ par.plainName, out ] + } + + // drop null outputs + outputFiles.removeAll{it.value == null} + + [ output[0], outputFiles ] + } + emit: output_ + } + + return processWf +} + +// depends on: session? +def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) { + // autodetect process key + def wfKey = workflowArgs["key"] + def procKeyPrefix = "${wfKey}_process" + def scriptMeta = nextflow.script.ScriptMeta.current() + def existing = scriptMeta.getProcessNames().findAll{it.startsWith(procKeyPrefix)} + def numbers = existing.collect{it.replace(procKeyPrefix, "0").toInteger()} + def newNumber = (numbers + [-1]).max() + 1 + + def procKey = newNumber == 0 ? procKeyPrefix : "$procKeyPrefix$newNumber" + + if (newNumber > 0) { + log.warn "Key for module '${wfKey}' is duplicated.\n", + "If you run a component multiple times in the same workflow,\n" + + "it's recommended you set a unique key for every call,\n" + + "for example: ${wfKey}.run(key: \"foo\")." + } + + // subset directives and convert to list of tuples + def drctv = workflowArgs.directives + + // TODO: unit test the two commands below + // convert publish array into tags + def valueToStr = { val -> + // ignore closures + if (val instanceof CharSequence) { + if (!val.matches('^[{].*[}]$')) { + '"' + val + '"' + } else { + val + } + } else if (val instanceof List) { + "[" + val.collect{valueToStr(it)}.join(", ") + "]" + } else if (val instanceof Map) { + "[" + val.collect{k, v -> k + ": " + valueToStr(v)}.join(", ") + "]" + } else { + val.inspect() + } + } + + // multiple entries allowed: label, publishdir + def drctvStrs = drctv.collect { key, value -> + if (key in ["label", "publishDir"]) { + value.collect{ val -> + if (val instanceof Map) { + "\n$key " + val.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else if (val == null) { + "" + } else { + "\n$key " + valueToStr(val) + } + }.join() + } else if (value instanceof Map) { + "\n$key " + value.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else { + "\n$key " + valueToStr(value) + } + }.join() + + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { ', path(viash_par_' + it.plainName + ', stageAs: "_viash_par/' + it.plainName + '_?/*")' } + .join() + + def outputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + // insert dummy into every output (see nextflow-io/nextflow#2678) + if (!par.multiple) { + ', path{[".exitcode", args.' + par.plainName + ']}' + } else { + ', path{[".exitcode"] + args.' + par.plainName + '}' + } + } + .join() + + // TODO: move this functionality somewhere else? + if (workflowArgs.auto.transcript) { + outputPaths = outputPaths + ', path{[".exitcode", ".command*"]}' + } else { + outputPaths = outputPaths + ', path{[".exitcode"]}' + } + + // create dirs for output files (based on BashWrapper.createParentFiles) + def createParentStr = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" && it.create_parent } + .collect { par -> + def contents = "args[\"${par.plainName}\"] instanceof List ? args[\"${par.plainName}\"].join('\" \"') : args[\"${par.plainName}\"]" + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent '\" + escapeText(${contents}) + \"'\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def contents = "viash_par_${par.plainName} instanceof List ? viash_par_${par.plainName}.join(\"${par.multiple_sep}\") : viash_par_${par.plainName}" + "\n\${viash_par_${par.plainName}.empty ? \"\" : \"export VIASH_PAR_${par.plainName.toUpperCase()}='\" + escapeText(${contents}) + \"'\"}" + } + + // NOTE: if using docker, use /tmp instead of tmpDir! + def tmpDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('VIASH_TMPDIR') ?: + System.getenv('VIASH_TEMPDIR') ?: + System.getenv('VIASH_TMP') ?: + System.getenv('TEMP') ?: + System.getenv('TMPDIR') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMP') ?: + '/tmp' + ).toAbsolutePath() + + // construct stub + def stub = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + "\${ args.containsKey(\"${par.plainName}\") ? \"touch2 \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"].replace(\"_*\", \"_0\") : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // escape script + def escapedScript = rawScript.replace('\\', '\\\\').replace('$', '\\$').replace('"""', '\\"\\"\\"') + + // publishdir assert + def assertStr = (workflowArgs.auto.publish == true) || workflowArgs.auto.transcript ? + """\nassert task.publishDir.size() > 0: "if auto.publish is true, params.publish_dir needs to be defined.\\n Example: --publish_dir './output/'" """ : + "" + + // generate process string + def procStr = + """nextflow.enable.dsl=2 + | + |def escapeText = { s -> s.toString().replaceAll("'", "'\\\"'\\\"'") } + |process $procKey {$drctvStrs + |input: + | tuple val(id)$inputPaths, val(args), path(resourcesDir, stageAs: ".viash_meta_resources") + |output: + | tuple val("\$id")$outputPaths, optional: true + |stub: + |\"\"\" + |touch2() { mkdir -p "\\\$(dirname "\\\$1")" && touch "\\\$1" ; } + |$stub + |\"\"\" + |script:$assertStr + |def parInject = args + | .findAll{key, value -> value != null} + | .collect{key, value -> "export VIASH_PAR_\${key.toUpperCase()}='\${escapeText(value)}'"} + | .join("\\n") + |\"\"\" + |# meta exports + |export VIASH_META_RESOURCES_DIR="\${resourcesDir}" + |export VIASH_META_TEMP_DIR="${['docker', 'podman', 'charliecloud'].any{ it == workflow.containerEngine } ? '/tmp' : tmpDir}" + |export VIASH_META_NAME="${meta.config.name}" + |# export VIASH_META_EXECUTABLE="\\\$VIASH_META_RESOURCES_DIR/\\\$VIASH_META_NAME" + |export VIASH_META_CONFIG="\\\$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" + |\${task.cpus ? "export VIASH_META_CPUS=\$task.cpus" : "" } + |\${task.memory?.bytes != null ? "export VIASH_META_MEMORY_B=\$task.memory.bytes" : "" } + |if [ ! -z \\\${VIASH_META_MEMORY_B+x} ]; then + | export VIASH_META_MEMORY_KB=\\\$(( (\\\$VIASH_META_MEMORY_B+999) / 1000 )) + | export VIASH_META_MEMORY_MB=\\\$(( (\\\$VIASH_META_MEMORY_KB+999) / 1000 )) + | export VIASH_META_MEMORY_GB=\\\$(( (\\\$VIASH_META_MEMORY_MB+999) / 1000 )) + | export VIASH_META_MEMORY_TB=\\\$(( (\\\$VIASH_META_MEMORY_GB+999) / 1000 )) + | export VIASH_META_MEMORY_PB=\\\$(( (\\\$VIASH_META_MEMORY_TB+999) / 1000 )) + | export VIASH_META_MEMORY_KIB=\\\$(( (\\\$VIASH_META_MEMORY_B+1023) / 1024 )) + | export VIASH_META_MEMORY_MIB=\\\$(( (\\\$VIASH_META_MEMORY_KIB+1023) / 1024 )) + | export VIASH_META_MEMORY_GIB=\\\$(( (\\\$VIASH_META_MEMORY_MIB+1023) / 1024 )) + | export VIASH_META_MEMORY_TIB=\\\$(( (\\\$VIASH_META_MEMORY_GIB+1023) / 1024 )) + | export VIASH_META_MEMORY_PIB=\\\$(( (\\\$VIASH_META_MEMORY_TIB+1023) / 1024 )) + |fi + | + |# meta synonyms + |export VIASH_TEMP="\\\$VIASH_META_TEMP_DIR" + |export TEMP_DIR="\\\$VIASH_META_TEMP_DIR" + | + |# create output dirs if need be + |function mkdir_parent { + | for file in "\\\$@"; do + | mkdir -p "\\\$(dirname "\\\$file")" + | done + |} + |$createParentStr + | + |# argument exports${inputFileExports.join()} + |\$parInject + | + |# process script + |${escapedScript} + |\"\"\" + |} + |""".stripMargin() + + // TODO: print on debug + // if (workflowArgs.debug == true) { + // println("######################\n$procStr\n######################") + // } + + // write process to temp file + def tempFile = java.nio.file.Files.createTempFile("viash-process-${procKey}-", ".nf") + addShutdownHook { java.nio.file.Files.deleteIfExists(tempFile) } + tempFile.text = procStr + + // create process from temp file + def binding = new nextflow.script.ScriptBinding([:]) + def session = nextflow.Nextflow.getSession() + def parser = new nextflow.script.ScriptParser(session) + .setModule(true) + .setBinding(binding) + def moduleScript = parser.runScript(tempFile) + .getScript() + + // register module in meta + def module = new nextflow.script.IncludeDef.Module(name: procKey) + scriptMeta.addModule(moduleScript, module.name, module.alias) + + // retrieve and return process from meta + return scriptMeta.getProcess(procKey) +} + +// defaults +meta["defaults"] = [ + // key to be used to trace the process and determine output names + key: null, + + // fixed arguments to be passed to script + args: [:], + + // default directives + directives: readJsonBlob('''{ + "container" : { + "registry" : "images.viash-hub.com", + "image" : "vsh/biobox/agat/agat_sp_filter_feature_from_kill_list", + "tag" : "main" + }, + "tag" : "$id" +}'''), + + // auto settings + auto: readJsonBlob('''{ + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false +}'''), + + // Apply a map over the incoming tuple + // Example: `{ tup -> [ tup[0], [input: tup[1].output] ] + tup.drop(2) }` + map: null, + + // Apply a map over the ID element of a tuple (i.e. the first element) + // Example: `{ id -> id + "_foo" }` + mapId: null, + + // Apply a map over the data element of a tuple (i.e. the second element) + // Example: `{ data -> [ input: data.output ] }` + mapData: null, + + // Apply a map over the passthrough elements of a tuple (i.e. the tuple excl. the first two elements) + // Example: `{ pt -> pt.drop(1) }` + mapPassthrough: null, + + // Filter the channel + // Example: `{ tup -> tup[0] == "foo" }` + filter: null, + + // Choose whether or not to run the component on the tuple if the condition is true. + // Otherwise, the tuple will be passed through. + // Example: `{ tup -> tup[0] != "skip_this" }` + runIf: null, + + // Rename keys in the data field of the tuple (i.e. the second element) + // Will likely be deprecated in favour of `fromState`. + // Example: `[ "new_key": "old_key" ]` + renameKeys: null, + + // Fetch data from the state and pass it to the module without altering the current state. + // + // `fromState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be passed to the module as is. + // - If it is a `List[String]`, the data will be the values of the state at the given keys. + // - If it is a `Map[String, String]`, the data will be the values of the state at the given keys, with the keys renamed according to the map. + // - If it is a function, the tuple (`[id, state]`) in the channel will be passed to the function, and the result will be used as the data. + // + // Example: `{ id, state -> [input: state.fastq_file] }` + // Default: `null` + fromState: null, + + // Determine how the state should be updated after the module has been run. + // + // `toState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be replaced with the output of the module. + // - If it is a `List[String]`, the state will be updated with the values of the data at the given keys. + // - If it is a `Map[String, String]`, the state will be updated with the values of the data at the given keys, with the keys renamed according to the map. + // - If it is a function, a tuple (`[id, output, state]`) will be passed to the function, and the result will be used as the new state. + // + // Example: `{ id, output, state -> state + [counts: state.output] }` + // Default: `{ id, output, state -> output }` + toState: null, + + // Whether or not to print debug messages + // Default: `false` + debug: false +] + +// initialise default workflow +meta["workflow"] = workflowFactory([key: meta.config.name], meta.defaults, meta) + +// add workflow to environment +nextflow.script.ScriptMeta.current().addDefinition(meta.workflow) + +// anonymous workflow for running this module as a standalone +workflow { + // add id argument if it's not already in the config + // TODO: deep copy + def newConfig = deepClone(meta.config) + def newParams = deepClone(params) + + def argsContainsId = newConfig.allArguments.any{it.plainName == "id"} + if (!argsContainsId) { + def idArg = [ + 'name': '--id', + 'required': false, + 'type': 'string', + 'description': 'A unique id for every entry.', + 'multiple': false + ] + newConfig.arguments.add(0, idArg) + newConfig = processConfig(newConfig) + } + if (!newParams.containsKey("id")) { + newParams.id = "run" + } + + helpMessage(newConfig) + + channelFromParams(newParams, newConfig) + // make sure id is not in the state if id is not in the args + | map {id, state -> + if (!argsContainsId) { + [id, state.findAll{k, v -> k != "id"}] + } else { + [id, state] + } + } + | meta.workflow.run( + auto: [ publish: "state" ] + ) +} + +// END COMPONENT-SPECIFIC CODE diff --git a/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/nextflow.config b/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/nextflow.config new file mode 100644 index 00000000..8d00c5df --- /dev/null +++ b/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'agat/agat_sp_filter_feature_from_kill_list' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'main' + description = 'Remove features based on a kill list. The default behaviour is to look at the features\'s ID. \nIf the feature has an ID (case insensitive) listed among the kill list it will be removed.\nRemoving a level1 or level2 feature will automatically remove all linked subfeatures, and \nremoving all children of a feature will automatically remove this feature too.\n' + author = 'Leïla Paquay' +} + +process.container = 'nextflow/bash:latest' + +// detect tempdir +tempDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMPDIR') ?: + '/tmp' +).toAbsolutePath() + +profiles { + no_publish { + process { + withName: '.*' { + publishDir = [ + enabled: false + ] + } + } + } + mount_temp { + docker.temp = tempDir + podman.temp = tempDir + charliecloud.temp = tempDir + } + docker { + docker.enabled = true + // docker.userEmulation = true + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + singularity { + singularity.enabled = true + singularity.autoMounts = true + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + podman { + podman.enabled = true + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + shifter { + shifter.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + } + charliecloud { + charliecloud.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + } +} + +process{ + withLabel: mem1gb { memory = 1000000000.B } + withLabel: mem2gb { memory = 2000000000.B } + withLabel: mem5gb { memory = 5000000000.B } + withLabel: mem10gb { memory = 10000000000.B } + withLabel: mem20gb { memory = 20000000000.B } + withLabel: mem50gb { memory = 50000000000.B } + withLabel: mem100gb { memory = 100000000000.B } + withLabel: mem200gb { memory = 200000000000.B } + withLabel: mem500gb { memory = 500000000000.B } + withLabel: mem1tb { memory = 1000000000000.B } + withLabel: mem2tb { memory = 2000000000000.B } + withLabel: mem5tb { memory = 5000000000000.B } + withLabel: mem10tb { memory = 10000000000000.B } + withLabel: mem20tb { memory = 20000000000000.B } + withLabel: mem50tb { memory = 50000000000000.B } + withLabel: mem100tb { memory = 100000000000000.B } + withLabel: mem200tb { memory = 200000000000000.B } + withLabel: mem500tb { memory = 500000000000000.B } + withLabel: mem1gib { memory = 1073741824.B } + withLabel: mem2gib { memory = 2147483648.B } + withLabel: mem4gib { memory = 4294967296.B } + withLabel: mem8gib { memory = 8589934592.B } + withLabel: mem16gib { memory = 17179869184.B } + withLabel: mem32gib { memory = 34359738368.B } + withLabel: mem64gib { memory = 68719476736.B } + withLabel: mem128gib { memory = 137438953472.B } + withLabel: mem256gib { memory = 274877906944.B } + withLabel: mem512gib { memory = 549755813888.B } + withLabel: mem1tib { memory = 1099511627776.B } + withLabel: mem2tib { memory = 2199023255552.B } + withLabel: mem4tib { memory = 4398046511104.B } + withLabel: mem8tib { memory = 8796093022208.B } + withLabel: mem16tib { memory = 17592186044416.B } + withLabel: mem32tib { memory = 35184372088832.B } + withLabel: mem64tib { memory = 70368744177664.B } + withLabel: mem128tib { memory = 140737488355328.B } + withLabel: mem256tib { memory = 281474976710656.B } + withLabel: mem512tib { memory = 562949953421312.B } + withLabel: cpu1 { cpus = 1 } + withLabel: cpu2 { cpus = 2 } + withLabel: cpu5 { cpus = 5 } + withLabel: cpu10 { cpus = 10 } + withLabel: cpu20 { cpus = 20 } + withLabel: cpu50 { cpus = 50 } + withLabel: cpu100 { cpus = 100 } + withLabel: cpu200 { cpus = 200 } + withLabel: cpu500 { cpus = 500 } + withLabel: cpu1000 { cpus = 1000 } +} + + diff --git a/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/nextflow_schema.json b/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/nextflow_schema.json new file mode 100644 index 00000000..190b4aee --- /dev/null +++ b/target/nextflow/agat/agat_sp_filter_feature_from_kill_list/nextflow_schema.json @@ -0,0 +1,160 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "agat_sp_filter_feature_from_kill_list", +"description": "Remove features based on a kill list. The default behaviour is to look at the features\u0027s ID. \nIf the feature has an ID (case insensitive) listed among the kill list it will be removed.\nRemoving a level1 or level2 feature will automatically remove all linked subfeatures, and \nremoving all children of a feature will automatically remove this feature too.\n", +"type": "object", +"definitions": { + + + + "inputs" : { + "title": "Inputs", + "type": "object", + "description": "No description", + "properties": { + + + "gff": { + "type": + "string", + "description": "Type: `file`, required. Input GFF3 file that will be read", + "help_text": "Type: `file`, required. Input GFF3 file that will be read." + + } + + + , + "kill_list": { + "type": + "string", + "description": "Type: `file`, required, example: `kill_list.txt`. Text file containing the kill list", + "help_text": "Type: `file`, required, example: `kill_list.txt`. Text file containing the kill list. One value per line." + + } + + +} +}, + + + "outputs" : { + "title": "Outputs", + "type": "object", + "description": "No description", + "properties": { + + + "output": { + "type": + "string", + "description": "Type: `file`, required, default: `$id.$key.output.output`. Path to the output GFF file that contains filtered features", + "help_text": "Type: `file`, required, default: `$id.$key.output.output`. Path to the output GFF file that contains filtered features. \n" + , + "default": "$id.$key.output.output" + } + + +} +}, + + + "arguments" : { + "title": "Arguments", + "type": "object", + "description": "No description", + "properties": { + + + "type": { + "type": + "string", + "description": "Type: List of `string`, multiple_sep: `\";\"`. Primary tag option, case insensitive, list", + "help_text": "Type: List of `string`, multiple_sep: `\";\"`. Primary tag option, case insensitive, list. Allow to specify the feature types that \nwill be handled. \n\nYou can specify a specific feature by giving its primary tag name (column 3) as: \n\n * cds\n * Gene\n * mRNA\n \nYou can specify directly all the feature of a particular\nlevel: \n\n * level2=mRNA,ncRNA,tRNA,etc \n * level3=CDS,exon,UTR,etc. \n\nBy default all features are taken into account. Fill the option with the value \"all\" will \nhave the same behaviour.\n" + + } + + + , + "attribute": { + "type": + "string", + "description": "Type: `string`, example: `ID`. Attribute tag to specify the attribute to analyse", + "help_text": "Type: `string`, example: `ID`. Attribute tag to specify the attribute to analyse. Case sensitive. Default: ID\n" + + } + + + , + "config": { + "type": + "string", + "description": "Type: `file`, example: `custom_agat_config.yaml`. AGAT config file", + "help_text": "Type: `file`, example: `custom_agat_config.yaml`. AGAT config file. By default AGAT takes the original agat_config.yaml shipped with AGAT.\nThe `--config` option gives you the possibility to use your own AGAT config file (located \nelsewhere or named differently).\n" + + } + + + , + "verbose": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Verbose option for debugging purpose", + "help_text": "Type: `boolean_true`, default: `false`. Verbose option for debugging purpose." + , + "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/inputs" + }, + + { + "$ref": "#/definitions/outputs" + }, + + { + "$ref": "#/definitions/arguments" + }, + + { + "$ref": "#/definitions/nextflow input-output arguments" + } +] +} diff --git a/target/nextflow/agat/agat_sp_merge_annotations/.config.vsh.yaml b/target/nextflow/agat/agat_sp_merge_annotations/.config.vsh.yaml new file mode 100644 index 00000000..fce2f26a --- /dev/null +++ b/target/nextflow/agat/agat_sp_merge_annotations/.config.vsh.yaml @@ -0,0 +1,211 @@ +name: "agat_sp_merge_annotations" +namespace: "agat" +version: "main" +authors: +- name: "Leïla Paquay" + roles: + - "author" + - "maintainer" + info: + links: + email: "leila@data-intuitive.com" + github: "Leila011" + linkedin: "leilapaquay" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Software Developer" +argument_groups: +- name: "Inputs" + arguments: + - type: "file" + name: "--gff" + alternatives: + - "-f" + description: "Input GTF/GFF file(s).\n" + info: null + example: + - "input1.gff;input2.gff" + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: true + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + - "--out" + description: "Output gff3 file where the gene incriminated will be writen." + info: null + example: + - "output.gff" + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Arguments" + arguments: + - type: "file" + name: "--config" + alternatives: + - "-c" + description: "AGAT config file. By default AGAT takes the original agat_config.yaml\ + \ shipped with AGAT. \nThe `--config` option gives you the possibility to use\ + \ your own AGAT config file (located\nelsewhere or named differently).\n" + info: null + example: + - "custom_agat_config.yaml" + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Merge different gff annotation files into one. It uses the AGAT parser\ + \ that takes care of\nduplicated names and fixes other oddities met in those files.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "gene annotations" +- "merge" +- "gff" +license: "GPL-3.0" +references: + doi: + - "10.5281/zenodo.3552717" +links: + repository: "https://github.com/NBISweden/AGAT" + homepage: "https://github.com/NBISweden/AGAT" + documentation: "https://agat.readthedocs.io/en/latest/tools/agat_sp_merge_annotations.html" + issue_tracker: "https://github.com/NBISweden/AGAT/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "docker" + run: + - "agat --version | sed 's/AGAT\\s\\(.*\\)/agat: \"\\1\"/' > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/agat/agat_sp_merge_annotations/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/agat/agat_sp_merge_annotations" + executable: "target/nextflow/agat/agat_sp_merge_annotations/main.nf" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/nextflow/agat/agat_sp_merge_annotations/main.nf b/target/nextflow/agat/agat_sp_merge_annotations/main.nf new file mode 100644 index 00000000..f52667d1 --- /dev/null +++ b/target/nextflow/agat/agat_sp_merge_annotations/main.nf @@ -0,0 +1,3612 @@ +// agat_sp_merge_annotations main +// +// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +// Intuitive. +// +// The component may contain files which fall under a different license. The +// authors of this component should specify the license in the header of such +// files, or include a separate license file detailing the licenses of all included +// files. +// +// Component authors: +// * Leïla Paquay (author, maintainer) + +//////////////////////////// +// VDSL3 helper functions // +//////////////////////////// + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_checkArgumentType.nf' +class UnexpectedArgumentTypeException extends Exception { + String errorIdentifier + String stage + String plainName + String expectedClass + String foundClass + + // ${key ? " in module '$key'" : ""}${id ? " id '$id'" : ""} + UnexpectedArgumentTypeException(String errorIdentifier, String stage, String plainName, String expectedClass, String foundClass) { + super("Error${errorIdentifier ? " $errorIdentifier" : ""}:${stage ? " $stage" : "" } argument '${plainName}' has the wrong type. " + + "Expected type: ${expectedClass}. Found type: ${foundClass}") + this.errorIdentifier = errorIdentifier + this.stage = stage + this.plainName = plainName + this.expectedClass = expectedClass + this.foundClass = foundClass + } +} + +/** + * Checks if the given value is of the expected type. If not, an exception is thrown. + * + * @param stage The stage of the argument (input or output) + * @param par The parameter definition + * @param value The value to check + * @param errorIdentifier The identifier to use in the error message + * @return The value, if it is of the expected type + * @throws UnexpectedArgumentTypeException If the value is not of the expected type +*/ +def _checkArgumentType(String stage, Map par, Object value, String errorIdentifier) { + // expectedClass will only be != null if value is not of the expected type + def expectedClass = null + def foundClass = null + + // todo: split if need be + + if (!par.required && value == null) { + expectedClass = null + } else if (par.multiple) { + if (value !instanceof Collection) { + value = [value] + } + + // split strings + value = value.collectMany{ val -> + if (val instanceof String) { + // collect() to ensure that the result is a List and not simply an array + val.split(par.multiple_sep).collect() + } else { + [val] + } + } + + // process globs + if (par.type == "file" && par.direction == "input") { + value = value.collect{ it instanceof String ? file(it, hidden: true) : it }.flatten() + } + + // check types of elements in list + try { + value = value.collect { listVal -> + _checkArgumentType(stage, par + [multiple: false], listVal, errorIdentifier) + } + } catch (UnexpectedArgumentTypeException e) { + expectedClass = "List[${e.expectedClass}]" + foundClass = "List[${e.foundClass}]" + } + } else if (par.type == "string") { + // cast to string if need be + if (value instanceof GString) { + value = value.toString() + } + expectedClass = value instanceof String ? null : "String" + } else if (par.type == "integer") { + // cast to integer if need be + if (value instanceof String) { + try { + value = value.toInteger() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toLong() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toDouble() + } catch (NumberFormatException e) { + // do nothing + } + } + if (value instanceof java.math.BigDecimal) { + value = value.doubleValue() + } + 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 + } + } + 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) { + value = file(value, hidden: true) + } + if (value instanceof File) { + value = value.toPath() + } + 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() + } + expectedClass = value instanceof String ? null : "String" + } else { + // didn't find a match for par.type + expectedClass = par.type + } + + if (expectedClass != null) { + if (foundClass == null) { + foundClass = value.getClass().getName() + } + throw new UnexpectedArgumentTypeException(errorIdentifier, stage, par.plainName, expectedClass, foundClass) + } + + return value +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processInputValues.nf' +Map _processInputValues(Map inputs, Map config, String id, String key) { + if (!workflow.stubRun) { + config.allArguments.each { arg -> + if (arg.required) { + assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null : + "Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing" + } + } + + inputs = inputs.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid input argument" + + value = _checkArgumentType("input", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return inputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf' +Map _processOutputValues(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" + + value = _checkArgumentType("output", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return outputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf' +class IDChecker { + final def items = [] as Set + + @groovy.transform.WithWriteLock + boolean observe(String item) { + if (items.contains(item)) { + return false + } else { + items << item + return true + } + } + + @groovy.transform.WithReadLock + boolean contains(String item) { + return items.contains(item) + } + + @groovy.transform.WithReadLock + Set getItems() { + return items.clone() + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_checkUniqueIds.nf' + +/** + * Check if the ids are unique across parameter sets + * + * @param parameterSets a list of parameter sets. + */ +private void _checkUniqueIds(List>> parameterSets) { + def ppIds = parameterSets.collect{it[0]} + assert ppIds.size() == ppIds.unique().size() : "All argument sets should have unique ids. Detected ids: $ppIds" +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_getChild.nf' + +// helper functions for reading params from file // +def _getChild(parent, child) { + if (child.contains("://") || java.nio.file.Paths.get(child).isAbsolute()) { + child + } else { + def parentAbsolute = java.nio.file.Paths.get(parent).toAbsolutePath().toString() + parentAbsolute.replaceAll('/[^/]*$', "/") + child + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_parseParamList.nf' +/** + * Figure out the param list format based on the file extension + * + * @param param_list A String containing the path to the parameter list file. + * + * @return A String containing the format of the parameter list file. + */ +def _paramListGuessFormat(param_list) { + if (param_list !instanceof String) { + "asis" + } else if (param_list.endsWith(".csv")) { + "csv" + } else if (param_list.endsWith(".json") || param_list.endsWith(".jsn")) { + "json" + } else if (param_list.endsWith(".yaml") || param_list.endsWith(".yml")) { + "yaml" + } else { + "yaml_blob" + } +} + + +/** + * Read the param list + * + * @param param_list One of the following: + * - A String containing the path to the parameter list file (csv, json or yaml), + * - A yaml blob of a list of maps (yaml_blob), + * - Or a groovy list of maps (asis). + * @param config A Map of the Viash configuration. + * + * @return A List of Maps containing the parameters. + */ +def _parseParamList(param_list, Map config) { + // first determine format by extension + def paramListFormat = _paramListGuessFormat(param_list) + + def paramListPath = (paramListFormat != "asis" && paramListFormat != "yaml_blob") ? + file(param_list, hidden: true) : + null + + // get the correct parser function for the detected params_list format + def paramSets = [] + if (paramListFormat == "asis") { + paramSets = param_list + } else if (paramListFormat == "yaml_blob") { + paramSets = readYamlBlob(param_list) + } else if (paramListFormat == "yaml") { + paramSets = readYaml(paramListPath) + } else if (paramListFormat == "json") { + paramSets = readJson(paramListPath) + } else if (paramListFormat == "csv") { + paramSets = readCsv(paramListPath) + } else { + error "Format of provided --param_list not recognised.\n" + + "Found: '$paramListFormat'.\n" + + "Expected: a csv file, a json file, a yaml file,\n" + + "a yaml blob or a groovy list of maps." + } + + // data checks + assert paramSets instanceof List: "--param_list should contain a list of maps" + for (value in paramSets) { + assert value instanceof Map: "--param_list should contain a list of maps" + } + + // id is argument + def idIsArgument = config.allArguments.any{it.plainName == "id"} + + // Reformat from List to List> by adding the ID as first element of a Tuple2 + paramSets = paramSets.collect({ data -> + def id = data.id + if (!idIsArgument) { + data = data.findAll{k, v -> k != "id"} + } + [id, data] + }) + + // Split parameters with 'multiple: true' + paramSets = paramSets.collect({ id, data -> + data = _splitParams(data, config) + [id, data] + }) + + // The paths of input files inside a param_list file may have been specified relatively to the + // location of the param_list file. These paths must be made absolute. + if (paramListPath) { + paramSets = paramSets.collect({ id, data -> + def new_data = data.collectEntries{ parName, parValue -> + def par = config.allArguments.find{it.plainName == parName} + if (par && par.type == "file" && par.direction == "input") { + if (parValue instanceof Collection) { + parValue = parValue.collectMany{path -> + def x = _resolveSiblingIfNotAbsolute(path, paramListPath) + x instanceof Collection ? x : [x] + } + } else { + parValue = _resolveSiblingIfNotAbsolute(parValue, paramListPath) + } + } + [parName, parValue] + } + [id, new_data] + }) + } + + return paramSets +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_splitParams.nf' +/** + * Split parameters for arguments that accept multiple values using their separator + * + * @param paramList A Map containing parameters to split. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A Map of parameters where the parameter values have been split into a list using + * their seperator. + */ +Map _splitParams(Map parValues, Map config){ + def parsedParamValues = parValues.collectEntries { parName, parValue -> + def parameterSettings = config.allArguments.find({it.plainName == parName}) + + if (!parameterSettings) { + // if argument is not found, do not alter + return [parName, parValue] + } + if (parameterSettings.multiple) { // Check if parameter can accept multiple values + if (parValue instanceof Collection) { + parValue = parValue.collect{it instanceof String ? it.split(parameterSettings.multiple_sep) : it } + } else if (parValue instanceof String) { + parValue = parValue.split(parameterSettings.multiple_sep) + } else if (parValue == null) { + parValue = [] + } else { + parValue = [ parValue ] + } + parValue = parValue.flatten() + } + // For all parameters check if multiple values are only passed for + // arguments that allow it. Quietly simplify lists of length 1. + if (!parameterSettings.multiple && parValue instanceof Collection) { + assert parValue.size() == 1 : + "Error: argument ${parName} has too many values.\n" + + " Expected amount: 1. Found: ${parValue.size()}" + parValue = parValue[0] + } + [parName, parValue] + } + return parsedParamValues +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/channelFromParams.nf' +/** + * Parse nextflow parameters based on settings defined in a viash config. + * Return a list of parameter sets, each parameter set corresponding to + * an event in a nextflow channel. The output from this function can be used + * with Channel.fromList to create a nextflow channel with Vdsl3 formatted + * events. + * + * This function performs: + * - A filtering of the params which can be found in the config file. + * - Process the params_list argument which allows a user to to initialise + * a Vsdl3 channel with multiple parameter sets. Possible formats are + * csv, json, yaml, or simply a yaml_blob. A csv should have column names + * which correspond to the different arguments of this pipeline. A json or a yaml + * file should be a list of maps, each of which has keys corresponding to the + * arguments of the pipeline. A yaml blob can also be passed directly as a parameter. + * When passing a csv, json or yaml, relative path names are relativized to the + * location of the parameter file. + * - Combine the parameter sets into a vdsl3 Channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A list of parameters with the first element of the event being + * the event ID and the second element containing a map of the parsed parameters. + */ + +private List>> _paramsToParamSets(Map params, Map config){ + // todo: fetch key from run args + def key_ = config.name + + /* parse regular parameters (not in param_list) */ + /*************************************************/ + def globalParams = config.allArguments + .findAll { params.containsKey(it.plainName) } + .collectEntries { [ it.plainName, params[it.plainName] ] } + def globalID = params.get("id", null) + + /* process params_list arguments */ + /*********************************/ + def paramList = params.containsKey("param_list") && params.param_list != null ? + params.param_list : [] + // if (paramList instanceof String) { + // paramList = [paramList] + // } + // def paramSets = paramList.collectMany{ _parseParamList(it, config) } + // TODO: be able to process param_list when it is a list of strings + def paramSets = _parseParamList(paramList, config) + if (paramSets.isEmpty()) { + paramSets = [[null, [:]]] + } + + /* combine arguments into channel */ + /**********************************/ + def processedParams = paramSets.indexed().collect{ index, tup -> + // Process ID + def id = tup[0] ?: globalID + + if (workflow.stubRun && !id) { + // if stub run, explicitly add an id if missing + id = "stub${index}" + } + assert id != null: "Each parameter set should have at least an 'id'" + + // Process params + def parValues = globalParams + tup[1] + // // Remove parameters which are null, if the default is also null + // parValues = parValues.collectEntries{paramName, paramValue -> + // parameterSettings = config.functionality.allArguments.find({it.plainName == paramName}) + // if ( paramValue != null || parameterSettings.get("default", null) != null ) { + // [paramName, paramValue] + // } + // } + parValues = parValues.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key_}' id '${id}': '${name}' is not a valid input argument" + + if (par == null) { + return [:] + } + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + + [ name, value ] + } + + [id, parValues] + } + + // Check if ids (first element of each list) is unique + _checkUniqueIds(processedParams) + return processedParams +} + +/** + * Parse nextflow parameters based on settings defined in a viash config + * and return a nextflow channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A nextflow Channel with events. Events are formatted as a tuple that contains + * first contains the ID of the event and as second element holds a parameter map. + * + * + */ +def channelFromParams(Map params, Map config) { + def processedParams = _paramsToParamSets(params, config) + return Channel.fromList(processedParams) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/checkUniqueIds.nf' +def checkUniqueIds(Map args) { + def stopOnError = args.stopOnError == null ? args.stopOnError : true + + def idChecker = new IDChecker() + + return filter { tup -> + if (!idChecker.observe(tup[0])) { + if (stopOnError) { + error "Duplicate id: ${tup[0]}" + } else { + log.warn "Duplicate id: ${tup[0]}, removing duplicate entry" + return false + } + } + return true + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/preprocessInputs.nf' +// This helper file will be deprecated soon +preprocessInputsDeprecationWarningPrinted = false + +def preprocessInputsDeprecationWarning() { + if (!preprocessInputsDeprecationWarningPrinted) { + preprocessInputsDeprecationWarningPrinted = true + System.err.println("Warning: preprocessInputs() is deprecated and will be removed in Viash 0.9.0.") + } +} + +/** + * Generate a nextflow Workflow that allows processing a channel of + * Vdsl3 formatted events and apply a Viash config to them: + * - Gather default parameters from the Viash config and make + * sure that they are correctly formatted (see applyConfig method). + * - Format the input parameters (also using the applyConfig method). + * - Apply the default parameter to the input parameters. + * - Do some assertions: + * ~ Check if the event IDs in the channel are unique. + * + * The events in the channel are formatted as tuples, with the + * first element of the tuples being a unique id of the parameter set, + * and the second element containg the the parameters themselves. + * Optional extra elements of the tuples will be passed to the output as is. + * + * @param args A map that must contain a 'config' key that points + * to a parsed config (see readConfig()). Optionally, a + * 'key' key can be provided which can be used to create a unique + * name for the workflow process. + * + * @return A workflow that allows processing a channel of Vdsl3 formatted events + * and apply a Viash config to them. + */ +def preprocessInputs(Map args) { + preprocessInputsDeprecationWarning() + + def config = args.config + assert config instanceof Map : + "Error in preprocessInputs: config must be a map. " + + "Expected class: Map. Found: config.getClass() is ${config.getClass()}" + def key_ = args.key ?: config.name + + // Get different parameter types (used throughout this function) + def defaultArgs = config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + map { tup -> + def id = tup[0] + def data = tup[1] + def passthrough = tup.drop(2) + + def new_data = (defaultArgs + data).collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + + if (par != null) { + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + } + + [ name, value ] + } + + [ id, new_data ] + passthrough + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runComponents.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component config. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component config. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component config. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component config. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runComponents(Map args) { + log.warn("runComponents is deprecated, use runEach instead") + assert args.components: "runComponents should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runComponents" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def id_ = args.id + + workflow runComponentsWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def comp_config = comp_.config + + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_config) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + // def new_id = id_(tup[0], tup[1], comp_config) + def new_id = tup[0] + if (id_ instanceof String) { + new_id = id_ + } else if (id_ instanceof Closure) { + new_id = id_(new_id, tup[1], comp_config) + } + [new_id] + tup.drop(1) + } + : filter_ch + def data_ch = id_ch | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_config) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_config) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + post_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runComponentsWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runEach.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component itself. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component itself. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component itself. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component itself. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runEach(Map args) { + assert args.components: "runEach should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runEach" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def runIf_ = args.runIf + def id_ = args.id + + assert !runIf_ || runIf_ instanceof Closure: "runEach: must pass a Closure to runIf." + + workflow runEachWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + def new_id = id_ + if (new_id instanceof Closure) { + new_id = new_id(tup[0], tup[1], comp_) + } + assert new_id instanceof String : "Error in runEach: id should be a String or a Closure that returns a String. Expected: id instanceof String. Found: ${new_id.getClass()}" + [new_id] + tup.drop(1) + } + : filter_ch + def chPassthrough = null + def chRun = null + if (runIf_) { + def idRunIfBranch = id_ch.branch{ tup -> + run: runIf_(tup[0], tup[1], comp_) + passthrough: true + } + chPassthrough = idRunIfBranch.passthrough + chRun = idRunIfBranch.run + } else { + chRun = id_ch + chPassthrough = Channel.empty() + } + def data_ch = chRun | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + def return_ch = post_ch + | concat(chPassthrough) + + return_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runEachWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/safeJoin.nf' +/** + * Join sourceChannel to targetChannel + * + * This function joins the sourceChannel to the targetChannel. + * However, each id in the targetChannel must be present in the + * sourceChannel. If _meta.join_id exists in the targetChannel, that is + * used as an id instead. If the id doesn't match any id in the sourceChannel, + * an error is thrown. + */ + +def safeJoin(targetChannel, sourceChannel, key) { + def sourceIDs = new IDChecker() + + def sourceCheck = sourceChannel + | map { tup -> + sourceIDs.observe(tup[0]) + tup + } + def targetCheck = targetChannel + | map { tup -> + def id = tup[0] + + if (!sourceIDs.contains(id)) { + error ( + "Error in module '${key}' when merging output with original state.\n" + + " Reason: output with id '${id}' could not be joined with source channel.\n" + + " If the IDs in the output channel differ from the input channel,\n" + + " please set `tup[1]._meta.join_id to the original ID.\n" + + " Original IDs in input channel: ['${sourceIDs.getItems().join("', '")}'].\n" + + " Unexpected ID in the output channel: '${id}'.\n" + + " Example input event: [\"id\", [input: file(...)]],\n" + + " Example output event: [\"newid\", [output: file(...), _meta: [join_id: \"id\"]]]" + ) + } + // TODO: add link to our documentation on how to fix this + + tup + } + + sourceCheck.cross(targetChannel) + | map{ left, right -> + right + left.drop(1) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/_processArgument.nf' +def _processArgument(arg) { + arg.multiple = arg.multiple != null ? arg.multiple : false + arg.required = arg.required != null ? arg.required : false + arg.direction = arg.direction != null ? arg.direction : "input" + arg.multiple_sep = arg.multiple_sep != null ? arg.multiple_sep : ";" + arg.plainName = arg.name.replaceAll("^-*", "") + + if (arg.type == "file") { + arg.must_exist = arg.must_exist != null ? arg.must_exist : true + arg.create_parent = arg.create_parent != null ? arg.create_parent : true + } + + // add default values to output files which haven't already got a default + if (arg.type == "file" && arg.direction == "output" && arg.default == null) { + def mult = arg.multiple ? "_*" : "" + def extSearch = "" + if (arg.default != null) { + extSearch = arg.default + } else if (arg.example != null) { + extSearch = arg.example + } + if (extSearch instanceof List) { + extSearch = extSearch[0] + } + def extSearchResult = extSearch.find("\\.[^\\.]+\$") + def ext = extSearchResult != null ? extSearchResult : "" + arg.default = "\$id.\$key.${arg.plainName}${mult}${ext}" + if (arg.multiple) { + arg.default = [arg.default] + } + } + + if (!arg.multiple) { + if (arg.default != null && arg.default instanceof List) { + arg.default = arg.default[0] + } + if (arg.example != null && arg.example instanceof List) { + arg.example = arg.example[0] + } + } + + if (arg.type == "boolean_true") { + arg.default = false + } + if (arg.type == "boolean_false") { + arg.default = true + } + + arg +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/addGlobalParams.nf' +def addGlobalArguments(config) { + def localConfig = [ + "argument_groups": [ + [ + "name": "Nextflow input-output arguments", + "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.", + "arguments" : [ + [ + 'name': '--publish_dir', + 'required': true, + 'type': 'string', + 'description': 'Path to an output directory.', + 'example': 'output/', + 'multiple': false + ], + [ + 'name': '--param_list', + 'required': false, + 'type': 'string', + 'description': '''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. + | + |* 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: [ ['id': 'foo', 'input': 'foo.txt'], ['id': 'bar', 'input': 'bar.txt'] ]`. + |* 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`. + |* 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 `[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]`. + |* A yaml blob can also be passed directly as a string. Example: `--param_list "[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]"`. + | + |When 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.'''.stripMargin(), + 'example': 'my_params.yaml', + 'multiple': false, + 'hidden': true + ] + // TODO: allow multiple: true in param_list? + // TODO: allow to specify a --param_list_regex to filter the param_list? + // TODO: allow to specify a --param_list_from_state to remap entries in the param_list? + ] + ] + ] + ] + + return processConfig(_mergeMap(config, localConfig)) +} + +def _mergeMap(Map lhs, Map rhs) { + return rhs.inject(lhs.clone()) { map, entry -> + if (map[entry.key] instanceof Map && entry.value instanceof Map) { + map[entry.key] = _mergeMap(map[entry.key], entry.value) + } else if (map[entry.key] instanceof Collection && entry.value instanceof Collection) { + map[entry.key] += entry.value + } else { + map[entry.key] = entry.value + } + return map + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/generateHelp.nf' +def _generateArgumentHelp(param) { + // alternatives are not supported + // def names = param.alternatives ::: List(param.name) + + def unnamedProps = [ + ["required parameter", param.required], + ["multiple values allowed", param.multiple], + ["output", param.direction.toLowerCase() == "output"], + ["file must exist", param.type == "file" && param.must_exist] + ].findAll{it[1]}.collect{it[0]} + + def dflt = null + if (param.default != null) { + if (param.default instanceof List) { + dflt = param.default.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + dflt = param.default.toString() + } + } + def example = null + if (param.example != null) { + if (param.example instanceof List) { + example = param.example.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + example = param.example.toString() + } + } + def min = param.min?.toString() + def max = param.max?.toString() + + def escapeChoice = { choice -> + def s1 = choice.replaceAll("\\n", "\\\\n") + def s2 = s1.replaceAll("\"", """\\\"""") + s2.contains(",") || s2 != choice ? "\"" + s2 + "\"" : s2 + } + def choices = param.choices == null ? + null : + "[ " + param.choices.collect{escapeChoice(it.toString())}.join(", ") + " ]" + + def namedPropsStr = [ + ["type", ([param.type] + unnamedProps).join(", ")], + ["default", dflt], + ["example", example], + ["choices", choices], + ["min", min], + ["max", max] + ] + .findAll{it[1]} + .collect{"\n " + it[0] + ": " + it[1].replaceAll("\n", "\\n")} + .join("") + + def descStr = param.description == null ? + "" : + _paragraphWrap("\n" + param.description.trim(), 80 - 8).join("\n ") + + "\n --" + param.plainName + + namedPropsStr + + descStr +} + +// Based on Helper.generateHelp() in Helper.scala +def _generateHelp(config) { + def fun = config + + // PART 1: NAME AND VERSION + def nameStr = fun.name + + (fun.version == null ? "" : " " + fun.version) + + // PART 2: DESCRIPTION + def descrStr = fun.description == null ? + "" : + "\n\n" + _paragraphWrap(fun.description.trim(), 80).join("\n") + + // PART 3: Usage + def usageStr = fun.usage == null ? + "" : + "\n\nUsage:\n" + fun.usage.trim() + + // PART 4: Options + def argGroupStrs = fun.allArgumentGroups.collect{argGroup -> + def name = argGroup.name + def descriptionStr = argGroup.description == null ? + "" : + "\n " + _paragraphWrap(argGroup.description.trim(), 80-4).join("\n ") + "\n" + def arguments = argGroup.arguments.collect{arg -> + arg instanceof String ? fun.allArguments.find{it.plainName == arg} : arg + }.findAll{it != null} + def argumentStrs = arguments.collect{param -> _generateArgumentHelp(param)} + + "\n\n$name:" + + descriptionStr + + argumentStrs.join("\n") + } + + // FINAL: combine + def out = nameStr + + descrStr + + usageStr + + argGroupStrs.join("") + + return out +} + +// based on Format._paragraphWrap +def _paragraphWrap(str, maxLength) { + def outLines = [] + str.split("\n").each{par -> + def words = par.split("\\s").toList() + + def word = null + def line = words.pop() + while(!words.isEmpty()) { + word = words.pop() + if (line.length() + word.length() + 1 <= maxLength) { + line = line + " " + word + } else { + outLines.add(line) + line = word + } + } + if (words.isEmpty()) { + outLines.add(line) + } + } + return outLines +} + +def helpMessage(config) { + if (params.containsKey("help") && params.help) { + def mergedConfig = addGlobalArguments(config) + def helpStr = _generateHelp(mergedConfig) + println(helpStr) + exit 0 + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/processConfig.nf' +def processConfig(config) { + // set defaults for arguments + config.arguments = + (config.arguments ?: []).collect{_processArgument(it)} + + // set defaults for argument_group arguments + config.argument_groups = + (config.argument_groups ?: []).collect{grp -> + grp.arguments = (grp.arguments ?: []).collect{_processArgument(it)} + grp + } + + // create combined arguments list + config.allArguments = + config.arguments + + config.argument_groups.collectMany{it.arguments} + + // add missing argument groups (based on Functionality::allArgumentGroups()) + def argGroups = config.argument_groups + if (argGroups.any{it.name.toLowerCase() == "arguments"}) { + argGroups = argGroups.collect{ grp -> + if (grp.name.toLowerCase() == "arguments") { + grp = grp + [ + arguments: grp.arguments + config.arguments + ] + } + grp + } + } else { + argGroups = argGroups + [ + name: "Arguments", + arguments: config.arguments + ] + } + config.allArgumentGroups = argGroups + + config +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/readConfig.nf' + +def readConfig(file) { + def config = readYaml(file ?: moduleDir.resolve("config.vsh.yaml")) + processConfig(config) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_resolveSiblingIfNotAbsolute.nf' +/** + * Resolve a path relative to the current file. + * + * @param str The path to resolve, as a String. + * @param parentPath The path to resolve relative to, as a Path. + * + * @return The path that may have been resovled, as a Path. + */ +def _resolveSiblingIfNotAbsolute(str, parentPath) { + if (str !instanceof String) { + return str + } + if (!_stringIsAbsolutePath(str)) { + return parentPath.resolveSibling(str) + } else { + return file(str, hidden: true) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_stringIsAbsolutePath.nf' +/** + * Check whether a path as a string is absolute. + * + * In the past, we tried using `file(., relative: true).isAbsolute()`, + * but the 'relative' option was added in 22.10.0. + * + * @param path The path to check, as a String. + * + * @return Whether the path is absolute, as a boolean. + */ +def _stringIsAbsolutePath(path) { + def _resolve_URL_PROTOCOL = ~/^([a-zA-Z][a-zA-Z0-9]*:)?\\/.+/ + + assert path instanceof String + return _resolve_URL_PROTOCOL.matcher(path).matches() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/collectTraces.nf' +class CustomTraceObserver implements nextflow.trace.TraceObserver { + List traces + + CustomTraceObserver(List traces) { + this.traces = traces + } + + @Override + void onProcessComplete(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } + + @Override + void onProcessCached(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } +} + +def collectTraces() { + def traces = Collections.synchronizedList([]) + + // add custom trace observer which stores traces in the traces object + session.observers.add(new CustomTraceObserver(traces)) + + traces +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/deepClone.nf' +/** + * Performs a deep clone of the given object. + * @param x an object + */ +def deepClone(x) { + iterateMap(x, {it instanceof Cloneable ? it.clone() : it}) +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getPublishDir.nf' +def getPublishDir() { + return params.containsKey("publish_dir") ? params.publish_dir : + params.containsKey("publishDir") ? params.publishDir : + null +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getRootDir.nf' + +// Recurse upwards until we find a '.build.yaml' file +def _findBuildYamlFile(pathPossiblySymlink) { + def path = pathPossiblySymlink.toRealPath() + def child = path.resolve(".build.yaml") + if (java.nio.file.Files.isDirectory(path) && java.nio.file.Files.exists(child)) { + return child + } else { + def parent = path.getParent() + if (parent == null) { + return null + } else { + return _findBuildYamlFile(parent) + } + } +} + +// get the root of the target folder +def getRootDir() { + def dir = _findBuildYamlFile(meta.resources_dir) + assert dir != null: "Could not find .build.yaml in the folder structure" + dir.getParent() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/iterateMap.nf' +/** + * Recursively apply a function over the leaves of an object. + * @param obj The object to iterate over. + * @param fun The function to apply to each value. + * @return The object with the function applied to each value. + */ +def iterateMap(obj, fun) { + if (obj instanceof List && obj !instanceof String) { + return obj.collect{item -> + iterateMap(item, fun) + } + } else if (obj instanceof Map) { + return obj.collectEntries{key, item -> + [key.toString(), iterateMap(item, fun)] + } + } else { + return fun(obj) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/niceView.nf' +/** + * A view for printing the event of each channel as a YAML blob. + * This is useful for debugging. + */ +def niceView() { + workflow niceViewWf { + take: input + main: + output = input + | view{toYamlBlob(it)} + emit: output + } + return niceViewWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readCsv.nf' + +def readCsv(file_path) { + def output = [] + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + + // todo: allow escaped quotes in string + // todo: allow single quotes? + def splitRegex = java.util.regex.Pattern.compile(''',(?=(?:[^"]*"[^"]*")*[^"]*$)''') + def removeQuote = java.util.regex.Pattern.compile('''"(.*)"''') + + def br = java.nio.file.Files.newBufferedReader(inputFile) + + def row = -1 + def header = null + while (br.ready() && header == null) { + def line = br.readLine() + row++ + if (!line.startsWith("#")) { + header = splitRegex.split(line, -1).collect{field -> + m = removeQuote.matcher(field) + m.find() ? m.replaceFirst('$1') : field + } + } + } + assert header != null: "CSV file should contain a header" + + while (br.ready()) { + def line = br.readLine() + row++ + if (line == null) { + br.close() + break + } + + if (!line.startsWith("#")) { + def predata = splitRegex.split(line, -1) + def data = predata.collect{field -> + if (field == "") { + return null + } + def m = removeQuote.matcher(field) + if (m.find()) { + return m.replaceFirst('$1') + } else { + return field + } + } + assert header.size() == data.size(): "Row $row should contain the same number as fields as the header" + + def dataMap = [header, data].transpose().collectEntries().findAll{it.value != null} + output.add(dataMap) + } + } + + output +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJson.nf' +def readJson(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parse(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJsonBlob.nf' +def readJsonBlob(str) { + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parseText(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readTaggedYaml.nf' +// Custom constructor to modify how certain objects are parsed from YAML +class CustomConstructor extends org.yaml.snakeyaml.constructor.Constructor { + Path root + + class ConstructPath extends org.yaml.snakeyaml.constructor.AbstractConstruct { + public Object construct(org.yaml.snakeyaml.nodes.Node node) { + String filename = (String) constructScalar(node); + if (root != null) { + return root.resolve(filename); + } + return java.nio.file.Paths.get(filename); + } + } + + CustomConstructor(org.yaml.snakeyaml.LoaderOptions options, Path root) { + super(options) + this.root = root + // Handling !file tag and parse it back to a File type + this.yamlConstructors.put(new org.yaml.snakeyaml.nodes.Tag("!file"), new ConstructPath()) + } +} + +def readTaggedYaml(Path path) { + def options = new org.yaml.snakeyaml.LoaderOptions() + def constructor = new CustomConstructor(options, path.getParent()) + def yaml = new org.yaml.snakeyaml.Yaml(constructor) + return yaml.load(path.text) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYaml.nf' +def readYaml(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYamlBlob.nf' +def readYamlBlob(str) { + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toJsonBlob.nf' +String toJsonBlob(data) { + return groovy.json.JsonOutput.toJson(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toTaggedYamlBlob.nf' +// Custom representer to modify how certain objects are represented in YAML +class CustomRepresenter extends org.yaml.snakeyaml.representer.Representer { + Path relativizer + + class RepresentPath implements org.yaml.snakeyaml.representer.Represent { + public String getFileName(Object obj) { + if (obj instanceof File) { + obj = ((File) obj).toPath(); + } + if (obj !instanceof Path) { + throw new IllegalArgumentException("Object: " + obj + " is not a Path or File"); + } + def path = (Path) obj; + + if (relativizer != null) { + return relativizer.relativize(path).toString() + } else { + return path.toString() + } + } + + public org.yaml.snakeyaml.nodes.Node representData(Object data) { + String filename = getFileName(data); + def tag = new org.yaml.snakeyaml.nodes.Tag("!file"); + return representScalar(tag, filename); + } + } + CustomRepresenter(org.yaml.snakeyaml.DumperOptions options, Path relativizer) { + super(options) + this.relativizer = relativizer + this.representers.put(sun.nio.fs.UnixPath, new RepresentPath()) + this.representers.put(Path, new RepresentPath()) + this.representers.put(File, new RepresentPath()) + } +} + +String toTaggedYamlBlob(data) { + return toRelativeTaggedYamlBlob(data, null) +} +String toRelativeTaggedYamlBlob(data, Path relativizer) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + def representer = new CustomRepresenter(options, relativizer) + def yaml = new org.yaml.snakeyaml.Yaml(representer, options) + return yaml.dump(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toYamlBlob.nf' +String toYamlBlob(data) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + options.setPrettyFlow(true) + def yaml = new org.yaml.snakeyaml.Yaml(options) + def cleanData = iterateMap(data, { it instanceof Path ? it.toString() : it }) + return yaml.dump(cleanData) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeJson.nf' +void writeJson(data, file) { + assert data: "writeJson: data should not be null" + assert file: "writeJson: file should not be null" + file.write(toJsonBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeYaml.nf' +void writeYaml(data, file) { + assert data: "writeYaml: data should not be null" + assert file: "writeYaml: file should not be null" + file.write(toYamlBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/findStates.nf' +def findStates(Map params, Map config) { + def auto_config = deepClone(config) + def auto_params = deepClone(params) + + auto_config = auto_config.clone() + // override arguments + auto_config.argument_groups = [] + auto_config.arguments = [ + [ + type: "string", + name: "--id", + description: "A dummy identifier", + required: false + ], + [ + type: "file", + name: "--input_states", + example: "/path/to/input/directory/**/state.yaml", + description: "Path to input directory containing the datasets to be integrated.", + required: true, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--filter", + example: "foo/.*/state.yaml", + description: "Regex to filter state files by path.", + required: false + ], + // to do: make this a yaml blob? + [ + type: "string", + name: "--rename_keys", + example: ["newKey1:oldKey1", "newKey2:oldKey2"], + description: "Rename keys in the detected input files. This is useful if the input files do not match the set of input arguments of the workflow.", + required: false, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--settings", + example: '{"output_dataset": "dataset.h5ad", "k": 10}', + description: "Global arguments as a JSON glob to be passed to all components.", + required: false + ] + ] + if (!(auto_params.containsKey("id"))) { + auto_params["id"] = "auto" + } + + // run auto config through processConfig once more + auto_config = processConfig(auto_config) + + workflow findStatesWf { + helpMessage(auto_config) + + output_ch = + channelFromParams(auto_params, auto_config) + | flatMap { autoId, args -> + + def globalSettings = args.settings ? readYamlBlob(args.settings) : [:] + + // look for state files in input dir + def stateFiles = args.input_states + + // filter state files by regex + if (args.filter) { + stateFiles = stateFiles.findAll{ stateFile -> + def stateFileStr = stateFile.toString() + def matcher = stateFileStr =~ args.filter + matcher.matches()} + } + + // read in states + def states = stateFiles.collect { stateFile -> + def state_ = readTaggedYaml(stateFile) + [state_.id, state_] + } + + // construct renameMap + if (args.rename_keys) { + def renameMap = args.rename_keys.collectEntries{renameString -> + def split = renameString.split(":") + assert split.size() == 2: "Argument 'rename_keys' should be of the form 'newKey:oldKey', or 'newKey:oldKey;newKey:oldKey' in case of multiple values" + split + } + + // rename keys in state, only let states through which have all keys + // also add global settings + states = states.collectMany{id, state -> + def newState = [:] + + for (key in renameMap.keySet()) { + def origKey = renameMap[key] + if (!(state.containsKey(origKey))) { + return [] + } + newState[key] = state[origKey] + } + + [[id, globalSettings + newState]] + } + } + + states + } + emit: + output_ch + } + + return findStatesWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/joinStates.nf' +def joinStates(Closure apply_) { + workflow joinStatesWf { + take: input_ch + main: + output_ch = input_ch + | toSortedList + | filter{ it.size() > 0 } + | map{ tups -> + def ids = tups.collect{it[0]} + def states = tups.collect{it[1]} + apply_(ids, states) + } + + emit: output_ch + } + return joinStatesWf +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf' +def collectFiles(obj) { + if (obj instanceof java.io.File || obj instanceof Path) { + return [obj] + } else if (obj instanceof List && obj !instanceof String) { + return obj.collectMany{item -> + collectFiles(item) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectFiles(item) + } + } else { + return [] + } +} + +/** + * Recurse through a state and collect all input files and their target output filenames. + * @param obj The state to recurse through. + * @param prefix The prefix to prepend to the output filenames. + */ +def collectInputOutputPaths(obj, prefix) { + if (obj instanceof File || obj instanceof Path) { + def path = obj instanceof Path ? obj : obj.toPath() + def ext = path.getFileName().toString().find("\\.[^\\.]+\$") ?: "" + def newFilename = prefix + ext + return [[obj, newFilename]] + } else if (obj instanceof List && obj !instanceof String) { + return obj.withIndex().collectMany{item, ix -> + collectInputOutputPaths(item, prefix + "_" + ix) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectInputOutputPaths(item, prefix + "." + key) + } + } else { + return [] + } +} + +def publishStates(Map args) { + def key_ = args.get("key") + def yamlTemplate_ = args.get("output_state", args.get("outputState", '$id.$key.state.yaml')) + + assert key_ != null : "publishStates: key must be specified" + + workflow publishStatesWf { + 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] + + def yamlFilename = yamlTemplate_ + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .replaceAll('\\$\\{key\\}', key_) + + // TODO: do the pathnames in state_ match up with the outputFilenames_? + + // convert state to yaml blob + def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename)) + + [id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_] + } + | publishStatesProc + emit: input_ch + } + return publishStatesWf +} +process publishStatesProc { + // todo: check publishpath? + publishDir path: "${getPublishDir()}/", mode: "copy" + tag "$id" + input: + tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles) + output: + tuple val(id), path{[yamlFile] + 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 + [] + } + } + """ +mkdir -p "\$(dirname '${yamlFile}')" +echo "Storing state as yaml" +echo '${yamlBlob}' > '${yamlFile}' +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 publishStatesByConfig(Map args) { + def config = args.get("config") + assert config != null : "publishStatesByConfig: config must be specified" + + def key_ = args.get("key", config.name) + assert key_ != null : "publishStatesByConfig: key must be specified" + + workflow publishStatesSimpleWf { + 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'] + + // TODO: allow overriding the state.yaml template + // TODO TODO: if auto.publish == "state", add output_state as an argument + def yamlTemplate = params.containsKey("output_state") ? params.output_state : '$id.$key.state.yaml' + def yamlFilename = yamlTemplate + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .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 + // - 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" } + .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 + 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 [[key: plainName_, value: value, 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 value_ = java.nio.file.Paths.get(filename_ix) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = val instanceof File ? val.toPath() : val + [value: value_, inputPath: inputPath, outputFilename: filename_ix] + } + def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key -> + [key, outputPerFile.collect{dic -> dic[key]}] + } + return [[key: plainName_] + transposedOutputs] + } else { + def value_ = java.nio.file.Paths.get(filename) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = value instanceof File ? value.toPath() : value + return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]] + } + } + + 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] + } + | publishStatesProc + emit: input_ch + } + return publishStatesSimpleWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/setState.nf' +def setState(fun) { + assert fun instanceof Closure || fun instanceof Map || fun instanceof List : + "Error in setState: Expected process argument to be a Closure, a Map, or a List. Found: class ${fun.getClass()}" + + // if fun is a List, convert to map + if (fun instanceof List) { + // check whether fun is a list[string] + assert fun.every{it instanceof CharSequence} : "Error in setState: argument is a List, but not all elements are Strings" + fun = fun.collectEntries{[it, it]} + } + + // if fun is a map, convert to closure + if (fun instanceof Map) { + // check whether fun is a map[string, string] + assert fun.values().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all values are Strings" + assert fun.keySet().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all keys are Strings" + def funMap = fun.clone() + // turn the map into a closure to be used later on + fun = { id_, state_ -> + assert state_ instanceof Map : "Error in setState: the state is not a Map" + funMap.collectMany{newkey, origkey -> + if (state_.containsKey(origkey)) { + [[newkey, state_[origkey]]] + } else { + [] + } + }.collectEntries() + } + } + + map { tup -> + def id = tup[0] + def state = tup[1] + def unfilteredState = fun(id, state) + def newState = unfilteredState.findAll{key, val -> val != null} + [id, newState] + tup.drop(2) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processAuto.nf' +// TODO: unit test processAuto +def processAuto(Map auto) { + // remove null values + auto = auto.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = ["simplifyInput", "simplifyOutput", "transcript", "publish"] + def unexpectedKeys = auto.keySet() - expectedKeys + assert unexpectedKeys.isEmpty(), "unexpected keys in auto: '${unexpectedKeys.join("', '")}'" + + // check auto.simplifyInput + assert auto.simplifyInput instanceof Boolean, "auto.simplifyInput must be a boolean" + + // check auto.simplifyOutput + assert auto.simplifyOutput instanceof Boolean, "auto.simplifyOutput must be a boolean" + + // check auto.transcript + assert auto.transcript instanceof Boolean, "auto.transcript must be a boolean" + + // check auto.publish + assert auto.publish instanceof Boolean || auto.publish == "state", "auto.publish must be a boolean or 'state'" + + return auto.subMap(expectedKeys) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processDirectives.nf' +def assertMapKeys(map, expectedKeys, requiredKeys, mapName) { + assert map instanceof Map : "Expected argument '$mapName' to be a Map. Found: class ${map.getClass()}" + map.forEach { key, val -> + assert key in expectedKeys : "Unexpected key '$key' in ${mapName ? mapName + " " : ""}map" + } + requiredKeys.forEach { requiredKey -> + assert map.containsKey(requiredKey) : "Missing required key '$key' in ${mapName ? mapName + " " : ""}map" + } +} + +// TODO: unit test processDirectives +def processDirectives(Map drctv) { + // remove null values + drctv = drctv.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = [ + "accelerator", "afterScript", "beforeScript", "cache", "conda", "container", "containerOptions", "cpus", "disk", "echo", "errorStrategy", "executor", "machineType", "maxErrors", "maxForks", "maxRetries", "memory", "module", "penv", "pod", "publishDir", "queue", "label", "scratch", "storeDir", "stageInMode", "stageOutMode", "tag", "time" + ] + def unexpectedKeys = drctv.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Unexpected keys in process directive: '${unexpectedKeys.join("', '")}'" + + /* DIRECTIVE accelerator + accepted examples: + - [ limit: 4, type: "nvidia-tesla-k80" ] + */ + if (drctv.containsKey("accelerator")) { + assertMapKeys(drctv["accelerator"], ["type", "limit", "request", "runtime"], [], "accelerator") + } + + /* DIRECTIVE afterScript + accepted examples: + - "source /cluster/bin/cleanup" + */ + if (drctv.containsKey("afterScript")) { + assert drctv["afterScript"] instanceof CharSequence + } + + /* DIRECTIVE beforeScript + accepted examples: + - "source /cluster/bin/setup" + */ + if (drctv.containsKey("beforeScript")) { + assert drctv["beforeScript"] instanceof CharSequence + } + + /* DIRECTIVE cache + accepted examples: + - true + - false + - "deep" + - "lenient" + */ + if (drctv.containsKey("cache")) { + assert drctv["cache"] instanceof CharSequence || drctv["cache"] instanceof Boolean + if (drctv["cache"] instanceof CharSequence) { + assert drctv["cache"] in ["deep", "lenient"] : "Unexpected value for cache" + } + } + + /* DIRECTIVE conda + accepted examples: + - "bwa=0.7.15" + - "bwa=0.7.15 fastqc=0.11.5" + - ["bwa=0.7.15", "fastqc=0.11.5"] + */ + if (drctv.containsKey("conda")) { + if (drctv["conda"] instanceof List) { + drctv["conda"] = drctv["conda"].join(" ") + } + assert drctv["conda"] instanceof CharSequence + } + + /* DIRECTIVE container + accepted examples: + - "foo/bar:tag" + - [ registry: "reg", image: "im", tag: "ta" ] + is transformed to "reg/im:ta" + - [ image: "im" ] + is transformed to "im:latest" + */ + if (drctv.containsKey("container")) { + assert drctv["container"] instanceof Map || drctv["container"] instanceof CharSequence + if (drctv["container"] instanceof Map) { + def m = drctv["container"] + assertMapKeys(m, [ "registry", "image", "tag" ], ["image"], "container") + def part1 = + System.getenv('OVERRIDE_CONTAINER_REGISTRY') ? System.getenv('OVERRIDE_CONTAINER_REGISTRY') + "/" : + params.containsKey("override_container_registry") ? params["override_container_registry"] + "/" : // todo: remove? + m.registry ? m.registry + "/" : + "" + def part2 = m.image + def part3 = m.tag ? ":" + m.tag : ":latest" + drctv["container"] = part1 + part2 + part3 + } + } + + /* DIRECTIVE containerOptions + accepted examples: + - "--foo bar" + - ["--foo bar", "-f b"] + */ + if (drctv.containsKey("containerOptions")) { + if (drctv["containerOptions"] instanceof List) { + drctv["containerOptions"] = drctv["containerOptions"].join(" ") + } + assert drctv["containerOptions"] instanceof CharSequence + } + + /* DIRECTIVE cpus + accepted examples: + - 1 + - 10 + */ + if (drctv.containsKey("cpus")) { + assert drctv["cpus"] instanceof Integer + } + + /* DIRECTIVE disk + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("disk")) { + assert drctv["disk"] instanceof CharSequence + // assert drctv["disk"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE echo + accepted examples: + - true + - false + */ + if (drctv.containsKey("echo")) { + assert drctv["echo"] instanceof Boolean + } + + /* DIRECTIVE errorStrategy + accepted examples: + - "terminate" + - "finish" + */ + if (drctv.containsKey("errorStrategy")) { + assert drctv["errorStrategy"] instanceof CharSequence + assert drctv["errorStrategy"] in ["terminate", "finish", "ignore", "retry"] : "Unexpected value for errorStrategy" + } + + /* DIRECTIVE executor + accepted examples: + - "local" + - "sge" + */ + if (drctv.containsKey("executor")) { + assert drctv["executor"] instanceof CharSequence + assert drctv["executor"] in ["local", "sge", "uge", "lsf", "slurm", "pbs", "pbspro", "moab", "condor", "nqsii", "ignite", "k8s", "awsbatch", "google-pipelines"] : "Unexpected value for executor" + } + + /* DIRECTIVE machineType + accepted examples: + - "n1-highmem-8" + */ + if (drctv.containsKey("machineType")) { + assert drctv["machineType"] instanceof CharSequence + } + + /* DIRECTIVE maxErrors + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxErrors")) { + assert drctv["maxErrors"] instanceof Integer + } + + /* DIRECTIVE maxForks + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxForks")) { + assert drctv["maxForks"] instanceof Integer + } + + /* DIRECTIVE maxRetries + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxRetries")) { + assert drctv["maxRetries"] instanceof Integer + } + + /* DIRECTIVE memory + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("memory")) { + assert drctv["memory"] instanceof CharSequence + // assert drctv["memory"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE module + accepted examples: + - "ncbi-blast/2.2.27" + - "ncbi-blast/2.2.27:t_coffee/10.0" + - ["ncbi-blast/2.2.27", "t_coffee/10.0"] + */ + if (drctv.containsKey("module")) { + if (drctv["module"] instanceof List) { + drctv["module"] = drctv["module"].join(":") + } + assert drctv["module"] instanceof CharSequence + } + + /* DIRECTIVE penv + accepted examples: + - "smp" + */ + if (drctv.containsKey("penv")) { + assert drctv["penv"] instanceof CharSequence + } + + /* DIRECTIVE pod + accepted examples: + - [ label: "key", value: "val" ] + - [ annotation: "key", value: "val" ] + - [ env: "key", value: "val" ] + - [ [label: "l", value: "v"], [env: "e", value: "v"]] + */ + if (drctv.containsKey("pod")) { + if (drctv["pod"] instanceof Map) { + drctv["pod"] = [ drctv["pod"] ] + } + assert drctv["pod"] instanceof List + drctv["pod"].forEach { pod -> + assert pod instanceof Map + // TODO: should more checks be added? + // See https://www.nextflow.io/docs/latest/process.html?highlight=directives#pod + // e.g. does it contain 'label' and 'value', or 'annotation' and 'value', or ...? + } + } + + /* DIRECTIVE publishDir + accepted examples: + - [] + - [ [ path: "foo", enabled: true ], [ path: "bar", enabled: false ] ] + - "/path/to/dir" + is transformed to [[ path: "/path/to/dir" ]] + - [ path: "/path/to/dir", mode: "cache" ] + is transformed to [[ path: "/path/to/dir", mode: "cache" ]] + */ + // TODO: should we also look at params["publishDir"]? + if (drctv.containsKey("publishDir")) { + def pblsh = drctv["publishDir"] + + // check different options + assert pblsh instanceof List || pblsh instanceof Map || pblsh instanceof CharSequence + + // turn into list if not already so + // for some reason, 'if (!pblsh instanceof List) pblsh = [ pblsh ]' doesn't work. + pblsh = pblsh instanceof List ? pblsh : [ pblsh ] + + // check elements of publishDir + pblsh = pblsh.collect{ elem -> + // turn into map if not already so + elem = elem instanceof CharSequence ? [ path: elem ] : elem + + // check types and keys + assert elem instanceof Map : "Expected publish argument '$elem' to be a String or a Map. Found: class ${elem.getClass()}" + assertMapKeys(elem, [ "path", "mode", "overwrite", "pattern", "saveAs", "enabled" ], ["path"], "publishDir") + + // check elements in map + assert elem.containsKey("path") + assert elem["path"] instanceof CharSequence + if (elem.containsKey("mode")) { + assert elem["mode"] instanceof CharSequence + assert elem["mode"] in [ "symlink", "rellink", "link", "copy", "copyNoFollow", "move" ] + } + if (elem.containsKey("overwrite")) { + assert elem["overwrite"] instanceof Boolean + } + if (elem.containsKey("pattern")) { + assert elem["pattern"] instanceof CharSequence + } + if (elem.containsKey("saveAs")) { + assert elem["saveAs"] instanceof CharSequence //: "saveAs as a Closure is currently not supported. Surround your closure with single quotes to get the desired effect. Example: '\{ foo \}'" + } + if (elem.containsKey("enabled")) { + assert elem["enabled"] instanceof Boolean + } + + // return final result + elem + } + // store final directive + drctv["publishDir"] = pblsh + } + + /* DIRECTIVE queue + accepted examples: + - "long" + - "short,long" + - ["short", "long"] + */ + if (drctv.containsKey("queue")) { + if (drctv["queue"] instanceof List) { + drctv["queue"] = drctv["queue"].join(",") + } + assert drctv["queue"] instanceof CharSequence + } + + /* DIRECTIVE label + accepted examples: + - "big_mem" + - "big_cpu" + - ["big_mem", "big_cpu"] + */ + if (drctv.containsKey("label")) { + if (drctv["label"] instanceof CharSequence) { + drctv["label"] = [ drctv["label"] ] + } + assert drctv["label"] instanceof List + drctv["label"].forEach { label -> + assert label instanceof CharSequence + // assert label.matches("[a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?") + // ^ does not allow closures + } + } + + /* DIRECTIVE scratch + accepted examples: + - true + - "/path/to/scratch" + - '$MY_PATH_TO_SCRATCH' + - "ram-disk" + */ + if (drctv.containsKey("scratch")) { + assert drctv["scratch"] == true || drctv["scratch"] instanceof CharSequence + } + + /* DIRECTIVE storeDir + accepted examples: + - "/path/to/storeDir" + */ + if (drctv.containsKey("storeDir")) { + assert drctv["storeDir"] instanceof CharSequence + } + + /* DIRECTIVE stageInMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageInMode")) { + assert drctv["stageInMode"] instanceof CharSequence + assert drctv["stageInMode"] in ["copy", "link", "symlink", "rellink"] + } + + /* DIRECTIVE stageOutMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageOutMode")) { + assert drctv["stageOutMode"] instanceof CharSequence + assert drctv["stageOutMode"] in ["copy", "move", "rsync"] + } + + /* DIRECTIVE tag + accepted examples: + - "foo" + - '$id' + */ + if (drctv.containsKey("tag")) { + assert drctv["tag"] instanceof CharSequence + } + + /* DIRECTIVE time + accepted examples: + - "1h" + - "2days" + - "1day 6hours 3minutes 30seconds" + */ + if (drctv.containsKey("time")) { + assert drctv["time"] instanceof CharSequence + // todo: validation regex? + } + + return drctv +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processWorkflowArgs.nf' +def processWorkflowArgs(Map args, Map defaultWfArgs, Map meta) { + // override defaults with args + def workflowArgs = defaultWfArgs + args + + // check whether 'key' exists + assert workflowArgs.containsKey("key") : "Error in module '${meta.config.name}': key is a required argument" + + // if 'key' is a closure, apply it to the original key + if (workflowArgs["key"] instanceof Closure) { + workflowArgs["key"] = workflowArgs["key"](meta.config.name) + } + def key = workflowArgs["key"] + assert key instanceof CharSequence : "Expected process argument 'key' to be a String. Found: class ${key.getClass()}" + assert key ==~ /^[a-zA-Z_]\w*$/ : "Error in module '$key': Expected process argument 'key' to consist of only letters, digits or underscores. Found: ${key}" + + // check for any unexpected keys + def expectedKeys = ["key", "directives", "auto", "map", "mapId", "mapData", "mapPassthrough", "filter", "runIf", "fromState", "toState", "args", "renameKeys", "debug"] + def unexpectedKeys = workflowArgs.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Error in module '$key': unexpected arguments to the '.run()' function: '${unexpectedKeys.join("', '")}'" + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("directives") : "Error in module '$key': directives is a required argument" + assert workflowArgs["directives"] instanceof Map : "Error in module '$key': Expected process argument 'directives' to be a Map. Found: class ${workflowArgs['directives'].getClass()}" + workflowArgs["directives"] = processDirectives(defaultWfArgs.directives + workflowArgs["directives"]) + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("auto") : "Error in module '$key': auto is a required argument" + assert workflowArgs["auto"] instanceof Map : "Error in module '$key': Expected process argument 'auto' to be a Map. Found: class ${workflowArgs['auto'].getClass()}" + workflowArgs["auto"] = processAuto(defaultWfArgs.auto + workflowArgs["auto"]) + + // auto define publish, if so desired + if (workflowArgs.auto.publish == true && (workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : [:]).isEmpty()) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.publish is true, params.publish_dir needs to be defined.\n" + + // " Example: params.publish_dir = \"./output/\"" + def publishDir = getPublishDir() + + if (publishDir != null) { + workflowArgs.directives.publishDir = [[ + path: publishDir, + saveAs: "{ it.startsWith('.') ? null : it }", // don't publish hidden files, by default + mode: "copy" + ]] + } + } + + // auto define transcript, if so desired + if (workflowArgs.auto.transcript == true) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("transcriptsDir") || params.containsKey("transcripts_dir") || params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.transcript is true, either params.transcripts_dir or params.publish_dir needs to be defined.\n" + + // " Example: params.transcripts_dir = \"./transcripts/\"" + def transcriptsDir = + params.containsKey("transcripts_dir") ? params.transcripts_dir : + params.containsKey("transcriptsDir") ? params.transcriptsDir : + params.containsKey("publish_dir") ? params.publish_dir + "/_transcripts" : + params.containsKey("publishDir") ? params.publishDir + "/_transcripts" : + null + if (transcriptsDir != null) { + def timestamp = nextflow.Nextflow.getSession().getWorkflowMetadata().start.format('yyyy-MM-dd_HH-mm-ss') + def transcriptsPublishDir = [ + path: "$transcriptsDir/$timestamp/\${task.process.replaceAll(':', '-')}/\${id}/", + saveAs: "{ it.startsWith('.') ? it.replaceAll('^.', '') : null }", + mode: "copy" + ] + def publishDirs = workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : null ? workflowArgs.directives.publishDir : [] + workflowArgs.directives.publishDir = publishDirs + transcriptsPublishDir + } + } + + // if this is a stubrun, remove certain directives? + if (workflow.stubRun) { + workflowArgs.directives.keySet().removeAll(["publishDir", "cpus", "memory", "label"]) + } + + for (nam in ["map", "mapId", "mapData", "mapPassthrough", "filter", "runIf"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam]) { + assert workflowArgs[nam] instanceof Closure : "Error in module '$key': Expected process argument '$nam' to be null or a Closure. Found: class ${workflowArgs[nam].getClass()}" + } + } + + // TODO: should functions like 'map', 'mapId', 'mapData', 'mapPassthrough' be deprecated as well? + for (nam in ["map", "mapData", "mapPassthrough", "renameKeys"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam] != null) { + log.warn "module '$key': workflow argument '$nam' is deprecated and will be removed in Viash 0.9.0. Please use 'fromState' and 'toState' instead." + } + } + + // check fromState + workflowArgs["fromState"] = _processFromState(workflowArgs.get("fromState"), key, meta.config) + + // check toState + workflowArgs["toState"] = _processToState(workflowArgs.get("toState"), key, meta.config) + + // return output + return workflowArgs +} + +def _processFromState(fromState, key_, config_) { + assert fromState == null || fromState instanceof Closure || fromState instanceof Map || fromState instanceof List : + "Error in module '$key_': Expected process argument 'fromState' to be null, a Closure, a Map, or a List. Found: class ${fromState.getClass()}" + if (fromState == null) { + return null + } + + // if fromState is a List, convert to map + if (fromState instanceof List) { + // check whether fromstate is a list[string] + assert fromState.every{it instanceof CharSequence} : "Error in module '$key_': fromState is a List, but not all elements are Strings" + fromState = fromState.collectEntries{[it, it]} + } + + // if fromState is a map, convert to closure + if (fromState instanceof Map) { + // check whether fromstate is a map[string, string] + assert fromState.values().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all values are Strings" + assert fromState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all keys are Strings" + def fromStateMap = fromState.clone() + def requiredInputNames = meta.config.allArguments.findAll{it.required && it.direction == "Input"}.collect{it.plainName} + // turn the map into a closure to be used later on + fromState = { it -> + def state = it[1] + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def data = fromStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (state.containsKey(origkey)) { + [[newkey, state[origkey]]] + } else if (!requiredInputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': fromState key '$origkey' not found in current state") + } + }.collectEntries() + data + } + } + + return fromState +} + +def _processToState(toState, key_, config_) { + if (toState == null) { + toState = { tup -> tup[1] } + } + + // toState should be a closure, map[string, string], or list[string] + assert toState instanceof Closure || toState instanceof Map || toState instanceof List : + "Error in module '$key_': Expected process argument 'toState' to be a Closure, a Map, or a List. Found: class ${toState.getClass()}" + + // if toState is a List, convert to map + if (toState instanceof List) { + // check whether toState is a list[string] + assert toState.every{it instanceof CharSequence} : "Error in module '$key_': toState is a List, but not all elements are Strings" + toState = toState.collectEntries{[it, it]} + } + + // if toState is a map, convert to closure + if (toState instanceof Map) { + // check whether toState is a map[string, string] + assert toState.values().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all values are Strings" + assert toState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all keys are Strings" + def toStateMap = toState.clone() + def requiredOutputNames = config_.allArguments.findAll{it.required && it.direction == "Output"}.collect{it.plainName} + // turn the map into a closure to be used later on + toState = { it -> + def output = it[1] + def state = it[2] + assert output instanceof Map : "Error in module '$key_': the output is not a Map" + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def extraEntries = toStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (output.containsKey(origkey)) { + [[newkey, output[origkey]]] + } else if (!requiredOutputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': toState key '$origkey' not found in current output") + } + }.collectEntries() + state + extraEntries + } + } + + return toState +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/workflowFactory.nf' +def _debug(workflowArgs, debugKey) { + if (workflowArgs.debug) { + view { "process '${workflowArgs.key}' $debugKey tuple: $it" } + } else { + map { it } + } +} + +// depends on: innerWorkflowFactory +def workflowFactory(Map args, Map defaultWfArgs, Map meta) { + def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta) + def key_ = workflowArgs["key"] + + workflow workflowInstance { + take: input_ + + main: + def chModified = input_ + | checkUniqueIds([:]) + | _debug(workflowArgs, "input") + | map { tuple -> + tuple = deepClone(tuple) + + if (workflowArgs.map) { + tuple = workflowArgs.map(tuple) + } + if (workflowArgs.mapId) { + tuple[0] = workflowArgs.mapId(tuple[0]) + } + if (workflowArgs.mapData) { + tuple[1] = workflowArgs.mapData(tuple[1]) + } + if (workflowArgs.mapPassthrough) { + tuple = tuple.take(2) + workflowArgs.mapPassthrough(tuple.drop(2)) + } + + // check tuple + assert tuple instanceof List : + "Error in module '${key_}': element in 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()}" + assert tuple.size() >= 2 : + "Error in module '${key_}': expected length of tuple in input channel to be two or greater.\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: tuple.size() == ${tuple.size()}" + + // check id field + if (tuple[0] instanceof GString) { + tuple[0] = tuple[0].toString() + } + assert tuple[0] instanceof CharSequence : + "Error in module '${key_}': first element of tuple in channel should be a String\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: ${tuple[0]}" + + // match file to input file + if (workflowArgs.auto.simplifyInput && (tuple[1] instanceof Path || tuple[1] instanceof List)) { + def inputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + + assert inputFiles.size() == 1 : + "Error in module '${key_}' id '${tuple[0]}'.\n" + + " Anonymous file inputs are only allowed when the process has exactly one file input.\n" + + " Expected: inputFiles.size() == 1. Found: inputFiles.size() is ${inputFiles.size()}" + + tuple[1] = [[ inputFiles[0].plainName, tuple[1] ]].collectEntries() + } + + // check data field + assert tuple[1] instanceof Map : + "Error in module '${key_}' id '${tuple[0]}': second element of tuple in channel should be a Map\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // rename keys of data field in tuple + if (workflowArgs.renameKeys) { + assert workflowArgs.renameKeys instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class: Map. Found: renameKeys.getClass() is ${workflowArgs.renameKeys.getClass()}" + assert tuple[1] instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // TODO: allow renameKeys to be a function? + workflowArgs.renameKeys.each { newKey, oldKey -> + assert newKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of newKey: String. Found: newKey.getClass() is ${newKey.getClass()}" + assert oldKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of oldKey: String. Found: oldKey.getClass() is ${oldKey.getClass()}" + assert tuple[1].containsKey(oldKey) : + "Error renaming data keys in module '${key}' id '${tuple[0]}'.\n" + + " Key '$oldKey' is missing in the data map. tuple[1].keySet() is '${tuple[1].keySet()}'" + tuple[1].put(newKey, tuple[1][oldKey]) + } + tuple[1].keySet().removeAll(workflowArgs.renameKeys.collect{ newKey, oldKey -> oldKey }) + } + tuple + } + + + def chRun = null + def chPassthrough = null + if (workflowArgs.runIf) { + def runIfBranch = chModified.branch{ tup -> + run: workflowArgs.runIf(tup[0], tup[1]) + passthrough: true + } + chRun = runIfBranch.run + chPassthrough = runIfBranch.passthrough + } else { + chRun = chModified + chPassthrough = Channel.empty() + } + + def chRunFiltered = workflowArgs.filter ? + chRun | filter{workflowArgs.filter(it)} : + chRun + + def chArgs = workflowArgs.fromState ? + chRunFiltered | map{ + def new_data = workflowArgs.fromState(it.take(2)) + [it[0], new_data] + } : + chRunFiltered | map {tup -> tup.take(2)} + + // fill in defaults + def chArgsWithDefaults = chArgs + | map { tuple -> + def id_ = tuple[0] + def data_ = tuple[1] + + // TODO: could move fromState to here + + // fetch default params from functionality + def defaultArgs = meta.config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + // fetch overrides in params + def paramArgs = meta.config.allArguments + .findAll { par -> + def argKey = key_ + "__" + par.plainName + params.containsKey(argKey) + } + .collectEntries { [ it.plainName, params[key_ + "__" + it.plainName] ] } + + // fetch overrides in data + def dataArgs = meta.config.allArguments + .findAll { data_.containsKey(it.plainName) } + .collectEntries { [ it.plainName, data_[it.plainName] ] } + + // combine params + def combinedArgs = defaultArgs + paramArgs + workflowArgs.args + dataArgs + + // remove arguments with explicit null values + combinedArgs + .removeAll{_, val -> val == null || val == "viash_no_value" || val == "force_null"} + + combinedArgs = _processInputValues(combinedArgs, meta.config, id_, key_) + + [id_, combinedArgs] + tuple.drop(2) + } + + // TODO: move some of the _meta.join_id wrangling to the safeJoin() function. + def chInitialOutput = chArgsWithDefaults + | _debug(workflowArgs, "processed") + // run workflow + | innerWorkflowFactory(workflowArgs) + // check output tuple + | map { id_, output_ -> + + // see if output map contains metadata + def meta_ = + output_ instanceof Map && output_.containsKey("_meta") ? + output_["_meta"] : + [:] + def join_id = meta_.join_id ?: id_ + + // remove metadata + output_ = output_.findAll{k, v -> k != "_meta"} + + // check value types + output_ = _processOutputValues(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_] + } + // | view{"chInitialOutput: ${it.take(3)}"} + + // join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...] + def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_) + // input tuple format: [join_id, id, output, prev_state, ...] + // output tuple format: [join_id, id, new_state, ...] + | map{ tup -> + def new_state = workflowArgs.toState(tup.drop(1).take(3)) + tup.take(2) + [new_state] + tup.drop(4) + } + + if (workflowArgs.auto.publish == "state") { + def chPublish = 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_) + // 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, ...] + // output tuple format: [id, new_state, ...] + tup.drop(1) + } + | _debug(workflowArgs, "output") + | concat(chPassthrough) + + emit: chReturn + } + + def wf = workflowInstance.cloneWithName(key_) + + // add factory function + wf.metaClass.run = { runArgs -> + workflowFactory(runArgs, workflowArgs, meta) + } + // add config to module for later introspection + wf.metaClass.config = meta.config + + return wf +} + +nextflow.enable.dsl=2 + +// START COMPONENT-SPECIFIC CODE + +// create meta object +meta = [ + "resources_dir": moduleDir.toRealPath().normalize(), + "config": processConfig(readJsonBlob('''{ + "name" : "agat_sp_merge_annotations", + "namespace" : "agat", + "version" : "main", + "authors" : [ + { + "name" : "Leïla Paquay", + "roles" : [ + "author", + "maintainer" + ], + "info" : { + "links" : { + "email" : "leila@data-intuitive.com", + "github" : "Leila011", + "linkedin" : "leilapaquay" + }, + "organizations" : [ + { + "name" : "Data Intuitive", + "href" : "https://www.data-intuitive.com", + "role" : "Software Developer" + } + ] + } + } + ], + "argument_groups" : [ + { + "name" : "Inputs", + "arguments" : [ + { + "type" : "file", + "name" : "--gff", + "alternatives" : [ + "-f" + ], + "description" : "Input GTF/GFF file(s).\n", + "example" : [ + "input1.gff;input2.gff" + ], + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : true, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Outputs", + "arguments" : [ + { + "type" : "file", + "name" : "--output", + "alternatives" : [ + "-o", + "--out" + ], + "description" : "Output gff3 file where the gene incriminated will be writen.", + "example" : [ + "output.gff" + ], + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Arguments", + "arguments" : [ + { + "type" : "file", + "name" : "--config", + "alternatives" : [ + "-c" + ], + "description" : "AGAT config file. By default AGAT takes the original agat_config.yaml shipped with AGAT. \nThe `--config` option gives you the possibility to use your own AGAT config file (located\nelsewhere or named differently).\n", + "example" : [ + "custom_agat_config.yaml" + ], + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Merge different gff annotation files into one. It uses the AGAT parser that takes care of\nduplicated names and fixes other oddities met in those files.\n", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + }, + { + "type" : "file", + "path" : "test_data" + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "keywords" : [ + "gene annotations", + "merge", + "gff" + ], + "license" : "GPL-3.0", + "references" : { + "doi" : [ + "10.5281/zenodo.3552717" + ] + }, + "links" : { + "repository" : "https://github.com/NBISweden/AGAT", + "homepage" : "https://github.com/NBISweden/AGAT", + "documentation" : "https://agat.readthedocs.io/en/latest/tools/agat_sp_merge_annotations.html", + "issue_tracker" : "https://github.com/NBISweden/AGAT/issues" + }, + "runners" : [ + { + "type" : "executable", + "id" : "executable", + "docker_setup_strategy" : "ifneedbepullelsecachedbuild" + }, + { + "type" : "nextflow", + "id" : "nextflow", + "directives" : { + "tag" : "$id" + }, + "auto" : { + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false + }, + "config" : { + "labels" : { + "mem1gb" : "memory = 1000000000.B", + "mem2gb" : "memory = 2000000000.B", + "mem5gb" : "memory = 5000000000.B", + "mem10gb" : "memory = 10000000000.B", + "mem20gb" : "memory = 20000000000.B", + "mem50gb" : "memory = 50000000000.B", + "mem100gb" : "memory = 100000000000.B", + "mem200gb" : "memory = 200000000000.B", + "mem500gb" : "memory = 500000000000.B", + "mem1tb" : "memory = 1000000000000.B", + "mem2tb" : "memory = 2000000000000.B", + "mem5tb" : "memory = 5000000000000.B", + "mem10tb" : "memory = 10000000000000.B", + "mem20tb" : "memory = 20000000000000.B", + "mem50tb" : "memory = 50000000000000.B", + "mem100tb" : "memory = 100000000000000.B", + "mem200tb" : "memory = 200000000000000.B", + "mem500tb" : "memory = 500000000000000.B", + "mem1gib" : "memory = 1073741824.B", + "mem2gib" : "memory = 2147483648.B", + "mem4gib" : "memory = 4294967296.B", + "mem8gib" : "memory = 8589934592.B", + "mem16gib" : "memory = 17179869184.B", + "mem32gib" : "memory = 34359738368.B", + "mem64gib" : "memory = 68719476736.B", + "mem128gib" : "memory = 137438953472.B", + "mem256gib" : "memory = 274877906944.B", + "mem512gib" : "memory = 549755813888.B", + "mem1tib" : "memory = 1099511627776.B", + "mem2tib" : "memory = 2199023255552.B", + "mem4tib" : "memory = 4398046511104.B", + "mem8tib" : "memory = 8796093022208.B", + "mem16tib" : "memory = 17592186044416.B", + "mem32tib" : "memory = 35184372088832.B", + "mem64tib" : "memory = 70368744177664.B", + "mem128tib" : "memory = 140737488355328.B", + "mem256tib" : "memory = 281474976710656.B", + "mem512tib" : "memory = 562949953421312.B", + "cpu1" : "cpus = 1", + "cpu2" : "cpus = 2", + "cpu5" : "cpus = 5", + "cpu10" : "cpus = 10", + "cpu20" : "cpus = 20", + "cpu50" : "cpus = 50", + "cpu100" : "cpus = 100", + "cpu200" : "cpus = 200", + "cpu500" : "cpus = 500", + "cpu1000" : "cpus = 1000" + } + }, + "debug" : false, + "container" : "docker" + } + ], + "engines" : [ + { + "type" : "docker", + "id" : "docker", + "image" : "quay.io/biocontainers/agat:1.4.0--pl5321hdfd78af_0", + "target_registry" : "images.viash-hub.com", + "target_tag" : "main", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "docker", + "run" : [ + "agat --version | sed 's/AGAT\\\\s\\\\(.*\\\\)/agat: \\"\\\\1\\"/' > /var/software_versions.txt\n" + ] + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/agat/agat_sp_merge_annotations/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/agat/agat_sp_merge_annotations", + "viash_version" : "0.9.0", + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" + }, + "package_config" : { + "name" : "biobox", + "version" : "main", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0", + "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 := 'main'" + ], + "keywords" : [ + "bioinformatics", + "modules", + "sequencing" + ], + "license" : "MIT", + "organization" : "vsh", + "links" : { + "repository" : "https://github.com/viash-hub/biobox", + "issue_tracker" : "https://github.com/viash-hub/biobox/issues" + } + } +}''')) +] + +// resolve dependencies dependencies (if any) + + +// inner workflow +// inner workflow hook +def innerWorkflowFactory(args) { + def rawScript = '''set -e +tempscript=".viash_script.sh" +cat > "$tempscript" << VIASHMAIN +#!/bin/bash + +set -eo pipefail + +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_GFF+x} ]; then echo "${VIASH_PAR_GFF}" | sed "s#'#'\\"'\\"'#g;s#.*#par_gff='&'#" ; else echo "# par_gff="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; fi ) +$( if [ ! -z ${VIASH_PAR_CONFIG+x} ]; then echo "${VIASH_PAR_CONFIG}" | sed "s#'#'\\"'\\"'#g;s#.*#par_config='&'#" ; else echo "# par_config="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END + +# Convert a list of file names to multiple -gff arguments +input_files="" +IFS=";" read -ra file_names <<< "\\$par_gff" +for file in "\\${file_names[@]}"; do + input_files+="--gff \\$file " +done + +# run agat_sp_merge_annotations +agat_sp_merge_annotations.pl \\\\ + \\$input_files \\\\ + -o "\\$par_output" \\\\ + \\${par_config:+--config "\\${par_config}"} +VIASHMAIN +bash "$tempscript" +''' + + return vdsl3WorkflowFactory(args, meta, rawScript) +} + + + +/** + * Generate a workflow for VDSL3 modules. + * + * This function is called by the workflowFactory() function. + * + * Input channel: [id, input_map] + * Output channel: [id, output_map] + * + * Internally, this workflow will convert the input channel + * to a format which the Nextflow module will be able to handle. + */ +def vdsl3WorkflowFactory(Map args, Map meta, String rawScript) { + def key = args["key"] + def processObj = null + + workflow processWf { + take: input_ + main: + + if (processObj == null) { + processObj = _vdsl3ProcessFactory(args, meta, rawScript) + } + + output_ = input_ + | map { tuple -> + def id = tuple[0] + def data_ = tuple[1] + + if (workflow.stubRun) { + // add id if missing + data_ = [id: 'stub'] + data_ + } + + // process input files separately + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { par -> + def val = data_.containsKey(par.plainName) ? data_[par.plainName] : [] + def inputFiles = [] + if (val == null) { + inputFiles = [] + } else if (val instanceof List) { + inputFiles = val + } else if (val instanceof Path) { + inputFiles = [ val ] + } else { + inputFiles = [] + } + if (!workflow.stubRun) { + // throw error when an input file doesn't exist + inputFiles.each{ file -> + assert file.exists() : + "Error in module '${key}' id '${id}' argument '${par.plainName}'.\n" + + " Required input file does not exist.\n" + + " Path: '$file'.\n" + + " Expected input file to exist" + } + } + inputFiles + } + + // remove input files + def argsExclInputFiles = meta.config.allArguments + .findAll { (it.type != "file" || it.direction != "input") && data_.containsKey(it.plainName) } + .collectEntries { par -> + def parName = par.plainName + def val = data_[parName] + if (par.multiple && val instanceof Collection) { + val = val.join(par.multiple_sep) + } + if (par.direction == "output" && par.type == "file") { + val = val + .replaceAll('\\$id', id) + .replaceAll('\\$\\{id\\}', id) + .replaceAll('\\$key', key) + .replaceAll('\\$\\{key\\}', key) + } + [parName, val] + } + + [ id ] + inputPaths + [ argsExclInputFiles, meta.resources_dir ] + } + | processObj + | map { output -> + def outputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .indexed() + .collectEntries{ index, par -> + def out = output[index + 1] + // strip dummy '.exitcode' file from output (see nextflow-io/nextflow#2678) + if (!out instanceof List || out.size() <= 1) { + if (par.multiple) { + out = [] + } else { + assert !par.required : + "Error in module '${key}' id '${output[0]}' argument '${par.plainName}'.\n" + + " Required output file is missing" + out = null + } + } else if (out.size() == 2 && !par.multiple) { + out = out[1] + } else { + out = out.drop(1) + } + [ par.plainName, out ] + } + + // drop null outputs + outputFiles.removeAll{it.value == null} + + [ output[0], outputFiles ] + } + emit: output_ + } + + return processWf +} + +// depends on: session? +def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) { + // autodetect process key + def wfKey = workflowArgs["key"] + def procKeyPrefix = "${wfKey}_process" + def scriptMeta = nextflow.script.ScriptMeta.current() + def existing = scriptMeta.getProcessNames().findAll{it.startsWith(procKeyPrefix)} + def numbers = existing.collect{it.replace(procKeyPrefix, "0").toInteger()} + def newNumber = (numbers + [-1]).max() + 1 + + def procKey = newNumber == 0 ? procKeyPrefix : "$procKeyPrefix$newNumber" + + if (newNumber > 0) { + log.warn "Key for module '${wfKey}' is duplicated.\n", + "If you run a component multiple times in the same workflow,\n" + + "it's recommended you set a unique key for every call,\n" + + "for example: ${wfKey}.run(key: \"foo\")." + } + + // subset directives and convert to list of tuples + def drctv = workflowArgs.directives + + // TODO: unit test the two commands below + // convert publish array into tags + def valueToStr = { val -> + // ignore closures + if (val instanceof CharSequence) { + if (!val.matches('^[{].*[}]$')) { + '"' + val + '"' + } else { + val + } + } else if (val instanceof List) { + "[" + val.collect{valueToStr(it)}.join(", ") + "]" + } else if (val instanceof Map) { + "[" + val.collect{k, v -> k + ": " + valueToStr(v)}.join(", ") + "]" + } else { + val.inspect() + } + } + + // multiple entries allowed: label, publishdir + def drctvStrs = drctv.collect { key, value -> + if (key in ["label", "publishDir"]) { + value.collect{ val -> + if (val instanceof Map) { + "\n$key " + val.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else if (val == null) { + "" + } else { + "\n$key " + valueToStr(val) + } + }.join() + } else if (value instanceof Map) { + "\n$key " + value.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else { + "\n$key " + valueToStr(value) + } + }.join() + + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { ', path(viash_par_' + it.plainName + ', stageAs: "_viash_par/' + it.plainName + '_?/*")' } + .join() + + def outputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + // insert dummy into every output (see nextflow-io/nextflow#2678) + if (!par.multiple) { + ', path{[".exitcode", args.' + par.plainName + ']}' + } else { + ', path{[".exitcode"] + args.' + par.plainName + '}' + } + } + .join() + + // TODO: move this functionality somewhere else? + if (workflowArgs.auto.transcript) { + outputPaths = outputPaths + ', path{[".exitcode", ".command*"]}' + } else { + outputPaths = outputPaths + ', path{[".exitcode"]}' + } + + // create dirs for output files (based on BashWrapper.createParentFiles) + def createParentStr = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" && it.create_parent } + .collect { par -> + def contents = "args[\"${par.plainName}\"] instanceof List ? args[\"${par.plainName}\"].join('\" \"') : args[\"${par.plainName}\"]" + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent '\" + escapeText(${contents}) + \"'\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def contents = "viash_par_${par.plainName} instanceof List ? viash_par_${par.plainName}.join(\"${par.multiple_sep}\") : viash_par_${par.plainName}" + "\n\${viash_par_${par.plainName}.empty ? \"\" : \"export VIASH_PAR_${par.plainName.toUpperCase()}='\" + escapeText(${contents}) + \"'\"}" + } + + // NOTE: if using docker, use /tmp instead of tmpDir! + def tmpDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('VIASH_TMPDIR') ?: + System.getenv('VIASH_TEMPDIR') ?: + System.getenv('VIASH_TMP') ?: + System.getenv('TEMP') ?: + System.getenv('TMPDIR') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMP') ?: + '/tmp' + ).toAbsolutePath() + + // construct stub + def stub = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + "\${ args.containsKey(\"${par.plainName}\") ? \"touch2 \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"].replace(\"_*\", \"_0\") : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // escape script + def escapedScript = rawScript.replace('\\', '\\\\').replace('$', '\\$').replace('"""', '\\"\\"\\"') + + // publishdir assert + def assertStr = (workflowArgs.auto.publish == true) || workflowArgs.auto.transcript ? + """\nassert task.publishDir.size() > 0: "if auto.publish is true, params.publish_dir needs to be defined.\\n Example: --publish_dir './output/'" """ : + "" + + // generate process string + def procStr = + """nextflow.enable.dsl=2 + | + |def escapeText = { s -> s.toString().replaceAll("'", "'\\\"'\\\"'") } + |process $procKey {$drctvStrs + |input: + | tuple val(id)$inputPaths, val(args), path(resourcesDir, stageAs: ".viash_meta_resources") + |output: + | tuple val("\$id")$outputPaths, optional: true + |stub: + |\"\"\" + |touch2() { mkdir -p "\\\$(dirname "\\\$1")" && touch "\\\$1" ; } + |$stub + |\"\"\" + |script:$assertStr + |def parInject = args + | .findAll{key, value -> value != null} + | .collect{key, value -> "export VIASH_PAR_\${key.toUpperCase()}='\${escapeText(value)}'"} + | .join("\\n") + |\"\"\" + |# meta exports + |export VIASH_META_RESOURCES_DIR="\${resourcesDir}" + |export VIASH_META_TEMP_DIR="${['docker', 'podman', 'charliecloud'].any{ it == workflow.containerEngine } ? '/tmp' : tmpDir}" + |export VIASH_META_NAME="${meta.config.name}" + |# export VIASH_META_EXECUTABLE="\\\$VIASH_META_RESOURCES_DIR/\\\$VIASH_META_NAME" + |export VIASH_META_CONFIG="\\\$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" + |\${task.cpus ? "export VIASH_META_CPUS=\$task.cpus" : "" } + |\${task.memory?.bytes != null ? "export VIASH_META_MEMORY_B=\$task.memory.bytes" : "" } + |if [ ! -z \\\${VIASH_META_MEMORY_B+x} ]; then + | export VIASH_META_MEMORY_KB=\\\$(( (\\\$VIASH_META_MEMORY_B+999) / 1000 )) + | export VIASH_META_MEMORY_MB=\\\$(( (\\\$VIASH_META_MEMORY_KB+999) / 1000 )) + | export VIASH_META_MEMORY_GB=\\\$(( (\\\$VIASH_META_MEMORY_MB+999) / 1000 )) + | export VIASH_META_MEMORY_TB=\\\$(( (\\\$VIASH_META_MEMORY_GB+999) / 1000 )) + | export VIASH_META_MEMORY_PB=\\\$(( (\\\$VIASH_META_MEMORY_TB+999) / 1000 )) + | export VIASH_META_MEMORY_KIB=\\\$(( (\\\$VIASH_META_MEMORY_B+1023) / 1024 )) + | export VIASH_META_MEMORY_MIB=\\\$(( (\\\$VIASH_META_MEMORY_KIB+1023) / 1024 )) + | export VIASH_META_MEMORY_GIB=\\\$(( (\\\$VIASH_META_MEMORY_MIB+1023) / 1024 )) + | export VIASH_META_MEMORY_TIB=\\\$(( (\\\$VIASH_META_MEMORY_GIB+1023) / 1024 )) + | export VIASH_META_MEMORY_PIB=\\\$(( (\\\$VIASH_META_MEMORY_TIB+1023) / 1024 )) + |fi + | + |# meta synonyms + |export VIASH_TEMP="\\\$VIASH_META_TEMP_DIR" + |export TEMP_DIR="\\\$VIASH_META_TEMP_DIR" + | + |# create output dirs if need be + |function mkdir_parent { + | for file in "\\\$@"; do + | mkdir -p "\\\$(dirname "\\\$file")" + | done + |} + |$createParentStr + | + |# argument exports${inputFileExports.join()} + |\$parInject + | + |# process script + |${escapedScript} + |\"\"\" + |} + |""".stripMargin() + + // TODO: print on debug + // if (workflowArgs.debug == true) { + // println("######################\n$procStr\n######################") + // } + + // write process to temp file + def tempFile = java.nio.file.Files.createTempFile("viash-process-${procKey}-", ".nf") + addShutdownHook { java.nio.file.Files.deleteIfExists(tempFile) } + tempFile.text = procStr + + // create process from temp file + def binding = new nextflow.script.ScriptBinding([:]) + def session = nextflow.Nextflow.getSession() + def parser = new nextflow.script.ScriptParser(session) + .setModule(true) + .setBinding(binding) + def moduleScript = parser.runScript(tempFile) + .getScript() + + // register module in meta + def module = new nextflow.script.IncludeDef.Module(name: procKey) + scriptMeta.addModule(moduleScript, module.name, module.alias) + + // retrieve and return process from meta + return scriptMeta.getProcess(procKey) +} + +// defaults +meta["defaults"] = [ + // key to be used to trace the process and determine output names + key: null, + + // fixed arguments to be passed to script + args: [:], + + // default directives + directives: readJsonBlob('''{ + "container" : { + "registry" : "images.viash-hub.com", + "image" : "vsh/biobox/agat/agat_sp_merge_annotations", + "tag" : "main" + }, + "tag" : "$id" +}'''), + + // auto settings + auto: readJsonBlob('''{ + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false +}'''), + + // Apply a map over the incoming tuple + // Example: `{ tup -> [ tup[0], [input: tup[1].output] ] + tup.drop(2) }` + map: null, + + // Apply a map over the ID element of a tuple (i.e. the first element) + // Example: `{ id -> id + "_foo" }` + mapId: null, + + // Apply a map over the data element of a tuple (i.e. the second element) + // Example: `{ data -> [ input: data.output ] }` + mapData: null, + + // Apply a map over the passthrough elements of a tuple (i.e. the tuple excl. the first two elements) + // Example: `{ pt -> pt.drop(1) }` + mapPassthrough: null, + + // Filter the channel + // Example: `{ tup -> tup[0] == "foo" }` + filter: null, + + // Choose whether or not to run the component on the tuple if the condition is true. + // Otherwise, the tuple will be passed through. + // Example: `{ tup -> tup[0] != "skip_this" }` + runIf: null, + + // Rename keys in the data field of the tuple (i.e. the second element) + // Will likely be deprecated in favour of `fromState`. + // Example: `[ "new_key": "old_key" ]` + renameKeys: null, + + // Fetch data from the state and pass it to the module without altering the current state. + // + // `fromState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be passed to the module as is. + // - If it is a `List[String]`, the data will be the values of the state at the given keys. + // - If it is a `Map[String, String]`, the data will be the values of the state at the given keys, with the keys renamed according to the map. + // - If it is a function, the tuple (`[id, state]`) in the channel will be passed to the function, and the result will be used as the data. + // + // Example: `{ id, state -> [input: state.fastq_file] }` + // Default: `null` + fromState: null, + + // Determine how the state should be updated after the module has been run. + // + // `toState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be replaced with the output of the module. + // - If it is a `List[String]`, the state will be updated with the values of the data at the given keys. + // - If it is a `Map[String, String]`, the state will be updated with the values of the data at the given keys, with the keys renamed according to the map. + // - If it is a function, a tuple (`[id, output, state]`) will be passed to the function, and the result will be used as the new state. + // + // Example: `{ id, output, state -> state + [counts: state.output] }` + // Default: `{ id, output, state -> output }` + toState: null, + + // Whether or not to print debug messages + // Default: `false` + debug: false +] + +// initialise default workflow +meta["workflow"] = workflowFactory([key: meta.config.name], meta.defaults, meta) + +// add workflow to environment +nextflow.script.ScriptMeta.current().addDefinition(meta.workflow) + +// anonymous workflow for running this module as a standalone +workflow { + // add id argument if it's not already in the config + // TODO: deep copy + def newConfig = deepClone(meta.config) + def newParams = deepClone(params) + + def argsContainsId = newConfig.allArguments.any{it.plainName == "id"} + if (!argsContainsId) { + def idArg = [ + 'name': '--id', + 'required': false, + 'type': 'string', + 'description': 'A unique id for every entry.', + 'multiple': false + ] + newConfig.arguments.add(0, idArg) + newConfig = processConfig(newConfig) + } + if (!newParams.containsKey("id")) { + newParams.id = "run" + } + + helpMessage(newConfig) + + channelFromParams(newParams, newConfig) + // make sure id is not in the state if id is not in the args + | map {id, state -> + if (!argsContainsId) { + [id, state.findAll{k, v -> k != "id"}] + } else { + [id, state] + } + } + | meta.workflow.run( + auto: [ publish: "state" ] + ) +} + +// END COMPONENT-SPECIFIC CODE diff --git a/target/nextflow/agat/agat_sp_merge_annotations/nextflow.config b/target/nextflow/agat/agat_sp_merge_annotations/nextflow.config new file mode 100644 index 00000000..bc7adce8 --- /dev/null +++ b/target/nextflow/agat/agat_sp_merge_annotations/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'agat/agat_sp_merge_annotations' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'main' + description = 'Merge different gff annotation files into one. It uses the AGAT parser that takes care of\nduplicated names and fixes other oddities met in those files.\n' + author = 'Leïla Paquay' +} + +process.container = 'nextflow/bash:latest' + +// detect tempdir +tempDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMPDIR') ?: + '/tmp' +).toAbsolutePath() + +profiles { + no_publish { + process { + withName: '.*' { + publishDir = [ + enabled: false + ] + } + } + } + mount_temp { + docker.temp = tempDir + podman.temp = tempDir + charliecloud.temp = tempDir + } + docker { + docker.enabled = true + // docker.userEmulation = true + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + singularity { + singularity.enabled = true + singularity.autoMounts = true + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + podman { + podman.enabled = true + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + shifter { + shifter.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + } + charliecloud { + charliecloud.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + } +} + +process{ + withLabel: mem1gb { memory = 1000000000.B } + withLabel: mem2gb { memory = 2000000000.B } + withLabel: mem5gb { memory = 5000000000.B } + withLabel: mem10gb { memory = 10000000000.B } + withLabel: mem20gb { memory = 20000000000.B } + withLabel: mem50gb { memory = 50000000000.B } + withLabel: mem100gb { memory = 100000000000.B } + withLabel: mem200gb { memory = 200000000000.B } + withLabel: mem500gb { memory = 500000000000.B } + withLabel: mem1tb { memory = 1000000000000.B } + withLabel: mem2tb { memory = 2000000000000.B } + withLabel: mem5tb { memory = 5000000000000.B } + withLabel: mem10tb { memory = 10000000000000.B } + withLabel: mem20tb { memory = 20000000000000.B } + withLabel: mem50tb { memory = 50000000000000.B } + withLabel: mem100tb { memory = 100000000000000.B } + withLabel: mem200tb { memory = 200000000000000.B } + withLabel: mem500tb { memory = 500000000000000.B } + withLabel: mem1gib { memory = 1073741824.B } + withLabel: mem2gib { memory = 2147483648.B } + withLabel: mem4gib { memory = 4294967296.B } + withLabel: mem8gib { memory = 8589934592.B } + withLabel: mem16gib { memory = 17179869184.B } + withLabel: mem32gib { memory = 34359738368.B } + withLabel: mem64gib { memory = 68719476736.B } + withLabel: mem128gib { memory = 137438953472.B } + withLabel: mem256gib { memory = 274877906944.B } + withLabel: mem512gib { memory = 549755813888.B } + withLabel: mem1tib { memory = 1099511627776.B } + withLabel: mem2tib { memory = 2199023255552.B } + withLabel: mem4tib { memory = 4398046511104.B } + withLabel: mem8tib { memory = 8796093022208.B } + withLabel: mem16tib { memory = 17592186044416.B } + withLabel: mem32tib { memory = 35184372088832.B } + withLabel: mem64tib { memory = 70368744177664.B } + withLabel: mem128tib { memory = 140737488355328.B } + withLabel: mem256tib { memory = 281474976710656.B } + withLabel: mem512tib { memory = 562949953421312.B } + withLabel: cpu1 { cpus = 1 } + withLabel: cpu2 { cpus = 2 } + withLabel: cpu5 { cpus = 5 } + withLabel: cpu10 { cpus = 10 } + withLabel: cpu20 { cpus = 20 } + withLabel: cpu50 { cpus = 50 } + withLabel: cpu100 { cpus = 100 } + withLabel: cpu200 { cpus = 200 } + withLabel: cpu500 { cpus = 500 } + withLabel: cpu1000 { cpus = 1000 } +} + + diff --git a/target/nextflow/agat/agat_sp_merge_annotations/nextflow_schema.json b/target/nextflow/agat/agat_sp_merge_annotations/nextflow_schema.json new file mode 100644 index 00000000..d864d8fa --- /dev/null +++ b/target/nextflow/agat/agat_sp_merge_annotations/nextflow_schema.json @@ -0,0 +1,119 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "agat_sp_merge_annotations", +"description": "Merge different gff annotation files into one. It uses the AGAT parser that takes care of\nduplicated names and fixes other oddities met in those files.\n", +"type": "object", +"definitions": { + + + + "inputs" : { + "title": "Inputs", + "type": "object", + "description": "No description", + "properties": { + + + "gff": { + "type": + "string", + "description": "Type: List of `file`, required, example: `input1.gff;input2.gff`, multiple_sep: `\";\"`. Input GTF/GFF file(s)", + "help_text": "Type: List of `file`, required, example: `input1.gff;input2.gff`, multiple_sep: `\";\"`. Input GTF/GFF file(s).\n" + + } + + +} +}, + + + "outputs" : { + "title": "Outputs", + "type": "object", + "description": "No description", + "properties": { + + + "output": { + "type": + "string", + "description": "Type: `file`, required, default: `$id.$key.output.gff`, example: `output.gff`. Output gff3 file where the gene incriminated will be writen", + "help_text": "Type: `file`, required, default: `$id.$key.output.gff`, example: `output.gff`. Output gff3 file where the gene incriminated will be writen." + , + "default": "$id.$key.output.gff" + } + + +} +}, + + + "arguments" : { + "title": "Arguments", + "type": "object", + "description": "No description", + "properties": { + + + "config": { + "type": + "string", + "description": "Type: `file`, example: `custom_agat_config.yaml`. AGAT config file", + "help_text": "Type: `file`, example: `custom_agat_config.yaml`. AGAT config file. By default AGAT takes the original agat_config.yaml shipped with AGAT. \nThe `--config` option gives you the possibility to use your own AGAT config file (located\nelsewhere or named differently).\n" + + } + + +} +}, + + + "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/inputs" + }, + + { + "$ref": "#/definitions/outputs" + }, + + { + "$ref": "#/definitions/arguments" + }, + + { + "$ref": "#/definitions/nextflow input-output arguments" + } +] +} diff --git a/target/nextflow/agat/agat_sp_statistics/.config.vsh.yaml b/target/nextflow/agat/agat_sp_statistics/.config.vsh.yaml index 6906ff69..bbb23a8f 100644 --- a/target/nextflow/agat/agat_sp_statistics/.config.vsh.yaml +++ b/target/nextflow/agat/agat_sp_statistics/.config.vsh.yaml @@ -231,9 +231,9 @@ build_info: output: "target/nextflow/agat/agat_sp_statistics" executable: "target/nextflow/agat/agat_sp_statistics/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/agat/agat_sp_statistics/main.nf b/target/nextflow/agat/agat_sp_statistics/main.nf index 21e1f6c1..6fb56cdf 100644 --- a/target/nextflow/agat/agat_sp_statistics/main.nf +++ b/target/nextflow/agat/agat_sp_statistics/main.nf @@ -3096,9 +3096,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_sp_statistics", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/arriba/.config.vsh.yaml b/target/nextflow/arriba/.config.vsh.yaml index 157b9d78..2336cb67 100644 --- a/target/nextflow/arriba/.config.vsh.yaml +++ b/target/nextflow/arriba/.config.vsh.yaml @@ -706,9 +706,9 @@ build_info: output: "target/nextflow/arriba" executable: "target/nextflow/arriba/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/arriba/main.nf b/target/nextflow/arriba/main.nf index 0b4b6791..8941edc0 100644 --- a/target/nextflow/arriba/main.nf +++ b/target/nextflow/arriba/main.nf @@ -3592,9 +3592,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/arriba", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bbmap/bbmap_bbsplit/.config.vsh.yaml b/target/nextflow/bbmap/bbmap_bbsplit/.config.vsh.yaml index b5b1d1e7..b052ae29 100644 --- a/target/nextflow/bbmap/bbmap_bbsplit/.config.vsh.yaml +++ b/target/nextflow/bbmap/bbmap_bbsplit/.config.vsh.yaml @@ -359,9 +359,9 @@ build_info: output: "target/nextflow/bbmap/bbmap_bbsplit" executable: "target/nextflow/bbmap/bbmap_bbsplit/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bbmap/bbmap_bbsplit/main.nf b/target/nextflow/bbmap/bbmap_bbsplit/main.nf index 0f56fce6..64b97122 100644 --- a/target/nextflow/bbmap/bbmap_bbsplit/main.nf +++ b/target/nextflow/bbmap/bbmap_bbsplit/main.nf @@ -3207,9 +3207,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bbmap/bbmap_bbsplit", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bcftools/bcftools_annotate/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_annotate/.config.vsh.yaml index 955049a6..e26babf9 100644 --- a/target/nextflow/bcftools/bcftools_annotate/.config.vsh.yaml +++ b/target/nextflow/bcftools/bcftools_annotate/.config.vsh.yaml @@ -469,9 +469,9 @@ build_info: output: "target/nextflow/bcftools/bcftools_annotate" executable: "target/nextflow/bcftools/bcftools_annotate/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bcftools/bcftools_annotate/main.nf b/target/nextflow/bcftools/bcftools_annotate/main.nf index 24d5bb9f..493c6cbb 100644 --- a/target/nextflow/bcftools/bcftools_annotate/main.nf +++ b/target/nextflow/bcftools/bcftools_annotate/main.nf @@ -3335,9 +3335,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bcftools/bcftools_annotate", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bcftools/bcftools_concat/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_concat/.config.vsh.yaml index 38373267..8725a7c6 100644 --- a/target/nextflow/bcftools/bcftools_concat/.config.vsh.yaml +++ b/target/nextflow/bcftools/bcftools_concat/.config.vsh.yaml @@ -335,9 +335,9 @@ build_info: output: "target/nextflow/bcftools/bcftools_concat" executable: "target/nextflow/bcftools/bcftools_concat/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bcftools/bcftools_concat/main.nf b/target/nextflow/bcftools/bcftools_concat/main.nf index 9a83e318..301be3f6 100644 --- a/target/nextflow/bcftools/bcftools_concat/main.nf +++ b/target/nextflow/bcftools/bcftools_concat/main.nf @@ -3207,9 +3207,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bcftools/bcftools_concat", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bcftools/bcftools_norm/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_norm/.config.vsh.yaml index 179ad075..92d42517 100644 --- a/target/nextflow/bcftools/bcftools_norm/.config.vsh.yaml +++ b/target/nextflow/bcftools/bcftools_norm/.config.vsh.yaml @@ -416,9 +416,9 @@ build_info: output: "target/nextflow/bcftools/bcftools_norm" executable: "target/nextflow/bcftools/bcftools_norm/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bcftools/bcftools_norm/main.nf b/target/nextflow/bcftools/bcftools_norm/main.nf index cd963691..7ada3f0d 100644 --- a/target/nextflow/bcftools/bcftools_norm/main.nf +++ b/target/nextflow/bcftools/bcftools_norm/main.nf @@ -3300,9 +3300,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bcftools/bcftools_norm", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bcftools/bcftools_sort/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_sort/.config.vsh.yaml index c7bd6350..77670a0d 100644 --- a/target/nextflow/bcftools/bcftools_sort/.config.vsh.yaml +++ b/target/nextflow/bcftools/bcftools_sort/.config.vsh.yaml @@ -185,9 +185,9 @@ build_info: output: "target/nextflow/bcftools/bcftools_sort" executable: "target/nextflow/bcftools/bcftools_sort/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bcftools/bcftools_sort/main.nf b/target/nextflow/bcftools/bcftools_sort/main.nf index a775fe7f..bb214da8 100644 --- a/target/nextflow/bcftools/bcftools_sort/main.nf +++ b/target/nextflow/bcftools/bcftools_sort/main.nf @@ -3048,9 +3048,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bcftools/bcftools_sort", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bcftools/bcftools_stats/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_stats/.config.vsh.yaml index 00ca9fba..3ad6adbf 100644 --- a/target/nextflow/bcftools/bcftools_stats/.config.vsh.yaml +++ b/target/nextflow/bcftools/bcftools_stats/.config.vsh.yaml @@ -458,9 +458,9 @@ build_info: output: "target/nextflow/bcftools/bcftools_stats" executable: "target/nextflow/bcftools/bcftools_stats/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bcftools/bcftools_stats/main.nf b/target/nextflow/bcftools/bcftools_stats/main.nf index 0a26132e..325d573b 100644 --- a/target/nextflow/bcftools/bcftools_stats/main.nf +++ b/target/nextflow/bcftools/bcftools_stats/main.nf @@ -3337,9 +3337,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bcftools/bcftools_stats", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bcl_convert/.config.vsh.yaml b/target/nextflow/bcl_convert/.config.vsh.yaml index 4c3d2f2d..aba9cf97 100644 --- a/target/nextflow/bcl_convert/.config.vsh.yaml +++ b/target/nextflow/bcl_convert/.config.vsh.yaml @@ -418,9 +418,9 @@ build_info: output: "target/nextflow/bcl_convert" executable: "target/nextflow/bcl_convert/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bcl_convert/main.nf b/target/nextflow/bcl_convert/main.nf index 6ef9e358..a8dc67d6 100644 --- a/target/nextflow/bcl_convert/main.nf +++ b/target/nextflow/bcl_convert/main.nf @@ -3329,9 +3329,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bcl_convert", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/.config.vsh.yaml b/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/.config.vsh.yaml index 2d466e4f..da113e86 100644 --- a/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/.config.vsh.yaml +++ b/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/.config.vsh.yaml @@ -274,9 +274,9 @@ build_info: output: "target/nextflow/bd_rhapsody/bd_rhapsody_make_reference" executable: "target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/main.nf b/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/main.nf index c39b9a5a..fc2e45a8 100644 --- a/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/main.nf +++ b/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/main.nf @@ -3146,9 +3146,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bd_rhapsody/bd_rhapsody_make_reference", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis/.config.vsh.yaml b/target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis/.config.vsh.yaml index 3685de52..fe3a2bc2 100644 --- a/target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis/.config.vsh.yaml +++ b/target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis/.config.vsh.yaml @@ -1115,9 +1115,9 @@ build_info: output: "target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis" executable: "target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis/main.nf b/target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis/main.nf index 34723612..be33fd1f 100644 --- a/target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis/main.nf +++ b/target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis/main.nf @@ -4193,9 +4193,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bd_rhapsody/bd_rhapsody_sequence_analysis", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_bamtobed/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_bamtobed/.config.vsh.yaml new file mode 100644 index 00000000..3549a3f5 --- /dev/null +++ b/target/nextflow/bedtools/bedtools_bamtobed/.config.vsh.yaml @@ -0,0 +1,262 @@ +name: "bedtools_bamtobed" +namespace: "bedtools" +version: "main" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + - "maintainer" + info: + links: + email: "theodorogtc@gmail.com" + github: "tgaspe" + linkedin: "theodoro-gasperin-terra-camargo" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Bioinformatician" +argument_groups: +- name: "Inputs" + arguments: + - type: "file" + name: "--input" + alternatives: + - "-i" + description: "Input BAM file." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + description: "Output BED file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "boolean_true" + name: "--bedpe" + description: "Write BEDPE format. Requires BAM to be grouped or sorted by query.\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--mate1" + description: "When writing BEDPE (-bedpe) format, always report mate one as the\ + \ first BEDPE \"block\".\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--bed12" + description: "Write \"blocked\" BED format (aka \"BED12\"). Forces -split.\nSee\ + \ http://genome-test.cse.ucsc.edu/FAQ/FAQformat#format1\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--split" + description: "Report \"split\" BAM alignments as separate BED entries.\nSplits\ + \ only on N CIGAR operations.\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--splitD" + description: "Split alignments based on N and D CIGAR operators.\nForces -split.\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--edit_distance" + alternatives: + - "-ed" + description: "Use BAM edit distance (NM tag) for BED score.\n- Default for BED\ + \ is to use mapping quality.\n- Default for BEDPE is to use the minimum of\n\ + \ the two mapping qualities for the pair.\n- When -ed is used with -bedpe,\ + \ the total edit\n distance from the two mates is reported.\n" + info: null + direction: "input" + - type: "string" + name: "--tag" + description: "Use other NUMERIC BAM alignment tag for BED score.\nDefault for\ + \ BED is to use mapping quality. Disallowed with BEDPE output.\n" + info: null + example: + - "SM" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--color" + description: "An R,G,B string for the color used with BED12 format.\nDefault is\ + \ (255,0,0).\n" + info: null + example: + - "250,250,250" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--cigar" + description: "Add the CIGAR string to the BED entry as a 7th column.\n" + info: null + direction: "input" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Converts BAM alignments to BED6 or BEDPE format." +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Converts" +- "BAM" +- "BED" +- "BED6" +- "BEDPE" +license: "MIT" +references: + doi: + - "10.1093/bioinformatics/btq033" +links: + repository: "https://github.com/arq5x/bedtools2" + homepage: "https://bedtools.readthedocs.io/en/latest/#" + documentation: "https://bedtools.readthedocs.io/en/latest/content/tools/bamtobed.html" + issue_tracker: "https://github.com/arq5x/bedtools2/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "debian:stable-slim" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bedtools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bedtools: \\\"$(bedtools --version | sed -n 's/^bedtools //p')\\\"\"\ + \ > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bedtools/bedtools_bamtobed/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/bedtools/bedtools_bamtobed" + executable: "target/nextflow/bedtools/bedtools_bamtobed/main.nf" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/nextflow/bedtools/bedtools_bamtobed/main.nf b/target/nextflow/bedtools/bedtools_bamtobed/main.nf new file mode 100644 index 00000000..38dce111 --- /dev/null +++ b/target/nextflow/bedtools/bedtools_bamtobed/main.nf @@ -0,0 +1,3694 @@ +// bedtools_bamtobed main +// +// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +// Intuitive. +// +// The component may contain files which fall under a different license. The +// authors of this component should specify the license in the header of such +// files, or include a separate license file detailing the licenses of all included +// files. +// +// Component authors: +// * Theodoro Gasperin Terra Camargo (author, maintainer) + +//////////////////////////// +// VDSL3 helper functions // +//////////////////////////// + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_checkArgumentType.nf' +class UnexpectedArgumentTypeException extends Exception { + String errorIdentifier + String stage + String plainName + String expectedClass + String foundClass + + // ${key ? " in module '$key'" : ""}${id ? " id '$id'" : ""} + UnexpectedArgumentTypeException(String errorIdentifier, String stage, String plainName, String expectedClass, String foundClass) { + super("Error${errorIdentifier ? " $errorIdentifier" : ""}:${stage ? " $stage" : "" } argument '${plainName}' has the wrong type. " + + "Expected type: ${expectedClass}. Found type: ${foundClass}") + this.errorIdentifier = errorIdentifier + this.stage = stage + this.plainName = plainName + this.expectedClass = expectedClass + this.foundClass = foundClass + } +} + +/** + * Checks if the given value is of the expected type. If not, an exception is thrown. + * + * @param stage The stage of the argument (input or output) + * @param par The parameter definition + * @param value The value to check + * @param errorIdentifier The identifier to use in the error message + * @return The value, if it is of the expected type + * @throws UnexpectedArgumentTypeException If the value is not of the expected type +*/ +def _checkArgumentType(String stage, Map par, Object value, String errorIdentifier) { + // expectedClass will only be != null if value is not of the expected type + def expectedClass = null + def foundClass = null + + // todo: split if need be + + if (!par.required && value == null) { + expectedClass = null + } else if (par.multiple) { + if (value !instanceof Collection) { + value = [value] + } + + // split strings + value = value.collectMany{ val -> + if (val instanceof String) { + // collect() to ensure that the result is a List and not simply an array + val.split(par.multiple_sep).collect() + } else { + [val] + } + } + + // process globs + if (par.type == "file" && par.direction == "input") { + value = value.collect{ it instanceof String ? file(it, hidden: true) : it }.flatten() + } + + // check types of elements in list + try { + value = value.collect { listVal -> + _checkArgumentType(stage, par + [multiple: false], listVal, errorIdentifier) + } + } catch (UnexpectedArgumentTypeException e) { + expectedClass = "List[${e.expectedClass}]" + foundClass = "List[${e.foundClass}]" + } + } else if (par.type == "string") { + // cast to string if need be + if (value instanceof GString) { + value = value.toString() + } + expectedClass = value instanceof String ? null : "String" + } else if (par.type == "integer") { + // cast to integer if need be + if (value instanceof String) { + try { + value = value.toInteger() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toLong() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toDouble() + } catch (NumberFormatException e) { + // do nothing + } + } + if (value instanceof java.math.BigDecimal) { + value = value.doubleValue() + } + 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 + } + } + 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) { + value = file(value, hidden: true) + } + if (value instanceof File) { + value = value.toPath() + } + 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() + } + expectedClass = value instanceof String ? null : "String" + } else { + // didn't find a match for par.type + expectedClass = par.type + } + + if (expectedClass != null) { + if (foundClass == null) { + foundClass = value.getClass().getName() + } + throw new UnexpectedArgumentTypeException(errorIdentifier, stage, par.plainName, expectedClass, foundClass) + } + + return value +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processInputValues.nf' +Map _processInputValues(Map inputs, Map config, String id, String key) { + if (!workflow.stubRun) { + config.allArguments.each { arg -> + if (arg.required) { + assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null : + "Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing" + } + } + + inputs = inputs.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid input argument" + + value = _checkArgumentType("input", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return inputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf' +Map _processOutputValues(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" + + value = _checkArgumentType("output", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return outputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf' +class IDChecker { + final def items = [] as Set + + @groovy.transform.WithWriteLock + boolean observe(String item) { + if (items.contains(item)) { + return false + } else { + items << item + return true + } + } + + @groovy.transform.WithReadLock + boolean contains(String item) { + return items.contains(item) + } + + @groovy.transform.WithReadLock + Set getItems() { + return items.clone() + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_checkUniqueIds.nf' + +/** + * Check if the ids are unique across parameter sets + * + * @param parameterSets a list of parameter sets. + */ +private void _checkUniqueIds(List>> parameterSets) { + def ppIds = parameterSets.collect{it[0]} + assert ppIds.size() == ppIds.unique().size() : "All argument sets should have unique ids. Detected ids: $ppIds" +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_getChild.nf' + +// helper functions for reading params from file // +def _getChild(parent, child) { + if (child.contains("://") || java.nio.file.Paths.get(child).isAbsolute()) { + child + } else { + def parentAbsolute = java.nio.file.Paths.get(parent).toAbsolutePath().toString() + parentAbsolute.replaceAll('/[^/]*$', "/") + child + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_parseParamList.nf' +/** + * Figure out the param list format based on the file extension + * + * @param param_list A String containing the path to the parameter list file. + * + * @return A String containing the format of the parameter list file. + */ +def _paramListGuessFormat(param_list) { + if (param_list !instanceof String) { + "asis" + } else if (param_list.endsWith(".csv")) { + "csv" + } else if (param_list.endsWith(".json") || param_list.endsWith(".jsn")) { + "json" + } else if (param_list.endsWith(".yaml") || param_list.endsWith(".yml")) { + "yaml" + } else { + "yaml_blob" + } +} + + +/** + * Read the param list + * + * @param param_list One of the following: + * - A String containing the path to the parameter list file (csv, json or yaml), + * - A yaml blob of a list of maps (yaml_blob), + * - Or a groovy list of maps (asis). + * @param config A Map of the Viash configuration. + * + * @return A List of Maps containing the parameters. + */ +def _parseParamList(param_list, Map config) { + // first determine format by extension + def paramListFormat = _paramListGuessFormat(param_list) + + def paramListPath = (paramListFormat != "asis" && paramListFormat != "yaml_blob") ? + file(param_list, hidden: true) : + null + + // get the correct parser function for the detected params_list format + def paramSets = [] + if (paramListFormat == "asis") { + paramSets = param_list + } else if (paramListFormat == "yaml_blob") { + paramSets = readYamlBlob(param_list) + } else if (paramListFormat == "yaml") { + paramSets = readYaml(paramListPath) + } else if (paramListFormat == "json") { + paramSets = readJson(paramListPath) + } else if (paramListFormat == "csv") { + paramSets = readCsv(paramListPath) + } else { + error "Format of provided --param_list not recognised.\n" + + "Found: '$paramListFormat'.\n" + + "Expected: a csv file, a json file, a yaml file,\n" + + "a yaml blob or a groovy list of maps." + } + + // data checks + assert paramSets instanceof List: "--param_list should contain a list of maps" + for (value in paramSets) { + assert value instanceof Map: "--param_list should contain a list of maps" + } + + // id is argument + def idIsArgument = config.allArguments.any{it.plainName == "id"} + + // Reformat from List to List> by adding the ID as first element of a Tuple2 + paramSets = paramSets.collect({ data -> + def id = data.id + if (!idIsArgument) { + data = data.findAll{k, v -> k != "id"} + } + [id, data] + }) + + // Split parameters with 'multiple: true' + paramSets = paramSets.collect({ id, data -> + data = _splitParams(data, config) + [id, data] + }) + + // The paths of input files inside a param_list file may have been specified relatively to the + // location of the param_list file. These paths must be made absolute. + if (paramListPath) { + paramSets = paramSets.collect({ id, data -> + def new_data = data.collectEntries{ parName, parValue -> + def par = config.allArguments.find{it.plainName == parName} + if (par && par.type == "file" && par.direction == "input") { + if (parValue instanceof Collection) { + parValue = parValue.collectMany{path -> + def x = _resolveSiblingIfNotAbsolute(path, paramListPath) + x instanceof Collection ? x : [x] + } + } else { + parValue = _resolveSiblingIfNotAbsolute(parValue, paramListPath) + } + } + [parName, parValue] + } + [id, new_data] + }) + } + + return paramSets +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_splitParams.nf' +/** + * Split parameters for arguments that accept multiple values using their separator + * + * @param paramList A Map containing parameters to split. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A Map of parameters where the parameter values have been split into a list using + * their seperator. + */ +Map _splitParams(Map parValues, Map config){ + def parsedParamValues = parValues.collectEntries { parName, parValue -> + def parameterSettings = config.allArguments.find({it.plainName == parName}) + + if (!parameterSettings) { + // if argument is not found, do not alter + return [parName, parValue] + } + if (parameterSettings.multiple) { // Check if parameter can accept multiple values + if (parValue instanceof Collection) { + parValue = parValue.collect{it instanceof String ? it.split(parameterSettings.multiple_sep) : it } + } else if (parValue instanceof String) { + parValue = parValue.split(parameterSettings.multiple_sep) + } else if (parValue == null) { + parValue = [] + } else { + parValue = [ parValue ] + } + parValue = parValue.flatten() + } + // For all parameters check if multiple values are only passed for + // arguments that allow it. Quietly simplify lists of length 1. + if (!parameterSettings.multiple && parValue instanceof Collection) { + assert parValue.size() == 1 : + "Error: argument ${parName} has too many values.\n" + + " Expected amount: 1. Found: ${parValue.size()}" + parValue = parValue[0] + } + [parName, parValue] + } + return parsedParamValues +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/channelFromParams.nf' +/** + * Parse nextflow parameters based on settings defined in a viash config. + * Return a list of parameter sets, each parameter set corresponding to + * an event in a nextflow channel. The output from this function can be used + * with Channel.fromList to create a nextflow channel with Vdsl3 formatted + * events. + * + * This function performs: + * - A filtering of the params which can be found in the config file. + * - Process the params_list argument which allows a user to to initialise + * a Vsdl3 channel with multiple parameter sets. Possible formats are + * csv, json, yaml, or simply a yaml_blob. A csv should have column names + * which correspond to the different arguments of this pipeline. A json or a yaml + * file should be a list of maps, each of which has keys corresponding to the + * arguments of the pipeline. A yaml blob can also be passed directly as a parameter. + * When passing a csv, json or yaml, relative path names are relativized to the + * location of the parameter file. + * - Combine the parameter sets into a vdsl3 Channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A list of parameters with the first element of the event being + * the event ID and the second element containing a map of the parsed parameters. + */ + +private List>> _paramsToParamSets(Map params, Map config){ + // todo: fetch key from run args + def key_ = config.name + + /* parse regular parameters (not in param_list) */ + /*************************************************/ + def globalParams = config.allArguments + .findAll { params.containsKey(it.plainName) } + .collectEntries { [ it.plainName, params[it.plainName] ] } + def globalID = params.get("id", null) + + /* process params_list arguments */ + /*********************************/ + def paramList = params.containsKey("param_list") && params.param_list != null ? + params.param_list : [] + // if (paramList instanceof String) { + // paramList = [paramList] + // } + // def paramSets = paramList.collectMany{ _parseParamList(it, config) } + // TODO: be able to process param_list when it is a list of strings + def paramSets = _parseParamList(paramList, config) + if (paramSets.isEmpty()) { + paramSets = [[null, [:]]] + } + + /* combine arguments into channel */ + /**********************************/ + def processedParams = paramSets.indexed().collect{ index, tup -> + // Process ID + def id = tup[0] ?: globalID + + if (workflow.stubRun && !id) { + // if stub run, explicitly add an id if missing + id = "stub${index}" + } + assert id != null: "Each parameter set should have at least an 'id'" + + // Process params + def parValues = globalParams + tup[1] + // // Remove parameters which are null, if the default is also null + // parValues = parValues.collectEntries{paramName, paramValue -> + // parameterSettings = config.functionality.allArguments.find({it.plainName == paramName}) + // if ( paramValue != null || parameterSettings.get("default", null) != null ) { + // [paramName, paramValue] + // } + // } + parValues = parValues.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key_}' id '${id}': '${name}' is not a valid input argument" + + if (par == null) { + return [:] + } + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + + [ name, value ] + } + + [id, parValues] + } + + // Check if ids (first element of each list) is unique + _checkUniqueIds(processedParams) + return processedParams +} + +/** + * Parse nextflow parameters based on settings defined in a viash config + * and return a nextflow channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A nextflow Channel with events. Events are formatted as a tuple that contains + * first contains the ID of the event and as second element holds a parameter map. + * + * + */ +def channelFromParams(Map params, Map config) { + def processedParams = _paramsToParamSets(params, config) + return Channel.fromList(processedParams) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/checkUniqueIds.nf' +def checkUniqueIds(Map args) { + def stopOnError = args.stopOnError == null ? args.stopOnError : true + + def idChecker = new IDChecker() + + return filter { tup -> + if (!idChecker.observe(tup[0])) { + if (stopOnError) { + error "Duplicate id: ${tup[0]}" + } else { + log.warn "Duplicate id: ${tup[0]}, removing duplicate entry" + return false + } + } + return true + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/preprocessInputs.nf' +// This helper file will be deprecated soon +preprocessInputsDeprecationWarningPrinted = false + +def preprocessInputsDeprecationWarning() { + if (!preprocessInputsDeprecationWarningPrinted) { + preprocessInputsDeprecationWarningPrinted = true + System.err.println("Warning: preprocessInputs() is deprecated and will be removed in Viash 0.9.0.") + } +} + +/** + * Generate a nextflow Workflow that allows processing a channel of + * Vdsl3 formatted events and apply a Viash config to them: + * - Gather default parameters from the Viash config and make + * sure that they are correctly formatted (see applyConfig method). + * - Format the input parameters (also using the applyConfig method). + * - Apply the default parameter to the input parameters. + * - Do some assertions: + * ~ Check if the event IDs in the channel are unique. + * + * The events in the channel are formatted as tuples, with the + * first element of the tuples being a unique id of the parameter set, + * and the second element containg the the parameters themselves. + * Optional extra elements of the tuples will be passed to the output as is. + * + * @param args A map that must contain a 'config' key that points + * to a parsed config (see readConfig()). Optionally, a + * 'key' key can be provided which can be used to create a unique + * name for the workflow process. + * + * @return A workflow that allows processing a channel of Vdsl3 formatted events + * and apply a Viash config to them. + */ +def preprocessInputs(Map args) { + preprocessInputsDeprecationWarning() + + def config = args.config + assert config instanceof Map : + "Error in preprocessInputs: config must be a map. " + + "Expected class: Map. Found: config.getClass() is ${config.getClass()}" + def key_ = args.key ?: config.name + + // Get different parameter types (used throughout this function) + def defaultArgs = config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + map { tup -> + def id = tup[0] + def data = tup[1] + def passthrough = tup.drop(2) + + def new_data = (defaultArgs + data).collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + + if (par != null) { + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + } + + [ name, value ] + } + + [ id, new_data ] + passthrough + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runComponents.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component config. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component config. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component config. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component config. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runComponents(Map args) { + log.warn("runComponents is deprecated, use runEach instead") + assert args.components: "runComponents should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runComponents" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def id_ = args.id + + workflow runComponentsWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def comp_config = comp_.config + + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_config) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + // def new_id = id_(tup[0], tup[1], comp_config) + def new_id = tup[0] + if (id_ instanceof String) { + new_id = id_ + } else if (id_ instanceof Closure) { + new_id = id_(new_id, tup[1], comp_config) + } + [new_id] + tup.drop(1) + } + : filter_ch + def data_ch = id_ch | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_config) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_config) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + post_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runComponentsWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runEach.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component itself. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component itself. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component itself. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component itself. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runEach(Map args) { + assert args.components: "runEach should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runEach" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def runIf_ = args.runIf + def id_ = args.id + + assert !runIf_ || runIf_ instanceof Closure: "runEach: must pass a Closure to runIf." + + workflow runEachWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + def new_id = id_ + if (new_id instanceof Closure) { + new_id = new_id(tup[0], tup[1], comp_) + } + assert new_id instanceof String : "Error in runEach: id should be a String or a Closure that returns a String. Expected: id instanceof String. Found: ${new_id.getClass()}" + [new_id] + tup.drop(1) + } + : filter_ch + def chPassthrough = null + def chRun = null + if (runIf_) { + def idRunIfBranch = id_ch.branch{ tup -> + run: runIf_(tup[0], tup[1], comp_) + passthrough: true + } + chPassthrough = idRunIfBranch.passthrough + chRun = idRunIfBranch.run + } else { + chRun = id_ch + chPassthrough = Channel.empty() + } + def data_ch = chRun | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + def return_ch = post_ch + | concat(chPassthrough) + + return_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runEachWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/safeJoin.nf' +/** + * Join sourceChannel to targetChannel + * + * This function joins the sourceChannel to the targetChannel. + * However, each id in the targetChannel must be present in the + * sourceChannel. If _meta.join_id exists in the targetChannel, that is + * used as an id instead. If the id doesn't match any id in the sourceChannel, + * an error is thrown. + */ + +def safeJoin(targetChannel, sourceChannel, key) { + def sourceIDs = new IDChecker() + + def sourceCheck = sourceChannel + | map { tup -> + sourceIDs.observe(tup[0]) + tup + } + def targetCheck = targetChannel + | map { tup -> + def id = tup[0] + + if (!sourceIDs.contains(id)) { + error ( + "Error in module '${key}' when merging output with original state.\n" + + " Reason: output with id '${id}' could not be joined with source channel.\n" + + " If the IDs in the output channel differ from the input channel,\n" + + " please set `tup[1]._meta.join_id to the original ID.\n" + + " Original IDs in input channel: ['${sourceIDs.getItems().join("', '")}'].\n" + + " Unexpected ID in the output channel: '${id}'.\n" + + " Example input event: [\"id\", [input: file(...)]],\n" + + " Example output event: [\"newid\", [output: file(...), _meta: [join_id: \"id\"]]]" + ) + } + // TODO: add link to our documentation on how to fix this + + tup + } + + sourceCheck.cross(targetChannel) + | map{ left, right -> + right + left.drop(1) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/_processArgument.nf' +def _processArgument(arg) { + arg.multiple = arg.multiple != null ? arg.multiple : false + arg.required = arg.required != null ? arg.required : false + arg.direction = arg.direction != null ? arg.direction : "input" + arg.multiple_sep = arg.multiple_sep != null ? arg.multiple_sep : ";" + arg.plainName = arg.name.replaceAll("^-*", "") + + if (arg.type == "file") { + arg.must_exist = arg.must_exist != null ? arg.must_exist : true + arg.create_parent = arg.create_parent != null ? arg.create_parent : true + } + + // add default values to output files which haven't already got a default + if (arg.type == "file" && arg.direction == "output" && arg.default == null) { + def mult = arg.multiple ? "_*" : "" + def extSearch = "" + if (arg.default != null) { + extSearch = arg.default + } else if (arg.example != null) { + extSearch = arg.example + } + if (extSearch instanceof List) { + extSearch = extSearch[0] + } + def extSearchResult = extSearch.find("\\.[^\\.]+\$") + def ext = extSearchResult != null ? extSearchResult : "" + arg.default = "\$id.\$key.${arg.plainName}${mult}${ext}" + if (arg.multiple) { + arg.default = [arg.default] + } + } + + if (!arg.multiple) { + if (arg.default != null && arg.default instanceof List) { + arg.default = arg.default[0] + } + if (arg.example != null && arg.example instanceof List) { + arg.example = arg.example[0] + } + } + + if (arg.type == "boolean_true") { + arg.default = false + } + if (arg.type == "boolean_false") { + arg.default = true + } + + arg +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/addGlobalParams.nf' +def addGlobalArguments(config) { + def localConfig = [ + "argument_groups": [ + [ + "name": "Nextflow input-output arguments", + "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.", + "arguments" : [ + [ + 'name': '--publish_dir', + 'required': true, + 'type': 'string', + 'description': 'Path to an output directory.', + 'example': 'output/', + 'multiple': false + ], + [ + 'name': '--param_list', + 'required': false, + 'type': 'string', + 'description': '''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. + | + |* 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: [ ['id': 'foo', 'input': 'foo.txt'], ['id': 'bar', 'input': 'bar.txt'] ]`. + |* 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`. + |* 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 `[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]`. + |* A yaml blob can also be passed directly as a string. Example: `--param_list "[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]"`. + | + |When 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.'''.stripMargin(), + 'example': 'my_params.yaml', + 'multiple': false, + 'hidden': true + ] + // TODO: allow multiple: true in param_list? + // TODO: allow to specify a --param_list_regex to filter the param_list? + // TODO: allow to specify a --param_list_from_state to remap entries in the param_list? + ] + ] + ] + ] + + return processConfig(_mergeMap(config, localConfig)) +} + +def _mergeMap(Map lhs, Map rhs) { + return rhs.inject(lhs.clone()) { map, entry -> + if (map[entry.key] instanceof Map && entry.value instanceof Map) { + map[entry.key] = _mergeMap(map[entry.key], entry.value) + } else if (map[entry.key] instanceof Collection && entry.value instanceof Collection) { + map[entry.key] += entry.value + } else { + map[entry.key] = entry.value + } + return map + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/generateHelp.nf' +def _generateArgumentHelp(param) { + // alternatives are not supported + // def names = param.alternatives ::: List(param.name) + + def unnamedProps = [ + ["required parameter", param.required], + ["multiple values allowed", param.multiple], + ["output", param.direction.toLowerCase() == "output"], + ["file must exist", param.type == "file" && param.must_exist] + ].findAll{it[1]}.collect{it[0]} + + def dflt = null + if (param.default != null) { + if (param.default instanceof List) { + dflt = param.default.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + dflt = param.default.toString() + } + } + def example = null + if (param.example != null) { + if (param.example instanceof List) { + example = param.example.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + example = param.example.toString() + } + } + def min = param.min?.toString() + def max = param.max?.toString() + + def escapeChoice = { choice -> + def s1 = choice.replaceAll("\\n", "\\\\n") + def s2 = s1.replaceAll("\"", """\\\"""") + s2.contains(",") || s2 != choice ? "\"" + s2 + "\"" : s2 + } + def choices = param.choices == null ? + null : + "[ " + param.choices.collect{escapeChoice(it.toString())}.join(", ") + " ]" + + def namedPropsStr = [ + ["type", ([param.type] + unnamedProps).join(", ")], + ["default", dflt], + ["example", example], + ["choices", choices], + ["min", min], + ["max", max] + ] + .findAll{it[1]} + .collect{"\n " + it[0] + ": " + it[1].replaceAll("\n", "\\n")} + .join("") + + def descStr = param.description == null ? + "" : + _paragraphWrap("\n" + param.description.trim(), 80 - 8).join("\n ") + + "\n --" + param.plainName + + namedPropsStr + + descStr +} + +// Based on Helper.generateHelp() in Helper.scala +def _generateHelp(config) { + def fun = config + + // PART 1: NAME AND VERSION + def nameStr = fun.name + + (fun.version == null ? "" : " " + fun.version) + + // PART 2: DESCRIPTION + def descrStr = fun.description == null ? + "" : + "\n\n" + _paragraphWrap(fun.description.trim(), 80).join("\n") + + // PART 3: Usage + def usageStr = fun.usage == null ? + "" : + "\n\nUsage:\n" + fun.usage.trim() + + // PART 4: Options + def argGroupStrs = fun.allArgumentGroups.collect{argGroup -> + def name = argGroup.name + def descriptionStr = argGroup.description == null ? + "" : + "\n " + _paragraphWrap(argGroup.description.trim(), 80-4).join("\n ") + "\n" + def arguments = argGroup.arguments.collect{arg -> + arg instanceof String ? fun.allArguments.find{it.plainName == arg} : arg + }.findAll{it != null} + def argumentStrs = arguments.collect{param -> _generateArgumentHelp(param)} + + "\n\n$name:" + + descriptionStr + + argumentStrs.join("\n") + } + + // FINAL: combine + def out = nameStr + + descrStr + + usageStr + + argGroupStrs.join("") + + return out +} + +// based on Format._paragraphWrap +def _paragraphWrap(str, maxLength) { + def outLines = [] + str.split("\n").each{par -> + def words = par.split("\\s").toList() + + def word = null + def line = words.pop() + while(!words.isEmpty()) { + word = words.pop() + if (line.length() + word.length() + 1 <= maxLength) { + line = line + " " + word + } else { + outLines.add(line) + line = word + } + } + if (words.isEmpty()) { + outLines.add(line) + } + } + return outLines +} + +def helpMessage(config) { + if (params.containsKey("help") && params.help) { + def mergedConfig = addGlobalArguments(config) + def helpStr = _generateHelp(mergedConfig) + println(helpStr) + exit 0 + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/processConfig.nf' +def processConfig(config) { + // set defaults for arguments + config.arguments = + (config.arguments ?: []).collect{_processArgument(it)} + + // set defaults for argument_group arguments + config.argument_groups = + (config.argument_groups ?: []).collect{grp -> + grp.arguments = (grp.arguments ?: []).collect{_processArgument(it)} + grp + } + + // create combined arguments list + config.allArguments = + config.arguments + + config.argument_groups.collectMany{it.arguments} + + // add missing argument groups (based on Functionality::allArgumentGroups()) + def argGroups = config.argument_groups + if (argGroups.any{it.name.toLowerCase() == "arguments"}) { + argGroups = argGroups.collect{ grp -> + if (grp.name.toLowerCase() == "arguments") { + grp = grp + [ + arguments: grp.arguments + config.arguments + ] + } + grp + } + } else { + argGroups = argGroups + [ + name: "Arguments", + arguments: config.arguments + ] + } + config.allArgumentGroups = argGroups + + config +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/readConfig.nf' + +def readConfig(file) { + def config = readYaml(file ?: moduleDir.resolve("config.vsh.yaml")) + processConfig(config) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_resolveSiblingIfNotAbsolute.nf' +/** + * Resolve a path relative to the current file. + * + * @param str The path to resolve, as a String. + * @param parentPath The path to resolve relative to, as a Path. + * + * @return The path that may have been resovled, as a Path. + */ +def _resolveSiblingIfNotAbsolute(str, parentPath) { + if (str !instanceof String) { + return str + } + if (!_stringIsAbsolutePath(str)) { + return parentPath.resolveSibling(str) + } else { + return file(str, hidden: true) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_stringIsAbsolutePath.nf' +/** + * Check whether a path as a string is absolute. + * + * In the past, we tried using `file(., relative: true).isAbsolute()`, + * but the 'relative' option was added in 22.10.0. + * + * @param path The path to check, as a String. + * + * @return Whether the path is absolute, as a boolean. + */ +def _stringIsAbsolutePath(path) { + def _resolve_URL_PROTOCOL = ~/^([a-zA-Z][a-zA-Z0-9]*:)?\\/.+/ + + assert path instanceof String + return _resolve_URL_PROTOCOL.matcher(path).matches() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/collectTraces.nf' +class CustomTraceObserver implements nextflow.trace.TraceObserver { + List traces + + CustomTraceObserver(List traces) { + this.traces = traces + } + + @Override + void onProcessComplete(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } + + @Override + void onProcessCached(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } +} + +def collectTraces() { + def traces = Collections.synchronizedList([]) + + // add custom trace observer which stores traces in the traces object + session.observers.add(new CustomTraceObserver(traces)) + + traces +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/deepClone.nf' +/** + * Performs a deep clone of the given object. + * @param x an object + */ +def deepClone(x) { + iterateMap(x, {it instanceof Cloneable ? it.clone() : it}) +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getPublishDir.nf' +def getPublishDir() { + return params.containsKey("publish_dir") ? params.publish_dir : + params.containsKey("publishDir") ? params.publishDir : + null +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getRootDir.nf' + +// Recurse upwards until we find a '.build.yaml' file +def _findBuildYamlFile(pathPossiblySymlink) { + def path = pathPossiblySymlink.toRealPath() + def child = path.resolve(".build.yaml") + if (java.nio.file.Files.isDirectory(path) && java.nio.file.Files.exists(child)) { + return child + } else { + def parent = path.getParent() + if (parent == null) { + return null + } else { + return _findBuildYamlFile(parent) + } + } +} + +// get the root of the target folder +def getRootDir() { + def dir = _findBuildYamlFile(meta.resources_dir) + assert dir != null: "Could not find .build.yaml in the folder structure" + dir.getParent() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/iterateMap.nf' +/** + * Recursively apply a function over the leaves of an object. + * @param obj The object to iterate over. + * @param fun The function to apply to each value. + * @return The object with the function applied to each value. + */ +def iterateMap(obj, fun) { + if (obj instanceof List && obj !instanceof String) { + return obj.collect{item -> + iterateMap(item, fun) + } + } else if (obj instanceof Map) { + return obj.collectEntries{key, item -> + [key.toString(), iterateMap(item, fun)] + } + } else { + return fun(obj) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/niceView.nf' +/** + * A view for printing the event of each channel as a YAML blob. + * This is useful for debugging. + */ +def niceView() { + workflow niceViewWf { + take: input + main: + output = input + | view{toYamlBlob(it)} + emit: output + } + return niceViewWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readCsv.nf' + +def readCsv(file_path) { + def output = [] + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + + // todo: allow escaped quotes in string + // todo: allow single quotes? + def splitRegex = java.util.regex.Pattern.compile(''',(?=(?:[^"]*"[^"]*")*[^"]*$)''') + def removeQuote = java.util.regex.Pattern.compile('''"(.*)"''') + + def br = java.nio.file.Files.newBufferedReader(inputFile) + + def row = -1 + def header = null + while (br.ready() && header == null) { + def line = br.readLine() + row++ + if (!line.startsWith("#")) { + header = splitRegex.split(line, -1).collect{field -> + m = removeQuote.matcher(field) + m.find() ? m.replaceFirst('$1') : field + } + } + } + assert header != null: "CSV file should contain a header" + + while (br.ready()) { + def line = br.readLine() + row++ + if (line == null) { + br.close() + break + } + + if (!line.startsWith("#")) { + def predata = splitRegex.split(line, -1) + def data = predata.collect{field -> + if (field == "") { + return null + } + def m = removeQuote.matcher(field) + if (m.find()) { + return m.replaceFirst('$1') + } else { + return field + } + } + assert header.size() == data.size(): "Row $row should contain the same number as fields as the header" + + def dataMap = [header, data].transpose().collectEntries().findAll{it.value != null} + output.add(dataMap) + } + } + + output +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJson.nf' +def readJson(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parse(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJsonBlob.nf' +def readJsonBlob(str) { + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parseText(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readTaggedYaml.nf' +// Custom constructor to modify how certain objects are parsed from YAML +class CustomConstructor extends org.yaml.snakeyaml.constructor.Constructor { + Path root + + class ConstructPath extends org.yaml.snakeyaml.constructor.AbstractConstruct { + public Object construct(org.yaml.snakeyaml.nodes.Node node) { + String filename = (String) constructScalar(node); + if (root != null) { + return root.resolve(filename); + } + return java.nio.file.Paths.get(filename); + } + } + + CustomConstructor(org.yaml.snakeyaml.LoaderOptions options, Path root) { + super(options) + this.root = root + // Handling !file tag and parse it back to a File type + this.yamlConstructors.put(new org.yaml.snakeyaml.nodes.Tag("!file"), new ConstructPath()) + } +} + +def readTaggedYaml(Path path) { + def options = new org.yaml.snakeyaml.LoaderOptions() + def constructor = new CustomConstructor(options, path.getParent()) + def yaml = new org.yaml.snakeyaml.Yaml(constructor) + return yaml.load(path.text) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYaml.nf' +def readYaml(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYamlBlob.nf' +def readYamlBlob(str) { + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toJsonBlob.nf' +String toJsonBlob(data) { + return groovy.json.JsonOutput.toJson(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toTaggedYamlBlob.nf' +// Custom representer to modify how certain objects are represented in YAML +class CustomRepresenter extends org.yaml.snakeyaml.representer.Representer { + Path relativizer + + class RepresentPath implements org.yaml.snakeyaml.representer.Represent { + public String getFileName(Object obj) { + if (obj instanceof File) { + obj = ((File) obj).toPath(); + } + if (obj !instanceof Path) { + throw new IllegalArgumentException("Object: " + obj + " is not a Path or File"); + } + def path = (Path) obj; + + if (relativizer != null) { + return relativizer.relativize(path).toString() + } else { + return path.toString() + } + } + + public org.yaml.snakeyaml.nodes.Node representData(Object data) { + String filename = getFileName(data); + def tag = new org.yaml.snakeyaml.nodes.Tag("!file"); + return representScalar(tag, filename); + } + } + CustomRepresenter(org.yaml.snakeyaml.DumperOptions options, Path relativizer) { + super(options) + this.relativizer = relativizer + this.representers.put(sun.nio.fs.UnixPath, new RepresentPath()) + this.representers.put(Path, new RepresentPath()) + this.representers.put(File, new RepresentPath()) + } +} + +String toTaggedYamlBlob(data) { + return toRelativeTaggedYamlBlob(data, null) +} +String toRelativeTaggedYamlBlob(data, Path relativizer) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + def representer = new CustomRepresenter(options, relativizer) + def yaml = new org.yaml.snakeyaml.Yaml(representer, options) + return yaml.dump(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toYamlBlob.nf' +String toYamlBlob(data) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + options.setPrettyFlow(true) + def yaml = new org.yaml.snakeyaml.Yaml(options) + def cleanData = iterateMap(data, { it instanceof Path ? it.toString() : it }) + return yaml.dump(cleanData) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeJson.nf' +void writeJson(data, file) { + assert data: "writeJson: data should not be null" + assert file: "writeJson: file should not be null" + file.write(toJsonBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeYaml.nf' +void writeYaml(data, file) { + assert data: "writeYaml: data should not be null" + assert file: "writeYaml: file should not be null" + file.write(toYamlBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/findStates.nf' +def findStates(Map params, Map config) { + def auto_config = deepClone(config) + def auto_params = deepClone(params) + + auto_config = auto_config.clone() + // override arguments + auto_config.argument_groups = [] + auto_config.arguments = [ + [ + type: "string", + name: "--id", + description: "A dummy identifier", + required: false + ], + [ + type: "file", + name: "--input_states", + example: "/path/to/input/directory/**/state.yaml", + description: "Path to input directory containing the datasets to be integrated.", + required: true, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--filter", + example: "foo/.*/state.yaml", + description: "Regex to filter state files by path.", + required: false + ], + // to do: make this a yaml blob? + [ + type: "string", + name: "--rename_keys", + example: ["newKey1:oldKey1", "newKey2:oldKey2"], + description: "Rename keys in the detected input files. This is useful if the input files do not match the set of input arguments of the workflow.", + required: false, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--settings", + example: '{"output_dataset": "dataset.h5ad", "k": 10}', + description: "Global arguments as a JSON glob to be passed to all components.", + required: false + ] + ] + if (!(auto_params.containsKey("id"))) { + auto_params["id"] = "auto" + } + + // run auto config through processConfig once more + auto_config = processConfig(auto_config) + + workflow findStatesWf { + helpMessage(auto_config) + + output_ch = + channelFromParams(auto_params, auto_config) + | flatMap { autoId, args -> + + def globalSettings = args.settings ? readYamlBlob(args.settings) : [:] + + // look for state files in input dir + def stateFiles = args.input_states + + // filter state files by regex + if (args.filter) { + stateFiles = stateFiles.findAll{ stateFile -> + def stateFileStr = stateFile.toString() + def matcher = stateFileStr =~ args.filter + matcher.matches()} + } + + // read in states + def states = stateFiles.collect { stateFile -> + def state_ = readTaggedYaml(stateFile) + [state_.id, state_] + } + + // construct renameMap + if (args.rename_keys) { + def renameMap = args.rename_keys.collectEntries{renameString -> + def split = renameString.split(":") + assert split.size() == 2: "Argument 'rename_keys' should be of the form 'newKey:oldKey', or 'newKey:oldKey;newKey:oldKey' in case of multiple values" + split + } + + // rename keys in state, only let states through which have all keys + // also add global settings + states = states.collectMany{id, state -> + def newState = [:] + + for (key in renameMap.keySet()) { + def origKey = renameMap[key] + if (!(state.containsKey(origKey))) { + return [] + } + newState[key] = state[origKey] + } + + [[id, globalSettings + newState]] + } + } + + states + } + emit: + output_ch + } + + return findStatesWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/joinStates.nf' +def joinStates(Closure apply_) { + workflow joinStatesWf { + take: input_ch + main: + output_ch = input_ch + | toSortedList + | filter{ it.size() > 0 } + | map{ tups -> + def ids = tups.collect{it[0]} + def states = tups.collect{it[1]} + apply_(ids, states) + } + + emit: output_ch + } + return joinStatesWf +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf' +def collectFiles(obj) { + if (obj instanceof java.io.File || obj instanceof Path) { + return [obj] + } else if (obj instanceof List && obj !instanceof String) { + return obj.collectMany{item -> + collectFiles(item) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectFiles(item) + } + } else { + return [] + } +} + +/** + * Recurse through a state and collect all input files and their target output filenames. + * @param obj The state to recurse through. + * @param prefix The prefix to prepend to the output filenames. + */ +def collectInputOutputPaths(obj, prefix) { + if (obj instanceof File || obj instanceof Path) { + def path = obj instanceof Path ? obj : obj.toPath() + def ext = path.getFileName().toString().find("\\.[^\\.]+\$") ?: "" + def newFilename = prefix + ext + return [[obj, newFilename]] + } else if (obj instanceof List && obj !instanceof String) { + return obj.withIndex().collectMany{item, ix -> + collectInputOutputPaths(item, prefix + "_" + ix) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectInputOutputPaths(item, prefix + "." + key) + } + } else { + return [] + } +} + +def publishStates(Map args) { + def key_ = args.get("key") + def yamlTemplate_ = args.get("output_state", args.get("outputState", '$id.$key.state.yaml')) + + assert key_ != null : "publishStates: key must be specified" + + workflow publishStatesWf { + 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] + + def yamlFilename = yamlTemplate_ + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .replaceAll('\\$\\{key\\}', key_) + + // TODO: do the pathnames in state_ match up with the outputFilenames_? + + // convert state to yaml blob + def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename)) + + [id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_] + } + | publishStatesProc + emit: input_ch + } + return publishStatesWf +} +process publishStatesProc { + // todo: check publishpath? + publishDir path: "${getPublishDir()}/", mode: "copy" + tag "$id" + input: + tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles) + output: + tuple val(id), path{[yamlFile] + 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 + [] + } + } + """ +mkdir -p "\$(dirname '${yamlFile}')" +echo "Storing state as yaml" +echo '${yamlBlob}' > '${yamlFile}' +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 publishStatesByConfig(Map args) { + def config = args.get("config") + assert config != null : "publishStatesByConfig: config must be specified" + + def key_ = args.get("key", config.name) + assert key_ != null : "publishStatesByConfig: key must be specified" + + workflow publishStatesSimpleWf { + 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'] + + // TODO: allow overriding the state.yaml template + // TODO TODO: if auto.publish == "state", add output_state as an argument + def yamlTemplate = params.containsKey("output_state") ? params.output_state : '$id.$key.state.yaml' + def yamlFilename = yamlTemplate + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .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 + // - 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" } + .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 + 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 [[key: plainName_, value: value, 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 value_ = java.nio.file.Paths.get(filename_ix) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = val instanceof File ? val.toPath() : val + [value: value_, inputPath: inputPath, outputFilename: filename_ix] + } + def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key -> + [key, outputPerFile.collect{dic -> dic[key]}] + } + return [[key: plainName_] + transposedOutputs] + } else { + def value_ = java.nio.file.Paths.get(filename) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = value instanceof File ? value.toPath() : value + return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]] + } + } + + 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] + } + | publishStatesProc + emit: input_ch + } + return publishStatesSimpleWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/setState.nf' +def setState(fun) { + assert fun instanceof Closure || fun instanceof Map || fun instanceof List : + "Error in setState: Expected process argument to be a Closure, a Map, or a List. Found: class ${fun.getClass()}" + + // if fun is a List, convert to map + if (fun instanceof List) { + // check whether fun is a list[string] + assert fun.every{it instanceof CharSequence} : "Error in setState: argument is a List, but not all elements are Strings" + fun = fun.collectEntries{[it, it]} + } + + // if fun is a map, convert to closure + if (fun instanceof Map) { + // check whether fun is a map[string, string] + assert fun.values().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all values are Strings" + assert fun.keySet().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all keys are Strings" + def funMap = fun.clone() + // turn the map into a closure to be used later on + fun = { id_, state_ -> + assert state_ instanceof Map : "Error in setState: the state is not a Map" + funMap.collectMany{newkey, origkey -> + if (state_.containsKey(origkey)) { + [[newkey, state_[origkey]]] + } else { + [] + } + }.collectEntries() + } + } + + map { tup -> + def id = tup[0] + def state = tup[1] + def unfilteredState = fun(id, state) + def newState = unfilteredState.findAll{key, val -> val != null} + [id, newState] + tup.drop(2) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processAuto.nf' +// TODO: unit test processAuto +def processAuto(Map auto) { + // remove null values + auto = auto.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = ["simplifyInput", "simplifyOutput", "transcript", "publish"] + def unexpectedKeys = auto.keySet() - expectedKeys + assert unexpectedKeys.isEmpty(), "unexpected keys in auto: '${unexpectedKeys.join("', '")}'" + + // check auto.simplifyInput + assert auto.simplifyInput instanceof Boolean, "auto.simplifyInput must be a boolean" + + // check auto.simplifyOutput + assert auto.simplifyOutput instanceof Boolean, "auto.simplifyOutput must be a boolean" + + // check auto.transcript + assert auto.transcript instanceof Boolean, "auto.transcript must be a boolean" + + // check auto.publish + assert auto.publish instanceof Boolean || auto.publish == "state", "auto.publish must be a boolean or 'state'" + + return auto.subMap(expectedKeys) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processDirectives.nf' +def assertMapKeys(map, expectedKeys, requiredKeys, mapName) { + assert map instanceof Map : "Expected argument '$mapName' to be a Map. Found: class ${map.getClass()}" + map.forEach { key, val -> + assert key in expectedKeys : "Unexpected key '$key' in ${mapName ? mapName + " " : ""}map" + } + requiredKeys.forEach { requiredKey -> + assert map.containsKey(requiredKey) : "Missing required key '$key' in ${mapName ? mapName + " " : ""}map" + } +} + +// TODO: unit test processDirectives +def processDirectives(Map drctv) { + // remove null values + drctv = drctv.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = [ + "accelerator", "afterScript", "beforeScript", "cache", "conda", "container", "containerOptions", "cpus", "disk", "echo", "errorStrategy", "executor", "machineType", "maxErrors", "maxForks", "maxRetries", "memory", "module", "penv", "pod", "publishDir", "queue", "label", "scratch", "storeDir", "stageInMode", "stageOutMode", "tag", "time" + ] + def unexpectedKeys = drctv.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Unexpected keys in process directive: '${unexpectedKeys.join("', '")}'" + + /* DIRECTIVE accelerator + accepted examples: + - [ limit: 4, type: "nvidia-tesla-k80" ] + */ + if (drctv.containsKey("accelerator")) { + assertMapKeys(drctv["accelerator"], ["type", "limit", "request", "runtime"], [], "accelerator") + } + + /* DIRECTIVE afterScript + accepted examples: + - "source /cluster/bin/cleanup" + */ + if (drctv.containsKey("afterScript")) { + assert drctv["afterScript"] instanceof CharSequence + } + + /* DIRECTIVE beforeScript + accepted examples: + - "source /cluster/bin/setup" + */ + if (drctv.containsKey("beforeScript")) { + assert drctv["beforeScript"] instanceof CharSequence + } + + /* DIRECTIVE cache + accepted examples: + - true + - false + - "deep" + - "lenient" + */ + if (drctv.containsKey("cache")) { + assert drctv["cache"] instanceof CharSequence || drctv["cache"] instanceof Boolean + if (drctv["cache"] instanceof CharSequence) { + assert drctv["cache"] in ["deep", "lenient"] : "Unexpected value for cache" + } + } + + /* DIRECTIVE conda + accepted examples: + - "bwa=0.7.15" + - "bwa=0.7.15 fastqc=0.11.5" + - ["bwa=0.7.15", "fastqc=0.11.5"] + */ + if (drctv.containsKey("conda")) { + if (drctv["conda"] instanceof List) { + drctv["conda"] = drctv["conda"].join(" ") + } + assert drctv["conda"] instanceof CharSequence + } + + /* DIRECTIVE container + accepted examples: + - "foo/bar:tag" + - [ registry: "reg", image: "im", tag: "ta" ] + is transformed to "reg/im:ta" + - [ image: "im" ] + is transformed to "im:latest" + */ + if (drctv.containsKey("container")) { + assert drctv["container"] instanceof Map || drctv["container"] instanceof CharSequence + if (drctv["container"] instanceof Map) { + def m = drctv["container"] + assertMapKeys(m, [ "registry", "image", "tag" ], ["image"], "container") + def part1 = + System.getenv('OVERRIDE_CONTAINER_REGISTRY') ? System.getenv('OVERRIDE_CONTAINER_REGISTRY') + "/" : + params.containsKey("override_container_registry") ? params["override_container_registry"] + "/" : // todo: remove? + m.registry ? m.registry + "/" : + "" + def part2 = m.image + def part3 = m.tag ? ":" + m.tag : ":latest" + drctv["container"] = part1 + part2 + part3 + } + } + + /* DIRECTIVE containerOptions + accepted examples: + - "--foo bar" + - ["--foo bar", "-f b"] + */ + if (drctv.containsKey("containerOptions")) { + if (drctv["containerOptions"] instanceof List) { + drctv["containerOptions"] = drctv["containerOptions"].join(" ") + } + assert drctv["containerOptions"] instanceof CharSequence + } + + /* DIRECTIVE cpus + accepted examples: + - 1 + - 10 + */ + if (drctv.containsKey("cpus")) { + assert drctv["cpus"] instanceof Integer + } + + /* DIRECTIVE disk + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("disk")) { + assert drctv["disk"] instanceof CharSequence + // assert drctv["disk"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE echo + accepted examples: + - true + - false + */ + if (drctv.containsKey("echo")) { + assert drctv["echo"] instanceof Boolean + } + + /* DIRECTIVE errorStrategy + accepted examples: + - "terminate" + - "finish" + */ + if (drctv.containsKey("errorStrategy")) { + assert drctv["errorStrategy"] instanceof CharSequence + assert drctv["errorStrategy"] in ["terminate", "finish", "ignore", "retry"] : "Unexpected value for errorStrategy" + } + + /* DIRECTIVE executor + accepted examples: + - "local" + - "sge" + */ + if (drctv.containsKey("executor")) { + assert drctv["executor"] instanceof CharSequence + assert drctv["executor"] in ["local", "sge", "uge", "lsf", "slurm", "pbs", "pbspro", "moab", "condor", "nqsii", "ignite", "k8s", "awsbatch", "google-pipelines"] : "Unexpected value for executor" + } + + /* DIRECTIVE machineType + accepted examples: + - "n1-highmem-8" + */ + if (drctv.containsKey("machineType")) { + assert drctv["machineType"] instanceof CharSequence + } + + /* DIRECTIVE maxErrors + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxErrors")) { + assert drctv["maxErrors"] instanceof Integer + } + + /* DIRECTIVE maxForks + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxForks")) { + assert drctv["maxForks"] instanceof Integer + } + + /* DIRECTIVE maxRetries + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxRetries")) { + assert drctv["maxRetries"] instanceof Integer + } + + /* DIRECTIVE memory + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("memory")) { + assert drctv["memory"] instanceof CharSequence + // assert drctv["memory"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE module + accepted examples: + - "ncbi-blast/2.2.27" + - "ncbi-blast/2.2.27:t_coffee/10.0" + - ["ncbi-blast/2.2.27", "t_coffee/10.0"] + */ + if (drctv.containsKey("module")) { + if (drctv["module"] instanceof List) { + drctv["module"] = drctv["module"].join(":") + } + assert drctv["module"] instanceof CharSequence + } + + /* DIRECTIVE penv + accepted examples: + - "smp" + */ + if (drctv.containsKey("penv")) { + assert drctv["penv"] instanceof CharSequence + } + + /* DIRECTIVE pod + accepted examples: + - [ label: "key", value: "val" ] + - [ annotation: "key", value: "val" ] + - [ env: "key", value: "val" ] + - [ [label: "l", value: "v"], [env: "e", value: "v"]] + */ + if (drctv.containsKey("pod")) { + if (drctv["pod"] instanceof Map) { + drctv["pod"] = [ drctv["pod"] ] + } + assert drctv["pod"] instanceof List + drctv["pod"].forEach { pod -> + assert pod instanceof Map + // TODO: should more checks be added? + // See https://www.nextflow.io/docs/latest/process.html?highlight=directives#pod + // e.g. does it contain 'label' and 'value', or 'annotation' and 'value', or ...? + } + } + + /* DIRECTIVE publishDir + accepted examples: + - [] + - [ [ path: "foo", enabled: true ], [ path: "bar", enabled: false ] ] + - "/path/to/dir" + is transformed to [[ path: "/path/to/dir" ]] + - [ path: "/path/to/dir", mode: "cache" ] + is transformed to [[ path: "/path/to/dir", mode: "cache" ]] + */ + // TODO: should we also look at params["publishDir"]? + if (drctv.containsKey("publishDir")) { + def pblsh = drctv["publishDir"] + + // check different options + assert pblsh instanceof List || pblsh instanceof Map || pblsh instanceof CharSequence + + // turn into list if not already so + // for some reason, 'if (!pblsh instanceof List) pblsh = [ pblsh ]' doesn't work. + pblsh = pblsh instanceof List ? pblsh : [ pblsh ] + + // check elements of publishDir + pblsh = pblsh.collect{ elem -> + // turn into map if not already so + elem = elem instanceof CharSequence ? [ path: elem ] : elem + + // check types and keys + assert elem instanceof Map : "Expected publish argument '$elem' to be a String or a Map. Found: class ${elem.getClass()}" + assertMapKeys(elem, [ "path", "mode", "overwrite", "pattern", "saveAs", "enabled" ], ["path"], "publishDir") + + // check elements in map + assert elem.containsKey("path") + assert elem["path"] instanceof CharSequence + if (elem.containsKey("mode")) { + assert elem["mode"] instanceof CharSequence + assert elem["mode"] in [ "symlink", "rellink", "link", "copy", "copyNoFollow", "move" ] + } + if (elem.containsKey("overwrite")) { + assert elem["overwrite"] instanceof Boolean + } + if (elem.containsKey("pattern")) { + assert elem["pattern"] instanceof CharSequence + } + if (elem.containsKey("saveAs")) { + assert elem["saveAs"] instanceof CharSequence //: "saveAs as a Closure is currently not supported. Surround your closure with single quotes to get the desired effect. Example: '\{ foo \}'" + } + if (elem.containsKey("enabled")) { + assert elem["enabled"] instanceof Boolean + } + + // return final result + elem + } + // store final directive + drctv["publishDir"] = pblsh + } + + /* DIRECTIVE queue + accepted examples: + - "long" + - "short,long" + - ["short", "long"] + */ + if (drctv.containsKey("queue")) { + if (drctv["queue"] instanceof List) { + drctv["queue"] = drctv["queue"].join(",") + } + assert drctv["queue"] instanceof CharSequence + } + + /* DIRECTIVE label + accepted examples: + - "big_mem" + - "big_cpu" + - ["big_mem", "big_cpu"] + */ + if (drctv.containsKey("label")) { + if (drctv["label"] instanceof CharSequence) { + drctv["label"] = [ drctv["label"] ] + } + assert drctv["label"] instanceof List + drctv["label"].forEach { label -> + assert label instanceof CharSequence + // assert label.matches("[a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?") + // ^ does not allow closures + } + } + + /* DIRECTIVE scratch + accepted examples: + - true + - "/path/to/scratch" + - '$MY_PATH_TO_SCRATCH' + - "ram-disk" + */ + if (drctv.containsKey("scratch")) { + assert drctv["scratch"] == true || drctv["scratch"] instanceof CharSequence + } + + /* DIRECTIVE storeDir + accepted examples: + - "/path/to/storeDir" + */ + if (drctv.containsKey("storeDir")) { + assert drctv["storeDir"] instanceof CharSequence + } + + /* DIRECTIVE stageInMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageInMode")) { + assert drctv["stageInMode"] instanceof CharSequence + assert drctv["stageInMode"] in ["copy", "link", "symlink", "rellink"] + } + + /* DIRECTIVE stageOutMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageOutMode")) { + assert drctv["stageOutMode"] instanceof CharSequence + assert drctv["stageOutMode"] in ["copy", "move", "rsync"] + } + + /* DIRECTIVE tag + accepted examples: + - "foo" + - '$id' + */ + if (drctv.containsKey("tag")) { + assert drctv["tag"] instanceof CharSequence + } + + /* DIRECTIVE time + accepted examples: + - "1h" + - "2days" + - "1day 6hours 3minutes 30seconds" + */ + if (drctv.containsKey("time")) { + assert drctv["time"] instanceof CharSequence + // todo: validation regex? + } + + return drctv +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processWorkflowArgs.nf' +def processWorkflowArgs(Map args, Map defaultWfArgs, Map meta) { + // override defaults with args + def workflowArgs = defaultWfArgs + args + + // check whether 'key' exists + assert workflowArgs.containsKey("key") : "Error in module '${meta.config.name}': key is a required argument" + + // if 'key' is a closure, apply it to the original key + if (workflowArgs["key"] instanceof Closure) { + workflowArgs["key"] = workflowArgs["key"](meta.config.name) + } + def key = workflowArgs["key"] + assert key instanceof CharSequence : "Expected process argument 'key' to be a String. Found: class ${key.getClass()}" + assert key ==~ /^[a-zA-Z_]\w*$/ : "Error in module '$key': Expected process argument 'key' to consist of only letters, digits or underscores. Found: ${key}" + + // check for any unexpected keys + def expectedKeys = ["key", "directives", "auto", "map", "mapId", "mapData", "mapPassthrough", "filter", "runIf", "fromState", "toState", "args", "renameKeys", "debug"] + def unexpectedKeys = workflowArgs.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Error in module '$key': unexpected arguments to the '.run()' function: '${unexpectedKeys.join("', '")}'" + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("directives") : "Error in module '$key': directives is a required argument" + assert workflowArgs["directives"] instanceof Map : "Error in module '$key': Expected process argument 'directives' to be a Map. Found: class ${workflowArgs['directives'].getClass()}" + workflowArgs["directives"] = processDirectives(defaultWfArgs.directives + workflowArgs["directives"]) + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("auto") : "Error in module '$key': auto is a required argument" + assert workflowArgs["auto"] instanceof Map : "Error in module '$key': Expected process argument 'auto' to be a Map. Found: class ${workflowArgs['auto'].getClass()}" + workflowArgs["auto"] = processAuto(defaultWfArgs.auto + workflowArgs["auto"]) + + // auto define publish, if so desired + if (workflowArgs.auto.publish == true && (workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : [:]).isEmpty()) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.publish is true, params.publish_dir needs to be defined.\n" + + // " Example: params.publish_dir = \"./output/\"" + def publishDir = getPublishDir() + + if (publishDir != null) { + workflowArgs.directives.publishDir = [[ + path: publishDir, + saveAs: "{ it.startsWith('.') ? null : it }", // don't publish hidden files, by default + mode: "copy" + ]] + } + } + + // auto define transcript, if so desired + if (workflowArgs.auto.transcript == true) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("transcriptsDir") || params.containsKey("transcripts_dir") || params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.transcript is true, either params.transcripts_dir or params.publish_dir needs to be defined.\n" + + // " Example: params.transcripts_dir = \"./transcripts/\"" + def transcriptsDir = + params.containsKey("transcripts_dir") ? params.transcripts_dir : + params.containsKey("transcriptsDir") ? params.transcriptsDir : + params.containsKey("publish_dir") ? params.publish_dir + "/_transcripts" : + params.containsKey("publishDir") ? params.publishDir + "/_transcripts" : + null + if (transcriptsDir != null) { + def timestamp = nextflow.Nextflow.getSession().getWorkflowMetadata().start.format('yyyy-MM-dd_HH-mm-ss') + def transcriptsPublishDir = [ + path: "$transcriptsDir/$timestamp/\${task.process.replaceAll(':', '-')}/\${id}/", + saveAs: "{ it.startsWith('.') ? it.replaceAll('^.', '') : null }", + mode: "copy" + ] + def publishDirs = workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : null ? workflowArgs.directives.publishDir : [] + workflowArgs.directives.publishDir = publishDirs + transcriptsPublishDir + } + } + + // if this is a stubrun, remove certain directives? + if (workflow.stubRun) { + workflowArgs.directives.keySet().removeAll(["publishDir", "cpus", "memory", "label"]) + } + + for (nam in ["map", "mapId", "mapData", "mapPassthrough", "filter", "runIf"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam]) { + assert workflowArgs[nam] instanceof Closure : "Error in module '$key': Expected process argument '$nam' to be null or a Closure. Found: class ${workflowArgs[nam].getClass()}" + } + } + + // TODO: should functions like 'map', 'mapId', 'mapData', 'mapPassthrough' be deprecated as well? + for (nam in ["map", "mapData", "mapPassthrough", "renameKeys"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam] != null) { + log.warn "module '$key': workflow argument '$nam' is deprecated and will be removed in Viash 0.9.0. Please use 'fromState' and 'toState' instead." + } + } + + // check fromState + workflowArgs["fromState"] = _processFromState(workflowArgs.get("fromState"), key, meta.config) + + // check toState + workflowArgs["toState"] = _processToState(workflowArgs.get("toState"), key, meta.config) + + // return output + return workflowArgs +} + +def _processFromState(fromState, key_, config_) { + assert fromState == null || fromState instanceof Closure || fromState instanceof Map || fromState instanceof List : + "Error in module '$key_': Expected process argument 'fromState' to be null, a Closure, a Map, or a List. Found: class ${fromState.getClass()}" + if (fromState == null) { + return null + } + + // if fromState is a List, convert to map + if (fromState instanceof List) { + // check whether fromstate is a list[string] + assert fromState.every{it instanceof CharSequence} : "Error in module '$key_': fromState is a List, but not all elements are Strings" + fromState = fromState.collectEntries{[it, it]} + } + + // if fromState is a map, convert to closure + if (fromState instanceof Map) { + // check whether fromstate is a map[string, string] + assert fromState.values().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all values are Strings" + assert fromState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all keys are Strings" + def fromStateMap = fromState.clone() + def requiredInputNames = meta.config.allArguments.findAll{it.required && it.direction == "Input"}.collect{it.plainName} + // turn the map into a closure to be used later on + fromState = { it -> + def state = it[1] + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def data = fromStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (state.containsKey(origkey)) { + [[newkey, state[origkey]]] + } else if (!requiredInputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': fromState key '$origkey' not found in current state") + } + }.collectEntries() + data + } + } + + return fromState +} + +def _processToState(toState, key_, config_) { + if (toState == null) { + toState = { tup -> tup[1] } + } + + // toState should be a closure, map[string, string], or list[string] + assert toState instanceof Closure || toState instanceof Map || toState instanceof List : + "Error in module '$key_': Expected process argument 'toState' to be a Closure, a Map, or a List. Found: class ${toState.getClass()}" + + // if toState is a List, convert to map + if (toState instanceof List) { + // check whether toState is a list[string] + assert toState.every{it instanceof CharSequence} : "Error in module '$key_': toState is a List, but not all elements are Strings" + toState = toState.collectEntries{[it, it]} + } + + // if toState is a map, convert to closure + if (toState instanceof Map) { + // check whether toState is a map[string, string] + assert toState.values().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all values are Strings" + assert toState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all keys are Strings" + def toStateMap = toState.clone() + def requiredOutputNames = config_.allArguments.findAll{it.required && it.direction == "Output"}.collect{it.plainName} + // turn the map into a closure to be used later on + toState = { it -> + def output = it[1] + def state = it[2] + assert output instanceof Map : "Error in module '$key_': the output is not a Map" + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def extraEntries = toStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (output.containsKey(origkey)) { + [[newkey, output[origkey]]] + } else if (!requiredOutputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': toState key '$origkey' not found in current output") + } + }.collectEntries() + state + extraEntries + } + } + + return toState +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/workflowFactory.nf' +def _debug(workflowArgs, debugKey) { + if (workflowArgs.debug) { + view { "process '${workflowArgs.key}' $debugKey tuple: $it" } + } else { + map { it } + } +} + +// depends on: innerWorkflowFactory +def workflowFactory(Map args, Map defaultWfArgs, Map meta) { + def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta) + def key_ = workflowArgs["key"] + + workflow workflowInstance { + take: input_ + + main: + def chModified = input_ + | checkUniqueIds([:]) + | _debug(workflowArgs, "input") + | map { tuple -> + tuple = deepClone(tuple) + + if (workflowArgs.map) { + tuple = workflowArgs.map(tuple) + } + if (workflowArgs.mapId) { + tuple[0] = workflowArgs.mapId(tuple[0]) + } + if (workflowArgs.mapData) { + tuple[1] = workflowArgs.mapData(tuple[1]) + } + if (workflowArgs.mapPassthrough) { + tuple = tuple.take(2) + workflowArgs.mapPassthrough(tuple.drop(2)) + } + + // check tuple + assert tuple instanceof List : + "Error in module '${key_}': element in 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()}" + assert tuple.size() >= 2 : + "Error in module '${key_}': expected length of tuple in input channel to be two or greater.\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: tuple.size() == ${tuple.size()}" + + // check id field + if (tuple[0] instanceof GString) { + tuple[0] = tuple[0].toString() + } + assert tuple[0] instanceof CharSequence : + "Error in module '${key_}': first element of tuple in channel should be a String\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: ${tuple[0]}" + + // match file to input file + if (workflowArgs.auto.simplifyInput && (tuple[1] instanceof Path || tuple[1] instanceof List)) { + def inputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + + assert inputFiles.size() == 1 : + "Error in module '${key_}' id '${tuple[0]}'.\n" + + " Anonymous file inputs are only allowed when the process has exactly one file input.\n" + + " Expected: inputFiles.size() == 1. Found: inputFiles.size() is ${inputFiles.size()}" + + tuple[1] = [[ inputFiles[0].plainName, tuple[1] ]].collectEntries() + } + + // check data field + assert tuple[1] instanceof Map : + "Error in module '${key_}' id '${tuple[0]}': second element of tuple in channel should be a Map\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // rename keys of data field in tuple + if (workflowArgs.renameKeys) { + assert workflowArgs.renameKeys instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class: Map. Found: renameKeys.getClass() is ${workflowArgs.renameKeys.getClass()}" + assert tuple[1] instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // TODO: allow renameKeys to be a function? + workflowArgs.renameKeys.each { newKey, oldKey -> + assert newKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of newKey: String. Found: newKey.getClass() is ${newKey.getClass()}" + assert oldKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of oldKey: String. Found: oldKey.getClass() is ${oldKey.getClass()}" + assert tuple[1].containsKey(oldKey) : + "Error renaming data keys in module '${key}' id '${tuple[0]}'.\n" + + " Key '$oldKey' is missing in the data map. tuple[1].keySet() is '${tuple[1].keySet()}'" + tuple[1].put(newKey, tuple[1][oldKey]) + } + tuple[1].keySet().removeAll(workflowArgs.renameKeys.collect{ newKey, oldKey -> oldKey }) + } + tuple + } + + + def chRun = null + def chPassthrough = null + if (workflowArgs.runIf) { + def runIfBranch = chModified.branch{ tup -> + run: workflowArgs.runIf(tup[0], tup[1]) + passthrough: true + } + chRun = runIfBranch.run + chPassthrough = runIfBranch.passthrough + } else { + chRun = chModified + chPassthrough = Channel.empty() + } + + def chRunFiltered = workflowArgs.filter ? + chRun | filter{workflowArgs.filter(it)} : + chRun + + def chArgs = workflowArgs.fromState ? + chRunFiltered | map{ + def new_data = workflowArgs.fromState(it.take(2)) + [it[0], new_data] + } : + chRunFiltered | map {tup -> tup.take(2)} + + // fill in defaults + def chArgsWithDefaults = chArgs + | map { tuple -> + def id_ = tuple[0] + def data_ = tuple[1] + + // TODO: could move fromState to here + + // fetch default params from functionality + def defaultArgs = meta.config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + // fetch overrides in params + def paramArgs = meta.config.allArguments + .findAll { par -> + def argKey = key_ + "__" + par.plainName + params.containsKey(argKey) + } + .collectEntries { [ it.plainName, params[key_ + "__" + it.plainName] ] } + + // fetch overrides in data + def dataArgs = meta.config.allArguments + .findAll { data_.containsKey(it.plainName) } + .collectEntries { [ it.plainName, data_[it.plainName] ] } + + // combine params + def combinedArgs = defaultArgs + paramArgs + workflowArgs.args + dataArgs + + // remove arguments with explicit null values + combinedArgs + .removeAll{_, val -> val == null || val == "viash_no_value" || val == "force_null"} + + combinedArgs = _processInputValues(combinedArgs, meta.config, id_, key_) + + [id_, combinedArgs] + tuple.drop(2) + } + + // TODO: move some of the _meta.join_id wrangling to the safeJoin() function. + def chInitialOutput = chArgsWithDefaults + | _debug(workflowArgs, "processed") + // run workflow + | innerWorkflowFactory(workflowArgs) + // check output tuple + | map { id_, output_ -> + + // see if output map contains metadata + def meta_ = + output_ instanceof Map && output_.containsKey("_meta") ? + output_["_meta"] : + [:] + def join_id = meta_.join_id ?: id_ + + // remove metadata + output_ = output_.findAll{k, v -> k != "_meta"} + + // check value types + output_ = _processOutputValues(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_] + } + // | view{"chInitialOutput: ${it.take(3)}"} + + // join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...] + def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_) + // input tuple format: [join_id, id, output, prev_state, ...] + // output tuple format: [join_id, id, new_state, ...] + | map{ tup -> + def new_state = workflowArgs.toState(tup.drop(1).take(3)) + tup.take(2) + [new_state] + tup.drop(4) + } + + if (workflowArgs.auto.publish == "state") { + def chPublish = 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_) + // 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, ...] + // output tuple format: [id, new_state, ...] + tup.drop(1) + } + | _debug(workflowArgs, "output") + | concat(chPassthrough) + + emit: chReturn + } + + def wf = workflowInstance.cloneWithName(key_) + + // add factory function + wf.metaClass.run = { runArgs -> + workflowFactory(runArgs, workflowArgs, meta) + } + // add config to module for later introspection + wf.metaClass.config = meta.config + + return wf +} + +nextflow.enable.dsl=2 + +// START COMPONENT-SPECIFIC CODE + +// create meta object +meta = [ + "resources_dir": moduleDir.toRealPath().normalize(), + "config": processConfig(readJsonBlob('''{ + "name" : "bedtools_bamtobed", + "namespace" : "bedtools", + "version" : "main", + "authors" : [ + { + "name" : "Theodoro Gasperin Terra Camargo", + "roles" : [ + "author", + "maintainer" + ], + "info" : { + "links" : { + "email" : "theodorogtc@gmail.com", + "github" : "tgaspe", + "linkedin" : "theodoro-gasperin-terra-camargo" + }, + "organizations" : [ + { + "name" : "Data Intuitive", + "href" : "https://www.data-intuitive.com", + "role" : "Bioinformatician" + } + ] + } + } + ], + "argument_groups" : [ + { + "name" : "Inputs", + "arguments" : [ + { + "type" : "file", + "name" : "--input", + "alternatives" : [ + "-i" + ], + "description" : "Input BAM file.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Outputs", + "arguments" : [ + { + "type" : "file", + "name" : "--output", + "alternatives" : [ + "-o" + ], + "description" : "Output BED file.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Options", + "arguments" : [ + { + "type" : "boolean_true", + "name" : "--bedpe", + "description" : "Write BEDPE format. Requires BAM to be grouped or sorted by query.\n", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--mate1", + "description" : "When writing BEDPE (-bedpe) format, always report mate one as the first BEDPE \\"block\\".\n", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--bed12", + "description" : "Write \\"blocked\\" BED format (aka \\"BED12\\"). Forces -split.\nSee http://genome-test.cse.ucsc.edu/FAQ/FAQformat#format1\n", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--split", + "description" : "Report \\"split\\" BAM alignments as separate BED entries.\nSplits only on N CIGAR operations.\n", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--splitD", + "description" : "Split alignments based on N and D CIGAR operators.\nForces -split.\n", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--edit_distance", + "alternatives" : [ + "-ed" + ], + "description" : "Use BAM edit distance (NM tag) for BED score.\n- Default for BED is to use mapping quality.\n- Default for BEDPE is to use the minimum of\n the two mapping qualities for the pair.\n- When -ed is used with -bedpe, the total edit\n distance from the two mates is reported.\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--tag", + "description" : "Use other NUMERIC BAM alignment tag for BED score.\nDefault for BED is to use mapping quality. Disallowed with BEDPE output.\n", + "example" : [ + "SM" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--color", + "description" : "An R,G,B string for the color used with BED12 format.\nDefault is (255,0,0).\n", + "example" : [ + "250,250,250" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--cigar", + "description" : "Add the CIGAR string to the BED entry as a 7th column.\n", + "direction" : "input" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Converts BAM alignments to BED6 or BEDPE format.", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + }, + { + "type" : "file", + "path" : "test_data" + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "keywords" : [ + "Converts", + "BAM", + "BED", + "BED6", + "BEDPE" + ], + "license" : "MIT", + "references" : { + "doi" : [ + "10.1093/bioinformatics/btq033" + ] + }, + "links" : { + "repository" : "https://github.com/arq5x/bedtools2", + "homepage" : "https://bedtools.readthedocs.io/en/latest/#", + "documentation" : "https://bedtools.readthedocs.io/en/latest/content/tools/bamtobed.html", + "issue_tracker" : "https://github.com/arq5x/bedtools2/issues" + }, + "runners" : [ + { + "type" : "executable", + "id" : "executable", + "docker_setup_strategy" : "ifneedbepullelsecachedbuild" + }, + { + "type" : "nextflow", + "id" : "nextflow", + "directives" : { + "tag" : "$id" + }, + "auto" : { + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false + }, + "config" : { + "labels" : { + "mem1gb" : "memory = 1000000000.B", + "mem2gb" : "memory = 2000000000.B", + "mem5gb" : "memory = 5000000000.B", + "mem10gb" : "memory = 10000000000.B", + "mem20gb" : "memory = 20000000000.B", + "mem50gb" : "memory = 50000000000.B", + "mem100gb" : "memory = 100000000000.B", + "mem200gb" : "memory = 200000000000.B", + "mem500gb" : "memory = 500000000000.B", + "mem1tb" : "memory = 1000000000000.B", + "mem2tb" : "memory = 2000000000000.B", + "mem5tb" : "memory = 5000000000000.B", + "mem10tb" : "memory = 10000000000000.B", + "mem20tb" : "memory = 20000000000000.B", + "mem50tb" : "memory = 50000000000000.B", + "mem100tb" : "memory = 100000000000000.B", + "mem200tb" : "memory = 200000000000000.B", + "mem500tb" : "memory = 500000000000000.B", + "mem1gib" : "memory = 1073741824.B", + "mem2gib" : "memory = 2147483648.B", + "mem4gib" : "memory = 4294967296.B", + "mem8gib" : "memory = 8589934592.B", + "mem16gib" : "memory = 17179869184.B", + "mem32gib" : "memory = 34359738368.B", + "mem64gib" : "memory = 68719476736.B", + "mem128gib" : "memory = 137438953472.B", + "mem256gib" : "memory = 274877906944.B", + "mem512gib" : "memory = 549755813888.B", + "mem1tib" : "memory = 1099511627776.B", + "mem2tib" : "memory = 2199023255552.B", + "mem4tib" : "memory = 4398046511104.B", + "mem8tib" : "memory = 8796093022208.B", + "mem16tib" : "memory = 17592186044416.B", + "mem32tib" : "memory = 35184372088832.B", + "mem64tib" : "memory = 70368744177664.B", + "mem128tib" : "memory = 140737488355328.B", + "mem256tib" : "memory = 281474976710656.B", + "mem512tib" : "memory = 562949953421312.B", + "cpu1" : "cpus = 1", + "cpu2" : "cpus = 2", + "cpu5" : "cpus = 5", + "cpu10" : "cpus = 10", + "cpu20" : "cpus = 20", + "cpu50" : "cpus = 50", + "cpu100" : "cpus = 100", + "cpu200" : "cpus = 200", + "cpu500" : "cpus = 500", + "cpu1000" : "cpus = 1000" + } + }, + "debug" : false, + "container" : "docker" + } + ], + "engines" : [ + { + "type" : "docker", + "id" : "docker", + "image" : "debian:stable-slim", + "target_registry" : "images.viash-hub.com", + "target_tag" : "main", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "apt", + "packages" : [ + "bedtools", + "procps" + ], + "interactive" : false + }, + { + "type" : "docker", + "run" : [ + "echo \\"bedtools: \\\\\\"$(bedtools --version | sed -n 's/^bedtools //p')\\\\\\"\\" > /var/software_versions.txt\n" + ] + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/bedtools/bedtools_bamtobed/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/bedtools/bedtools_bamtobed", + "viash_version" : "0.9.0", + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" + }, + "package_config" : { + "name" : "biobox", + "version" : "main", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0", + "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 := 'main'" + ], + "keywords" : [ + "bioinformatics", + "modules", + "sequencing" + ], + "license" : "MIT", + "organization" : "vsh", + "links" : { + "repository" : "https://github.com/viash-hub/biobox", + "issue_tracker" : "https://github.com/viash-hub/biobox/issues" + } + } +}''')) +] + +// resolve dependencies dependencies (if any) + + +// inner workflow +// inner workflow hook +def innerWorkflowFactory(args) { + def rawScript = '''set -e +tempscript=".viash_script.sh" +cat > "$tempscript" << VIASHMAIN +#!/bin/bash + +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_INPUT+x} ]; then echo "${VIASH_PAR_INPUT}" | sed "s#'#'\\"'\\"'#g;s#.*#par_input='&'#" ; else echo "# par_input="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; fi ) +$( if [ ! -z ${VIASH_PAR_BEDPE+x} ]; then echo "${VIASH_PAR_BEDPE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_bedpe='&'#" ; else echo "# par_bedpe="; fi ) +$( if [ ! -z ${VIASH_PAR_MATE1+x} ]; then echo "${VIASH_PAR_MATE1}" | sed "s#'#'\\"'\\"'#g;s#.*#par_mate1='&'#" ; else echo "# par_mate1="; fi ) +$( if [ ! -z ${VIASH_PAR_BED12+x} ]; then echo "${VIASH_PAR_BED12}" | sed "s#'#'\\"'\\"'#g;s#.*#par_bed12='&'#" ; else echo "# par_bed12="; fi ) +$( if [ ! -z ${VIASH_PAR_SPLIT+x} ]; then echo "${VIASH_PAR_SPLIT}" | sed "s#'#'\\"'\\"'#g;s#.*#par_split='&'#" ; else echo "# par_split="; fi ) +$( if [ ! -z ${VIASH_PAR_SPLITD+x} ]; then echo "${VIASH_PAR_SPLITD}" | sed "s#'#'\\"'\\"'#g;s#.*#par_splitD='&'#" ; else echo "# par_splitD="; fi ) +$( if [ ! -z ${VIASH_PAR_EDIT_DISTANCE+x} ]; then echo "${VIASH_PAR_EDIT_DISTANCE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_edit_distance='&'#" ; else echo "# par_edit_distance="; fi ) +$( if [ ! -z ${VIASH_PAR_TAG+x} ]; then echo "${VIASH_PAR_TAG}" | sed "s#'#'\\"'\\"'#g;s#.*#par_tag='&'#" ; else echo "# par_tag="; fi ) +$( if [ ! -z ${VIASH_PAR_COLOR+x} ]; then echo "${VIASH_PAR_COLOR}" | sed "s#'#'\\"'\\"'#g;s#.*#par_color='&'#" ; else echo "# par_color="; fi ) +$( if [ ! -z ${VIASH_PAR_CIGAR+x} ]; then echo "${VIASH_PAR_CIGAR}" | sed "s#'#'\\"'\\"'#g;s#.*#par_cigar='&'#" ; else echo "# par_cigar="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END + +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_bedpe + par_mate1 + par_bed12 + par_split + par_splitD + par_edit_distance + par_tag + par_color + par_cigar +) + +for par in \\${unset_if_false[@]}; do + test_val="\\${!par}" + [[ "\\$test_val" == "false" ]] && unset \\$par +done + +# Execute bedtools sort with the provided arguments +bedtools bamtobed \\\\ + \\${par_bedpe:+-bedpe} \\\\ + \\${par_mate1:+-mate1} \\\\ + \\${par_bed12:+-bed12} \\\\ + \\${par_split:+-split} \\\\ + \\${par_splitD:+-splitD} \\\\ + \\${par_edit_distance:+-ed} \\\\ + \\${par_tag:+-tag "\\$par_tag"} \\\\ + \\${par_cigar:+-cigar} \\\\ + \\${par_color:+-color "\\$par_color"} \\\\ + -i "\\$par_input" \\\\ + > "\\$par_output" +VIASHMAIN +bash "$tempscript" +''' + + return vdsl3WorkflowFactory(args, meta, rawScript) +} + + + +/** + * Generate a workflow for VDSL3 modules. + * + * This function is called by the workflowFactory() function. + * + * Input channel: [id, input_map] + * Output channel: [id, output_map] + * + * Internally, this workflow will convert the input channel + * to a format which the Nextflow module will be able to handle. + */ +def vdsl3WorkflowFactory(Map args, Map meta, String rawScript) { + def key = args["key"] + def processObj = null + + workflow processWf { + take: input_ + main: + + if (processObj == null) { + processObj = _vdsl3ProcessFactory(args, meta, rawScript) + } + + output_ = input_ + | map { tuple -> + def id = tuple[0] + def data_ = tuple[1] + + if (workflow.stubRun) { + // add id if missing + data_ = [id: 'stub'] + data_ + } + + // process input files separately + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { par -> + def val = data_.containsKey(par.plainName) ? data_[par.plainName] : [] + def inputFiles = [] + if (val == null) { + inputFiles = [] + } else if (val instanceof List) { + inputFiles = val + } else if (val instanceof Path) { + inputFiles = [ val ] + } else { + inputFiles = [] + } + if (!workflow.stubRun) { + // throw error when an input file doesn't exist + inputFiles.each{ file -> + assert file.exists() : + "Error in module '${key}' id '${id}' argument '${par.plainName}'.\n" + + " Required input file does not exist.\n" + + " Path: '$file'.\n" + + " Expected input file to exist" + } + } + inputFiles + } + + // remove input files + def argsExclInputFiles = meta.config.allArguments + .findAll { (it.type != "file" || it.direction != "input") && data_.containsKey(it.plainName) } + .collectEntries { par -> + def parName = par.plainName + def val = data_[parName] + if (par.multiple && val instanceof Collection) { + val = val.join(par.multiple_sep) + } + if (par.direction == "output" && par.type == "file") { + val = val + .replaceAll('\\$id', id) + .replaceAll('\\$\\{id\\}', id) + .replaceAll('\\$key', key) + .replaceAll('\\$\\{key\\}', key) + } + [parName, val] + } + + [ id ] + inputPaths + [ argsExclInputFiles, meta.resources_dir ] + } + | processObj + | map { output -> + def outputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .indexed() + .collectEntries{ index, par -> + def out = output[index + 1] + // strip dummy '.exitcode' file from output (see nextflow-io/nextflow#2678) + if (!out instanceof List || out.size() <= 1) { + if (par.multiple) { + out = [] + } else { + assert !par.required : + "Error in module '${key}' id '${output[0]}' argument '${par.plainName}'.\n" + + " Required output file is missing" + out = null + } + } else if (out.size() == 2 && !par.multiple) { + out = out[1] + } else { + out = out.drop(1) + } + [ par.plainName, out ] + } + + // drop null outputs + outputFiles.removeAll{it.value == null} + + [ output[0], outputFiles ] + } + emit: output_ + } + + return processWf +} + +// depends on: session? +def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) { + // autodetect process key + def wfKey = workflowArgs["key"] + def procKeyPrefix = "${wfKey}_process" + def scriptMeta = nextflow.script.ScriptMeta.current() + def existing = scriptMeta.getProcessNames().findAll{it.startsWith(procKeyPrefix)} + def numbers = existing.collect{it.replace(procKeyPrefix, "0").toInteger()} + def newNumber = (numbers + [-1]).max() + 1 + + def procKey = newNumber == 0 ? procKeyPrefix : "$procKeyPrefix$newNumber" + + if (newNumber > 0) { + log.warn "Key for module '${wfKey}' is duplicated.\n", + "If you run a component multiple times in the same workflow,\n" + + "it's recommended you set a unique key for every call,\n" + + "for example: ${wfKey}.run(key: \"foo\")." + } + + // subset directives and convert to list of tuples + def drctv = workflowArgs.directives + + // TODO: unit test the two commands below + // convert publish array into tags + def valueToStr = { val -> + // ignore closures + if (val instanceof CharSequence) { + if (!val.matches('^[{].*[}]$')) { + '"' + val + '"' + } else { + val + } + } else if (val instanceof List) { + "[" + val.collect{valueToStr(it)}.join(", ") + "]" + } else if (val instanceof Map) { + "[" + val.collect{k, v -> k + ": " + valueToStr(v)}.join(", ") + "]" + } else { + val.inspect() + } + } + + // multiple entries allowed: label, publishdir + def drctvStrs = drctv.collect { key, value -> + if (key in ["label", "publishDir"]) { + value.collect{ val -> + if (val instanceof Map) { + "\n$key " + val.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else if (val == null) { + "" + } else { + "\n$key " + valueToStr(val) + } + }.join() + } else if (value instanceof Map) { + "\n$key " + value.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else { + "\n$key " + valueToStr(value) + } + }.join() + + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { ', path(viash_par_' + it.plainName + ', stageAs: "_viash_par/' + it.plainName + '_?/*")' } + .join() + + def outputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + // insert dummy into every output (see nextflow-io/nextflow#2678) + if (!par.multiple) { + ', path{[".exitcode", args.' + par.plainName + ']}' + } else { + ', path{[".exitcode"] + args.' + par.plainName + '}' + } + } + .join() + + // TODO: move this functionality somewhere else? + if (workflowArgs.auto.transcript) { + outputPaths = outputPaths + ', path{[".exitcode", ".command*"]}' + } else { + outputPaths = outputPaths + ', path{[".exitcode"]}' + } + + // create dirs for output files (based on BashWrapper.createParentFiles) + def createParentStr = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" && it.create_parent } + .collect { par -> + def contents = "args[\"${par.plainName}\"] instanceof List ? args[\"${par.plainName}\"].join('\" \"') : args[\"${par.plainName}\"]" + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent '\" + escapeText(${contents}) + \"'\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def contents = "viash_par_${par.plainName} instanceof List ? viash_par_${par.plainName}.join(\"${par.multiple_sep}\") : viash_par_${par.plainName}" + "\n\${viash_par_${par.plainName}.empty ? \"\" : \"export VIASH_PAR_${par.plainName.toUpperCase()}='\" + escapeText(${contents}) + \"'\"}" + } + + // NOTE: if using docker, use /tmp instead of tmpDir! + def tmpDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('VIASH_TMPDIR') ?: + System.getenv('VIASH_TEMPDIR') ?: + System.getenv('VIASH_TMP') ?: + System.getenv('TEMP') ?: + System.getenv('TMPDIR') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMP') ?: + '/tmp' + ).toAbsolutePath() + + // construct stub + def stub = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + "\${ args.containsKey(\"${par.plainName}\") ? \"touch2 \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"].replace(\"_*\", \"_0\") : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // escape script + def escapedScript = rawScript.replace('\\', '\\\\').replace('$', '\\$').replace('"""', '\\"\\"\\"') + + // publishdir assert + def assertStr = (workflowArgs.auto.publish == true) || workflowArgs.auto.transcript ? + """\nassert task.publishDir.size() > 0: "if auto.publish is true, params.publish_dir needs to be defined.\\n Example: --publish_dir './output/'" """ : + "" + + // generate process string + def procStr = + """nextflow.enable.dsl=2 + | + |def escapeText = { s -> s.toString().replaceAll("'", "'\\\"'\\\"'") } + |process $procKey {$drctvStrs + |input: + | tuple val(id)$inputPaths, val(args), path(resourcesDir, stageAs: ".viash_meta_resources") + |output: + | tuple val("\$id")$outputPaths, optional: true + |stub: + |\"\"\" + |touch2() { mkdir -p "\\\$(dirname "\\\$1")" && touch "\\\$1" ; } + |$stub + |\"\"\" + |script:$assertStr + |def parInject = args + | .findAll{key, value -> value != null} + | .collect{key, value -> "export VIASH_PAR_\${key.toUpperCase()}='\${escapeText(value)}'"} + | .join("\\n") + |\"\"\" + |# meta exports + |export VIASH_META_RESOURCES_DIR="\${resourcesDir}" + |export VIASH_META_TEMP_DIR="${['docker', 'podman', 'charliecloud'].any{ it == workflow.containerEngine } ? '/tmp' : tmpDir}" + |export VIASH_META_NAME="${meta.config.name}" + |# export VIASH_META_EXECUTABLE="\\\$VIASH_META_RESOURCES_DIR/\\\$VIASH_META_NAME" + |export VIASH_META_CONFIG="\\\$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" + |\${task.cpus ? "export VIASH_META_CPUS=\$task.cpus" : "" } + |\${task.memory?.bytes != null ? "export VIASH_META_MEMORY_B=\$task.memory.bytes" : "" } + |if [ ! -z \\\${VIASH_META_MEMORY_B+x} ]; then + | export VIASH_META_MEMORY_KB=\\\$(( (\\\$VIASH_META_MEMORY_B+999) / 1000 )) + | export VIASH_META_MEMORY_MB=\\\$(( (\\\$VIASH_META_MEMORY_KB+999) / 1000 )) + | export VIASH_META_MEMORY_GB=\\\$(( (\\\$VIASH_META_MEMORY_MB+999) / 1000 )) + | export VIASH_META_MEMORY_TB=\\\$(( (\\\$VIASH_META_MEMORY_GB+999) / 1000 )) + | export VIASH_META_MEMORY_PB=\\\$(( (\\\$VIASH_META_MEMORY_TB+999) / 1000 )) + | export VIASH_META_MEMORY_KIB=\\\$(( (\\\$VIASH_META_MEMORY_B+1023) / 1024 )) + | export VIASH_META_MEMORY_MIB=\\\$(( (\\\$VIASH_META_MEMORY_KIB+1023) / 1024 )) + | export VIASH_META_MEMORY_GIB=\\\$(( (\\\$VIASH_META_MEMORY_MIB+1023) / 1024 )) + | export VIASH_META_MEMORY_TIB=\\\$(( (\\\$VIASH_META_MEMORY_GIB+1023) / 1024 )) + | export VIASH_META_MEMORY_PIB=\\\$(( (\\\$VIASH_META_MEMORY_TIB+1023) / 1024 )) + |fi + | + |# meta synonyms + |export VIASH_TEMP="\\\$VIASH_META_TEMP_DIR" + |export TEMP_DIR="\\\$VIASH_META_TEMP_DIR" + | + |# create output dirs if need be + |function mkdir_parent { + | for file in "\\\$@"; do + | mkdir -p "\\\$(dirname "\\\$file")" + | done + |} + |$createParentStr + | + |# argument exports${inputFileExports.join()} + |\$parInject + | + |# process script + |${escapedScript} + |\"\"\" + |} + |""".stripMargin() + + // TODO: print on debug + // if (workflowArgs.debug == true) { + // println("######################\n$procStr\n######################") + // } + + // write process to temp file + def tempFile = java.nio.file.Files.createTempFile("viash-process-${procKey}-", ".nf") + addShutdownHook { java.nio.file.Files.deleteIfExists(tempFile) } + tempFile.text = procStr + + // create process from temp file + def binding = new nextflow.script.ScriptBinding([:]) + def session = nextflow.Nextflow.getSession() + def parser = new nextflow.script.ScriptParser(session) + .setModule(true) + .setBinding(binding) + def moduleScript = parser.runScript(tempFile) + .getScript() + + // register module in meta + def module = new nextflow.script.IncludeDef.Module(name: procKey) + scriptMeta.addModule(moduleScript, module.name, module.alias) + + // retrieve and return process from meta + return scriptMeta.getProcess(procKey) +} + +// defaults +meta["defaults"] = [ + // key to be used to trace the process and determine output names + key: null, + + // fixed arguments to be passed to script + args: [:], + + // default directives + directives: readJsonBlob('''{ + "container" : { + "registry" : "images.viash-hub.com", + "image" : "vsh/biobox/bedtools/bedtools_bamtobed", + "tag" : "main" + }, + "tag" : "$id" +}'''), + + // auto settings + auto: readJsonBlob('''{ + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false +}'''), + + // Apply a map over the incoming tuple + // Example: `{ tup -> [ tup[0], [input: tup[1].output] ] + tup.drop(2) }` + map: null, + + // Apply a map over the ID element of a tuple (i.e. the first element) + // Example: `{ id -> id + "_foo" }` + mapId: null, + + // Apply a map over the data element of a tuple (i.e. the second element) + // Example: `{ data -> [ input: data.output ] }` + mapData: null, + + // Apply a map over the passthrough elements of a tuple (i.e. the tuple excl. the first two elements) + // Example: `{ pt -> pt.drop(1) }` + mapPassthrough: null, + + // Filter the channel + // Example: `{ tup -> tup[0] == "foo" }` + filter: null, + + // Choose whether or not to run the component on the tuple if the condition is true. + // Otherwise, the tuple will be passed through. + // Example: `{ tup -> tup[0] != "skip_this" }` + runIf: null, + + // Rename keys in the data field of the tuple (i.e. the second element) + // Will likely be deprecated in favour of `fromState`. + // Example: `[ "new_key": "old_key" ]` + renameKeys: null, + + // Fetch data from the state and pass it to the module without altering the current state. + // + // `fromState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be passed to the module as is. + // - If it is a `List[String]`, the data will be the values of the state at the given keys. + // - If it is a `Map[String, String]`, the data will be the values of the state at the given keys, with the keys renamed according to the map. + // - If it is a function, the tuple (`[id, state]`) in the channel will be passed to the function, and the result will be used as the data. + // + // Example: `{ id, state -> [input: state.fastq_file] }` + // Default: `null` + fromState: null, + + // Determine how the state should be updated after the module has been run. + // + // `toState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be replaced with the output of the module. + // - If it is a `List[String]`, the state will be updated with the values of the data at the given keys. + // - If it is a `Map[String, String]`, the state will be updated with the values of the data at the given keys, with the keys renamed according to the map. + // - If it is a function, a tuple (`[id, output, state]`) will be passed to the function, and the result will be used as the new state. + // + // Example: `{ id, output, state -> state + [counts: state.output] }` + // Default: `{ id, output, state -> output }` + toState: null, + + // Whether or not to print debug messages + // Default: `false` + debug: false +] + +// initialise default workflow +meta["workflow"] = workflowFactory([key: meta.config.name], meta.defaults, meta) + +// add workflow to environment +nextflow.script.ScriptMeta.current().addDefinition(meta.workflow) + +// anonymous workflow for running this module as a standalone +workflow { + // add id argument if it's not already in the config + // TODO: deep copy + def newConfig = deepClone(meta.config) + def newParams = deepClone(params) + + def argsContainsId = newConfig.allArguments.any{it.plainName == "id"} + if (!argsContainsId) { + def idArg = [ + 'name': '--id', + 'required': false, + 'type': 'string', + 'description': 'A unique id for every entry.', + 'multiple': false + ] + newConfig.arguments.add(0, idArg) + newConfig = processConfig(newConfig) + } + if (!newParams.containsKey("id")) { + newParams.id = "run" + } + + helpMessage(newConfig) + + channelFromParams(newParams, newConfig) + // make sure id is not in the state if id is not in the args + | map {id, state -> + if (!argsContainsId) { + [id, state.findAll{k, v -> k != "id"}] + } else { + [id, state] + } + } + | meta.workflow.run( + auto: [ publish: "state" ] + ) +} + +// END COMPONENT-SPECIFIC CODE diff --git a/target/nextflow/bedtools/bedtools_bamtobed/nextflow.config b/target/nextflow/bedtools/bedtools_bamtobed/nextflow.config new file mode 100644 index 00000000..131c419d --- /dev/null +++ b/target/nextflow/bedtools/bedtools_bamtobed/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'bedtools/bedtools_bamtobed' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'main' + description = 'Converts BAM alignments to BED6 or BEDPE format.' + author = 'Theodoro Gasperin Terra Camargo' +} + +process.container = 'nextflow/bash:latest' + +// detect tempdir +tempDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMPDIR') ?: + '/tmp' +).toAbsolutePath() + +profiles { + no_publish { + process { + withName: '.*' { + publishDir = [ + enabled: false + ] + } + } + } + mount_temp { + docker.temp = tempDir + podman.temp = tempDir + charliecloud.temp = tempDir + } + docker { + docker.enabled = true + // docker.userEmulation = true + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + singularity { + singularity.enabled = true + singularity.autoMounts = true + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + podman { + podman.enabled = true + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + shifter { + shifter.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + } + charliecloud { + charliecloud.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + } +} + +process{ + withLabel: mem1gb { memory = 1000000000.B } + withLabel: mem2gb { memory = 2000000000.B } + withLabel: mem5gb { memory = 5000000000.B } + withLabel: mem10gb { memory = 10000000000.B } + withLabel: mem20gb { memory = 20000000000.B } + withLabel: mem50gb { memory = 50000000000.B } + withLabel: mem100gb { memory = 100000000000.B } + withLabel: mem200gb { memory = 200000000000.B } + withLabel: mem500gb { memory = 500000000000.B } + withLabel: mem1tb { memory = 1000000000000.B } + withLabel: mem2tb { memory = 2000000000000.B } + withLabel: mem5tb { memory = 5000000000000.B } + withLabel: mem10tb { memory = 10000000000000.B } + withLabel: mem20tb { memory = 20000000000000.B } + withLabel: mem50tb { memory = 50000000000000.B } + withLabel: mem100tb { memory = 100000000000000.B } + withLabel: mem200tb { memory = 200000000000000.B } + withLabel: mem500tb { memory = 500000000000000.B } + withLabel: mem1gib { memory = 1073741824.B } + withLabel: mem2gib { memory = 2147483648.B } + withLabel: mem4gib { memory = 4294967296.B } + withLabel: mem8gib { memory = 8589934592.B } + withLabel: mem16gib { memory = 17179869184.B } + withLabel: mem32gib { memory = 34359738368.B } + withLabel: mem64gib { memory = 68719476736.B } + withLabel: mem128gib { memory = 137438953472.B } + withLabel: mem256gib { memory = 274877906944.B } + withLabel: mem512gib { memory = 549755813888.B } + withLabel: mem1tib { memory = 1099511627776.B } + withLabel: mem2tib { memory = 2199023255552.B } + withLabel: mem4tib { memory = 4398046511104.B } + withLabel: mem8tib { memory = 8796093022208.B } + withLabel: mem16tib { memory = 17592186044416.B } + withLabel: mem32tib { memory = 35184372088832.B } + withLabel: mem64tib { memory = 70368744177664.B } + withLabel: mem128tib { memory = 140737488355328.B } + withLabel: mem256tib { memory = 281474976710656.B } + withLabel: mem512tib { memory = 562949953421312.B } + withLabel: cpu1 { cpus = 1 } + withLabel: cpu2 { cpus = 2 } + withLabel: cpu5 { cpus = 5 } + withLabel: cpu10 { cpus = 10 } + withLabel: cpu20 { cpus = 20 } + withLabel: cpu50 { cpus = 50 } + withLabel: cpu100 { cpus = 100 } + withLabel: cpu200 { cpus = 200 } + withLabel: cpu500 { cpus = 500 } + withLabel: cpu1000 { cpus = 1000 } +} + + diff --git a/target/nextflow/bedtools/bedtools_bamtobed/nextflow_schema.json b/target/nextflow/bedtools/bedtools_bamtobed/nextflow_schema.json new file mode 100644 index 00000000..733d2a87 --- /dev/null +++ b/target/nextflow/bedtools/bedtools_bamtobed/nextflow_schema.json @@ -0,0 +1,206 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "bedtools_bamtobed", +"description": "Converts BAM alignments to BED6 or BEDPE format.", +"type": "object", +"definitions": { + + + + "inputs" : { + "title": "Inputs", + "type": "object", + "description": "No description", + "properties": { + + + "input": { + "type": + "string", + "description": "Type: `file`, required. Input BAM file", + "help_text": "Type: `file`, required. Input BAM file." + + } + + +} +}, + + + "outputs" : { + "title": "Outputs", + "type": "object", + "description": "No description", + "properties": { + + + "output": { + "type": + "string", + "description": "Type: `file`, required, default: `$id.$key.output.output`. Output BED file", + "help_text": "Type: `file`, required, default: `$id.$key.output.output`. Output BED file." + , + "default": "$id.$key.output.output" + } + + +} +}, + + + "options" : { + "title": "Options", + "type": "object", + "description": "No description", + "properties": { + + + "bedpe": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Write BEDPE format", + "help_text": "Type: `boolean_true`, default: `false`. Write BEDPE format. Requires BAM to be grouped or sorted by query.\n" + , + "default": "False" + } + + + , + "mate1": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. When writing BEDPE (-bedpe) format, always report mate one as the first BEDPE \"block\"", + "help_text": "Type: `boolean_true`, default: `false`. When writing BEDPE (-bedpe) format, always report mate one as the first BEDPE \"block\".\n" + , + "default": "False" + } + + + , + "bed12": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Write \"blocked\" BED format (aka \"BED12\")", + "help_text": "Type: `boolean_true`, default: `false`. Write \"blocked\" BED format (aka \"BED12\"). Forces -split.\nSee http://genome-test.cse.ucsc.edu/FAQ/FAQformat#format1\n" + , + "default": "False" + } + + + , + "split": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Report \"split\" BAM alignments as separate BED entries", + "help_text": "Type: `boolean_true`, default: `false`. Report \"split\" BAM alignments as separate BED entries.\nSplits only on N CIGAR operations.\n" + , + "default": "False" + } + + + , + "splitD": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Split alignments based on N and D CIGAR operators", + "help_text": "Type: `boolean_true`, default: `false`. Split alignments based on N and D CIGAR operators.\nForces -split.\n" + , + "default": "False" + } + + + , + "edit_distance": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Use BAM edit distance (NM tag) for BED score", + "help_text": "Type: `boolean_true`, default: `false`. Use BAM edit distance (NM tag) for BED score.\n- Default for BED is to use mapping quality.\n- Default for BEDPE is to use the minimum of\n the two mapping qualities for the pair.\n- When -ed is used with -bedpe, the total edit\n distance from the two mates is reported.\n" + , + "default": "False" + } + + + , + "tag": { + "type": + "string", + "description": "Type: `string`, example: `SM`. Use other NUMERIC BAM alignment tag for BED score", + "help_text": "Type: `string`, example: `SM`. Use other NUMERIC BAM alignment tag for BED score.\nDefault for BED is to use mapping quality. Disallowed with BEDPE output.\n" + + } + + + , + "color": { + "type": + "string", + "description": "Type: `string`, example: `250,250,250`. An R,G,B string for the color used with BED12 format", + "help_text": "Type: `string`, example: `250,250,250`. An R,G,B string for the color used with BED12 format.\nDefault is (255,0,0).\n" + + } + + + , + "cigar": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Add the CIGAR string to the BED entry as a 7th column", + "help_text": "Type: `boolean_true`, default: `false`. Add the CIGAR string to the BED entry as a 7th column.\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/inputs" + }, + + { + "$ref": "#/definitions/outputs" + }, + + { + "$ref": "#/definitions/options" + }, + + { + "$ref": "#/definitions/nextflow input-output arguments" + } +] +} diff --git a/target/nextflow/bedtools/bedtools_bamtofastq/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_bamtofastq/.config.vsh.yaml index 8009a09a..5ed71e60 100644 --- a/target/nextflow/bedtools/bedtools_bamtofastq/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_bamtofastq/.config.vsh.yaml @@ -187,9 +187,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_bamtofastq" executable: "target/nextflow/bedtools/bedtools_bamtofastq/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_bamtofastq/main.nf b/target/nextflow/bedtools/bedtools_bamtofastq/main.nf index 9ac5aa0f..d80a14a7 100644 --- a/target/nextflow/bedtools/bedtools_bamtofastq/main.nf +++ b/target/nextflow/bedtools/bedtools_bamtofastq/main.nf @@ -3050,9 +3050,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_bamtofastq", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_bed12tobed6/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_bed12tobed6/.config.vsh.yaml index b30c7594..52354569 100644 --- a/target/nextflow/bedtools/bedtools_bed12tobed6/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_bed12tobed6/.config.vsh.yaml @@ -176,9 +176,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_bed12tobed6" executable: "target/nextflow/bedtools/bedtools_bed12tobed6/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_bed12tobed6/main.nf b/target/nextflow/bedtools/bedtools_bed12tobed6/main.nf index 49e51345..262d9a20 100644 --- a/target/nextflow/bedtools/bedtools_bed12tobed6/main.nf +++ b/target/nextflow/bedtools/bedtools_bed12tobed6/main.nf @@ -3035,9 +3035,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_bed12tobed6", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_bedtobam/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_bedtobam/.config.vsh.yaml index ccc69bcf..f68171c0 100644 --- a/target/nextflow/bedtools/bedtools_bedtobam/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_bedtobam/.config.vsh.yaml @@ -214,9 +214,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_bedtobam" executable: "target/nextflow/bedtools/bedtools_bedtobam/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_bedtobam/main.nf b/target/nextflow/bedtools/bedtools_bedtobam/main.nf index b3cbde2a..0c09d6f4 100644 --- a/target/nextflow/bedtools/bedtools_bedtobam/main.nf +++ b/target/nextflow/bedtools/bedtools_bedtobam/main.nf @@ -3083,9 +3083,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_bedtobam", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_genomecov/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_genomecov/.config.vsh.yaml index b679691b..bfb05453 100644 --- a/target/nextflow/bedtools/bedtools_genomecov/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_genomecov/.config.vsh.yaml @@ -337,9 +337,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_genomecov" executable: "target/nextflow/bedtools/bedtools_genomecov/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_genomecov/main.nf b/target/nextflow/bedtools/bedtools_genomecov/main.nf index 2d0cde48..29d326ab 100644 --- a/target/nextflow/bedtools/bedtools_genomecov/main.nf +++ b/target/nextflow/bedtools/bedtools_genomecov/main.nf @@ -3207,9 +3207,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_genomecov", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_getfasta/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_getfasta/.config.vsh.yaml index f731a00d..1c02380e 100644 --- a/target/nextflow/bedtools/bedtools_getfasta/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_getfasta/.config.vsh.yaml @@ -232,9 +232,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_getfasta" executable: "target/nextflow/bedtools/bedtools_getfasta/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_getfasta/main.nf b/target/nextflow/bedtools/bedtools_getfasta/main.nf index aefb0d81..208d7946 100644 --- a/target/nextflow/bedtools/bedtools_getfasta/main.nf +++ b/target/nextflow/bedtools/bedtools_getfasta/main.nf @@ -3086,9 +3086,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_getfasta", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_groupby/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_groupby/.config.vsh.yaml index 6053c58f..20bd4b1a 100644 --- a/target/nextflow/bedtools/bedtools_groupby/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_groupby/.config.vsh.yaml @@ -273,9 +273,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_groupby" executable: "target/nextflow/bedtools/bedtools_groupby/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_groupby/main.nf b/target/nextflow/bedtools/bedtools_groupby/main.nf index 878095c9..831b59f3 100644 --- a/target/nextflow/bedtools/bedtools_groupby/main.nf +++ b/target/nextflow/bedtools/bedtools_groupby/main.nf @@ -3130,9 +3130,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_groupby", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_intersect/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_intersect/.config.vsh.yaml index aef995b5..9cd8ee94 100644 --- a/target/nextflow/bedtools/bedtools_intersect/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_intersect/.config.vsh.yaml @@ -410,9 +410,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_intersect" executable: "target/nextflow/bedtools/bedtools_intersect/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_intersect/main.nf b/target/nextflow/bedtools/bedtools_intersect/main.nf index c1b69759..c61c7ffc 100644 --- a/target/nextflow/bedtools/bedtools_intersect/main.nf +++ b/target/nextflow/bedtools/bedtools_intersect/main.nf @@ -3282,9 +3282,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_intersect", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_links/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_links/.config.vsh.yaml index 17095134..8b9d53bc 100644 --- a/target/nextflow/bedtools/bedtools_links/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_links/.config.vsh.yaml @@ -210,9 +210,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_links" executable: "target/nextflow/bedtools/bedtools_links/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_links/main.nf b/target/nextflow/bedtools/bedtools_links/main.nf index 68a7efbe..ae289cb9 100644 --- a/target/nextflow/bedtools/bedtools_links/main.nf +++ b/target/nextflow/bedtools/bedtools_links/main.nf @@ -3073,9 +3073,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_links", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_merge/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_merge/.config.vsh.yaml index f31081cc..8a8233b7 100644 --- a/target/nextflow/bedtools/bedtools_merge/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_merge/.config.vsh.yaml @@ -279,9 +279,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_merge" executable: "target/nextflow/bedtools/bedtools_merge/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_merge/main.nf b/target/nextflow/bedtools/bedtools_merge/main.nf index d932a4ad..b7ff7c5d 100644 --- a/target/nextflow/bedtools/bedtools_merge/main.nf +++ b/target/nextflow/bedtools/bedtools_merge/main.nf @@ -3134,9 +3134,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_merge", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_sort/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_sort/.config.vsh.yaml index e5a05df5..953b28d9 100644 --- a/target/nextflow/bedtools/bedtools_sort/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_sort/.config.vsh.yaml @@ -222,9 +222,9 @@ build_info: output: "target/nextflow/bedtools/bedtools_sort" executable: "target/nextflow/bedtools/bedtools_sort/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/bedtools/bedtools_sort/main.nf b/target/nextflow/bedtools/bedtools_sort/main.nf index c0d09a63..b76a0121 100644 --- a/target/nextflow/bedtools/bedtools_sort/main.nf +++ b/target/nextflow/bedtools/bedtools_sort/main.nf @@ -3092,9 +3092,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_sort", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/busco/busco_download_datasets/.config.vsh.yaml b/target/nextflow/busco/busco_download_datasets/.config.vsh.yaml index f5095890..643a6832 100644 --- a/target/nextflow/busco/busco_download_datasets/.config.vsh.yaml +++ b/target/nextflow/busco/busco_download_datasets/.config.vsh.yaml @@ -158,9 +158,9 @@ build_info: output: "target/nextflow/busco/busco_download_datasets" executable: "target/nextflow/busco/busco_download_datasets/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/busco/busco_download_datasets/main.nf b/target/nextflow/busco/busco_download_datasets/main.nf index 75ddb55e..4c195aff 100644 --- a/target/nextflow/busco/busco_download_datasets/main.nf +++ b/target/nextflow/busco/busco_download_datasets/main.nf @@ -3011,9 +3011,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/busco/busco_download_datasets", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/busco/busco_list_datasets/.config.vsh.yaml b/target/nextflow/busco/busco_list_datasets/.config.vsh.yaml index 3185c80f..e7679ac8 100644 --- a/target/nextflow/busco/busco_list_datasets/.config.vsh.yaml +++ b/target/nextflow/busco/busco_list_datasets/.config.vsh.yaml @@ -145,9 +145,9 @@ build_info: output: "target/nextflow/busco/busco_list_datasets" executable: "target/nextflow/busco/busco_list_datasets/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/busco/busco_list_datasets/main.nf b/target/nextflow/busco/busco_list_datasets/main.nf index 95bf98d7..d1ca78ba 100644 --- a/target/nextflow/busco/busco_list_datasets/main.nf +++ b/target/nextflow/busco/busco_list_datasets/main.nf @@ -2997,9 +2997,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/busco/busco_list_datasets", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/busco/busco_run/.config.vsh.yaml b/target/nextflow/busco/busco_run/.config.vsh.yaml index e81730a1..a993e3dd 100644 --- a/target/nextflow/busco/busco_run/.config.vsh.yaml +++ b/target/nextflow/busco/busco_run/.config.vsh.yaml @@ -423,9 +423,9 @@ build_info: output: "target/nextflow/busco/busco_run" executable: "target/nextflow/busco/busco_run/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/busco/busco_run/main.nf b/target/nextflow/busco/busco_run/main.nf index 661b5db2..9d3f16ef 100644 --- a/target/nextflow/busco/busco_run/main.nf +++ b/target/nextflow/busco/busco_run/main.nf @@ -3309,9 +3309,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/busco/busco_run", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/cutadapt/.config.vsh.yaml b/target/nextflow/cutadapt/.config.vsh.yaml index e181fac7..483469af 100644 --- a/target/nextflow/cutadapt/.config.vsh.yaml +++ b/target/nextflow/cutadapt/.config.vsh.yaml @@ -740,9 +740,9 @@ build_info: output: "target/nextflow/cutadapt" executable: "target/nextflow/cutadapt/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/cutadapt/main.nf b/target/nextflow/cutadapt/main.nf index efaaba94..b1f71137 100644 --- a/target/nextflow/cutadapt/main.nf +++ b/target/nextflow/cutadapt/main.nf @@ -3619,9 +3619,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/cutadapt", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/falco/.config.vsh.yaml b/target/nextflow/falco/.config.vsh.yaml index 0cc13a8e..9e5b0a45 100644 --- a/target/nextflow/falco/.config.vsh.yaml +++ b/target/nextflow/falco/.config.vsh.yaml @@ -317,9 +317,9 @@ build_info: output: "target/nextflow/falco" executable: "target/nextflow/falco/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/falco/main.nf b/target/nextflow/falco/main.nf index 3cecbdde..7726536e 100644 --- a/target/nextflow/falco/main.nf +++ b/target/nextflow/falco/main.nf @@ -3170,9 +3170,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/falco", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/fastp/.config.vsh.yaml b/target/nextflow/fastp/.config.vsh.yaml index 6186d865..ff74fb20 100644 --- a/target/nextflow/fastp/.config.vsh.yaml +++ b/target/nextflow/fastp/.config.vsh.yaml @@ -1083,9 +1083,9 @@ build_info: output: "target/nextflow/fastp" executable: "target/nextflow/fastp/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/fastp/main.nf b/target/nextflow/fastp/main.nf index 2cab6a6f..4e53f73c 100644 --- a/target/nextflow/fastp/main.nf +++ b/target/nextflow/fastp/main.nf @@ -4023,9 +4023,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/fastp", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/fastqc/.config.vsh.yaml b/target/nextflow/fastqc/.config.vsh.yaml index 2e7105e0..e452520f 100644 --- a/target/nextflow/fastqc/.config.vsh.yaml +++ b/target/nextflow/fastqc/.config.vsh.yaml @@ -340,9 +340,9 @@ build_info: output: "target/nextflow/fastqc" executable: "target/nextflow/fastqc/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/fastqc/main.nf b/target/nextflow/fastqc/main.nf index 40db44fb..db3d6e05 100644 --- a/target/nextflow/fastqc/main.nf +++ b/target/nextflow/fastqc/main.nf @@ -3182,9 +3182,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/fastqc", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/featurecounts/.config.vsh.yaml b/target/nextflow/featurecounts/.config.vsh.yaml index 92f0b820..1a78e19f 100644 --- a/target/nextflow/featurecounts/.config.vsh.yaml +++ b/target/nextflow/featurecounts/.config.vsh.yaml @@ -645,9 +645,9 @@ build_info: output: "target/nextflow/featurecounts" executable: "target/nextflow/featurecounts/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/featurecounts/main.nf b/target/nextflow/featurecounts/main.nf index 70b8fd3d..96d1548d 100644 --- a/target/nextflow/featurecounts/main.nf +++ b/target/nextflow/featurecounts/main.nf @@ -3549,9 +3549,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/featurecounts", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/fq_subsample/.config.vsh.yaml b/target/nextflow/fq_subsample/.config.vsh.yaml index 93310c6f..4e800eb6 100644 --- a/target/nextflow/fq_subsample/.config.vsh.yaml +++ b/target/nextflow/fq_subsample/.config.vsh.yaml @@ -190,9 +190,9 @@ build_info: output: "target/nextflow/fq_subsample" executable: "target/nextflow/fq_subsample/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/fq_subsample/main.nf b/target/nextflow/fq_subsample/main.nf index b263b064..b98d7bb4 100644 --- a/target/nextflow/fq_subsample/main.nf +++ b/target/nextflow/fq_subsample/main.nf @@ -3032,9 +3032,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/fq_subsample", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/gffread/.config.vsh.yaml b/target/nextflow/gffread/.config.vsh.yaml index 53e8a38c..b1940e11 100644 --- a/target/nextflow/gffread/.config.vsh.yaml +++ b/target/nextflow/gffread/.config.vsh.yaml @@ -685,9 +685,9 @@ build_info: output: "target/nextflow/gffread" executable: "target/nextflow/gffread/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/gffread/main.nf b/target/nextflow/gffread/main.nf index 2c814c0f..6006a931 100644 --- a/target/nextflow/gffread/main.nf +++ b/target/nextflow/gffread/main.nf @@ -3606,9 +3606,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/gffread", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/kallisto/kallisto_index/.config.vsh.yaml b/target/nextflow/kallisto/kallisto_index/.config.vsh.yaml index e376deb9..cab2c353 100644 --- a/target/nextflow/kallisto/kallisto_index/.config.vsh.yaml +++ b/target/nextflow/kallisto/kallisto_index/.config.vsh.yaml @@ -218,9 +218,9 @@ build_info: output: "target/nextflow/kallisto/kallisto_index" executable: "target/nextflow/kallisto/kallisto_index/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/kallisto/kallisto_index/main.nf b/target/nextflow/kallisto/kallisto_index/main.nf index 7b9e3c35..402fe9b8 100644 --- a/target/nextflow/kallisto/kallisto_index/main.nf +++ b/target/nextflow/kallisto/kallisto_index/main.nf @@ -3071,9 +3071,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/kallisto/kallisto_index", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/kallisto/kallisto_quant/.config.vsh.yaml b/target/nextflow/kallisto/kallisto_quant/.config.vsh.yaml index e0a3ec9e..643a4ced 100644 --- a/target/nextflow/kallisto/kallisto_quant/.config.vsh.yaml +++ b/target/nextflow/kallisto/kallisto_quant/.config.vsh.yaml @@ -234,9 +234,9 @@ build_info: output: "target/nextflow/kallisto/kallisto_quant" executable: "target/nextflow/kallisto/kallisto_quant/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/kallisto/kallisto_quant/main.nf b/target/nextflow/kallisto/kallisto_quant/main.nf index 7f859e2a..6f55f1e8 100644 --- a/target/nextflow/kallisto/kallisto_quant/main.nf +++ b/target/nextflow/kallisto/kallisto_quant/main.nf @@ -3092,9 +3092,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/kallisto/kallisto_quant", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/lofreq/lofreq_call/.config.vsh.yaml b/target/nextflow/lofreq/lofreq_call/.config.vsh.yaml index 3421e6cb..dc1f0017 100644 --- a/target/nextflow/lofreq/lofreq_call/.config.vsh.yaml +++ b/target/nextflow/lofreq/lofreq_call/.config.vsh.yaml @@ -507,9 +507,9 @@ build_info: output: "target/nextflow/lofreq/lofreq_call" executable: "target/nextflow/lofreq/lofreq_call/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/lofreq/lofreq_call/main.nf b/target/nextflow/lofreq/lofreq_call/main.nf index a3cab2bd..5646710b 100644 --- a/target/nextflow/lofreq/lofreq_call/main.nf +++ b/target/nextflow/lofreq/lofreq_call/main.nf @@ -3414,9 +3414,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/lofreq/lofreq_call", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/lofreq/lofreq_indelqual/.config.vsh.yaml b/target/nextflow/lofreq/lofreq_indelqual/.config.vsh.yaml index 22be4f92..4d42f045 100644 --- a/target/nextflow/lofreq/lofreq_indelqual/.config.vsh.yaml +++ b/target/nextflow/lofreq/lofreq_indelqual/.config.vsh.yaml @@ -215,9 +215,9 @@ build_info: output: "target/nextflow/lofreq/lofreq_indelqual" executable: "target/nextflow/lofreq/lofreq_indelqual/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/lofreq/lofreq_indelqual/main.nf b/target/nextflow/lofreq/lofreq_indelqual/main.nf index f0c88079..56b19630 100644 --- a/target/nextflow/lofreq/lofreq_indelqual/main.nf +++ b/target/nextflow/lofreq/lofreq_indelqual/main.nf @@ -3077,9 +3077,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/lofreq/lofreq_indelqual", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/multiqc/.config.vsh.yaml b/target/nextflow/multiqc/.config.vsh.yaml index ff7a5d19..0cb194c9 100644 --- a/target/nextflow/multiqc/.config.vsh.yaml +++ b/target/nextflow/multiqc/.config.vsh.yaml @@ -456,9 +456,9 @@ build_info: output: "target/nextflow/multiqc" executable: "target/nextflow/multiqc/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/multiqc/main.nf b/target/nextflow/multiqc/main.nf index 2bb46281..bf304714 100644 --- a/target/nextflow/multiqc/main.nf +++ b/target/nextflow/multiqc/main.nf @@ -3366,9 +3366,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/multiqc", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/nanoplot/.config.vsh.yaml b/target/nextflow/nanoplot/.config.vsh.yaml index 3344e9e7..53b8ee23 100644 --- a/target/nextflow/nanoplot/.config.vsh.yaml +++ b/target/nextflow/nanoplot/.config.vsh.yaml @@ -492,9 +492,9 @@ build_info: output: "target/nextflow/nanoplot" executable: "target/nextflow/nanoplot/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/nanoplot/main.nf b/target/nextflow/nanoplot/main.nf index 1979783b..77ef76a0 100644 --- a/target/nextflow/nanoplot/main.nf +++ b/target/nextflow/nanoplot/main.nf @@ -3397,9 +3397,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/nanoplot", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/pear/.config.vsh.yaml b/target/nextflow/pear/.config.vsh.yaml index 4af49547..47d4eafd 100644 --- a/target/nextflow/pear/.config.vsh.yaml +++ b/target/nextflow/pear/.config.vsh.yaml @@ -398,9 +398,9 @@ build_info: output: "target/nextflow/pear" executable: "target/nextflow/pear/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/pear/main.nf b/target/nextflow/pear/main.nf index d59f5338..be34e640 100644 --- a/target/nextflow/pear/main.nf +++ b/target/nextflow/pear/main.nf @@ -3259,9 +3259,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/pear", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/qualimap/qualimap_rnaseq/.config.vsh.yaml b/target/nextflow/qualimap/qualimap_rnaseq/.config.vsh.yaml index 836cd753..c8416da8 100644 --- a/target/nextflow/qualimap/qualimap_rnaseq/.config.vsh.yaml +++ b/target/nextflow/qualimap/qualimap_rnaseq/.config.vsh.yaml @@ -264,9 +264,9 @@ build_info: output: "target/nextflow/qualimap/qualimap_rnaseq" executable: "target/nextflow/qualimap/qualimap_rnaseq/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/qualimap/qualimap_rnaseq/main.nf b/target/nextflow/qualimap/qualimap_rnaseq/main.nf index 0405ecde..502efc68 100644 --- a/target/nextflow/qualimap/qualimap_rnaseq/main.nf +++ b/target/nextflow/qualimap/qualimap_rnaseq/main.nf @@ -3129,9 +3129,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/qualimap/qualimap_rnaseq", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/rsem/rsem_calculate_expression/.config.vsh.yaml b/target/nextflow/rsem/rsem_calculate_expression/.config.vsh.yaml index 9f5dd35e..12804391 100644 --- a/target/nextflow/rsem/rsem_calculate_expression/.config.vsh.yaml +++ b/target/nextflow/rsem/rsem_calculate_expression/.config.vsh.yaml @@ -852,9 +852,9 @@ build_info: output: "target/nextflow/rsem/rsem_calculate_expression" executable: "target/nextflow/rsem/rsem_calculate_expression/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/rsem/rsem_calculate_expression/main.nf b/target/nextflow/rsem/rsem_calculate_expression/main.nf index 71dc940b..f4476aed 100644 --- a/target/nextflow/rsem/rsem_calculate_expression/main.nf +++ b/target/nextflow/rsem/rsem_calculate_expression/main.nf @@ -3661,9 +3661,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/rsem/rsem_calculate_expression", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/rsem/rsem_prepare_reference/.config.vsh.yaml b/target/nextflow/rsem/rsem_prepare_reference/.config.vsh.yaml index b5b8c58c..82a6bee2 100644 --- a/target/nextflow/rsem/rsem_prepare_reference/.config.vsh.yaml +++ b/target/nextflow/rsem/rsem_prepare_reference/.config.vsh.yaml @@ -416,9 +416,9 @@ build_info: output: "target/nextflow/rsem/rsem_prepare_reference" executable: "target/nextflow/rsem/rsem_prepare_reference/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/rsem/rsem_prepare_reference/main.nf b/target/nextflow/rsem/rsem_prepare_reference/main.nf index f395c2a9..3b34d47c 100644 --- a/target/nextflow/rsem/rsem_prepare_reference/main.nf +++ b/target/nextflow/rsem/rsem_prepare_reference/main.nf @@ -3245,9 +3245,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/rsem/rsem_prepare_reference", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/rseqc/rseqc_bamstat/.config.vsh.yaml b/target/nextflow/rseqc/rseqc_bamstat/.config.vsh.yaml new file mode 100644 index 00000000..25e87f31 --- /dev/null +++ b/target/nextflow/rseqc/rseqc_bamstat/.config.vsh.yaml @@ -0,0 +1,202 @@ +name: "rseqc_bamstat" +namespace: "rseqc" +version: "main" +authors: +- name: "Emma Rousseau" + roles: + - "author" + - "maintainer" + info: + links: + email: "emma@data-intuitive.com" + github: "emmarousseau" + linkedin: "emmarousseau1" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Bioinformatician" +argument_groups: +- name: "Input" + arguments: + - type: "file" + name: "--input_file" + alternatives: + - "-i" + description: "Input alignment file in BAM or SAM format." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--mapq" + alternatives: + - "-q" + description: "Minimum mapping quality (phred scaled) to determine uniquely mapped\ + \ reads. Default: '30'.\n" + info: null + example: + - 30 + required: false + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Output" + arguments: + - type: "file" + name: "--output" + description: "Output file (txt) with mapping quality statistics." + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Generate statistics from a bam file." +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "rnaseq" +- "genomics" +license: "GPL-3.0" +references: + doi: + - "10.1093/bioinformatics/bts356" +links: + repository: "https://github.com/MonashBioinformaticsPlatform/RSeQC" + homepage: "https://rseqc.sourceforge.net/" + documentation: "https://rseqc.sourceforge.net/#bam-stat-py" + issue_tracker: "https://github.com/MonashBioinformaticsPlatform/RSeQC/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "python:3.10" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "python" + user: false + packages: + - "RSeQC" + upgrade: true + - type: "docker" + run: + - "echo \"RSeQC bam_stat.py: $(bam_stat.py --version | cut -d' ' -f2-)\" > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/rseqc/rseqc_bamstat/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/rseqc/rseqc_bamstat" + executable: "target/nextflow/rseqc/rseqc_bamstat/main.nf" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/nextflow/rseqc/rseqc_bamstat/main.nf b/target/nextflow/rseqc/rseqc_bamstat/main.nf new file mode 100644 index 00000000..1e545087 --- /dev/null +++ b/target/nextflow/rseqc/rseqc_bamstat/main.nf @@ -0,0 +1,3594 @@ +// rseqc_bamstat main +// +// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +// Intuitive. +// +// The component may contain files which fall under a different license. The +// authors of this component should specify the license in the header of such +// files, or include a separate license file detailing the licenses of all included +// files. +// +// Component authors: +// * Emma Rousseau (author, maintainer) + +//////////////////////////// +// VDSL3 helper functions // +//////////////////////////// + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_checkArgumentType.nf' +class UnexpectedArgumentTypeException extends Exception { + String errorIdentifier + String stage + String plainName + String expectedClass + String foundClass + + // ${key ? " in module '$key'" : ""}${id ? " id '$id'" : ""} + UnexpectedArgumentTypeException(String errorIdentifier, String stage, String plainName, String expectedClass, String foundClass) { + super("Error${errorIdentifier ? " $errorIdentifier" : ""}:${stage ? " $stage" : "" } argument '${plainName}' has the wrong type. " + + "Expected type: ${expectedClass}. Found type: ${foundClass}") + this.errorIdentifier = errorIdentifier + this.stage = stage + this.plainName = plainName + this.expectedClass = expectedClass + this.foundClass = foundClass + } +} + +/** + * Checks if the given value is of the expected type. If not, an exception is thrown. + * + * @param stage The stage of the argument (input or output) + * @param par The parameter definition + * @param value The value to check + * @param errorIdentifier The identifier to use in the error message + * @return The value, if it is of the expected type + * @throws UnexpectedArgumentTypeException If the value is not of the expected type +*/ +def _checkArgumentType(String stage, Map par, Object value, String errorIdentifier) { + // expectedClass will only be != null if value is not of the expected type + def expectedClass = null + def foundClass = null + + // todo: split if need be + + if (!par.required && value == null) { + expectedClass = null + } else if (par.multiple) { + if (value !instanceof Collection) { + value = [value] + } + + // split strings + value = value.collectMany{ val -> + if (val instanceof String) { + // collect() to ensure that the result is a List and not simply an array + val.split(par.multiple_sep).collect() + } else { + [val] + } + } + + // process globs + if (par.type == "file" && par.direction == "input") { + value = value.collect{ it instanceof String ? file(it, hidden: true) : it }.flatten() + } + + // check types of elements in list + try { + value = value.collect { listVal -> + _checkArgumentType(stage, par + [multiple: false], listVal, errorIdentifier) + } + } catch (UnexpectedArgumentTypeException e) { + expectedClass = "List[${e.expectedClass}]" + foundClass = "List[${e.foundClass}]" + } + } else if (par.type == "string") { + // cast to string if need be + if (value instanceof GString) { + value = value.toString() + } + expectedClass = value instanceof String ? null : "String" + } else if (par.type == "integer") { + // cast to integer if need be + if (value instanceof String) { + try { + value = value.toInteger() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toLong() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toDouble() + } catch (NumberFormatException e) { + // do nothing + } + } + if (value instanceof java.math.BigDecimal) { + value = value.doubleValue() + } + 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 + } + } + 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) { + value = file(value, hidden: true) + } + if (value instanceof File) { + value = value.toPath() + } + 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() + } + expectedClass = value instanceof String ? null : "String" + } else { + // didn't find a match for par.type + expectedClass = par.type + } + + if (expectedClass != null) { + if (foundClass == null) { + foundClass = value.getClass().getName() + } + throw new UnexpectedArgumentTypeException(errorIdentifier, stage, par.plainName, expectedClass, foundClass) + } + + return value +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processInputValues.nf' +Map _processInputValues(Map inputs, Map config, String id, String key) { + if (!workflow.stubRun) { + config.allArguments.each { arg -> + if (arg.required) { + assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null : + "Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing" + } + } + + inputs = inputs.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid input argument" + + value = _checkArgumentType("input", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return inputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf' +Map _processOutputValues(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" + + value = _checkArgumentType("output", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return outputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf' +class IDChecker { + final def items = [] as Set + + @groovy.transform.WithWriteLock + boolean observe(String item) { + if (items.contains(item)) { + return false + } else { + items << item + return true + } + } + + @groovy.transform.WithReadLock + boolean contains(String item) { + return items.contains(item) + } + + @groovy.transform.WithReadLock + Set getItems() { + return items.clone() + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_checkUniqueIds.nf' + +/** + * Check if the ids are unique across parameter sets + * + * @param parameterSets a list of parameter sets. + */ +private void _checkUniqueIds(List>> parameterSets) { + def ppIds = parameterSets.collect{it[0]} + assert ppIds.size() == ppIds.unique().size() : "All argument sets should have unique ids. Detected ids: $ppIds" +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_getChild.nf' + +// helper functions for reading params from file // +def _getChild(parent, child) { + if (child.contains("://") || java.nio.file.Paths.get(child).isAbsolute()) { + child + } else { + def parentAbsolute = java.nio.file.Paths.get(parent).toAbsolutePath().toString() + parentAbsolute.replaceAll('/[^/]*$', "/") + child + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_parseParamList.nf' +/** + * Figure out the param list format based on the file extension + * + * @param param_list A String containing the path to the parameter list file. + * + * @return A String containing the format of the parameter list file. + */ +def _paramListGuessFormat(param_list) { + if (param_list !instanceof String) { + "asis" + } else if (param_list.endsWith(".csv")) { + "csv" + } else if (param_list.endsWith(".json") || param_list.endsWith(".jsn")) { + "json" + } else if (param_list.endsWith(".yaml") || param_list.endsWith(".yml")) { + "yaml" + } else { + "yaml_blob" + } +} + + +/** + * Read the param list + * + * @param param_list One of the following: + * - A String containing the path to the parameter list file (csv, json or yaml), + * - A yaml blob of a list of maps (yaml_blob), + * - Or a groovy list of maps (asis). + * @param config A Map of the Viash configuration. + * + * @return A List of Maps containing the parameters. + */ +def _parseParamList(param_list, Map config) { + // first determine format by extension + def paramListFormat = _paramListGuessFormat(param_list) + + def paramListPath = (paramListFormat != "asis" && paramListFormat != "yaml_blob") ? + file(param_list, hidden: true) : + null + + // get the correct parser function for the detected params_list format + def paramSets = [] + if (paramListFormat == "asis") { + paramSets = param_list + } else if (paramListFormat == "yaml_blob") { + paramSets = readYamlBlob(param_list) + } else if (paramListFormat == "yaml") { + paramSets = readYaml(paramListPath) + } else if (paramListFormat == "json") { + paramSets = readJson(paramListPath) + } else if (paramListFormat == "csv") { + paramSets = readCsv(paramListPath) + } else { + error "Format of provided --param_list not recognised.\n" + + "Found: '$paramListFormat'.\n" + + "Expected: a csv file, a json file, a yaml file,\n" + + "a yaml blob or a groovy list of maps." + } + + // data checks + assert paramSets instanceof List: "--param_list should contain a list of maps" + for (value in paramSets) { + assert value instanceof Map: "--param_list should contain a list of maps" + } + + // id is argument + def idIsArgument = config.allArguments.any{it.plainName == "id"} + + // Reformat from List to List> by adding the ID as first element of a Tuple2 + paramSets = paramSets.collect({ data -> + def id = data.id + if (!idIsArgument) { + data = data.findAll{k, v -> k != "id"} + } + [id, data] + }) + + // Split parameters with 'multiple: true' + paramSets = paramSets.collect({ id, data -> + data = _splitParams(data, config) + [id, data] + }) + + // The paths of input files inside a param_list file may have been specified relatively to the + // location of the param_list file. These paths must be made absolute. + if (paramListPath) { + paramSets = paramSets.collect({ id, data -> + def new_data = data.collectEntries{ parName, parValue -> + def par = config.allArguments.find{it.plainName == parName} + if (par && par.type == "file" && par.direction == "input") { + if (parValue instanceof Collection) { + parValue = parValue.collectMany{path -> + def x = _resolveSiblingIfNotAbsolute(path, paramListPath) + x instanceof Collection ? x : [x] + } + } else { + parValue = _resolveSiblingIfNotAbsolute(parValue, paramListPath) + } + } + [parName, parValue] + } + [id, new_data] + }) + } + + return paramSets +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_splitParams.nf' +/** + * Split parameters for arguments that accept multiple values using their separator + * + * @param paramList A Map containing parameters to split. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A Map of parameters where the parameter values have been split into a list using + * their seperator. + */ +Map _splitParams(Map parValues, Map config){ + def parsedParamValues = parValues.collectEntries { parName, parValue -> + def parameterSettings = config.allArguments.find({it.plainName == parName}) + + if (!parameterSettings) { + // if argument is not found, do not alter + return [parName, parValue] + } + if (parameterSettings.multiple) { // Check if parameter can accept multiple values + if (parValue instanceof Collection) { + parValue = parValue.collect{it instanceof String ? it.split(parameterSettings.multiple_sep) : it } + } else if (parValue instanceof String) { + parValue = parValue.split(parameterSettings.multiple_sep) + } else if (parValue == null) { + parValue = [] + } else { + parValue = [ parValue ] + } + parValue = parValue.flatten() + } + // For all parameters check if multiple values are only passed for + // arguments that allow it. Quietly simplify lists of length 1. + if (!parameterSettings.multiple && parValue instanceof Collection) { + assert parValue.size() == 1 : + "Error: argument ${parName} has too many values.\n" + + " Expected amount: 1. Found: ${parValue.size()}" + parValue = parValue[0] + } + [parName, parValue] + } + return parsedParamValues +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/channelFromParams.nf' +/** + * Parse nextflow parameters based on settings defined in a viash config. + * Return a list of parameter sets, each parameter set corresponding to + * an event in a nextflow channel. The output from this function can be used + * with Channel.fromList to create a nextflow channel with Vdsl3 formatted + * events. + * + * This function performs: + * - A filtering of the params which can be found in the config file. + * - Process the params_list argument which allows a user to to initialise + * a Vsdl3 channel with multiple parameter sets. Possible formats are + * csv, json, yaml, or simply a yaml_blob. A csv should have column names + * which correspond to the different arguments of this pipeline. A json or a yaml + * file should be a list of maps, each of which has keys corresponding to the + * arguments of the pipeline. A yaml blob can also be passed directly as a parameter. + * When passing a csv, json or yaml, relative path names are relativized to the + * location of the parameter file. + * - Combine the parameter sets into a vdsl3 Channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A list of parameters with the first element of the event being + * the event ID and the second element containing a map of the parsed parameters. + */ + +private List>> _paramsToParamSets(Map params, Map config){ + // todo: fetch key from run args + def key_ = config.name + + /* parse regular parameters (not in param_list) */ + /*************************************************/ + def globalParams = config.allArguments + .findAll { params.containsKey(it.plainName) } + .collectEntries { [ it.plainName, params[it.plainName] ] } + def globalID = params.get("id", null) + + /* process params_list arguments */ + /*********************************/ + def paramList = params.containsKey("param_list") && params.param_list != null ? + params.param_list : [] + // if (paramList instanceof String) { + // paramList = [paramList] + // } + // def paramSets = paramList.collectMany{ _parseParamList(it, config) } + // TODO: be able to process param_list when it is a list of strings + def paramSets = _parseParamList(paramList, config) + if (paramSets.isEmpty()) { + paramSets = [[null, [:]]] + } + + /* combine arguments into channel */ + /**********************************/ + def processedParams = paramSets.indexed().collect{ index, tup -> + // Process ID + def id = tup[0] ?: globalID + + if (workflow.stubRun && !id) { + // if stub run, explicitly add an id if missing + id = "stub${index}" + } + assert id != null: "Each parameter set should have at least an 'id'" + + // Process params + def parValues = globalParams + tup[1] + // // Remove parameters which are null, if the default is also null + // parValues = parValues.collectEntries{paramName, paramValue -> + // parameterSettings = config.functionality.allArguments.find({it.plainName == paramName}) + // if ( paramValue != null || parameterSettings.get("default", null) != null ) { + // [paramName, paramValue] + // } + // } + parValues = parValues.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key_}' id '${id}': '${name}' is not a valid input argument" + + if (par == null) { + return [:] + } + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + + [ name, value ] + } + + [id, parValues] + } + + // Check if ids (first element of each list) is unique + _checkUniqueIds(processedParams) + return processedParams +} + +/** + * Parse nextflow parameters based on settings defined in a viash config + * and return a nextflow channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A nextflow Channel with events. Events are formatted as a tuple that contains + * first contains the ID of the event and as second element holds a parameter map. + * + * + */ +def channelFromParams(Map params, Map config) { + def processedParams = _paramsToParamSets(params, config) + return Channel.fromList(processedParams) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/checkUniqueIds.nf' +def checkUniqueIds(Map args) { + def stopOnError = args.stopOnError == null ? args.stopOnError : true + + def idChecker = new IDChecker() + + return filter { tup -> + if (!idChecker.observe(tup[0])) { + if (stopOnError) { + error "Duplicate id: ${tup[0]}" + } else { + log.warn "Duplicate id: ${tup[0]}, removing duplicate entry" + return false + } + } + return true + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/preprocessInputs.nf' +// This helper file will be deprecated soon +preprocessInputsDeprecationWarningPrinted = false + +def preprocessInputsDeprecationWarning() { + if (!preprocessInputsDeprecationWarningPrinted) { + preprocessInputsDeprecationWarningPrinted = true + System.err.println("Warning: preprocessInputs() is deprecated and will be removed in Viash 0.9.0.") + } +} + +/** + * Generate a nextflow Workflow that allows processing a channel of + * Vdsl3 formatted events and apply a Viash config to them: + * - Gather default parameters from the Viash config and make + * sure that they are correctly formatted (see applyConfig method). + * - Format the input parameters (also using the applyConfig method). + * - Apply the default parameter to the input parameters. + * - Do some assertions: + * ~ Check if the event IDs in the channel are unique. + * + * The events in the channel are formatted as tuples, with the + * first element of the tuples being a unique id of the parameter set, + * and the second element containg the the parameters themselves. + * Optional extra elements of the tuples will be passed to the output as is. + * + * @param args A map that must contain a 'config' key that points + * to a parsed config (see readConfig()). Optionally, a + * 'key' key can be provided which can be used to create a unique + * name for the workflow process. + * + * @return A workflow that allows processing a channel of Vdsl3 formatted events + * and apply a Viash config to them. + */ +def preprocessInputs(Map args) { + preprocessInputsDeprecationWarning() + + def config = args.config + assert config instanceof Map : + "Error in preprocessInputs: config must be a map. " + + "Expected class: Map. Found: config.getClass() is ${config.getClass()}" + def key_ = args.key ?: config.name + + // Get different parameter types (used throughout this function) + def defaultArgs = config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + map { tup -> + def id = tup[0] + def data = tup[1] + def passthrough = tup.drop(2) + + def new_data = (defaultArgs + data).collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + + if (par != null) { + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + } + + [ name, value ] + } + + [ id, new_data ] + passthrough + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runComponents.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component config. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component config. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component config. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component config. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runComponents(Map args) { + log.warn("runComponents is deprecated, use runEach instead") + assert args.components: "runComponents should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runComponents" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def id_ = args.id + + workflow runComponentsWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def comp_config = comp_.config + + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_config) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + // def new_id = id_(tup[0], tup[1], comp_config) + def new_id = tup[0] + if (id_ instanceof String) { + new_id = id_ + } else if (id_ instanceof Closure) { + new_id = id_(new_id, tup[1], comp_config) + } + [new_id] + tup.drop(1) + } + : filter_ch + def data_ch = id_ch | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_config) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_config) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + post_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runComponentsWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runEach.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component itself. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component itself. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component itself. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component itself. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runEach(Map args) { + assert args.components: "runEach should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runEach" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def runIf_ = args.runIf + def id_ = args.id + + assert !runIf_ || runIf_ instanceof Closure: "runEach: must pass a Closure to runIf." + + workflow runEachWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + def new_id = id_ + if (new_id instanceof Closure) { + new_id = new_id(tup[0], tup[1], comp_) + } + assert new_id instanceof String : "Error in runEach: id should be a String or a Closure that returns a String. Expected: id instanceof String. Found: ${new_id.getClass()}" + [new_id] + tup.drop(1) + } + : filter_ch + def chPassthrough = null + def chRun = null + if (runIf_) { + def idRunIfBranch = id_ch.branch{ tup -> + run: runIf_(tup[0], tup[1], comp_) + passthrough: true + } + chPassthrough = idRunIfBranch.passthrough + chRun = idRunIfBranch.run + } else { + chRun = id_ch + chPassthrough = Channel.empty() + } + def data_ch = chRun | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + def return_ch = post_ch + | concat(chPassthrough) + + return_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runEachWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/safeJoin.nf' +/** + * Join sourceChannel to targetChannel + * + * This function joins the sourceChannel to the targetChannel. + * However, each id in the targetChannel must be present in the + * sourceChannel. If _meta.join_id exists in the targetChannel, that is + * used as an id instead. If the id doesn't match any id in the sourceChannel, + * an error is thrown. + */ + +def safeJoin(targetChannel, sourceChannel, key) { + def sourceIDs = new IDChecker() + + def sourceCheck = sourceChannel + | map { tup -> + sourceIDs.observe(tup[0]) + tup + } + def targetCheck = targetChannel + | map { tup -> + def id = tup[0] + + if (!sourceIDs.contains(id)) { + error ( + "Error in module '${key}' when merging output with original state.\n" + + " Reason: output with id '${id}' could not be joined with source channel.\n" + + " If the IDs in the output channel differ from the input channel,\n" + + " please set `tup[1]._meta.join_id to the original ID.\n" + + " Original IDs in input channel: ['${sourceIDs.getItems().join("', '")}'].\n" + + " Unexpected ID in the output channel: '${id}'.\n" + + " Example input event: [\"id\", [input: file(...)]],\n" + + " Example output event: [\"newid\", [output: file(...), _meta: [join_id: \"id\"]]]" + ) + } + // TODO: add link to our documentation on how to fix this + + tup + } + + sourceCheck.cross(targetChannel) + | map{ left, right -> + right + left.drop(1) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/_processArgument.nf' +def _processArgument(arg) { + arg.multiple = arg.multiple != null ? arg.multiple : false + arg.required = arg.required != null ? arg.required : false + arg.direction = arg.direction != null ? arg.direction : "input" + arg.multiple_sep = arg.multiple_sep != null ? arg.multiple_sep : ";" + arg.plainName = arg.name.replaceAll("^-*", "") + + if (arg.type == "file") { + arg.must_exist = arg.must_exist != null ? arg.must_exist : true + arg.create_parent = arg.create_parent != null ? arg.create_parent : true + } + + // add default values to output files which haven't already got a default + if (arg.type == "file" && arg.direction == "output" && arg.default == null) { + def mult = arg.multiple ? "_*" : "" + def extSearch = "" + if (arg.default != null) { + extSearch = arg.default + } else if (arg.example != null) { + extSearch = arg.example + } + if (extSearch instanceof List) { + extSearch = extSearch[0] + } + def extSearchResult = extSearch.find("\\.[^\\.]+\$") + def ext = extSearchResult != null ? extSearchResult : "" + arg.default = "\$id.\$key.${arg.plainName}${mult}${ext}" + if (arg.multiple) { + arg.default = [arg.default] + } + } + + if (!arg.multiple) { + if (arg.default != null && arg.default instanceof List) { + arg.default = arg.default[0] + } + if (arg.example != null && arg.example instanceof List) { + arg.example = arg.example[0] + } + } + + if (arg.type == "boolean_true") { + arg.default = false + } + if (arg.type == "boolean_false") { + arg.default = true + } + + arg +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/addGlobalParams.nf' +def addGlobalArguments(config) { + def localConfig = [ + "argument_groups": [ + [ + "name": "Nextflow input-output arguments", + "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.", + "arguments" : [ + [ + 'name': '--publish_dir', + 'required': true, + 'type': 'string', + 'description': 'Path to an output directory.', + 'example': 'output/', + 'multiple': false + ], + [ + 'name': '--param_list', + 'required': false, + 'type': 'string', + 'description': '''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. + | + |* 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: [ ['id': 'foo', 'input': 'foo.txt'], ['id': 'bar', 'input': 'bar.txt'] ]`. + |* 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`. + |* 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 `[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]`. + |* A yaml blob can also be passed directly as a string. Example: `--param_list "[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]"`. + | + |When 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.'''.stripMargin(), + 'example': 'my_params.yaml', + 'multiple': false, + 'hidden': true + ] + // TODO: allow multiple: true in param_list? + // TODO: allow to specify a --param_list_regex to filter the param_list? + // TODO: allow to specify a --param_list_from_state to remap entries in the param_list? + ] + ] + ] + ] + + return processConfig(_mergeMap(config, localConfig)) +} + +def _mergeMap(Map lhs, Map rhs) { + return rhs.inject(lhs.clone()) { map, entry -> + if (map[entry.key] instanceof Map && entry.value instanceof Map) { + map[entry.key] = _mergeMap(map[entry.key], entry.value) + } else if (map[entry.key] instanceof Collection && entry.value instanceof Collection) { + map[entry.key] += entry.value + } else { + map[entry.key] = entry.value + } + return map + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/generateHelp.nf' +def _generateArgumentHelp(param) { + // alternatives are not supported + // def names = param.alternatives ::: List(param.name) + + def unnamedProps = [ + ["required parameter", param.required], + ["multiple values allowed", param.multiple], + ["output", param.direction.toLowerCase() == "output"], + ["file must exist", param.type == "file" && param.must_exist] + ].findAll{it[1]}.collect{it[0]} + + def dflt = null + if (param.default != null) { + if (param.default instanceof List) { + dflt = param.default.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + dflt = param.default.toString() + } + } + def example = null + if (param.example != null) { + if (param.example instanceof List) { + example = param.example.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + example = param.example.toString() + } + } + def min = param.min?.toString() + def max = param.max?.toString() + + def escapeChoice = { choice -> + def s1 = choice.replaceAll("\\n", "\\\\n") + def s2 = s1.replaceAll("\"", """\\\"""") + s2.contains(",") || s2 != choice ? "\"" + s2 + "\"" : s2 + } + def choices = param.choices == null ? + null : + "[ " + param.choices.collect{escapeChoice(it.toString())}.join(", ") + " ]" + + def namedPropsStr = [ + ["type", ([param.type] + unnamedProps).join(", ")], + ["default", dflt], + ["example", example], + ["choices", choices], + ["min", min], + ["max", max] + ] + .findAll{it[1]} + .collect{"\n " + it[0] + ": " + it[1].replaceAll("\n", "\\n")} + .join("") + + def descStr = param.description == null ? + "" : + _paragraphWrap("\n" + param.description.trim(), 80 - 8).join("\n ") + + "\n --" + param.plainName + + namedPropsStr + + descStr +} + +// Based on Helper.generateHelp() in Helper.scala +def _generateHelp(config) { + def fun = config + + // PART 1: NAME AND VERSION + def nameStr = fun.name + + (fun.version == null ? "" : " " + fun.version) + + // PART 2: DESCRIPTION + def descrStr = fun.description == null ? + "" : + "\n\n" + _paragraphWrap(fun.description.trim(), 80).join("\n") + + // PART 3: Usage + def usageStr = fun.usage == null ? + "" : + "\n\nUsage:\n" + fun.usage.trim() + + // PART 4: Options + def argGroupStrs = fun.allArgumentGroups.collect{argGroup -> + def name = argGroup.name + def descriptionStr = argGroup.description == null ? + "" : + "\n " + _paragraphWrap(argGroup.description.trim(), 80-4).join("\n ") + "\n" + def arguments = argGroup.arguments.collect{arg -> + arg instanceof String ? fun.allArguments.find{it.plainName == arg} : arg + }.findAll{it != null} + def argumentStrs = arguments.collect{param -> _generateArgumentHelp(param)} + + "\n\n$name:" + + descriptionStr + + argumentStrs.join("\n") + } + + // FINAL: combine + def out = nameStr + + descrStr + + usageStr + + argGroupStrs.join("") + + return out +} + +// based on Format._paragraphWrap +def _paragraphWrap(str, maxLength) { + def outLines = [] + str.split("\n").each{par -> + def words = par.split("\\s").toList() + + def word = null + def line = words.pop() + while(!words.isEmpty()) { + word = words.pop() + if (line.length() + word.length() + 1 <= maxLength) { + line = line + " " + word + } else { + outLines.add(line) + line = word + } + } + if (words.isEmpty()) { + outLines.add(line) + } + } + return outLines +} + +def helpMessage(config) { + if (params.containsKey("help") && params.help) { + def mergedConfig = addGlobalArguments(config) + def helpStr = _generateHelp(mergedConfig) + println(helpStr) + exit 0 + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/processConfig.nf' +def processConfig(config) { + // set defaults for arguments + config.arguments = + (config.arguments ?: []).collect{_processArgument(it)} + + // set defaults for argument_group arguments + config.argument_groups = + (config.argument_groups ?: []).collect{grp -> + grp.arguments = (grp.arguments ?: []).collect{_processArgument(it)} + grp + } + + // create combined arguments list + config.allArguments = + config.arguments + + config.argument_groups.collectMany{it.arguments} + + // add missing argument groups (based on Functionality::allArgumentGroups()) + def argGroups = config.argument_groups + if (argGroups.any{it.name.toLowerCase() == "arguments"}) { + argGroups = argGroups.collect{ grp -> + if (grp.name.toLowerCase() == "arguments") { + grp = grp + [ + arguments: grp.arguments + config.arguments + ] + } + grp + } + } else { + argGroups = argGroups + [ + name: "Arguments", + arguments: config.arguments + ] + } + config.allArgumentGroups = argGroups + + config +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/readConfig.nf' + +def readConfig(file) { + def config = readYaml(file ?: moduleDir.resolve("config.vsh.yaml")) + processConfig(config) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_resolveSiblingIfNotAbsolute.nf' +/** + * Resolve a path relative to the current file. + * + * @param str The path to resolve, as a String. + * @param parentPath The path to resolve relative to, as a Path. + * + * @return The path that may have been resovled, as a Path. + */ +def _resolveSiblingIfNotAbsolute(str, parentPath) { + if (str !instanceof String) { + return str + } + if (!_stringIsAbsolutePath(str)) { + return parentPath.resolveSibling(str) + } else { + return file(str, hidden: true) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_stringIsAbsolutePath.nf' +/** + * Check whether a path as a string is absolute. + * + * In the past, we tried using `file(., relative: true).isAbsolute()`, + * but the 'relative' option was added in 22.10.0. + * + * @param path The path to check, as a String. + * + * @return Whether the path is absolute, as a boolean. + */ +def _stringIsAbsolutePath(path) { + def _resolve_URL_PROTOCOL = ~/^([a-zA-Z][a-zA-Z0-9]*:)?\\/.+/ + + assert path instanceof String + return _resolve_URL_PROTOCOL.matcher(path).matches() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/collectTraces.nf' +class CustomTraceObserver implements nextflow.trace.TraceObserver { + List traces + + CustomTraceObserver(List traces) { + this.traces = traces + } + + @Override + void onProcessComplete(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } + + @Override + void onProcessCached(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } +} + +def collectTraces() { + def traces = Collections.synchronizedList([]) + + // add custom trace observer which stores traces in the traces object + session.observers.add(new CustomTraceObserver(traces)) + + traces +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/deepClone.nf' +/** + * Performs a deep clone of the given object. + * @param x an object + */ +def deepClone(x) { + iterateMap(x, {it instanceof Cloneable ? it.clone() : it}) +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getPublishDir.nf' +def getPublishDir() { + return params.containsKey("publish_dir") ? params.publish_dir : + params.containsKey("publishDir") ? params.publishDir : + null +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getRootDir.nf' + +// Recurse upwards until we find a '.build.yaml' file +def _findBuildYamlFile(pathPossiblySymlink) { + def path = pathPossiblySymlink.toRealPath() + def child = path.resolve(".build.yaml") + if (java.nio.file.Files.isDirectory(path) && java.nio.file.Files.exists(child)) { + return child + } else { + def parent = path.getParent() + if (parent == null) { + return null + } else { + return _findBuildYamlFile(parent) + } + } +} + +// get the root of the target folder +def getRootDir() { + def dir = _findBuildYamlFile(meta.resources_dir) + assert dir != null: "Could not find .build.yaml in the folder structure" + dir.getParent() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/iterateMap.nf' +/** + * Recursively apply a function over the leaves of an object. + * @param obj The object to iterate over. + * @param fun The function to apply to each value. + * @return The object with the function applied to each value. + */ +def iterateMap(obj, fun) { + if (obj instanceof List && obj !instanceof String) { + return obj.collect{item -> + iterateMap(item, fun) + } + } else if (obj instanceof Map) { + return obj.collectEntries{key, item -> + [key.toString(), iterateMap(item, fun)] + } + } else { + return fun(obj) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/niceView.nf' +/** + * A view for printing the event of each channel as a YAML blob. + * This is useful for debugging. + */ +def niceView() { + workflow niceViewWf { + take: input + main: + output = input + | view{toYamlBlob(it)} + emit: output + } + return niceViewWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readCsv.nf' + +def readCsv(file_path) { + def output = [] + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + + // todo: allow escaped quotes in string + // todo: allow single quotes? + def splitRegex = java.util.regex.Pattern.compile(''',(?=(?:[^"]*"[^"]*")*[^"]*$)''') + def removeQuote = java.util.regex.Pattern.compile('''"(.*)"''') + + def br = java.nio.file.Files.newBufferedReader(inputFile) + + def row = -1 + def header = null + while (br.ready() && header == null) { + def line = br.readLine() + row++ + if (!line.startsWith("#")) { + header = splitRegex.split(line, -1).collect{field -> + m = removeQuote.matcher(field) + m.find() ? m.replaceFirst('$1') : field + } + } + } + assert header != null: "CSV file should contain a header" + + while (br.ready()) { + def line = br.readLine() + row++ + if (line == null) { + br.close() + break + } + + if (!line.startsWith("#")) { + def predata = splitRegex.split(line, -1) + def data = predata.collect{field -> + if (field == "") { + return null + } + def m = removeQuote.matcher(field) + if (m.find()) { + return m.replaceFirst('$1') + } else { + return field + } + } + assert header.size() == data.size(): "Row $row should contain the same number as fields as the header" + + def dataMap = [header, data].transpose().collectEntries().findAll{it.value != null} + output.add(dataMap) + } + } + + output +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJson.nf' +def readJson(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parse(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJsonBlob.nf' +def readJsonBlob(str) { + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parseText(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readTaggedYaml.nf' +// Custom constructor to modify how certain objects are parsed from YAML +class CustomConstructor extends org.yaml.snakeyaml.constructor.Constructor { + Path root + + class ConstructPath extends org.yaml.snakeyaml.constructor.AbstractConstruct { + public Object construct(org.yaml.snakeyaml.nodes.Node node) { + String filename = (String) constructScalar(node); + if (root != null) { + return root.resolve(filename); + } + return java.nio.file.Paths.get(filename); + } + } + + CustomConstructor(org.yaml.snakeyaml.LoaderOptions options, Path root) { + super(options) + this.root = root + // Handling !file tag and parse it back to a File type + this.yamlConstructors.put(new org.yaml.snakeyaml.nodes.Tag("!file"), new ConstructPath()) + } +} + +def readTaggedYaml(Path path) { + def options = new org.yaml.snakeyaml.LoaderOptions() + def constructor = new CustomConstructor(options, path.getParent()) + def yaml = new org.yaml.snakeyaml.Yaml(constructor) + return yaml.load(path.text) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYaml.nf' +def readYaml(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYamlBlob.nf' +def readYamlBlob(str) { + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toJsonBlob.nf' +String toJsonBlob(data) { + return groovy.json.JsonOutput.toJson(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toTaggedYamlBlob.nf' +// Custom representer to modify how certain objects are represented in YAML +class CustomRepresenter extends org.yaml.snakeyaml.representer.Representer { + Path relativizer + + class RepresentPath implements org.yaml.snakeyaml.representer.Represent { + public String getFileName(Object obj) { + if (obj instanceof File) { + obj = ((File) obj).toPath(); + } + if (obj !instanceof Path) { + throw new IllegalArgumentException("Object: " + obj + " is not a Path or File"); + } + def path = (Path) obj; + + if (relativizer != null) { + return relativizer.relativize(path).toString() + } else { + return path.toString() + } + } + + public org.yaml.snakeyaml.nodes.Node representData(Object data) { + String filename = getFileName(data); + def tag = new org.yaml.snakeyaml.nodes.Tag("!file"); + return representScalar(tag, filename); + } + } + CustomRepresenter(org.yaml.snakeyaml.DumperOptions options, Path relativizer) { + super(options) + this.relativizer = relativizer + this.representers.put(sun.nio.fs.UnixPath, new RepresentPath()) + this.representers.put(Path, new RepresentPath()) + this.representers.put(File, new RepresentPath()) + } +} + +String toTaggedYamlBlob(data) { + return toRelativeTaggedYamlBlob(data, null) +} +String toRelativeTaggedYamlBlob(data, Path relativizer) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + def representer = new CustomRepresenter(options, relativizer) + def yaml = new org.yaml.snakeyaml.Yaml(representer, options) + return yaml.dump(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toYamlBlob.nf' +String toYamlBlob(data) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + options.setPrettyFlow(true) + def yaml = new org.yaml.snakeyaml.Yaml(options) + def cleanData = iterateMap(data, { it instanceof Path ? it.toString() : it }) + return yaml.dump(cleanData) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeJson.nf' +void writeJson(data, file) { + assert data: "writeJson: data should not be null" + assert file: "writeJson: file should not be null" + file.write(toJsonBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeYaml.nf' +void writeYaml(data, file) { + assert data: "writeYaml: data should not be null" + assert file: "writeYaml: file should not be null" + file.write(toYamlBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/findStates.nf' +def findStates(Map params, Map config) { + def auto_config = deepClone(config) + def auto_params = deepClone(params) + + auto_config = auto_config.clone() + // override arguments + auto_config.argument_groups = [] + auto_config.arguments = [ + [ + type: "string", + name: "--id", + description: "A dummy identifier", + required: false + ], + [ + type: "file", + name: "--input_states", + example: "/path/to/input/directory/**/state.yaml", + description: "Path to input directory containing the datasets to be integrated.", + required: true, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--filter", + example: "foo/.*/state.yaml", + description: "Regex to filter state files by path.", + required: false + ], + // to do: make this a yaml blob? + [ + type: "string", + name: "--rename_keys", + example: ["newKey1:oldKey1", "newKey2:oldKey2"], + description: "Rename keys in the detected input files. This is useful if the input files do not match the set of input arguments of the workflow.", + required: false, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--settings", + example: '{"output_dataset": "dataset.h5ad", "k": 10}', + description: "Global arguments as a JSON glob to be passed to all components.", + required: false + ] + ] + if (!(auto_params.containsKey("id"))) { + auto_params["id"] = "auto" + } + + // run auto config through processConfig once more + auto_config = processConfig(auto_config) + + workflow findStatesWf { + helpMessage(auto_config) + + output_ch = + channelFromParams(auto_params, auto_config) + | flatMap { autoId, args -> + + def globalSettings = args.settings ? readYamlBlob(args.settings) : [:] + + // look for state files in input dir + def stateFiles = args.input_states + + // filter state files by regex + if (args.filter) { + stateFiles = stateFiles.findAll{ stateFile -> + def stateFileStr = stateFile.toString() + def matcher = stateFileStr =~ args.filter + matcher.matches()} + } + + // read in states + def states = stateFiles.collect { stateFile -> + def state_ = readTaggedYaml(stateFile) + [state_.id, state_] + } + + // construct renameMap + if (args.rename_keys) { + def renameMap = args.rename_keys.collectEntries{renameString -> + def split = renameString.split(":") + assert split.size() == 2: "Argument 'rename_keys' should be of the form 'newKey:oldKey', or 'newKey:oldKey;newKey:oldKey' in case of multiple values" + split + } + + // rename keys in state, only let states through which have all keys + // also add global settings + states = states.collectMany{id, state -> + def newState = [:] + + for (key in renameMap.keySet()) { + def origKey = renameMap[key] + if (!(state.containsKey(origKey))) { + return [] + } + newState[key] = state[origKey] + } + + [[id, globalSettings + newState]] + } + } + + states + } + emit: + output_ch + } + + return findStatesWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/joinStates.nf' +def joinStates(Closure apply_) { + workflow joinStatesWf { + take: input_ch + main: + output_ch = input_ch + | toSortedList + | filter{ it.size() > 0 } + | map{ tups -> + def ids = tups.collect{it[0]} + def states = tups.collect{it[1]} + apply_(ids, states) + } + + emit: output_ch + } + return joinStatesWf +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf' +def collectFiles(obj) { + if (obj instanceof java.io.File || obj instanceof Path) { + return [obj] + } else if (obj instanceof List && obj !instanceof String) { + return obj.collectMany{item -> + collectFiles(item) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectFiles(item) + } + } else { + return [] + } +} + +/** + * Recurse through a state and collect all input files and their target output filenames. + * @param obj The state to recurse through. + * @param prefix The prefix to prepend to the output filenames. + */ +def collectInputOutputPaths(obj, prefix) { + if (obj instanceof File || obj instanceof Path) { + def path = obj instanceof Path ? obj : obj.toPath() + def ext = path.getFileName().toString().find("\\.[^\\.]+\$") ?: "" + def newFilename = prefix + ext + return [[obj, newFilename]] + } else if (obj instanceof List && obj !instanceof String) { + return obj.withIndex().collectMany{item, ix -> + collectInputOutputPaths(item, prefix + "_" + ix) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectInputOutputPaths(item, prefix + "." + key) + } + } else { + return [] + } +} + +def publishStates(Map args) { + def key_ = args.get("key") + def yamlTemplate_ = args.get("output_state", args.get("outputState", '$id.$key.state.yaml')) + + assert key_ != null : "publishStates: key must be specified" + + workflow publishStatesWf { + 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] + + def yamlFilename = yamlTemplate_ + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .replaceAll('\\$\\{key\\}', key_) + + // TODO: do the pathnames in state_ match up with the outputFilenames_? + + // convert state to yaml blob + def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename)) + + [id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_] + } + | publishStatesProc + emit: input_ch + } + return publishStatesWf +} +process publishStatesProc { + // todo: check publishpath? + publishDir path: "${getPublishDir()}/", mode: "copy" + tag "$id" + input: + tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles) + output: + tuple val(id), path{[yamlFile] + 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 + [] + } + } + """ +mkdir -p "\$(dirname '${yamlFile}')" +echo "Storing state as yaml" +echo '${yamlBlob}' > '${yamlFile}' +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 publishStatesByConfig(Map args) { + def config = args.get("config") + assert config != null : "publishStatesByConfig: config must be specified" + + def key_ = args.get("key", config.name) + assert key_ != null : "publishStatesByConfig: key must be specified" + + workflow publishStatesSimpleWf { + 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'] + + // TODO: allow overriding the state.yaml template + // TODO TODO: if auto.publish == "state", add output_state as an argument + def yamlTemplate = params.containsKey("output_state") ? params.output_state : '$id.$key.state.yaml' + def yamlFilename = yamlTemplate + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .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 + // - 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" } + .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 + 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 [[key: plainName_, value: value, 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 value_ = java.nio.file.Paths.get(filename_ix) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = val instanceof File ? val.toPath() : val + [value: value_, inputPath: inputPath, outputFilename: filename_ix] + } + def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key -> + [key, outputPerFile.collect{dic -> dic[key]}] + } + return [[key: plainName_] + transposedOutputs] + } else { + def value_ = java.nio.file.Paths.get(filename) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = value instanceof File ? value.toPath() : value + return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]] + } + } + + 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] + } + | publishStatesProc + emit: input_ch + } + return publishStatesSimpleWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/setState.nf' +def setState(fun) { + assert fun instanceof Closure || fun instanceof Map || fun instanceof List : + "Error in setState: Expected process argument to be a Closure, a Map, or a List. Found: class ${fun.getClass()}" + + // if fun is a List, convert to map + if (fun instanceof List) { + // check whether fun is a list[string] + assert fun.every{it instanceof CharSequence} : "Error in setState: argument is a List, but not all elements are Strings" + fun = fun.collectEntries{[it, it]} + } + + // if fun is a map, convert to closure + if (fun instanceof Map) { + // check whether fun is a map[string, string] + assert fun.values().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all values are Strings" + assert fun.keySet().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all keys are Strings" + def funMap = fun.clone() + // turn the map into a closure to be used later on + fun = { id_, state_ -> + assert state_ instanceof Map : "Error in setState: the state is not a Map" + funMap.collectMany{newkey, origkey -> + if (state_.containsKey(origkey)) { + [[newkey, state_[origkey]]] + } else { + [] + } + }.collectEntries() + } + } + + map { tup -> + def id = tup[0] + def state = tup[1] + def unfilteredState = fun(id, state) + def newState = unfilteredState.findAll{key, val -> val != null} + [id, newState] + tup.drop(2) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processAuto.nf' +// TODO: unit test processAuto +def processAuto(Map auto) { + // remove null values + auto = auto.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = ["simplifyInput", "simplifyOutput", "transcript", "publish"] + def unexpectedKeys = auto.keySet() - expectedKeys + assert unexpectedKeys.isEmpty(), "unexpected keys in auto: '${unexpectedKeys.join("', '")}'" + + // check auto.simplifyInput + assert auto.simplifyInput instanceof Boolean, "auto.simplifyInput must be a boolean" + + // check auto.simplifyOutput + assert auto.simplifyOutput instanceof Boolean, "auto.simplifyOutput must be a boolean" + + // check auto.transcript + assert auto.transcript instanceof Boolean, "auto.transcript must be a boolean" + + // check auto.publish + assert auto.publish instanceof Boolean || auto.publish == "state", "auto.publish must be a boolean or 'state'" + + return auto.subMap(expectedKeys) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processDirectives.nf' +def assertMapKeys(map, expectedKeys, requiredKeys, mapName) { + assert map instanceof Map : "Expected argument '$mapName' to be a Map. Found: class ${map.getClass()}" + map.forEach { key, val -> + assert key in expectedKeys : "Unexpected key '$key' in ${mapName ? mapName + " " : ""}map" + } + requiredKeys.forEach { requiredKey -> + assert map.containsKey(requiredKey) : "Missing required key '$key' in ${mapName ? mapName + " " : ""}map" + } +} + +// TODO: unit test processDirectives +def processDirectives(Map drctv) { + // remove null values + drctv = drctv.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = [ + "accelerator", "afterScript", "beforeScript", "cache", "conda", "container", "containerOptions", "cpus", "disk", "echo", "errorStrategy", "executor", "machineType", "maxErrors", "maxForks", "maxRetries", "memory", "module", "penv", "pod", "publishDir", "queue", "label", "scratch", "storeDir", "stageInMode", "stageOutMode", "tag", "time" + ] + def unexpectedKeys = drctv.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Unexpected keys in process directive: '${unexpectedKeys.join("', '")}'" + + /* DIRECTIVE accelerator + accepted examples: + - [ limit: 4, type: "nvidia-tesla-k80" ] + */ + if (drctv.containsKey("accelerator")) { + assertMapKeys(drctv["accelerator"], ["type", "limit", "request", "runtime"], [], "accelerator") + } + + /* DIRECTIVE afterScript + accepted examples: + - "source /cluster/bin/cleanup" + */ + if (drctv.containsKey("afterScript")) { + assert drctv["afterScript"] instanceof CharSequence + } + + /* DIRECTIVE beforeScript + accepted examples: + - "source /cluster/bin/setup" + */ + if (drctv.containsKey("beforeScript")) { + assert drctv["beforeScript"] instanceof CharSequence + } + + /* DIRECTIVE cache + accepted examples: + - true + - false + - "deep" + - "lenient" + */ + if (drctv.containsKey("cache")) { + assert drctv["cache"] instanceof CharSequence || drctv["cache"] instanceof Boolean + if (drctv["cache"] instanceof CharSequence) { + assert drctv["cache"] in ["deep", "lenient"] : "Unexpected value for cache" + } + } + + /* DIRECTIVE conda + accepted examples: + - "bwa=0.7.15" + - "bwa=0.7.15 fastqc=0.11.5" + - ["bwa=0.7.15", "fastqc=0.11.5"] + */ + if (drctv.containsKey("conda")) { + if (drctv["conda"] instanceof List) { + drctv["conda"] = drctv["conda"].join(" ") + } + assert drctv["conda"] instanceof CharSequence + } + + /* DIRECTIVE container + accepted examples: + - "foo/bar:tag" + - [ registry: "reg", image: "im", tag: "ta" ] + is transformed to "reg/im:ta" + - [ image: "im" ] + is transformed to "im:latest" + */ + if (drctv.containsKey("container")) { + assert drctv["container"] instanceof Map || drctv["container"] instanceof CharSequence + if (drctv["container"] instanceof Map) { + def m = drctv["container"] + assertMapKeys(m, [ "registry", "image", "tag" ], ["image"], "container") + def part1 = + System.getenv('OVERRIDE_CONTAINER_REGISTRY') ? System.getenv('OVERRIDE_CONTAINER_REGISTRY') + "/" : + params.containsKey("override_container_registry") ? params["override_container_registry"] + "/" : // todo: remove? + m.registry ? m.registry + "/" : + "" + def part2 = m.image + def part3 = m.tag ? ":" + m.tag : ":latest" + drctv["container"] = part1 + part2 + part3 + } + } + + /* DIRECTIVE containerOptions + accepted examples: + - "--foo bar" + - ["--foo bar", "-f b"] + */ + if (drctv.containsKey("containerOptions")) { + if (drctv["containerOptions"] instanceof List) { + drctv["containerOptions"] = drctv["containerOptions"].join(" ") + } + assert drctv["containerOptions"] instanceof CharSequence + } + + /* DIRECTIVE cpus + accepted examples: + - 1 + - 10 + */ + if (drctv.containsKey("cpus")) { + assert drctv["cpus"] instanceof Integer + } + + /* DIRECTIVE disk + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("disk")) { + assert drctv["disk"] instanceof CharSequence + // assert drctv["disk"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE echo + accepted examples: + - true + - false + */ + if (drctv.containsKey("echo")) { + assert drctv["echo"] instanceof Boolean + } + + /* DIRECTIVE errorStrategy + accepted examples: + - "terminate" + - "finish" + */ + if (drctv.containsKey("errorStrategy")) { + assert drctv["errorStrategy"] instanceof CharSequence + assert drctv["errorStrategy"] in ["terminate", "finish", "ignore", "retry"] : "Unexpected value for errorStrategy" + } + + /* DIRECTIVE executor + accepted examples: + - "local" + - "sge" + */ + if (drctv.containsKey("executor")) { + assert drctv["executor"] instanceof CharSequence + assert drctv["executor"] in ["local", "sge", "uge", "lsf", "slurm", "pbs", "pbspro", "moab", "condor", "nqsii", "ignite", "k8s", "awsbatch", "google-pipelines"] : "Unexpected value for executor" + } + + /* DIRECTIVE machineType + accepted examples: + - "n1-highmem-8" + */ + if (drctv.containsKey("machineType")) { + assert drctv["machineType"] instanceof CharSequence + } + + /* DIRECTIVE maxErrors + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxErrors")) { + assert drctv["maxErrors"] instanceof Integer + } + + /* DIRECTIVE maxForks + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxForks")) { + assert drctv["maxForks"] instanceof Integer + } + + /* DIRECTIVE maxRetries + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxRetries")) { + assert drctv["maxRetries"] instanceof Integer + } + + /* DIRECTIVE memory + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("memory")) { + assert drctv["memory"] instanceof CharSequence + // assert drctv["memory"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE module + accepted examples: + - "ncbi-blast/2.2.27" + - "ncbi-blast/2.2.27:t_coffee/10.0" + - ["ncbi-blast/2.2.27", "t_coffee/10.0"] + */ + if (drctv.containsKey("module")) { + if (drctv["module"] instanceof List) { + drctv["module"] = drctv["module"].join(":") + } + assert drctv["module"] instanceof CharSequence + } + + /* DIRECTIVE penv + accepted examples: + - "smp" + */ + if (drctv.containsKey("penv")) { + assert drctv["penv"] instanceof CharSequence + } + + /* DIRECTIVE pod + accepted examples: + - [ label: "key", value: "val" ] + - [ annotation: "key", value: "val" ] + - [ env: "key", value: "val" ] + - [ [label: "l", value: "v"], [env: "e", value: "v"]] + */ + if (drctv.containsKey("pod")) { + if (drctv["pod"] instanceof Map) { + drctv["pod"] = [ drctv["pod"] ] + } + assert drctv["pod"] instanceof List + drctv["pod"].forEach { pod -> + assert pod instanceof Map + // TODO: should more checks be added? + // See https://www.nextflow.io/docs/latest/process.html?highlight=directives#pod + // e.g. does it contain 'label' and 'value', or 'annotation' and 'value', or ...? + } + } + + /* DIRECTIVE publishDir + accepted examples: + - [] + - [ [ path: "foo", enabled: true ], [ path: "bar", enabled: false ] ] + - "/path/to/dir" + is transformed to [[ path: "/path/to/dir" ]] + - [ path: "/path/to/dir", mode: "cache" ] + is transformed to [[ path: "/path/to/dir", mode: "cache" ]] + */ + // TODO: should we also look at params["publishDir"]? + if (drctv.containsKey("publishDir")) { + def pblsh = drctv["publishDir"] + + // check different options + assert pblsh instanceof List || pblsh instanceof Map || pblsh instanceof CharSequence + + // turn into list if not already so + // for some reason, 'if (!pblsh instanceof List) pblsh = [ pblsh ]' doesn't work. + pblsh = pblsh instanceof List ? pblsh : [ pblsh ] + + // check elements of publishDir + pblsh = pblsh.collect{ elem -> + // turn into map if not already so + elem = elem instanceof CharSequence ? [ path: elem ] : elem + + // check types and keys + assert elem instanceof Map : "Expected publish argument '$elem' to be a String or a Map. Found: class ${elem.getClass()}" + assertMapKeys(elem, [ "path", "mode", "overwrite", "pattern", "saveAs", "enabled" ], ["path"], "publishDir") + + // check elements in map + assert elem.containsKey("path") + assert elem["path"] instanceof CharSequence + if (elem.containsKey("mode")) { + assert elem["mode"] instanceof CharSequence + assert elem["mode"] in [ "symlink", "rellink", "link", "copy", "copyNoFollow", "move" ] + } + if (elem.containsKey("overwrite")) { + assert elem["overwrite"] instanceof Boolean + } + if (elem.containsKey("pattern")) { + assert elem["pattern"] instanceof CharSequence + } + if (elem.containsKey("saveAs")) { + assert elem["saveAs"] instanceof CharSequence //: "saveAs as a Closure is currently not supported. Surround your closure with single quotes to get the desired effect. Example: '\{ foo \}'" + } + if (elem.containsKey("enabled")) { + assert elem["enabled"] instanceof Boolean + } + + // return final result + elem + } + // store final directive + drctv["publishDir"] = pblsh + } + + /* DIRECTIVE queue + accepted examples: + - "long" + - "short,long" + - ["short", "long"] + */ + if (drctv.containsKey("queue")) { + if (drctv["queue"] instanceof List) { + drctv["queue"] = drctv["queue"].join(",") + } + assert drctv["queue"] instanceof CharSequence + } + + /* DIRECTIVE label + accepted examples: + - "big_mem" + - "big_cpu" + - ["big_mem", "big_cpu"] + */ + if (drctv.containsKey("label")) { + if (drctv["label"] instanceof CharSequence) { + drctv["label"] = [ drctv["label"] ] + } + assert drctv["label"] instanceof List + drctv["label"].forEach { label -> + assert label instanceof CharSequence + // assert label.matches("[a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?") + // ^ does not allow closures + } + } + + /* DIRECTIVE scratch + accepted examples: + - true + - "/path/to/scratch" + - '$MY_PATH_TO_SCRATCH' + - "ram-disk" + */ + if (drctv.containsKey("scratch")) { + assert drctv["scratch"] == true || drctv["scratch"] instanceof CharSequence + } + + /* DIRECTIVE storeDir + accepted examples: + - "/path/to/storeDir" + */ + if (drctv.containsKey("storeDir")) { + assert drctv["storeDir"] instanceof CharSequence + } + + /* DIRECTIVE stageInMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageInMode")) { + assert drctv["stageInMode"] instanceof CharSequence + assert drctv["stageInMode"] in ["copy", "link", "symlink", "rellink"] + } + + /* DIRECTIVE stageOutMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageOutMode")) { + assert drctv["stageOutMode"] instanceof CharSequence + assert drctv["stageOutMode"] in ["copy", "move", "rsync"] + } + + /* DIRECTIVE tag + accepted examples: + - "foo" + - '$id' + */ + if (drctv.containsKey("tag")) { + assert drctv["tag"] instanceof CharSequence + } + + /* DIRECTIVE time + accepted examples: + - "1h" + - "2days" + - "1day 6hours 3minutes 30seconds" + */ + if (drctv.containsKey("time")) { + assert drctv["time"] instanceof CharSequence + // todo: validation regex? + } + + return drctv +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processWorkflowArgs.nf' +def processWorkflowArgs(Map args, Map defaultWfArgs, Map meta) { + // override defaults with args + def workflowArgs = defaultWfArgs + args + + // check whether 'key' exists + assert workflowArgs.containsKey("key") : "Error in module '${meta.config.name}': key is a required argument" + + // if 'key' is a closure, apply it to the original key + if (workflowArgs["key"] instanceof Closure) { + workflowArgs["key"] = workflowArgs["key"](meta.config.name) + } + def key = workflowArgs["key"] + assert key instanceof CharSequence : "Expected process argument 'key' to be a String. Found: class ${key.getClass()}" + assert key ==~ /^[a-zA-Z_]\w*$/ : "Error in module '$key': Expected process argument 'key' to consist of only letters, digits or underscores. Found: ${key}" + + // check for any unexpected keys + def expectedKeys = ["key", "directives", "auto", "map", "mapId", "mapData", "mapPassthrough", "filter", "runIf", "fromState", "toState", "args", "renameKeys", "debug"] + def unexpectedKeys = workflowArgs.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Error in module '$key': unexpected arguments to the '.run()' function: '${unexpectedKeys.join("', '")}'" + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("directives") : "Error in module '$key': directives is a required argument" + assert workflowArgs["directives"] instanceof Map : "Error in module '$key': Expected process argument 'directives' to be a Map. Found: class ${workflowArgs['directives'].getClass()}" + workflowArgs["directives"] = processDirectives(defaultWfArgs.directives + workflowArgs["directives"]) + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("auto") : "Error in module '$key': auto is a required argument" + assert workflowArgs["auto"] instanceof Map : "Error in module '$key': Expected process argument 'auto' to be a Map. Found: class ${workflowArgs['auto'].getClass()}" + workflowArgs["auto"] = processAuto(defaultWfArgs.auto + workflowArgs["auto"]) + + // auto define publish, if so desired + if (workflowArgs.auto.publish == true && (workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : [:]).isEmpty()) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.publish is true, params.publish_dir needs to be defined.\n" + + // " Example: params.publish_dir = \"./output/\"" + def publishDir = getPublishDir() + + if (publishDir != null) { + workflowArgs.directives.publishDir = [[ + path: publishDir, + saveAs: "{ it.startsWith('.') ? null : it }", // don't publish hidden files, by default + mode: "copy" + ]] + } + } + + // auto define transcript, if so desired + if (workflowArgs.auto.transcript == true) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("transcriptsDir") || params.containsKey("transcripts_dir") || params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.transcript is true, either params.transcripts_dir or params.publish_dir needs to be defined.\n" + + // " Example: params.transcripts_dir = \"./transcripts/\"" + def transcriptsDir = + params.containsKey("transcripts_dir") ? params.transcripts_dir : + params.containsKey("transcriptsDir") ? params.transcriptsDir : + params.containsKey("publish_dir") ? params.publish_dir + "/_transcripts" : + params.containsKey("publishDir") ? params.publishDir + "/_transcripts" : + null + if (transcriptsDir != null) { + def timestamp = nextflow.Nextflow.getSession().getWorkflowMetadata().start.format('yyyy-MM-dd_HH-mm-ss') + def transcriptsPublishDir = [ + path: "$transcriptsDir/$timestamp/\${task.process.replaceAll(':', '-')}/\${id}/", + saveAs: "{ it.startsWith('.') ? it.replaceAll('^.', '') : null }", + mode: "copy" + ] + def publishDirs = workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : null ? workflowArgs.directives.publishDir : [] + workflowArgs.directives.publishDir = publishDirs + transcriptsPublishDir + } + } + + // if this is a stubrun, remove certain directives? + if (workflow.stubRun) { + workflowArgs.directives.keySet().removeAll(["publishDir", "cpus", "memory", "label"]) + } + + for (nam in ["map", "mapId", "mapData", "mapPassthrough", "filter", "runIf"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam]) { + assert workflowArgs[nam] instanceof Closure : "Error in module '$key': Expected process argument '$nam' to be null or a Closure. Found: class ${workflowArgs[nam].getClass()}" + } + } + + // TODO: should functions like 'map', 'mapId', 'mapData', 'mapPassthrough' be deprecated as well? + for (nam in ["map", "mapData", "mapPassthrough", "renameKeys"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam] != null) { + log.warn "module '$key': workflow argument '$nam' is deprecated and will be removed in Viash 0.9.0. Please use 'fromState' and 'toState' instead." + } + } + + // check fromState + workflowArgs["fromState"] = _processFromState(workflowArgs.get("fromState"), key, meta.config) + + // check toState + workflowArgs["toState"] = _processToState(workflowArgs.get("toState"), key, meta.config) + + // return output + return workflowArgs +} + +def _processFromState(fromState, key_, config_) { + assert fromState == null || fromState instanceof Closure || fromState instanceof Map || fromState instanceof List : + "Error in module '$key_': Expected process argument 'fromState' to be null, a Closure, a Map, or a List. Found: class ${fromState.getClass()}" + if (fromState == null) { + return null + } + + // if fromState is a List, convert to map + if (fromState instanceof List) { + // check whether fromstate is a list[string] + assert fromState.every{it instanceof CharSequence} : "Error in module '$key_': fromState is a List, but not all elements are Strings" + fromState = fromState.collectEntries{[it, it]} + } + + // if fromState is a map, convert to closure + if (fromState instanceof Map) { + // check whether fromstate is a map[string, string] + assert fromState.values().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all values are Strings" + assert fromState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all keys are Strings" + def fromStateMap = fromState.clone() + def requiredInputNames = meta.config.allArguments.findAll{it.required && it.direction == "Input"}.collect{it.plainName} + // turn the map into a closure to be used later on + fromState = { it -> + def state = it[1] + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def data = fromStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (state.containsKey(origkey)) { + [[newkey, state[origkey]]] + } else if (!requiredInputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': fromState key '$origkey' not found in current state") + } + }.collectEntries() + data + } + } + + return fromState +} + +def _processToState(toState, key_, config_) { + if (toState == null) { + toState = { tup -> tup[1] } + } + + // toState should be a closure, map[string, string], or list[string] + assert toState instanceof Closure || toState instanceof Map || toState instanceof List : + "Error in module '$key_': Expected process argument 'toState' to be a Closure, a Map, or a List. Found: class ${toState.getClass()}" + + // if toState is a List, convert to map + if (toState instanceof List) { + // check whether toState is a list[string] + assert toState.every{it instanceof CharSequence} : "Error in module '$key_': toState is a List, but not all elements are Strings" + toState = toState.collectEntries{[it, it]} + } + + // if toState is a map, convert to closure + if (toState instanceof Map) { + // check whether toState is a map[string, string] + assert toState.values().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all values are Strings" + assert toState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all keys are Strings" + def toStateMap = toState.clone() + def requiredOutputNames = config_.allArguments.findAll{it.required && it.direction == "Output"}.collect{it.plainName} + // turn the map into a closure to be used later on + toState = { it -> + def output = it[1] + def state = it[2] + assert output instanceof Map : "Error in module '$key_': the output is not a Map" + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def extraEntries = toStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (output.containsKey(origkey)) { + [[newkey, output[origkey]]] + } else if (!requiredOutputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': toState key '$origkey' not found in current output") + } + }.collectEntries() + state + extraEntries + } + } + + return toState +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/workflowFactory.nf' +def _debug(workflowArgs, debugKey) { + if (workflowArgs.debug) { + view { "process '${workflowArgs.key}' $debugKey tuple: $it" } + } else { + map { it } + } +} + +// depends on: innerWorkflowFactory +def workflowFactory(Map args, Map defaultWfArgs, Map meta) { + def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta) + def key_ = workflowArgs["key"] + + workflow workflowInstance { + take: input_ + + main: + def chModified = input_ + | checkUniqueIds([:]) + | _debug(workflowArgs, "input") + | map { tuple -> + tuple = deepClone(tuple) + + if (workflowArgs.map) { + tuple = workflowArgs.map(tuple) + } + if (workflowArgs.mapId) { + tuple[0] = workflowArgs.mapId(tuple[0]) + } + if (workflowArgs.mapData) { + tuple[1] = workflowArgs.mapData(tuple[1]) + } + if (workflowArgs.mapPassthrough) { + tuple = tuple.take(2) + workflowArgs.mapPassthrough(tuple.drop(2)) + } + + // check tuple + assert tuple instanceof List : + "Error in module '${key_}': element in 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()}" + assert tuple.size() >= 2 : + "Error in module '${key_}': expected length of tuple in input channel to be two or greater.\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: tuple.size() == ${tuple.size()}" + + // check id field + if (tuple[0] instanceof GString) { + tuple[0] = tuple[0].toString() + } + assert tuple[0] instanceof CharSequence : + "Error in module '${key_}': first element of tuple in channel should be a String\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: ${tuple[0]}" + + // match file to input file + if (workflowArgs.auto.simplifyInput && (tuple[1] instanceof Path || tuple[1] instanceof List)) { + def inputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + + assert inputFiles.size() == 1 : + "Error in module '${key_}' id '${tuple[0]}'.\n" + + " Anonymous file inputs are only allowed when the process has exactly one file input.\n" + + " Expected: inputFiles.size() == 1. Found: inputFiles.size() is ${inputFiles.size()}" + + tuple[1] = [[ inputFiles[0].plainName, tuple[1] ]].collectEntries() + } + + // check data field + assert tuple[1] instanceof Map : + "Error in module '${key_}' id '${tuple[0]}': second element of tuple in channel should be a Map\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // rename keys of data field in tuple + if (workflowArgs.renameKeys) { + assert workflowArgs.renameKeys instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class: Map. Found: renameKeys.getClass() is ${workflowArgs.renameKeys.getClass()}" + assert tuple[1] instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // TODO: allow renameKeys to be a function? + workflowArgs.renameKeys.each { newKey, oldKey -> + assert newKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of newKey: String. Found: newKey.getClass() is ${newKey.getClass()}" + assert oldKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of oldKey: String. Found: oldKey.getClass() is ${oldKey.getClass()}" + assert tuple[1].containsKey(oldKey) : + "Error renaming data keys in module '${key}' id '${tuple[0]}'.\n" + + " Key '$oldKey' is missing in the data map. tuple[1].keySet() is '${tuple[1].keySet()}'" + tuple[1].put(newKey, tuple[1][oldKey]) + } + tuple[1].keySet().removeAll(workflowArgs.renameKeys.collect{ newKey, oldKey -> oldKey }) + } + tuple + } + + + def chRun = null + def chPassthrough = null + if (workflowArgs.runIf) { + def runIfBranch = chModified.branch{ tup -> + run: workflowArgs.runIf(tup[0], tup[1]) + passthrough: true + } + chRun = runIfBranch.run + chPassthrough = runIfBranch.passthrough + } else { + chRun = chModified + chPassthrough = Channel.empty() + } + + def chRunFiltered = workflowArgs.filter ? + chRun | filter{workflowArgs.filter(it)} : + chRun + + def chArgs = workflowArgs.fromState ? + chRunFiltered | map{ + def new_data = workflowArgs.fromState(it.take(2)) + [it[0], new_data] + } : + chRunFiltered | map {tup -> tup.take(2)} + + // fill in defaults + def chArgsWithDefaults = chArgs + | map { tuple -> + def id_ = tuple[0] + def data_ = tuple[1] + + // TODO: could move fromState to here + + // fetch default params from functionality + def defaultArgs = meta.config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + // fetch overrides in params + def paramArgs = meta.config.allArguments + .findAll { par -> + def argKey = key_ + "__" + par.plainName + params.containsKey(argKey) + } + .collectEntries { [ it.plainName, params[key_ + "__" + it.plainName] ] } + + // fetch overrides in data + def dataArgs = meta.config.allArguments + .findAll { data_.containsKey(it.plainName) } + .collectEntries { [ it.plainName, data_[it.plainName] ] } + + // combine params + def combinedArgs = defaultArgs + paramArgs + workflowArgs.args + dataArgs + + // remove arguments with explicit null values + combinedArgs + .removeAll{_, val -> val == null || val == "viash_no_value" || val == "force_null"} + + combinedArgs = _processInputValues(combinedArgs, meta.config, id_, key_) + + [id_, combinedArgs] + tuple.drop(2) + } + + // TODO: move some of the _meta.join_id wrangling to the safeJoin() function. + def chInitialOutput = chArgsWithDefaults + | _debug(workflowArgs, "processed") + // run workflow + | innerWorkflowFactory(workflowArgs) + // check output tuple + | map { id_, output_ -> + + // see if output map contains metadata + def meta_ = + output_ instanceof Map && output_.containsKey("_meta") ? + output_["_meta"] : + [:] + def join_id = meta_.join_id ?: id_ + + // remove metadata + output_ = output_.findAll{k, v -> k != "_meta"} + + // check value types + output_ = _processOutputValues(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_] + } + // | view{"chInitialOutput: ${it.take(3)}"} + + // join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...] + def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_) + // input tuple format: [join_id, id, output, prev_state, ...] + // output tuple format: [join_id, id, new_state, ...] + | map{ tup -> + def new_state = workflowArgs.toState(tup.drop(1).take(3)) + tup.take(2) + [new_state] + tup.drop(4) + } + + if (workflowArgs.auto.publish == "state") { + def chPublish = 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_) + // 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, ...] + // output tuple format: [id, new_state, ...] + tup.drop(1) + } + | _debug(workflowArgs, "output") + | concat(chPassthrough) + + emit: chReturn + } + + def wf = workflowInstance.cloneWithName(key_) + + // add factory function + wf.metaClass.run = { runArgs -> + workflowFactory(runArgs, workflowArgs, meta) + } + // add config to module for later introspection + wf.metaClass.config = meta.config + + return wf +} + +nextflow.enable.dsl=2 + +// START COMPONENT-SPECIFIC CODE + +// create meta object +meta = [ + "resources_dir": moduleDir.toRealPath().normalize(), + "config": processConfig(readJsonBlob('''{ + "name" : "rseqc_bamstat", + "namespace" : "rseqc", + "version" : "main", + "authors" : [ + { + "name" : "Emma Rousseau", + "roles" : [ + "author", + "maintainer" + ], + "info" : { + "links" : { + "email" : "emma@data-intuitive.com", + "github" : "emmarousseau", + "linkedin" : "emmarousseau1" + }, + "organizations" : [ + { + "name" : "Data Intuitive", + "href" : "https://www.data-intuitive.com", + "role" : "Bioinformatician" + } + ] + } + } + ], + "argument_groups" : [ + { + "name" : "Input", + "arguments" : [ + { + "type" : "file", + "name" : "--input_file", + "alternatives" : [ + "-i" + ], + "description" : "Input alignment file in BAM or SAM format.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "integer", + "name" : "--mapq", + "alternatives" : [ + "-q" + ], + "description" : "Minimum mapping quality (phred scaled) to determine uniquely mapped reads. Default: '30'.\n", + "example" : [ + 30 + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Output", + "arguments" : [ + { + "type" : "file", + "name" : "--output", + "description" : "Output file (txt) with mapping quality statistics.", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Generate statistics from a bam file.", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + }, + { + "type" : "file", + "path" : "test_data" + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "keywords" : [ + "rnaseq", + "genomics" + ], + "license" : "GPL-3.0", + "references" : { + "doi" : [ + "10.1093/bioinformatics/bts356" + ] + }, + "links" : { + "repository" : "https://github.com/MonashBioinformaticsPlatform/RSeQC", + "homepage" : "https://rseqc.sourceforge.net/", + "documentation" : "https://rseqc.sourceforge.net/#bam-stat-py", + "issue_tracker" : "https://github.com/MonashBioinformaticsPlatform/RSeQC/issues" + }, + "runners" : [ + { + "type" : "executable", + "id" : "executable", + "docker_setup_strategy" : "ifneedbepullelsecachedbuild" + }, + { + "type" : "nextflow", + "id" : "nextflow", + "directives" : { + "tag" : "$id" + }, + "auto" : { + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false + }, + "config" : { + "labels" : { + "mem1gb" : "memory = 1000000000.B", + "mem2gb" : "memory = 2000000000.B", + "mem5gb" : "memory = 5000000000.B", + "mem10gb" : "memory = 10000000000.B", + "mem20gb" : "memory = 20000000000.B", + "mem50gb" : "memory = 50000000000.B", + "mem100gb" : "memory = 100000000000.B", + "mem200gb" : "memory = 200000000000.B", + "mem500gb" : "memory = 500000000000.B", + "mem1tb" : "memory = 1000000000000.B", + "mem2tb" : "memory = 2000000000000.B", + "mem5tb" : "memory = 5000000000000.B", + "mem10tb" : "memory = 10000000000000.B", + "mem20tb" : "memory = 20000000000000.B", + "mem50tb" : "memory = 50000000000000.B", + "mem100tb" : "memory = 100000000000000.B", + "mem200tb" : "memory = 200000000000000.B", + "mem500tb" : "memory = 500000000000000.B", + "mem1gib" : "memory = 1073741824.B", + "mem2gib" : "memory = 2147483648.B", + "mem4gib" : "memory = 4294967296.B", + "mem8gib" : "memory = 8589934592.B", + "mem16gib" : "memory = 17179869184.B", + "mem32gib" : "memory = 34359738368.B", + "mem64gib" : "memory = 68719476736.B", + "mem128gib" : "memory = 137438953472.B", + "mem256gib" : "memory = 274877906944.B", + "mem512gib" : "memory = 549755813888.B", + "mem1tib" : "memory = 1099511627776.B", + "mem2tib" : "memory = 2199023255552.B", + "mem4tib" : "memory = 4398046511104.B", + "mem8tib" : "memory = 8796093022208.B", + "mem16tib" : "memory = 17592186044416.B", + "mem32tib" : "memory = 35184372088832.B", + "mem64tib" : "memory = 70368744177664.B", + "mem128tib" : "memory = 140737488355328.B", + "mem256tib" : "memory = 281474976710656.B", + "mem512tib" : "memory = 562949953421312.B", + "cpu1" : "cpus = 1", + "cpu2" : "cpus = 2", + "cpu5" : "cpus = 5", + "cpu10" : "cpus = 10", + "cpu20" : "cpus = 20", + "cpu50" : "cpus = 50", + "cpu100" : "cpus = 100", + "cpu200" : "cpus = 200", + "cpu500" : "cpus = 500", + "cpu1000" : "cpus = 1000" + } + }, + "debug" : false, + "container" : "docker" + } + ], + "engines" : [ + { + "type" : "docker", + "id" : "docker", + "image" : "python:3.10", + "target_registry" : "images.viash-hub.com", + "target_tag" : "main", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "python", + "user" : false, + "packages" : [ + "RSeQC" + ], + "upgrade" : true + }, + { + "type" : "docker", + "run" : [ + "echo \\"RSeQC bam_stat.py: $(bam_stat.py --version | cut -d' ' -f2-)\\" > /var/software_versions.txt\n" + ] + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/rseqc/rseqc_bamstat/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/rseqc/rseqc_bamstat", + "viash_version" : "0.9.0", + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" + }, + "package_config" : { + "name" : "biobox", + "version" : "main", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0", + "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 := 'main'" + ], + "keywords" : [ + "bioinformatics", + "modules", + "sequencing" + ], + "license" : "MIT", + "organization" : "vsh", + "links" : { + "repository" : "https://github.com/viash-hub/biobox", + "issue_tracker" : "https://github.com/viash-hub/biobox/issues" + } + } +}''')) +] + +// resolve dependencies dependencies (if any) + + +// inner workflow +// inner workflow hook +def innerWorkflowFactory(args) { + def rawScript = '''set -e +tempscript=".viash_script.sh" +cat > "$tempscript" << VIASHMAIN +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_INPUT_FILE+x} ]; then echo "${VIASH_PAR_INPUT_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_input_file='&'#" ; else echo "# par_input_file="; fi ) +$( if [ ! -z ${VIASH_PAR_MAPQ+x} ]; then echo "${VIASH_PAR_MAPQ}" | sed "s#'#'\\"'\\"'#g;s#.*#par_mapq='&'#" ; else echo "# par_mapq="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END +#!/bin/bash + + +set -eo pipefail + +bam_stat.py \\\\ + --input-file "\\${par_input_file}" \\\\ + \\${par_mapq:+--mapq "\\${par_mapq}"} \\\\ +> \\$par_output +VIASHMAIN +bash "$tempscript" +''' + + return vdsl3WorkflowFactory(args, meta, rawScript) +} + + + +/** + * Generate a workflow for VDSL3 modules. + * + * This function is called by the workflowFactory() function. + * + * Input channel: [id, input_map] + * Output channel: [id, output_map] + * + * Internally, this workflow will convert the input channel + * to a format which the Nextflow module will be able to handle. + */ +def vdsl3WorkflowFactory(Map args, Map meta, String rawScript) { + def key = args["key"] + def processObj = null + + workflow processWf { + take: input_ + main: + + if (processObj == null) { + processObj = _vdsl3ProcessFactory(args, meta, rawScript) + } + + output_ = input_ + | map { tuple -> + def id = tuple[0] + def data_ = tuple[1] + + if (workflow.stubRun) { + // add id if missing + data_ = [id: 'stub'] + data_ + } + + // process input files separately + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { par -> + def val = data_.containsKey(par.plainName) ? data_[par.plainName] : [] + def inputFiles = [] + if (val == null) { + inputFiles = [] + } else if (val instanceof List) { + inputFiles = val + } else if (val instanceof Path) { + inputFiles = [ val ] + } else { + inputFiles = [] + } + if (!workflow.stubRun) { + // throw error when an input file doesn't exist + inputFiles.each{ file -> + assert file.exists() : + "Error in module '${key}' id '${id}' argument '${par.plainName}'.\n" + + " Required input file does not exist.\n" + + " Path: '$file'.\n" + + " Expected input file to exist" + } + } + inputFiles + } + + // remove input files + def argsExclInputFiles = meta.config.allArguments + .findAll { (it.type != "file" || it.direction != "input") && data_.containsKey(it.plainName) } + .collectEntries { par -> + def parName = par.plainName + def val = data_[parName] + if (par.multiple && val instanceof Collection) { + val = val.join(par.multiple_sep) + } + if (par.direction == "output" && par.type == "file") { + val = val + .replaceAll('\\$id', id) + .replaceAll('\\$\\{id\\}', id) + .replaceAll('\\$key', key) + .replaceAll('\\$\\{key\\}', key) + } + [parName, val] + } + + [ id ] + inputPaths + [ argsExclInputFiles, meta.resources_dir ] + } + | processObj + | map { output -> + def outputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .indexed() + .collectEntries{ index, par -> + def out = output[index + 1] + // strip dummy '.exitcode' file from output (see nextflow-io/nextflow#2678) + if (!out instanceof List || out.size() <= 1) { + if (par.multiple) { + out = [] + } else { + assert !par.required : + "Error in module '${key}' id '${output[0]}' argument '${par.plainName}'.\n" + + " Required output file is missing" + out = null + } + } else if (out.size() == 2 && !par.multiple) { + out = out[1] + } else { + out = out.drop(1) + } + [ par.plainName, out ] + } + + // drop null outputs + outputFiles.removeAll{it.value == null} + + [ output[0], outputFiles ] + } + emit: output_ + } + + return processWf +} + +// depends on: session? +def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) { + // autodetect process key + def wfKey = workflowArgs["key"] + def procKeyPrefix = "${wfKey}_process" + def scriptMeta = nextflow.script.ScriptMeta.current() + def existing = scriptMeta.getProcessNames().findAll{it.startsWith(procKeyPrefix)} + def numbers = existing.collect{it.replace(procKeyPrefix, "0").toInteger()} + def newNumber = (numbers + [-1]).max() + 1 + + def procKey = newNumber == 0 ? procKeyPrefix : "$procKeyPrefix$newNumber" + + if (newNumber > 0) { + log.warn "Key for module '${wfKey}' is duplicated.\n", + "If you run a component multiple times in the same workflow,\n" + + "it's recommended you set a unique key for every call,\n" + + "for example: ${wfKey}.run(key: \"foo\")." + } + + // subset directives and convert to list of tuples + def drctv = workflowArgs.directives + + // TODO: unit test the two commands below + // convert publish array into tags + def valueToStr = { val -> + // ignore closures + if (val instanceof CharSequence) { + if (!val.matches('^[{].*[}]$')) { + '"' + val + '"' + } else { + val + } + } else if (val instanceof List) { + "[" + val.collect{valueToStr(it)}.join(", ") + "]" + } else if (val instanceof Map) { + "[" + val.collect{k, v -> k + ": " + valueToStr(v)}.join(", ") + "]" + } else { + val.inspect() + } + } + + // multiple entries allowed: label, publishdir + def drctvStrs = drctv.collect { key, value -> + if (key in ["label", "publishDir"]) { + value.collect{ val -> + if (val instanceof Map) { + "\n$key " + val.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else if (val == null) { + "" + } else { + "\n$key " + valueToStr(val) + } + }.join() + } else if (value instanceof Map) { + "\n$key " + value.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else { + "\n$key " + valueToStr(value) + } + }.join() + + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { ', path(viash_par_' + it.plainName + ', stageAs: "_viash_par/' + it.plainName + '_?/*")' } + .join() + + def outputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + // insert dummy into every output (see nextflow-io/nextflow#2678) + if (!par.multiple) { + ', path{[".exitcode", args.' + par.plainName + ']}' + } else { + ', path{[".exitcode"] + args.' + par.plainName + '}' + } + } + .join() + + // TODO: move this functionality somewhere else? + if (workflowArgs.auto.transcript) { + outputPaths = outputPaths + ', path{[".exitcode", ".command*"]}' + } else { + outputPaths = outputPaths + ', path{[".exitcode"]}' + } + + // create dirs for output files (based on BashWrapper.createParentFiles) + def createParentStr = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" && it.create_parent } + .collect { par -> + def contents = "args[\"${par.plainName}\"] instanceof List ? args[\"${par.plainName}\"].join('\" \"') : args[\"${par.plainName}\"]" + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent '\" + escapeText(${contents}) + \"'\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def contents = "viash_par_${par.plainName} instanceof List ? viash_par_${par.plainName}.join(\"${par.multiple_sep}\") : viash_par_${par.plainName}" + "\n\${viash_par_${par.plainName}.empty ? \"\" : \"export VIASH_PAR_${par.plainName.toUpperCase()}='\" + escapeText(${contents}) + \"'\"}" + } + + // NOTE: if using docker, use /tmp instead of tmpDir! + def tmpDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('VIASH_TMPDIR') ?: + System.getenv('VIASH_TEMPDIR') ?: + System.getenv('VIASH_TMP') ?: + System.getenv('TEMP') ?: + System.getenv('TMPDIR') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMP') ?: + '/tmp' + ).toAbsolutePath() + + // construct stub + def stub = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + "\${ args.containsKey(\"${par.plainName}\") ? \"touch2 \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"].replace(\"_*\", \"_0\") : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // escape script + def escapedScript = rawScript.replace('\\', '\\\\').replace('$', '\\$').replace('"""', '\\"\\"\\"') + + // publishdir assert + def assertStr = (workflowArgs.auto.publish == true) || workflowArgs.auto.transcript ? + """\nassert task.publishDir.size() > 0: "if auto.publish is true, params.publish_dir needs to be defined.\\n Example: --publish_dir './output/'" """ : + "" + + // generate process string + def procStr = + """nextflow.enable.dsl=2 + | + |def escapeText = { s -> s.toString().replaceAll("'", "'\\\"'\\\"'") } + |process $procKey {$drctvStrs + |input: + | tuple val(id)$inputPaths, val(args), path(resourcesDir, stageAs: ".viash_meta_resources") + |output: + | tuple val("\$id")$outputPaths, optional: true + |stub: + |\"\"\" + |touch2() { mkdir -p "\\\$(dirname "\\\$1")" && touch "\\\$1" ; } + |$stub + |\"\"\" + |script:$assertStr + |def parInject = args + | .findAll{key, value -> value != null} + | .collect{key, value -> "export VIASH_PAR_\${key.toUpperCase()}='\${escapeText(value)}'"} + | .join("\\n") + |\"\"\" + |# meta exports + |export VIASH_META_RESOURCES_DIR="\${resourcesDir}" + |export VIASH_META_TEMP_DIR="${['docker', 'podman', 'charliecloud'].any{ it == workflow.containerEngine } ? '/tmp' : tmpDir}" + |export VIASH_META_NAME="${meta.config.name}" + |# export VIASH_META_EXECUTABLE="\\\$VIASH_META_RESOURCES_DIR/\\\$VIASH_META_NAME" + |export VIASH_META_CONFIG="\\\$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" + |\${task.cpus ? "export VIASH_META_CPUS=\$task.cpus" : "" } + |\${task.memory?.bytes != null ? "export VIASH_META_MEMORY_B=\$task.memory.bytes" : "" } + |if [ ! -z \\\${VIASH_META_MEMORY_B+x} ]; then + | export VIASH_META_MEMORY_KB=\\\$(( (\\\$VIASH_META_MEMORY_B+999) / 1000 )) + | export VIASH_META_MEMORY_MB=\\\$(( (\\\$VIASH_META_MEMORY_KB+999) / 1000 )) + | export VIASH_META_MEMORY_GB=\\\$(( (\\\$VIASH_META_MEMORY_MB+999) / 1000 )) + | export VIASH_META_MEMORY_TB=\\\$(( (\\\$VIASH_META_MEMORY_GB+999) / 1000 )) + | export VIASH_META_MEMORY_PB=\\\$(( (\\\$VIASH_META_MEMORY_TB+999) / 1000 )) + | export VIASH_META_MEMORY_KIB=\\\$(( (\\\$VIASH_META_MEMORY_B+1023) / 1024 )) + | export VIASH_META_MEMORY_MIB=\\\$(( (\\\$VIASH_META_MEMORY_KIB+1023) / 1024 )) + | export VIASH_META_MEMORY_GIB=\\\$(( (\\\$VIASH_META_MEMORY_MIB+1023) / 1024 )) + | export VIASH_META_MEMORY_TIB=\\\$(( (\\\$VIASH_META_MEMORY_GIB+1023) / 1024 )) + | export VIASH_META_MEMORY_PIB=\\\$(( (\\\$VIASH_META_MEMORY_TIB+1023) / 1024 )) + |fi + | + |# meta synonyms + |export VIASH_TEMP="\\\$VIASH_META_TEMP_DIR" + |export TEMP_DIR="\\\$VIASH_META_TEMP_DIR" + | + |# create output dirs if need be + |function mkdir_parent { + | for file in "\\\$@"; do + | mkdir -p "\\\$(dirname "\\\$file")" + | done + |} + |$createParentStr + | + |# argument exports${inputFileExports.join()} + |\$parInject + | + |# process script + |${escapedScript} + |\"\"\" + |} + |""".stripMargin() + + // TODO: print on debug + // if (workflowArgs.debug == true) { + // println("######################\n$procStr\n######################") + // } + + // write process to temp file + def tempFile = java.nio.file.Files.createTempFile("viash-process-${procKey}-", ".nf") + addShutdownHook { java.nio.file.Files.deleteIfExists(tempFile) } + tempFile.text = procStr + + // create process from temp file + def binding = new nextflow.script.ScriptBinding([:]) + def session = nextflow.Nextflow.getSession() + def parser = new nextflow.script.ScriptParser(session) + .setModule(true) + .setBinding(binding) + def moduleScript = parser.runScript(tempFile) + .getScript() + + // register module in meta + def module = new nextflow.script.IncludeDef.Module(name: procKey) + scriptMeta.addModule(moduleScript, module.name, module.alias) + + // retrieve and return process from meta + return scriptMeta.getProcess(procKey) +} + +// defaults +meta["defaults"] = [ + // key to be used to trace the process and determine output names + key: null, + + // fixed arguments to be passed to script + args: [:], + + // default directives + directives: readJsonBlob('''{ + "container" : { + "registry" : "images.viash-hub.com", + "image" : "vsh/biobox/rseqc/rseqc_bamstat", + "tag" : "main" + }, + "tag" : "$id" +}'''), + + // auto settings + auto: readJsonBlob('''{ + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false +}'''), + + // Apply a map over the incoming tuple + // Example: `{ tup -> [ tup[0], [input: tup[1].output] ] + tup.drop(2) }` + map: null, + + // Apply a map over the ID element of a tuple (i.e. the first element) + // Example: `{ id -> id + "_foo" }` + mapId: null, + + // Apply a map over the data element of a tuple (i.e. the second element) + // Example: `{ data -> [ input: data.output ] }` + mapData: null, + + // Apply a map over the passthrough elements of a tuple (i.e. the tuple excl. the first two elements) + // Example: `{ pt -> pt.drop(1) }` + mapPassthrough: null, + + // Filter the channel + // Example: `{ tup -> tup[0] == "foo" }` + filter: null, + + // Choose whether or not to run the component on the tuple if the condition is true. + // Otherwise, the tuple will be passed through. + // Example: `{ tup -> tup[0] != "skip_this" }` + runIf: null, + + // Rename keys in the data field of the tuple (i.e. the second element) + // Will likely be deprecated in favour of `fromState`. + // Example: `[ "new_key": "old_key" ]` + renameKeys: null, + + // Fetch data from the state and pass it to the module without altering the current state. + // + // `fromState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be passed to the module as is. + // - If it is a `List[String]`, the data will be the values of the state at the given keys. + // - If it is a `Map[String, String]`, the data will be the values of the state at the given keys, with the keys renamed according to the map. + // - If it is a function, the tuple (`[id, state]`) in the channel will be passed to the function, and the result will be used as the data. + // + // Example: `{ id, state -> [input: state.fastq_file] }` + // Default: `null` + fromState: null, + + // Determine how the state should be updated after the module has been run. + // + // `toState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be replaced with the output of the module. + // - If it is a `List[String]`, the state will be updated with the values of the data at the given keys. + // - If it is a `Map[String, String]`, the state will be updated with the values of the data at the given keys, with the keys renamed according to the map. + // - If it is a function, a tuple (`[id, output, state]`) will be passed to the function, and the result will be used as the new state. + // + // Example: `{ id, output, state -> state + [counts: state.output] }` + // Default: `{ id, output, state -> output }` + toState: null, + + // Whether or not to print debug messages + // Default: `false` + debug: false +] + +// initialise default workflow +meta["workflow"] = workflowFactory([key: meta.config.name], meta.defaults, meta) + +// add workflow to environment +nextflow.script.ScriptMeta.current().addDefinition(meta.workflow) + +// anonymous workflow for running this module as a standalone +workflow { + // add id argument if it's not already in the config + // TODO: deep copy + def newConfig = deepClone(meta.config) + def newParams = deepClone(params) + + def argsContainsId = newConfig.allArguments.any{it.plainName == "id"} + if (!argsContainsId) { + def idArg = [ + 'name': '--id', + 'required': false, + 'type': 'string', + 'description': 'A unique id for every entry.', + 'multiple': false + ] + newConfig.arguments.add(0, idArg) + newConfig = processConfig(newConfig) + } + if (!newParams.containsKey("id")) { + newParams.id = "run" + } + + helpMessage(newConfig) + + channelFromParams(newParams, newConfig) + // make sure id is not in the state if id is not in the args + | map {id, state -> + if (!argsContainsId) { + [id, state.findAll{k, v -> k != "id"}] + } else { + [id, state] + } + } + | meta.workflow.run( + auto: [ publish: "state" ] + ) +} + +// END COMPONENT-SPECIFIC CODE diff --git a/target/nextflow/rseqc/rseqc_bamstat/nextflow.config b/target/nextflow/rseqc/rseqc_bamstat/nextflow.config new file mode 100644 index 00000000..b9cffed1 --- /dev/null +++ b/target/nextflow/rseqc/rseqc_bamstat/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'rseqc/rseqc_bamstat' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'main' + description = 'Generate statistics from a bam file.' + author = 'Emma Rousseau' +} + +process.container = 'nextflow/bash:latest' + +// detect tempdir +tempDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMPDIR') ?: + '/tmp' +).toAbsolutePath() + +profiles { + no_publish { + process { + withName: '.*' { + publishDir = [ + enabled: false + ] + } + } + } + mount_temp { + docker.temp = tempDir + podman.temp = tempDir + charliecloud.temp = tempDir + } + docker { + docker.enabled = true + // docker.userEmulation = true + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + singularity { + singularity.enabled = true + singularity.autoMounts = true + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + podman { + podman.enabled = true + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + shifter { + shifter.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + } + charliecloud { + charliecloud.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + } +} + +process{ + withLabel: mem1gb { memory = 1000000000.B } + withLabel: mem2gb { memory = 2000000000.B } + withLabel: mem5gb { memory = 5000000000.B } + withLabel: mem10gb { memory = 10000000000.B } + withLabel: mem20gb { memory = 20000000000.B } + withLabel: mem50gb { memory = 50000000000.B } + withLabel: mem100gb { memory = 100000000000.B } + withLabel: mem200gb { memory = 200000000000.B } + withLabel: mem500gb { memory = 500000000000.B } + withLabel: mem1tb { memory = 1000000000000.B } + withLabel: mem2tb { memory = 2000000000000.B } + withLabel: mem5tb { memory = 5000000000000.B } + withLabel: mem10tb { memory = 10000000000000.B } + withLabel: mem20tb { memory = 20000000000000.B } + withLabel: mem50tb { memory = 50000000000000.B } + withLabel: mem100tb { memory = 100000000000000.B } + withLabel: mem200tb { memory = 200000000000000.B } + withLabel: mem500tb { memory = 500000000000000.B } + withLabel: mem1gib { memory = 1073741824.B } + withLabel: mem2gib { memory = 2147483648.B } + withLabel: mem4gib { memory = 4294967296.B } + withLabel: mem8gib { memory = 8589934592.B } + withLabel: mem16gib { memory = 17179869184.B } + withLabel: mem32gib { memory = 34359738368.B } + withLabel: mem64gib { memory = 68719476736.B } + withLabel: mem128gib { memory = 137438953472.B } + withLabel: mem256gib { memory = 274877906944.B } + withLabel: mem512gib { memory = 549755813888.B } + withLabel: mem1tib { memory = 1099511627776.B } + withLabel: mem2tib { memory = 2199023255552.B } + withLabel: mem4tib { memory = 4398046511104.B } + withLabel: mem8tib { memory = 8796093022208.B } + withLabel: mem16tib { memory = 17592186044416.B } + withLabel: mem32tib { memory = 35184372088832.B } + withLabel: mem64tib { memory = 70368744177664.B } + withLabel: mem128tib { memory = 140737488355328.B } + withLabel: mem256tib { memory = 281474976710656.B } + withLabel: mem512tib { memory = 562949953421312.B } + withLabel: cpu1 { cpus = 1 } + withLabel: cpu2 { cpus = 2 } + withLabel: cpu5 { cpus = 5 } + withLabel: cpu10 { cpus = 10 } + withLabel: cpu20 { cpus = 20 } + withLabel: cpu50 { cpus = 50 } + withLabel: cpu100 { cpus = 100 } + withLabel: cpu200 { cpus = 200 } + withLabel: cpu500 { cpus = 500 } + withLabel: cpu1000 { cpus = 1000 } +} + + diff --git a/target/nextflow/rseqc/rseqc_bamstat/nextflow_schema.json b/target/nextflow/rseqc/rseqc_bamstat/nextflow_schema.json new file mode 100644 index 00000000..21b1df1b --- /dev/null +++ b/target/nextflow/rseqc/rseqc_bamstat/nextflow_schema.json @@ -0,0 +1,105 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "rseqc_bamstat", +"description": "Generate statistics from a bam file.", +"type": "object", +"definitions": { + + + + "input" : { + "title": "Input", + "type": "object", + "description": "No description", + "properties": { + + + "input_file": { + "type": + "string", + "description": "Type: `file`, required. Input alignment file in BAM or SAM format", + "help_text": "Type: `file`, required. Input alignment file in BAM or SAM format." + + } + + + , + "mapq": { + "type": + "integer", + "description": "Type: `integer`, example: `30`. Minimum mapping quality (phred scaled) to determine uniquely mapped reads", + "help_text": "Type: `integer`, example: `30`. Minimum mapping quality (phred scaled) to determine uniquely mapped reads. Default: \u002730\u0027.\n" + + } + + +} +}, + + + "output" : { + "title": "Output", + "type": "object", + "description": "No description", + "properties": { + + + "output": { + "type": + "string", + "description": "Type: `file`, default: `$id.$key.output.output`. Output file (txt) with mapping quality statistics", + "help_text": "Type: `file`, default: `$id.$key.output.output`. Output file (txt) with mapping quality statistics." + , + "default": "$id.$key.output.output" + } + + +} +}, + + + "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" + }, + + { + "$ref": "#/definitions/output" + }, + + { + "$ref": "#/definitions/nextflow input-output arguments" + } +] +} diff --git a/target/nextflow/rseqc/rseqc_inferexperiment/.config.vsh.yaml b/target/nextflow/rseqc/rseqc_inferexperiment/.config.vsh.yaml new file mode 100644 index 00000000..2b628405 --- /dev/null +++ b/target/nextflow/rseqc/rseqc_inferexperiment/.config.vsh.yaml @@ -0,0 +1,228 @@ +name: "rseqc_inferexperiment" +namespace: "rseqc" +version: "main" +authors: +- name: "Emma Rousseau" + roles: + - "author" + - "maintainer" + info: + links: + email: "emma@data-intuitive.com" + github: "emmarousseau" + linkedin: "emmarousseau1" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Bioinformatician" +argument_groups: +- name: "Input" + arguments: + - type: "file" + name: "--input_file" + alternatives: + - "-i" + description: "input alignment file in BAM or SAM format" + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--refgene" + alternatives: + - "-r" + description: "Reference gene model in bed format" + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Output" + arguments: + - type: "file" + name: "--output" + description: "Output file (txt) of strandness report." + info: null + example: + - "$id.strandedness.txt" + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "integer" + name: "--sample_size" + alternatives: + - "-s" + description: "Number of reads sampled from SAM/BAM file. Default: 200000\n" + info: null + example: + - 200000 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--mapq" + alternatives: + - "-q" + description: "Minimum mapping quality (phred scaled) to determine uniquely mapped\ + \ reads. Default: 30\n" + info: null + example: + - 30 + required: false + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Infer strandedness from sequencing reads\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +license: "GPL-3.0" +references: + doi: + - "10.1093/bioinformatics/bts356" +links: + repository: "https://github.com/MonashBioinformaticsPlatform/RSeQC" + homepage: "https://rseqc.sourceforge.net/" + documentation: "https://rseqc.sourceforge.net/#infer-experiment-py" + issue_tracker: "https://github.com/MonashBioinformaticsPlatform/RSeQC/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "python:3.10" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "python" + user: false + packages: + - "RSeQC" + upgrade: true + - type: "docker" + run: + - "echo \"RSeQC - infer_experiment.py: $(infer_experiment.py --version | cut -d'\ + \ ' -f2)\" > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/rseqc/rseqc_inferexperiment/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/rseqc/rseqc_inferexperiment" + executable: "target/nextflow/rseqc/rseqc_inferexperiment/main.nf" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/nextflow/rseqc/rseqc_inferexperiment/main.nf b/target/nextflow/rseqc/rseqc_inferexperiment/main.nf new file mode 100644 index 00000000..308162e2 --- /dev/null +++ b/target/nextflow/rseqc/rseqc_inferexperiment/main.nf @@ -0,0 +1,3630 @@ +// rseqc_inferexperiment main +// +// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +// Intuitive. +// +// The component may contain files which fall under a different license. The +// authors of this component should specify the license in the header of such +// files, or include a separate license file detailing the licenses of all included +// files. +// +// Component authors: +// * Emma Rousseau (author, maintainer) + +//////////////////////////// +// VDSL3 helper functions // +//////////////////////////// + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_checkArgumentType.nf' +class UnexpectedArgumentTypeException extends Exception { + String errorIdentifier + String stage + String plainName + String expectedClass + String foundClass + + // ${key ? " in module '$key'" : ""}${id ? " id '$id'" : ""} + UnexpectedArgumentTypeException(String errorIdentifier, String stage, String plainName, String expectedClass, String foundClass) { + super("Error${errorIdentifier ? " $errorIdentifier" : ""}:${stage ? " $stage" : "" } argument '${plainName}' has the wrong type. " + + "Expected type: ${expectedClass}. Found type: ${foundClass}") + this.errorIdentifier = errorIdentifier + this.stage = stage + this.plainName = plainName + this.expectedClass = expectedClass + this.foundClass = foundClass + } +} + +/** + * Checks if the given value is of the expected type. If not, an exception is thrown. + * + * @param stage The stage of the argument (input or output) + * @param par The parameter definition + * @param value The value to check + * @param errorIdentifier The identifier to use in the error message + * @return The value, if it is of the expected type + * @throws UnexpectedArgumentTypeException If the value is not of the expected type +*/ +def _checkArgumentType(String stage, Map par, Object value, String errorIdentifier) { + // expectedClass will only be != null if value is not of the expected type + def expectedClass = null + def foundClass = null + + // todo: split if need be + + if (!par.required && value == null) { + expectedClass = null + } else if (par.multiple) { + if (value !instanceof Collection) { + value = [value] + } + + // split strings + value = value.collectMany{ val -> + if (val instanceof String) { + // collect() to ensure that the result is a List and not simply an array + val.split(par.multiple_sep).collect() + } else { + [val] + } + } + + // process globs + if (par.type == "file" && par.direction == "input") { + value = value.collect{ it instanceof String ? file(it, hidden: true) : it }.flatten() + } + + // check types of elements in list + try { + value = value.collect { listVal -> + _checkArgumentType(stage, par + [multiple: false], listVal, errorIdentifier) + } + } catch (UnexpectedArgumentTypeException e) { + expectedClass = "List[${e.expectedClass}]" + foundClass = "List[${e.foundClass}]" + } + } else if (par.type == "string") { + // cast to string if need be + if (value instanceof GString) { + value = value.toString() + } + expectedClass = value instanceof String ? null : "String" + } else if (par.type == "integer") { + // cast to integer if need be + if (value instanceof String) { + try { + value = value.toInteger() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toLong() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toDouble() + } catch (NumberFormatException e) { + // do nothing + } + } + if (value instanceof java.math.BigDecimal) { + value = value.doubleValue() + } + 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 + } + } + 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) { + value = file(value, hidden: true) + } + if (value instanceof File) { + value = value.toPath() + } + 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() + } + expectedClass = value instanceof String ? null : "String" + } else { + // didn't find a match for par.type + expectedClass = par.type + } + + if (expectedClass != null) { + if (foundClass == null) { + foundClass = value.getClass().getName() + } + throw new UnexpectedArgumentTypeException(errorIdentifier, stage, par.plainName, expectedClass, foundClass) + } + + return value +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processInputValues.nf' +Map _processInputValues(Map inputs, Map config, String id, String key) { + if (!workflow.stubRun) { + config.allArguments.each { arg -> + if (arg.required) { + assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null : + "Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing" + } + } + + inputs = inputs.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid input argument" + + value = _checkArgumentType("input", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return inputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf' +Map _processOutputValues(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" + + value = _checkArgumentType("output", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return outputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf' +class IDChecker { + final def items = [] as Set + + @groovy.transform.WithWriteLock + boolean observe(String item) { + if (items.contains(item)) { + return false + } else { + items << item + return true + } + } + + @groovy.transform.WithReadLock + boolean contains(String item) { + return items.contains(item) + } + + @groovy.transform.WithReadLock + Set getItems() { + return items.clone() + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_checkUniqueIds.nf' + +/** + * Check if the ids are unique across parameter sets + * + * @param parameterSets a list of parameter sets. + */ +private void _checkUniqueIds(List>> parameterSets) { + def ppIds = parameterSets.collect{it[0]} + assert ppIds.size() == ppIds.unique().size() : "All argument sets should have unique ids. Detected ids: $ppIds" +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_getChild.nf' + +// helper functions for reading params from file // +def _getChild(parent, child) { + if (child.contains("://") || java.nio.file.Paths.get(child).isAbsolute()) { + child + } else { + def parentAbsolute = java.nio.file.Paths.get(parent).toAbsolutePath().toString() + parentAbsolute.replaceAll('/[^/]*$', "/") + child + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_parseParamList.nf' +/** + * Figure out the param list format based on the file extension + * + * @param param_list A String containing the path to the parameter list file. + * + * @return A String containing the format of the parameter list file. + */ +def _paramListGuessFormat(param_list) { + if (param_list !instanceof String) { + "asis" + } else if (param_list.endsWith(".csv")) { + "csv" + } else if (param_list.endsWith(".json") || param_list.endsWith(".jsn")) { + "json" + } else if (param_list.endsWith(".yaml") || param_list.endsWith(".yml")) { + "yaml" + } else { + "yaml_blob" + } +} + + +/** + * Read the param list + * + * @param param_list One of the following: + * - A String containing the path to the parameter list file (csv, json or yaml), + * - A yaml blob of a list of maps (yaml_blob), + * - Or a groovy list of maps (asis). + * @param config A Map of the Viash configuration. + * + * @return A List of Maps containing the parameters. + */ +def _parseParamList(param_list, Map config) { + // first determine format by extension + def paramListFormat = _paramListGuessFormat(param_list) + + def paramListPath = (paramListFormat != "asis" && paramListFormat != "yaml_blob") ? + file(param_list, hidden: true) : + null + + // get the correct parser function for the detected params_list format + def paramSets = [] + if (paramListFormat == "asis") { + paramSets = param_list + } else if (paramListFormat == "yaml_blob") { + paramSets = readYamlBlob(param_list) + } else if (paramListFormat == "yaml") { + paramSets = readYaml(paramListPath) + } else if (paramListFormat == "json") { + paramSets = readJson(paramListPath) + } else if (paramListFormat == "csv") { + paramSets = readCsv(paramListPath) + } else { + error "Format of provided --param_list not recognised.\n" + + "Found: '$paramListFormat'.\n" + + "Expected: a csv file, a json file, a yaml file,\n" + + "a yaml blob or a groovy list of maps." + } + + // data checks + assert paramSets instanceof List: "--param_list should contain a list of maps" + for (value in paramSets) { + assert value instanceof Map: "--param_list should contain a list of maps" + } + + // id is argument + def idIsArgument = config.allArguments.any{it.plainName == "id"} + + // Reformat from List to List> by adding the ID as first element of a Tuple2 + paramSets = paramSets.collect({ data -> + def id = data.id + if (!idIsArgument) { + data = data.findAll{k, v -> k != "id"} + } + [id, data] + }) + + // Split parameters with 'multiple: true' + paramSets = paramSets.collect({ id, data -> + data = _splitParams(data, config) + [id, data] + }) + + // The paths of input files inside a param_list file may have been specified relatively to the + // location of the param_list file. These paths must be made absolute. + if (paramListPath) { + paramSets = paramSets.collect({ id, data -> + def new_data = data.collectEntries{ parName, parValue -> + def par = config.allArguments.find{it.plainName == parName} + if (par && par.type == "file" && par.direction == "input") { + if (parValue instanceof Collection) { + parValue = parValue.collectMany{path -> + def x = _resolveSiblingIfNotAbsolute(path, paramListPath) + x instanceof Collection ? x : [x] + } + } else { + parValue = _resolveSiblingIfNotAbsolute(parValue, paramListPath) + } + } + [parName, parValue] + } + [id, new_data] + }) + } + + return paramSets +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_splitParams.nf' +/** + * Split parameters for arguments that accept multiple values using their separator + * + * @param paramList A Map containing parameters to split. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A Map of parameters where the parameter values have been split into a list using + * their seperator. + */ +Map _splitParams(Map parValues, Map config){ + def parsedParamValues = parValues.collectEntries { parName, parValue -> + def parameterSettings = config.allArguments.find({it.plainName == parName}) + + if (!parameterSettings) { + // if argument is not found, do not alter + return [parName, parValue] + } + if (parameterSettings.multiple) { // Check if parameter can accept multiple values + if (parValue instanceof Collection) { + parValue = parValue.collect{it instanceof String ? it.split(parameterSettings.multiple_sep) : it } + } else if (parValue instanceof String) { + parValue = parValue.split(parameterSettings.multiple_sep) + } else if (parValue == null) { + parValue = [] + } else { + parValue = [ parValue ] + } + parValue = parValue.flatten() + } + // For all parameters check if multiple values are only passed for + // arguments that allow it. Quietly simplify lists of length 1. + if (!parameterSettings.multiple && parValue instanceof Collection) { + assert parValue.size() == 1 : + "Error: argument ${parName} has too many values.\n" + + " Expected amount: 1. Found: ${parValue.size()}" + parValue = parValue[0] + } + [parName, parValue] + } + return parsedParamValues +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/channelFromParams.nf' +/** + * Parse nextflow parameters based on settings defined in a viash config. + * Return a list of parameter sets, each parameter set corresponding to + * an event in a nextflow channel. The output from this function can be used + * with Channel.fromList to create a nextflow channel with Vdsl3 formatted + * events. + * + * This function performs: + * - A filtering of the params which can be found in the config file. + * - Process the params_list argument which allows a user to to initialise + * a Vsdl3 channel with multiple parameter sets. Possible formats are + * csv, json, yaml, or simply a yaml_blob. A csv should have column names + * which correspond to the different arguments of this pipeline. A json or a yaml + * file should be a list of maps, each of which has keys corresponding to the + * arguments of the pipeline. A yaml blob can also be passed directly as a parameter. + * When passing a csv, json or yaml, relative path names are relativized to the + * location of the parameter file. + * - Combine the parameter sets into a vdsl3 Channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A list of parameters with the first element of the event being + * the event ID and the second element containing a map of the parsed parameters. + */ + +private List>> _paramsToParamSets(Map params, Map config){ + // todo: fetch key from run args + def key_ = config.name + + /* parse regular parameters (not in param_list) */ + /*************************************************/ + def globalParams = config.allArguments + .findAll { params.containsKey(it.plainName) } + .collectEntries { [ it.plainName, params[it.plainName] ] } + def globalID = params.get("id", null) + + /* process params_list arguments */ + /*********************************/ + def paramList = params.containsKey("param_list") && params.param_list != null ? + params.param_list : [] + // if (paramList instanceof String) { + // paramList = [paramList] + // } + // def paramSets = paramList.collectMany{ _parseParamList(it, config) } + // TODO: be able to process param_list when it is a list of strings + def paramSets = _parseParamList(paramList, config) + if (paramSets.isEmpty()) { + paramSets = [[null, [:]]] + } + + /* combine arguments into channel */ + /**********************************/ + def processedParams = paramSets.indexed().collect{ index, tup -> + // Process ID + def id = tup[0] ?: globalID + + if (workflow.stubRun && !id) { + // if stub run, explicitly add an id if missing + id = "stub${index}" + } + assert id != null: "Each parameter set should have at least an 'id'" + + // Process params + def parValues = globalParams + tup[1] + // // Remove parameters which are null, if the default is also null + // parValues = parValues.collectEntries{paramName, paramValue -> + // parameterSettings = config.functionality.allArguments.find({it.plainName == paramName}) + // if ( paramValue != null || parameterSettings.get("default", null) != null ) { + // [paramName, paramValue] + // } + // } + parValues = parValues.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key_}' id '${id}': '${name}' is not a valid input argument" + + if (par == null) { + return [:] + } + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + + [ name, value ] + } + + [id, parValues] + } + + // Check if ids (first element of each list) is unique + _checkUniqueIds(processedParams) + return processedParams +} + +/** + * Parse nextflow parameters based on settings defined in a viash config + * and return a nextflow channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A nextflow Channel with events. Events are formatted as a tuple that contains + * first contains the ID of the event and as second element holds a parameter map. + * + * + */ +def channelFromParams(Map params, Map config) { + def processedParams = _paramsToParamSets(params, config) + return Channel.fromList(processedParams) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/checkUniqueIds.nf' +def checkUniqueIds(Map args) { + def stopOnError = args.stopOnError == null ? args.stopOnError : true + + def idChecker = new IDChecker() + + return filter { tup -> + if (!idChecker.observe(tup[0])) { + if (stopOnError) { + error "Duplicate id: ${tup[0]}" + } else { + log.warn "Duplicate id: ${tup[0]}, removing duplicate entry" + return false + } + } + return true + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/preprocessInputs.nf' +// This helper file will be deprecated soon +preprocessInputsDeprecationWarningPrinted = false + +def preprocessInputsDeprecationWarning() { + if (!preprocessInputsDeprecationWarningPrinted) { + preprocessInputsDeprecationWarningPrinted = true + System.err.println("Warning: preprocessInputs() is deprecated and will be removed in Viash 0.9.0.") + } +} + +/** + * Generate a nextflow Workflow that allows processing a channel of + * Vdsl3 formatted events and apply a Viash config to them: + * - Gather default parameters from the Viash config and make + * sure that they are correctly formatted (see applyConfig method). + * - Format the input parameters (also using the applyConfig method). + * - Apply the default parameter to the input parameters. + * - Do some assertions: + * ~ Check if the event IDs in the channel are unique. + * + * The events in the channel are formatted as tuples, with the + * first element of the tuples being a unique id of the parameter set, + * and the second element containg the the parameters themselves. + * Optional extra elements of the tuples will be passed to the output as is. + * + * @param args A map that must contain a 'config' key that points + * to a parsed config (see readConfig()). Optionally, a + * 'key' key can be provided which can be used to create a unique + * name for the workflow process. + * + * @return A workflow that allows processing a channel of Vdsl3 formatted events + * and apply a Viash config to them. + */ +def preprocessInputs(Map args) { + preprocessInputsDeprecationWarning() + + def config = args.config + assert config instanceof Map : + "Error in preprocessInputs: config must be a map. " + + "Expected class: Map. Found: config.getClass() is ${config.getClass()}" + def key_ = args.key ?: config.name + + // Get different parameter types (used throughout this function) + def defaultArgs = config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + map { tup -> + def id = tup[0] + def data = tup[1] + def passthrough = tup.drop(2) + + def new_data = (defaultArgs + data).collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + + if (par != null) { + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + } + + [ name, value ] + } + + [ id, new_data ] + passthrough + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runComponents.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component config. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component config. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component config. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component config. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runComponents(Map args) { + log.warn("runComponents is deprecated, use runEach instead") + assert args.components: "runComponents should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runComponents" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def id_ = args.id + + workflow runComponentsWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def comp_config = comp_.config + + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_config) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + // def new_id = id_(tup[0], tup[1], comp_config) + def new_id = tup[0] + if (id_ instanceof String) { + new_id = id_ + } else if (id_ instanceof Closure) { + new_id = id_(new_id, tup[1], comp_config) + } + [new_id] + tup.drop(1) + } + : filter_ch + def data_ch = id_ch | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_config) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_config) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + post_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runComponentsWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runEach.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component itself. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component itself. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component itself. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component itself. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runEach(Map args) { + assert args.components: "runEach should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runEach" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def runIf_ = args.runIf + def id_ = args.id + + assert !runIf_ || runIf_ instanceof Closure: "runEach: must pass a Closure to runIf." + + workflow runEachWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + def new_id = id_ + if (new_id instanceof Closure) { + new_id = new_id(tup[0], tup[1], comp_) + } + assert new_id instanceof String : "Error in runEach: id should be a String or a Closure that returns a String. Expected: id instanceof String. Found: ${new_id.getClass()}" + [new_id] + tup.drop(1) + } + : filter_ch + def chPassthrough = null + def chRun = null + if (runIf_) { + def idRunIfBranch = id_ch.branch{ tup -> + run: runIf_(tup[0], tup[1], comp_) + passthrough: true + } + chPassthrough = idRunIfBranch.passthrough + chRun = idRunIfBranch.run + } else { + chRun = id_ch + chPassthrough = Channel.empty() + } + def data_ch = chRun | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + def return_ch = post_ch + | concat(chPassthrough) + + return_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runEachWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/safeJoin.nf' +/** + * Join sourceChannel to targetChannel + * + * This function joins the sourceChannel to the targetChannel. + * However, each id in the targetChannel must be present in the + * sourceChannel. If _meta.join_id exists in the targetChannel, that is + * used as an id instead. If the id doesn't match any id in the sourceChannel, + * an error is thrown. + */ + +def safeJoin(targetChannel, sourceChannel, key) { + def sourceIDs = new IDChecker() + + def sourceCheck = sourceChannel + | map { tup -> + sourceIDs.observe(tup[0]) + tup + } + def targetCheck = targetChannel + | map { tup -> + def id = tup[0] + + if (!sourceIDs.contains(id)) { + error ( + "Error in module '${key}' when merging output with original state.\n" + + " Reason: output with id '${id}' could not be joined with source channel.\n" + + " If the IDs in the output channel differ from the input channel,\n" + + " please set `tup[1]._meta.join_id to the original ID.\n" + + " Original IDs in input channel: ['${sourceIDs.getItems().join("', '")}'].\n" + + " Unexpected ID in the output channel: '${id}'.\n" + + " Example input event: [\"id\", [input: file(...)]],\n" + + " Example output event: [\"newid\", [output: file(...), _meta: [join_id: \"id\"]]]" + ) + } + // TODO: add link to our documentation on how to fix this + + tup + } + + sourceCheck.cross(targetChannel) + | map{ left, right -> + right + left.drop(1) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/_processArgument.nf' +def _processArgument(arg) { + arg.multiple = arg.multiple != null ? arg.multiple : false + arg.required = arg.required != null ? arg.required : false + arg.direction = arg.direction != null ? arg.direction : "input" + arg.multiple_sep = arg.multiple_sep != null ? arg.multiple_sep : ";" + arg.plainName = arg.name.replaceAll("^-*", "") + + if (arg.type == "file") { + arg.must_exist = arg.must_exist != null ? arg.must_exist : true + arg.create_parent = arg.create_parent != null ? arg.create_parent : true + } + + // add default values to output files which haven't already got a default + if (arg.type == "file" && arg.direction == "output" && arg.default == null) { + def mult = arg.multiple ? "_*" : "" + def extSearch = "" + if (arg.default != null) { + extSearch = arg.default + } else if (arg.example != null) { + extSearch = arg.example + } + if (extSearch instanceof List) { + extSearch = extSearch[0] + } + def extSearchResult = extSearch.find("\\.[^\\.]+\$") + def ext = extSearchResult != null ? extSearchResult : "" + arg.default = "\$id.\$key.${arg.plainName}${mult}${ext}" + if (arg.multiple) { + arg.default = [arg.default] + } + } + + if (!arg.multiple) { + if (arg.default != null && arg.default instanceof List) { + arg.default = arg.default[0] + } + if (arg.example != null && arg.example instanceof List) { + arg.example = arg.example[0] + } + } + + if (arg.type == "boolean_true") { + arg.default = false + } + if (arg.type == "boolean_false") { + arg.default = true + } + + arg +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/addGlobalParams.nf' +def addGlobalArguments(config) { + def localConfig = [ + "argument_groups": [ + [ + "name": "Nextflow input-output arguments", + "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.", + "arguments" : [ + [ + 'name': '--publish_dir', + 'required': true, + 'type': 'string', + 'description': 'Path to an output directory.', + 'example': 'output/', + 'multiple': false + ], + [ + 'name': '--param_list', + 'required': false, + 'type': 'string', + 'description': '''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. + | + |* 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: [ ['id': 'foo', 'input': 'foo.txt'], ['id': 'bar', 'input': 'bar.txt'] ]`. + |* 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`. + |* 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 `[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]`. + |* A yaml blob can also be passed directly as a string. Example: `--param_list "[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]"`. + | + |When 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.'''.stripMargin(), + 'example': 'my_params.yaml', + 'multiple': false, + 'hidden': true + ] + // TODO: allow multiple: true in param_list? + // TODO: allow to specify a --param_list_regex to filter the param_list? + // TODO: allow to specify a --param_list_from_state to remap entries in the param_list? + ] + ] + ] + ] + + return processConfig(_mergeMap(config, localConfig)) +} + +def _mergeMap(Map lhs, Map rhs) { + return rhs.inject(lhs.clone()) { map, entry -> + if (map[entry.key] instanceof Map && entry.value instanceof Map) { + map[entry.key] = _mergeMap(map[entry.key], entry.value) + } else if (map[entry.key] instanceof Collection && entry.value instanceof Collection) { + map[entry.key] += entry.value + } else { + map[entry.key] = entry.value + } + return map + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/generateHelp.nf' +def _generateArgumentHelp(param) { + // alternatives are not supported + // def names = param.alternatives ::: List(param.name) + + def unnamedProps = [ + ["required parameter", param.required], + ["multiple values allowed", param.multiple], + ["output", param.direction.toLowerCase() == "output"], + ["file must exist", param.type == "file" && param.must_exist] + ].findAll{it[1]}.collect{it[0]} + + def dflt = null + if (param.default != null) { + if (param.default instanceof List) { + dflt = param.default.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + dflt = param.default.toString() + } + } + def example = null + if (param.example != null) { + if (param.example instanceof List) { + example = param.example.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + example = param.example.toString() + } + } + def min = param.min?.toString() + def max = param.max?.toString() + + def escapeChoice = { choice -> + def s1 = choice.replaceAll("\\n", "\\\\n") + def s2 = s1.replaceAll("\"", """\\\"""") + s2.contains(",") || s2 != choice ? "\"" + s2 + "\"" : s2 + } + def choices = param.choices == null ? + null : + "[ " + param.choices.collect{escapeChoice(it.toString())}.join(", ") + " ]" + + def namedPropsStr = [ + ["type", ([param.type] + unnamedProps).join(", ")], + ["default", dflt], + ["example", example], + ["choices", choices], + ["min", min], + ["max", max] + ] + .findAll{it[1]} + .collect{"\n " + it[0] + ": " + it[1].replaceAll("\n", "\\n")} + .join("") + + def descStr = param.description == null ? + "" : + _paragraphWrap("\n" + param.description.trim(), 80 - 8).join("\n ") + + "\n --" + param.plainName + + namedPropsStr + + descStr +} + +// Based on Helper.generateHelp() in Helper.scala +def _generateHelp(config) { + def fun = config + + // PART 1: NAME AND VERSION + def nameStr = fun.name + + (fun.version == null ? "" : " " + fun.version) + + // PART 2: DESCRIPTION + def descrStr = fun.description == null ? + "" : + "\n\n" + _paragraphWrap(fun.description.trim(), 80).join("\n") + + // PART 3: Usage + def usageStr = fun.usage == null ? + "" : + "\n\nUsage:\n" + fun.usage.trim() + + // PART 4: Options + def argGroupStrs = fun.allArgumentGroups.collect{argGroup -> + def name = argGroup.name + def descriptionStr = argGroup.description == null ? + "" : + "\n " + _paragraphWrap(argGroup.description.trim(), 80-4).join("\n ") + "\n" + def arguments = argGroup.arguments.collect{arg -> + arg instanceof String ? fun.allArguments.find{it.plainName == arg} : arg + }.findAll{it != null} + def argumentStrs = arguments.collect{param -> _generateArgumentHelp(param)} + + "\n\n$name:" + + descriptionStr + + argumentStrs.join("\n") + } + + // FINAL: combine + def out = nameStr + + descrStr + + usageStr + + argGroupStrs.join("") + + return out +} + +// based on Format._paragraphWrap +def _paragraphWrap(str, maxLength) { + def outLines = [] + str.split("\n").each{par -> + def words = par.split("\\s").toList() + + def word = null + def line = words.pop() + while(!words.isEmpty()) { + word = words.pop() + if (line.length() + word.length() + 1 <= maxLength) { + line = line + " " + word + } else { + outLines.add(line) + line = word + } + } + if (words.isEmpty()) { + outLines.add(line) + } + } + return outLines +} + +def helpMessage(config) { + if (params.containsKey("help") && params.help) { + def mergedConfig = addGlobalArguments(config) + def helpStr = _generateHelp(mergedConfig) + println(helpStr) + exit 0 + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/processConfig.nf' +def processConfig(config) { + // set defaults for arguments + config.arguments = + (config.arguments ?: []).collect{_processArgument(it)} + + // set defaults for argument_group arguments + config.argument_groups = + (config.argument_groups ?: []).collect{grp -> + grp.arguments = (grp.arguments ?: []).collect{_processArgument(it)} + grp + } + + // create combined arguments list + config.allArguments = + config.arguments + + config.argument_groups.collectMany{it.arguments} + + // add missing argument groups (based on Functionality::allArgumentGroups()) + def argGroups = config.argument_groups + if (argGroups.any{it.name.toLowerCase() == "arguments"}) { + argGroups = argGroups.collect{ grp -> + if (grp.name.toLowerCase() == "arguments") { + grp = grp + [ + arguments: grp.arguments + config.arguments + ] + } + grp + } + } else { + argGroups = argGroups + [ + name: "Arguments", + arguments: config.arguments + ] + } + config.allArgumentGroups = argGroups + + config +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/readConfig.nf' + +def readConfig(file) { + def config = readYaml(file ?: moduleDir.resolve("config.vsh.yaml")) + processConfig(config) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_resolveSiblingIfNotAbsolute.nf' +/** + * Resolve a path relative to the current file. + * + * @param str The path to resolve, as a String. + * @param parentPath The path to resolve relative to, as a Path. + * + * @return The path that may have been resovled, as a Path. + */ +def _resolveSiblingIfNotAbsolute(str, parentPath) { + if (str !instanceof String) { + return str + } + if (!_stringIsAbsolutePath(str)) { + return parentPath.resolveSibling(str) + } else { + return file(str, hidden: true) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_stringIsAbsolutePath.nf' +/** + * Check whether a path as a string is absolute. + * + * In the past, we tried using `file(., relative: true).isAbsolute()`, + * but the 'relative' option was added in 22.10.0. + * + * @param path The path to check, as a String. + * + * @return Whether the path is absolute, as a boolean. + */ +def _stringIsAbsolutePath(path) { + def _resolve_URL_PROTOCOL = ~/^([a-zA-Z][a-zA-Z0-9]*:)?\\/.+/ + + assert path instanceof String + return _resolve_URL_PROTOCOL.matcher(path).matches() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/collectTraces.nf' +class CustomTraceObserver implements nextflow.trace.TraceObserver { + List traces + + CustomTraceObserver(List traces) { + this.traces = traces + } + + @Override + void onProcessComplete(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } + + @Override + void onProcessCached(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } +} + +def collectTraces() { + def traces = Collections.synchronizedList([]) + + // add custom trace observer which stores traces in the traces object + session.observers.add(new CustomTraceObserver(traces)) + + traces +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/deepClone.nf' +/** + * Performs a deep clone of the given object. + * @param x an object + */ +def deepClone(x) { + iterateMap(x, {it instanceof Cloneable ? it.clone() : it}) +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getPublishDir.nf' +def getPublishDir() { + return params.containsKey("publish_dir") ? params.publish_dir : + params.containsKey("publishDir") ? params.publishDir : + null +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getRootDir.nf' + +// Recurse upwards until we find a '.build.yaml' file +def _findBuildYamlFile(pathPossiblySymlink) { + def path = pathPossiblySymlink.toRealPath() + def child = path.resolve(".build.yaml") + if (java.nio.file.Files.isDirectory(path) && java.nio.file.Files.exists(child)) { + return child + } else { + def parent = path.getParent() + if (parent == null) { + return null + } else { + return _findBuildYamlFile(parent) + } + } +} + +// get the root of the target folder +def getRootDir() { + def dir = _findBuildYamlFile(meta.resources_dir) + assert dir != null: "Could not find .build.yaml in the folder structure" + dir.getParent() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/iterateMap.nf' +/** + * Recursively apply a function over the leaves of an object. + * @param obj The object to iterate over. + * @param fun The function to apply to each value. + * @return The object with the function applied to each value. + */ +def iterateMap(obj, fun) { + if (obj instanceof List && obj !instanceof String) { + return obj.collect{item -> + iterateMap(item, fun) + } + } else if (obj instanceof Map) { + return obj.collectEntries{key, item -> + [key.toString(), iterateMap(item, fun)] + } + } else { + return fun(obj) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/niceView.nf' +/** + * A view for printing the event of each channel as a YAML blob. + * This is useful for debugging. + */ +def niceView() { + workflow niceViewWf { + take: input + main: + output = input + | view{toYamlBlob(it)} + emit: output + } + return niceViewWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readCsv.nf' + +def readCsv(file_path) { + def output = [] + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + + // todo: allow escaped quotes in string + // todo: allow single quotes? + def splitRegex = java.util.regex.Pattern.compile(''',(?=(?:[^"]*"[^"]*")*[^"]*$)''') + def removeQuote = java.util.regex.Pattern.compile('''"(.*)"''') + + def br = java.nio.file.Files.newBufferedReader(inputFile) + + def row = -1 + def header = null + while (br.ready() && header == null) { + def line = br.readLine() + row++ + if (!line.startsWith("#")) { + header = splitRegex.split(line, -1).collect{field -> + m = removeQuote.matcher(field) + m.find() ? m.replaceFirst('$1') : field + } + } + } + assert header != null: "CSV file should contain a header" + + while (br.ready()) { + def line = br.readLine() + row++ + if (line == null) { + br.close() + break + } + + if (!line.startsWith("#")) { + def predata = splitRegex.split(line, -1) + def data = predata.collect{field -> + if (field == "") { + return null + } + def m = removeQuote.matcher(field) + if (m.find()) { + return m.replaceFirst('$1') + } else { + return field + } + } + assert header.size() == data.size(): "Row $row should contain the same number as fields as the header" + + def dataMap = [header, data].transpose().collectEntries().findAll{it.value != null} + output.add(dataMap) + } + } + + output +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJson.nf' +def readJson(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parse(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJsonBlob.nf' +def readJsonBlob(str) { + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parseText(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readTaggedYaml.nf' +// Custom constructor to modify how certain objects are parsed from YAML +class CustomConstructor extends org.yaml.snakeyaml.constructor.Constructor { + Path root + + class ConstructPath extends org.yaml.snakeyaml.constructor.AbstractConstruct { + public Object construct(org.yaml.snakeyaml.nodes.Node node) { + String filename = (String) constructScalar(node); + if (root != null) { + return root.resolve(filename); + } + return java.nio.file.Paths.get(filename); + } + } + + CustomConstructor(org.yaml.snakeyaml.LoaderOptions options, Path root) { + super(options) + this.root = root + // Handling !file tag and parse it back to a File type + this.yamlConstructors.put(new org.yaml.snakeyaml.nodes.Tag("!file"), new ConstructPath()) + } +} + +def readTaggedYaml(Path path) { + def options = new org.yaml.snakeyaml.LoaderOptions() + def constructor = new CustomConstructor(options, path.getParent()) + def yaml = new org.yaml.snakeyaml.Yaml(constructor) + return yaml.load(path.text) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYaml.nf' +def readYaml(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYamlBlob.nf' +def readYamlBlob(str) { + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toJsonBlob.nf' +String toJsonBlob(data) { + return groovy.json.JsonOutput.toJson(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toTaggedYamlBlob.nf' +// Custom representer to modify how certain objects are represented in YAML +class CustomRepresenter extends org.yaml.snakeyaml.representer.Representer { + Path relativizer + + class RepresentPath implements org.yaml.snakeyaml.representer.Represent { + public String getFileName(Object obj) { + if (obj instanceof File) { + obj = ((File) obj).toPath(); + } + if (obj !instanceof Path) { + throw new IllegalArgumentException("Object: " + obj + " is not a Path or File"); + } + def path = (Path) obj; + + if (relativizer != null) { + return relativizer.relativize(path).toString() + } else { + return path.toString() + } + } + + public org.yaml.snakeyaml.nodes.Node representData(Object data) { + String filename = getFileName(data); + def tag = new org.yaml.snakeyaml.nodes.Tag("!file"); + return representScalar(tag, filename); + } + } + CustomRepresenter(org.yaml.snakeyaml.DumperOptions options, Path relativizer) { + super(options) + this.relativizer = relativizer + this.representers.put(sun.nio.fs.UnixPath, new RepresentPath()) + this.representers.put(Path, new RepresentPath()) + this.representers.put(File, new RepresentPath()) + } +} + +String toTaggedYamlBlob(data) { + return toRelativeTaggedYamlBlob(data, null) +} +String toRelativeTaggedYamlBlob(data, Path relativizer) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + def representer = new CustomRepresenter(options, relativizer) + def yaml = new org.yaml.snakeyaml.Yaml(representer, options) + return yaml.dump(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toYamlBlob.nf' +String toYamlBlob(data) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + options.setPrettyFlow(true) + def yaml = new org.yaml.snakeyaml.Yaml(options) + def cleanData = iterateMap(data, { it instanceof Path ? it.toString() : it }) + return yaml.dump(cleanData) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeJson.nf' +void writeJson(data, file) { + assert data: "writeJson: data should not be null" + assert file: "writeJson: file should not be null" + file.write(toJsonBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeYaml.nf' +void writeYaml(data, file) { + assert data: "writeYaml: data should not be null" + assert file: "writeYaml: file should not be null" + file.write(toYamlBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/findStates.nf' +def findStates(Map params, Map config) { + def auto_config = deepClone(config) + def auto_params = deepClone(params) + + auto_config = auto_config.clone() + // override arguments + auto_config.argument_groups = [] + auto_config.arguments = [ + [ + type: "string", + name: "--id", + description: "A dummy identifier", + required: false + ], + [ + type: "file", + name: "--input_states", + example: "/path/to/input/directory/**/state.yaml", + description: "Path to input directory containing the datasets to be integrated.", + required: true, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--filter", + example: "foo/.*/state.yaml", + description: "Regex to filter state files by path.", + required: false + ], + // to do: make this a yaml blob? + [ + type: "string", + name: "--rename_keys", + example: ["newKey1:oldKey1", "newKey2:oldKey2"], + description: "Rename keys in the detected input files. This is useful if the input files do not match the set of input arguments of the workflow.", + required: false, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--settings", + example: '{"output_dataset": "dataset.h5ad", "k": 10}', + description: "Global arguments as a JSON glob to be passed to all components.", + required: false + ] + ] + if (!(auto_params.containsKey("id"))) { + auto_params["id"] = "auto" + } + + // run auto config through processConfig once more + auto_config = processConfig(auto_config) + + workflow findStatesWf { + helpMessage(auto_config) + + output_ch = + channelFromParams(auto_params, auto_config) + | flatMap { autoId, args -> + + def globalSettings = args.settings ? readYamlBlob(args.settings) : [:] + + // look for state files in input dir + def stateFiles = args.input_states + + // filter state files by regex + if (args.filter) { + stateFiles = stateFiles.findAll{ stateFile -> + def stateFileStr = stateFile.toString() + def matcher = stateFileStr =~ args.filter + matcher.matches()} + } + + // read in states + def states = stateFiles.collect { stateFile -> + def state_ = readTaggedYaml(stateFile) + [state_.id, state_] + } + + // construct renameMap + if (args.rename_keys) { + def renameMap = args.rename_keys.collectEntries{renameString -> + def split = renameString.split(":") + assert split.size() == 2: "Argument 'rename_keys' should be of the form 'newKey:oldKey', or 'newKey:oldKey;newKey:oldKey' in case of multiple values" + split + } + + // rename keys in state, only let states through which have all keys + // also add global settings + states = states.collectMany{id, state -> + def newState = [:] + + for (key in renameMap.keySet()) { + def origKey = renameMap[key] + if (!(state.containsKey(origKey))) { + return [] + } + newState[key] = state[origKey] + } + + [[id, globalSettings + newState]] + } + } + + states + } + emit: + output_ch + } + + return findStatesWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/joinStates.nf' +def joinStates(Closure apply_) { + workflow joinStatesWf { + take: input_ch + main: + output_ch = input_ch + | toSortedList + | filter{ it.size() > 0 } + | map{ tups -> + def ids = tups.collect{it[0]} + def states = tups.collect{it[1]} + apply_(ids, states) + } + + emit: output_ch + } + return joinStatesWf +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf' +def collectFiles(obj) { + if (obj instanceof java.io.File || obj instanceof Path) { + return [obj] + } else if (obj instanceof List && obj !instanceof String) { + return obj.collectMany{item -> + collectFiles(item) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectFiles(item) + } + } else { + return [] + } +} + +/** + * Recurse through a state and collect all input files and their target output filenames. + * @param obj The state to recurse through. + * @param prefix The prefix to prepend to the output filenames. + */ +def collectInputOutputPaths(obj, prefix) { + if (obj instanceof File || obj instanceof Path) { + def path = obj instanceof Path ? obj : obj.toPath() + def ext = path.getFileName().toString().find("\\.[^\\.]+\$") ?: "" + def newFilename = prefix + ext + return [[obj, newFilename]] + } else if (obj instanceof List && obj !instanceof String) { + return obj.withIndex().collectMany{item, ix -> + collectInputOutputPaths(item, prefix + "_" + ix) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectInputOutputPaths(item, prefix + "." + key) + } + } else { + return [] + } +} + +def publishStates(Map args) { + def key_ = args.get("key") + def yamlTemplate_ = args.get("output_state", args.get("outputState", '$id.$key.state.yaml')) + + assert key_ != null : "publishStates: key must be specified" + + workflow publishStatesWf { + 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] + + def yamlFilename = yamlTemplate_ + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .replaceAll('\\$\\{key\\}', key_) + + // TODO: do the pathnames in state_ match up with the outputFilenames_? + + // convert state to yaml blob + def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename)) + + [id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_] + } + | publishStatesProc + emit: input_ch + } + return publishStatesWf +} +process publishStatesProc { + // todo: check publishpath? + publishDir path: "${getPublishDir()}/", mode: "copy" + tag "$id" + input: + tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles) + output: + tuple val(id), path{[yamlFile] + 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 + [] + } + } + """ +mkdir -p "\$(dirname '${yamlFile}')" +echo "Storing state as yaml" +echo '${yamlBlob}' > '${yamlFile}' +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 publishStatesByConfig(Map args) { + def config = args.get("config") + assert config != null : "publishStatesByConfig: config must be specified" + + def key_ = args.get("key", config.name) + assert key_ != null : "publishStatesByConfig: key must be specified" + + workflow publishStatesSimpleWf { + 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'] + + // TODO: allow overriding the state.yaml template + // TODO TODO: if auto.publish == "state", add output_state as an argument + def yamlTemplate = params.containsKey("output_state") ? params.output_state : '$id.$key.state.yaml' + def yamlFilename = yamlTemplate + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .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 + // - 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" } + .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 + 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 [[key: plainName_, value: value, 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 value_ = java.nio.file.Paths.get(filename_ix) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = val instanceof File ? val.toPath() : val + [value: value_, inputPath: inputPath, outputFilename: filename_ix] + } + def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key -> + [key, outputPerFile.collect{dic -> dic[key]}] + } + return [[key: plainName_] + transposedOutputs] + } else { + def value_ = java.nio.file.Paths.get(filename) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = value instanceof File ? value.toPath() : value + return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]] + } + } + + 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] + } + | publishStatesProc + emit: input_ch + } + return publishStatesSimpleWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/setState.nf' +def setState(fun) { + assert fun instanceof Closure || fun instanceof Map || fun instanceof List : + "Error in setState: Expected process argument to be a Closure, a Map, or a List. Found: class ${fun.getClass()}" + + // if fun is a List, convert to map + if (fun instanceof List) { + // check whether fun is a list[string] + assert fun.every{it instanceof CharSequence} : "Error in setState: argument is a List, but not all elements are Strings" + fun = fun.collectEntries{[it, it]} + } + + // if fun is a map, convert to closure + if (fun instanceof Map) { + // check whether fun is a map[string, string] + assert fun.values().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all values are Strings" + assert fun.keySet().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all keys are Strings" + def funMap = fun.clone() + // turn the map into a closure to be used later on + fun = { id_, state_ -> + assert state_ instanceof Map : "Error in setState: the state is not a Map" + funMap.collectMany{newkey, origkey -> + if (state_.containsKey(origkey)) { + [[newkey, state_[origkey]]] + } else { + [] + } + }.collectEntries() + } + } + + map { tup -> + def id = tup[0] + def state = tup[1] + def unfilteredState = fun(id, state) + def newState = unfilteredState.findAll{key, val -> val != null} + [id, newState] + tup.drop(2) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processAuto.nf' +// TODO: unit test processAuto +def processAuto(Map auto) { + // remove null values + auto = auto.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = ["simplifyInput", "simplifyOutput", "transcript", "publish"] + def unexpectedKeys = auto.keySet() - expectedKeys + assert unexpectedKeys.isEmpty(), "unexpected keys in auto: '${unexpectedKeys.join("', '")}'" + + // check auto.simplifyInput + assert auto.simplifyInput instanceof Boolean, "auto.simplifyInput must be a boolean" + + // check auto.simplifyOutput + assert auto.simplifyOutput instanceof Boolean, "auto.simplifyOutput must be a boolean" + + // check auto.transcript + assert auto.transcript instanceof Boolean, "auto.transcript must be a boolean" + + // check auto.publish + assert auto.publish instanceof Boolean || auto.publish == "state", "auto.publish must be a boolean or 'state'" + + return auto.subMap(expectedKeys) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processDirectives.nf' +def assertMapKeys(map, expectedKeys, requiredKeys, mapName) { + assert map instanceof Map : "Expected argument '$mapName' to be a Map. Found: class ${map.getClass()}" + map.forEach { key, val -> + assert key in expectedKeys : "Unexpected key '$key' in ${mapName ? mapName + " " : ""}map" + } + requiredKeys.forEach { requiredKey -> + assert map.containsKey(requiredKey) : "Missing required key '$key' in ${mapName ? mapName + " " : ""}map" + } +} + +// TODO: unit test processDirectives +def processDirectives(Map drctv) { + // remove null values + drctv = drctv.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = [ + "accelerator", "afterScript", "beforeScript", "cache", "conda", "container", "containerOptions", "cpus", "disk", "echo", "errorStrategy", "executor", "machineType", "maxErrors", "maxForks", "maxRetries", "memory", "module", "penv", "pod", "publishDir", "queue", "label", "scratch", "storeDir", "stageInMode", "stageOutMode", "tag", "time" + ] + def unexpectedKeys = drctv.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Unexpected keys in process directive: '${unexpectedKeys.join("', '")}'" + + /* DIRECTIVE accelerator + accepted examples: + - [ limit: 4, type: "nvidia-tesla-k80" ] + */ + if (drctv.containsKey("accelerator")) { + assertMapKeys(drctv["accelerator"], ["type", "limit", "request", "runtime"], [], "accelerator") + } + + /* DIRECTIVE afterScript + accepted examples: + - "source /cluster/bin/cleanup" + */ + if (drctv.containsKey("afterScript")) { + assert drctv["afterScript"] instanceof CharSequence + } + + /* DIRECTIVE beforeScript + accepted examples: + - "source /cluster/bin/setup" + */ + if (drctv.containsKey("beforeScript")) { + assert drctv["beforeScript"] instanceof CharSequence + } + + /* DIRECTIVE cache + accepted examples: + - true + - false + - "deep" + - "lenient" + */ + if (drctv.containsKey("cache")) { + assert drctv["cache"] instanceof CharSequence || drctv["cache"] instanceof Boolean + if (drctv["cache"] instanceof CharSequence) { + assert drctv["cache"] in ["deep", "lenient"] : "Unexpected value for cache" + } + } + + /* DIRECTIVE conda + accepted examples: + - "bwa=0.7.15" + - "bwa=0.7.15 fastqc=0.11.5" + - ["bwa=0.7.15", "fastqc=0.11.5"] + */ + if (drctv.containsKey("conda")) { + if (drctv["conda"] instanceof List) { + drctv["conda"] = drctv["conda"].join(" ") + } + assert drctv["conda"] instanceof CharSequence + } + + /* DIRECTIVE container + accepted examples: + - "foo/bar:tag" + - [ registry: "reg", image: "im", tag: "ta" ] + is transformed to "reg/im:ta" + - [ image: "im" ] + is transformed to "im:latest" + */ + if (drctv.containsKey("container")) { + assert drctv["container"] instanceof Map || drctv["container"] instanceof CharSequence + if (drctv["container"] instanceof Map) { + def m = drctv["container"] + assertMapKeys(m, [ "registry", "image", "tag" ], ["image"], "container") + def part1 = + System.getenv('OVERRIDE_CONTAINER_REGISTRY') ? System.getenv('OVERRIDE_CONTAINER_REGISTRY') + "/" : + params.containsKey("override_container_registry") ? params["override_container_registry"] + "/" : // todo: remove? + m.registry ? m.registry + "/" : + "" + def part2 = m.image + def part3 = m.tag ? ":" + m.tag : ":latest" + drctv["container"] = part1 + part2 + part3 + } + } + + /* DIRECTIVE containerOptions + accepted examples: + - "--foo bar" + - ["--foo bar", "-f b"] + */ + if (drctv.containsKey("containerOptions")) { + if (drctv["containerOptions"] instanceof List) { + drctv["containerOptions"] = drctv["containerOptions"].join(" ") + } + assert drctv["containerOptions"] instanceof CharSequence + } + + /* DIRECTIVE cpus + accepted examples: + - 1 + - 10 + */ + if (drctv.containsKey("cpus")) { + assert drctv["cpus"] instanceof Integer + } + + /* DIRECTIVE disk + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("disk")) { + assert drctv["disk"] instanceof CharSequence + // assert drctv["disk"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE echo + accepted examples: + - true + - false + */ + if (drctv.containsKey("echo")) { + assert drctv["echo"] instanceof Boolean + } + + /* DIRECTIVE errorStrategy + accepted examples: + - "terminate" + - "finish" + */ + if (drctv.containsKey("errorStrategy")) { + assert drctv["errorStrategy"] instanceof CharSequence + assert drctv["errorStrategy"] in ["terminate", "finish", "ignore", "retry"] : "Unexpected value for errorStrategy" + } + + /* DIRECTIVE executor + accepted examples: + - "local" + - "sge" + */ + if (drctv.containsKey("executor")) { + assert drctv["executor"] instanceof CharSequence + assert drctv["executor"] in ["local", "sge", "uge", "lsf", "slurm", "pbs", "pbspro", "moab", "condor", "nqsii", "ignite", "k8s", "awsbatch", "google-pipelines"] : "Unexpected value for executor" + } + + /* DIRECTIVE machineType + accepted examples: + - "n1-highmem-8" + */ + if (drctv.containsKey("machineType")) { + assert drctv["machineType"] instanceof CharSequence + } + + /* DIRECTIVE maxErrors + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxErrors")) { + assert drctv["maxErrors"] instanceof Integer + } + + /* DIRECTIVE maxForks + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxForks")) { + assert drctv["maxForks"] instanceof Integer + } + + /* DIRECTIVE maxRetries + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxRetries")) { + assert drctv["maxRetries"] instanceof Integer + } + + /* DIRECTIVE memory + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("memory")) { + assert drctv["memory"] instanceof CharSequence + // assert drctv["memory"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE module + accepted examples: + - "ncbi-blast/2.2.27" + - "ncbi-blast/2.2.27:t_coffee/10.0" + - ["ncbi-blast/2.2.27", "t_coffee/10.0"] + */ + if (drctv.containsKey("module")) { + if (drctv["module"] instanceof List) { + drctv["module"] = drctv["module"].join(":") + } + assert drctv["module"] instanceof CharSequence + } + + /* DIRECTIVE penv + accepted examples: + - "smp" + */ + if (drctv.containsKey("penv")) { + assert drctv["penv"] instanceof CharSequence + } + + /* DIRECTIVE pod + accepted examples: + - [ label: "key", value: "val" ] + - [ annotation: "key", value: "val" ] + - [ env: "key", value: "val" ] + - [ [label: "l", value: "v"], [env: "e", value: "v"]] + */ + if (drctv.containsKey("pod")) { + if (drctv["pod"] instanceof Map) { + drctv["pod"] = [ drctv["pod"] ] + } + assert drctv["pod"] instanceof List + drctv["pod"].forEach { pod -> + assert pod instanceof Map + // TODO: should more checks be added? + // See https://www.nextflow.io/docs/latest/process.html?highlight=directives#pod + // e.g. does it contain 'label' and 'value', or 'annotation' and 'value', or ...? + } + } + + /* DIRECTIVE publishDir + accepted examples: + - [] + - [ [ path: "foo", enabled: true ], [ path: "bar", enabled: false ] ] + - "/path/to/dir" + is transformed to [[ path: "/path/to/dir" ]] + - [ path: "/path/to/dir", mode: "cache" ] + is transformed to [[ path: "/path/to/dir", mode: "cache" ]] + */ + // TODO: should we also look at params["publishDir"]? + if (drctv.containsKey("publishDir")) { + def pblsh = drctv["publishDir"] + + // check different options + assert pblsh instanceof List || pblsh instanceof Map || pblsh instanceof CharSequence + + // turn into list if not already so + // for some reason, 'if (!pblsh instanceof List) pblsh = [ pblsh ]' doesn't work. + pblsh = pblsh instanceof List ? pblsh : [ pblsh ] + + // check elements of publishDir + pblsh = pblsh.collect{ elem -> + // turn into map if not already so + elem = elem instanceof CharSequence ? [ path: elem ] : elem + + // check types and keys + assert elem instanceof Map : "Expected publish argument '$elem' to be a String or a Map. Found: class ${elem.getClass()}" + assertMapKeys(elem, [ "path", "mode", "overwrite", "pattern", "saveAs", "enabled" ], ["path"], "publishDir") + + // check elements in map + assert elem.containsKey("path") + assert elem["path"] instanceof CharSequence + if (elem.containsKey("mode")) { + assert elem["mode"] instanceof CharSequence + assert elem["mode"] in [ "symlink", "rellink", "link", "copy", "copyNoFollow", "move" ] + } + if (elem.containsKey("overwrite")) { + assert elem["overwrite"] instanceof Boolean + } + if (elem.containsKey("pattern")) { + assert elem["pattern"] instanceof CharSequence + } + if (elem.containsKey("saveAs")) { + assert elem["saveAs"] instanceof CharSequence //: "saveAs as a Closure is currently not supported. Surround your closure with single quotes to get the desired effect. Example: '\{ foo \}'" + } + if (elem.containsKey("enabled")) { + assert elem["enabled"] instanceof Boolean + } + + // return final result + elem + } + // store final directive + drctv["publishDir"] = pblsh + } + + /* DIRECTIVE queue + accepted examples: + - "long" + - "short,long" + - ["short", "long"] + */ + if (drctv.containsKey("queue")) { + if (drctv["queue"] instanceof List) { + drctv["queue"] = drctv["queue"].join(",") + } + assert drctv["queue"] instanceof CharSequence + } + + /* DIRECTIVE label + accepted examples: + - "big_mem" + - "big_cpu" + - ["big_mem", "big_cpu"] + */ + if (drctv.containsKey("label")) { + if (drctv["label"] instanceof CharSequence) { + drctv["label"] = [ drctv["label"] ] + } + assert drctv["label"] instanceof List + drctv["label"].forEach { label -> + assert label instanceof CharSequence + // assert label.matches("[a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?") + // ^ does not allow closures + } + } + + /* DIRECTIVE scratch + accepted examples: + - true + - "/path/to/scratch" + - '$MY_PATH_TO_SCRATCH' + - "ram-disk" + */ + if (drctv.containsKey("scratch")) { + assert drctv["scratch"] == true || drctv["scratch"] instanceof CharSequence + } + + /* DIRECTIVE storeDir + accepted examples: + - "/path/to/storeDir" + */ + if (drctv.containsKey("storeDir")) { + assert drctv["storeDir"] instanceof CharSequence + } + + /* DIRECTIVE stageInMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageInMode")) { + assert drctv["stageInMode"] instanceof CharSequence + assert drctv["stageInMode"] in ["copy", "link", "symlink", "rellink"] + } + + /* DIRECTIVE stageOutMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageOutMode")) { + assert drctv["stageOutMode"] instanceof CharSequence + assert drctv["stageOutMode"] in ["copy", "move", "rsync"] + } + + /* DIRECTIVE tag + accepted examples: + - "foo" + - '$id' + */ + if (drctv.containsKey("tag")) { + assert drctv["tag"] instanceof CharSequence + } + + /* DIRECTIVE time + accepted examples: + - "1h" + - "2days" + - "1day 6hours 3minutes 30seconds" + */ + if (drctv.containsKey("time")) { + assert drctv["time"] instanceof CharSequence + // todo: validation regex? + } + + return drctv +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processWorkflowArgs.nf' +def processWorkflowArgs(Map args, Map defaultWfArgs, Map meta) { + // override defaults with args + def workflowArgs = defaultWfArgs + args + + // check whether 'key' exists + assert workflowArgs.containsKey("key") : "Error in module '${meta.config.name}': key is a required argument" + + // if 'key' is a closure, apply it to the original key + if (workflowArgs["key"] instanceof Closure) { + workflowArgs["key"] = workflowArgs["key"](meta.config.name) + } + def key = workflowArgs["key"] + assert key instanceof CharSequence : "Expected process argument 'key' to be a String. Found: class ${key.getClass()}" + assert key ==~ /^[a-zA-Z_]\w*$/ : "Error in module '$key': Expected process argument 'key' to consist of only letters, digits or underscores. Found: ${key}" + + // check for any unexpected keys + def expectedKeys = ["key", "directives", "auto", "map", "mapId", "mapData", "mapPassthrough", "filter", "runIf", "fromState", "toState", "args", "renameKeys", "debug"] + def unexpectedKeys = workflowArgs.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Error in module '$key': unexpected arguments to the '.run()' function: '${unexpectedKeys.join("', '")}'" + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("directives") : "Error in module '$key': directives is a required argument" + assert workflowArgs["directives"] instanceof Map : "Error in module '$key': Expected process argument 'directives' to be a Map. Found: class ${workflowArgs['directives'].getClass()}" + workflowArgs["directives"] = processDirectives(defaultWfArgs.directives + workflowArgs["directives"]) + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("auto") : "Error in module '$key': auto is a required argument" + assert workflowArgs["auto"] instanceof Map : "Error in module '$key': Expected process argument 'auto' to be a Map. Found: class ${workflowArgs['auto'].getClass()}" + workflowArgs["auto"] = processAuto(defaultWfArgs.auto + workflowArgs["auto"]) + + // auto define publish, if so desired + if (workflowArgs.auto.publish == true && (workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : [:]).isEmpty()) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.publish is true, params.publish_dir needs to be defined.\n" + + // " Example: params.publish_dir = \"./output/\"" + def publishDir = getPublishDir() + + if (publishDir != null) { + workflowArgs.directives.publishDir = [[ + path: publishDir, + saveAs: "{ it.startsWith('.') ? null : it }", // don't publish hidden files, by default + mode: "copy" + ]] + } + } + + // auto define transcript, if so desired + if (workflowArgs.auto.transcript == true) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("transcriptsDir") || params.containsKey("transcripts_dir") || params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.transcript is true, either params.transcripts_dir or params.publish_dir needs to be defined.\n" + + // " Example: params.transcripts_dir = \"./transcripts/\"" + def transcriptsDir = + params.containsKey("transcripts_dir") ? params.transcripts_dir : + params.containsKey("transcriptsDir") ? params.transcriptsDir : + params.containsKey("publish_dir") ? params.publish_dir + "/_transcripts" : + params.containsKey("publishDir") ? params.publishDir + "/_transcripts" : + null + if (transcriptsDir != null) { + def timestamp = nextflow.Nextflow.getSession().getWorkflowMetadata().start.format('yyyy-MM-dd_HH-mm-ss') + def transcriptsPublishDir = [ + path: "$transcriptsDir/$timestamp/\${task.process.replaceAll(':', '-')}/\${id}/", + saveAs: "{ it.startsWith('.') ? it.replaceAll('^.', '') : null }", + mode: "copy" + ] + def publishDirs = workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : null ? workflowArgs.directives.publishDir : [] + workflowArgs.directives.publishDir = publishDirs + transcriptsPublishDir + } + } + + // if this is a stubrun, remove certain directives? + if (workflow.stubRun) { + workflowArgs.directives.keySet().removeAll(["publishDir", "cpus", "memory", "label"]) + } + + for (nam in ["map", "mapId", "mapData", "mapPassthrough", "filter", "runIf"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam]) { + assert workflowArgs[nam] instanceof Closure : "Error in module '$key': Expected process argument '$nam' to be null or a Closure. Found: class ${workflowArgs[nam].getClass()}" + } + } + + // TODO: should functions like 'map', 'mapId', 'mapData', 'mapPassthrough' be deprecated as well? + for (nam in ["map", "mapData", "mapPassthrough", "renameKeys"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam] != null) { + log.warn "module '$key': workflow argument '$nam' is deprecated and will be removed in Viash 0.9.0. Please use 'fromState' and 'toState' instead." + } + } + + // check fromState + workflowArgs["fromState"] = _processFromState(workflowArgs.get("fromState"), key, meta.config) + + // check toState + workflowArgs["toState"] = _processToState(workflowArgs.get("toState"), key, meta.config) + + // return output + return workflowArgs +} + +def _processFromState(fromState, key_, config_) { + assert fromState == null || fromState instanceof Closure || fromState instanceof Map || fromState instanceof List : + "Error in module '$key_': Expected process argument 'fromState' to be null, a Closure, a Map, or a List. Found: class ${fromState.getClass()}" + if (fromState == null) { + return null + } + + // if fromState is a List, convert to map + if (fromState instanceof List) { + // check whether fromstate is a list[string] + assert fromState.every{it instanceof CharSequence} : "Error in module '$key_': fromState is a List, but not all elements are Strings" + fromState = fromState.collectEntries{[it, it]} + } + + // if fromState is a map, convert to closure + if (fromState instanceof Map) { + // check whether fromstate is a map[string, string] + assert fromState.values().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all values are Strings" + assert fromState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all keys are Strings" + def fromStateMap = fromState.clone() + def requiredInputNames = meta.config.allArguments.findAll{it.required && it.direction == "Input"}.collect{it.plainName} + // turn the map into a closure to be used later on + fromState = { it -> + def state = it[1] + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def data = fromStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (state.containsKey(origkey)) { + [[newkey, state[origkey]]] + } else if (!requiredInputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': fromState key '$origkey' not found in current state") + } + }.collectEntries() + data + } + } + + return fromState +} + +def _processToState(toState, key_, config_) { + if (toState == null) { + toState = { tup -> tup[1] } + } + + // toState should be a closure, map[string, string], or list[string] + assert toState instanceof Closure || toState instanceof Map || toState instanceof List : + "Error in module '$key_': Expected process argument 'toState' to be a Closure, a Map, or a List. Found: class ${toState.getClass()}" + + // if toState is a List, convert to map + if (toState instanceof List) { + // check whether toState is a list[string] + assert toState.every{it instanceof CharSequence} : "Error in module '$key_': toState is a List, but not all elements are Strings" + toState = toState.collectEntries{[it, it]} + } + + // if toState is a map, convert to closure + if (toState instanceof Map) { + // check whether toState is a map[string, string] + assert toState.values().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all values are Strings" + assert toState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all keys are Strings" + def toStateMap = toState.clone() + def requiredOutputNames = config_.allArguments.findAll{it.required && it.direction == "Output"}.collect{it.plainName} + // turn the map into a closure to be used later on + toState = { it -> + def output = it[1] + def state = it[2] + assert output instanceof Map : "Error in module '$key_': the output is not a Map" + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def extraEntries = toStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (output.containsKey(origkey)) { + [[newkey, output[origkey]]] + } else if (!requiredOutputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': toState key '$origkey' not found in current output") + } + }.collectEntries() + state + extraEntries + } + } + + return toState +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/workflowFactory.nf' +def _debug(workflowArgs, debugKey) { + if (workflowArgs.debug) { + view { "process '${workflowArgs.key}' $debugKey tuple: $it" } + } else { + map { it } + } +} + +// depends on: innerWorkflowFactory +def workflowFactory(Map args, Map defaultWfArgs, Map meta) { + def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta) + def key_ = workflowArgs["key"] + + workflow workflowInstance { + take: input_ + + main: + def chModified = input_ + | checkUniqueIds([:]) + | _debug(workflowArgs, "input") + | map { tuple -> + tuple = deepClone(tuple) + + if (workflowArgs.map) { + tuple = workflowArgs.map(tuple) + } + if (workflowArgs.mapId) { + tuple[0] = workflowArgs.mapId(tuple[0]) + } + if (workflowArgs.mapData) { + tuple[1] = workflowArgs.mapData(tuple[1]) + } + if (workflowArgs.mapPassthrough) { + tuple = tuple.take(2) + workflowArgs.mapPassthrough(tuple.drop(2)) + } + + // check tuple + assert tuple instanceof List : + "Error in module '${key_}': element in 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()}" + assert tuple.size() >= 2 : + "Error in module '${key_}': expected length of tuple in input channel to be two or greater.\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: tuple.size() == ${tuple.size()}" + + // check id field + if (tuple[0] instanceof GString) { + tuple[0] = tuple[0].toString() + } + assert tuple[0] instanceof CharSequence : + "Error in module '${key_}': first element of tuple in channel should be a String\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: ${tuple[0]}" + + // match file to input file + if (workflowArgs.auto.simplifyInput && (tuple[1] instanceof Path || tuple[1] instanceof List)) { + def inputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + + assert inputFiles.size() == 1 : + "Error in module '${key_}' id '${tuple[0]}'.\n" + + " Anonymous file inputs are only allowed when the process has exactly one file input.\n" + + " Expected: inputFiles.size() == 1. Found: inputFiles.size() is ${inputFiles.size()}" + + tuple[1] = [[ inputFiles[0].plainName, tuple[1] ]].collectEntries() + } + + // check data field + assert tuple[1] instanceof Map : + "Error in module '${key_}' id '${tuple[0]}': second element of tuple in channel should be a Map\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // rename keys of data field in tuple + if (workflowArgs.renameKeys) { + assert workflowArgs.renameKeys instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class: Map. Found: renameKeys.getClass() is ${workflowArgs.renameKeys.getClass()}" + assert tuple[1] instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // TODO: allow renameKeys to be a function? + workflowArgs.renameKeys.each { newKey, oldKey -> + assert newKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of newKey: String. Found: newKey.getClass() is ${newKey.getClass()}" + assert oldKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of oldKey: String. Found: oldKey.getClass() is ${oldKey.getClass()}" + assert tuple[1].containsKey(oldKey) : + "Error renaming data keys in module '${key}' id '${tuple[0]}'.\n" + + " Key '$oldKey' is missing in the data map. tuple[1].keySet() is '${tuple[1].keySet()}'" + tuple[1].put(newKey, tuple[1][oldKey]) + } + tuple[1].keySet().removeAll(workflowArgs.renameKeys.collect{ newKey, oldKey -> oldKey }) + } + tuple + } + + + def chRun = null + def chPassthrough = null + if (workflowArgs.runIf) { + def runIfBranch = chModified.branch{ tup -> + run: workflowArgs.runIf(tup[0], tup[1]) + passthrough: true + } + chRun = runIfBranch.run + chPassthrough = runIfBranch.passthrough + } else { + chRun = chModified + chPassthrough = Channel.empty() + } + + def chRunFiltered = workflowArgs.filter ? + chRun | filter{workflowArgs.filter(it)} : + chRun + + def chArgs = workflowArgs.fromState ? + chRunFiltered | map{ + def new_data = workflowArgs.fromState(it.take(2)) + [it[0], new_data] + } : + chRunFiltered | map {tup -> tup.take(2)} + + // fill in defaults + def chArgsWithDefaults = chArgs + | map { tuple -> + def id_ = tuple[0] + def data_ = tuple[1] + + // TODO: could move fromState to here + + // fetch default params from functionality + def defaultArgs = meta.config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + // fetch overrides in params + def paramArgs = meta.config.allArguments + .findAll { par -> + def argKey = key_ + "__" + par.plainName + params.containsKey(argKey) + } + .collectEntries { [ it.plainName, params[key_ + "__" + it.plainName] ] } + + // fetch overrides in data + def dataArgs = meta.config.allArguments + .findAll { data_.containsKey(it.plainName) } + .collectEntries { [ it.plainName, data_[it.plainName] ] } + + // combine params + def combinedArgs = defaultArgs + paramArgs + workflowArgs.args + dataArgs + + // remove arguments with explicit null values + combinedArgs + .removeAll{_, val -> val == null || val == "viash_no_value" || val == "force_null"} + + combinedArgs = _processInputValues(combinedArgs, meta.config, id_, key_) + + [id_, combinedArgs] + tuple.drop(2) + } + + // TODO: move some of the _meta.join_id wrangling to the safeJoin() function. + def chInitialOutput = chArgsWithDefaults + | _debug(workflowArgs, "processed") + // run workflow + | innerWorkflowFactory(workflowArgs) + // check output tuple + | map { id_, output_ -> + + // see if output map contains metadata + def meta_ = + output_ instanceof Map && output_.containsKey("_meta") ? + output_["_meta"] : + [:] + def join_id = meta_.join_id ?: id_ + + // remove metadata + output_ = output_.findAll{k, v -> k != "_meta"} + + // check value types + output_ = _processOutputValues(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_] + } + // | view{"chInitialOutput: ${it.take(3)}"} + + // join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...] + def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_) + // input tuple format: [join_id, id, output, prev_state, ...] + // output tuple format: [join_id, id, new_state, ...] + | map{ tup -> + def new_state = workflowArgs.toState(tup.drop(1).take(3)) + tup.take(2) + [new_state] + tup.drop(4) + } + + if (workflowArgs.auto.publish == "state") { + def chPublish = 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_) + // 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, ...] + // output tuple format: [id, new_state, ...] + tup.drop(1) + } + | _debug(workflowArgs, "output") + | concat(chPassthrough) + + emit: chReturn + } + + def wf = workflowInstance.cloneWithName(key_) + + // add factory function + wf.metaClass.run = { runArgs -> + workflowFactory(runArgs, workflowArgs, meta) + } + // add config to module for later introspection + wf.metaClass.config = meta.config + + return wf +} + +nextflow.enable.dsl=2 + +// START COMPONENT-SPECIFIC CODE + +// create meta object +meta = [ + "resources_dir": moduleDir.toRealPath().normalize(), + "config": processConfig(readJsonBlob('''{ + "name" : "rseqc_inferexperiment", + "namespace" : "rseqc", + "version" : "main", + "authors" : [ + { + "name" : "Emma Rousseau", + "roles" : [ + "author", + "maintainer" + ], + "info" : { + "links" : { + "email" : "emma@data-intuitive.com", + "github" : "emmarousseau", + "linkedin" : "emmarousseau1" + }, + "organizations" : [ + { + "name" : "Data Intuitive", + "href" : "https://www.data-intuitive.com", + "role" : "Bioinformatician" + } + ] + } + } + ], + "argument_groups" : [ + { + "name" : "Input", + "arguments" : [ + { + "type" : "file", + "name" : "--input_file", + "alternatives" : [ + "-i" + ], + "description" : "input alignment file in BAM or SAM format", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--refgene", + "alternatives" : [ + "-r" + ], + "description" : "Reference gene model in bed format", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Output", + "arguments" : [ + { + "type" : "file", + "name" : "--output", + "description" : "Output file (txt) of strandness report.", + "example" : [ + "$id.strandedness.txt" + ], + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Options", + "arguments" : [ + { + "type" : "integer", + "name" : "--sample_size", + "alternatives" : [ + "-s" + ], + "description" : "Number of reads sampled from SAM/BAM file. Default: 200000\n", + "example" : [ + 200000 + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "integer", + "name" : "--mapq", + "alternatives" : [ + "-q" + ], + "description" : "Minimum mapping quality (phred scaled) to determine uniquely mapped reads. Default: 30\n", + "example" : [ + 30 + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Infer strandedness from sequencing reads\n", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + }, + { + "type" : "file", + "path" : "test_data" + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "license" : "GPL-3.0", + "references" : { + "doi" : [ + "10.1093/bioinformatics/bts356" + ] + }, + "links" : { + "repository" : "https://github.com/MonashBioinformaticsPlatform/RSeQC", + "homepage" : "https://rseqc.sourceforge.net/", + "documentation" : "https://rseqc.sourceforge.net/#infer-experiment-py", + "issue_tracker" : "https://github.com/MonashBioinformaticsPlatform/RSeQC/issues" + }, + "runners" : [ + { + "type" : "executable", + "id" : "executable", + "docker_setup_strategy" : "ifneedbepullelsecachedbuild" + }, + { + "type" : "nextflow", + "id" : "nextflow", + "directives" : { + "tag" : "$id" + }, + "auto" : { + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false + }, + "config" : { + "labels" : { + "mem1gb" : "memory = 1000000000.B", + "mem2gb" : "memory = 2000000000.B", + "mem5gb" : "memory = 5000000000.B", + "mem10gb" : "memory = 10000000000.B", + "mem20gb" : "memory = 20000000000.B", + "mem50gb" : "memory = 50000000000.B", + "mem100gb" : "memory = 100000000000.B", + "mem200gb" : "memory = 200000000000.B", + "mem500gb" : "memory = 500000000000.B", + "mem1tb" : "memory = 1000000000000.B", + "mem2tb" : "memory = 2000000000000.B", + "mem5tb" : "memory = 5000000000000.B", + "mem10tb" : "memory = 10000000000000.B", + "mem20tb" : "memory = 20000000000000.B", + "mem50tb" : "memory = 50000000000000.B", + "mem100tb" : "memory = 100000000000000.B", + "mem200tb" : "memory = 200000000000000.B", + "mem500tb" : "memory = 500000000000000.B", + "mem1gib" : "memory = 1073741824.B", + "mem2gib" : "memory = 2147483648.B", + "mem4gib" : "memory = 4294967296.B", + "mem8gib" : "memory = 8589934592.B", + "mem16gib" : "memory = 17179869184.B", + "mem32gib" : "memory = 34359738368.B", + "mem64gib" : "memory = 68719476736.B", + "mem128gib" : "memory = 137438953472.B", + "mem256gib" : "memory = 274877906944.B", + "mem512gib" : "memory = 549755813888.B", + "mem1tib" : "memory = 1099511627776.B", + "mem2tib" : "memory = 2199023255552.B", + "mem4tib" : "memory = 4398046511104.B", + "mem8tib" : "memory = 8796093022208.B", + "mem16tib" : "memory = 17592186044416.B", + "mem32tib" : "memory = 35184372088832.B", + "mem64tib" : "memory = 70368744177664.B", + "mem128tib" : "memory = 140737488355328.B", + "mem256tib" : "memory = 281474976710656.B", + "mem512tib" : "memory = 562949953421312.B", + "cpu1" : "cpus = 1", + "cpu2" : "cpus = 2", + "cpu5" : "cpus = 5", + "cpu10" : "cpus = 10", + "cpu20" : "cpus = 20", + "cpu50" : "cpus = 50", + "cpu100" : "cpus = 100", + "cpu200" : "cpus = 200", + "cpu500" : "cpus = 500", + "cpu1000" : "cpus = 1000" + } + }, + "debug" : false, + "container" : "docker" + } + ], + "engines" : [ + { + "type" : "docker", + "id" : "docker", + "image" : "python:3.10", + "target_registry" : "images.viash-hub.com", + "target_tag" : "main", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "python", + "user" : false, + "packages" : [ + "RSeQC" + ], + "upgrade" : true + }, + { + "type" : "docker", + "run" : [ + "echo \\"RSeQC - infer_experiment.py: $(infer_experiment.py --version | cut -d' ' -f2)\\" > /var/software_versions.txt\n" + ] + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/rseqc/rseqc_inferexperiment/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/rseqc/rseqc_inferexperiment", + "viash_version" : "0.9.0", + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" + }, + "package_config" : { + "name" : "biobox", + "version" : "main", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0", + "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 := 'main'" + ], + "keywords" : [ + "bioinformatics", + "modules", + "sequencing" + ], + "license" : "MIT", + "organization" : "vsh", + "links" : { + "repository" : "https://github.com/viash-hub/biobox", + "issue_tracker" : "https://github.com/viash-hub/biobox/issues" + } + } +}''')) +] + +// resolve dependencies dependencies (if any) + + +// inner workflow +// inner workflow hook +def innerWorkflowFactory(args) { + def rawScript = '''set -e +tempscript=".viash_script.sh" +cat > "$tempscript" << VIASHMAIN +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_INPUT_FILE+x} ]; then echo "${VIASH_PAR_INPUT_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_input_file='&'#" ; else echo "# par_input_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REFGENE+x} ]; then echo "${VIASH_PAR_REFGENE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_refgene='&'#" ; else echo "# par_refgene="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT+x} ]; then echo "${VIASH_PAR_OUTPUT}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output='&'#" ; else echo "# par_output="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLE_SIZE+x} ]; then echo "${VIASH_PAR_SAMPLE_SIZE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_sample_size='&'#" ; else echo "# par_sample_size="; fi ) +$( if [ ! -z ${VIASH_PAR_MAPQ+x} ]; then echo "${VIASH_PAR_MAPQ}" | sed "s#'#'\\"'\\"'#g;s#.*#par_mapq='&'#" ; else echo "# par_mapq="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END +#!/bin/bash + +set -eo pipefail + +infer_experiment.py \\\\ + -i \\$par_input_file \\\\ + -r \\$par_refgene \\\\ + \\${par_sample_size:+-s "\\${par_sample_size}"} \\\\ + \\${par_mapq:+-q "\\${par_mapq}"} \\\\ +> \\$par_output +VIASHMAIN +bash "$tempscript" +''' + + return vdsl3WorkflowFactory(args, meta, rawScript) +} + + + +/** + * Generate a workflow for VDSL3 modules. + * + * This function is called by the workflowFactory() function. + * + * Input channel: [id, input_map] + * Output channel: [id, output_map] + * + * Internally, this workflow will convert the input channel + * to a format which the Nextflow module will be able to handle. + */ +def vdsl3WorkflowFactory(Map args, Map meta, String rawScript) { + def key = args["key"] + def processObj = null + + workflow processWf { + take: input_ + main: + + if (processObj == null) { + processObj = _vdsl3ProcessFactory(args, meta, rawScript) + } + + output_ = input_ + | map { tuple -> + def id = tuple[0] + def data_ = tuple[1] + + if (workflow.stubRun) { + // add id if missing + data_ = [id: 'stub'] + data_ + } + + // process input files separately + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { par -> + def val = data_.containsKey(par.plainName) ? data_[par.plainName] : [] + def inputFiles = [] + if (val == null) { + inputFiles = [] + } else if (val instanceof List) { + inputFiles = val + } else if (val instanceof Path) { + inputFiles = [ val ] + } else { + inputFiles = [] + } + if (!workflow.stubRun) { + // throw error when an input file doesn't exist + inputFiles.each{ file -> + assert file.exists() : + "Error in module '${key}' id '${id}' argument '${par.plainName}'.\n" + + " Required input file does not exist.\n" + + " Path: '$file'.\n" + + " Expected input file to exist" + } + } + inputFiles + } + + // remove input files + def argsExclInputFiles = meta.config.allArguments + .findAll { (it.type != "file" || it.direction != "input") && data_.containsKey(it.plainName) } + .collectEntries { par -> + def parName = par.plainName + def val = data_[parName] + if (par.multiple && val instanceof Collection) { + val = val.join(par.multiple_sep) + } + if (par.direction == "output" && par.type == "file") { + val = val + .replaceAll('\\$id', id) + .replaceAll('\\$\\{id\\}', id) + .replaceAll('\\$key', key) + .replaceAll('\\$\\{key\\}', key) + } + [parName, val] + } + + [ id ] + inputPaths + [ argsExclInputFiles, meta.resources_dir ] + } + | processObj + | map { output -> + def outputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .indexed() + .collectEntries{ index, par -> + def out = output[index + 1] + // strip dummy '.exitcode' file from output (see nextflow-io/nextflow#2678) + if (!out instanceof List || out.size() <= 1) { + if (par.multiple) { + out = [] + } else { + assert !par.required : + "Error in module '${key}' id '${output[0]}' argument '${par.plainName}'.\n" + + " Required output file is missing" + out = null + } + } else if (out.size() == 2 && !par.multiple) { + out = out[1] + } else { + out = out.drop(1) + } + [ par.plainName, out ] + } + + // drop null outputs + outputFiles.removeAll{it.value == null} + + [ output[0], outputFiles ] + } + emit: output_ + } + + return processWf +} + +// depends on: session? +def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) { + // autodetect process key + def wfKey = workflowArgs["key"] + def procKeyPrefix = "${wfKey}_process" + def scriptMeta = nextflow.script.ScriptMeta.current() + def existing = scriptMeta.getProcessNames().findAll{it.startsWith(procKeyPrefix)} + def numbers = existing.collect{it.replace(procKeyPrefix, "0").toInteger()} + def newNumber = (numbers + [-1]).max() + 1 + + def procKey = newNumber == 0 ? procKeyPrefix : "$procKeyPrefix$newNumber" + + if (newNumber > 0) { + log.warn "Key for module '${wfKey}' is duplicated.\n", + "If you run a component multiple times in the same workflow,\n" + + "it's recommended you set a unique key for every call,\n" + + "for example: ${wfKey}.run(key: \"foo\")." + } + + // subset directives and convert to list of tuples + def drctv = workflowArgs.directives + + // TODO: unit test the two commands below + // convert publish array into tags + def valueToStr = { val -> + // ignore closures + if (val instanceof CharSequence) { + if (!val.matches('^[{].*[}]$')) { + '"' + val + '"' + } else { + val + } + } else if (val instanceof List) { + "[" + val.collect{valueToStr(it)}.join(", ") + "]" + } else if (val instanceof Map) { + "[" + val.collect{k, v -> k + ": " + valueToStr(v)}.join(", ") + "]" + } else { + val.inspect() + } + } + + // multiple entries allowed: label, publishdir + def drctvStrs = drctv.collect { key, value -> + if (key in ["label", "publishDir"]) { + value.collect{ val -> + if (val instanceof Map) { + "\n$key " + val.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else if (val == null) { + "" + } else { + "\n$key " + valueToStr(val) + } + }.join() + } else if (value instanceof Map) { + "\n$key " + value.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else { + "\n$key " + valueToStr(value) + } + }.join() + + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { ', path(viash_par_' + it.plainName + ', stageAs: "_viash_par/' + it.plainName + '_?/*")' } + .join() + + def outputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + // insert dummy into every output (see nextflow-io/nextflow#2678) + if (!par.multiple) { + ', path{[".exitcode", args.' + par.plainName + ']}' + } else { + ', path{[".exitcode"] + args.' + par.plainName + '}' + } + } + .join() + + // TODO: move this functionality somewhere else? + if (workflowArgs.auto.transcript) { + outputPaths = outputPaths + ', path{[".exitcode", ".command*"]}' + } else { + outputPaths = outputPaths + ', path{[".exitcode"]}' + } + + // create dirs for output files (based on BashWrapper.createParentFiles) + def createParentStr = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" && it.create_parent } + .collect { par -> + def contents = "args[\"${par.plainName}\"] instanceof List ? args[\"${par.plainName}\"].join('\" \"') : args[\"${par.plainName}\"]" + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent '\" + escapeText(${contents}) + \"'\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def contents = "viash_par_${par.plainName} instanceof List ? viash_par_${par.plainName}.join(\"${par.multiple_sep}\") : viash_par_${par.plainName}" + "\n\${viash_par_${par.plainName}.empty ? \"\" : \"export VIASH_PAR_${par.plainName.toUpperCase()}='\" + escapeText(${contents}) + \"'\"}" + } + + // NOTE: if using docker, use /tmp instead of tmpDir! + def tmpDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('VIASH_TMPDIR') ?: + System.getenv('VIASH_TEMPDIR') ?: + System.getenv('VIASH_TMP') ?: + System.getenv('TEMP') ?: + System.getenv('TMPDIR') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMP') ?: + '/tmp' + ).toAbsolutePath() + + // construct stub + def stub = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + "\${ args.containsKey(\"${par.plainName}\") ? \"touch2 \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"].replace(\"_*\", \"_0\") : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // escape script + def escapedScript = rawScript.replace('\\', '\\\\').replace('$', '\\$').replace('"""', '\\"\\"\\"') + + // publishdir assert + def assertStr = (workflowArgs.auto.publish == true) || workflowArgs.auto.transcript ? + """\nassert task.publishDir.size() > 0: "if auto.publish is true, params.publish_dir needs to be defined.\\n Example: --publish_dir './output/'" """ : + "" + + // generate process string + def procStr = + """nextflow.enable.dsl=2 + | + |def escapeText = { s -> s.toString().replaceAll("'", "'\\\"'\\\"'") } + |process $procKey {$drctvStrs + |input: + | tuple val(id)$inputPaths, val(args), path(resourcesDir, stageAs: ".viash_meta_resources") + |output: + | tuple val("\$id")$outputPaths, optional: true + |stub: + |\"\"\" + |touch2() { mkdir -p "\\\$(dirname "\\\$1")" && touch "\\\$1" ; } + |$stub + |\"\"\" + |script:$assertStr + |def parInject = args + | .findAll{key, value -> value != null} + | .collect{key, value -> "export VIASH_PAR_\${key.toUpperCase()}='\${escapeText(value)}'"} + | .join("\\n") + |\"\"\" + |# meta exports + |export VIASH_META_RESOURCES_DIR="\${resourcesDir}" + |export VIASH_META_TEMP_DIR="${['docker', 'podman', 'charliecloud'].any{ it == workflow.containerEngine } ? '/tmp' : tmpDir}" + |export VIASH_META_NAME="${meta.config.name}" + |# export VIASH_META_EXECUTABLE="\\\$VIASH_META_RESOURCES_DIR/\\\$VIASH_META_NAME" + |export VIASH_META_CONFIG="\\\$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" + |\${task.cpus ? "export VIASH_META_CPUS=\$task.cpus" : "" } + |\${task.memory?.bytes != null ? "export VIASH_META_MEMORY_B=\$task.memory.bytes" : "" } + |if [ ! -z \\\${VIASH_META_MEMORY_B+x} ]; then + | export VIASH_META_MEMORY_KB=\\\$(( (\\\$VIASH_META_MEMORY_B+999) / 1000 )) + | export VIASH_META_MEMORY_MB=\\\$(( (\\\$VIASH_META_MEMORY_KB+999) / 1000 )) + | export VIASH_META_MEMORY_GB=\\\$(( (\\\$VIASH_META_MEMORY_MB+999) / 1000 )) + | export VIASH_META_MEMORY_TB=\\\$(( (\\\$VIASH_META_MEMORY_GB+999) / 1000 )) + | export VIASH_META_MEMORY_PB=\\\$(( (\\\$VIASH_META_MEMORY_TB+999) / 1000 )) + | export VIASH_META_MEMORY_KIB=\\\$(( (\\\$VIASH_META_MEMORY_B+1023) / 1024 )) + | export VIASH_META_MEMORY_MIB=\\\$(( (\\\$VIASH_META_MEMORY_KIB+1023) / 1024 )) + | export VIASH_META_MEMORY_GIB=\\\$(( (\\\$VIASH_META_MEMORY_MIB+1023) / 1024 )) + | export VIASH_META_MEMORY_TIB=\\\$(( (\\\$VIASH_META_MEMORY_GIB+1023) / 1024 )) + | export VIASH_META_MEMORY_PIB=\\\$(( (\\\$VIASH_META_MEMORY_TIB+1023) / 1024 )) + |fi + | + |# meta synonyms + |export VIASH_TEMP="\\\$VIASH_META_TEMP_DIR" + |export TEMP_DIR="\\\$VIASH_META_TEMP_DIR" + | + |# create output dirs if need be + |function mkdir_parent { + | for file in "\\\$@"; do + | mkdir -p "\\\$(dirname "\\\$file")" + | done + |} + |$createParentStr + | + |# argument exports${inputFileExports.join()} + |\$parInject + | + |# process script + |${escapedScript} + |\"\"\" + |} + |""".stripMargin() + + // TODO: print on debug + // if (workflowArgs.debug == true) { + // println("######################\n$procStr\n######################") + // } + + // write process to temp file + def tempFile = java.nio.file.Files.createTempFile("viash-process-${procKey}-", ".nf") + addShutdownHook { java.nio.file.Files.deleteIfExists(tempFile) } + tempFile.text = procStr + + // create process from temp file + def binding = new nextflow.script.ScriptBinding([:]) + def session = nextflow.Nextflow.getSession() + def parser = new nextflow.script.ScriptParser(session) + .setModule(true) + .setBinding(binding) + def moduleScript = parser.runScript(tempFile) + .getScript() + + // register module in meta + def module = new nextflow.script.IncludeDef.Module(name: procKey) + scriptMeta.addModule(moduleScript, module.name, module.alias) + + // retrieve and return process from meta + return scriptMeta.getProcess(procKey) +} + +// defaults +meta["defaults"] = [ + // key to be used to trace the process and determine output names + key: null, + + // fixed arguments to be passed to script + args: [:], + + // default directives + directives: readJsonBlob('''{ + "container" : { + "registry" : "images.viash-hub.com", + "image" : "vsh/biobox/rseqc/rseqc_inferexperiment", + "tag" : "main" + }, + "tag" : "$id" +}'''), + + // auto settings + auto: readJsonBlob('''{ + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false +}'''), + + // Apply a map over the incoming tuple + // Example: `{ tup -> [ tup[0], [input: tup[1].output] ] + tup.drop(2) }` + map: null, + + // Apply a map over the ID element of a tuple (i.e. the first element) + // Example: `{ id -> id + "_foo" }` + mapId: null, + + // Apply a map over the data element of a tuple (i.e. the second element) + // Example: `{ data -> [ input: data.output ] }` + mapData: null, + + // Apply a map over the passthrough elements of a tuple (i.e. the tuple excl. the first two elements) + // Example: `{ pt -> pt.drop(1) }` + mapPassthrough: null, + + // Filter the channel + // Example: `{ tup -> tup[0] == "foo" }` + filter: null, + + // Choose whether or not to run the component on the tuple if the condition is true. + // Otherwise, the tuple will be passed through. + // Example: `{ tup -> tup[0] != "skip_this" }` + runIf: null, + + // Rename keys in the data field of the tuple (i.e. the second element) + // Will likely be deprecated in favour of `fromState`. + // Example: `[ "new_key": "old_key" ]` + renameKeys: null, + + // Fetch data from the state and pass it to the module without altering the current state. + // + // `fromState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be passed to the module as is. + // - If it is a `List[String]`, the data will be the values of the state at the given keys. + // - If it is a `Map[String, String]`, the data will be the values of the state at the given keys, with the keys renamed according to the map. + // - If it is a function, the tuple (`[id, state]`) in the channel will be passed to the function, and the result will be used as the data. + // + // Example: `{ id, state -> [input: state.fastq_file] }` + // Default: `null` + fromState: null, + + // Determine how the state should be updated after the module has been run. + // + // `toState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be replaced with the output of the module. + // - If it is a `List[String]`, the state will be updated with the values of the data at the given keys. + // - If it is a `Map[String, String]`, the state will be updated with the values of the data at the given keys, with the keys renamed according to the map. + // - If it is a function, a tuple (`[id, output, state]`) will be passed to the function, and the result will be used as the new state. + // + // Example: `{ id, output, state -> state + [counts: state.output] }` + // Default: `{ id, output, state -> output }` + toState: null, + + // Whether or not to print debug messages + // Default: `false` + debug: false +] + +// initialise default workflow +meta["workflow"] = workflowFactory([key: meta.config.name], meta.defaults, meta) + +// add workflow to environment +nextflow.script.ScriptMeta.current().addDefinition(meta.workflow) + +// anonymous workflow for running this module as a standalone +workflow { + // add id argument if it's not already in the config + // TODO: deep copy + def newConfig = deepClone(meta.config) + def newParams = deepClone(params) + + def argsContainsId = newConfig.allArguments.any{it.plainName == "id"} + if (!argsContainsId) { + def idArg = [ + 'name': '--id', + 'required': false, + 'type': 'string', + 'description': 'A unique id for every entry.', + 'multiple': false + ] + newConfig.arguments.add(0, idArg) + newConfig = processConfig(newConfig) + } + if (!newParams.containsKey("id")) { + newParams.id = "run" + } + + helpMessage(newConfig) + + channelFromParams(newParams, newConfig) + // make sure id is not in the state if id is not in the args + | map {id, state -> + if (!argsContainsId) { + [id, state.findAll{k, v -> k != "id"}] + } else { + [id, state] + } + } + | meta.workflow.run( + auto: [ publish: "state" ] + ) +} + +// END COMPONENT-SPECIFIC CODE diff --git a/target/nextflow/rseqc/rseqc_inferexperiment/nextflow.config b/target/nextflow/rseqc/rseqc_inferexperiment/nextflow.config new file mode 100644 index 00000000..d10d30e1 --- /dev/null +++ b/target/nextflow/rseqc/rseqc_inferexperiment/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'rseqc/rseqc_inferexperiment' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'main' + description = 'Infer strandedness from sequencing reads\n' + author = 'Emma Rousseau' +} + +process.container = 'nextflow/bash:latest' + +// detect tempdir +tempDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMPDIR') ?: + '/tmp' +).toAbsolutePath() + +profiles { + no_publish { + process { + withName: '.*' { + publishDir = [ + enabled: false + ] + } + } + } + mount_temp { + docker.temp = tempDir + podman.temp = tempDir + charliecloud.temp = tempDir + } + docker { + docker.enabled = true + // docker.userEmulation = true + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + singularity { + singularity.enabled = true + singularity.autoMounts = true + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + podman { + podman.enabled = true + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + shifter { + shifter.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + } + charliecloud { + charliecloud.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + } +} + +process{ + withLabel: mem1gb { memory = 1000000000.B } + withLabel: mem2gb { memory = 2000000000.B } + withLabel: mem5gb { memory = 5000000000.B } + withLabel: mem10gb { memory = 10000000000.B } + withLabel: mem20gb { memory = 20000000000.B } + withLabel: mem50gb { memory = 50000000000.B } + withLabel: mem100gb { memory = 100000000000.B } + withLabel: mem200gb { memory = 200000000000.B } + withLabel: mem500gb { memory = 500000000000.B } + withLabel: mem1tb { memory = 1000000000000.B } + withLabel: mem2tb { memory = 2000000000000.B } + withLabel: mem5tb { memory = 5000000000000.B } + withLabel: mem10tb { memory = 10000000000000.B } + withLabel: mem20tb { memory = 20000000000000.B } + withLabel: mem50tb { memory = 50000000000000.B } + withLabel: mem100tb { memory = 100000000000000.B } + withLabel: mem200tb { memory = 200000000000000.B } + withLabel: mem500tb { memory = 500000000000000.B } + withLabel: mem1gib { memory = 1073741824.B } + withLabel: mem2gib { memory = 2147483648.B } + withLabel: mem4gib { memory = 4294967296.B } + withLabel: mem8gib { memory = 8589934592.B } + withLabel: mem16gib { memory = 17179869184.B } + withLabel: mem32gib { memory = 34359738368.B } + withLabel: mem64gib { memory = 68719476736.B } + withLabel: mem128gib { memory = 137438953472.B } + withLabel: mem256gib { memory = 274877906944.B } + withLabel: mem512gib { memory = 549755813888.B } + withLabel: mem1tib { memory = 1099511627776.B } + withLabel: mem2tib { memory = 2199023255552.B } + withLabel: mem4tib { memory = 4398046511104.B } + withLabel: mem8tib { memory = 8796093022208.B } + withLabel: mem16tib { memory = 17592186044416.B } + withLabel: mem32tib { memory = 35184372088832.B } + withLabel: mem64tib { memory = 70368744177664.B } + withLabel: mem128tib { memory = 140737488355328.B } + withLabel: mem256tib { memory = 281474976710656.B } + withLabel: mem512tib { memory = 562949953421312.B } + withLabel: cpu1 { cpus = 1 } + withLabel: cpu2 { cpus = 2 } + withLabel: cpu5 { cpus = 5 } + withLabel: cpu10 { cpus = 10 } + withLabel: cpu20 { cpus = 20 } + withLabel: cpu50 { cpus = 50 } + withLabel: cpu100 { cpus = 100 } + withLabel: cpu200 { cpus = 200 } + withLabel: cpu500 { cpus = 500 } + withLabel: cpu1000 { cpus = 1000 } +} + + diff --git a/target/nextflow/rseqc/rseqc_inferexperiment/nextflow_schema.json b/target/nextflow/rseqc/rseqc_inferexperiment/nextflow_schema.json new file mode 100644 index 00000000..5ac5937d --- /dev/null +++ b/target/nextflow/rseqc/rseqc_inferexperiment/nextflow_schema.json @@ -0,0 +1,139 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "rseqc_inferexperiment", +"description": "Infer strandedness from sequencing reads\n", +"type": "object", +"definitions": { + + + + "input" : { + "title": "Input", + "type": "object", + "description": "No description", + "properties": { + + + "input_file": { + "type": + "string", + "description": "Type: `file`, required. input alignment file in BAM or SAM format", + "help_text": "Type: `file`, required. input alignment file in BAM or SAM format" + + } + + + , + "refgene": { + "type": + "string", + "description": "Type: `file`, required. Reference gene model in bed format", + "help_text": "Type: `file`, required. Reference gene model in bed format" + + } + + +} +}, + + + "output" : { + "title": "Output", + "type": "object", + "description": "No description", + "properties": { + + + "output": { + "type": + "string", + "description": "Type: `file`, required, default: `$id.$key.output.txt`, example: `$id.strandedness.txt`. Output file (txt) of strandness report", + "help_text": "Type: `file`, required, default: `$id.$key.output.txt`, example: `$id.strandedness.txt`. Output file (txt) of strandness report." + , + "default": "$id.$key.output.txt" + } + + +} +}, + + + "options" : { + "title": "Options", + "type": "object", + "description": "No description", + "properties": { + + + "sample_size": { + "type": + "integer", + "description": "Type: `integer`, example: `200000`. Number of reads sampled from SAM/BAM file", + "help_text": "Type: `integer`, example: `200000`. Number of reads sampled from SAM/BAM file. Default: 200000\n" + + } + + + , + "mapq": { + "type": + "integer", + "description": "Type: `integer`, example: `30`. Minimum mapping quality (phred scaled) to determine uniquely mapped reads", + "help_text": "Type: `integer`, example: `30`. Minimum mapping quality (phred scaled) to determine uniquely mapped reads. Default: 30\n" + + } + + +} +}, + + + "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" + }, + + { + "$ref": "#/definitions/output" + }, + + { + "$ref": "#/definitions/options" + }, + + { + "$ref": "#/definitions/nextflow input-output arguments" + } +] +} diff --git a/target/nextflow/rseqc/rseqc_inner_distance/.config.vsh.yaml b/target/nextflow/rseqc/rseqc_inner_distance/.config.vsh.yaml new file mode 100644 index 00000000..a2620a9e --- /dev/null +++ b/target/nextflow/rseqc/rseqc_inner_distance/.config.vsh.yaml @@ -0,0 +1,321 @@ +name: "rseqc_inner_distance" +namespace: "rseqc" +version: "main" +authors: +- name: "Emma Rousseau" + roles: + - "author" + - "maintainer" + info: + links: + email: "emma@data-intuitive.com" + github: "emmarousseau" + linkedin: "emmarousseau1" + organizations: + - name: "Data Intuitive" + href: "https://www.data-intuitive.com" + role: "Bioinformatician" +argument_groups: +- name: "Input" + arguments: + - type: "file" + name: "--input_file" + alternatives: + - "-i" + description: "input alignment file in BAM or SAM format" + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--refgene" + alternatives: + - "-r" + description: "Reference gene model in bed format" + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--sample_size" + alternatives: + - "-k" + description: "Numer of reads sampled from SAM/BAM file, default = 1000000." + info: null + example: + - 1000000 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--mapq" + alternatives: + - "-q" + description: "Minimum mapping quality (phred scaled) to determine uniquely mapped\ + \ reads, default=30." + info: null + example: + - 30 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--lower_bound" + alternatives: + - "-l" + description: "Lower bound of inner distance (bp). This option is used for ploting\ + \ histograme, default=-250." + info: null + example: + - -250 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--upper_bound" + alternatives: + - "-u" + description: "Upper bound of inner distance (bp). This option is used for ploting\ + \ histograme, default=250." + info: null + example: + - 250 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--step" + alternatives: + - "-s" + description: "Step size (bp) of histograme. This option is used for plotting histogram,\ + \ default=5." + info: null + example: + - 5 + required: false + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Output" + arguments: + - type: "string" + name: "--output_prefix" + alternatives: + - "-o" + description: "Rrefix of output files." + info: null + required: true + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_stats" + description: "output file (txt) with summary statistics of inner distances of\ + \ paired reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_dist" + description: "output file (txt) with inner distances of all paired reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_freq" + description: "output file (txt) with frequencies of inner distances of all paired\ + \ reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_plot" + description: "output file (pdf) with histogram plot of of inner distances of all\ + \ paired reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--output_plot_r" + description: "output file (R) with script of histogram plot of of inner distances\ + \ of all paired reads" + info: null + must_exist: true + create_parent: true + required: false + direction: "output" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Calculate inner distance between read pairs.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +- type: "file" + path: "test_data" +info: null +status: "enabled" +requirements: + commands: + - "ps" +license: "GPL-3.0" +references: + doi: + - "10.1093/bioinformatics/bts356" +links: + repository: "https://github.com/MonashBioinformaticsPlatform/RSeQC" + homepage: "https://rseqc.sourceforge.net/" + documentation: "https://rseqc.sourceforge.net/#inner-distance-py" + issue_tracker: "https://github.com/MonashBioinformaticsPlatform/RSeQC/issues" +runners: +- type: "executable" + id: "executable" + docker_setup_strategy: "ifneedbepullelsecachedbuild" +- type: "nextflow" + id: "nextflow" + directives: + tag: "$id" + auto: + simplifyInput: true + simplifyOutput: false + transcript: false + publish: false + config: + labels: + mem1gb: "memory = 1000000000.B" + mem2gb: "memory = 2000000000.B" + mem5gb: "memory = 5000000000.B" + mem10gb: "memory = 10000000000.B" + mem20gb: "memory = 20000000000.B" + mem50gb: "memory = 50000000000.B" + mem100gb: "memory = 100000000000.B" + mem200gb: "memory = 200000000000.B" + mem500gb: "memory = 500000000000.B" + mem1tb: "memory = 1000000000000.B" + mem2tb: "memory = 2000000000000.B" + mem5tb: "memory = 5000000000000.B" + mem10tb: "memory = 10000000000000.B" + mem20tb: "memory = 20000000000000.B" + mem50tb: "memory = 50000000000000.B" + mem100tb: "memory = 100000000000000.B" + mem200tb: "memory = 200000000000000.B" + mem500tb: "memory = 500000000000000.B" + mem1gib: "memory = 1073741824.B" + mem2gib: "memory = 2147483648.B" + mem4gib: "memory = 4294967296.B" + mem8gib: "memory = 8589934592.B" + mem16gib: "memory = 17179869184.B" + mem32gib: "memory = 34359738368.B" + mem64gib: "memory = 68719476736.B" + mem128gib: "memory = 137438953472.B" + mem256gib: "memory = 274877906944.B" + mem512gib: "memory = 549755813888.B" + mem1tib: "memory = 1099511627776.B" + mem2tib: "memory = 2199023255552.B" + mem4tib: "memory = 4398046511104.B" + mem8tib: "memory = 8796093022208.B" + mem16tib: "memory = 17592186044416.B" + mem32tib: "memory = 35184372088832.B" + mem64tib: "memory = 70368744177664.B" + mem128tib: "memory = 140737488355328.B" + mem256tib: "memory = 281474976710656.B" + mem512tib: "memory = 562949953421312.B" + cpu1: "cpus = 1" + cpu2: "cpus = 2" + cpu5: "cpus = 5" + cpu10: "cpus = 10" + cpu20: "cpus = 20" + cpu50: "cpus = 50" + cpu100: "cpus = 100" + cpu200: "cpus = 200" + cpu500: "cpus = 500" + cpu1000: "cpus = 1000" + debug: false + container: "docker" +engines: +- type: "docker" + id: "docker" + image: "python:3.10" + target_registry: "images.viash-hub.com" + target_tag: "main" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "r-base" + interactive: false + - type: "python" + user: false + packages: + - "RSeQC" + upgrade: true + - type: "docker" + run: + - "echo \"RSeQC - inner_distance.py: $(inner_distance.py --version | cut -d' '\ + \ -f2)\" > /var/software_versions.txt\n" + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/rseqc/rseqc_inner_distance/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/rseqc/rseqc_inner_distance" + executable: "target/nextflow/rseqc/rseqc_inner_distance/main.nf" + viash_version: "0.9.0" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" +package_config: + name: "biobox" + version: "main" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0" + 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 := 'main'" + keywords: + - "bioinformatics" + - "modules" + - "sequencing" + license: "MIT" + organization: "vsh" + links: + repository: "https://github.com/viash-hub/biobox" + issue_tracker: "https://github.com/viash-hub/biobox/issues" diff --git a/target/nextflow/rseqc/rseqc_inner_distance/main.nf b/target/nextflow/rseqc/rseqc_inner_distance/main.nf new file mode 100644 index 00000000..50bd7154 --- /dev/null +++ b/target/nextflow/rseqc/rseqc_inner_distance/main.nf @@ -0,0 +1,3753 @@ +// rseqc_inner_distance main +// +// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative +// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data +// Intuitive. +// +// The component may contain files which fall under a different license. The +// authors of this component should specify the license in the header of such +// files, or include a separate license file detailing the licenses of all included +// files. +// +// Component authors: +// * Emma Rousseau (author, maintainer) + +//////////////////////////// +// VDSL3 helper functions // +//////////////////////////// + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_checkArgumentType.nf' +class UnexpectedArgumentTypeException extends Exception { + String errorIdentifier + String stage + String plainName + String expectedClass + String foundClass + + // ${key ? " in module '$key'" : ""}${id ? " id '$id'" : ""} + UnexpectedArgumentTypeException(String errorIdentifier, String stage, String plainName, String expectedClass, String foundClass) { + super("Error${errorIdentifier ? " $errorIdentifier" : ""}:${stage ? " $stage" : "" } argument '${plainName}' has the wrong type. " + + "Expected type: ${expectedClass}. Found type: ${foundClass}") + this.errorIdentifier = errorIdentifier + this.stage = stage + this.plainName = plainName + this.expectedClass = expectedClass + this.foundClass = foundClass + } +} + +/** + * Checks if the given value is of the expected type. If not, an exception is thrown. + * + * @param stage The stage of the argument (input or output) + * @param par The parameter definition + * @param value The value to check + * @param errorIdentifier The identifier to use in the error message + * @return The value, if it is of the expected type + * @throws UnexpectedArgumentTypeException If the value is not of the expected type +*/ +def _checkArgumentType(String stage, Map par, Object value, String errorIdentifier) { + // expectedClass will only be != null if value is not of the expected type + def expectedClass = null + def foundClass = null + + // todo: split if need be + + if (!par.required && value == null) { + expectedClass = null + } else if (par.multiple) { + if (value !instanceof Collection) { + value = [value] + } + + // split strings + value = value.collectMany{ val -> + if (val instanceof String) { + // collect() to ensure that the result is a List and not simply an array + val.split(par.multiple_sep).collect() + } else { + [val] + } + } + + // process globs + if (par.type == "file" && par.direction == "input") { + value = value.collect{ it instanceof String ? file(it, hidden: true) : it }.flatten() + } + + // check types of elements in list + try { + value = value.collect { listVal -> + _checkArgumentType(stage, par + [multiple: false], listVal, errorIdentifier) + } + } catch (UnexpectedArgumentTypeException e) { + expectedClass = "List[${e.expectedClass}]" + foundClass = "List[${e.foundClass}]" + } + } else if (par.type == "string") { + // cast to string if need be + if (value instanceof GString) { + value = value.toString() + } + expectedClass = value instanceof String ? null : "String" + } else if (par.type == "integer") { + // cast to integer if need be + if (value instanceof String) { + try { + value = value.toInteger() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toLong() + } catch (NumberFormatException e) { + // do nothing + } + } + 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) { + try { + value = value.toDouble() + } catch (NumberFormatException e) { + // do nothing + } + } + if (value instanceof java.math.BigDecimal) { + value = value.doubleValue() + } + 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 + } + } + 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) { + value = file(value, hidden: true) + } + if (value instanceof File) { + value = value.toPath() + } + 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() + } + expectedClass = value instanceof String ? null : "String" + } else { + // didn't find a match for par.type + expectedClass = par.type + } + + if (expectedClass != null) { + if (foundClass == null) { + foundClass = value.getClass().getName() + } + throw new UnexpectedArgumentTypeException(errorIdentifier, stage, par.plainName, expectedClass, foundClass) + } + + return value +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processInputValues.nf' +Map _processInputValues(Map inputs, Map config, String id, String key) { + if (!workflow.stubRun) { + config.allArguments.each { arg -> + if (arg.required) { + assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null : + "Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing" + } + } + + inputs = inputs.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid input argument" + + value = _checkArgumentType("input", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return inputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf' +Map _processOutputValues(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" + + value = _checkArgumentType("output", par, value, "in module '$key' id '$id'") + + [ name, value ] + } + } + return outputs +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf' +class IDChecker { + final def items = [] as Set + + @groovy.transform.WithWriteLock + boolean observe(String item) { + if (items.contains(item)) { + return false + } else { + items << item + return true + } + } + + @groovy.transform.WithReadLock + boolean contains(String item) { + return items.contains(item) + } + + @groovy.transform.WithReadLock + Set getItems() { + return items.clone() + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_checkUniqueIds.nf' + +/** + * Check if the ids are unique across parameter sets + * + * @param parameterSets a list of parameter sets. + */ +private void _checkUniqueIds(List>> parameterSets) { + def ppIds = parameterSets.collect{it[0]} + assert ppIds.size() == ppIds.unique().size() : "All argument sets should have unique ids. Detected ids: $ppIds" +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_getChild.nf' + +// helper functions for reading params from file // +def _getChild(parent, child) { + if (child.contains("://") || java.nio.file.Paths.get(child).isAbsolute()) { + child + } else { + def parentAbsolute = java.nio.file.Paths.get(parent).toAbsolutePath().toString() + parentAbsolute.replaceAll('/[^/]*$', "/") + child + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_parseParamList.nf' +/** + * Figure out the param list format based on the file extension + * + * @param param_list A String containing the path to the parameter list file. + * + * @return A String containing the format of the parameter list file. + */ +def _paramListGuessFormat(param_list) { + if (param_list !instanceof String) { + "asis" + } else if (param_list.endsWith(".csv")) { + "csv" + } else if (param_list.endsWith(".json") || param_list.endsWith(".jsn")) { + "json" + } else if (param_list.endsWith(".yaml") || param_list.endsWith(".yml")) { + "yaml" + } else { + "yaml_blob" + } +} + + +/** + * Read the param list + * + * @param param_list One of the following: + * - A String containing the path to the parameter list file (csv, json or yaml), + * - A yaml blob of a list of maps (yaml_blob), + * - Or a groovy list of maps (asis). + * @param config A Map of the Viash configuration. + * + * @return A List of Maps containing the parameters. + */ +def _parseParamList(param_list, Map config) { + // first determine format by extension + def paramListFormat = _paramListGuessFormat(param_list) + + def paramListPath = (paramListFormat != "asis" && paramListFormat != "yaml_blob") ? + file(param_list, hidden: true) : + null + + // get the correct parser function for the detected params_list format + def paramSets = [] + if (paramListFormat == "asis") { + paramSets = param_list + } else if (paramListFormat == "yaml_blob") { + paramSets = readYamlBlob(param_list) + } else if (paramListFormat == "yaml") { + paramSets = readYaml(paramListPath) + } else if (paramListFormat == "json") { + paramSets = readJson(paramListPath) + } else if (paramListFormat == "csv") { + paramSets = readCsv(paramListPath) + } else { + error "Format of provided --param_list not recognised.\n" + + "Found: '$paramListFormat'.\n" + + "Expected: a csv file, a json file, a yaml file,\n" + + "a yaml blob or a groovy list of maps." + } + + // data checks + assert paramSets instanceof List: "--param_list should contain a list of maps" + for (value in paramSets) { + assert value instanceof Map: "--param_list should contain a list of maps" + } + + // id is argument + def idIsArgument = config.allArguments.any{it.plainName == "id"} + + // Reformat from List to List> by adding the ID as first element of a Tuple2 + paramSets = paramSets.collect({ data -> + def id = data.id + if (!idIsArgument) { + data = data.findAll{k, v -> k != "id"} + } + [id, data] + }) + + // Split parameters with 'multiple: true' + paramSets = paramSets.collect({ id, data -> + data = _splitParams(data, config) + [id, data] + }) + + // The paths of input files inside a param_list file may have been specified relatively to the + // location of the param_list file. These paths must be made absolute. + if (paramListPath) { + paramSets = paramSets.collect({ id, data -> + def new_data = data.collectEntries{ parName, parValue -> + def par = config.allArguments.find{it.plainName == parName} + if (par && par.type == "file" && par.direction == "input") { + if (parValue instanceof Collection) { + parValue = parValue.collectMany{path -> + def x = _resolveSiblingIfNotAbsolute(path, paramListPath) + x instanceof Collection ? x : [x] + } + } else { + parValue = _resolveSiblingIfNotAbsolute(parValue, paramListPath) + } + } + [parName, parValue] + } + [id, new_data] + }) + } + + return paramSets +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_splitParams.nf' +/** + * Split parameters for arguments that accept multiple values using their separator + * + * @param paramList A Map containing parameters to split. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A Map of parameters where the parameter values have been split into a list using + * their seperator. + */ +Map _splitParams(Map parValues, Map config){ + def parsedParamValues = parValues.collectEntries { parName, parValue -> + def parameterSettings = config.allArguments.find({it.plainName == parName}) + + if (!parameterSettings) { + // if argument is not found, do not alter + return [parName, parValue] + } + if (parameterSettings.multiple) { // Check if parameter can accept multiple values + if (parValue instanceof Collection) { + parValue = parValue.collect{it instanceof String ? it.split(parameterSettings.multiple_sep) : it } + } else if (parValue instanceof String) { + parValue = parValue.split(parameterSettings.multiple_sep) + } else if (parValue == null) { + parValue = [] + } else { + parValue = [ parValue ] + } + parValue = parValue.flatten() + } + // For all parameters check if multiple values are only passed for + // arguments that allow it. Quietly simplify lists of length 1. + if (!parameterSettings.multiple && parValue instanceof Collection) { + assert parValue.size() == 1 : + "Error: argument ${parName} has too many values.\n" + + " Expected amount: 1. Found: ${parValue.size()}" + parValue = parValue[0] + } + [parName, parValue] + } + return parsedParamValues +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/channelFromParams.nf' +/** + * Parse nextflow parameters based on settings defined in a viash config. + * Return a list of parameter sets, each parameter set corresponding to + * an event in a nextflow channel. The output from this function can be used + * with Channel.fromList to create a nextflow channel with Vdsl3 formatted + * events. + * + * This function performs: + * - A filtering of the params which can be found in the config file. + * - Process the params_list argument which allows a user to to initialise + * a Vsdl3 channel with multiple parameter sets. Possible formats are + * csv, json, yaml, or simply a yaml_blob. A csv should have column names + * which correspond to the different arguments of this pipeline. A json or a yaml + * file should be a list of maps, each of which has keys corresponding to the + * arguments of the pipeline. A yaml blob can also be passed directly as a parameter. + * When passing a csv, json or yaml, relative path names are relativized to the + * location of the parameter file. + * - Combine the parameter sets into a vdsl3 Channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A list of parameters with the first element of the event being + * the event ID and the second element containing a map of the parsed parameters. + */ + +private List>> _paramsToParamSets(Map params, Map config){ + // todo: fetch key from run args + def key_ = config.name + + /* parse regular parameters (not in param_list) */ + /*************************************************/ + def globalParams = config.allArguments + .findAll { params.containsKey(it.plainName) } + .collectEntries { [ it.plainName, params[it.plainName] ] } + def globalID = params.get("id", null) + + /* process params_list arguments */ + /*********************************/ + def paramList = params.containsKey("param_list") && params.param_list != null ? + params.param_list : [] + // if (paramList instanceof String) { + // paramList = [paramList] + // } + // def paramSets = paramList.collectMany{ _parseParamList(it, config) } + // TODO: be able to process param_list when it is a list of strings + def paramSets = _parseParamList(paramList, config) + if (paramSets.isEmpty()) { + paramSets = [[null, [:]]] + } + + /* combine arguments into channel */ + /**********************************/ + def processedParams = paramSets.indexed().collect{ index, tup -> + // Process ID + def id = tup[0] ?: globalID + + if (workflow.stubRun && !id) { + // if stub run, explicitly add an id if missing + id = "stub${index}" + } + assert id != null: "Each parameter set should have at least an 'id'" + + // Process params + def parValues = globalParams + tup[1] + // // Remove parameters which are null, if the default is also null + // parValues = parValues.collectEntries{paramName, paramValue -> + // parameterSettings = config.functionality.allArguments.find({it.plainName == paramName}) + // if ( paramValue != null || parameterSettings.get("default", null) != null ) { + // [paramName, paramValue] + // } + // } + parValues = parValues.collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + assert par != null : "Error in module '${key_}' id '${id}': '${name}' is not a valid input argument" + + if (par == null) { + return [:] + } + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + + [ name, value ] + } + + [id, parValues] + } + + // Check if ids (first element of each list) is unique + _checkUniqueIds(processedParams) + return processedParams +} + +/** + * Parse nextflow parameters based on settings defined in a viash config + * and return a nextflow channel. + * + * @param params Input parameters. Can optionaly contain a 'param_list' key that + * provides a list of arguments that can be split up into multiple events + * in the output channel possible formats of param_lists are: a csv file, + * json file, a yaml file or a yaml blob. Each parameters set (event) must + * have a unique ID. + * @param config A Map of the Viash configuration. This Map can be generated from the config file + * using the readConfig() function. + * + * @return A nextflow Channel with events. Events are formatted as a tuple that contains + * first contains the ID of the event and as second element holds a parameter map. + * + * + */ +def channelFromParams(Map params, Map config) { + def processedParams = _paramsToParamSets(params, config) + return Channel.fromList(processedParams) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/checkUniqueIds.nf' +def checkUniqueIds(Map args) { + def stopOnError = args.stopOnError == null ? args.stopOnError : true + + def idChecker = new IDChecker() + + return filter { tup -> + if (!idChecker.observe(tup[0])) { + if (stopOnError) { + error "Duplicate id: ${tup[0]}" + } else { + log.warn "Duplicate id: ${tup[0]}, removing duplicate entry" + return false + } + } + return true + } +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/preprocessInputs.nf' +// This helper file will be deprecated soon +preprocessInputsDeprecationWarningPrinted = false + +def preprocessInputsDeprecationWarning() { + if (!preprocessInputsDeprecationWarningPrinted) { + preprocessInputsDeprecationWarningPrinted = true + System.err.println("Warning: preprocessInputs() is deprecated and will be removed in Viash 0.9.0.") + } +} + +/** + * Generate a nextflow Workflow that allows processing a channel of + * Vdsl3 formatted events and apply a Viash config to them: + * - Gather default parameters from the Viash config and make + * sure that they are correctly formatted (see applyConfig method). + * - Format the input parameters (also using the applyConfig method). + * - Apply the default parameter to the input parameters. + * - Do some assertions: + * ~ Check if the event IDs in the channel are unique. + * + * The events in the channel are formatted as tuples, with the + * first element of the tuples being a unique id of the parameter set, + * and the second element containg the the parameters themselves. + * Optional extra elements of the tuples will be passed to the output as is. + * + * @param args A map that must contain a 'config' key that points + * to a parsed config (see readConfig()). Optionally, a + * 'key' key can be provided which can be used to create a unique + * name for the workflow process. + * + * @return A workflow that allows processing a channel of Vdsl3 formatted events + * and apply a Viash config to them. + */ +def preprocessInputs(Map args) { + preprocessInputsDeprecationWarning() + + def config = args.config + assert config instanceof Map : + "Error in preprocessInputs: config must be a map. " + + "Expected class: Map. Found: config.getClass() is ${config.getClass()}" + def key_ = args.key ?: config.name + + // Get different parameter types (used throughout this function) + def defaultArgs = config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + map { tup -> + def id = tup[0] + def data = tup[1] + def passthrough = tup.drop(2) + + def new_data = (defaultArgs + data).collectEntries { name, value -> + def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") } + + if (par != null) { + value = _checkArgumentType("input", par, value, "in module '$key_' id '$id'") + } + + [ name, value ] + } + + [ id, new_data ] + passthrough + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runComponents.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component config. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component config. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component config. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component config. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runComponents(Map args) { + log.warn("runComponents is deprecated, use runEach instead") + assert args.components: "runComponents should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runComponents" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def id_ = args.id + + workflow runComponentsWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def comp_config = comp_.config + + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_config) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + // def new_id = id_(tup[0], tup[1], comp_config) + def new_id = tup[0] + if (id_ instanceof String) { + new_id = id_ + } else if (id_ instanceof Closure) { + new_id = id_(new_id, tup[1], comp_config) + } + [new_id] + tup.drop(1) + } + : filter_ch + def data_ch = id_ch | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_config) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_config) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + post_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runComponentsWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/runEach.nf' +/** + * Run a list of components on a stream of data. + * + * @param components: list of Viash VDSL3 modules to run + * @param fromState: a closure, a map or a list of keys to extract from the input data. + * If a closure, it will be called with the id, the data and the component itself. + * @param toState: a closure, a map or a list of keys to extract from the output data + * If a closure, it will be called with the id, the output data, the old state and the component itself. + * @param filter: filter function to apply to the input. + * It will be called with the id, the data and the component itself. + * @param id: id to use for the output data + * If a closure, it will be called with the id, the data and the component itself. + * @param auto: auto options to pass to the components + * + * @return: a workflow that runs the components + **/ +def runEach(Map args) { + assert args.components: "runEach should be passed a list of components to run" + + def components_ = args.components + if (components_ !instanceof List) { + components_ = [ components_ ] + } + assert components_.size() > 0: "pass at least one component to runEach" + + def fromState_ = args.fromState + def toState_ = args.toState + def filter_ = args.filter + def runIf_ = args.runIf + def id_ = args.id + + assert !runIf_ || runIf_ instanceof Closure: "runEach: must pass a Closure to runIf." + + workflow runEachWf { + take: input_ch + main: + + // generate one channel per method + out_chs = components_.collect{ comp_ -> + def filter_ch = filter_ + ? input_ch | filter{tup -> + filter_(tup[0], tup[1], comp_) + } + : input_ch + def id_ch = id_ + ? filter_ch | map{tup -> + def new_id = id_ + if (new_id instanceof Closure) { + new_id = new_id(tup[0], tup[1], comp_) + } + assert new_id instanceof String : "Error in runEach: id should be a String or a Closure that returns a String. Expected: id instanceof String. Found: ${new_id.getClass()}" + [new_id] + tup.drop(1) + } + : filter_ch + def chPassthrough = null + def chRun = null + if (runIf_) { + def idRunIfBranch = id_ch.branch{ tup -> + run: runIf_(tup[0], tup[1], comp_) + passthrough: true + } + chPassthrough = idRunIfBranch.passthrough + chRun = idRunIfBranch.run + } else { + chRun = id_ch + chPassthrough = Channel.empty() + } + def data_ch = chRun | map{tup -> + def new_data = tup[1] + if (fromState_ instanceof Map) { + new_data = fromState_.collectEntries{ key0, key1 -> + [key0, new_data[key1]] + } + } else if (fromState_ instanceof List) { + new_data = fromState_.collectEntries{ key -> + [key, new_data[key]] + } + } else if (fromState_ instanceof Closure) { + new_data = fromState_(tup[0], new_data, comp_) + } + tup.take(1) + [new_data] + tup.drop(1) + } + def out_ch = data_ch + | comp_.run( + auto: (args.auto ?: [:]) + [simplifyInput: false, simplifyOutput: false] + ) + def post_ch = toState_ + ? out_ch | map{tup -> + def output = tup[1] + def old_state = tup[2] + def new_state = null + if (toState_ instanceof Map) { + new_state = old_state + toState_.collectEntries{ key0, key1 -> + [key0, output[key1]] + } + } else if (toState_ instanceof List) { + new_state = old_state + toState_.collectEntries{ key -> + [key, output[key]] + } + } else if (toState_ instanceof Closure) { + new_state = toState_(tup[0], output, old_state, comp_) + } + [tup[0], new_state] + tup.drop(3) + } + : out_ch + + def return_ch = post_ch + | concat(chPassthrough) + + return_ch + } + + // mix all results + output_ch = + (out_chs.size == 1) + ? out_chs[0] + : out_chs[0].mix(*out_chs.drop(1)) + + emit: output_ch + } + + return runEachWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/safeJoin.nf' +/** + * Join sourceChannel to targetChannel + * + * This function joins the sourceChannel to the targetChannel. + * However, each id in the targetChannel must be present in the + * sourceChannel. If _meta.join_id exists in the targetChannel, that is + * used as an id instead. If the id doesn't match any id in the sourceChannel, + * an error is thrown. + */ + +def safeJoin(targetChannel, sourceChannel, key) { + def sourceIDs = new IDChecker() + + def sourceCheck = sourceChannel + | map { tup -> + sourceIDs.observe(tup[0]) + tup + } + def targetCheck = targetChannel + | map { tup -> + def id = tup[0] + + if (!sourceIDs.contains(id)) { + error ( + "Error in module '${key}' when merging output with original state.\n" + + " Reason: output with id '${id}' could not be joined with source channel.\n" + + " If the IDs in the output channel differ from the input channel,\n" + + " please set `tup[1]._meta.join_id to the original ID.\n" + + " Original IDs in input channel: ['${sourceIDs.getItems().join("', '")}'].\n" + + " Unexpected ID in the output channel: '${id}'.\n" + + " Example input event: [\"id\", [input: file(...)]],\n" + + " Example output event: [\"newid\", [output: file(...), _meta: [join_id: \"id\"]]]" + ) + } + // TODO: add link to our documentation on how to fix this + + tup + } + + sourceCheck.cross(targetChannel) + | map{ left, right -> + right + left.drop(1) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/_processArgument.nf' +def _processArgument(arg) { + arg.multiple = arg.multiple != null ? arg.multiple : false + arg.required = arg.required != null ? arg.required : false + arg.direction = arg.direction != null ? arg.direction : "input" + arg.multiple_sep = arg.multiple_sep != null ? arg.multiple_sep : ";" + arg.plainName = arg.name.replaceAll("^-*", "") + + if (arg.type == "file") { + arg.must_exist = arg.must_exist != null ? arg.must_exist : true + arg.create_parent = arg.create_parent != null ? arg.create_parent : true + } + + // add default values to output files which haven't already got a default + if (arg.type == "file" && arg.direction == "output" && arg.default == null) { + def mult = arg.multiple ? "_*" : "" + def extSearch = "" + if (arg.default != null) { + extSearch = arg.default + } else if (arg.example != null) { + extSearch = arg.example + } + if (extSearch instanceof List) { + extSearch = extSearch[0] + } + def extSearchResult = extSearch.find("\\.[^\\.]+\$") + def ext = extSearchResult != null ? extSearchResult : "" + arg.default = "\$id.\$key.${arg.plainName}${mult}${ext}" + if (arg.multiple) { + arg.default = [arg.default] + } + } + + if (!arg.multiple) { + if (arg.default != null && arg.default instanceof List) { + arg.default = arg.default[0] + } + if (arg.example != null && arg.example instanceof List) { + arg.example = arg.example[0] + } + } + + if (arg.type == "boolean_true") { + arg.default = false + } + if (arg.type == "boolean_false") { + arg.default = true + } + + arg +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/addGlobalParams.nf' +def addGlobalArguments(config) { + def localConfig = [ + "argument_groups": [ + [ + "name": "Nextflow input-output arguments", + "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.", + "arguments" : [ + [ + 'name': '--publish_dir', + 'required': true, + 'type': 'string', + 'description': 'Path to an output directory.', + 'example': 'output/', + 'multiple': false + ], + [ + 'name': '--param_list', + 'required': false, + 'type': 'string', + 'description': '''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. + | + |* 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: [ ['id': 'foo', 'input': 'foo.txt'], ['id': 'bar', 'input': 'bar.txt'] ]`. + |* 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`. + |* 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 `[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]`. + |* A yaml blob can also be passed directly as a string. Example: `--param_list "[ {'id': 'foo', 'input': 'foo.txt'}, {'id': 'bar', 'input': 'bar.txt'} ]"`. + | + |When 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.'''.stripMargin(), + 'example': 'my_params.yaml', + 'multiple': false, + 'hidden': true + ] + // TODO: allow multiple: true in param_list? + // TODO: allow to specify a --param_list_regex to filter the param_list? + // TODO: allow to specify a --param_list_from_state to remap entries in the param_list? + ] + ] + ] + ] + + return processConfig(_mergeMap(config, localConfig)) +} + +def _mergeMap(Map lhs, Map rhs) { + return rhs.inject(lhs.clone()) { map, entry -> + if (map[entry.key] instanceof Map && entry.value instanceof Map) { + map[entry.key] = _mergeMap(map[entry.key], entry.value) + } else if (map[entry.key] instanceof Collection && entry.value instanceof Collection) { + map[entry.key] += entry.value + } else { + map[entry.key] = entry.value + } + return map + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/generateHelp.nf' +def _generateArgumentHelp(param) { + // alternatives are not supported + // def names = param.alternatives ::: List(param.name) + + def unnamedProps = [ + ["required parameter", param.required], + ["multiple values allowed", param.multiple], + ["output", param.direction.toLowerCase() == "output"], + ["file must exist", param.type == "file" && param.must_exist] + ].findAll{it[1]}.collect{it[0]} + + def dflt = null + if (param.default != null) { + if (param.default instanceof List) { + dflt = param.default.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + dflt = param.default.toString() + } + } + def example = null + if (param.example != null) { + if (param.example instanceof List) { + example = param.example.join(param.multiple_sep != null ? param.multiple_sep : ", ") + } else { + example = param.example.toString() + } + } + def min = param.min?.toString() + def max = param.max?.toString() + + def escapeChoice = { choice -> + def s1 = choice.replaceAll("\\n", "\\\\n") + def s2 = s1.replaceAll("\"", """\\\"""") + s2.contains(",") || s2 != choice ? "\"" + s2 + "\"" : s2 + } + def choices = param.choices == null ? + null : + "[ " + param.choices.collect{escapeChoice(it.toString())}.join(", ") + " ]" + + def namedPropsStr = [ + ["type", ([param.type] + unnamedProps).join(", ")], + ["default", dflt], + ["example", example], + ["choices", choices], + ["min", min], + ["max", max] + ] + .findAll{it[1]} + .collect{"\n " + it[0] + ": " + it[1].replaceAll("\n", "\\n")} + .join("") + + def descStr = param.description == null ? + "" : + _paragraphWrap("\n" + param.description.trim(), 80 - 8).join("\n ") + + "\n --" + param.plainName + + namedPropsStr + + descStr +} + +// Based on Helper.generateHelp() in Helper.scala +def _generateHelp(config) { + def fun = config + + // PART 1: NAME AND VERSION + def nameStr = fun.name + + (fun.version == null ? "" : " " + fun.version) + + // PART 2: DESCRIPTION + def descrStr = fun.description == null ? + "" : + "\n\n" + _paragraphWrap(fun.description.trim(), 80).join("\n") + + // PART 3: Usage + def usageStr = fun.usage == null ? + "" : + "\n\nUsage:\n" + fun.usage.trim() + + // PART 4: Options + def argGroupStrs = fun.allArgumentGroups.collect{argGroup -> + def name = argGroup.name + def descriptionStr = argGroup.description == null ? + "" : + "\n " + _paragraphWrap(argGroup.description.trim(), 80-4).join("\n ") + "\n" + def arguments = argGroup.arguments.collect{arg -> + arg instanceof String ? fun.allArguments.find{it.plainName == arg} : arg + }.findAll{it != null} + def argumentStrs = arguments.collect{param -> _generateArgumentHelp(param)} + + "\n\n$name:" + + descriptionStr + + argumentStrs.join("\n") + } + + // FINAL: combine + def out = nameStr + + descrStr + + usageStr + + argGroupStrs.join("") + + return out +} + +// based on Format._paragraphWrap +def _paragraphWrap(str, maxLength) { + def outLines = [] + str.split("\n").each{par -> + def words = par.split("\\s").toList() + + def word = null + def line = words.pop() + while(!words.isEmpty()) { + word = words.pop() + if (line.length() + word.length() + 1 <= maxLength) { + line = line + " " + word + } else { + outLines.add(line) + line = word + } + } + if (words.isEmpty()) { + outLines.add(line) + } + } + return outLines +} + +def helpMessage(config) { + if (params.containsKey("help") && params.help) { + def mergedConfig = addGlobalArguments(config) + def helpStr = _generateHelp(mergedConfig) + println(helpStr) + exit 0 + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/processConfig.nf' +def processConfig(config) { + // set defaults for arguments + config.arguments = + (config.arguments ?: []).collect{_processArgument(it)} + + // set defaults for argument_group arguments + config.argument_groups = + (config.argument_groups ?: []).collect{grp -> + grp.arguments = (grp.arguments ?: []).collect{_processArgument(it)} + grp + } + + // create combined arguments list + config.allArguments = + config.arguments + + config.argument_groups.collectMany{it.arguments} + + // add missing argument groups (based on Functionality::allArgumentGroups()) + def argGroups = config.argument_groups + if (argGroups.any{it.name.toLowerCase() == "arguments"}) { + argGroups = argGroups.collect{ grp -> + if (grp.name.toLowerCase() == "arguments") { + grp = grp + [ + arguments: grp.arguments + config.arguments + ] + } + grp + } + } else { + argGroups = argGroups + [ + name: "Arguments", + arguments: config.arguments + ] + } + config.allArgumentGroups = argGroups + + config +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/config/readConfig.nf' + +def readConfig(file) { + def config = readYaml(file ?: moduleDir.resolve("config.vsh.yaml")) + processConfig(config) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_resolveSiblingIfNotAbsolute.nf' +/** + * Resolve a path relative to the current file. + * + * @param str The path to resolve, as a String. + * @param parentPath The path to resolve relative to, as a Path. + * + * @return The path that may have been resovled, as a Path. + */ +def _resolveSiblingIfNotAbsolute(str, parentPath) { + if (str !instanceof String) { + return str + } + if (!_stringIsAbsolutePath(str)) { + return parentPath.resolveSibling(str) + } else { + return file(str, hidden: true) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/_stringIsAbsolutePath.nf' +/** + * Check whether a path as a string is absolute. + * + * In the past, we tried using `file(., relative: true).isAbsolute()`, + * but the 'relative' option was added in 22.10.0. + * + * @param path The path to check, as a String. + * + * @return Whether the path is absolute, as a boolean. + */ +def _stringIsAbsolutePath(path) { + def _resolve_URL_PROTOCOL = ~/^([a-zA-Z][a-zA-Z0-9]*:)?\\/.+/ + + assert path instanceof String + return _resolve_URL_PROTOCOL.matcher(path).matches() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/collectTraces.nf' +class CustomTraceObserver implements nextflow.trace.TraceObserver { + List traces + + CustomTraceObserver(List traces) { + this.traces = traces + } + + @Override + void onProcessComplete(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } + + @Override + void onProcessCached(nextflow.processor.TaskHandler handler, nextflow.trace.TraceRecord trace) { + def trace2 = trace.store.clone() + trace2.script = null + traces.add(trace2) + } +} + +def collectTraces() { + def traces = Collections.synchronizedList([]) + + // add custom trace observer which stores traces in the traces object + session.observers.add(new CustomTraceObserver(traces)) + + traces +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/deepClone.nf' +/** + * Performs a deep clone of the given object. + * @param x an object + */ +def deepClone(x) { + iterateMap(x, {it instanceof Cloneable ? it.clone() : it}) +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getPublishDir.nf' +def getPublishDir() { + return params.containsKey("publish_dir") ? params.publish_dir : + params.containsKey("publishDir") ? params.publishDir : + null +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/getRootDir.nf' + +// Recurse upwards until we find a '.build.yaml' file +def _findBuildYamlFile(pathPossiblySymlink) { + def path = pathPossiblySymlink.toRealPath() + def child = path.resolve(".build.yaml") + if (java.nio.file.Files.isDirectory(path) && java.nio.file.Files.exists(child)) { + return child + } else { + def parent = path.getParent() + if (parent == null) { + return null + } else { + return _findBuildYamlFile(parent) + } + } +} + +// get the root of the target folder +def getRootDir() { + def dir = _findBuildYamlFile(meta.resources_dir) + assert dir != null: "Could not find .build.yaml in the folder structure" + dir.getParent() +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/iterateMap.nf' +/** + * Recursively apply a function over the leaves of an object. + * @param obj The object to iterate over. + * @param fun The function to apply to each value. + * @return The object with the function applied to each value. + */ +def iterateMap(obj, fun) { + if (obj instanceof List && obj !instanceof String) { + return obj.collect{item -> + iterateMap(item, fun) + } + } else if (obj instanceof Map) { + return obj.collectEntries{key, item -> + [key.toString(), iterateMap(item, fun)] + } + } else { + return fun(obj) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/functions/niceView.nf' +/** + * A view for printing the event of each channel as a YAML blob. + * This is useful for debugging. + */ +def niceView() { + workflow niceViewWf { + take: input + main: + output = input + | view{toYamlBlob(it)} + emit: output + } + return niceViewWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readCsv.nf' + +def readCsv(file_path) { + def output = [] + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + + // todo: allow escaped quotes in string + // todo: allow single quotes? + def splitRegex = java.util.regex.Pattern.compile(''',(?=(?:[^"]*"[^"]*")*[^"]*$)''') + def removeQuote = java.util.regex.Pattern.compile('''"(.*)"''') + + def br = java.nio.file.Files.newBufferedReader(inputFile) + + def row = -1 + def header = null + while (br.ready() && header == null) { + def line = br.readLine() + row++ + if (!line.startsWith("#")) { + header = splitRegex.split(line, -1).collect{field -> + m = removeQuote.matcher(field) + m.find() ? m.replaceFirst('$1') : field + } + } + } + assert header != null: "CSV file should contain a header" + + while (br.ready()) { + def line = br.readLine() + row++ + if (line == null) { + br.close() + break + } + + if (!line.startsWith("#")) { + def predata = splitRegex.split(line, -1) + def data = predata.collect{field -> + if (field == "") { + return null + } + def m = removeQuote.matcher(field) + if (m.find()) { + return m.replaceFirst('$1') + } else { + return field + } + } + assert header.size() == data.size(): "Row $row should contain the same number as fields as the header" + + def dataMap = [header, data].transpose().collectEntries().findAll{it.value != null} + output.add(dataMap) + } + } + + output +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJson.nf' +def readJson(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parse(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readJsonBlob.nf' +def readJsonBlob(str) { + def jsonSlurper = new groovy.json.JsonSlurper() + jsonSlurper.parseText(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readTaggedYaml.nf' +// Custom constructor to modify how certain objects are parsed from YAML +class CustomConstructor extends org.yaml.snakeyaml.constructor.Constructor { + Path root + + class ConstructPath extends org.yaml.snakeyaml.constructor.AbstractConstruct { + public Object construct(org.yaml.snakeyaml.nodes.Node node) { + String filename = (String) constructScalar(node); + if (root != null) { + return root.resolve(filename); + } + return java.nio.file.Paths.get(filename); + } + } + + CustomConstructor(org.yaml.snakeyaml.LoaderOptions options, Path root) { + super(options) + this.root = root + // Handling !file tag and parse it back to a File type + this.yamlConstructors.put(new org.yaml.snakeyaml.nodes.Tag("!file"), new ConstructPath()) + } +} + +def readTaggedYaml(Path path) { + def options = new org.yaml.snakeyaml.LoaderOptions() + def constructor = new CustomConstructor(options, path.getParent()) + def yaml = new org.yaml.snakeyaml.Yaml(constructor) + return yaml.load(path.text) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYaml.nf' +def readYaml(file_path) { + def inputFile = file_path !instanceof Path ? file(file_path, hidden: true) : file_path + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(inputFile) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/readYamlBlob.nf' +def readYamlBlob(str) { + def yamlSlurper = new org.yaml.snakeyaml.Yaml() + yamlSlurper.load(str) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toJsonBlob.nf' +String toJsonBlob(data) { + return groovy.json.JsonOutput.toJson(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toTaggedYamlBlob.nf' +// Custom representer to modify how certain objects are represented in YAML +class CustomRepresenter extends org.yaml.snakeyaml.representer.Representer { + Path relativizer + + class RepresentPath implements org.yaml.snakeyaml.representer.Represent { + public String getFileName(Object obj) { + if (obj instanceof File) { + obj = ((File) obj).toPath(); + } + if (obj !instanceof Path) { + throw new IllegalArgumentException("Object: " + obj + " is not a Path or File"); + } + def path = (Path) obj; + + if (relativizer != null) { + return relativizer.relativize(path).toString() + } else { + return path.toString() + } + } + + public org.yaml.snakeyaml.nodes.Node representData(Object data) { + String filename = getFileName(data); + def tag = new org.yaml.snakeyaml.nodes.Tag("!file"); + return representScalar(tag, filename); + } + } + CustomRepresenter(org.yaml.snakeyaml.DumperOptions options, Path relativizer) { + super(options) + this.relativizer = relativizer + this.representers.put(sun.nio.fs.UnixPath, new RepresentPath()) + this.representers.put(Path, new RepresentPath()) + this.representers.put(File, new RepresentPath()) + } +} + +String toTaggedYamlBlob(data) { + return toRelativeTaggedYamlBlob(data, null) +} +String toRelativeTaggedYamlBlob(data, Path relativizer) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + def representer = new CustomRepresenter(options, relativizer) + def yaml = new org.yaml.snakeyaml.Yaml(representer, options) + return yaml.dump(data) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/toYamlBlob.nf' +String toYamlBlob(data) { + def options = new org.yaml.snakeyaml.DumperOptions() + options.setDefaultFlowStyle(org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK) + options.setPrettyFlow(true) + def yaml = new org.yaml.snakeyaml.Yaml(options) + def cleanData = iterateMap(data, { it instanceof Path ? it.toString() : it }) + return yaml.dump(cleanData) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeJson.nf' +void writeJson(data, file) { + assert data: "writeJson: data should not be null" + assert file: "writeJson: file should not be null" + file.write(toJsonBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/readwrite/writeYaml.nf' +void writeYaml(data, file) { + assert data: "writeYaml: data should not be null" + assert file: "writeYaml: file should not be null" + file.write(toYamlBlob(data)) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/findStates.nf' +def findStates(Map params, Map config) { + def auto_config = deepClone(config) + def auto_params = deepClone(params) + + auto_config = auto_config.clone() + // override arguments + auto_config.argument_groups = [] + auto_config.arguments = [ + [ + type: "string", + name: "--id", + description: "A dummy identifier", + required: false + ], + [ + type: "file", + name: "--input_states", + example: "/path/to/input/directory/**/state.yaml", + description: "Path to input directory containing the datasets to be integrated.", + required: true, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--filter", + example: "foo/.*/state.yaml", + description: "Regex to filter state files by path.", + required: false + ], + // to do: make this a yaml blob? + [ + type: "string", + name: "--rename_keys", + example: ["newKey1:oldKey1", "newKey2:oldKey2"], + description: "Rename keys in the detected input files. This is useful if the input files do not match the set of input arguments of the workflow.", + required: false, + multiple: true, + multiple_sep: ";" + ], + [ + type: "string", + name: "--settings", + example: '{"output_dataset": "dataset.h5ad", "k": 10}', + description: "Global arguments as a JSON glob to be passed to all components.", + required: false + ] + ] + if (!(auto_params.containsKey("id"))) { + auto_params["id"] = "auto" + } + + // run auto config through processConfig once more + auto_config = processConfig(auto_config) + + workflow findStatesWf { + helpMessage(auto_config) + + output_ch = + channelFromParams(auto_params, auto_config) + | flatMap { autoId, args -> + + def globalSettings = args.settings ? readYamlBlob(args.settings) : [:] + + // look for state files in input dir + def stateFiles = args.input_states + + // filter state files by regex + if (args.filter) { + stateFiles = stateFiles.findAll{ stateFile -> + def stateFileStr = stateFile.toString() + def matcher = stateFileStr =~ args.filter + matcher.matches()} + } + + // read in states + def states = stateFiles.collect { stateFile -> + def state_ = readTaggedYaml(stateFile) + [state_.id, state_] + } + + // construct renameMap + if (args.rename_keys) { + def renameMap = args.rename_keys.collectEntries{renameString -> + def split = renameString.split(":") + assert split.size() == 2: "Argument 'rename_keys' should be of the form 'newKey:oldKey', or 'newKey:oldKey;newKey:oldKey' in case of multiple values" + split + } + + // rename keys in state, only let states through which have all keys + // also add global settings + states = states.collectMany{id, state -> + def newState = [:] + + for (key in renameMap.keySet()) { + def origKey = renameMap[key] + if (!(state.containsKey(origKey))) { + return [] + } + newState[key] = state[origKey] + } + + [[id, globalSettings + newState]] + } + } + + states + } + emit: + output_ch + } + + return findStatesWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/joinStates.nf' +def joinStates(Closure apply_) { + workflow joinStatesWf { + take: input_ch + main: + output_ch = input_ch + | toSortedList + | filter{ it.size() > 0 } + | map{ tups -> + def ids = tups.collect{it[0]} + def states = tups.collect{it[1]} + apply_(ids, states) + } + + emit: output_ch + } + return joinStatesWf +} +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/publishStates.nf' +def collectFiles(obj) { + if (obj instanceof java.io.File || obj instanceof Path) { + return [obj] + } else if (obj instanceof List && obj !instanceof String) { + return obj.collectMany{item -> + collectFiles(item) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectFiles(item) + } + } else { + return [] + } +} + +/** + * Recurse through a state and collect all input files and their target output filenames. + * @param obj The state to recurse through. + * @param prefix The prefix to prepend to the output filenames. + */ +def collectInputOutputPaths(obj, prefix) { + if (obj instanceof File || obj instanceof Path) { + def path = obj instanceof Path ? obj : obj.toPath() + def ext = path.getFileName().toString().find("\\.[^\\.]+\$") ?: "" + def newFilename = prefix + ext + return [[obj, newFilename]] + } else if (obj instanceof List && obj !instanceof String) { + return obj.withIndex().collectMany{item, ix -> + collectInputOutputPaths(item, prefix + "_" + ix) + } + } else if (obj instanceof Map) { + return obj.collectMany{key, item -> + collectInputOutputPaths(item, prefix + "." + key) + } + } else { + return [] + } +} + +def publishStates(Map args) { + def key_ = args.get("key") + def yamlTemplate_ = args.get("output_state", args.get("outputState", '$id.$key.state.yaml')) + + assert key_ != null : "publishStates: key must be specified" + + workflow publishStatesWf { + 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] + + def yamlFilename = yamlTemplate_ + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .replaceAll('\\$\\{key\\}', key_) + + // TODO: do the pathnames in state_ match up with the outputFilenames_? + + // convert state to yaml blob + def yamlBlob_ = toRelativeTaggedYamlBlob([id: id_] + state_, java.nio.file.Paths.get(yamlFilename)) + + [id_, yamlBlob_, yamlFilename, inputFiles_, outputFilenames_] + } + | publishStatesProc + emit: input_ch + } + return publishStatesWf +} +process publishStatesProc { + // todo: check publishpath? + publishDir path: "${getPublishDir()}/", mode: "copy" + tag "$id" + input: + tuple val(id), val(yamlBlob), val(yamlFile), path(inputFiles, stageAs: "_inputfile?/*"), val(outputFiles) + output: + tuple val(id), path{[yamlFile] + 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 + [] + } + } + """ +mkdir -p "\$(dirname '${yamlFile}')" +echo "Storing state as yaml" +echo '${yamlBlob}' > '${yamlFile}' +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 publishStatesByConfig(Map args) { + def config = args.get("config") + assert config != null : "publishStatesByConfig: config must be specified" + + def key_ = args.get("key", config.name) + assert key_ != null : "publishStatesByConfig: key must be specified" + + workflow publishStatesSimpleWf { + 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'] + + // TODO: allow overriding the state.yaml template + // TODO TODO: if auto.publish == "state", add output_state as an argument + def yamlTemplate = params.containsKey("output_state") ? params.output_state : '$id.$key.state.yaml' + def yamlFilename = yamlTemplate + .replaceAll('\\$id', id_) + .replaceAll('\\$\\{id\\}', id_) + .replaceAll('\\$key', key_) + .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 + // - 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" } + .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 + 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 [[key: plainName_, value: value, 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 value_ = java.nio.file.Paths.get(filename_ix) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = val instanceof File ? val.toPath() : val + [value: value_, inputPath: inputPath, outputFilename: filename_ix] + } + def transposedOutputs = ["value", "inputPath", "outputFilename"].collectEntries{ key -> + [key, outputPerFile.collect{dic -> dic[key]}] + } + return [[key: plainName_] + transposedOutputs] + } else { + def value_ = java.nio.file.Paths.get(filename) + // if id contains a slash + if (yamlDir != null) { + value_ = yamlDir.relativize(value_) + } + def inputPath = value instanceof File ? value.toPath() : value + return [[key: plainName_, value: value_, inputPath: [inputPath], outputFilename: [filename]]] + } + } + + 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] + } + | publishStatesProc + emit: input_ch + } + return publishStatesSimpleWf +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/states/setState.nf' +def setState(fun) { + assert fun instanceof Closure || fun instanceof Map || fun instanceof List : + "Error in setState: Expected process argument to be a Closure, a Map, or a List. Found: class ${fun.getClass()}" + + // if fun is a List, convert to map + if (fun instanceof List) { + // check whether fun is a list[string] + assert fun.every{it instanceof CharSequence} : "Error in setState: argument is a List, but not all elements are Strings" + fun = fun.collectEntries{[it, it]} + } + + // if fun is a map, convert to closure + if (fun instanceof Map) { + // check whether fun is a map[string, string] + assert fun.values().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all values are Strings" + assert fun.keySet().every{it instanceof CharSequence} : "Error in setState: argument is a Map, but not all keys are Strings" + def funMap = fun.clone() + // turn the map into a closure to be used later on + fun = { id_, state_ -> + assert state_ instanceof Map : "Error in setState: the state is not a Map" + funMap.collectMany{newkey, origkey -> + if (state_.containsKey(origkey)) { + [[newkey, state_[origkey]]] + } else { + [] + } + }.collectEntries() + } + } + + map { tup -> + def id = tup[0] + def state = tup[1] + def unfilteredState = fun(id, state) + def newState = unfilteredState.findAll{key, val -> val != null} + [id, newState] + tup.drop(2) + } +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processAuto.nf' +// TODO: unit test processAuto +def processAuto(Map auto) { + // remove null values + auto = auto.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = ["simplifyInput", "simplifyOutput", "transcript", "publish"] + def unexpectedKeys = auto.keySet() - expectedKeys + assert unexpectedKeys.isEmpty(), "unexpected keys in auto: '${unexpectedKeys.join("', '")}'" + + // check auto.simplifyInput + assert auto.simplifyInput instanceof Boolean, "auto.simplifyInput must be a boolean" + + // check auto.simplifyOutput + assert auto.simplifyOutput instanceof Boolean, "auto.simplifyOutput must be a boolean" + + // check auto.transcript + assert auto.transcript instanceof Boolean, "auto.transcript must be a boolean" + + // check auto.publish + assert auto.publish instanceof Boolean || auto.publish == "state", "auto.publish must be a boolean or 'state'" + + return auto.subMap(expectedKeys) +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processDirectives.nf' +def assertMapKeys(map, expectedKeys, requiredKeys, mapName) { + assert map instanceof Map : "Expected argument '$mapName' to be a Map. Found: class ${map.getClass()}" + map.forEach { key, val -> + assert key in expectedKeys : "Unexpected key '$key' in ${mapName ? mapName + " " : ""}map" + } + requiredKeys.forEach { requiredKey -> + assert map.containsKey(requiredKey) : "Missing required key '$key' in ${mapName ? mapName + " " : ""}map" + } +} + +// TODO: unit test processDirectives +def processDirectives(Map drctv) { + // remove null values + drctv = drctv.findAll{k, v -> v != null} + + // check for unexpected keys + def expectedKeys = [ + "accelerator", "afterScript", "beforeScript", "cache", "conda", "container", "containerOptions", "cpus", "disk", "echo", "errorStrategy", "executor", "machineType", "maxErrors", "maxForks", "maxRetries", "memory", "module", "penv", "pod", "publishDir", "queue", "label", "scratch", "storeDir", "stageInMode", "stageOutMode", "tag", "time" + ] + def unexpectedKeys = drctv.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Unexpected keys in process directive: '${unexpectedKeys.join("', '")}'" + + /* DIRECTIVE accelerator + accepted examples: + - [ limit: 4, type: "nvidia-tesla-k80" ] + */ + if (drctv.containsKey("accelerator")) { + assertMapKeys(drctv["accelerator"], ["type", "limit", "request", "runtime"], [], "accelerator") + } + + /* DIRECTIVE afterScript + accepted examples: + - "source /cluster/bin/cleanup" + */ + if (drctv.containsKey("afterScript")) { + assert drctv["afterScript"] instanceof CharSequence + } + + /* DIRECTIVE beforeScript + accepted examples: + - "source /cluster/bin/setup" + */ + if (drctv.containsKey("beforeScript")) { + assert drctv["beforeScript"] instanceof CharSequence + } + + /* DIRECTIVE cache + accepted examples: + - true + - false + - "deep" + - "lenient" + */ + if (drctv.containsKey("cache")) { + assert drctv["cache"] instanceof CharSequence || drctv["cache"] instanceof Boolean + if (drctv["cache"] instanceof CharSequence) { + assert drctv["cache"] in ["deep", "lenient"] : "Unexpected value for cache" + } + } + + /* DIRECTIVE conda + accepted examples: + - "bwa=0.7.15" + - "bwa=0.7.15 fastqc=0.11.5" + - ["bwa=0.7.15", "fastqc=0.11.5"] + */ + if (drctv.containsKey("conda")) { + if (drctv["conda"] instanceof List) { + drctv["conda"] = drctv["conda"].join(" ") + } + assert drctv["conda"] instanceof CharSequence + } + + /* DIRECTIVE container + accepted examples: + - "foo/bar:tag" + - [ registry: "reg", image: "im", tag: "ta" ] + is transformed to "reg/im:ta" + - [ image: "im" ] + is transformed to "im:latest" + */ + if (drctv.containsKey("container")) { + assert drctv["container"] instanceof Map || drctv["container"] instanceof CharSequence + if (drctv["container"] instanceof Map) { + def m = drctv["container"] + assertMapKeys(m, [ "registry", "image", "tag" ], ["image"], "container") + def part1 = + System.getenv('OVERRIDE_CONTAINER_REGISTRY') ? System.getenv('OVERRIDE_CONTAINER_REGISTRY') + "/" : + params.containsKey("override_container_registry") ? params["override_container_registry"] + "/" : // todo: remove? + m.registry ? m.registry + "/" : + "" + def part2 = m.image + def part3 = m.tag ? ":" + m.tag : ":latest" + drctv["container"] = part1 + part2 + part3 + } + } + + /* DIRECTIVE containerOptions + accepted examples: + - "--foo bar" + - ["--foo bar", "-f b"] + */ + if (drctv.containsKey("containerOptions")) { + if (drctv["containerOptions"] instanceof List) { + drctv["containerOptions"] = drctv["containerOptions"].join(" ") + } + assert drctv["containerOptions"] instanceof CharSequence + } + + /* DIRECTIVE cpus + accepted examples: + - 1 + - 10 + */ + if (drctv.containsKey("cpus")) { + assert drctv["cpus"] instanceof Integer + } + + /* DIRECTIVE disk + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("disk")) { + assert drctv["disk"] instanceof CharSequence + // assert drctv["disk"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE echo + accepted examples: + - true + - false + */ + if (drctv.containsKey("echo")) { + assert drctv["echo"] instanceof Boolean + } + + /* DIRECTIVE errorStrategy + accepted examples: + - "terminate" + - "finish" + */ + if (drctv.containsKey("errorStrategy")) { + assert drctv["errorStrategy"] instanceof CharSequence + assert drctv["errorStrategy"] in ["terminate", "finish", "ignore", "retry"] : "Unexpected value for errorStrategy" + } + + /* DIRECTIVE executor + accepted examples: + - "local" + - "sge" + */ + if (drctv.containsKey("executor")) { + assert drctv["executor"] instanceof CharSequence + assert drctv["executor"] in ["local", "sge", "uge", "lsf", "slurm", "pbs", "pbspro", "moab", "condor", "nqsii", "ignite", "k8s", "awsbatch", "google-pipelines"] : "Unexpected value for executor" + } + + /* DIRECTIVE machineType + accepted examples: + - "n1-highmem-8" + */ + if (drctv.containsKey("machineType")) { + assert drctv["machineType"] instanceof CharSequence + } + + /* DIRECTIVE maxErrors + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxErrors")) { + assert drctv["maxErrors"] instanceof Integer + } + + /* DIRECTIVE maxForks + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxForks")) { + assert drctv["maxForks"] instanceof Integer + } + + /* DIRECTIVE maxRetries + accepted examples: + - 1 + - 3 + */ + if (drctv.containsKey("maxRetries")) { + assert drctv["maxRetries"] instanceof Integer + } + + /* DIRECTIVE memory + accepted examples: + - "1 GB" + - "2TB" + - "3.2KB" + - "10.B" + */ + if (drctv.containsKey("memory")) { + assert drctv["memory"] instanceof CharSequence + // assert drctv["memory"].matches("[0-9]+(\\.[0-9]*)? *[KMGTPEZY]?B") + // ^ does not allow closures + } + + /* DIRECTIVE module + accepted examples: + - "ncbi-blast/2.2.27" + - "ncbi-blast/2.2.27:t_coffee/10.0" + - ["ncbi-blast/2.2.27", "t_coffee/10.0"] + */ + if (drctv.containsKey("module")) { + if (drctv["module"] instanceof List) { + drctv["module"] = drctv["module"].join(":") + } + assert drctv["module"] instanceof CharSequence + } + + /* DIRECTIVE penv + accepted examples: + - "smp" + */ + if (drctv.containsKey("penv")) { + assert drctv["penv"] instanceof CharSequence + } + + /* DIRECTIVE pod + accepted examples: + - [ label: "key", value: "val" ] + - [ annotation: "key", value: "val" ] + - [ env: "key", value: "val" ] + - [ [label: "l", value: "v"], [env: "e", value: "v"]] + */ + if (drctv.containsKey("pod")) { + if (drctv["pod"] instanceof Map) { + drctv["pod"] = [ drctv["pod"] ] + } + assert drctv["pod"] instanceof List + drctv["pod"].forEach { pod -> + assert pod instanceof Map + // TODO: should more checks be added? + // See https://www.nextflow.io/docs/latest/process.html?highlight=directives#pod + // e.g. does it contain 'label' and 'value', or 'annotation' and 'value', or ...? + } + } + + /* DIRECTIVE publishDir + accepted examples: + - [] + - [ [ path: "foo", enabled: true ], [ path: "bar", enabled: false ] ] + - "/path/to/dir" + is transformed to [[ path: "/path/to/dir" ]] + - [ path: "/path/to/dir", mode: "cache" ] + is transformed to [[ path: "/path/to/dir", mode: "cache" ]] + */ + // TODO: should we also look at params["publishDir"]? + if (drctv.containsKey("publishDir")) { + def pblsh = drctv["publishDir"] + + // check different options + assert pblsh instanceof List || pblsh instanceof Map || pblsh instanceof CharSequence + + // turn into list if not already so + // for some reason, 'if (!pblsh instanceof List) pblsh = [ pblsh ]' doesn't work. + pblsh = pblsh instanceof List ? pblsh : [ pblsh ] + + // check elements of publishDir + pblsh = pblsh.collect{ elem -> + // turn into map if not already so + elem = elem instanceof CharSequence ? [ path: elem ] : elem + + // check types and keys + assert elem instanceof Map : "Expected publish argument '$elem' to be a String or a Map. Found: class ${elem.getClass()}" + assertMapKeys(elem, [ "path", "mode", "overwrite", "pattern", "saveAs", "enabled" ], ["path"], "publishDir") + + // check elements in map + assert elem.containsKey("path") + assert elem["path"] instanceof CharSequence + if (elem.containsKey("mode")) { + assert elem["mode"] instanceof CharSequence + assert elem["mode"] in [ "symlink", "rellink", "link", "copy", "copyNoFollow", "move" ] + } + if (elem.containsKey("overwrite")) { + assert elem["overwrite"] instanceof Boolean + } + if (elem.containsKey("pattern")) { + assert elem["pattern"] instanceof CharSequence + } + if (elem.containsKey("saveAs")) { + assert elem["saveAs"] instanceof CharSequence //: "saveAs as a Closure is currently not supported. Surround your closure with single quotes to get the desired effect. Example: '\{ foo \}'" + } + if (elem.containsKey("enabled")) { + assert elem["enabled"] instanceof Boolean + } + + // return final result + elem + } + // store final directive + drctv["publishDir"] = pblsh + } + + /* DIRECTIVE queue + accepted examples: + - "long" + - "short,long" + - ["short", "long"] + */ + if (drctv.containsKey("queue")) { + if (drctv["queue"] instanceof List) { + drctv["queue"] = drctv["queue"].join(",") + } + assert drctv["queue"] instanceof CharSequence + } + + /* DIRECTIVE label + accepted examples: + - "big_mem" + - "big_cpu" + - ["big_mem", "big_cpu"] + */ + if (drctv.containsKey("label")) { + if (drctv["label"] instanceof CharSequence) { + drctv["label"] = [ drctv["label"] ] + } + assert drctv["label"] instanceof List + drctv["label"].forEach { label -> + assert label instanceof CharSequence + // assert label.matches("[a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?") + // ^ does not allow closures + } + } + + /* DIRECTIVE scratch + accepted examples: + - true + - "/path/to/scratch" + - '$MY_PATH_TO_SCRATCH' + - "ram-disk" + */ + if (drctv.containsKey("scratch")) { + assert drctv["scratch"] == true || drctv["scratch"] instanceof CharSequence + } + + /* DIRECTIVE storeDir + accepted examples: + - "/path/to/storeDir" + */ + if (drctv.containsKey("storeDir")) { + assert drctv["storeDir"] instanceof CharSequence + } + + /* DIRECTIVE stageInMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageInMode")) { + assert drctv["stageInMode"] instanceof CharSequence + assert drctv["stageInMode"] in ["copy", "link", "symlink", "rellink"] + } + + /* DIRECTIVE stageOutMode + accepted examples: + - "copy" + - "link" + */ + if (drctv.containsKey("stageOutMode")) { + assert drctv["stageOutMode"] instanceof CharSequence + assert drctv["stageOutMode"] in ["copy", "move", "rsync"] + } + + /* DIRECTIVE tag + accepted examples: + - "foo" + - '$id' + */ + if (drctv.containsKey("tag")) { + assert drctv["tag"] instanceof CharSequence + } + + /* DIRECTIVE time + accepted examples: + - "1h" + - "2days" + - "1day 6hours 3minutes 30seconds" + */ + if (drctv.containsKey("time")) { + assert drctv["time"] instanceof CharSequence + // todo: validation regex? + } + + return drctv +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/processWorkflowArgs.nf' +def processWorkflowArgs(Map args, Map defaultWfArgs, Map meta) { + // override defaults with args + def workflowArgs = defaultWfArgs + args + + // check whether 'key' exists + assert workflowArgs.containsKey("key") : "Error in module '${meta.config.name}': key is a required argument" + + // if 'key' is a closure, apply it to the original key + if (workflowArgs["key"] instanceof Closure) { + workflowArgs["key"] = workflowArgs["key"](meta.config.name) + } + def key = workflowArgs["key"] + assert key instanceof CharSequence : "Expected process argument 'key' to be a String. Found: class ${key.getClass()}" + assert key ==~ /^[a-zA-Z_]\w*$/ : "Error in module '$key': Expected process argument 'key' to consist of only letters, digits or underscores. Found: ${key}" + + // check for any unexpected keys + def expectedKeys = ["key", "directives", "auto", "map", "mapId", "mapData", "mapPassthrough", "filter", "runIf", "fromState", "toState", "args", "renameKeys", "debug"] + def unexpectedKeys = workflowArgs.keySet() - expectedKeys + assert unexpectedKeys.isEmpty() : "Error in module '$key': unexpected arguments to the '.run()' function: '${unexpectedKeys.join("', '")}'" + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("directives") : "Error in module '$key': directives is a required argument" + assert workflowArgs["directives"] instanceof Map : "Error in module '$key': Expected process argument 'directives' to be a Map. Found: class ${workflowArgs['directives'].getClass()}" + workflowArgs["directives"] = processDirectives(defaultWfArgs.directives + workflowArgs["directives"]) + + // check whether directives exists and apply defaults + assert workflowArgs.containsKey("auto") : "Error in module '$key': auto is a required argument" + assert workflowArgs["auto"] instanceof Map : "Error in module '$key': Expected process argument 'auto' to be a Map. Found: class ${workflowArgs['auto'].getClass()}" + workflowArgs["auto"] = processAuto(defaultWfArgs.auto + workflowArgs["auto"]) + + // auto define publish, if so desired + if (workflowArgs.auto.publish == true && (workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : [:]).isEmpty()) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.publish is true, params.publish_dir needs to be defined.\n" + + // " Example: params.publish_dir = \"./output/\"" + def publishDir = getPublishDir() + + if (publishDir != null) { + workflowArgs.directives.publishDir = [[ + path: publishDir, + saveAs: "{ it.startsWith('.') ? null : it }", // don't publish hidden files, by default + mode: "copy" + ]] + } + } + + // auto define transcript, if so desired + if (workflowArgs.auto.transcript == true) { + // can't assert at this level thanks to the no_publish profile + // assert params.containsKey("transcriptsDir") || params.containsKey("transcripts_dir") || params.containsKey("publishDir") || params.containsKey("publish_dir") : + // "Error in module '${workflowArgs['key']}': if auto.transcript is true, either params.transcripts_dir or params.publish_dir needs to be defined.\n" + + // " Example: params.transcripts_dir = \"./transcripts/\"" + def transcriptsDir = + params.containsKey("transcripts_dir") ? params.transcripts_dir : + params.containsKey("transcriptsDir") ? params.transcriptsDir : + params.containsKey("publish_dir") ? params.publish_dir + "/_transcripts" : + params.containsKey("publishDir") ? params.publishDir + "/_transcripts" : + null + if (transcriptsDir != null) { + def timestamp = nextflow.Nextflow.getSession().getWorkflowMetadata().start.format('yyyy-MM-dd_HH-mm-ss') + def transcriptsPublishDir = [ + path: "$transcriptsDir/$timestamp/\${task.process.replaceAll(':', '-')}/\${id}/", + saveAs: "{ it.startsWith('.') ? it.replaceAll('^.', '') : null }", + mode: "copy" + ] + def publishDirs = workflowArgs.directives.publishDir != null ? workflowArgs.directives.publishDir : null ? workflowArgs.directives.publishDir : [] + workflowArgs.directives.publishDir = publishDirs + transcriptsPublishDir + } + } + + // if this is a stubrun, remove certain directives? + if (workflow.stubRun) { + workflowArgs.directives.keySet().removeAll(["publishDir", "cpus", "memory", "label"]) + } + + for (nam in ["map", "mapId", "mapData", "mapPassthrough", "filter", "runIf"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam]) { + assert workflowArgs[nam] instanceof Closure : "Error in module '$key': Expected process argument '$nam' to be null or a Closure. Found: class ${workflowArgs[nam].getClass()}" + } + } + + // TODO: should functions like 'map', 'mapId', 'mapData', 'mapPassthrough' be deprecated as well? + for (nam in ["map", "mapData", "mapPassthrough", "renameKeys"]) { + if (workflowArgs.containsKey(nam) && workflowArgs[nam] != null) { + log.warn "module '$key': workflow argument '$nam' is deprecated and will be removed in Viash 0.9.0. Please use 'fromState' and 'toState' instead." + } + } + + // check fromState + workflowArgs["fromState"] = _processFromState(workflowArgs.get("fromState"), key, meta.config) + + // check toState + workflowArgs["toState"] = _processToState(workflowArgs.get("toState"), key, meta.config) + + // return output + return workflowArgs +} + +def _processFromState(fromState, key_, config_) { + assert fromState == null || fromState instanceof Closure || fromState instanceof Map || fromState instanceof List : + "Error in module '$key_': Expected process argument 'fromState' to be null, a Closure, a Map, or a List. Found: class ${fromState.getClass()}" + if (fromState == null) { + return null + } + + // if fromState is a List, convert to map + if (fromState instanceof List) { + // check whether fromstate is a list[string] + assert fromState.every{it instanceof CharSequence} : "Error in module '$key_': fromState is a List, but not all elements are Strings" + fromState = fromState.collectEntries{[it, it]} + } + + // if fromState is a map, convert to closure + if (fromState instanceof Map) { + // check whether fromstate is a map[string, string] + assert fromState.values().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all values are Strings" + assert fromState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': fromState is a Map, but not all keys are Strings" + def fromStateMap = fromState.clone() + def requiredInputNames = meta.config.allArguments.findAll{it.required && it.direction == "Input"}.collect{it.plainName} + // turn the map into a closure to be used later on + fromState = { it -> + def state = it[1] + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def data = fromStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (state.containsKey(origkey)) { + [[newkey, state[origkey]]] + } else if (!requiredInputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': fromState key '$origkey' not found in current state") + } + }.collectEntries() + data + } + } + + return fromState +} + +def _processToState(toState, key_, config_) { + if (toState == null) { + toState = { tup -> tup[1] } + } + + // toState should be a closure, map[string, string], or list[string] + assert toState instanceof Closure || toState instanceof Map || toState instanceof List : + "Error in module '$key_': Expected process argument 'toState' to be a Closure, a Map, or a List. Found: class ${toState.getClass()}" + + // if toState is a List, convert to map + if (toState instanceof List) { + // check whether toState is a list[string] + assert toState.every{it instanceof CharSequence} : "Error in module '$key_': toState is a List, but not all elements are Strings" + toState = toState.collectEntries{[it, it]} + } + + // if toState is a map, convert to closure + if (toState instanceof Map) { + // check whether toState is a map[string, string] + assert toState.values().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all values are Strings" + assert toState.keySet().every{it instanceof CharSequence} : "Error in module '$key_': toState is a Map, but not all keys are Strings" + def toStateMap = toState.clone() + def requiredOutputNames = config_.allArguments.findAll{it.required && it.direction == "Output"}.collect{it.plainName} + // turn the map into a closure to be used later on + toState = { it -> + def output = it[1] + def state = it[2] + assert output instanceof Map : "Error in module '$key_': the output is not a Map" + assert state instanceof Map : "Error in module '$key_': the state is not a Map" + def extraEntries = toStateMap.collectMany{newkey, origkey -> + // check whether newkey corresponds to a required argument + if (output.containsKey(origkey)) { + [[newkey, output[origkey]]] + } else if (!requiredOutputNames.contains(origkey)) { + [] + } else { + throw new Exception("Error in module '$key_': toState key '$origkey' not found in current output") + } + }.collectEntries() + state + extraEntries + } + } + + return toState +} + +// helper file: 'src/main/resources/io/viash/runners/nextflow/workflowFactory/workflowFactory.nf' +def _debug(workflowArgs, debugKey) { + if (workflowArgs.debug) { + view { "process '${workflowArgs.key}' $debugKey tuple: $it" } + } else { + map { it } + } +} + +// depends on: innerWorkflowFactory +def workflowFactory(Map args, Map defaultWfArgs, Map meta) { + def workflowArgs = processWorkflowArgs(args, defaultWfArgs, meta) + def key_ = workflowArgs["key"] + + workflow workflowInstance { + take: input_ + + main: + def chModified = input_ + | checkUniqueIds([:]) + | _debug(workflowArgs, "input") + | map { tuple -> + tuple = deepClone(tuple) + + if (workflowArgs.map) { + tuple = workflowArgs.map(tuple) + } + if (workflowArgs.mapId) { + tuple[0] = workflowArgs.mapId(tuple[0]) + } + if (workflowArgs.mapData) { + tuple[1] = workflowArgs.mapData(tuple[1]) + } + if (workflowArgs.mapPassthrough) { + tuple = tuple.take(2) + workflowArgs.mapPassthrough(tuple.drop(2)) + } + + // check tuple + assert tuple instanceof List : + "Error in module '${key_}': element in 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()}" + assert tuple.size() >= 2 : + "Error in module '${key_}': expected length of tuple in input channel to be two or greater.\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: tuple.size() == ${tuple.size()}" + + // check id field + if (tuple[0] instanceof GString) { + tuple[0] = tuple[0].toString() + } + assert tuple[0] instanceof CharSequence : + "Error in module '${key_}': first element of tuple in channel should be a String\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Found: ${tuple[0]}" + + // match file to input file + if (workflowArgs.auto.simplifyInput && (tuple[1] instanceof Path || tuple[1] instanceof List)) { + def inputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + + assert inputFiles.size() == 1 : + "Error in module '${key_}' id '${tuple[0]}'.\n" + + " Anonymous file inputs are only allowed when the process has exactly one file input.\n" + + " Expected: inputFiles.size() == 1. Found: inputFiles.size() is ${inputFiles.size()}" + + tuple[1] = [[ inputFiles[0].plainName, tuple[1] ]].collectEntries() + } + + // check data field + assert tuple[1] instanceof Map : + "Error in module '${key_}' id '${tuple[0]}': second element of tuple in channel should be a Map\n" + + " Example: [\"id\", [input: file('foo.txt'), arg: 10]].\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // rename keys of data field in tuple + if (workflowArgs.renameKeys) { + assert workflowArgs.renameKeys instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class: Map. Found: renameKeys.getClass() is ${workflowArgs.renameKeys.getClass()}" + assert tuple[1] instanceof Map : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Expected class: Map. Found: tuple[1].getClass() is ${tuple[1].getClass()}" + + // TODO: allow renameKeys to be a function? + workflowArgs.renameKeys.each { newKey, oldKey -> + assert newKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of newKey: String. Found: newKey.getClass() is ${newKey.getClass()}" + assert oldKey instanceof CharSequence : + "Error renaming data keys in module '${key_}' id '${tuple[0]}'.\n" + + " Example: renameKeys: ['new_key': 'old_key'].\n" + + " Expected class of oldKey: String. Found: oldKey.getClass() is ${oldKey.getClass()}" + assert tuple[1].containsKey(oldKey) : + "Error renaming data keys in module '${key}' id '${tuple[0]}'.\n" + + " Key '$oldKey' is missing in the data map. tuple[1].keySet() is '${tuple[1].keySet()}'" + tuple[1].put(newKey, tuple[1][oldKey]) + } + tuple[1].keySet().removeAll(workflowArgs.renameKeys.collect{ newKey, oldKey -> oldKey }) + } + tuple + } + + + def chRun = null + def chPassthrough = null + if (workflowArgs.runIf) { + def runIfBranch = chModified.branch{ tup -> + run: workflowArgs.runIf(tup[0], tup[1]) + passthrough: true + } + chRun = runIfBranch.run + chPassthrough = runIfBranch.passthrough + } else { + chRun = chModified + chPassthrough = Channel.empty() + } + + def chRunFiltered = workflowArgs.filter ? + chRun | filter{workflowArgs.filter(it)} : + chRun + + def chArgs = workflowArgs.fromState ? + chRunFiltered | map{ + def new_data = workflowArgs.fromState(it.take(2)) + [it[0], new_data] + } : + chRunFiltered | map {tup -> tup.take(2)} + + // fill in defaults + def chArgsWithDefaults = chArgs + | map { tuple -> + def id_ = tuple[0] + def data_ = tuple[1] + + // TODO: could move fromState to here + + // fetch default params from functionality + def defaultArgs = meta.config.allArguments + .findAll { it.containsKey("default") } + .collectEntries { [ it.plainName, it.default ] } + + // fetch overrides in params + def paramArgs = meta.config.allArguments + .findAll { par -> + def argKey = key_ + "__" + par.plainName + params.containsKey(argKey) + } + .collectEntries { [ it.plainName, params[key_ + "__" + it.plainName] ] } + + // fetch overrides in data + def dataArgs = meta.config.allArguments + .findAll { data_.containsKey(it.plainName) } + .collectEntries { [ it.plainName, data_[it.plainName] ] } + + // combine params + def combinedArgs = defaultArgs + paramArgs + workflowArgs.args + dataArgs + + // remove arguments with explicit null values + combinedArgs + .removeAll{_, val -> val == null || val == "viash_no_value" || val == "force_null"} + + combinedArgs = _processInputValues(combinedArgs, meta.config, id_, key_) + + [id_, combinedArgs] + tuple.drop(2) + } + + // TODO: move some of the _meta.join_id wrangling to the safeJoin() function. + def chInitialOutput = chArgsWithDefaults + | _debug(workflowArgs, "processed") + // run workflow + | innerWorkflowFactory(workflowArgs) + // check output tuple + | map { id_, output_ -> + + // see if output map contains metadata + def meta_ = + output_ instanceof Map && output_.containsKey("_meta") ? + output_["_meta"] : + [:] + def join_id = meta_.join_id ?: id_ + + // remove metadata + output_ = output_.findAll{k, v -> k != "_meta"} + + // check value types + output_ = _processOutputValues(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_] + } + // | view{"chInitialOutput: ${it.take(3)}"} + + // join the output [prev_id, new_id, output] with the previous state [prev_id, state, ...] + def chNewState = safeJoin(chInitialOutput, chRunFiltered, key_) + // input tuple format: [join_id, id, output, prev_state, ...] + // output tuple format: [join_id, id, new_state, ...] + | map{ tup -> + def new_state = workflowArgs.toState(tup.drop(1).take(3)) + tup.take(2) + [new_state] + tup.drop(4) + } + + if (workflowArgs.auto.publish == "state") { + def chPublish = 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_) + // 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, ...] + // output tuple format: [id, new_state, ...] + tup.drop(1) + } + | _debug(workflowArgs, "output") + | concat(chPassthrough) + + emit: chReturn + } + + def wf = workflowInstance.cloneWithName(key_) + + // add factory function + wf.metaClass.run = { runArgs -> + workflowFactory(runArgs, workflowArgs, meta) + } + // add config to module for later introspection + wf.metaClass.config = meta.config + + return wf +} + +nextflow.enable.dsl=2 + +// START COMPONENT-SPECIFIC CODE + +// create meta object +meta = [ + "resources_dir": moduleDir.toRealPath().normalize(), + "config": processConfig(readJsonBlob('''{ + "name" : "rseqc_inner_distance", + "namespace" : "rseqc", + "version" : "main", + "authors" : [ + { + "name" : "Emma Rousseau", + "roles" : [ + "author", + "maintainer" + ], + "info" : { + "links" : { + "email" : "emma@data-intuitive.com", + "github" : "emmarousseau", + "linkedin" : "emmarousseau1" + }, + "organizations" : [ + { + "name" : "Data Intuitive", + "href" : "https://www.data-intuitive.com", + "role" : "Bioinformatician" + } + ] + } + } + ], + "argument_groups" : [ + { + "name" : "Input", + "arguments" : [ + { + "type" : "file", + "name" : "--input_file", + "alternatives" : [ + "-i" + ], + "description" : "input alignment file in BAM or SAM format", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--refgene", + "alternatives" : [ + "-r" + ], + "description" : "Reference gene model in bed format", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "integer", + "name" : "--sample_size", + "alternatives" : [ + "-k" + ], + "description" : "Numer of reads sampled from SAM/BAM file, default = 1000000.", + "example" : [ + 1000000 + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "integer", + "name" : "--mapq", + "alternatives" : [ + "-q" + ], + "description" : "Minimum mapping quality (phred scaled) to determine uniquely mapped reads, default=30.", + "example" : [ + 30 + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "integer", + "name" : "--lower_bound", + "alternatives" : [ + "-l" + ], + "description" : "Lower bound of inner distance (bp). This option is used for ploting histograme, default=-250.", + "example" : [ + -250 + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "integer", + "name" : "--upper_bound", + "alternatives" : [ + "-u" + ], + "description" : "Upper bound of inner distance (bp). This option is used for ploting histograme, default=250.", + "example" : [ + 250 + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "integer", + "name" : "--step", + "alternatives" : [ + "-s" + ], + "description" : "Step size (bp) of histograme. This option is used for plotting histogram, default=5.", + "example" : [ + 5 + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Output", + "arguments" : [ + { + "type" : "string", + "name" : "--output_prefix", + "alternatives" : [ + "-o" + ], + "description" : "Rrefix of output files.", + "required" : true, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--output_stats", + "description" : "output file (txt) with summary statistics of inner distances of paired reads", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--output_dist", + "description" : "output file (txt) with inner distances of all paired reads", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--output_freq", + "description" : "output file (txt) with frequencies of inner distances of all paired reads", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--output_plot", + "description" : "output file (pdf) with histogram plot of of inner distances of all paired reads", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--output_plot_r", + "description" : "output file (R) with script of histogram plot of of inner distances of all paired reads", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Calculate inner distance between read pairs.\n", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + }, + { + "type" : "file", + "path" : "test_data" + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "license" : "GPL-3.0", + "references" : { + "doi" : [ + "10.1093/bioinformatics/bts356" + ] + }, + "links" : { + "repository" : "https://github.com/MonashBioinformaticsPlatform/RSeQC", + "homepage" : "https://rseqc.sourceforge.net/", + "documentation" : "https://rseqc.sourceforge.net/#inner-distance-py", + "issue_tracker" : "https://github.com/MonashBioinformaticsPlatform/RSeQC/issues" + }, + "runners" : [ + { + "type" : "executable", + "id" : "executable", + "docker_setup_strategy" : "ifneedbepullelsecachedbuild" + }, + { + "type" : "nextflow", + "id" : "nextflow", + "directives" : { + "tag" : "$id" + }, + "auto" : { + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false + }, + "config" : { + "labels" : { + "mem1gb" : "memory = 1000000000.B", + "mem2gb" : "memory = 2000000000.B", + "mem5gb" : "memory = 5000000000.B", + "mem10gb" : "memory = 10000000000.B", + "mem20gb" : "memory = 20000000000.B", + "mem50gb" : "memory = 50000000000.B", + "mem100gb" : "memory = 100000000000.B", + "mem200gb" : "memory = 200000000000.B", + "mem500gb" : "memory = 500000000000.B", + "mem1tb" : "memory = 1000000000000.B", + "mem2tb" : "memory = 2000000000000.B", + "mem5tb" : "memory = 5000000000000.B", + "mem10tb" : "memory = 10000000000000.B", + "mem20tb" : "memory = 20000000000000.B", + "mem50tb" : "memory = 50000000000000.B", + "mem100tb" : "memory = 100000000000000.B", + "mem200tb" : "memory = 200000000000000.B", + "mem500tb" : "memory = 500000000000000.B", + "mem1gib" : "memory = 1073741824.B", + "mem2gib" : "memory = 2147483648.B", + "mem4gib" : "memory = 4294967296.B", + "mem8gib" : "memory = 8589934592.B", + "mem16gib" : "memory = 17179869184.B", + "mem32gib" : "memory = 34359738368.B", + "mem64gib" : "memory = 68719476736.B", + "mem128gib" : "memory = 137438953472.B", + "mem256gib" : "memory = 274877906944.B", + "mem512gib" : "memory = 549755813888.B", + "mem1tib" : "memory = 1099511627776.B", + "mem2tib" : "memory = 2199023255552.B", + "mem4tib" : "memory = 4398046511104.B", + "mem8tib" : "memory = 8796093022208.B", + "mem16tib" : "memory = 17592186044416.B", + "mem32tib" : "memory = 35184372088832.B", + "mem64tib" : "memory = 70368744177664.B", + "mem128tib" : "memory = 140737488355328.B", + "mem256tib" : "memory = 281474976710656.B", + "mem512tib" : "memory = 562949953421312.B", + "cpu1" : "cpus = 1", + "cpu2" : "cpus = 2", + "cpu5" : "cpus = 5", + "cpu10" : "cpus = 10", + "cpu20" : "cpus = 20", + "cpu50" : "cpus = 50", + "cpu100" : "cpus = 100", + "cpu200" : "cpus = 200", + "cpu500" : "cpus = 500", + "cpu1000" : "cpus = 1000" + } + }, + "debug" : false, + "container" : "docker" + } + ], + "engines" : [ + { + "type" : "docker", + "id" : "docker", + "image" : "python:3.10", + "target_registry" : "images.viash-hub.com", + "target_tag" : "main", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "apt", + "packages" : [ + "r-base" + ], + "interactive" : false + }, + { + "type" : "python", + "user" : false, + "packages" : [ + "RSeQC" + ], + "upgrade" : true + }, + { + "type" : "docker", + "run" : [ + "echo \\"RSeQC - inner_distance.py: $(inner_distance.py --version | cut -d' ' -f2)\\" > /var/software_versions.txt\n" + ] + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/rseqc/rseqc_inner_distance/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/rseqc/rseqc_inner_distance", + "viash_version" : "0.9.0", + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" + }, + "package_config" : { + "name" : "biobox", + "version" : "main", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0", + "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 := 'main'" + ], + "keywords" : [ + "bioinformatics", + "modules", + "sequencing" + ], + "license" : "MIT", + "organization" : "vsh", + "links" : { + "repository" : "https://github.com/viash-hub/biobox", + "issue_tracker" : "https://github.com/viash-hub/biobox/issues" + } + } +}''')) +] + +// resolve dependencies dependencies (if any) + + +// inner workflow +// inner workflow hook +def innerWorkflowFactory(args) { + def rawScript = '''set -e +tempscript=".viash_script.sh" +cat > "$tempscript" << VIASHMAIN +## VIASH START +# The following code has been auto-generated by Viash. +$( if [ ! -z ${VIASH_PAR_INPUT_FILE+x} ]; then echo "${VIASH_PAR_INPUT_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_input_file='&'#" ; else echo "# par_input_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REFGENE+x} ]; then echo "${VIASH_PAR_REFGENE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_refgene='&'#" ; else echo "# par_refgene="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLE_SIZE+x} ]; then echo "${VIASH_PAR_SAMPLE_SIZE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_sample_size='&'#" ; else echo "# par_sample_size="; fi ) +$( if [ ! -z ${VIASH_PAR_MAPQ+x} ]; then echo "${VIASH_PAR_MAPQ}" | sed "s#'#'\\"'\\"'#g;s#.*#par_mapq='&'#" ; else echo "# par_mapq="; fi ) +$( if [ ! -z ${VIASH_PAR_LOWER_BOUND+x} ]; then echo "${VIASH_PAR_LOWER_BOUND}" | sed "s#'#'\\"'\\"'#g;s#.*#par_lower_bound='&'#" ; else echo "# par_lower_bound="; fi ) +$( if [ ! -z ${VIASH_PAR_UPPER_BOUND+x} ]; then echo "${VIASH_PAR_UPPER_BOUND}" | sed "s#'#'\\"'\\"'#g;s#.*#par_upper_bound='&'#" ; else echo "# par_upper_bound="; fi ) +$( if [ ! -z ${VIASH_PAR_STEP+x} ]; then echo "${VIASH_PAR_STEP}" | sed "s#'#'\\"'\\"'#g;s#.*#par_step='&'#" ; else echo "# par_step="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_PREFIX+x} ]; then echo "${VIASH_PAR_OUTPUT_PREFIX}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output_prefix='&'#" ; else echo "# par_output_prefix="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_STATS+x} ]; then echo "${VIASH_PAR_OUTPUT_STATS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output_stats='&'#" ; else echo "# par_output_stats="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_DIST+x} ]; then echo "${VIASH_PAR_OUTPUT_DIST}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output_dist='&'#" ; else echo "# par_output_dist="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_FREQ+x} ]; then echo "${VIASH_PAR_OUTPUT_FREQ}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output_freq='&'#" ; else echo "# par_output_freq="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_PLOT+x} ]; then echo "${VIASH_PAR_OUTPUT_PLOT}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output_plot='&'#" ; else echo "# par_output_plot="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_PLOT_R+x} ]; then echo "${VIASH_PAR_OUTPUT_PLOT_R}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output_plot_r='&'#" ; else echo "# par_output_plot_r="; 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 ) +$( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo "${VIASH_META_EXECUTABLE}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_executable='&'#" ; else echo "# meta_executable="; fi ) +$( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo "${VIASH_META_CONFIG}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_config='&'#" ; else echo "# meta_config="; fi ) +$( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo "${VIASH_META_TEMP_DIR}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_temp_dir='&'#" ; else echo "# meta_temp_dir="; fi ) +$( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo "${VIASH_META_CPUS}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_cpus='&'#" ; else echo "# meta_cpus="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo "${VIASH_META_MEMORY_B}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_b='&'#" ; else echo "# meta_memory_b="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo "${VIASH_META_MEMORY_KB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kb='&'#" ; else echo "# meta_memory_kb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo "${VIASH_META_MEMORY_MB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mb='&'#" ; else echo "# meta_memory_mb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo "${VIASH_META_MEMORY_GB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gb='&'#" ; else echo "# meta_memory_gb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo "${VIASH_META_MEMORY_TB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tb='&'#" ; else echo "# meta_memory_tb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo "${VIASH_META_MEMORY_PB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pb='&'#" ; else echo "# meta_memory_pb="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo "${VIASH_META_MEMORY_KIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_kib='&'#" ; else echo "# meta_memory_kib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo "${VIASH_META_MEMORY_MIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_mib='&'#" ; else echo "# meta_memory_mib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo "${VIASH_META_MEMORY_GIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_gib='&'#" ; else echo "# meta_memory_gib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo "${VIASH_META_MEMORY_TIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_tib='&'#" ; else echo "# meta_memory_tib="; fi ) +$( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo "${VIASH_META_MEMORY_PIB}" | sed "s#'#'\\"'\\"'#g;s#.*#meta_memory_pib='&'#" ; else echo "# meta_memory_pib="; fi ) + +## VIASH END +#!/bin/bash + +set -exo pipefail + + +inner_distance.py \\\\ + -i \\$par_input_file \\\\ + -r \\$par_refgene \\\\ + -o \\$par_output_prefix \\\\ + \\${par_sample_size:+-k "\\${par_sample_size}"} \\\\ + \\${par_lower_bound:+-l "\\${par_lower_bound}"} \\\\ + \\${par_upper_bound:+-u "\\${par_upper_bound}"} \\\\ + \\${par_step:+-s "\\${par_step}"} \\\\ + \\${par_mapq:+-q "\\${par_mapq}"} \\\\ +> stdout.txt + +if [[ -n \\$par_output_stats ]]; then head -n 2 stdout.txt > \\$par_output_stats; fi + + +[[ -n "\\$par_output_dist" && -f "\\$par_output_prefix.inner_distance.txt" ]] && mv \\$par_output_prefix.inner_distance.txt \\$par_output_dist +[[ -n "\\$par_output_plot" && -f "\\$par_output_prefix.inner_distance_plot.pdf" ]] && mv \\$par_output_prefix.inner_distance_plot.pdf \\$par_output_plot +[[ -n "\\$par_output_plot_r" && -f "\\$par_output_prefix.inner_distance_plot.r" ]] && mv \\$par_output_prefix.inner_distance_plot.r \\$par_output_plot_r +[[ -n "\\$par_output_freq" && -f "\\$par_output_prefix.inner_distance_freq.txt" ]] && mv \\$par_output_prefix.inner_distance_freq.txt \\$par_output_freq + +exit 0 +VIASHMAIN +bash "$tempscript" +''' + + return vdsl3WorkflowFactory(args, meta, rawScript) +} + + + +/** + * Generate a workflow for VDSL3 modules. + * + * This function is called by the workflowFactory() function. + * + * Input channel: [id, input_map] + * Output channel: [id, output_map] + * + * Internally, this workflow will convert the input channel + * to a format which the Nextflow module will be able to handle. + */ +def vdsl3WorkflowFactory(Map args, Map meta, String rawScript) { + def key = args["key"] + def processObj = null + + workflow processWf { + take: input_ + main: + + if (processObj == null) { + processObj = _vdsl3ProcessFactory(args, meta, rawScript) + } + + output_ = input_ + | map { tuple -> + def id = tuple[0] + def data_ = tuple[1] + + if (workflow.stubRun) { + // add id if missing + data_ = [id: 'stub'] + data_ + } + + // process input files separately + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { par -> + def val = data_.containsKey(par.plainName) ? data_[par.plainName] : [] + def inputFiles = [] + if (val == null) { + inputFiles = [] + } else if (val instanceof List) { + inputFiles = val + } else if (val instanceof Path) { + inputFiles = [ val ] + } else { + inputFiles = [] + } + if (!workflow.stubRun) { + // throw error when an input file doesn't exist + inputFiles.each{ file -> + assert file.exists() : + "Error in module '${key}' id '${id}' argument '${par.plainName}'.\n" + + " Required input file does not exist.\n" + + " Path: '$file'.\n" + + " Expected input file to exist" + } + } + inputFiles + } + + // remove input files + def argsExclInputFiles = meta.config.allArguments + .findAll { (it.type != "file" || it.direction != "input") && data_.containsKey(it.plainName) } + .collectEntries { par -> + def parName = par.plainName + def val = data_[parName] + if (par.multiple && val instanceof Collection) { + val = val.join(par.multiple_sep) + } + if (par.direction == "output" && par.type == "file") { + val = val + .replaceAll('\\$id', id) + .replaceAll('\\$\\{id\\}', id) + .replaceAll('\\$key', key) + .replaceAll('\\$\\{key\\}', key) + } + [parName, val] + } + + [ id ] + inputPaths + [ argsExclInputFiles, meta.resources_dir ] + } + | processObj + | map { output -> + def outputFiles = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .indexed() + .collectEntries{ index, par -> + def out = output[index + 1] + // strip dummy '.exitcode' file from output (see nextflow-io/nextflow#2678) + if (!out instanceof List || out.size() <= 1) { + if (par.multiple) { + out = [] + } else { + assert !par.required : + "Error in module '${key}' id '${output[0]}' argument '${par.plainName}'.\n" + + " Required output file is missing" + out = null + } + } else if (out.size() == 2 && !par.multiple) { + out = out[1] + } else { + out = out.drop(1) + } + [ par.plainName, out ] + } + + // drop null outputs + outputFiles.removeAll{it.value == null} + + [ output[0], outputFiles ] + } + emit: output_ + } + + return processWf +} + +// depends on: session? +def _vdsl3ProcessFactory(Map workflowArgs, Map meta, String rawScript) { + // autodetect process key + def wfKey = workflowArgs["key"] + def procKeyPrefix = "${wfKey}_process" + def scriptMeta = nextflow.script.ScriptMeta.current() + def existing = scriptMeta.getProcessNames().findAll{it.startsWith(procKeyPrefix)} + def numbers = existing.collect{it.replace(procKeyPrefix, "0").toInteger()} + def newNumber = (numbers + [-1]).max() + 1 + + def procKey = newNumber == 0 ? procKeyPrefix : "$procKeyPrefix$newNumber" + + if (newNumber > 0) { + log.warn "Key for module '${wfKey}' is duplicated.\n", + "If you run a component multiple times in the same workflow,\n" + + "it's recommended you set a unique key for every call,\n" + + "for example: ${wfKey}.run(key: \"foo\")." + } + + // subset directives and convert to list of tuples + def drctv = workflowArgs.directives + + // TODO: unit test the two commands below + // convert publish array into tags + def valueToStr = { val -> + // ignore closures + if (val instanceof CharSequence) { + if (!val.matches('^[{].*[}]$')) { + '"' + val + '"' + } else { + val + } + } else if (val instanceof List) { + "[" + val.collect{valueToStr(it)}.join(", ") + "]" + } else if (val instanceof Map) { + "[" + val.collect{k, v -> k + ": " + valueToStr(v)}.join(", ") + "]" + } else { + val.inspect() + } + } + + // multiple entries allowed: label, publishdir + def drctvStrs = drctv.collect { key, value -> + if (key in ["label", "publishDir"]) { + value.collect{ val -> + if (val instanceof Map) { + "\n$key " + val.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else if (val == null) { + "" + } else { + "\n$key " + valueToStr(val) + } + }.join() + } else if (value instanceof Map) { + "\n$key " + value.collect{ k, v -> k + ": " + valueToStr(v) }.join(", ") + } else { + "\n$key " + valueToStr(value) + } + }.join() + + def inputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "input" } + .collect { ', path(viash_par_' + it.plainName + ', stageAs: "_viash_par/' + it.plainName + '_?/*")' } + .join() + + def outputPaths = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + // insert dummy into every output (see nextflow-io/nextflow#2678) + if (!par.multiple) { + ', path{[".exitcode", args.' + par.plainName + ']}' + } else { + ', path{[".exitcode"] + args.' + par.plainName + '}' + } + } + .join() + + // TODO: move this functionality somewhere else? + if (workflowArgs.auto.transcript) { + outputPaths = outputPaths + ', path{[".exitcode", ".command*"]}' + } else { + outputPaths = outputPaths + ', path{[".exitcode"]}' + } + + // create dirs for output files (based on BashWrapper.createParentFiles) + def createParentStr = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" && it.create_parent } + .collect { par -> + def contents = "args[\"${par.plainName}\"] instanceof List ? args[\"${par.plainName}\"].join('\" \"') : args[\"${par.plainName}\"]" + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent '\" + escapeText(${contents}) + \"'\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def contents = "viash_par_${par.plainName} instanceof List ? viash_par_${par.plainName}.join(\"${par.multiple_sep}\") : viash_par_${par.plainName}" + "\n\${viash_par_${par.plainName}.empty ? \"\" : \"export VIASH_PAR_${par.plainName.toUpperCase()}='\" + escapeText(${contents}) + \"'\"}" + } + + // NOTE: if using docker, use /tmp instead of tmpDir! + def tmpDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('VIASH_TMPDIR') ?: + System.getenv('VIASH_TEMPDIR') ?: + System.getenv('VIASH_TMP') ?: + System.getenv('TEMP') ?: + System.getenv('TMPDIR') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMP') ?: + '/tmp' + ).toAbsolutePath() + + // construct stub + def stub = meta.config.allArguments + .findAll { it.type == "file" && it.direction == "output" } + .collect { par -> + "\${ args.containsKey(\"${par.plainName}\") ? \"touch2 \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"].replace(\"_*\", \"_0\") : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // escape script + def escapedScript = rawScript.replace('\\', '\\\\').replace('$', '\\$').replace('"""', '\\"\\"\\"') + + // publishdir assert + def assertStr = (workflowArgs.auto.publish == true) || workflowArgs.auto.transcript ? + """\nassert task.publishDir.size() > 0: "if auto.publish is true, params.publish_dir needs to be defined.\\n Example: --publish_dir './output/'" """ : + "" + + // generate process string + def procStr = + """nextflow.enable.dsl=2 + | + |def escapeText = { s -> s.toString().replaceAll("'", "'\\\"'\\\"'") } + |process $procKey {$drctvStrs + |input: + | tuple val(id)$inputPaths, val(args), path(resourcesDir, stageAs: ".viash_meta_resources") + |output: + | tuple val("\$id")$outputPaths, optional: true + |stub: + |\"\"\" + |touch2() { mkdir -p "\\\$(dirname "\\\$1")" && touch "\\\$1" ; } + |$stub + |\"\"\" + |script:$assertStr + |def parInject = args + | .findAll{key, value -> value != null} + | .collect{key, value -> "export VIASH_PAR_\${key.toUpperCase()}='\${escapeText(value)}'"} + | .join("\\n") + |\"\"\" + |# meta exports + |export VIASH_META_RESOURCES_DIR="\${resourcesDir}" + |export VIASH_META_TEMP_DIR="${['docker', 'podman', 'charliecloud'].any{ it == workflow.containerEngine } ? '/tmp' : tmpDir}" + |export VIASH_META_NAME="${meta.config.name}" + |# export VIASH_META_EXECUTABLE="\\\$VIASH_META_RESOURCES_DIR/\\\$VIASH_META_NAME" + |export VIASH_META_CONFIG="\\\$VIASH_META_RESOURCES_DIR/.config.vsh.yaml" + |\${task.cpus ? "export VIASH_META_CPUS=\$task.cpus" : "" } + |\${task.memory?.bytes != null ? "export VIASH_META_MEMORY_B=\$task.memory.bytes" : "" } + |if [ ! -z \\\${VIASH_META_MEMORY_B+x} ]; then + | export VIASH_META_MEMORY_KB=\\\$(( (\\\$VIASH_META_MEMORY_B+999) / 1000 )) + | export VIASH_META_MEMORY_MB=\\\$(( (\\\$VIASH_META_MEMORY_KB+999) / 1000 )) + | export VIASH_META_MEMORY_GB=\\\$(( (\\\$VIASH_META_MEMORY_MB+999) / 1000 )) + | export VIASH_META_MEMORY_TB=\\\$(( (\\\$VIASH_META_MEMORY_GB+999) / 1000 )) + | export VIASH_META_MEMORY_PB=\\\$(( (\\\$VIASH_META_MEMORY_TB+999) / 1000 )) + | export VIASH_META_MEMORY_KIB=\\\$(( (\\\$VIASH_META_MEMORY_B+1023) / 1024 )) + | export VIASH_META_MEMORY_MIB=\\\$(( (\\\$VIASH_META_MEMORY_KIB+1023) / 1024 )) + | export VIASH_META_MEMORY_GIB=\\\$(( (\\\$VIASH_META_MEMORY_MIB+1023) / 1024 )) + | export VIASH_META_MEMORY_TIB=\\\$(( (\\\$VIASH_META_MEMORY_GIB+1023) / 1024 )) + | export VIASH_META_MEMORY_PIB=\\\$(( (\\\$VIASH_META_MEMORY_TIB+1023) / 1024 )) + |fi + | + |# meta synonyms + |export VIASH_TEMP="\\\$VIASH_META_TEMP_DIR" + |export TEMP_DIR="\\\$VIASH_META_TEMP_DIR" + | + |# create output dirs if need be + |function mkdir_parent { + | for file in "\\\$@"; do + | mkdir -p "\\\$(dirname "\\\$file")" + | done + |} + |$createParentStr + | + |# argument exports${inputFileExports.join()} + |\$parInject + | + |# process script + |${escapedScript} + |\"\"\" + |} + |""".stripMargin() + + // TODO: print on debug + // if (workflowArgs.debug == true) { + // println("######################\n$procStr\n######################") + // } + + // write process to temp file + def tempFile = java.nio.file.Files.createTempFile("viash-process-${procKey}-", ".nf") + addShutdownHook { java.nio.file.Files.deleteIfExists(tempFile) } + tempFile.text = procStr + + // create process from temp file + def binding = new nextflow.script.ScriptBinding([:]) + def session = nextflow.Nextflow.getSession() + def parser = new nextflow.script.ScriptParser(session) + .setModule(true) + .setBinding(binding) + def moduleScript = parser.runScript(tempFile) + .getScript() + + // register module in meta + def module = new nextflow.script.IncludeDef.Module(name: procKey) + scriptMeta.addModule(moduleScript, module.name, module.alias) + + // retrieve and return process from meta + return scriptMeta.getProcess(procKey) +} + +// defaults +meta["defaults"] = [ + // key to be used to trace the process and determine output names + key: null, + + // fixed arguments to be passed to script + args: [:], + + // default directives + directives: readJsonBlob('''{ + "container" : { + "registry" : "images.viash-hub.com", + "image" : "vsh/biobox/rseqc/rseqc_inner_distance", + "tag" : "main" + }, + "tag" : "$id" +}'''), + + // auto settings + auto: readJsonBlob('''{ + "simplifyInput" : true, + "simplifyOutput" : false, + "transcript" : false, + "publish" : false +}'''), + + // Apply a map over the incoming tuple + // Example: `{ tup -> [ tup[0], [input: tup[1].output] ] + tup.drop(2) }` + map: null, + + // Apply a map over the ID element of a tuple (i.e. the first element) + // Example: `{ id -> id + "_foo" }` + mapId: null, + + // Apply a map over the data element of a tuple (i.e. the second element) + // Example: `{ data -> [ input: data.output ] }` + mapData: null, + + // Apply a map over the passthrough elements of a tuple (i.e. the tuple excl. the first two elements) + // Example: `{ pt -> pt.drop(1) }` + mapPassthrough: null, + + // Filter the channel + // Example: `{ tup -> tup[0] == "foo" }` + filter: null, + + // Choose whether or not to run the component on the tuple if the condition is true. + // Otherwise, the tuple will be passed through. + // Example: `{ tup -> tup[0] != "skip_this" }` + runIf: null, + + // Rename keys in the data field of the tuple (i.e. the second element) + // Will likely be deprecated in favour of `fromState`. + // Example: `[ "new_key": "old_key" ]` + renameKeys: null, + + // Fetch data from the state and pass it to the module without altering the current state. + // + // `fromState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be passed to the module as is. + // - If it is a `List[String]`, the data will be the values of the state at the given keys. + // - If it is a `Map[String, String]`, the data will be the values of the state at the given keys, with the keys renamed according to the map. + // - If it is a function, the tuple (`[id, state]`) in the channel will be passed to the function, and the result will be used as the data. + // + // Example: `{ id, state -> [input: state.fastq_file] }` + // Default: `null` + fromState: null, + + // Determine how the state should be updated after the module has been run. + // + // `toState` should be `null`, `List[String]`, `Map[String, String]` or a function. + // + // - If it is `null`, the state will be replaced with the output of the module. + // - If it is a `List[String]`, the state will be updated with the values of the data at the given keys. + // - If it is a `Map[String, String]`, the state will be updated with the values of the data at the given keys, with the keys renamed according to the map. + // - If it is a function, a tuple (`[id, output, state]`) will be passed to the function, and the result will be used as the new state. + // + // Example: `{ id, output, state -> state + [counts: state.output] }` + // Default: `{ id, output, state -> output }` + toState: null, + + // Whether or not to print debug messages + // Default: `false` + debug: false +] + +// initialise default workflow +meta["workflow"] = workflowFactory([key: meta.config.name], meta.defaults, meta) + +// add workflow to environment +nextflow.script.ScriptMeta.current().addDefinition(meta.workflow) + +// anonymous workflow for running this module as a standalone +workflow { + // add id argument if it's not already in the config + // TODO: deep copy + def newConfig = deepClone(meta.config) + def newParams = deepClone(params) + + def argsContainsId = newConfig.allArguments.any{it.plainName == "id"} + if (!argsContainsId) { + def idArg = [ + 'name': '--id', + 'required': false, + 'type': 'string', + 'description': 'A unique id for every entry.', + 'multiple': false + ] + newConfig.arguments.add(0, idArg) + newConfig = processConfig(newConfig) + } + if (!newParams.containsKey("id")) { + newParams.id = "run" + } + + helpMessage(newConfig) + + channelFromParams(newParams, newConfig) + // make sure id is not in the state if id is not in the args + | map {id, state -> + if (!argsContainsId) { + [id, state.findAll{k, v -> k != "id"}] + } else { + [id, state] + } + } + | meta.workflow.run( + auto: [ publish: "state" ] + ) +} + +// END COMPONENT-SPECIFIC CODE diff --git a/target/nextflow/rseqc/rseqc_inner_distance/nextflow.config b/target/nextflow/rseqc/rseqc_inner_distance/nextflow.config new file mode 100644 index 00000000..b7c9979a --- /dev/null +++ b/target/nextflow/rseqc/rseqc_inner_distance/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'rseqc/rseqc_inner_distance' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'main' + description = 'Calculate inner distance between read pairs.\n' + author = 'Emma Rousseau' +} + +process.container = 'nextflow/bash:latest' + +// detect tempdir +tempDir = java.nio.file.Paths.get( + System.getenv('NXF_TEMP') ?: + System.getenv('VIASH_TEMP') ?: + System.getenv('TEMPDIR') ?: + System.getenv('TMPDIR') ?: + '/tmp' +).toAbsolutePath() + +profiles { + no_publish { + process { + withName: '.*' { + publishDir = [ + enabled: false + ] + } + } + } + mount_temp { + docker.temp = tempDir + podman.temp = tempDir + charliecloud.temp = tempDir + } + docker { + docker.enabled = true + // docker.userEmulation = true + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + singularity { + singularity.enabled = true + singularity.autoMounts = true + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + podman { + podman.enabled = true + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + shifter { + shifter.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + } + charliecloud { + charliecloud.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + } +} + +process{ + withLabel: mem1gb { memory = 1000000000.B } + withLabel: mem2gb { memory = 2000000000.B } + withLabel: mem5gb { memory = 5000000000.B } + withLabel: mem10gb { memory = 10000000000.B } + withLabel: mem20gb { memory = 20000000000.B } + withLabel: mem50gb { memory = 50000000000.B } + withLabel: mem100gb { memory = 100000000000.B } + withLabel: mem200gb { memory = 200000000000.B } + withLabel: mem500gb { memory = 500000000000.B } + withLabel: mem1tb { memory = 1000000000000.B } + withLabel: mem2tb { memory = 2000000000000.B } + withLabel: mem5tb { memory = 5000000000000.B } + withLabel: mem10tb { memory = 10000000000000.B } + withLabel: mem20tb { memory = 20000000000000.B } + withLabel: mem50tb { memory = 50000000000000.B } + withLabel: mem100tb { memory = 100000000000000.B } + withLabel: mem200tb { memory = 200000000000000.B } + withLabel: mem500tb { memory = 500000000000000.B } + withLabel: mem1gib { memory = 1073741824.B } + withLabel: mem2gib { memory = 2147483648.B } + withLabel: mem4gib { memory = 4294967296.B } + withLabel: mem8gib { memory = 8589934592.B } + withLabel: mem16gib { memory = 17179869184.B } + withLabel: mem32gib { memory = 34359738368.B } + withLabel: mem64gib { memory = 68719476736.B } + withLabel: mem128gib { memory = 137438953472.B } + withLabel: mem256gib { memory = 274877906944.B } + withLabel: mem512gib { memory = 549755813888.B } + withLabel: mem1tib { memory = 1099511627776.B } + withLabel: mem2tib { memory = 2199023255552.B } + withLabel: mem4tib { memory = 4398046511104.B } + withLabel: mem8tib { memory = 8796093022208.B } + withLabel: mem16tib { memory = 17592186044416.B } + withLabel: mem32tib { memory = 35184372088832.B } + withLabel: mem64tib { memory = 70368744177664.B } + withLabel: mem128tib { memory = 140737488355328.B } + withLabel: mem256tib { memory = 281474976710656.B } + withLabel: mem512tib { memory = 562949953421312.B } + withLabel: cpu1 { cpus = 1 } + withLabel: cpu2 { cpus = 2 } + withLabel: cpu5 { cpus = 5 } + withLabel: cpu10 { cpus = 10 } + withLabel: cpu20 { cpus = 20 } + withLabel: cpu50 { cpus = 50 } + withLabel: cpu100 { cpus = 100 } + withLabel: cpu200 { cpus = 200 } + withLabel: cpu500 { cpus = 500 } + withLabel: cpu1000 { cpus = 1000 } +} + + diff --git a/target/nextflow/rseqc/rseqc_inner_distance/nextflow_schema.json b/target/nextflow/rseqc/rseqc_inner_distance/nextflow_schema.json new file mode 100644 index 00000000..34e93183 --- /dev/null +++ b/target/nextflow/rseqc/rseqc_inner_distance/nextflow_schema.json @@ -0,0 +1,209 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "rseqc_inner_distance", +"description": "Calculate inner distance between read pairs.\n", +"type": "object", +"definitions": { + + + + "input" : { + "title": "Input", + "type": "object", + "description": "No description", + "properties": { + + + "input_file": { + "type": + "string", + "description": "Type: `file`, required. input alignment file in BAM or SAM format", + "help_text": "Type: `file`, required. input alignment file in BAM or SAM format" + + } + + + , + "refgene": { + "type": + "string", + "description": "Type: `file`, required. Reference gene model in bed format", + "help_text": "Type: `file`, required. Reference gene model in bed format" + + } + + + , + "sample_size": { + "type": + "integer", + "description": "Type: `integer`, example: `1000000`. Numer of reads sampled from SAM/BAM file, default = 1000000", + "help_text": "Type: `integer`, example: `1000000`. Numer of reads sampled from SAM/BAM file, default = 1000000." + + } + + + , + "mapq": { + "type": + "integer", + "description": "Type: `integer`, example: `30`. Minimum mapping quality (phred scaled) to determine uniquely mapped reads, default=30", + "help_text": "Type: `integer`, example: `30`. Minimum mapping quality (phred scaled) to determine uniquely mapped reads, default=30." + + } + + + , + "lower_bound": { + "type": + "integer", + "description": "Type: `integer`, example: `-250`. Lower bound of inner distance (bp)", + "help_text": "Type: `integer`, example: `-250`. Lower bound of inner distance (bp). This option is used for ploting histograme, default=-250." + + } + + + , + "upper_bound": { + "type": + "integer", + "description": "Type: `integer`, example: `250`. Upper bound of inner distance (bp)", + "help_text": "Type: `integer`, example: `250`. Upper bound of inner distance (bp). This option is used for ploting histograme, default=250." + + } + + + , + "step": { + "type": + "integer", + "description": "Type: `integer`, example: `5`. Step size (bp) of histograme", + "help_text": "Type: `integer`, example: `5`. Step size (bp) of histograme. This option is used for plotting histogram, default=5." + + } + + +} +}, + + + "output" : { + "title": "Output", + "type": "object", + "description": "No description", + "properties": { + + + "output_prefix": { + "type": + "string", + "description": "Type: `string`, required. Rrefix of output files", + "help_text": "Type: `string`, required. Rrefix of output files." + + } + + + , + "output_stats": { + "type": + "string", + "description": "Type: `file`, default: `$id.$key.output_stats.output_stats`. output file (txt) with summary statistics of inner distances of paired reads", + "help_text": "Type: `file`, default: `$id.$key.output_stats.output_stats`. output file (txt) with summary statistics of inner distances of paired reads" + , + "default": "$id.$key.output_stats.output_stats" + } + + + , + "output_dist": { + "type": + "string", + "description": "Type: `file`, default: `$id.$key.output_dist.output_dist`. output file (txt) with inner distances of all paired reads", + "help_text": "Type: `file`, default: `$id.$key.output_dist.output_dist`. output file (txt) with inner distances of all paired reads" + , + "default": "$id.$key.output_dist.output_dist" + } + + + , + "output_freq": { + "type": + "string", + "description": "Type: `file`, default: `$id.$key.output_freq.output_freq`. output file (txt) with frequencies of inner distances of all paired reads", + "help_text": "Type: `file`, default: `$id.$key.output_freq.output_freq`. output file (txt) with frequencies of inner distances of all paired reads" + , + "default": "$id.$key.output_freq.output_freq" + } + + + , + "output_plot": { + "type": + "string", + "description": "Type: `file`, default: `$id.$key.output_plot.output_plot`. output file (pdf) with histogram plot of of inner distances of all paired reads", + "help_text": "Type: `file`, default: `$id.$key.output_plot.output_plot`. output file (pdf) with histogram plot of of inner distances of all paired reads" + , + "default": "$id.$key.output_plot.output_plot" + } + + + , + "output_plot_r": { + "type": + "string", + "description": "Type: `file`, default: `$id.$key.output_plot_r.output_plot_r`. output file (R) with script of histogram plot of of inner distances of all paired reads", + "help_text": "Type: `file`, default: `$id.$key.output_plot_r.output_plot_r`. output file (R) with script of histogram plot of of inner distances of all paired reads" + , + "default": "$id.$key.output_plot_r.output_plot_r" + } + + +} +}, + + + "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" + }, + + { + "$ref": "#/definitions/output" + }, + + { + "$ref": "#/definitions/nextflow input-output arguments" + } +] +} diff --git a/target/nextflow/salmon/salmon_index/.config.vsh.yaml b/target/nextflow/salmon/salmon_index/.config.vsh.yaml index 0e2f7745..9178942c 100644 --- a/target/nextflow/salmon/salmon_index/.config.vsh.yaml +++ b/target/nextflow/salmon/salmon_index/.config.vsh.yaml @@ -277,9 +277,9 @@ build_info: output: "target/nextflow/salmon/salmon_index" executable: "target/nextflow/salmon/salmon_index/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/salmon/salmon_index/main.nf b/target/nextflow/salmon/salmon_index/main.nf index f0322fb6..71ccc050 100644 --- a/target/nextflow/salmon/salmon_index/main.nf +++ b/target/nextflow/salmon/salmon_index/main.nf @@ -3129,9 +3129,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/salmon/salmon_index", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/salmon/salmon_quant/.config.vsh.yaml b/target/nextflow/salmon/salmon_quant/.config.vsh.yaml index 40d8c017..58b965db 100644 --- a/target/nextflow/salmon/salmon_quant/.config.vsh.yaml +++ b/target/nextflow/salmon/salmon_quant/.config.vsh.yaml @@ -1173,9 +1173,9 @@ build_info: output: "target/nextflow/salmon/salmon_quant" executable: "target/nextflow/salmon/salmon_quant/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/salmon/salmon_quant/main.nf b/target/nextflow/salmon/salmon_quant/main.nf index 1f91c578..ea86078c 100644 --- a/target/nextflow/salmon/salmon_quant/main.nf +++ b/target/nextflow/salmon/salmon_quant/main.nf @@ -3964,9 +3964,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/salmon/salmon_quant", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_collate/.config.vsh.yaml b/target/nextflow/samtools/samtools_collate/.config.vsh.yaml index 3fc26275..4f0d52ce 100644 --- a/target/nextflow/samtools/samtools_collate/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_collate/.config.vsh.yaml @@ -264,9 +264,9 @@ build_info: output: "target/nextflow/samtools/samtools_collate" executable: "target/nextflow/samtools/samtools_collate/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_collate/main.nf b/target/nextflow/samtools/samtools_collate/main.nf index 30508e71..a5395a5f 100644 --- a/target/nextflow/samtools/samtools_collate/main.nf +++ b/target/nextflow/samtools/samtools_collate/main.nf @@ -3140,9 +3140,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_collate", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_faidx/.config.vsh.yaml b/target/nextflow/samtools/samtools_faidx/.config.vsh.yaml index 98d403fe..2865fe3c 100644 --- a/target/nextflow/samtools/samtools_faidx/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_faidx/.config.vsh.yaml @@ -243,9 +243,9 @@ build_info: output: "target/nextflow/samtools/samtools_faidx" executable: "target/nextflow/samtools/samtools_faidx/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_faidx/main.nf b/target/nextflow/samtools/samtools_faidx/main.nf index aaeda3f8..66182629 100644 --- a/target/nextflow/samtools/samtools_faidx/main.nf +++ b/target/nextflow/samtools/samtools_faidx/main.nf @@ -3112,9 +3112,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_faidx", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_fasta/.config.vsh.yaml b/target/nextflow/samtools/samtools_fasta/.config.vsh.yaml index eda1b294..1b66b116 100644 --- a/target/nextflow/samtools/samtools_fasta/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_fasta/.config.vsh.yaml @@ -433,9 +433,9 @@ build_info: output: "target/nextflow/samtools/samtools_fasta" executable: "target/nextflow/samtools/samtools_fasta/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_fasta/main.nf b/target/nextflow/samtools/samtools_fasta/main.nf index 66a7f022..1496e396 100644 --- a/target/nextflow/samtools/samtools_fasta/main.nf +++ b/target/nextflow/samtools/samtools_fasta/main.nf @@ -3304,9 +3304,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_fasta", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_fastq/.config.vsh.yaml b/target/nextflow/samtools/samtools_fastq/.config.vsh.yaml index 2320f91c..4124925c 100644 --- a/target/nextflow/samtools/samtools_fastq/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_fastq/.config.vsh.yaml @@ -433,9 +433,9 @@ build_info: output: "target/nextflow/samtools/samtools_fastq" executable: "target/nextflow/samtools/samtools_fastq/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_fastq/main.nf b/target/nextflow/samtools/samtools_fastq/main.nf index 7d638c43..dcac0a63 100644 --- a/target/nextflow/samtools/samtools_fastq/main.nf +++ b/target/nextflow/samtools/samtools_fastq/main.nf @@ -3304,9 +3304,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_fastq", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_flagstat/.config.vsh.yaml b/target/nextflow/samtools/samtools_flagstat/.config.vsh.yaml index 5638073e..9db4af4e 100644 --- a/target/nextflow/samtools/samtools_flagstat/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_flagstat/.config.vsh.yaml @@ -173,9 +173,9 @@ build_info: output: "target/nextflow/samtools/samtools_flagstat" executable: "target/nextflow/samtools/samtools_flagstat/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_flagstat/main.nf b/target/nextflow/samtools/samtools_flagstat/main.nf index f12b54ae..1b87bd95 100644 --- a/target/nextflow/samtools/samtools_flagstat/main.nf +++ b/target/nextflow/samtools/samtools_flagstat/main.nf @@ -3028,9 +3028,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_flagstat", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_idxstats/.config.vsh.yaml b/target/nextflow/samtools/samtools_idxstats/.config.vsh.yaml index 89fad7c0..d92260ea 100644 --- a/target/nextflow/samtools/samtools_idxstats/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_idxstats/.config.vsh.yaml @@ -183,9 +183,9 @@ build_info: output: "target/nextflow/samtools/samtools_idxstats" executable: "target/nextflow/samtools/samtools_idxstats/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_idxstats/main.nf b/target/nextflow/samtools/samtools_idxstats/main.nf index c5737dba..e70a99b9 100644 --- a/target/nextflow/samtools/samtools_idxstats/main.nf +++ b/target/nextflow/samtools/samtools_idxstats/main.nf @@ -3040,9 +3040,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_idxstats", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_index/.config.vsh.yaml b/target/nextflow/samtools/samtools_index/.config.vsh.yaml index b6cf0f31..58bc5856 100644 --- a/target/nextflow/samtools/samtools_index/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_index/.config.vsh.yaml @@ -189,9 +189,9 @@ build_info: output: "target/nextflow/samtools/samtools_index" executable: "target/nextflow/samtools/samtools_index/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_index/main.nf b/target/nextflow/samtools/samtools_index/main.nf index 9ff11d84..37d74d85 100644 --- a/target/nextflow/samtools/samtools_index/main.nf +++ b/target/nextflow/samtools/samtools_index/main.nf @@ -3053,9 +3053,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_index", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_sort/.config.vsh.yaml b/target/nextflow/samtools/samtools_sort/.config.vsh.yaml index 4d531c4f..48348d75 100644 --- a/target/nextflow/samtools/samtools_sort/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_sort/.config.vsh.yaml @@ -332,9 +332,9 @@ build_info: output: "target/nextflow/samtools/samtools_sort" executable: "target/nextflow/samtools/samtools_sort/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_sort/main.nf b/target/nextflow/samtools/samtools_sort/main.nf index c9c8ecea..f9b31557 100644 --- a/target/nextflow/samtools/samtools_sort/main.nf +++ b/target/nextflow/samtools/samtools_sort/main.nf @@ -3225,9 +3225,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_sort", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_stats/.config.vsh.yaml b/target/nextflow/samtools/samtools_stats/.config.vsh.yaml index e155f70c..45f98e1e 100644 --- a/target/nextflow/samtools/samtools_stats/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_stats/.config.vsh.yaml @@ -401,9 +401,9 @@ build_info: output: "target/nextflow/samtools/samtools_stats" executable: "target/nextflow/samtools/samtools_stats/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_stats/main.nf b/target/nextflow/samtools/samtools_stats/main.nf index 75f76daf..435ef291 100644 --- a/target/nextflow/samtools/samtools_stats/main.nf +++ b/target/nextflow/samtools/samtools_stats/main.nf @@ -3295,9 +3295,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_stats", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/samtools/samtools_view/.config.vsh.yaml b/target/nextflow/samtools/samtools_view/.config.vsh.yaml index 1c64c3e7..dda15972 100644 --- a/target/nextflow/samtools/samtools_view/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_view/.config.vsh.yaml @@ -665,9 +665,9 @@ build_info: output: "target/nextflow/samtools/samtools_view" executable: "target/nextflow/samtools/samtools_view/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/samtools/samtools_view/main.nf b/target/nextflow/samtools/samtools_view/main.nf index 1e326291..117ba5da 100644 --- a/target/nextflow/samtools/samtools_view/main.nf +++ b/target/nextflow/samtools/samtools_view/main.nf @@ -3476,9 +3476,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_view", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/seqtk/seqtk_sample/.config.vsh.yaml b/target/nextflow/seqtk/seqtk_sample/.config.vsh.yaml index ea45df49..295a9983 100644 --- a/target/nextflow/seqtk/seqtk_sample/.config.vsh.yaml +++ b/target/nextflow/seqtk/seqtk_sample/.config.vsh.yaml @@ -173,9 +173,9 @@ build_info: output: "target/nextflow/seqtk/seqtk_sample" executable: "target/nextflow/seqtk/seqtk_sample/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/seqtk/seqtk_sample/main.nf b/target/nextflow/seqtk/seqtk_sample/main.nf index b4fdec0a..01065c2e 100644 --- a/target/nextflow/seqtk/seqtk_sample/main.nf +++ b/target/nextflow/seqtk/seqtk_sample/main.nf @@ -3030,9 +3030,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/seqtk/seqtk_sample", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/seqtk/seqtk_subseq/.config.vsh.yaml b/target/nextflow/seqtk/seqtk_subseq/.config.vsh.yaml index 5e09e498..884ce881 100644 --- a/target/nextflow/seqtk/seqtk_subseq/.config.vsh.yaml +++ b/target/nextflow/seqtk/seqtk_subseq/.config.vsh.yaml @@ -196,9 +196,9 @@ build_info: output: "target/nextflow/seqtk/seqtk_subseq" executable: "target/nextflow/seqtk/seqtk_subseq/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/seqtk/seqtk_subseq/main.nf b/target/nextflow/seqtk/seqtk_subseq/main.nf index 19a71312..cc8ab07b 100644 --- a/target/nextflow/seqtk/seqtk_subseq/main.nf +++ b/target/nextflow/seqtk/seqtk_subseq/main.nf @@ -3060,9 +3060,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/seqtk/seqtk_subseq", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/snpeff/.config.vsh.yaml b/target/nextflow/snpeff/.config.vsh.yaml index 4cee3bcc..3ced6f4f 100644 --- a/target/nextflow/snpeff/.config.vsh.yaml +++ b/target/nextflow/snpeff/.config.vsh.yaml @@ -628,9 +628,9 @@ build_info: output: "target/nextflow/snpeff" executable: "target/nextflow/snpeff/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/snpeff/main.nf b/target/nextflow/snpeff/main.nf index 10f456cc..47342a89 100644 --- a/target/nextflow/snpeff/main.nf +++ b/target/nextflow/snpeff/main.nf @@ -3555,9 +3555,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/snpeff", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/sortmerna/.config.vsh.yaml b/target/nextflow/sortmerna/.config.vsh.yaml index 80eca719..dc619c1b 100644 --- a/target/nextflow/sortmerna/.config.vsh.yaml +++ b/target/nextflow/sortmerna/.config.vsh.yaml @@ -591,9 +591,9 @@ build_info: output: "target/nextflow/sortmerna" executable: "target/nextflow/sortmerna/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/sortmerna/main.nf b/target/nextflow/sortmerna/main.nf index fa214093..9cc8d9b6 100644 --- a/target/nextflow/sortmerna/main.nf +++ b/target/nextflow/sortmerna/main.nf @@ -3456,9 +3456,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/sortmerna", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/star/star_align_reads/.config.vsh.yaml b/target/nextflow/star/star_align_reads/.config.vsh.yaml index 1b8c3470..d89af70f 100644 --- a/target/nextflow/star/star_align_reads/.config.vsh.yaml +++ b/target/nextflow/star/star_align_reads/.config.vsh.yaml @@ -2663,9 +2663,9 @@ build_info: output: "target/nextflow/star/star_align_reads" executable: "target/nextflow/star/star_align_reads/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/star/star_align_reads/main.nf b/target/nextflow/star/star_align_reads/main.nf index 4f294d92..a6377b73 100644 --- a/target/nextflow/star/star_align_reads/main.nf +++ b/target/nextflow/star/star_align_reads/main.nf @@ -5943,9 +5943,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/star/star_align_reads", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/star/star_genome_generate/.config.vsh.yaml b/target/nextflow/star/star_genome_generate/.config.vsh.yaml index 3e2ca331..0f79a2dc 100644 --- a/target/nextflow/star/star_genome_generate/.config.vsh.yaml +++ b/target/nextflow/star/star_genome_generate/.config.vsh.yaml @@ -333,9 +333,9 @@ build_info: output: "target/nextflow/star/star_genome_generate" executable: "target/nextflow/star/star_genome_generate/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/star/star_genome_generate/main.nf b/target/nextflow/star/star_genome_generate/main.nf index e3c5aa6b..2cc6bc08 100644 --- a/target/nextflow/star/star_genome_generate/main.nf +++ b/target/nextflow/star/star_genome_generate/main.nf @@ -3195,9 +3195,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/star/star_genome_generate", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/trimgalore/.config.vsh.yaml b/target/nextflow/trimgalore/.config.vsh.yaml index 53f2ae4b..cbc68f4a 100644 --- a/target/nextflow/trimgalore/.config.vsh.yaml +++ b/target/nextflow/trimgalore/.config.vsh.yaml @@ -770,9 +770,9 @@ build_info: output: "target/nextflow/trimgalore" executable: "target/nextflow/trimgalore/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/trimgalore/main.nf b/target/nextflow/trimgalore/main.nf index de770f0b..9325e6fc 100644 --- a/target/nextflow/trimgalore/main.nf +++ b/target/nextflow/trimgalore/main.nf @@ -3560,9 +3560,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/trimgalore", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/umi_tools/umi_tools_dedup/.config.vsh.yaml b/target/nextflow/umi_tools/umi_tools_dedup/.config.vsh.yaml index 694f6c1e..8f48bd65 100644 --- a/target/nextflow/umi_tools/umi_tools_dedup/.config.vsh.yaml +++ b/target/nextflow/umi_tools/umi_tools_dedup/.config.vsh.yaml @@ -611,9 +611,9 @@ build_info: output: "target/nextflow/umi_tools/umi_tools_dedup" executable: "target/nextflow/umi_tools/umi_tools_dedup/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/umi_tools/umi_tools_dedup/main.nf b/target/nextflow/umi_tools/umi_tools_dedup/main.nf index 70a361d4..0f3803b2 100644 --- a/target/nextflow/umi_tools/umi_tools_dedup/main.nf +++ b/target/nextflow/umi_tools/umi_tools_dedup/main.nf @@ -3487,9 +3487,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/umi_tools/umi_tools_dedup", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/umi_tools/umi_tools_extract/.config.vsh.yaml b/target/nextflow/umi_tools/umi_tools_extract/.config.vsh.yaml index 797ea610..e9c440ea 100644 --- a/target/nextflow/umi_tools/umi_tools_extract/.config.vsh.yaml +++ b/target/nextflow/umi_tools/umi_tools_extract/.config.vsh.yaml @@ -449,9 +449,9 @@ build_info: output: "target/nextflow/umi_tools/umi_tools_extract" executable: "target/nextflow/umi_tools/umi_tools_extract/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/umi_tools/umi_tools_extract/main.nf b/target/nextflow/umi_tools/umi_tools_extract/main.nf index 0a781812..cf3722b9 100644 --- a/target/nextflow/umi_tools/umi_tools_extract/main.nf +++ b/target/nextflow/umi_tools/umi_tools_extract/main.nf @@ -3316,9 +3316,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/umi_tools/umi_tools_extract", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/umi_tools/umi_tools_prepareforrsem/.config.vsh.yaml b/target/nextflow/umi_tools/umi_tools_prepareforrsem/.config.vsh.yaml index 467ecff2..142ac5c4 100644 --- a/target/nextflow/umi_tools/umi_tools_prepareforrsem/.config.vsh.yaml +++ b/target/nextflow/umi_tools/umi_tools_prepareforrsem/.config.vsh.yaml @@ -256,9 +256,9 @@ build_info: output: "target/nextflow/umi_tools/umi_tools_prepareforrsem" executable: "target/nextflow/umi_tools/umi_tools_prepareforrsem/main.nf" viash_version: "0.9.0" - git_commit: "52f44f5049606ac655154cf54ed53fa76b49896f" - git_remote: "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox" - git_tag: "v0.2.0-14-g52f44f5" + git_commit: "aa43543e1fb609901d09b7a9f0c5e72707cb47a4" + git_remote: "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox" + git_tag: "v0.2.0-20-gaa43543" package_config: name: "biobox" version: "main" diff --git a/target/nextflow/umi_tools/umi_tools_prepareforrsem/main.nf b/target/nextflow/umi_tools/umi_tools_prepareforrsem/main.nf index 2c74d881..b700b618 100644 --- a/target/nextflow/umi_tools/umi_tools_prepareforrsem/main.nf +++ b/target/nextflow/umi_tools/umi_tools_prepareforrsem/main.nf @@ -3121,9 +3121,9 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/umi_tools/umi_tools_prepareforrsem", "viash_version" : "0.9.0", - "git_commit" : "52f44f5049606ac655154cf54ed53fa76b49896f", - "git_remote" : "https://x-access-token:ghs_Clbt7tbJqVcfiS3VxySrdzjhMh1FWp3VaTFP@github.com/viash-hub/biobox", - "git_tag" : "v0.2.0-14-g52f44f5" + "git_commit" : "aa43543e1fb609901d09b7a9f0c5e72707cb47a4", + "git_remote" : "https://x-access-token:ghs_9v4VhFt3rgNHA8iZY5HYB5rN6bmxTd2UtBuO@github.com/viash-hub/biobox", + "git_tag" : "v0.2.0-20-gaa43543" }, "package_config" : { "name" : "biobox",