module Bio::Command
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.
Constants
- QUOTE_CHARS_WINDOWS
- UNESCAPABLE_CHARS
- UNSAFE_CHARS_UNIX
Public Instance Methods
Executes the program. Automatically select popen for Ruby 1.9 or 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)
# File lib/bio/command.rb 196 def call_command(cmd, options = {}, &block) #:yields: io 197 if RUBY_VERSION >= "1.9.0" then 198 return call_command_popen(cmd, options, &block) 199 elsif no_fork? then 200 call_command_popen(cmd, options, &block) 201 else 202 begin 203 call_command_fork(cmd, options, &block) 204 rescue NotImplementedError 205 # fork(2) not implemented 206 @@no_fork = true 207 call_command_popen(cmd, options, &block) 208 end 209 end 210 end
This method is internally called from the call_command
method. In normal case, use call_command
, and do not call this method directly.
Executes the program via fork (by using IO.popen(“-”)) and exec. A block must be given. An IO object is passed to the block.
See the document of call_command
for available options.
Note for Ruby 1.8: In Ruby 1.8, from the view point of security, this method is recommended rather than call_command_popen. However, this method might have problems with multi-threads.
Note for Ruby 1.9: In Ruby 1.9, this method can not be used, because Thread.critical is removed. In Ruby 1.9, call_command_popen
is safe and robust enough, and is the recommended way, because IO.popen is improved to get a command-line as an array without calling shell.
Arguments:
-
(required) cmd: Array containing String objects
-
(optional) options: Hash
- Returns
-
(undefined)
# File lib/bio/command.rb 373 def call_command_fork(cmd, options = {}) 374 dir = options[:chdir] 375 cmd = safe_command_line_array(cmd) 376 begin 377 tc, Thread.critical, flag0, flag1 = Thread.critical, true, true, true 378 IO.popen("-", "r+") do |io| 379 if io then 380 # parent 381 flag0, Thread.critical, flag1 = false, tc, false 382 yield io 383 else 384 # child 385 Thread.critical = true # for safety, though already true 386 GC.disable 387 # chdir to options[:chdir] if available 388 begin 389 Dir.chdir(dir) if dir 390 rescue Exception 391 Process.exit!(1) 392 end 393 # executing the command 394 begin 395 Kernel.exec(*cmd) 396 rescue Errno::ENOENT, Errno::EACCES 397 Process.exit!(127) 398 rescue Exception 399 end 400 Process.exit!(1) 401 end 402 end 403 ensure 404 # When IO.popen("-") raises error, Thread.critical will be set here. 405 Thread.critical = tc if flag0 or flag1 406 #warn 'Thread.critical might have wrong value.' if flag0 != flag1 407 end 408 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)
# File lib/bio/command.rb 419 def call_command_open3(cmd) 420 cmd = safe_command_line_array(cmd) 421 Open3.popen3(*cmd) do |pin, pout, perr| 422 yield pin, pout, perr 423 end 424 end
This method is internally called from the call_command
method. In normal case, use call_command
, and do not call this method directly.
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.
See the document of call_command
for available options.
Note for Ruby 1.8: In Ruby 1.8, although shell unsafe characters are escaped. If inescapable characters exists, it raises RuntimeError. So, call_command_fork
is normally recommended.
Note for Ruby 1.9: In Ruby 1.9, call_command_popen
is safe and robust enough, and is the recommended way, because IO.popen is improved to get a command-line as an array without calling shell.
Arguments:
-
(required) cmd: Array containing String objects
-
(optional) options: Hash
- Returns
-
(undefined)
# File lib/bio/command.rb 235 def call_command_popen(cmd, options = {}, &block) 236 if RUBY_VERSION >= "1.9.0" then 237 if RUBY_ENGINE == 'jruby' then 238 _call_command_popen_jruby19(cmd, options, &block) 239 else 240 _call_command_popen_ruby19(cmd, options, &block) 241 end 242 else 243 _call_command_popen_ruby18(cmd, options, &block) 244 end 245 end
Escape special characters in command line string.
Arguments:
-
(required) str: String
- Returns
-
String object
# File lib/bio/command.rb 121 def escape_shell(str) 122 if windows_platform? then 123 escape_shell_windows(str) 124 else 125 escape_shell_unix(str) 126 end 127 end
Escape special characters in command line string for UNIX shells.
Arguments:
-
(required) str: String
- Returns
-
String object
# File lib/bio/command.rb 110 def escape_shell_unix(str) 111 str = str.to_s 112 raise 'cannot escape control characters' if UNESCAPABLE_CHARS =~ str 113 str.gsub(UNSAFE_CHARS_UNIX) { |x| "\\#{x}" } 114 end
Escape special characters in command line string for cmd.exe on Windows.
Arguments:
-
(required) str: String
- Returns
-
String object
# File lib/bio/command.rb 95 def escape_shell_windows(str) 96 str = str.to_s 97 raise 'cannot escape control characters' if UNESCAPABLE_CHARS =~ str 98 if QUOTE_CHARS_WINDOWS =~ str then 99 '"' + str.gsub(/\"/, '""') + '"' 100 else 101 String.new(str) 102 end 103 end
Same as:
http = Net::HTTP.new(...); http.post(path, data, header)
and it uses proxy if an environment variable (same as OpenURI.open_uri) is set. In addition, header
can be set. (Default Content-Type is application/octet-stream. Content-Length is 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
-
(required) data: String containing data
-
(optional) header: Hash containing header strings
- Returns
-
(same as Net::HTTP::post)
# File lib/bio/command.rb 950 def http_post(http, path, data, header = {}) 951 hash = { 952 'Content-Type' => 'application/octet-stream', 953 'Content-Length' => data.length.to_s 954 } 955 hash.update(header) 956 957 http.post(path, data, hash) 958 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)
# File lib/bio/command.rb 822 def http_post_form(http, path, params = nil, header = {}) 823 data = make_cgi_params(params) 824 825 hash = { 826 'Content-Type' => 'application/x-www-form-urlencoded', 827 'Content-Length' => data.length.to_s 828 } 829 hash.update(header) 830 831 http.post(path, data, hash) 832 end
Builds parameter string for from Hash of parameters for application/x-www-form-urlencoded.
Arguments:
-
(required) params: Hash containing parameters
- Returns
-
String
# File lib/bio/command.rb 876 def make_cgi_params(params) 877 data = "" 878 case params 879 when Hash 880 data = params.map do |key, val| 881 make_cgi_params_key_value(key, val) 882 end.join('&') 883 when Array 884 case params.first 885 when Hash 886 data = params.map do |hash| 887 hash.map do |key, val| 888 make_cgi_params_key_value(key, val) 889 end 890 end.join('&') 891 when Array 892 data = params.map do |key, val| 893 make_cgi_params_key_value(key, val) 894 end.join('&') 895 when String 896 data = params.map do |str| 897 key, val = str.split(/\=/, 2) 898 if val then 899 make_cgi_params_key_value(key, val) 900 else 901 CGI.escape(str) 902 end 903 end.join('&') 904 end 905 when String 906 raise TypeError, 'Bio::Command.make_cgi_params no longer accepts a single String as a form' 907 end 908 return data 909 end
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
# File lib/bio/command.rb 919 def make_cgi_params_key_value(key, value) 920 result = [] 921 case value 922 when Array 923 value.each do |val| 924 result << [key, val].map {|x| CGI.escape(x.to_s) }.join('=') 925 end 926 else 927 result << [key, value].map {|x| CGI.escape(x.to_s) }.join('=') 928 end 929 return result 930 end
Generate command line string with special characters escaped.
Arguments:
-
(required) ary: Array containing String objects
- Returns
-
String object
# File lib/bio/command.rb 134 def make_command_line(ary) 135 if windows_platform? then 136 make_command_line_windows(ary) 137 else 138 make_command_line_unix(ary) 139 end 140 end
Generate command line string with special characters escaped for UNIX shells.
Arguments:
-
(required) ary: Array containing String objects
- Returns
-
String object
# File lib/bio/command.rb 158 def make_command_line_unix(ary) 159 ary.collect { |str| escape_shell_unix(str) }.join(" ") 160 end
Generate command line string with special characters escaped for cmd.exe on Windows.
Arguments:
-
(required) ary: Array containing String objects
- Returns
-
String object
# File lib/bio/command.rb 148 def make_command_line_windows(ary) 149 ary.collect { |str| escape_shell_windows(str) }.join(" ") 150 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
# File lib/bio/command.rb 573 def mktmpdir(prefix_suffix = nil, tmpdir = nil, &block) 574 begin 575 Dir.mktmpdir(prefix_suffix, tmpdir, &block) 576 rescue NoMethodError 577 # backported from Ruby 1.9.2-preview1. 578 # ***** Below is excerpted from Ruby 1.9.2-preview1's lib/tmpdir.rb **** 579 # ***** Be careful about copyright. **** 580 case prefix_suffix 581 when nil 582 prefix = "d" 583 suffix = "" 584 when String 585 prefix = prefix_suffix 586 suffix = "" 587 when Array 588 prefix = prefix_suffix[0] 589 suffix = prefix_suffix[1] 590 else 591 raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}" 592 end 593 tmpdir ||= Dir.tmpdir 594 t = Time.now.strftime("%Y%m%d") 595 n = nil 596 begin 597 path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}" 598 path << "-#{n}" if n 599 path << suffix 600 Dir.mkdir(path, 0700) 601 rescue Errno::EEXIST 602 n ||= 0 603 n += 1 604 retry 605 end 606 607 if block_given? 608 begin 609 yield path 610 ensure 611 remove_entry_secure path 612 end 613 else 614 path 615 end 616 # ***** Above is excerpted from Ruby 1.9.2-preview1's lib/tmpdir.rb **** 617 end 618 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)
# File lib/bio/command.rb 782 def new_http(address, port = 80) 783 uri = URI.parse("http://#{address}:#{port}") 784 # Note: URI#find_proxy is an unofficial method defined in open-uri.rb. 785 # If the spec of open-uri.rb would be changed, we should change below. 786 if proxyuri = uri.find_proxy then 787 raise 'Non-HTTP proxy' if proxyuri.class != URI::HTTP 788 Net::HTTP.new(address, port, proxyuri.host, proxyuri.port) 789 else 790 Net::HTTP.new(address, port) 791 end 792 end
Same as:
h = Bio::Command.new_http(address, port) h.use_ssl = true h
# File lib/bio/command.rb 798 def new_https(address, port = 443) 799 connection = new_http(address, port) 800 connection.use_ssl = true 801 connection 802 end
CAUTION Bio::Command
INTERNAL USE ONLY. Users must NOT use the method. The method will be removed when it is not needed.
Checks if the OS does not support fork(2) system call. When not supported, it returns true. When supported or unknown, it returns false or nil.
Known issues:
-
It might make a mistake in minor platforms/architectures/interpreters.
- Returns
-
true, false or nil.
# File lib/bio/command.rb 80 def no_fork? 81 if (defined?(@@no_fork) && @@no_fork) or 82 windows_platform? or /java/i =~ RUBY_PLATFORM then 83 true 84 else 85 false 86 end 87 end
Same as: Net::HTTP.post(uri, params) and it uses proxy if an environment variable (same as OpenURI.open_uri) is set. In addition, header
can be set. (Default Content-Type is application/octet-stream. Content-Length is automatically set by default.) uri
must be a URI object, data
must be a String, and header
must be a hash.
Arguments:
-
(required) uri: URI object or String
-
(optional) data: String containing data
-
(optional) header: Hash containing header strings
- Returns
-
(same as Net::HTTP::post)
# File lib/bio/command.rb 977 def post(uri, data, header = {}) 978 unless uri.is_a?(URI) 979 uri = URI.parse(uri) 980 end 981 982 hash = { 983 'Content-Type' => 'application/octet-stream', 984 'Content-Length' => data.length.to_s 985 } 986 hash.update(header) 987 988 start_http_uri(uri) do |http| 989 http.post(uri.path, data, hash) 990 end 991 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)
# File lib/bio/command.rb 851 def post_form(uri, params = nil, header = {}) 852 unless uri.is_a?(URI) 853 uri = URI.parse(uri) 854 end 855 856 data = make_cgi_params(params) 857 858 hash = { 859 'Content-Type' => 'application/x-www-form-urlencoded', 860 'Content-Length' => data.length.to_s 861 } 862 hash.update(header) 863 864 start_http_uri(uri) do |http| 865 http.post(uri.path, data, hash) 866 end 867 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 Ruby 1.9 or 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
# File lib/bio/command.rb 442 def query_command(cmd, query = nil, options = {}) 443 if RUBY_VERSION >= "1.9.0" then 444 return query_command_popen(cmd, query, options) 445 elsif no_fork? then 446 query_command_popen(cmd, query, options) 447 else 448 begin 449 query_command_fork(cmd, query, options) 450 rescue NotImplementedError 451 # fork(2) not implemented 452 @@no_fork = true 453 query_command_fork(cmd, query, options) 454 end 455 end 456 end
This method is internally called from the query_command
method. In normal case, use query_command
, and do not call this method directly.
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.
See the document of query_command
for available options.
See the document of call_command_fork
for the security and Ruby version specific issues.
Arguments:
-
(required) cmd: Array containing String objects
-
(optional) query: String
-
(optional) options: Hash
- Returns
-
String or nil
# File lib/bio/command.rb 507 def query_command_fork(cmd, query = nil, options = {}) 508 ret = nil 509 call_command_fork(cmd, options) do |io| 510 io.sync = true 511 io.print query if query 512 io.close_write 513 ret = io.read 514 end 515 ret 516 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)
# File lib/bio/command.rb 529 def query_command_open3(cmd, query = nil) 530 errorlog = nil 531 cmd = safe_command_line_array(cmd) 532 Open3.popen3(*cmd) do |pin, pout, perr| 533 perr.sync = true 534 t = Thread.start { errorlog = perr.read } 535 begin 536 pin.print query if query 537 pin.close 538 output = pout.read 539 ensure 540 t.join 541 end 542 [ output, errorlog ] 543 end 544 end
This method is internally called from the query_command
method. In normal case, use query_command
, and do not call this method directly.
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.
See the document of query_command
for available options.
See the document of call_command_popen
for the security and Ruby version specific issues.
Arguments:
-
(required) cmd: Array containing String objects
-
(optional) query: String
-
(optional) options: Hash
- Returns
-
String or nil
# File lib/bio/command.rb 476 def query_command_popen(cmd, query = nil, options = {}) 477 ret = nil 478 call_command_popen(cmd, options) do |io| 479 io.sync = true 480 io.print query if query 481 io.close_write 482 ret = io.read 483 end 484 ret 485 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
# File lib/bio/command.rb 706 def read_uri(uri) 707 OpenURI.open_uri(uri).read 708 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
# File lib/bio/command.rb 555 def remove_entry_secure(path, force = false) 556 begin 557 FileUtils.remove_entry_secure(path, force) 558 rescue NoMethodError 559 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}" 560 nil 561 end 562 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
# File lib/bio/command.rb 169 def safe_command_line_array(ary) 170 ary = ary.to_ary 171 return ary if ary.size >= 2 or ary.empty? 172 if ary.size != 1 then 173 raise 'Bug: assersion of ary.size == 1 failed' 174 end 175 arg0 = ary[0] 176 begin 177 arg0 = arg0.to_ary 178 rescue NoMethodError 179 arg0 = [ arg0, arg0 ] 180 end 181 [ arg0 ] 182 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)
# File lib/bio/command.rb 758 def start_http(address, port = 80, &block) 759 uri = URI.parse("http://#{address}:#{port}") 760 # Note: URI#find_proxy is an unofficial method defined in open-uri.rb. 761 # If the spec of open-uri.rb would be changed, we should change below. 762 if proxyuri = uri.find_proxy then 763 raise 'Non-HTTP proxy' if proxyuri.class != URI::HTTP 764 http = Net::HTTP.Proxy(proxyuri.host, proxyuri.port) 765 else 766 http = Net::HTTP 767 end 768 http.start(address, port, &block) 769 end
Same as:
Net::HTTP.start(uri.address, uri.port)
and it uses proxy if an environment variable (same as OpenURI.open_uri) is set. It supports https.
Note: This method ignores uri.path. It only uses uri.address and uri.port.
Arguments:
-
(required) uri: URI object or String containing URI
- Returns
-
(same as Net::HTTP::start except for proxy and https support)
# File lib/bio/command.rb 724 def start_http_uri(uri, &block) 725 unless uri.is_a?(URI) 726 uri = URI.parse(uri) 727 end 728 729 # Note: URI#find_proxy is an unofficial method defined in open-uri.rb. 730 # If the spec of open-uri.rb would be changed, we should change below. 731 if proxyuri = uri.find_proxy then 732 raise 'Non-HTTP proxy' if proxyuri.class != URI::HTTP 733 klass = Net::HTTP.Proxy(proxyuri.host, proxyuri.port) 734 else 735 klass = Net::HTTP 736 end 737 738 http = klass.new(uri.host, uri.port) 739 case uri.scheme 740 when 'https' 741 http.use_ssl = true 742 end 743 744 http.start(&block) 745 end
CAUTION Bio::Command
INTERNAL USE ONLY. Users must NOT use the method. The method will be removed when it is not needed.
Checks if the program is running on Microsoft Windows. If Windows, returns true. Otherwise, returns false. Note that Cygwin is not treated as Windows.
Known issues:
-
It might make a mistake in minor platforms/architectures/interpreters.
-
When running JRuby on Cygwin, the result is unknown.
- Returns
-
true or false
# File lib/bio/command.rb 50 def windows_platform? 51 case RUBY_PLATFORM 52 when /(?:mswin|bccwin|mingw)(?:32|64)/i 53 true 54 when /java/i 55 # Reference: Redmine's platform.rb 56 # http://www.redmine.org/projects/redmine/repository/revisions/1753/entry/trunk/lib/redmine/platform.rb 57 if /windows/i =~ (ENV['OS'] || ENV['os']).to_s then 58 true 59 else 60 false 61 end 62 else 63 false 64 end 65 end