/
sequenceserver
executable file
·379 lines (299 loc) · 10.7 KB
/
sequenceserver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
#!/usr/bin/env ruby
require 'readline'
require 'English'
require 'slop'
ENV['RACK_ENV'] ||= 'production'
# display name for tools like `ps`
$PROGRAM_NAME = 'sequenceserver'
begin
Slop.parse!(:strict => true, :help => true) do
banner <<BANNER
SUMMARY
custom, local, BLAST server
USAGE
sequenceserver [options]
Example:
# launch SequenceServer with the given config file
$ sequenceserver -c ~/.sequenceserver.ants.conf
# use the bundled database formatter utility to prepare databases for use
# with SequenceServer
$ sequenceserver -m
DESCRIPTION
SequenceServer lets you rapidly set up a BLAST+ server with an intuitive user
interface for use locally or over the web.
If BLAST+ is not installed on your system, SequenceServer will offer to install
BLAST+ for you.
You should only ever have to point it to a directory of FASTA files.
In a given directory, SequenceServer is able to tell FASTA files that are yet
to be formatted for use with BLAST+ and format them, and FASTA files that are
already formatted for use with BLAST+, heuristically skipping all other files
in the directory. Directories are scanned recursively. Type of sequences in a
FASTA file is detected automagically. `parse_seqids` option of `makeblastdb` is
used to create BLAST+ databases.
BANNER
on 'c', 'config_file=',
'Use the given configuration file',
:argument => true
on 'config=',
'Same as --config_file (deprecated)',
:argument => true
on 'b', 'bin=',
'Load BLAST+ binaries from this directory',
:argument => true
on 'd', 'database_dir=',
'Read FASTA and BLAST database from this directory',
:argument => true
on 'n', 'num_threads=',
'Number of threads to use to run a BLAST search',
:argument => true
on 'r', 'require=',
'Load extension from this file',
:argument => true
on 'h', 'host=',
'Host to run SequenceServer on',
:argument => true
on 'p', 'port=',
'Port to run SequenceServer on',
:argument => true
on 's', 'set',
'Set configuration value in default or given config file'
on 'm', 'make-blast-databases',
'Create BLAST databases'
on 'l', 'list_databases',
'List BLAST databases'
on 'u', 'list-unformatted-fastas',
'List unformatted FASTA files'
on 'i', 'interactive',
'Run SequenceServer in interactive mode'
on 'D', 'devel',
'Start SequenceServer in development mode'
on '-v', '--version',
'Print version number of SequenceServer that will be loaded'
on '-h', '--help',
'Display this help message'
clean_opts = lambda do |hash|
hash.delete_if { |k, v| k == :set || v.nil? }
hash[:config_file] ||= hash.delete(:config)
hash
end
run do
if version?
gemspec_file = File.join(File.dirname(__FILE__), '..',
'sequenceserver.gemspec')
gemspec = eval File.read gemspec_file
puts gemspec.version
exit
end
ENV['RACK_ENV'] = 'development' if devel?
# Exit gracefully on SIGINT.
stty = `stty -g`.chomp
trap('INT') do
puts ''
puts 'Aborted.'
system('stty', stty)
exit
end
require 'sequenceserver'
begin
SequenceServer.init clean_opts[to_h]
# The aim of following error recovery scenarios is to guide user to a
# working SequenceServer installation. We expect to land following
# error scenarios either when creating a new SequenceServer (first
# time or later), or updating config values using -s CLI option.
rescue SequenceServer::CONFIG_FILE_ERROR => e
puts e
exit!
rescue SequenceServer::BIN_DIR_NOT_FOUND => e
puts e
unless bin?
puts 'You can set the correct value by running:'
puts
puts ' sequenceserver -s -b <value>'
puts
end
exit!
rescue SequenceServer::DATABASE_DIR_NOT_FOUND => e
puts e
unless database_dir?
puts 'You can set the correct value by running:'
puts
puts ' sequenceserver -s -d <value>'
puts
end
exit!
rescue SequenceServer::NUM_THREADS_INCORRECT => e
puts e
unless num_threads?
puts 'You can set the correct value by running:'
puts
puts ' sequenceserver -s -n <value>'
puts
end
exit!
rescue SequenceServer::EXTENSION_FILE_NOT_FOUND => e
puts e
unless require?
puts 'You can set the correct value by running:'
puts
puts ' sequenceserver -s -r <value>'
puts
end
exit!
rescue SequenceServer::BLAST_NOT_INSTALLED,
SequenceServer::BLAST_NOT_COMPATIBLE => e
# Show original error message first.
puts
puts e
# Set a flag so that if we recovered from error resulting config can be
# saved. Config will be saved unless invoked with -b option.
fetch_option(:set).value = !bin?
# Ask user if she already has BLAST+ downloaded or offer to download
# BLAST+ for her.
puts
puts <<MSG
SequenceServer can use NCBI BLAST+ that you may have on your system already, or
download the correct package for itself. Please enter the path to NCBI BLAST+
or press Enter to download.
Press Ctrl+C to quit.
MSG
puts
response = Readline.readline('>> ').to_s.strip
if response.empty?
puts
puts 'Installing NCBI BLAST+.'
puts "RUBY_PLATFORM #{RUBY_PLATFORM}"
version = SequenceServer::MINIMUM_BLAST_VERSION
url = case RUBY_PLATFORM
when /i686-linux/ # 32 bit Linux
'ftp://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/' \
"#{version.chop}/ncbi-blast-#{version}-ia32-linux.tar.gz"
when /x86_64-linux/ # 64 bit Linux
'ftp://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/' \
"#{version.chop}/ncbi-blast-#{version}-x64-linux.tar.gz"
when /darwin/ # Mac
'ftp://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/' \
"#{version.chop}/" \
"ncbi-blast-#{version}-universal-macosx.tar.gz"
else
puts <<ERR
------------------------------------------------------------------------
FAILED!! to install NCBI BLAST+.
We currently support Linux and Mac only (both 32 and 64 bit). If you
believe you are running a supported platform, please open a support
ticket titled "#{RUBY_PLATFORM}" at:
https://github.com/yannickwurm/sequenceserver/issues
------------------------------------------------------------------------
ERR
end
archive = File.join('/tmp', File.basename(url))
# -ip4 is required to avoid this curl bug http://sourceforge.net/p/curl/bugs/1424/?limit=25
# see also https://github.com/yannickwurm/sequenceserver/issues/139
system "curl -ip4 -C - #{url} -o #{archive} && mkdir -p ~/.sequenceserver" \
"&& tar xvf #{archive} -C ~/.sequenceserver"
unless $CHILD_STATUS.success?
puts 'Failed to install BLAST+.'
puts ' You may need to download BLAST+ from - '
puts ' http://www.ncbi.nlm.nih.gov/blast/Blast.cgi?CMD=Web&PAGE_TYPE=BlastDocs&DOC_TYPE=Download'
puts " Please ensure that you download BLAST+ version
#{SequenceServer::MINIMUM_BLAST_VERSION} or higher."
exit!
end
fetch_option(:bin).value =
"~/.sequenceserver/ncbi-blast-#{version}/bin/"
redo
else
unless File.basename(response) == 'bin'
response = File.join(response, 'bin')
end
fetch_option(:bin).value = File.join(response)
puts
redo
end
rescue SequenceServer::DATABASE_DIR_NOT_SET => e
# Show original error message.
puts
puts e
# Set a flag so that if we recovered from error resulting config can be
# saved. Config will be saved unless invoked with -d option.
fetch_option(:set).value = !database_dir?
# Ask user for the directory containing sequences or BLAST+
# databases.
puts
puts <<MSG
SequenceServer needs to know where your FASTA files or BLAST+ databases are.
Please enter the path to the relevant directory (default: current directory).
Press Ctrl+C to quit.
MSG
puts
response = Readline.readline('>> ').to_s.strip
fetch_option(:database_dir).value = response
redo
rescue SequenceServer::NO_BLAST_DATABASE_FOUND => e
unless list_databases? || list_unformatted_fastas? ||
make_blast_databases?
# Print error raised.
puts
puts e
# Offer user to format the FASTA files.
database_dir = SequenceServer.config[:database_dir]
puts
puts <<MSG
Search for FASTA files (.fa, .fasta, .fna) in '#{database_dir}' and try
creating BLAST+ databases? [y/n] (Default: y).
MSG
puts
print '>> '
response = STDIN.gets.to_s.strip
unless response.match(/^[n]$/i)
puts
puts 'Searching ...'
if SequenceServer::Database.unformatted_fastas.empty?
puts "Couldn't find any FASTA files."
exit!
else
formatted = SequenceServer::Database.make_blast_databases
exit! if formatted.empty? && !set?
redo unless set?
end
else
exit! unless set?
end
end
end
if interactive?
SequenceServer.irb
exit
end
if list_databases?
puts SequenceServer::Database.all
exit
end
if list_unformatted_fastas? || make_blast_databases?
unformatted_fastas = SequenceServer::Database.unformatted_fastas
if unformatted_fastas.empty?
puts "All FASTA files in #{SequenceServer.config[:database_dir]} " \
'are formatted.'
exit
end
end
if list_unformatted_fastas?
puts unformatted_fastas
exit
end
if make_blast_databases?
SequenceServer::Database.make_blast_databases
exit
end
if set?
SequenceServer.config.write_config_file
exit
end
SequenceServer.config.write_config_file if fetch_option(:set).value
SequenceServer.run
end
end
rescue Slop::Error => e
puts e
puts "Run '#{$PROGRAM_NAME} -h' for help with command line options."
exit
end