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

config[R]
public_dir[R]
temp_dir[R]

Public Class Methods

call(env) click to toggle source

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
environment() click to toggle source
# File lib/genevalidatorapp.rb, line 18
def environment
  ENV['RACK_ENV']
end
init(config = {}) click to toggle source

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
logger() click to toggle source
# File lib/genevalidatorapp.rb, line 34
def logger
  @logger ||= Logger.new(STDERR, verbose?)
end
on_start() click to toggle source
# 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
on_stop() click to toggle source
# 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
root() click to toggle source
# File lib/genevalidatorapp.rb, line 26
def root
  File.dirname(File.dirname(__FILE__))
end
run() click to toggle source

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
ssl?() click to toggle source
# File lib/genevalidatorapp.rb, line 30
def ssl?
  @config[:ssl]
end
verbose?() click to toggle source
# File lib/genevalidatorapp.rb, line 22
def verbose?
  @verbose ||= (environment == 'development')
end

Private Class Methods

assert_blast_databases_present_in_database_dir() click to toggle source
# 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
assert_blast_installed_and_compatible() click to toggle source
# 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
assert_mafft_installed() click to toggle source
# File lib/genevalidatorapp.rb, line 215
def assert_mafft_installed
  raise MAFFT_NOT_INSTALLED unless command? 'mafft'
end
check_host() click to toggle source

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
check_max_characters() click to toggle source
# 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
check_num_threads() click to toggle source
# 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
command?(command) click to toggle source

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
export_bin_dir(bin_dir) click to toggle source

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
init_binaries() click to toggle source
# 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
init_bins() click to toggle source
# 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
init_database() click to toggle source
# 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
init_dirs() click to toggle source
# 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
init_public_dir() click to toggle source

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
is_compatible(given, expected) click to toggle source

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
load_extension() click to toggle source
# 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
open_in_browser(server_url) click to toggle source
# 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
parse_version(version_string) click to toggle source

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
server_url() click to toggle source
# 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
set_database_from_env() click to toggle source

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
using_ssh?() click to toggle source
# File lib/genevalidatorapp.rb, line 241
def using_ssh?
  true if ENV['SSH_CLIENT'] || ENV['SSH_TTY'] || ENV['SSH_CONNECTION']
end
xdg?() click to toggle source
# File lib/genevalidatorapp.rb, line 245
def xdg?
  true if ENV['DISPLAY'] && command?('xdg-open')
end