cocaine 0.5.8 → 0.6.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +13 -197
- data/cocaine.gemspec +1 -1
- data/lib/cocaine.rb +9 -9
- data/lib/cocaine/version.rb +1 -2
- metadata +10 -27
- data/lib/cocaine/command_line.rb +0 -197
- data/lib/cocaine/command_line/multi_pipe.rb +0 -50
- data/lib/cocaine/command_line/output.rb +0 -12
- data/lib/cocaine/command_line/runners.rb +0 -7
- data/lib/cocaine/command_line/runners/backticks_runner.rb +0 -30
- data/lib/cocaine/command_line/runners/fake_runner.rb +0 -30
- data/lib/cocaine/command_line/runners/popen_runner.rb +0 -29
- data/lib/cocaine/command_line/runners/posix_runner.rb +0 -49
- data/lib/cocaine/command_line/runners/process_runner.rb +0 -41
- data/lib/cocaine/exceptions.rb +0 -8
- data/lib/cocaine/os_detector.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 42a6b84941e1f52afbc43e5b0fff0dc534668c516427ba7dea6733082ee5f978
|
4
|
+
data.tar.gz: 58ef2f4fc4d3d85956500094a1727f61ace61e11f306704b15abd20ddacce8ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd079d559e02c3a1d53c1df45cba1cb9e88dce214cf3f6f92dd9a459174bb9505fc534ea7321cfbc2ff2200c6ab13aad2de7cc0c114f4bf50496cec806bcf74e
|
7
|
+
data.tar.gz: 9fd6add73507e9ef1139b05bfe3c7f53eaee262e5b366793f64addc9fdccdf286707ea68168ae746ae945e785332c6861be74d901ed5c8b23c061c5ea55c126b
|
data/README.md
CHANGED
@@ -1,215 +1,31 @@
|
|
1
|
-
# Cocaine
|
1
|
+
# Cocaine has been renamed to Terrapin
|
2
2
|
|
3
|
-
|
3
|
+
Please track further development on (the Terrapin project
|
4
|
+
page)[http://github.com/thoughtbot/terrapin].
|
4
5
|
|
5
|
-
|
6
|
+
The final version of this gem simply requires Terrapin. It should not function any
|
7
|
+
differently from previous versions.
|
6
8
|
|
7
|
-
##
|
9
|
+
## Upgrading to Terrapin
|
8
10
|
|
9
|
-
|
11
|
+
Upgrading to Terrapin is expected to be as simple as replacing the `Cocaine`
|
12
|
+
constant with `Terrapin`. That is
|
10
13
|
|
11
14
|
```ruby
|
12
|
-
|
13
|
-
line.command # => "echo hello 'world'"
|
14
|
-
line.run # => "hello world\n"
|
15
|
+
Cocaine::CommandLine.new("echo", "hello")
|
15
16
|
```
|
16
17
|
|
17
|
-
|
18
|
+
should become
|
18
19
|
|
19
20
|
```ruby
|
20
|
-
|
21
|
-
line.command(in: "omg.jpg",
|
22
|
-
resolution: "32x32",
|
23
|
-
out: "omg_thumb.jpg")
|
24
|
-
# => "convert 'omg.jpg' -scale '32x32' 'omg_thumb.jpg'"
|
21
|
+
Terrapin::CommandLine.new("echo", "hello")
|
25
22
|
```
|
26
23
|
|
27
|
-
|
28
|
-
|
29
|
-
```ruby
|
30
|
-
line = Cocaine::CommandLine.new("cat", ":file")
|
31
|
-
line.command(file: "haha`rm -rf /`.txt") # => "cat 'haha`rm -rf /`.txt'"
|
32
|
-
|
33
|
-
line = Cocaine::CommandLine.new("cat", ":file")
|
34
|
-
line.command(file: "ohyeah?'`rm -rf /`.ha!") # => "cat 'ohyeah?'\\''`rm -rf /`.ha!'"
|
35
|
-
```
|
36
|
-
|
37
|
-
NOTE: It only does that for arguments interpolated via `run`, NOT arguments
|
38
|
-
passed into `new` (see 'Security' below):
|
39
|
-
|
40
|
-
```ruby
|
41
|
-
line = Cocaine::CommandLine.new("echo", "haha`whoami`")
|
42
|
-
line.command # => "echo haha`whoami`"
|
43
|
-
line.run # => "hahawebserver"
|
44
|
-
```
|
45
|
-
|
46
|
-
You can ignore the result:
|
47
|
-
|
48
|
-
```ruby
|
49
|
-
line = Cocaine::CommandLine.new("noisy", "--extra-verbose", swallow_stderr: true)
|
50
|
-
line.command # => "noisy --extra-verbose 2>/dev/null"
|
51
|
-
|
52
|
-
# ... and on Windows...
|
53
|
-
line.command # => "noisy --extra-verbose 2>NUL"
|
54
|
-
```
|
55
|
-
|
56
|
-
If your command errors, you get an exception:
|
57
|
-
|
58
|
-
```ruby
|
59
|
-
line = Cocaine::CommandLine.new("git", "commit")
|
60
|
-
begin
|
61
|
-
line.run
|
62
|
-
rescue Cocaine::ExitStatusError => e
|
63
|
-
e.message # => "Command 'git commit' returned 1. Expected 0"
|
64
|
-
end
|
65
|
-
```
|
66
|
-
|
67
|
-
If your command might return something non-zero, and you expect that, it's cool:
|
68
|
-
|
69
|
-
```ruby
|
70
|
-
line = Cocaine::CommandLine.new("/usr/bin/false", "", expected_outcodes: [0, 1])
|
71
|
-
begin
|
72
|
-
line.run
|
73
|
-
rescue Cocaine::ExitStatusError => e
|
74
|
-
# => You never get here!
|
75
|
-
end
|
76
|
-
```
|
77
|
-
|
78
|
-
You don't have the command? You get an exception:
|
79
|
-
|
80
|
-
```ruby
|
81
|
-
line = Cocaine::CommandLine.new("lolwut")
|
82
|
-
begin
|
83
|
-
line.run
|
84
|
-
rescue Cocaine::CommandNotFoundError => e
|
85
|
-
e # => the command isn't in the $PATH for this process.
|
86
|
-
end
|
87
|
-
```
|
88
|
-
|
89
|
-
But don't fear, you can specify where to look for the command:
|
90
|
-
|
91
|
-
```ruby
|
92
|
-
Cocaine::CommandLine.path = "/opt/bin"
|
93
|
-
line = Cocaine::CommandLine.new("lolwut")
|
94
|
-
line.command # => "lolwut", but it looks in /opt/bin for it.
|
95
|
-
```
|
96
|
-
|
97
|
-
You can even give it a bunch of places to look:
|
98
|
-
|
99
|
-
```ruby
|
100
|
-
FileUtils.rm("/opt/bin/lolwut")
|
101
|
-
File.open('/usr/local/bin/lolwut') {|f| f.write('echo Hello') }
|
102
|
-
Cocaine::CommandLine.path = ["/opt/bin", "/usr/local/bin"]
|
103
|
-
line = Cocaine::CommandLine.new("lolwut")
|
104
|
-
line.run # => prints 'Hello', because it searches the path
|
105
|
-
```
|
106
|
-
|
107
|
-
Or just put it in the command:
|
108
|
-
|
109
|
-
```ruby
|
110
|
-
line = Cocaine::CommandLine.new("/opt/bin/lolwut")
|
111
|
-
line.command # => "/opt/bin/lolwut"
|
112
|
-
```
|
113
|
-
|
114
|
-
You can see what's getting run. The 'Command' part it logs is in green for visibility!
|
115
|
-
|
116
|
-
```ruby
|
117
|
-
line = Cocaine::CommandLine.new("echo", ":var", logger: Logger.new(STDOUT))
|
118
|
-
line.run(var: "LOL!") # => Logs this with #info -> Command :: echo 'LOL!'
|
119
|
-
```
|
120
|
-
|
121
|
-
Or log every command:
|
122
|
-
|
123
|
-
```ruby
|
124
|
-
Cocaine::CommandLine.logger = Logger.new(STDOUT)
|
125
|
-
Cocaine::CommandLine.new("date").run # => Logs this -> Command :: date
|
126
|
-
```
|
127
|
-
|
128
|
-
## Security
|
129
|
-
|
130
|
-
Short version: Only pass user-generated data into the `run` method and NOT
|
131
|
-
`new`.
|
132
|
-
|
133
|
-
As shown in examples above, Cocaine will only shell-escape what is passed in as
|
134
|
-
interpolations to the `run` method. It WILL NOT escape what is passed in to the
|
135
|
-
second argument of `new`. Cocaine assumes that you will not be manually
|
136
|
-
passing user-generated data to that argument and will be using it as a template
|
137
|
-
for your command line's structure.
|
138
|
-
|
139
|
-
## POSIX Spawn
|
140
|
-
|
141
|
-
You can potentially increase performance by installing [the posix-spawn
|
142
|
-
gem](https://rubygems.org/gems/posix-spawn). This gem can keep your
|
143
|
-
application's heap from being copied when forking command line
|
144
|
-
processes. For applications with large heaps the gain can be
|
145
|
-
significant. To include `posix-spawn`, simply add it to your `Gemfile` or,
|
146
|
-
if you don't use bundler, install the gem.
|
147
|
-
|
148
|
-
## Runners
|
149
|
-
|
150
|
-
Cocaine will attempt to choose from among 3 different ways of running commands.
|
151
|
-
The simplest is using backticks, and is the default in 1.8. In Ruby 1.9, it
|
152
|
-
will attempt to use `Process.spawn`. And, as mentioned above, if the
|
153
|
-
`posix-spawn` gem is installed, it will attempt to use that. If for some reason
|
154
|
-
one of the `.spawn` runners don't work for you, you can override them manually
|
155
|
-
by setting a new runner, like so:
|
156
|
-
|
157
|
-
```ruby
|
158
|
-
Cocaine::CommandLine.runner = Cocaine::CommandLine::BackticksRunner.new
|
159
|
-
```
|
160
|
-
|
161
|
-
And if you really want to, you can define your own Runner, though I can't
|
162
|
-
imagine why you would.
|
163
|
-
|
164
|
-
### JRuby issues
|
165
|
-
|
166
|
-
#### Caveat
|
167
|
-
|
168
|
-
If you get `Error::ECHILD` errors and are using JRuby, there is a very good
|
169
|
-
chance that the error is actually in JRuby. This was brought to our attention
|
170
|
-
in https://github.com/thoughtbot/cocaine/issues/24 and probably fixed in
|
171
|
-
http://jira.codehaus.org/browse/JRUBY-6162. You *will* want to use the
|
172
|
-
`BackticksRunner` if you are unable to update JRuby.
|
173
|
-
|
174
|
-
#### Spawn warning
|
175
|
-
|
176
|
-
If you get `unsupported spawn option: out` warning (like in [issue 38](https://github.com/thoughtbot/cocaine/issues/38)),
|
177
|
-
try to use `PopenRunner`:
|
178
|
-
|
179
|
-
```ruby
|
180
|
-
Cocaine::CommandLine.runner = Cocaine::CommandLine::PopenRunner.new
|
181
|
-
```
|
182
|
-
|
183
|
-
## Thread Safety
|
184
|
-
|
185
|
-
Cocaine should be thread safe. As discussed [here, in this climate_control
|
186
|
-
thread](https://github.com/thoughtbot/climate_control/pull/11), climate_control,
|
187
|
-
which modifies the environment under which commands are run for the
|
188
|
-
BackticksRunner and PopenRunner, is thread-safe but not reentrant. Please let us
|
189
|
-
know if you find this is ever not the case.
|
190
|
-
|
191
|
-
## Feedback
|
192
|
-
|
193
|
-
*Security* concerns must be privately emailed to
|
194
|
-
[security@thoughtbot.com](security@thoughtbot.com).
|
195
|
-
|
196
|
-
Question? Idea? Problem? Bug? Comment? Concern? Like using question marks?
|
197
|
-
|
198
|
-
[GitHub Issues For All!](https://github.com/thoughtbot/cocaine/issues)
|
199
|
-
|
200
|
-
## Credits
|
201
|
-
|
202
|
-
Thank you to all [the contributors](https://github.com/thoughtbot/cocaine/graphs/contributors)!
|
203
|
-
|
204
|
-
![thoughtbot](http://thoughtbot.com/logo.png)
|
205
|
-
|
206
|
-
Cocaine is maintained and funded by [thoughtbot, inc](http://thoughtbot.com/community)
|
207
|
-
|
208
|
-
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
24
|
+
and should continue to work fine.
|
209
25
|
|
210
26
|
## License
|
211
27
|
|
212
|
-
Copyright 2011-
|
28
|
+
Copyright 2011-2018 Jon Yurek and thoughtbot, inc. This is free software, and
|
213
29
|
may be redistributed under the terms specified in the
|
214
30
|
[LICENSE](https://github.com/thoughtbot/cocaine/blob/master/LICENSE)
|
215
31
|
file.
|
data/cocaine.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
|
20
|
-
s.add_dependency(
|
20
|
+
s.add_dependency("terrapin", "= 0.6.0.alpha")
|
21
21
|
s.add_development_dependency('rspec')
|
22
22
|
s.add_development_dependency('bourne')
|
23
23
|
s.add_development_dependency('mocha')
|
data/lib/cocaine.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# coding: UTF-8
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
5
|
-
require 'cocaine/command_line'
|
6
|
-
require 'cocaine/command_line/output'
|
7
|
-
require 'cocaine/command_line/multi_pipe'
|
8
|
-
require 'cocaine/command_line/runners'
|
9
|
-
require 'cocaine/exceptions'
|
3
|
+
require 'terrapin'
|
4
|
+
Cocaine = Terrapin
|
10
5
|
|
11
|
-
|
12
|
-
|
6
|
+
$stderr.puts [
|
7
|
+
"===========================================\n",
|
8
|
+
"DEPRECATION: The cocaine gem is deprecated.",
|
9
|
+
"Please upgrade to terrapin.",
|
10
|
+
"See https://github.com/thoughtbot/terrapin/ for further instructions.",
|
11
|
+
"\n==========================================="
|
12
|
+
].join(" ")
|
data/lib/cocaine/version.rb
CHANGED
metadata
CHANGED
@@ -1,35 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cocaine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Yurek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: terrapin
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0.3
|
20
|
-
- - "<"
|
17
|
+
- - '='
|
21
18
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
19
|
+
version: 0.6.0.alpha
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '='
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.0.
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '1.0'
|
26
|
+
version: 0.6.0.alpha
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: rspec
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,17 +130,6 @@ files:
|
|
136
130
|
- Rakefile
|
137
131
|
- cocaine.gemspec
|
138
132
|
- lib/cocaine.rb
|
139
|
-
- lib/cocaine/command_line.rb
|
140
|
-
- lib/cocaine/command_line/multi_pipe.rb
|
141
|
-
- lib/cocaine/command_line/output.rb
|
142
|
-
- lib/cocaine/command_line/runners.rb
|
143
|
-
- lib/cocaine/command_line/runners/backticks_runner.rb
|
144
|
-
- lib/cocaine/command_line/runners/fake_runner.rb
|
145
|
-
- lib/cocaine/command_line/runners/popen_runner.rb
|
146
|
-
- lib/cocaine/command_line/runners/posix_runner.rb
|
147
|
-
- lib/cocaine/command_line/runners/process_runner.rb
|
148
|
-
- lib/cocaine/exceptions.rb
|
149
|
-
- lib/cocaine/os_detector.rb
|
150
133
|
- lib/cocaine/version.rb
|
151
134
|
- spec/cocaine/command_line/output_spec.rb
|
152
135
|
- spec/cocaine/command_line/runners/backticks_runner_spec.rb
|
@@ -180,12 +163,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
180
163
|
version: '0'
|
181
164
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
165
|
requirements:
|
183
|
-
- - "
|
166
|
+
- - ">"
|
184
167
|
- !ruby/object:Gem::Version
|
185
|
-
version:
|
168
|
+
version: 1.3.1
|
186
169
|
requirements: []
|
187
170
|
rubyforge_project:
|
188
|
-
rubygems_version: 2.4
|
171
|
+
rubygems_version: 2.7.4
|
189
172
|
signing_key:
|
190
173
|
specification_version: 4
|
191
174
|
summary: A small library for doing (command) lines
|
data/lib/cocaine/command_line.rb
DELETED
@@ -1,197 +0,0 @@
|
|
1
|
-
# coding: UTF-8
|
2
|
-
|
3
|
-
module Cocaine
|
4
|
-
class CommandLine
|
5
|
-
class << self
|
6
|
-
attr_accessor :logger, :runner
|
7
|
-
|
8
|
-
def path
|
9
|
-
@supplemental_path
|
10
|
-
end
|
11
|
-
|
12
|
-
def path=(supplemental_path)
|
13
|
-
@supplemental_path = Array(supplemental_path).
|
14
|
-
flatten.
|
15
|
-
join(OS.path_separator)
|
16
|
-
end
|
17
|
-
|
18
|
-
def environment
|
19
|
-
@supplemental_environment ||= {}
|
20
|
-
end
|
21
|
-
|
22
|
-
def runner
|
23
|
-
@runner || best_runner
|
24
|
-
end
|
25
|
-
|
26
|
-
def runner_options
|
27
|
-
@default_runner_options ||= {}
|
28
|
-
end
|
29
|
-
|
30
|
-
def fake!
|
31
|
-
@runner = FakeRunner.new
|
32
|
-
end
|
33
|
-
|
34
|
-
def unfake!
|
35
|
-
@runner = nil
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def best_runner
|
41
|
-
[PosixRunner, ProcessRunner, BackticksRunner].detect do |runner|
|
42
|
-
runner.supported?
|
43
|
-
end.new
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
@environment = {}
|
48
|
-
|
49
|
-
attr_reader :exit_status, :runner
|
50
|
-
|
51
|
-
def initialize(binary, params = "", options = {})
|
52
|
-
@binary = binary.dup
|
53
|
-
@params = params.dup
|
54
|
-
@options = options.dup
|
55
|
-
@runner = @options.delete(:runner) || self.class.runner
|
56
|
-
@logger = @options.delete(:logger) || self.class.logger
|
57
|
-
@swallow_stderr = @options.delete(:swallow_stderr)
|
58
|
-
@expected_outcodes = @options.delete(:expected_outcodes) || [0]
|
59
|
-
@environment = @options.delete(:environment) || {}
|
60
|
-
@runner_options = @options.delete(:runner_options) || {}
|
61
|
-
end
|
62
|
-
|
63
|
-
def command(interpolations = {})
|
64
|
-
cmd = [path_prefix, @binary, interpolate(@params, interpolations)]
|
65
|
-
cmd << bit_bucket if @swallow_stderr
|
66
|
-
cmd.join(" ").strip
|
67
|
-
end
|
68
|
-
|
69
|
-
def run(interpolations = {})
|
70
|
-
@exit_status = nil
|
71
|
-
begin
|
72
|
-
full_command = command(interpolations)
|
73
|
-
log("#{colored("Command")} :: #{full_command}")
|
74
|
-
@output = execute(full_command)
|
75
|
-
rescue Errno::ENOENT => e
|
76
|
-
raise Cocaine::CommandNotFoundError, e.message
|
77
|
-
ensure
|
78
|
-
@exit_status = $?.respond_to?(:exitstatus) ? $?.exitstatus : 0
|
79
|
-
end
|
80
|
-
|
81
|
-
if @exit_status == 127
|
82
|
-
raise Cocaine::CommandNotFoundError
|
83
|
-
end
|
84
|
-
|
85
|
-
unless @expected_outcodes.include?(@exit_status)
|
86
|
-
message = [
|
87
|
-
"Command '#{full_command}' returned #{@exit_status}. Expected #{@expected_outcodes.join(", ")}",
|
88
|
-
"Here is the command output: STDOUT:\n", command_output,
|
89
|
-
"\nSTDERR:\n", command_error_output
|
90
|
-
].join("\n")
|
91
|
-
raise Cocaine::ExitStatusError, message
|
92
|
-
end
|
93
|
-
command_output
|
94
|
-
end
|
95
|
-
|
96
|
-
def command_output
|
97
|
-
output.output
|
98
|
-
end
|
99
|
-
|
100
|
-
def command_error_output
|
101
|
-
output.error_output
|
102
|
-
end
|
103
|
-
|
104
|
-
def output
|
105
|
-
@output || Output.new
|
106
|
-
end
|
107
|
-
|
108
|
-
private
|
109
|
-
|
110
|
-
def colored(text, ansi_color = "\e[32m")
|
111
|
-
if @logger && @logger.respond_to?(:tty?) && @logger.tty?
|
112
|
-
"#{ansi_color}#{text}\e[0m"
|
113
|
-
else
|
114
|
-
text
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def log(text)
|
119
|
-
if @logger
|
120
|
-
@logger.info(text)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def path_prefix
|
125
|
-
if !self.class.path.nil? && !self.class.path.empty?
|
126
|
-
os_path_prefix
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def os_path_prefix
|
131
|
-
if OS.unix?
|
132
|
-
unix_path_prefix
|
133
|
-
else
|
134
|
-
windows_path_prefix
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def unix_path_prefix
|
139
|
-
"PATH=#{self.class.path}#{OS.path_separator}$PATH;"
|
140
|
-
end
|
141
|
-
|
142
|
-
def windows_path_prefix
|
143
|
-
"SET PATH=#{self.class.path}#{OS.path_separator}%PATH% &"
|
144
|
-
end
|
145
|
-
|
146
|
-
def execute(command)
|
147
|
-
runner.call(command, environment, runner_options)
|
148
|
-
end
|
149
|
-
|
150
|
-
def environment
|
151
|
-
self.class.environment.merge(@environment)
|
152
|
-
end
|
153
|
-
|
154
|
-
def runner_options
|
155
|
-
self.class.runner_options.merge(@runner_options)
|
156
|
-
end
|
157
|
-
|
158
|
-
def interpolate(pattern, interpolations)
|
159
|
-
interpolations = stringify_keys(interpolations)
|
160
|
-
pattern.gsub(/:\{?(\w+)\b\}?/) do |match|
|
161
|
-
key = match.tr(":{}", "")
|
162
|
-
if interpolations.key?(key)
|
163
|
-
shell_quote_all_values(interpolations[key])
|
164
|
-
else
|
165
|
-
match
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def stringify_keys(hash)
|
171
|
-
Hash[hash.map{ |k, v| [k.to_s, v] }]
|
172
|
-
end
|
173
|
-
|
174
|
-
def shell_quote_all_values(values)
|
175
|
-
Array(values).map(&method(:shell_quote)).join(" ")
|
176
|
-
end
|
177
|
-
|
178
|
-
def shell_quote(string)
|
179
|
-
return "" if string.nil?
|
180
|
-
string = string.to_s if string.respond_to? :to_s
|
181
|
-
|
182
|
-
if OS.unix?
|
183
|
-
if string.empty?
|
184
|
-
"''"
|
185
|
-
else
|
186
|
-
string.split("'", -1).map{|m| "'#{m}'" }.join("\\'")
|
187
|
-
end
|
188
|
-
else
|
189
|
-
%{"#{string}"}
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def bit_bucket
|
194
|
-
OS.unix? ? "2>/dev/null" : "2>NUL"
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module Cocaine
|
2
|
-
class CommandLine
|
3
|
-
class MultiPipe
|
4
|
-
def initialize
|
5
|
-
@stdout_in, @stdout_out = IO.pipe
|
6
|
-
@stderr_in, @stderr_out = IO.pipe
|
7
|
-
end
|
8
|
-
|
9
|
-
def pipe_options
|
10
|
-
{ out: @stdout_out, err: @stderr_out }
|
11
|
-
end
|
12
|
-
|
13
|
-
def output
|
14
|
-
Output.new(@stdout_output, @stderr_output)
|
15
|
-
end
|
16
|
-
|
17
|
-
def read_and_then(&block)
|
18
|
-
close_write
|
19
|
-
read
|
20
|
-
block.call
|
21
|
-
close_read
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def close_write
|
27
|
-
@stdout_out.close
|
28
|
-
@stderr_out.close
|
29
|
-
end
|
30
|
-
|
31
|
-
def read
|
32
|
-
@stdout_output = read_stream(@stdout_in)
|
33
|
-
@stderr_output = read_stream(@stderr_in)
|
34
|
-
end
|
35
|
-
|
36
|
-
def close_read
|
37
|
-
@stdout_in.close
|
38
|
-
@stderr_in.close
|
39
|
-
end
|
40
|
-
|
41
|
-
def read_stream(io)
|
42
|
-
result = ""
|
43
|
-
while partial_result = io.read(8192)
|
44
|
-
result << partial_result
|
45
|
-
end
|
46
|
-
result
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,7 +0,0 @@
|
|
1
|
-
# coding: UTF-8
|
2
|
-
|
3
|
-
require 'cocaine/command_line/runners/backticks_runner'
|
4
|
-
require 'cocaine/command_line/runners/process_runner'
|
5
|
-
require 'cocaine/command_line/runners/posix_runner'
|
6
|
-
require 'cocaine/command_line/runners/popen_runner'
|
7
|
-
require 'cocaine/command_line/runners/fake_runner'
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# coding: UTF-8
|
2
|
-
|
3
|
-
require 'climate_control'
|
4
|
-
|
5
|
-
module Cocaine
|
6
|
-
class CommandLine
|
7
|
-
class BackticksRunner
|
8
|
-
def self.supported?
|
9
|
-
true
|
10
|
-
end
|
11
|
-
|
12
|
-
def supported?
|
13
|
-
self.class.supported?
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(command, env = {}, options = {})
|
17
|
-
with_modified_environment(env) do
|
18
|
-
Output.new(`#{command}`)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def with_modified_environment(env, &block)
|
25
|
-
ClimateControl.modify(env, &block)
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# coding: UTF-8
|
2
|
-
|
3
|
-
module Cocaine
|
4
|
-
class CommandLine
|
5
|
-
class FakeRunner
|
6
|
-
def self.supported?
|
7
|
-
false
|
8
|
-
end
|
9
|
-
|
10
|
-
def supported?
|
11
|
-
self.class.supported?
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_reader :commands
|
15
|
-
|
16
|
-
def initialize
|
17
|
-
@commands = []
|
18
|
-
end
|
19
|
-
|
20
|
-
def call(command, env = {}, options = {})
|
21
|
-
commands << [command, env]
|
22
|
-
Output.new("")
|
23
|
-
end
|
24
|
-
|
25
|
-
def ran?(predicate_command)
|
26
|
-
@commands.any?{|(command, _)| command =~ Regexp.new(predicate_command) }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# coding: UTF-8
|
2
|
-
|
3
|
-
module Cocaine
|
4
|
-
class CommandLine
|
5
|
-
class PopenRunner
|
6
|
-
def self.supported?
|
7
|
-
true
|
8
|
-
end
|
9
|
-
|
10
|
-
def supported?
|
11
|
-
self.class.supported?
|
12
|
-
end
|
13
|
-
|
14
|
-
def call(command, env = {}, options = {})
|
15
|
-
with_modified_environment(env) do
|
16
|
-
IO.popen(command, "r", options) do |pipe|
|
17
|
-
Output.new(pipe.read)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def with_modified_environment(env, &block)
|
25
|
-
ClimateControl.modify(env, &block)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# coding: UTF-8
|
2
|
-
|
3
|
-
module Cocaine
|
4
|
-
class CommandLine
|
5
|
-
class PosixRunner
|
6
|
-
def self.available?
|
7
|
-
return @available unless @available.nil?
|
8
|
-
|
9
|
-
@available = posix_spawn_gem_available?
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.supported?
|
13
|
-
available? && !OS.java?
|
14
|
-
end
|
15
|
-
|
16
|
-
def supported?
|
17
|
-
self.class.supported?
|
18
|
-
end
|
19
|
-
|
20
|
-
def call(command, env = {}, options = {})
|
21
|
-
pipe = MultiPipe.new
|
22
|
-
pid = spawn(env, command, options.merge(pipe.pipe_options))
|
23
|
-
pipe.read_and_then do
|
24
|
-
waitpid(pid)
|
25
|
-
end
|
26
|
-
pipe.output
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def spawn(*args)
|
32
|
-
POSIX::Spawn.spawn(*args)
|
33
|
-
end
|
34
|
-
|
35
|
-
def waitpid(pid)
|
36
|
-
Process.waitpid(pid)
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.posix_spawn_gem_available?
|
40
|
-
require 'posix/spawn'
|
41
|
-
true
|
42
|
-
rescue LoadError
|
43
|
-
false
|
44
|
-
end
|
45
|
-
|
46
|
-
private_class_method :posix_spawn_gem_available?
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# coding: UTF-8
|
2
|
-
|
3
|
-
module Cocaine
|
4
|
-
class CommandLine
|
5
|
-
class ProcessRunner
|
6
|
-
def self.available?
|
7
|
-
Process.respond_to?(:spawn)
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.supported?
|
11
|
-
available? && !OS.java?
|
12
|
-
end
|
13
|
-
|
14
|
-
def supported?
|
15
|
-
self.class.supported?
|
16
|
-
end
|
17
|
-
|
18
|
-
def call(command, env = {}, options = {})
|
19
|
-
pipe = MultiPipe.new
|
20
|
-
pid = spawn(env, command, options.merge(pipe.pipe_options))
|
21
|
-
pipe.read_and_then do
|
22
|
-
waitpid(pid)
|
23
|
-
end
|
24
|
-
pipe.output
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def spawn(*args)
|
30
|
-
Process.spawn(*args)
|
31
|
-
end
|
32
|
-
|
33
|
-
def waitpid(pid)
|
34
|
-
Process.waitpid(pid)
|
35
|
-
rescue Errno::ECHILD
|
36
|
-
# In JRuby, waiting on a finished pid raises.
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/lib/cocaine/exceptions.rb
DELETED
data/lib/cocaine/os_detector.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# coding: UTF-8
|
2
|
-
|
3
|
-
module Cocaine
|
4
|
-
class OSDetector
|
5
|
-
def java?
|
6
|
-
arch =~ /java/
|
7
|
-
end
|
8
|
-
|
9
|
-
def unix?
|
10
|
-
RbConfig::CONFIG['host_os'] !~ /mswin|mingw/
|
11
|
-
end
|
12
|
-
|
13
|
-
def windows?
|
14
|
-
!unix?
|
15
|
-
end
|
16
|
-
|
17
|
-
def path_separator
|
18
|
-
File::PATH_SEPARATOR
|
19
|
-
end
|
20
|
-
|
21
|
-
def arch
|
22
|
-
RUBY_PLATFORM
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
OS = OSDetector.new
|
27
|
-
end
|