sequenceserver 2.0.0.beta4 → 2.0.0.rc5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +5 -5
  2. data/.dockerignore +1 -0
  3. data/.travis.yml +7 -4
  4. data/AppImage/sequenceserver.sh +5 -0
  5. data/Dockerfile +14 -12
  6. data/bin/sequenceserver +37 -28
  7. data/lib/sequenceserver.rb +35 -7
  8. data/lib/sequenceserver/blast/job.rb +18 -25
  9. data/lib/sequenceserver/blast/report.rb +68 -34
  10. data/lib/sequenceserver/config.rb +1 -1
  11. data/lib/sequenceserver/database.rb +0 -129
  12. data/lib/sequenceserver/makeblastdb.rb +243 -0
  13. data/lib/sequenceserver/routes.rb +28 -2
  14. data/lib/sequenceserver/version.rb +1 -1
  15. data/public/SequenceServer_logo.png +0 -0
  16. data/public/css/grapher.css +8 -15
  17. data/public/css/sequenceserver.css +119 -55
  18. data/public/css/sequenceserver.min.css +3 -3
  19. data/public/js/circos.js +1 -1
  20. data/public/js/download_fasta.js +17 -0
  21. data/public/js/grapher.js +7 -9
  22. data/public/js/hit.js +217 -0
  23. data/public/js/hits_overview.js +12 -13
  24. data/public/js/hsp.js +104 -84
  25. data/public/js/{sequenceserver.js → jquery_world.js} +1 -18
  26. data/public/js/kablammo.js +337 -334
  27. data/public/js/length_distribution.js +1 -1
  28. data/public/js/query.js +147 -0
  29. data/public/js/report.js +216 -836
  30. data/public/js/search.js +194 -192
  31. data/public/js/sequence_modal.js +167 -0
  32. data/public/js/sidebar.js +210 -0
  33. data/public/js/utils.js +2 -19
  34. data/public/js/visualisation_helpers.js +2 -2
  35. data/public/sequenceserver-report.min.js +19 -19
  36. data/public/sequenceserver-search.min.js +11 -11
  37. data/public/vendor/github/twbs/bootstrap@3.3.5/js/bootstrap.js +2 -2
  38. data/spec/blast_versions/blast_2.2.30/import_spec_capybara_local_2.2.30.rb +15 -15
  39. data/spec/blast_versions/blast_2.2.31/import_spec_capybara_local_2.2.31.rb +15 -15
  40. data/spec/blast_versions/blast_2.3.0/import_spec_capybara_local_2.3.0.rb +15 -15
  41. data/spec/blast_versions/blast_2.4.0/import_spec_capybara_local_2.4.0.rb +15 -15
  42. data/spec/blast_versions/blast_2.5.0/import_spec_capybara_local_2.5.0.rb +15 -15
  43. data/spec/blast_versions/blast_2.6.0/import_spec_capybara_local_2.6.0.rb +15 -15
  44. data/spec/blast_versions/blast_2.7.1/import_spec_capybara_local_2.7.1.rb +15 -15
  45. data/spec/blast_versions/blast_2.8.1/import_spec_capybara_local_2.8.1.rb +15 -15
  46. data/spec/blast_versions/blast_2.9.0/import_spec_capybara_local_2.9.0.rb +15 -15
  47. data/spec/blast_versions/diamond_0.9.24/import_spec_capybara_local_0.9.24.rb +6 -6
  48. data/spec/capybara_spec.rb +14 -3
  49. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.ndb +0 -0
  50. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhr +0 -0
  51. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nin +0 -0
  52. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nos +0 -0
  53. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.not +0 -0
  54. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.ntf +0 -0
  55. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nto +0 -0
  56. data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pdb +0 -0
  57. data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phr +0 -0
  58. data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pin +0 -0
  59. data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pos +0 -0
  60. data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pot +0 -0
  61. data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.ptf +0 -0
  62. data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pto +0 -0
  63. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pdb +0 -0
  64. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phr +0 -0
  65. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pin +0 -0
  66. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pos +0 -0
  67. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pot +0 -0
  68. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.ptf +0 -0
  69. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pto +0 -0
  70. data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.ndb +0 -0
  71. data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhr +0 -0
  72. data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nin +0 -0
  73. data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nos +0 -0
  74. data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.not +0 -0
  75. data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsq +0 -0
  76. data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.ntf +0 -0
  77. data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nto +0 -0
  78. data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhd +8 -0
  79. data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhi +0 -0
  80. data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhr +0 -0
  81. data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nin +0 -0
  82. data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nog +0 -0
  83. data/spec/database/{sample → v4}/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsd +0 -0
  84. data/spec/database/{sample → v4}/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsi +0 -0
  85. data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsq +0 -0
  86. data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.txt +8 -0
  87. data/spec/database/v4/links.rb +23 -0
  88. data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta +6449 -0
  89. data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phd +1189 -0
  90. data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phi +0 -0
  91. data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phr +0 -0
  92. data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pin +0 -0
  93. data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pog +0 -0
  94. data/spec/database/{sample → v4}/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.psd +0 -0
  95. data/spec/database/{sample → v4}/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.psi +0 -0
  96. data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.psq +0 -0
  97. data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phd +9140 -0
  98. data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phi +0 -0
  99. data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phr +0 -0
  100. data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pin +0 -0
  101. data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pog +0 -0
  102. data/spec/database/{sample → v4}/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psd +0 -0
  103. data/spec/database/{sample → v4}/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psi +0 -0
  104. data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psq +0 -0
  105. data/spec/database/v4/proteins/uniprot/URL +1 -0
  106. data/spec/database/v4/si_uniprot_idmap.yml +14180 -0
  107. data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta +5486 -0
  108. data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhd +473 -0
  109. data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhi +0 -0
  110. data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhr +0 -0
  111. data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nin +0 -0
  112. data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nog +0 -0
  113. data/spec/database/{sample → v4}/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsd +0 -0
  114. data/spec/database/{sample → v4}/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsi +0 -0
  115. data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsq +0 -0
  116. data/spec/database_spec.rb +0 -76
  117. data/spec/makeblastdb_spec.rb +121 -0
  118. data/views/layout.erb +5 -1
  119. metadata +75 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a8617ffb07710b984f84dfc0dfb7d43c66cac4c3
4
- data.tar.gz: 14ddad09e8dcb15793d8e06227138ee4c862b280
2
+ SHA256:
3
+ metadata.gz: b04c2f43509bf7d4a15d555e3bd9cea86d3c7770c7a3e35016f963f877055ecf
4
+ data.tar.gz: 25678397eacb2c3f445902624baff80a90d2a47ca98d2b703e13de3eca84cf1e
5
5
  SHA512:
6
- metadata.gz: c130d6e3828eae5dae108786e08433d5641112305962884dc2dada918a6a92c17632f7c46400c58ea0adabf106cb02e348bf6adc35dc8cbf296300081221fc99
7
- data.tar.gz: 17a41dcb923c2e64337b960de1e3717b458077a9658a9e7785ab5815c43860aff09033aacd7812146e0f1fe368878f649794b1aa5bd8bbaf13c8a4a34fe7b0ac
6
+ metadata.gz: a8e6a4c1b4917d9bd35d07ef8e580e1b75105bfd1709fb892d9ed523da91f8c3a08d50c1c9da304530cd0bb5d77da00a4944c65cd5ce90fc979c9d6099149058
7
+ data.tar.gz: ef493ec4cf1aef63b2f535251143b34154d0d332a47a1d15668c7a74b139d5e6c2a2f9c33b5c7072ae9c2fbbcf33048fad4e828273c85a199a6ab79874d6e766
@@ -0,0 +1 @@
1
+ _site
@@ -24,14 +24,17 @@ before_install:
24
24
  - wget -c "https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-linux64.tar.gz" && tar xvf geckodriver-*.tar.gz -C bin
25
25
  # Download codeclimate test reporter to bin and make it executable
26
26
  - wget -c "https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64" -O bin/cc-test-reporter && chmod +x bin/cc-test-reporter
27
- # Download and extract NCBI BLAST+ 2.9.0
28
- - wget -c "ftp://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/2.9.0/ncbi-blast-2.9.0+-x64-linux.tar.gz" && tar xvf ncbi-blast-*.tar.gz
27
+ # Download and extract NCBI BLAST+ 2.10.0
28
+ - wget -c "ftp://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/2.10.0/ncbi-blast-2.10.0+-x64-linux.tar.gz" && tar xvf ncbi-blast-*.tar.gz
29
29
  # Conclude installation by adding opt/bin/ containing codeclimate test reporter
30
- # and geckodriver, and opt/ncbi-blast-2.9.0+/bin containing BLAST+ binaries to
30
+ # and geckodriver, and opt/ncbi-blast-2.10.0+/bin containing BLAST+ binaries to
31
31
  # PATH.
32
- - export PATH="$PWD/bin:$PWD/ncbi-blast-2.9.0+/bin:$PATH"
32
+ - export PATH="$PWD/bin:$PWD/ncbi-blast-2.10.0+/bin:$PATH"
33
33
  # Reset working directory or subsequent steps may fail.
34
34
  - cd ..
35
+ # Update bundler. Travis was using bundler 1.16.2 at the time of this writing
36
+ # and the builds were failing because Gemfile.lock requires bundler > 2.0
37
+ - gem install bundler -v 2.1.4
35
38
 
36
39
  env:
37
40
  global:
@@ -1,3 +1,8 @@
1
+ # cd back to the directory where the AppImage was launched from. AppRun changes
2
+ # the working directory so as to work with binaries that have /usr hard-coded;
3
+ # we don't.
4
+ cd $OWD
5
+
1
6
  # Set GEM_PATH to where we installed gems in the AppImage.
2
7
  export GEM_PATH=$APPDIR/var/lib/gems/2.3.0
3
8
 
data/Dockerfile CHANGED
@@ -1,23 +1,25 @@
1
- FROM debian:stretch-backports
1
+ FROM debian:buster-slim
2
2
 
3
3
  LABEL Description="Intuitive local web frontend for the BLAST bioinformatics tool"
4
4
  LABEL MailingList="https://groups.google.com/forum/#!forum/sequenceserver"
5
5
  LABEL Website="http://www.sequenceserver.com"
6
- LABEL Version="1.1.0 beta"
7
6
 
8
- RUN apt-get update && apt-get install -y --no-install-recommends \
9
- build-essential \
10
- ruby ruby-dev \
11
- curl wget \
12
- gnupg \
13
- git \
14
- zlib1g-dev
7
+ RUN apt-get update && apt-get install -y --no-install-recommends \
8
+ ruby ruby-dev build-essential curl gnupg git wget \
9
+ zlib1g-dev && rm -rf /var/lib/apt/lists/*
15
10
 
16
11
  VOLUME ["/db"]
17
12
  EXPOSE 4567
18
13
 
19
14
  COPY . /sequenceserver
20
15
  WORKDIR /sequenceserver
21
- RUN gem install bundler && bundle install --without=development
22
- RUN yes '' | bundle exec bin/sequenceserver -s
23
- ENTRYPOINT ["bundle", "exec", "bin/sequenceserver", "-d", "/db"]
16
+ # Install bundler, then use bundler to install SequenceServer's dependencies,
17
+ # and then use SequenceServer to install BLAST. In the last step, -s is used
18
+ # so that SequenceServer will exit after writing configuration file instead
19
+ # of starting up, while -d is used to suppress questions about database dir.
20
+ RUN gem install bundler && \
21
+ bundle install --without=development && \
22
+ yes '' | bundle exec bin/sequenceserver -s -d spec/database/sample
23
+ RUN touch ~/.sequenceserver/asked_to_join
24
+
25
+ CMD ["bundle", "exec", "bin/sequenceserver", "-d", "/db"]
@@ -20,6 +20,30 @@ def download_from_url(url)
20
20
  system(cmd)
21
21
  end
22
22
 
23
+ def ask_to_join
24
+ asked_to_join = File.join(SequenceServer::DOTDIR, 'asked_to_join')
25
+ unless File.exist?(asked_to_join)
26
+ puts
27
+ puts <<~MSG
28
+ Do you want to be notified of SequenceServer releases and any
29
+ other important announcements (3-12 messages a year)? If yes,
30
+ please provide your email address below or press enter to
31
+ continue (you won't be prompted again).
32
+ MSG
33
+ print '>> '
34
+ response = STDIN.gets.to_s.strip
35
+ puts
36
+
37
+ if response =~ /@/
38
+ post_email_cmd = "curl -m 5 https://docs.google.com/forms/u/0/d/e/" \
39
+ "1FAIpQLSe7sOCiKzYbI7LwErid-g3wfIU5Zpi6VTm0ILJyR036RqC8zg/formResponse " \
40
+ "-d ifq -d emailAddress=#{response} -d submit=Submit > /dev/null 2> /dev/null"
41
+ system post_email_cmd
42
+ end
43
+ system "touch #{asked_to_join}"
44
+ end
45
+ end
46
+
23
47
  begin
24
48
  Slop.parse!(strict: true, help: true) do
25
49
  banner <<~BANNER
@@ -44,10 +68,6 @@ begin
44
68
  # of threads to use in config file.
45
69
  $ sequenceserver -s -n 16
46
70
 
47
- # See if you have FASTA files in database dir that haven't
48
- # been converted into BLAST database.
49
- $ sequenceserver -u
50
-
51
71
  # Search for FASTA files in database dir that haven't been
52
72
  # converted into BLAST database yet, and convert them.
53
73
  $ sequenceserver -m
@@ -111,9 +131,6 @@ begin
111
131
  on 'l', 'list_databases',
112
132
  'List BLAST databases'
113
133
 
114
- on 'u', 'list-unformatted-fastas',
115
- 'List unformatted FASTA files'
116
-
117
134
  on 'i', 'interactive',
118
135
  'Run SequenceServer in interactive mode'
119
136
 
@@ -261,8 +278,7 @@ begin
261
278
  fetch_option(:database_dir).value = response
262
279
  redo
263
280
  rescue SequenceServer::NO_BLAST_DATABASE_FOUND => e
264
- unless list_databases? || list_unformatted_fastas? ||
265
- make_blast_databases?
281
+ unless list_databases? || make_blast_databases?
266
282
 
267
283
  # Print error raised.
268
284
  puts
@@ -281,13 +297,13 @@ begin
281
297
  unless response =~ /^[n]$/i
282
298
  puts
283
299
  puts 'Searching ...'
284
- if SequenceServer::Database.unformatted_fastas.empty?
285
- puts "Couldn't find any FASTA files."
286
- exit!
287
- else
288
- formatted = SequenceServer::Database.make_blast_databases
300
+ if SequenceServer.makeblastdb.scan
301
+ formatted = SequenceServer.makeblastdb.run
289
302
  exit! if formatted.empty? && !set?
290
303
  redo unless set?
304
+ else
305
+ puts "Couldn't find any FASTA files."
306
+ exit!
291
307
  end
292
308
  else
293
309
  exit! unless set?
@@ -337,22 +353,13 @@ begin
337
353
  exit
338
354
  end
339
355
 
340
- if list_unformatted_fastas? || make_blast_databases?
341
- unformatted_fastas = SequenceServer::Database.unformatted_fastas
342
- if unformatted_fastas.empty?
356
+ if make_blast_databases?
357
+ if SequenceServer.makeblastdb.scan
358
+ SequenceServer.makeblastdb.run
359
+ else
343
360
  puts "All FASTA files in #{SequenceServer.config[:database_dir]} " \
344
361
  'are formatted.'
345
- exit
346
362
  end
347
- end
348
-
349
- if list_unformatted_fastas?
350
- puts unformatted_fastas
351
- exit
352
- end
353
-
354
- if make_blast_databases?
355
- SequenceServer::Database.make_blast_databases
356
363
  exit
357
364
  end
358
365
 
@@ -379,6 +386,8 @@ begin
379
386
 
380
387
  SequenceServer.config.write_config_file if fetch_option(:set).value
381
388
 
389
+ ask_to_join
390
+
382
391
  SequenceServer.run
383
392
  end
384
393
  end
@@ -386,4 +395,4 @@ rescue Slop::Error => e
386
395
  puts e
387
396
  puts "Run '#{$PROGRAM_NAME} -h' for help with command line options."
388
397
  exit
389
- end
398
+ end
@@ -4,8 +4,12 @@ require 'resolv'
4
4
 
5
5
  # Top level module / namespace.
6
6
  module SequenceServer
7
- # Use a fixed minimum version of BLAST+
8
- BLAST_VERSION = '2.9.0+'.freeze
7
+ # The default version of BLAST that will be downloaded and configured for use.
8
+ BLAST_VERSION = '2.10.0+'.freeze
9
+ # The minimum version of BLAST that SequenceServer is happy to run with. This
10
+ # is for compatiblity with older database formats. Users will download BLAST
11
+ # themselves.
12
+ MIN_BLAST_VERSION = '2.9.0+'.freeze
9
13
 
10
14
  # Default location of configuration file.
11
15
  DEFAULT_CONFIG_FILE = '~/.sequenceserver.conf'.freeze
@@ -20,6 +24,7 @@ module SequenceServer
20
24
  require 'sequenceserver/config'
21
25
  require 'sequenceserver/server'
22
26
  require 'sequenceserver/routes'
27
+ require 'sequenceserver/makeblastdb'
23
28
  require 'sequenceserver/job_remover'
24
29
  require 'sequenceserver/exceptions'
25
30
  require 'sequenceserver/sys'
@@ -53,6 +58,11 @@ module SequenceServer
53
58
  end
54
59
  end
55
60
 
61
+ # MAKEBLASTDB service object.
62
+ def makeblastdb
63
+ @makeblastdb ||= MAKEBLASTDB.new(config[:database_dir])
64
+ end
65
+
56
66
  # SequenceServer initialisation routine.
57
67
  def init(config = {})
58
68
  # Use default config file if caller didn't specify one.
@@ -138,10 +148,14 @@ module SequenceServer
138
148
  puts
139
149
  puts '** Thank you for using SequenceServer :).'
140
150
  puts ' Please cite: '
141
- puts ' Priyam A, Woodcroft BJ, Rai V, Munagala A, Moghul I, Ter F,'
142
- puts ' Gibbins MA, Moon H, Leonard G, Rumpf W & Wurm Y. 2015.'
143
- puts ' Sequenceserver: a modern graphical user interface for'
144
- puts ' custom BLAST databases. biorxiv doi: 10.1101/033142.'
151
+ puts ' Priyam A, Woodcroft BJ, Rai V, Moghul I, Munagala A, Ter F,'
152
+ puts ' Chowdhary H, Pieniak I, Maynard LJ, Gibbins MA, Moon H,'
153
+ puts ' Davis-Richardson A, Uludag M, Watson-Haigh N, Challis R,'
154
+ puts ' Nakamura H, Favreau E, Gómez EA, Pluskal T, Leonard G,'
155
+ puts ' Rumpf W & Wurm Y.'
156
+ puts ' Sequenceserver: A modern graphical user interface for'
157
+ puts ' custom BLAST databases.'
158
+ puts ' Molecular Biology and Evolution (2019)'
145
159
  end
146
160
 
147
161
  # This method is invoked by the -i switch to start an IRB shell with
@@ -230,7 +244,7 @@ module SequenceServer
230
244
  end
231
245
  version = out.split[1]
232
246
  fail BLAST_NOT_INSTALLED_OR_NOT_EXECUTABLE if version.empty?
233
- fail BLAST_NOT_COMPATIBLE, version unless version == BLAST_VERSION
247
+ fail BLAST_NOT_COMPATIBLE, version unless is_compatible(version, MIN_BLAST_VERSION)
234
248
  end
235
249
 
236
250
  def server_url
@@ -281,5 +295,19 @@ module SequenceServer
281
295
  def command?(command)
282
296
  system("which #{command} > /dev/null 2>&1")
283
297
  end
298
+
299
+ # Returns true if the given version is higher than the minimum expected
300
+ # version string.
301
+ def is_compatible(given, expected)
302
+ # The speceship operator (<=>) below returns -1, 0, 1 depending on
303
+ # on whether the left operand is lower, same, or higher than the
304
+ # right operand. We want the left operand to be the same or higher.
305
+ (parse_version(given) <=> parse_version(expected)) >= 0
306
+ end
307
+
308
+ # Turn version string into an arrary of its component numbers.
309
+ def parse_version(version_string)
310
+ version_string.split('.').map(&:to_i)
311
+ end
284
312
  end
285
313
  end
@@ -13,7 +13,6 @@ module SequenceServer
13
13
  # itself is self-contained. This will help with tests among
14
14
  # other things.
15
15
  FileUtils.cp(params[:xml], dir)
16
- @advanced_params = {}
17
16
  @databases = []
18
17
  done!
19
18
  end
@@ -23,17 +22,19 @@ module SequenceServer
23
22
  @method = params[:method]
24
23
  @qfile = store('query.fa', params[:sequence])
25
24
  @databases = Database[params[:databases]]
26
- @options = params[:advanced].to_s.strip + defaults
27
- @advanced_params = parse_advanced params[:advanced]
25
+ @advanced = params[:advanced].to_s.strip
26
+ @options = @advanced + defaults
28
27
  end
29
28
  end
30
29
  end
31
30
 
32
- attr_reader :advanced_params
33
-
34
31
  # :nodoc:
35
32
  # Attributes used by us - should be considered private.
36
- attr_reader :method, :qfile, :databases, :options
33
+ attr_reader :method, :qfile, :databases, :advanced, :options
34
+
35
+ # :nodoc:
36
+ # Deprecated; see Report#extract_params
37
+ attr_reader :advanced_params
37
38
 
38
39
  # :nodoc:
39
40
  # Returns path to the imported xml file if the job was created using the
@@ -64,6 +65,16 @@ module SequenceServer
64
65
  error = IO.foreach(stderr).grep(ERROR_LINE).join
65
66
  error = File.read(stderr) if error.empty?
66
67
  fail InputError, error
68
+ when 2
69
+ fail InputError, <<~MSG
70
+ BLAST signalled a problem with the databases that you searched.
71
+
72
+ Most likely one or more of your databases were created using an
73
+ older version of BLAST. Please consider recreating the databases
74
+ using BLAST #{BLAST_VERSION}.
75
+
76
+ As a temporary solution, you can try searching one database at a time.
77
+ MSG
67
78
  when 4
68
79
  # Out of memory. User can retry with a shorter search, so raising
69
80
  # InputError here instead of SystemError.
@@ -78,7 +89,7 @@ module SequenceServer
78
89
  # the job. This is a SystemError.
79
90
  fail SystemError, 'Ran out of disk space.'
80
91
  else
81
- # I am not sure what the exit codes 2 & 3 means and we should note
92
+ # I am not sure what the exit codes 3 means and we should not
82
93
  # encounter exit code 5. The only other error that I know can happen
83
94
  # but is not yet handled is when BLAST+ binaries break such as after
84
95
  # macOS updates. So raise SystemError, include the exit status in the
@@ -94,24 +105,6 @@ module SequenceServer
94
105
 
95
106
  private
96
107
 
97
- def parse_advanced(param_line)
98
- param_list = (param_line || '').split(' ')
99
- res = {}
100
-
101
- param_list.each_with_index do |word, i|
102
- nxt = param_list[i + 1]
103
- if word.start_with? '-'
104
- word.sub!('-', '')
105
- unless nxt.nil? || nxt.start_with?('-')
106
- res[word] = nxt
107
- else
108
- res[word] = 'True'
109
- end
110
- end
111
- end
112
- res
113
- end
114
-
115
108
  def validate(params)
116
109
  validate_method params[:method]
117
110
  validate_sequences params[:sequence]
@@ -24,34 +24,15 @@ module SequenceServer
24
24
  class Report < Report
25
25
  def initialize(job)
26
26
  super do
27
- @querydb = job.databases
28
27
  @queries = []
29
28
  end
30
29
  end
31
30
 
32
- # Attributes parsed out from XML output.
33
- attr_reader :program, :program_version, :params, :stats, :queries
34
-
35
- # This is obtained from the job object.
36
- attr_reader :querydb
31
+ # Attributes parsed out from BLAST output.
32
+ attr_reader :program, :program_version, :stats, :queries
37
33
 
38
- # Returns database type (nucleotide or protein) used for running BLAST
39
- # search. If we ran the BLAST search, this information is available
40
- # from Job#databases. For imported XML, this is inferred from
41
- # Report#program (i.e., the BLAST algorithm)
42
- def dbtype
43
- return @dbtype if @dbtype
44
- @dbtype = if @querydb.empty?
45
- case program
46
- when /blastn|tblastn|tblastx/
47
- 'nucleotide'
48
- when /blastp|blastx/
49
- 'protein'
50
- end
51
- else
52
- @querydb.first.type
53
- end
54
- end
34
+ # Attributes parsed from job metadata and BLAST output.
35
+ attr_reader :querydb, :dbtype, :params
55
36
 
56
37
  def to_json
57
38
  [:querydb, :program, :program_version, :params, :stats,
@@ -60,7 +41,8 @@ module SequenceServer
60
41
  h
61
42
  }.update(search_id: job.id,
62
43
  submitted_at: job.submitted_at.utc,
63
- imported_xml: !!job.imported_xml_file).to_json
44
+ imported_xml: !!job.imported_xml_file,
45
+ seqserv_version: SequenceServer::VERSION).to_json
64
46
  end
65
47
 
66
48
  private
@@ -68,6 +50,8 @@ module SequenceServer
68
50
  # Generate report.
69
51
  def generate
70
52
  job.raise!
53
+ xml_ir = nil
54
+ tsv_ir = nil
71
55
  if job.imported_xml_file
72
56
  xml_ir = parse_xml File.read(job.imported_xml_file)
73
57
  tsv_ir = Hash.new do |h1,k1|
@@ -75,18 +59,15 @@ module SequenceServer
75
59
  h2[k2]=['','',[]]
76
60
  end
77
61
  end
78
- extract_program_info xml_ir
79
- extract_params xml_ir
80
- extract_stats xml_ir
81
- extract_queries xml_ir, tsv_ir
82
62
  else
83
63
  xml_ir = parse_xml File.read(Formatter.run(job, 'xml').file)
84
- tsv_ir = parse_tsv File.read(Formatter.run(job, 'custom_tsv').file )
85
- extract_program_info xml_ir
86
- extract_params xml_ir
87
- extract_stats xml_ir
88
- extract_queries xml_ir, tsv_ir
64
+ tsv_ir = parse_tsv File.read(Formatter.run(job, 'custom_tsv').file)
89
65
  end
66
+ extract_program_info xml_ir
67
+ extract_db_info xml_ir
68
+ extract_params xml_ir
69
+ extract_stats xml_ir
70
+ extract_queries xml_ir, tsv_ir
90
71
  end
91
72
 
92
73
  # Make program name and program name + version available via `program`
@@ -96,6 +77,20 @@ module SequenceServer
96
77
  @program_version = ir[1]
97
78
  end
98
79
 
80
+ # Get database information (title and type) from job yaml or from XML.
81
+ # Sets `querydb` and `dbtype` attributes.
82
+ def extract_db_info(ir)
83
+ if job.databases.empty?
84
+ @querydb = ir[3].split.map do |path|
85
+ { title: File.basename(path) }
86
+ end
87
+ @dbtype = dbtype_from_program
88
+ else
89
+ @querydb = job.databases
90
+ @dbtype = @querydb.first.type
91
+ end
92
+ end
93
+
99
94
  # Make search params available via `params` attribute.
100
95
  #
101
96
  # Search params tweak the results. Like evalue cutoff or penalty to open
@@ -103,11 +98,20 @@ module SequenceServer
103
98
  # matrix, evalue, gapopen, gapextend, and filters are available from XML
104
99
  # output.
105
100
  def extract_params(ir)
101
+ # Parse/get params from the job first.
102
+ job_params = parse_advanced(job.advanced)
103
+ # Old jobs from beta releases may not have the advanced key but they
104
+ # will have the deprecated advanced_params key.
105
+ job_params.update(job.advanced_params) if job.advanced_params
106
+
107
+ # Parse params from BLAST XML.
106
108
  @params = Hash[
107
109
  *ir[7].first.map { |k, v| [k.gsub('Parameters_', ''), v] }.flatten
108
110
  ]
109
111
  @params['evalue'] = @params.delete('expect')
110
- @params = job.advanced_params.merge(@params)
112
+
113
+ # Merge into job_params.
114
+ @params = job_params.merge(@params)
111
115
  end
112
116
 
113
117
  # Make search stats available via `stats` attribute.
@@ -232,6 +236,36 @@ module SequenceServer
232
236
  end
233
237
  ir
234
238
  end
239
+
240
+ # Parse BLAST CLI string from job.advanced.
241
+ def parse_advanced(param_line)
242
+ param_list = (param_line || '').split(' ')
243
+ res = {}
244
+
245
+ param_list.each_with_index do |word, i|
246
+ nxt = param_list[i + 1]
247
+ if word.start_with? '-'
248
+ word.sub!('-', '')
249
+ unless nxt.nil? || nxt.start_with?('-')
250
+ res[word] = nxt
251
+ else
252
+ res[word] = 'True'
253
+ end
254
+ end
255
+ end
256
+ res
257
+ end
258
+
259
+ # Returns database type (nucleotide or protein) inferred from
260
+ # Report#program (i.e., the BLAST algorithm)
261
+ def dbtype_from_program
262
+ case program
263
+ when /blastn|tblastn|tblastx/
264
+ 'nucleotide'
265
+ when /blastp|blastx/
266
+ 'protein'
267
+ end
268
+ end
235
269
  end
236
270
  end
237
271
  end