sequenceserver 2.0.0.beta4 → 2.0.0.rc5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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