Module Bio::Command
In: lib/bio/command.rb

Bio::Command

Bio::Command is a collection of useful methods for execution of external commands or web applications. Any wrapper class for applications shall use this class.

Library internal use only. Users should not directly use it.

Methods

Classes and Modules

Class Bio::Command::Tmpdir

Constants

UNSAFE_CHARS_UNIX = /[^A-Za-z0-9\_\-\.\:\,\/\@\x1b\x80-\xfe]/n
QUOTE_CHARS_WINDOWS = /[^A-Za-z0-9\_\-\.\:\,\/\@\\]/n
UNESCAPABLE_CHARS = /[\x00-\x08\x10-\x1a\x1c-\x1f\x7f\xff]/n

Public Instance methods

Executes the program. Automatically select popen for Windows environment and fork for the others. A block must be given. An IO object is passed to the block.

Available options:

  :chdir => "path" : changes working directory to the specified path.

Arguments:

  • (required) cmd: Array containing String objects
  • (optional) options: Hash
Returns:(undefined)

[Source]

     # File lib/bio/command.rb, line 145
145:   def call_command(cmd, options = {}, &block) #:yields: io
146:     case RUBY_PLATFORM
147:     when /mswin32|bccwin32/
148:       call_command_popen(cmd, options, &block)
149:     else
150:       call_command_fork(cmd, options, &block)
151:     end
152:   end

Executes the program via fork (by using IO.popen("-")) and exec. A block must be given. An IO object is passed to the block.

From the view point of security, this method is recommended rather than call_command_popen.


Arguments:

  • (required) cmd: Array containing String objects
  • (optional) options: Hash
Returns:(undefined)

[Source]

     # File lib/bio/command.rb, line 196
196:   def call_command_fork(cmd, options = {})
197:     dir = options[:chdir]
198:     cmd = safe_command_line_array(cmd)
199:     IO.popen("-", "r+") do |io|
200:       if io then
201:         # parent
202:         yield io
203:       else
204:         # child
205:         # chdir to options[:chdir] if available
206:         begin
207:           Dir.chdir(dir) if dir
208:         rescue Exception
209:           Process.exit!(1)
210:         end
211:         # executing the command
212:         begin
213:           Kernel.exec(*cmd)
214:         rescue Errno::ENOENT, Errno::EACCES
215:           Process.exit!(127)
216:         rescue Exception
217:         end
218:         Process.exit!(1)
219:       end
220:     end
221:   end

Executes the program via Open3.popen3 A block must be given. IO objects are passed to the block.

You would use this method only when you really need to get stderr.


Arguments:

  • (required) cmd: Array containing String objects
Returns:(undefined)

[Source]

     # File lib/bio/command.rb, line 232
232:   def call_command_open3(cmd)
233:     cmd = safe_command_line_array(cmd)
234:     Open3.popen3(*cmd) do |pin, pout, perr|
235:       yield pin, pout, perr
236:     end
237:   end

Executes the program via IO.popen for OS which doesn‘t support fork. A block must be given. An IO object is passed to the block.


Arguments:

  • (required) cmd: Array containing String objects
  • (optional) options: Hash
Returns:(undefined)

[Source]

     # File lib/bio/command.rb, line 161
161:   def call_command_popen(cmd, options = {})
162:     str = make_command_line(cmd)
163:     # processing options
164:     if dir = options[:chdir] then
165:       case RUBY_PLATFORM
166:       when /mswin32|bccwin32/
167:         # Unix-like dir separator is changed to Windows dir separator
168:         # by using String#gsub.
169:         dirstr = dir.gsub(/\//, "\\")
170:         chdirstr = make_command_line([ 'cd', '/D', dirstr ])
171:         str = chdirstr + ' && ' + str
172:       else
173:         # UNIX shell
174:         chdirstr = make_command_line([ 'cd', dir ])
175:         str = chdirstr + ' && ' + str
176:       end
177:     end
178:     # call command by using IO.popen
179:     IO.popen(str, "w+") do |io|
180:       io.sync = true
181:       yield io
182:     end
183:   end

Escape special characters in command line string.


Arguments:

Returns:String object

[Source]

    # File lib/bio/command.rb, line 68
68:   def escape_shell(str)
69:     case RUBY_PLATFORM
70:     when /mswin32|bccwin32/
71:       escape_shell_windows(str)
72:     else
73:       escape_shell_unix(str)
74:     end
75:   end

Escape special characters in command line string for UNIX shells.


Arguments:

Returns:String object

[Source]

    # File lib/bio/command.rb, line 57
57:   def escape_shell_unix(str)
58:     str = str.to_s
59:     raise 'cannot escape control characters' if UNESCAPABLE_CHARS =~ str
60:     str.gsub(UNSAFE_CHARS_UNIX) { |x| "\\#{x}" }
61:   end

Escape special characters in command line string for cmd.exe on Windows.


Arguments:

Returns:String object

[Source]

    # File lib/bio/command.rb, line 42
42:   def escape_shell_windows(str)
43:     str = str.to_s
44:     raise 'cannot escape control characters' if UNESCAPABLE_CHARS =~ str
45:     if QUOTE_CHARS_WINDOWS =~ str then
46:       '"' + str.gsub(/\"/, '""') + '"'
47:     else
48:       String.new(str)
49:     end
50:   end

Same as:

 http = Net::HTTP.new(...); http.post_form(path, params)

and it uses proxy if an environment variable (same as OpenURI.open_uri) is set. In addition, header can be set. (Note that Content-Type and Content-Length are automatically set by default.) uri must be a URI object, params must be a hash, and header must be a hash.


Arguments:

  • (required) http: Net::HTTP object or compatible object
  • (required) path: String
  • (optional) params: Hash containing parameters
  • (optional) header: Hash containing header strings
Returns:(same as Net::HTTP::post_form)

[Source]

     # File lib/bio/command.rb, line 565
565:   def http_post_form(http, path, params = nil, header = {})
566:     data = make_cgi_params(params)
567: 
568:     hash = {
569:       'Content-Type'   => 'application/x-www-form-urlencoded',
570:       'Content-Length' => data.length.to_s
571:     }
572:     hash.update(header)
573: 
574:     http.post(path, data, hash)
575:   end

Builds parameter string for from Hash of parameters for application/x-www-form-urlencoded.


Arguments:

  • (required) params: Hash containing parameters
Returns:String

[Source]

     # File lib/bio/command.rb, line 619
619:   def make_cgi_params(params)
620:     data = ""
621:     case params
622:     when Hash
623:       data = params.map do |key, val|
624:         make_cgi_params_key_value(key, val)
625:       end.join('&')
626:     when Array
627:       case params.first
628:       when Hash
629:         data = params.map do |hash|
630:           hash.map do |key, val|
631:             make_cgi_params_key_value(key, val)
632:           end
633:         end.join('&')
634:       when Array
635:         data = params.map do |key, val|
636:           make_cgi_params_key_value(key, val)
637:         end.join('&')
638:       when String
639:         data = params.map do |str|
640:           key, val = str.split(/\=/, 2)
641:           if val then
642:             make_cgi_params_key_value(key, val)
643:           else
644:             CGI.escape(str)
645:           end
646:         end.join('&')
647:       end
648:     when String
649:       data = URI.escape(params.strip)
650:     end
651:     return data
652:   end

Builds parameter string for from a key string and a value (or values) for application/x-www-form-urlencoded.


Arguments:

Returns:String

[Source]

     # File lib/bio/command.rb, line 662
662:   def make_cgi_params_key_value(key, value)
663:     result = []
664:     case value
665:     when Array
666:       value.each do |val|
667:         result << [key, val].map {|x| CGI.escape(x.to_s) }.join('=')
668:       end
669:     else
670:       result << [key, value].map {|x| CGI.escape(x.to_s) }.join('=')
671:     end
672:     return result
673:   end

Generate command line string with special characters escaped.


Arguments:

  • (required) ary: Array containing String objects
Returns:String object

[Source]

    # File lib/bio/command.rb, line 82
82:   def make_command_line(ary)
83:     case RUBY_PLATFORM
84:     when /mswin32|bccwin32/
85:       make_command_line_windows(ary)
86:     else
87:       make_command_line_unix(ary)
88:     end
89:   end

Generate command line string with special characters escaped for UNIX shells.


Arguments:

  • (required) ary: Array containing String objects
Returns:String object

[Source]

     # File lib/bio/command.rb, line 107
107:   def make_command_line_unix(ary)
108:     ary.collect { |str| escape_shell_unix(str) }.join(" ")
109:   end

Generate command line string with special characters escaped for cmd.exe on Windows.


Arguments:

  • (required) ary: Array containing String objects
Returns:String object

[Source]

    # File lib/bio/command.rb, line 97
97:   def make_command_line_windows(ary)
98:     ary.collect { |str| escape_shell_windows(str) }.join(" ")
99:   end

Backport of Dir.mktmpdir in Ruby 1.9.

Same as Dir.mktmpdir(prefix_suffix) in Ruby 1.9.


Arguments:

  • (optional) prefix_suffix: String (or Array, etc.)
  • (optional) tmpdir: String: temporary directory‘s path

[Source]

     # File lib/bio/command.rb, line 367
367:   def mktmpdir(prefix_suffix = nil, tmpdir = nil, &block)
368:     begin
369:       Dir.mktmpdir(prefix_suffix, tmpdir, &block)
370:     rescue NoMethodError
371:       # backported from Ruby 1.9.2-preview1.
372:       # ***** Below is excerpted from Ruby 1.9.2-preview1's lib/tmpdir.rb ****
373:       # ***** Be careful about copyright. ****
374:       case prefix_suffix
375:       when nil
376:         prefix = "d"
377:         suffix = ""
378:       when String
379:         prefix = prefix_suffix
380:         suffix = ""
381:       when Array
382:         prefix = prefix_suffix[0]
383:         suffix = prefix_suffix[1]
384:       else
385:         raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
386:       end
387:       tmpdir ||= Dir.tmpdir
388:       t = Time.now.strftime("%Y%m%d")
389:       n = nil
390:       begin
391:         path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
392:         path << "-#{n}" if n
393:         path << suffix
394:         Dir.mkdir(path, 0700)
395:       rescue Errno::EEXIST
396:         n ||= 0
397:         n += 1
398:         retry
399:       end
400: 
401:       if block_given?
402:         begin
403:           yield path
404:         ensure
405:           remove_entry_secure path
406:         end
407:       else
408:         path
409:       end
410:       # ***** Above is excerpted from Ruby 1.9.2-preview1's lib/tmpdir.rb ****
411:     end
412:   end

Same as:

  Net::HTTP.new(address, port)

and it uses proxy if an environment variable (same as OpenURI.open_uri) is set.


Arguments:

  • (required) address: String containing host name or IP address
  • (optional) port: port (sanme as Net::HTTP::start)
Returns:(same as Net::HTTP.new except for proxy support)

[Source]

     # File lib/bio/command.rb, line 535
535:   def new_http(address, port = 80)
536:     uri = URI.parse("http://#{address}:#{port}")
537:     # Note: URI#find_proxy is an unofficial method defined in open-uri.rb.
538:     # If the spec of open-uri.rb would be changed, we should change below.
539:     if proxyuri = uri.find_proxy then
540:       raise 'Non-HTTP proxy' if proxyuri.class != URI::HTTP
541:       Net::HTTP.new(address, port, proxyuri.host, proxyuri.port)
542:     else
543:       Net::HTTP.new(address, port)
544:     end
545:   end

Same as: Net::HTTP.post_form(uri, params) and it uses proxy if an environment variable (same as OpenURI.open_uri) is set. In addition, header can be set. (Note that Content-Type and Content-Length are automatically set by default.) uri must be a URI object, params must be a hash, and header must be a hash.


Arguments:

  • (required) uri: URI object or String
  • (optional) params: Hash containing parameters
  • (optional) header: Hash containing header strings
Returns:(same as Net::HTTP::post_form)

[Source]

     # File lib/bio/command.rb, line 594
594:   def post_form(uri, params = nil, header = {})
595:     unless uri.is_a?(URI)
596:       uri = URI.parse(uri)
597:     end
598: 
599:     data = make_cgi_params(params)
600: 
601:     hash = {
602:       'Content-Type'   => 'application/x-www-form-urlencoded',
603:       'Content-Length' => data.length.to_s
604:     }
605:     hash.update(header)
606: 
607:     start_http(uri.host, uri.port) do |http|
608:       http.post(uri.path, data, hash)
609:     end
610:   end

Executes the program with the query (String) given to the standard input, waits the program termination, and returns the output data printed to the standard output as a string.

Automatically select popen for Windows environment and fork for the others.

Available options:

  :chdir => "path" : changes working directory to the specified path.

Arguments:

  • (required) cmd: Array containing String objects
  • (optional) query: String
  • (optional) options: Hash
Returns:String or nil

[Source]

     # File lib/bio/command.rb, line 254
254:   def query_command(cmd, query = nil, options = {})
255:     case RUBY_PLATFORM
256:     when /mswin32|bccwin32/
257:       query_command_popen(cmd, query, options)
258:     else
259:       query_command_fork(cmd, query, options)
260:     end
261:   end

Executes the program with the query (String) given to the standard input, waits the program termination, and returns the output data printed to the standard output as a string.

Fork (by using IO.popen("-")) and exec is used to execute the program.

From the view point of security, this method is recommended rather than query_command_popen.


Arguments:

  • (required) cmd: Array containing String objects
  • (optional) query: String
  • (optional) options: Hash
Returns:String or nil

[Source]

     # File lib/bio/command.rb, line 301
301:   def query_command_fork(cmd, query = nil, options = {})
302:     ret = nil
303:     call_command_fork(cmd, options) do |io|
304:       io.sync = true
305:       io.print query if query
306:       io.close_write
307:       ret = io.read
308:     end
309:     ret
310:   end

Executes the program via Open3.popen3 with the query (String) given to the stain, waits the program termination, and returns the data from stdout and stderr as an array of the strings.

You would use this method only when you really need to get stderr.


Arguments:

  • (required) cmd: Array containing String objects
  • (optional) query: String
Returns:Array containing 2 objects: output string (or nil) and stderr string (or nil)

[Source]

     # File lib/bio/command.rb, line 323
323:   def query_command_open3(cmd, query = nil)
324:     errorlog = nil
325:     cmd = safe_command_line_array(cmd)
326:     Open3.popen3(*cmd) do |pin, pout, perr|
327:       perr.sync = true
328:       t = Thread.start { errorlog = perr.read }
329:       begin
330:         pin.print query if query
331:         pin.close
332:         output = pout.read
333:       ensure
334:         t.join
335:       end
336:       [ output, errorlog ]
337:     end
338:   end

Executes the program with the query (String) given to the standard input, waits the program termination, and returns the output data printed to the standard output as a string.

IO.popen is used for OS which doesn‘t support fork.


Arguments:

  • (required) cmd: Array containing String objects
  • (optional) query: String
  • (optional) options: Hash
Returns:String or nil

[Source]

     # File lib/bio/command.rb, line 275
275:   def query_command_popen(cmd, query = nil, options = {})
276:     ret = nil
277:     call_command_popen(cmd, options) do |io|
278:       io.sync = true
279:       io.print query if query
280:       io.close_write
281:       ret = io.read
282:     end
283:     ret
284:   end

Same as OpenURI.open_uri(uri).read and it uses proxy if an environment variable (same as OpenURI.open_uri) is set.


Arguments:

  • (required) uri: URI object or String
Returns:String

[Source]

     # File lib/bio/command.rb, line 496
496:   def read_uri(uri)
497:     OpenURI.open_uri(uri).read
498:   end

Same as FileUtils.remove_entry_secure after Ruby 1.8.3. In Ruby 1.8.2 or previous version, it only shows warning message and does nothing.

It is strongly recommended using Ruby 1.8.5 or later.


Arguments:

  • (required) path: String
  • (optional) force: boolean

[Source]

     # File lib/bio/command.rb, line 349
349:   def remove_entry_secure(path, force = false)
350:     begin
351:       FileUtils.remove_entry_secure(path, force)
352:     rescue NoMethodError
353:       warn "The temporary file or directory is not removed because of the lack of FileUtils.remove_entry_secure. Use Ruby 1.8.3 or later (1.8.5 or later is strongly recommended): #{path}"
354:       nil
355:     end
356:   end

Returns an Array of command-line command and arguments that can be safely passed to Kernel.exec etc. If the given array is already safe (or empty), returns the given array.


Arguments:

  • (required) ary: Array
Returns:Array

[Source]

     # File lib/bio/command.rb, line 118
118:   def safe_command_line_array(ary)
119:     ary = ary.to_ary
120:     return ary if ary.size >= 2 or ary.empty?
121:     if ary.size != 1 then
122:       raise 'Bug: assersion of ary.size == 1 failed'
123:     end
124:     arg0 = ary[0]
125:     begin
126:       arg0 = arg0.to_ary
127:     rescue NoMethodError
128:       arg0 = [ arg0, arg0 ]
129:     end
130:     [ arg0 ]
131:   end

Same as:

  Net::HTTP.start(address, port)

and it uses proxy if an environment variable (same as OpenURI.open_uri) is set.


Arguments:

  • (required) address: String containing host name or IP address
  • (optional) port: port (sanme as Net::HTTP::start)
Returns:(same as Net::HTTP::start except for proxy support)

[Source]

     # File lib/bio/command.rb, line 511
511:   def start_http(address, port = 80, &block)
512:     uri = URI.parse("http://#{address}:#{port}")
513:     # Note: URI#find_proxy is an unofficial method defined in open-uri.rb.
514:     # If the spec of open-uri.rb would be changed, we should change below.
515:     if proxyuri = uri.find_proxy then
516:       raise 'Non-HTTP proxy' if proxyuri.class != URI::HTTP
517:       http = Net::HTTP.Proxy(proxyuri.host, proxyuri.port)
518:     else
519:       http = Net::HTTP
520:     end
521:     http.start(address, port, &block)
522:   end

[Validate]