sequenceserver 1.1.0.beta2 → 1.1.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +16 -5
  3. data/README.md +3 -0
  4. data/lib/sequenceserver/api_errors.rb +67 -0
  5. data/lib/sequenceserver/blast/constants.rb +1 -1
  6. data/lib/sequenceserver/blast/formatter.rb +4 -2
  7. data/lib/sequenceserver/blast/job.rb +17 -62
  8. data/lib/sequenceserver/blast/report.rb +15 -2
  9. data/lib/sequenceserver/blast.rb +1 -0
  10. data/lib/sequenceserver/exceptions.rb +2 -3
  11. data/lib/sequenceserver/job.rb +72 -44
  12. data/lib/sequenceserver/routes.rb +29 -25
  13. data/lib/sequenceserver/version.rb +1 -1
  14. data/lib/sequenceserver.rb +32 -20
  15. data/public/js/errormodal.js +55 -0
  16. data/public/js/report.js +6 -2
  17. data/public/js/sequenceserver.js +0 -12
  18. data/public/sequenceserver-report.min.js +15 -15
  19. data/public/sequenceserver-search.min.js +3 -3
  20. data/sequenceserver.gemspec +2 -1
  21. data/spec/capybara_spec.rb +120 -21
  22. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhd +8 -0
  23. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhi +0 -0
  24. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhr +0 -0
  25. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nin +0 -0
  26. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nog +0 -0
  27. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsd +16 -0
  28. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsi +0 -0
  29. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsq +0 -0
  30. data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.txt +8 -0
  31. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phd +9140 -0
  32. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phi +0 -0
  33. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phr +0 -0
  34. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pin +0 -0
  35. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pog +0 -0
  36. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psd +18280 -0
  37. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psi +0 -0
  38. data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psq +0 -0
  39. data/spec/database/sample/proteins/uniprot/URL +1 -0
  40. data/spec/nucleotide_query.fa +21 -0
  41. data/spec/protein_query.fa +21 -0
  42. data/spec/routes_spec.rb +2 -0
  43. data/spec/sample_reports/blastn_sample/job.yaml +1 -0
  44. data/spec/sample_reports/blastn_sample/{rfile → stdout} +0 -0
  45. data/spec/sample_reports/blastp_sample/job.yaml +1 -0
  46. data/spec/sample_reports/blastp_sample/{rfile → stdout} +0 -0
  47. data/spec/sample_reports/blastx_sample/job.yaml +1 -0
  48. data/spec/sample_reports/blastx_sample/{rfile → stdout} +0 -0
  49. data/spec/sample_reports/no_hits_sample/job.yaml +1 -0
  50. data/spec/sample_reports/no_hits_sample/{rfile → stdout} +0 -0
  51. data/spec/sample_reports/tblastn_sample/job.yaml +1 -0
  52. data/spec/sample_reports/tblastn_sample/{rfile → stdout} +0 -0
  53. data/spec/sample_reports/tblastx_sample/job.yaml +1 -0
  54. data/spec/sample_reports/tblastx_sample/{rfile → stdout} +0 -0
  55. data/spec/sample_reports/with_hits_sample/job.yaml +1 -0
  56. data/spec/sample_reports/with_hits_sample/{rfile → stdout} +0 -0
  57. data/spec/sequenceserver_spec.rb +1 -1
  58. data/spec/spec_helper.rb +2 -16
  59. data/views/layout.erb +0 -45
  60. metadata +55 -16
  61. data/lib/sequenceserver/blast/exceptions.rb +0 -27
  62. data/views/400.erb +0 -29
  63. data/views/500.erb +0 -41
@@ -90,11 +90,15 @@ module SequenceServer
90
90
  # sys(command, :dir => '/path/to/directory',
91
91
  # :path => '/path/to/directory', :stdout => '/path/to/stdout_file',
92
92
  # :stderr => '/path/to/stderr_file')
93
-
94
93
  def sys(command, options = {})
94
+ # Available output channels
95
+ channels = [:stdout, :stderr]
96
+
95
97
  # Make temporary files to store output from stdout and stderr.
96
- temp_stdout_file = Tempfile.new 'sequenceserver-sys'
97
- temp_stderr_file = Tempfile.new 'sequenceserver-sys'
98
+ temp_files = {
99
+ stdout: Tempfile.new('sequenceserver-sys'),
100
+ stderr: Tempfile.new('sequenceserver-sys')
101
+ }
98
102
 
99
103
  # Log the command we are going to run - use -D option to view.
100
104
  logger.debug("Executing: #{command}")
@@ -111,32 +115,40 @@ module SequenceServer
111
115
 
112
116
  # Execute the shell command, redirect stdout and stderr to the
113
117
  # temporary files.
114
- exec("#{command} 1>#{temp_stdout_file.path} 2>#{temp_stderr_file.path}")
118
+ exec("#{command} 1>#{temp_files[:stdout].path}" \
119
+ " 2>#{temp_files[:stderr].path}")
115
120
  end
116
121
 
117
122
  # Wait for the termination of the child process.
118
123
  _, status = Process.wait2(child_pid)
119
124
 
120
- unless status == 0
121
- raise CommandFailed.new(temp_stdout_file.read, temp_stderr_file.read, status)
125
+ # If a full path was given for stdout and stderr files, move the
126
+ # temporary files to this path. If the path given does not exist,
127
+ # create it.
128
+ channels.each do |channel|
129
+ filename = options[channel]
130
+ break unless filename
131
+
132
+ # If the given path has a directory component, ensure it exists.
133
+ file_dir = File.dirname(filename)
134
+ FileUtils.mkdir_p(file_dir) unless File.directory?(file_dir)
135
+
136
+ # Now move the temporary file to the given path.
137
+ # TODO: don't we need to explicitly close the temp file here?
138
+ FileUtils.mv(temp_files.delete(channel), filename)
122
139
  end
123
140
 
124
- # Store stdout and/or stderr in files, if paths for the files were given.
125
- # If a full path was given for an output file, move the temporary file
126
- # to this path. If the path given does not exist, create it.
127
- [options[:stdout], options[:stderr]].each_with_index do |filename, index|
128
- if filename
129
- file_dir = File.dirname(filename)
130
- unless File.directory?(file_dir)
131
- FileUtils.mkdir_p(file_dir)
132
- end
133
- FileUtils.mv([temp_stdout_file, temp_stderr_file][index], filename)
134
- end
141
+ # Read the remaining temp files into memory. For large outputs,
142
+ # the caller should supply a file path to prevent loading the
143
+ # output in memory.
144
+ temp_files.each do |channel, tempfile|
145
+ temp_files[channel] = tempfile.read
135
146
  end
136
147
 
137
- # If paths to write stdout and stderr to were not given, return the
138
- # contents of stdout and/or stderr. Otherwise, return nil.
139
- return temp_stdout_file.read, temp_stderr_file.read unless options[:stdout] || options[:stderr]
148
+ # Finally, return contents of the remaining temp files if the
149
+ # command completed successfully or raise CommandFailed error.
150
+ return temp_files.values if status.success?
151
+ raise CommandFailed.new(status.exitstatus, **temp_files)
140
152
  end
141
153
 
142
154
  # Run SequenceServer as a self-hosted server using Thin webserver.
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+
3
+ class ErrorModal extends React.Component {
4
+
5
+ constructor(props) {
6
+ super(props);
7
+ }
8
+
9
+ render() {
10
+ return (
11
+ <div
12
+ id="error" ref="errorModal" className="modal fade"
13
+ data-keyboard="false" data-backdrop="static">
14
+ <div
15
+ className="modal-dialog modal-lg">
16
+ <div
17
+ className="modal-content">
18
+ <div
19
+ className="modal-header">
20
+ <h3>{this.props.errorData.title}</h3>
21
+ </div>
22
+
23
+ <div
24
+ className="modal-body">
25
+ <p dangerouslySetInnerHTML={{ __html: this.props.errorData.message}}></p>
26
+
27
+ {
28
+ this.props.errorData.more_info &&
29
+ <pre className="pre-scrollable">
30
+ {this.props.errorData.more_info}
31
+ </pre>
32
+ }
33
+ </div>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ );
38
+ }
39
+
40
+ componentDidMount() {
41
+ $(React.findDOMNode(this.refs.errorModal)).modal('show');
42
+ }
43
+ }
44
+
45
+ export default function showErrorModal (errorData, beforeShow) {
46
+ if (!beforeShow) {
47
+ beforeShow = function () {};
48
+ }
49
+
50
+ setTimeout(function () {
51
+ beforeShow();
52
+ React.render(<ErrorModal errorData={errorData}/>,
53
+ document.getElementById('view'));
54
+ }, 500);
55
+ }
data/public/js/report.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import SequenceServer from './sequenceserver';
2
+ import showErrorModal from './errormodal';
3
+
2
4
  import _ from 'underscore';
3
5
  import React from 'react';
4
6
  import d3 from 'd3';
@@ -272,7 +274,7 @@ var SequenceViewer = (function () {
272
274
  })
273
275
  }, this))
274
276
  .fail(function (jqXHR, status, error) {
275
- SequenceServer.showErrorModal(jqXHR, function () {
277
+ showErrorModal(jqXHR, function () {
276
278
  this.hide();
277
279
  });
278
280
  });
@@ -989,8 +991,10 @@ var Report = React.createClass({
989
991
  case 200:
990
992
  this.setState(jqXHR.responseJSON);
991
993
  break;
994
+ case 404:
995
+ case 400:
992
996
  case 500:
993
- SequenceServer.showErrorModal(jqXHR, function () {});
997
+ showErrorModal(jqXHR.responseJSON);
994
998
  break;
995
999
  }
996
1000
  }, this));
@@ -107,16 +107,4 @@ export default {
107
107
  $(this).tooltip();
108
108
  });
109
109
  },
110
-
111
- showErrorModal: function (jqXHR, beforeShow) {
112
- setTimeout(function () {
113
- beforeShow();
114
- if (jqXHR.responseText) {
115
- $("#error").html(jqXHR.responseText).modal();
116
- }
117
- else {
118
- $("#error-no-response").modal();
119
- }
120
- }, 500);
121
- }
122
110
  };