chupa-text 1.2.0 → 1.2.1
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 +16 -0
- data/lib/chupa-text/decomposers/tar.rb +3 -12
- data/lib/chupa-text/decomposers/zip.rb +3 -12
- data/lib/chupa-text/external-command.rb +122 -58
- data/lib/chupa-text/version.rb +1 -1
- data/lib/chupa-text/virtual-content.rb +37 -10
- data/test/test-virtual-content.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99a53085d7eca8e459b0944e44cdb415036d19b6dc5a366e10bc3921a8c8cb09
|
4
|
+
data.tar.gz: ce808a0a9e9352e2b4cf92c9e7348b57e522ee1717dc8070631451aa6a3b9a29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 334356c90df57f22ae1fe0871e93147470c7505782487f71613f3fa794ea7fe0ed03b16980892beb46d662f830b876b6b4ff5132b8677892be1246ea26e38f40
|
7
|
+
data.tar.gz: 86de4013d3f07d4d89c2113d01d78d4e6685b95af28ab1ad72267908d3c4b9ea30720eec515380989b6fb2a50d913041ee8223197cbcfa00c51b61b97506d1d7
|
data/doc/text/news.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## 1.2.1: 2019-03-04
|
4
|
+
|
5
|
+
### Improvements
|
6
|
+
|
7
|
+
* `ChupaText::ExternalCommand`:
|
8
|
+
|
9
|
+
* Added more logs.
|
10
|
+
|
11
|
+
* Added support for ensuring killing external command.
|
12
|
+
|
13
|
+
* Added default value API.
|
14
|
+
|
15
|
+
* `ChupaText::VirtualFileContent`:
|
16
|
+
|
17
|
+
* Added support for inlining small data.
|
18
|
+
|
3
19
|
## 1.2.0: 2019-03-03
|
4
20
|
|
5
21
|
### Improvements
|
@@ -40,18 +40,9 @@ module ChupaText
|
|
40
40
|
path_converter = PathConverter.new(entry.full_name,
|
41
41
|
uri_escape: true)
|
42
42
|
entry_uri.path = "#{base_path}/#{path_converter.convert}"
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
entry_data.uri = entry_uri
|
47
|
-
body = entry.read || ""
|
48
|
-
entry_data.body = body
|
49
|
-
entry_data.size = body.bytesize
|
50
|
-
else
|
51
|
-
entry_data = VirtualFileData.new(entry_uri,
|
52
|
-
entry,
|
53
|
-
:source_data => data)
|
54
|
-
end
|
43
|
+
entry_data = VirtualFileData.new(entry_uri,
|
44
|
+
entry,
|
45
|
+
:source_data => data)
|
55
46
|
yield(entry_data)
|
56
47
|
end
|
57
48
|
end
|
@@ -49,18 +49,9 @@ module ChupaText
|
|
49
49
|
encoding: base_path.encoding,
|
50
50
|
uri_escape: true)
|
51
51
|
entry_uri.path = "#{base_path}/#{path_converter.convert}"
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
entry_data.uri = entry_uri
|
56
|
-
body = entry.file_data.read
|
57
|
-
entry_data.body = body
|
58
|
-
entry_data.size = body.bytesize
|
59
|
-
else
|
60
|
-
entry_data = VirtualFileData.new(entry_uri,
|
61
|
-
entry.file_data,
|
62
|
-
source_data: data)
|
63
|
-
end
|
52
|
+
entry_data = VirtualFileData.new(entry_uri,
|
53
|
+
entry.file_data,
|
54
|
+
source_data: data)
|
64
55
|
yield(entry_data)
|
65
56
|
end
|
66
57
|
end
|
@@ -22,6 +22,42 @@ module ChupaText
|
|
22
22
|
class ExternalCommand
|
23
23
|
include Loggable
|
24
24
|
|
25
|
+
@default_timeout = nil
|
26
|
+
@default_limit_cpu = nil
|
27
|
+
@default_limit_as = nil
|
28
|
+
class << self
|
29
|
+
def default_timeout
|
30
|
+
@default_timeout || ENV["CHUPA_TEXT_EXTERNAL_COMMAND_TIMEOUT"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def default_timeout=(timeout)
|
34
|
+
@default_timeout = timeout
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_limit_cpu
|
38
|
+
@default_limit_cpu || limit_env("CPU")
|
39
|
+
end
|
40
|
+
|
41
|
+
def default_limit_cpu=(cpu)
|
42
|
+
@default_limit_cpu = cpu
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_limit_as
|
46
|
+
@default_limit_as || limit_env("AS")
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_limit_as=(as)
|
50
|
+
@default_limit_as = as
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def limit_env(name)
|
55
|
+
ENV["CHUPA_TEXT_EXTERNAL_COMMAND_LIMIT_#{name}"] ||
|
56
|
+
# For backward compatibility
|
57
|
+
ENV["CHUPA_EXTERNAL_COMMAND_LIMIT_#{name}"]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
25
61
|
attr_reader :path
|
26
62
|
def initialize(path)
|
27
63
|
@path = Pathname.new(path)
|
@@ -37,7 +73,18 @@ module ChupaText
|
|
37
73
|
@path.to_s,
|
38
74
|
*arguments,
|
39
75
|
spawn_options(options[:spawn_options]))
|
40
|
-
status =
|
76
|
+
status = nil
|
77
|
+
begin
|
78
|
+
status = wait_process(pid, options[:timeout])
|
79
|
+
ensure
|
80
|
+
unless status
|
81
|
+
begin
|
82
|
+
Process.kill(:KILL, pid)
|
83
|
+
Process.waitpid(pid)
|
84
|
+
rescue SystemCallError
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
41
88
|
status.success?
|
42
89
|
end
|
43
90
|
|
@@ -72,11 +119,8 @@ module ChupaText
|
|
72
119
|
return if options[option_key]
|
73
120
|
|
74
121
|
tag = "[limit][#{key}]"
|
75
|
-
value =
|
76
|
-
|
77
|
-
# For backward compatibility
|
78
|
-
ENV["CHUPA_EXTERNAL_COMMAND_LIMIT_#{key.to_s.upcase}"]
|
79
|
-
value = send("parse_#{type}", tag, value)
|
122
|
+
value = self.class.__send__("default_limit_#{key}")
|
123
|
+
value = __send__("parse_#{type}", tag, value)
|
80
124
|
return if value.nil?
|
81
125
|
rlimit_number = Process.const_get("RLIMIT_#{key.to_s.upcase}")
|
82
126
|
soft_limit, hard_limit = Process.getrlimit(rlimit_number)
|
@@ -96,67 +140,87 @@ module ChupaText
|
|
96
140
|
end
|
97
141
|
|
98
142
|
def parse_int(tag, value)
|
99
|
-
|
100
|
-
|
101
|
-
begin
|
102
|
-
Integer(value)
|
103
|
-
rescue ArgumentError
|
104
|
-
log_invalid_value(tag, value, type, "int")
|
143
|
+
case value
|
144
|
+
when nil
|
105
145
|
nil
|
146
|
+
when Integer
|
147
|
+
value
|
148
|
+
when Float
|
149
|
+
value.round
|
150
|
+
else
|
151
|
+
return nil if value.empty?
|
152
|
+
begin
|
153
|
+
Integer(value)
|
154
|
+
rescue ArgumentError
|
155
|
+
log_invalid_value(tag, value, type, "int")
|
156
|
+
nil
|
157
|
+
end
|
106
158
|
end
|
107
159
|
end
|
108
160
|
|
109
161
|
def parse_size(tag, value)
|
110
|
-
return nil if value.nil?
|
111
|
-
return nil if value.empty?
|
112
|
-
scale = 1
|
113
162
|
case value
|
114
|
-
when
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
163
|
+
when nil
|
164
|
+
nil
|
165
|
+
when Numeric
|
166
|
+
value
|
125
167
|
else
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
168
|
+
return nil if value.empty?
|
169
|
+
scale = 1
|
170
|
+
case value
|
171
|
+
when /GB?\z/i
|
172
|
+
scale = 1024 ** 3
|
173
|
+
number = $PREMATCH
|
174
|
+
when /MB?\z/i
|
175
|
+
scale = 1024 ** 2
|
176
|
+
number = $PREMATCH
|
177
|
+
when /KB?\z/i
|
178
|
+
scale = 1024 ** 1
|
179
|
+
number = $PREMATCH
|
180
|
+
when /B?\z/i
|
181
|
+
number = $PREMATCH
|
182
|
+
else
|
183
|
+
number = value
|
184
|
+
end
|
185
|
+
begin
|
186
|
+
number = Float(number)
|
187
|
+
rescue ArgumentError
|
188
|
+
log_invalid_value(tag, value, "size")
|
189
|
+
return nil
|
190
|
+
end
|
191
|
+
(number * scale).to_i
|
133
192
|
end
|
134
|
-
(number * scale).to_i
|
135
193
|
end
|
136
194
|
|
137
195
|
def parse_time(tag, value)
|
138
|
-
return nil if value.nil?
|
139
|
-
return nil if value.empty?
|
140
|
-
scale = 1
|
141
196
|
case value
|
142
|
-
when
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
scale = 60
|
147
|
-
number = $PREMATCH
|
148
|
-
when /s\z/i
|
149
|
-
number = $PREMATCH
|
197
|
+
when nil
|
198
|
+
nil
|
199
|
+
when Numeric
|
200
|
+
value
|
150
201
|
else
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
202
|
+
return nil if value.empty?
|
203
|
+
scale = 1
|
204
|
+
case value
|
205
|
+
when /h\z/i
|
206
|
+
scale = 60 * 60
|
207
|
+
number = $PREMATCH
|
208
|
+
when /m\z/i
|
209
|
+
scale = 60
|
210
|
+
number = $PREMATCH
|
211
|
+
when /s\z/i
|
212
|
+
number = $PREMATCH
|
213
|
+
else
|
214
|
+
number = value
|
215
|
+
end
|
216
|
+
begin
|
217
|
+
number = Float(number)
|
218
|
+
rescue ArgumentError
|
219
|
+
log_invalid_value(tag, value, "time")
|
220
|
+
return nil
|
221
|
+
end
|
222
|
+
(number * scale).to_f
|
158
223
|
end
|
159
|
-
(number * scale).to_f
|
160
224
|
end
|
161
225
|
|
162
226
|
def log_invalid_value(tag, value, type)
|
@@ -164,17 +228,17 @@ module ChupaText
|
|
164
228
|
end
|
165
229
|
|
166
230
|
def wait_process(pid, timeout)
|
167
|
-
|
168
|
-
|
169
|
-
timeout = parse_time("[timeout]", timeout_env) if timeout_env
|
170
|
-
end
|
171
|
-
|
231
|
+
tag = "[timeout]"
|
232
|
+
timeout = parse_time(tag, timeout || self.class.default_timeout)
|
172
233
|
if timeout
|
234
|
+
info("#{log_tag}#{tag}[use] <#{timeout}s>: <#{pid}>")
|
173
235
|
status = wait_process_timeout(pid, timeout)
|
174
236
|
return status if status
|
237
|
+
info("#{log_tag}#{tag}[terminate] <#{pid}>")
|
175
238
|
Process.kill(:TERM, pid)
|
176
239
|
status = wait_process_timeout(pid, 5)
|
177
240
|
return status if status
|
241
|
+
info("#{log_tag}#{tag}[kill] <#{pid}>")
|
178
242
|
Process.kill(:KILL, pid)
|
179
243
|
end
|
180
244
|
_, status = Process.waitpid2(pid)
|
data/lib/chupa-text/version.rb
CHANGED
@@ -20,12 +20,10 @@ require "tempfile"
|
|
20
20
|
|
21
21
|
module ChupaText
|
22
22
|
class VirtualContent
|
23
|
-
|
24
|
-
BUFFER_SIZE = 64 * KILO_BYTE
|
23
|
+
INLINE_MAX_SIZE = 64 * 1024
|
25
24
|
|
26
25
|
attr_reader :size
|
27
26
|
def initialize(input, original_path=nil)
|
28
|
-
@file = nil
|
29
27
|
if original_path.is_a?(String)
|
30
28
|
if original_path.empty?
|
31
29
|
original_path = nil
|
@@ -34,28 +32,56 @@ module ChupaText
|
|
34
32
|
end
|
35
33
|
end
|
36
34
|
@original_path = original_path
|
37
|
-
|
38
|
-
|
35
|
+
body = input.read(INLINE_MAX_SIZE + 1) || ""
|
36
|
+
if body.bytesize <= INLINE_MAX_SIZE
|
37
|
+
@body = body
|
38
|
+
@size = @body.bytesize
|
39
|
+
@file = nil
|
40
|
+
@path = nil
|
41
|
+
else
|
42
|
+
@body = nil
|
43
|
+
setup_file do |file|
|
44
|
+
file.write(body)
|
45
|
+
@size = body.bytesize
|
46
|
+
@size += IO.copy_stream(input, file)
|
47
|
+
end
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
42
51
|
def open(&block)
|
43
|
-
|
52
|
+
if @body
|
53
|
+
yield(StringIO.new(@body))
|
54
|
+
else
|
55
|
+
File.open(path, "rb", &block)
|
56
|
+
end
|
44
57
|
end
|
45
58
|
|
46
59
|
def body
|
47
|
-
|
48
|
-
|
60
|
+
if @body
|
61
|
+
@body
|
62
|
+
else
|
63
|
+
open do |file|
|
64
|
+
file.read
|
65
|
+
end
|
49
66
|
end
|
50
67
|
end
|
51
68
|
|
52
69
|
def peek_body(size)
|
53
|
-
|
54
|
-
|
70
|
+
if @body
|
71
|
+
@body[0, size]
|
72
|
+
else
|
73
|
+
open do |file|
|
74
|
+
file.read(size)
|
75
|
+
end
|
55
76
|
end
|
56
77
|
end
|
57
78
|
|
58
79
|
def path
|
80
|
+
if @path.nil?
|
81
|
+
setup_file do |file|
|
82
|
+
file.write(@body)
|
83
|
+
end
|
84
|
+
end
|
59
85
|
@path
|
60
86
|
end
|
61
87
|
|
@@ -77,6 +103,7 @@ module ChupaText
|
|
77
103
|
def setup_file
|
78
104
|
basename = compute_tempfile_basename
|
79
105
|
@file = Tempfile.new(basename)
|
106
|
+
@file.binmode
|
80
107
|
@path = @file.path
|
81
108
|
yield(@file)
|
82
109
|
@file.close
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
|
1
|
+
# Copyright (C) 2013-2019 Kouhei Sutou <kou@clear-code.com>
|
2
2
|
#
|
3
3
|
# This library is free software; you can redistribute it and/or
|
4
4
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -53,7 +53,7 @@ class TestVirtualContent < Test::Unit::TestCase
|
|
53
53
|
|
54
54
|
sub_test_case("large data") do
|
55
55
|
def setup
|
56
|
-
@body = "X" * (ChupaText::VirtualContent::
|
56
|
+
@body = "X" * (ChupaText::VirtualContent::INLINE_MAX_SIZE + 1)
|
57
57
|
end
|
58
58
|
|
59
59
|
def test_size
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chupa-text
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kouhei Sutou
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-03-
|
11
|
+
date: 2019-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: archive-zip
|