module GeneValidatorApp
Define Config
class.
This file defines all possible exceptions that can be thrown by GeneValidatorApp
on startup.
Exceptions only ever inform another entity (downstream code or users) of an issue. Exceptions may or may not be recoverable.
Error classes should be seen as: the error code (class name), human readable message (to_s method), and necessary attributes to act on the error.
We define as many error classes as needed to be precise about the issue, thus making it easy for downstream code (bin/genevalidatorapp or config.ru) to act on them.
Constants
- MINIMUM_BLAST_VERSION
Use a fixed minimum version of BLAST+
- VERSION
Attributes
Public Class Methods
Rack-interface.
Inject our logger in the env and dispatch request to our controller.
# File lib/genevalidatorapp.rb, line 90 def call(env) env['rack.logger'] = logger Routes.call(env) end
# File lib/genevalidatorapp.rb, line 18 def environment ENV['RACK_ENV'] end
Setting up the environment before running the app…
# File lib/genevalidatorapp.rb, line 39 def init(config = {}) @config = Config.new(config) init_binaries init_database init_dirs load_extension check_num_threads check_max_characters self end
# File lib/genevalidatorapp.rb, line 34 def logger @logger ||= Logger.new(STDERR, verbose?) end
# File lib/genevalidatorapp.rb, line 71 def on_start puts '** GeneValidator is ready.' puts " Go to #{server_url} in your browser and start analysing genes!" puts ' Press CTRL+C to quit.' open_in_browser(server_url) end
# File lib/genevalidatorapp.rb, line 78 def on_stop puts puts '** Thank you for using GeneValidator :).' puts ' Please cite: ' puts ' Dragan M, Moghul MI, Priyam A, Bustos C, Wurm Y. 2016.' puts ' GeneValidator: identify problems with protein-coding gene' puts ' predictions. Bioinformatics, doi: 10.1093/bioinformatics/btw015.' end
# File lib/genevalidatorapp.rb, line 26 def root File.dirname(File.dirname(__FILE__)) end
Starting the app manually
# File lib/genevalidatorapp.rb, line 56 def run check_host Server.run(self) rescue Errno::EADDRINUSE puts "** Could not bind to port #{config[:port]}." puts " Is GeneValidator already accessible at #{server_url}?" puts ' No? Try running GeneValidator on another port, like so:' puts puts ' genevalidator app -p 4570.' rescue Errno::EACCES puts "** Need root privilege to bind to port #{config[:port]}." puts ' It is not advisable to run GeneValidator as root.' puts ' Please use Apache/Nginx to bind to a privileged port.' end
# File lib/genevalidatorapp.rb, line 30 def ssl? @config[:ssl] end
# File lib/genevalidatorapp.rb, line 22 def verbose? @verbose ||= (environment == 'development') end
Private Class Methods
# File lib/genevalidatorapp.rb, line 156 def assert_blast_databases_present_in_database_dir cmd = "blastdbcmd -recursive -list '#{config[:database_dir]}'" out = `#{cmd}` errpat = /BLAST Database error/ raise NO_BLAST_DATABASE_FOUND, config[:database_dir] if out.empty? raise BLAST_DATABASE_ERROR, cmd, out if out.match(errpat) || !$CHILD_STATUS.success? type = [] out.lines.each { |l| type << l.split[1] } return if type.include? 'Protein' raise NO_PROTEIN_BLAST_DATABASE_FOUND, config[:database_dir] end
# File lib/genevalidatorapp.rb, line 208 def assert_blast_installed_and_compatible raise BLAST_NOT_INSTALLED unless command? 'blastdbcmd' version = `blastdbcmd -version`.split[1] return if is_compatible(version, MINIMUM_BLAST_VERSION) raise BLAST_NOT_COMPATIBLE, version end
# File lib/genevalidatorapp.rb, line 215 def assert_mafft_installed raise MAFFT_NOT_INSTALLED unless command? 'mafft' end
Check and warn user if host is 0.0.0.0 (default).
# File lib/genevalidatorapp.rb, line 220 def check_host return unless config[:host] == '0.0.0.0' logger.warn 'Will listen on all interfaces (0.0.0.0).' \ ' Consider using 127.0.0.1 (--host option).' end
# File lib/genevalidatorapp.rb, line 181 def check_max_characters if config[:max_characters] != 'undefined' config[:max_characters] = Integer(config[:max_characters]) end rescue StandardError raise MAX_CHARACTERS_INCORRECT end
# File lib/genevalidatorapp.rb, line 169 def check_num_threads num_threads = Integer(config[:num_threads]) raise NUM_THREADS_INCORRECT unless num_threads > 0 logger.debug "Will use #{num_threads} threads to run BLAST." if num_threads > 256 logger.warn "Number of threads set at #{num_threads} is unusually high." end rescue StandardError raise NUM_THREADS_INCORRECT end
Return `true` if the given command exists and is executable.
# File lib/genevalidatorapp.rb, line 250 def command?(command) system("which #{command} > /dev/null 2>&1") end
Checks if dir is in $PATH and if not, it adds the dir to the $PATH.
# File lib/genevalidatorapp.rb, line 202 def export_bin_dir(bin_dir) return unless bin_dir return if ENV['PATH'].split(':').include?(bin_dir) ENV['PATH'] = "#{bin_dir}:#{ENV['PATH']}" end
# File lib/genevalidatorapp.rb, line 114 def init_binaries config[:bin] = init_bins if config[:bin] assert_blast_installed_and_compatible assert_mafft_installed end
# File lib/genevalidatorapp.rb, line 189 def init_bins bins = [] Array(config[:bin]).each do |bin| bins << File.expand_path(bin) unless File.exist?(bin) && File.directory?(bin) raise BIN_DIR_NOT_FOUND, config[:bin] end export_bin_dir(bin) end bins end
# File lib/genevalidatorapp.rb, line 120 def init_database set_database_from_env unless config[:database_dir] raise DATABASE_DIR_NOT_SET unless config[:database_dir] config[:database_dir] = File.expand_path(config[:database_dir]) unless File.exist?(config[:database_dir]) && File.directory?(config[:database_dir]) raise DATABASE_DIR_NOT_FOUND, config[:database_dir] end assert_blast_databases_present_in_database_dir logger.debug("Will use BLAST+ databases at: #{config[:database_dir]}") Database.scan_databases_dir Database.each do |database| logger.debug("Found #{database.type.chomp} database" \ " '#{database.title.chomp}' at '#{database.name.chomp}'") end end
# File lib/genevalidatorapp.rb, line 97 def init_dirs config[:serve_public_dir] = File.expand_path(config[:serve_public_dir]) unique_start_id = 'GV_' + Time.now.strftime('%Y%m%d-%H-%M-%S').to_s @public_dir = File.join(config[:serve_public_dir], unique_start_id) init_public_dir end
Create the Public Dir and copy files from gem root - this public dir
is served by the app is accessible at URL/...
# File lib/genevalidatorapp.rb, line 106 def init_public_dir FileUtils.mkdir_p(File.join(@public_dir, 'GeneValidator')) root_web_files = File.join(GeneValidatorApp.root, 'public/web_files') root_gv = File.join(GeneValidatorApp.root, 'public/GeneValidator') FileUtils.cp_r(root_web_files, @public_dir) FileUtils.cp_r(root_gv, @public_dir) end
Returns true if the given version is higher than the minimum expected version string.
# File lib/genevalidatorapp.rb, line 256 def is_compatible(given, expected) # The speceship operator (<=>) below returns -1, 0, 1 depending on # on whether the left operand is lower, same, or higher than the # right operand. We want the left operand to be the same or higher. (parse_version(given) <=> parse_version(expected)) >= 0 end
# File lib/genevalidatorapp.rb, line 145 def load_extension return unless config[:require] config[:require] = File.expand_path config[:require] unless File.exist?(config[:require]) && File.file?(config[:require]) raise EXTENSION_FILE_NOT_FOUND, config[:require] end logger.debug("Loading extension: #{config[:require]}") require config[:require] end
# File lib/genevalidatorapp.rb, line 232 def open_in_browser(server_url) return if using_ssh? || verbose? if RUBY_PLATFORM =~ /linux/ && xdg? `xdg-open #{server_url}` elsif RUBY_PLATFORM =~ /darwin/ `open #{server_url}` end end
Turn version string into an arrary of its component numbers.
# File lib/genevalidatorapp.rb, line 264 def parse_version(version_string) version_string.split('.').map(&:to_i) end
# File lib/genevalidatorapp.rb, line 226 def server_url host = config[:host] host = 'localhost' if host == '127.0.0.1' || host == '0.0.0.0' "http://#{host}:#{config[:port]}" end
attempt to set the database dir to GV_BLAST_DB_DIR if it exists
# File lib/genevalidatorapp.rb, line 141 def set_database_from_env config[:database_dir] = ENV['GV_BLAST_DB_DIR'] end
# File lib/genevalidatorapp.rb, line 241 def using_ssh? true if ENV['SSH_CLIENT'] || ENV['SSH_TTY'] || ENV['SSH_CONNECTION'] end
# File lib/genevalidatorapp.rb, line 245 def xdg? true if ENV['DISPLAY'] && command?('xdg-open') end