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

call_command call_command_fork call_command_open3 call_command_popen escape_shell escape_shell_unix escape_shell_windows http_post_form make_cgi_params make_cgi_params_key_value make_command_line make_command_line_unix make_command_line_windows mktmpdir new_http post_form query_command query_command_fork query_command_open3 query_command_popen read_uri remove_entry_secure safe_command_line_array start_http

### 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

call_command(cmd, options = {}) {|io| ...}

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

call_command_fork(cmd, options = {}) {|io| ...}

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

call_command_open3(cmd) {|pin, pout, perr| ...}

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

call_command_popen(cmd, options = {}) {|io| ...}

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_shell(str)

Escape special characters in command line string.

Arguments:

- (required) str: String

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_shell_unix(str)

Escape special characters in command line string for UNIX shells.

Arguments:

- (required) str: String

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_shell_windows(str)

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

Arguments:

- (required) str: String

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

http_post_form(http, path, params = nil, header = {})

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

make_cgi_params(params)

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

make_cgi_params_key_value(key, value)

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

Arguments:

- (required) key: String
- (required) value: String or Array containing String

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

make_command_line(ary)

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

make_command_line_unix(ary)

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

make_command_line_windows(ary)

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

mktmpdir(prefix_suffix = nil, tmpdir = nil) {|path| ...}

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

new_http(address, port = 80)

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

post_form(uri, params = nil, header = {})

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

query_command(cmd, query = nil, options = {})

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

query_command_fork(cmd, query = nil, options = {})

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

query_command_open3(cmd, query = nil)

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

query_command_popen(cmd, query = nil, options = {})

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

read_uri(uri)

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

remove_entry_secure(path, force = false)

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

safe_command_line_array(ary)

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

start_http(address, port = 80, &block)

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]