#!/opt/conda/conda-bld/trinotate_1694220261901/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_pla/bin/perl 

use strict;
use warnings;
use FindBin;

use Pipeliner;
use Carp;
use Cwd 'abs_path';
use Getopt::Long qw(:config posix_default no_ignore_case bundling pass_through);
use Data::Dumper;
use List::Util qw(max);
use File::Basename;

my $usage = <<_EOUSAGE_;


              ___________      .__               __          __           
              \__    ___/______|__| ____   _____/  |______ _/  |_  ____   
                |    |  \_  __ \  |/    \ /  _ \   __\__  \\   __\/ __ \  
                |    |   |  | \/  |   |  (  <_> )  |  / __ \|  | \  ___/  
                |____|   |__|  |__|___|  /\____/|__| (____  /__|  \___  > 
                                       \/                 \/          \/  

     usage: $0 --db <sqlite.db> <--command ...>
 

     <commands>: 

         * Initial creation of the Trinotate sqlite database and downloading of the required data sets
              
             Trinotate --db <sqlite.db> --create --trinotate_data_dir /path/to/TRINOTATE_DATA_DIR

                 The sqlite.db file is created as named and search databases are downloaded into /path/to/TRINOTATE_DATA_DIR
                   (Note, if EggnogMapper is installed and env var EGGNOG_DATA_DIR is NOT set, 
                    will additionally download those data too into TRINOTATE_DATA_DIR !) 

         * Initial import of transcriptome and protein data:

             Trinotate --db <sqlite.db> --init --gene_trans_map <file> --transcript_fasta <file> --transdecoder_pep <file>

         * Running annotation computes automatically including auto-loading of results.

             * to run ALL supported computes:
                   
                   Trinotate --db <sqlite.db> --run ALL --CPU <int> --transcript_fasta <file> --transdecoder_pep <file> 

             * or to run select supported computes, indicate which ones to run: 

                   Trinotate --db <sqlite.db> --CPU <int> --transcript_fasta <file> --transdecoder_pep <file> \
                                   --run "swissprot_blastp swissprot_blastx pfam signalp6 tmhmmv2 infernal EggnogMapper" 

                    Notes:
                        -  when specifying run with multiple values, enclose the list in quotes as shown above.
                        -  include --use_diamond if you would prefer to use diamond blast instead of ncbi (default) blast)
                        -  include --trinotate_data_dir <path> unless you have TRINOTATE_DATA_DIR env var set. 
                        -  if running using provided docker or singularity, signalp6 is not automatically included due to licensing restrictions)
                        -  deeptmhmm must be run separately from Trinotate and then loaded using Trinotate --LOAD_deeptmhmm

         * Transdecoder loading protein search results:

             Trinotate --db <sqlite.db> --LOAD_swissprot_blastp <file.outfmt6>
             Trinotate --db <sqlite.db> --LOAD_pfam <file>
             Trinotate --db <sqlite.db> --LOAD_signalp <file>
             Trinotate --db <sqlite.db> --LOAD_EggnogMapper <file>
             Trinotate --db <sqlite.db> --LOAD_tmhmmv2 <file>  or Trinotate --db <sqlite.db> --LOAD_deeptmhmm <file.gff3>


          * Trinity loading transcript search results:

             Trinotate --db <sqlite.db> --LOAD_swissprot_blastx <file.outfmt6>
             Trinotate --db <sqlite.db> --LOAD_infernal <file>
             

          * Load custom blast results using any searchable database

             Trinotate --db <sqlite.db> --LOAD_custom_blast <file.outfmt6> --blast_type <blastp|blastx> --custom_db_name <database_name>
                    (The custom_db_name is used for the column name for that annotation in the final report.)

          * report generation:

             Trinotate --db <sqlite.db> --report [ -E (default: 1e-5) ] \
                                                 [--pfam_cutoff DNC|DGC|DTC|SNC|SGC|STC (default: DNC=domain noise cutoff)] \
                                                 [--incl_pep] \
                                                 [--incl_trans]


_EOUSAGE_

;

                                        

                                        
my $help_flag;
my $sqlite_db;
my ($CREATE_flag, 
    $INIT_flag,
    $REPORT_flag,
    $RUN_flag);

my $RUN_list = "";

my ($LOAD_swissprot_blastp, $LOAD_pfam, $LOAD_deeptmhmm, $LOAD_signalp, 
    $LOAD_EggnogMapper, $LOAD_swissprot_blastx, $LOAD_infernal, $LOAD_tmhmmv2,
    $LOAD_custom_blast, $custom_db_name, $blast_type) = ("", "", "", "", "", "", "", "", "", "", "");

my ($trinotate_data_dir, $transcript_fasta, $transdecoder_pep, $gene_trans_map);

my $USE_DIAMOND_BLAST_flag = 0;
my $CPU = 4;

my %PARAMS = map { $_ => 1 } @ARGV;

my $EVALUE = "1e-5";
my $PFAM_CUTOFF = "DNC";
my $include_pep = 0;
my $include_trans = 0;



&GetOptions ( 
    'h' => \$help_flag,
    
    'db=s' => \$sqlite_db,

    # exec modes
    'create' => \$CREATE_flag,
    'init' => \$INIT_flag,
    'report' => \$REPORT_flag,
    'run=s' => \$RUN_list,
    
    # loading modes
    'LOAD_swissprot_blastp=s' => \$LOAD_swissprot_blastp,
    'LOAD_pfam=s' => \$LOAD_pfam,
    'LOAD_deeptmhmm=s' => \$LOAD_deeptmhmm,
    'LOAD_signalp=s' => \$LOAD_signalp,
    'LOAD_EggnogMapper=s' => \$LOAD_EggnogMapper,
    'LOAD_swissprot_blastx=s' => \$LOAD_swissprot_blastx,
    'LOAD_infernal=s' => \$LOAD_infernal,
    'LOAD_custom_blast=s' => \$LOAD_custom_blast,
    'LOAD_tmhmmv2=s' => \$LOAD_tmhmmv2,
    'custom_db_name=s' => \$custom_db_name,
    'blast_type=s' => \$blast_type,

    'trinotate_data_dir=s' => \$trinotate_data_dir,
    'transcript_fasta=s' => \$transcript_fasta,
    'transdecoder_pep=s' => \$transdecoder_pep,
    'gene_trans_map=s' => \$gene_trans_map,

    'use_diamond' => \$USE_DIAMOND_BLAST_flag,
    
    'CPU=i' => \$CPU,
    
    'E|evalue=s' => \$EVALUE,
    'PFAM_CUTOFF=s' => \$PFAM_CUTOFF,
    'incl_pep' => \$include_pep,
    'incl_trans' => \$include_trans,
    
    );


# env var TRINOTATE_DATA_DIR is set or re-set here.
if ($trinotate_data_dir) {
    $ENV{'TRINOTATE_DATA_DIR'} = $trinotate_data_dir; # setting or re-setting
}
else {
    $trinotate_data_dir = $ENV{'TRINOTATE_DATA_DIR'} || "";
}


if ($RUN_list) {
    $RUN_flag = 1;
}

unless ($sqlite_db && 
        ($CREATE_flag || $INIT_flag || $REPORT_flag || $RUN_flag ||
         $LOAD_swissprot_blastp || $LOAD_pfam || $LOAD_deeptmhmm || $LOAD_signalp || $LOAD_tmhmmv2 ||
         $LOAD_EggnogMapper || $LOAD_swissprot_blastx || $LOAD_infernal || $LOAD_custom_blast) ) {

    die $usage;
}

if ($LOAD_custom_blast && ! ($custom_db_name && $blast_type)) {
    die "Error, must specify --custom_db_name and --blast_type values when loading custom blast results. This will be your report column header for these annotations.\n";
}

my $util_dir = "$FindBin::RealBin/util";
my $loaders_dir = "$util_dir/trinotateSeqLoader";
my $admin_dir = "$util_dir/admin";


if (@ARGV) {
    confess "Error, not recognizing parameters: [ @ARGV ] ";
}

## Trinotate working directory and Trinotate data dir should be distinct paths.


if ($trinotate_data_dir && Cwd::abs_path(Cwd::getcwd()) eq Cwd::abs_path($trinotate_data_dir)) {

    confess("Error, your TRINOTATE_DATA_DIR [" . Cwd::abs_path($trinotate_data_dir) . "] " .
	    "must be distinct from your Trinotate working directory [" . Cwd::abs_path(Cwd::getcwd()) ." ]" .
	    "The TRINOTATE_DATA_DIR should only house resource files, not Trinoate outputs"
	);
}

&ensure_prog_exists("sqlite3");


my %command_to_params = ( 
    # protein-based
    '--LOAD_swissprot_blastp' => "$loaders_dir/Trinotate_BLAST_loader.pl --sqlite $sqlite_db --outfmt6 $LOAD_swissprot_blastp --prog blastp --dbtype Swissprot",
    '--LOAD_pfam'  => "$loaders_dir/Trinotate_PFAM_loader.pl --sqlite $sqlite_db --pfam $LOAD_pfam",
    '--LOAD_deeptmhmm' => "$loaders_dir/Trinotate_DeepTmHMM_loader.pl --sqlite $sqlite_db --deeptmhmm_gff3 $LOAD_deeptmhmm",
    '--LOAD_signalp' => "$loaders_dir/Trinotate_SIGNALP_loader.pl --sqlite $sqlite_db --signalp $LOAD_signalp",
    '--LOAD_EggnogMapper' => "$loaders_dir/Trinotate_EggnogMapper_loader.pl --sqlite $sqlite_db --emapper $LOAD_EggnogMapper",
    '--LOAD_tmhmmv2' => "$loaders_dir/Trinotate_TmHMMv2_loader.pl --sqlite $sqlite_db --tmhmm $LOAD_tmhmmv2",
    
    # transcript-based
    '--LOAD_swissprot_blastx' => "$loaders_dir/Trinotate_BLAST_loader.pl --sqlite $sqlite_db --outfmt6 $LOAD_swissprot_blastx --prog blastx --dbtype Swissprot",
    '--LOAD_infernal' => "$loaders_dir/Trinotate_Infernal_loader.pl --sqlite $sqlite_db --infernal $LOAD_infernal",
    
    # custom blast searches
    '--LOAD_custom_blast' => "$loaders_dir/Trinotate_BLAST_loader.pl --sqlite $sqlite_db --outfmt6 $LOAD_custom_blast --prog $blast_type --dbtype $custom_db_name",
    
    
    );



my @LOAD_cmds = grep { /^--LOAD_/ } keys %PARAMS;



if ($CREATE_flag) {
    # set up Trinotate database and data dir

    print STDERR "-CREATING $sqlite_db and populating data dir: $trinotate_data_dir\n"; 
    unless($trinotate_data_dir) {
        die "Error, the Trinotate create parameter requires a path to a destination data directory via --trinotate_data_dir or env var TRINOTATE_DATA_DIR to indicate the area to be created/populated";
    }

    if (-e $sqlite_db) {
        print STDERR "WARNING: SQLITE database $sqlite_db already exists and wont be replaced.\n";
    }
    
    &run_Trinotate_create($sqlite_db, $trinotate_data_dir);
}


if ($INIT_flag) {
    my $init_checkpt = "__init.ok";
    if (! -e $init_checkpt) {
        print STDERR "-INIT populating $sqlite_db with transcripts and proteins\n";
        # populate sequence and gene/trans/orf data
        unless ($gene_trans_map && $transcript_fasta && $transdecoder_pep) {
            confess "Error, for 'init' the following are required:  --gene_trans_map, --transcript_fasta, and --transdecoder_pep ";
        }
        my $cmd = "$FindBin::RealBin/util/trinotateSeqLoader/TrinotateSeqLoader.pl --sqlite $sqlite_db --gene_trans_map $gene_trans_map --transcript_fasta $transcript_fasta --transdecoder_pep $transdecoder_pep --bulk_load";
        &process_cmd($cmd);
        &process_cmd("touch $init_checkpt");
    }
}

if (@LOAD_cmds) {
    foreach my $LOAD_cmd (@LOAD_cmds) {
        my $cmd = $command_to_params{$LOAD_cmd};
        unless ($cmd) {
            confess "Error, cannot find a command for loading instruction: $LOAD_cmd ";
        }
        print STDERR "-LOADING as per $LOAD_cmd\n";
        &process_cmd($cmd);
    }
}


if ($RUN_flag) {

    print STDERR "-RUN mode indicated. Will process bioinformatics computes.\n";
    
    unless ($trinotate_data_dir) {
        confess "Error, --trinotate_data_dir or env var TRINOTATE_DATA_DIR must be set.";
    }

    unless ($transcript_fasta && $transdecoder_pep) {
        confess "Error, for 'run' the following are required:  --gene_trans_map, --transcript_fasta, and --transdecoder_pep ";
    }
    
    my @supported = qw( ALL swissprot_blastp swissprot_blastx pfam signalp6 tmhmmv2 infernal EggnogMapper );
    my %supported_run_types = map { $_ => 1 } @supported;
    

    $RUN_list =~ s/^\s+|\s+$//g; # strip whitespace from ends.
    my @run_types = split(/\s+/, $RUN_list);
    if (grep { /^ALL$/i } @run_types) {
        print STDERR "-found ALL among run types so running everything supported.\n";
        @run_types = ("ALL");
    }
    
    
    my @unsupported = grep { ! exists $supported_run_types{$_} } @run_types;
    if (@unsupported) {
        confess "Error, run types not recognized include [ @unsupported ].  Please edit or remove unsupported entries. Only the following are supported: [ @supported ]  ";
    }
    
                              
    &Trinotate_RUN_annotators($sqlite_db, \@run_types, $CPU, $trinotate_data_dir, $transcript_fasta, $transdecoder_pep);
}


if ($REPORT_flag) {
    print STDERR "-REPORT being generated.\n";
    ## generate Trinotate report.
    my $cmd = "$FindBin::RealBin/util/Trinotate_report_writer.pl --sqlite $sqlite_db -E $EVALUE --pfam_cutoff $PFAM_CUTOFF ";
    if ($include_pep) {
        $cmd .= " --incl_pep ";
    }
    if ($include_trans) {
        $cmd .= " --incl_trans ";
    }
    
    &process_cmd($cmd);
    
}



exit(0);

####
sub process_cmd {
    my ($cmd) = @_;

    print STDERR "CMD: $cmd\n";
    my $ret = system($cmd);
    if ($ret) {
        die "Error, cmd: $cmd died with ret $ret";
    }

    return;
}


####
sub run_Trinotate_create {
    my ($sqlite_db, $path_to_trinotate_db) = @_;

    ## first, check for tools required for a successful build.
    my @required_utilities = qw(makeblastdb hmmpress cmpress wget);
    if ($USE_DIAMOND_BLAST_flag) {
        push(@required_utilities, 'diamond');
    }
    my $missing = 0;
    for my $prog (@required_utilities) {
        unless (`which $prog` =~ /\w/) {
            $missing += 1;
            print STDERR "-error, cannot locate required utility: $prog, be sure it is installed and available via your PATH env var setting\n";
        }
    }
    if ($missing) {
        confess "Error, missing at least one required utility. See above for specifics.\n";
    }
    
    
    unless ($path_to_trinotate_db) {
        confess("Error, require path_to_trinotate_db_param");
    }

    $path_to_trinotate_db = abs_path($path_to_trinotate_db);
    
    if (! -d $path_to_trinotate_db) {
        &process_cmd("mkdir -p $path_to_trinotate_db");
    }
    
    my $trin_db_build_checkpoint_dir = "$path_to_trinotate_db/__chckpts";
    if (! -d $trin_db_build_checkpoint_dir) {
        mkdir($trin_db_build_checkpoint_dir) or die "Error, cannot mkdir $trin_db_build_checkpoint_dir";
    }
    
    my $pipeliner = new Pipeliner(-verbose => 2, -checkpoint_dir => $trin_db_build_checkpoint_dir);
        
    my $cmd = "$admin_dir/Build_Trinotate_Boilerplate_SQLite_db.pl TrinotateBoilerplate";
    $pipeliner->add_commands(new Command($cmd, "build_boilerplate.ok"));


    # copy boilerplate sqlite and misc datafiles worth retaining to data dir:
    $cmd = "mv TrinotateBoilerplate.sqlite pfam2go go-basic.obo pfam2go.tab NOG.annotations.tsv.gz $path_to_trinotate_db/";
    $pipeliner->add_commands(new Command($cmd, "copy_boilerplate_to_datadir.ok"));

    if (-s $sqlite_db) {
        print STDERR "-sqlite db $sqlite_db already exists and is not being replaced. If a new boilerplate is required, copy db from: $path_to_trinotate_db/TrinotateBoilerplate.sqlite\n";
    }
    else {
        $cmd = "cp $path_to_trinotate_db/TrinotateBoilerplate.sqlite $sqlite_db";
        my $bname_sqlite = basename($sqlite_db);
        $pipeliner->add_commands(new Command($cmd, "cp_trinotate_boilerplate_sqlite_to_$bname_sqlite.ok"));
    }
    
    $cmd = "makeblastdb -in uniprot_sprot.pep -dbtype prot";
    $pipeliner->add_commands(new Command($cmd, "make_sprot_blast_db.ok"));
            
    # diamond is optional
    if (`which diamond` =~ /\w/) {
        $cmd = "diamond makedb --in uniprot_sprot.pep -d uniprot_sprot";
        $pipeliner->add_commands(new Command($cmd, "make_diamond_sprot_db.ok"));
    }
    
    $cmd = "mv uniprot_sprot* $path_to_trinotate_db/";
    $pipeliner->add_commands(new Command($cmd, "relocate_sprot_db.ok"));
    
    $cmd = "gunzip Pfam-A.hmm.gz";
    $pipeliner->add_commands(new Command($cmd, "gunzip_pfam.ok"));

    $cmd = "hmmpress Pfam-A.hmm";
    $pipeliner->add_commands(new Command($cmd, "hmmpress_pfam_db.ok"));

    
    $cmd = "mv Pfam-A.hmm* $path_to_trinotate_db/";
    $pipeliner->add_commands(new Command($cmd, "relocate_pfam_db.ok"));

    ## add Infernal
    $cmd = "wget ftp://ftp.ebi.ac.uk/pub/databases/Rfam/CURRENT/Rfam.cm.gz";
    $pipeliner->add_commands(new Command($cmd, "wget_Rfam.cm.gz"));

    $cmd = "gunzip Rfam.cm.gz";
    $pipeliner->add_commands(new Command($cmd, "gunzip_Rfam.cm.gz"));
    
    $cmd = "wget ftp://ftp.ebi.ac.uk/pub/databases/Rfam/CURRENT/Rfam.clanin";
    $pipeliner->add_commands(new Command($cmd, "wget_clanin.cm.gz"));
    
    $cmd = "cmpress Rfam.cm";
    $pipeliner->add_commands(new Command($cmd, "cmpress_Rfam_cm.ok"));
    
    $cmd = "mv Rfam.* $path_to_trinotate_db/";
    $pipeliner->add_commands(new Command($cmd, "relocate_Rfam_db.ok"));


    $pipeliner->run();



    ## Install EggnogMapper data dir if software is available but

    if (`which download_eggnog_data.py` =~ /\w/ 
        &&
        `which emapper.py` =~ /\w/
        &&
        (! exists $ENV{EGGNOG_DATA_DIR})) {
                
        my $eggnog_data_dir = $ENV{EGGNOG_DATA_DIR} = "$path_to_trinotate_db/EGGNOG_DATA_DIR";
        if (! -d $eggnog_data_dir) {
            mkdir($eggnog_data_dir) or confess "Error, cannot mkdir $eggnog_data_dir";
        }

        print STDERR "-EGGNOG_MAPPER: installing eggnogmapper data at: $eggnog_data_dir\n";
        
        # populate it.
        my $cmd = "download_eggnog_data.py --data_dir $eggnog_data_dir -y";
        $pipeliner->add_commands(new Command($cmd, "eggnog_mapper_data_download.ok"));

        $pipeliner->run();
    }
        
    
    print "\n\n####################################################\n\n"
        . "#  For future Trinotate execution, first set environment variable TRINOTATE_DATA_DIR like so:"
        . "#\n"
        . "#  export TRINOTATE_DATA_DIR=$path_to_trinotate_db\n\n"
        . "#\n"
        . "#      add the above export statement to your ~/.bashrc file to have it set automatically for all future sessions.\n\n"
        . "########################################################\n\n";

    
    return;
}


####
sub ensure_prog_exists {
    my (@progs) = @_;
    
    my $missing = 0;
    for my $prog (@progs) {
        unless (`which $prog` =~ /\w/) {
            $missing += 1;
            print STDERR "-error, cannot locate required utility: $prog, be sure it is installed and available via your PATH env var setting\n";
        }
    }
    if ($missing) {
        confess "Error, missing at least one required utility. See above for specifics.\n";
    }

    return;
}


####
sub Trinotate_RUN_annotators {
    my ($sqlite_db, $run_types_aref, $CPU, $trinotate_data_dir, $transcript_fasta, $transdecoder_pep) = @_;
    
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Supported: 
    #     ALL 
    #     swissprot_blastp 
    #     swissprot_blastx 
    #     pfam 
    #     signalp6 
    #     infernal 
    #     EggnogMapper
    #     tmhmmv2
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    my %run_types = map { $_ => 1 } @$run_types_aref;
    
    
    my @required_utilities = qw(blastp blastx hmmsearch cmscan sqlite3);
    if ($USE_DIAMOND_BLAST_flag) {
        push(@required_utilities, 'diamond');
    }
    &ensure_prog_exists(@required_utilities);
    
    my $pipeliner = new Pipeliner(-verbose => 2, -checkpoint_dir => "__trinotate_run_checkpts");

    ###################
    # swissprot_blastp
    ###################


    if ($run_types{'ALL'} || $run_types{'swissprot_blastp'}) {


        if ($USE_DIAMOND_BLAST_flag) {
            
            &ensure_prog_exists('diamond');
            
            my $cmd = "diamond blastp -d $trinotate_data_dir/uniprot_sprot -q $transdecoder_pep -p $CPU -k 1 -e $EVALUE -o uniprot_sprot.diamond.blastp.outfmt6 --outfmt 6";
            $pipeliner->add_commands(new Command($cmd, "diamond.uniprot_sprot.blastp.ok"));
            
            # load results.
            $cmd = "$0 --db $sqlite_db --LOAD_swissprot_blastp uniprot_sprot.diamond.blastp.outfmt6";
            $pipeliner->add_commands(new Command($cmd, "diamond.uniprot_sprot.blastp.loaded.ok"));
            
        }
        else {
            # default, ncbi blastp
            &ensure_prog_exists('blastp');
            
            my $cmd = "blastp -query $transdecoder_pep -db $trinotate_data_dir/uniprot_sprot.pep -num_threads $CPU  -max_target_seqs 1 -outfmt 6 -evalue $EVALUE > uniprot_sprot.ncbi.blastp.outfmt6";
            $pipeliner->add_commands(new Command($cmd, "ncbi.uniprot_sprot.blastp.ok"));
            
            $cmd = "$0 --db $sqlite_db --LOAD_swissprot_blastp uniprot_sprot.ncbi.blastp.outfmt6";
            $pipeliner->add_commands(new Command($cmd, "ncbi.uniprot_sprot.blastp.loaded.ok"));
            
        }
    }
        
    ######################
    # swissprot_blastx
    ######################

    if ($run_types{'ALL'} || $run_types{'swissprot_blastx'}) {
        
        if ($USE_DIAMOND_BLAST_flag) {

            &ensure_prog_exists('diamond');
            
            my $cmd = "diamond blastx -d $trinotate_data_dir/uniprot_sprot -q $transcript_fasta -p $CPU -k 1 -e $EVALUE -o uniprot_sprot.diamond.blastx.outfmt6 --outfmt 6";
            $pipeliner->add_commands(new Command($cmd, "diamond.uniprot_sprot.blastx.ok"));
            
            # load results.
            $cmd = "$0 --db $sqlite_db --LOAD_swissprot_blastx uniprot_sprot.diamond.blastx.outfmt6";
            $pipeliner->add_commands(new Command($cmd, "diamond.uniprot_sprot.blastx.loaded.ok"));
            
        }
        else {
            # default, ncbi blastx
            
            &ensure_prog_exists('blastx');
            
            my $cmd = "blastx -query $transcript_fasta -db $trinotate_data_dir/uniprot_sprot.pep -num_threads $CPU  -max_target_seqs 1 -outfmt 6 -evalue $EVALUE > uniprot_sprot.ncbi.blastx.outfmt6";
            $pipeliner->add_commands(new Command($cmd, "ncbi.uniprot_sprot.blastx.ok"));
            
            $cmd = "$0 --db $sqlite_db --LOAD_swissprot_blastx uniprot_sprot.ncbi.blastx.outfmt6";
            $pipeliner->add_commands(new Command($cmd, "ncbi.uniprot_sprot.blastx.loaded.ok"));
            
        }
        
    }
    
    #~~~~~~~~~~~~~~~~~~
    # hmmpfam
    #~~~~~~~~~~~~~~~~~

    if ($run_types{'ALL'} || $run_types{'pfam'}) {

        &ensure_prog_exists('hmmsearch');
        
        my $cmd = "hmmsearch --cpu $CPU --noali --domtblout TrinotatePFAM.out $trinotate_data_dir/Pfam-A.hmm $transdecoder_pep > pfam.log";
        $pipeliner->add_commands(new Command($cmd, "pfam_hmmsearch.ok"));

        $cmd = "$0 --db $sqlite_db --LOAD_pfam  TrinotatePFAM.out";
        $pipeliner->add_commands(new Command($cmd, "pfam_hmmsearch_loading.ok"));
        
    }


    #~~~~~~~~~~~~~~~~~~~~~
    # DeepTmHMM
    #~~~~~~~~~~~~~~~~~~~~~

    # can run it locally like so:
    # biolib run --local DTU/DeepTMHMM --fasta Trinity.fasta.transdecoder.pep
    # but it uses docker, and so should be run separately from here (where here may already be in a docker or singularity image)

    
    #if ($run_types{'ALL'} || $run_types{'deeptmhmm'}) {
    #
    #
    #    &ensure_prog_exists('biolib');
    #
    #    my $biolib = `which biolib`;
    #    chomp $biolib;
    #    # why do this?  because biolib itself may have different python in shebang than the one we want to run here.
    #    my $cmd = "python3 $biolib run DTU/DeepTMHMM --fasta $transdecoder_pep";
    #    $pipeliner->add_commands(new Command($cmd, "deep_tmhmm.ok")); 
    #
    #    $cmd = "$0 --db $sqlite_db --LOAD_deeptmhmm biolib_results/TMRs.gff3";
    #    $pipeliner->add_commands(new Command($cmd, "deep_tmhmm.loading.ok")); 
    #}
    

    if ($run_types{'ALL'} || $run_types{'tmhmmv2'}) {
        if (`which tmhmm` =~ /\w/) {

            my $cmd = "tmhmm --short $transdecoder_pep > tmhmm.v2.out";
            $pipeliner->add_commands(new Command($cmd, "tmhmm.v2.ok"));

            $cmd = "$0 --db $sqlite_db --LOAD_tmhmmv2 tmhmm.v2.out";
            $pipeliner->add_commands(new Command($cmd, "tmhmm.v2.loading.ok"));
                        
        }
        else {
            print STDERR "-WARNING: cannot run tmhmm as cannot find it in your PATH setting. Please review tmhmm v2 installation procedures.\n";
            
        }
    }
    
    
    #~~~~~~~~~~~~~~~~~~
    # signalP6
    #~~~~~~~~~~~~~~~~~

    if ($run_types{'ALL'} || $run_types{'signalp6'}) {   

        if (`which signalp6` =~ /\w/) {
            
            my $cmd = "signalp6 --fastafile $transdecoder_pep --output_dir sigP6outdir --format none --organism euk --mode fast";
            $pipeliner->add_commands(new Command($cmd, "sigP6.ok"));

            $cmd = "$0 --db $sqlite_db --LOAD_signalp sigP6outdir/output.gff3";
            $pipeliner->add_commands(new Command($cmd, "sigP6.loading.ok"));
            
        }
        else {
            print STDERR "*** signalp6 not found installed, so skipping signalp6 computes ***\n";
        }
                
        

    }

    #~~~~~~~~~~~~~~~~
    # Infernal
    #~~~~~~~~~~~~~~~~

    
    if ($run_types{'ALL'} || $run_types{'infernal'}) {

        &ensure_prog_exists('cmscan');

        my $Z = max(5, int ( (-s $transcript_fasta)/1e6 + 0.5));
        
        my $cmd = "cmscan -Z $Z --cut_ga --rfam --nohmmonly --tblout infernal.out --fmt 2 --cpu $CPU --clanin $trinotate_data_dir/Rfam.clanin $trinotate_data_dir/Rfam.cm $transcript_fasta > infernal.log";
        $pipeliner->add_commands(new Command($cmd, "infernal.ok"));

        $cmd = "$0 --db $sqlite_db --LOAD_infernal infernal.out";
        $pipeliner->add_commands(new Command($cmd, "infernal.loading.ok"));
        
    }
    

    #~~~~~~~~~~~~~~~
    # EggnogMapper
    #~~~~~~~~~~~~~~~

    if ($run_types{'ALL'} || $run_types{'EggnogMapper'}) {

        my $found_emapper = 1;
        unless (`which emapper.py` =~ /\w/) {
            $found_emapper = 0;
            print STDERR "-cannot run EggnogMapper because can't locate emapper.py   Be sure egnnogmapper is installed and utilities are available via PATH env var\n";
        }

        my $eggnog_data_dir = undef;
        
        if ($found_emapper) {
                        
            if (exists $ENV{EGGNOG_DATA_DIR}) {
                $eggnog_data_dir = $ENV{EGGNOG_DATA_DIR};
            }
            elsif (-d "$ENV{TRINOTATE_DATA_DIR}/EGGNOG_DATA_DIR") {
                $eggnog_data_dir = "$ENV{TRINOTATE_DATA_DIR}/EGGNOG_DATA_DIR";
            }
            else {
                print STDERR "-cannot run EggnogMapper because cannot locate EGGNOG_DATA_DIR\n";
            }
        }

        if ($found_emapper && $eggnog_data_dir) {
            # Run eggnogmapper:
            my $cmd = "emapper.py -i $transdecoder_pep --cpu $CPU --data_dir $eggnog_data_dir -o eggnog_mapper";
            $pipeliner->add_commands(new Command($cmd, "run_eggnogmapper.ok"));

            $cmd = "$0 --db $sqlite_db --LOAD_EggnogMapper eggnog_mapper.emapper.annotations";
            $pipeliner->add_commands(new Command($cmd, "load_eggnogmapper.ok"));
            
        }
            
        
    }
    
    
    # Execute pipeline
    
    $pipeliner->run();

    
}
