Navigation Menu

Skip to content

Commit

Permalink
Add ExternalCommand
Browse files Browse the repository at this point in the history
  • Loading branch information
kou committed Feb 15, 2014
1 parent 0f21192 commit 2f2bfd4
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 2 deletions.
8 changes: 6 additions & 2 deletions lib/chupa-text.rb
Expand Up @@ -26,13 +26,17 @@

require "chupa-text/configuration"
require "chupa-text/configuration-loader"
require "chupa-text/mime-type"
require "chupa-text/mime-type-registry"

require "chupa-text/external-command"

require "chupa-text/decomposer"
require "chupa-text/decomposer-registry"
require "chupa-text/decomposers"

require "chupa-text/extractor"
require "chupa-text/formatters"
require "chupa-text/mime-type"
require "chupa-text/mime-type-registry"

require "chupa-text/file-content"
require "chupa-text/virtual-content"
Expand Down
136 changes: 136 additions & 0 deletions lib/chupa-text/external-command.rb
@@ -0,0 +1,136 @@
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
# Copyright (C) 2010 Yuto HAYAMIZU <y.hayamizu@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

require "English"
require "pathname"

module ChupaText
class ExternalCommand
def initialize(command)
@command = Pathname.new(command)
end

def run(*arguments)
if arguments.last.is_a?(Hash)
options = arguments.pop
else
options = {}
end
spawn_options = options[:spawn_options] || {}
pid = spawn(options[:env] || {},
@command.to_s,
*arguments,
spawn_options.merge(default_spawn_options))
pid, status = Process.waitpid2(pid)
status.success?
end

def exist?
if @command.absolute?
@command.file? and @command.executable?
else
(ENV['PATH'] || "").split(File::PATH_SEPARATOR).any? do |path|
(Pathname.new(path) + @command).expand_path.exist?
end
end
end

private
def default_spawn_options
SpawnLimitOptions.new.options
end

class SpawnLimitOptions
attr_reader :options
def initialize
@options = {}
set_default_options
end

private
def set_default_options
set_option(:cpu, :int)
set_option(:rss, :size)
set_option(:as, :size)
end

def set_option(key, type)
value = ENV["CHUPA_EXTERNAL_COMMAND_LIMIT_#{key.to_s.upcase}"]
return if value.nil?
value = send("parse_#{type}", key, value)
return if value.nil?
rlimit_number = Process.const_get("RLIMIT_#{key.to_s.upcase}")
soft_limit, hard_limit = Process.getrlimit(rlimit_number)
if hard_limit < value
log_hard_limit_over_value(key, value, hard_limit)
return nil
end
limit_info = "soft-limit:#{soft_limit}, hard-limit:#{hard_limit}"
log(:info, "[#{key}][set] <#{value}>(#{limit_info})")
@options[:"rlimit_#{key}"] = value
end

def parse_int(key, value)
begin
Integer(value)
rescue ArgumentError
log_invalid_value(key, value, type, "int")
nil
end
end

def parse_size(key, value)
return nil if value.nil?
scale = 1
case value
when /GB?\z/i
scale = 1024 ** 3
number = $PREMATCH
when /MB?\z/i
scale = 1024 ** 2
number = $PREMATCH
when /KB?\z/i
scale = 1024 ** 1
number = $PREMATCH
when /B?\z/i
number = $PREMATCH
else
number = value
end
begin
number = Float(number)
rescue ArgumentError
log_invalid_value(key, value, "size")
return nil
end
(number * scale).to_i
end

def log_hard_limit_over_value(key, value, hard_limit)
log(:warning, "[#{key}][large] <#{value}>(hard-limit:#{hard_limit})")
end

def log_invalid_value(key, value, type)
log(:warning, "[#{key}][invalid] <#{value}>(#{type})")
end

def log(level, message)
ChupaText.logger.send(level, "[external-command][limit]#{message}")
end
end
end
end
79 changes: 79 additions & 0 deletions test/test-external-command.rb
@@ -0,0 +1,79 @@
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

require "rbconfig"

class TestExternalCommand < Test::Unit::TestCase
def ruby
RbConfig.ruby
end

def create_command(command)
ChupaText::ExternalCommand.new(command)
end

class TestRun < self
def run_command(command, *arguments)
create_command(command).run(*arguments)
end

def test_success
assert_true(run_command(ruby, "-e", "true"))
end

def test_failure
error = Tempfile.new("error")
spawn_options = {
:err => error.path,
}
assert_false(run_command(ruby,
"-e", "raise 'XXX'",
:spawn_options => spawn_options))
end
end

class TestExist < self
def setup
@original_path = ENV["PATH"]
end

def teardown
ENV["PATH"] = @original_path
end

def exist?(command)
create_command(command).exist?
end

def test_exist_absolete_path
assert_true(exist?(ruby))
end

def test_exist_in_path
ruby_dir, ruby_base_name = File.split(ruby)
ENV["PATH"] += "#{File::PATH_SEPARATOR}#{ruby_dir}"
assert_true(exist?(ruby_base_name))
end

def test_not_executable
assert_false(exist?(__FILE__))
end

def test_not_exist
assert_false(exist?("nonexistent"))
end
end
end

0 comments on commit 2f2bfd4

Please sign in to comment.