From 954a6d03e358d710c86c2a29eb3bfb17f06f33e4 Mon Sep 17 00:00:00 2001 From: Dries Schaumont <5946712+DriesSchaumont@users.noreply.github.com> Date: Mon, 6 May 2024 11:32:44 +0200 Subject: [PATCH 1/8] FEAT: require 'ps' command to be available. (#45) * FEAT: require 'ps' command to be available. * Move to root of config * Add 'ps' to falco. --- _viash.yaml | 5 ++++- src/falco/config.vsh.yaml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/_viash.yaml b/_viash.yaml index a72a1ab7..6d658e2d 100644 --- a/_viash.yaml +++ b/_viash.yaml @@ -7,4 +7,7 @@ links: issue_tracker: https://github.com/viash-hub/biobase/issues repository: https://github.com/viash-hub/biobase -viash_version: 0.9.0-RC2 \ No newline at end of file +viash_version: 0.9.0-RC2 + +config_mods: | + .requirements.commands := ['ps'] diff --git a/src/falco/config.vsh.yaml b/src/falco/config.vsh.yaml index 61cbb0d5..4d9cf656 100644 --- a/src/falco/config.vsh.yaml +++ b/src/falco/config.vsh.yaml @@ -177,7 +177,7 @@ engines: image: debian:trixie-slim setup: - type: apt - packages: [wget, build-essential, g++, zlib1g-dev] + packages: [wget, build-essential, g++, zlib1g-dev, procps] - type: docker run: | wget https://github.com/smithlabcode/falco/releases/download/v1.2.2/falco-1.2.2.tar.gz -O /tmp/falco.tar.gz && \ From ce27c3e41be1dd12433dcf1406509908ea76c26a Mon Sep 17 00:00:00 2001 From: Dries Schaumont <5946712+DriesSchaumont@users.noreply.github.com> Date: Mon, 6 May 2024 16:10:32 +0200 Subject: [PATCH 2/8] FEAT: Add --cl_config to MultiQC (#46) --- src/multiqc/config.vsh.yaml | 6 ++++++ src/multiqc/script.sh | 1 + 2 files changed, 7 insertions(+) diff --git a/src/multiqc/config.vsh.yaml b/src/multiqc/config.vsh.yaml index 7f29d109..0a3a784b 100644 --- a/src/multiqc/config.vsh.yaml +++ b/src/multiqc/config.vsh.yaml @@ -161,6 +161,12 @@ argument_groups: type: boolean_true description: | Disable coloured log output. + - name: "--cl_config" + type: string + required: false + description: | + YAML formatted string that allows to customize MultiQC behaviour like input file detection. + example: "qualimap_config: { general_stats_coverage: [20,40,200] }" - name: "Output format" arguments: diff --git a/src/multiqc/script.sh b/src/multiqc/script.sh index 6b04ff5b..b765520b 100755 --- a/src/multiqc/script.sh +++ b/src/multiqc/script.sh @@ -99,6 +99,7 @@ multiqc \ ${include_modules} \ ${par_include_modules:+--include-modules "$par_include_modules"} \ ${par_data_format:+--data-format "$par_data_format"} \ + ${par_cl_config:+--cl-config "$par_cl_config"} \ ${par_zip_data_dir:+--zip-data-dir} \ ${par_pdf:+--pdf} \ ${par_interactive:+--interactive} \ From fe8ffc238a2a93b60abf8a6aab2e0fce2116da19 Mon Sep 17 00:00:00 2001 From: Dries Schaumont <5946712+DriesSchaumont@users.noreply.github.com> Date: Tue, 7 May 2024 08:42:20 +0200 Subject: [PATCH 3/8] BUG: multiqc always ignores symlinked directories. (#47) --- src/multiqc/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multiqc/script.sh b/src/multiqc/script.sh index b765520b..6353eb11 100755 --- a/src/multiqc/script.sh +++ b/src/multiqc/script.sh @@ -1,7 +1,7 @@ #!/bin/bash # disable flags -[[ "$par_ignore_symlinks" == "false" ]] && unset ignore_symlinks +[[ "$par_ignore_symlinks" == "false" ]] && unset par_ignore_symlinks [[ "$par_dirs" == "false" ]] && unset par_dirs [[ "$par_full_names" == "false" ]] && unset par_full_names [[ "$par_fn_as_s_name" == "false" ]] && unset par_fn_as_s_name From f537c99b3dca87b773c7eb83df341fdd246b695a Mon Sep 17 00:00:00 2001 From: Leila011 Date: Fri, 17 May 2024 12:04:16 +0200 Subject: [PATCH 4/8] add escaping character before leading hashtag (#50) * add escaping character before leading hashtag * update changelog * Update CHANGELOG.md Co-authored-by: Robrecht Cannoodt * replace escaping \ by \\ --------- Co-authored-by: Robrecht Cannoodt --- CHANGELOG.md | 2 ++ src/bcl_convert/config.vsh.yaml | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8d0a08b..1bc08e37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,3 +58,5 @@ ## DOCUMENTATION ## BUG FIXES + +* Add escaping character before leading hashtag in the description field of the config file (PR #50). \ No newline at end of file diff --git a/src/bcl_convert/config.vsh.yaml b/src/bcl_convert/config.vsh.yaml index 7a9bce24..d0cedfa7 100644 --- a/src/bcl_convert/config.vsh.yaml +++ b/src/bcl_convert/config.vsh.yaml @@ -50,20 +50,20 @@ argument_groups: example: true - name: --bcl_num_parallel_tiles type: integer - description: "# of tiles to process in parallel (default 1)" + description: "\\# of tiles to process in parallel (default 1)" example: 1 - name: --bcl_num_conversion_threads type: integer - description: "# of threads for conversion (per tile, default # cpu threads)" + description: "\\# of threads for conversion (per tile, default # cpu threads)" example: 1 - name: --bcl_num_compression_threads type: integer - description: "# of threads for fastq.gz output compression (per tile, default # cpu threads, or HW+12)" + description: "\\# of threads for fastq.gz output compression (per tile, default # cpu threads, or HW+12)" example: 1 - name: --bcl_num_decompression_threads type: integer description: - "# of threads for bcl/cbcl input decompression (per tile, default half # cpu threads, or HW+8). + "\\# of threads for bcl/cbcl input decompression (per tile, default half # cpu threads, or HW+8). Only applies when preloading files" example: 1 @@ -79,7 +79,7 @@ argument_groups: example: true - name: --num_unknown_barcodes_reported type: integer - description: "# of Top Unknown Barcodes to output (1000 by default)" + description: "\\# of Top Unknown Barcodes to output (1000 by default)" example: 1000 - name: --bcl_validate_sample_sheet_only type: boolean From ed1a3aa962044cb3409e4fae94420ea5591a8f67 Mon Sep 17 00:00:00 2001 From: emmarousseau Date: Tue, 21 May 2024 22:29:57 +0200 Subject: [PATCH 5/8] Samtools collate (#49) * initial commit dedup * Revert "initial commit dedup" This reverts commit 38f586bec0ac9e4312b016e29c3aa0bd53f292b2. * Initial commit, whole component is functional --- CHANGELOG.md | 1 + src/samtools/samtools_collate/config.vsh.yaml | 94 ++++++++++++++++++ src/samtools/samtools_collate/help.txt | 31 ++++++ src/samtools/samtools_collate/script.sh | 27 +++++ src/samtools/samtools_collate/test.sh | 67 +++++++++++++ .../samtools_collate/test_data/collated.bam | Bin 0 -> 21343 bytes .../test_data/comp_collated.bam | Bin 0 -> 18856 bytes .../test_data/fast_collated.bam | Bin 0 -> 20692 bytes .../samtools_collate/test_data/script.sh | 4 + .../test_data/test.paired_end.sorted.bam | Bin 0 -> 19725 bytes 10 files changed, 224 insertions(+) create mode 100644 src/samtools/samtools_collate/config.vsh.yaml create mode 100644 src/samtools/samtools_collate/help.txt create mode 100644 src/samtools/samtools_collate/script.sh create mode 100644 src/samtools/samtools_collate/test.sh create mode 100644 src/samtools/samtools_collate/test_data/collated.bam create mode 100644 src/samtools/samtools_collate/test_data/comp_collated.bam create mode 100644 src/samtools/samtools_collate/test_data/fast_collated.bam create mode 100755 src/samtools/samtools_collate/test_data/script.sh create mode 100644 src/samtools/samtools_collate/test_data/test.paired_end.sorted.bam diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bc08e37..95c0451e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ - `samtools/samtools_sort`: Sort SAM/BAM/CRAM files (PR #36). - `samtools/samtools_stats`: Reports alignment summary statistics for a BAM file (PR #39). - `samtools/samtools_stats`: Indexes FASTA files to enable random access to fasta and fastq files (PR #41). + - `samtools_collate`: Shuffles and groups reads in SAM/BAM/CRAM files together by their names (PR #42). * `falco`: A C++ drop-in replacement of FastQC to assess the quality of sequence read data (PR #43). diff --git a/src/samtools/samtools_collate/config.vsh.yaml b/src/samtools/samtools_collate/config.vsh.yaml new file mode 100644 index 00000000..669f4cdf --- /dev/null +++ b/src/samtools/samtools_collate/config.vsh.yaml @@ -0,0 +1,94 @@ +name: samtools_collate +namespace: samtools +description: Shuffles and groups reads in SAM/BAM/CRAM files together by their names. +keywords: [collate, counts, bam, sam, cram] +links: + homepage: https://www.htslib.org/ + documentation: https://www.htslib.org/doc/samtools-icollate.html + repository: https://github.com/samtools/samtools +references: + doi: [10.1093/bioinformatics/btp352, 10.1093/gigascience/giab008] +license: MIT/Expat + +argument_groups: + - name: Inputs + arguments: + - name: --input + type: file + description: The input BAM file. + required: true + - name: --reference + type: file + description: Reference sequence FASTA FILE. + + - name: Outputs + arguments: + - name: --output + alternatives: -o + type: file + description: The output filename. + required: true + direction: output + + - name: Options + arguments: + - name: --uncompressed + alternatives: -u + type: boolean_true + description: Output uncompressed BAM. + - name: --fast + alternatives: -f + type: boolean_true + description: Fast mode, only primary alignments. + - name: --working_reads + alternatives: -r + type: integer + description: Working reads stored (for use with -f). + default: 10000 + - name: --compression + alternatives: -l + type: integer + description: Compression level. + default: 1 + - name: --nb_tmp_files + alternatives: -n + type: integer + description: Number of temporary files. + default: 64 + - name: --tmp_prefix + alternatives: -T + type: string + description: Write temporary files to PREFIX.nnnn.bam. + - name: --no_pg + type: boolean_true + description: Do not add a PG line. + - name: --input_fmt_option + type: string + description: Specify a single input file format option in the form of OPTION or OPTION=VALUE. + - name: --output_fmt + type: string + description: Specify output format (SAM, BAM, CRAM). + - name: --output_fmt_option + type: string + description: Specify a single output file format option in the form of OPTION or OPTION=VALUE. + + +resources: + - type: bash_script + path: script.sh +test_resources: + - type: bash_script + path: test.sh + - type: file + path: test_data +engines: + - type: docker + image: quay.io/biocontainers/samtools:1.19.2--h50ea8bc_1 + setup: + - type: docker + run: | + samtools --version 2>&1 | grep -E '^(samtools|Using htslib)' | \ + sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt +runners: +- type: executable +- type: nextflow diff --git a/src/samtools/samtools_collate/help.txt b/src/samtools/samtools_collate/help.txt new file mode 100644 index 00000000..16190f4b --- /dev/null +++ b/src/samtools/samtools_collate/help.txt @@ -0,0 +1,31 @@ +``` +samtools collate +``` +Usage: samtools collate [options...] [] + +Options: + -O Output to stdout + -o Output file name (use prefix if not set) + -u Uncompressed BAM output + -f Fast (only primary alignments) + -r Working reads stored (with -f) [10000] + -l INT Compression level [1] + -n INT Number of temporary files [64] + -T PREFIX + Write temporary files to PREFIX.nnnn.bam + --no-PG do not add a PG line + --input-fmt-option OPT[=VAL] + Specify a single input file format option in the form + of OPTION or OPTION=VALUE + --output-fmt FORMAT[,OPT[=VAL]]... + Specify output format (SAM, BAM, CRAM) + --output-fmt-option OPT[=VAL] + Specify a single output file format option in the form + of OPTION or OPTION=VALUE + --reference FILE + Reference sequence FASTA FILE [null] + -@, --threads INT + Number of additional threads to use [0] + --verbosity INT + Set level of verbosity + is required unless the -o or -O options are used. \ No newline at end of file diff --git a/src/samtools/samtools_collate/script.sh b/src/samtools/samtools_collate/script.sh new file mode 100644 index 00000000..25847a52 --- /dev/null +++ b/src/samtools/samtools_collate/script.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +set -e + +[[ "$par_uncompressed" == "false" ]] && unset par_uncompressed +[[ "$par_fast" == "false" ]] && unset par_fast +[[ "$par_no_pg" == "false" ]] && unset par_no_pg + +samtools collate \ + "$par_input" \ + ${par_output:+-o "$par_output"} \ + ${par_reference:+-T "$par_reference"} \ + ${par_uncompressed:+-u} \ + ${par_fast:+-f} \ + ${par_working_reads:+-r "$par_working_reads"} \ + ${par_compression:+-l "$par_compression"} \ + ${par_nb_tmp_files:+-n "$par_nb_tmp_files"} \ + ${par_tmp_prefix:+-T "$par_tmp_prefix"} \ + ${par_no_pg:+-P} \ + ${par_input_fmt_option:+-O "$par_input_fmt_option"} \ + ${par_output_fmt:+-O "$par_output_fmt"} \ + ${par_output_fmt_option:+-O "$par_output_fmt_option"} + +exit 0 diff --git a/src/samtools/samtools_collate/test.sh b/src/samtools/samtools_collate/test.sh new file mode 100644 index 00000000..c5a2e6e6 --- /dev/null +++ b/src/samtools/samtools_collate/test.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +test_dir="${meta_resources_dir}/test_data" +out_dir="${meta_resources_dir}/out" + +############################################################################################ + +echo ">>> Test 1: $meta_functionality_name" +"$meta_executable" \ + --input "$test_dir/test.paired_end.sorted.bam" \ + --output "$out_dir/collated.bam" + +echo ">>> Checking whether output exists" +[ ! -f "$out_dir/collated.bam" ] && echo "File 'collated.bam' does not exist!" && exit 1 + +echo ">>> Checking whether output is non-empty" +[ ! -s "$out_dir/collated.bam" ] && echo "File 'collated.bam' is empty!" && exit 1 + +echo ">>> Checking whether output is correct" +diff <(samtools view "$out_dir/collated.bam") \ + <(samtools view "$test_dir/collated.bam") || \ + (echo "Output file collated.bam does not match expected output" && exit 1) + +############################################################################################ + +echo ">>> Test 2: $meta_functionality_name with --fast option" +"$meta_executable" \ + --fast \ + --input "$test_dir/test.paired_end.sorted.bam" \ + --output "$out_dir/fast_collated.bam" + +echo ">>> Checking whether output exists" +[ ! -f "$test_dir/fast_collated.bam" ] && echo "File 'fast_collated.bam' does not exist!" && exit 1 + +echo ">>> Checking whether output is non-empty" +[ ! -s "$test_dir/fast_collated.bam" ] && echo "File 'fast_collated.bam' is empty!" && exit 1 + +echo ">>> Checking whether output is correct" +diff <(samtools view "$test_dir/fast_collated.bam") \ + <(samtools view "$test_dir/fast_collated.bam") || \ + (echo "Output file fast_collated.bam does not match expected output" && exit 1) + + +############################################################################################ + +echo ">>> Test 3: $meta_functionality_name with compression" +"$meta_executable" \ + --compression 8 \ + --input "$test_dir/test.paired_end.sorted.bam" \ + --output "$out_dir/comp_collated.bam" + +echo ">>> Checking whether output exists" +[ ! -f "$out_dir/comp_collated.bam" ] && echo "File 'comp_collated.bam' does not exist!" && exit 1 + +echo ">>> Checking whether output is non-empty" +[ ! -s "$out_dir/comp_collated.bam" ] && echo "File 'comp_collated.bam' is empty!" && exit 1 + +echo ">>> Checking whether output is correct" +diff <(samtools view "$out_dir/comp_collated.bam") \ + <(samtools view "$test_dir/comp_collated.bam") || \ + (echo "Output file comp_collated.bam does not match expected output" && exit 1) + +############################################################################################ + +echo ">>> All tests passed successfully." + +exit 0 diff --git a/src/samtools/samtools_collate/test_data/collated.bam b/src/samtools/samtools_collate/test_data/collated.bam new file mode 100644 index 0000000000000000000000000000000000000000..f6d5eab99b0c728b4c1a1e49cf38b408a735d0f9 GIT binary patch literal 21343 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 L0000000000MFZWw literal 0 HcmV?d00001 diff --git a/src/samtools/samtools_collate/test_data/script.sh b/src/samtools/samtools_collate/test_data/script.sh new file mode 100755 index 00000000..f97a7efe --- /dev/null +++ b/src/samtools/samtools_collate/test_data/script.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# dowload test data from nf-core module +wget https://github.com/nf-core/test-datasets/raw/modules/data/genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam \ No newline at end of file diff --git a/src/samtools/samtools_collate/test_data/test.paired_end.sorted.bam b/src/samtools/samtools_collate/test_data/test.paired_end.sorted.bam new file mode 100644 index 0000000000000000000000000000000000000000..85cccf14b05a885509f1a1a2945ead6370bff9d5 GIT binary patch literal 19725 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 Date: Wed, 22 May 2024 10:58:56 +0200 Subject: [PATCH 6/8] Update viash (#51) * update viash * update readme * update changelog * update changelog * fix incorrect heading detection * update again * clean up readme --- CHANGELOG.md | 2 ++ README.md | 41 ++++++++++++++++------------------------- README.qmd | 17 ++++++----------- _viash.yaml | 2 +- 4 files changed, 25 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95c0451e..f52a6d02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,8 @@ * Update to Viash 0.8.5 (PR #25). +* Update to Viash 0.9.0-RC3 (PR #51). + ## DOCUMENTATION ## BUG FIXES diff --git a/README.md b/README.md index 1639481f..ecf807ca 100644 --- a/README.md +++ b/README.md @@ -26,34 +26,25 @@ We encourage contributions from the community. To contribute: ## Contribution Guidelines -- **Documentation of Functionality**: The purpose and functionality of - each component should be adequately described. -- **Documentation of Inputs and Outputs**: All input and output - arguments should have a description and example (with extension). -- **Docker Image**: A Docker image (with optional additional - dependencies) should be provided. -- **Write unit tests**: A unit test with possibly test resources needs - to be provided. -- **Provide test resources**: If the unit test requires test resources, - these should be provided in the `test_resources` section of the - component. -- **Versioning**: If the component uses custom software (not installed - via Apt, Apk, Yum, Pip, Conda, or R), a Bash script `version.sh` needs - to be provided that outputs the version of the software. -- **File format specifications**: If a component returns a directory or - data structure such as AnnData or MuData, a specification of the file - format should be provided. +The contribution guidelines describes which steps you should follow to +contribute a component to this repository. + +1. Find a component to contribute +2. Add config template +3. Fill in the metadata +4. Find a suitable container +5. Create help file +6. Create or fetch test data +7. Add arguments for the input files +8. Add arguments for the output files +9. Add arguments for the other arguments +10. Add a Docker engine +11. Write a runner script +12. Create test script +13. Create a `/var/software_versions.txt` file See the [CONTRIBUTING](CONTRIBUTING.md) file for more details. -## Repository Structure - -… - -## Installation and Usage - -… - ## Support and Community For support, questions, or to join our community: diff --git a/README.qmd b/README.qmd index f7e5139b..656cdac7 100644 --- a/README.qmd +++ b/README.qmd @@ -21,29 +21,24 @@ We encourage contributions from the community. To contribute: ## Contribution Guidelines +The contribution guidelines describes which steps you should follow to contribute a component to this repository. + ```{r echo=FALSE} lines <- readr::read_lines("CONTRIBUTING.md") -index_start <- grep("^## ", lines) +index_start <- grep("^### Step [0-9]*:", lines) + index_end <- c(index_start[-1] - 1, length(lines)) -name <- gsub("^## ", "", lines[index_start]) -description <- lines[index_start + 2] +name <- gsub("^### Step [0-9]*: *", "", lines[index_start]) knitr::asis_output( - paste(paste0(" * **", name, "**: ", description, "\n"), collapse = "") + paste(paste0(" 1. ", name, "\n"), collapse = "") ) ``` See the [CONTRIBUTING](CONTRIBUTING.md) file for more details. -## Repository Structure - -... - -## Installation and Usage - -... ## Support and Community diff --git a/_viash.yaml b/_viash.yaml index 6d658e2d..397a8d69 100644 --- a/_viash.yaml +++ b/_viash.yaml @@ -7,7 +7,7 @@ links: issue_tracker: https://github.com/viash-hub/biobase/issues repository: https://github.com/viash-hub/biobase -viash_version: 0.9.0-RC2 +viash_version: 0.9.0-RC3 config_mods: | .requirements.commands := ['ps'] From 0370b4c6b30d58f8508f4331501187ecb7778f9b Mon Sep 17 00:00:00 2001 From: emmarousseau Date: Thu, 23 May 2024 09:17:44 +0200 Subject: [PATCH 7/8] Samtools view (#48) * initial commit dedup * Revert "initial commit dedup" This reverts commit 38f586bec0ac9e4312b016e29c3aa0bd53f292b2. * initial version with a few tests, script, and config file * update changelog, add one test * add a 4th test, fix option names in the script * Fix name of component in config * remove option named with a number * add must_exist to input file argument * removed "default: null" from one of the arguments in config * remove utf8 characters from config * Update CHANGELOG.md --------- Co-authored-by: Robrecht Cannoodt --- CHANGELOG.md | 6 +- .../samtools_idxstats/config.vsh.yaml | 2 +- src/samtools/samtools_sort/config.vsh.yaml | 2 +- src/samtools/samtools_stats/config.vsh.yaml | 4 +- src/samtools/samtools_view/config.vsh.yaml | 351 ++++++++++++++++++ src/samtools/samtools_view/help.txt | 80 ++++ src/samtools/samtools_view/script.sh | 71 ++++ src/samtools/samtools_view/test.sh | 87 +++++ src/samtools/samtools_view/test_data/a.bam | Bin 0 -> 254 bytes src/samtools/samtools_view/test_data/a.count | 1 + src/samtools/samtools_view/test_data/a.cram | Bin 0 -> 692 bytes .../samtools_view/test_data/a.forward | 3 + src/samtools/samtools_view/test_data/a.sam | 7 + .../samtools_view/test_data/script.sh | 8 + 14 files changed, 616 insertions(+), 6 deletions(-) create mode 100644 src/samtools/samtools_view/config.vsh.yaml create mode 100644 src/samtools/samtools_view/help.txt create mode 100644 src/samtools/samtools_view/script.sh create mode 100644 src/samtools/samtools_view/test.sh create mode 100644 src/samtools/samtools_view/test_data/a.bam create mode 100644 src/samtools/samtools_view/test_data/a.count create mode 100644 src/samtools/samtools_view/test_data/a.cram create mode 100644 src/samtools/samtools_view/test_data/a.forward create mode 100644 src/samtools/samtools_view/test_data/a.sam create mode 100755 src/samtools/samtools_view/test_data/script.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index f52a6d02..b1d7a7af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,11 +43,13 @@ - `samtools/samtools_index`: Index SAM/BAM/CRAM files (PR #35). - `samtools/samtools_sort`: Sort SAM/BAM/CRAM files (PR #36). - `samtools/samtools_stats`: Reports alignment summary statistics for a BAM file (PR #39). - - `samtools/samtools_stats`: Indexes FASTA files to enable random access to fasta and fastq files (PR #41). - - `samtools_collate`: Shuffles and groups reads in SAM/BAM/CRAM files together by their names (PR #42). + - `samtools/samtools_faidx`: Indexes FASTA files to enable random access to fasta and fastq files (PR #41). + - `samtools/samtools_collate`: Shuffles and groups reads in SAM/BAM/CRAM files together by their names (PR #42). + - `samtools/samtools_view`: Views and converts SAM/BAM/CRAM files (PR #48). * `falco`: A C++ drop-in replacement of FastQC to assess the quality of sequence read data (PR #43). + ## MAJOR CHANGES ## MINOR CHANGES diff --git a/src/samtools/samtools_idxstats/config.vsh.yaml b/src/samtools/samtools_idxstats/config.vsh.yaml index d5e32077..30f21348 100644 --- a/src/samtools/samtools_idxstats/config.vsh.yaml +++ b/src/samtools/samtools_idxstats/config.vsh.yaml @@ -7,7 +7,7 @@ links: documentation: https://www.htslib.org/doc/samtools-idxstats.html repository: https://github.com/samtools/samtools references: - doi: 10.1093/bioinformatics/btp352, 10.1093/gigascience/giab008 + doi: [10.1093/bioinformatics/btp352, 10.1093/gigascience/giab008] license: MIT/Expat argument_groups: diff --git a/src/samtools/samtools_sort/config.vsh.yaml b/src/samtools/samtools_sort/config.vsh.yaml index 7cd9ec48..a78800da 100644 --- a/src/samtools/samtools_sort/config.vsh.yaml +++ b/src/samtools/samtools_sort/config.vsh.yaml @@ -4,7 +4,7 @@ description: Sort SAM/BAM/CRAM file. keywords: [sort, bam, sam, cram] links: homepage: https://www.htslib.org/ - documentation: https://www.htslib.org/doc/samtools-idxstats.html + documentation: https://www.htslib.org/doc/samtools-sort.html repository: https://github.com/samtools/samtools references: doi: [10.1093/bioinformatics/btp352, 10.1093/gigascience/giab008] diff --git a/src/samtools/samtools_stats/config.vsh.yaml b/src/samtools/samtools_stats/config.vsh.yaml index 554a11e8..0d8f57a4 100644 --- a/src/samtools/samtools_stats/config.vsh.yaml +++ b/src/samtools/samtools_stats/config.vsh.yaml @@ -4,10 +4,10 @@ description: Reports alignment summary statistics for a BAM file. keywords: [statistics, counts, bam, sam, cram] links: homepage: https://www.htslib.org/ - documentation: https://www.htslib.org/doc/samtools-idxstats.html + documentation: https://www.htslib.org/doc/samtools-stats.html repository: https://github.com/samtools/samtools references: - doi: 10.1093/bioinformatics/btp352, 10.1093/gigascience/giab008 + doi: [10.1093/bioinformatics/btp352, 10.1093/gigascience/giab008] license: MIT/Expat argument_groups: diff --git a/src/samtools/samtools_view/config.vsh.yaml b/src/samtools/samtools_view/config.vsh.yaml new file mode 100644 index 00000000..206b87ac --- /dev/null +++ b/src/samtools/samtools_view/config.vsh.yaml @@ -0,0 +1,351 @@ +name: samtools_view +namespace: samtools +description: Views and converts SAM/BAM/CRAM files. +keywords: [view, convert, bam, sam, cram] +links: + homepage: https://www.htslib.org/ + documentation: https://www.htslib.org/doc/samtools-view.html + repository: https://github.com/samtools/samtools +references: + doi: [10.1093/bioinformatics/btp352, 10.1093/gigascience/giab008] +license: MIT/Expat + +argument_groups: + - name: Inputs + arguments: + - name: --input + type: file + description: Input SAM, BAM, or CRAM file. + required: true + must_exist: true + - name: --fai_reference + alternatives: -t + type: file + description: | + A tab-delimited FILE. Each line must contain the reference name in the first column + and the length of the reference in the second column, with one line for each distinct + reference. Any additional fields beyond the second column are ignored. This file also + defines the order of the reference sequences in sorting. If you run: `samtools faidx ', + the resulting index file .fai can be used as this FILE. + - name: --reference + alternatives: -T + type: file + description: | + A FASTA format reference FILE, optionally compressed by bgzip and ideally indexed by samtools faidx. + If an index is not present one will be generated for you, if the reference file is local. + If the reference file is not local, but is accessed instead via an https://, s3:// or other URL, + the index file will need to be supplied by the server alongside the reference. It is possible to + have the reference and index files in different locations by supplying both to this option separated + by the string "##idx##", for example: + --reference ftp://x.com/ref.fa##idx##ftp://y.com/index.fa.fai + However, note that only the location of the reference will be stored in the output file header. + If this method is used to make CRAM files, the cram reader may not be able to find the index, + and may not be able to decode the file unless it can get the references it needs using a different + method. + - name: --target_file + alternatives: -L + type: file + description: | + Only output alignments overlapping the input BED FILE [null]. + - name: --region_file + type: file + description: | + Use an index and multi-region iterator to only output alignments overlapping the input BED FILE. + Equivalent to --use_index --target_file FILE. + - name: --qname_file + alternatives: -N + type: file + description: | + Output only alignments with read names listed in FILE. If FILE starts with ^ then the operation is + negated and only outputs alignment with read groups not listed in FILE. It is not permissible to mix + both the filter-in and filter-out style syntax in the same command. + must_exist: true + - name: --read_group_file + alternatives: -R + type: file + description: | + Output alignments in read groups listed in FILE [null]. If FILE starts with ^ then the operation is + negated and only outputs alignment with read names not listed in FILE. It is not permissible to mix + both the filter-in and filter-out style syntax in the same command. Note that records with no RG tag + will also be output when using this option. This behaviour may change in a future release. + must_exist: true + - name: --use_index + alternatives: -M + type: boolean_true + description: | + Use the multi-region iterator on the union of a BED file and command-line region arguments. + This avoids re-reading the same regions of files so can sometimes be much faster. Note this also + removes duplicate sequences. Without this a sequence that overlaps multiple regions specified on + the command line will be reported multiple times. The usage of a BED file is optional and its path + has to be preceded by --target_file option. + + - name: Outputs + arguments: + - name: --output + alternatives: -o + type: file + description: Output to FILE instead of [stdout]. + required: true + direction: output + example: output.bam + - name: --bam + alternatives: -b + type: boolean_true + description: Output in the BAM format. + - name: --cram + alternatives: -C + type: boolean_true + description: | + Output in the CRAM format (requires --reference). + - name: --fast + type: boolean_true + description: | + Enable fast compression. This also changes the default output format to BAM, + but this can be overridden by the explicit format options or using a filename + with a known suffix. + - name: --uncompressed + alternatives: -u + type: boolean_true + description: | + Output uncompressed data. This also changes the default output format to BAM, + but this can be overridden by the explicit format options or using a filename + with a known suffix. + This option saves time spent on compression/decompression and is thus preferred + when the output is piped to another samtools command. + - name: --with_header + type: boolean_true + description: | + Include the header in the output. + - name: --header_only + alternatives: -H + type: boolean_true + description: | + Output the header only. + - name: --no_header + type: boolean_true + description: | + When producing SAM format, output alignment records but not headers. + This is the default; the option can be used to reset the effect of + --with_header/--header_only. + - name: --count + alternatives: -c + type: boolean_true + description: | + Instead of printing the alignments, only count them and print the total number. + All filter options, such as --require_flags, --excl_flags, and --min_MQ, are taken + into account. The --unmap option is ignored in this mode. + - name: --output_unselected + alternatives: -U + type: file + description: | + Write alignments that are not selected by the various filter options to FILE. + When this option is used, all alignments (or all alignments intersecting the regions + specified) are written to either the output file or this file, but never both. + - name: --unmap + alternatives: -p + type: boolean_true + description: | + Set the UNMAP flag on alignments that are not selected by the filter options. + These alignments are then written to the normal output. This is not compatible + with --output_unselected. + - name: --read_group + alternatives: -r + type: string + description: | + Output alignments in read group STR [null]. Note that records with no RG tag will also be output + when using this option. This behaviour may change in a future release. + - name: --tag + alternatives: -d + type: string + description: | + Only output alignments with tag STR1 and associated value STR2, which can be a string or an integer + [null]. + The value can be omitted, in which case only the tag is considered. + Note that this option does not specify a tag type. For example, use --tag XX:42 to select alignments + with an XX:i:42 field, not --tag XX:i:42. + - name: --tag_file + alternatives: -D + type: file + description: | + Only output alignments with tag STR and associated values listed in FILE. + must_exist: true + - name: --min_MQ + alternatives: -q + type: integer + description: | + Skip alignments with MAPQ smaller than INT. + default: 0 + - name: --library + alternatives: -l + type: string + description: | + Only output alignments in library STR. + - name: --min_qlen + alternatives: -m + type: integer + description: | + Only output alignments with number of CIGAR bases consuming query sequence >= INT. + default: 0 + - name: --expr + alternatives: -e + type: string + description: | + Only include alignments that match the filter expression STR. The syntax for these expressions is + described in the main samtools. + - name: --require_flags + alternatives: -f + type: string + description: | + Only output alignments with all bits set in FLAG present in the FLAG field. FLAG can be specified + in hex by beginning with `0x' (i.e. /^0x[0-9A-F]+/), in octal by beginning with `0' (i.e. /^0[0-7]+/), + as a decimal number not beginning with '0' or as a comma-separated list of flag names. + - name: --excl_flags + alternatives: -F + type: string + description: | + Do not output alignments with any bits set in FLAG present in the FLAG field. FLAG can be specified + in hex by beginning with `0x' (i.e. /^0x[0-9A-F]+/), in octal by beginning with `0' (i.e. /^0[0-7]+/), + as a decimal number not beginning with '0' or as a comma-separated list of flag names. + - name: --excl_all_flags + alternatives: -G + type: integer + description: | + Do not output alignments with all bits set in INT present in the FLAG field. This is the opposite of + --require_flags such that --require_flags 12 --exclude_all_flags 12 is the same as no filtering at all. + FLAG can be specified in hex by beginning with `0x' (i.e. /^0x[0-9A-F]+/), in octal by beginning with `0' + (i.e. /^0[0-7]+/), as a decimal number not beginning with '0' or as a comma-separated list of flag names. + - name: --incl_flags + alternatives: --rf + type: string + description: | + Only output alignments with any bit set in FLAG present in the FLAG field. FLAG can be specified in hex + by beginning with `0x' (i.e. /^0x[0-9A-F]+/), in octal by beginning with `0' (i.e. /^0[0-7]+/), as a decimal + number not beginning with '0' or as a comma-separated list of flag names. + - name: --remove_tag + alternatives: -x + type: string + description: | + Read tag(s) to exclude from output (repeatable) [null]. This can be a single tag or a comma separated list. + Alternatively the option itself can be repeated multiple times. + If the list starts with a `^' then it is negated and treated as a request to remove all tags except those in STR. + The list may be empty, so --remove_tag ^ will remove all tags. + Note that tags will only be removed from reads that pass filtering. + - name: --keep_tag + type: string + description: | + This keeps only tags listed in STR and is directly equivalent to --remove_tag ^STR. Specifying an empty list + will remove all tags. If both --keep_tag and --remove_tag are specified then --keep_tag has precedence. + Note that tags will only be removed from reads that pass filtering. + - name: --remove_B + alternatives: -B + type: boolean_true + description: | + Collapse the backward CIGAR operation. + - name: --add_flags + type: string + description: | + Adds flag(s) to read. FLAG can be specified in hex by beginning with `0x' (i.e. /^0x[0-9A-F]+/), in octal + by beginning with `0' (i.e. /^0[0-7]+/), as a decimal number not beginning with '0' or as a comma-separated + list of flag names. + - name: --remove_flags + type: string + description: | + Remove flag(s) from read. FLAG is specified in the same way as with the --add_flags option. + - name: --subsample + type: double + description: | + Output only a proportion of the input alignments, as specified by 0.0 <= FLOAT <= 1.0, which gives the fraction + of templates/pairs to be kept. This subsampling acts in the same way on all of the alignment records in the same + template or read pair, so it never keeps a read but not its mate. + - name: --subsample_seed + type: integer + description: | + Subsampling seed used to influence which subset of reads is kept. When subsampling data that has previously + been subsampled, be sure to use a different seed value from those used previously; otherwise more reads will + be retained than expected. + default: 0 + - name: --fetch_pairs + alternatives: -P + type: boolean_true + description: | + Retrieve pairs even when the mate is outside of the requested region. Enabling this option also turns on the + multi-region iterator (-M). A region to search must be specified, either on the command-line, or using the + --target_file option. The input file must be an indexed regular file. + This option first scans the requested region, using the RNEXT and PNEXT fields of the records that have the + PAIRED flag set and pass other filtering options to find where paired reads are located. These locations are + used to build an expanded region list, and a set of QNAMEs to allow from the new regions. It will then make + a second pass, collecting all reads from the originally-specified region list together with reads from additional + locations that match the allowed set of QNAMEs. Any other filtering options used will be applied to all reads + found during this second pass. + As this option links reads using RNEXT and PNEXT, it is important that these fields are set accurately. Use + 'samtools fixmate' to correct them if necessary. + Note that this option does not work with the --count, --output-unselected or --unmap options. + - name: --customized_index + alternatives: -X + type: boolean_true + description: | + Include customized index file as a part of arguments. See EXAMPLES section for sample of usage. + - name: --sanitize + alternatives: -z + type: string + description: | + Perform some sanity checks on the state of SAM record fields, fixing up common mistakes made by aligners. + These include soft-clipping alignments when they extend beyond the end of the reference, marking records as + unmapped when they have reference * or position 0, and ensuring unmapped alignments have no CIGAR or mapping + quality for unmapped alignments and no MD, NM, CG or SM tags. + FLAGs is a comma-separated list of keywords chosen from the following list. + + unmap: The UNMAPPED BAM flag. This is set for reads with position <= 0, reference name "*" or reads starting + beyond the end of the reference. Note CIGAR "*" is permitted for mapped data so does not trigger this. + + pos: Position and reference name fields. These may be cleared when a sequence is unmapped due to the + coordinates being beyond the end of the reference. Selecting this may change the sort order of the file, + so it is not a part of the on compound argument. + mqual: Mapping quality. This is set to zero for unmapped reads. + cigar: Modifies CIGAR fields, either by adding soft-clips for reads that overlap the end of the reference or + by clearing it for unmapped reads. + aux: For unmapped data, some auxiliary fields are meaningless and will be removed. These include NM, MD, CG and SM. + off: Perform no sanity fixing. This is the default + on: Sanitize data in a way that guarantees the same sort order. This is everything except for pos. + all: All sanitizing options, including pos. + - name: --no_PG + type: boolean_true + description: | + Do not add a @PG line to the header of the output file. + - name: --input_fmt_option + type: string + description: | + Specify a single input file format option in the form of OPTION or OPTION=VALUE. + - name: --output_fmt + alternatives: -O + type: string + description: | + Specify output format (SAM, BAM, CRAM). + - name: --output_fmt_option + type: string + description: | + Specify a single output file format option in the form of OPTION or OPTION=VALUE. + - name: --write_index + type: boolean_true + description: | + Automatically index the output files. + +resources: + - type: bash_script + path: script.sh +test_resources: + - type: bash_script + path: test.sh + - type: file + path: test_data +engines: + - type: docker + image: quay.io/biocontainers/samtools:1.19.2--h50ea8bc_1 + setup: + - type: docker + run: | + samtools --version 2>&1 | grep -E '^(samtools|Using htslib)' | \ + sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt +runners: +- type: executable +- type: nextflow \ No newline at end of file diff --git a/src/samtools/samtools_view/help.txt b/src/samtools/samtools_view/help.txt new file mode 100644 index 00000000..753b1bc6 --- /dev/null +++ b/src/samtools/samtools_view/help.txt @@ -0,0 +1,80 @@ +``` +samtools view +``` + +Usage: samtools view [options] || [region ...] + +Output options: + -b, --bam Output BAM + -C, --cram Output CRAM (requires -T) + -1, --fast Use fast BAM compression (and default to --bam) + -u, --uncompressed Uncompressed BAM output (and default to --bam) + -h, --with-header Include header in SAM output + -H, --header-only Print SAM header only (no alignments) + --no-header Print SAM alignment records only [default] + -c, --count Print only the count of matching records + -o, --output FILE Write output to FILE [standard output] + -U, --unoutput FILE, --output-unselected FILE + Output reads not selected by filters to FILE + -p, --unmap Set flag to UNMAP on reads not selected + then write to output file. + -P, --fetch-pairs Retrieve complete pairs even when outside of region +Input options: + -t, --fai-reference FILE FILE listing reference names and lengths + -M, --use-index Use index and multi-region iterator for regions + --region[s]-file FILE Use index to include only reads overlapping FILE + -X, --customized-index Expect extra index file argument after + +Filtering options (Only include in output reads that...): + -L, --target[s]-file FILE ...overlap (BED) regions in FILE + -N, --qname-file [^]FILE ...whose read name is listed in FILE ("^" negates) + -r, --read-group STR ...are in read group STR + -R, --read-group-file [^]FILE + ...are in a read group listed in FILE + -d, --tag STR1[:STR2] ...have a tag STR1 (with associated value STR2) + -D, --tag-file STR:FILE ...have a tag STR whose value is listed in FILE + -q, --min-MQ INT ...have mapping quality >= INT + -l, --library STR ...are in library STR + -m, --min-qlen INT ...cover >= INT query bases (as measured via CIGAR) + -e, --expr STR ...match the filter expression STR + -f, --require-flags FLAG ...have all of the FLAGs present + -F, --excl[ude]-flags FLAG ...have none of the FLAGs present + --rf, --incl-flags, --include-flags FLAG + ...have some of the FLAGs present + -G FLAG EXCLUDE reads with all of the FLAGs present + --subsample FLOAT Keep only FLOAT fraction of templates/read pairs + --subsample-seed INT Influence WHICH reads are kept in subsampling [0] + -s INT.FRAC Same as --subsample 0.FRAC --subsample-seed INT + +Processing options: + --add-flags FLAG Add FLAGs to reads + --remove-flags FLAG Remove FLAGs from reads + -x, --remove-tag STR + Comma-separated read tags to strip (repeatable) [null] + --keep-tag STR + Comma-separated read tags to preserve (repeatable) [null]. + Equivalent to "-x ^STR" + -B, --remove-B Collapse the backward CIGAR operation + -z, --sanitize FLAGS Perform sanitity checking and fixing on records. + FLAGS is comma separated (see manual). [off] + +General options: + -?, --help Print long help, including note about region specification + -S Ignored (input format is auto-detected) + --no-PG Do not add a PG line + --input-fmt-option OPT[=VAL] + Specify a single input file format option in the form + of OPTION or OPTION=VALUE + -O, --output-fmt FORMAT[,OPT[=VAL]]... + Specify output format (SAM, BAM, CRAM) + --output-fmt-option OPT[=VAL] + Specify a single output file format option in the form + of OPTION or OPTION=VALUE + -T, --reference FILE + Reference sequence FASTA FILE [null] + -@, --threads INT + Number of additional threads to use [0] + --write-index + Automatically index the output files [off] + --verbosity INT + Set level of verbosity diff --git a/src/samtools/samtools_view/script.sh b/src/samtools/samtools_view/script.sh new file mode 100644 index 00000000..c3911b48 --- /dev/null +++ b/src/samtools/samtools_view/script.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +set -e + +[[ "$par_bam" == "false" ]] && unset par_bam +[[ "$par_cram" == "false" ]] && unset par_cram +[[ "$par_fast" == "false" ]] && unset par_fast +[[ "$par_uncompressed" == "false" ]] && unset par_uncompressed +[[ "$par_with_header" == "false" ]] && unset par_with_header +[[ "$par_header_only" == "false" ]] && unset par_header_only +[[ "$par_no_header" == "false" ]] && unset par_no_header +[[ "$par_count" == "false" ]] && unset par_count +[[ "$par_unmap" == "false" ]] && unset par_unmap +[[ "$par_use_index" == "false" ]] && unset par_use_index +[[ "$par_fetch_pairs" == "false" ]] && unset par_fetch_pairs +[[ "$par_customized_index" == "false" ]] && unset par_customized_index +[[ "$par_no_PG" == "false" ]] && unset par_no_PG +[[ "$par_write_index" == "false" ]] && unset par_write_index +[[ "$par_remove_B" == "false" ]] && unset par_remove_B + +samtools view \ + ${par_bam:+-b} \ + ${par_cram:+-C} \ + ${par_fast:+--fast} \ + ${par_uncompressed:+-u} \ + ${par_with_header:+--with-header} \ + ${par_header_only:+-H} \ + ${par_no_header:+--no-header} \ + ${par_count:+-c} \ + ${par_output:+-o "$par_output"} \ + ${par_output_unselected:+-U "$par_output_unselected"} \ + ${par_unmap:+-p "$par_unmap"} \ + ${par_fetch_pairs:+-P "$par_fetch_pairs"} \ + ${par_fai_reference:+-t "$par_fai_reference"} \ + ${par_use_index:+-M "$par_use_index"} \ + ${par_region_file:+--region-file "$par_region_file"} \ + ${par_customized_index:+-X} \ + ${par_target_file:+-L "$par_target_file"} \ + ${par_qname_file:+-N "$par_qname_file"} \ + ${par_read_group:+-r "$par_read_group"} \ + ${par_read_group_file:+-R "$par_read_group_file"} \ + ${par_tag:+-d "$par_tag"} \ + ${par_tag_file:+-D "$par_tag_file"} \ + ${par_min_MQ:+-q "$par_min_MQ"} \ + ${par_library:+-l "$par_library"} \ + ${par_min_qlen:+-m "$par_min_qlen"} \ + ${par_expr:+-e "$par_expr"} \ + ${par_require_flags:+-f "$par_require_flags"} \ + ${par_excl_flags:+-F "$par_excl_flags"} \ + ${par_incl_flags:+--rf "$par_incl_flags"} \ + ${par_excl_all_flags:+-G "$par_excl_all_flags"} \ + ${par_subsample:+--subsample "$par_subsample"} \ + ${par_subsample_seed:+--subsample-seed "$par_subsample_seed"} \ + ${par_add_flags:+--add-flags "$par_add_flags"} \ + ${par_remove_flags:+--remove-flags "$par_remove_flags"} \ + ${par_remove_tag:+-x "$par_remove_tag"} \ + ${par_keep_tag:+--keep-tag "$par_keep_tag"} \ + ${par_remove_B:+-B} \ + ${par_sanitize:+-z "$par_sanitize"} \ + ${par_input_fmt_option:+--input-fmt-option "$par_input_fmt_option"} \ + ${par_output_fmt:+-O "$par_output_fmt"} \ + ${par_output_fmt_option:+--output-fmt-option "$par_output_fmt_option"} \ + ${par_reference:+-T "$par_reference"} \ + ${par_write_index:+--write-index} \ + ${par_no_PG:+--no-PG} \ + "$par_input" + +exit 0 diff --git a/src/samtools/samtools_view/test.sh b/src/samtools/samtools_view/test.sh new file mode 100644 index 00000000..1de29a7c --- /dev/null +++ b/src/samtools/samtools_view/test.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +test_dir="${meta_resources_dir}/test_data" +temp_dir="${meta_resources_dir}/out" + +############################################################################################ + +echo ">>> Test 1: Import SAM to BAM when @SQ lines are present in the header" +"$meta_executable" \ + --bam \ + --output "$temp_dir/a.bam" \ + --input "$test_dir/a.sam" + +echo ">>> Checking whether output exists" +[ ! -f "$temp_dir/a.bam" ] && echo "File 'a.bam' does not exist!" && exit 1 + +echo ">>> Checking whether output is non-empty" +[ ! -s "$temp_dir/a.bam" ] && echo "File 'a.bam' is empty!" && exit 1 + +echo ">>> Checking whether output is correct" +# compare output of "samtools view" for both files +diff <(samtools view "$temp_dir/a.bam") <(samtools view "$test_dir/a.bam") || \ + (echo "Output file a.bam does not match expected output" && exit 1) + +############################################################################################ + +echo ">>> Test 2: ${meta_functionality_name} with CRAM format output" + +"$meta_executable" \ + --cram \ + --output "$temp_dir/a.cram" \ + --input "$test_dir/a.sam" + +echo ">>> Checking whether output exists" +[ ! -f "$temp_dir/a.cram" ] && echo "File 'a.cram' does not exist!" && exit 1 + +echo ">>> Checking whether output is non-empty" +[ ! -s "$temp_dir/a.cram" ] && echo "File 'a.cram' is empty!" && exit 1 + +echo ">>> Checking whether output is correct" +# compare output of "samtools view" for both files +diff <(samtools view "$temp_dir/a.cram") <(samtools view "$test_dir/a.cram") || \ + (echo "Output file a.cram does not match expected output" && exit 1) + +############################################################################################ + +echo ">>> Test 3: ${meta_functionality_name} with --count option" + +"$meta_executable" \ + --count \ + --output "$temp_dir/a.count" \ + --input "$test_dir/a.sam" + +echo ">>> Checking whether output exists" +[ ! -f "$temp_dir/a.count" ] && echo "File 'a.count' does not exist!" && exit 1 + +echo ">>> Checking whether output is non-empty" +[ ! -s "$temp_dir/a.count" ] && echo "File 'a.count' is empty!" && exit 1 + +echo ">>> Checking whether output is correct" +diff "$temp_dir/a.count" "$test_dir/a.count" || \ + (echo "Output file a.count does not match expected output" && exit 1) + +############################################################################################ + +echo ">>> Test 4: ${meta_functionality_name} including only the forward reads from read pairs" + +"$meta_executable" \ + --output "$temp_dir/a.forward" \ + --excl_flags "0x80" \ + --input "$test_dir/a.sam" + +echo ">>> Checking whether output exists" +[ ! -f "$temp_dir/a.forward" ] && echo "File 'a.forward' does not exist!" && exit 1 + +echo ">>> Checking whether output is non-empty" +[ ! -s "$temp_dir/a.forward" ] && echo "File 'a.forward' is empty!" && exit 1 + +echo ">>> Checking whether output is correct" +diff "$temp_dir/a.forward" "$test_dir/a.forward" || \ + (echo "Output file a.forward does not match expected output" && exit 1) + +############################################################################################ + +echo ">>> All test passed successfully" +rm -rf "${temp_dir}" +exit 0 \ No newline at end of file diff --git a/src/samtools/samtools_view/test_data/a.bam b/src/samtools/samtools_view/test_data/a.bam new file mode 100644 index 0000000000000000000000000000000000000000..95b85b72e85bba4f2ecfed9f289bab13bcebfbf5 GIT binary patch literal 254 zcmb2|=3rp}f&Xj_PR>jW6%55iUs8FJ6A}tI_@3~5+q`PUgD)R98yP();wX6jrDUU) z-x=ML=g(_C}`M^ziWT zoB?7{Q642A#c*VXT}m#{K6x~YGZ>7M9T?Kw{1x5WQrPq~=65$XI<_=6DqftB$jHpx zyZ{Ik)MaJ}E;R1UnR~LLwCG@|U)$@HgoK2O&;S3|ugJEx0s@cAGhMcwOIc&Zc-(iZ QZVV%)MbZq+U=M=`0DTczqyPW_ literal 0 HcmV?d00001 diff --git a/src/samtools/samtools_view/test_data/a.count b/src/samtools/samtools_view/test_data/a.count new file mode 100644 index 00000000..1e8b3149 --- /dev/null +++ b/src/samtools/samtools_view/test_data/a.count @@ -0,0 +1 @@ +6 diff --git a/src/samtools/samtools_view/test_data/a.cram b/src/samtools/samtools_view/test_data/a.cram new file mode 100644 index 0000000000000000000000000000000000000000..57fb3269c06238f3f35201ce71f5a554098b5ebe GIT binary patch literal 692 zcmZ<`a`a_pNYqO%O3Y}Y6&fsz=PDjk6K_20>viTS6N9DK-?^KBwq36IoCl=r z?cr`Bk5T(Aa!wb}8w`vhYz#JBj19XvmaW~xz{t?Bp<#mrYlsU=vYRtQP!L0~uXMZj zWa%J3M#lighDJdrH%3N&XCNUEJ26lW9+a%bjX{0{{Dj0}DOKnX@hhLB*0 z*gqbim>W=x2`C2A1hmG@4?=tTu`)66IytehF*0f~GOGFpLi7fK#JK~585wzkJRwSh zoqhJ&4pn}=UO5G2F3`^&xDmgx&6?=E{# z5+vq)N2O`TUItd6zxCPwd}LtZ5)pBPgAh1)b|^=afrVR0DAAB1$&ex0kO9s(WfZxM zk%dRX1`+#@pQy+)Fubiw@2~+Hyf0=74+9H7CueeUa>Ha06fA39%fKSQ#>UFZ3Je$T zS9YrzSOnSFfQq>o7|#FuU&sLV1{)hQ7_8`bQ{o3of`jvctG^qN4Gc2Yy*K@V6dM~T M{1_SDB{O;h0B-B2a{vGU literal 0 HcmV?d00001 diff --git a/src/samtools/samtools_view/test_data/a.forward b/src/samtools/samtools_view/test_data/a.forward new file mode 100644 index 00000000..766d4f20 --- /dev/null +++ b/src/samtools/samtools_view/test_data/a.forward @@ -0,0 +1,3 @@ +a1 99 xx 1 1 10M = 11 20 AAAAAAAAAA ********** +b1 99 xx 1 1 10M = 11 20 AAAAAAAAAA ********** +c1 99 xx 1 1 10M = 11 20 AAAAAAAAAA ********** diff --git a/src/samtools/samtools_view/test_data/a.sam b/src/samtools/samtools_view/test_data/a.sam new file mode 100644 index 00000000..aa8c77b3 --- /dev/null +++ b/src/samtools/samtools_view/test_data/a.sam @@ -0,0 +1,7 @@ +@SQ SN:xx LN:20 +a1 99 xx 1 1 10M = 11 20 AAAAAAAAAA ********** +b1 99 xx 1 1 10M = 11 20 AAAAAAAAAA ********** +c1 99 xx 1 1 10M = 11 20 AAAAAAAAAA ********** +a1 147 xx 11 1 10M = 1 -20 TTTTTTTTTT ********** +b1 147 xx 11 1 10M = 1 -20 TTTTTTTTTT ********** +c1 147 xx 11 1 10M = 1 -20 TTTTTTTTTT ********** diff --git a/src/samtools/samtools_view/test_data/script.sh b/src/samtools/samtools_view/test_data/script.sh new file mode 100755 index 00000000..90918e44 --- /dev/null +++ b/src/samtools/samtools_view/test_data/script.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# dowload test data from snakemake wrapper +if [ ! -d /tmp/view_source ]; then + git clone --depth 1 --single-branch --branch master https://github.com/snakemake/snakemake-wrappers.git /tmp/view_source +fi + +cp -r /tmp/idxstats_source/bio/samtools/view/test/*.sam src/samtools/samtools_view/test_data \ No newline at end of file From a0a323aa87ba114dc10f4e69909d28f4fe4d0eea Mon Sep 17 00:00:00 2001 From: emmarousseau Date: Thu, 23 May 2024 09:19:43 +0200 Subject: [PATCH 8/8] Samtools fastq (#52) * initial commit dedup * Revert "initial commit dedup" This reverts commit 38f586bec0ac9e4312b016e29c3aa0bd53f292b2. * Initial commit, config, script, help and test_data * Update changelog, add tests, fix argument naming errors, add test data * update changelog, remove gffread namespace field --------- Co-authored-by: Robrecht Cannoodt --- CHANGELOG.md | 1 + src/gffread/config.vsh.yaml | 1 - src/samtools/samtools_fastq/config.vsh.yaml | 189 ++++++++++++++++++ src/samtools/samtools_fastq/help.txt | 80 ++++++++ src/samtools/samtools_fastq/script.sh | 40 ++++ src/samtools/samtools_fastq/test.sh | 96 +++++++++ src/samtools/samtools_fastq/test_data/a.1.fq | 12 ++ src/samtools/samtools_fastq/test_data/a.2.fq | 12 ++ src/samtools/samtools_fastq/test_data/a.bam | Bin 0 -> 184 bytes src/samtools/samtools_fastq/test_data/a.fq | 24 +++ src/samtools/samtools_fastq/test_data/a.sam | 7 + src/samtools/samtools_fastq/test_data/half.fq | 12 ++ .../samtools_fastq/test_data/script.sh | 11 + 13 files changed, 484 insertions(+), 1 deletion(-) create mode 100644 src/samtools/samtools_fastq/config.vsh.yaml create mode 100644 src/samtools/samtools_fastq/help.txt create mode 100644 src/samtools/samtools_fastq/script.sh create mode 100644 src/samtools/samtools_fastq/test.sh create mode 100644 src/samtools/samtools_fastq/test_data/a.1.fq create mode 100644 src/samtools/samtools_fastq/test_data/a.2.fq create mode 100644 src/samtools/samtools_fastq/test_data/a.bam create mode 100644 src/samtools/samtools_fastq/test_data/a.fq create mode 100644 src/samtools/samtools_fastq/test_data/a.sam create mode 100644 src/samtools/samtools_fastq/test_data/half.fq create mode 100755 src/samtools/samtools_fastq/test_data/script.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index b1d7a7af..151b7a41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ - `samtools/samtools_faidx`: Indexes FASTA files to enable random access to fasta and fastq files (PR #41). - `samtools/samtools_collate`: Shuffles and groups reads in SAM/BAM/CRAM files together by their names (PR #42). - `samtools/samtools_view`: Views and converts SAM/BAM/CRAM files (PR #48). + - `samtools/samtools_fastq`: Converts a SAM/BAM/CRAM file to FASTQ (PR #52). * `falco`: A C++ drop-in replacement of FastQC to assess the quality of sequence read data (PR #43). diff --git a/src/gffread/config.vsh.yaml b/src/gffread/config.vsh.yaml index c7f3d551..d2c41a87 100644 --- a/src/gffread/config.vsh.yaml +++ b/src/gffread/config.vsh.yaml @@ -1,5 +1,4 @@ name: gffread -namespace: gffread description: Validate, filter, convert and perform various other operations on GFF files. keywords: [gff, conversion, validation, filtering] links: diff --git a/src/samtools/samtools_fastq/config.vsh.yaml b/src/samtools/samtools_fastq/config.vsh.yaml new file mode 100644 index 00000000..39e926f0 --- /dev/null +++ b/src/samtools/samtools_fastq/config.vsh.yaml @@ -0,0 +1,189 @@ +name: samtools_fastq +namespace: samtools +description: Converts a SAM, BAM or CRAM to FASTQ format. +keywords: [fastq, bam, sam, cram] +links: + homepage: https://www.htslib.org/ + documentation: https://www.htslib.org/doc/samtools-fastq.html + repository: https://github.com/samtools/samtools +references: + doi: [10.1093/bioinformatics/btp352, 10.1093/gigascience/giab008] +license: MIT/Expat + +argument_groups: + - name: Inputs + arguments: + - name: --input + type: file + description: input SAM/BAM/CRAM file + required: true + - name: Outputs + arguments: + - name: --output + type: file + description: output FASTQ file + required: true + direction: output + - name: Options + arguments: + - name: --no_suffix + alternatives: -n + type: boolean_true + description: | + By default, either '/1' or '/2' is added to the end of read names where the corresponding + READ1 or READ2 FLAG bit is set. Using -n causes read names to be left as they are. + - name: --suffix + alternatives: -N + type: boolean_true + description: | + Always add either '/1' or '/2' to the end of read names even when put into different files. + - name: --use_oq + alternatives: -O + type: boolean_true + description: | + Use quality values from OQ tags in preference to standard quality string if available. + - name: --singleton + alternatives: -s + type: file + description: write singleton reads to FILE. + - name: --copy_tags + alternatives: -t + type: boolean_true + description: | + Copy RG, BC and QT tags to the FASTQ header line, if they exist. + - name: --copy_tags_list + alternatives: -T + type: string + description: | + Specify a comma-separated list of tags to copy to the FASTQ header line, if they exist. + TAGLIST can be blank or * to indicate all tags should be copied to the output. If using *, + be careful to quote it to avoid unwanted shell expansion. + - name: --read1 + alternatives: -1 + type: file + description: | + Write reads with the READ1 FLAG set (and READ2 not set) to FILE instead of outputting them. + If the -s option is used, only paired reads will be written to this file. + direction: output + - name: --read2 + alternatives: -2 + type: file + description: | + Write reads with the READ2 FLAG set (and READ1 not set) to FILE instead of outputting them. + If the -s option is used, only paired reads will be written to this file. + direction: output + - name: --output_reads + alternatives: -o + type: file + description: | + Write reads with either READ1 FLAG or READ2 flag set to FILE instead of outputting them to stdout. + This is equivalent to -1 FILE -2 FILE. + direction: output + - name: --output_reads_both + alternatives: -0 + type: file + description: | + Write reads where the READ1 and READ2 FLAG bits set are either both set or both unset to FILE + instead of outputting them. + direction: output + - name: --filter_flags + alternatives: -f + type: integer + description: | + Only output alignments with all bits set in INT present in the FLAG field. INT can be specified + in hex by beginning with `0x' (i.e. /^0x[0-9A-F]+/) or in octal by beginning with `0' + (i.e. /^0[0-7]+/). + default: 0 + - name: --excl_flags + alternatives: -F + type: string + description: | + Do not output alignments with any bits set in INT present in the FLAG field. INT can be specified + in hex by beginning with `0x' (i.e. /^0x[0-9A-F]+/) or in octal by beginning with `0' + (i.e. /^0[0-7]+/). This defaults to 0x900 representing filtering of secondary and + supplementary alignments. + default: 0x900 + - name: --incl_flags + alternatives: --rf + type: string + description: | + Only output alignments with any bits set in INT present in the FLAG field. INT can be specified + in hex by beginning with `0x' (i.e. /^0x[0-9A-F]+/), in octal by beginning with `0' + (i.e. /^0[0-7]+/), as a decimal number not beginning with '0' or as a comma-separated list of + flag names. + default: 0 + - name: --excl_flags_all + alternatives: -G + type: integer + description: | + Only EXCLUDE reads with all of the bits set in INT present in the FLAG field. INT can be specified + in hex by beginning with `0x' (i.e. /^0x[0-9A-F]+/) or in octal by beginning with `0' + (i.e. /^0[0-7]+/). + default: 0 + - name: --aux_tag + alternatives: -d + type: string + description: | + Only output alignments containing an auxiliary tag matching both TAG and VAL. If VAL is omitted + then any value is accepted. The tag types supported are i, f, Z, A and H. "B" arrays are not + supported. This is comparable to the method used in samtools view --tag. The option may be specified + multiple times and is equivalent to using the --aux_tag_file option. + - name: --aux_tag_file + alternatives: -D + type: string + description: | + Only output alignments containing an auxiliary tag matching TAG and having a value listed in FILE. + The format of the file is one line per value. This is equivalent to specifying --aux_tag multiple times. + - name: --casava + alternatives: -i + type: boolean_true + description: add Illumina Casava 1.8 format entry to header (eg 1:N:0:ATCACG) + - name: --compression + alternatives: -c + type: integer + description: set compression level when writing gz or bgzf fastq files. + default: 0 + - name: --index1 + alternatives: --i1 + type: file + description: write first index reads to FILE. + - name: --index2 + alternatives: --i2 + type: file + description: write second index reads to FILE. + - name: --barcode_tag + type: string + description: Auxiliary tag to find index reads in. + default: BC + - name: --quality_tag + type: string + description: Auxiliary tag to find index quality in. + default: QT + - name: --index_format + type: string + description: | + string to describe how to parse the barcode and quality tags. For example: + [i14i8]: the first 14 characters are index 1, the next 8 characters are index 2. + [n8i14]: ignore the first 8 characters, and use the next 14 characters for index 1. + If the tag contains a separator, then the numeric part can be replaced with '*' to mean + 'read until the separator or end of tag', for example: [n*i*]. + +resources: + - type: bash_script + path: script.sh +test_resources: + - type: bash_script + path: test.sh + - type: file + path: test_data +engines: + - type: docker + image: quay.io/biocontainers/samtools:1.19.2--h50ea8bc_1 + setup: + - type: docker + run: | + samtools --version 2>&1 | grep -E '^(samtools|Using htslib)' | \ + sed 's#Using ##;s# \([0-9\.]*\)$#: \1#' > /var/software_versions.txt +runners: +- type: executable +- type: nextflow diff --git a/src/samtools/samtools_fastq/help.txt b/src/samtools/samtools_fastq/help.txt new file mode 100644 index 00000000..39ed0d00 --- /dev/null +++ b/src/samtools/samtools_fastq/help.txt @@ -0,0 +1,80 @@ +``` +samtools fastq +``` + +Usage: samtools fastq [options...] + +Description: +Converts a SAM, BAM or CRAM to FASTQ format. + +Options: + -0 FILE write reads designated READ_OTHER to FILE + -1 FILE write reads designated READ1 to FILE + -2 FILE write reads designated READ2 to FILE + -o FILE write reads designated READ1 or READ2 to FILE + note: if a singleton file is specified with -s, only + paired reads will be written to the -1 and -2 files. + -d, --tag TAG[:VAL] + only include reads containing TAG, optionally with value VAL + -f, --require-flags INT + only include reads with all of the FLAGs in INT present [0] + -F, --excl[ude]-flags INT + only include reads with none of the FLAGs in INT present [0x900] + --rf, --incl[ude]-flags INT + only include reads with any of the FLAGs in INT present [0] + -G INT only EXCLUDE reads with all of the FLAGs in INT present [0] + -n don't append /1 and /2 to the read name + -N always append /1 and /2 to the read name + -O output quality in the OQ tag if present + -s FILE write singleton reads designated READ1 or READ2 to FILE + -t copy RG, BC and QT tags to the FASTQ header line + -T TAGLIST copy arbitrary tags to the FASTQ header line, '*' for all + -v INT default quality score if not given in file [1] + -i add Illumina Casava 1.8 format entry to header (eg 1:N:0:ATCACG) + -c INT compression level [0..9] to use when writing bgzf files [1] + --i1 FILE write first index reads to FILE + --i2 FILE write second index reads to FILE + --barcode-tag TAG + Barcode tag [BC] + --quality-tag TAG + Quality tag [QT] + --index-format STR + How to parse barcode and quality tags + + --input-fmt-option OPT[=VAL] + Specify a single input file format option in the form + of OPTION or OPTION=VALUE + --reference FILE + Reference sequence FASTA FILE [null] + -@, --threads INT + Number of additional threads to use [0] + --verbosity INT + Set level of verbosity + +The files will be automatically compressed if the file names have a .gz +or .bgzf extension. The input to this program must be collated by name. +Run 'samtools collate' or 'samtools sort -n' to achieve this. + +Reads are designated READ1 if FLAG READ1 is set and READ2 is not set. +Reads are designated READ2 if FLAG READ1 is not set and READ2 is set. +Otherwise reads are designated READ_OTHER (both flags set or both flags unset). +Run 'samtools flags' for more information on flag codes and meanings. + +The index-format string describes how to parse the barcode and quality tags. +It is made up of 'i' or 'n' followed by a length or '*'. For example: + i14i8 The first 14 characters are index 1, the next 8 are index 2 + n8i14 Ignore the first 8 characters, and use the next 14 for index 1 + +If the tag contains a separator, then the numeric part can be replaced with +'*' to mean 'read until the separator or end of tag', for example: + i*i* Break the tag at the separator into index 1 and index 2 + n*i* Ignore the left part of the tag until the separator, + then use the second part of the tag as index 1 + +Examples: +To get just the paired reads in separate files, use: + samtools fastq -1 pair1.fq -2 pair2.fq -0 /dev/null -s /dev/null -n in.bam + +To get all non-supplementary/secondary reads in a single file, redirect +the output: + samtools fastq in.bam > all_reads.fq \ No newline at end of file diff --git a/src/samtools/samtools_fastq/script.sh b/src/samtools/samtools_fastq/script.sh new file mode 100644 index 00000000..367432f9 --- /dev/null +++ b/src/samtools/samtools_fastq/script.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +## VIASH START +## VIASH END + +set -e + +[[ "$par_no_suffix" == "false" ]] && unset par_no_suffix +[[ "$par_suffix" == "false" ]] && unset par_suffix +[[ "$par_use_oq" == "false" ]] && unset par_use_oq +[[ "$par_copy_tags" == "false" ]] && unset par_copy_tags +[[ "$par_casava" == "false" ]] && unset par_casava + +samtools fastq \ + ${par_no_suffix:+-n} \ + ${par_suffix:+-N} \ + ${par_use_oq:+-O} \ + ${par_singleton:+-s "$par_singleton"} \ + ${par_copy_tags:+-t} \ + ${par_copy_tags_list:+-T "$par_copy_tags_list"} \ + ${par_read1:+-1 "$par_read1"} \ + ${par_read2:+-2 "$par_read2"} \ + ${par_output_reads:+-o "$par_output_reads"} \ + ${par_output_reads_both:+-0 "$par_output_reads_both"} \ + ${par_filter_flags:+-f "$par_filter_flags"} \ + ${par_excl_flags:+-F "$par_excl_flags"} \ + ${par_incl_flags:+--rf "$par_incl_flags"} \ + ${par_excl_flags_all:+-G "$par_excl_flags_all"} \ + ${par_aux_tag:+-d "$par_aux_tag"} \ + ${par_aux_tag_file:+-D "$par_aux_tag_file"} \ + ${par_casava:+-i} \ + ${par_compression:+-c "$par_compression"} \ + ${par_index1:+--i1 "$par_index1"} \ + ${par_index2:+--i2 "$par_index2"} \ + ${par_barcode_tag:+--barcode-tag "$par_barcode_tag"} \ + ${par_quality_tag:+--quality-tag "$par_quality_tag"} \ + ${par_index_format:+--index-format "$par_index_format"} \ + "$par_input" \ + > "$par_output" + diff --git a/src/samtools/samtools_fastq/test.sh b/src/samtools/samtools_fastq/test.sh new file mode 100644 index 00000000..32ee3f5e --- /dev/null +++ b/src/samtools/samtools_fastq/test.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +test_dir="${meta_resources_dir}/test_data" +out_dir="${meta_resources_dir}/out_data" + +############################################################################################ + +echo ">>> Test 1: Convert all reads from a bam file to fastq format" +"$meta_executable" \ + --input "$test_dir/a.bam" \ + --output "$out_dir/a.fq" + +echo ">>> Check if output file exists" +[ ! -f "$out_dir/a.fq" ] && echo "Output file a.fq does not exist" && exit 1 + +echo ">>> Check if output is empty" +[ ! -s "$out_dir/a.fq" ] && echo "Output file a.fq is empty" && exit 1 + +echo ">>> Check if output matches expected output" +diff "$out_dir/a.fq" "$test_dir/a.fq" || + (echo "Output file a.fq does not match expected output" && exit 1) + +rm "$out_dir/a.fq" + +############################################################################################ + +echo ">>> Test 2: Convert all reads from a sam file to fastq format" +"$meta_executable" \ + --input "$test_dir/a.sam" \ + --output "$out_dir/a.fq" + +echo ">>> Check if output file exists" +[ ! -f "$out_dir/a.fq" ] && echo "Output file a.fq does not exist" && exit 1 + +echo ">>> Check if output is empty" +[ ! -s "$out_dir/a.fq" ] && echo "Output file a.fq is empty" && exit 1 + +echo ">>> Check if output matches expected output" +diff "$out_dir/a.fq" "$test_dir/a.fq" || + (echo "Output file a.fq does not match expected output" && exit 1) + +rm "$out_dir/a.fq" + +############################################################################################ + +echo ">>> Test 3: Output reads from bam file to separate files" + +"$meta_executable" \ + --input "$test_dir/a.bam" \ + --read1 "$out_dir/a.1.fq" \ + --read2 "$out_dir/a.2.fq" \ + --output "$out_dir/a.fq" + +echo ">>> Check if output files exist" +[ ! -f "$out_dir/a.1.fq" ] && echo "Output file a.1.fq does not exist" && exit 1 +[ ! -f "$out_dir/a.2.fq" ] && echo "Output file a.2.fq does not exist" && exit 1 +[ ! -f "$out_dir/a.fq" ] && echo "Output file a.fq does not exist" && exit 1 + +echo ">>> Check if output files are empty" +[ ! -s "$out_dir/a.1.fq" ] && echo "Output file a.1.fq is empty" && exit 1 +[ ! -s "$out_dir/a.2.fq" ] && echo "Output file a.2.fq is empty" && exit 1 +# output should be empty since input has no singleton reads + +echo ">>> Check if output files match expected output" +diff "$out_dir/a.1.fq" "$test_dir/a.1.fq" || + (echo "Output file a.1.fq does not match expected output" && exit 1) +diff "$out_dir/a.2.fq" "$test_dir/a.2.fq" || + (echo "Output file a.2.fq does not match expected output" && exit 1) + +rm "$out_dir/a.1.fq" "$out_dir/a.2.fq" "$out_dir/a.fq" + +############################################################################################ + +echo ">>> Test 4: Output only forward reads from bam file to fastq format" + +"$meta_executable" \ + --input "$test_dir/a.sam" \ + --excl_flags "0x80" \ + --output "$out_dir/half.fq" + +echo ">>> Check if output file exists" +[ ! -f "$out_dir/half.fq" ] && echo "Output file half.fq does not exist" && exit 1 + +echo ">>> Check if output is empty" +[ ! -s "$out_dir/half.fq" ] && echo "Output file half.fq is empty" && exit 1 + +echo ">>> Check if output matches expected output" +diff "$out_dir/half.fq" "$test_dir/half.fq" || + (echo "Output file half.fq does not match expected output" && exit 1) + +rm "$out_dir/half.fq" + +############################################################################################ + +echo "All tests succeeded!" +exit 0 \ No newline at end of file diff --git a/src/samtools/samtools_fastq/test_data/a.1.fq b/src/samtools/samtools_fastq/test_data/a.1.fq new file mode 100644 index 00000000..03eaa725 --- /dev/null +++ b/src/samtools/samtools_fastq/test_data/a.1.fq @@ -0,0 +1,12 @@ +@a1 +AAAAAAAAAA ++ +********** +@b1 +AAAAAAAAAA ++ +********** +@c1 +AAAAAAAAAA ++ +********** diff --git a/src/samtools/samtools_fastq/test_data/a.2.fq b/src/samtools/samtools_fastq/test_data/a.2.fq new file mode 100644 index 00000000..03eaa725 --- /dev/null +++ b/src/samtools/samtools_fastq/test_data/a.2.fq @@ -0,0 +1,12 @@ +@a1 +AAAAAAAAAA ++ +********** +@b1 +AAAAAAAAAA ++ +********** +@c1 +AAAAAAAAAA ++ +********** diff --git a/src/samtools/samtools_fastq/test_data/a.bam b/src/samtools/samtools_fastq/test_data/a.bam new file mode 100644 index 0000000000000000000000000000000000000000..dba1268acbd8446e4fde54d7da33434597fbe635 GIT binary patch literal 184 zcmb2|=3rp}f&Xj_PR>jWb_~TuUs6R95)ukH_@3~5+q`PUgD)R98yP)FV(BtuE_7vW z=9s|5aI{h|P#vgC9!+};gK@G0Lz-KrbIh-tVq12fpEAOZjf CvNY8I literal 0 HcmV?d00001 diff --git a/src/samtools/samtools_fastq/test_data/a.fq b/src/samtools/samtools_fastq/test_data/a.fq new file mode 100644 index 00000000..d12c62ca --- /dev/null +++ b/src/samtools/samtools_fastq/test_data/a.fq @@ -0,0 +1,24 @@ +@a1/1 +AAAAAAAAAA ++ +********** +@b1/1 +AAAAAAAAAA ++ +********** +@c1/1 +AAAAAAAAAA ++ +********** +@a1/2 +AAAAAAAAAA ++ +********** +@b1/2 +AAAAAAAAAA ++ +********** +@c1/2 +AAAAAAAAAA ++ +********** diff --git a/src/samtools/samtools_fastq/test_data/a.sam b/src/samtools/samtools_fastq/test_data/a.sam new file mode 100644 index 00000000..aa8c77b3 --- /dev/null +++ b/src/samtools/samtools_fastq/test_data/a.sam @@ -0,0 +1,7 @@ +@SQ SN:xx LN:20 +a1 99 xx 1 1 10M = 11 20 AAAAAAAAAA ********** +b1 99 xx 1 1 10M = 11 20 AAAAAAAAAA ********** +c1 99 xx 1 1 10M = 11 20 AAAAAAAAAA ********** +a1 147 xx 11 1 10M = 1 -20 TTTTTTTTTT ********** +b1 147 xx 11 1 10M = 1 -20 TTTTTTTTTT ********** +c1 147 xx 11 1 10M = 1 -20 TTTTTTTTTT ********** diff --git a/src/samtools/samtools_fastq/test_data/half.fq b/src/samtools/samtools_fastq/test_data/half.fq new file mode 100644 index 00000000..85a2b1c4 --- /dev/null +++ b/src/samtools/samtools_fastq/test_data/half.fq @@ -0,0 +1,12 @@ +@a1/1 +AAAAAAAAAA ++ +********** +@b1/1 +AAAAAAAAAA ++ +********** +@c1/1 +AAAAAAAAAA ++ +********** diff --git a/src/samtools/samtools_fastq/test_data/script.sh b/src/samtools/samtools_fastq/test_data/script.sh new file mode 100755 index 00000000..b59bc1bd --- /dev/null +++ b/src/samtools/samtools_fastq/test_data/script.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# dowload test data from snakemake wrapper +if [ ! -d /tmp/fastq_source ]; then + git clone --depth 1 --single-branch --branch master https://github.com/snakemake/snakemake-wrappers.git /tmp/fastq_source +fi + +cp -r /tmp/fastq_source/bio/samtools/fastx/test/*.sam src/samtools/samtools_fastq/test_data/ +cp -r /tmp/fastq_source/bio/samtools/fastq/interleaved/test/mapped/*.bam src/samtools/samtools_fastq/test_data/ +cp -r /tmp/fastq_source/bio/samtools/fastq/interleaved/test/reads/*.fq src/samtools/samtools_fastq/test_data/ +cp -r /tmp/fastq_source/bio/samtools/fastq/separate/test/reads/*.fq src/samtools/samtools_fastq/test_data/ \ No newline at end of file