libis-tools 0.9.60 → 0.9.62

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
  SHA1:
3
- metadata.gz: 849924a2ded64d5bdf008c008bfef08c7147ed86
4
- data.tar.gz: de30bd5fdb3957bfb2065859be5dfbe21acf211a
3
+ metadata.gz: a2464bf3e02e56791cd56ff6c266ab875fec58b5
4
+ data.tar.gz: cbef32af7fde215e0b7cf2b3e8f1ca4d0c5609b9
5
5
  SHA512:
6
- metadata.gz: c38376b193fa67a9258bb1ee42e3635627a10e1b271946f134b2a425eb86bd154e29603de52f15e1c22126042afd104f220a4f5ff65606a702a8b040b90aac99
7
- data.tar.gz: 77a2529dc92b94c6cc8395363cd3ea133a9ccdc1c8061f6164f28917aed932a84f600675f5b229ed989ac109ea684e2a5cbdfecef73fa884bd36b900669f48f4
6
+ metadata.gz: 94c9e9154bfdb7b56ef646dded3b31031f8011c01a1cfd9e6f15e23349a680bcecb984734da1a383663993e0ae69c36b066f9b71364d4b39842645cd33e65e47
7
+ data.tar.gz: d67f4c5487a564cf9d24a55fd500017706d669caa3b7d7667ddf2767e3f4430d99051993073531cbad57a053f52be0860097cd94b2ed66947f90d58d18f8c1ea
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- require 'open3'
2
+ require 'timeout'
3
3
 
4
4
  module Libis
5
5
  module Tools
@@ -10,6 +10,17 @@ module Libis
10
10
  # * :out => an array with lines that were printed on the external program's standard out.
11
11
  # * :err => an array with lines that were printed on the external program's standard error.
12
12
  # * :status => exit code returned by the external program.
13
+ # * :timeout => true if the command was terminated due to a timeout.
14
+ # * :pid => pid of the command (in case <pid>.log files need to be cleaned up)
15
+ #
16
+ # Optionally an option hash can be appended to the list of arguments with:
17
+ # * :stdin_data => values sent to the command's standard input (optional, nothing sent if not present)
18
+ # * :binmode => if present and true, will set the IO communication to binary data
19
+ # * :timeout => if specified, SIGTERM signal is sent to the command after the number of seconds
20
+ # * :signal => Signal sent to the command instead of the default SIGTERM
21
+ # * :kill_after => if specified, SIGKILL signal is sent aftern the number of seconds if command is still running
22
+ # after initial signal was sent
23
+ # * any other options will be handed over to the spawn command (e.g. pgroup)
13
24
  #
14
25
  # Examples:
15
26
  #
@@ -30,32 +41,92 @@ module Libis
30
41
  # Run an external program and return status, stdout and stderr.
31
42
  #
32
43
  #
33
- # @param [String] cmd program name
34
- # @param [Array<String>] opts optional list of command line arguments
44
+ # @param [Array<String>] cmd command name optionally prepended with env and appended with command-line arguments
35
45
  # @return [Hash] a Hash with:
36
46
  # * :status (Integer) - the exit status of the command
37
47
  # * :out (Array<String>) - the stdout output of the command
38
48
  # * :err (Array<String>)- the stderr output of the command
39
- def self.run(cmd, *opts)
49
+ # * :timeout(Boolean) - if true, the command did not return in time
50
+ # * :pid(Integer) - the command's processID
51
+ def self.run(*cmd)
52
+
53
+ spawn_opts = Hash === cmd.last ? cmd.pop.dup : {}
54
+ opts = {
55
+ :stdin_data => spawn_opts.delete(:stdin_data) || '',
56
+ :binmode => spawn_opts.delete(:binmode) || false,
57
+ :timeout => spawn_opts.delete(:timeout),
58
+ :signal => spawn_opts.delete(:signal) || :TERM,
59
+ :kill_after => spawn_opts.delete(:kill_after),
60
+ }
61
+ in_r, in_w = IO.pipe
62
+ out_r, out_w = IO.pipe
63
+ err_r, err_w = IO.pipe
64
+ in_w.sync = true
65
+
66
+ if opts[:binmode]
67
+ in_w.binmode
68
+ out_r.binmode
69
+ err_r.binmode
70
+ end
71
+
72
+ spawn_opts[:in] = in_r
73
+ spawn_opts[:out] = out_w
74
+ spawn_opts[:err] = err_w
75
+
40
76
  result = {
41
- status: 999,
42
- out: [],
43
- err: []
77
+ :pid => nil,
78
+ :status => nil,
79
+ :out => [],
80
+ :err => [],
81
+ :timeout => false,
44
82
  }
83
+
84
+ out_reader = nil
85
+ err_reader = nil
86
+ wait_thr = nil
87
+
45
88
  begin
46
- output, error, status = Open3.capture3(cmd, *opts)
47
- result[:out] = output.split("\n").map(&:chomp)
48
- result[:err] = error.split("\n").map(&:chomp)
49
- result[:status] = status.exitstatus
89
+ Timeout.timeout(opts[:timeout]) do
90
+ result[:pid] = spawn(*cmd, spawn_opts)
91
+ wait_thr = Process.detach(result[:pid])
92
+ in_r.close
93
+ out_w.close
94
+ err_w.close
95
+
96
+ out_reader = Thread.new {out_r.read}
97
+ err_reader = Thread.new {err_r.read}
98
+
99
+ in_w.write opts[:stdin_data]
100
+ in_w.close
101
+
102
+ result[:status] = wait_thr.value
103
+ end
104
+
105
+ rescue Timeout::Error
106
+ result[:timeout] = true
107
+ pid = spawn_opts[:pgroup] ? -result[:pid] : result[:pid]
108
+ Process.kill(opts[:signal], pid)
109
+ if opts[:kill_after]
110
+ unless wait_thr.join(opts[:kill_after])
111
+ Process.kill(:KILL, pid)
112
+ end
113
+ end
50
114
 
51
115
  rescue StandardError => e
52
116
  result[:err] = [e.class.name, e.message]
53
117
 
118
+ ensure
119
+ result[:status] = wait_thr.value.exitstatus if wait_thr
120
+ result[:out] += out_reader.value.split("\n").map(&:chomp) if out_reader
121
+ result[:err] += err_reader.value.split("\n").map(&:chomp) if err_reader
122
+ out_r.close unless out_r.closed?
123
+ err_r.close unless err_r.closed?
54
124
  end
55
125
 
56
126
  result
57
127
 
58
128
  end
129
+
59
130
  end
60
131
 
61
132
  end
@@ -240,11 +240,7 @@ module Libis
240
240
 
241
241
  def get_id(klass)
242
242
  self.mutex.synchronize do
243
- if @id_map[klass]
244
- @id_map[klass] += 1
245
- else
246
- @id_map[klass] = 1
247
- end
243
+ @id_map[klass] = (@id_map[klass] ? @id_map[klass] + 1 : 1)
248
244
  return @id_map[klass]
249
245
  end
250
246
  end
@@ -1,4 +1,5 @@
1
1
  require 'libis/tools/thread_safe'
2
+ require 'uri'
2
3
 
3
4
  module Libis
4
5
  module Tools
@@ -280,9 +281,9 @@ module Libis
280
281
  compositionLevel: composition_level,
281
282
  # fileLocationType: 'FILE',
282
283
  # fileLocation: '',
283
- fileOriginalName: orig_name,
284
- fileOriginalPath: orig_path,
285
- fileOriginalID: location,
284
+ fileOriginalName: URI.encode(orig_name),
285
+ fileOriginalPath: URI.encode(orig_path),
286
+ fileOriginalID: URI.encode(location),
286
287
  fileExtension: ::File.extname(orig_name),
287
288
  fileMIMEType: mimetype,
288
289
  fileSizeBytes: size,
@@ -1,5 +1,5 @@
1
1
  module Libis
2
2
  module Tools
3
- VERSION = '0.9.60'
3
+ VERSION = '0.9.62'
4
4
  end
5
5
  end
data/spec/command_spec.rb CHANGED
@@ -61,4 +61,27 @@ describe 'Command' do
61
61
 
62
62
  end
63
63
 
64
+ it 'should allow to supply input data' do
65
+
66
+ result = Libis::Tools::Command.run('cat', stdin_data: "FooBar", timeout: 1)
67
+ expect(result[:out]).to eq ['FooBar']
68
+ expect(result[:err].size).to eq 0
69
+ expect(result[:status]).to eq 0
70
+
71
+ end
72
+
73
+ it 'should not timeout if command finishes' do
74
+
75
+ result = Libis::Tools::Command.run('cat', stdin_data: "FooBar", timeout: 1)
76
+ expect(result[:timeout]).to be_falsey
77
+
78
+ end
79
+
80
+ it 'should timeout if command hangs' do
81
+
82
+ result = Libis::Tools::Command.run('ls', '-aRlp', '/', timeout: 1)
83
+ expect(result[:timeout]).to be_truthy
84
+
85
+ end
86
+
64
87
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libis-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.60
4
+ version: 0.9.62
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kris Dekeyser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-22 00:00:00.000000000 Z
11
+ date: 2018-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler