backticks 0.4.0 → 0.5.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 +4 -4
- data/README.md +12 -0
- data/lib/backticks/command.rb +6 -3
- data/lib/backticks/runner.rb +45 -42
- data/lib/backticks/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8199c03291828b81d31df59a9e3341d20b13b27a
|
4
|
+
data.tar.gz: 5a4058b1ada73100e623660cf0c201f1aba3accb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 943ceaf445259b9c4fc67e94652fa5be8d613496abf198578842b81a97d5bb782d371bc5ac1b519c8143850fce1290a7f8e1245989c1a3cc71c76c4da237c279
|
7
|
+
data.tar.gz: 2c6ac11905c9a76836acb555d8819f74947fbf90fa42a0104bdb8823b2b3dff36d44bda9df56206cd9676ced6d5df65a24b201d1aa2d23295968e8d62b8f9c43
|
data/README.md
CHANGED
@@ -111,6 +111,18 @@ include Backticks::Ext
|
|
111
111
|
|
112
112
|
If you do this, I will hunt you down and scoff at you. You have been warned!
|
113
113
|
|
114
|
+
## Security
|
115
|
+
|
116
|
+
Backticks avoids using your OS shell, which helps prevent security bugs.
|
117
|
+
This also means that you can't pass strings such as "$HOME" to commands;
|
118
|
+
Backticks does not perform shell substitution. Pass ENV['HOME'] instead.
|
119
|
+
|
120
|
+
Be careful about the commands you pass to Backticks! Never run commands that
|
121
|
+
you read from an untrusted source, e.g. the network.
|
122
|
+
|
123
|
+
In the future, Backticks may integrate with Ruby's $SAFE level to provide smart
|
124
|
+
escaping and shell safety.
|
125
|
+
|
114
126
|
## Development
|
115
127
|
|
116
128
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/backticks/command.rb
CHANGED
@@ -21,7 +21,10 @@ module Backticks
|
|
21
21
|
attr_reader :pid
|
22
22
|
|
23
23
|
# @return [String] all data captured (so far) from child's stdin/stdout/stderr
|
24
|
-
attr_reader :captured_input, :captured_output, :captured_error
|
24
|
+
attr_reader :captured_input, :captured_output, :captured_error
|
25
|
+
|
26
|
+
# @return [nil,Process::Status] result of command if it has ended; nil if still running
|
27
|
+
attr_reader :status
|
25
28
|
|
26
29
|
# Watch a running command.
|
27
30
|
def initialize(pid, stdin, stdout, stderr)
|
@@ -93,12 +96,12 @@ module Backticks
|
|
93
96
|
# proxy STDIN to child's stdin
|
94
97
|
if ready && ready.include?(STDIN)
|
95
98
|
input = STDIN.readpartial(CHUNK) rescue nil
|
96
|
-
@captured_input << input
|
97
99
|
if input
|
100
|
+
@captured_input << input
|
98
101
|
@stdin.write(input)
|
99
102
|
else
|
100
103
|
# our own STDIN got closed; proxy this fact to the child
|
101
|
-
@stdin.close
|
104
|
+
@stdin.close unless @stdin.closed?
|
102
105
|
end
|
103
106
|
end
|
104
107
|
|
data/lib/backticks/runner.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'pty'
|
2
|
+
require 'open3'
|
2
3
|
|
3
4
|
module Backticks
|
4
5
|
# An easy-to-use interface for invoking commands and capturing their output.
|
5
6
|
# Instances of Runner can be interactive, which prints the command's output
|
6
7
|
# to the terminal and also allows the user to interact with the command.
|
7
|
-
#
|
8
|
-
#
|
8
|
+
# By default commands are unbuffered, using a pseudoterminal to capture
|
9
|
+
# the output with no delay.
|
9
10
|
class Runner
|
11
|
+
# Default streams to buffer if someone calls bufferered= with Boolean.
|
12
|
+
BUFFERED = [:stdin, :stdout, :stderr].freeze
|
13
|
+
|
10
14
|
# If true, commands will have their stdio streams tied to the parent
|
11
15
|
# process so the user can view their output and send input to them.
|
12
16
|
# Commands' output is still captured normally when they are interactive.
|
@@ -21,18 +25,25 @@ module Backticks
|
|
21
25
|
# @return [Boolean]
|
22
26
|
attr_accessor :interactive
|
23
27
|
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# to fill.
|
28
|
+
# List of I/O streams that should be captured using a pipe instead of
|
29
|
+
# a pseudoterminal.
|
27
30
|
#
|
28
|
-
#
|
29
|
-
|
31
|
+
# This may be a Boolean, or it may be an Array of stream names from the
|
32
|
+
# set [:stdin, stdout, stderr].
|
33
|
+
#
|
34
|
+
# @return [Array] list of symbolic stream names
|
35
|
+
attr_reader :buffered
|
30
36
|
|
31
37
|
# @return [#parameters] the CLI-translation object used by this runner
|
32
38
|
attr_reader :cli
|
33
39
|
|
34
40
|
# Create an instance of Runner.
|
35
|
-
# @
|
41
|
+
# @option [#include?,Boolean] buffered list of names; true/false for all/none
|
42
|
+
# @option [#parameters] cli command-line parameter translator
|
43
|
+
# @option [Boolean] interactive true to tie parent stdout/stdin to child
|
44
|
+
#
|
45
|
+
# @example buffer stdout
|
46
|
+
# Runner.new(buffered:[:stdout])
|
36
47
|
def initialize(options={})
|
37
48
|
options = {
|
38
49
|
:buffered => false,
|
@@ -40,9 +51,19 @@ module Backticks
|
|
40
51
|
:interactive => false,
|
41
52
|
}.merge(options)
|
42
53
|
|
43
|
-
@buffered = options[:buffered]
|
44
54
|
@cli = options[:cli]
|
45
|
-
|
55
|
+
self.buffered = options[:buffered]
|
56
|
+
self.interactive = options[:interactive]
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param [Array,Boolean] buffered list of symbolic stream names; true/false for all/none
|
60
|
+
def buffered=(b)
|
61
|
+
@buffered = case b
|
62
|
+
when true then BUFFERED
|
63
|
+
when false, nil then []
|
64
|
+
else
|
65
|
+
b
|
66
|
+
end
|
46
67
|
end
|
47
68
|
|
48
69
|
# @deprecated
|
@@ -79,50 +100,32 @@ module Backticks
|
|
79
100
|
# remaining elements are parameters and flags
|
80
101
|
# @return [Command] the running command
|
81
102
|
def run_without_sugar(argv)
|
82
|
-
if
|
83
|
-
|
103
|
+
stdin_r, stdin = if buffered.include?(:stdin) && !interactive
|
104
|
+
IO.pipe
|
84
105
|
else
|
85
|
-
|
106
|
+
PTY.open
|
107
|
+
end
|
108
|
+
stdout, stdout_w = if buffered.include?(:stdout) && !interactive
|
109
|
+
IO.pipe
|
110
|
+
else
|
111
|
+
PTY.open
|
112
|
+
end
|
113
|
+
stderr, stderr_w = if buffered.include?(:stderr)
|
114
|
+
IO.pipe
|
115
|
+
else
|
116
|
+
PTY.open
|
86
117
|
end
|
87
|
-
end
|
88
118
|
|
89
|
-
# Run a command. Use a pty to capture the unbuffered output.
|
90
|
-
#
|
91
|
-
# @param [Array] argv command to run; argv[0] is program name and the
|
92
|
-
# remaining elements are parameters and flags
|
93
|
-
# @return [Command] the running command
|
94
|
-
private
|
95
|
-
def run_unbuffered(argv)
|
96
|
-
stdout, stdout_w = PTY.open
|
97
|
-
stdin_r, stdin = PTY.open
|
98
|
-
stderr, stderr_w = PTY.open
|
99
119
|
pid = spawn(*argv, in: stdin_r, out: stdout_w, err: stderr_w)
|
100
120
|
stdin_r.close
|
101
121
|
stdout_w.close
|
102
122
|
stderr_w.close
|
103
|
-
unless
|
123
|
+
unless interactive
|
104
124
|
stdin.close
|
105
125
|
stdin = nil
|
106
126
|
end
|
107
127
|
|
108
128
|
Command.new(pid, stdin, stdout, stderr)
|
109
129
|
end
|
110
|
-
|
111
|
-
# Run a command. Perform no translation or substitution. Use a pipe
|
112
|
-
# to read the output, which may be buffered by the OS. Return the program's
|
113
|
-
# exit status and stdout.
|
114
|
-
#
|
115
|
-
# @param [Array] argv command to run; argv[0] is program name and the
|
116
|
-
# remaining elements are command-line arguments.
|
117
|
-
# @return [Command] the running command
|
118
|
-
def run_buffered(argv)
|
119
|
-
stdin, stdout, stderr, thr = Open3.popen3(*argv)
|
120
|
-
unless @interactive
|
121
|
-
stdin.close
|
122
|
-
stdin = nil
|
123
|
-
end
|
124
|
-
|
125
|
-
Command.new(thr.pid, stdin, stdout, stderr)
|
126
|
-
end
|
127
130
|
end
|
128
131
|
end
|
data/lib/backticks/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backticks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Spataro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|