require 'stringio'
require 'zlib'
+BEGIN { Dir.mkdir ENV["BP_TMP"] unless File.directory? ENV["BP_TMP"] }
+
TEST = false
# Monkey patch (evil) changing the to_s method of the Hash class to
# records. Records are read from STDIN (default) or file (possibly gzipped)
# and written to STDOUT (default) or file.
def self.open(input = STDIN, output = STDOUT)
- input = self.open_input(input)
- output = self.open_output(output)
+ io_in = self.open_input(input)
+ io_out = self.open_output(output)
- if block_given?
+ if block_given? # FIXME begin block outmost?
begin
- yield input, output
+ yield io_in, io_out
ensure
- input.close
- output.close
+ io_in.close
+ io_out.close
end
else
- return input, output
+ return io_in, io_out
end
end
# Method to parse and yield a Biopiece record from _ios_.
def each_record
+ while record = get_entry
+ yield record
+ end
+
+ self # conventionally
+ end
+
+ alias :each :each_record
+
+ def get_entry
record = {}
@ios.each_line do |line|
when /^([^:]+): (.*)$/
record[$1.to_sym] = $2
when /^---$/
- yield record unless record.empty?
- record = {}
+ break
else
raise BiopiecesError, "Bad record format: #{line}"
end
end
- yield record unless record.empty?
-
- self # conventionally
+ return record unless record.empty?
end
- alias :each :each_record
+ alias :get_record :each_entry
private
if STDIN.tty?
input = self.new(StringIO.new)
else
- input = self.new(STDIN, stdio = true)
+ input = self.new(STDIN, true)
end
elsif File.exists? input
- ios = File.open(input, mode='r')
+ ios = File.open(input, 'r')
begin
ios = Zlib::GzipReader.new(ios)
# Records are written to STDOUT (default) or file.
def self.open_output(output)
if output.nil?
- output = self.new(STDOUT, stdio = true)
+ output = self.new(STDOUT, true)
elsif not output.is_a? IO
- output = self.new(File.open(output, mode='w'))
+ output = self.new(File.open(output, 'w'))
end
output
def check_keys
@cast_list.each do |cast|
MANDATORY.each do |mandatory|
- raise CastError, "Missing symbol in cast: '#{mandatory.to_sym}'" unless cast.has_key? mandatory.to_sym
+ raise CastError, "Missing symbol in cast: '#{mandatory}'" unless cast.has_key? mandatory.to_sym
end
end
end
type_hash[type] = true
end
- unless type_hash.has_key? cast[:type]
+ unless type_hash[cast[:type]]
raise CastError, "Illegal cast of type: '#{cast[:type]}'"
end
end
def check_duplicates
check_hash = {}
@cast_list.each do |cast|
- raise CastError, "Duplicate argument: '--#{cast[:long]}'" if check_hash.has_key? cast[:long]
- raise CastError, "Duplicate argument: '-#{cast[:short]}'" if check_hash.has_key? cast[:short]
+ raise CastError, "Duplicate argument: '--#{cast[:long]}'" if check_hash[cast[:long]]
+ raise CastError, "Duplicate argument: '-#{cast[:short]}'" if check_hash[cast[:short]]
check_hash[cast[:long]] = true
check_hash[cast[:short]] = true
end
option_parser.parse!(@argv)
if print_usage_full?
- print_usage_and_exit(full=true)
+ print_usage_and_exit(true)
elsif print_usage_short?
print_usage_and_exit
end
def options_default
@casts.each do |cast|
if cast[:default]
- unless @options.has_key? cast[:long]
+ unless @options[cast[:long]]
if cast[:type] == 'list'
@options[cast[:long]] = cast[:default].split ','
else
def options_glob
@casts.each do |cast|
if cast[:type] == 'files' or cast[:type] == 'files!'
- if @options.has_key? cast[:long]
+ if @options[cast[:long]]
files = []
@options[cast[:long]].each do |path|
# Check if a mandatory option is set and raise if it isn't.
def options_check_mandatory(cast)
if cast[:mandatory]
- raise ArgumentError, "Mandatory argument: --#{cast[:long]}" unless @options.has_key? cast[:long]
+ raise ArgumentError, "Mandatory argument: --#{cast[:long]}" unless @options[cast[:long]]
end
end
# Check int type option and raise if not an integer.
def options_check_int(cast)
- if cast[:type] == 'int' and @options.has_key? cast[:long]
+ if cast[:type] == 'int' and @options[cast[:long]]
unless @options[cast[:long]].is_a? Integer
raise ArgumentError, "Argument to --#{cast[:long]} must be an integer, not '#{@options[cast[:long]]}'"
end
# Check uint type option and raise if not an unsinged integer.
def options_check_uint(cast)
- if cast[:type] == 'uint' and @options.has_key? cast[:long]
+ if cast[:type] == 'uint' and @options[cast[:long]]
unless @options[cast[:long]].is_a? Integer and @options[cast[:long]] >= 0
raise ArgumentError, "Argument to --#{cast[:long]} must be an unsigned integer, not '#{@options[cast[:long]]}'"
end
# Check file! type argument and raise if file don't exists.
def options_check_file(cast)
- if cast[:type] == 'file!' and @options.has_key? cast[:long]
+ if cast[:type] == 'file!' and @options[cast[:long]]
raise ArgumentError, "No such file: '#{@options[cast[:long]]}'" unless File.file? @options[cast[:long]]
end
end
# Check files! type argument and raise if files don't exists.
def options_check_files(cast)
- if cast[:type] == 'files!' and @options.has_key? cast[:long]
+ if cast[:type] == 'files!' and @options[cast[:long]]
@options[cast[:long]].each do |path|
next if path == "-"
raise ArgumentError, "File not readable: '#{path}'" unless File.readable? path
# Check dir! type argument and raise if directory don't exist.
def options_check_dir(cast)
- if cast[:type] == 'dir!' and @options.has_key? cast[:long]
+ if cast[:type] == 'dir!' and @options[cast[:long]]
raise ArgumentError, "No such directory: '#{@options[cast[:long]]}'" unless File.directory? @options[cast[:long]]
end
end
# Check options and raise unless allowed.
def options_check_allowed(cast)
- if cast[:allowed] and @options.has_key? cast[:long]
+ if cast[:allowed] and @options[cast[:long]]
allowed_hash = {}
cast[:allowed].split(',').each { |a| allowed_hash[a.to_s] = 1 }
- raise ArgumentError, "Argument '#{@options[cast[:long]]}' to --#{cast[:long]} not allowed" unless allowed_hash.has_key? @options[cast[:long]].to_s
+ raise ArgumentError, "Argument '#{@options[cast[:long]]}' to --#{cast[:long]} not allowed" unless allowed_hash[@options[cast[:long]].to_s]
end
end
# Check disallowed argument values and raise if disallowed.
def options_check_disallowed(cast)
- if cast[:disallowed] and @options.has_key? cast[:long]
+ if cast[:disallowed] and @options[cast[:long]]
cast[:disallowed].split(',').each do |val|
raise ArgumentError, "Argument '#{@options[cast[:long]]}' to --#{cast[:long]} is disallowed" if val.to_s == @options[cast[:long]].to_s
end
def set
time0 = Time.new.strftime("%Y-%m-%d %X")
- File.open(path, mode="w") do |fh|
+ File.open(path, "w") do |fh|
+ fh.flock(File::LOCK_EX)
fh.puts [time0, ARGV.join(" ")].join(";")
end
end
def set_tmpdir(tmpdir_path)
status = ""
- File.open(path, mode="r") do |fh|
+ File.open(path, "r") do |fh|
+ fh.flock(File::LOCK_SH)
status = fh.read.chomp
end
status = "#{status};#{tmpdir_path}\n"
- File.open(path, mode="w") do |fh|
+ File.open(path, "w") do |fh|
+ fh.flock(File::LOCK_EX)
fh << status
end
end
# Extract the temporary directory path from the status file,
# and return this or nil if not found.
def get_tmpdir
- File.open(path, mode="r") do |fh|
+ File.open(path, "r") do |fh|
+ fh.flock(File::LOCK_SH)
tmpdir_path = fh.read.chomp.split(";").last
return tmpdir_path if File.directory?(tmpdir_path)
end
user = ENV["USER"]
script = File.basename($0)
- stream = File.open(path)
- time0, args, tmp_dir = stream.first.split(";")
- stream.close
+ time0 = nil
+ args = nil
+
+ File.open(path, "r") do |fh|
+ fh.flock(File::LOCK_SH)
+ time0, args = fh.first.split(";")
+ end
elap = time_diff(time0, time1)
command = [script, args].join(" ")
log_file = File.join(ENV["BP_LOG"], "biopieces.log")
- File.open(log_file, mode = "a") { |file| file.puts [time0, time1, elap, user, exit_status, command].join("\t") }
+ File.open(log_file, "a") do |fh|
+ fh.flock(File::LOCK_EX)
+ fh.puts [time0, time1, elap, user, exit_status, command].join("\t")
+ end
end
# Delete status file.
script = File.basename($0)
pid = $$
path = File.join(ENV["BP_TMP"], [user, script, pid, "status"].join("."))
+
+ path
end
# Get the elapsed time from the difference between two time stamps.