shell-proxy 0.0.0 → 0.0.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.
- data/.gitignore +1 -0
- data/README.md +71 -2
- data/lib/shell-proxy.rb +203 -0
- data/lib/shell-proxy/case.rb +38 -0
- data/lib/shell-proxy/escaping.rb +15 -0
- data/lib/shell-proxy/for.rb +17 -0
- data/lib/shell-proxy/if.rb +40 -0
- data/proof_of_concept.rb +40 -2
- data/shell-proxy.gemspec +1 -1
- data/test_shell_proxy.rb +1 -1
- metadata +8 -3
- data/shell_proxy.rb +0 -105
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/README.md
CHANGED
@@ -6,27 +6,65 @@ Totes leeb.
|
|
6
6
|
Inputs:
|
7
7
|
|
8
8
|
```ruby
|
9
|
-
require './
|
9
|
+
require './lib/shell-proxy'
|
10
10
|
|
11
11
|
ShellProxy.new.__main__ do
|
12
12
|
cd "Somedir"
|
13
13
|
|
14
|
+
__function("butts_function") do
|
15
|
+
touch "butts"
|
16
|
+
end
|
17
|
+
|
14
18
|
__subshell do
|
15
19
|
__subshell do
|
16
20
|
mkdir "borp"
|
17
21
|
cd "borp"
|
18
22
|
touch "thing"
|
19
23
|
end
|
20
|
-
|
24
|
+
%w[foo bar baz].each do |dir|
|
25
|
+
mkdir dir
|
26
|
+
touch "#{dir}/#{dir}"
|
27
|
+
end
|
28
|
+
touch("somefile")
|
21
29
|
mkdir "foo/bar/thing", { :p => nil }
|
30
|
+
echo("foo") | wc({:c => nil})
|
22
31
|
end
|
23
32
|
|
24
33
|
__chdir "/tmp" do
|
25
34
|
touch "rawr"
|
26
35
|
end
|
27
36
|
|
37
|
+
__set("foo", bare("$RANDOM"))
|
38
|
+
|
39
|
+
some | thing | some | other | thing
|
40
|
+
|
41
|
+
__case(raw("$foo")) do |c|
|
42
|
+
c.when(10000) do
|
43
|
+
echo "holy shit, did not expect that"
|
44
|
+
end
|
45
|
+
c.when("*") do
|
46
|
+
echo "Welp, that was predictable"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
__for(bare("foo bar baz"), "i") do
|
51
|
+
echo raw("$i")
|
52
|
+
end
|
53
|
+
|
28
54
|
rm "foo", { :r => nil, :f => nil }
|
29
55
|
mongod({ :config => "/usr/local/etc/mongod.conf" })
|
56
|
+
|
57
|
+
__if(raw("[[ $foo == 'foo' ]]")) do |c|
|
58
|
+
c.then do
|
59
|
+
echo "it was true"
|
60
|
+
end
|
61
|
+
c.elseif(raw("[[ bar == bar ]]")) do
|
62
|
+
echo "this is definitely true"
|
63
|
+
end
|
64
|
+
c.else do
|
65
|
+
echo "This wont be reached"
|
66
|
+
end
|
67
|
+
end
|
30
68
|
end
|
31
69
|
```
|
32
70
|
|
@@ -34,19 +72,50 @@ outputs:
|
|
34
72
|
|
35
73
|
```bash
|
36
74
|
cd 'Somedir'
|
75
|
+
function butts_function() {
|
76
|
+
touch 'butts'
|
77
|
+
}
|
37
78
|
(
|
38
79
|
(
|
39
80
|
mkdir 'borp'
|
40
81
|
cd 'borp'
|
41
82
|
touch 'thing'
|
42
83
|
)
|
84
|
+
mkdir 'foo'
|
85
|
+
touch 'foo/foo'
|
86
|
+
mkdir 'bar'
|
87
|
+
touch 'bar/bar'
|
88
|
+
mkdir 'baz'
|
89
|
+
touch 'baz/baz'
|
43
90
|
touch 'somefile'
|
44
91
|
mkdir '-p' 'foo/bar/thing'
|
92
|
+
echo 'foo' | wc '-c'
|
45
93
|
)
|
46
94
|
(
|
47
95
|
cd '/tmp'
|
48
96
|
touch 'rawr'
|
49
97
|
)
|
98
|
+
foo=$RANDOM
|
99
|
+
some | thing | some | other | thing
|
100
|
+
case "$foo" in
|
101
|
+
10000)
|
102
|
+
echo 'holy shit, did not expect that'
|
103
|
+
;;
|
104
|
+
*)
|
105
|
+
echo 'Welp, that was predictable'
|
106
|
+
;;
|
107
|
+
esac
|
108
|
+
for i in foo bar baz; do
|
109
|
+
echo "$i"
|
110
|
+
done
|
50
111
|
rm '-r' '-f' 'foo'
|
51
112
|
mongod '--config' '/usr/local/etc/mongod.conf'
|
113
|
+
if [[ $foo == 'foo' ]]
|
114
|
+
then
|
115
|
+
echo 'it was true'
|
116
|
+
else if [[ bar == bar ]]
|
117
|
+
echo 'this is definitely true'
|
118
|
+
else
|
119
|
+
echo 'This wont be reached'
|
120
|
+
fi
|
52
121
|
```
|
data/lib/shell-proxy.rb
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
require_relative 'shell-proxy/escaping'
|
2
|
+
require_relative 'shell-proxy/case'
|
3
|
+
require_relative 'shell-proxy/for'
|
4
|
+
require_relative 'shell-proxy/if'
|
5
|
+
|
6
|
+
INDENT_PADDING=" "
|
7
|
+
|
8
|
+
class RawString < String
|
9
|
+
def quote
|
10
|
+
inspect
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class BareString < String
|
15
|
+
end
|
16
|
+
|
17
|
+
def raw(s)
|
18
|
+
RawString.new(s)
|
19
|
+
end
|
20
|
+
|
21
|
+
def bare(s)
|
22
|
+
BareString.new(s)
|
23
|
+
end
|
24
|
+
|
25
|
+
class ShellProxy
|
26
|
+
include Escaping
|
27
|
+
|
28
|
+
def __main__(writer = nil, &block)
|
29
|
+
@cmd_buffer = CmdBuffer.new
|
30
|
+
instance_exec(&block)
|
31
|
+
@cmd_buffer.write(writer || __writer)
|
32
|
+
end
|
33
|
+
|
34
|
+
def __subshell(&block)
|
35
|
+
@cmd_buffer << "("
|
36
|
+
@cmd_buffer.indent
|
37
|
+
yield
|
38
|
+
@cmd_buffer.undent
|
39
|
+
@cmd_buffer << ")"
|
40
|
+
end
|
41
|
+
|
42
|
+
def __chdir(dir, &block)
|
43
|
+
__subshell do
|
44
|
+
cd(dir)
|
45
|
+
yield
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def __case(value, &block)
|
50
|
+
CaseStub.new(__escapinate(value), &block).__handle(@cmd_buffer)
|
51
|
+
end
|
52
|
+
|
53
|
+
def __for(over, iter, &block)
|
54
|
+
ForStub.new(over, iter, &block).__handle(@cmd_buffer)
|
55
|
+
end
|
56
|
+
|
57
|
+
def __if(condition, &block)
|
58
|
+
IfStub.new(condition, &block).__handle(@cmd_buffer)
|
59
|
+
end
|
60
|
+
|
61
|
+
def __set(variable, value)
|
62
|
+
__eval("#{variable}=#{__escapinate(value)}")
|
63
|
+
end
|
64
|
+
|
65
|
+
def __return(val)
|
66
|
+
__eval("return #{__escapinate(val)}")
|
67
|
+
end
|
68
|
+
|
69
|
+
def __function(name, &block)
|
70
|
+
@cmd_buffer << "function #{name}() {"
|
71
|
+
@cmd_buffer.indent
|
72
|
+
yield
|
73
|
+
@cmd_buffer.undent
|
74
|
+
@cmd_buffer << "}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_missing(sym, *args)
|
78
|
+
opts = case args[-1]
|
79
|
+
when Hash
|
80
|
+
args.pop
|
81
|
+
else
|
82
|
+
{}
|
83
|
+
end
|
84
|
+
|
85
|
+
stub = CmdStub.new(@cmd_buffer)
|
86
|
+
|
87
|
+
cmd = sym.to_s
|
88
|
+
cmd << " #{__process_opts(opts)}" unless opts.empty?
|
89
|
+
cmd << " #{__process_args(args)}" unless args.empty?
|
90
|
+
@cmd_buffer << cmd
|
91
|
+
stub
|
92
|
+
end
|
93
|
+
|
94
|
+
def __eval(str)
|
95
|
+
@cmd_buffer << str
|
96
|
+
end
|
97
|
+
|
98
|
+
def __emit(str)
|
99
|
+
__writer.flush
|
100
|
+
end
|
101
|
+
|
102
|
+
def __writer
|
103
|
+
@writer ||= ShellWriter.new($stdout)
|
104
|
+
end
|
105
|
+
|
106
|
+
def __process_args(args)
|
107
|
+
args.map do |v|
|
108
|
+
__escapinate(v)
|
109
|
+
end.join(" ")
|
110
|
+
end
|
111
|
+
|
112
|
+
def __process_opts(opts)
|
113
|
+
outputs = []
|
114
|
+
__process_and_escape(opts) do |value|
|
115
|
+
outputs << value
|
116
|
+
end
|
117
|
+
outputs.join(" ")
|
118
|
+
end
|
119
|
+
|
120
|
+
def __process_and_escape(opts)
|
121
|
+
opts.each do |k, v|
|
122
|
+
k = k.to_s
|
123
|
+
k = (k.length == 1 ? "-" : "--") + k
|
124
|
+
yield __escapinate(k)
|
125
|
+
yield __escapinate(v) unless v.nil?
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
class CmdStub
|
132
|
+
def initialize(buffer)
|
133
|
+
@buffer = buffer
|
134
|
+
end
|
135
|
+
|
136
|
+
def emit(data)
|
137
|
+
@emitter.call(data)
|
138
|
+
end
|
139
|
+
|
140
|
+
def |(other)
|
141
|
+
# Append a pipe to the second last command in the stack
|
142
|
+
last = @buffer.pop
|
143
|
+
@buffer << "#{@buffer.pop} | #{last.strip}"
|
144
|
+
self
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
class CmdBuffer
|
150
|
+
def initialize
|
151
|
+
@indent = 0
|
152
|
+
@buffer = []
|
153
|
+
end
|
154
|
+
|
155
|
+
def indent
|
156
|
+
@indent += 1
|
157
|
+
end
|
158
|
+
|
159
|
+
def undent
|
160
|
+
@indent -= 1
|
161
|
+
end
|
162
|
+
|
163
|
+
def << (other)
|
164
|
+
@buffer << "#{INDENT_PADDING * @indent}#{other}"
|
165
|
+
end
|
166
|
+
|
167
|
+
def pop
|
168
|
+
@buffer.pop
|
169
|
+
end
|
170
|
+
|
171
|
+
def write(buf)
|
172
|
+
@buffer.each do |l|
|
173
|
+
buf.puts l
|
174
|
+
end
|
175
|
+
buf.flush
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class ShellWriter
|
180
|
+
def initialize(to)
|
181
|
+
case to
|
182
|
+
when String
|
183
|
+
@to = File.open(to)
|
184
|
+
when IO
|
185
|
+
@to = to
|
186
|
+
else
|
187
|
+
raise "I don't know what to do"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def write(str)
|
192
|
+
@to.write(str)
|
193
|
+
end
|
194
|
+
|
195
|
+
def puts(str)
|
196
|
+
@to.puts(str)
|
197
|
+
end
|
198
|
+
|
199
|
+
def flush
|
200
|
+
@to.flush
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class CaseStub
|
2
|
+
def initialize(value, &block)
|
3
|
+
@value = value
|
4
|
+
@block = block
|
5
|
+
end
|
6
|
+
|
7
|
+
def __handle(buffer)
|
8
|
+
handler = CaseHandler.new(buffer)
|
9
|
+
buffer << "case #{@value} in"
|
10
|
+
buffer.indent
|
11
|
+
@block.call(handler)
|
12
|
+
buffer.undent
|
13
|
+
buffer << "esac"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
class CaseHandler
|
19
|
+
def initialize(buffer)
|
20
|
+
@buffer = buffer
|
21
|
+
end
|
22
|
+
|
23
|
+
def __escapinate(v)
|
24
|
+
if v.empty?
|
25
|
+
'""'
|
26
|
+
else
|
27
|
+
v
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def when(opt, &block)
|
32
|
+
@buffer << "#{__escapinate(opt.to_s)})"
|
33
|
+
@buffer.indent
|
34
|
+
yield
|
35
|
+
@buffer.undent
|
36
|
+
@buffer << ";;"
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class ForStub
|
2
|
+
include ::Escaping
|
3
|
+
|
4
|
+
def initialize(over, iter, &block)
|
5
|
+
@over = over
|
6
|
+
@iter = iter
|
7
|
+
@block = block
|
8
|
+
end
|
9
|
+
|
10
|
+
def __handle(buffer)
|
11
|
+
buffer << "for #{@iter} in #{__escapinate(@over)}; do"
|
12
|
+
buffer.indent
|
13
|
+
@block.call
|
14
|
+
buffer.undent
|
15
|
+
buffer << "done"
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class IfStub
|
2
|
+
def initialize(condition, &block)
|
3
|
+
@condition = condition
|
4
|
+
@block = block
|
5
|
+
end
|
6
|
+
|
7
|
+
def __handle(buffer)
|
8
|
+
handler = IfHandler.new(buffer)
|
9
|
+
buffer << "if #{@condition}"
|
10
|
+
@block.call(handler)
|
11
|
+
buffer << "fi"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class IfHandler
|
16
|
+
def initialize(buffer)
|
17
|
+
@buffer = buffer
|
18
|
+
end
|
19
|
+
|
20
|
+
def then(&block)
|
21
|
+
@buffer << "then"
|
22
|
+
@buffer.indent
|
23
|
+
block.call
|
24
|
+
@buffer.undent
|
25
|
+
end
|
26
|
+
|
27
|
+
def elseif(condition, &block)
|
28
|
+
@buffer << "else if #{condition}"
|
29
|
+
@buffer.indent
|
30
|
+
block.call
|
31
|
+
@buffer.undent
|
32
|
+
end
|
33
|
+
|
34
|
+
def else(&block)
|
35
|
+
@buffer << "else"
|
36
|
+
@buffer.indent
|
37
|
+
block.call
|
38
|
+
@buffer.undent
|
39
|
+
end
|
40
|
+
end
|
data/proof_of_concept.rb
CHANGED
@@ -1,22 +1,60 @@
|
|
1
|
-
require './
|
1
|
+
require './lib/shell-proxy'
|
2
2
|
|
3
3
|
ShellProxy.new.__main__ do
|
4
4
|
cd "Somedir"
|
5
5
|
|
6
|
+
__function("butts_function") do
|
7
|
+
touch "butts"
|
8
|
+
end
|
9
|
+
|
6
10
|
__subshell do
|
7
11
|
__subshell do
|
8
12
|
mkdir "borp"
|
9
13
|
cd "borp"
|
10
14
|
touch "thing"
|
11
15
|
end
|
12
|
-
|
16
|
+
%w[foo bar baz].each do |dir|
|
17
|
+
mkdir dir
|
18
|
+
touch "#{dir}/#{dir}"
|
19
|
+
end
|
20
|
+
touch("somefile")
|
13
21
|
mkdir "foo/bar/thing", { :p => nil }
|
22
|
+
echo("foo") | wc({:c => nil})
|
14
23
|
end
|
15
24
|
|
16
25
|
__chdir "/tmp" do
|
17
26
|
touch "rawr"
|
18
27
|
end
|
19
28
|
|
29
|
+
__set("foo", bare("$RANDOM"))
|
30
|
+
|
31
|
+
some | thing | some | other | thing
|
32
|
+
|
33
|
+
__case(raw("$foo")) do |c|
|
34
|
+
c.when(10000) do
|
35
|
+
echo "holy shit, did not expect that"
|
36
|
+
end
|
37
|
+
c.when("*") do
|
38
|
+
echo "Welp, that was predictable"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
__for(bare("foo bar baz"), "i") do
|
43
|
+
echo raw("$i")
|
44
|
+
end
|
45
|
+
|
20
46
|
rm "foo", { :r => nil, :f => nil }
|
21
47
|
mongod({ :config => "/usr/local/etc/mongod.conf" })
|
48
|
+
|
49
|
+
__if(raw("[[ $foo == 'foo' ]]")) do |c|
|
50
|
+
c.then do
|
51
|
+
echo "it was true"
|
52
|
+
end
|
53
|
+
c.elseif(raw("[[ bar == bar ]]")) do
|
54
|
+
echo "this is definitely true"
|
55
|
+
end
|
56
|
+
c.else do
|
57
|
+
echo "This wont be reached"
|
58
|
+
end
|
59
|
+
end
|
22
60
|
end
|
data/shell-proxy.gemspec
CHANGED
data/test_shell_proxy.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shell-proxy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-18 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: description
|
15
15
|
email:
|
@@ -18,14 +18,19 @@ executables: []
|
|
18
18
|
extensions: []
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
|
+
- .gitignore
|
21
22
|
- Makefile
|
22
23
|
- README.md
|
23
24
|
- README/1
|
24
25
|
- README/2
|
25
26
|
- README/3
|
27
|
+
- lib/shell-proxy.rb
|
28
|
+
- lib/shell-proxy/case.rb
|
29
|
+
- lib/shell-proxy/escaping.rb
|
30
|
+
- lib/shell-proxy/for.rb
|
31
|
+
- lib/shell-proxy/if.rb
|
26
32
|
- proof_of_concept.rb
|
27
33
|
- shell-proxy.gemspec
|
28
|
-
- shell_proxy.rb
|
29
34
|
- test_shell_proxy.rb
|
30
35
|
homepage: http://github.com/richo/shell-proxy
|
31
36
|
licenses: []
|
data/shell_proxy.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
class ShellProxy
|
2
|
-
|
3
|
-
INDENT_PADDING=" "
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@indent = 0
|
7
|
-
end
|
8
|
-
|
9
|
-
def __main__(&block)
|
10
|
-
instance_exec(&block)
|
11
|
-
end
|
12
|
-
|
13
|
-
def __subshell(&block)
|
14
|
-
__emit("(")
|
15
|
-
@indent += 1
|
16
|
-
yield
|
17
|
-
@indent -= 1
|
18
|
-
__emit(")")
|
19
|
-
end
|
20
|
-
|
21
|
-
def __chdir(dir, &block)
|
22
|
-
__subshell do
|
23
|
-
cd(dir)
|
24
|
-
yield
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def method_missing(sym, *args)
|
29
|
-
opts = case args[-1]
|
30
|
-
when Hash
|
31
|
-
args.pop
|
32
|
-
else
|
33
|
-
{}
|
34
|
-
end
|
35
|
-
|
36
|
-
cmd = sym.to_s
|
37
|
-
cmd << " #{__process_opts(opts)}" unless opts.empty?
|
38
|
-
cmd << " #{__process_args(args)}" unless args.empty?
|
39
|
-
__emit cmd
|
40
|
-
end
|
41
|
-
|
42
|
-
def __emit(str)
|
43
|
-
__writer.write(INDENT_PADDING * @indent)
|
44
|
-
__writer.puts(str)
|
45
|
-
__writer.flush
|
46
|
-
end
|
47
|
-
|
48
|
-
def __writer
|
49
|
-
@writer ||= ShellWriter.new($stdout)
|
50
|
-
end
|
51
|
-
|
52
|
-
def __process_args(args)
|
53
|
-
args.map do |v|
|
54
|
-
__escapinate(v)
|
55
|
-
end.join(" ")
|
56
|
-
end
|
57
|
-
|
58
|
-
def __process_opts(opts)
|
59
|
-
outputs = []
|
60
|
-
__process_and_escape(opts) do |value|
|
61
|
-
outputs << value
|
62
|
-
end
|
63
|
-
outputs.join(" ")
|
64
|
-
end
|
65
|
-
|
66
|
-
def __process_and_escape(opts)
|
67
|
-
opts.each do |k, v|
|
68
|
-
k = k.to_s
|
69
|
-
k = (k.length == 1 ? "-" : "--") + k
|
70
|
-
yield __escapinate(k)
|
71
|
-
yield __escapinate(v) unless v.nil?
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def __escapinate(v)
|
76
|
-
"'#{v.gsub(/'/, "\\'").gsub("\\", "\\\\")}'"
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
class ShellWriter
|
82
|
-
def initialize(to)
|
83
|
-
case to
|
84
|
-
when String
|
85
|
-
@to = File.open(to)
|
86
|
-
when IO
|
87
|
-
@to = to
|
88
|
-
else
|
89
|
-
raise "I don't know what to do"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def write(str)
|
94
|
-
@to.write(str)
|
95
|
-
end
|
96
|
-
|
97
|
-
def puts(str)
|
98
|
-
@to.puts(str)
|
99
|
-
end
|
100
|
-
|
101
|
-
def flush
|
102
|
-
@to.flush
|
103
|
-
end
|
104
|
-
|
105
|
-
end
|