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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16a8f0167ee54c9339de2a91a3ca5dcd5550a19daac95228c57869a67e09f54c
4
- data.tar.gz: 14d0a81b1f75aef784e20fc895037397c15f0dd88dbdcda0dbed58d7f7d16f58
3
+ metadata.gz: ae05a44da20490f2d7833d513cfc423819dd65ef5e1d6285e5a82db8482673fa
4
+ data.tar.gz: b202c67426ca48058422f169339c069cb6bc42e892a40fd9c72bda3463610b94
5
5
  SHA512:
6
- metadata.gz: b6abd29982245d2817af96ef24bc2000ea99fcf89758c3eed0de8de70b3a1d25691d41898bc20c2661d5e521cb8c8d1b23fe6adeeea83b6f8515b3e9a298379f
7
- data.tar.gz: 3afc26b51edff767f8b86a3cbfa55405e07217f2b42a69a00c698f97a3e0fc2b567ef0f25b39cf645d434876f52ad246ea00c1af71faa0fc926d3fe617b2143f
6
+ metadata.gz: 28126643d65dc7ef423dccc0f727be7b275db0005f66f4c40f0c8e5dafe8b159cdea2b6c8aeca98bf7e9979849cf531ddd5afad81f30c85d031dae925029e763
7
+ data.tar.gz: 498fb93a26bfd139d9fba1d15d00bbc17547b9e326c403301794b89f2548c78e8d000ed45c3404c3b0a00073e677c1783c64b1423357893c89326d60efeb07d3
data/doc/text/news.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # News
2
2
 
3
+ ## 1.2.0: 2019-03-03
4
+
5
+ ### Improvements
6
+
7
+ * Added support timeout for external command execution by
8
+ `CHUPA_TEXT_EXTERNAL_COMMAND_TIMEOUT` environment variable.
9
+
3
10
  ## 1.1.9: 2019-03-03
4
11
 
5
12
  ### Improvements
@@ -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
- default_spawn_options.merge(spawn_options))
39
- pid, status = Process.waitpid2(pid)
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 default_spawn_options
55
- SpawnLimitOptions.new.options
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
- class SpawnLimitOptions
59
- include Loggable
60
-
61
- attr_reader :options
62
- def initialize
63
- @options = {}
64
- set_default_options
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
- private
68
- def set_default_options
69
- set_option(:cpu, :int)
70
- set_option(:as, :size)
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
- def set_option(key, type)
74
- value =
75
- ENV["CHUPA_TEXT_EXTERNAL_COMMAND_LIMIT_#{key.to_s.upcase}"] ||
76
- # For backward compatibility
77
- ENV["CHUPA_EXTERNAL_COMMAND_LIMIT_#{key.to_s.upcase}"]
78
- return if value.nil?
79
- return if value.empty?
80
- value = send("parse_#{type}", key, value)
81
- return if value.nil?
82
- rlimit_number = Process.const_get("RLIMIT_#{key.to_s.upcase}")
83
- soft_limit, hard_limit = Process.getrlimit(rlimit_number)
84
- if hard_limit < value
85
- log_hard_limit_over_value(key, value, hard_limit)
86
- return nil
87
- end
88
- limit_info = "soft-limit:#{soft_limit}, hard-limit:#{hard_limit}"
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
- def parse_int(key, value)
103
- begin
104
- Integer(value)
105
- rescue ArgumentError
106
- log_invalid_value(key, value, type, "int")
107
- nil
108
- end
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
- def parse_size(key, value)
112
- return nil if value.nil?
113
- scale = 1
114
- case value
115
- when /GB?\z/i
116
- scale = 1024 ** 3
117
- number = $PREMATCH
118
- when /MB?\z/i
119
- scale = 1024 ** 2
120
- number = $PREMATCH
121
- when /KB?\z/i
122
- scale = 1024 ** 1
123
- number = $PREMATCH
124
- when /B?\z/i
125
- number = $PREMATCH
126
- else
127
- number = value
128
- end
129
- begin
130
- number = Float(number)
131
- rescue ArgumentError
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
- def log_hard_limit_over_value(key, value, hard_limit)
139
- warn("#{log_tag}[#{key}][large] <#{value}>(hard-limit:#{hard_limit})")
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
- def log_invalid_value(key, value, type)
143
- warn("#{log_tag}[#{key}][invalid] <#{value}>(#{type})")
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
- def log_tag
147
- "[external-command][limit]"
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
@@ -15,5 +15,5 @@
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
  module ChupaText
18
- VERSION = "1.1.9"
18
+ VERSION = "1.2.0"
19
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chupa-text
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.9
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kouhei Sutou