cheetah 0.3.0 → 0.4.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.
- data/CHANGELOG +10 -0
- data/README.md +1 -1
- data/VERSION +1 -1
- data/lib/cheetah.rb +74 -35
- metadata +76 -86
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
0.4.0 (2013-11-21)
|
2
|
+
------------------
|
3
|
+
|
4
|
+
* Implemented incremental logging. The input and both outputs of the executed
|
5
|
+
command are now logged one-by-line by the default recorder. A custom recorder
|
6
|
+
can record them on even finer granularity.
|
7
|
+
* Dropped support of Ruby 1.8.7.
|
8
|
+
* Added support of Ruby 2.0.0.
|
9
|
+
* Internal code improvements.
|
10
|
+
|
1
11
|
0.3.0 (2012-06-21)
|
2
12
|
------------------
|
3
13
|
|
data/README.md
CHANGED
@@ -164,7 +164,7 @@ For more information, see the
|
|
164
164
|
Compatibility
|
165
165
|
-------------
|
166
166
|
|
167
|
-
Cheetah should run well on any Unix system with Ruby 1.
|
167
|
+
Cheetah should run well on any Unix system with Ruby 1.9.3 or 2.0.0. Non-Unix
|
168
168
|
systems and different Ruby implementations/versions may work too but they were
|
169
169
|
not tested.
|
170
170
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/lib/cheetah.rb
CHANGED
@@ -90,35 +90,36 @@ module Cheetah
|
|
90
90
|
abstract_method :record_commands
|
91
91
|
|
92
92
|
# @!method record_stdin(stdin)
|
93
|
-
# Called to record the executed command input
|
94
|
-
# stream).
|
93
|
+
# Called to record part of the executed command input.
|
95
94
|
#
|
96
95
|
# @abstract
|
97
|
-
# @param [String] stdin the executed command input
|
96
|
+
# @param [String] stdin part of the executed command input
|
98
97
|
abstract_method :record_stdin
|
99
98
|
|
100
|
-
# @!method record_status(status)
|
101
|
-
# Called to record the executed command exit status.
|
102
|
-
#
|
103
|
-
# @abstract
|
104
|
-
# @param [Process::Status] status the executed command exit status
|
105
|
-
abstract_method :record_status
|
106
|
-
|
107
99
|
# @!method record_stdout(stdout)
|
108
|
-
# Called to record the output the executed command wrote to
|
109
|
-
#
|
100
|
+
# Called to record part of the output the executed command wrote to
|
101
|
+
# stdout.
|
110
102
|
#
|
111
103
|
# @abstract
|
112
|
-
# @param [String] stdout the output the executed command wrote to
|
104
|
+
# @param [String] stdout part of the output the executed command wrote to
|
105
|
+
# stdout
|
113
106
|
abstract_method :record_stdout
|
114
107
|
|
115
108
|
# @!method record_stderr(stderr)
|
116
|
-
# Called to record the output the executed command wrote to
|
117
|
-
#
|
109
|
+
# Called to record part of the output the executed command wrote to
|
110
|
+
# stderr.
|
118
111
|
#
|
119
112
|
# @abstract
|
120
|
-
# @param [String] stderr the output the executed command wrote to
|
113
|
+
# @param [String] stderr part of the output the executed command wrote to
|
114
|
+
# stderr
|
121
115
|
abstract_method :record_stderr
|
116
|
+
|
117
|
+
# @!method record_status(status)
|
118
|
+
# Called to record the executed command exit status.
|
119
|
+
#
|
120
|
+
# @abstract
|
121
|
+
# @param [Process::Status] status the executed command exit status
|
122
|
+
abstract_method :record_status
|
122
123
|
end
|
123
124
|
|
124
125
|
# A recorder that does not record anyting. Used by {Cheetah.run} when no
|
@@ -126,17 +127,27 @@ module Cheetah
|
|
126
127
|
class NullRecorder < Recorder
|
127
128
|
def record_commands(commands); end
|
128
129
|
def record_stdin(stdin); end
|
129
|
-
def record_status(status); end
|
130
130
|
def record_stdout(stdout); end
|
131
131
|
def record_stderr(stderr); end
|
132
|
+
def record_status(status); end
|
132
133
|
end
|
133
134
|
|
134
135
|
# A default recorder. It uses the `Logger::INFO` level for normal messages and
|
135
136
|
# the `Logger::ERROR` level for messages about errors (non-zero exit status or
|
136
137
|
# non-empty error output). Used by {Cheetah.run} when a logger is passed.
|
137
138
|
class DefaultRecorder < Recorder
|
139
|
+
# @private
|
140
|
+
STREAM_INFO = {
|
141
|
+
:stdin => { :name => "Standard input", :method => :info },
|
142
|
+
:stdout => { :name => "Standard output", :method => :info },
|
143
|
+
:stderr => { :name => "Error output", :method => :error }
|
144
|
+
}
|
145
|
+
|
138
146
|
def initialize(logger)
|
139
147
|
@logger = logger
|
148
|
+
|
149
|
+
@stream_used = { :stdin => false, :stdout => false, :stderr => false }
|
150
|
+
@stream_buffer = { :stdin => "", :stdout => "", :stderr => "" }
|
140
151
|
end
|
141
152
|
|
142
153
|
def record_commands(commands)
|
@@ -144,32 +155,54 @@ module Cheetah
|
|
144
155
|
end
|
145
156
|
|
146
157
|
def record_stdin(stdin)
|
147
|
-
|
148
|
-
end
|
149
|
-
|
150
|
-
def record_status(status)
|
151
|
-
@logger.send status.success? ? :info : :error,
|
152
|
-
"Status: #{status.exitstatus}"
|
158
|
+
log_stream_increment(:stdin, stdin)
|
153
159
|
end
|
154
160
|
|
155
161
|
def record_stdout(stdout)
|
156
|
-
|
162
|
+
log_stream_increment(:stdout, stdout)
|
157
163
|
end
|
158
164
|
|
159
165
|
def record_stderr(stderr)
|
160
|
-
|
161
|
-
"Error output: #{format_input_output(stderr)}"
|
166
|
+
log_stream_increment(:stderr, stderr)
|
162
167
|
end
|
163
168
|
|
164
|
-
|
169
|
+
def record_status(status)
|
170
|
+
log_stream_remainder(:stdin)
|
171
|
+
log_stream_remainder(:stdout)
|
172
|
+
log_stream_remainder(:stderr)
|
165
173
|
|
166
|
-
|
167
|
-
|
174
|
+
@logger.send status.success? ? :info : :error,
|
175
|
+
"Status: #{status.exitstatus}"
|
168
176
|
end
|
169
177
|
|
178
|
+
protected
|
179
|
+
|
170
180
|
def format_commands(commands)
|
171
181
|
'"' + commands.map { |c| Shellwords.join(c) }.join(" | ") + '"'
|
172
182
|
end
|
183
|
+
|
184
|
+
def log_stream_increment(stream, data)
|
185
|
+
@stream_buffer[stream] + data =~ /\A((?:.*\n)*)(.*)\z/
|
186
|
+
lines, rest = $1, $2
|
187
|
+
|
188
|
+
lines.each_line { |l| log_stream_line(stream, l) }
|
189
|
+
|
190
|
+
@stream_used[stream] = true
|
191
|
+
@stream_buffer[stream] = rest
|
192
|
+
end
|
193
|
+
|
194
|
+
def log_stream_remainder(stream)
|
195
|
+
if @stream_used[stream] && !@stream_buffer[stream].empty?
|
196
|
+
log_stream_line(stream, @stream_buffer[stream])
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def log_stream_line(stream, line)
|
201
|
+
@logger.send(
|
202
|
+
STREAM_INFO[stream][:method],
|
203
|
+
"#{STREAM_INFO[stream][:name]}: #{line.chomp}"
|
204
|
+
)
|
205
|
+
end
|
173
206
|
end
|
174
207
|
|
175
208
|
# @private
|
@@ -322,18 +355,15 @@ module Cheetah
|
|
322
355
|
recorder = build_recorder(options)
|
323
356
|
|
324
357
|
recorder.record_commands(commands)
|
325
|
-
recorder.record_stdin(streams[:stdin].string) unless streamed[:stdin]
|
326
358
|
|
327
359
|
pid, pipes = fork_commands(commands)
|
328
|
-
select_loop(streams, pipes)
|
360
|
+
select_loop(streams, pipes, recorder)
|
329
361
|
pid, status = Process.wait2(pid)
|
330
362
|
|
331
363
|
begin
|
332
364
|
check_errors(commands, status, streams, streamed)
|
333
365
|
ensure
|
334
366
|
recorder.record_status(status)
|
335
|
-
recorder.record_stdout(streams[:stdout].string) unless streamed[:stdout]
|
336
|
-
recorder.record_stderr(streams[:stderr].string) unless streamed[:stderr]
|
337
367
|
end
|
338
368
|
|
339
369
|
build_result(streams, options)
|
@@ -449,7 +479,7 @@ module Cheetah
|
|
449
479
|
[pid, pipes]
|
450
480
|
end
|
451
481
|
|
452
|
-
def select_loop(streams, pipes)
|
482
|
+
def select_loop(streams, pipes, recorder)
|
453
483
|
# We write the command's input and read its output using a select loop.
|
454
484
|
# Why? Because otherwise we could end up with a deadlock.
|
455
485
|
#
|
@@ -465,6 +495,10 @@ module Cheetah
|
|
465
495
|
pipes[:stdout][READ] => streams[:stdout],
|
466
496
|
pipes[:stderr][READ] => streams[:stderr]
|
467
497
|
}
|
498
|
+
recorder_methods = {
|
499
|
+
pipes[:stdout][READ] => :record_stdout,
|
500
|
+
pipes[:stderr][READ] => :record_stderr
|
501
|
+
}
|
468
502
|
pipes_readable = [pipes[:stdout][READ], pipes[:stderr][READ]]
|
469
503
|
pipes_writable = [pipes[:stdin][WRITE]]
|
470
504
|
loop do
|
@@ -482,10 +516,14 @@ module Cheetah
|
|
482
516
|
|
483
517
|
ios_read.each do |pipe|
|
484
518
|
begin
|
485
|
-
|
519
|
+
data = pipe.readpartial(4096)
|
486
520
|
rescue EOFError
|
487
521
|
pipe.close
|
522
|
+
next
|
488
523
|
end
|
524
|
+
|
525
|
+
outputs[pipe] << data
|
526
|
+
recorder.send(recorder_methods[pipe], data)
|
489
527
|
end
|
490
528
|
|
491
529
|
ios_write.each do |pipe|
|
@@ -496,6 +534,7 @@ module Cheetah
|
|
496
534
|
end
|
497
535
|
|
498
536
|
n = pipe.syswrite(stdin_buffer)
|
537
|
+
recorder.record_stdin(stdin_buffer[0...n])
|
499
538
|
stdin_buffer = stdin_buffer[n..-1]
|
500
539
|
end
|
501
540
|
end
|
metadata
CHANGED
@@ -1,128 +1,118 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: cheetah
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
- 0
|
10
|
-
version: 0.3.0
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- David Majda
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2013-11-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
22
15
|
name: abstract_method
|
23
|
-
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
25
17
|
none: false
|
26
|
-
requirements:
|
18
|
+
requirements:
|
27
19
|
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 1
|
32
|
-
- 2
|
33
|
-
version: "1.2"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.2'
|
34
22
|
type: :runtime
|
35
|
-
version_requirements: *id001
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: rspec
|
38
23
|
prerelease: false
|
39
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
25
|
none: false
|
41
|
-
requirements:
|
42
|
-
- -
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.2'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
48
38
|
type: :development
|
49
|
-
version_requirements: *id002
|
50
|
-
- !ruby/object:Gem::Dependency
|
51
|
-
name: redcarpet
|
52
39
|
prerelease: false
|
53
|
-
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
41
|
none: false
|
55
|
-
requirements:
|
56
|
-
- -
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: redcarpet
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
62
54
|
type: :development
|
63
|
-
version_requirements: *id003
|
64
|
-
- !ruby/object:Gem::Dependency
|
65
|
-
name: yard
|
66
55
|
prerelease: false
|
67
|
-
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: yard
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
68
65
|
none: false
|
69
|
-
requirements:
|
70
|
-
- -
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
|
73
|
-
segments:
|
74
|
-
- 0
|
75
|
-
version: "0"
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
76
70
|
type: :development
|
77
|
-
|
78
|
-
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Your swiss army knife for executing external commands in Ruby safely
|
79
|
+
and conveniently.
|
79
80
|
email: dmajda@suse.de
|
80
81
|
executables: []
|
81
|
-
|
82
82
|
extensions: []
|
83
|
-
|
84
83
|
extra_rdoc_files: []
|
85
|
-
|
86
|
-
files:
|
84
|
+
files:
|
87
85
|
- CHANGELOG
|
88
86
|
- LICENSE
|
89
87
|
- README.md
|
90
88
|
- VERSION
|
91
89
|
- lib/cheetah.rb
|
92
90
|
- lib/cheetah/version.rb
|
93
|
-
has_rdoc: true
|
94
91
|
homepage: https://github.com/openSUSE/cheetah
|
95
|
-
licenses:
|
92
|
+
licenses:
|
96
93
|
- MIT
|
97
94
|
post_install_message:
|
98
95
|
rdoc_options: []
|
99
|
-
|
100
|
-
require_paths:
|
96
|
+
require_paths:
|
101
97
|
- lib
|
102
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
99
|
none: false
|
104
|
-
requirements:
|
105
|
-
- -
|
106
|
-
- !ruby/object:Gem::Version
|
107
|
-
|
108
|
-
|
109
|
-
- 0
|
110
|
-
version: "0"
|
111
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
105
|
none: false
|
113
|
-
requirements:
|
114
|
-
- -
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
|
117
|
-
segments:
|
118
|
-
- 0
|
119
|
-
version: "0"
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
120
110
|
requirements: []
|
121
|
-
|
122
111
|
rubyforge_project:
|
123
|
-
rubygems_version: 1.
|
112
|
+
rubygems_version: 1.8.23
|
124
113
|
signing_key:
|
125
114
|
specification_version: 3
|
126
|
-
summary: Your swiss army knife for executing external commands in Ruby safely and
|
115
|
+
summary: Your swiss army knife for executing external commands in Ruby safely and
|
116
|
+
conveniently.
|
127
117
|
test_files: []
|
128
|
-
|
118
|
+
has_rdoc:
|