chupa-text 1.1.9 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/doc/text/news.md +7 -0
- data/lib/chupa-text/external-command.rb +129 -82
- data/lib/chupa-text/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae05a44da20490f2d7833d513cfc423819dd65ef5e1d6285e5a82db8482673fa
|
4
|
+
data.tar.gz: b202c67426ca48058422f169339c069cb6bc42e892a40fd9c72bda3463610b94
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28126643d65dc7ef423dccc0f727be7b275db0005f66f4c40f0c8e5dafe8b159cdea2b6c8aeca98bf7e9979849cf531ddd5afad81f30c85d031dae925029e763
|
7
|
+
data.tar.gz: 498fb93a26bfd139d9fba1d15d00bbc17547b9e326c403301794b89f2548c78e8d000ed45c3404c3b0a00073e677c1783c64b1423357893c89326d60efeb07d3
|
data/doc/text/news.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
|
1
|
+
# Copyright (C) 2014-2019 Kouhei Sutou <kou@clear-code.com>
|
2
2
|
# Copyright (C) 2010 Yuto HAYAMIZU <y.hayamizu@gmail.com>
|
3
3
|
#
|
4
4
|
# This library is free software; you can redistribute it and/or
|
@@ -20,6 +20,8 @@ require "pathname"
|
|
20
20
|
|
21
21
|
module ChupaText
|
22
22
|
class ExternalCommand
|
23
|
+
include Loggable
|
24
|
+
|
23
25
|
attr_reader :path
|
24
26
|
def initialize(path)
|
25
27
|
@path = Pathname.new(path)
|
@@ -31,12 +33,11 @@ module ChupaText
|
|
31
33
|
else
|
32
34
|
options = {}
|
33
35
|
end
|
34
|
-
spawn_options = options[:spawn_options] || {}
|
35
36
|
pid = spawn(options[:env] || {},
|
36
37
|
@path.to_s,
|
37
38
|
*arguments,
|
38
|
-
|
39
|
-
|
39
|
+
spawn_options(options[:spawn_options]))
|
40
|
+
status = wait_process(pid, options[:timeout])
|
40
41
|
status.success?
|
41
42
|
end
|
42
43
|
|
@@ -51,101 +52,147 @@ module ChupaText
|
|
51
52
|
end
|
52
53
|
|
53
54
|
private
|
54
|
-
def
|
55
|
-
|
55
|
+
def spawn_options(user_options)
|
56
|
+
options = (user_options || {}).dup
|
57
|
+
apply_default_spawn_limit(options, :cpu, :int)
|
58
|
+
apply_default_spawn_limit(options, :as, :size)
|
59
|
+
options
|
56
60
|
end
|
57
61
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
def apply_default_spawn_limit(options, key, type)
|
63
|
+
# TODO: Workaround for Ruby 2.3.3p222
|
64
|
+
case key
|
65
|
+
when :cpu
|
66
|
+
option_key = :rlimit_cpu
|
67
|
+
when :as
|
68
|
+
option_key = :rlimit_as
|
69
|
+
else
|
70
|
+
option_key = :"rlimit_#{key}"
|
65
71
|
end
|
72
|
+
return if options[option_key]
|
66
73
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
74
|
+
tag = "[limit][#{key}]"
|
75
|
+
value =
|
76
|
+
ENV["CHUPA_TEXT_EXTERNAL_COMMAND_LIMIT_#{key.to_s.upcase}"] ||
|
77
|
+
# For backward compatibility
|
78
|
+
ENV["CHUPA_EXTERNAL_COMMAND_LIMIT_#{key.to_s.upcase}"]
|
79
|
+
value = send("parse_#{type}", tag, value)
|
80
|
+
return if value.nil?
|
81
|
+
rlimit_number = Process.const_get("RLIMIT_#{key.to_s.upcase}")
|
82
|
+
soft_limit, hard_limit = Process.getrlimit(rlimit_number)
|
83
|
+
if hard_limit < value
|
84
|
+
log_hard_limit_over_value(tag, value, hard_limit)
|
85
|
+
return nil
|
71
86
|
end
|
87
|
+
limit_info = "soft-limit:#{soft_limit}, hard-limit:#{hard_limit}"
|
88
|
+
info("#{log_tag}#{tag}[set] <#{value}>(#{limit_info})")
|
72
89
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
info("#{log_tag}[#{key}][set] <#{value}>(#{limit_info})")
|
90
|
-
|
91
|
-
# TODO: Workaround for Ruby 2.3.3p222
|
92
|
-
case key
|
93
|
-
when :cpu
|
94
|
-
@options[:rlimit_cpu] = value
|
95
|
-
when :as
|
96
|
-
@options[:rlimit_as] = value
|
97
|
-
else
|
98
|
-
@options[:"rlimit_#{key}"] = value
|
99
|
-
end
|
90
|
+
options[option_key] = value
|
91
|
+
end
|
92
|
+
|
93
|
+
def log_hard_limit_over_value(tag, value, hard_limit)
|
94
|
+
warn("#{log_tag}#{tag}[large] " +
|
95
|
+
"<#{value}>(hard-limit:#{hard_limit})")
|
96
|
+
end
|
97
|
+
|
98
|
+
def parse_int(tag, value)
|
99
|
+
return nil if value.nil?
|
100
|
+
return nil if value.empty?
|
101
|
+
begin
|
102
|
+
Integer(value)
|
103
|
+
rescue ArgumentError
|
104
|
+
log_invalid_value(tag, value, type, "int")
|
105
|
+
nil
|
100
106
|
end
|
107
|
+
end
|
101
108
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
+
def parse_size(tag, value)
|
110
|
+
return nil if value.nil?
|
111
|
+
return nil if value.empty?
|
112
|
+
scale = 1
|
113
|
+
case value
|
114
|
+
when /GB?\z/i
|
115
|
+
scale = 1024 ** 3
|
116
|
+
number = $PREMATCH
|
117
|
+
when /MB?\z/i
|
118
|
+
scale = 1024 ** 2
|
119
|
+
number = $PREMATCH
|
120
|
+
when /KB?\z/i
|
121
|
+
scale = 1024 ** 1
|
122
|
+
number = $PREMATCH
|
123
|
+
when /B?\z/i
|
124
|
+
number = $PREMATCH
|
125
|
+
else
|
126
|
+
number = value
|
109
127
|
end
|
128
|
+
begin
|
129
|
+
number = Float(number)
|
130
|
+
rescue ArgumentError
|
131
|
+
log_invalid_value(tag, value, "size")
|
132
|
+
return nil
|
133
|
+
end
|
134
|
+
(number * scale).to_i
|
135
|
+
end
|
110
136
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
log_invalid_value(key, value, "size")
|
133
|
-
return nil
|
134
|
-
end
|
135
|
-
(number * scale).to_i
|
137
|
+
def parse_time(tag, value)
|
138
|
+
return nil if value.nil?
|
139
|
+
return nil if value.empty?
|
140
|
+
scale = 1
|
141
|
+
case value
|
142
|
+
when /h\z/i
|
143
|
+
scale = 60 * 60
|
144
|
+
number = $PREMATCH
|
145
|
+
when /m\z/i
|
146
|
+
scale = 60
|
147
|
+
number = $PREMATCH
|
148
|
+
when /s\z/i
|
149
|
+
number = $PREMATCH
|
150
|
+
else
|
151
|
+
number = value
|
152
|
+
end
|
153
|
+
begin
|
154
|
+
number = Float(number)
|
155
|
+
rescue ArgumentError
|
156
|
+
log_invalid_value(tag, value, "time")
|
157
|
+
return nil
|
136
158
|
end
|
159
|
+
(number * scale).to_f
|
160
|
+
end
|
161
|
+
|
162
|
+
def log_invalid_value(tag, value, type)
|
163
|
+
warn("#{log_tag}#{tag}[invalid] <#{value}>(#{type})")
|
164
|
+
end
|
137
165
|
|
138
|
-
|
139
|
-
|
166
|
+
def wait_process(pid, timeout)
|
167
|
+
if timeout.nil?
|
168
|
+
timeout_env = ENV["CHUPA_TEXT_EXTERNAL_COMMAND_TIMEOUT"]
|
169
|
+
timeout = parse_time("[timeout]", timeout_env) if timeout_env
|
140
170
|
end
|
141
171
|
|
142
|
-
|
143
|
-
|
172
|
+
if timeout
|
173
|
+
status = wait_process_timeout(pid, timeout)
|
174
|
+
return status if status
|
175
|
+
Process.kill(:TERM, pid)
|
176
|
+
status = wait_process_timeout(pid, 5)
|
177
|
+
return status if status
|
178
|
+
Process.kill(:KILL, pid)
|
144
179
|
end
|
180
|
+
_, status = Process.waitpid2(pid)
|
181
|
+
status
|
182
|
+
end
|
145
183
|
|
146
|
-
|
147
|
-
|
184
|
+
def wait_process_timeout(pid, timeout)
|
185
|
+
limit = Time.now + timeout
|
186
|
+
while Time.now < limit
|
187
|
+
_, status = Process.waitpid2(pid, Process::WNOHANG)
|
188
|
+
return status if status
|
189
|
+
sleep(1)
|
148
190
|
end
|
191
|
+
nil
|
192
|
+
end
|
193
|
+
|
194
|
+
def log_tag
|
195
|
+
"[external-command]"
|
149
196
|
end
|
150
197
|
end
|
151
198
|
end
|
data/lib/chupa-text/version.rb
CHANGED