diff --git a/CHANGELOG.md b/CHANGELOG.md index 114e9adb..18705ca6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,11 +42,14 @@ * `rsem/rsem_prepare_reference`: Prepare transcript references for RSEM (PR #89). * `bcftools`: + - `bcftools/bcftools_concat`: Concatenate or combine VCF/BCF files (PR #145). + - `bcftools/bcftools_norm`: Left-align and normalize indels, check if REF alleles match the reference, split multiallelic sites into multiple rows; recover multiallelics from multiple rows (PR #144). + - `bcftools/bcftools_annotate`: Add or remove annotations from a VCF/BCF file (PR #143). + - `bcftools/bcftools_stats`: Parses VCF or BCF and produces a txt stats file which can be plotted using plot-vcfstats (PR #142). - `bcftools/bcftools_sort`: Sorts BCF/VCF files by position and other criteria (PR #141). * `fastqc`: High throughput sequence quality control analysis tool (PR #92). - * `trimgalore`: Quality and adapter trimming for fastq files (PR #117). ## MINOR CHANGES diff --git a/src/bcftools/bcftools_annotate/config.vsh.yaml b/src/bcftools/bcftools_annotate/config.vsh.yaml new file mode 100644 index 00000000..67e8f46e --- /dev/null +++ b/src/bcftools/bcftools_annotate/config.vsh.yaml @@ -0,0 +1,250 @@ +name: bcftools_annotate +namespace: bcftools +description: | + Add or remove annotations from a VCF/BCF file. +keywords: [Annotate, VCF, BCF] +links: + homepage: https://samtools.github.io/bcftools/ + documentation: https://samtools.github.io/bcftools/bcftools.html#annotate + repository: https://github.com/samtools/bcftools + issue_tracker: https://github.com/samtools/bcftools/issues +references: + doi: https://doi.org/10.1093/gigascience/giab008 +license: MIT/Expat, GNU +requirements: + commands: [bcftools] +authors: + - __merge__: /src/_authors/theodoro_gasperin.yaml + roles: [author] + +argument_groups: + - name: Inputs + arguments: + - name: --input + alternatives: -i + type: file + multiple: true + description: Input VCF/BCF file. + required: true + + - name: Outputs + arguments: + - name: --output + alternatives: -o + direction: output + type: file + description: Output annotated file. + required: true + + - name: Options + description: | + For examples on how to use use bcftools annotate see http://samtools.github.io/bcftools/howtos/annotate.html. + For more details on the options see https://samtools.github.io/bcftools/bcftools.html#annotate. + arguments: + + - name: --annotations + alternatives: --a + type: file + description: | + VCF file or tabix-indexed FILE with annotations: CHR\tPOS[\tVALUE]+ . + + - name: --columns + alternatives: --c + type: string + description: | + List of columns in the annotation file, e.g. CHROM,POS,REF,ALT,-,INFO/TAG. + See man page for details. + + - name: --columns_file + alternatives: --C + type: file + description: | + Read -c columns from FILE, one name per row, with optional --merge_logic TYPE: NAME[ TYPE]. + + - name: --exclude + alternatives: --e + type: string + description: | + Exclude sites for which the expression is true. + See https://samtools.github.io/bcftools/bcftools.html#expressions for details. + example: 'QUAL >= 30 && DP >= 10' + + - name: --force + type: boolean_true + description: | + continue even when parsing errors, such as undefined tags, are encountered. + Note this can be an unsafe operation and can result in corrupted BCF files. + If this option is used, make sure to sanity check the result thoroughly. + + - name: --header_line + alternatives: --H + type: string + description: | + Header line which should be appended to the VCF header, can be given multiple times. + + - name: --header_lines + alternatives: --h + type: file + description: | + File with header lines to append to the VCF header. + For example: + ##INFO= + ##INFO= + + - name: --set_id + alternatives: --I + type: string + description: | + Set ID column using a `bcftools query`-like expression, see man page for details. + + - name: --include + type: string + description: | + Select sites for which the expression is true. + See https://samtools.github.io/bcftools/bcftools.html#expressions for details. + example: 'QUAL >= 30 && DP >= 10' + + - name: --keep_sites + alternatives: --k + type: boolean_true + description: | + Leave --include/--exclude sites unchanged instead of discarding them. + + - name: --merge_logic + alternatives: --l + type: string + choices: + description: | + When multiple regions overlap a single record, this option defines how to treat multiple annotation values. + See man page for more details. + + - name: --mark_sites + alternatives: --m + type: string + description: | + Annotate sites which are present ("+") or absent ("-") in the -a file with a new INFO/TAG flag. + + - name: --min_overlap + type: string + description: | + Minimum overlap required as a fraction of the variant in the annotation -a file (ANN), + in the target VCF file (:VCF), or both for reciprocal overlap (ANN:VCF). + By default overlaps of arbitrary length are sufficient. + The option can be used only with the tab-delimited annotation -a file and with BEG and END columns present. + + - name: --no_version + type: boolean_true + description: | + Do not append version and command line information to the output VCF header. + + - name: --output_type + alternatives: --O + type: string + choices: ['u', 'z', 'b', 'v'] + description: | + Output type: + u: uncompressed BCF + z: compressed VCF + b: compressed BCF + v: uncompressed VCF + + - name: --pair_logic + type: string + choices: ['snps', 'indels', 'both', 'all', 'some', 'exact'] + description: | + Controls how to match records from the annotation file to the target VCF. + Effective only when -a is a VCF or BCF file. + The option replaces the former uninuitive --collapse. + See Common Options for more. + + - name: --regions + alternatives: --r + type: string + description: | + Restrict to comma-separated list of regions. + Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]. + example: '20:1000000-2000000' + + - name: --regions_file + alternatives: --R + type: file + description: | + Restrict to regions listed in a file. + Regions can be specified either on a VCF, BED, or tab-delimited file (the default). + For more information check manual. + + - name: --regions_overlap + type: string + choices: ['pos', 'record', 'variant', '0', '1', '2'] + description: | + This option controls how overlapping records are determined: + set to 'pos' or '0' if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); + set to 'record' or '1' if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, + and includes indels with POS at the end of a region, which are technically outside the region); + or set to 'variant' or '2' to include only true overlapping variation (compare the full VCF representation "TA>T-" vs the true sequence variation "A>-"). + + - name: --rename_annotations + type: file + description: | + Rename annotations: TYPE/old\tnew, where TYPE is one of FILTER,INFO,FORMAT. + + - name: --rename_chromosomes + type: file + description: | + Rename chromosomes according to the map in file, with "old_name new_name\n" pairs + separated by whitespaces, each on a separate line. + + - name: --samples + type: string + description: | + Subset of samples to annotate. + See also https://samtools.github.io/bcftools/bcftools.html#common_options. + + - name: --samples_file + type: file + description: | + Subset of samples to annotate in file format. + See also https://samtools.github.io/bcftools/bcftools.html#common_options. + + - name: --single_overlaps + type: boolean_true + description: | + Use this option to keep memory requirements low with very large annotation files. + Note, however, that this comes at a cost, only single overlapping intervals are considered in this mode. + This was the default mode until the commit af6f0c9 (Feb 24 2019). + + - name: --remove + alternatives: --x + type: string + description: | + List of annotations to remove. + Use "FILTER" to remove all filters or "FILTER/SomeFilter" to remove a specific filter. + Similarly, "INFO" can be used to remove all INFO tags and "FORMAT" to remove all FORMAT tags except GT. + To remove all INFO tags except "FOO" and "BAR", use "^INFO/FOO,INFO/BAR" (and similarly for FORMAT and FILTER). + "INFO" can be abbreviated to "INF" and "FORMAT" to "FMT". + +resources: + - type: bash_script + path: script.sh + +test_resources: + - type: bash_script + path: test.sh + +engines: + - type: docker + image: debian:stable-slim + setup: + - type: apt + packages: [bcftools, procps] + - type: docker + run: | + echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\"" > /var/software_versions.txt + test_setup: + - type: apt + packages: [tabix] + +runners: + - type: executable + - type: nextflow + diff --git a/src/bcftools/bcftools_annotate/help.txt b/src/bcftools/bcftools_annotate/help.txt new file mode 100644 index 00000000..2d1c7807 --- /dev/null +++ b/src/bcftools/bcftools_annotate/help.txt @@ -0,0 +1,41 @@ +``` +bcftools annotate -h +``` + +annotate: option requires an argument -- 'h' + +About: Annotate and edit VCF/BCF files. +Usage: bcftools annotate [options] VCF + +Options: + -a, --annotations FILE VCF file or tabix-indexed FILE with annotations: CHR\tPOS[\tVALUE]+ + -c, --columns LIST List of columns in the annotation file, e.g. CHROM,POS,REF,ALT,-,INFO/TAG. See man page for details + -C, --columns-file FILE Read -c columns from FILE, one name per row, with optional --merge-logic TYPE: NAME[ TYPE] + -e, --exclude EXPR Exclude sites for which the expression is true (see man page for details) + --force Continue despite parsing error (at your own risk!) + -H, --header-line STR Header line which should be appended to the VCF header, can be given multiple times + -h, --header-lines FILE Lines which should be appended to the VCF header + -I, --set-id [+]FORMAT Set ID column using a `bcftools query`-like expression, see man page for details + -i, --include EXPR Select sites for which the expression is true (see man page for details) + -k, --keep-sites Leave -i/-e sites unchanged instead of discarding them + -l, --merge-logic TAG:TYPE Merge logic for multiple overlapping regions (see man page for details), EXPERIMENTAL + -m, --mark-sites [+-]TAG Add INFO/TAG flag to sites which are ("+") or are not ("-") listed in the -a file + --min-overlap ANN:VCF Required overlap as a fraction of variant in the -a file (ANN), the VCF (:VCF), or reciprocal (ANN:VCF) + --no-version Do not append version and command line to the header + -o, --output FILE Write output to a file [standard output] + -O, --output-type u|b|v|z[0-9] u/b: un/compressed BCF, v/z: un/compressed VCF, 0-9: compression level [v] + --pair-logic STR Matching records by , see man page for details [some] + -r, --regions REGION Restrict to comma-separated list of regions + -R, --regions-file FILE Restrict to regions listed in FILE + --regions-overlap 0|1|2 Include if POS in the region (0), record overlaps (1), variant overlaps (2) [1] + --rename-annots FILE Rename annotations: TYPE/old\tnew, where TYPE is one of FILTER,INFO,FORMAT + --rename-chrs FILE Rename sequences according to the mapping: old\tnew + -s, --samples [^]LIST Comma separated list of samples to annotate (or exclude with "^" prefix) + -S, --samples-file [^]FILE File of samples to annotate (or exclude with "^" prefix) + --single-overlaps Keep memory low by avoiding complexities arising from handling multiple overlapping intervals + -x, --remove LIST List of annotations (e.g. ID,INFO/DP,FORMAT/DP,FILTER) to remove (or keep with "^" prefix). See man page for details + --threads INT Number of extra output compression threads [0] + +Examples: + http://samtools.github.io/bcftools/howtos/annotate.html + diff --git a/src/bcftools/bcftools_annotate/script.sh b/src/bcftools/bcftools_annotate/script.sh new file mode 100644 index 00000000..18137bbf --- /dev/null +++ b/src/bcftools/bcftools_annotate/script.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_force + par_keep_sites + par_no_version + par_single_overlaps +) + +for par in ${unset_if_false[@]}; do + test_val="${!par}" + [[ "$test_val" == "false" ]] && unset $par +done + +# Execute bcftools annotate with the provided arguments +bcftools annotate \ + ${par_annotations:+-a "$par_annotations"} \ + ${par_columns:+-c "$par_columns"} \ + ${par_columns_file:+-C "$par_columns_file"} \ + ${par_exclude:+-e "$par_exclude"} \ + ${par_force:+--force} \ + ${par_header_line:+-H "$par_header_line"} \ + ${par_header_lines:+-h "$par_header_lines"} \ + ${par_set_id:+-I "$par_set_id"} \ + ${par_include:+-i "$par_include"} \ + ${par_keep_sites:+-k} \ + ${par_merge_logic:+-l "$par_merge_logic"} \ + ${par_mark_sites:+-m "$par_mark_sites"} \ + ${par_min_overlap:+--min-overlap "$par_min_overlap"} \ + ${par_no_version:+--no-version} \ + ${par_samples_file:+-S "$par_samples_file"} \ + ${par_output_type:+-O "$par_output_type"} \ + ${par_pair_logic:+--pair-logic "$par_pair_logic"} \ + ${par_regions:+-r "$par_regions"} \ + ${par_regions_file:+-R "$par_regions_file"} \ + ${par_regions_overlap:+--regions-overlap "$par_regions_overlap"} \ + ${par_rename_annotations:+--rename-annots "$par_rename_annotations"} \ + ${par_rename_chromosomes:+--rename-chrs "$par_rename_chromosomes"} \ + ${par_samples:+-s "$par_samples"} \ + ${par_single_overlaps:+--single-overlaps} \ + ${par_threads:+--threads "$par_threads"} \ + ${par_remove:+-x "$par_remove"} \ + -o $par_output \ + $par_input + + + \ No newline at end of file diff --git a/src/bcftools/bcftools_annotate/test.sh b/src/bcftools/bcftools_annotate/test.sh new file mode 100644 index 00000000..39835c82 --- /dev/null +++ b/src/bcftools/bcftools_annotate/test.sh @@ -0,0 +1,305 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +# Exit on error +set -eo pipefail + +#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) +} +############################################# + +# Create directories for tests +echo "Creating Test Data..." +TMPDIR=$(mktemp -d "$meta_temp_dir/XXXXXX") +function clean_up { + [[ -d "$TMPDIR" ]] && rm -r "$TMPDIR" +} +trap clean_up EXIT + +# Create test data +cat < "$TMPDIR/example.vcf" +##fileformat=VCFv4.1 +##contig= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE1 +1 752567 llama A C . . . . . +1 752722 . G A . . . . . +EOF + +bgzip -c $TMPDIR/example.vcf > $TMPDIR/example.vcf.gz +tabix -p vcf $TMPDIR/example.vcf.gz + +cat < "$TMPDIR/annots.tsv" +1 752567 752567 FooValue1 12345 +1 752722 752722 FooValue2 67890 +EOF + +cat < "$TMPDIR/rename.tsv" +INFO/. Luigi +EOF + +bgzip $TMPDIR/annots.tsv +tabix -s1 -b2 -e3 $TMPDIR/annots.tsv.gz + +cat < "$TMPDIR/header.hdr" +##FORMAT= +##INFO= +EOF + +cat < "$TMPDIR/rename_chrm.tsv" +1 chr1 +2 chr2 +EOF + +# Test 1: Remove ID annotations +mkdir "$TMPDIR/test1" && pushd "$TMPDIR/test1" > /dev/null + +echo "> Run bcftools_annotate remove annotations" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --remove "ID" \ + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "1 752567 . A C" +echo "- test1 succeeded -" + +popd > /dev/null + +# Test 2: Annotate with -a, -c and -h options +mkdir "$TMPDIR/test2" && pushd "$TMPDIR/test2" > /dev/null + +echo "> Run bcftools_annotate with -a, -c and -h options" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --annotations "../annots.tsv.gz" \ + --header_lines "../header.hdr" \ + --columns "CHROM,FROM,TO,FMT/FOO,BAR" \ + --mark_sites "BAR" \ + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" $(echo -e "1\t752567\tllama\tA\tC\t.\t.\tBAR=12345\tFOO\tFooValue1") +echo "- test2 succeeded -" + +popd > /dev/null + +# Test 3: +mkdir "$TMPDIR/test3" && pushd "$TMPDIR/test3" > /dev/null + +echo "> Run bcftools_annotate with --set_id option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --set_id "+'%CHROM\_%POS\_%REF\_%FIRST_ALT'" \ + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "'1_752722_G_A'" +echo "- test3 succeeded -" + +popd > /dev/null + +# Test 4: +mkdir "$TMPDIR/test4" && pushd "$TMPDIR/test4" > /dev/null + +echo "> Run bcftools_annotate with --rename-annotations option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --rename_annotations "../rename.tsv" + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "##bcftools_annotateCommand=annotate --rename-annots ../rename.tsv -o annotated.vcf" +echo "- test4 succeeded -" + +popd > /dev/null + +# Test 5: Rename chromosomes +mkdir "$TMPDIR/test5" && pushd "$TMPDIR/test5" > /dev/null + +echo "> Run bcftools_annotate with --rename-chromosomes option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --rename_chromosomes "../rename_chrm.tsv" + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "chr1" +echo "- test5 succeeded -" + +popd > /dev/null + +# Test 6: Sample option +mkdir "$TMPDIR/test6" && pushd "$TMPDIR/test6" > /dev/null + +echo "> Run bcftools_annotate with -s option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --samples "SAMPLE1" + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "##bcftools_annotateCommand=annotate -s SAMPLE1 -o annotated.vcf ../example.vcf" +echo "- test6 succeeded -" + +popd > /dev/null + +# Test 7: Single overlaps +mkdir "$TMPDIR/test7" && pushd "$TMPDIR/test7" > /dev/null + +echo "> Run bcftools_annotate with --single-overlaps option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --single_overlaps \ + --keep_sites \ + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "annotate -k --single-overlaps -o annotated.vcf ../example.vcf" +echo "- test7 succeeded -" + +popd > /dev/null + +# Test 8: Min overlap +mkdir "$TMPDIR/test8" && pushd "$TMPDIR/test8" > /dev/null + +echo "> Run bcftools_annotate with --min-overlap option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --annotations "../annots.tsv.gz" \ + --columns "CHROM,FROM,TO,FMT/FOO,BAR" \ + --header_lines "../header.hdr" \ + --min_overlap "1" + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "annotate -a ../annots.tsv.gz -c CHROM,FROM,TO,FMT/FOO,BAR -h ../header.hdr --min-overlap 1 -o annotated.vcf ../example.vcf" +echo "- test8 succeeded -" + +popd > /dev/null + +# Test 9: Regions +mkdir "$TMPDIR/test9" && pushd "$TMPDIR/test9" > /dev/null + +echo "> Run bcftools_annotate with -r option" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --output "annotated.vcf" \ + --regions "1:752567-752722" + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "annotate -r 1:752567-752722 -o annotated.vcf ../example.vcf.gz" +echo "- test9 succeeded -" + +popd > /dev/null + +# Test 10: pair-logic +mkdir "$TMPDIR/test10" && pushd "$TMPDIR/test10" > /dev/null + +echo "> Run bcftools_annotate with --pair-logic option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --pair_logic "all" + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "annotate --pair-logic all -o annotated.vcf ../example.vcf" +echo "- test10 succeeded -" + +popd > /dev/null + +# Test 11: regions-overlap +mkdir "$TMPDIR/test11" && pushd "$TMPDIR/test11" > /dev/null + +echo "> Run bcftools_annotate with --regions-overlap option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --regions_overlap "1" + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "annotate --regions-overlap 1 -o annotated.vcf ../example.vcf" +echo "- test11 succeeded -" + +popd > /dev/null + +# Test 12: include +mkdir "$TMPDIR/test12" && pushd "$TMPDIR/test12" > /dev/null + +echo "> Run bcftools_annotate with -i option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --include "FILTER='PASS'" \ + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "annotate -i FILTER='PASS' -o annotated.vcf ../example.vcf" +echo "- test12 succeeded -" + +popd > /dev/null + +# Test 13: exclude +mkdir "$TMPDIR/test13" && pushd "$TMPDIR/test13" > /dev/null + +echo "> Run bcftools_annotate with -e option" +"$meta_executable" \ + --annotations "../annots.tsv.gz" \ + --input "../example.vcf" \ + --output "annotated.vcf" \ + --exclude "FILTER='PASS'" \ + --header_lines "../header.hdr" \ + --columns "CHROM,FROM,TO,FMT/FOO,BAR" \ + --merge_logic "FOO:first" \ + +# checks +assert_file_exists "annotated.vcf" +assert_file_not_empty "annotated.vcf" +assert_file_contains "annotated.vcf" "annotate -a ../annots.tsv.gz -c CHROM,FROM,TO,FMT/FOO,BAR -e FILTER='PASS' -h ../header.hdr -l FOO:first -o annotated.vcf ../example.vcf" +echo "- test13 succeeded -" + +popd > /dev/null + + +echo "---- All tests succeeded! ----" +exit 0 + diff --git a/src/bcftools/bcftools_concat/config.vsh.yaml b/src/bcftools/bcftools_concat/config.vsh.yaml new file mode 100644 index 00000000..2bb32f1c --- /dev/null +++ b/src/bcftools/bcftools_concat/config.vsh.yaml @@ -0,0 +1,172 @@ +name: bcftools_concat +namespace: bcftools +description: | + Concatenate or combine VCF/BCF files. All source files must have the same sample + columns appearing in the same order. The program can be used, for example, to + concatenate chromosome VCFs into one VCF, or combine a SNP VCF and an indel + VCF into one. The input files must be sorted by chr and position. The files + must be given in the correct order to produce sorted VCF on output unless + the -a, --allow-overlaps option is specified. With the --naive option, the files + are concatenated without being recompressed, which is very fast. +keywords: [Concatenate, VCF, BCF] +links: + homepage: https://samtools.github.io/bcftools/ + documentation: https://samtools.github.io/bcftools/bcftools.html#concat + repository: https://github.com/samtools/bcftools + issue_tracker: https://github.com/samtools/bcftools/issues +references: + doi: https://doi.org/10.1093/gigascience/giab008 +license: MIT/Expat, GNU +requirements: + commands: [bcftools] +authors: + - __merge__: /src/_authors/theodoro_gasperin.yaml + roles: [author] + +argument_groups: + - name: Inputs + arguments: + - name: --input + alternatives: -i + type: file + multiple: true + description: Input VCF/BCF files to concatenate. + + - name: --file_list + alternatives: -f + type: file + description: Read the list of VCF/BCF files from a file, one file name per line. + + - name: Outputs + arguments: + - name: --output + alternatives: -o + direction: output + type: file + description: Output concatenated VCF/BCF file. + required: true + + - name: Options + arguments: + + - name: --allow_overlaps + alternatives: -a + type: boolean_true + description: | + First coordinate of the next file can precede last record of the current file. + + - name: --compact_PS + alternatives: -c + type: boolean_true + description: | + Do not output PS tag at each site, only at the start of a new phase set block. + + - name: --remove_duplicates + alternatives: -d + type: string + choices: ['snps', 'indels', 'both', 'all', 'exact', 'none'] + description: | + Output duplicate records present in multiple files only once: . + + - name: --ligate + alternatives: -l + type: boolean_true + description: Ligate phased VCFs by matching phase at overlapping haplotypes. + + - name: --ligate_force + type: boolean_true + description: Ligate even non-overlapping chunks, keep all sites. + + - name: --ligate_warn + type: boolean_true + description: Drop sites in imperfect overlaps. + + - name: --no_version + type: boolean_true + description: Do not append version and command line information to the header. + + - name: --naive + alternatives: -n + type: boolean_true + description: Concatenate files without recompression, a header check compatibility is performed. + + - name: --naive_force + type: boolean_true + description: | + Same as --naive, but header compatibility is not checked. + Dangerous, use with caution. + + - name: --output_type + alternatives: -O + type: string + choices: ['u', 'z', 'b', 'v'] + description: | + Output type: + u: uncompressed BCF + z: compressed VCF + b: compressed BCF + v: uncompressed VCF + + - name: --min_PQ + alternatives: -q + type: integer + description: Break phase set if phasing quality is lower than . + example: 30 + + - name: --regions + alternatives: -r + type: string + description: | + Restrict to comma-separated list of regions. + Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]. + example: '20:1000000-2000000' + + - name: --regions_file + alternatives: -R + type: file + description: | + Restrict to regions listed in a file. + Regions can be specified either on a VCF, BED, or tab-delimited file (the default). + For more information check manual. + + - name: --regions_overlap + type: string + choices: ['pos', 'record', 'variant', '0', '1', '2'] + description: | + This option controls how overlapping records are determined: + set to 'pos' or '0' if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); + set to 'record' or '1' if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, + and includes indels with POS at the end of a region, which are technically outside the region); + or set to 'variant' or '2' to include only true overlapping variation (compare the full VCF representation "TA>T-" vs the true sequence variation "A>-"). + + #PS: Verbose seems to be broken in this version of bcftools + # - name: --verbose + # alternatives: -v + # type: integer + # choices: [0, 1] + # description: Set verbosity level. + +resources: + - type: bash_script + path: script.sh + +test_resources: + - type: bash_script + path: test.sh + +engines: + - type: docker + image: debian:stable-slim + setup: + - type: apt + packages: [bcftools, procps] + - type: docker + run: | + echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\"" > /var/software_versions.txt + test_setup: + - type: apt + packages: [tabix] + +runners: + - type: executable + - type: nextflow \ No newline at end of file diff --git a/src/bcftools/bcftools_concat/help.txt b/src/bcftools/bcftools_concat/help.txt new file mode 100644 index 00000000..fc0f1914 --- /dev/null +++ b/src/bcftools/bcftools_concat/help.txt @@ -0,0 +1,36 @@ +``` +bcftools concat -h +``` + +concat: option requires an argument -- 'h' + +About: Concatenate or combine VCF/BCF files. All source files must have the same sample + columns appearing in the same order. The program can be used, for example, to + concatenate chromosome VCFs into one VCF, or combine a SNP VCF and an indel + VCF into one. The input files must be sorted by chr and position. The files + must be given in the correct order to produce sorted VCF on output unless + the -a, --allow-overlaps option is specified. With the --naive option, the files + are concatenated without being recompressed, which is very fast. +Usage: bcftools concat [options] [ [...]] + +Options: + -a, --allow-overlaps First coordinate of the next file can precede last record of the current file. + -c, --compact-PS Do not output PS tag at each site, only at the start of a new phase set block. + -d, --rm-dups STRING Output duplicate records present in multiple files only once: + -D, --remove-duplicates Alias for -d exact + -f, --file-list FILE Read the list of files from a file. + -l, --ligate Ligate phased VCFs by matching phase at overlapping haplotypes + --ligate-force Ligate even non-overlapping chunks, keep all sites + --ligate-warn Drop sites in imperfect overlaps + --no-version Do not append version and command line to the header + -n, --naive Concatenate files without recompression, a header check compatibility is performed + --naive-force Same as --naive, but header compatibility is not checked. Dangerous, use with caution. + -o, --output FILE Write output to a file [standard output] + -O, --output-type u|b|v|z[0-9] u/b: un/compressed BCF, v/z: un/compressed VCF, 0-9: compression level [v] + -q, --min-PQ INT Break phase set if phasing quality is lower than [30] + -r, --regions REGION Restrict to comma-separated list of regions + -R, --regions-file FILE Restrict to regions listed in a file + --regions-overlap 0|1|2 Include if POS in the region (0), record overlaps (1), variant overlaps (2) [1] + --threads INT Use multithreading with worker threads [0] + -v, --verbose 0|1 Set verbosity level [1] + diff --git a/src/bcftools/bcftools_concat/script.sh b/src/bcftools/bcftools_concat/script.sh new file mode 100644 index 00000000..5614cd1b --- /dev/null +++ b/src/bcftools/bcftools_concat/script.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_allow_overlaps + par_compact_PS + par_ligate + par_ligate_force + par_ligate_warn + par_no_version + par_naive + par_naive_force +) + +for par in ${unset_if_false[@]}; do + test_val="${!par}" + [[ "$test_val" == "false" ]] && unset $par +done + +# Check to see whether the par_input or the par_file_list is set +if [[ -z "${par_input}" && -z "${par_file_list}" ]]; then + echo "Error: One of the parameters '--input' or '--file_list' must be used." + exit 1 +fi + +# Create input array +IFS=";" read -ra input <<< $par_input + +# Execute bcftools concat with the provided arguments +bcftools concat \ + ${par_allow_overlaps:+-a} \ + ${par_compact_PS:+-c} \ + ${par_remove_duplicates:+-d "$par_remove_duplicates"} \ + ${par_ligate:+-l} \ + ${par_ligate_force:+--ligate-force} \ + ${par_ligate_warn:+--ligate-warn} \ + ${par_no_version:+--no-version} \ + ${par_naive:+-n} \ + ${par_naive_force:+--naive-force} \ + ${par_output_type:+--O "$par_output_type"} \ + ${par_min_PQ:+-q "$par_min_PQ"} \ + ${par_regions:+-r "$par_regions"} \ + ${par_regions_file:+-R "$par_regions_file"} \ + ${par_regions_overlap:+--regions-overlap "$par_regions_overlap"} \ + ${meta_cpus:+--threads "$meta_cpus"} \ + -o $par_output \ + ${par_file_list:+-f "$par_file_list"} \ + ${input[@]} \ \ No newline at end of file diff --git a/src/bcftools/bcftools_concat/test.sh b/src/bcftools/bcftools_concat/test.sh new file mode 100644 index 00000000..3c1c7bb6 --- /dev/null +++ b/src/bcftools/bcftools_concat/test.sh @@ -0,0 +1,227 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +# Exit on error +set -eo pipefail + +#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) +} +############################################# + +# Create directories for tests +echo "Creating Test Data..." +TMPDIR=$(mktemp -d "$meta_temp_dir/XXXXXX") +function clean_up { + [[ -d "$TMPDIR" ]] && rm -r "$TMPDIR" +} +trap clean_up EXIT + +# Create test data +cat < "$TMPDIR/example.vcf" +##fileformat=VCFv4.1 +##contig= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE1 +1 752567 llama G C,A 15 . . . 1/2 +1 752752 . G A,AAA 20 . . . ./. +EOF + +bgzip -c $TMPDIR/example.vcf > $TMPDIR/example.vcf.gz +tabix -p vcf $TMPDIR/example.vcf.gz + +cat < "$TMPDIR/example_2.vcf" +##fileformat=VCFv4.1 +##contig= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE1 +1 752569 cat G C,A 15 . . . 1/2 +1 752739 . G A,AAA 20 . . . ./. +EOF + +bgzip -c $TMPDIR/example_2.vcf > $TMPDIR/example_2.vcf.gz +tabix -p vcf $TMPDIR/example_2.vcf.gz + +cat < "$TMPDIR/file_list.txt" +$TMPDIR/example.vcf.gz +$TMPDIR/example_2.vcf.gz +EOF + +# Test 1: Default test +mkdir "$TMPDIR/test1" && pushd "$TMPDIR/test1" > /dev/null + +echo "> Run bcftools_concat default test" +"$meta_executable" \ + --input "../example.vcf" \ + --input "../example_2.vcf" \ + --output "concatenated.vcf" \ + &> /dev/null + +# checks +assert_file_exists "concatenated.vcf" +assert_file_not_empty "concatenated.vcf" +assert_file_contains "concatenated.vcf" "concat -o concatenated.vcf ../example.vcf ../example_2.vcf" +echo "- test1 succeeded -" + +popd > /dev/null + +# Test 2: Allow overlaps, compact PS and remove duplicates +mkdir "$TMPDIR/test2" && pushd "$TMPDIR/test2" > /dev/null + +echo "> Run bcftools_concat test with allow overlaps, and remove duplicates" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --input "../example_2.vcf.gz" \ + --output "concatenated.vcf" \ + --allow_overlaps \ + --remove_duplicates 'none' \ + &> /dev/null + +# checks +assert_file_exists "concatenated.vcf" +assert_file_not_empty "concatenated.vcf" +assert_file_contains "concatenated.vcf" "concat -a -d none -o concatenated.vcf ../example.vcf.gz ../example_2.vcf.gz" +echo "- test2 succeeded -" + +popd > /dev/null + + +# Test 3: Ligate, ligate force and ligate warn +mkdir "$TMPDIR/test3" && pushd "$TMPDIR/test3" > /dev/null + +echo "> Run bcftools_concat test with ligate, ligate force and ligate warn" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --input "../example_2.vcf.gz" \ + --output "concatenated.vcf" \ + --ligate \ + --compact_PS \ + &> /dev/null + + +# checks +assert_file_exists "concatenated.vcf" +assert_file_not_empty "concatenated.vcf" +assert_file_contains "concatenated.vcf" "concat -c -l -o concatenated.vcf ../example.vcf.gz ../example_2.vcf.gz" +echo "- test3 succeeded -" + +popd > /dev/null + +# Test 4: file list with ligate force and ligate warn +mkdir "$TMPDIR/test4" && pushd "$TMPDIR/test4" > /dev/null + +echo "> Run bcftools_concat test with file list, ligate force and ligate warn" +"$meta_executable" \ + --file_list "../file_list.txt" \ + --output "concatenated.vcf" \ + --ligate_force \ + &> /dev/null + +# checks +assert_file_exists "concatenated.vcf" +assert_file_not_empty "concatenated.vcf" +assert_file_contains "concatenated.vcf" "concat --ligate-force -o concatenated.vcf -f ../file_list.txt" +echo "- test4 succeeded -" + +popd > /dev/null + +# Test 5: ligate warn and naive +mkdir "$TMPDIR/test5" && pushd "$TMPDIR/test5" > /dev/null + +echo "> Run bcftools_concat test with ligate warn and naive" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --input "../example_2.vcf.gz" \ + --output "concatenated.vcf.gz" \ + --ligate_warn \ + --naive \ + &> /dev/null + +bgzip -d concatenated.vcf.gz + +# checks +assert_file_exists "concatenated.vcf" +assert_file_not_empty "concatenated.vcf" +assert_file_contains "concatenated.vcf" "##fileformat=VCFv4.1" +echo "- test5 succeeded -" + +popd > /dev/null + +# Test 6: minimal PQ +mkdir "$TMPDIR/test6" && pushd "$TMPDIR/test6" > /dev/null + +echo "> Run bcftools_concat test with minimal PQ" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --input "../example_2.vcf.gz" \ + --output "concatenated.vcf" \ + --min_PQ 20 \ + &> /dev/null + +# checks +assert_file_exists "concatenated.vcf" +assert_file_not_empty "concatenated.vcf" +assert_file_contains "concatenated.vcf" "concat -q 20 -o concatenated.vcf ../example.vcf.gz ../example_2.vcf.gz" +echo "- test6 succeeded -" + +popd > /dev/null + +# Test 7: regions +mkdir "$TMPDIR/test7" && pushd "$TMPDIR/test7" > /dev/null + +echo "> Run bcftools_concat test with regions" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --input "../example_2.vcf.gz" \ + --output "concatenated.vcf" \ + --allow_overlaps \ + --regions "1:752569-752739" \ + &> /dev/null + +# checks +assert_file_exists "concatenated.vcf" +assert_file_not_empty "concatenated.vcf" +assert_file_contains "concatenated.vcf" "concat -a -r 1:752569-752739 -o concatenated.vcf ../example.vcf.gz ../example_2.vcf.gz" +echo "- test7 succeeded -" + +popd > /dev/null + +# Test 8: regions overlap +mkdir "$TMPDIR/test8" && pushd "$TMPDIR/test8" > /dev/null + +echo "> Run bcftools_concat test with regions overlap" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --input "../example_2.vcf.gz" \ + --output "concatenated.vcf" \ + --allow_overlaps \ + --regions_overlap 'pos' \ + &> /dev/null + +# checks +assert_file_exists "concatenated.vcf" +assert_file_not_empty "concatenated.vcf" +assert_file_contains "concatenated.vcf" "concat -a --regions-overlap pos -o concatenated.vcf ../example.vcf.gz ../example_2.vcf.gz" +echo "- test8 succeeded -" + +popd > /dev/null + +echo "---- All tests succeeded! ----" +exit 0 + + + diff --git a/src/bcftools/bcftools_norm/config.vsh.yaml b/src/bcftools/bcftools_norm/config.vsh.yaml new file mode 100644 index 00000000..5c525d3a --- /dev/null +++ b/src/bcftools/bcftools_norm/config.vsh.yaml @@ -0,0 +1,194 @@ +name: bcftools_norm +namespace: bcftools +description: | + Left-align and normalize indels, check if REF alleles match the reference, split multiallelic sites into multiple rows; + recover multiallelics from multiple rows. +keywords: [Normalize, VCF, BCF] +links: + homepage: https://samtools.github.io/bcftools/ + documentation: https://samtools.github.io/bcftools/bcftools.html#norm + repository: https://github.com/samtools/bcftools + issue_tracker: https://github.com/samtools/bcftools/issues +references: + doi: https://doi.org/10.1093/gigascience/giab008 +license: MIT/Expat, GNU +requirements: + commands: [bcftools] +authors: + - __merge__: /src/_authors/theodoro_gasperin.yaml + roles: [author] + +argument_groups: + - name: Inputs + arguments: + - name: --input + alternatives: -i + type: file + description: Input VCF/BCF file. + required: true + + - name: Outputs + arguments: + - name: --output + alternatives: -o + direction: output + type: file + description: Output normalized VCF/BCF file. + required: true + + - name: Options + arguments: + + - name: --atomize + alternatives: -a + type: boolean_true + description: | + Decompose complex variants (e.g., MNVs become consecutive SNVs). + + - name: --atom_overlaps + type: string + choices: [".", "*"] + description: | + Use the star allele (*) for overlapping alleles or set to missing (.). + + - name: --check_ref + alternatives: -c + type: string + choices: ['e', 'w', 'x', 's'] + description: | + Check REF alleles and exit (e), warn (w), exclude (x), or set (s) bad sites. + + - name: --remove_duplicates + alternatives: -d + type: string + choices: ['snps', 'indels', 'both', 'all', 'exact', 'none'] + description: Remove duplicate snps, indels, both, all, exact matches, or none (old -D option). + + - name: --fasta_ref + alternatives: -f + type: file + description: Reference fasta sequence file. + + - name: --force + type: boolean_true + description: | + Try to proceed even if malformed tags are encountered. + Experimental, use at your own risk. + + - name: --keep_sum + type: string + description: | + Keep vector sum constant when splitting multiallelics (see github issue #360). + + - name: --multiallelics + alternatives: -m + type: string + choices: ['+snps', '+indels', '+both', '+any', '-snps', '-indels', '-both', '-any'] + description: | + Split multiallelics (-) or join biallelics (+), type: snps, indels, both, any [default: both]. + + - name: --no_version + type: boolean_true + description: Do not append version and command line information to the header. + + - name: --do_not_normalize + alternatives: -N + type: boolean_true + description: Do not normalize indels (with -m or -c s). + + - name: --output_type + alternatives: --O + type: string + choices: ['u', 'z', 'b', 'v'] + description: | + Output type: + u: uncompressed BCF + z: compressed VCF + b: compressed BCF + v: uncompressed VCF + + - name: --old_rec_tag + type: string + description: Annotate modified records with INFO/STR indicating the original variant. + + - name: --regions + alternatives: --r + type: string + description: | + Restrict to comma-separated list of regions. + Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]. + example: '20:1000000-2000000' + + - name: --regions_file + alternatives: --R + type: file + description: | + Restrict to regions listed in a file. + Regions can be specified either on a VCF, BED, or tab-delimited file (the default). + For more information check manual. + + - name: --regions_overlap + type: string + choices: ['pos', 'record', 'variant', '0', '1', '2'] + description: | + This option controls how overlapping records are determined: + set to 'pos' or '0' if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); + set to 'record' or '1' if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, + and includes indels with POS at the end of a region, which are technically outside the region); + or set to 'variant' or '2' to include only true overlapping variation (compare the full VCF representation "TA>T-" vs the true sequence variation "A>-"). + + - name: --site_win + alternatives: -w + type: integer + description: | + Buffer for sorting lines that changed position during realignment. + + - name: --strict_filter + alternatives: -s + type: boolean_true + description: When merging (-m+), merged site is PASS only if all sites being merged PASS. + + - name: --targets + alternatives: -t + type: string + description: Similar to --regions but streams rather than index-jumps. + example: '20:1000000-2000000' + + - name: --targets_file + alternatives: -T + type: file + description: Similar to --regions_file but streams rather than index-jumps. + + - name: --targets_overlap + type: string + choices: ['pos', 'record', 'variant', '0', '1', '2'] + description: | + Include if POS in the region (0), record overlaps (1), variant overlaps (2). + Similar to --regions_overlap. + +resources: + - type: bash_script + path: script.sh + +test_resources: + - type: bash_script + path: test.sh + +engines: + - type: docker + image: debian:stable-slim + setup: + - type: apt + packages: [bcftools, procps] + - type: docker + run: | + echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\"" > /var/software_versions.txt + test_setup: + - type: apt + packages: [tabix] + +runners: + - type: executable + - type: nextflow + + diff --git a/src/bcftools/bcftools_norm/help.txt b/src/bcftools/bcftools_norm/help.txt new file mode 100644 index 00000000..02e9761a --- /dev/null +++ b/src/bcftools/bcftools_norm/help.txt @@ -0,0 +1,41 @@ +``` +bcftools norm -h +``` + +About: Left-align and normalize indels; check if REF alleles match the reference; + split multiallelic sites into multiple rows; recover multiallelics from + multiple rows. +Usage: bcftools norm [options] + +Options: + -a, --atomize Decompose complex variants (e.g. MNVs become consecutive SNVs) + --atom-overlaps '*'|. Use the star allele (*) for overlapping alleles or set to missing (.) [*] + -c, --check-ref e|w|x|s Check REF alleles and exit (e), warn (w), exclude (x), or set (s) bad sites [e] + -D, --remove-duplicates Remove duplicate lines of the same type. + -d, --rm-dup TYPE Remove duplicate snps|indels|both|all|exact + -f, --fasta-ref FILE Reference sequence + --force Try to proceed even if malformed tags are encountered. Experimental, use at your own risk + --keep-sum TAG,.. Keep vector sum constant when splitting multiallelics (see github issue #360) + -m, --multiallelics -|+TYPE Split multiallelics (-) or join biallelics (+), type: snps|indels|both|any [both] + --no-version Do not append version and command line to the header + -N, --do-not-normalize Do not normalize indels (with -m or -c s) + --old-rec-tag STR Annotate modified records with INFO/STR indicating the original variant + -o, --output FILE Write output to a file [standard output] + -O, --output-type u|b|v|z[0-9] u/b: un/compressed BCF, v/z: un/compressed VCF, 0-9: compression level [v] + -r, --regions REGION Restrict to comma-separated list of regions + -R, --regions-file FILE Restrict to regions listed in a file + --regions-overlap 0|1|2 Include if POS in the region (0), record overlaps (1), variant overlaps (2) [1] + -s, --strict-filter When merging (-m+), merged site is PASS only if all sites being merged PASS + -t, --targets REGION Similar to -r but streams rather than index-jumps + -T, --targets-file FILE Similar to -R but streams rather than index-jumps + --targets-overlap 0|1|2 Include if POS in the region (0), record overlaps (1), variant overlaps (2) [0] + --threads INT Use multithreading with worker threads [0] + -w, --site-win INT Buffer for sorting lines which changed position during realignment [1000] + +Examples: + # normalize and left-align indels + bcftools norm -f ref.fa in.vcf + + # split multi-allelic sites + bcftools norm -m- in.vcf + diff --git a/src/bcftools/bcftools_norm/script.sh b/src/bcftools/bcftools_norm/script.sh new file mode 100644 index 00000000..0f43e593 --- /dev/null +++ b/src/bcftools/bcftools_norm/script.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_atomize + par_remove_duplicates + par_force + par_no_version + par_do_not_normalize + par_strict_filter +) + +for par in ${unset_if_false[@]}; do + test_val="${!par}" + [[ "$test_val" == "false" ]] && unset $par +done + +# Execute bcftools norm with the provided arguments +bcftools norm \ + ${par_atomize:+--atomize} \ + ${par_atom_overlaps:+--atom-overlaps "$par_atom_overlaps"} \ + ${par_check_ref:+-c "$par_check_ref"} \ + ${par_remove_duplicates:+-d "$par_remove_duplicates"} \ + ${par_fasta_ref:+-f "$par_fasta_ref"} \ + ${par_force:+--force} \ + ${par_keep_sum:+--keep-sum "$par_keep_sum"} \ + ${par_multiallelics:+-m "$par_multiallelics"} \ + ${par_no_version:+--no-version} \ + ${par_do_not_normalize:+-N} \ + ${par_old_rec_tag:+--old-rec-tag "$par_old_rec_tag"} \ + ${par_regions:+-r "$par_regions"} \ + ${par_regions_file:+-R "$par_regions_file"} \ + ${par_regions_overlap:+--regions-overlap "$par_regions_overlap"} \ + ${par_site_win:+-w "$par_site_win"} \ + ${par_strict_filter:+-s} \ + ${par_targets:+-t "$par_targets"} \ + ${par_targets_file:+-T "$par_targets_file"} \ + ${par_targets_overlap:+--targets-overlap "$par_targets_overlap"} \ + ${meta_cpus:+--threads "$meta_cpus"} \ + ${par_output_type:+-O "$par_output_type"} \ + -o $par_output \ + $par_input + diff --git a/src/bcftools/bcftools_norm/test.sh b/src/bcftools/bcftools_norm/test.sh new file mode 100644 index 00000000..254c7176 --- /dev/null +++ b/src/bcftools/bcftools_norm/test.sh @@ -0,0 +1,231 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +# Exit on error +set -eo pipefail + +#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) +} +############################################# + +# Create directories for tests +echo "Creating Test Data..." +TMPDIR=$(mktemp -d "$meta_temp_dir/XXXXXX") +function clean_up { + [[ -d "$TMPDIR" ]] && rm -r "$TMPDIR" +} +trap clean_up EXIT + +# Create test data +cat < "$TMPDIR/example.vcf" +##fileformat=VCFv4.1 +##contig= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE1 +1 752567 llama G C,A . . . . 1/2 +1 752722 . G A,AAA . . . . ./. +EOF + +bgzip -c $TMPDIR/example.vcf > $TMPDIR/example.vcf.gz +tabix -p vcf $TMPDIR/example.vcf.gz + +cat < "$TMPDIR/reference.fa" +>1 +ATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCG +>2 +CGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGAT +EOF + +# Test 1: Remove ID annotations +mkdir "$TMPDIR/test1" && pushd "$TMPDIR/test1" > /dev/null + +echo "> Run bcftools_norm" +"$meta_executable" \ + --input "../example.vcf" \ + --output "normalized.vcf" \ + --atomize \ + --atom_overlaps "." \ + &> /dev/null + +# checks +assert_file_exists "normalized.vcf" +assert_file_not_empty "normalized.vcf" +assert_file_contains "normalized.vcf" "bcftools_normCommand=norm --atomize --atom-overlaps . -o normalized.vcf ../example.vcf" +echo "- test1 succeeded -" + +popd > /dev/null + +# Test 2: Check reference +mkdir "$TMPDIR/test2" && pushd "$TMPDIR/test2" > /dev/null + +echo "> Run bcftools_norm with remove duplicates" +"$meta_executable" \ + --input "../example.vcf" \ + --output "normalized.vcf" \ + --atomize \ + --remove_duplicates 'all' \ + &> /dev/null + +# checks +assert_file_exists "normalized.vcf" +assert_file_not_empty "normalized.vcf" +assert_file_contains "normalized.vcf" "norm --atomize -d all -o normalized.vcf ../example.vcf" +echo "- test2 succeeded -" + +popd > /dev/null + +# Test 3: Check reference and fasta reference +mkdir "$TMPDIR/test3" && pushd "$TMPDIR/test3" > /dev/null + +echo "> Run bcftools_norm with check reference and fasta reference" +"$meta_executable" \ + --input "../example.vcf" \ + --output "normalized.vcf" \ + --atomize \ + --fasta_ref "../reference.fa" \ + --check_ref "e" \ + &> /dev/null + +# checks +assert_file_exists "normalized.vcf" +assert_file_not_empty "normalized.vcf" +assert_file_contains "normalized.vcf" "norm --atomize -c e -f ../reference.fa -o normalized.vcf ../example.vcf" +echo "- test3 succeeded -" + +popd > /dev/null + +# Test 4: Multiallelics +mkdir "$TMPDIR/test4" && pushd "$TMPDIR/test4" > /dev/null + +echo "> Run bcftools_norm with multiallelics" +"$meta_executable" \ + --input "../example.vcf" \ + --output "normalized.vcf" \ + --multiallelics "-any" \ + --old_rec_tag "wazzaaa" \ + &> /dev/null + +# checks +assert_file_exists "normalized.vcf" +assert_file_not_empty "normalized.vcf" +assert_file_contains "normalized.vcf" "norm -m -any --old-rec-tag wazzaaa -o normalized.vcf ../example.vcf" +echo "- test4 succeeded -" + +popd > /dev/null + +# Test 5: Regions +mkdir "$TMPDIR/test5" && pushd "$TMPDIR/test5" > /dev/null + +echo "> Run bcftools_norm with regions" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --output "normalized.vcf" \ + --atomize \ + --regions "1:752567-752722" \ + &> /dev/null + +# checks +assert_file_exists "normalized.vcf" +assert_file_not_empty "normalized.vcf" +assert_file_contains "normalized.vcf" "norm --atomize -r 1:752567-752722 -o normalized.vcf ../example.vcf.gz" +echo "- test5 succeeded -" + +popd > /dev/null + +# Test 6: Targets +mkdir "$TMPDIR/test6" && pushd "$TMPDIR/test6" > /dev/null + +echo "> Run bcftools_norm with targets" +"$meta_executable" \ + --input "../example.vcf" \ + --output "normalized.vcf" \ + --atomize \ + --targets "1:752567-752722" \ + &> /dev/null + +# checks +assert_file_exists "normalized.vcf" +assert_file_not_empty "normalized.vcf" +assert_file_contains "normalized.vcf" "norm --atomize -t 1:752567-752722 -o normalized.vcf ../example.vcf" +echo "- test6 succeeded -" + +popd > /dev/null + +# Test 7: Regions overlap +mkdir "$TMPDIR/test7" && pushd "$TMPDIR/test7" > /dev/null + +echo "> Run bcftools_norm with regions overlap" +"$meta_executable" \ + --input "../example.vcf" \ + --output "normalized.vcf" \ + --atomize \ + --regions_overlap "pos" \ + &> /dev/null + +# checks +assert_file_exists "normalized.vcf" +assert_file_not_empty "normalized.vcf" +assert_file_contains "normalized.vcf" "norm --atomize --regions-overlap pos -o normalized.vcf ../example.vcf" +echo "- test7 succeeded -" + +popd > /dev/null + +# Test 8: Strict filter and targets overlap +mkdir "$TMPDIR/test8" && pushd "$TMPDIR/test8" > /dev/null + +echo "> Run bcftools_norm with strict filter and targets overlap" +"$meta_executable" \ + --input "../example.vcf" \ + --output "normalized.vcf" \ + --atomize \ + --strict_filter \ + --targets_overlap "1" \ + &> /dev/null + +# checks +assert_file_exists "normalized.vcf" +assert_file_not_empty "normalized.vcf" +assert_file_contains "normalized.vcf" "norm --atomize -s --targets-overlap 1 -o normalized.vcf ../example.vcf" +echo "- test8 succeeded -" + +popd > /dev/null + +# Test 9: Do not normalize +mkdir "$TMPDIR/test9" && pushd "$TMPDIR/test9" > /dev/null + +echo "> Run bcftools_norm with do not normalize" +"$meta_executable" \ + --input "../example.vcf" \ + --output "normalized.vcf" \ + --do_not_normalize \ + --atomize \ + &> /dev/null + +# checks +assert_file_exists "normalized.vcf" +assert_file_not_empty "normalized.vcf" +assert_file_contains "normalized.vcf" "norm --atomize -N -o normalized.vcf ../example.vcf" +echo "- test9 succeeded -" + +popd > /dev/null + +echo "---- All tests succeeded! ----" +exit 0 + + diff --git a/src/bcftools/bcftools_stats/config.vsh.yaml b/src/bcftools/bcftools_stats/config.vsh.yaml new file mode 100644 index 00000000..8fb57f7a --- /dev/null +++ b/src/bcftools/bcftools_stats/config.vsh.yaml @@ -0,0 +1,240 @@ +name: bcftools_stats +namespace: bcftools +description: | + Parses VCF or BCF and produces a txt stats file which can be plotted using plot-vcfstats. + When two files are given, the program generates separate stats for intersection + and the complements. By default only sites are compared, -s/-S must given to include + also sample columns. +keywords: [Stats, VCF, BCF] +links: + homepage: https://samtools.github.io/bcftools/ + documentation: https://samtools.github.io/bcftools/bcftools.html#stats + repository: https://github.com/samtools/bcftools + issue_tracker: https://github.com/samtools/bcftools/issues +references: + doi: https://doi.org/10.1093/gigascience/giab008 +license: MIT/Expat, GNU +requirements: + commands: [bcftools] +authors: + - __merge__: /src/_authors/theodoro_gasperin.yaml + roles: [ author ] + +argument_groups: + - name: Inputs + arguments: + - name: --input + alternatives: -i + type: file + multiple: true + description: Input VCF/BCF file. Maximum of two files. + required: true + + - name: Outputs + arguments: + - name: --output + alternatives: -o + direction: output + type: file + description: Output txt statistics file. + required: true + + - name: Options + arguments: + + - name: --allele_frequency_bins + alternatives: --af_bins + type: string + description: | + Allele frequency bins, a list of bin values (0.1,0.5,1). + example: 0.1,0.5,1 + + - name: --allele_frequency_bins_file + alternatives: --af_bins_file + type: file + description: | + Same as allele_frequency_bins, but in a file. + Format of file is one value per line. + e.g. + 0.1 + 0.5 + 1 + + - name: --allele_frequency_tag + alternatives: --af_tag + type: string + description: | + Allele frequency tag to use, by default estimated from AN,AC or GT. + + - name: --first_allele_only + alternatives: --first_only + type: boolean_true + description: | + Include only 1st allele at multiallelic sites. + + - name: --collapse + alternatives: --c + type: string + choices: [ snps, indels, both, all, some, none ] + description: | + Treat as identical records with . + See https://samtools.github.io/bcftools/bcftools.html#common_options for details. + + - name: --depth + alternatives: --d + type: string + description: | + Depth distribution: min,max,bin size. + example: 0,500,1 + + - name: --exclude + alternatives: --e + type: string + description: | + Exclude sites for which the expression is true. + See https://samtools.github.io/bcftools/bcftools.html#expressions for details. + example: 'QUAL < 30 && DP < 10' + + - name: --exons + alternatives: --E + type: file + description: | + tab-delimited file with exons for indel frameshifts statistics. + The columns of the file are CHR, FROM, TO, with 1-based, inclusive, positions. + The file is BGZF-compressed and indexed with tabix (e.g. tabix -s1 -b2 -e3 file.gz). + + - name: --apply_filters + alternatives: --f + type: string + description: | + Require at least one of the listed FILTER strings (e.g. "PASS,."). + + - name: --fasta_reference + alternatives: --F + type: file + description: | + Faidx indexed reference sequence file to determine INDEL context. + + - name: --include + alternatives: --i + type: string + description: | + Select sites for which the expression is true. + See https://samtools.github.io/bcftools/bcftools.html#expressions for details. + example: 'QUAL >= 30 && DP >= 10' + + - name: --split_by_ID + alternatives: --I + type: boolean_true + description: | + Collect stats for sites with ID separately (known vs novel). + + - name: --regions + alternatives: --r + type: string + description: | + Restrict to comma-separated list of regions. + Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]. + example: '20:1000000-2000000' + + - name: --regions_file + alternatives: --R + type: file + description: | + Restrict to regions listed in a file. + Regions can be specified either on a VCF, BED, or tab-delimited file (the default). + For more information check manual. + + - name: --regions_overlap + type: string + choices: ['pos', 'record', 'variant', '0', '1', '2'] + description: | + This option controls how overlapping records are determined: + set to 'pos' or '0' if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); + set to 'record' or '1' if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, + and includes indels with POS at the end of a region, which are technically outside the region); + or set to 'variant' or '2' to include only true overlapping variation (compare the full VCF representation "TA>T-" vs the true sequence variation "A>-"). + + - name: --samples + alternatives: --s + type: string + description: | + List of samples for sample stats, "-" to include all samples. + + - name: --samples_file + alternatives: --S + type: file + description: | + File of samples to include. + e.g. + sample1 1 + sample2 2 + sample3 2 + + - name: --targets + alternatives: --t + type: string + description: | + Similar as -r, --regions, but the next position is accessed by streaming the whole VCF/BCF + rather than using the tbi/csi index. Both -r and -t options can be applied simultaneously: -r uses the + index to jump to a region and -t discards positions which are not in the targets. Unlike -r, targets + can be prefixed with "^" to request logical complement. For example, "^X,Y,MT" indicates that + sequences X, Y and MT should be skipped. Yet another difference between the -t/-T and -r/-R is + that -r/-R checks for proper overlaps and considers both POS and the end position of an indel, + while -t/-T considers the POS coordinate only (by default; see also --regions-overlap and --targets-overlap). + Note that -t cannot be used in combination with -T. + Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]. + example: '20:1000000-2000000' + + - name: --targets_file + alternatives: --T + type: file + description: | + Similar to --regions_file option but streams rather than index-jumps. + + - name: --targets_overlaps + type: string + choices: ['pos', 'record', 'variant', '0', '1', '2'] + description: | + Include if POS in the region (0), record overlaps (1), variant overlaps (2). + + - name: --user_tstv + alternatives: --u + type: string + description: | + Collect Ts/Tv stats for any tag using the given binning [0:1:100]. + Format is . + A subfield can be selected as e.g. 'PV4[0]', here the first value of the PV4 tag. + + + - name: --verbose + alternatives: --v + type: boolean_true + description: | + Produce verbose per-site and per-sample output. + +resources: + - type: bash_script + path: script.sh + +test_resources: + - type: bash_script + path: test.sh + +engines: + - type: docker + image: debian:stable-slim + setup: + - type: apt + packages: [bcftools, procps] + - type: docker + run: | + echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\"" > /var/software_versions.txt + test_setup: + - type: apt + packages: [tabix] + +runners: + - type: executable + - type: nextflow + diff --git a/src/bcftools/bcftools_stats/help.txt b/src/bcftools/bcftools_stats/help.txt new file mode 100644 index 00000000..e702e838 --- /dev/null +++ b/src/bcftools/bcftools_stats/help.txt @@ -0,0 +1,35 @@ +``` +bcftools stats -h +``` + +About: Parses VCF or BCF and produces stats which can be plotted using plot-vcfstats. + When two files are given, the program generates separate stats for intersection + and the complements. By default only sites are compared, -s/-S must given to include + also sample columns. +Usage: bcftools stats [options] [] + +Options: + --af-bins LIST Allele frequency bins, a list (0.1,0.5,1) or a file (0.1\n0.5\n1) + --af-tag STRING Allele frequency tag to use, by default estimated from AN,AC or GT + -1, --1st-allele-only Include only 1st allele at multiallelic sites + -c, --collapse STRING Treat as identical records with , see man page for details [none] + -d, --depth INT,INT,INT Depth distribution: min,max,bin size [0,500,1] + -e, --exclude EXPR Exclude sites for which the expression is true (see man page for details) + -E, --exons FILE.gz Tab-delimited file with exons for indel frameshifts (chr,beg,end; 1-based, inclusive, bgzip compressed) + -f, --apply-filters LIST Require at least one of the listed FILTER strings (e.g. "PASS,.") + -F, --fasta-ref FILE Faidx indexed reference sequence file to determine INDEL context + -i, --include EXPR Select sites for which the expression is true (see man page for details) + -I, --split-by-ID Collect stats for sites with ID separately (known vs novel) + -r, --regions REGION Restrict to comma-separated list of regions + -R, --regions-file FILE Restrict to regions listed in a file + --regions-overlap 0|1|2 Include if POS in the region (0), record overlaps (1), variant overlaps (2) [1] + -s, --samples LIST List of samples for sample stats, "-" to include all samples + -S, --samples-file FILE File of samples to include + -t, --targets REGION Similar to -r but streams rather than index-jumps + -T, --targets-file FILE Similar to -R but streams rather than index-jumps + --targets-overlap 0|1|2 Include if POS in the region (0), record overlaps (1), variant overlaps (2) [0] + -u, --user-tstv TAG[:min:max:n] Collect Ts/Tv stats for any tag using the given binning [0:1:100] + A subfield can be selected as e.g. 'PV4[0]', here the first value of the PV4 tag + --threads INT Use multithreading with worker threads [0] + -v, --verbose Produce verbose per-site and per-sample output + diff --git a/src/bcftools/bcftools_stats/script.sh b/src/bcftools/bcftools_stats/script.sh new file mode 100644 index 00000000..119502fd --- /dev/null +++ b/src/bcftools/bcftools_stats/script.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_first_allele_only + par_split_by_ID + par_verbose +) + +for par in ${unset_if_false[@]}; do + test_val="${!par}" + [[ "$test_val" == "false" ]] && unset $par +done + +# Create input array +IFS=";" read -ra input <<< $par_input + +# Check the size of the input array +if [[ ${#input[@]} -gt 2 ]]; then + echo "Error: --input only takes a max of two files!" + exit 1 +fi + +# Execute bcftools stats with the provided arguments +bcftools stats \ + ${par_first_allele_only:+--1st-allele-only} \ + ${par_split_by_ID:+--split-by-ID} \ + ${par_verbose:+--verbose} \ + ${par_allele_frequency_bins:+--af-bins "${par_allele_frequency_bins}"} \ + ${par_allele_frequency_bins_file:+--af-bins "${par_allele_frequency_bins_file}"} \ + ${par_allele_frequency_tag:+--af-tag "${par_allele_frequency_tag}"} \ + ${par_collapse:+-c "${par_collapse}"} \ + ${par_depth:+-d "${par_depth}"} \ + ${par_exclude:+-e "${par_exclude}"} \ + ${par_exons:+-E "${par_exons}"} \ + ${par_apply_filters:+-f "${par_apply_filters}"} \ + ${par_fasta_reference:+-F "${par_fasta_reference}"} \ + ${par_include:+-i "${par_include}"} \ + ${par_regions:+-r "${par_regions}"} \ + ${par_regions_file:+-R "${par_regions_file}"} \ + ${par_regions_overlap:+--regions-overlap "${par_regions_overlap}"} \ + ${par_samples:+-s "${par_samples}"} \ + ${par_samples_file:+-S "${par_samples_file}"} \ + ${par_targets:+-t "${par_targets}"} \ + ${par_targets_file:+-T "${par_targets_file}"} \ + ${par_targets_overlaps:+--targets-overlap "${par_targets_overlaps}"} \ + ${par_user_tstv:+-u "${par_user_tstv}"} \ + "${input[@]}" \ + > $par_output + diff --git a/src/bcftools/bcftools_stats/test.sh b/src/bcftools/bcftools_stats/test.sh new file mode 100644 index 00000000..18f0256b --- /dev/null +++ b/src/bcftools/bcftools_stats/test.sh @@ -0,0 +1,306 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +# Exit on error +set -eo pipefail + +#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) +} +############################################# + +# Create directories for tests +echo "Creating Test Data..." +TMPDIR=$(mktemp -d "$meta_temp_dir/XXXXXX") +function clean_up { + [[ -d "$TMPDIR" ]] && rm -r "$TMPDIR" +} +trap clean_up EXIT + +# Create test data +cat < "$TMPDIR/example.vcf" +##fileformat=VCFv4.0 +##fileDate=20090805 +##source=myImputationProgramV3.1 +##reference=1000GenomesPilot-NCBI36 +##contig= +##contig= +##phasing=partial +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +##FILTER= +##FILTER= +##FORMAT= +##FORMAT= +##FORMAT= +##FORMAT= +##ALT= +##ALT= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT NA00001 NA00002 NA00003 +19 111 . A C 9.6 . . GT:HQ 0|0:10,10 0|0:10,10 0/1:3,3 +19 112 . A G 10 . . GT:HQ 0|0:10,10 0|0:10,10 0/1:3,3 +20 14370 rs6054257 G A 29 PASS NS=3;DP=14;AF=0.5;DB;H2 GT:GQ:DP:HQ 0|0:48:1:51,51 1|0:48:8:51,51 1/1:43:5:.,. +20 17330 . T A 3 q10 NS=3;DP=11;AF=0.017 GT:GQ:DP:HQ 0|0:49:3:58,50 0|1:3:5:65,3 0/0:41:3:.,. +20 1110696 rs6040355 A G,T 67 PASS NS=2;DP=10;AF=0.333,0.667;AA=T;DB GT:GQ:DP:HQ 1|2:21:6:23,27 2|1:2:0:18,2 2/2:35:4:.,. +20 1230237 . T . 47 PASS NS=3;DP=13;AA=T GT:GQ:DP:HQ 0|0:54:.:56,60 0|0:48:4:51,51 0/0:61:2:.,. +20 1234567 microsat1 G GA,GAC 50 PASS NS=3;DP=9;AA=G;AN=6;AC=3,1 GT:GQ:DP 0/1:.:4 0/2:17:2 1/1:40:3 +20 1235237 . T . . . . GT 0/0 0|0 ./. +EOF + +bgzip -c $TMPDIR/example.vcf > $TMPDIR/example.vcf.gz +tabix -p vcf $TMPDIR/example.vcf.gz + +cat < "$TMPDIR/exons.bed" +chr19 12345 12567 +chr20 23456 23789 +EOF + +# Compressing and indexing the exons file +bgzip -c $TMPDIR/exons.bed > $TMPDIR/exons.bed.gz +tabix -s1 -b2 -e3 $TMPDIR/exons.bed.gz + +# Create fai test file +# cat < "$TMPDIR/reference.fasta.fai" +# 19 100 895464957 60 61 +# 20 10000 1083893029 60 61 +# EOF + +# Create allele frequency bins file +cat < "$TMPDIR/allele_frequency_bins.txt" +0.1 +0.2 +0.3 +0.4 +0.5 +0.6 +0.7 +0.8 +0.9 +EOF + +# Test 1: Default Use +mkdir "$TMPDIR/test1" && pushd "$TMPDIR/test1" > /dev/null + +echo "> Run bcftools_stats on VCF file" +"$meta_executable" \ + --input "../example.vcf" \ + --output "stats.txt" \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats ../example.vcf" +echo "- test1 succeeded -" + +popd > /dev/null + +# Test 2: First allele only +mkdir "$TMPDIR/test2" && pushd "$TMPDIR/test2" > /dev/null + +echo "> Run bcftools_stats on VCF file with first allele only" +"$meta_executable" \ + --input "../example.vcf" \ + --output "stats.txt" \ + --first_allele_only \ + --allele_frequency_bins "0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9" \ + --allele_frequency_tag "AF" \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats --1st-allele-only --af-bins 0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9 --af-tag AF ../example.vcf" +echo "- test2 succeeded -" + +popd > /dev/null + +# Test 3: Split by ID +mkdir "$TMPDIR/test3" && pushd "$TMPDIR/test3" > /dev/null + +echo "> Run bcftools_stats on VCF file with split by ID" +"$meta_executable" \ + --input "../example.vcf" \ + --output "stats.txt" \ + --split_by_ID \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats --split-by-ID ../example.vcf" +echo "- test3 succeeded -" + +popd > /dev/null + +# Test 4: Collapse, Depth, Exclude +mkdir "$TMPDIR/test4" && pushd "$TMPDIR/test4" > /dev/null + +echo "> Run bcftools_stats on VCF file with collapse, depth, and exclude" +"$meta_executable" \ + --input "../example.vcf" \ + --output "stats.txt" \ + --depth "0,500,1" \ + --exclude "GT='mis'" \ + --collapse "snps" \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats -c snps -d 0,500,1 -e GT='mis' ../example.vcf" +echo "- test4 succeeded -" + +popd > /dev/null + +# Test 5: Exons, Apply Filters +mkdir "$TMPDIR/test5" && pushd "$TMPDIR/test5" > /dev/null + +echo "> Run bcftools_stats on VCF file with exons, apply filters, and fasta reference" +"$meta_executable" \ + --input "../example.vcf" \ + --output "stats.txt" \ + --exons "../exons.bed.gz" \ + --apply_filters "PASS" \ +# --fasta_reference "../reference.fasta.fai" \ + +# NOTE: fasta_reference option not included in testing because of error from bcftools stats. + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats -E ../exons.bed.gz -f PASS ../example.vcf" +#assert_file_contains "stats.txt" "bcftools stats -E ../exons.bed.gz -f PASS -F ../reference.fasta.fai ../example.vcf" +echo "- test5 succeeded -" + +popd > /dev/null + +# Test 6: Include, Regions +mkdir "$TMPDIR/test6" && pushd "$TMPDIR/test6" > /dev/null + +echo "> Run bcftools_stats on VCF file with include and regions options" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --output "stats.txt" \ + --include "GT='mis'" \ + --regions "20:1000000-2000000" \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats -i GT='mis' -r 20:1000000-2000000 ../example.vcf.gz" +echo "- test6 succeeded -" + +popd > /dev/null + +# Test 7: Regions Overlap, Samples +mkdir "$TMPDIR/test7" && pushd "$TMPDIR/test7" > /dev/null + +echo "> Run bcftools_stats on VCF file with regions overlap, and samples options" +"$meta_executable" \ + --input "../example.vcf" \ + --output "stats.txt" \ + --regions_overlap "record" \ + --samples "NA00001,NA00002" \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats --regions-overlap record -s NA00001,NA00002 ../example.vcf" +echo "- test7 succeeded -" + +popd > /dev/null + +# Test 8: Targets, Targets File, Targets Overlaps +mkdir "$TMPDIR/test8" && pushd "$TMPDIR/test8" > /dev/null + +echo "> Run bcftools_stats on VCF file with targets, targets file, and targets overlaps" +"$meta_executable" \ + --input "../example.vcf" \ + --output "stats.txt" \ + --targets "20:1000000-2000000" \ + --targets_overlaps "pos" \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats -t 20:1000000-2000000 --targets-overlap pos ../example.vcf" +echo "- test8 succeeded -" + +popd > /dev/null + +# Test 9: User TSTV and Verbose +mkdir "$TMPDIR/test9" && pushd "$TMPDIR/test9" > /dev/null + +echo "> Run bcftools_stats on VCF file with user TSTV and verbose" +"$meta_executable" \ + --input "../example.vcf" \ + --output "stats.txt" \ + --user_tstv "DP" \ + --verbose \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats --verbose -u DP ../example.vcf" +echo "- test9 succeeded -" + +popd > /dev/null + +# Test 10: Two vcf files +mkdir "$TMPDIR/test10" && pushd "$TMPDIR/test10" > /dev/null + +echo "> Run bcftools_stats on two VCF files" +"$meta_executable" \ + --input "../example.vcf.gz" \ + --input "../example.vcf.gz" \ + --output "stats.txt" \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats ../example.vcf.gz ../example.vcf.gz" +echo "- test10 succeeded -" + +popd > /dev/null + +# Test 11: with allele frequency bins file option +mkdir "$TMPDIR/test11" && pushd "$TMPDIR/test11" > /dev/null + +echo "> Run bcftools_stats on VCF file with allele frequency bins file option" +"$meta_executable" \ + --input "../example.vcf" \ + --output "stats.txt" \ + --allele_frequency_bins "../allele_frequency_bins.txt" \ + +# checks +assert_file_exists "stats.txt" +assert_file_not_empty "stats.txt" +assert_file_contains "stats.txt" "bcftools stats --af-bins ../allele_frequency_bins.txt ../example.vcf" +echo "- test11 succeeded -" + +popd > /dev/null + + +echo "---- All tests succeeded! ----" +exit 0 + + diff --git a/src/trimgalore/config.vsh.yaml b/src/trimgalore/config.vsh.yaml index 79edc09e..ae12fb10 100644 --- a/src/trimgalore/config.vsh.yaml +++ b/src/trimgalore/config.vsh.yaml @@ -42,8 +42,20 @@ argument_groups: description: Run FastQC in the default mode on the FastQ file once trimming is complete. - name: --fastqc_args type: string - description: Passes extra arguments to FastQC. If more than one argument is to be passed to FastQC they must be in the form "arg1 arg2 ...". Passing extra arguments will automatically invoke FastQC, so --fastqc does not have to be specified separately. - example: "--nogroup --outdir /home/" + description: Passes extra arguments (excluding files) to FastQC. If more than one argument is to be passed to FastQC they must be in the form "arg1 arg2 ...". Passing extra arguments will automatically invoke FastQC, so --fastqc does not have to be specified separately. + example: "--nogroup --noextract" + - name: --fastqc_contaminants + type: file + description: Specifies a non-default file which contains the list of contaminants for FastQC to screen overrepresented sequences against. The file must contain sets of named contaminants in the form name[tab]sequence. Lines prefixed with a hash will be ignored. + example: "contaminants.txt" + - name: --fastqc_adapters + type: file + description: Specifies a non-default file which contains the list of adapter sequences which which FasstQC will explicity search against the library. The file must contain sets of named adapters in the form name[tab]sequence. Lines prefixed with a hash will be ignored. + example: "adapters.txt" + - name: --fastqc_limits + type: file + description: Specifies a non-default file which contains a set of criteria which FastQC will use to determine the warn/error limits for the various modules. This file can also be used to selectively remove some modules from the output all together. The format needs to mirror the default limits.txt file found in the Configuration folder. + example: "limits.txt" - name: --adapter alternatives: -a type: string @@ -201,7 +213,7 @@ argument_groups: type: file description: If specified all output will be written to this directory instead of the current directory. direction: output - required: false + required: true default: trimmed_output - name: --trimmed_r1 type: file diff --git a/src/trimgalore/script.sh b/src/trimgalore/script.sh index 6c0401ef..1cceea4b 100755 --- a/src/trimgalore/script.sh +++ b/src/trimgalore/script.sh @@ -34,12 +34,24 @@ for par in ${unset_if_false[@]}; do [[ "$test_val" == "false" ]] && unset $par done +# Add FastQC file arguments to fastqc_args +fastqc_args="${par_fastqc_args}" +if [ -f "$par_fastqc_contaminants" ]; then + fastqc_args+=" --contaminants $par_fastqc_contaminants" +fi +if [ -f "$par_fastqc_adapters" ]; then + fastqc_args+=" --adapters $par_fastqc_adapters" +fi +if [ -f "$par_fastqc_limits" ]; then + fastqc_args+=" --limits $par_fastqc_limits" +fi + trim_galore \ ${par_quality:+-q "${par_quality}"} \ ${par_phred33:+--phred33} \ ${par_phred64:+--phred64 } \ ${par_fastqc:+--fastqc } \ - ${par_fastqc_args:+--fastqc_args "${par_fastqc_args}"} \ + ${fastqc_args:+--fastqc_args "${fastqc_args}"} \ ${par_adapter:+-a "${par_adapter}"} \ ${par_adapter2:+-a2 "${par_adapter2}"} \ ${par_illumina:+--illumina} \ diff --git a/target/executable/agat/agat_convert_bed2gff/.config.vsh.yaml b/target/executable/agat/agat_convert_bed2gff/.config.vsh.yaml index 6207fbf3..cb6fcc39 100644 --- a/target/executable/agat/agat_convert_bed2gff/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_bed2gff/.config.vsh.yaml @@ -235,8 +235,8 @@ build_info: output: "target/executable/agat/agat_convert_bed2gff" executable: "target/executable/agat/agat_convert_bed2gff/agat_convert_bed2gff" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/agat/agat_convert_bed2gff/agat_convert_bed2gff b/target/executable/agat/agat_convert_bed2gff/agat_convert_bed2gff index e1bf6f41..62415ebf 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-09-10T07:43:33Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:04Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/agat/agat_convert_embl2gff/.config.vsh.yaml b/target/executable/agat/agat_convert_embl2gff/.config.vsh.yaml index 5e0ffcf1..08f30f83 100644 --- a/target/executable/agat/agat_convert_embl2gff/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_embl2gff/.config.vsh.yaml @@ -225,8 +225,8 @@ build_info: output: "target/executable/agat/agat_convert_embl2gff" executable: "target/executable/agat/agat_convert_embl2gff/agat_convert_embl2gff" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/agat/agat_convert_embl2gff/agat_convert_embl2gff b/target/executable/agat/agat_convert_embl2gff/agat_convert_embl2gff index ad9ba221..0eb62fc6 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-09-10T07:43:33Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:04Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" 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 3e44f0c0..c4a92656 100644 --- a/target/executable/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml @@ -228,8 +228,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" 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 2b13950e..7e9271dd 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-09-10T07:43:34Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:04Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" 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 26772e0d..302db3a3 100644 --- a/target/executable/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml @@ -188,8 +188,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" 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 2b0c77c7..e83823d3 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-09-10T07:43:33Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:03Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" 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 a1712646..d30f6b07 100644 --- a/target/executable/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml +++ b/target/executable/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml @@ -195,8 +195,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" 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 5dbe40da..172b837f 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-09-10T07:43:32Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:03Z" LABEL org.opencontainers.image.source="https://github.com/NBISweden/AGAT" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/arriba/.config.vsh.yaml b/target/executable/arriba/.config.vsh.yaml index 72c56597..077eacea 100644 --- a/target/executable/arriba/.config.vsh.yaml +++ b/target/executable/arriba/.config.vsh.yaml @@ -706,8 +706,8 @@ build_info: output: "target/executable/arriba" executable: "target/executable/arriba/arriba" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/arriba/arriba b/target/executable/arriba/arriba index 64203887..45d9db65 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-09-10T07:43:36Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:07Z" LABEL org.opencontainers.image.source="https://github.com/suhrig/arriba" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bcftools/bcftools_annotate/.config.vsh.yaml b/target/executable/bcftools/bcftools_annotate/.config.vsh.yaml new file mode 100644 index 00000000..5d234d01 --- /dev/null +++ b/target/executable/bcftools/bcftools_annotate/.config.vsh.yaml @@ -0,0 +1,495 @@ +name: "bcftools_annotate" +namespace: "bcftools" +version: "add_trimgalore" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + 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 VCF/BCF file." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: true + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + description: "Output annotated file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + description: "For examples on how to use use bcftools annotate see http://samtools.github.io/bcftools/howtos/annotate.html.\n\ + For more details on the options see https://samtools.github.io/bcftools/bcftools.html#annotate.\n" + arguments: + - type: "file" + name: "--annotations" + alternatives: + - "--a" + description: "VCF file or tabix-indexed FILE with annotations: CHR\\tPOS[\\tVALUE]+\ + \ . \n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--columns" + alternatives: + - "--c" + description: "List of columns in the annotation file, e.g. CHROM,POS,REF,ALT,-,INFO/TAG.\ + \ \nSee man page for details.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--columns_file" + alternatives: + - "--C" + description: "Read -c columns from FILE, one name per row, with optional --merge_logic\ + \ TYPE: NAME[ TYPE].\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--exclude" + alternatives: + - "--e" + description: "Exclude sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions\ + \ for details.\n" + info: null + example: + - "QUAL >= 30 && DP >= 10" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--force" + description: "continue even when parsing errors, such as undefined tags, are encountered.\ + \ \nNote this can be an unsafe operation and can result in corrupted BCF files.\ + \ \nIf this option is used, make sure to sanity check the result thoroughly.\n" + info: null + direction: "input" + - type: "string" + name: "--header_line" + alternatives: + - "--H" + description: "Header line which should be appended to the VCF header, can be given\ + \ multiple times.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--header_lines" + alternatives: + - "--h" + description: "File with header lines to append to the VCF header.\nFor example:\n\ + \ ##INFO=\n ##INFO=\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--set_id" + alternatives: + - "--I" + description: "Set ID column using a `bcftools query`-like expression, see man\ + \ page for details.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--include" + description: "Select sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions\ + \ for details.\n" + info: null + example: + - "QUAL >= 30 && DP >= 10" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--keep_sites" + alternatives: + - "--k" + description: "Leave --include/--exclude sites unchanged instead of discarding\ + \ them.\n" + info: null + direction: "input" + - type: "string" + name: "--merge_logic" + alternatives: + - "--l" + description: "When multiple regions overlap a single record, this option defines\ + \ how to treat multiple annotation values.\nSee man page for more details.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--mark_sites" + alternatives: + - "--m" + description: "Annotate sites which are present (\"+\") or absent (\"-\") in the\ + \ -a file with a new INFO/TAG flag.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--min_overlap" + description: "Minimum overlap required as a fraction of the variant in the annotation\ + \ -a file (ANN), \nin the target VCF file (:VCF), or both for reciprocal overlap\ + \ (ANN:VCF). \nBy default overlaps of arbitrary length are sufficient. \nThe\ + \ option can be used only with the tab-delimited annotation -a file and with\ + \ BEG and END columns present.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--no_version" + description: "Do not append version and command line information to the output\ + \ VCF header.\n" + info: null + direction: "input" + - type: "string" + name: "--output_type" + alternatives: + - "--O" + description: "Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed\ + \ BCF\n v: uncompressed VCF\n" + info: null + required: false + choices: + - "u" + - "z" + - "b" + - "v" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--pair_logic" + description: "Controls how to match records from the annotation file to the target\ + \ VCF. \nEffective only when -a is a VCF or BCF file. \nThe option replaces\ + \ the former uninuitive --collapse. \nSee Common Options for more.\n" + info: null + required: false + choices: + - "snps" + - "indels" + - "both" + - "all" + - "some" + - "exact" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions" + alternatives: + - "--r" + description: "Restrict to comma-separated list of regions. \nFollowing formats\ + \ are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--regions_file" + alternatives: + - "--R" + description: "Restrict to regions listed in a file. \nRegions can be specified\ + \ either on a VCF, BED, or tab-delimited file (the default). \nFor more information\ + \ check manual.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions_overlap" + description: "This option controls how overlapping records are determined: \n\ + set to 'pos' or '0' if the VCF record has to have POS inside a region (this\ + \ corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if\ + \ also overlapping records with POS outside a region should be included (this\ + \ is the default behavior of -r/-R, \nand includes indels with POS at the end\ + \ of a region, which are technically outside the region); \nor set to 'variant'\ + \ or '2' to include only true overlapping variation (compare the full VCF representation\ + \ \"TA>T-\" vs the true sequence variation \"A>-\").\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--rename_annotations" + description: "Rename annotations: TYPE/old\\tnew, where TYPE is one of FILTER,INFO,FORMAT.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--rename_chromosomes" + description: "Rename chromosomes according to the map in file, with \"old_name\ + \ new_name\\n\" pairs \nseparated by whitespaces, each on a separate line.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--samples" + description: "Subset of samples to annotate.\nSee also https://samtools.github.io/bcftools/bcftools.html#common_options.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--samples_file" + description: "Subset of samples to annotate in file format.\nSee also https://samtools.github.io/bcftools/bcftools.html#common_options.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--single_overlaps" + description: "Use this option to keep memory requirements low with very large\ + \ annotation files. \nNote, however, that this comes at a cost, only single\ + \ overlapping intervals are considered in this mode. \nThis was the default\ + \ mode until the commit af6f0c9 (Feb 24 2019).\n" + info: null + direction: "input" + - type: "string" + name: "--remove" + alternatives: + - "--x" + description: "List of annotations to remove. \nUse \"FILTER\" to remove all filters\ + \ or \"FILTER/SomeFilter\" to remove a specific filter. \nSimilarly, \"INFO\"\ + \ can be used to remove all INFO tags and \"FORMAT\" to remove all FORMAT tags\ + \ except GT. \nTo remove all INFO tags except \"FOO\" and \"BAR\", use \"^INFO/FOO,INFO/BAR\"\ + \ (and similarly for FORMAT and FILTER). \n\"INFO\" can be abbreviated to \"\ + INF\" and \"FORMAT\" to \"FMT\".\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Add or remove annotations from a VCF/BCF file.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Annotate" +- "VCF" +- "BCF" +license: "MIT/Expat, GNU" +references: + doi: + - "https://doi.org/10.1093/gigascience/giab008" +links: + repository: "https://github.com/samtools/bcftools" + homepage: "https://samtools.github.io/bcftools/" + documentation: "https://samtools.github.io/bcftools/bcftools.html#annotate" + issue_tracker: "https://github.com/samtools/bcftools/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: "add_trimgalore" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bcftools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bcftools: \\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools\ + \ //p')\\\"\" > /var/software_versions.txt\n" + test_setup: + - type: "apt" + packages: + - "tabix" + interactive: false + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bcftools/bcftools_annotate/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/bcftools/bcftools_annotate" + executable: "target/executable/bcftools/bcftools_annotate/bcftools_annotate" + viash_version: "0.9.0-RC7" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" +package_config: + name: "biobox" + version: "add_trimgalore" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0-RC7" + 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 := 'add_trimgalore'" + 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/bcftools/bcftools_annotate/bcftools_annotate b/target/executable/bcftools/bcftools_annotate/bcftools_annotate new file mode 100755 index 00000000..6a3fb3e5 --- /dev/null +++ b/target/executable/bcftools/bcftools_annotate/bcftools_annotate @@ -0,0 +1,1866 @@ +#!/usr/bin/env bash + +# bcftools_annotate add_trimgalore +# +# This wrapper script is auto-generated by viash 0.9.0-RC7 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) + +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="bcftools_annotate" +VIASH_META_FUNCTIONALITY_NAME="bcftools_annotate" +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 "bcftools_annotate add_trimgalore" + echo "" + echo "Add or remove annotations from a VCF/BCF file." + echo "" + echo "Inputs:" + echo " -i, --input" + echo " type: file, required parameter, multiple values allowed, file must exist" + echo " Input VCF/BCF file." + echo "" + echo "Outputs:" + echo " -o, --output" + echo " type: file, required parameter, output, file must exist" + echo " Output annotated file." + echo "" + echo "Options:" + echo " For examples on how to use use bcftools annotate see" + echo " http://samtools.github.io/bcftools/howtos/annotate.html." + echo " For more details on the options see" + echo " https://samtools.github.io/bcftools/bcftools.html#annotate." + echo "" + echo " --a, --annotations" + echo " type: file, file must exist" + echo " VCF file or tabix-indexed FILE with annotations: CHR\\tPOS[\\tVALUE]+ ." + echo "" + echo " --c, --columns" + echo " type: string" + echo " List of columns in the annotation file, e.g." + echo " CHROM,POS,REF,ALT,-,INFO/TAG." + echo " See man page for details." + echo "" + echo " --C, --columns_file" + echo " type: file, file must exist" + echo " Read -c columns from FILE, one name per row, with optional --merge_logic" + echo " TYPE: NAME[ TYPE]." + echo "" + echo " --e, --exclude" + echo " type: string" + echo " example: QUAL >= 30 && DP >= 10" + echo " Exclude sites for which the expression is true." + echo " See https://samtools.github.io/bcftools/bcftools.html#expressions for" + echo " details." + echo "" + echo " --force" + echo " type: boolean_true" + echo " continue even when parsing errors, such as undefined tags, are" + echo " encountered." + echo " Note this can be an unsafe operation and can result in corrupted BCF" + echo " files." + echo " If this option is used, make sure to sanity check the result thoroughly." + echo "" + echo " --H, --header_line" + echo " type: string" + echo " Header line which should be appended to the VCF header, can be given" + echo " multiple times." + echo "" + echo " --h, --header_lines" + echo " type: file, file must exist" + echo " File with header lines to append to the VCF header." + echo " For example:" + echo " ##INFO=" + echo " ##INFO=" + echo "" + echo " --I, --set_id" + echo " type: string" + echo " Set ID column using a \`bcftools query\`-like expression, see man page for" + echo " details." + echo "" + echo " --include" + echo " type: string" + echo " example: QUAL >= 30 && DP >= 10" + echo " Select sites for which the expression is true." + echo " See https://samtools.github.io/bcftools/bcftools.html#expressions for" + echo " details." + echo "" + echo " --k, --keep_sites" + echo " type: boolean_true" + echo " Leave --include/--exclude sites unchanged instead of discarding them." + echo "" + echo " --l, --merge_logic" + echo " type: string" + echo " When multiple regions overlap a single record, this option defines how" + echo " to treat multiple annotation values." + echo " See man page for more details." + echo "" + echo " --m, --mark_sites" + echo " type: string" + echo " Annotate sites which are present (\"+\") or absent (\"-\") in the -a file" + echo " with a new INFO/TAG flag." + echo "" + echo " --min_overlap" + echo " type: string" + echo " Minimum overlap required as a fraction of the variant in the annotation" + echo " -a file (ANN)," + echo " in the target VCF file (:VCF), or both for reciprocal overlap (ANN:VCF)." + echo " By default overlaps of arbitrary length are sufficient." + echo " The option can be used only with the tab-delimited annotation -a file" + echo " and with BEG and END columns present." + echo "" + echo " --no_version" + echo " type: boolean_true" + echo " Do not append version and command line information to the output VCF" + echo " header." + echo "" + echo " --O, --output_type" + echo " type: string" + echo " choices: [ u, z, b, v ]" + echo " Output type:" + echo " u: uncompressed BCF" + echo " z: compressed VCF" + echo " b: compressed BCF" + echo " v: uncompressed VCF" + echo "" + echo " --pair_logic" + echo " type: string" + echo " choices: [ snps, indels, both, all, some, exact ]" + echo " Controls how to match records from the annotation file to the target" + echo " VCF." + echo " Effective only when -a is a VCF or BCF file." + echo " The option replaces the former uninuitive --collapse." + echo " See Common Options for more." + echo "" + echo " --r, --regions" + echo " type: string" + echo " example: 20:1000000-2000000" + echo " Restrict to comma-separated list of regions." + echo " Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]." + echo "" + echo " --R, --regions_file" + echo " type: file, file must exist" + echo " Restrict to regions listed in a file." + echo " Regions can be specified either on a VCF, BED, or tab-delimited file" + echo " (the default)." + echo " For more information check manual." + echo "" + echo " --regions_overlap" + echo " type: string" + echo " choices: [ pos, record, variant, 0, 1, 2 ]" + echo " This option controls how overlapping records are determined:" + echo " set to 'pos' or '0' if the VCF record has to have POS inside a region" + echo " (this corresponds to the default behavior of -t/-T);" + echo " set to 'record' or '1' if also overlapping records with POS outside a" + echo " region should be included (this is the default behavior of -r/-R," + echo " and includes indels with POS at the end of a region, which are" + echo " technically outside the region);" + echo " or set to 'variant' or '2' to include only true overlapping variation" + echo " (compare the full VCF representation \"TA>T-\" vs the true sequence" + echo " variation \"A>-\")." + echo "" + echo " --rename_annotations" + echo " type: file, file must exist" + echo " Rename annotations: TYPE/old\\tnew, where TYPE is one of" + echo " FILTER,INFO,FORMAT." + echo "" + echo " --rename_chromosomes" + echo " type: file, file must exist" + echo " Rename chromosomes according to the map in file, with \"old_name" + echo " new_name\\n\" pairs" + echo " separated by whitespaces, each on a separate line." + echo "" + echo " --samples" + echo " type: string" + echo " Subset of samples to annotate." + echo " See also" + echo " https://samtools.github.io/bcftools/bcftools.html#common_options." + echo "" + echo " --samples_file" + echo " type: file, file must exist" + echo " Subset of samples to annotate in file format." + echo " See also" + echo " https://samtools.github.io/bcftools/bcftools.html#common_options." + echo "" + echo " --single_overlaps" + echo " type: boolean_true" + echo " Use this option to keep memory requirements low with very large" + echo " annotation files." + echo " Note, however, that this comes at a cost, only single overlapping" + echo " intervals are considered in this mode." + echo " This was the default mode until the commit af6f0c9 (Feb 24 2019)." + echo "" + echo " --x, --remove" + echo " type: string" + echo " List of annotations to remove." + echo " Use \"FILTER\" to remove all filters or \"FILTER/SomeFilter\" to remove a" + echo " specific filter." + echo " Similarly, \"INFO\" can be used to remove all INFO tags and \"FORMAT\" to" + echo " remove all FORMAT tags except GT." + echo " To remove all INFO tags except \"FOO\" and \"BAR\", use \"^INFO/FOO,INFO/BAR\"" + echo " (and similarly for FORMAT and FILTER)." + echo " \"INFO\" can be abbreviated to \"INF\" and \"FORMAT\" to \"FMT\"." +} + +# 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 bcftools procps && \ + rm -rf /var/lib/apt/lists/* + +RUN echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\"" > /var/software_versions.txt + +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-09-19T08:35:57Z" +LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" +LABEL org.opencontainers.image.version="add_trimgalore" + +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 "bcftools_annotate add_trimgalore" + exit + ;; + --input) + if [ -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT="$2" + else + VIASH_PAR_INPUT="$VIASH_PAR_INPUT;""$2" + fi + [ $# -lt 2 ] && ViashError Not enough arguments passed to --input. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --input=*) + if [ -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT=$(ViashRemoveFlags "$1") + else + VIASH_PAR_INPUT="$VIASH_PAR_INPUT;"$(ViashRemoveFlags "$1") + fi + shift 1 + ;; + -i) + if [ -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT="$2" + else + VIASH_PAR_INPUT="$VIASH_PAR_INPUT;""$2" + fi + [ $# -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 + ;; + --annotations) + [ -n "$VIASH_PAR_ANNOTATIONS" ] && ViashError Bad arguments for option \'--annotations\': \'$VIASH_PAR_ANNOTATIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ANNOTATIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --annotations. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --annotations=*) + [ -n "$VIASH_PAR_ANNOTATIONS" ] && ViashError Bad arguments for option \'--annotations=*\': \'$VIASH_PAR_ANNOTATIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ANNOTATIONS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --a) + [ -n "$VIASH_PAR_ANNOTATIONS" ] && ViashError Bad arguments for option \'--a\': \'$VIASH_PAR_ANNOTATIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ANNOTATIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --a. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --columns) + [ -n "$VIASH_PAR_COLUMNS" ] && ViashError Bad arguments for option \'--columns\': \'$VIASH_PAR_COLUMNS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLUMNS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --columns. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --columns=*) + [ -n "$VIASH_PAR_COLUMNS" ] && ViashError Bad arguments for option \'--columns=*\': \'$VIASH_PAR_COLUMNS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLUMNS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --c) + [ -n "$VIASH_PAR_COLUMNS" ] && ViashError Bad arguments for option \'--c\': \'$VIASH_PAR_COLUMNS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLUMNS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --c. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --columns_file) + [ -n "$VIASH_PAR_COLUMNS_FILE" ] && ViashError Bad arguments for option \'--columns_file\': \'$VIASH_PAR_COLUMNS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLUMNS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --columns_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --columns_file=*) + [ -n "$VIASH_PAR_COLUMNS_FILE" ] && ViashError Bad arguments for option \'--columns_file=*\': \'$VIASH_PAR_COLUMNS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLUMNS_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --C) + [ -n "$VIASH_PAR_COLUMNS_FILE" ] && ViashError Bad arguments for option \'--C\': \'$VIASH_PAR_COLUMNS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLUMNS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --C. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --exclude) + [ -n "$VIASH_PAR_EXCLUDE" ] && ViashError Bad arguments for option \'--exclude\': \'$VIASH_PAR_EXCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EXCLUDE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --exclude. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --exclude=*) + [ -n "$VIASH_PAR_EXCLUDE" ] && ViashError Bad arguments for option \'--exclude=*\': \'$VIASH_PAR_EXCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EXCLUDE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --e) + [ -n "$VIASH_PAR_EXCLUDE" ] && ViashError Bad arguments for option \'--e\': \'$VIASH_PAR_EXCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EXCLUDE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --e. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --force) + [ -n "$VIASH_PAR_FORCE" ] && ViashError Bad arguments for option \'--force\': \'$VIASH_PAR_FORCE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FORCE=true + shift 1 + ;; + --header_line) + [ -n "$VIASH_PAR_HEADER_LINE" ] && ViashError Bad arguments for option \'--header_line\': \'$VIASH_PAR_HEADER_LINE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_HEADER_LINE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --header_line. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --header_line=*) + [ -n "$VIASH_PAR_HEADER_LINE" ] && ViashError Bad arguments for option \'--header_line=*\': \'$VIASH_PAR_HEADER_LINE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_HEADER_LINE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --H) + [ -n "$VIASH_PAR_HEADER_LINE" ] && ViashError Bad arguments for option \'--H\': \'$VIASH_PAR_HEADER_LINE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_HEADER_LINE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --H. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --header_lines) + [ -n "$VIASH_PAR_HEADER_LINES" ] && ViashError Bad arguments for option \'--header_lines\': \'$VIASH_PAR_HEADER_LINES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_HEADER_LINES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --header_lines. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --header_lines=*) + [ -n "$VIASH_PAR_HEADER_LINES" ] && ViashError Bad arguments for option \'--header_lines=*\': \'$VIASH_PAR_HEADER_LINES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_HEADER_LINES=$(ViashRemoveFlags "$1") + shift 1 + ;; + --h) + [ -n "$VIASH_PAR_HEADER_LINES" ] && ViashError Bad arguments for option \'--h\': \'$VIASH_PAR_HEADER_LINES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_HEADER_LINES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --h. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --set_id) + [ -n "$VIASH_PAR_SET_ID" ] && ViashError Bad arguments for option \'--set_id\': \'$VIASH_PAR_SET_ID\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SET_ID="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --set_id. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --set_id=*) + [ -n "$VIASH_PAR_SET_ID" ] && ViashError Bad arguments for option \'--set_id=*\': \'$VIASH_PAR_SET_ID\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SET_ID=$(ViashRemoveFlags "$1") + shift 1 + ;; + --I) + [ -n "$VIASH_PAR_SET_ID" ] && ViashError Bad arguments for option \'--I\': \'$VIASH_PAR_SET_ID\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SET_ID="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --I. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --include) + [ -n "$VIASH_PAR_INCLUDE" ] && ViashError Bad arguments for option \'--include\': \'$VIASH_PAR_INCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INCLUDE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --include. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --include=*) + [ -n "$VIASH_PAR_INCLUDE" ] && ViashError Bad arguments for option \'--include=*\': \'$VIASH_PAR_INCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INCLUDE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --keep_sites) + [ -n "$VIASH_PAR_KEEP_SITES" ] && ViashError Bad arguments for option \'--keep_sites\': \'$VIASH_PAR_KEEP_SITES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_KEEP_SITES=true + shift 1 + ;; + --k) + [ -n "$VIASH_PAR_KEEP_SITES" ] && ViashError Bad arguments for option \'--k\': \'$VIASH_PAR_KEEP_SITES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_KEEP_SITES=true + shift 1 + ;; + --merge_logic) + [ -n "$VIASH_PAR_MERGE_LOGIC" ] && ViashError Bad arguments for option \'--merge_logic\': \'$VIASH_PAR_MERGE_LOGIC\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MERGE_LOGIC="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --merge_logic. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --merge_logic=*) + [ -n "$VIASH_PAR_MERGE_LOGIC" ] && ViashError Bad arguments for option \'--merge_logic=*\': \'$VIASH_PAR_MERGE_LOGIC\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MERGE_LOGIC=$(ViashRemoveFlags "$1") + shift 1 + ;; + --l) + [ -n "$VIASH_PAR_MERGE_LOGIC" ] && ViashError Bad arguments for option \'--l\': \'$VIASH_PAR_MERGE_LOGIC\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MERGE_LOGIC="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --l. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --mark_sites) + [ -n "$VIASH_PAR_MARK_SITES" ] && ViashError Bad arguments for option \'--mark_sites\': \'$VIASH_PAR_MARK_SITES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MARK_SITES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --mark_sites. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --mark_sites=*) + [ -n "$VIASH_PAR_MARK_SITES" ] && ViashError Bad arguments for option \'--mark_sites=*\': \'$VIASH_PAR_MARK_SITES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MARK_SITES=$(ViashRemoveFlags "$1") + shift 1 + ;; + --m) + [ -n "$VIASH_PAR_MARK_SITES" ] && ViashError Bad arguments for option \'--m\': \'$VIASH_PAR_MARK_SITES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MARK_SITES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --m. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --min_overlap) + [ -n "$VIASH_PAR_MIN_OVERLAP" ] && ViashError Bad arguments for option \'--min_overlap\': \'$VIASH_PAR_MIN_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MIN_OVERLAP="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --min_overlap. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --min_overlap=*) + [ -n "$VIASH_PAR_MIN_OVERLAP" ] && ViashError Bad arguments for option \'--min_overlap=*\': \'$VIASH_PAR_MIN_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MIN_OVERLAP=$(ViashRemoveFlags "$1") + shift 1 + ;; + --no_version) + [ -n "$VIASH_PAR_NO_VERSION" ] && ViashError Bad arguments for option \'--no_version\': \'$VIASH_PAR_NO_VERSION\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_NO_VERSION=true + shift 1 + ;; + --output_type) + [ -n "$VIASH_PAR_OUTPUT_TYPE" ] && ViashError Bad arguments for option \'--output_type\': \'$VIASH_PAR_OUTPUT_TYPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_TYPE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_type. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_type=*) + [ -n "$VIASH_PAR_OUTPUT_TYPE" ] && ViashError Bad arguments for option \'--output_type=*\': \'$VIASH_PAR_OUTPUT_TYPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_TYPE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --O) + [ -n "$VIASH_PAR_OUTPUT_TYPE" ] && ViashError Bad arguments for option \'--O\': \'$VIASH_PAR_OUTPUT_TYPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_TYPE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --O. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --pair_logic) + [ -n "$VIASH_PAR_PAIR_LOGIC" ] && ViashError Bad arguments for option \'--pair_logic\': \'$VIASH_PAR_PAIR_LOGIC\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_PAIR_LOGIC="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --pair_logic. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --pair_logic=*) + [ -n "$VIASH_PAR_PAIR_LOGIC" ] && ViashError Bad arguments for option \'--pair_logic=*\': \'$VIASH_PAR_PAIR_LOGIC\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_PAIR_LOGIC=$(ViashRemoveFlags "$1") + shift 1 + ;; + --regions) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--regions\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions=*) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--regions=*\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --r) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--r\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --r. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_file) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--regions_file\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_file=*) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--regions_file=*\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --R) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--R\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --R. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_overlap) + [ -n "$VIASH_PAR_REGIONS_OVERLAP" ] && ViashError Bad arguments for option \'--regions_overlap\': \'$VIASH_PAR_REGIONS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_OVERLAP="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions_overlap. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_overlap=*) + [ -n "$VIASH_PAR_REGIONS_OVERLAP" ] && ViashError Bad arguments for option \'--regions_overlap=*\': \'$VIASH_PAR_REGIONS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_OVERLAP=$(ViashRemoveFlags "$1") + shift 1 + ;; + --rename_annotations) + [ -n "$VIASH_PAR_RENAME_ANNOTATIONS" ] && ViashError Bad arguments for option \'--rename_annotations\': \'$VIASH_PAR_RENAME_ANNOTATIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_RENAME_ANNOTATIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --rename_annotations. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --rename_annotations=*) + [ -n "$VIASH_PAR_RENAME_ANNOTATIONS" ] && ViashError Bad arguments for option \'--rename_annotations=*\': \'$VIASH_PAR_RENAME_ANNOTATIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_RENAME_ANNOTATIONS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --rename_chromosomes) + [ -n "$VIASH_PAR_RENAME_CHROMOSOMES" ] && ViashError Bad arguments for option \'--rename_chromosomes\': \'$VIASH_PAR_RENAME_CHROMOSOMES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_RENAME_CHROMOSOMES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --rename_chromosomes. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --rename_chromosomes=*) + [ -n "$VIASH_PAR_RENAME_CHROMOSOMES" ] && ViashError Bad arguments for option \'--rename_chromosomes=*\': \'$VIASH_PAR_RENAME_CHROMOSOMES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_RENAME_CHROMOSOMES=$(ViashRemoveFlags "$1") + shift 1 + ;; + --samples) + [ -n "$VIASH_PAR_SAMPLES" ] && ViashError Bad arguments for option \'--samples\': \'$VIASH_PAR_SAMPLES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --samples. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --samples=*) + [ -n "$VIASH_PAR_SAMPLES" ] && ViashError Bad arguments for option \'--samples=*\': \'$VIASH_PAR_SAMPLES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES=$(ViashRemoveFlags "$1") + shift 1 + ;; + --samples_file) + [ -n "$VIASH_PAR_SAMPLES_FILE" ] && ViashError Bad arguments for option \'--samples_file\': \'$VIASH_PAR_SAMPLES_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --samples_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --samples_file=*) + [ -n "$VIASH_PAR_SAMPLES_FILE" ] && ViashError Bad arguments for option \'--samples_file=*\': \'$VIASH_PAR_SAMPLES_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --single_overlaps) + [ -n "$VIASH_PAR_SINGLE_OVERLAPS" ] && ViashError Bad arguments for option \'--single_overlaps\': \'$VIASH_PAR_SINGLE_OVERLAPS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SINGLE_OVERLAPS=true + shift 1 + ;; + --remove) + [ -n "$VIASH_PAR_REMOVE" ] && ViashError Bad arguments for option \'--remove\': \'$VIASH_PAR_REMOVE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REMOVE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --remove. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --remove=*) + [ -n "$VIASH_PAR_REMOVE" ] && ViashError Bad arguments for option \'--remove=*\': \'$VIASH_PAR_REMOVE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REMOVE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --x) + [ -n "$VIASH_PAR_REMOVE" ] && ViashError Bad arguments for option \'--x\': \'$VIASH_PAR_REMOVE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REMOVE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --x. 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/bcftools/bcftools_annotate:add_trimgalore' + 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_FORCE+x} ]; then + VIASH_PAR_FORCE="false" +fi +if [ -z ${VIASH_PAR_KEEP_SITES+x} ]; then + VIASH_PAR_KEEP_SITES="false" +fi +if [ -z ${VIASH_PAR_NO_VERSION+x} ]; then + VIASH_PAR_NO_VERSION="false" +fi +if [ -z ${VIASH_PAR_SINGLE_OVERLAPS+x} ]; then + VIASH_PAR_SINGLE_OVERLAPS="false" +fi + +# check whether required files exist +if [ ! -z "$VIASH_PAR_INPUT" ]; then + IFS=';' + set -f + for file in $VIASH_PAR_INPUT; 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_ANNOTATIONS" ] && [ ! -e "$VIASH_PAR_ANNOTATIONS" ]; then + ViashError "Input file '$VIASH_PAR_ANNOTATIONS' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_COLUMNS_FILE" ] && [ ! -e "$VIASH_PAR_COLUMNS_FILE" ]; then + ViashError "Input file '$VIASH_PAR_COLUMNS_FILE' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_HEADER_LINES" ] && [ ! -e "$VIASH_PAR_HEADER_LINES" ]; then + ViashError "Input file '$VIASH_PAR_HEADER_LINES' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_REGIONS_FILE" ] && [ ! -e "$VIASH_PAR_REGIONS_FILE" ]; then + ViashError "Input file '$VIASH_PAR_REGIONS_FILE' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_RENAME_ANNOTATIONS" ] && [ ! -e "$VIASH_PAR_RENAME_ANNOTATIONS" ]; then + ViashError "Input file '$VIASH_PAR_RENAME_ANNOTATIONS' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_RENAME_CHROMOSOMES" ] && [ ! -e "$VIASH_PAR_RENAME_CHROMOSOMES" ]; then + ViashError "Input file '$VIASH_PAR_RENAME_CHROMOSOMES' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_SAMPLES_FILE" ] && [ ! -e "$VIASH_PAR_SAMPLES_FILE" ]; then + ViashError "Input file '$VIASH_PAR_SAMPLES_FILE' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_PAR_FORCE" ]]; then + if ! [[ "$VIASH_PAR_FORCE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--force' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_KEEP_SITES" ]]; then + if ! [[ "$VIASH_PAR_KEEP_SITES" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--keep_sites' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_NO_VERSION" ]]; then + if ! [[ "$VIASH_PAR_NO_VERSION" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--no_version' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_SINGLE_OVERLAPS" ]]; then + if ! [[ "$VIASH_PAR_SINGLE_OVERLAPS" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--single_overlaps' 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 + +# check whether value is belongs to a set of choices +if [ ! -z "$VIASH_PAR_OUTPUT_TYPE" ]; then + VIASH_PAR_OUTPUT_TYPE_CHOICES=("u;z;b;v") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_OUTPUT_TYPE_CHOICES[*]};" =~ ";$VIASH_PAR_OUTPUT_TYPE;" ]]; then + ViashError '--output_type' specified value of \'$VIASH_PAR_OUTPUT_TYPE\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_PAIR_LOGIC" ]; then + VIASH_PAR_PAIR_LOGIC_CHOICES=("snps;indels;both;all;some;exact") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_PAIR_LOGIC_CHOICES[*]};" =~ ";$VIASH_PAR_PAIR_LOGIC;" ]]; then + ViashError '--pair_logic' specified value of \'$VIASH_PAR_PAIR_LOGIC\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_REGIONS_OVERLAP" ]; then + VIASH_PAR_REGIONS_OVERLAP_CHOICES=("pos;record;variant;0;1;2") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_REGIONS_OVERLAP_CHOICES[*]};" =~ ";$VIASH_PAR_REGIONS_OVERLAP;" ]]; then + ViashError '--regions_overlap' specified value of \'$VIASH_PAR_REGIONS_OVERLAP\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +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_TEST_INPUT=() + IFS=';' + for var in $VIASH_PAR_INPUT; do + unset IFS + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$var")" ) + var=$(ViashDockerAutodetectMount "$var") + VIASH_TEST_INPUT+=( "$var" ) + done + VIASH_PAR_INPUT=$(IFS=';' ; echo "${VIASH_TEST_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_PAR_ANNOTATIONS" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_ANNOTATIONS")" ) + VIASH_PAR_ANNOTATIONS=$(ViashDockerAutodetectMount "$VIASH_PAR_ANNOTATIONS") +fi +if [ ! -z "$VIASH_PAR_COLUMNS_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_COLUMNS_FILE")" ) + VIASH_PAR_COLUMNS_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_COLUMNS_FILE") +fi +if [ ! -z "$VIASH_PAR_HEADER_LINES" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_HEADER_LINES")" ) + VIASH_PAR_HEADER_LINES=$(ViashDockerAutodetectMount "$VIASH_PAR_HEADER_LINES") +fi +if [ ! -z "$VIASH_PAR_REGIONS_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_REGIONS_FILE")" ) + VIASH_PAR_REGIONS_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_REGIONS_FILE") +fi +if [ ! -z "$VIASH_PAR_RENAME_ANNOTATIONS" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_RENAME_ANNOTATIONS")" ) + VIASH_PAR_RENAME_ANNOTATIONS=$(ViashDockerAutodetectMount "$VIASH_PAR_RENAME_ANNOTATIONS") +fi +if [ ! -z "$VIASH_PAR_RENAME_CHROMOSOMES" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_RENAME_CHROMOSOMES")" ) + VIASH_PAR_RENAME_CHROMOSOMES=$(ViashDockerAutodetectMount "$VIASH_PAR_RENAME_CHROMOSOMES") +fi +if [ ! -z "$VIASH_PAR_SAMPLES_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_SAMPLES_FILE")" ) + VIASH_PAR_SAMPLES_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_SAMPLES_FILE") +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-bcftools_annotate-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_ANNOTATIONS+x} ]; then echo "${VIASH_PAR_ANNOTATIONS}" | sed "s#'#'\"'\"'#g;s#.*#par_annotations='&'#" ; else echo "# par_annotations="; fi ) +$( if [ ! -z ${VIASH_PAR_COLUMNS+x} ]; then echo "${VIASH_PAR_COLUMNS}" | sed "s#'#'\"'\"'#g;s#.*#par_columns='&'#" ; else echo "# par_columns="; fi ) +$( if [ ! -z ${VIASH_PAR_COLUMNS_FILE+x} ]; then echo "${VIASH_PAR_COLUMNS_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_columns_file='&'#" ; else echo "# par_columns_file="; fi ) +$( if [ ! -z ${VIASH_PAR_EXCLUDE+x} ]; then echo "${VIASH_PAR_EXCLUDE}" | sed "s#'#'\"'\"'#g;s#.*#par_exclude='&'#" ; else echo "# par_exclude="; fi ) +$( if [ ! -z ${VIASH_PAR_FORCE+x} ]; then echo "${VIASH_PAR_FORCE}" | sed "s#'#'\"'\"'#g;s#.*#par_force='&'#" ; else echo "# par_force="; fi ) +$( if [ ! -z ${VIASH_PAR_HEADER_LINE+x} ]; then echo "${VIASH_PAR_HEADER_LINE}" | sed "s#'#'\"'\"'#g;s#.*#par_header_line='&'#" ; else echo "# par_header_line="; fi ) +$( if [ ! -z ${VIASH_PAR_HEADER_LINES+x} ]; then echo "${VIASH_PAR_HEADER_LINES}" | sed "s#'#'\"'\"'#g;s#.*#par_header_lines='&'#" ; else echo "# par_header_lines="; fi ) +$( if [ ! -z ${VIASH_PAR_SET_ID+x} ]; then echo "${VIASH_PAR_SET_ID}" | sed "s#'#'\"'\"'#g;s#.*#par_set_id='&'#" ; else echo "# par_set_id="; fi ) +$( if [ ! -z ${VIASH_PAR_INCLUDE+x} ]; then echo "${VIASH_PAR_INCLUDE}" | sed "s#'#'\"'\"'#g;s#.*#par_include='&'#" ; else echo "# par_include="; fi ) +$( if [ ! -z ${VIASH_PAR_KEEP_SITES+x} ]; then echo "${VIASH_PAR_KEEP_SITES}" | sed "s#'#'\"'\"'#g;s#.*#par_keep_sites='&'#" ; else echo "# par_keep_sites="; fi ) +$( if [ ! -z ${VIASH_PAR_MERGE_LOGIC+x} ]; then echo "${VIASH_PAR_MERGE_LOGIC}" | sed "s#'#'\"'\"'#g;s#.*#par_merge_logic='&'#" ; else echo "# par_merge_logic="; fi ) +$( if [ ! -z ${VIASH_PAR_MARK_SITES+x} ]; then echo "${VIASH_PAR_MARK_SITES}" | sed "s#'#'\"'\"'#g;s#.*#par_mark_sites='&'#" ; else echo "# par_mark_sites="; fi ) +$( if [ ! -z ${VIASH_PAR_MIN_OVERLAP+x} ]; then echo "${VIASH_PAR_MIN_OVERLAP}" | sed "s#'#'\"'\"'#g;s#.*#par_min_overlap='&'#" ; else echo "# par_min_overlap="; fi ) +$( if [ ! -z ${VIASH_PAR_NO_VERSION+x} ]; then echo "${VIASH_PAR_NO_VERSION}" | sed "s#'#'\"'\"'#g;s#.*#par_no_version='&'#" ; else echo "# par_no_version="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_TYPE+x} ]; then echo "${VIASH_PAR_OUTPUT_TYPE}" | sed "s#'#'\"'\"'#g;s#.*#par_output_type='&'#" ; else echo "# par_output_type="; fi ) +$( if [ ! -z ${VIASH_PAR_PAIR_LOGIC+x} ]; then echo "${VIASH_PAR_PAIR_LOGIC}" | sed "s#'#'\"'\"'#g;s#.*#par_pair_logic='&'#" ; else echo "# par_pair_logic="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS+x} ]; then echo "${VIASH_PAR_REGIONS}" | sed "s#'#'\"'\"'#g;s#.*#par_regions='&'#" ; else echo "# par_regions="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_FILE+x} ]; then echo "${VIASH_PAR_REGIONS_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_regions_file='&'#" ; else echo "# par_regions_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_OVERLAP+x} ]; then echo "${VIASH_PAR_REGIONS_OVERLAP}" | sed "s#'#'\"'\"'#g;s#.*#par_regions_overlap='&'#" ; else echo "# par_regions_overlap="; fi ) +$( if [ ! -z ${VIASH_PAR_RENAME_ANNOTATIONS+x} ]; then echo "${VIASH_PAR_RENAME_ANNOTATIONS}" | sed "s#'#'\"'\"'#g;s#.*#par_rename_annotations='&'#" ; else echo "# par_rename_annotations="; fi ) +$( if [ ! -z ${VIASH_PAR_RENAME_CHROMOSOMES+x} ]; then echo "${VIASH_PAR_RENAME_CHROMOSOMES}" | sed "s#'#'\"'\"'#g;s#.*#par_rename_chromosomes='&'#" ; else echo "# par_rename_chromosomes="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLES+x} ]; then echo "${VIASH_PAR_SAMPLES}" | sed "s#'#'\"'\"'#g;s#.*#par_samples='&'#" ; else echo "# par_samples="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLES_FILE+x} ]; then echo "${VIASH_PAR_SAMPLES_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_samples_file='&'#" ; else echo "# par_samples_file="; fi ) +$( if [ ! -z ${VIASH_PAR_SINGLE_OVERLAPS+x} ]; then echo "${VIASH_PAR_SINGLE_OVERLAPS}" | sed "s#'#'\"'\"'#g;s#.*#par_single_overlaps='&'#" ; else echo "# par_single_overlaps="; fi ) +$( if [ ! -z ${VIASH_PAR_REMOVE+x} ]; then echo "${VIASH_PAR_REMOVE}" | sed "s#'#'\"'\"'#g;s#.*#par_remove='&'#" ; else echo "# par_remove="; 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 + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_force + par_keep_sites + par_no_version + par_single_overlaps +) + +for par in \${unset_if_false[@]}; do + test_val="\${!par}" + [[ "\$test_val" == "false" ]] && unset \$par +done + +# Execute bcftools annotate with the provided arguments +bcftools annotate \\ + \${par_annotations:+-a "\$par_annotations"} \\ + \${par_columns:+-c "\$par_columns"} \\ + \${par_columns_file:+-C "\$par_columns_file"} \\ + \${par_exclude:+-e "\$par_exclude"} \\ + \${par_force:+--force} \\ + \${par_header_line:+-H "\$par_header_line"} \\ + \${par_header_lines:+-h "\$par_header_lines"} \\ + \${par_set_id:+-I "\$par_set_id"} \\ + \${par_include:+-i "\$par_include"} \\ + \${par_keep_sites:+-k} \\ + \${par_merge_logic:+-l "\$par_merge_logic"} \\ + \${par_mark_sites:+-m "\$par_mark_sites"} \\ + \${par_min_overlap:+--min-overlap "\$par_min_overlap"} \\ + \${par_no_version:+--no-version} \\ + \${par_samples_file:+-S "\$par_samples_file"} \\ + \${par_output_type:+-O "\$par_output_type"} \\ + \${par_pair_logic:+--pair-logic "\$par_pair_logic"} \\ + \${par_regions:+-r "\$par_regions"} \\ + \${par_regions_file:+-R "\$par_regions_file"} \\ + \${par_regions_overlap:+--regions-overlap "\$par_regions_overlap"} \\ + \${par_rename_annotations:+--rename-annots "\$par_rename_annotations"} \\ + \${par_rename_chromosomes:+--rename-chrs "\$par_rename_chromosomes"} \\ + \${par_samples:+-s "\$par_samples"} \\ + \${par_single_overlaps:+--single-overlaps} \\ + \${par_threads:+--threads "\$par_threads"} \\ + \${par_remove:+-x "\$par_remove"} \\ + -o \$par_output \\ + \$par_input + + + +VIASHMAIN +bash "\$tempscript" & +wait "\$!" + +VIASHEOF + + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # strip viash automount from file paths + + if [ ! -z "$VIASH_PAR_INPUT" ]; then + unset VIASH_TEST_INPUT + IFS=';' + for var in $VIASH_PAR_INPUT; do + unset IFS + if [ -z "$VIASH_TEST_INPUT" ]; then + VIASH_TEST_INPUT="$(ViashDockerStripAutomount "$var")" + else + VIASH_TEST_INPUT="$VIASH_TEST_INPUT;""$(ViashDockerStripAutomount "$var")" + fi + done + VIASH_PAR_INPUT="$VIASH_TEST_INPUT" + fi + if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_PAR_OUTPUT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT") + fi + if [ ! -z "$VIASH_PAR_ANNOTATIONS" ]; then + VIASH_PAR_ANNOTATIONS=$(ViashDockerStripAutomount "$VIASH_PAR_ANNOTATIONS") + fi + if [ ! -z "$VIASH_PAR_COLUMNS_FILE" ]; then + VIASH_PAR_COLUMNS_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_COLUMNS_FILE") + fi + if [ ! -z "$VIASH_PAR_HEADER_LINES" ]; then + VIASH_PAR_HEADER_LINES=$(ViashDockerStripAutomount "$VIASH_PAR_HEADER_LINES") + fi + if [ ! -z "$VIASH_PAR_REGIONS_FILE" ]; then + VIASH_PAR_REGIONS_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_REGIONS_FILE") + fi + if [ ! -z "$VIASH_PAR_RENAME_ANNOTATIONS" ]; then + VIASH_PAR_RENAME_ANNOTATIONS=$(ViashDockerStripAutomount "$VIASH_PAR_RENAME_ANNOTATIONS") + fi + if [ ! -z "$VIASH_PAR_RENAME_CHROMOSOMES" ]; then + VIASH_PAR_RENAME_CHROMOSOMES=$(ViashDockerStripAutomount "$VIASH_PAR_RENAME_CHROMOSOMES") + fi + if [ ! -z "$VIASH_PAR_SAMPLES_FILE" ]; then + VIASH_PAR_SAMPLES_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_SAMPLES_FILE") + 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/bcftools/bcftools_concat/.config.vsh.yaml b/target/executable/bcftools/bcftools_concat/.config.vsh.yaml new file mode 100644 index 00000000..6284afa8 --- /dev/null +++ b/target/executable/bcftools/bcftools_concat/.config.vsh.yaml @@ -0,0 +1,361 @@ +name: "bcftools_concat" +namespace: "bcftools" +version: "add_trimgalore" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + 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 VCF/BCF files to concatenate." + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: true + multiple_sep: ";" + - type: "file" + name: "--file_list" + alternatives: + - "-f" + description: "Read the list of VCF/BCF files from a file, one file name per line." + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + description: "Output concatenated VCF/BCF file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "boolean_true" + name: "--allow_overlaps" + alternatives: + - "-a" + description: "First coordinate of the next file can precede last record of the\ + \ current file.\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--compact_PS" + alternatives: + - "-c" + description: "Do not output PS tag at each site, only at the start of a new phase\ + \ set block.\n" + info: null + direction: "input" + - type: "string" + name: "--remove_duplicates" + alternatives: + - "-d" + description: "Output duplicate records present in multiple files only once: .\n\ + \ \n" + info: null + required: false + choices: + - "snps" + - "indels" + - "both" + - "all" + - "exact" + - "none" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--ligate" + alternatives: + - "-l" + description: "Ligate phased VCFs by matching phase at overlapping haplotypes." + info: null + direction: "input" + - type: "boolean_true" + name: "--ligate_force" + description: "Ligate even non-overlapping chunks, keep all sites." + info: null + direction: "input" + - type: "boolean_true" + name: "--ligate_warn" + description: "Drop sites in imperfect overlaps." + info: null + direction: "input" + - type: "boolean_true" + name: "--no_version" + description: "Do not append version and command line information to the header." + info: null + direction: "input" + - type: "boolean_true" + name: "--naive" + alternatives: + - "-n" + description: "Concatenate files without recompression, a header check compatibility\ + \ is performed." + info: null + direction: "input" + - type: "boolean_true" + name: "--naive_force" + description: "Same as --naive, but header compatibility is not checked. \nDangerous,\ + \ use with caution.\n" + info: null + direction: "input" + - type: "string" + name: "--output_type" + alternatives: + - "-O" + description: "Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed\ + \ BCF\n v: uncompressed VCF\n" + info: null + required: false + choices: + - "u" + - "z" + - "b" + - "v" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--min_PQ" + alternatives: + - "-q" + description: "Break phase set if phasing quality is lower than ." + info: null + example: + - 30 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions" + alternatives: + - "-r" + description: "Restrict to comma-separated list of regions. \nFollowing formats\ + \ are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--regions_file" + alternatives: + - "-R" + description: "Restrict to regions listed in a file. \nRegions can be specified\ + \ either on a VCF, BED, or tab-delimited file (the default). \nFor more information\ + \ check manual.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions_overlap" + description: "This option controls how overlapping records are determined: \n\ + set to 'pos' or '0' if the VCF record has to have POS inside a region (this\ + \ corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if\ + \ also overlapping records with POS outside a region should be included (this\ + \ is the default behavior of -r/-R, \nand includes indels with POS at the end\ + \ of a region, which are technically outside the region); \nor set to 'variant'\ + \ or '2' to include only true overlapping variation (compare the full VCF representation\ + \ \"TA>T-\" vs the true sequence variation \"A>-\").\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Concatenate or combine VCF/BCF files. All source files must have the\ + \ same sample\ncolumns appearing in the same order. The program can be used, for\ + \ example, to\nconcatenate chromosome VCFs into one VCF, or combine a SNP VCF and\ + \ an indel\nVCF into one. The input files must be sorted by chr and position. The\ + \ files\nmust be given in the correct order to produce sorted VCF on output unless\n\ + the -a, --allow-overlaps option is specified. With the --naive option, the files\n\ + are concatenated without being recompressed, which is very fast.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Concatenate" +- "VCF" +- "BCF" +license: "MIT/Expat, GNU" +references: + doi: + - "https://doi.org/10.1093/gigascience/giab008" +links: + repository: "https://github.com/samtools/bcftools" + homepage: "https://samtools.github.io/bcftools/" + documentation: "https://samtools.github.io/bcftools/bcftools.html#concat" + issue_tracker: "https://github.com/samtools/bcftools/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: "add_trimgalore" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bcftools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bcftools: \\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools\ + \ //p')\\\"\" > /var/software_versions.txt\n" + test_setup: + - type: "apt" + packages: + - "tabix" + interactive: false + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bcftools/bcftools_concat/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/bcftools/bcftools_concat" + executable: "target/executable/bcftools/bcftools_concat/bcftools_concat" + viash_version: "0.9.0-RC7" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" +package_config: + name: "biobox" + version: "add_trimgalore" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0-RC7" + 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 := 'add_trimgalore'" + 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/bcftools/bcftools_concat/bcftools_concat b/target/executable/bcftools/bcftools_concat/bcftools_concat new file mode 100755 index 00000000..aaacff2d --- /dev/null +++ b/target/executable/bcftools/bcftools_concat/bcftools_concat @@ -0,0 +1,1594 @@ +#!/usr/bin/env bash + +# bcftools_concat add_trimgalore +# +# This wrapper script is auto-generated by viash 0.9.0-RC7 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) + +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="bcftools_concat" +VIASH_META_FUNCTIONALITY_NAME="bcftools_concat" +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 "bcftools_concat add_trimgalore" + echo "" + echo "Concatenate or combine VCF/BCF files. All source files must have the same sample" + echo "columns appearing in the same order. The program can be used, for example, to" + echo "concatenate chromosome VCFs into one VCF, or combine a SNP VCF and an indel" + echo "VCF into one. The input files must be sorted by chr and position. The files" + echo "must be given in the correct order to produce sorted VCF on output unless" + echo "the -a, --allow-overlaps option is specified. With the --naive option, the files" + echo "are concatenated without being recompressed, which is very fast." + echo "" + echo "Inputs:" + echo " -i, --input" + echo " type: file, multiple values allowed, file must exist" + echo " Input VCF/BCF files to concatenate." + echo "" + echo " -f, --file_list" + echo " type: file, file must exist" + echo " Read the list of VCF/BCF files from a file, one file name per line." + echo "" + echo "Outputs:" + echo " -o, --output" + echo " type: file, required parameter, output, file must exist" + echo " Output concatenated VCF/BCF file." + echo "" + echo "Options:" + echo " -a, --allow_overlaps" + echo " type: boolean_true" + echo " First coordinate of the next file can precede last record of the current" + echo " file." + echo "" + echo " -c, --compact_PS" + echo " type: boolean_true" + echo " Do not output PS tag at each site, only at the start of a new phase set" + echo " block." + echo "" + echo " -d, --remove_duplicates" + echo " type: string" + echo " choices: [ snps, indels, both, all, exact, none ]" + echo " Output duplicate records present in multiple files only once:" + echo " ." + echo "" + echo " -l, --ligate" + echo " type: boolean_true" + echo " Ligate phased VCFs by matching phase at overlapping haplotypes." + echo "" + echo " --ligate_force" + echo " type: boolean_true" + echo " Ligate even non-overlapping chunks, keep all sites." + echo "" + echo " --ligate_warn" + echo " type: boolean_true" + echo " Drop sites in imperfect overlaps." + echo "" + echo " --no_version" + echo " type: boolean_true" + echo " Do not append version and command line information to the header." + echo "" + echo " -n, --naive" + echo " type: boolean_true" + echo " Concatenate files without recompression, a header check compatibility is" + echo " performed." + echo "" + echo " --naive_force" + echo " type: boolean_true" + echo " Same as --naive, but header compatibility is not checked." + echo " Dangerous, use with caution." + echo "" + echo " -O, --output_type" + echo " type: string" + echo " choices: [ u, z, b, v ]" + echo " Output type:" + echo " u: uncompressed BCF" + echo " z: compressed VCF" + echo " b: compressed BCF" + echo " v: uncompressed VCF" + echo "" + echo " -q, --min_PQ" + echo " type: integer" + echo " example: 30" + echo " Break phase set if phasing quality is lower than ." + echo "" + echo " -r, --regions" + echo " type: string" + echo " example: 20:1000000-2000000" + echo " Restrict to comma-separated list of regions." + echo " Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]." + echo "" + echo " -R, --regions_file" + echo " type: file, file must exist" + echo " Restrict to regions listed in a file." + echo " Regions can be specified either on a VCF, BED, or tab-delimited file" + echo " (the default)." + echo " For more information check manual." + echo "" + echo " --regions_overlap" + echo " type: string" + echo " choices: [ pos, record, variant, 0, 1, 2 ]" + echo " This option controls how overlapping records are determined:" + echo " set to 'pos' or '0' if the VCF record has to have POS inside a region" + echo " (this corresponds to the default behavior of -t/-T);" + echo " set to 'record' or '1' if also overlapping records with POS outside a" + echo " region should be included (this is the default behavior of -r/-R," + echo " and includes indels with POS at the end of a region, which are" + echo " technically outside the region);" + echo " or set to 'variant' or '2' to include only true overlapping variation" + echo " (compare the full VCF representation \"TA>T-\" vs the true sequence" + echo " variation \"A>-\")." +} + +# 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 bcftools procps && \ + rm -rf /var/lib/apt/lists/* + +RUN echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\"" > /var/software_versions.txt + +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-09-19T08:35:58Z" +LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" +LABEL org.opencontainers.image.version="add_trimgalore" + +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 "bcftools_concat add_trimgalore" + exit + ;; + --input) + if [ -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT="$2" + else + VIASH_PAR_INPUT="$VIASH_PAR_INPUT;""$2" + fi + [ $# -lt 2 ] && ViashError Not enough arguments passed to --input. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --input=*) + if [ -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT=$(ViashRemoveFlags "$1") + else + VIASH_PAR_INPUT="$VIASH_PAR_INPUT;"$(ViashRemoveFlags "$1") + fi + shift 1 + ;; + -i) + if [ -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT="$2" + else + VIASH_PAR_INPUT="$VIASH_PAR_INPUT;""$2" + fi + [ $# -lt 2 ] && ViashError Not enough arguments passed to -i. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --file_list) + [ -n "$VIASH_PAR_FILE_LIST" ] && ViashError Bad arguments for option \'--file_list\': \'$VIASH_PAR_FILE_LIST\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FILE_LIST="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --file_list. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --file_list=*) + [ -n "$VIASH_PAR_FILE_LIST" ] && ViashError Bad arguments for option \'--file_list=*\': \'$VIASH_PAR_FILE_LIST\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FILE_LIST=$(ViashRemoveFlags "$1") + shift 1 + ;; + -f) + [ -n "$VIASH_PAR_FILE_LIST" ] && ViashError Bad arguments for option \'-f\': \'$VIASH_PAR_FILE_LIST\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FILE_LIST="$2" + [ $# -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 + ;; + --allow_overlaps) + [ -n "$VIASH_PAR_ALLOW_OVERLAPS" ] && ViashError Bad arguments for option \'--allow_overlaps\': \'$VIASH_PAR_ALLOW_OVERLAPS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLOW_OVERLAPS=true + shift 1 + ;; + -a) + [ -n "$VIASH_PAR_ALLOW_OVERLAPS" ] && ViashError Bad arguments for option \'-a\': \'$VIASH_PAR_ALLOW_OVERLAPS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLOW_OVERLAPS=true + shift 1 + ;; + --compact_PS) + [ -n "$VIASH_PAR_COMPACT_PS" ] && ViashError Bad arguments for option \'--compact_PS\': \'$VIASH_PAR_COMPACT_PS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COMPACT_PS=true + shift 1 + ;; + -c) + [ -n "$VIASH_PAR_COMPACT_PS" ] && ViashError Bad arguments for option \'-c\': \'$VIASH_PAR_COMPACT_PS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COMPACT_PS=true + shift 1 + ;; + --remove_duplicates) + [ -n "$VIASH_PAR_REMOVE_DUPLICATES" ] && ViashError Bad arguments for option \'--remove_duplicates\': \'$VIASH_PAR_REMOVE_DUPLICATES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REMOVE_DUPLICATES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --remove_duplicates. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --remove_duplicates=*) + [ -n "$VIASH_PAR_REMOVE_DUPLICATES" ] && ViashError Bad arguments for option \'--remove_duplicates=*\': \'$VIASH_PAR_REMOVE_DUPLICATES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REMOVE_DUPLICATES=$(ViashRemoveFlags "$1") + shift 1 + ;; + -d) + [ -n "$VIASH_PAR_REMOVE_DUPLICATES" ] && ViashError Bad arguments for option \'-d\': \'$VIASH_PAR_REMOVE_DUPLICATES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REMOVE_DUPLICATES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -d. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --ligate) + [ -n "$VIASH_PAR_LIGATE" ] && ViashError Bad arguments for option \'--ligate\': \'$VIASH_PAR_LIGATE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_LIGATE=true + shift 1 + ;; + -l) + [ -n "$VIASH_PAR_LIGATE" ] && ViashError Bad arguments for option \'-l\': \'$VIASH_PAR_LIGATE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_LIGATE=true + shift 1 + ;; + --ligate_force) + [ -n "$VIASH_PAR_LIGATE_FORCE" ] && ViashError Bad arguments for option \'--ligate_force\': \'$VIASH_PAR_LIGATE_FORCE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_LIGATE_FORCE=true + shift 1 + ;; + --ligate_warn) + [ -n "$VIASH_PAR_LIGATE_WARN" ] && ViashError Bad arguments for option \'--ligate_warn\': \'$VIASH_PAR_LIGATE_WARN\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_LIGATE_WARN=true + shift 1 + ;; + --no_version) + [ -n "$VIASH_PAR_NO_VERSION" ] && ViashError Bad arguments for option \'--no_version\': \'$VIASH_PAR_NO_VERSION\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_NO_VERSION=true + shift 1 + ;; + --naive) + [ -n "$VIASH_PAR_NAIVE" ] && ViashError Bad arguments for option \'--naive\': \'$VIASH_PAR_NAIVE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_NAIVE=true + shift 1 + ;; + -n) + [ -n "$VIASH_PAR_NAIVE" ] && ViashError Bad arguments for option \'-n\': \'$VIASH_PAR_NAIVE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_NAIVE=true + shift 1 + ;; + --naive_force) + [ -n "$VIASH_PAR_NAIVE_FORCE" ] && ViashError Bad arguments for option \'--naive_force\': \'$VIASH_PAR_NAIVE_FORCE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_NAIVE_FORCE=true + shift 1 + ;; + --output_type) + [ -n "$VIASH_PAR_OUTPUT_TYPE" ] && ViashError Bad arguments for option \'--output_type\': \'$VIASH_PAR_OUTPUT_TYPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_TYPE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_type. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_type=*) + [ -n "$VIASH_PAR_OUTPUT_TYPE" ] && ViashError Bad arguments for option \'--output_type=*\': \'$VIASH_PAR_OUTPUT_TYPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_TYPE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -O) + [ -n "$VIASH_PAR_OUTPUT_TYPE" ] && ViashError Bad arguments for option \'-O\': \'$VIASH_PAR_OUTPUT_TYPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_TYPE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -O. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --min_PQ) + [ -n "$VIASH_PAR_MIN_PQ" ] && ViashError Bad arguments for option \'--min_PQ\': \'$VIASH_PAR_MIN_PQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MIN_PQ="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --min_PQ. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --min_PQ=*) + [ -n "$VIASH_PAR_MIN_PQ" ] && ViashError Bad arguments for option \'--min_PQ=*\': \'$VIASH_PAR_MIN_PQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MIN_PQ=$(ViashRemoveFlags "$1") + shift 1 + ;; + -q) + [ -n "$VIASH_PAR_MIN_PQ" ] && ViashError Bad arguments for option \'-q\': \'$VIASH_PAR_MIN_PQ\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MIN_PQ="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -q. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--regions\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions=*) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--regions=*\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS=$(ViashRemoveFlags "$1") + shift 1 + ;; + -r) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'-r\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -r. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_file) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--regions_file\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_file=*) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--regions_file=*\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -R) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'-R\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -R. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_overlap) + [ -n "$VIASH_PAR_REGIONS_OVERLAP" ] && ViashError Bad arguments for option \'--regions_overlap\': \'$VIASH_PAR_REGIONS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_OVERLAP="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions_overlap. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_overlap=*) + [ -n "$VIASH_PAR_REGIONS_OVERLAP" ] && ViashError Bad arguments for option \'--regions_overlap=*\': \'$VIASH_PAR_REGIONS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_OVERLAP=$(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/bcftools/bcftools_concat:add_trimgalore' + 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_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_ALLOW_OVERLAPS+x} ]; then + VIASH_PAR_ALLOW_OVERLAPS="false" +fi +if [ -z ${VIASH_PAR_COMPACT_PS+x} ]; then + VIASH_PAR_COMPACT_PS="false" +fi +if [ -z ${VIASH_PAR_LIGATE+x} ]; then + VIASH_PAR_LIGATE="false" +fi +if [ -z ${VIASH_PAR_LIGATE_FORCE+x} ]; then + VIASH_PAR_LIGATE_FORCE="false" +fi +if [ -z ${VIASH_PAR_LIGATE_WARN+x} ]; then + VIASH_PAR_LIGATE_WARN="false" +fi +if [ -z ${VIASH_PAR_NO_VERSION+x} ]; then + VIASH_PAR_NO_VERSION="false" +fi +if [ -z ${VIASH_PAR_NAIVE+x} ]; then + VIASH_PAR_NAIVE="false" +fi +if [ -z ${VIASH_PAR_NAIVE_FORCE+x} ]; then + VIASH_PAR_NAIVE_FORCE="false" +fi + +# check whether required files exist +if [ ! -z "$VIASH_PAR_INPUT" ]; then + IFS=';' + set -f + for file in $VIASH_PAR_INPUT; 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_FILE_LIST" ] && [ ! -e "$VIASH_PAR_FILE_LIST" ]; then + ViashError "Input file '$VIASH_PAR_FILE_LIST' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_REGIONS_FILE" ] && [ ! -e "$VIASH_PAR_REGIONS_FILE" ]; then + ViashError "Input file '$VIASH_PAR_REGIONS_FILE' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_PAR_ALLOW_OVERLAPS" ]]; then + if ! [[ "$VIASH_PAR_ALLOW_OVERLAPS" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--allow_overlaps' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_COMPACT_PS" ]]; then + if ! [[ "$VIASH_PAR_COMPACT_PS" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--compact_PS' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_LIGATE" ]]; then + if ! [[ "$VIASH_PAR_LIGATE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--ligate' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_LIGATE_FORCE" ]]; then + if ! [[ "$VIASH_PAR_LIGATE_FORCE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--ligate_force' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_LIGATE_WARN" ]]; then + if ! [[ "$VIASH_PAR_LIGATE_WARN" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--ligate_warn' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_NO_VERSION" ]]; then + if ! [[ "$VIASH_PAR_NO_VERSION" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--no_version' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_NAIVE" ]]; then + if ! [[ "$VIASH_PAR_NAIVE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--naive' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_NAIVE_FORCE" ]]; then + if ! [[ "$VIASH_PAR_NAIVE_FORCE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--naive_force' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_MIN_PQ" ]]; then + if ! [[ "$VIASH_PAR_MIN_PQ" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--min_PQ' 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 + +# check whether value is belongs to a set of choices +if [ ! -z "$VIASH_PAR_REMOVE_DUPLICATES" ]; then + VIASH_PAR_REMOVE_DUPLICATES_CHOICES=("snps;indels;both;all;exact;none") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_REMOVE_DUPLICATES_CHOICES[*]};" =~ ";$VIASH_PAR_REMOVE_DUPLICATES;" ]]; then + ViashError '--remove_duplicates' specified value of \'$VIASH_PAR_REMOVE_DUPLICATES\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_OUTPUT_TYPE" ]; then + VIASH_PAR_OUTPUT_TYPE_CHOICES=("u;z;b;v") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_OUTPUT_TYPE_CHOICES[*]};" =~ ";$VIASH_PAR_OUTPUT_TYPE;" ]]; then + ViashError '--output_type' specified value of \'$VIASH_PAR_OUTPUT_TYPE\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_REGIONS_OVERLAP" ]; then + VIASH_PAR_REGIONS_OVERLAP_CHOICES=("pos;record;variant;0;1;2") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_REGIONS_OVERLAP_CHOICES[*]};" =~ ";$VIASH_PAR_REGIONS_OVERLAP;" ]]; then + ViashError '--regions_overlap' specified value of \'$VIASH_PAR_REGIONS_OVERLAP\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +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_TEST_INPUT=() + IFS=';' + for var in $VIASH_PAR_INPUT; do + unset IFS + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$var")" ) + var=$(ViashDockerAutodetectMount "$var") + VIASH_TEST_INPUT+=( "$var" ) + done + VIASH_PAR_INPUT=$(IFS=';' ; echo "${VIASH_TEST_INPUT[*]}") +fi +if [ ! -z "$VIASH_PAR_FILE_LIST" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_FILE_LIST")" ) + VIASH_PAR_FILE_LIST=$(ViashDockerAutodetectMount "$VIASH_PAR_FILE_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_REGIONS_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_REGIONS_FILE")" ) + VIASH_PAR_REGIONS_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_REGIONS_FILE") +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-bcftools_concat-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_FILE_LIST+x} ]; then echo "${VIASH_PAR_FILE_LIST}" | sed "s#'#'\"'\"'#g;s#.*#par_file_list='&'#" ; else echo "# par_file_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_ALLOW_OVERLAPS+x} ]; then echo "${VIASH_PAR_ALLOW_OVERLAPS}" | sed "s#'#'\"'\"'#g;s#.*#par_allow_overlaps='&'#" ; else echo "# par_allow_overlaps="; fi ) +$( if [ ! -z ${VIASH_PAR_COMPACT_PS+x} ]; then echo "${VIASH_PAR_COMPACT_PS}" | sed "s#'#'\"'\"'#g;s#.*#par_compact_PS='&'#" ; else echo "# par_compact_PS="; fi ) +$( if [ ! -z ${VIASH_PAR_REMOVE_DUPLICATES+x} ]; then echo "${VIASH_PAR_REMOVE_DUPLICATES}" | sed "s#'#'\"'\"'#g;s#.*#par_remove_duplicates='&'#" ; else echo "# par_remove_duplicates="; fi ) +$( if [ ! -z ${VIASH_PAR_LIGATE+x} ]; then echo "${VIASH_PAR_LIGATE}" | sed "s#'#'\"'\"'#g;s#.*#par_ligate='&'#" ; else echo "# par_ligate="; fi ) +$( if [ ! -z ${VIASH_PAR_LIGATE_FORCE+x} ]; then echo "${VIASH_PAR_LIGATE_FORCE}" | sed "s#'#'\"'\"'#g;s#.*#par_ligate_force='&'#" ; else echo "# par_ligate_force="; fi ) +$( if [ ! -z ${VIASH_PAR_LIGATE_WARN+x} ]; then echo "${VIASH_PAR_LIGATE_WARN}" | sed "s#'#'\"'\"'#g;s#.*#par_ligate_warn='&'#" ; else echo "# par_ligate_warn="; fi ) +$( if [ ! -z ${VIASH_PAR_NO_VERSION+x} ]; then echo "${VIASH_PAR_NO_VERSION}" | sed "s#'#'\"'\"'#g;s#.*#par_no_version='&'#" ; else echo "# par_no_version="; fi ) +$( if [ ! -z ${VIASH_PAR_NAIVE+x} ]; then echo "${VIASH_PAR_NAIVE}" | sed "s#'#'\"'\"'#g;s#.*#par_naive='&'#" ; else echo "# par_naive="; fi ) +$( if [ ! -z ${VIASH_PAR_NAIVE_FORCE+x} ]; then echo "${VIASH_PAR_NAIVE_FORCE}" | sed "s#'#'\"'\"'#g;s#.*#par_naive_force='&'#" ; else echo "# par_naive_force="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_TYPE+x} ]; then echo "${VIASH_PAR_OUTPUT_TYPE}" | sed "s#'#'\"'\"'#g;s#.*#par_output_type='&'#" ; else echo "# par_output_type="; fi ) +$( if [ ! -z ${VIASH_PAR_MIN_PQ+x} ]; then echo "${VIASH_PAR_MIN_PQ}" | sed "s#'#'\"'\"'#g;s#.*#par_min_PQ='&'#" ; else echo "# par_min_PQ="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS+x} ]; then echo "${VIASH_PAR_REGIONS}" | sed "s#'#'\"'\"'#g;s#.*#par_regions='&'#" ; else echo "# par_regions="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_FILE+x} ]; then echo "${VIASH_PAR_REGIONS_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_regions_file='&'#" ; else echo "# par_regions_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_OVERLAP+x} ]; then echo "${VIASH_PAR_REGIONS_OVERLAP}" | sed "s#'#'\"'\"'#g;s#.*#par_regions_overlap='&'#" ; else echo "# par_regions_overlap="; 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 + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_allow_overlaps + par_compact_PS + par_ligate + par_ligate_force + par_ligate_warn + par_no_version + par_naive + par_naive_force +) + +for par in \${unset_if_false[@]}; do + test_val="\${!par}" + [[ "\$test_val" == "false" ]] && unset \$par +done + +# Check to see whether the par_input or the par_file_list is set +if [[ -z "\${par_input}" && -z "\${par_file_list}" ]]; then + echo "Error: One of the parameters '--input' or '--file_list' must be used." + exit 1 +fi + +# Create input array +IFS=";" read -ra input <<< \$par_input + +# Execute bcftools concat with the provided arguments +bcftools concat \\ + \${par_allow_overlaps:+-a} \\ + \${par_compact_PS:+-c} \\ + \${par_remove_duplicates:+-d "\$par_remove_duplicates"} \\ + \${par_ligate:+-l} \\ + \${par_ligate_force:+--ligate-force} \\ + \${par_ligate_warn:+--ligate-warn} \\ + \${par_no_version:+--no-version} \\ + \${par_naive:+-n} \\ + \${par_naive_force:+--naive-force} \\ + \${par_output_type:+--O "\$par_output_type"} \\ + \${par_min_PQ:+-q "\$par_min_PQ"} \\ + \${par_regions:+-r "\$par_regions"} \\ + \${par_regions_file:+-R "\$par_regions_file"} \\ + \${par_regions_overlap:+--regions-overlap "\$par_regions_overlap"} \\ + \${meta_cpus:+--threads "\$meta_cpus"} \\ + -o \$par_output \\ + \${par_file_list:+-f "\$par_file_list"} \\ + \${input[@]} \\ +VIASHMAIN +bash "\$tempscript" & +wait "\$!" + +VIASHEOF + + +if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then + # strip viash automount from file paths + + if [ ! -z "$VIASH_PAR_INPUT" ]; then + unset VIASH_TEST_INPUT + IFS=';' + for var in $VIASH_PAR_INPUT; do + unset IFS + if [ -z "$VIASH_TEST_INPUT" ]; then + VIASH_TEST_INPUT="$(ViashDockerStripAutomount "$var")" + else + VIASH_TEST_INPUT="$VIASH_TEST_INPUT;""$(ViashDockerStripAutomount "$var")" + fi + done + VIASH_PAR_INPUT="$VIASH_TEST_INPUT" + fi + if [ ! -z "$VIASH_PAR_FILE_LIST" ]; then + VIASH_PAR_FILE_LIST=$(ViashDockerStripAutomount "$VIASH_PAR_FILE_LIST") + fi + if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_PAR_OUTPUT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT") + fi + if [ ! -z "$VIASH_PAR_REGIONS_FILE" ]; then + VIASH_PAR_REGIONS_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_REGIONS_FILE") + 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/bcftools/bcftools_norm/.config.vsh.yaml b/target/executable/bcftools/bcftools_norm/.config.vsh.yaml new file mode 100644 index 00000000..341b8af1 --- /dev/null +++ b/target/executable/bcftools/bcftools_norm/.config.vsh.yaml @@ -0,0 +1,442 @@ +name: "bcftools_norm" +namespace: "bcftools" +version: "add_trimgalore" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + 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 VCF/BCF 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 normalized VCF/BCF file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "boolean_true" + name: "--atomize" + alternatives: + - "-a" + description: "Decompose complex variants (e.g., MNVs become consecutive SNVs).\n" + info: null + direction: "input" + - type: "string" + name: "--atom_overlaps" + description: "Use the star allele (*) for overlapping alleles or set to missing\ + \ (.).\n" + info: null + required: false + choices: + - "." + - "*" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--check_ref" + alternatives: + - "-c" + description: "Check REF alleles and exit (e), warn (w), exclude (x), or set (s)\ + \ bad sites.\n" + info: null + required: false + choices: + - "e" + - "w" + - "x" + - "s" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--remove_duplicates" + alternatives: + - "-d" + description: "Remove duplicate snps, indels, both, all, exact matches, or none\ + \ (old -D option)." + info: null + required: false + choices: + - "snps" + - "indels" + - "both" + - "all" + - "exact" + - "none" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fasta_ref" + alternatives: + - "-f" + description: "Reference fasta sequence file." + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--force" + description: "Try to proceed even if malformed tags are encountered. \nExperimental,\ + \ use at your own risk.\n" + info: null + direction: "input" + - type: "string" + name: "--keep_sum" + description: "Keep vector sum constant when splitting multiallelics (see github\ + \ issue #360).\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--multiallelics" + alternatives: + - "-m" + description: "Split multiallelics (-) or join biallelics (+), type: snps, indels,\ + \ both, any [default: both].\n" + info: null + required: false + choices: + - "+snps" + - "+indels" + - "+both" + - "+any" + - "-snps" + - "-indels" + - "-both" + - "-any" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--no_version" + description: "Do not append version and command line information to the header." + info: null + direction: "input" + - type: "boolean_true" + name: "--do_not_normalize" + alternatives: + - "-N" + description: "Do not normalize indels (with -m or -c s)." + info: null + direction: "input" + - type: "string" + name: "--output_type" + alternatives: + - "--O" + description: "Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed\ + \ BCF\n v: uncompressed VCF\n" + info: null + required: false + choices: + - "u" + - "z" + - "b" + - "v" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--old_rec_tag" + description: "Annotate modified records with INFO/STR indicating the original\ + \ variant." + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions" + alternatives: + - "--r" + description: "Restrict to comma-separated list of regions. \nFollowing formats\ + \ are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--regions_file" + alternatives: + - "--R" + description: "Restrict to regions listed in a file. \nRegions can be specified\ + \ either on a VCF, BED, or tab-delimited file (the default). \nFor more information\ + \ check manual.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions_overlap" + description: "This option controls how overlapping records are determined: \n\ + set to 'pos' or '0' if the VCF record has to have POS inside a region (this\ + \ corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if\ + \ also overlapping records with POS outside a region should be included (this\ + \ is the default behavior of -r/-R, \nand includes indels with POS at the end\ + \ of a region, which are technically outside the region); \nor set to 'variant'\ + \ or '2' to include only true overlapping variation (compare the full VCF representation\ + \ \"TA>T-\" vs the true sequence variation \"A>-\").\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--site_win" + alternatives: + - "-w" + description: "Buffer for sorting lines that changed position during realignment.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--strict_filter" + alternatives: + - "-s" + description: "When merging (-m+), merged site is PASS only if all sites being\ + \ merged PASS." + info: null + direction: "input" + - type: "string" + name: "--targets" + alternatives: + - "-t" + description: "Similar to --regions but streams rather than index-jumps." + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--targets_file" + alternatives: + - "-T" + description: "Similar to --regions_file but streams rather than index-jumps." + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--targets_overlap" + description: "Include if POS in the region (0), record overlaps (1), variant overlaps\ + \ (2).\nSimilar to --regions_overlap.\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Left-align and normalize indels, check if REF alleles match the reference,\ + \ split multiallelic sites into multiple rows; \nrecover multiallelics from multiple\ + \ rows. \n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Normalize" +- "VCF" +- "BCF" +license: "MIT/Expat, GNU" +references: + doi: + - "https://doi.org/10.1093/gigascience/giab008" +links: + repository: "https://github.com/samtools/bcftools" + homepage: "https://samtools.github.io/bcftools/" + documentation: "https://samtools.github.io/bcftools/bcftools.html#norm" + issue_tracker: "https://github.com/samtools/bcftools/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: "add_trimgalore" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bcftools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bcftools: \\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools\ + \ //p')\\\"\" > /var/software_versions.txt\n" + test_setup: + - type: "apt" + packages: + - "tabix" + interactive: false + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bcftools/bcftools_norm/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/bcftools/bcftools_norm" + executable: "target/executable/bcftools/bcftools_norm/bcftools_norm" + viash_version: "0.9.0-RC7" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" +package_config: + name: "biobox" + version: "add_trimgalore" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0-RC7" + 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 := 'add_trimgalore'" + 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/bcftools/bcftools_norm/bcftools_norm b/target/executable/bcftools/bcftools_norm/bcftools_norm new file mode 100755 index 00000000..85a31a0d --- /dev/null +++ b/target/executable/bcftools/bcftools_norm/bcftools_norm @@ -0,0 +1,1711 @@ +#!/usr/bin/env bash + +# bcftools_norm add_trimgalore +# +# This wrapper script is auto-generated by viash 0.9.0-RC7 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) + +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="bcftools_norm" +VIASH_META_FUNCTIONALITY_NAME="bcftools_norm" +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 "bcftools_norm add_trimgalore" + echo "" + echo "Left-align and normalize indels, check if REF alleles match the reference, split" + echo "multiallelic sites into multiple rows;" + echo "recover multiallelics from multiple rows." + echo "" + echo "Inputs:" + echo " -i, --input" + echo " type: file, required parameter, file must exist" + echo " Input VCF/BCF file." + echo "" + echo "Outputs:" + echo " -o, --output" + echo " type: file, required parameter, output, file must exist" + echo " Output normalized VCF/BCF file." + echo "" + echo "Options:" + echo " -a, --atomize" + echo " type: boolean_true" + echo " Decompose complex variants (e.g., MNVs become consecutive SNVs)." + echo "" + echo " --atom_overlaps" + echo " type: string" + echo " choices: [ ., * ]" + echo " Use the star allele (*) for overlapping alleles or set to missing (.)." + echo "" + echo " -c, --check_ref" + echo " type: string" + echo " choices: [ e, w, x, s ]" + echo " Check REF alleles and exit (e), warn (w), exclude (x), or set (s) bad" + echo " sites." + echo "" + echo " -d, --remove_duplicates" + echo " type: string" + echo " choices: [ snps, indels, both, all, exact, none ]" + echo " Remove duplicate snps, indels, both, all, exact matches, or none (old -D" + echo " option)." + echo "" + echo " -f, --fasta_ref" + echo " type: file, file must exist" + echo " Reference fasta sequence file." + echo "" + echo " --force" + echo " type: boolean_true" + echo " Try to proceed even if malformed tags are encountered." + echo " Experimental, use at your own risk." + echo "" + echo " --keep_sum" + echo " type: string" + echo " Keep vector sum constant when splitting multiallelics (see github issue" + echo " #360)." + echo "" + echo " -m, --multiallelics" + echo " type: string" + echo " choices: [ +snps, +indels, +both, +any, -snps, -indels, -both, -any ]" + echo " Split multiallelics (-) or join biallelics (+), type: snps, indels," + echo " both, any [default: both]." + echo "" + echo " --no_version" + echo " type: boolean_true" + echo " Do not append version and command line information to the header." + echo "" + echo " -N, --do_not_normalize" + echo " type: boolean_true" + echo " Do not normalize indels (with -m or -c s)." + echo "" + echo " --O, --output_type" + echo " type: string" + echo " choices: [ u, z, b, v ]" + echo " Output type:" + echo " u: uncompressed BCF" + echo " z: compressed VCF" + echo " b: compressed BCF" + echo " v: uncompressed VCF" + echo "" + echo " --old_rec_tag" + echo " type: string" + echo " Annotate modified records with INFO/STR indicating the original variant." + echo "" + echo " --r, --regions" + echo " type: string" + echo " example: 20:1000000-2000000" + echo " Restrict to comma-separated list of regions." + echo " Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]." + echo "" + echo " --R, --regions_file" + echo " type: file, file must exist" + echo " Restrict to regions listed in a file." + echo " Regions can be specified either on a VCF, BED, or tab-delimited file" + echo " (the default)." + echo " For more information check manual." + echo "" + echo " --regions_overlap" + echo " type: string" + echo " choices: [ pos, record, variant, 0, 1, 2 ]" + echo " This option controls how overlapping records are determined:" + echo " set to 'pos' or '0' if the VCF record has to have POS inside a region" + echo " (this corresponds to the default behavior of -t/-T);" + echo " set to 'record' or '1' if also overlapping records with POS outside a" + echo " region should be included (this is the default behavior of -r/-R," + echo " and includes indels with POS at the end of a region, which are" + echo " technically outside the region);" + echo " or set to 'variant' or '2' to include only true overlapping variation" + echo " (compare the full VCF representation \"TA>T-\" vs the true sequence" + echo " variation \"A>-\")." + echo "" + echo " -w, --site_win" + echo " type: integer" + echo " Buffer for sorting lines that changed position during realignment." + echo "" + echo " -s, --strict_filter" + echo " type: boolean_true" + echo " When merging (-m+), merged site is PASS only if all sites being merged" + echo " PASS." + echo "" + echo " -t, --targets" + echo " type: string" + echo " example: 20:1000000-2000000" + echo " Similar to --regions but streams rather than index-jumps." + echo "" + echo " -T, --targets_file" + echo " type: file, file must exist" + echo " Similar to --regions_file but streams rather than index-jumps." + echo "" + echo " --targets_overlap" + echo " type: string" + echo " choices: [ pos, record, variant, 0, 1, 2 ]" + echo " Include if POS in the region (0), record overlaps (1), variant overlaps" + echo " (2)." + echo " Similar to --regions_overlap." +} + +# 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 bcftools procps && \ + rm -rf /var/lib/apt/lists/* + +RUN echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\"" > /var/software_versions.txt + +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-09-19T08:35:59Z" +LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" +LABEL org.opencontainers.image.version="add_trimgalore" + +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 "bcftools_norm add_trimgalore" + 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 + ;; + --atomize) + [ -n "$VIASH_PAR_ATOMIZE" ] && ViashError Bad arguments for option \'--atomize\': \'$VIASH_PAR_ATOMIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ATOMIZE=true + shift 1 + ;; + -a) + [ -n "$VIASH_PAR_ATOMIZE" ] && ViashError Bad arguments for option \'-a\': \'$VIASH_PAR_ATOMIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ATOMIZE=true + shift 1 + ;; + --atom_overlaps) + [ -n "$VIASH_PAR_ATOM_OVERLAPS" ] && ViashError Bad arguments for option \'--atom_overlaps\': \'$VIASH_PAR_ATOM_OVERLAPS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ATOM_OVERLAPS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --atom_overlaps. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --atom_overlaps=*) + [ -n "$VIASH_PAR_ATOM_OVERLAPS" ] && ViashError Bad arguments for option \'--atom_overlaps=*\': \'$VIASH_PAR_ATOM_OVERLAPS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ATOM_OVERLAPS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --check_ref) + [ -n "$VIASH_PAR_CHECK_REF" ] && ViashError Bad arguments for option \'--check_ref\': \'$VIASH_PAR_CHECK_REF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CHECK_REF="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --check_ref. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --check_ref=*) + [ -n "$VIASH_PAR_CHECK_REF" ] && ViashError Bad arguments for option \'--check_ref=*\': \'$VIASH_PAR_CHECK_REF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CHECK_REF=$(ViashRemoveFlags "$1") + shift 1 + ;; + -c) + [ -n "$VIASH_PAR_CHECK_REF" ] && ViashError Bad arguments for option \'-c\': \'$VIASH_PAR_CHECK_REF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_CHECK_REF="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -c. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --remove_duplicates) + [ -n "$VIASH_PAR_REMOVE_DUPLICATES" ] && ViashError Bad arguments for option \'--remove_duplicates\': \'$VIASH_PAR_REMOVE_DUPLICATES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REMOVE_DUPLICATES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --remove_duplicates. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --remove_duplicates=*) + [ -n "$VIASH_PAR_REMOVE_DUPLICATES" ] && ViashError Bad arguments for option \'--remove_duplicates=*\': \'$VIASH_PAR_REMOVE_DUPLICATES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REMOVE_DUPLICATES=$(ViashRemoveFlags "$1") + shift 1 + ;; + -d) + [ -n "$VIASH_PAR_REMOVE_DUPLICATES" ] && ViashError Bad arguments for option \'-d\': \'$VIASH_PAR_REMOVE_DUPLICATES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REMOVE_DUPLICATES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -d. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --fasta_ref) + [ -n "$VIASH_PAR_FASTA_REF" ] && ViashError Bad arguments for option \'--fasta_ref\': \'$VIASH_PAR_FASTA_REF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTA_REF="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --fasta_ref. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --fasta_ref=*) + [ -n "$VIASH_PAR_FASTA_REF" ] && ViashError Bad arguments for option \'--fasta_ref=*\': \'$VIASH_PAR_FASTA_REF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTA_REF=$(ViashRemoveFlags "$1") + shift 1 + ;; + -f) + [ -n "$VIASH_PAR_FASTA_REF" ] && ViashError Bad arguments for option \'-f\': \'$VIASH_PAR_FASTA_REF\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTA_REF="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -f. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --force) + [ -n "$VIASH_PAR_FORCE" ] && ViashError Bad arguments for option \'--force\': \'$VIASH_PAR_FORCE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FORCE=true + shift 1 + ;; + --keep_sum) + [ -n "$VIASH_PAR_KEEP_SUM" ] && ViashError Bad arguments for option \'--keep_sum\': \'$VIASH_PAR_KEEP_SUM\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_KEEP_SUM="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --keep_sum. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --keep_sum=*) + [ -n "$VIASH_PAR_KEEP_SUM" ] && ViashError Bad arguments for option \'--keep_sum=*\': \'$VIASH_PAR_KEEP_SUM\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_KEEP_SUM=$(ViashRemoveFlags "$1") + shift 1 + ;; + --multiallelics) + [ -n "$VIASH_PAR_MULTIALLELICS" ] && ViashError Bad arguments for option \'--multiallelics\': \'$VIASH_PAR_MULTIALLELICS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MULTIALLELICS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --multiallelics. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --multiallelics=*) + [ -n "$VIASH_PAR_MULTIALLELICS" ] && ViashError Bad arguments for option \'--multiallelics=*\': \'$VIASH_PAR_MULTIALLELICS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MULTIALLELICS=$(ViashRemoveFlags "$1") + shift 1 + ;; + -m) + [ -n "$VIASH_PAR_MULTIALLELICS" ] && ViashError Bad arguments for option \'-m\': \'$VIASH_PAR_MULTIALLELICS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_MULTIALLELICS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -m. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --no_version) + [ -n "$VIASH_PAR_NO_VERSION" ] && ViashError Bad arguments for option \'--no_version\': \'$VIASH_PAR_NO_VERSION\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_NO_VERSION=true + shift 1 + ;; + --do_not_normalize) + [ -n "$VIASH_PAR_DO_NOT_NORMALIZE" ] && ViashError Bad arguments for option \'--do_not_normalize\': \'$VIASH_PAR_DO_NOT_NORMALIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_DO_NOT_NORMALIZE=true + shift 1 + ;; + -N) + [ -n "$VIASH_PAR_DO_NOT_NORMALIZE" ] && ViashError Bad arguments for option \'-N\': \'$VIASH_PAR_DO_NOT_NORMALIZE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_DO_NOT_NORMALIZE=true + shift 1 + ;; + --output_type) + [ -n "$VIASH_PAR_OUTPUT_TYPE" ] && ViashError Bad arguments for option \'--output_type\': \'$VIASH_PAR_OUTPUT_TYPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_TYPE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_type. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --output_type=*) + [ -n "$VIASH_PAR_OUTPUT_TYPE" ] && ViashError Bad arguments for option \'--output_type=*\': \'$VIASH_PAR_OUTPUT_TYPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_TYPE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --O) + [ -n "$VIASH_PAR_OUTPUT_TYPE" ] && ViashError Bad arguments for option \'--O\': \'$VIASH_PAR_OUTPUT_TYPE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OUTPUT_TYPE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --O. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --old_rec_tag) + [ -n "$VIASH_PAR_OLD_REC_TAG" ] && ViashError Bad arguments for option \'--old_rec_tag\': \'$VIASH_PAR_OLD_REC_TAG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OLD_REC_TAG="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --old_rec_tag. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --old_rec_tag=*) + [ -n "$VIASH_PAR_OLD_REC_TAG" ] && ViashError Bad arguments for option \'--old_rec_tag=*\': \'$VIASH_PAR_OLD_REC_TAG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_OLD_REC_TAG=$(ViashRemoveFlags "$1") + shift 1 + ;; + --regions) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--regions\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions=*) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--regions=*\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --r) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--r\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --r. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_file) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--regions_file\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_file=*) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--regions_file=*\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --R) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--R\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --R. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_overlap) + [ -n "$VIASH_PAR_REGIONS_OVERLAP" ] && ViashError Bad arguments for option \'--regions_overlap\': \'$VIASH_PAR_REGIONS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_OVERLAP="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions_overlap. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_overlap=*) + [ -n "$VIASH_PAR_REGIONS_OVERLAP" ] && ViashError Bad arguments for option \'--regions_overlap=*\': \'$VIASH_PAR_REGIONS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_OVERLAP=$(ViashRemoveFlags "$1") + shift 1 + ;; + --site_win) + [ -n "$VIASH_PAR_SITE_WIN" ] && ViashError Bad arguments for option \'--site_win\': \'$VIASH_PAR_SITE_WIN\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SITE_WIN="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --site_win. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --site_win=*) + [ -n "$VIASH_PAR_SITE_WIN" ] && ViashError Bad arguments for option \'--site_win=*\': \'$VIASH_PAR_SITE_WIN\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SITE_WIN=$(ViashRemoveFlags "$1") + shift 1 + ;; + -w) + [ -n "$VIASH_PAR_SITE_WIN" ] && ViashError Bad arguments for option \'-w\': \'$VIASH_PAR_SITE_WIN\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SITE_WIN="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -w. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --strict_filter) + [ -n "$VIASH_PAR_STRICT_FILTER" ] && ViashError Bad arguments for option \'--strict_filter\': \'$VIASH_PAR_STRICT_FILTER\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_STRICT_FILTER=true + shift 1 + ;; + -s) + [ -n "$VIASH_PAR_STRICT_FILTER" ] && ViashError Bad arguments for option \'-s\': \'$VIASH_PAR_STRICT_FILTER\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_STRICT_FILTER=true + shift 1 + ;; + --targets) + [ -n "$VIASH_PAR_TARGETS" ] && ViashError Bad arguments for option \'--targets\': \'$VIASH_PAR_TARGETS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --targets. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets=*) + [ -n "$VIASH_PAR_TARGETS" ] && ViashError Bad arguments for option \'--targets=*\': \'$VIASH_PAR_TARGETS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS=$(ViashRemoveFlags "$1") + shift 1 + ;; + -t) + [ -n "$VIASH_PAR_TARGETS" ] && ViashError Bad arguments for option \'-t\': \'$VIASH_PAR_TARGETS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -t. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets_file) + [ -n "$VIASH_PAR_TARGETS_FILE" ] && ViashError Bad arguments for option \'--targets_file\': \'$VIASH_PAR_TARGETS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --targets_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets_file=*) + [ -n "$VIASH_PAR_TARGETS_FILE" ] && ViashError Bad arguments for option \'--targets_file=*\': \'$VIASH_PAR_TARGETS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + -T) + [ -n "$VIASH_PAR_TARGETS_FILE" ] && ViashError Bad arguments for option \'-T\': \'$VIASH_PAR_TARGETS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to -T. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets_overlap) + [ -n "$VIASH_PAR_TARGETS_OVERLAP" ] && ViashError Bad arguments for option \'--targets_overlap\': \'$VIASH_PAR_TARGETS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_OVERLAP="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --targets_overlap. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets_overlap=*) + [ -n "$VIASH_PAR_TARGETS_OVERLAP" ] && ViashError Bad arguments for option \'--targets_overlap=*\': \'$VIASH_PAR_TARGETS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_OVERLAP=$(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/bcftools/bcftools_norm:add_trimgalore' + 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_ATOMIZE+x} ]; then + VIASH_PAR_ATOMIZE="false" +fi +if [ -z ${VIASH_PAR_FORCE+x} ]; then + VIASH_PAR_FORCE="false" +fi +if [ -z ${VIASH_PAR_NO_VERSION+x} ]; then + VIASH_PAR_NO_VERSION="false" +fi +if [ -z ${VIASH_PAR_DO_NOT_NORMALIZE+x} ]; then + VIASH_PAR_DO_NOT_NORMALIZE="false" +fi +if [ -z ${VIASH_PAR_STRICT_FILTER+x} ]; then + VIASH_PAR_STRICT_FILTER="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 +if [ ! -z "$VIASH_PAR_FASTA_REF" ] && [ ! -e "$VIASH_PAR_FASTA_REF" ]; then + ViashError "Input file '$VIASH_PAR_FASTA_REF' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_REGIONS_FILE" ] && [ ! -e "$VIASH_PAR_REGIONS_FILE" ]; then + ViashError "Input file '$VIASH_PAR_REGIONS_FILE' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_TARGETS_FILE" ] && [ ! -e "$VIASH_PAR_TARGETS_FILE" ]; then + ViashError "Input file '$VIASH_PAR_TARGETS_FILE' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_PAR_ATOMIZE" ]]; then + if ! [[ "$VIASH_PAR_ATOMIZE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--atomize' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_FORCE" ]]; then + if ! [[ "$VIASH_PAR_FORCE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--force' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_NO_VERSION" ]]; then + if ! [[ "$VIASH_PAR_NO_VERSION" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--no_version' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_DO_NOT_NORMALIZE" ]]; then + if ! [[ "$VIASH_PAR_DO_NOT_NORMALIZE" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--do_not_normalize' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_SITE_WIN" ]]; then + if ! [[ "$VIASH_PAR_SITE_WIN" =~ ^[-+]?[0-9]+$ ]]; then + ViashError '--site_win' has to be an integer. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_STRICT_FILTER" ]]; then + if ! [[ "$VIASH_PAR_STRICT_FILTER" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--strict_filter' 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 + +# check whether value is belongs to a set of choices +if [ ! -z "$VIASH_PAR_ATOM_OVERLAPS" ]; then + VIASH_PAR_ATOM_OVERLAPS_CHOICES=(".;*") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_ATOM_OVERLAPS_CHOICES[*]};" =~ ";$VIASH_PAR_ATOM_OVERLAPS;" ]]; then + ViashError '--atom_overlaps' specified value of \'$VIASH_PAR_ATOM_OVERLAPS\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_CHECK_REF" ]; then + VIASH_PAR_CHECK_REF_CHOICES=("e;w;x;s") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_CHECK_REF_CHOICES[*]};" =~ ";$VIASH_PAR_CHECK_REF;" ]]; then + ViashError '--check_ref' specified value of \'$VIASH_PAR_CHECK_REF\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_REMOVE_DUPLICATES" ]; then + VIASH_PAR_REMOVE_DUPLICATES_CHOICES=("snps;indels;both;all;exact;none") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_REMOVE_DUPLICATES_CHOICES[*]};" =~ ";$VIASH_PAR_REMOVE_DUPLICATES;" ]]; then + ViashError '--remove_duplicates' specified value of \'$VIASH_PAR_REMOVE_DUPLICATES\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_MULTIALLELICS" ]; then + VIASH_PAR_MULTIALLELICS_CHOICES=("+snps;+indels;+both;+any;-snps;-indels;-both;-any") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_MULTIALLELICS_CHOICES[*]};" =~ ";$VIASH_PAR_MULTIALLELICS;" ]]; then + ViashError '--multiallelics' specified value of \'$VIASH_PAR_MULTIALLELICS\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_OUTPUT_TYPE" ]; then + VIASH_PAR_OUTPUT_TYPE_CHOICES=("u;z;b;v") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_OUTPUT_TYPE_CHOICES[*]};" =~ ";$VIASH_PAR_OUTPUT_TYPE;" ]]; then + ViashError '--output_type' specified value of \'$VIASH_PAR_OUTPUT_TYPE\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_REGIONS_OVERLAP" ]; then + VIASH_PAR_REGIONS_OVERLAP_CHOICES=("pos;record;variant;0;1;2") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_REGIONS_OVERLAP_CHOICES[*]};" =~ ";$VIASH_PAR_REGIONS_OVERLAP;" ]]; then + ViashError '--regions_overlap' specified value of \'$VIASH_PAR_REGIONS_OVERLAP\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_TARGETS_OVERLAP" ]; then + VIASH_PAR_TARGETS_OVERLAP_CHOICES=("pos;record;variant;0;1;2") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_TARGETS_OVERLAP_CHOICES[*]};" =~ ";$VIASH_PAR_TARGETS_OVERLAP;" ]]; then + ViashError '--targets_overlap' specified value of \'$VIASH_PAR_TARGETS_OVERLAP\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +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_PAR_FASTA_REF" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_FASTA_REF")" ) + VIASH_PAR_FASTA_REF=$(ViashDockerAutodetectMount "$VIASH_PAR_FASTA_REF") +fi +if [ ! -z "$VIASH_PAR_REGIONS_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_REGIONS_FILE")" ) + VIASH_PAR_REGIONS_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_REGIONS_FILE") +fi +if [ ! -z "$VIASH_PAR_TARGETS_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_TARGETS_FILE")" ) + VIASH_PAR_TARGETS_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_TARGETS_FILE") +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-bcftools_norm-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_ATOMIZE+x} ]; then echo "${VIASH_PAR_ATOMIZE}" | sed "s#'#'\"'\"'#g;s#.*#par_atomize='&'#" ; else echo "# par_atomize="; fi ) +$( if [ ! -z ${VIASH_PAR_ATOM_OVERLAPS+x} ]; then echo "${VIASH_PAR_ATOM_OVERLAPS}" | sed "s#'#'\"'\"'#g;s#.*#par_atom_overlaps='&'#" ; else echo "# par_atom_overlaps="; fi ) +$( if [ ! -z ${VIASH_PAR_CHECK_REF+x} ]; then echo "${VIASH_PAR_CHECK_REF}" | sed "s#'#'\"'\"'#g;s#.*#par_check_ref='&'#" ; else echo "# par_check_ref="; fi ) +$( if [ ! -z ${VIASH_PAR_REMOVE_DUPLICATES+x} ]; then echo "${VIASH_PAR_REMOVE_DUPLICATES}" | sed "s#'#'\"'\"'#g;s#.*#par_remove_duplicates='&'#" ; else echo "# par_remove_duplicates="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTA_REF+x} ]; then echo "${VIASH_PAR_FASTA_REF}" | sed "s#'#'\"'\"'#g;s#.*#par_fasta_ref='&'#" ; else echo "# par_fasta_ref="; fi ) +$( if [ ! -z ${VIASH_PAR_FORCE+x} ]; then echo "${VIASH_PAR_FORCE}" | sed "s#'#'\"'\"'#g;s#.*#par_force='&'#" ; else echo "# par_force="; fi ) +$( if [ ! -z ${VIASH_PAR_KEEP_SUM+x} ]; then echo "${VIASH_PAR_KEEP_SUM}" | sed "s#'#'\"'\"'#g;s#.*#par_keep_sum='&'#" ; else echo "# par_keep_sum="; fi ) +$( if [ ! -z ${VIASH_PAR_MULTIALLELICS+x} ]; then echo "${VIASH_PAR_MULTIALLELICS}" | sed "s#'#'\"'\"'#g;s#.*#par_multiallelics='&'#" ; else echo "# par_multiallelics="; fi ) +$( if [ ! -z ${VIASH_PAR_NO_VERSION+x} ]; then echo "${VIASH_PAR_NO_VERSION}" | sed "s#'#'\"'\"'#g;s#.*#par_no_version='&'#" ; else echo "# par_no_version="; fi ) +$( if [ ! -z ${VIASH_PAR_DO_NOT_NORMALIZE+x} ]; then echo "${VIASH_PAR_DO_NOT_NORMALIZE}" | sed "s#'#'\"'\"'#g;s#.*#par_do_not_normalize='&'#" ; else echo "# par_do_not_normalize="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_TYPE+x} ]; then echo "${VIASH_PAR_OUTPUT_TYPE}" | sed "s#'#'\"'\"'#g;s#.*#par_output_type='&'#" ; else echo "# par_output_type="; fi ) +$( if [ ! -z ${VIASH_PAR_OLD_REC_TAG+x} ]; then echo "${VIASH_PAR_OLD_REC_TAG}" | sed "s#'#'\"'\"'#g;s#.*#par_old_rec_tag='&'#" ; else echo "# par_old_rec_tag="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS+x} ]; then echo "${VIASH_PAR_REGIONS}" | sed "s#'#'\"'\"'#g;s#.*#par_regions='&'#" ; else echo "# par_regions="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_FILE+x} ]; then echo "${VIASH_PAR_REGIONS_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_regions_file='&'#" ; else echo "# par_regions_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_OVERLAP+x} ]; then echo "${VIASH_PAR_REGIONS_OVERLAP}" | sed "s#'#'\"'\"'#g;s#.*#par_regions_overlap='&'#" ; else echo "# par_regions_overlap="; fi ) +$( if [ ! -z ${VIASH_PAR_SITE_WIN+x} ]; then echo "${VIASH_PAR_SITE_WIN}" | sed "s#'#'\"'\"'#g;s#.*#par_site_win='&'#" ; else echo "# par_site_win="; fi ) +$( if [ ! -z ${VIASH_PAR_STRICT_FILTER+x} ]; then echo "${VIASH_PAR_STRICT_FILTER}" | sed "s#'#'\"'\"'#g;s#.*#par_strict_filter='&'#" ; else echo "# par_strict_filter="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS+x} ]; then echo "${VIASH_PAR_TARGETS}" | sed "s#'#'\"'\"'#g;s#.*#par_targets='&'#" ; else echo "# par_targets="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS_FILE+x} ]; then echo "${VIASH_PAR_TARGETS_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_targets_file='&'#" ; else echo "# par_targets_file="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS_OVERLAP+x} ]; then echo "${VIASH_PAR_TARGETS_OVERLAP}" | sed "s#'#'\"'\"'#g;s#.*#par_targets_overlap='&'#" ; else echo "# par_targets_overlap="; 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 + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_atomize + par_remove_duplicates + par_force + par_no_version + par_do_not_normalize + par_strict_filter +) + +for par in \${unset_if_false[@]}; do + test_val="\${!par}" + [[ "\$test_val" == "false" ]] && unset \$par +done + +# Execute bcftools norm with the provided arguments +bcftools norm \\ + \${par_atomize:+--atomize} \\ + \${par_atom_overlaps:+--atom-overlaps "\$par_atom_overlaps"} \\ + \${par_check_ref:+-c "\$par_check_ref"} \\ + \${par_remove_duplicates:+-d "\$par_remove_duplicates"} \\ + \${par_fasta_ref:+-f "\$par_fasta_ref"} \\ + \${par_force:+--force} \\ + \${par_keep_sum:+--keep-sum "\$par_keep_sum"} \\ + \${par_multiallelics:+-m "\$par_multiallelics"} \\ + \${par_no_version:+--no-version} \\ + \${par_do_not_normalize:+-N} \\ + \${par_old_rec_tag:+--old-rec-tag "\$par_old_rec_tag"} \\ + \${par_regions:+-r "\$par_regions"} \\ + \${par_regions_file:+-R "\$par_regions_file"} \\ + \${par_regions_overlap:+--regions-overlap "\$par_regions_overlap"} \\ + \${par_site_win:+-w "\$par_site_win"} \\ + \${par_strict_filter:+-s} \\ + \${par_targets:+-t "\$par_targets"} \\ + \${par_targets_file:+-T "\$par_targets_file"} \\ + \${par_targets_overlap:+--targets-overlap "\$par_targets_overlap"} \\ + \${meta_cpus:+--threads "\$meta_cpus"} \\ + \${par_output_type:+-O "\$par_output_type"} \\ + -o \$par_output \\ + \$par_input + +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_PAR_FASTA_REF" ]; then + VIASH_PAR_FASTA_REF=$(ViashDockerStripAutomount "$VIASH_PAR_FASTA_REF") + fi + if [ ! -z "$VIASH_PAR_REGIONS_FILE" ]; then + VIASH_PAR_REGIONS_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_REGIONS_FILE") + fi + if [ ! -z "$VIASH_PAR_TARGETS_FILE" ]; then + VIASH_PAR_TARGETS_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_TARGETS_FILE") + 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/bcftools/bcftools_sort/.config.vsh.yaml b/target/executable/bcftools/bcftools_sort/.config.vsh.yaml index 7b6af98b..d2de1067 100644 --- a/target/executable/bcftools/bcftools_sort/.config.vsh.yaml +++ b/target/executable/bcftools/bcftools_sort/.config.vsh.yaml @@ -185,8 +185,8 @@ build_info: output: "target/executable/bcftools/bcftools_sort" executable: "target/executable/bcftools/bcftools_sort/bcftools_sort" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bcftools/bcftools_sort/bcftools_sort b/target/executable/bcftools/bcftools_sort/bcftools_sort index 80139900..9dd09ea5 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-09-10T07:43:28Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:57Z" LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bcftools/bcftools_stats/.config.vsh.yaml b/target/executable/bcftools/bcftools_stats/.config.vsh.yaml new file mode 100644 index 00000000..531d09cb --- /dev/null +++ b/target/executable/bcftools/bcftools_stats/.config.vsh.yaml @@ -0,0 +1,484 @@ +name: "bcftools_stats" +namespace: "bcftools" +version: "add_trimgalore" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + 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 VCF/BCF file. Maximum of two files." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: true + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + description: "Output txt statistics file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "string" + name: "--allele_frequency_bins" + alternatives: + - "--af_bins" + description: "Allele frequency bins, a list of bin values (0.1,0.5,1).\n" + info: null + example: + - "0.1,0.5,1" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--allele_frequency_bins_file" + alternatives: + - "--af_bins_file" + description: "Same as allele_frequency_bins, but in a file.\nFormat of file is\ + \ one value per line. \ne.g. \n 0.1\n 0.5\n 1\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--allele_frequency_tag" + alternatives: + - "--af_tag" + description: "Allele frequency tag to use, by default estimated from AN,AC or\ + \ GT.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--first_allele_only" + alternatives: + - "--first_only" + description: "Include only 1st allele at multiallelic sites.\n" + info: null + direction: "input" + - type: "string" + name: "--collapse" + alternatives: + - "--c" + description: "Treat as identical records with .\n\ + See https://samtools.github.io/bcftools/bcftools.html#common_options for details.\n" + info: null + required: false + choices: + - "snps" + - "indels" + - "both" + - "all" + - "some" + - "none" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--depth" + alternatives: + - "--d" + description: "Depth distribution: min,max,bin size.\n" + info: null + example: + - "0,500,1" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--exclude" + alternatives: + - "--e" + description: "Exclude sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions\ + \ for details.\n" + info: null + example: + - "QUAL < 30 && DP < 10" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--exons" + alternatives: + - "--E" + description: "tab-delimited file with exons for indel frameshifts statistics.\ + \ \nThe columns of the file are CHR, FROM, TO, with 1-based, inclusive, positions.\ + \ \nThe file is BGZF-compressed and indexed with tabix (e.g. tabix -s1 -b2 -e3\ + \ file.gz).\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--apply_filters" + alternatives: + - "--f" + description: "Require at least one of the listed FILTER strings (e.g. \"PASS,.\"\ + ).\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fasta_reference" + alternatives: + - "--F" + description: "Faidx indexed reference sequence file to determine INDEL context.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--include" + alternatives: + - "--i" + description: "Select sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions\ + \ for details.\n" + info: null + example: + - "QUAL >= 30 && DP >= 10" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--split_by_ID" + alternatives: + - "--I" + description: "Collect stats for sites with ID separately (known vs novel).\n" + info: null + direction: "input" + - type: "string" + name: "--regions" + alternatives: + - "--r" + description: "Restrict to comma-separated list of regions. \nFollowing formats\ + \ are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--regions_file" + alternatives: + - "--R" + description: "Restrict to regions listed in a file. \nRegions can be specified\ + \ either on a VCF, BED, or tab-delimited file (the default). \nFor more information\ + \ check manual.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions_overlap" + description: "This option controls how overlapping records are determined: \n\ + set to 'pos' or '0' if the VCF record has to have POS inside a region (this\ + \ corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if\ + \ also overlapping records with POS outside a region should be included (this\ + \ is the default behavior of -r/-R, \nand includes indels with POS at the end\ + \ of a region, which are technically outside the region); \nor set to 'variant'\ + \ or '2' to include only true overlapping variation (compare the full VCF representation\ + \ \"TA>T-\" vs the true sequence variation \"A>-\").\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--samples" + alternatives: + - "--s" + description: "List of samples for sample stats, \"-\" to include all samples.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--samples_file" + alternatives: + - "--S" + description: "File of samples to include.\ne.g. \n sample1 1\n sample2 \ + \ 2\n sample3 2\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--targets" + alternatives: + - "--t" + description: "Similar as -r, --regions, but the next position is accessed by streaming\ + \ the whole VCF/BCF \nrather than using the tbi/csi index. Both -r and -t options\ + \ can be applied simultaneously: -r uses the \nindex to jump to a region and\ + \ -t discards positions which are not in the targets. Unlike -r, targets \n\ + can be prefixed with \"^\" to request logical complement. For example, \"^X,Y,MT\"\ + \ indicates that \nsequences X, Y and MT should be skipped. Yet another difference\ + \ between the -t/-T and -r/-R is \nthat -r/-R checks for proper overlaps and\ + \ considers both POS and the end position of an indel, \nwhile -t/-T considers\ + \ the POS coordinate only (by default; see also --regions-overlap and --targets-overlap).\ + \ \nNote that -t cannot be used in combination with -T.\nFollowing formats are\ + \ supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--targets_file" + alternatives: + - "--T" + description: "Similar to --regions_file option but streams rather than index-jumps.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--targets_overlaps" + description: "Include if POS in the region (0), record overlaps (1), variant overlaps\ + \ (2).\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--user_tstv" + alternatives: + - "--u" + description: "Collect Ts/Tv stats for any tag using the given binning [0:1:100].\n\ + Format is .\nA subfield can be selected as e.g. 'PV4[0]', here\ + \ the first value of the PV4 tag.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--verbose" + alternatives: + - "--v" + description: "Produce verbose per-site and per-sample output.\n" + info: null + direction: "input" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Parses VCF or BCF and produces a txt stats file which can be plotted\ + \ using plot-vcfstats.\nWhen two files are given, the program generates separate\ + \ stats for intersection\nand the complements. By default only sites are compared,\ + \ -s/-S must given to include\nalso sample columns.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Stats" +- "VCF" +- "BCF" +license: "MIT/Expat, GNU" +references: + doi: + - "https://doi.org/10.1093/gigascience/giab008" +links: + repository: "https://github.com/samtools/bcftools" + homepage: "https://samtools.github.io/bcftools/" + documentation: "https://samtools.github.io/bcftools/bcftools.html#stats" + issue_tracker: "https://github.com/samtools/bcftools/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: "add_trimgalore" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bcftools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bcftools: \\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools\ + \ //p')\\\"\" > /var/software_versions.txt\n" + test_setup: + - type: "apt" + packages: + - "tabix" + interactive: false + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bcftools/bcftools_stats/config.vsh.yaml" + runner: "executable" + engine: "docker|native" + output: "target/executable/bcftools/bcftools_stats" + executable: "target/executable/bcftools/bcftools_stats/bcftools_stats" + viash_version: "0.9.0-RC7" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" +package_config: + name: "biobox" + version: "add_trimgalore" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0-RC7" + 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 := 'add_trimgalore'" + 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/bcftools/bcftools_stats/bcftools_stats b/target/executable/bcftools/bcftools_stats/bcftools_stats new file mode 100755 index 00000000..eca7ba3a --- /dev/null +++ b/target/executable/bcftools/bcftools_stats/bcftools_stats @@ -0,0 +1,1827 @@ +#!/usr/bin/env bash + +# bcftools_stats add_trimgalore +# +# This wrapper script is auto-generated by viash 0.9.0-RC7 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) + +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="bcftools_stats" +VIASH_META_FUNCTIONALITY_NAME="bcftools_stats" +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 "bcftools_stats add_trimgalore" + echo "" + echo "Parses VCF or BCF and produces a txt stats file which can be plotted using" + echo "plot-vcfstats." + echo "When two files are given, the program generates separate stats for intersection" + echo "and the complements. By default only sites are compared, -s/-S must given to" + echo "include" + echo "also sample columns." + echo "" + echo "Inputs:" + echo " -i, --input" + echo " type: file, required parameter, multiple values allowed, file must exist" + echo " Input VCF/BCF file. Maximum of two files." + echo "" + echo "Outputs:" + echo " -o, --output" + echo " type: file, required parameter, output, file must exist" + echo " Output txt statistics file." + echo "" + echo "Options:" + echo " --af_bins, --allele_frequency_bins" + echo " type: string" + echo " example: 0.1,0.5,1" + echo " Allele frequency bins, a list of bin values (0.1,0.5,1)." + echo "" + echo " --af_bins_file, --allele_frequency_bins_file" + echo " type: file, file must exist" + echo " Same as allele_frequency_bins, but in a file." + echo " Format of file is one value per line." + echo " e.g." + echo " 0.1" + echo " 0.5" + echo " 1" + echo "" + echo " --af_tag, --allele_frequency_tag" + echo " type: string" + echo " Allele frequency tag to use, by default estimated from AN,AC or GT." + echo "" + echo " --first_only, --first_allele_only" + echo " type: boolean_true" + echo " Include only 1st allele at multiallelic sites." + echo "" + echo " --c, --collapse" + echo " type: string" + echo " choices: [ snps, indels, both, all, some, none ]" + echo " Treat as identical records with ." + echo " See https://samtools.github.io/bcftools/bcftools.html#common_options for" + echo " details." + echo "" + echo " --d, --depth" + echo " type: string" + echo " example: 0,500,1" + echo " Depth distribution: min,max,bin size." + echo "" + echo " --e, --exclude" + echo " type: string" + echo " example: QUAL < 30 && DP < 10" + echo " Exclude sites for which the expression is true." + echo " See https://samtools.github.io/bcftools/bcftools.html#expressions for" + echo " details." + echo "" + echo " --E, --exons" + echo " type: file, file must exist" + echo " tab-delimited file with exons for indel frameshifts statistics." + echo " The columns of the file are CHR, FROM, TO, with 1-based, inclusive," + echo " positions." + echo " The file is BGZF-compressed and indexed with tabix (e.g. tabix -s1 -b2" + echo " -e3 file.gz)." + echo "" + echo " --f, --apply_filters" + echo " type: string" + echo " Require at least one of the listed FILTER strings (e.g. \"PASS,.\")." + echo "" + echo " --F, --fasta_reference" + echo " type: file, file must exist" + echo " Faidx indexed reference sequence file to determine INDEL context." + echo "" + echo " --i, --include" + echo " type: string" + echo " example: QUAL >= 30 && DP >= 10" + echo " Select sites for which the expression is true." + echo " See https://samtools.github.io/bcftools/bcftools.html#expressions for" + echo " details." + echo "" + echo " --I, --split_by_ID" + echo " type: boolean_true" + echo " Collect stats for sites with ID separately (known vs novel)." + echo "" + echo " --r, --regions" + echo " type: string" + echo " example: 20:1000000-2000000" + echo " Restrict to comma-separated list of regions." + echo " Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]." + echo "" + echo " --R, --regions_file" + echo " type: file, file must exist" + echo " Restrict to regions listed in a file." + echo " Regions can be specified either on a VCF, BED, or tab-delimited file" + echo " (the default)." + echo " For more information check manual." + echo "" + echo " --regions_overlap" + echo " type: string" + echo " choices: [ pos, record, variant, 0, 1, 2 ]" + echo " This option controls how overlapping records are determined:" + echo " set to 'pos' or '0' if the VCF record has to have POS inside a region" + echo " (this corresponds to the default behavior of -t/-T);" + echo " set to 'record' or '1' if also overlapping records with POS outside a" + echo " region should be included (this is the default behavior of -r/-R," + echo " and includes indels with POS at the end of a region, which are" + echo " technically outside the region);" + echo " or set to 'variant' or '2' to include only true overlapping variation" + echo " (compare the full VCF representation \"TA>T-\" vs the true sequence" + echo " variation \"A>-\")." + echo "" + echo " --s, --samples" + echo " type: string" + echo " List of samples for sample stats, \"-\" to include all samples." + echo "" + echo " --S, --samples_file" + echo " type: file, file must exist" + echo " File of samples to include." + echo " e.g." + echo " sample1 1" + echo " sample2 2" + echo " sample3 2" + echo "" + echo " --t, --targets" + echo " type: string" + echo " example: 20:1000000-2000000" + echo " Similar as -r, --regions, but the next position is accessed by streaming" + echo " the whole VCF/BCF" + echo " rather than using the tbi/csi index. Both -r and -t options can be" + echo " applied simultaneously: -r uses the" + echo " index to jump to a region and -t discards positions which are not in the" + echo " targets. Unlike -r, targets" + echo " can be prefixed with \"^\" to request logical complement. For example," + echo " \"^X,Y,MT\" indicates that" + echo " sequences X, Y and MT should be skipped. Yet another difference between" + echo " the -t/-T and -r/-R is" + echo " that -r/-R checks for proper overlaps and considers both POS and the end" + echo " position of an indel," + echo " while -t/-T considers the POS coordinate only (by default; see also" + echo " --regions-overlap and --targets-overlap)." + echo " Note that -t cannot be used in combination with -T." + echo " Following formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​]." + echo "" + echo " --T, --targets_file" + echo " type: file, file must exist" + echo " Similar to --regions_file option but streams rather than index-jumps." + echo "" + echo " --targets_overlaps" + echo " type: string" + echo " choices: [ pos, record, variant, 0, 1, 2 ]" + echo " Include if POS in the region (0), record overlaps (1), variant overlaps" + echo " (2)." + echo "" + echo " --u, --user_tstv" + echo " type: string" + echo " Collect Ts/Tv stats for any tag using the given binning [0:1:100]." + echo " Format is ." + echo " A subfield can be selected as e.g. 'PV4[0]', here the first value of the" + echo " PV4 tag." + echo "" + echo " --v, --verbose" + echo " type: boolean_true" + echo " Produce verbose per-site and per-sample output." +} + +# 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 bcftools procps && \ + rm -rf /var/lib/apt/lists/* + +RUN echo "bcftools: \"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\"" > /var/software_versions.txt + +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-09-19T08:35:58Z" +LABEL org.opencontainers.image.source="https://github.com/samtools/bcftools" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" +LABEL org.opencontainers.image.version="add_trimgalore" + +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 "bcftools_stats add_trimgalore" + exit + ;; + --input) + if [ -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT="$2" + else + VIASH_PAR_INPUT="$VIASH_PAR_INPUT;""$2" + fi + [ $# -lt 2 ] && ViashError Not enough arguments passed to --input. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --input=*) + if [ -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT=$(ViashRemoveFlags "$1") + else + VIASH_PAR_INPUT="$VIASH_PAR_INPUT;"$(ViashRemoveFlags "$1") + fi + shift 1 + ;; + -i) + if [ -z "$VIASH_PAR_INPUT" ]; then + VIASH_PAR_INPUT="$2" + else + VIASH_PAR_INPUT="$VIASH_PAR_INPUT;""$2" + fi + [ $# -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 + ;; + --allele_frequency_bins) + [ -n "$VIASH_PAR_ALLELE_FREQUENCY_BINS" ] && ViashError Bad arguments for option \'--allele_frequency_bins\': \'$VIASH_PAR_ALLELE_FREQUENCY_BINS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLELE_FREQUENCY_BINS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --allele_frequency_bins. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --allele_frequency_bins=*) + [ -n "$VIASH_PAR_ALLELE_FREQUENCY_BINS" ] && ViashError Bad arguments for option \'--allele_frequency_bins=*\': \'$VIASH_PAR_ALLELE_FREQUENCY_BINS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLELE_FREQUENCY_BINS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --af_bins) + [ -n "$VIASH_PAR_ALLELE_FREQUENCY_BINS" ] && ViashError Bad arguments for option \'--af_bins\': \'$VIASH_PAR_ALLELE_FREQUENCY_BINS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLELE_FREQUENCY_BINS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --af_bins. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --allele_frequency_bins_file) + [ -n "$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE" ] && ViashError Bad arguments for option \'--allele_frequency_bins_file\': \'$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --allele_frequency_bins_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --allele_frequency_bins_file=*) + [ -n "$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE" ] && ViashError Bad arguments for option \'--allele_frequency_bins_file=*\': \'$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --af_bins_file) + [ -n "$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE" ] && ViashError Bad arguments for option \'--af_bins_file\': \'$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --af_bins_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --allele_frequency_tag) + [ -n "$VIASH_PAR_ALLELE_FREQUENCY_TAG" ] && ViashError Bad arguments for option \'--allele_frequency_tag\': \'$VIASH_PAR_ALLELE_FREQUENCY_TAG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLELE_FREQUENCY_TAG="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --allele_frequency_tag. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --allele_frequency_tag=*) + [ -n "$VIASH_PAR_ALLELE_FREQUENCY_TAG" ] && ViashError Bad arguments for option \'--allele_frequency_tag=*\': \'$VIASH_PAR_ALLELE_FREQUENCY_TAG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLELE_FREQUENCY_TAG=$(ViashRemoveFlags "$1") + shift 1 + ;; + --af_tag) + [ -n "$VIASH_PAR_ALLELE_FREQUENCY_TAG" ] && ViashError Bad arguments for option \'--af_tag\': \'$VIASH_PAR_ALLELE_FREQUENCY_TAG\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_ALLELE_FREQUENCY_TAG="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --af_tag. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --first_allele_only) + [ -n "$VIASH_PAR_FIRST_ALLELE_ONLY" ] && ViashError Bad arguments for option \'--first_allele_only\': \'$VIASH_PAR_FIRST_ALLELE_ONLY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FIRST_ALLELE_ONLY=true + shift 1 + ;; + --first_only) + [ -n "$VIASH_PAR_FIRST_ALLELE_ONLY" ] && ViashError Bad arguments for option \'--first_only\': \'$VIASH_PAR_FIRST_ALLELE_ONLY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FIRST_ALLELE_ONLY=true + shift 1 + ;; + --collapse) + [ -n "$VIASH_PAR_COLLAPSE" ] && ViashError Bad arguments for option \'--collapse\': \'$VIASH_PAR_COLLAPSE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLLAPSE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --collapse. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --collapse=*) + [ -n "$VIASH_PAR_COLLAPSE" ] && ViashError Bad arguments for option \'--collapse=*\': \'$VIASH_PAR_COLLAPSE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLLAPSE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --c) + [ -n "$VIASH_PAR_COLLAPSE" ] && ViashError Bad arguments for option \'--c\': \'$VIASH_PAR_COLLAPSE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_COLLAPSE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --c. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --depth) + [ -n "$VIASH_PAR_DEPTH" ] && ViashError Bad arguments for option \'--depth\': \'$VIASH_PAR_DEPTH\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_DEPTH="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --depth. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --depth=*) + [ -n "$VIASH_PAR_DEPTH" ] && ViashError Bad arguments for option \'--depth=*\': \'$VIASH_PAR_DEPTH\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_DEPTH=$(ViashRemoveFlags "$1") + shift 1 + ;; + --d) + [ -n "$VIASH_PAR_DEPTH" ] && ViashError Bad arguments for option \'--d\': \'$VIASH_PAR_DEPTH\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_DEPTH="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --d. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --exclude) + [ -n "$VIASH_PAR_EXCLUDE" ] && ViashError Bad arguments for option \'--exclude\': \'$VIASH_PAR_EXCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EXCLUDE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --exclude. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --exclude=*) + [ -n "$VIASH_PAR_EXCLUDE" ] && ViashError Bad arguments for option \'--exclude=*\': \'$VIASH_PAR_EXCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EXCLUDE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --e) + [ -n "$VIASH_PAR_EXCLUDE" ] && ViashError Bad arguments for option \'--e\': \'$VIASH_PAR_EXCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EXCLUDE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --e. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --exons) + [ -n "$VIASH_PAR_EXONS" ] && ViashError Bad arguments for option \'--exons\': \'$VIASH_PAR_EXONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EXONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --exons. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --exons=*) + [ -n "$VIASH_PAR_EXONS" ] && ViashError Bad arguments for option \'--exons=*\': \'$VIASH_PAR_EXONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EXONS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --E) + [ -n "$VIASH_PAR_EXONS" ] && ViashError Bad arguments for option \'--E\': \'$VIASH_PAR_EXONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_EXONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --E. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --apply_filters) + [ -n "$VIASH_PAR_APPLY_FILTERS" ] && ViashError Bad arguments for option \'--apply_filters\': \'$VIASH_PAR_APPLY_FILTERS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_APPLY_FILTERS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --apply_filters. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --apply_filters=*) + [ -n "$VIASH_PAR_APPLY_FILTERS" ] && ViashError Bad arguments for option \'--apply_filters=*\': \'$VIASH_PAR_APPLY_FILTERS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_APPLY_FILTERS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --f) + [ -n "$VIASH_PAR_APPLY_FILTERS" ] && ViashError Bad arguments for option \'--f\': \'$VIASH_PAR_APPLY_FILTERS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_APPLY_FILTERS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --f. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --fasta_reference) + [ -n "$VIASH_PAR_FASTA_REFERENCE" ] && ViashError Bad arguments for option \'--fasta_reference\': \'$VIASH_PAR_FASTA_REFERENCE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTA_REFERENCE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --fasta_reference. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --fasta_reference=*) + [ -n "$VIASH_PAR_FASTA_REFERENCE" ] && ViashError Bad arguments for option \'--fasta_reference=*\': \'$VIASH_PAR_FASTA_REFERENCE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTA_REFERENCE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --F) + [ -n "$VIASH_PAR_FASTA_REFERENCE" ] && ViashError Bad arguments for option \'--F\': \'$VIASH_PAR_FASTA_REFERENCE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTA_REFERENCE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --F. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --include) + [ -n "$VIASH_PAR_INCLUDE" ] && ViashError Bad arguments for option \'--include\': \'$VIASH_PAR_INCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INCLUDE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --include. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --include=*) + [ -n "$VIASH_PAR_INCLUDE" ] && ViashError Bad arguments for option \'--include=*\': \'$VIASH_PAR_INCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INCLUDE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --i) + [ -n "$VIASH_PAR_INCLUDE" ] && ViashError Bad arguments for option \'--i\': \'$VIASH_PAR_INCLUDE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_INCLUDE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --i. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --split_by_ID) + [ -n "$VIASH_PAR_SPLIT_BY_ID" ] && ViashError Bad arguments for option \'--split_by_ID\': \'$VIASH_PAR_SPLIT_BY_ID\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SPLIT_BY_ID=true + shift 1 + ;; + --I) + [ -n "$VIASH_PAR_SPLIT_BY_ID" ] && ViashError Bad arguments for option \'--I\': \'$VIASH_PAR_SPLIT_BY_ID\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SPLIT_BY_ID=true + shift 1 + ;; + --regions) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--regions\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions=*) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--regions=*\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --r) + [ -n "$VIASH_PAR_REGIONS" ] && ViashError Bad arguments for option \'--r\': \'$VIASH_PAR_REGIONS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --r. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_file) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--regions_file\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_file=*) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--regions_file=*\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --R) + [ -n "$VIASH_PAR_REGIONS_FILE" ] && ViashError Bad arguments for option \'--R\': \'$VIASH_PAR_REGIONS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --R. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_overlap) + [ -n "$VIASH_PAR_REGIONS_OVERLAP" ] && ViashError Bad arguments for option \'--regions_overlap\': \'$VIASH_PAR_REGIONS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_OVERLAP="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --regions_overlap. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --regions_overlap=*) + [ -n "$VIASH_PAR_REGIONS_OVERLAP" ] && ViashError Bad arguments for option \'--regions_overlap=*\': \'$VIASH_PAR_REGIONS_OVERLAP\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_REGIONS_OVERLAP=$(ViashRemoveFlags "$1") + shift 1 + ;; + --samples) + [ -n "$VIASH_PAR_SAMPLES" ] && ViashError Bad arguments for option \'--samples\': \'$VIASH_PAR_SAMPLES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --samples. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --samples=*) + [ -n "$VIASH_PAR_SAMPLES" ] && ViashError Bad arguments for option \'--samples=*\': \'$VIASH_PAR_SAMPLES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES=$(ViashRemoveFlags "$1") + shift 1 + ;; + --s) + [ -n "$VIASH_PAR_SAMPLES" ] && ViashError Bad arguments for option \'--s\': \'$VIASH_PAR_SAMPLES\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --s. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --samples_file) + [ -n "$VIASH_PAR_SAMPLES_FILE" ] && ViashError Bad arguments for option \'--samples_file\': \'$VIASH_PAR_SAMPLES_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --samples_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --samples_file=*) + [ -n "$VIASH_PAR_SAMPLES_FILE" ] && ViashError Bad arguments for option \'--samples_file=*\': \'$VIASH_PAR_SAMPLES_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --S) + [ -n "$VIASH_PAR_SAMPLES_FILE" ] && ViashError Bad arguments for option \'--S\': \'$VIASH_PAR_SAMPLES_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_SAMPLES_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --S. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets) + [ -n "$VIASH_PAR_TARGETS" ] && ViashError Bad arguments for option \'--targets\': \'$VIASH_PAR_TARGETS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --targets. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets=*) + [ -n "$VIASH_PAR_TARGETS" ] && ViashError Bad arguments for option \'--targets=*\': \'$VIASH_PAR_TARGETS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --t) + [ -n "$VIASH_PAR_TARGETS" ] && ViashError Bad arguments for option \'--t\': \'$VIASH_PAR_TARGETS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --t. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets_file) + [ -n "$VIASH_PAR_TARGETS_FILE" ] && ViashError Bad arguments for option \'--targets_file\': \'$VIASH_PAR_TARGETS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --targets_file. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets_file=*) + [ -n "$VIASH_PAR_TARGETS_FILE" ] && ViashError Bad arguments for option \'--targets_file=*\': \'$VIASH_PAR_TARGETS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_FILE=$(ViashRemoveFlags "$1") + shift 1 + ;; + --T) + [ -n "$VIASH_PAR_TARGETS_FILE" ] && ViashError Bad arguments for option \'--T\': \'$VIASH_PAR_TARGETS_FILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_FILE="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --T. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets_overlaps) + [ -n "$VIASH_PAR_TARGETS_OVERLAPS" ] && ViashError Bad arguments for option \'--targets_overlaps\': \'$VIASH_PAR_TARGETS_OVERLAPS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_OVERLAPS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --targets_overlaps. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --targets_overlaps=*) + [ -n "$VIASH_PAR_TARGETS_OVERLAPS" ] && ViashError Bad arguments for option \'--targets_overlaps=*\': \'$VIASH_PAR_TARGETS_OVERLAPS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_TARGETS_OVERLAPS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --user_tstv) + [ -n "$VIASH_PAR_USER_TSTV" ] && ViashError Bad arguments for option \'--user_tstv\': \'$VIASH_PAR_USER_TSTV\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_USER_TSTV="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --user_tstv. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --user_tstv=*) + [ -n "$VIASH_PAR_USER_TSTV" ] && ViashError Bad arguments for option \'--user_tstv=*\': \'$VIASH_PAR_USER_TSTV\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_USER_TSTV=$(ViashRemoveFlags "$1") + shift 1 + ;; + --u) + [ -n "$VIASH_PAR_USER_TSTV" ] && ViashError Bad arguments for option \'--u\': \'$VIASH_PAR_USER_TSTV\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_USER_TSTV="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --u. 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/bcftools/bcftools_stats:add_trimgalore' + 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_FIRST_ALLELE_ONLY+x} ]; then + VIASH_PAR_FIRST_ALLELE_ONLY="false" +fi +if [ -z ${VIASH_PAR_SPLIT_BY_ID+x} ]; then + VIASH_PAR_SPLIT_BY_ID="false" +fi +if [ -z ${VIASH_PAR_VERBOSE+x} ]; then + VIASH_PAR_VERBOSE="false" +fi + +# check whether required files exist +if [ ! -z "$VIASH_PAR_INPUT" ]; then + IFS=';' + set -f + for file in $VIASH_PAR_INPUT; 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_ALLELE_FREQUENCY_BINS_FILE" ] && [ ! -e "$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE" ]; then + ViashError "Input file '$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_EXONS" ] && [ ! -e "$VIASH_PAR_EXONS" ]; then + ViashError "Input file '$VIASH_PAR_EXONS' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_FASTA_REFERENCE" ] && [ ! -e "$VIASH_PAR_FASTA_REFERENCE" ]; then + ViashError "Input file '$VIASH_PAR_FASTA_REFERENCE' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_REGIONS_FILE" ] && [ ! -e "$VIASH_PAR_REGIONS_FILE" ]; then + ViashError "Input file '$VIASH_PAR_REGIONS_FILE' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_SAMPLES_FILE" ] && [ ! -e "$VIASH_PAR_SAMPLES_FILE" ]; then + ViashError "Input file '$VIASH_PAR_SAMPLES_FILE' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_TARGETS_FILE" ] && [ ! -e "$VIASH_PAR_TARGETS_FILE" ]; then + ViashError "Input file '$VIASH_PAR_TARGETS_FILE' does not exist." + exit 1 +fi + +# check whether parameters values are of the right type +if [[ -n "$VIASH_PAR_FIRST_ALLELE_ONLY" ]]; then + if ! [[ "$VIASH_PAR_FIRST_ALLELE_ONLY" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--first_allele_only' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +if [[ -n "$VIASH_PAR_SPLIT_BY_ID" ]]; then + if ! [[ "$VIASH_PAR_SPLIT_BY_ID" =~ ^(true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO)$ ]]; then + ViashError '--split_by_ID' has to be a boolean_true. Use "--help" to get more information on the parameters. + exit 1 + fi +fi +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 + +# check whether value is belongs to a set of choices +if [ ! -z "$VIASH_PAR_COLLAPSE" ]; then + VIASH_PAR_COLLAPSE_CHOICES=("snps;indels;both;all;some;none") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_COLLAPSE_CHOICES[*]};" =~ ";$VIASH_PAR_COLLAPSE;" ]]; then + ViashError '--collapse' specified value of \'$VIASH_PAR_COLLAPSE\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_REGIONS_OVERLAP" ]; then + VIASH_PAR_REGIONS_OVERLAP_CHOICES=("pos;record;variant;0;1;2") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_REGIONS_OVERLAP_CHOICES[*]};" =~ ";$VIASH_PAR_REGIONS_OVERLAP;" ]]; then + ViashError '--regions_overlap' specified value of \'$VIASH_PAR_REGIONS_OVERLAP\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +fi + +if [ ! -z "$VIASH_PAR_TARGETS_OVERLAPS" ]; then + VIASH_PAR_TARGETS_OVERLAPS_CHOICES=("pos;record;variant;0;1;2") + IFS=';' + set -f + if ! [[ ";${VIASH_PAR_TARGETS_OVERLAPS_CHOICES[*]};" =~ ";$VIASH_PAR_TARGETS_OVERLAPS;" ]]; then + ViashError '--targets_overlaps' specified value of \'$VIASH_PAR_TARGETS_OVERLAPS\' is not in the list of allowed values. Use "--help" to get more information on the parameters. + exit 1 + fi + set +f + unset IFS +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_TEST_INPUT=() + IFS=';' + for var in $VIASH_PAR_INPUT; do + unset IFS + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$var")" ) + var=$(ViashDockerAutodetectMount "$var") + VIASH_TEST_INPUT+=( "$var" ) + done + VIASH_PAR_INPUT=$(IFS=';' ; echo "${VIASH_TEST_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_PAR_ALLELE_FREQUENCY_BINS_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE")" ) + VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE") +fi +if [ ! -z "$VIASH_PAR_EXONS" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_EXONS")" ) + VIASH_PAR_EXONS=$(ViashDockerAutodetectMount "$VIASH_PAR_EXONS") +fi +if [ ! -z "$VIASH_PAR_FASTA_REFERENCE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_FASTA_REFERENCE")" ) + VIASH_PAR_FASTA_REFERENCE=$(ViashDockerAutodetectMount "$VIASH_PAR_FASTA_REFERENCE") +fi +if [ ! -z "$VIASH_PAR_REGIONS_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_REGIONS_FILE")" ) + VIASH_PAR_REGIONS_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_REGIONS_FILE") +fi +if [ ! -z "$VIASH_PAR_SAMPLES_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_SAMPLES_FILE")" ) + VIASH_PAR_SAMPLES_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_SAMPLES_FILE") +fi +if [ ! -z "$VIASH_PAR_TARGETS_FILE" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_TARGETS_FILE")" ) + VIASH_PAR_TARGETS_FILE=$(ViashDockerAutodetectMount "$VIASH_PAR_TARGETS_FILE") +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-bcftools_stats-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_ALLELE_FREQUENCY_BINS+x} ]; then echo "${VIASH_PAR_ALLELE_FREQUENCY_BINS}" | sed "s#'#'\"'\"'#g;s#.*#par_allele_frequency_bins='&'#" ; else echo "# par_allele_frequency_bins="; fi ) +$( if [ ! -z ${VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE+x} ]; then echo "${VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_allele_frequency_bins_file='&'#" ; else echo "# par_allele_frequency_bins_file="; fi ) +$( if [ ! -z ${VIASH_PAR_ALLELE_FREQUENCY_TAG+x} ]; then echo "${VIASH_PAR_ALLELE_FREQUENCY_TAG}" | sed "s#'#'\"'\"'#g;s#.*#par_allele_frequency_tag='&'#" ; else echo "# par_allele_frequency_tag="; fi ) +$( if [ ! -z ${VIASH_PAR_FIRST_ALLELE_ONLY+x} ]; then echo "${VIASH_PAR_FIRST_ALLELE_ONLY}" | sed "s#'#'\"'\"'#g;s#.*#par_first_allele_only='&'#" ; else echo "# par_first_allele_only="; fi ) +$( if [ ! -z ${VIASH_PAR_COLLAPSE+x} ]; then echo "${VIASH_PAR_COLLAPSE}" | sed "s#'#'\"'\"'#g;s#.*#par_collapse='&'#" ; else echo "# par_collapse="; fi ) +$( if [ ! -z ${VIASH_PAR_DEPTH+x} ]; then echo "${VIASH_PAR_DEPTH}" | sed "s#'#'\"'\"'#g;s#.*#par_depth='&'#" ; else echo "# par_depth="; fi ) +$( if [ ! -z ${VIASH_PAR_EXCLUDE+x} ]; then echo "${VIASH_PAR_EXCLUDE}" | sed "s#'#'\"'\"'#g;s#.*#par_exclude='&'#" ; else echo "# par_exclude="; fi ) +$( if [ ! -z ${VIASH_PAR_EXONS+x} ]; then echo "${VIASH_PAR_EXONS}" | sed "s#'#'\"'\"'#g;s#.*#par_exons='&'#" ; else echo "# par_exons="; fi ) +$( if [ ! -z ${VIASH_PAR_APPLY_FILTERS+x} ]; then echo "${VIASH_PAR_APPLY_FILTERS}" | sed "s#'#'\"'\"'#g;s#.*#par_apply_filters='&'#" ; else echo "# par_apply_filters="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTA_REFERENCE+x} ]; then echo "${VIASH_PAR_FASTA_REFERENCE}" | sed "s#'#'\"'\"'#g;s#.*#par_fasta_reference='&'#" ; else echo "# par_fasta_reference="; fi ) +$( if [ ! -z ${VIASH_PAR_INCLUDE+x} ]; then echo "${VIASH_PAR_INCLUDE}" | sed "s#'#'\"'\"'#g;s#.*#par_include='&'#" ; else echo "# par_include="; fi ) +$( if [ ! -z ${VIASH_PAR_SPLIT_BY_ID+x} ]; then echo "${VIASH_PAR_SPLIT_BY_ID}" | sed "s#'#'\"'\"'#g;s#.*#par_split_by_ID='&'#" ; else echo "# par_split_by_ID="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS+x} ]; then echo "${VIASH_PAR_REGIONS}" | sed "s#'#'\"'\"'#g;s#.*#par_regions='&'#" ; else echo "# par_regions="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_FILE+x} ]; then echo "${VIASH_PAR_REGIONS_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_regions_file='&'#" ; else echo "# par_regions_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_OVERLAP+x} ]; then echo "${VIASH_PAR_REGIONS_OVERLAP}" | sed "s#'#'\"'\"'#g;s#.*#par_regions_overlap='&'#" ; else echo "# par_regions_overlap="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLES+x} ]; then echo "${VIASH_PAR_SAMPLES}" | sed "s#'#'\"'\"'#g;s#.*#par_samples='&'#" ; else echo "# par_samples="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLES_FILE+x} ]; then echo "${VIASH_PAR_SAMPLES_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_samples_file='&'#" ; else echo "# par_samples_file="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS+x} ]; then echo "${VIASH_PAR_TARGETS}" | sed "s#'#'\"'\"'#g;s#.*#par_targets='&'#" ; else echo "# par_targets="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS_FILE+x} ]; then echo "${VIASH_PAR_TARGETS_FILE}" | sed "s#'#'\"'\"'#g;s#.*#par_targets_file='&'#" ; else echo "# par_targets_file="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS_OVERLAPS+x} ]; then echo "${VIASH_PAR_TARGETS_OVERLAPS}" | sed "s#'#'\"'\"'#g;s#.*#par_targets_overlaps='&'#" ; else echo "# par_targets_overlaps="; fi ) +$( if [ ! -z ${VIASH_PAR_USER_TSTV+x} ]; then echo "${VIASH_PAR_USER_TSTV}" | sed "s#'#'\"'\"'#g;s#.*#par_user_tstv='&'#" ; else echo "# par_user_tstv="; 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 + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_first_allele_only + par_split_by_ID + par_verbose +) + +for par in \${unset_if_false[@]}; do + test_val="\${!par}" + [[ "\$test_val" == "false" ]] && unset \$par +done + +# Create input array +IFS=";" read -ra input <<< \$par_input + +# Check the size of the input array +if [[ \${#input[@]} -gt 2 ]]; then + echo "Error: --input only takes a max of two files!" + exit 1 +fi + +# Execute bcftools stats with the provided arguments +bcftools stats \\ + \${par_first_allele_only:+--1st-allele-only} \\ + \${par_split_by_ID:+--split-by-ID} \\ + \${par_verbose:+--verbose} \\ + \${par_allele_frequency_bins:+--af-bins "\${par_allele_frequency_bins}"} \\ + \${par_allele_frequency_bins_file:+--af-bins "\${par_allele_frequency_bins_file}"} \\ + \${par_allele_frequency_tag:+--af-tag "\${par_allele_frequency_tag}"} \\ + \${par_collapse:+-c "\${par_collapse}"} \\ + \${par_depth:+-d "\${par_depth}"} \\ + \${par_exclude:+-e "\${par_exclude}"} \\ + \${par_exons:+-E "\${par_exons}"} \\ + \${par_apply_filters:+-f "\${par_apply_filters}"} \\ + \${par_fasta_reference:+-F "\${par_fasta_reference}"} \\ + \${par_include:+-i "\${par_include}"} \\ + \${par_regions:+-r "\${par_regions}"} \\ + \${par_regions_file:+-R "\${par_regions_file}"} \\ + \${par_regions_overlap:+--regions-overlap "\${par_regions_overlap}"} \\ + \${par_samples:+-s "\${par_samples}"} \\ + \${par_samples_file:+-S "\${par_samples_file}"} \\ + \${par_targets:+-t "\${par_targets}"} \\ + \${par_targets_file:+-T "\${par_targets_file}"} \\ + \${par_targets_overlaps:+--targets-overlap "\${par_targets_overlaps}"} \\ + \${par_user_tstv:+-u "\${par_user_tstv}"} \\ + "\${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 + unset VIASH_TEST_INPUT + IFS=';' + for var in $VIASH_PAR_INPUT; do + unset IFS + if [ -z "$VIASH_TEST_INPUT" ]; then + VIASH_TEST_INPUT="$(ViashDockerStripAutomount "$var")" + else + VIASH_TEST_INPUT="$VIASH_TEST_INPUT;""$(ViashDockerStripAutomount "$var")" + fi + done + VIASH_PAR_INPUT="$VIASH_TEST_INPUT" + fi + if [ ! -z "$VIASH_PAR_OUTPUT" ]; then + VIASH_PAR_OUTPUT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT") + fi + if [ ! -z "$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE" ]; then + VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE") + fi + if [ ! -z "$VIASH_PAR_EXONS" ]; then + VIASH_PAR_EXONS=$(ViashDockerStripAutomount "$VIASH_PAR_EXONS") + fi + if [ ! -z "$VIASH_PAR_FASTA_REFERENCE" ]; then + VIASH_PAR_FASTA_REFERENCE=$(ViashDockerStripAutomount "$VIASH_PAR_FASTA_REFERENCE") + fi + if [ ! -z "$VIASH_PAR_REGIONS_FILE" ]; then + VIASH_PAR_REGIONS_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_REGIONS_FILE") + fi + if [ ! -z "$VIASH_PAR_SAMPLES_FILE" ]; then + VIASH_PAR_SAMPLES_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_SAMPLES_FILE") + fi + if [ ! -z "$VIASH_PAR_TARGETS_FILE" ]; then + VIASH_PAR_TARGETS_FILE=$(ViashDockerStripAutomount "$VIASH_PAR_TARGETS_FILE") + 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/bcl_convert/.config.vsh.yaml b/target/executable/bcl_convert/.config.vsh.yaml index 9bf58504..03b3b0a2 100644 --- a/target/executable/bcl_convert/.config.vsh.yaml +++ b/target/executable/bcl_convert/.config.vsh.yaml @@ -418,8 +418,8 @@ build_info: output: "target/executable/bcl_convert" executable: "target/executable/bcl_convert/bcl_convert" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bcl_convert/bcl_convert b/target/executable/bcl_convert/bcl_convert index 5d3b1ed2..5d0427e1 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-09-10T07:43:35Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:06Z" LABEL org.opencontainers.image.source="https://github.com/viash-hub/biobox" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" 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 118635c8..5b7756fe 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 @@ -270,8 +270,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" 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 9fd444b1..4cc94177 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 @@ -549,9 +549,9 @@ RUN echo "bdgenomics/rhapsody: 2.2.1" > /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-09-10T07:43:39Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:09Z" LABEL org.opencontainers.image.source="https://bitbucket.org/CRSwDev/cwl/src/master/v2.2.1/Extra_Utilities/" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_bamtofastq/.config.vsh.yaml b/target/executable/bedtools/bedtools_bamtofastq/.config.vsh.yaml index 5d2336f9..958df897 100644 --- a/target/executable/bedtools/bedtools_bamtofastq/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_bamtofastq/.config.vsh.yaml @@ -187,8 +187,8 @@ build_info: output: "target/executable/bedtools/bedtools_bamtofastq" executable: "target/executable/bedtools/bedtools_bamtofastq/bedtools_bamtofastq" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_bamtofastq/bedtools_bamtofastq b/target/executable/bedtools/bedtools_bamtofastq/bedtools_bamtofastq index 34ffc7ec..57db784d 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-09-10T07:43:21Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:50Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_bed12tobed6/.config.vsh.yaml b/target/executable/bedtools/bedtools_bed12tobed6/.config.vsh.yaml index 9c9e27d1..cc1653be 100644 --- a/target/executable/bedtools/bedtools_bed12tobed6/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_bed12tobed6/.config.vsh.yaml @@ -176,8 +176,8 @@ build_info: output: "target/executable/bedtools/bedtools_bed12tobed6" executable: "target/executable/bedtools/bedtools_bed12tobed6/bedtools_bed12tobed6" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_bed12tobed6/bedtools_bed12tobed6 b/target/executable/bedtools/bedtools_bed12tobed6/bedtools_bed12tobed6 index a91ea2dc..bbf89b38 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-09-10T07:43:19Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:49Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_bedtobam/.config.vsh.yaml b/target/executable/bedtools/bedtools_bedtobam/.config.vsh.yaml index 07e1a787..61d5d218 100644 --- a/target/executable/bedtools/bedtools_bedtobam/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_bedtobam/.config.vsh.yaml @@ -214,8 +214,8 @@ build_info: output: "target/executable/bedtools/bedtools_bedtobam" executable: "target/executable/bedtools/bedtools_bedtobam/bedtools_bedtobam" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_bedtobam/bedtools_bedtobam b/target/executable/bedtools/bedtools_bedtobam/bedtools_bedtobam index dde8b737..54e9b4ba 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-09-10T07:43:22Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:51Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_genomecov/.config.vsh.yaml b/target/executable/bedtools/bedtools_genomecov/.config.vsh.yaml index f8266566..d1478d4c 100644 --- a/target/executable/bedtools/bedtools_genomecov/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_genomecov/.config.vsh.yaml @@ -337,8 +337,8 @@ build_info: output: "target/executable/bedtools/bedtools_genomecov" executable: "target/executable/bedtools/bedtools_genomecov/bedtools_genomecov" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_genomecov/bedtools_genomecov b/target/executable/bedtools/bedtools_genomecov/bedtools_genomecov index e41abc7e..981e1d24 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-09-10T07:43:19Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:48Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_getfasta/.config.vsh.yaml b/target/executable/bedtools/bedtools_getfasta/.config.vsh.yaml index 96ddbc51..5327d71f 100644 --- a/target/executable/bedtools/bedtools_getfasta/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_getfasta/.config.vsh.yaml @@ -232,8 +232,8 @@ build_info: output: "target/executable/bedtools/bedtools_getfasta" executable: "target/executable/bedtools/bedtools_getfasta/bedtools_getfasta" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_getfasta/bedtools_getfasta b/target/executable/bedtools/bedtools_getfasta/bedtools_getfasta index f9a8f93a..06e09f57 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-09-10T07:43:20Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:49Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_groupby/.config.vsh.yaml b/target/executable/bedtools/bedtools_groupby/.config.vsh.yaml index 86315fe3..18f22367 100644 --- a/target/executable/bedtools/bedtools_groupby/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_groupby/.config.vsh.yaml @@ -273,8 +273,8 @@ build_info: output: "target/executable/bedtools/bedtools_groupby" executable: "target/executable/bedtools/bedtools_groupby/bedtools_groupby" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_groupby/bedtools_groupby b/target/executable/bedtools/bedtools_groupby/bedtools_groupby index 00e79832..9c047112 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-09-10T07:43:21Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:50Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_intersect/.config.vsh.yaml b/target/executable/bedtools/bedtools_intersect/.config.vsh.yaml index 3a46c43d..973d3ddd 100644 --- a/target/executable/bedtools/bedtools_intersect/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_intersect/.config.vsh.yaml @@ -410,8 +410,8 @@ build_info: output: "target/executable/bedtools/bedtools_intersect" executable: "target/executable/bedtools/bedtools_intersect/bedtools_intersect" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_intersect/bedtools_intersect b/target/executable/bedtools/bedtools_intersect/bedtools_intersect index c78a7c5b..7bb8e219 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-09-10T07:43:20Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:49Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_links/.config.vsh.yaml b/target/executable/bedtools/bedtools_links/.config.vsh.yaml index a8fb4e5e..d217b6f4 100644 --- a/target/executable/bedtools/bedtools_links/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_links/.config.vsh.yaml @@ -210,8 +210,8 @@ build_info: output: "target/executable/bedtools/bedtools_links" executable: "target/executable/bedtools/bedtools_links/bedtools_links" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_links/bedtools_links b/target/executable/bedtools/bedtools_links/bedtools_links index ee48bd21..463b338f 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-09-10T07:43:20Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:50Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_merge/.config.vsh.yaml b/target/executable/bedtools/bedtools_merge/.config.vsh.yaml index 8928e38b..13ae60ed 100644 --- a/target/executable/bedtools/bedtools_merge/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_merge/.config.vsh.yaml @@ -279,8 +279,8 @@ build_info: output: "target/executable/bedtools/bedtools_merge" executable: "target/executable/bedtools/bedtools_merge/bedtools_merge" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_merge/bedtools_merge b/target/executable/bedtools/bedtools_merge/bedtools_merge index d635bc9b..1a86ae66 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-09-10T07:43:18Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:48Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/bedtools/bedtools_sort/.config.vsh.yaml b/target/executable/bedtools/bedtools_sort/.config.vsh.yaml index 3e4cf5b0..1dd665e3 100644 --- a/target/executable/bedtools/bedtools_sort/.config.vsh.yaml +++ b/target/executable/bedtools/bedtools_sort/.config.vsh.yaml @@ -222,8 +222,8 @@ build_info: output: "target/executable/bedtools/bedtools_sort" executable: "target/executable/bedtools/bedtools_sort/bedtools_sort" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/bedtools/bedtools_sort/bedtools_sort b/target/executable/bedtools/bedtools_sort/bedtools_sort index 37a27f9d..779210ec 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-09-10T07:43:21Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:51Z" LABEL org.opencontainers.image.source="https://github.com/arq5x/bedtools2" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/busco/busco_download_datasets/.config.vsh.yaml b/target/executable/busco/busco_download_datasets/.config.vsh.yaml index 0d67348c..9582a5e2 100644 --- a/target/executable/busco/busco_download_datasets/.config.vsh.yaml +++ b/target/executable/busco/busco_download_datasets/.config.vsh.yaml @@ -158,8 +158,8 @@ build_info: output: "target/executable/busco/busco_download_datasets" executable: "target/executable/busco/busco_download_datasets/busco_download_datasets" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/busco/busco_download_datasets/busco_download_datasets b/target/executable/busco/busco_download_datasets/busco_download_datasets index 6d21142d..d0136afe 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-09-10T07:43:31Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:02Z" LABEL org.opencontainers.image.source="https://gitlab.com/ezlab/busco" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/busco/busco_list_datasets/.config.vsh.yaml b/target/executable/busco/busco_list_datasets/.config.vsh.yaml index 3bb89cb2..d1071103 100644 --- a/target/executable/busco/busco_list_datasets/.config.vsh.yaml +++ b/target/executable/busco/busco_list_datasets/.config.vsh.yaml @@ -145,8 +145,8 @@ build_info: output: "target/executable/busco/busco_list_datasets" executable: "target/executable/busco/busco_list_datasets/busco_list_datasets" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/busco/busco_list_datasets/busco_list_datasets b/target/executable/busco/busco_list_datasets/busco_list_datasets index 7011486d..23615eab 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-09-10T07:43:31Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:02Z" LABEL org.opencontainers.image.source="https://gitlab.com/ezlab/busco" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/busco/busco_run/.config.vsh.yaml b/target/executable/busco/busco_run/.config.vsh.yaml index 3badfd63..d825b944 100644 --- a/target/executable/busco/busco_run/.config.vsh.yaml +++ b/target/executable/busco/busco_run/.config.vsh.yaml @@ -423,8 +423,8 @@ build_info: output: "target/executable/busco/busco_run" executable: "target/executable/busco/busco_run/busco_run" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/busco/busco_run/busco_run b/target/executable/busco/busco_run/busco_run index 178f2fad..c3633644 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-09-10T07:43:32Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:02Z" LABEL org.opencontainers.image.source="https://gitlab.com/ezlab/busco" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/cutadapt/.config.vsh.yaml b/target/executable/cutadapt/.config.vsh.yaml index de17bb78..3f937525 100644 --- a/target/executable/cutadapt/.config.vsh.yaml +++ b/target/executable/cutadapt/.config.vsh.yaml @@ -740,8 +740,8 @@ build_info: output: "target/executable/cutadapt" executable: "target/executable/cutadapt/cutadapt" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/cutadapt/cutadapt b/target/executable/cutadapt/cutadapt index 419c3c92..a902d970 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-09-10T07:43:37Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:08Z" LABEL org.opencontainers.image.source="https://github.com/marcelm/cutadapt" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/falco/.config.vsh.yaml b/target/executable/falco/.config.vsh.yaml index 522b503e..0492a168 100644 --- a/target/executable/falco/.config.vsh.yaml +++ b/target/executable/falco/.config.vsh.yaml @@ -317,8 +317,8 @@ build_info: output: "target/executable/falco" executable: "target/executable/falco/falco" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/falco/falco b/target/executable/falco/falco index de628890..9e1cc59b 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-09-10T07:43:38Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:09Z" LABEL org.opencontainers.image.source="https://github.com/smithlabcode/falco" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/fastp/.config.vsh.yaml b/target/executable/fastp/.config.vsh.yaml index f050ce87..012bc9e4 100644 --- a/target/executable/fastp/.config.vsh.yaml +++ b/target/executable/fastp/.config.vsh.yaml @@ -1083,8 +1083,8 @@ build_info: output: "target/executable/fastp" executable: "target/executable/fastp/fastp" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/fastp/fastp b/target/executable/fastp/fastp index 55e02cfe..aa0f2ef9 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-09-10T07:43:34Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:05Z" LABEL org.opencontainers.image.source="https://github.com/OpenGene/fastp" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/fastqc/.config.vsh.yaml b/target/executable/fastqc/.config.vsh.yaml index 82f0ea6e..7fef8319 100644 --- a/target/executable/fastqc/.config.vsh.yaml +++ b/target/executable/fastqc/.config.vsh.yaml @@ -340,8 +340,8 @@ build_info: output: "target/executable/fastqc" executable: "target/executable/fastqc/fastqc" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/fastqc/fastqc b/target/executable/fastqc/fastqc index 08ddd579..4e1a2ed6 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-09-10T07:43:27Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:56Z" LABEL org.opencontainers.image.source="https://github.com/s-andrews/FastQC" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/featurecounts/.config.vsh.yaml b/target/executable/featurecounts/.config.vsh.yaml index dc84f2ee..a9bd1b67 100644 --- a/target/executable/featurecounts/.config.vsh.yaml +++ b/target/executable/featurecounts/.config.vsh.yaml @@ -645,8 +645,8 @@ build_info: output: "target/executable/featurecounts" executable: "target/executable/featurecounts/featurecounts" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/featurecounts/featurecounts b/target/executable/featurecounts/featurecounts index a6e9162a..28b0a570 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-09-10T07:43:29Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:00Z" LABEL org.opencontainers.image.source="https://github.com/ShiLab-Bioinformatics/subread" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/fq_subsample/.config.vsh.yaml b/target/executable/fq_subsample/.config.vsh.yaml index c951f8ab..47ed4b08 100644 --- a/target/executable/fq_subsample/.config.vsh.yaml +++ b/target/executable/fq_subsample/.config.vsh.yaml @@ -190,8 +190,8 @@ build_info: output: "target/executable/fq_subsample" executable: "target/executable/fq_subsample/fq_subsample" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/fq_subsample/fq_subsample b/target/executable/fq_subsample/fq_subsample index dba4fe04..b94f8c64 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-09-10T07:43:26Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:56Z" LABEL org.opencontainers.image.source="https://github.com/stjude-rust-labs/fq" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/gffread/.config.vsh.yaml b/target/executable/gffread/.config.vsh.yaml index 6fb05de2..05192f7c 100644 --- a/target/executable/gffread/.config.vsh.yaml +++ b/target/executable/gffread/.config.vsh.yaml @@ -685,8 +685,8 @@ build_info: output: "target/executable/gffread" executable: "target/executable/gffread/gffread" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/gffread/gffread b/target/executable/gffread/gffread index 7c039120..874dce93 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-09-10T07:43:18Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:47Z" LABEL org.opencontainers.image.source="https://github.com/gpertea/gffread" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/lofreq/lofreq_call/.config.vsh.yaml b/target/executable/lofreq/lofreq_call/.config.vsh.yaml index fcf83da5..ccc47ca0 100644 --- a/target/executable/lofreq/lofreq_call/.config.vsh.yaml +++ b/target/executable/lofreq/lofreq_call/.config.vsh.yaml @@ -507,8 +507,8 @@ build_info: output: "target/executable/lofreq/lofreq_call" executable: "target/executable/lofreq/lofreq_call/lofreq_call" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/lofreq/lofreq_call/lofreq_call b/target/executable/lofreq/lofreq_call/lofreq_call index e0a35117..e4b41eee 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-09-10T07:43:29Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:59Z" LABEL org.opencontainers.image.source="https://github.com/viash-hub/biobox" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/lofreq/lofreq_indelqual/.config.vsh.yaml b/target/executable/lofreq/lofreq_indelqual/.config.vsh.yaml index 84daab16..523bd850 100644 --- a/target/executable/lofreq/lofreq_indelqual/.config.vsh.yaml +++ b/target/executable/lofreq/lofreq_indelqual/.config.vsh.yaml @@ -215,8 +215,8 @@ build_info: output: "target/executable/lofreq/lofreq_indelqual" executable: "target/executable/lofreq/lofreq_indelqual/lofreq_indelqual" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/lofreq/lofreq_indelqual/lofreq_indelqual b/target/executable/lofreq/lofreq_indelqual/lofreq_indelqual index 9f4c117d..118bd9d2 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-09-10T07:43:28Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:59Z" LABEL org.opencontainers.image.source="https://github.com/viash-hub/biobox" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/multiqc/.config.vsh.yaml b/target/executable/multiqc/.config.vsh.yaml index 96be3ec0..deedacd6 100644 --- a/target/executable/multiqc/.config.vsh.yaml +++ b/target/executable/multiqc/.config.vsh.yaml @@ -456,8 +456,8 @@ build_info: output: "target/executable/multiqc" executable: "target/executable/multiqc/multiqc" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/multiqc/multiqc b/target/executable/multiqc/multiqc index 1b40f689..6d4c3d3e 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-09-10T07:43:38Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:08Z" LABEL org.opencontainers.image.source="https://github.com/viash-hub/biobox" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/pear/.config.vsh.yaml b/target/executable/pear/.config.vsh.yaml index f7cebb34..176ecbae 100644 --- a/target/executable/pear/.config.vsh.yaml +++ b/target/executable/pear/.config.vsh.yaml @@ -398,8 +398,8 @@ build_info: output: "target/executable/pear" executable: "target/executable/pear/pear" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/pear/pear b/target/executable/pear/pear index acd94269..840f8b9a 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-09-10T07:43:22Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:51Z" LABEL org.opencontainers.image.source="https://github.com/tseemann/PEAR" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/qualimap/qualimap_rnaseq/.config.vsh.yaml b/target/executable/qualimap/qualimap_rnaseq/.config.vsh.yaml index 7b14f9b8..d066bd69 100644 --- a/target/executable/qualimap/qualimap_rnaseq/.config.vsh.yaml +++ b/target/executable/qualimap/qualimap_rnaseq/.config.vsh.yaml @@ -264,8 +264,8 @@ build_info: output: "target/executable/qualimap/qualimap_rnaseq" executable: "target/executable/qualimap/qualimap_rnaseq/qualimap_rnaseq" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/qualimap/qualimap_rnaseq/qualimap_rnaseq b/target/executable/qualimap/qualimap_rnaseq/qualimap_rnaseq index a7568169..c0b45aea 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-09-10T07:43:26Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:55Z" LABEL org.opencontainers.image.source="https://bitbucket.org/kokonech/qualimap/commits/branch/master" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/rsem/rsem_prepare_reference/.config.vsh.yaml b/target/executable/rsem/rsem_prepare_reference/.config.vsh.yaml index 3e890f1d..ebc93e5d 100644 --- a/target/executable/rsem/rsem_prepare_reference/.config.vsh.yaml +++ b/target/executable/rsem/rsem_prepare_reference/.config.vsh.yaml @@ -416,8 +416,8 @@ build_info: output: "target/executable/rsem/rsem_prepare_reference" executable: "target/executable/rsem/rsem_prepare_reference/rsem_prepare_reference" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/rsem/rsem_prepare_reference/rsem_prepare_reference b/target/executable/rsem/rsem_prepare_reference/rsem_prepare_reference index e562feac..dce46a46 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-09-10T07:43:32Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:03Z" LABEL org.opencontainers.image.source="https://github.com/deweylab/RSEM" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/salmon/salmon_index/.config.vsh.yaml b/target/executable/salmon/salmon_index/.config.vsh.yaml index d1a26bdb..e8f19dd6 100644 --- a/target/executable/salmon/salmon_index/.config.vsh.yaml +++ b/target/executable/salmon/salmon_index/.config.vsh.yaml @@ -277,8 +277,8 @@ build_info: output: "target/executable/salmon/salmon_index" executable: "target/executable/salmon/salmon_index/salmon_index" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/salmon/salmon_index/salmon_index b/target/executable/salmon/salmon_index/salmon_index index 227be01e..e10ccd81 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-09-10T07:43:36Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:07Z" LABEL org.opencontainers.image.source="https://github.com/COMBINE-lab/salmon" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/salmon/salmon_quant/.config.vsh.yaml b/target/executable/salmon/salmon_quant/.config.vsh.yaml index ba202cd9..9c13978b 100644 --- a/target/executable/salmon/salmon_quant/.config.vsh.yaml +++ b/target/executable/salmon/salmon_quant/.config.vsh.yaml @@ -1173,8 +1173,8 @@ build_info: output: "target/executable/salmon/salmon_quant" executable: "target/executable/salmon/salmon_quant/salmon_quant" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/salmon/salmon_quant/salmon_quant b/target/executable/salmon/salmon_quant/salmon_quant index 5a6cad83..48905fda 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-09-10T07:43:37Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:07Z" LABEL org.opencontainers.image.source="https://github.com/COMBINE-lab/salmon" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_collate/.config.vsh.yaml b/target/executable/samtools/samtools_collate/.config.vsh.yaml index 04b6ec6d..c2bb1890 100644 --- a/target/executable/samtools/samtools_collate/.config.vsh.yaml +++ b/target/executable/samtools/samtools_collate/.config.vsh.yaml @@ -264,8 +264,8 @@ build_info: output: "target/executable/samtools/samtools_collate" executable: "target/executable/samtools/samtools_collate/samtools_collate" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_collate/samtools_collate b/target/executable/samtools/samtools_collate/samtools_collate index c48eb053..2a7aa1de 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-09-10T07:43:25Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:54Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_faidx/.config.vsh.yaml b/target/executable/samtools/samtools_faidx/.config.vsh.yaml index d6ad8339..2a0d2ae2 100644 --- a/target/executable/samtools/samtools_faidx/.config.vsh.yaml +++ b/target/executable/samtools/samtools_faidx/.config.vsh.yaml @@ -243,8 +243,8 @@ build_info: output: "target/executable/samtools/samtools_faidx" executable: "target/executable/samtools/samtools_faidx/samtools_faidx" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_faidx/samtools_faidx b/target/executable/samtools/samtools_faidx/samtools_faidx index 615e3c65..61609d0a 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-09-10T07:43:24Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:53Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_fasta/.config.vsh.yaml b/target/executable/samtools/samtools_fasta/.config.vsh.yaml index a5ff0768..dad748e3 100644 --- a/target/executable/samtools/samtools_fasta/.config.vsh.yaml +++ b/target/executable/samtools/samtools_fasta/.config.vsh.yaml @@ -433,8 +433,8 @@ build_info: output: "target/executable/samtools/samtools_fasta" executable: "target/executable/samtools/samtools_fasta/samtools_fasta" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_fasta/samtools_fasta b/target/executable/samtools/samtools_fasta/samtools_fasta index ce5002c8..3c8c7693 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-09-10T07:43:25Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:54Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_fastq/.config.vsh.yaml b/target/executable/samtools/samtools_fastq/.config.vsh.yaml index 922eb08e..fa3e509e 100644 --- a/target/executable/samtools/samtools_fastq/.config.vsh.yaml +++ b/target/executable/samtools/samtools_fastq/.config.vsh.yaml @@ -433,8 +433,8 @@ build_info: output: "target/executable/samtools/samtools_fastq" executable: "target/executable/samtools/samtools_fastq/samtools_fastq" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_fastq/samtools_fastq b/target/executable/samtools/samtools_fastq/samtools_fastq index 7aa35b9c..8d631dd4 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-09-10T07:43:24Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:53Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_flagstat/.config.vsh.yaml b/target/executable/samtools/samtools_flagstat/.config.vsh.yaml index fe680c62..73636c6b 100644 --- a/target/executable/samtools/samtools_flagstat/.config.vsh.yaml +++ b/target/executable/samtools/samtools_flagstat/.config.vsh.yaml @@ -173,8 +173,8 @@ build_info: output: "target/executable/samtools/samtools_flagstat" executable: "target/executable/samtools/samtools_flagstat/samtools_flagstat" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_flagstat/samtools_flagstat b/target/executable/samtools/samtools_flagstat/samtools_flagstat index f4c28db8..c77aa93e 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-09-10T07:43:23Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:53Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_idxstats/.config.vsh.yaml b/target/executable/samtools/samtools_idxstats/.config.vsh.yaml index 56deb7c1..c6812213 100644 --- a/target/executable/samtools/samtools_idxstats/.config.vsh.yaml +++ b/target/executable/samtools/samtools_idxstats/.config.vsh.yaml @@ -183,8 +183,8 @@ build_info: output: "target/executable/samtools/samtools_idxstats" executable: "target/executable/samtools/samtools_idxstats/samtools_idxstats" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_idxstats/samtools_idxstats b/target/executable/samtools/samtools_idxstats/samtools_idxstats index 417d3158..4c157fb7 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-09-10T07:43:23Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:52Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_index/.config.vsh.yaml b/target/executable/samtools/samtools_index/.config.vsh.yaml index a7012ace..b644769c 100644 --- a/target/executable/samtools/samtools_index/.config.vsh.yaml +++ b/target/executable/samtools/samtools_index/.config.vsh.yaml @@ -189,8 +189,8 @@ build_info: output: "target/executable/samtools/samtools_index" executable: "target/executable/samtools/samtools_index/samtools_index" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_index/samtools_index b/target/executable/samtools/samtools_index/samtools_index index b52136fe..4d58622c 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-09-10T07:43:22Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:52Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_sort/.config.vsh.yaml b/target/executable/samtools/samtools_sort/.config.vsh.yaml index 62ff1dbf..a0d4386a 100644 --- a/target/executable/samtools/samtools_sort/.config.vsh.yaml +++ b/target/executable/samtools/samtools_sort/.config.vsh.yaml @@ -332,8 +332,8 @@ build_info: output: "target/executable/samtools/samtools_sort" executable: "target/executable/samtools/samtools_sort/samtools_sort" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_sort/samtools_sort b/target/executable/samtools/samtools_sort/samtools_sort index 5d9c1b44..ad035913 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-09-10T07:43:25Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:55Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_stats/.config.vsh.yaml b/target/executable/samtools/samtools_stats/.config.vsh.yaml index 69015235..55780bbb 100644 --- a/target/executable/samtools/samtools_stats/.config.vsh.yaml +++ b/target/executable/samtools/samtools_stats/.config.vsh.yaml @@ -401,8 +401,8 @@ build_info: output: "target/executable/samtools/samtools_stats" executable: "target/executable/samtools/samtools_stats/samtools_stats" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_stats/samtools_stats b/target/executable/samtools/samtools_stats/samtools_stats index 09235c35..38a61110 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-09-10T07:43:26Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:55Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/samtools/samtools_view/.config.vsh.yaml b/target/executable/samtools/samtools_view/.config.vsh.yaml index 6c4b6644..7fcd5044 100644 --- a/target/executable/samtools/samtools_view/.config.vsh.yaml +++ b/target/executable/samtools/samtools_view/.config.vsh.yaml @@ -665,8 +665,8 @@ build_info: output: "target/executable/samtools/samtools_view" executable: "target/executable/samtools/samtools_view/samtools_view" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/samtools/samtools_view/samtools_view b/target/executable/samtools/samtools_view/samtools_view index 57131ad8..13318139 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-09-10T07:43:23Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:52Z" LABEL org.opencontainers.image.source="https://github.com/samtools/samtools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/seqtk/seqtk_sample/.config.vsh.yaml b/target/executable/seqtk/seqtk_sample/.config.vsh.yaml index c9ca689f..4360be11 100644 --- a/target/executable/seqtk/seqtk_sample/.config.vsh.yaml +++ b/target/executable/seqtk/seqtk_sample/.config.vsh.yaml @@ -173,8 +173,8 @@ build_info: output: "target/executable/seqtk/seqtk_sample" executable: "target/executable/seqtk/seqtk_sample/seqtk_sample" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/seqtk/seqtk_sample/seqtk_sample b/target/executable/seqtk/seqtk_sample/seqtk_sample index 87f34870..6f839b46 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-09-10T07:43:39Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:10Z" LABEL org.opencontainers.image.source="https://github.com/lh3/seqtk/tree/v1.4" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/seqtk/seqtk_subseq/.config.vsh.yaml b/target/executable/seqtk/seqtk_subseq/.config.vsh.yaml index 01062d53..8b5c8bc6 100644 --- a/target/executable/seqtk/seqtk_subseq/.config.vsh.yaml +++ b/target/executable/seqtk/seqtk_subseq/.config.vsh.yaml @@ -196,8 +196,8 @@ build_info: output: "target/executable/seqtk/seqtk_subseq" executable: "target/executable/seqtk/seqtk_subseq/seqtk_subseq" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/seqtk/seqtk_subseq/seqtk_subseq b/target/executable/seqtk/seqtk_subseq/seqtk_subseq index 49a155a9..6268ccfa 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-09-10T07:43:39Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:10Z" LABEL org.opencontainers.image.source="https://github.com/lh3/seqtk/tree/v1.4" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/sortmerna/.config.vsh.yaml b/target/executable/sortmerna/.config.vsh.yaml index 1af90977..46eb1de5 100644 --- a/target/executable/sortmerna/.config.vsh.yaml +++ b/target/executable/sortmerna/.config.vsh.yaml @@ -591,8 +591,8 @@ build_info: output: "target/executable/sortmerna" executable: "target/executable/sortmerna/sortmerna" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/sortmerna/sortmerna b/target/executable/sortmerna/sortmerna index 2ed63543..f0f5be40 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-09-10T07:43:35Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:06Z" LABEL org.opencontainers.image.source="https://github.com/sortmerna/sortmerna" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/star/star_align_reads/.config.vsh.yaml b/target/executable/star/star_align_reads/.config.vsh.yaml index cc51e93a..b0e025a1 100644 --- a/target/executable/star/star_align_reads/.config.vsh.yaml +++ b/target/executable/star/star_align_reads/.config.vsh.yaml @@ -2663,8 +2663,8 @@ build_info: output: "target/executable/star/star_align_reads" executable: "target/executable/star/star_align_reads/star_align_reads" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/star/star_align_reads/star_align_reads b/target/executable/star/star_align_reads/star_align_reads index 73e2ca26..be54464f 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-09-10T07:43:30Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:01Z" LABEL org.opencontainers.image.source="https://github.com/alexdobin/STAR" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/star/star_genome_generate/.config.vsh.yaml b/target/executable/star/star_genome_generate/.config.vsh.yaml index 6b1c7185..96b31bf7 100644 --- a/target/executable/star/star_genome_generate/.config.vsh.yaml +++ b/target/executable/star/star_genome_generate/.config.vsh.yaml @@ -333,8 +333,8 @@ build_info: output: "target/executable/star/star_genome_generate" executable: "target/executable/star/star_genome_generate/star_genome_generate" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/star/star_genome_generate/star_genome_generate b/target/executable/star/star_genome_generate/star_genome_generate index 6bd8ef04..d509ecc9 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-09-10T07:43:29Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:00Z" LABEL org.opencontainers.image.source="https://github.com/alexdobin/STAR" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/executable/trimgalore/.config.vsh.yaml b/target/executable/trimgalore/.config.vsh.yaml index 21a09348..53fd668d 100644 --- a/target/executable/trimgalore/.config.vsh.yaml +++ b/target/executable/trimgalore/.config.vsh.yaml @@ -70,13 +70,59 @@ argument_groups: direction: "input" - type: "string" name: "--fastqc_args" - description: "Passes extra arguments to FastQC. If more than one argument is to\ - \ be passed to FastQC they must be in the form \"arg1 arg2 ...\". Passing extra\ - \ arguments will automatically invoke FastQC, so --fastqc does not have to be\ - \ specified separately." + description: "Passes extra arguments (excluding files) to FastQC. If more than\ + \ one argument is to be passed to FastQC they must be in the form \"arg1 arg2\ + \ ...\". Passing extra arguments will automatically invoke FastQC, so --fastqc\ + \ does not have to be specified separately." info: null example: - - "--nogroup --outdir /home/" + - "--nogroup --noextract" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fastqc_contaminants" + description: "Specifies a non-default file which contains the list of contaminants\ + \ for FastQC to screen overrepresented sequences against. The file must contain\ + \ sets of named contaminants in the form name[tab]sequence. Lines prefixed with\ + \ a hash will be ignored." + info: null + example: + - "contaminants.txt" + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fastqc_adapters" + description: "Specifies a non-default file which contains the list of adapter\ + \ sequences which which FasstQC will explicity search against the library. The\ + \ file must contain sets of named adapters in the form name[tab]sequence. Lines\ + \ prefixed with a hash will be ignored." + info: null + example: + - "adapters.txt" + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fastqc_limits" + description: "Specifies a non-default file which contains a set of criteria which\ + \ FastQC will use to determine the warn/error limits for the various modules.\ + \ This file can also be used to selectively remove some modules from the output\ + \ all together. The format needs to mirror the default limits.txt file found\ + \ in the Configuration folder." + info: null + example: + - "limits.txt" + must_exist: true + create_parent: true required: false direction: "input" multiple: false @@ -472,7 +518,7 @@ argument_groups: - "trimmed_output" must_exist: true create_parent: true - required: false + required: true direction: "output" multiple: false multiple_sep: ";" @@ -724,8 +770,8 @@ build_info: output: "target/executable/trimgalore" executable: "target/executable/trimgalore/trimgalore" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/executable/trimgalore/trimgalore b/target/executable/trimgalore/trimgalore index c87a0d99..b4d10b6e 100755 --- a/target/executable/trimgalore/trimgalore +++ b/target/executable/trimgalore/trimgalore @@ -215,11 +215,36 @@ function ViashHelp { echo "" echo " --fastqc_args" echo " type: string" - echo " example: --nogroup --outdir /home/" - echo " Passes extra arguments to FastQC. If more than one argument is to be" - echo " passed to FastQC they must be in the form \"arg1 arg2 ...\". Passing extra" - echo " arguments will automatically invoke FastQC, so --fastqc does not have to" - echo " be specified separately." + echo " example: --nogroup --noextract" + echo " Passes extra arguments (excluding files) to FastQC. If more than one" + echo " argument is to be passed to FastQC they must be in the form \"arg1 arg2" + echo " ...\". Passing extra arguments will automatically invoke FastQC, so" + echo " --fastqc does not have to be specified separately." + echo "" + echo " --fastqc_contaminants" + echo " type: file, file must exist" + echo " example: contaminants.txt" + echo " Specifies a non-default file which contains the list of contaminants for" + echo " FastQC to screen overrepresented sequences against. The file must" + echo " contain sets of named contaminants in the form name[tab]sequence. Lines" + echo " prefixed with a hash will be ignored." + echo "" + echo " --fastqc_adapters" + echo " type: file, file must exist" + echo " example: adapters.txt" + echo " Specifies a non-default file which contains the list of adapter" + echo " sequences which which FasstQC will explicity search against the library." + echo " The file must contain sets of named adapters in the form" + echo " name[tab]sequence. Lines prefixed with a hash will be ignored." + echo "" + echo " --fastqc_limits" + echo " type: file, file must exist" + echo " example: limits.txt" + echo " Specifies a non-default file which contains a set of criteria which" + echo " FastQC will use to determine the warn/error limits for the various" + echo " modules. This file can also be used to selectively remove some modules" + echo " from the output all together. The format needs to mirror the default" + echo " limits.txt file found in the Configuration folder." echo "" echo " -a, --adapter" echo " type: string" @@ -507,7 +532,7 @@ function ViashHelp { echo "" echo "Output:" echo " -o, --output_dir" - echo " type: file, output, file must exist" + echo " type: file, required parameter, output, file must exist" echo " default: trimmed_output" echo " If specified all output will be written to this directory instead of the" echo " current directory." @@ -856,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-09-10T07:43:34Z" +LABEL org.opencontainers.image.created="2024-09-19T08:36:05Z" LABEL org.opencontainers.image.source="https://github.com/FelixKrueger/TrimGalore" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER @@ -1058,6 +1083,39 @@ while [[ $# -gt 0 ]]; do VIASH_PAR_FASTQC_ARGS=$(ViashRemoveFlags "$1") shift 1 ;; + --fastqc_contaminants) + [ -n "$VIASH_PAR_FASTQC_CONTAMINANTS" ] && ViashError Bad arguments for option \'--fastqc_contaminants\': \'$VIASH_PAR_FASTQC_CONTAMINANTS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTQC_CONTAMINANTS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --fastqc_contaminants. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --fastqc_contaminants=*) + [ -n "$VIASH_PAR_FASTQC_CONTAMINANTS" ] && ViashError Bad arguments for option \'--fastqc_contaminants=*\': \'$VIASH_PAR_FASTQC_CONTAMINANTS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTQC_CONTAMINANTS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --fastqc_adapters) + [ -n "$VIASH_PAR_FASTQC_ADAPTERS" ] && ViashError Bad arguments for option \'--fastqc_adapters\': \'$VIASH_PAR_FASTQC_ADAPTERS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTQC_ADAPTERS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --fastqc_adapters. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --fastqc_adapters=*) + [ -n "$VIASH_PAR_FASTQC_ADAPTERS" ] && ViashError Bad arguments for option \'--fastqc_adapters=*\': \'$VIASH_PAR_FASTQC_ADAPTERS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTQC_ADAPTERS=$(ViashRemoveFlags "$1") + shift 1 + ;; + --fastqc_limits) + [ -n "$VIASH_PAR_FASTQC_LIMITS" ] && ViashError Bad arguments for option \'--fastqc_limits\': \'$VIASH_PAR_FASTQC_LIMITS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTQC_LIMITS="$2" + [ $# -lt 2 ] && ViashError Not enough arguments passed to --fastqc_limits. Use "--help" to get more information on the parameters. && exit 1 + shift 2 + ;; + --fastqc_limits=*) + [ -n "$VIASH_PAR_FASTQC_LIMITS" ] && ViashError Bad arguments for option \'--fastqc_limits=*\': \'$VIASH_PAR_FASTQC_LIMITS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 + VIASH_PAR_FASTQC_LIMITS=$(ViashRemoveFlags "$1") + shift 1 + ;; --adapter) [ -n "$VIASH_PAR_ADAPTER" ] && ViashError Bad arguments for option \'--adapter\': \'$VIASH_PAR_ADAPTER\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1 VIASH_PAR_ADAPTER="$2" @@ -1674,6 +1732,10 @@ 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_DIR+x} ]; then + ViashError '--output_dir' 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 @@ -1760,9 +1822,6 @@ fi if [ -z ${VIASH_PAR_RETAIN_UNPAIRED+x} ]; then VIASH_PAR_RETAIN_UNPAIRED="false" fi -if [ -z ${VIASH_PAR_OUTPUT_DIR+x} ]; then - VIASH_PAR_OUTPUT_DIR="trimmed_output" -fi # check whether required files exist if [ ! -z "$VIASH_PAR_INPUT" ]; then @@ -1777,6 +1836,18 @@ if [ ! -z "$VIASH_PAR_INPUT" ]; then done set +f fi +if [ ! -z "$VIASH_PAR_FASTQC_CONTAMINANTS" ] && [ ! -e "$VIASH_PAR_FASTQC_CONTAMINANTS" ]; then + ViashError "Input file '$VIASH_PAR_FASTQC_CONTAMINANTS' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_FASTQC_ADAPTERS" ] && [ ! -e "$VIASH_PAR_FASTQC_ADAPTERS" ]; then + ViashError "Input file '$VIASH_PAR_FASTQC_ADAPTERS' does not exist." + exit 1 +fi +if [ ! -z "$VIASH_PAR_FASTQC_LIMITS" ] && [ ! -e "$VIASH_PAR_FASTQC_LIMITS" ]; then + ViashError "Input file '$VIASH_PAR_FASTQC_LIMITS' does not exist." + exit 1 +fi # check whether parameters values are of the right type if [[ -n "$VIASH_PAR_QUALITY" ]]; then @@ -2126,6 +2197,18 @@ if [ ! -z "$VIASH_PAR_INPUT" ]; then done VIASH_PAR_INPUT=$(IFS=';' ; echo "${VIASH_TEST_INPUT[*]}") fi +if [ ! -z "$VIASH_PAR_FASTQC_CONTAMINANTS" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_FASTQC_CONTAMINANTS")" ) + VIASH_PAR_FASTQC_CONTAMINANTS=$(ViashDockerAutodetectMount "$VIASH_PAR_FASTQC_CONTAMINANTS") +fi +if [ ! -z "$VIASH_PAR_FASTQC_ADAPTERS" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_FASTQC_ADAPTERS")" ) + VIASH_PAR_FASTQC_ADAPTERS=$(ViashDockerAutodetectMount "$VIASH_PAR_FASTQC_ADAPTERS") +fi +if [ ! -z "$VIASH_PAR_FASTQC_LIMITS" ]; then + VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_FASTQC_LIMITS")" ) + VIASH_PAR_FASTQC_LIMITS=$(ViashDockerAutodetectMount "$VIASH_PAR_FASTQC_LIMITS") +fi if [ ! -z "$VIASH_PAR_OUTPUT_DIR" ]; then VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT_DIR")" ) VIASH_PAR_OUTPUT_DIR=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT_DIR") @@ -2256,6 +2339,9 @@ $( if [ ! -z ${VIASH_PAR_PHRED33+x} ]; then echo "${VIASH_PAR_PHRED33}" | sed "s $( if [ ! -z ${VIASH_PAR_PHRED64+x} ]; then echo "${VIASH_PAR_PHRED64}" | sed "s#'#'\"'\"'#g;s#.*#par_phred64='&'#" ; else echo "# par_phred64="; fi ) $( if [ ! -z ${VIASH_PAR_FASTQC+x} ]; then echo "${VIASH_PAR_FASTQC}" | sed "s#'#'\"'\"'#g;s#.*#par_fastqc='&'#" ; else echo "# par_fastqc="; fi ) $( if [ ! -z ${VIASH_PAR_FASTQC_ARGS+x} ]; then echo "${VIASH_PAR_FASTQC_ARGS}" | sed "s#'#'\"'\"'#g;s#.*#par_fastqc_args='&'#" ; else echo "# par_fastqc_args="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTQC_CONTAMINANTS+x} ]; then echo "${VIASH_PAR_FASTQC_CONTAMINANTS}" | sed "s#'#'\"'\"'#g;s#.*#par_fastqc_contaminants='&'#" ; else echo "# par_fastqc_contaminants="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTQC_ADAPTERS+x} ]; then echo "${VIASH_PAR_FASTQC_ADAPTERS}" | sed "s#'#'\"'\"'#g;s#.*#par_fastqc_adapters='&'#" ; else echo "# par_fastqc_adapters="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTQC_LIMITS+x} ]; then echo "${VIASH_PAR_FASTQC_LIMITS}" | sed "s#'#'\"'\"'#g;s#.*#par_fastqc_limits='&'#" ; else echo "# par_fastqc_limits="; fi ) $( if [ ! -z ${VIASH_PAR_ADAPTER+x} ]; then echo "${VIASH_PAR_ADAPTER}" | sed "s#'#'\"'\"'#g;s#.*#par_adapter='&'#" ; else echo "# par_adapter="; fi ) $( if [ ! -z ${VIASH_PAR_ADAPTER2+x} ]; then echo "${VIASH_PAR_ADAPTER2}" | sed "s#'#'\"'\"'#g;s#.*#par_adapter2='&'#" ; else echo "# par_adapter2="; fi ) $( if [ ! -z ${VIASH_PAR_ILLUMINA+x} ]; then echo "${VIASH_PAR_ILLUMINA}" | sed "s#'#'\"'\"'#g;s#.*#par_illumina='&'#" ; else echo "# par_illumina="; fi ) @@ -2358,12 +2444,24 @@ for par in \${unset_if_false[@]}; do [[ "\$test_val" == "false" ]] && unset \$par done +# Add FastQC file arguments to fastqc_args +fastqc_args="\${par_fastqc_args}" +if [ -f "\$par_fastqc_contaminants" ]; then + fastqc_args+=" --contaminants \$par_fastqc_contaminants" +fi +if [ -f "\$par_fastqc_adapters" ]; then + fastqc_args+=" --adapters \$par_fastqc_adapters" +fi +if [ -f "\$par_fastqc_limits" ]; then + fastqc_args+=" --limits \$par_fastqc_limits" +fi + trim_galore \\ \${par_quality:+-q "\${par_quality}"} \\ \${par_phred33:+--phred33} \\ \${par_phred64:+--phred64 } \\ \${par_fastqc:+--fastqc } \\ - \${par_fastqc_args:+--fastqc_args "\${par_fastqc_args}"} \\ + \${fastqc_args:+--fastqc_args "\${fastqc_args}"} \\ \${par_adapter:+-a "\${par_adapter}"} \\ \${par_adapter2:+-a2 "\${par_adapter2}"} \\ \${par_illumina:+--illumina} \\ @@ -2459,6 +2557,15 @@ if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then done VIASH_PAR_INPUT="$VIASH_TEST_INPUT" fi + if [ ! -z "$VIASH_PAR_FASTQC_CONTAMINANTS" ]; then + VIASH_PAR_FASTQC_CONTAMINANTS=$(ViashDockerStripAutomount "$VIASH_PAR_FASTQC_CONTAMINANTS") + fi + if [ ! -z "$VIASH_PAR_FASTQC_ADAPTERS" ]; then + VIASH_PAR_FASTQC_ADAPTERS=$(ViashDockerStripAutomount "$VIASH_PAR_FASTQC_ADAPTERS") + fi + if [ ! -z "$VIASH_PAR_FASTQC_LIMITS" ]; then + VIASH_PAR_FASTQC_LIMITS=$(ViashDockerStripAutomount "$VIASH_PAR_FASTQC_LIMITS") + fi if [ ! -z "$VIASH_PAR_OUTPUT_DIR" ]; then VIASH_PAR_OUTPUT_DIR=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT_DIR") fi 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 df8c4ef8..c2e3ac78 100644 --- a/target/executable/umi_tools/umi_tools_dedup/.config.vsh.yaml +++ b/target/executable/umi_tools/umi_tools_dedup/.config.vsh.yaml @@ -611,8 +611,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" 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 8efbeed8..7dbceb1f 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-09-10T07:43:27Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:57Z" LABEL org.opencontainers.image.source="https://github.com/CGATOxford/UMI-tools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" 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 1a8aacf2..94154a02 100644 --- a/target/executable/umi_tools/umi_tools_extract/.config.vsh.yaml +++ b/target/executable/umi_tools/umi_tools_extract/.config.vsh.yaml @@ -449,8 +449,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" 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 151dbaf7..f66eb0a1 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-09-10T07:43:27Z" +LABEL org.opencontainers.image.created="2024-09-19T08:35:56Z" LABEL org.opencontainers.image.source="https://github.com/CGATOxford/UMI-tools" -LABEL org.opencontainers.image.revision="89fb3575f697065135a647a21efb3815efe66e44" +LABEL org.opencontainers.image.revision="90735159b7bafa4aa8643eb132534d078ea299cf" LABEL org.opencontainers.image.version="add_trimgalore" VIASHDOCKER diff --git a/target/nextflow/agat/agat_convert_bed2gff/.config.vsh.yaml b/target/nextflow/agat/agat_convert_bed2gff/.config.vsh.yaml index d0f085a5..c87dfd14 100644 --- a/target/nextflow/agat/agat_convert_bed2gff/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_bed2gff/.config.vsh.yaml @@ -235,8 +235,8 @@ build_info: output: "target/nextflow/agat/agat_convert_bed2gff" executable: "target/nextflow/agat/agat_convert_bed2gff/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/agat/agat_convert_bed2gff/main.nf b/target/nextflow/agat/agat_convert_bed2gff/main.nf index e65aca46..24347690 100644 --- a/target/nextflow/agat/agat_convert_bed2gff/main.nf +++ b/target/nextflow/agat/agat_convert_bed2gff/main.nf @@ -3086,8 +3086,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_bed2gff", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 889bcf82..b9b52839 100644 --- a/target/nextflow/agat/agat_convert_embl2gff/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_embl2gff/.config.vsh.yaml @@ -225,8 +225,8 @@ build_info: output: "target/nextflow/agat/agat_convert_embl2gff" executable: "target/nextflow/agat/agat_convert_embl2gff/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/agat/agat_convert_embl2gff/main.nf b/target/nextflow/agat/agat_convert_embl2gff/main.nf index 6bf85b82..dd8e1777 100644 --- a/target/nextflow/agat/agat_convert_embl2gff/main.nf +++ b/target/nextflow/agat/agat_convert_embl2gff/main.nf @@ -3079,8 +3079,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_embl2gff", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 5462a65a..9c808d5a 100644 --- a/target/nextflow/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_sp_gff2gtf/.config.vsh.yaml @@ -228,8 +228,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/agat/agat_convert_sp_gff2gtf/main.nf b/target/nextflow/agat/agat_convert_sp_gff2gtf/main.nf index 08780abd..a759b591 100644 --- a/target/nextflow/agat/agat_convert_sp_gff2gtf/main.nf +++ b/target/nextflow/agat/agat_convert_sp_gff2gtf/main.nf @@ -3062,8 +3062,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_sp_gff2gtf", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 05de79da..bc390a8a 100644 --- a/target/nextflow/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_sp_gff2tsv/.config.vsh.yaml @@ -188,8 +188,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/agat/agat_convert_sp_gff2tsv/main.nf b/target/nextflow/agat/agat_convert_sp_gff2tsv/main.nf index e417971b..0bae9336 100644 --- a/target/nextflow/agat/agat_convert_sp_gff2tsv/main.nf +++ b/target/nextflow/agat/agat_convert_sp_gff2tsv/main.nf @@ -3040,8 +3040,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_sp_gff2tsv", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 04313b3c..4880bda6 100644 --- a/target/nextflow/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml +++ b/target/nextflow/agat/agat_convert_sp_gxf2gxf/.config.vsh.yaml @@ -195,8 +195,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/agat/agat_convert_sp_gxf2gxf/main.nf b/target/nextflow/agat/agat_convert_sp_gxf2gxf/main.nf index 53d5eade..0d1cc66c 100644 --- a/target/nextflow/agat/agat_convert_sp_gxf2gxf/main.nf +++ b/target/nextflow/agat/agat_convert_sp_gxf2gxf/main.nf @@ -3040,8 +3040,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/agat/agat_convert_sp_gxf2gxf", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/arriba/.config.vsh.yaml b/target/nextflow/arriba/.config.vsh.yaml index e7e581af..8dbdbea6 100644 --- a/target/nextflow/arriba/.config.vsh.yaml +++ b/target/nextflow/arriba/.config.vsh.yaml @@ -706,8 +706,8 @@ build_info: output: "target/nextflow/arriba" executable: "target/nextflow/arriba/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/arriba/main.nf b/target/nextflow/arriba/main.nf index b51d7c8e..1194b3eb 100644 --- a/target/nextflow/arriba/main.nf +++ b/target/nextflow/arriba/main.nf @@ -3586,8 +3586,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/arriba", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bcftools/bcftools_annotate/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_annotate/.config.vsh.yaml new file mode 100644 index 00000000..0e839002 --- /dev/null +++ b/target/nextflow/bcftools/bcftools_annotate/.config.vsh.yaml @@ -0,0 +1,495 @@ +name: "bcftools_annotate" +namespace: "bcftools" +version: "add_trimgalore" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + 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 VCF/BCF file." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: true + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + description: "Output annotated file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + description: "For examples on how to use use bcftools annotate see http://samtools.github.io/bcftools/howtos/annotate.html.\n\ + For more details on the options see https://samtools.github.io/bcftools/bcftools.html#annotate.\n" + arguments: + - type: "file" + name: "--annotations" + alternatives: + - "--a" + description: "VCF file or tabix-indexed FILE with annotations: CHR\\tPOS[\\tVALUE]+\ + \ . \n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--columns" + alternatives: + - "--c" + description: "List of columns in the annotation file, e.g. CHROM,POS,REF,ALT,-,INFO/TAG.\ + \ \nSee man page for details.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--columns_file" + alternatives: + - "--C" + description: "Read -c columns from FILE, one name per row, with optional --merge_logic\ + \ TYPE: NAME[ TYPE].\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--exclude" + alternatives: + - "--e" + description: "Exclude sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions\ + \ for details.\n" + info: null + example: + - "QUAL >= 30 && DP >= 10" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--force" + description: "continue even when parsing errors, such as undefined tags, are encountered.\ + \ \nNote this can be an unsafe operation and can result in corrupted BCF files.\ + \ \nIf this option is used, make sure to sanity check the result thoroughly.\n" + info: null + direction: "input" + - type: "string" + name: "--header_line" + alternatives: + - "--H" + description: "Header line which should be appended to the VCF header, can be given\ + \ multiple times.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--header_lines" + alternatives: + - "--h" + description: "File with header lines to append to the VCF header.\nFor example:\n\ + \ ##INFO=\n ##INFO=\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--set_id" + alternatives: + - "--I" + description: "Set ID column using a `bcftools query`-like expression, see man\ + \ page for details.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--include" + description: "Select sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions\ + \ for details.\n" + info: null + example: + - "QUAL >= 30 && DP >= 10" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--keep_sites" + alternatives: + - "--k" + description: "Leave --include/--exclude sites unchanged instead of discarding\ + \ them.\n" + info: null + direction: "input" + - type: "string" + name: "--merge_logic" + alternatives: + - "--l" + description: "When multiple regions overlap a single record, this option defines\ + \ how to treat multiple annotation values.\nSee man page for more details.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--mark_sites" + alternatives: + - "--m" + description: "Annotate sites which are present (\"+\") or absent (\"-\") in the\ + \ -a file with a new INFO/TAG flag.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--min_overlap" + description: "Minimum overlap required as a fraction of the variant in the annotation\ + \ -a file (ANN), \nin the target VCF file (:VCF), or both for reciprocal overlap\ + \ (ANN:VCF). \nBy default overlaps of arbitrary length are sufficient. \nThe\ + \ option can be used only with the tab-delimited annotation -a file and with\ + \ BEG and END columns present.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--no_version" + description: "Do not append version and command line information to the output\ + \ VCF header.\n" + info: null + direction: "input" + - type: "string" + name: "--output_type" + alternatives: + - "--O" + description: "Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed\ + \ BCF\n v: uncompressed VCF\n" + info: null + required: false + choices: + - "u" + - "z" + - "b" + - "v" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--pair_logic" + description: "Controls how to match records from the annotation file to the target\ + \ VCF. \nEffective only when -a is a VCF or BCF file. \nThe option replaces\ + \ the former uninuitive --collapse. \nSee Common Options for more.\n" + info: null + required: false + choices: + - "snps" + - "indels" + - "both" + - "all" + - "some" + - "exact" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions" + alternatives: + - "--r" + description: "Restrict to comma-separated list of regions. \nFollowing formats\ + \ are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--regions_file" + alternatives: + - "--R" + description: "Restrict to regions listed in a file. \nRegions can be specified\ + \ either on a VCF, BED, or tab-delimited file (the default). \nFor more information\ + \ check manual.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions_overlap" + description: "This option controls how overlapping records are determined: \n\ + set to 'pos' or '0' if the VCF record has to have POS inside a region (this\ + \ corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if\ + \ also overlapping records with POS outside a region should be included (this\ + \ is the default behavior of -r/-R, \nand includes indels with POS at the end\ + \ of a region, which are technically outside the region); \nor set to 'variant'\ + \ or '2' to include only true overlapping variation (compare the full VCF representation\ + \ \"TA>T-\" vs the true sequence variation \"A>-\").\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--rename_annotations" + description: "Rename annotations: TYPE/old\\tnew, where TYPE is one of FILTER,INFO,FORMAT.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--rename_chromosomes" + description: "Rename chromosomes according to the map in file, with \"old_name\ + \ new_name\\n\" pairs \nseparated by whitespaces, each on a separate line.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--samples" + description: "Subset of samples to annotate.\nSee also https://samtools.github.io/bcftools/bcftools.html#common_options.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--samples_file" + description: "Subset of samples to annotate in file format.\nSee also https://samtools.github.io/bcftools/bcftools.html#common_options.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--single_overlaps" + description: "Use this option to keep memory requirements low with very large\ + \ annotation files. \nNote, however, that this comes at a cost, only single\ + \ overlapping intervals are considered in this mode. \nThis was the default\ + \ mode until the commit af6f0c9 (Feb 24 2019).\n" + info: null + direction: "input" + - type: "string" + name: "--remove" + alternatives: + - "--x" + description: "List of annotations to remove. \nUse \"FILTER\" to remove all filters\ + \ or \"FILTER/SomeFilter\" to remove a specific filter. \nSimilarly, \"INFO\"\ + \ can be used to remove all INFO tags and \"FORMAT\" to remove all FORMAT tags\ + \ except GT. \nTo remove all INFO tags except \"FOO\" and \"BAR\", use \"^INFO/FOO,INFO/BAR\"\ + \ (and similarly for FORMAT and FILTER). \n\"INFO\" can be abbreviated to \"\ + INF\" and \"FORMAT\" to \"FMT\".\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Add or remove annotations from a VCF/BCF file.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Annotate" +- "VCF" +- "BCF" +license: "MIT/Expat, GNU" +references: + doi: + - "https://doi.org/10.1093/gigascience/giab008" +links: + repository: "https://github.com/samtools/bcftools" + homepage: "https://samtools.github.io/bcftools/" + documentation: "https://samtools.github.io/bcftools/bcftools.html#annotate" + issue_tracker: "https://github.com/samtools/bcftools/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: "add_trimgalore" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bcftools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bcftools: \\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools\ + \ //p')\\\"\" > /var/software_versions.txt\n" + test_setup: + - type: "apt" + packages: + - "tabix" + interactive: false + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bcftools/bcftools_annotate/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/bcftools/bcftools_annotate" + executable: "target/nextflow/bcftools/bcftools_annotate/main.nf" + viash_version: "0.9.0-RC7" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" +package_config: + name: "biobox" + version: "add_trimgalore" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0-RC7" + 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 := 'add_trimgalore'" + 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/bcftools/bcftools_annotate/main.nf b/target/nextflow/bcftools/bcftools_annotate/main.nf new file mode 100644 index 00000000..bd10d358 --- /dev/null +++ b/target/nextflow/bcftools/bcftools_annotate/main.nf @@ -0,0 +1,3948 @@ +// bcftools_annotate add_trimgalore +// +// This wrapper script is auto-generated by viash 0.9.0-RC7 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) + +//////////////////////////// +// 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('\\$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('\\$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('\\$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" : "bcftools_annotate", + "namespace" : "bcftools", + "version" : "add_trimgalore", + "authors" : [ + { + "name" : "Theodoro Gasperin Terra Camargo", + "roles" : [ + "author" + ], + "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 VCF/BCF file.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : true, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Outputs", + "arguments" : [ + { + "type" : "file", + "name" : "--output", + "alternatives" : [ + "-o" + ], + "description" : "Output annotated file.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Options", + "description" : "For examples on how to use use bcftools annotate see http://samtools.github.io/bcftools/howtos/annotate.html.\nFor more details on the options see https://samtools.github.io/bcftools/bcftools.html#annotate.\n", + "arguments" : [ + { + "type" : "file", + "name" : "--annotations", + "alternatives" : [ + "--a" + ], + "description" : "VCF file or tabix-indexed FILE with annotations: CHR\\\\tPOS[\\\\tVALUE]+ . \n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--columns", + "alternatives" : [ + "--c" + ], + "description" : "List of columns in the annotation file, e.g. CHROM,POS,REF,ALT,-,INFO/TAG. \nSee man page for details.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--columns_file", + "alternatives" : [ + "--C" + ], + "description" : "Read -c columns from FILE, one name per row, with optional --merge_logic TYPE: NAME[ TYPE].\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--exclude", + "alternatives" : [ + "--e" + ], + "description" : "Exclude sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions for details.\n", + "example" : [ + "QUAL >= 30 && DP >= 10" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--force", + "description" : "continue even when parsing errors, such as undefined tags, are encountered. \nNote this can be an unsafe operation and can result in corrupted BCF files. \nIf this option is used, make sure to sanity check the result thoroughly.\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--header_line", + "alternatives" : [ + "--H" + ], + "description" : "Header line which should be appended to the VCF header, can be given multiple times.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--header_lines", + "alternatives" : [ + "--h" + ], + "description" : "File with header lines to append to the VCF header.\nFor example:\n ##INFO=\n ##INFO=\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--set_id", + "alternatives" : [ + "--I" + ], + "description" : "Set ID column using a `bcftools query`-like expression, see man page for details.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--include", + "description" : "Select sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions for details.\n", + "example" : [ + "QUAL >= 30 && DP >= 10" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--keep_sites", + "alternatives" : [ + "--k" + ], + "description" : "Leave --include/--exclude sites unchanged instead of discarding them.\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--merge_logic", + "alternatives" : [ + "--l" + ], + "description" : "When multiple regions overlap a single record, this option defines how to treat multiple annotation values.\nSee man page for more details.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--mark_sites", + "alternatives" : [ + "--m" + ], + "description" : "Annotate sites which are present (\\"+\\") or absent (\\"-\\") in the -a file with a new INFO/TAG flag.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--min_overlap", + "description" : "Minimum overlap required as a fraction of the variant in the annotation -a file (ANN), \nin the target VCF file (:VCF), or both for reciprocal overlap (ANN:VCF). \nBy default overlaps of arbitrary length are sufficient. \nThe option can be used only with the tab-delimited annotation -a file and with BEG and END columns present.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--no_version", + "description" : "Do not append version and command line information to the output VCF header.\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--output_type", + "alternatives" : [ + "--O" + ], + "description" : "Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed BCF\n v: uncompressed VCF\n", + "required" : false, + "choices" : [ + "u", + "z", + "b", + "v" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--pair_logic", + "description" : "Controls how to match records from the annotation file to the target VCF. \nEffective only when -a is a VCF or BCF file. \nThe option replaces the former uninuitive --collapse. \nSee Common Options for more.\n", + "required" : false, + "choices" : [ + "snps", + "indels", + "both", + "all", + "some", + "exact" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--regions", + "alternatives" : [ + "--r" + ], + "description" : "Restrict to comma-separated list of regions. \nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n", + "example" : [ + "20:1000000-2000000" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--regions_file", + "alternatives" : [ + "--R" + ], + "description" : "Restrict to regions listed in a file. \nRegions can be specified either on a VCF, BED, or tab-delimited file (the default). \nFor more information check manual.\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--regions_overlap", + "description" : "This option controls how overlapping records are determined: \nset to 'pos' or '0' if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to 'variant' or '2' to include only true overlapping variation (compare the full VCF representation \\"TA>T-\\" vs the true sequence variation \\"A>-\\").\n", + "required" : false, + "choices" : [ + "pos", + "record", + "variant", + "0", + "1", + "2" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--rename_annotations", + "description" : "Rename annotations: TYPE/old\\\\tnew, where TYPE is one of FILTER,INFO,FORMAT.\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--rename_chromosomes", + "description" : "Rename chromosomes according to the map in file, with \\"old_name new_name\\\\n\\" pairs \nseparated by whitespaces, each on a separate line.\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--samples", + "description" : "Subset of samples to annotate.\nSee also https://samtools.github.io/bcftools/bcftools.html#common_options.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--samples_file", + "description" : "Subset of samples to annotate in file format.\nSee also https://samtools.github.io/bcftools/bcftools.html#common_options.\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--single_overlaps", + "description" : "Use this option to keep memory requirements low with very large annotation files. \nNote, however, that this comes at a cost, only single overlapping intervals are considered in this mode. \nThis was the default mode until the commit af6f0c9 (Feb 24 2019).\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--remove", + "alternatives" : [ + "--x" + ], + "description" : "List of annotations to remove. \nUse \\"FILTER\\" to remove all filters or \\"FILTER/SomeFilter\\" to remove a specific filter. \nSimilarly, \\"INFO\\" can be used to remove all INFO tags and \\"FORMAT\\" to remove all FORMAT tags except GT. \nTo remove all INFO tags except \\"FOO\\" and \\"BAR\\", use \\"^INFO/FOO,INFO/BAR\\" (and similarly for FORMAT and FILTER). \n\\"INFO\\" can be abbreviated to \\"INF\\" and \\"FORMAT\\" to \\"FMT\\".\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Add or remove annotations from a VCF/BCF file.\n", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "keywords" : [ + "Annotate", + "VCF", + "BCF" + ], + "license" : "MIT/Expat, GNU", + "references" : { + "doi" : [ + "https://doi.org/10.1093/gigascience/giab008" + ] + }, + "links" : { + "repository" : "https://github.com/samtools/bcftools", + "homepage" : "https://samtools.github.io/bcftools/", + "documentation" : "https://samtools.github.io/bcftools/bcftools.html#annotate", + "issue_tracker" : "https://github.com/samtools/bcftools/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" : "add_trimgalore", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "apt", + "packages" : [ + "bcftools", + "procps" + ], + "interactive" : false + }, + { + "type" : "docker", + "run" : [ + "echo \\"bcftools: \\\\\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\\\\\\"\\" > /var/software_versions.txt\n" + ] + } + ], + "test_setup" : [ + { + "type" : "apt", + "packages" : [ + "tabix" + ], + "interactive" : false + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/bcftools/bcftools_annotate/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/bcftools/bcftools_annotate", + "viash_version" : "0.9.0-RC7", + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" + }, + "package_config" : { + "name" : "biobox", + "version" : "add_trimgalore", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0-RC7", + "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 := 'add_trimgalore'" + ], + "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_ANNOTATIONS+x} ]; then echo "${VIASH_PAR_ANNOTATIONS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_annotations='&'#" ; else echo "# par_annotations="; fi ) +$( if [ ! -z ${VIASH_PAR_COLUMNS+x} ]; then echo "${VIASH_PAR_COLUMNS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_columns='&'#" ; else echo "# par_columns="; fi ) +$( if [ ! -z ${VIASH_PAR_COLUMNS_FILE+x} ]; then echo "${VIASH_PAR_COLUMNS_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_columns_file='&'#" ; else echo "# par_columns_file="; fi ) +$( if [ ! -z ${VIASH_PAR_EXCLUDE+x} ]; then echo "${VIASH_PAR_EXCLUDE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_exclude='&'#" ; else echo "# par_exclude="; fi ) +$( if [ ! -z ${VIASH_PAR_FORCE+x} ]; then echo "${VIASH_PAR_FORCE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_force='&'#" ; else echo "# par_force="; fi ) +$( if [ ! -z ${VIASH_PAR_HEADER_LINE+x} ]; then echo "${VIASH_PAR_HEADER_LINE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_header_line='&'#" ; else echo "# par_header_line="; fi ) +$( if [ ! -z ${VIASH_PAR_HEADER_LINES+x} ]; then echo "${VIASH_PAR_HEADER_LINES}" | sed "s#'#'\\"'\\"'#g;s#.*#par_header_lines='&'#" ; else echo "# par_header_lines="; fi ) +$( if [ ! -z ${VIASH_PAR_SET_ID+x} ]; then echo "${VIASH_PAR_SET_ID}" | sed "s#'#'\\"'\\"'#g;s#.*#par_set_id='&'#" ; else echo "# par_set_id="; fi ) +$( if [ ! -z ${VIASH_PAR_INCLUDE+x} ]; then echo "${VIASH_PAR_INCLUDE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_include='&'#" ; else echo "# par_include="; fi ) +$( if [ ! -z ${VIASH_PAR_KEEP_SITES+x} ]; then echo "${VIASH_PAR_KEEP_SITES}" | sed "s#'#'\\"'\\"'#g;s#.*#par_keep_sites='&'#" ; else echo "# par_keep_sites="; fi ) +$( if [ ! -z ${VIASH_PAR_MERGE_LOGIC+x} ]; then echo "${VIASH_PAR_MERGE_LOGIC}" | sed "s#'#'\\"'\\"'#g;s#.*#par_merge_logic='&'#" ; else echo "# par_merge_logic="; fi ) +$( if [ ! -z ${VIASH_PAR_MARK_SITES+x} ]; then echo "${VIASH_PAR_MARK_SITES}" | sed "s#'#'\\"'\\"'#g;s#.*#par_mark_sites='&'#" ; else echo "# par_mark_sites="; fi ) +$( if [ ! -z ${VIASH_PAR_MIN_OVERLAP+x} ]; then echo "${VIASH_PAR_MIN_OVERLAP}" | sed "s#'#'\\"'\\"'#g;s#.*#par_min_overlap='&'#" ; else echo "# par_min_overlap="; fi ) +$( if [ ! -z ${VIASH_PAR_NO_VERSION+x} ]; then echo "${VIASH_PAR_NO_VERSION}" | sed "s#'#'\\"'\\"'#g;s#.*#par_no_version='&'#" ; else echo "# par_no_version="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_TYPE+x} ]; then echo "${VIASH_PAR_OUTPUT_TYPE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output_type='&'#" ; else echo "# par_output_type="; fi ) +$( if [ ! -z ${VIASH_PAR_PAIR_LOGIC+x} ]; then echo "${VIASH_PAR_PAIR_LOGIC}" | sed "s#'#'\\"'\\"'#g;s#.*#par_pair_logic='&'#" ; else echo "# par_pair_logic="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS+x} ]; then echo "${VIASH_PAR_REGIONS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions='&'#" ; else echo "# par_regions="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_FILE+x} ]; then echo "${VIASH_PAR_REGIONS_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions_file='&'#" ; else echo "# par_regions_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_OVERLAP+x} ]; then echo "${VIASH_PAR_REGIONS_OVERLAP}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions_overlap='&'#" ; else echo "# par_regions_overlap="; fi ) +$( if [ ! -z ${VIASH_PAR_RENAME_ANNOTATIONS+x} ]; then echo "${VIASH_PAR_RENAME_ANNOTATIONS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_rename_annotations='&'#" ; else echo "# par_rename_annotations="; fi ) +$( if [ ! -z ${VIASH_PAR_RENAME_CHROMOSOMES+x} ]; then echo "${VIASH_PAR_RENAME_CHROMOSOMES}" | sed "s#'#'\\"'\\"'#g;s#.*#par_rename_chromosomes='&'#" ; else echo "# par_rename_chromosomes="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLES+x} ]; then echo "${VIASH_PAR_SAMPLES}" | sed "s#'#'\\"'\\"'#g;s#.*#par_samples='&'#" ; else echo "# par_samples="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLES_FILE+x} ]; then echo "${VIASH_PAR_SAMPLES_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_samples_file='&'#" ; else echo "# par_samples_file="; fi ) +$( if [ ! -z ${VIASH_PAR_SINGLE_OVERLAPS+x} ]; then echo "${VIASH_PAR_SINGLE_OVERLAPS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_single_overlaps='&'#" ; else echo "# par_single_overlaps="; fi ) +$( if [ ! -z ${VIASH_PAR_REMOVE+x} ]; then echo "${VIASH_PAR_REMOVE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_remove='&'#" ; else echo "# par_remove="; 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 + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_force + par_keep_sites + par_no_version + par_single_overlaps +) + +for par in \\${unset_if_false[@]}; do + test_val="\\${!par}" + [[ "\\$test_val" == "false" ]] && unset \\$par +done + +# Execute bcftools annotate with the provided arguments +bcftools annotate \\\\ + \\${par_annotations:+-a "\\$par_annotations"} \\\\ + \\${par_columns:+-c "\\$par_columns"} \\\\ + \\${par_columns_file:+-C "\\$par_columns_file"} \\\\ + \\${par_exclude:+-e "\\$par_exclude"} \\\\ + \\${par_force:+--force} \\\\ + \\${par_header_line:+-H "\\$par_header_line"} \\\\ + \\${par_header_lines:+-h "\\$par_header_lines"} \\\\ + \\${par_set_id:+-I "\\$par_set_id"} \\\\ + \\${par_include:+-i "\\$par_include"} \\\\ + \\${par_keep_sites:+-k} \\\\ + \\${par_merge_logic:+-l "\\$par_merge_logic"} \\\\ + \\${par_mark_sites:+-m "\\$par_mark_sites"} \\\\ + \\${par_min_overlap:+--min-overlap "\\$par_min_overlap"} \\\\ + \\${par_no_version:+--no-version} \\\\ + \\${par_samples_file:+-S "\\$par_samples_file"} \\\\ + \\${par_output_type:+-O "\\$par_output_type"} \\\\ + \\${par_pair_logic:+--pair-logic "\\$par_pair_logic"} \\\\ + \\${par_regions:+-r "\\$par_regions"} \\\\ + \\${par_regions_file:+-R "\\$par_regions_file"} \\\\ + \\${par_regions_overlap:+--regions-overlap "\\$par_regions_overlap"} \\\\ + \\${par_rename_annotations:+--rename-annots "\\$par_rename_annotations"} \\\\ + \\${par_rename_chromosomes:+--rename-chrs "\\$par_rename_chromosomes"} \\\\ + \\${par_samples:+-s "\\$par_samples"} \\\\ + \\${par_single_overlaps:+--single-overlaps} \\\\ + \\${par_threads:+--threads "\\$par_threads"} \\\\ + \\${par_remove:+-x "\\$par_remove"} \\\\ + -o \\$par_output \\\\ + \\$par_input + + + +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('\\$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 -> + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"] : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def viash_par_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()}=\\\"\" + ${viash_par_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 + | + |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 escapeText = { s -> s.toString().replaceAll('([`"])', '\\\\\\\\\$1') } + |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/bcftools/bcftools_annotate", + "tag" : "add_trimgalore" + }, + "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/bcftools/bcftools_annotate/nextflow.config b/target/nextflow/bcftools/bcftools_annotate/nextflow.config new file mode 100644 index 00000000..3fa4b52d --- /dev/null +++ b/target/nextflow/bcftools/bcftools_annotate/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'bcftools/bcftools_annotate' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'add_trimgalore' + description = 'Add or remove annotations from a VCF/BCF file.\n' + 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/bcftools/bcftools_annotate/nextflow_schema.json b/target/nextflow/bcftools/bcftools_annotate/nextflow_schema.json new file mode 100644 index 00000000..4bda14e8 --- /dev/null +++ b/target/nextflow/bcftools/bcftools_annotate/nextflow_schema.json @@ -0,0 +1,369 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "bcftools_annotate", +"description": "Add or remove annotations from a VCF/BCF file.\n", +"type": "object", +"definitions": { + + + + "inputs" : { + "title": "Inputs", + "type": "object", + "description": "No description", + "properties": { + + + "input": { + "type": + "string", + "description": "Type: List of `file`, required, multiple_sep: `\";\"`. Input VCF/BCF file", + "help_text": "Type: List of `file`, required, multiple_sep: `\";\"`. Input VCF/BCF file." + + } + + +} +}, + + + "outputs" : { + "title": "Outputs", + "type": "object", + "description": "No description", + "properties": { + + + "output": { + "type": + "string", + "description": "Type: `file`, required, default: `$id.$key.output.output`. Output annotated file", + "help_text": "Type: `file`, required, default: `$id.$key.output.output`. Output annotated file." + , + "default": "$id.$key.output.output" + } + + +} +}, + + + "options" : { + "title": "Options", + "type": "object", + "description": "For examples on how to use use bcftools annotate see http://samtools.github.io/bcftools/howtos/annotate.html.\nFor more details on the options see https://samtools.github.io/bcftools/bcftools.html#annotate.\n", + "properties": { + + + "annotations": { + "type": + "string", + "description": "Type: `file`. VCF file or tabix-indexed FILE with annotations: CHR\\tPOS[\\tVALUE]+ ", + "help_text": "Type: `file`. VCF file or tabix-indexed FILE with annotations: CHR\\tPOS[\\tVALUE]+ . \n" + + } + + + , + "columns": { + "type": + "string", + "description": "Type: `string`. List of columns in the annotation file, e", + "help_text": "Type: `string`. List of columns in the annotation file, e.g. CHROM,POS,REF,ALT,-,INFO/TAG. \nSee man page for details.\n" + + } + + + , + "columns_file": { + "type": + "string", + "description": "Type: `file`. Read -c columns from FILE, one name per row, with optional --merge_logic TYPE: NAME[ TYPE]", + "help_text": "Type: `file`. Read -c columns from FILE, one name per row, with optional --merge_logic TYPE: NAME[ TYPE].\n" + + } + + + , + "exclude": { + "type": + "string", + "description": "Type: `string`, example: `QUAL \u003e= 30 \u0026\u0026 DP \u003e= 10`. Exclude sites for which the expression is true", + "help_text": "Type: `string`, example: `QUAL \u003e= 30 \u0026\u0026 DP \u003e= 10`. Exclude sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions for details.\n" + + } + + + , + "force": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. continue even when parsing errors, such as undefined tags, are encountered", + "help_text": "Type: `boolean_true`, default: `false`. continue even when parsing errors, such as undefined tags, are encountered. \nNote this can be an unsafe operation and can result in corrupted BCF files. \nIf this option is used, make sure to sanity check the result thoroughly.\n" + , + "default": "False" + } + + + , + "header_line": { + "type": + "string", + "description": "Type: `string`. Header line which should be appended to the VCF header, can be given multiple times", + "help_text": "Type: `string`. Header line which should be appended to the VCF header, can be given multiple times.\n" + + } + + + , + "header_lines": { + "type": + "string", + "description": "Type: `file`. File with header lines to append to the VCF header", + "help_text": "Type: `file`. File with header lines to append to the VCF header.\nFor example:\n ##INFO=\u003cID=NUMERIC_TAG,Number=1,Type=Integer,Description=\"Example header line\"\u003e\n ##INFO=\u003cID=STRING_TAG,Number=1,Type=String,Description=\"Yet another header line\"\u003e\n" + + } + + + , + "set_id": { + "type": + "string", + "description": "Type: `string`. Set ID column using a `bcftools query`-like expression, see man page for details", + "help_text": "Type: `string`. Set ID column using a `bcftools query`-like expression, see man page for details.\n" + + } + + + , + "include": { + "type": + "string", + "description": "Type: `string`, example: `QUAL \u003e= 30 \u0026\u0026 DP \u003e= 10`. Select sites for which the expression is true", + "help_text": "Type: `string`, example: `QUAL \u003e= 30 \u0026\u0026 DP \u003e= 10`. Select sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions for details.\n" + + } + + + , + "keep_sites": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Leave --include/--exclude sites unchanged instead of discarding them", + "help_text": "Type: `boolean_true`, default: `false`. Leave --include/--exclude sites unchanged instead of discarding them.\n" + , + "default": "False" + } + + + , + "merge_logic": { + "type": + "string", + "description": "Type: `string`. When multiple regions overlap a single record, this option defines how to treat multiple annotation values", + "help_text": "Type: `string`. When multiple regions overlap a single record, this option defines how to treat multiple annotation values.\nSee man page for more details.\n" + + } + + + , + "mark_sites": { + "type": + "string", + "description": "Type: `string`. Annotate sites which are present (\"+\") or absent (\"-\") in the -a file with a new INFO/TAG flag", + "help_text": "Type: `string`. Annotate sites which are present (\"+\") or absent (\"-\") in the -a file with a new INFO/TAG flag.\n" + + } + + + , + "min_overlap": { + "type": + "string", + "description": "Type: `string`. Minimum overlap required as a fraction of the variant in the annotation -a file (ANN), \nin the target VCF file (:VCF), or both for reciprocal overlap (ANN:VCF)", + "help_text": "Type: `string`. Minimum overlap required as a fraction of the variant in the annotation -a file (ANN), \nin the target VCF file (:VCF), or both for reciprocal overlap (ANN:VCF). \nBy default overlaps of arbitrary length are sufficient. \nThe option can be used only with the tab-delimited annotation -a file and with BEG and END columns present.\n" + + } + + + , + "no_version": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Do not append version and command line information to the output VCF header", + "help_text": "Type: `boolean_true`, default: `false`. Do not append version and command line information to the output VCF header.\n" + , + "default": "False" + } + + + , + "output_type": { + "type": + "string", + "description": "Type: `string`, choices: ``u`, `z`, `b`, `v``. Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed BCF\n v: uncompressed VCF\n", + "help_text": "Type: `string`, choices: ``u`, `z`, `b`, `v``. Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed BCF\n v: uncompressed VCF\n", + "enum": ["u", "z", "b", "v"] + + + } + + + , + "pair_logic": { + "type": + "string", + "description": "Type: `string`, choices: ``snps`, `indels`, `both`, `all`, `some`, `exact``. Controls how to match records from the annotation file to the target VCF", + "help_text": "Type: `string`, choices: ``snps`, `indels`, `both`, `all`, `some`, `exact``. Controls how to match records from the annotation file to the target VCF. \nEffective only when -a is a VCF or BCF file. \nThe option replaces the former uninuitive --collapse. \nSee Common Options for more.\n", + "enum": ["snps", "indels", "both", "all", "some", "exact"] + + + } + + + , + "regions": { + "type": + "string", + "description": "Type: `string`, example: `20:1000000-2000000`. Restrict to comma-separated list of regions", + "help_text": "Type: `string`, example: `20:1000000-2000000`. Restrict to comma-separated list of regions. \nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,\u2026\u200b].\n" + + } + + + , + "regions_file": { + "type": + "string", + "description": "Type: `file`. Restrict to regions listed in a file", + "help_text": "Type: `file`. Restrict to regions listed in a file. \nRegions can be specified either on a VCF, BED, or tab-delimited file (the default). \nFor more information check manual.\n" + + } + + + , + "regions_overlap": { + "type": + "string", + "description": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. This option controls how overlapping records are determined: \nset to \u0027pos\u0027 or \u00270\u0027 if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to \u0027record\u0027 or \u00271\u0027 if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to \u0027variant\u0027 or \u00272\u0027 to include only true overlapping variation (compare the full VCF representation \"TA\u003eT-\" vs the true sequence variation \"A\u003e-\")", + "help_text": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. This option controls how overlapping records are determined: \nset to \u0027pos\u0027 or \u00270\u0027 if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to \u0027record\u0027 or \u00271\u0027 if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to \u0027variant\u0027 or \u00272\u0027 to include only true overlapping variation (compare the full VCF representation \"TA\u003eT-\" vs the true sequence variation \"A\u003e-\").\n", + "enum": ["pos", "record", "variant", "0", "1", "2"] + + + } + + + , + "rename_annotations": { + "type": + "string", + "description": "Type: `file`. Rename annotations: TYPE/old\\tnew, where TYPE is one of FILTER,INFO,FORMAT", + "help_text": "Type: `file`. Rename annotations: TYPE/old\\tnew, where TYPE is one of FILTER,INFO,FORMAT.\n" + + } + + + , + "rename_chromosomes": { + "type": + "string", + "description": "Type: `file`. Rename chromosomes according to the map in file, with \"old_name new_name\\n\" pairs \nseparated by whitespaces, each on a separate line", + "help_text": "Type: `file`. Rename chromosomes according to the map in file, with \"old_name new_name\\n\" pairs \nseparated by whitespaces, each on a separate line.\n" + + } + + + , + "samples": { + "type": + "string", + "description": "Type: `string`. Subset of samples to annotate", + "help_text": "Type: `string`. Subset of samples to annotate.\nSee also https://samtools.github.io/bcftools/bcftools.html#common_options.\n" + + } + + + , + "samples_file": { + "type": + "string", + "description": "Type: `file`. Subset of samples to annotate in file format", + "help_text": "Type: `file`. Subset of samples to annotate in file format.\nSee also https://samtools.github.io/bcftools/bcftools.html#common_options.\n" + + } + + + , + "single_overlaps": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Use this option to keep memory requirements low with very large annotation files", + "help_text": "Type: `boolean_true`, default: `false`. Use this option to keep memory requirements low with very large annotation files. \nNote, however, that this comes at a cost, only single overlapping intervals are considered in this mode. \nThis was the default mode until the commit af6f0c9 (Feb 24 2019).\n" + , + "default": "False" + } + + + , + "remove": { + "type": + "string", + "description": "Type: `string`. List of annotations to remove", + "help_text": "Type: `string`. List of annotations to remove. \nUse \"FILTER\" to remove all filters or \"FILTER/SomeFilter\" to remove a specific filter. \nSimilarly, \"INFO\" can be used to remove all INFO tags and \"FORMAT\" to remove all FORMAT tags except GT. \nTo remove all INFO tags except \"FOO\" and \"BAR\", use \"^INFO/FOO,INFO/BAR\" (and similarly for FORMAT and FILTER). \n\"INFO\" can be abbreviated to \"INF\" and \"FORMAT\" to \"FMT\".\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/options" + }, + + { + "$ref": "#/definitions/nextflow input-output arguments" + } +] +} diff --git a/target/nextflow/bcftools/bcftools_concat/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_concat/.config.vsh.yaml new file mode 100644 index 00000000..760c294a --- /dev/null +++ b/target/nextflow/bcftools/bcftools_concat/.config.vsh.yaml @@ -0,0 +1,361 @@ +name: "bcftools_concat" +namespace: "bcftools" +version: "add_trimgalore" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + 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 VCF/BCF files to concatenate." + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: true + multiple_sep: ";" + - type: "file" + name: "--file_list" + alternatives: + - "-f" + description: "Read the list of VCF/BCF files from a file, one file name per line." + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + description: "Output concatenated VCF/BCF file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "boolean_true" + name: "--allow_overlaps" + alternatives: + - "-a" + description: "First coordinate of the next file can precede last record of the\ + \ current file.\n" + info: null + direction: "input" + - type: "boolean_true" + name: "--compact_PS" + alternatives: + - "-c" + description: "Do not output PS tag at each site, only at the start of a new phase\ + \ set block.\n" + info: null + direction: "input" + - type: "string" + name: "--remove_duplicates" + alternatives: + - "-d" + description: "Output duplicate records present in multiple files only once: .\n\ + \ \n" + info: null + required: false + choices: + - "snps" + - "indels" + - "both" + - "all" + - "exact" + - "none" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--ligate" + alternatives: + - "-l" + description: "Ligate phased VCFs by matching phase at overlapping haplotypes." + info: null + direction: "input" + - type: "boolean_true" + name: "--ligate_force" + description: "Ligate even non-overlapping chunks, keep all sites." + info: null + direction: "input" + - type: "boolean_true" + name: "--ligate_warn" + description: "Drop sites in imperfect overlaps." + info: null + direction: "input" + - type: "boolean_true" + name: "--no_version" + description: "Do not append version and command line information to the header." + info: null + direction: "input" + - type: "boolean_true" + name: "--naive" + alternatives: + - "-n" + description: "Concatenate files without recompression, a header check compatibility\ + \ is performed." + info: null + direction: "input" + - type: "boolean_true" + name: "--naive_force" + description: "Same as --naive, but header compatibility is not checked. \nDangerous,\ + \ use with caution.\n" + info: null + direction: "input" + - type: "string" + name: "--output_type" + alternatives: + - "-O" + description: "Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed\ + \ BCF\n v: uncompressed VCF\n" + info: null + required: false + choices: + - "u" + - "z" + - "b" + - "v" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--min_PQ" + alternatives: + - "-q" + description: "Break phase set if phasing quality is lower than ." + info: null + example: + - 30 + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions" + alternatives: + - "-r" + description: "Restrict to comma-separated list of regions. \nFollowing formats\ + \ are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--regions_file" + alternatives: + - "-R" + description: "Restrict to regions listed in a file. \nRegions can be specified\ + \ either on a VCF, BED, or tab-delimited file (the default). \nFor more information\ + \ check manual.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions_overlap" + description: "This option controls how overlapping records are determined: \n\ + set to 'pos' or '0' if the VCF record has to have POS inside a region (this\ + \ corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if\ + \ also overlapping records with POS outside a region should be included (this\ + \ is the default behavior of -r/-R, \nand includes indels with POS at the end\ + \ of a region, which are technically outside the region); \nor set to 'variant'\ + \ or '2' to include only true overlapping variation (compare the full VCF representation\ + \ \"TA>T-\" vs the true sequence variation \"A>-\").\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Concatenate or combine VCF/BCF files. All source files must have the\ + \ same sample\ncolumns appearing in the same order. The program can be used, for\ + \ example, to\nconcatenate chromosome VCFs into one VCF, or combine a SNP VCF and\ + \ an indel\nVCF into one. The input files must be sorted by chr and position. The\ + \ files\nmust be given in the correct order to produce sorted VCF on output unless\n\ + the -a, --allow-overlaps option is specified. With the --naive option, the files\n\ + are concatenated without being recompressed, which is very fast.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Concatenate" +- "VCF" +- "BCF" +license: "MIT/Expat, GNU" +references: + doi: + - "https://doi.org/10.1093/gigascience/giab008" +links: + repository: "https://github.com/samtools/bcftools" + homepage: "https://samtools.github.io/bcftools/" + documentation: "https://samtools.github.io/bcftools/bcftools.html#concat" + issue_tracker: "https://github.com/samtools/bcftools/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: "add_trimgalore" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bcftools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bcftools: \\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools\ + \ //p')\\\"\" > /var/software_versions.txt\n" + test_setup: + - type: "apt" + packages: + - "tabix" + interactive: false + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bcftools/bcftools_concat/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/bcftools/bcftools_concat" + executable: "target/nextflow/bcftools/bcftools_concat/main.nf" + viash_version: "0.9.0-RC7" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" +package_config: + name: "biobox" + version: "add_trimgalore" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0-RC7" + 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 := 'add_trimgalore'" + 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/bcftools/bcftools_concat/main.nf b/target/nextflow/bcftools/bcftools_concat/main.nf new file mode 100644 index 00000000..b74ff5ce --- /dev/null +++ b/target/nextflow/bcftools/bcftools_concat/main.nf @@ -0,0 +1,3810 @@ +// bcftools_concat add_trimgalore +// +// This wrapper script is auto-generated by viash 0.9.0-RC7 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) + +//////////////////////////// +// 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('\\$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('\\$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('\\$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" : "bcftools_concat", + "namespace" : "bcftools", + "version" : "add_trimgalore", + "authors" : [ + { + "name" : "Theodoro Gasperin Terra Camargo", + "roles" : [ + "author" + ], + "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 VCF/BCF files to concatenate.", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : true, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--file_list", + "alternatives" : [ + "-f" + ], + "description" : "Read the list of VCF/BCF files from a file, one file name per line.", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Outputs", + "arguments" : [ + { + "type" : "file", + "name" : "--output", + "alternatives" : [ + "-o" + ], + "description" : "Output concatenated VCF/BCF file.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Options", + "arguments" : [ + { + "type" : "boolean_true", + "name" : "--allow_overlaps", + "alternatives" : [ + "-a" + ], + "description" : "First coordinate of the next file can precede last record of the current file.\n", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--compact_PS", + "alternatives" : [ + "-c" + ], + "description" : "Do not output PS tag at each site, only at the start of a new phase set block.\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--remove_duplicates", + "alternatives" : [ + "-d" + ], + "description" : "Output duplicate records present in multiple files only once: .\n \n", + "required" : false, + "choices" : [ + "snps", + "indels", + "both", + "all", + "exact", + "none" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--ligate", + "alternatives" : [ + "-l" + ], + "description" : "Ligate phased VCFs by matching phase at overlapping haplotypes.", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--ligate_force", + "description" : "Ligate even non-overlapping chunks, keep all sites.", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--ligate_warn", + "description" : "Drop sites in imperfect overlaps.", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--no_version", + "description" : "Do not append version and command line information to the header.", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--naive", + "alternatives" : [ + "-n" + ], + "description" : "Concatenate files without recompression, a header check compatibility is performed.", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--naive_force", + "description" : "Same as --naive, but header compatibility is not checked. \nDangerous, use with caution.\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--output_type", + "alternatives" : [ + "-O" + ], + "description" : "Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed BCF\n v: uncompressed VCF\n", + "required" : false, + "choices" : [ + "u", + "z", + "b", + "v" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "integer", + "name" : "--min_PQ", + "alternatives" : [ + "-q" + ], + "description" : "Break phase set if phasing quality is lower than .", + "example" : [ + 30 + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--regions", + "alternatives" : [ + "-r" + ], + "description" : "Restrict to comma-separated list of regions. \nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n", + "example" : [ + "20:1000000-2000000" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--regions_file", + "alternatives" : [ + "-R" + ], + "description" : "Restrict to regions listed in a file. \nRegions can be specified either on a VCF, BED, or tab-delimited file (the default). \nFor more information check manual.\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--regions_overlap", + "description" : "This option controls how overlapping records are determined: \nset to 'pos' or '0' if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to 'variant' or '2' to include only true overlapping variation (compare the full VCF representation \\"TA>T-\\" vs the true sequence variation \\"A>-\\").\n", + "required" : false, + "choices" : [ + "pos", + "record", + "variant", + "0", + "1", + "2" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Concatenate or combine VCF/BCF files. All source files must have the same sample\ncolumns appearing in the same order. The program can be used, for example, to\nconcatenate chromosome VCFs into one VCF, or combine a SNP VCF and an indel\nVCF into one. The input files must be sorted by chr and position. The files\nmust be given in the correct order to produce sorted VCF on output unless\nthe -a, --allow-overlaps option is specified. With the --naive option, the files\nare concatenated without being recompressed, which is very fast.\n", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "keywords" : [ + "Concatenate", + "VCF", + "BCF" + ], + "license" : "MIT/Expat, GNU", + "references" : { + "doi" : [ + "https://doi.org/10.1093/gigascience/giab008" + ] + }, + "links" : { + "repository" : "https://github.com/samtools/bcftools", + "homepage" : "https://samtools.github.io/bcftools/", + "documentation" : "https://samtools.github.io/bcftools/bcftools.html#concat", + "issue_tracker" : "https://github.com/samtools/bcftools/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" : "add_trimgalore", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "apt", + "packages" : [ + "bcftools", + "procps" + ], + "interactive" : false + }, + { + "type" : "docker", + "run" : [ + "echo \\"bcftools: \\\\\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\\\\\\"\\" > /var/software_versions.txt\n" + ] + } + ], + "test_setup" : [ + { + "type" : "apt", + "packages" : [ + "tabix" + ], + "interactive" : false + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/bcftools/bcftools_concat/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/bcftools/bcftools_concat", + "viash_version" : "0.9.0-RC7", + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" + }, + "package_config" : { + "name" : "biobox", + "version" : "add_trimgalore", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0-RC7", + "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 := 'add_trimgalore'" + ], + "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_FILE_LIST+x} ]; then echo "${VIASH_PAR_FILE_LIST}" | sed "s#'#'\\"'\\"'#g;s#.*#par_file_list='&'#" ; else echo "# par_file_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_ALLOW_OVERLAPS+x} ]; then echo "${VIASH_PAR_ALLOW_OVERLAPS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_allow_overlaps='&'#" ; else echo "# par_allow_overlaps="; fi ) +$( if [ ! -z ${VIASH_PAR_COMPACT_PS+x} ]; then echo "${VIASH_PAR_COMPACT_PS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_compact_PS='&'#" ; else echo "# par_compact_PS="; fi ) +$( if [ ! -z ${VIASH_PAR_REMOVE_DUPLICATES+x} ]; then echo "${VIASH_PAR_REMOVE_DUPLICATES}" | sed "s#'#'\\"'\\"'#g;s#.*#par_remove_duplicates='&'#" ; else echo "# par_remove_duplicates="; fi ) +$( if [ ! -z ${VIASH_PAR_LIGATE+x} ]; then echo "${VIASH_PAR_LIGATE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_ligate='&'#" ; else echo "# par_ligate="; fi ) +$( if [ ! -z ${VIASH_PAR_LIGATE_FORCE+x} ]; then echo "${VIASH_PAR_LIGATE_FORCE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_ligate_force='&'#" ; else echo "# par_ligate_force="; fi ) +$( if [ ! -z ${VIASH_PAR_LIGATE_WARN+x} ]; then echo "${VIASH_PAR_LIGATE_WARN}" | sed "s#'#'\\"'\\"'#g;s#.*#par_ligate_warn='&'#" ; else echo "# par_ligate_warn="; fi ) +$( if [ ! -z ${VIASH_PAR_NO_VERSION+x} ]; then echo "${VIASH_PAR_NO_VERSION}" | sed "s#'#'\\"'\\"'#g;s#.*#par_no_version='&'#" ; else echo "# par_no_version="; fi ) +$( if [ ! -z ${VIASH_PAR_NAIVE+x} ]; then echo "${VIASH_PAR_NAIVE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_naive='&'#" ; else echo "# par_naive="; fi ) +$( if [ ! -z ${VIASH_PAR_NAIVE_FORCE+x} ]; then echo "${VIASH_PAR_NAIVE_FORCE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_naive_force='&'#" ; else echo "# par_naive_force="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_TYPE+x} ]; then echo "${VIASH_PAR_OUTPUT_TYPE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output_type='&'#" ; else echo "# par_output_type="; fi ) +$( if [ ! -z ${VIASH_PAR_MIN_PQ+x} ]; then echo "${VIASH_PAR_MIN_PQ}" | sed "s#'#'\\"'\\"'#g;s#.*#par_min_PQ='&'#" ; else echo "# par_min_PQ="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS+x} ]; then echo "${VIASH_PAR_REGIONS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions='&'#" ; else echo "# par_regions="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_FILE+x} ]; then echo "${VIASH_PAR_REGIONS_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions_file='&'#" ; else echo "# par_regions_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_OVERLAP+x} ]; then echo "${VIASH_PAR_REGIONS_OVERLAP}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions_overlap='&'#" ; else echo "# par_regions_overlap="; 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 + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_allow_overlaps + par_compact_PS + par_ligate + par_ligate_force + par_ligate_warn + par_no_version + par_naive + par_naive_force +) + +for par in \\${unset_if_false[@]}; do + test_val="\\${!par}" + [[ "\\$test_val" == "false" ]] && unset \\$par +done + +# Check to see whether the par_input or the par_file_list is set +if [[ -z "\\${par_input}" && -z "\\${par_file_list}" ]]; then + echo "Error: One of the parameters '--input' or '--file_list' must be used." + exit 1 +fi + +# Create input array +IFS=";" read -ra input <<< \\$par_input + +# Execute bcftools concat with the provided arguments +bcftools concat \\\\ + \\${par_allow_overlaps:+-a} \\\\ + \\${par_compact_PS:+-c} \\\\ + \\${par_remove_duplicates:+-d "\\$par_remove_duplicates"} \\\\ + \\${par_ligate:+-l} \\\\ + \\${par_ligate_force:+--ligate-force} \\\\ + \\${par_ligate_warn:+--ligate-warn} \\\\ + \\${par_no_version:+--no-version} \\\\ + \\${par_naive:+-n} \\\\ + \\${par_naive_force:+--naive-force} \\\\ + \\${par_output_type:+--O "\\$par_output_type"} \\\\ + \\${par_min_PQ:+-q "\\$par_min_PQ"} \\\\ + \\${par_regions:+-r "\\$par_regions"} \\\\ + \\${par_regions_file:+-R "\\$par_regions_file"} \\\\ + \\${par_regions_overlap:+--regions-overlap "\\$par_regions_overlap"} \\\\ + \\${meta_cpus:+--threads "\\$meta_cpus"} \\\\ + -o \\$par_output \\\\ + \\${par_file_list:+-f "\\$par_file_list"} \\\\ + \\${input[@]} \\\\ +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('\\$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 -> + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"] : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def viash_par_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()}=\\\"\" + ${viash_par_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 + | + |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 escapeText = { s -> s.toString().replaceAll('([`"])', '\\\\\\\\\$1') } + |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/bcftools/bcftools_concat", + "tag" : "add_trimgalore" + }, + "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/bcftools/bcftools_concat/nextflow.config b/target/nextflow/bcftools/bcftools_concat/nextflow.config new file mode 100644 index 00000000..b93e203a --- /dev/null +++ b/target/nextflow/bcftools/bcftools_concat/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'bcftools/bcftools_concat' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'add_trimgalore' + description = 'Concatenate or combine VCF/BCF files. All source files must have the same sample\ncolumns appearing in the same order. The program can be used, for example, to\nconcatenate chromosome VCFs into one VCF, or combine a SNP VCF and an indel\nVCF into one. The input files must be sorted by chr and position. The files\nmust be given in the correct order to produce sorted VCF on output unless\nthe -a, --allow-overlaps option is specified. With the --naive option, the files\nare concatenated without being recompressed, which is very fast.\n' + 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/bcftools/bcftools_concat/nextflow_schema.json b/target/nextflow/bcftools/bcftools_concat/nextflow_schema.json new file mode 100644 index 00000000..acf49c75 --- /dev/null +++ b/target/nextflow/bcftools/bcftools_concat/nextflow_schema.json @@ -0,0 +1,273 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "bcftools_concat", +"description": "Concatenate or combine VCF/BCF files. All source files must have the same sample\ncolumns appearing in the same order. The program can be used, for example, to\nconcatenate chromosome VCFs into one VCF, or combine a SNP VCF and an indel\nVCF into one. The input files must be sorted by chr and position. The files\nmust be given in the correct order to produce sorted VCF on output unless\nthe -a, --allow-overlaps option is specified. With the --naive option, the files\nare concatenated without being recompressed, which is very fast.\n", +"type": "object", +"definitions": { + + + + "inputs" : { + "title": "Inputs", + "type": "object", + "description": "No description", + "properties": { + + + "input": { + "type": + "string", + "description": "Type: List of `file`, multiple_sep: `\";\"`. Input VCF/BCF files to concatenate", + "help_text": "Type: List of `file`, multiple_sep: `\";\"`. Input VCF/BCF files to concatenate." + + } + + + , + "file_list": { + "type": + "string", + "description": "Type: `file`. Read the list of VCF/BCF files from a file, one file name per line", + "help_text": "Type: `file`. Read the list of VCF/BCF files from a file, one file name per line." + + } + + +} +}, + + + "outputs" : { + "title": "Outputs", + "type": "object", + "description": "No description", + "properties": { + + + "output": { + "type": + "string", + "description": "Type: `file`, required, default: `$id.$key.output.output`. Output concatenated VCF/BCF file", + "help_text": "Type: `file`, required, default: `$id.$key.output.output`. Output concatenated VCF/BCF file." + , + "default": "$id.$key.output.output" + } + + +} +}, + + + "options" : { + "title": "Options", + "type": "object", + "description": "No description", + "properties": { + + + "allow_overlaps": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. First coordinate of the next file can precede last record of the current file", + "help_text": "Type: `boolean_true`, default: `false`. First coordinate of the next file can precede last record of the current file.\n" + , + "default": "False" + } + + + , + "compact_PS": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Do not output PS tag at each site, only at the start of a new phase set block", + "help_text": "Type: `boolean_true`, default: `false`. Do not output PS tag at each site, only at the start of a new phase set block.\n" + , + "default": "False" + } + + + , + "remove_duplicates": { + "type": + "string", + "description": "Type: `string`, choices: ``snps`, `indels`, `both`, `all`, `exact`, `none``. Output duplicate records present in multiple files only once: \u003csnps|indels|both|all|exact\u003e", + "help_text": "Type: `string`, choices: ``snps`, `indels`, `both`, `all`, `exact`, `none``. Output duplicate records present in multiple files only once: \u003csnps|indels|both|all|exact\u003e.\n \n", + "enum": ["snps", "indels", "both", "all", "exact", "none"] + + + } + + + , + "ligate": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Ligate phased VCFs by matching phase at overlapping haplotypes", + "help_text": "Type: `boolean_true`, default: `false`. Ligate phased VCFs by matching phase at overlapping haplotypes." + , + "default": "False" + } + + + , + "ligate_force": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Ligate even non-overlapping chunks, keep all sites", + "help_text": "Type: `boolean_true`, default: `false`. Ligate even non-overlapping chunks, keep all sites." + , + "default": "False" + } + + + , + "ligate_warn": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Drop sites in imperfect overlaps", + "help_text": "Type: `boolean_true`, default: `false`. Drop sites in imperfect overlaps." + , + "default": "False" + } + + + , + "no_version": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Do not append version and command line information to the header", + "help_text": "Type: `boolean_true`, default: `false`. Do not append version and command line information to the header." + , + "default": "False" + } + + + , + "naive": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Concatenate files without recompression, a header check compatibility is performed", + "help_text": "Type: `boolean_true`, default: `false`. Concatenate files without recompression, a header check compatibility is performed." + , + "default": "False" + } + + + , + "naive_force": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Same as --naive, but header compatibility is not checked", + "help_text": "Type: `boolean_true`, default: `false`. Same as --naive, but header compatibility is not checked. \nDangerous, use with caution.\n" + , + "default": "False" + } + + + , + "output_type": { + "type": + "string", + "description": "Type: `string`, choices: ``u`, `z`, `b`, `v``. Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed BCF\n v: uncompressed VCF\n", + "help_text": "Type: `string`, choices: ``u`, `z`, `b`, `v``. Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed BCF\n v: uncompressed VCF\n", + "enum": ["u", "z", "b", "v"] + + + } + + + , + "min_PQ": { + "type": + "integer", + "description": "Type: `integer`, example: `30`. Break phase set if phasing quality is lower than \u003cint\u003e", + "help_text": "Type: `integer`, example: `30`. Break phase set if phasing quality is lower than \u003cint\u003e." + + } + + + , + "regions": { + "type": + "string", + "description": "Type: `string`, example: `20:1000000-2000000`. Restrict to comma-separated list of regions", + "help_text": "Type: `string`, example: `20:1000000-2000000`. Restrict to comma-separated list of regions. \nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,\u2026\u200b].\n" + + } + + + , + "regions_file": { + "type": + "string", + "description": "Type: `file`. Restrict to regions listed in a file", + "help_text": "Type: `file`. Restrict to regions listed in a file. \nRegions can be specified either on a VCF, BED, or tab-delimited file (the default). \nFor more information check manual.\n" + + } + + + , + "regions_overlap": { + "type": + "string", + "description": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. This option controls how overlapping records are determined: \nset to \u0027pos\u0027 or \u00270\u0027 if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to \u0027record\u0027 or \u00271\u0027 if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to \u0027variant\u0027 or \u00272\u0027 to include only true overlapping variation (compare the full VCF representation \"TA\u003eT-\" vs the true sequence variation \"A\u003e-\")", + "help_text": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. This option controls how overlapping records are determined: \nset to \u0027pos\u0027 or \u00270\u0027 if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to \u0027record\u0027 or \u00271\u0027 if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to \u0027variant\u0027 or \u00272\u0027 to include only true overlapping variation (compare the full VCF representation \"TA\u003eT-\" vs the true sequence variation \"A\u003e-\").\n", + "enum": ["pos", "record", "variant", "0", "1", "2"] + + + } + + +} +}, + + + "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/bcftools/bcftools_norm/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_norm/.config.vsh.yaml new file mode 100644 index 00000000..d4573f91 --- /dev/null +++ b/target/nextflow/bcftools/bcftools_norm/.config.vsh.yaml @@ -0,0 +1,442 @@ +name: "bcftools_norm" +namespace: "bcftools" +version: "add_trimgalore" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + 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 VCF/BCF 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 normalized VCF/BCF file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "boolean_true" + name: "--atomize" + alternatives: + - "-a" + description: "Decompose complex variants (e.g., MNVs become consecutive SNVs).\n" + info: null + direction: "input" + - type: "string" + name: "--atom_overlaps" + description: "Use the star allele (*) for overlapping alleles or set to missing\ + \ (.).\n" + info: null + required: false + choices: + - "." + - "*" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--check_ref" + alternatives: + - "-c" + description: "Check REF alleles and exit (e), warn (w), exclude (x), or set (s)\ + \ bad sites.\n" + info: null + required: false + choices: + - "e" + - "w" + - "x" + - "s" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--remove_duplicates" + alternatives: + - "-d" + description: "Remove duplicate snps, indels, both, all, exact matches, or none\ + \ (old -D option)." + info: null + required: false + choices: + - "snps" + - "indels" + - "both" + - "all" + - "exact" + - "none" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fasta_ref" + alternatives: + - "-f" + description: "Reference fasta sequence file." + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--force" + description: "Try to proceed even if malformed tags are encountered. \nExperimental,\ + \ use at your own risk.\n" + info: null + direction: "input" + - type: "string" + name: "--keep_sum" + description: "Keep vector sum constant when splitting multiallelics (see github\ + \ issue #360).\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--multiallelics" + alternatives: + - "-m" + description: "Split multiallelics (-) or join biallelics (+), type: snps, indels,\ + \ both, any [default: both].\n" + info: null + required: false + choices: + - "+snps" + - "+indels" + - "+both" + - "+any" + - "-snps" + - "-indels" + - "-both" + - "-any" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--no_version" + description: "Do not append version and command line information to the header." + info: null + direction: "input" + - type: "boolean_true" + name: "--do_not_normalize" + alternatives: + - "-N" + description: "Do not normalize indels (with -m or -c s)." + info: null + direction: "input" + - type: "string" + name: "--output_type" + alternatives: + - "--O" + description: "Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed\ + \ BCF\n v: uncompressed VCF\n" + info: null + required: false + choices: + - "u" + - "z" + - "b" + - "v" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--old_rec_tag" + description: "Annotate modified records with INFO/STR indicating the original\ + \ variant." + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions" + alternatives: + - "--r" + description: "Restrict to comma-separated list of regions. \nFollowing formats\ + \ are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--regions_file" + alternatives: + - "--R" + description: "Restrict to regions listed in a file. \nRegions can be specified\ + \ either on a VCF, BED, or tab-delimited file (the default). \nFor more information\ + \ check manual.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions_overlap" + description: "This option controls how overlapping records are determined: \n\ + set to 'pos' or '0' if the VCF record has to have POS inside a region (this\ + \ corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if\ + \ also overlapping records with POS outside a region should be included (this\ + \ is the default behavior of -r/-R, \nand includes indels with POS at the end\ + \ of a region, which are technically outside the region); \nor set to 'variant'\ + \ or '2' to include only true overlapping variation (compare the full VCF representation\ + \ \"TA>T-\" vs the true sequence variation \"A>-\").\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "integer" + name: "--site_win" + alternatives: + - "-w" + description: "Buffer for sorting lines that changed position during realignment.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--strict_filter" + alternatives: + - "-s" + description: "When merging (-m+), merged site is PASS only if all sites being\ + \ merged PASS." + info: null + direction: "input" + - type: "string" + name: "--targets" + alternatives: + - "-t" + description: "Similar to --regions but streams rather than index-jumps." + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--targets_file" + alternatives: + - "-T" + description: "Similar to --regions_file but streams rather than index-jumps." + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--targets_overlap" + description: "Include if POS in the region (0), record overlaps (1), variant overlaps\ + \ (2).\nSimilar to --regions_overlap.\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Left-align and normalize indels, check if REF alleles match the reference,\ + \ split multiallelic sites into multiple rows; \nrecover multiallelics from multiple\ + \ rows. \n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Normalize" +- "VCF" +- "BCF" +license: "MIT/Expat, GNU" +references: + doi: + - "https://doi.org/10.1093/gigascience/giab008" +links: + repository: "https://github.com/samtools/bcftools" + homepage: "https://samtools.github.io/bcftools/" + documentation: "https://samtools.github.io/bcftools/bcftools.html#norm" + issue_tracker: "https://github.com/samtools/bcftools/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: "add_trimgalore" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bcftools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bcftools: \\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools\ + \ //p')\\\"\" > /var/software_versions.txt\n" + test_setup: + - type: "apt" + packages: + - "tabix" + interactive: false + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bcftools/bcftools_norm/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/bcftools/bcftools_norm" + executable: "target/nextflow/bcftools/bcftools_norm/main.nf" + viash_version: "0.9.0-RC7" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" +package_config: + name: "biobox" + version: "add_trimgalore" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0-RC7" + 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 := 'add_trimgalore'" + 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/bcftools/bcftools_norm/main.nf b/target/nextflow/bcftools/bcftools_norm/main.nf new file mode 100644 index 00000000..4ff86977 --- /dev/null +++ b/target/nextflow/bcftools/bcftools_norm/main.nf @@ -0,0 +1,3903 @@ +// bcftools_norm add_trimgalore +// +// This wrapper script is auto-generated by viash 0.9.0-RC7 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) + +//////////////////////////// +// 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('\\$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('\\$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('\\$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" : "bcftools_norm", + "namespace" : "bcftools", + "version" : "add_trimgalore", + "authors" : [ + { + "name" : "Theodoro Gasperin Terra Camargo", + "roles" : [ + "author" + ], + "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 VCF/BCF 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 normalized VCF/BCF file.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Options", + "arguments" : [ + { + "type" : "boolean_true", + "name" : "--atomize", + "alternatives" : [ + "-a" + ], + "description" : "Decompose complex variants (e.g., MNVs become consecutive SNVs).\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--atom_overlaps", + "description" : "Use the star allele (*) for overlapping alleles or set to missing (.).\n", + "required" : false, + "choices" : [ + ".", + "*" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--check_ref", + "alternatives" : [ + "-c" + ], + "description" : "Check REF alleles and exit (e), warn (w), exclude (x), or set (s) bad sites.\n", + "required" : false, + "choices" : [ + "e", + "w", + "x", + "s" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--remove_duplicates", + "alternatives" : [ + "-d" + ], + "description" : "Remove duplicate snps, indels, both, all, exact matches, or none (old -D option).", + "required" : false, + "choices" : [ + "snps", + "indels", + "both", + "all", + "exact", + "none" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--fasta_ref", + "alternatives" : [ + "-f" + ], + "description" : "Reference fasta sequence file.", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--force", + "description" : "Try to proceed even if malformed tags are encountered. \nExperimental, use at your own risk.\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--keep_sum", + "description" : "Keep vector sum constant when splitting multiallelics (see github issue #360).\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--multiallelics", + "alternatives" : [ + "-m" + ], + "description" : "Split multiallelics (-) or join biallelics (+), type: snps, indels, both, any [default: both].\n", + "required" : false, + "choices" : [ + "+snps", + "+indels", + "+both", + "+any", + "-snps", + "-indels", + "-both", + "-any" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--no_version", + "description" : "Do not append version and command line information to the header.", + "direction" : "input" + }, + { + "type" : "boolean_true", + "name" : "--do_not_normalize", + "alternatives" : [ + "-N" + ], + "description" : "Do not normalize indels (with -m or -c s).", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--output_type", + "alternatives" : [ + "--O" + ], + "description" : "Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed BCF\n v: uncompressed VCF\n", + "required" : false, + "choices" : [ + "u", + "z", + "b", + "v" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--old_rec_tag", + "description" : "Annotate modified records with INFO/STR indicating the original variant.", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--regions", + "alternatives" : [ + "--r" + ], + "description" : "Restrict to comma-separated list of regions. \nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n", + "example" : [ + "20:1000000-2000000" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--regions_file", + "alternatives" : [ + "--R" + ], + "description" : "Restrict to regions listed in a file. \nRegions can be specified either on a VCF, BED, or tab-delimited file (the default). \nFor more information check manual.\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--regions_overlap", + "description" : "This option controls how overlapping records are determined: \nset to 'pos' or '0' if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to 'variant' or '2' to include only true overlapping variation (compare the full VCF representation \\"TA>T-\\" vs the true sequence variation \\"A>-\\").\n", + "required" : false, + "choices" : [ + "pos", + "record", + "variant", + "0", + "1", + "2" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "integer", + "name" : "--site_win", + "alternatives" : [ + "-w" + ], + "description" : "Buffer for sorting lines that changed position during realignment.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--strict_filter", + "alternatives" : [ + "-s" + ], + "description" : "When merging (-m+), merged site is PASS only if all sites being merged PASS.", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--targets", + "alternatives" : [ + "-t" + ], + "description" : "Similar to --regions but streams rather than index-jumps.", + "example" : [ + "20:1000000-2000000" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--targets_file", + "alternatives" : [ + "-T" + ], + "description" : "Similar to --regions_file but streams rather than index-jumps.", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--targets_overlap", + "description" : "Include if POS in the region (0), record overlaps (1), variant overlaps (2).\nSimilar to --regions_overlap.\n", + "required" : false, + "choices" : [ + "pos", + "record", + "variant", + "0", + "1", + "2" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Left-align and normalize indels, check if REF alleles match the reference, split multiallelic sites into multiple rows; \nrecover multiallelics from multiple rows. \n", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "keywords" : [ + "Normalize", + "VCF", + "BCF" + ], + "license" : "MIT/Expat, GNU", + "references" : { + "doi" : [ + "https://doi.org/10.1093/gigascience/giab008" + ] + }, + "links" : { + "repository" : "https://github.com/samtools/bcftools", + "homepage" : "https://samtools.github.io/bcftools/", + "documentation" : "https://samtools.github.io/bcftools/bcftools.html#norm", + "issue_tracker" : "https://github.com/samtools/bcftools/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" : "add_trimgalore", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "apt", + "packages" : [ + "bcftools", + "procps" + ], + "interactive" : false + }, + { + "type" : "docker", + "run" : [ + "echo \\"bcftools: \\\\\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\\\\\\"\\" > /var/software_versions.txt\n" + ] + } + ], + "test_setup" : [ + { + "type" : "apt", + "packages" : [ + "tabix" + ], + "interactive" : false + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/bcftools/bcftools_norm/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/bcftools/bcftools_norm", + "viash_version" : "0.9.0-RC7", + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" + }, + "package_config" : { + "name" : "biobox", + "version" : "add_trimgalore", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0-RC7", + "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 := 'add_trimgalore'" + ], + "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_ATOMIZE+x} ]; then echo "${VIASH_PAR_ATOMIZE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_atomize='&'#" ; else echo "# par_atomize="; fi ) +$( if [ ! -z ${VIASH_PAR_ATOM_OVERLAPS+x} ]; then echo "${VIASH_PAR_ATOM_OVERLAPS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_atom_overlaps='&'#" ; else echo "# par_atom_overlaps="; fi ) +$( if [ ! -z ${VIASH_PAR_CHECK_REF+x} ]; then echo "${VIASH_PAR_CHECK_REF}" | sed "s#'#'\\"'\\"'#g;s#.*#par_check_ref='&'#" ; else echo "# par_check_ref="; fi ) +$( if [ ! -z ${VIASH_PAR_REMOVE_DUPLICATES+x} ]; then echo "${VIASH_PAR_REMOVE_DUPLICATES}" | sed "s#'#'\\"'\\"'#g;s#.*#par_remove_duplicates='&'#" ; else echo "# par_remove_duplicates="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTA_REF+x} ]; then echo "${VIASH_PAR_FASTA_REF}" | sed "s#'#'\\"'\\"'#g;s#.*#par_fasta_ref='&'#" ; else echo "# par_fasta_ref="; fi ) +$( if [ ! -z ${VIASH_PAR_FORCE+x} ]; then echo "${VIASH_PAR_FORCE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_force='&'#" ; else echo "# par_force="; fi ) +$( if [ ! -z ${VIASH_PAR_KEEP_SUM+x} ]; then echo "${VIASH_PAR_KEEP_SUM}" | sed "s#'#'\\"'\\"'#g;s#.*#par_keep_sum='&'#" ; else echo "# par_keep_sum="; fi ) +$( if [ ! -z ${VIASH_PAR_MULTIALLELICS+x} ]; then echo "${VIASH_PAR_MULTIALLELICS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_multiallelics='&'#" ; else echo "# par_multiallelics="; fi ) +$( if [ ! -z ${VIASH_PAR_NO_VERSION+x} ]; then echo "${VIASH_PAR_NO_VERSION}" | sed "s#'#'\\"'\\"'#g;s#.*#par_no_version='&'#" ; else echo "# par_no_version="; fi ) +$( if [ ! -z ${VIASH_PAR_DO_NOT_NORMALIZE+x} ]; then echo "${VIASH_PAR_DO_NOT_NORMALIZE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_do_not_normalize='&'#" ; else echo "# par_do_not_normalize="; fi ) +$( if [ ! -z ${VIASH_PAR_OUTPUT_TYPE+x} ]; then echo "${VIASH_PAR_OUTPUT_TYPE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_output_type='&'#" ; else echo "# par_output_type="; fi ) +$( if [ ! -z ${VIASH_PAR_OLD_REC_TAG+x} ]; then echo "${VIASH_PAR_OLD_REC_TAG}" | sed "s#'#'\\"'\\"'#g;s#.*#par_old_rec_tag='&'#" ; else echo "# par_old_rec_tag="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS+x} ]; then echo "${VIASH_PAR_REGIONS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions='&'#" ; else echo "# par_regions="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_FILE+x} ]; then echo "${VIASH_PAR_REGIONS_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions_file='&'#" ; else echo "# par_regions_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_OVERLAP+x} ]; then echo "${VIASH_PAR_REGIONS_OVERLAP}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions_overlap='&'#" ; else echo "# par_regions_overlap="; fi ) +$( if [ ! -z ${VIASH_PAR_SITE_WIN+x} ]; then echo "${VIASH_PAR_SITE_WIN}" | sed "s#'#'\\"'\\"'#g;s#.*#par_site_win='&'#" ; else echo "# par_site_win="; fi ) +$( if [ ! -z ${VIASH_PAR_STRICT_FILTER+x} ]; then echo "${VIASH_PAR_STRICT_FILTER}" | sed "s#'#'\\"'\\"'#g;s#.*#par_strict_filter='&'#" ; else echo "# par_strict_filter="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS+x} ]; then echo "${VIASH_PAR_TARGETS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_targets='&'#" ; else echo "# par_targets="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS_FILE+x} ]; then echo "${VIASH_PAR_TARGETS_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_targets_file='&'#" ; else echo "# par_targets_file="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS_OVERLAP+x} ]; then echo "${VIASH_PAR_TARGETS_OVERLAP}" | sed "s#'#'\\"'\\"'#g;s#.*#par_targets_overlap='&'#" ; else echo "# par_targets_overlap="; 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 + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_atomize + par_remove_duplicates + par_force + par_no_version + par_do_not_normalize + par_strict_filter +) + +for par in \\${unset_if_false[@]}; do + test_val="\\${!par}" + [[ "\\$test_val" == "false" ]] && unset \\$par +done + +# Execute bcftools norm with the provided arguments +bcftools norm \\\\ + \\${par_atomize:+--atomize} \\\\ + \\${par_atom_overlaps:+--atom-overlaps "\\$par_atom_overlaps"} \\\\ + \\${par_check_ref:+-c "\\$par_check_ref"} \\\\ + \\${par_remove_duplicates:+-d "\\$par_remove_duplicates"} \\\\ + \\${par_fasta_ref:+-f "\\$par_fasta_ref"} \\\\ + \\${par_force:+--force} \\\\ + \\${par_keep_sum:+--keep-sum "\\$par_keep_sum"} \\\\ + \\${par_multiallelics:+-m "\\$par_multiallelics"} \\\\ + \\${par_no_version:+--no-version} \\\\ + \\${par_do_not_normalize:+-N} \\\\ + \\${par_old_rec_tag:+--old-rec-tag "\\$par_old_rec_tag"} \\\\ + \\${par_regions:+-r "\\$par_regions"} \\\\ + \\${par_regions_file:+-R "\\$par_regions_file"} \\\\ + \\${par_regions_overlap:+--regions-overlap "\\$par_regions_overlap"} \\\\ + \\${par_site_win:+-w "\\$par_site_win"} \\\\ + \\${par_strict_filter:+-s} \\\\ + \\${par_targets:+-t "\\$par_targets"} \\\\ + \\${par_targets_file:+-T "\\$par_targets_file"} \\\\ + \\${par_targets_overlap:+--targets-overlap "\\$par_targets_overlap"} \\\\ + \\${meta_cpus:+--threads "\\$meta_cpus"} \\\\ + \\${par_output_type:+-O "\\$par_output_type"} \\\\ + -o \\$par_output \\\\ + \\$par_input + +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('\\$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 -> + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"] : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def viash_par_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()}=\\\"\" + ${viash_par_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 + | + |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 escapeText = { s -> s.toString().replaceAll('([`"])', '\\\\\\\\\$1') } + |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/bcftools/bcftools_norm", + "tag" : "add_trimgalore" + }, + "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/bcftools/bcftools_norm/nextflow.config b/target/nextflow/bcftools/bcftools_norm/nextflow.config new file mode 100644 index 00000000..80f25471 --- /dev/null +++ b/target/nextflow/bcftools/bcftools_norm/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'bcftools/bcftools_norm' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'add_trimgalore' + description = 'Left-align and normalize indels, check if REF alleles match the reference, split multiallelic sites into multiple rows; \nrecover multiallelics from multiple rows. \n' + 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/bcftools/bcftools_norm/nextflow_schema.json b/target/nextflow/bcftools/bcftools_norm/nextflow_schema.json new file mode 100644 index 00000000..5bfd9667 --- /dev/null +++ b/target/nextflow/bcftools/bcftools_norm/nextflow_schema.json @@ -0,0 +1,328 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "bcftools_norm", +"description": "Left-align and normalize indels, check if REF alleles match the reference, split multiallelic sites into multiple rows; \nrecover multiallelics from multiple rows. \n", +"type": "object", +"definitions": { + + + + "inputs" : { + "title": "Inputs", + "type": "object", + "description": "No description", + "properties": { + + + "input": { + "type": + "string", + "description": "Type: `file`, required. Input VCF/BCF file", + "help_text": "Type: `file`, required. Input VCF/BCF file." + + } + + +} +}, + + + "outputs" : { + "title": "Outputs", + "type": "object", + "description": "No description", + "properties": { + + + "output": { + "type": + "string", + "description": "Type: `file`, required, default: `$id.$key.output.output`. Output normalized VCF/BCF file", + "help_text": "Type: `file`, required, default: `$id.$key.output.output`. Output normalized VCF/BCF file." + , + "default": "$id.$key.output.output" + } + + +} +}, + + + "options" : { + "title": "Options", + "type": "object", + "description": "No description", + "properties": { + + + "atomize": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Decompose complex variants (e", + "help_text": "Type: `boolean_true`, default: `false`. Decompose complex variants (e.g., MNVs become consecutive SNVs).\n" + , + "default": "False" + } + + + , + "atom_overlaps": { + "type": + "string", + "description": "Type: `string`, choices: ``.`, `*``. Use the star allele (*) for overlapping alleles or set to missing (", + "help_text": "Type: `string`, choices: ``.`, `*``. Use the star allele (*) for overlapping alleles or set to missing (.).\n", + "enum": [".", "*"] + + + } + + + , + "check_ref": { + "type": + "string", + "description": "Type: `string`, choices: ``e`, `w`, `x`, `s``. Check REF alleles and exit (e), warn (w), exclude (x), or set (s) bad sites", + "help_text": "Type: `string`, choices: ``e`, `w`, `x`, `s``. Check REF alleles and exit (e), warn (w), exclude (x), or set (s) bad sites.\n", + "enum": ["e", "w", "x", "s"] + + + } + + + , + "remove_duplicates": { + "type": + "string", + "description": "Type: `string`, choices: ``snps`, `indels`, `both`, `all`, `exact`, `none``. Remove duplicate snps, indels, both, all, exact matches, or none (old -D option)", + "help_text": "Type: `string`, choices: ``snps`, `indels`, `both`, `all`, `exact`, `none``. Remove duplicate snps, indels, both, all, exact matches, or none (old -D option).", + "enum": ["snps", "indels", "both", "all", "exact", "none"] + + + } + + + , + "fasta_ref": { + "type": + "string", + "description": "Type: `file`. Reference fasta sequence file", + "help_text": "Type: `file`. Reference fasta sequence file." + + } + + + , + "force": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Try to proceed even if malformed tags are encountered", + "help_text": "Type: `boolean_true`, default: `false`. Try to proceed even if malformed tags are encountered. \nExperimental, use at your own risk.\n" + , + "default": "False" + } + + + , + "keep_sum": { + "type": + "string", + "description": "Type: `string`. Keep vector sum constant when splitting multiallelics (see github issue #360)", + "help_text": "Type: `string`. Keep vector sum constant when splitting multiallelics (see github issue #360).\n" + + } + + + , + "multiallelics": { + "type": + "string", + "description": "Type: `string`, choices: ``+snps`, `+indels`, `+both`, `+any`, `-snps`, `-indels`, `-both`, `-any``. Split multiallelics (-) or join biallelics (+), type: snps, indels, both, any [default: both]", + "help_text": "Type: `string`, choices: ``+snps`, `+indels`, `+both`, `+any`, `-snps`, `-indels`, `-both`, `-any``. Split multiallelics (-) or join biallelics (+), type: snps, indels, both, any [default: both].\n", + "enum": ["+snps", "+indels", "+both", "+any", "-snps", "-indels", "-both", "-any"] + + + } + + + , + "no_version": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Do not append version and command line information to the header", + "help_text": "Type: `boolean_true`, default: `false`. Do not append version and command line information to the header." + , + "default": "False" + } + + + , + "do_not_normalize": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Do not normalize indels (with -m or -c s)", + "help_text": "Type: `boolean_true`, default: `false`. Do not normalize indels (with -m or -c s)." + , + "default": "False" + } + + + , + "output_type": { + "type": + "string", + "description": "Type: `string`, choices: ``u`, `z`, `b`, `v``. Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed BCF\n v: uncompressed VCF\n", + "help_text": "Type: `string`, choices: ``u`, `z`, `b`, `v``. Output type:\n u: uncompressed BCF\n z: compressed VCF\n b: compressed BCF\n v: uncompressed VCF\n", + "enum": ["u", "z", "b", "v"] + + + } + + + , + "old_rec_tag": { + "type": + "string", + "description": "Type: `string`. Annotate modified records with INFO/STR indicating the original variant", + "help_text": "Type: `string`. Annotate modified records with INFO/STR indicating the original variant." + + } + + + , + "regions": { + "type": + "string", + "description": "Type: `string`, example: `20:1000000-2000000`. Restrict to comma-separated list of regions", + "help_text": "Type: `string`, example: `20:1000000-2000000`. Restrict to comma-separated list of regions. \nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,\u2026\u200b].\n" + + } + + + , + "regions_file": { + "type": + "string", + "description": "Type: `file`. Restrict to regions listed in a file", + "help_text": "Type: `file`. Restrict to regions listed in a file. \nRegions can be specified either on a VCF, BED, or tab-delimited file (the default). \nFor more information check manual.\n" + + } + + + , + "regions_overlap": { + "type": + "string", + "description": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. This option controls how overlapping records are determined: \nset to \u0027pos\u0027 or \u00270\u0027 if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to \u0027record\u0027 or \u00271\u0027 if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to \u0027variant\u0027 or \u00272\u0027 to include only true overlapping variation (compare the full VCF representation \"TA\u003eT-\" vs the true sequence variation \"A\u003e-\")", + "help_text": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. This option controls how overlapping records are determined: \nset to \u0027pos\u0027 or \u00270\u0027 if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to \u0027record\u0027 or \u00271\u0027 if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to \u0027variant\u0027 or \u00272\u0027 to include only true overlapping variation (compare the full VCF representation \"TA\u003eT-\" vs the true sequence variation \"A\u003e-\").\n", + "enum": ["pos", "record", "variant", "0", "1", "2"] + + + } + + + , + "site_win": { + "type": + "integer", + "description": "Type: `integer`. Buffer for sorting lines that changed position during realignment", + "help_text": "Type: `integer`. Buffer for sorting lines that changed position during realignment.\n" + + } + + + , + "strict_filter": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. When merging (-m+), merged site is PASS only if all sites being merged PASS", + "help_text": "Type: `boolean_true`, default: `false`. When merging (-m+), merged site is PASS only if all sites being merged PASS." + , + "default": "False" + } + + + , + "targets": { + "type": + "string", + "description": "Type: `string`, example: `20:1000000-2000000`. Similar to --regions but streams rather than index-jumps", + "help_text": "Type: `string`, example: `20:1000000-2000000`. Similar to --regions but streams rather than index-jumps." + + } + + + , + "targets_file": { + "type": + "string", + "description": "Type: `file`. Similar to --regions_file but streams rather than index-jumps", + "help_text": "Type: `file`. Similar to --regions_file but streams rather than index-jumps." + + } + + + , + "targets_overlap": { + "type": + "string", + "description": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. Include if POS in the region (0), record overlaps (1), variant overlaps (2)", + "help_text": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. Include if POS in the region (0), record overlaps (1), variant overlaps (2).\nSimilar to --regions_overlap.\n", + "enum": ["pos", "record", "variant", "0", "1", "2"] + + + } + + +} +}, + + + "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/bcftools/bcftools_sort/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_sort/.config.vsh.yaml index 339c9a14..8fe8d0de 100644 --- a/target/nextflow/bcftools/bcftools_sort/.config.vsh.yaml +++ b/target/nextflow/bcftools/bcftools_sort/.config.vsh.yaml @@ -185,8 +185,8 @@ build_info: output: "target/nextflow/bcftools/bcftools_sort" executable: "target/nextflow/bcftools/bcftools_sort/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bcftools/bcftools_sort/main.nf b/target/nextflow/bcftools/bcftools_sort/main.nf index f4a196cc..242644b3 100644 --- a/target/nextflow/bcftools/bcftools_sort/main.nf +++ b/target/nextflow/bcftools/bcftools_sort/main.nf @@ -3042,8 +3042,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bcftools/bcftools_sort", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bcftools/bcftools_stats/.config.vsh.yaml b/target/nextflow/bcftools/bcftools_stats/.config.vsh.yaml new file mode 100644 index 00000000..9ee48e6b --- /dev/null +++ b/target/nextflow/bcftools/bcftools_stats/.config.vsh.yaml @@ -0,0 +1,484 @@ +name: "bcftools_stats" +namespace: "bcftools" +version: "add_trimgalore" +authors: +- name: "Theodoro Gasperin Terra Camargo" + roles: + - "author" + 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 VCF/BCF file. Maximum of two files." + info: null + must_exist: true + create_parent: true + required: true + direction: "input" + multiple: true + multiple_sep: ";" +- name: "Outputs" + arguments: + - type: "file" + name: "--output" + alternatives: + - "-o" + description: "Output txt statistics file." + info: null + must_exist: true + create_parent: true + required: true + direction: "output" + multiple: false + multiple_sep: ";" +- name: "Options" + arguments: + - type: "string" + name: "--allele_frequency_bins" + alternatives: + - "--af_bins" + description: "Allele frequency bins, a list of bin values (0.1,0.5,1).\n" + info: null + example: + - "0.1,0.5,1" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--allele_frequency_bins_file" + alternatives: + - "--af_bins_file" + description: "Same as allele_frequency_bins, but in a file.\nFormat of file is\ + \ one value per line. \ne.g. \n 0.1\n 0.5\n 1\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--allele_frequency_tag" + alternatives: + - "--af_tag" + description: "Allele frequency tag to use, by default estimated from AN,AC or\ + \ GT.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--first_allele_only" + alternatives: + - "--first_only" + description: "Include only 1st allele at multiallelic sites.\n" + info: null + direction: "input" + - type: "string" + name: "--collapse" + alternatives: + - "--c" + description: "Treat as identical records with .\n\ + See https://samtools.github.io/bcftools/bcftools.html#common_options for details.\n" + info: null + required: false + choices: + - "snps" + - "indels" + - "both" + - "all" + - "some" + - "none" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--depth" + alternatives: + - "--d" + description: "Depth distribution: min,max,bin size.\n" + info: null + example: + - "0,500,1" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--exclude" + alternatives: + - "--e" + description: "Exclude sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions\ + \ for details.\n" + info: null + example: + - "QUAL < 30 && DP < 10" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--exons" + alternatives: + - "--E" + description: "tab-delimited file with exons for indel frameshifts statistics.\ + \ \nThe columns of the file are CHR, FROM, TO, with 1-based, inclusive, positions.\ + \ \nThe file is BGZF-compressed and indexed with tabix (e.g. tabix -s1 -b2 -e3\ + \ file.gz).\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--apply_filters" + alternatives: + - "--f" + description: "Require at least one of the listed FILTER strings (e.g. \"PASS,.\"\ + ).\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fasta_reference" + alternatives: + - "--F" + description: "Faidx indexed reference sequence file to determine INDEL context.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--include" + alternatives: + - "--i" + description: "Select sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions\ + \ for details.\n" + info: null + example: + - "QUAL >= 30 && DP >= 10" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--split_by_ID" + alternatives: + - "--I" + description: "Collect stats for sites with ID separately (known vs novel).\n" + info: null + direction: "input" + - type: "string" + name: "--regions" + alternatives: + - "--r" + description: "Restrict to comma-separated list of regions. \nFollowing formats\ + \ are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--regions_file" + alternatives: + - "--R" + description: "Restrict to regions listed in a file. \nRegions can be specified\ + \ either on a VCF, BED, or tab-delimited file (the default). \nFor more information\ + \ check manual.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--regions_overlap" + description: "This option controls how overlapping records are determined: \n\ + set to 'pos' or '0' if the VCF record has to have POS inside a region (this\ + \ corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if\ + \ also overlapping records with POS outside a region should be included (this\ + \ is the default behavior of -r/-R, \nand includes indels with POS at the end\ + \ of a region, which are technically outside the region); \nor set to 'variant'\ + \ or '2' to include only true overlapping variation (compare the full VCF representation\ + \ \"TA>T-\" vs the true sequence variation \"A>-\").\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--samples" + alternatives: + - "--s" + description: "List of samples for sample stats, \"-\" to include all samples.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--samples_file" + alternatives: + - "--S" + description: "File of samples to include.\ne.g. \n sample1 1\n sample2 \ + \ 2\n sample3 2\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--targets" + alternatives: + - "--t" + description: "Similar as -r, --regions, but the next position is accessed by streaming\ + \ the whole VCF/BCF \nrather than using the tbi/csi index. Both -r and -t options\ + \ can be applied simultaneously: -r uses the \nindex to jump to a region and\ + \ -t discards positions which are not in the targets. Unlike -r, targets \n\ + can be prefixed with \"^\" to request logical complement. For example, \"^X,Y,MT\"\ + \ indicates that \nsequences X, Y and MT should be skipped. Yet another difference\ + \ between the -t/-T and -r/-R is \nthat -r/-R checks for proper overlaps and\ + \ considers both POS and the end position of an indel, \nwhile -t/-T considers\ + \ the POS coordinate only (by default; see also --regions-overlap and --targets-overlap).\ + \ \nNote that -t cannot be used in combination with -T.\nFollowing formats are\ + \ supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n" + info: null + example: + - "20:1000000-2000000" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--targets_file" + alternatives: + - "--T" + description: "Similar to --regions_file option but streams rather than index-jumps.\n" + info: null + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--targets_overlaps" + description: "Include if POS in the region (0), record overlaps (1), variant overlaps\ + \ (2).\n" + info: null + required: false + choices: + - "pos" + - "record" + - "variant" + - "0" + - "1" + - "2" + direction: "input" + multiple: false + multiple_sep: ";" + - type: "string" + name: "--user_tstv" + alternatives: + - "--u" + description: "Collect Ts/Tv stats for any tag using the given binning [0:1:100].\n\ + Format is .\nA subfield can be selected as e.g. 'PV4[0]', here\ + \ the first value of the PV4 tag.\n" + info: null + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "boolean_true" + name: "--verbose" + alternatives: + - "--v" + description: "Produce verbose per-site and per-sample output.\n" + info: null + direction: "input" +resources: +- type: "bash_script" + path: "script.sh" + is_executable: true +description: "Parses VCF or BCF and produces a txt stats file which can be plotted\ + \ using plot-vcfstats.\nWhen two files are given, the program generates separate\ + \ stats for intersection\nand the complements. By default only sites are compared,\ + \ -s/-S must given to include\nalso sample columns.\n" +test_resources: +- type: "bash_script" + path: "test.sh" + is_executable: true +info: null +status: "enabled" +requirements: + commands: + - "ps" +keywords: +- "Stats" +- "VCF" +- "BCF" +license: "MIT/Expat, GNU" +references: + doi: + - "https://doi.org/10.1093/gigascience/giab008" +links: + repository: "https://github.com/samtools/bcftools" + homepage: "https://samtools.github.io/bcftools/" + documentation: "https://samtools.github.io/bcftools/bcftools.html#stats" + issue_tracker: "https://github.com/samtools/bcftools/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: "add_trimgalore" + namespace_separator: "/" + setup: + - type: "apt" + packages: + - "bcftools" + - "procps" + interactive: false + - type: "docker" + run: + - "echo \"bcftools: \\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools\ + \ //p')\\\"\" > /var/software_versions.txt\n" + test_setup: + - type: "apt" + packages: + - "tabix" + interactive: false + entrypoint: [] + cmd: null +- type: "native" + id: "native" +build_info: + config: "src/bcftools/bcftools_stats/config.vsh.yaml" + runner: "nextflow" + engine: "docker|native" + output: "target/nextflow/bcftools/bcftools_stats" + executable: "target/nextflow/bcftools/bcftools_stats/main.nf" + viash_version: "0.9.0-RC7" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" +package_config: + name: "biobox" + version: "add_trimgalore" + description: "A collection of bioinformatics tools for working with sequence data.\n" + info: null + viash_version: "0.9.0-RC7" + 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 := 'add_trimgalore'" + 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/bcftools/bcftools_stats/main.nf b/target/nextflow/bcftools/bcftools_stats/main.nf new file mode 100644 index 00000000..e65b82b1 --- /dev/null +++ b/target/nextflow/bcftools/bcftools_stats/main.nf @@ -0,0 +1,3948 @@ +// bcftools_stats add_trimgalore +// +// This wrapper script is auto-generated by viash 0.9.0-RC7 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) + +//////////////////////////// +// 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('\\$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('\\$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('\\$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" : "bcftools_stats", + "namespace" : "bcftools", + "version" : "add_trimgalore", + "authors" : [ + { + "name" : "Theodoro Gasperin Terra Camargo", + "roles" : [ + "author" + ], + "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 VCF/BCF file. Maximum of two files.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "input", + "multiple" : true, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Outputs", + "arguments" : [ + { + "type" : "file", + "name" : "--output", + "alternatives" : [ + "-o" + ], + "description" : "Output txt statistics file.", + "must_exist" : true, + "create_parent" : true, + "required" : true, + "direction" : "output", + "multiple" : false, + "multiple_sep" : ";" + } + ] + }, + { + "name" : "Options", + "arguments" : [ + { + "type" : "string", + "name" : "--allele_frequency_bins", + "alternatives" : [ + "--af_bins" + ], + "description" : "Allele frequency bins, a list of bin values (0.1,0.5,1).\n", + "example" : [ + "0.1,0.5,1" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--allele_frequency_bins_file", + "alternatives" : [ + "--af_bins_file" + ], + "description" : "Same as allele_frequency_bins, but in a file.\nFormat of file is one value per line. \ne.g. \n 0.1\n 0.5\n 1\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--allele_frequency_tag", + "alternatives" : [ + "--af_tag" + ], + "description" : "Allele frequency tag to use, by default estimated from AN,AC or GT.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--first_allele_only", + "alternatives" : [ + "--first_only" + ], + "description" : "Include only 1st allele at multiallelic sites.\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--collapse", + "alternatives" : [ + "--c" + ], + "description" : "Treat as identical records with .\nSee https://samtools.github.io/bcftools/bcftools.html#common_options for details.\n", + "required" : false, + "choices" : [ + "snps", + "indels", + "both", + "all", + "some", + "none" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--depth", + "alternatives" : [ + "--d" + ], + "description" : "Depth distribution: min,max,bin size.\n", + "example" : [ + "0,500,1" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--exclude", + "alternatives" : [ + "--e" + ], + "description" : "Exclude sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions for details.\n", + "example" : [ + "QUAL < 30 && DP < 10" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--exons", + "alternatives" : [ + "--E" + ], + "description" : "tab-delimited file with exons for indel frameshifts statistics. \nThe columns of the file are CHR, FROM, TO, with 1-based, inclusive, positions. \nThe file is BGZF-compressed and indexed with tabix (e.g. tabix -s1 -b2 -e3 file.gz).\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--apply_filters", + "alternatives" : [ + "--f" + ], + "description" : "Require at least one of the listed FILTER strings (e.g. \\"PASS,.\\").\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--fasta_reference", + "alternatives" : [ + "--F" + ], + "description" : "Faidx indexed reference sequence file to determine INDEL context.\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--include", + "alternatives" : [ + "--i" + ], + "description" : "Select sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions for details.\n", + "example" : [ + "QUAL >= 30 && DP >= 10" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--split_by_ID", + "alternatives" : [ + "--I" + ], + "description" : "Collect stats for sites with ID separately (known vs novel).\n", + "direction" : "input" + }, + { + "type" : "string", + "name" : "--regions", + "alternatives" : [ + "--r" + ], + "description" : "Restrict to comma-separated list of regions. \nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n", + "example" : [ + "20:1000000-2000000" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--regions_file", + "alternatives" : [ + "--R" + ], + "description" : "Restrict to regions listed in a file. \nRegions can be specified either on a VCF, BED, or tab-delimited file (the default). \nFor more information check manual.\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--regions_overlap", + "description" : "This option controls how overlapping records are determined: \nset to 'pos' or '0' if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to 'record' or '1' if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to 'variant' or '2' to include only true overlapping variation (compare the full VCF representation \\"TA>T-\\" vs the true sequence variation \\"A>-\\").\n", + "required" : false, + "choices" : [ + "pos", + "record", + "variant", + "0", + "1", + "2" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--samples", + "alternatives" : [ + "--s" + ], + "description" : "List of samples for sample stats, \\"-\\" to include all samples.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--samples_file", + "alternatives" : [ + "--S" + ], + "description" : "File of samples to include.\ne.g. \n sample1 1\n sample2 2\n sample3 2\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--targets", + "alternatives" : [ + "--t" + ], + "description" : "Similar as -r, --regions, but the next position is accessed by streaming the whole VCF/BCF \nrather than using the tbi/csi index. Both -r and -t options can be applied simultaneously: -r uses the \nindex to jump to a region and -t discards positions which are not in the targets. Unlike -r, targets \ncan be prefixed with \\"^\\" to request logical complement. For example, \\"^X,Y,MT\\" indicates that \nsequences X, Y and MT should be skipped. Yet another difference between the -t/-T and -r/-R is \nthat -r/-R checks for proper overlaps and considers both POS and the end position of an indel, \nwhile -t/-T considers the POS coordinate only (by default; see also --regions-overlap and --targets-overlap). \nNote that -t cannot be used in combination with -T.\nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,…​].\n", + "example" : [ + "20:1000000-2000000" + ], + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--targets_file", + "alternatives" : [ + "--T" + ], + "description" : "Similar to --regions_file option but streams rather than index-jumps.\n", + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--targets_overlaps", + "description" : "Include if POS in the region (0), record overlaps (1), variant overlaps (2).\n", + "required" : false, + "choices" : [ + "pos", + "record", + "variant", + "0", + "1", + "2" + ], + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "string", + "name" : "--user_tstv", + "alternatives" : [ + "--u" + ], + "description" : "Collect Ts/Tv stats for any tag using the given binning [0:1:100].\nFormat is .\nA subfield can be selected as e.g. 'PV4[0]', here the first value of the PV4 tag.\n", + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "boolean_true", + "name" : "--verbose", + "alternatives" : [ + "--v" + ], + "description" : "Produce verbose per-site and per-sample output.\n", + "direction" : "input" + } + ] + } + ], + "resources" : [ + { + "type" : "bash_script", + "path" : "script.sh", + "is_executable" : true + } + ], + "description" : "Parses VCF or BCF and produces a txt stats file which can be plotted using plot-vcfstats.\nWhen two files are given, the program generates separate stats for intersection\nand the complements. By default only sites are compared, -s/-S must given to include\nalso sample columns.\n", + "test_resources" : [ + { + "type" : "bash_script", + "path" : "test.sh", + "is_executable" : true + } + ], + "status" : "enabled", + "requirements" : { + "commands" : [ + "ps" + ] + }, + "keywords" : [ + "Stats", + "VCF", + "BCF" + ], + "license" : "MIT/Expat, GNU", + "references" : { + "doi" : [ + "https://doi.org/10.1093/gigascience/giab008" + ] + }, + "links" : { + "repository" : "https://github.com/samtools/bcftools", + "homepage" : "https://samtools.github.io/bcftools/", + "documentation" : "https://samtools.github.io/bcftools/bcftools.html#stats", + "issue_tracker" : "https://github.com/samtools/bcftools/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" : "add_trimgalore", + "namespace_separator" : "/", + "setup" : [ + { + "type" : "apt", + "packages" : [ + "bcftools", + "procps" + ], + "interactive" : false + }, + { + "type" : "docker", + "run" : [ + "echo \\"bcftools: \\\\\\"$(bcftools --version | grep 'bcftools' | sed -n 's/^bcftools //p')\\\\\\"\\" > /var/software_versions.txt\n" + ] + } + ], + "test_setup" : [ + { + "type" : "apt", + "packages" : [ + "tabix" + ], + "interactive" : false + } + ] + }, + { + "type" : "native", + "id" : "native" + } + ], + "build_info" : { + "config" : "/workdir/root/repo/src/bcftools/bcftools_stats/config.vsh.yaml", + "runner" : "nextflow", + "engine" : "docker|native", + "output" : "target/nextflow/bcftools/bcftools_stats", + "viash_version" : "0.9.0-RC7", + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" + }, + "package_config" : { + "name" : "biobox", + "version" : "add_trimgalore", + "description" : "A collection of bioinformatics tools for working with sequence data.\n", + "viash_version" : "0.9.0-RC7", + "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 := 'add_trimgalore'" + ], + "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_ALLELE_FREQUENCY_BINS+x} ]; then echo "${VIASH_PAR_ALLELE_FREQUENCY_BINS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_allele_frequency_bins='&'#" ; else echo "# par_allele_frequency_bins="; fi ) +$( if [ ! -z ${VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE+x} ]; then echo "${VIASH_PAR_ALLELE_FREQUENCY_BINS_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_allele_frequency_bins_file='&'#" ; else echo "# par_allele_frequency_bins_file="; fi ) +$( if [ ! -z ${VIASH_PAR_ALLELE_FREQUENCY_TAG+x} ]; then echo "${VIASH_PAR_ALLELE_FREQUENCY_TAG}" | sed "s#'#'\\"'\\"'#g;s#.*#par_allele_frequency_tag='&'#" ; else echo "# par_allele_frequency_tag="; fi ) +$( if [ ! -z ${VIASH_PAR_FIRST_ALLELE_ONLY+x} ]; then echo "${VIASH_PAR_FIRST_ALLELE_ONLY}" | sed "s#'#'\\"'\\"'#g;s#.*#par_first_allele_only='&'#" ; else echo "# par_first_allele_only="; fi ) +$( if [ ! -z ${VIASH_PAR_COLLAPSE+x} ]; then echo "${VIASH_PAR_COLLAPSE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_collapse='&'#" ; else echo "# par_collapse="; fi ) +$( if [ ! -z ${VIASH_PAR_DEPTH+x} ]; then echo "${VIASH_PAR_DEPTH}" | sed "s#'#'\\"'\\"'#g;s#.*#par_depth='&'#" ; else echo "# par_depth="; fi ) +$( if [ ! -z ${VIASH_PAR_EXCLUDE+x} ]; then echo "${VIASH_PAR_EXCLUDE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_exclude='&'#" ; else echo "# par_exclude="; fi ) +$( if [ ! -z ${VIASH_PAR_EXONS+x} ]; then echo "${VIASH_PAR_EXONS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_exons='&'#" ; else echo "# par_exons="; fi ) +$( if [ ! -z ${VIASH_PAR_APPLY_FILTERS+x} ]; then echo "${VIASH_PAR_APPLY_FILTERS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_apply_filters='&'#" ; else echo "# par_apply_filters="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTA_REFERENCE+x} ]; then echo "${VIASH_PAR_FASTA_REFERENCE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_fasta_reference='&'#" ; else echo "# par_fasta_reference="; fi ) +$( if [ ! -z ${VIASH_PAR_INCLUDE+x} ]; then echo "${VIASH_PAR_INCLUDE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_include='&'#" ; else echo "# par_include="; fi ) +$( if [ ! -z ${VIASH_PAR_SPLIT_BY_ID+x} ]; then echo "${VIASH_PAR_SPLIT_BY_ID}" | sed "s#'#'\\"'\\"'#g;s#.*#par_split_by_ID='&'#" ; else echo "# par_split_by_ID="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS+x} ]; then echo "${VIASH_PAR_REGIONS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions='&'#" ; else echo "# par_regions="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_FILE+x} ]; then echo "${VIASH_PAR_REGIONS_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions_file='&'#" ; else echo "# par_regions_file="; fi ) +$( if [ ! -z ${VIASH_PAR_REGIONS_OVERLAP+x} ]; then echo "${VIASH_PAR_REGIONS_OVERLAP}" | sed "s#'#'\\"'\\"'#g;s#.*#par_regions_overlap='&'#" ; else echo "# par_regions_overlap="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLES+x} ]; then echo "${VIASH_PAR_SAMPLES}" | sed "s#'#'\\"'\\"'#g;s#.*#par_samples='&'#" ; else echo "# par_samples="; fi ) +$( if [ ! -z ${VIASH_PAR_SAMPLES_FILE+x} ]; then echo "${VIASH_PAR_SAMPLES_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_samples_file='&'#" ; else echo "# par_samples_file="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS+x} ]; then echo "${VIASH_PAR_TARGETS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_targets='&'#" ; else echo "# par_targets="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS_FILE+x} ]; then echo "${VIASH_PAR_TARGETS_FILE}" | sed "s#'#'\\"'\\"'#g;s#.*#par_targets_file='&'#" ; else echo "# par_targets_file="; fi ) +$( if [ ! -z ${VIASH_PAR_TARGETS_OVERLAPS+x} ]; then echo "${VIASH_PAR_TARGETS_OVERLAPS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_targets_overlaps='&'#" ; else echo "# par_targets_overlaps="; fi ) +$( if [ ! -z ${VIASH_PAR_USER_TSTV+x} ]; then echo "${VIASH_PAR_USER_TSTV}" | sed "s#'#'\\"'\\"'#g;s#.*#par_user_tstv='&'#" ; else echo "# par_user_tstv="; 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 + +# Exit on error +set -eo pipefail + +# Unset parameters +unset_if_false=( + par_first_allele_only + par_split_by_ID + par_verbose +) + +for par in \\${unset_if_false[@]}; do + test_val="\\${!par}" + [[ "\\$test_val" == "false" ]] && unset \\$par +done + +# Create input array +IFS=";" read -ra input <<< \\$par_input + +# Check the size of the input array +if [[ \\${#input[@]} -gt 2 ]]; then + echo "Error: --input only takes a max of two files!" + exit 1 +fi + +# Execute bcftools stats with the provided arguments +bcftools stats \\\\ + \\${par_first_allele_only:+--1st-allele-only} \\\\ + \\${par_split_by_ID:+--split-by-ID} \\\\ + \\${par_verbose:+--verbose} \\\\ + \\${par_allele_frequency_bins:+--af-bins "\\${par_allele_frequency_bins}"} \\\\ + \\${par_allele_frequency_bins_file:+--af-bins "\\${par_allele_frequency_bins_file}"} \\\\ + \\${par_allele_frequency_tag:+--af-tag "\\${par_allele_frequency_tag}"} \\\\ + \\${par_collapse:+-c "\\${par_collapse}"} \\\\ + \\${par_depth:+-d "\\${par_depth}"} \\\\ + \\${par_exclude:+-e "\\${par_exclude}"} \\\\ + \\${par_exons:+-E "\\${par_exons}"} \\\\ + \\${par_apply_filters:+-f "\\${par_apply_filters}"} \\\\ + \\${par_fasta_reference:+-F "\\${par_fasta_reference}"} \\\\ + \\${par_include:+-i "\\${par_include}"} \\\\ + \\${par_regions:+-r "\\${par_regions}"} \\\\ + \\${par_regions_file:+-R "\\${par_regions_file}"} \\\\ + \\${par_regions_overlap:+--regions-overlap "\\${par_regions_overlap}"} \\\\ + \\${par_samples:+-s "\\${par_samples}"} \\\\ + \\${par_samples_file:+-S "\\${par_samples_file}"} \\\\ + \\${par_targets:+-t "\\${par_targets}"} \\\\ + \\${par_targets_file:+-T "\\${par_targets_file}"} \\\\ + \\${par_targets_overlaps:+--targets-overlap "\\${par_targets_overlaps}"} \\\\ + \\${par_user_tstv:+-u "\\${par_user_tstv}"} \\\\ + "\\${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('\\$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 -> + "\${ args.containsKey(\"${par.plainName}\") ? \"mkdir_parent \\\"\" + (args[\"${par.plainName}\"] instanceof String ? args[\"${par.plainName}\"] : args[\"${par.plainName}\"].join('\" \"')) + \"\\\"\" : \"\" }" + } + .join("\n") + + // construct inputFileExports + def inputFileExports = meta.config.allArguments + .findAll { it.type == "file" && it.direction.toLowerCase() == "input" } + .collect { par -> + def viash_par_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()}=\\\"\" + ${viash_par_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 + | + |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 escapeText = { s -> s.toString().replaceAll('([`"])', '\\\\\\\\\$1') } + |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/bcftools/bcftools_stats", + "tag" : "add_trimgalore" + }, + "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/bcftools/bcftools_stats/nextflow.config b/target/nextflow/bcftools/bcftools_stats/nextflow.config new file mode 100644 index 00000000..e736566d --- /dev/null +++ b/target/nextflow/bcftools/bcftools_stats/nextflow.config @@ -0,0 +1,126 @@ +manifest { + name = 'bcftools/bcftools_stats' + mainScript = 'main.nf' + nextflowVersion = '!>=20.12.1-edge' + version = 'add_trimgalore' + description = 'Parses VCF or BCF and produces a txt stats file which can be plotted using plot-vcfstats.\nWhen two files are given, the program generates separate stats for intersection\nand the complements. By default only sites are compared, -s/-S must given to include\nalso sample columns.\n' + 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/bcftools/bcftools_stats/nextflow_schema.json b/target/nextflow/bcftools/bcftools_stats/nextflow_schema.json new file mode 100644 index 00000000..2c35fa3c --- /dev/null +++ b/target/nextflow/bcftools/bcftools_stats/nextflow_schema.json @@ -0,0 +1,338 @@ +{ +"$schema": "http://json-schema.org/draft-07/schema", +"title": "bcftools_stats", +"description": "Parses VCF or BCF and produces a txt stats file which can be plotted using plot-vcfstats.\nWhen two files are given, the program generates separate stats for intersection\nand the complements. By default only sites are compared, -s/-S must given to include\nalso sample columns.\n", +"type": "object", +"definitions": { + + + + "inputs" : { + "title": "Inputs", + "type": "object", + "description": "No description", + "properties": { + + + "input": { + "type": + "string", + "description": "Type: List of `file`, required, multiple_sep: `\";\"`. Input VCF/BCF file", + "help_text": "Type: List of `file`, required, multiple_sep: `\";\"`. Input VCF/BCF file. Maximum of two files." + + } + + +} +}, + + + "outputs" : { + "title": "Outputs", + "type": "object", + "description": "No description", + "properties": { + + + "output": { + "type": + "string", + "description": "Type: `file`, required, default: `$id.$key.output.output`. Output txt statistics file", + "help_text": "Type: `file`, required, default: `$id.$key.output.output`. Output txt statistics file." + , + "default": "$id.$key.output.output" + } + + +} +}, + + + "options" : { + "title": "Options", + "type": "object", + "description": "No description", + "properties": { + + + "allele_frequency_bins": { + "type": + "string", + "description": "Type: `string`, example: `0.1,0.5,1`. Allele frequency bins, a list of bin values (0", + "help_text": "Type: `string`, example: `0.1,0.5,1`. Allele frequency bins, a list of bin values (0.1,0.5,1).\n" + + } + + + , + "allele_frequency_bins_file": { + "type": + "string", + "description": "Type: `file`. Same as allele_frequency_bins, but in a file", + "help_text": "Type: `file`. Same as allele_frequency_bins, but in a file.\nFormat of file is one value per line. \ne.g. \n 0.1\n 0.5\n 1\n" + + } + + + , + "allele_frequency_tag": { + "type": + "string", + "description": "Type: `string`. Allele frequency tag to use, by default estimated from AN,AC or GT", + "help_text": "Type: `string`. Allele frequency tag to use, by default estimated from AN,AC or GT.\n" + + } + + + , + "first_allele_only": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Include only 1st allele at multiallelic sites", + "help_text": "Type: `boolean_true`, default: `false`. Include only 1st allele at multiallelic sites.\n" + , + "default": "False" + } + + + , + "collapse": { + "type": + "string", + "description": "Type: `string`, choices: ``snps`, `indels`, `both`, `all`, `some`, `none``. Treat as identical records with \u003csnps|indels|both|all|some|none\u003e", + "help_text": "Type: `string`, choices: ``snps`, `indels`, `both`, `all`, `some`, `none``. Treat as identical records with \u003csnps|indels|both|all|some|none\u003e.\nSee https://samtools.github.io/bcftools/bcftools.html#common_options for details.\n", + "enum": ["snps", "indels", "both", "all", "some", "none"] + + + } + + + , + "depth": { + "type": + "string", + "description": "Type: `string`, example: `0,500,1`. Depth distribution: min,max,bin size", + "help_text": "Type: `string`, example: `0,500,1`. Depth distribution: min,max,bin size.\n" + + } + + + , + "exclude": { + "type": + "string", + "description": "Type: `string`, example: `QUAL \u003c 30 \u0026\u0026 DP \u003c 10`. Exclude sites for which the expression is true", + "help_text": "Type: `string`, example: `QUAL \u003c 30 \u0026\u0026 DP \u003c 10`. Exclude sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions for details.\n" + + } + + + , + "exons": { + "type": + "string", + "description": "Type: `file`. tab-delimited file with exons for indel frameshifts statistics", + "help_text": "Type: `file`. tab-delimited file with exons for indel frameshifts statistics. \nThe columns of the file are CHR, FROM, TO, with 1-based, inclusive, positions. \nThe file is BGZF-compressed and indexed with tabix (e.g. tabix -s1 -b2 -e3 file.gz).\n" + + } + + + , + "apply_filters": { + "type": + "string", + "description": "Type: `string`. Require at least one of the listed FILTER strings (e", + "help_text": "Type: `string`. Require at least one of the listed FILTER strings (e.g. \"PASS,.\").\n" + + } + + + , + "fasta_reference": { + "type": + "string", + "description": "Type: `file`. Faidx indexed reference sequence file to determine INDEL context", + "help_text": "Type: `file`. Faidx indexed reference sequence file to determine INDEL context.\n" + + } + + + , + "include": { + "type": + "string", + "description": "Type: `string`, example: `QUAL \u003e= 30 \u0026\u0026 DP \u003e= 10`. Select sites for which the expression is true", + "help_text": "Type: `string`, example: `QUAL \u003e= 30 \u0026\u0026 DP \u003e= 10`. Select sites for which the expression is true.\nSee https://samtools.github.io/bcftools/bcftools.html#expressions for details.\n" + + } + + + , + "split_by_ID": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Collect stats for sites with ID separately (known vs novel)", + "help_text": "Type: `boolean_true`, default: `false`. Collect stats for sites with ID separately (known vs novel).\n" + , + "default": "False" + } + + + , + "regions": { + "type": + "string", + "description": "Type: `string`, example: `20:1000000-2000000`. Restrict to comma-separated list of regions", + "help_text": "Type: `string`, example: `20:1000000-2000000`. Restrict to comma-separated list of regions. \nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,\u2026\u200b].\n" + + } + + + , + "regions_file": { + "type": + "string", + "description": "Type: `file`. Restrict to regions listed in a file", + "help_text": "Type: `file`. Restrict to regions listed in a file. \nRegions can be specified either on a VCF, BED, or tab-delimited file (the default). \nFor more information check manual.\n" + + } + + + , + "regions_overlap": { + "type": + "string", + "description": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. This option controls how overlapping records are determined: \nset to \u0027pos\u0027 or \u00270\u0027 if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to \u0027record\u0027 or \u00271\u0027 if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to \u0027variant\u0027 or \u00272\u0027 to include only true overlapping variation (compare the full VCF representation \"TA\u003eT-\" vs the true sequence variation \"A\u003e-\")", + "help_text": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. This option controls how overlapping records are determined: \nset to \u0027pos\u0027 or \u00270\u0027 if the VCF record has to have POS inside a region (this corresponds to the default behavior of -t/-T); \nset to \u0027record\u0027 or \u00271\u0027 if also overlapping records with POS outside a region should be included (this is the default behavior of -r/-R, \nand includes indels with POS at the end of a region, which are technically outside the region); \nor set to \u0027variant\u0027 or \u00272\u0027 to include only true overlapping variation (compare the full VCF representation \"TA\u003eT-\" vs the true sequence variation \"A\u003e-\").\n", + "enum": ["pos", "record", "variant", "0", "1", "2"] + + + } + + + , + "samples": { + "type": + "string", + "description": "Type: `string`. List of samples for sample stats, \"-\" to include all samples", + "help_text": "Type: `string`. List of samples for sample stats, \"-\" to include all samples.\n" + + } + + + , + "samples_file": { + "type": + "string", + "description": "Type: `file`. File of samples to include", + "help_text": "Type: `file`. File of samples to include.\ne.g. \n sample1 1\n sample2 2\n sample3 2\n" + + } + + + , + "targets": { + "type": + "string", + "description": "Type: `string`, example: `20:1000000-2000000`. Similar as -r, --regions, but the next position is accessed by streaming the whole VCF/BCF \nrather than using the tbi/csi index", + "help_text": "Type: `string`, example: `20:1000000-2000000`. Similar as -r, --regions, but the next position is accessed by streaming the whole VCF/BCF \nrather than using the tbi/csi index. Both -r and -t options can be applied simultaneously: -r uses the \nindex to jump to a region and -t discards positions which are not in the targets. Unlike -r, targets \ncan be prefixed with \"^\" to request logical complement. For example, \"^X,Y,MT\" indicates that \nsequences X, Y and MT should be skipped. Yet another difference between the -t/-T and -r/-R is \nthat -r/-R checks for proper overlaps and considers both POS and the end position of an indel, \nwhile -t/-T considers the POS coordinate only (by default; see also --regions-overlap and --targets-overlap). \nNote that -t cannot be used in combination with -T.\nFollowing formats are supported: chr|chr:pos|chr:beg-end|chr:beg-[,\u2026\u200b].\n" + + } + + + , + "targets_file": { + "type": + "string", + "description": "Type: `file`. Similar to --regions_file option but streams rather than index-jumps", + "help_text": "Type: `file`. Similar to --regions_file option but streams rather than index-jumps.\n" + + } + + + , + "targets_overlaps": { + "type": + "string", + "description": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. Include if POS in the region (0), record overlaps (1), variant overlaps (2)", + "help_text": "Type: `string`, choices: ``pos`, `record`, `variant`, `0`, `1`, `2``. Include if POS in the region (0), record overlaps (1), variant overlaps (2).\n", + "enum": ["pos", "record", "variant", "0", "1", "2"] + + + } + + + , + "user_tstv": { + "type": + "string", + "description": "Type: `string`. Collect Ts/Tv stats for any tag using the given binning [0:1:100]", + "help_text": "Type: `string`. Collect Ts/Tv stats for any tag using the given binning [0:1:100].\nFormat is \u003cTAG[:min:max:n]\u003e.\nA subfield can be selected as e.g. \u0027PV4[0]\u0027, here the first value of the PV4 tag.\n" + + } + + + , + "verbose": { + "type": + "boolean", + "description": "Type: `boolean_true`, default: `false`. Produce verbose per-site and per-sample output", + "help_text": "Type: `boolean_true`, default: `false`. Produce verbose per-site and per-sample output.\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/bcl_convert/.config.vsh.yaml b/target/nextflow/bcl_convert/.config.vsh.yaml index b1813125..9900bfb6 100644 --- a/target/nextflow/bcl_convert/.config.vsh.yaml +++ b/target/nextflow/bcl_convert/.config.vsh.yaml @@ -418,8 +418,8 @@ build_info: output: "target/nextflow/bcl_convert" executable: "target/nextflow/bcl_convert/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bcl_convert/main.nf b/target/nextflow/bcl_convert/main.nf index 3451739d..ea3d88d2 100644 --- a/target/nextflow/bcl_convert/main.nf +++ b/target/nextflow/bcl_convert/main.nf @@ -3323,8 +3323,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bcl_convert", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 428580fc..6e15b9be 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 @@ -270,8 +270,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" 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 c2562b8f..39702c99 100644 --- a/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/main.nf +++ b/target/nextflow/bd_rhapsody/bd_rhapsody_make_reference/main.nf @@ -3136,8 +3136,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bd_rhapsody/bd_rhapsody_make_reference", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/bedtools/bedtools_bamtofastq/.config.vsh.yaml b/target/nextflow/bedtools/bedtools_bamtofastq/.config.vsh.yaml index e5f1eadf..37039174 100644 --- a/target/nextflow/bedtools/bedtools_bamtofastq/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_bamtofastq/.config.vsh.yaml @@ -187,8 +187,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_bamtofastq" executable: "target/nextflow/bedtools/bedtools_bamtofastq/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_bamtofastq/main.nf b/target/nextflow/bedtools/bedtools_bamtofastq/main.nf index d54845d1..c6823fff 100644 --- a/target/nextflow/bedtools/bedtools_bamtofastq/main.nf +++ b/target/nextflow/bedtools/bedtools_bamtofastq/main.nf @@ -3044,8 +3044,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_bamtofastq", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 b2c0f83e..b580c05b 100644 --- a/target/nextflow/bedtools/bedtools_bed12tobed6/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_bed12tobed6/.config.vsh.yaml @@ -176,8 +176,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_bed12tobed6" executable: "target/nextflow/bedtools/bedtools_bed12tobed6/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_bed12tobed6/main.nf b/target/nextflow/bedtools/bedtools_bed12tobed6/main.nf index f8780992..e558d496 100644 --- a/target/nextflow/bedtools/bedtools_bed12tobed6/main.nf +++ b/target/nextflow/bedtools/bedtools_bed12tobed6/main.nf @@ -3029,8 +3029,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_bed12tobed6", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 fbf82ce5..fab12a50 100644 --- a/target/nextflow/bedtools/bedtools_bedtobam/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_bedtobam/.config.vsh.yaml @@ -214,8 +214,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_bedtobam" executable: "target/nextflow/bedtools/bedtools_bedtobam/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_bedtobam/main.nf b/target/nextflow/bedtools/bedtools_bedtobam/main.nf index f3f716d4..7086a7f4 100644 --- a/target/nextflow/bedtools/bedtools_bedtobam/main.nf +++ b/target/nextflow/bedtools/bedtools_bedtobam/main.nf @@ -3077,8 +3077,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_bedtobam", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 d8353443..465b00f8 100644 --- a/target/nextflow/bedtools/bedtools_genomecov/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_genomecov/.config.vsh.yaml @@ -337,8 +337,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_genomecov" executable: "target/nextflow/bedtools/bedtools_genomecov/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_genomecov/main.nf b/target/nextflow/bedtools/bedtools_genomecov/main.nf index f63b30e6..decf508d 100644 --- a/target/nextflow/bedtools/bedtools_genomecov/main.nf +++ b/target/nextflow/bedtools/bedtools_genomecov/main.nf @@ -3201,8 +3201,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_genomecov", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 041dc6e4..83b452a2 100644 --- a/target/nextflow/bedtools/bedtools_getfasta/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_getfasta/.config.vsh.yaml @@ -232,8 +232,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_getfasta" executable: "target/nextflow/bedtools/bedtools_getfasta/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_getfasta/main.nf b/target/nextflow/bedtools/bedtools_getfasta/main.nf index df2ebb4f..3dbeba33 100644 --- a/target/nextflow/bedtools/bedtools_getfasta/main.nf +++ b/target/nextflow/bedtools/bedtools_getfasta/main.nf @@ -3080,8 +3080,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_getfasta", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 00208ae2..f581ade3 100644 --- a/target/nextflow/bedtools/bedtools_groupby/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_groupby/.config.vsh.yaml @@ -273,8 +273,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_groupby" executable: "target/nextflow/bedtools/bedtools_groupby/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_groupby/main.nf b/target/nextflow/bedtools/bedtools_groupby/main.nf index 391e2d39..37af7c71 100644 --- a/target/nextflow/bedtools/bedtools_groupby/main.nf +++ b/target/nextflow/bedtools/bedtools_groupby/main.nf @@ -3124,8 +3124,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_groupby", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 da4e739a..614d7bf7 100644 --- a/target/nextflow/bedtools/bedtools_intersect/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_intersect/.config.vsh.yaml @@ -410,8 +410,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_intersect" executable: "target/nextflow/bedtools/bedtools_intersect/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_intersect/main.nf b/target/nextflow/bedtools/bedtools_intersect/main.nf index fb45150f..4a710c61 100644 --- a/target/nextflow/bedtools/bedtools_intersect/main.nf +++ b/target/nextflow/bedtools/bedtools_intersect/main.nf @@ -3276,8 +3276,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_intersect", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 4f3b9ad5..b83f3c07 100644 --- a/target/nextflow/bedtools/bedtools_links/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_links/.config.vsh.yaml @@ -210,8 +210,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_links" executable: "target/nextflow/bedtools/bedtools_links/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_links/main.nf b/target/nextflow/bedtools/bedtools_links/main.nf index 9284a2bd..de64cca0 100644 --- a/target/nextflow/bedtools/bedtools_links/main.nf +++ b/target/nextflow/bedtools/bedtools_links/main.nf @@ -3067,8 +3067,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_links", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 2716b643..e6167007 100644 --- a/target/nextflow/bedtools/bedtools_merge/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_merge/.config.vsh.yaml @@ -279,8 +279,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_merge" executable: "target/nextflow/bedtools/bedtools_merge/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_merge/main.nf b/target/nextflow/bedtools/bedtools_merge/main.nf index 578d2f25..69628c8f 100644 --- a/target/nextflow/bedtools/bedtools_merge/main.nf +++ b/target/nextflow/bedtools/bedtools_merge/main.nf @@ -3128,8 +3128,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_merge", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 8a50c884..ea2b5ced 100644 --- a/target/nextflow/bedtools/bedtools_sort/.config.vsh.yaml +++ b/target/nextflow/bedtools/bedtools_sort/.config.vsh.yaml @@ -222,8 +222,8 @@ build_info: output: "target/nextflow/bedtools/bedtools_sort" executable: "target/nextflow/bedtools/bedtools_sort/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/bedtools/bedtools_sort/main.nf b/target/nextflow/bedtools/bedtools_sort/main.nf index 2f59b8c3..238b047b 100644 --- a/target/nextflow/bedtools/bedtools_sort/main.nf +++ b/target/nextflow/bedtools/bedtools_sort/main.nf @@ -3086,8 +3086,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/bedtools/bedtools_sort", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 4b6e2418..d37070d1 100644 --- a/target/nextflow/busco/busco_download_datasets/.config.vsh.yaml +++ b/target/nextflow/busco/busco_download_datasets/.config.vsh.yaml @@ -158,8 +158,8 @@ build_info: output: "target/nextflow/busco/busco_download_datasets" executable: "target/nextflow/busco/busco_download_datasets/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/busco/busco_download_datasets/main.nf b/target/nextflow/busco/busco_download_datasets/main.nf index 3c1ec601..639dec97 100644 --- a/target/nextflow/busco/busco_download_datasets/main.nf +++ b/target/nextflow/busco/busco_download_datasets/main.nf @@ -3005,8 +3005,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/busco/busco_download_datasets", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 eeb2e986..d79f562d 100644 --- a/target/nextflow/busco/busco_list_datasets/.config.vsh.yaml +++ b/target/nextflow/busco/busco_list_datasets/.config.vsh.yaml @@ -145,8 +145,8 @@ build_info: output: "target/nextflow/busco/busco_list_datasets" executable: "target/nextflow/busco/busco_list_datasets/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/busco/busco_list_datasets/main.nf b/target/nextflow/busco/busco_list_datasets/main.nf index 3a78cbd1..0bfb3850 100644 --- a/target/nextflow/busco/busco_list_datasets/main.nf +++ b/target/nextflow/busco/busco_list_datasets/main.nf @@ -2991,8 +2991,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/busco/busco_list_datasets", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 5bd7ec0a..e766b6d2 100644 --- a/target/nextflow/busco/busco_run/.config.vsh.yaml +++ b/target/nextflow/busco/busco_run/.config.vsh.yaml @@ -423,8 +423,8 @@ build_info: output: "target/nextflow/busco/busco_run" executable: "target/nextflow/busco/busco_run/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/busco/busco_run/main.nf b/target/nextflow/busco/busco_run/main.nf index 85716958..a82e6130 100644 --- a/target/nextflow/busco/busco_run/main.nf +++ b/target/nextflow/busco/busco_run/main.nf @@ -3303,8 +3303,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/busco/busco_run", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/cutadapt/.config.vsh.yaml b/target/nextflow/cutadapt/.config.vsh.yaml index 4f5f086e..e7701e92 100644 --- a/target/nextflow/cutadapt/.config.vsh.yaml +++ b/target/nextflow/cutadapt/.config.vsh.yaml @@ -740,8 +740,8 @@ build_info: output: "target/nextflow/cutadapt" executable: "target/nextflow/cutadapt/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/cutadapt/main.nf b/target/nextflow/cutadapt/main.nf index 92955327..b8347b95 100644 --- a/target/nextflow/cutadapt/main.nf +++ b/target/nextflow/cutadapt/main.nf @@ -3613,8 +3613,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/cutadapt", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/falco/.config.vsh.yaml b/target/nextflow/falco/.config.vsh.yaml index 36802020..e640c4b9 100644 --- a/target/nextflow/falco/.config.vsh.yaml +++ b/target/nextflow/falco/.config.vsh.yaml @@ -317,8 +317,8 @@ build_info: output: "target/nextflow/falco" executable: "target/nextflow/falco/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/falco/main.nf b/target/nextflow/falco/main.nf index e5188a51..a77ce390 100644 --- a/target/nextflow/falco/main.nf +++ b/target/nextflow/falco/main.nf @@ -3164,8 +3164,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/falco", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/fastp/.config.vsh.yaml b/target/nextflow/fastp/.config.vsh.yaml index a5c23b33..b7141bd8 100644 --- a/target/nextflow/fastp/.config.vsh.yaml +++ b/target/nextflow/fastp/.config.vsh.yaml @@ -1083,8 +1083,8 @@ build_info: output: "target/nextflow/fastp" executable: "target/nextflow/fastp/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/fastp/main.nf b/target/nextflow/fastp/main.nf index bbdfece2..fcb5b9cc 100644 --- a/target/nextflow/fastp/main.nf +++ b/target/nextflow/fastp/main.nf @@ -4017,8 +4017,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/fastp", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/fastqc/.config.vsh.yaml b/target/nextflow/fastqc/.config.vsh.yaml index e4d71aad..940b5015 100644 --- a/target/nextflow/fastqc/.config.vsh.yaml +++ b/target/nextflow/fastqc/.config.vsh.yaml @@ -340,8 +340,8 @@ build_info: output: "target/nextflow/fastqc" executable: "target/nextflow/fastqc/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/fastqc/main.nf b/target/nextflow/fastqc/main.nf index 41319a03..5fc2a111 100644 --- a/target/nextflow/fastqc/main.nf +++ b/target/nextflow/fastqc/main.nf @@ -3176,8 +3176,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/fastqc", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/featurecounts/.config.vsh.yaml b/target/nextflow/featurecounts/.config.vsh.yaml index 6b63059c..3e2d6dfb 100644 --- a/target/nextflow/featurecounts/.config.vsh.yaml +++ b/target/nextflow/featurecounts/.config.vsh.yaml @@ -645,8 +645,8 @@ build_info: output: "target/nextflow/featurecounts" executable: "target/nextflow/featurecounts/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/featurecounts/main.nf b/target/nextflow/featurecounts/main.nf index 6770266b..04c409ff 100644 --- a/target/nextflow/featurecounts/main.nf +++ b/target/nextflow/featurecounts/main.nf @@ -3543,8 +3543,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/featurecounts", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/fq_subsample/.config.vsh.yaml b/target/nextflow/fq_subsample/.config.vsh.yaml index b1ac3622..ea7cd6bb 100644 --- a/target/nextflow/fq_subsample/.config.vsh.yaml +++ b/target/nextflow/fq_subsample/.config.vsh.yaml @@ -190,8 +190,8 @@ build_info: output: "target/nextflow/fq_subsample" executable: "target/nextflow/fq_subsample/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/fq_subsample/main.nf b/target/nextflow/fq_subsample/main.nf index 406ffdcd..98e2a07d 100644 --- a/target/nextflow/fq_subsample/main.nf +++ b/target/nextflow/fq_subsample/main.nf @@ -3026,8 +3026,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/fq_subsample", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/gffread/.config.vsh.yaml b/target/nextflow/gffread/.config.vsh.yaml index c2432147..8b8beda6 100644 --- a/target/nextflow/gffread/.config.vsh.yaml +++ b/target/nextflow/gffread/.config.vsh.yaml @@ -685,8 +685,8 @@ build_info: output: "target/nextflow/gffread" executable: "target/nextflow/gffread/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/gffread/main.nf b/target/nextflow/gffread/main.nf index 429c6020..0b61822f 100644 --- a/target/nextflow/gffread/main.nf +++ b/target/nextflow/gffread/main.nf @@ -3600,8 +3600,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/gffread", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 b1f3d937..5e84c334 100644 --- a/target/nextflow/lofreq/lofreq_call/.config.vsh.yaml +++ b/target/nextflow/lofreq/lofreq_call/.config.vsh.yaml @@ -507,8 +507,8 @@ build_info: output: "target/nextflow/lofreq/lofreq_call" executable: "target/nextflow/lofreq/lofreq_call/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/lofreq/lofreq_call/main.nf b/target/nextflow/lofreq/lofreq_call/main.nf index 07b9580f..9961dc0a 100644 --- a/target/nextflow/lofreq/lofreq_call/main.nf +++ b/target/nextflow/lofreq/lofreq_call/main.nf @@ -3408,8 +3408,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/lofreq/lofreq_call", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 ec5eaffb..3e6c7e99 100644 --- a/target/nextflow/lofreq/lofreq_indelqual/.config.vsh.yaml +++ b/target/nextflow/lofreq/lofreq_indelqual/.config.vsh.yaml @@ -215,8 +215,8 @@ build_info: output: "target/nextflow/lofreq/lofreq_indelqual" executable: "target/nextflow/lofreq/lofreq_indelqual/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/lofreq/lofreq_indelqual/main.nf b/target/nextflow/lofreq/lofreq_indelqual/main.nf index ccd96b16..2363d6b9 100644 --- a/target/nextflow/lofreq/lofreq_indelqual/main.nf +++ b/target/nextflow/lofreq/lofreq_indelqual/main.nf @@ -3071,8 +3071,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/lofreq/lofreq_indelqual", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/multiqc/.config.vsh.yaml b/target/nextflow/multiqc/.config.vsh.yaml index 023824ac..5c13d705 100644 --- a/target/nextflow/multiqc/.config.vsh.yaml +++ b/target/nextflow/multiqc/.config.vsh.yaml @@ -456,8 +456,8 @@ build_info: output: "target/nextflow/multiqc" executable: "target/nextflow/multiqc/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/multiqc/main.nf b/target/nextflow/multiqc/main.nf index 3ecdfe23..a627704f 100644 --- a/target/nextflow/multiqc/main.nf +++ b/target/nextflow/multiqc/main.nf @@ -3360,8 +3360,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/multiqc", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/pear/.config.vsh.yaml b/target/nextflow/pear/.config.vsh.yaml index d743cb7a..f5ddbcd9 100644 --- a/target/nextflow/pear/.config.vsh.yaml +++ b/target/nextflow/pear/.config.vsh.yaml @@ -398,8 +398,8 @@ build_info: output: "target/nextflow/pear" executable: "target/nextflow/pear/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/pear/main.nf b/target/nextflow/pear/main.nf index 6fce1383..b9d202b1 100644 --- a/target/nextflow/pear/main.nf +++ b/target/nextflow/pear/main.nf @@ -3253,8 +3253,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/pear", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 b5f03821..b6e540ff 100644 --- a/target/nextflow/qualimap/qualimap_rnaseq/.config.vsh.yaml +++ b/target/nextflow/qualimap/qualimap_rnaseq/.config.vsh.yaml @@ -264,8 +264,8 @@ build_info: output: "target/nextflow/qualimap/qualimap_rnaseq" executable: "target/nextflow/qualimap/qualimap_rnaseq/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/qualimap/qualimap_rnaseq/main.nf b/target/nextflow/qualimap/qualimap_rnaseq/main.nf index 8df3a7fa..97e1e0ca 100644 --- a/target/nextflow/qualimap/qualimap_rnaseq/main.nf +++ b/target/nextflow/qualimap/qualimap_rnaseq/main.nf @@ -3123,8 +3123,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/qualimap/qualimap_rnaseq", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 7380be76..6ee79de6 100644 --- a/target/nextflow/rsem/rsem_prepare_reference/.config.vsh.yaml +++ b/target/nextflow/rsem/rsem_prepare_reference/.config.vsh.yaml @@ -416,8 +416,8 @@ build_info: output: "target/nextflow/rsem/rsem_prepare_reference" executable: "target/nextflow/rsem/rsem_prepare_reference/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/rsem/rsem_prepare_reference/main.nf b/target/nextflow/rsem/rsem_prepare_reference/main.nf index 9fedccfc..810c1c78 100644 --- a/target/nextflow/rsem/rsem_prepare_reference/main.nf +++ b/target/nextflow/rsem/rsem_prepare_reference/main.nf @@ -3239,8 +3239,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/rsem/rsem_prepare_reference", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/salmon/salmon_index/.config.vsh.yaml b/target/nextflow/salmon/salmon_index/.config.vsh.yaml index 8d885a50..fa3bca33 100644 --- a/target/nextflow/salmon/salmon_index/.config.vsh.yaml +++ b/target/nextflow/salmon/salmon_index/.config.vsh.yaml @@ -277,8 +277,8 @@ build_info: output: "target/nextflow/salmon/salmon_index" executable: "target/nextflow/salmon/salmon_index/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/salmon/salmon_index/main.nf b/target/nextflow/salmon/salmon_index/main.nf index e98e511f..0e6b684e 100644 --- a/target/nextflow/salmon/salmon_index/main.nf +++ b/target/nextflow/salmon/salmon_index/main.nf @@ -3123,8 +3123,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/salmon/salmon_index", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 30e829b9..be031c64 100644 --- a/target/nextflow/salmon/salmon_quant/.config.vsh.yaml +++ b/target/nextflow/salmon/salmon_quant/.config.vsh.yaml @@ -1173,8 +1173,8 @@ build_info: output: "target/nextflow/salmon/salmon_quant" executable: "target/nextflow/salmon/salmon_quant/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/salmon/salmon_quant/main.nf b/target/nextflow/salmon/salmon_quant/main.nf index 0296d771..b3f7e28d 100644 --- a/target/nextflow/salmon/salmon_quant/main.nf +++ b/target/nextflow/salmon/salmon_quant/main.nf @@ -3958,8 +3958,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/salmon/salmon_quant", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 be7f484e..c08fcedf 100644 --- a/target/nextflow/samtools/samtools_collate/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_collate/.config.vsh.yaml @@ -264,8 +264,8 @@ build_info: output: "target/nextflow/samtools/samtools_collate" executable: "target/nextflow/samtools/samtools_collate/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_collate/main.nf b/target/nextflow/samtools/samtools_collate/main.nf index 0f145b7f..7dfdc1e6 100644 --- a/target/nextflow/samtools/samtools_collate/main.nf +++ b/target/nextflow/samtools/samtools_collate/main.nf @@ -3134,8 +3134,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_collate", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 d431c40e..001a3b29 100644 --- a/target/nextflow/samtools/samtools_faidx/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_faidx/.config.vsh.yaml @@ -243,8 +243,8 @@ build_info: output: "target/nextflow/samtools/samtools_faidx" executable: "target/nextflow/samtools/samtools_faidx/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_faidx/main.nf b/target/nextflow/samtools/samtools_faidx/main.nf index 4e902eaa..9bc2fe73 100644 --- a/target/nextflow/samtools/samtools_faidx/main.nf +++ b/target/nextflow/samtools/samtools_faidx/main.nf @@ -3106,8 +3106,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_faidx", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 e3c9060e..8d1fbe51 100644 --- a/target/nextflow/samtools/samtools_fasta/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_fasta/.config.vsh.yaml @@ -433,8 +433,8 @@ build_info: output: "target/nextflow/samtools/samtools_fasta" executable: "target/nextflow/samtools/samtools_fasta/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_fasta/main.nf b/target/nextflow/samtools/samtools_fasta/main.nf index 5bac6148..b1fcc847 100644 --- a/target/nextflow/samtools/samtools_fasta/main.nf +++ b/target/nextflow/samtools/samtools_fasta/main.nf @@ -3298,8 +3298,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_fasta", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 2d848da1..645d8dd8 100644 --- a/target/nextflow/samtools/samtools_fastq/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_fastq/.config.vsh.yaml @@ -433,8 +433,8 @@ build_info: output: "target/nextflow/samtools/samtools_fastq" executable: "target/nextflow/samtools/samtools_fastq/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_fastq/main.nf b/target/nextflow/samtools/samtools_fastq/main.nf index 999e8f8b..bb8a7d8a 100644 --- a/target/nextflow/samtools/samtools_fastq/main.nf +++ b/target/nextflow/samtools/samtools_fastq/main.nf @@ -3298,8 +3298,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_fastq", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 f788759b..e6593121 100644 --- a/target/nextflow/samtools/samtools_flagstat/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_flagstat/.config.vsh.yaml @@ -173,8 +173,8 @@ build_info: output: "target/nextflow/samtools/samtools_flagstat" executable: "target/nextflow/samtools/samtools_flagstat/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_flagstat/main.nf b/target/nextflow/samtools/samtools_flagstat/main.nf index afed9eb6..174829d0 100644 --- a/target/nextflow/samtools/samtools_flagstat/main.nf +++ b/target/nextflow/samtools/samtools_flagstat/main.nf @@ -3022,8 +3022,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_flagstat", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 b77b58ef..dc31b31a 100644 --- a/target/nextflow/samtools/samtools_idxstats/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_idxstats/.config.vsh.yaml @@ -183,8 +183,8 @@ build_info: output: "target/nextflow/samtools/samtools_idxstats" executable: "target/nextflow/samtools/samtools_idxstats/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_idxstats/main.nf b/target/nextflow/samtools/samtools_idxstats/main.nf index 6c267aa2..9961873f 100644 --- a/target/nextflow/samtools/samtools_idxstats/main.nf +++ b/target/nextflow/samtools/samtools_idxstats/main.nf @@ -3034,8 +3034,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_idxstats", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 49113e47..e66038a4 100644 --- a/target/nextflow/samtools/samtools_index/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_index/.config.vsh.yaml @@ -189,8 +189,8 @@ build_info: output: "target/nextflow/samtools/samtools_index" executable: "target/nextflow/samtools/samtools_index/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_index/main.nf b/target/nextflow/samtools/samtools_index/main.nf index 7e2c58c8..a016d3f3 100644 --- a/target/nextflow/samtools/samtools_index/main.nf +++ b/target/nextflow/samtools/samtools_index/main.nf @@ -3047,8 +3047,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_index", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 bbed8b1a..dbe18ae9 100644 --- a/target/nextflow/samtools/samtools_sort/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_sort/.config.vsh.yaml @@ -332,8 +332,8 @@ build_info: output: "target/nextflow/samtools/samtools_sort" executable: "target/nextflow/samtools/samtools_sort/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_sort/main.nf b/target/nextflow/samtools/samtools_sort/main.nf index 479ffd85..77236dc2 100644 --- a/target/nextflow/samtools/samtools_sort/main.nf +++ b/target/nextflow/samtools/samtools_sort/main.nf @@ -3219,8 +3219,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_sort", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 937d4e3c..78f4f6dc 100644 --- a/target/nextflow/samtools/samtools_stats/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_stats/.config.vsh.yaml @@ -401,8 +401,8 @@ build_info: output: "target/nextflow/samtools/samtools_stats" executable: "target/nextflow/samtools/samtools_stats/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_stats/main.nf b/target/nextflow/samtools/samtools_stats/main.nf index 38c78935..e325ebe4 100644 --- a/target/nextflow/samtools/samtools_stats/main.nf +++ b/target/nextflow/samtools/samtools_stats/main.nf @@ -3289,8 +3289,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_stats", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 be20db32..6a369373 100644 --- a/target/nextflow/samtools/samtools_view/.config.vsh.yaml +++ b/target/nextflow/samtools/samtools_view/.config.vsh.yaml @@ -665,8 +665,8 @@ build_info: output: "target/nextflow/samtools/samtools_view" executable: "target/nextflow/samtools/samtools_view/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/samtools/samtools_view/main.nf b/target/nextflow/samtools/samtools_view/main.nf index ef72f101..f3aff545 100644 --- a/target/nextflow/samtools/samtools_view/main.nf +++ b/target/nextflow/samtools/samtools_view/main.nf @@ -3470,8 +3470,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/samtools/samtools_view", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 fa9d180a..2e052b68 100644 --- a/target/nextflow/seqtk/seqtk_sample/.config.vsh.yaml +++ b/target/nextflow/seqtk/seqtk_sample/.config.vsh.yaml @@ -173,8 +173,8 @@ build_info: output: "target/nextflow/seqtk/seqtk_sample" executable: "target/nextflow/seqtk/seqtk_sample/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/seqtk/seqtk_sample/main.nf b/target/nextflow/seqtk/seqtk_sample/main.nf index 9f24367d..e14d0ae7 100644 --- a/target/nextflow/seqtk/seqtk_sample/main.nf +++ b/target/nextflow/seqtk/seqtk_sample/main.nf @@ -3024,8 +3024,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/seqtk/seqtk_sample", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 b52bab6e..2c693ecf 100644 --- a/target/nextflow/seqtk/seqtk_subseq/.config.vsh.yaml +++ b/target/nextflow/seqtk/seqtk_subseq/.config.vsh.yaml @@ -196,8 +196,8 @@ build_info: output: "target/nextflow/seqtk/seqtk_subseq" executable: "target/nextflow/seqtk/seqtk_subseq/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/seqtk/seqtk_subseq/main.nf b/target/nextflow/seqtk/seqtk_subseq/main.nf index bcd85910..d915f702 100644 --- a/target/nextflow/seqtk/seqtk_subseq/main.nf +++ b/target/nextflow/seqtk/seqtk_subseq/main.nf @@ -3054,8 +3054,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/seqtk/seqtk_subseq", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/sortmerna/.config.vsh.yaml b/target/nextflow/sortmerna/.config.vsh.yaml index d3cd530d..44b23d10 100644 --- a/target/nextflow/sortmerna/.config.vsh.yaml +++ b/target/nextflow/sortmerna/.config.vsh.yaml @@ -591,8 +591,8 @@ build_info: output: "target/nextflow/sortmerna" executable: "target/nextflow/sortmerna/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/sortmerna/main.nf b/target/nextflow/sortmerna/main.nf index 5906d545..88a7e837 100644 --- a/target/nextflow/sortmerna/main.nf +++ b/target/nextflow/sortmerna/main.nf @@ -3450,8 +3450,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/sortmerna", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 aa8a4d71..28c8c0f3 100644 --- a/target/nextflow/star/star_align_reads/.config.vsh.yaml +++ b/target/nextflow/star/star_align_reads/.config.vsh.yaml @@ -2663,8 +2663,8 @@ build_info: output: "target/nextflow/star/star_align_reads" executable: "target/nextflow/star/star_align_reads/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/star/star_align_reads/main.nf b/target/nextflow/star/star_align_reads/main.nf index d2200bb1..e1fccf0a 100644 --- a/target/nextflow/star/star_align_reads/main.nf +++ b/target/nextflow/star/star_align_reads/main.nf @@ -5937,8 +5937,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/star/star_align_reads", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 497daa97..c07d13bf 100644 --- a/target/nextflow/star/star_genome_generate/.config.vsh.yaml +++ b/target/nextflow/star/star_genome_generate/.config.vsh.yaml @@ -333,8 +333,8 @@ build_info: output: "target/nextflow/star/star_genome_generate" executable: "target/nextflow/star/star_genome_generate/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/star/star_genome_generate/main.nf b/target/nextflow/star/star_genome_generate/main.nf index 18e33d7c..3bc57bbc 100644 --- a/target/nextflow/star/star_genome_generate/main.nf +++ b/target/nextflow/star/star_genome_generate/main.nf @@ -3189,8 +3189,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/star/star_genome_generate", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", diff --git a/target/nextflow/trimgalore/.config.vsh.yaml b/target/nextflow/trimgalore/.config.vsh.yaml index c29cec68..cc7e9a68 100644 --- a/target/nextflow/trimgalore/.config.vsh.yaml +++ b/target/nextflow/trimgalore/.config.vsh.yaml @@ -70,13 +70,59 @@ argument_groups: direction: "input" - type: "string" name: "--fastqc_args" - description: "Passes extra arguments to FastQC. If more than one argument is to\ - \ be passed to FastQC they must be in the form \"arg1 arg2 ...\". Passing extra\ - \ arguments will automatically invoke FastQC, so --fastqc does not have to be\ - \ specified separately." + description: "Passes extra arguments (excluding files) to FastQC. If more than\ + \ one argument is to be passed to FastQC they must be in the form \"arg1 arg2\ + \ ...\". Passing extra arguments will automatically invoke FastQC, so --fastqc\ + \ does not have to be specified separately." info: null example: - - "--nogroup --outdir /home/" + - "--nogroup --noextract" + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fastqc_contaminants" + description: "Specifies a non-default file which contains the list of contaminants\ + \ for FastQC to screen overrepresented sequences against. The file must contain\ + \ sets of named contaminants in the form name[tab]sequence. Lines prefixed with\ + \ a hash will be ignored." + info: null + example: + - "contaminants.txt" + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fastqc_adapters" + description: "Specifies a non-default file which contains the list of adapter\ + \ sequences which which FasstQC will explicity search against the library. The\ + \ file must contain sets of named adapters in the form name[tab]sequence. Lines\ + \ prefixed with a hash will be ignored." + info: null + example: + - "adapters.txt" + must_exist: true + create_parent: true + required: false + direction: "input" + multiple: false + multiple_sep: ";" + - type: "file" + name: "--fastqc_limits" + description: "Specifies a non-default file which contains a set of criteria which\ + \ FastQC will use to determine the warn/error limits for the various modules.\ + \ This file can also be used to selectively remove some modules from the output\ + \ all together. The format needs to mirror the default limits.txt file found\ + \ in the Configuration folder." + info: null + example: + - "limits.txt" + must_exist: true + create_parent: true required: false direction: "input" multiple: false @@ -472,7 +518,7 @@ argument_groups: - "trimmed_output" must_exist: true create_parent: true - required: false + required: true direction: "output" multiple: false multiple_sep: ";" @@ -724,8 +770,8 @@ build_info: output: "target/nextflow/trimgalore" executable: "target/nextflow/trimgalore/main.nf" viash_version: "0.9.0-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/trimgalore/main.nf b/target/nextflow/trimgalore/main.nf index 7d512401..68aa6eb7 100644 --- a/target/nextflow/trimgalore/main.nf +++ b/target/nextflow/trimgalore/main.nf @@ -2885,15 +2885,57 @@ meta = [ { "type" : "string", "name" : "--fastqc_args", - "description" : "Passes extra arguments to FastQC. If more than one argument is to be passed to FastQC they must be in the form \\"arg1 arg2 ...\\". Passing extra arguments will automatically invoke FastQC, so --fastqc does not have to be specified separately.", + "description" : "Passes extra arguments (excluding files) to FastQC. If more than one argument is to be passed to FastQC they must be in the form \\"arg1 arg2 ...\\". Passing extra arguments will automatically invoke FastQC, so --fastqc does not have to be specified separately.", "example" : [ - "--nogroup --outdir /home/" + "--nogroup --noextract" ], "required" : false, "direction" : "input", "multiple" : false, "multiple_sep" : ";" }, + { + "type" : "file", + "name" : "--fastqc_contaminants", + "description" : "Specifies a non-default file which contains the list of contaminants for FastQC to screen overrepresented sequences against. The file must contain sets of named contaminants in the form name[tab]sequence. Lines prefixed with a hash will be ignored.", + "example" : [ + "contaminants.txt" + ], + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--fastqc_adapters", + "description" : "Specifies a non-default file which contains the list of adapter sequences which which FasstQC will explicity search against the library. The file must contain sets of named adapters in the form name[tab]sequence. Lines prefixed with a hash will be ignored.", + "example" : [ + "adapters.txt" + ], + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, + { + "type" : "file", + "name" : "--fastqc_limits", + "description" : "Specifies a non-default file which contains a set of criteria which FastQC will use to determine the warn/error limits for the various modules. This file can also be used to selectively remove some modules from the output all together. The format needs to mirror the default limits.txt file found in the Configuration folder.", + "example" : [ + "limits.txt" + ], + "must_exist" : true, + "create_parent" : true, + "required" : false, + "direction" : "input", + "multiple" : false, + "multiple_sep" : ";" + }, { "type" : "string", "name" : "--adapter", @@ -3226,7 +3268,7 @@ meta = [ ], "must_exist" : true, "create_parent" : true, - "required" : false, + "required" : true, "direction" : "output", "multiple" : false, "multiple_sep" : ";" @@ -3512,8 +3554,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/trimgalore", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox", @@ -3560,6 +3602,9 @@ $( if [ ! -z ${VIASH_PAR_PHRED33+x} ]; then echo "${VIASH_PAR_PHRED33}" | sed "s $( if [ ! -z ${VIASH_PAR_PHRED64+x} ]; then echo "${VIASH_PAR_PHRED64}" | sed "s#'#'\\"'\\"'#g;s#.*#par_phred64='&'#" ; else echo "# par_phred64="; fi ) $( if [ ! -z ${VIASH_PAR_FASTQC+x} ]; then echo "${VIASH_PAR_FASTQC}" | sed "s#'#'\\"'\\"'#g;s#.*#par_fastqc='&'#" ; else echo "# par_fastqc="; fi ) $( if [ ! -z ${VIASH_PAR_FASTQC_ARGS+x} ]; then echo "${VIASH_PAR_FASTQC_ARGS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_fastqc_args='&'#" ; else echo "# par_fastqc_args="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTQC_CONTAMINANTS+x} ]; then echo "${VIASH_PAR_FASTQC_CONTAMINANTS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_fastqc_contaminants='&'#" ; else echo "# par_fastqc_contaminants="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTQC_ADAPTERS+x} ]; then echo "${VIASH_PAR_FASTQC_ADAPTERS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_fastqc_adapters='&'#" ; else echo "# par_fastqc_adapters="; fi ) +$( if [ ! -z ${VIASH_PAR_FASTQC_LIMITS+x} ]; then echo "${VIASH_PAR_FASTQC_LIMITS}" | sed "s#'#'\\"'\\"'#g;s#.*#par_fastqc_limits='&'#" ; else echo "# par_fastqc_limits="; fi ) $( if [ ! -z ${VIASH_PAR_ADAPTER+x} ]; then echo "${VIASH_PAR_ADAPTER}" | sed "s#'#'\\"'\\"'#g;s#.*#par_adapter='&'#" ; else echo "# par_adapter="; fi ) $( if [ ! -z ${VIASH_PAR_ADAPTER2+x} ]; then echo "${VIASH_PAR_ADAPTER2}" | sed "s#'#'\\"'\\"'#g;s#.*#par_adapter2='&'#" ; else echo "# par_adapter2="; fi ) $( if [ ! -z ${VIASH_PAR_ILLUMINA+x} ]; then echo "${VIASH_PAR_ILLUMINA}" | sed "s#'#'\\"'\\"'#g;s#.*#par_illumina='&'#" ; else echo "# par_illumina="; fi ) @@ -3662,12 +3707,24 @@ for par in \\${unset_if_false[@]}; do [[ "\\$test_val" == "false" ]] && unset \\$par done +# Add FastQC file arguments to fastqc_args +fastqc_args="\\${par_fastqc_args}" +if [ -f "\\$par_fastqc_contaminants" ]; then + fastqc_args+=" --contaminants \\$par_fastqc_contaminants" +fi +if [ -f "\\$par_fastqc_adapters" ]; then + fastqc_args+=" --adapters \\$par_fastqc_adapters" +fi +if [ -f "\\$par_fastqc_limits" ]; then + fastqc_args+=" --limits \\$par_fastqc_limits" +fi + trim_galore \\\\ \\${par_quality:+-q "\\${par_quality}"} \\\\ \\${par_phred33:+--phred33} \\\\ \\${par_phred64:+--phred64 } \\\\ \\${par_fastqc:+--fastqc } \\\\ - \\${par_fastqc_args:+--fastqc_args "\\${par_fastqc_args}"} \\\\ + \\${fastqc_args:+--fastqc_args "\\${fastqc_args}"} \\\\ \\${par_adapter:+-a "\\${par_adapter}"} \\\\ \\${par_adapter2:+-a2 "\\${par_adapter2}"} \\\\ \\${par_illumina:+--illumina} \\\\ diff --git a/target/nextflow/trimgalore/nextflow_schema.json b/target/nextflow/trimgalore/nextflow_schema.json index 0db2e780..99334938 100644 --- a/target/nextflow/trimgalore/nextflow_schema.json +++ b/target/nextflow/trimgalore/nextflow_schema.json @@ -80,8 +80,38 @@ "fastqc_args": { "type": "string", - "description": "Type: `string`, example: `--nogroup --outdir /home/`. Passes extra arguments to FastQC", - "help_text": "Type: `string`, example: `--nogroup --outdir /home/`. Passes extra arguments to FastQC. If more than one argument is to be passed to FastQC they must be in the form \"arg1 arg2 ...\". Passing extra arguments will automatically invoke FastQC, so --fastqc does not have to be specified separately." + "description": "Type: `string`, example: `--nogroup --noextract`. Passes extra arguments (excluding files) to FastQC", + "help_text": "Type: `string`, example: `--nogroup --noextract`. Passes extra arguments (excluding files) to FastQC. If more than one argument is to be passed to FastQC they must be in the form \"arg1 arg2 ...\". Passing extra arguments will automatically invoke FastQC, so --fastqc does not have to be specified separately." + + } + + + , + "fastqc_contaminants": { + "type": + "string", + "description": "Type: `file`, example: `contaminants.txt`. Specifies a non-default file which contains the list of contaminants for FastQC to screen overrepresented sequences against", + "help_text": "Type: `file`, example: `contaminants.txt`. Specifies a non-default file which contains the list of contaminants for FastQC to screen overrepresented sequences against. The file must contain sets of named contaminants in the form name[tab]sequence. Lines prefixed with a hash will be ignored." + + } + + + , + "fastqc_adapters": { + "type": + "string", + "description": "Type: `file`, example: `adapters.txt`. Specifies a non-default file which contains the list of adapter sequences which which FasstQC will explicity search against the library", + "help_text": "Type: `file`, example: `adapters.txt`. Specifies a non-default file which contains the list of adapter sequences which which FasstQC will explicity search against the library. The file must contain sets of named adapters in the form name[tab]sequence. Lines prefixed with a hash will be ignored." + + } + + + , + "fastqc_limits": { + "type": + "string", + "description": "Type: `file`, example: `limits.txt`. Specifies a non-default file which contains a set of criteria which FastQC will use to determine the warn/error limits for the various modules", + "help_text": "Type: `file`, example: `limits.txt`. Specifies a non-default file which contains a set of criteria which FastQC will use to determine the warn/error limits for the various modules. This file can also be used to selectively remove some modules from the output all together. The format needs to mirror the default limits.txt file found in the Configuration folder." } @@ -497,8 +527,8 @@ "output_dir": { "type": "string", - "description": "Type: `file`, default: `$id.$key.output_dir.output_dir`. If specified all output will be written to this directory instead of the current directory", - "help_text": "Type: `file`, default: `$id.$key.output_dir.output_dir`. If specified all output will be written to this directory instead of the current directory." + "description": "Type: `file`, required, default: `$id.$key.output_dir.output_dir`. If specified all output will be written to this directory instead of the current directory", + "help_text": "Type: `file`, required, default: `$id.$key.output_dir.output_dir`. If specified all output will be written to this directory instead of the current directory." , "default": "$id.$key.output_dir.output_dir" } 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 fde28b26..4037a0d8 100644 --- a/target/nextflow/umi_tools/umi_tools_dedup/.config.vsh.yaml +++ b/target/nextflow/umi_tools/umi_tools_dedup/.config.vsh.yaml @@ -611,8 +611,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/umi_tools/umi_tools_dedup/main.nf b/target/nextflow/umi_tools/umi_tools_dedup/main.nf index 3fd4838b..6e15867e 100644 --- a/target/nextflow/umi_tools/umi_tools_dedup/main.nf +++ b/target/nextflow/umi_tools/umi_tools_dedup/main.nf @@ -3481,8 +3481,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/umi_tools/umi_tools_dedup", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "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 c794d410..f585124d 100644 --- a/target/nextflow/umi_tools/umi_tools_extract/.config.vsh.yaml +++ b/target/nextflow/umi_tools/umi_tools_extract/.config.vsh.yaml @@ -449,8 +449,8 @@ 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-RC7" - git_commit: "89fb3575f697065135a647a21efb3815efe66e44" - git_remote: "https://github.com/viash-hub/biobox" + git_commit: "90735159b7bafa4aa8643eb132534d078ea299cf" + git_remote: "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" package_config: name: "biobox" version: "add_trimgalore" diff --git a/target/nextflow/umi_tools/umi_tools_extract/main.nf b/target/nextflow/umi_tools/umi_tools_extract/main.nf index 589e569c..40fd7dba 100644 --- a/target/nextflow/umi_tools/umi_tools_extract/main.nf +++ b/target/nextflow/umi_tools/umi_tools_extract/main.nf @@ -3310,8 +3310,8 @@ meta = [ "engine" : "docker|native", "output" : "target/nextflow/umi_tools/umi_tools_extract", "viash_version" : "0.9.0-RC7", - "git_commit" : "89fb3575f697065135a647a21efb3815efe66e44", - "git_remote" : "https://github.com/viash-hub/biobox" + "git_commit" : "90735159b7bafa4aa8643eb132534d078ea299cf", + "git_remote" : "https://x-access-token:ghs_f5MGzzY8TnzQWjJSiZ9z9t1HGTq1aI25g7mw@github.com/viash-hub/biobox" }, "package_config" : { "name" : "biobox",