hets.rb revision 519002bc41b20a069be1c669660e702f9bd4a593
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Valerequire 'date'
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning muellermodule Hets
083f87068ffcf24df8b0154bfbca4ca5027f8ecehenning mueller
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger class HetsError < ::StandardError; end
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger class ExecutionError < HetsError; end
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger class DeploymentError < HetsError; end
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger class VersionOutdatedError < DeploymentError; end
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger class ConfigDateFormatError < DeploymentError; end
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger class VersionDateFormatError < DeploymentError; end
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller class Config
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger attr_reader :path, :library_path, :stack_size, :env
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller def initialize
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller yaml = YAML.load_file(File.join(Rails.root, 'config', 'hets.yml'))
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger @path = first_which_exists yaml['hets_path']
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger @library_path = first_which_exists yaml['hets_lib']
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger @stack_size = yaml['stack_size'] || '1G'
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger @env = yaml['env'] || {}
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger raise DeploymentError, 'Could not find hets' unless @path
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger raise DeploymentError, 'Hets library not found.' unless @library_path
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger unless is_compatible? yaml['version_minimum_date']
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger raise VersionOutdatedError, 'The installed version of Hets is too old'
82d525750e23960f3f2cc6a11220e0ef8505918fhenning mueller end
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger # Set hets environment variables
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger %w( hets_lib hets_owl_tools ).each do |key|
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger @env[key.upcase] = first_which_exists yaml[key]
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller end
a837d007b255d7a6cca7994e1e555aba95ce41cchenning mueller
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller end
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller
083f87068ffcf24df8b0154bfbca4ca5027f8ecehenning mueller
083f87068ffcf24df8b0154bfbca4ca5027f8ecehenning mueller private
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale # Checks Hets installation compatibility by its version date
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale #
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale # * *Args* :
b0c849916b1471424344717ada19c745833e4c5bhenning mueller # * - +minimum_date+ -> Minimum working hets version date
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale # * *Returns* :
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale # * - true if hets version minimum date prior or equal to actual hets version date
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale # * - false otherwise
b0c849916b1471424344717ada19c745833e4c5bhenning mueller def is_compatible?(minimum_date)
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale # Read Hets version minimum date
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger raise ConfigDateFormatError, 'Could not read hets version minimum date in YAML' unless minimum_date
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale # Read Hets version date
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale version = `#{@path} -V`
71fdc30cc6e637d99cacb455537e7b8fbfe77395henning mueller version_date = begin
b0c849916b1471424344717ada19c745833e4c5bhenning mueller Date.parse version.split.last
71fdc30cc6e637d99cacb455537e7b8fbfe77395henning mueller rescue ArgumentError
71fdc30cc6e637d99cacb455537e7b8fbfe77395henning mueller nil
71fdc30cc6e637d99cacb455537e7b8fbfe77395henning mueller end
71fdc30cc6e637d99cacb455537e7b8fbfe77395henning mueller
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger raise VersionDateFormatError, 'Could not read hets version date in output of `hets -V`' unless version_date
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale # Return true if minimum date is prior or equal to version date
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale return minimum_date <= version_date
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale end
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale
a837d007b255d7a6cca7994e1e555aba95ce41cchenning mueller def first_which_exists(paths)
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger paths.map { |path| File.expand_path path }.find do |path|
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger File.exists? path
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller end
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller end
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller end
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller # Runs hets with input_file and returns XML output file path.
519002bc41b20a069be1c669660e702f9bd4a593Eugen Kuksa def self.parse(input_file, url_catalog = [], output_path = nil, structure_only: false)
705933deb08bc4269e8c08d50143af3cb5c1c670henning mueller
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger # Arguments to run the subprocess
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger args = [config.path, *%w( -o pp.xml -o xml --full-signatures -a none -v2 )]
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger
ac2169141f0b549fc8917a4b1d778f4ba3cab0bfJulian Kornberger if output_path
ac2169141f0b549fc8917a4b1d778f4ba3cab0bfJulian Kornberger FileUtils.mkdir_p output_path
aa056a2e5efb6505701a4e4a31bf2f7e71ff1738henning mueller args += ['-O', output_path]
ac2169141f0b549fc8917a4b1d778f4ba3cab0bfJulian Kornberger end
705933deb08bc4269e8c08d50143af3cb5c1c670henning mueller
519002bc41b20a069be1c669660e702f9bd4a593Eugen Kuksa args += ['-s'] if structure_only
519002bc41b20a069be1c669660e702f9bd4a593Eugen Kuksa
aa056a2e5efb6505701a4e4a31bf2f7e71ff1738henning mueller args += ['-C', url_catalog.join(',')] unless url_catalog.empty?
aa056a2e5efb6505701a4e4a31bf2f7e71ff1738henning mueller
aa056a2e5efb6505701a4e4a31bf2f7e71ff1738henning mueller # Configure stack size
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger args += ['+RTS', "-K#{config.stack_size}", '-RTS']
705933deb08bc4269e8c08d50143af3cb5c1c670henning mueller
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger # add the path to the input file as last argument
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger args << input_file
705933deb08bc4269e8c08d50143af3cb5c1c670henning mueller
b5bf21df9d1d61069e6dc9e13569543d0b868bc8Daniel Couto Vale # Executes command with low priority
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger Rails.logger.debug "Running hets with: #{args.inspect}"
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger output = Subprocess.run :nice, *args, config.env
aa056a2e5efb6505701a4e4a31bf2f7e71ff1738henning mueller
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger if output.starts_with? '*** Error'
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger # some error occured
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger raise ExecutionError, output
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger elsif match = output.lines.last.match(/Writing file: (.+)/)
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger # successful execution
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger match[1]
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger else
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger # we can not handle this response
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger raise ExecutionError, "Unexpected output:\n#{output}"
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller end
7ea9649883e1bbe8f2582db1a3c66af8b7206056henning mueller
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger rescue Subprocess::Error => e
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger output = e.output
b5bf21df9d1d61069e6dc9e13569543d0b868bc8Daniel Couto Vale
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger # Exclude usage message if exit status equals 2
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger if e.status == 2 and output.include? 'Usage:'
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger raise ExecutionError, output.split("Usage:").first
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger else
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger raise ExecutionError, e.message
b5bf21df9d1d61069e6dc9e13569543d0b868bc8Daniel Couto Vale end
ec416eab0158cfe34b77cea4a11f8b84bc194a7aDaniel Couto Vale end
ec416eab0158cfe34b77cea4a11f8b84bc194a7aDaniel Couto Vale
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger def self.config
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger config ||= Config.new
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger end
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning muellerend