loom-core 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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +99 -0
- data/Guardfile +54 -0
- data/Rakefile +6 -0
- data/bin/loom +185 -0
- data/lib/env/development.rb +1 -0
- data/lib/loom.rb +44 -0
- data/lib/loom/all.rb +20 -0
- data/lib/loom/config.rb +106 -0
- data/lib/loom/core_ext.rb +37 -0
- data/lib/loom/dsl.rb +60 -0
- data/lib/loom/facts.rb +13 -0
- data/lib/loom/facts/all.rb +2 -0
- data/lib/loom/facts/fact_file_provider.rb +86 -0
- data/lib/loom/facts/fact_set.rb +138 -0
- data/lib/loom/host_spec.rb +32 -0
- data/lib/loom/inventory.rb +124 -0
- data/lib/loom/logger.rb +141 -0
- data/lib/loom/method_signature.rb +174 -0
- data/lib/loom/mods.rb +4 -0
- data/lib/loom/mods/action_proxy.rb +105 -0
- data/lib/loom/mods/all.rb +3 -0
- data/lib/loom/mods/mod_loader.rb +80 -0
- data/lib/loom/mods/module.rb +113 -0
- data/lib/loom/pattern.rb +15 -0
- data/lib/loom/pattern/all.rb +7 -0
- data/lib/loom/pattern/definition_context.rb +74 -0
- data/lib/loom/pattern/dsl.rb +176 -0
- data/lib/loom/pattern/hook.rb +28 -0
- data/lib/loom/pattern/loader.rb +48 -0
- data/lib/loom/pattern/reference.rb +71 -0
- data/lib/loom/pattern/reference_set.rb +169 -0
- data/lib/loom/pattern/result_reporter.rb +77 -0
- data/lib/loom/runner.rb +209 -0
- data/lib/loom/shell.rb +12 -0
- data/lib/loom/shell/all.rb +10 -0
- data/lib/loom/shell/api.rb +48 -0
- data/lib/loom/shell/cmd_result.rb +33 -0
- data/lib/loom/shell/cmd_wrapper.rb +164 -0
- data/lib/loom/shell/core.rb +226 -0
- data/lib/loom/shell/harness_blob.rb +26 -0
- data/lib/loom/shell/harness_command_builder.rb +50 -0
- data/lib/loom/shell/session.rb +25 -0
- data/lib/loom/trap.rb +44 -0
- data/lib/loom/version.rb +3 -0
- data/lib/loomext/all.rb +4 -0
- data/lib/loomext/corefacts.rb +6 -0
- data/lib/loomext/corefacts/all.rb +8 -0
- data/lib/loomext/corefacts/facter_provider.rb +24 -0
- data/lib/loomext/coremods.rb +5 -0
- data/lib/loomext/coremods/all.rb +13 -0
- data/lib/loomext/coremods/exec.rb +50 -0
- data/lib/loomext/coremods/files.rb +104 -0
- data/lib/loomext/coremods/net.rb +33 -0
- data/lib/loomext/coremods/package/adapter.rb +100 -0
- data/lib/loomext/coremods/package/package.rb +62 -0
- data/lib/loomext/coremods/user.rb +82 -0
- data/lib/loomext/coremods/vm.rb +0 -0
- data/lib/loomext/coremods/vm/all.rb +6 -0
- data/lib/loomext/coremods/vm/vbox.rb +84 -0
- data/loom.gemspec +39 -0
- data/loom/inventory.yml +13 -0
- data/scripts/harness.sh +242 -0
- data/spec/loom/host_spec_spec.rb +101 -0
- data/spec/loom/inventory_spec.rb +154 -0
- data/spec/loom/method_signature_spec.rb +275 -0
- data/spec/loom/pattern/dsl_spec.rb +207 -0
- data/spec/loom/shell/cmd_wrapper_spec.rb +239 -0
- data/spec/loom/shell/harness_blob_spec.rb +42 -0
- data/spec/loom/shell/harness_command_builder_spec.rb +36 -0
- data/spec/runloom.sh +35 -0
- data/spec/scripts/harness_spec.rb +385 -0
- data/spec/spec_helper.rb +94 -0
- data/spec/test.loom +370 -0
- data/spec/test_loom_spec.rb +57 -0
- metadata +287 -0
@@ -0,0 +1,207 @@
|
|
1
|
+
require "loom/facts"
|
2
|
+
require "loom/pattern"
|
3
|
+
require "loom/shell"
|
4
|
+
|
5
|
+
describe Loom::Pattern::DSL do
|
6
|
+
|
7
|
+
# Fake API for tests. This object should raise an error on any command
|
8
|
+
# execution.
|
9
|
+
let(:fake_shell) { Loom::Shell::FakeApi.new }
|
10
|
+
let(:a_fact_set) do
|
11
|
+
Loom::Facts::FactSet.new('fake.host', :fact_one => 1, :fact_two => :two)
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
# bit buckets the logs
|
16
|
+
@logger_io = StringIO.new
|
17
|
+
Loom.configure do |config|
|
18
|
+
config.log_device = @logger_io
|
19
|
+
end
|
20
|
+
|
21
|
+
@reference_set = Loom::Pattern::ReferenceSet::Builder
|
22
|
+
.create(loom_file, ':loom_file')
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:pattern_under_test) { @reference_set['pattern_under_test'] }
|
26
|
+
let(:inner_pattern) { @reference_set['inner:an_inner_pattern'] }
|
27
|
+
|
28
|
+
context "pattern basics" do
|
29
|
+
|
30
|
+
let(:loom_file) do
|
31
|
+
<<EOS
|
32
|
+
desc "a description of pattern_under_test"
|
33
|
+
pattern :pattern_under_test do |loom, facts|
|
34
|
+
loom.do_outer_thing
|
35
|
+
end
|
36
|
+
|
37
|
+
module Inner
|
38
|
+
include Loom::Pattern
|
39
|
+
|
40
|
+
desc "an inner pattern"
|
41
|
+
pattern :an_inner_pattern do |loom, facts|
|
42
|
+
loom.do_inner_thing
|
43
|
+
end
|
44
|
+
end
|
45
|
+
EOS
|
46
|
+
end
|
47
|
+
|
48
|
+
it "defines a Pattern::Reference" do
|
49
|
+
expect(pattern_under_test).to be_a Loom::Pattern::Reference
|
50
|
+
end
|
51
|
+
|
52
|
+
it "defines a reference with a desc" do
|
53
|
+
expect(pattern_under_test.desc).to(
|
54
|
+
eql "a description of pattern_under_test")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "defines an inner reference with a desc" do
|
58
|
+
expect(inner_pattern.desc).to eql "an inner pattern"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "is runnable" do
|
62
|
+
pattern_under_test.call fake_shell, a_fact_set
|
63
|
+
expect(fake_shell.cmd_executions.first).to be :do_outer_thing
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "#let" do
|
68
|
+
|
69
|
+
let(:loom_file) do
|
70
|
+
<<EOS
|
71
|
+
let(:let_var_1) { "let var 1"}
|
72
|
+
let(:let_var_2) { "let var 2"}
|
73
|
+
|
74
|
+
desc "a description of pattern_under_test"
|
75
|
+
pattern :pattern_under_test do |loom, facts|
|
76
|
+
loom.do_outer_thing(let_var_1, let_var_2)
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "a pattern that will raise an erorr"
|
80
|
+
pattern :bogus_pattern do |loom, facts|
|
81
|
+
loom.do_outer_thing(let_var_3)
|
82
|
+
end
|
83
|
+
|
84
|
+
module Inner
|
85
|
+
include Loom::Pattern
|
86
|
+
|
87
|
+
let(:let_var_2) { "override let var 2"}
|
88
|
+
let(:let_var_3) { "let var 3"}
|
89
|
+
|
90
|
+
desc "an inner pattern"
|
91
|
+
pattern :an_inner_pattern do |loom, facts|
|
92
|
+
loom.do_inner_thing(let_var_1, let_var_2, let_var_3)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
EOS
|
96
|
+
end
|
97
|
+
|
98
|
+
it "defines :let declartions at the top level" do
|
99
|
+
pattern_under_test.call fake_shell, a_fact_set
|
100
|
+
expect(fake_shell.cmd_execution_args.first).to(
|
101
|
+
eql ["let var 1", "let var 2"])
|
102
|
+
end
|
103
|
+
|
104
|
+
it "defines :let declartions at inner scopes, innacessible to outer" do
|
105
|
+
expect do
|
106
|
+
@reference_set['bogus_pattern'].call fake_shell, a_fact_set
|
107
|
+
end.to raise_error /^undefined local variable/
|
108
|
+
end
|
109
|
+
|
110
|
+
it "defines :let declarations at inner scopes, overriding outer scope" do
|
111
|
+
inner_pattern.call fake_shell, a_fact_set
|
112
|
+
expect(fake_shell.cmd_execution_args.first).to(
|
113
|
+
eql ["let var 1", "override let var 2", "let var 3"])
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "#with_facts" do
|
118
|
+
|
119
|
+
let(:loom_file) do
|
120
|
+
<<EOS
|
121
|
+
with_facts :outer_fact => :outer
|
122
|
+
|
123
|
+
desc "a description of pattern_under_test"
|
124
|
+
pattern :pattern_under_test do |loom, facts|
|
125
|
+
loom.do_outer_thing facts[:outer_fact]
|
126
|
+
end
|
127
|
+
|
128
|
+
module Inner
|
129
|
+
include Loom::Pattern
|
130
|
+
|
131
|
+
with_facts :inner_fact => :inner
|
132
|
+
|
133
|
+
desc "an inner pattern"
|
134
|
+
pattern :an_inner_pattern do |loom, facts|
|
135
|
+
loom.do_inner_thing(facts[:outer_fact], facts[:inner_fact])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
EOS
|
139
|
+
end
|
140
|
+
|
141
|
+
it "defines fact sets at the top level" do
|
142
|
+
pattern_under_test.call fake_shell, a_fact_set
|
143
|
+
expect(fake_shell.cmd_execution_args.first).to(
|
144
|
+
eql [:outer])
|
145
|
+
end
|
146
|
+
|
147
|
+
it "provides fact sets that get merged into inner modules" do
|
148
|
+
inner_pattern.call fake_shell, a_fact_set
|
149
|
+
expect(fake_shell.cmd_execution_args.first).to(
|
150
|
+
eql [:outer, :inner])
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "hooks" do
|
155
|
+
|
156
|
+
let(:loom_file) do
|
157
|
+
<<EOS
|
158
|
+
|
159
|
+
let(:hook_order) { [] }
|
160
|
+
|
161
|
+
before do hook_order.push("outer before hook") end
|
162
|
+
after do hook_order.push("outer after hook") end
|
163
|
+
|
164
|
+
desc "a description of pattern_under_test"
|
165
|
+
pattern :pattern_under_test do |loom, facts|
|
166
|
+
hook_order.push "execute the pattern"
|
167
|
+
loom.do_outer_thing(hook_order)
|
168
|
+
end
|
169
|
+
|
170
|
+
module Inner
|
171
|
+
include Loom::Pattern
|
172
|
+
|
173
|
+
before do hook_order.push("inner before hook") end
|
174
|
+
after do hook_order.push("inner after hook") end
|
175
|
+
|
176
|
+
desc "an inner pattern"
|
177
|
+
pattern :an_inner_pattern do |loom, facts|
|
178
|
+
hook_order.push "execute inner pattern"
|
179
|
+
loom.do_inner_thing(hook_order)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
EOS
|
183
|
+
end
|
184
|
+
|
185
|
+
it "executes outer before hooks first and after hooks last" do
|
186
|
+
pattern_under_test.call fake_shell, a_fact_set
|
187
|
+
expect(fake_shell.cmd_execution_args.first).to eql [[
|
188
|
+
"outer before hook",
|
189
|
+
"execute the pattern",
|
190
|
+
"outer after hook"
|
191
|
+
]]
|
192
|
+
end
|
193
|
+
|
194
|
+
it "executes nested hooks in wrapped order" do
|
195
|
+
inner_pattern.call fake_shell, a_fact_set
|
196
|
+
expect(fake_shell.cmd_execution_args.first).to eql [[
|
197
|
+
"outer before hook",
|
198
|
+
"inner before hook",
|
199
|
+
"execute inner pattern",
|
200
|
+
"inner after hook",
|
201
|
+
"outer after hook"
|
202
|
+
]]
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
require "loom/shell"
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
describe Loom::Shell::CmdWrapper do
|
5
|
+
|
6
|
+
def unescape_cmd(cmd)
|
7
|
+
YAML.load(%Q(---\n"#{cmd.to_s}"\n))
|
8
|
+
end
|
9
|
+
|
10
|
+
context "examples" do
|
11
|
+
it "escapes spaces" do
|
12
|
+
cmd = Loom::Shell::CmdWrapper.new :printf, "print out this string"
|
13
|
+
expect(%x{#{cmd}}).to eql "print out this string"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "skips escaping symbols and frozen string" do
|
17
|
+
cmd = Loom::Shell::CmdWrapper.new :"/bin/echo", :"\"yy\"", "\"xx\""
|
18
|
+
expect(%x{#{cmd}}.strip).to eql "yy \"xx\""
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context ".new" do
|
23
|
+
it "does not escape whitespace between joined commands parts" do
|
24
|
+
cmd = Loom::Shell::CmdWrapper.new :echo, "-n", "\"all the rest\""
|
25
|
+
expect(cmd.escape_cmd).to eql "echo -n \\\"all\\ the\\ rest\\\""
|
26
|
+
end
|
27
|
+
|
28
|
+
it "flattens cmd input" do
|
29
|
+
cmd = Loom::Shell::CmdWrapper.new :somecmd, ["-f", "file.txt"], [:a, [:b]]
|
30
|
+
expect(cmd.to_s).to eql "somecmd -f file.txt a b"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context ".escape" do
|
35
|
+
it "escapes CmdWrappers" do
|
36
|
+
cmd = Loom::Shell::CmdWrapper.new '"hi"'
|
37
|
+
expect(Loom::Shell::CmdWrapper.escape cmd).to eql cmd.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
it "escapes recursively" do
|
41
|
+
content = 'I said "row row row your boat"'
|
42
|
+
cmd_inner = 'echo "%s"' % Loom::Shell::CmdWrapper.escape(content)
|
43
|
+
cmd_outer = '"%s"' % Loom::Shell::CmdWrapper.escape(cmd_inner)
|
44
|
+
|
45
|
+
expected = '"echo\ \"I\\\\\ said\\\\\ ' +
|
46
|
+
'\\\\\"row\\\\\ row\\\\\ row\\\\\ your\\\\\ boat\\\\\"\""'
|
47
|
+
|
48
|
+
printf_expected = 'echo\\ "I\ said\ "row\ row\ row\ your\ boat""'
|
49
|
+
|
50
|
+
expect(cmd_outer).to eql expected
|
51
|
+
expect(%x{printf #{cmd_outer}}.strip).to eql printf_expected
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "#escape" do
|
56
|
+
it "escapes strings with quotes" do
|
57
|
+
cmd = Loom::Shell::CmdWrapper.new '"hi"'
|
58
|
+
|
59
|
+
expected = '\"hi\"'
|
60
|
+
expect(cmd.escape_cmd).to eql expected
|
61
|
+
expect(%x{printf #{expected}}.strip).to eql unescape_cmd(cmd)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "ignores strings without quotes" do
|
65
|
+
cmd = Loom::Shell::CmdWrapper.new 'hi'
|
66
|
+
|
67
|
+
expected = 'hi'
|
68
|
+
expect(cmd.escape_cmd).to eql expected
|
69
|
+
expect(%x{printf #{expected}}.strip).to eql unescape_cmd(cmd)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "escapes nested quotes" do
|
73
|
+
cmd = Loom::Shell::CmdWrapper.new 'echo "hi"'
|
74
|
+
|
75
|
+
expected = 'echo\\ \"hi\"'
|
76
|
+
expect(cmd.escape_cmd).to eql expected
|
77
|
+
expect(%x{printf #{expected}}.strip).to eql unescape_cmd(cmd)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "respects frozen? string" do
|
81
|
+
cmd = Loom::Shell::CmdWrapper.new :echo, "\"^FROZEN^\"".freeze, :"^", "^"
|
82
|
+
|
83
|
+
expected = 'echo "^FROZEN^" ^ \^'
|
84
|
+
expect(cmd.escape_cmd).to eql expected
|
85
|
+
end
|
86
|
+
|
87
|
+
it "respects wrapped frozen? strings" do
|
88
|
+
cmd_inner = Loom::Shell::CmdWrapper.new :echo, "\"^#FROZEN^\"".freeze
|
89
|
+
cmd = Loom::Shell::CmdWrapper.wrap_cmd :sudo, cmd_inner
|
90
|
+
|
91
|
+
expected = 'sudo echo "^#FROZEN^"'
|
92
|
+
expect(cmd.escape_cmd).to eql expected
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# I don't want to think about this shit anymore. Don't touch this unless its
|
97
|
+
# broken.
|
98
|
+
context "#wrap" do
|
99
|
+
it "preserves escaped CmdWrappers: depth 2" do
|
100
|
+
cmd_which = Loom::Shell::CmdWrapper.new :which, :ls
|
101
|
+
cmd_sh = Loom::Shell::CmdWrapper.new :"/bin/sh", "-c", should_quote: true
|
102
|
+
|
103
|
+
composed_cmd = cmd_sh.wrap(cmd_sh.wrap(cmd_which)).to_s
|
104
|
+
|
105
|
+
expected = "/bin/sh -c \"/bin/sh -c \\\"which ls\\\"\""
|
106
|
+
|
107
|
+
expect(composed_cmd).to eql expected
|
108
|
+
# Matches /bin/ls$ for portability, on fedora it's /usr/bin/ls
|
109
|
+
expect(%x{#{composed_cmd}}.strip).to match /\/bin\/ls$/
|
110
|
+
end
|
111
|
+
|
112
|
+
it "preserves escaped CmdWrappers: depth N" do
|
113
|
+
cmd_which = Loom::Shell::CmdWrapper.new :which, :ls
|
114
|
+
cmd_sh = Loom::Shell::CmdWrapper.new :"/bin/sh", "-c", should_quote: true
|
115
|
+
|
116
|
+
composed_cmd = cmd_sh.wrap(cmd_sh.wrap(cmd_sh.wrap(cmd_which))).to_s
|
117
|
+
|
118
|
+
expected =
|
119
|
+
"/bin/sh -c \"/bin/sh -c \\\"/bin/sh -c \\\\\\\"which ls\\\\\\\"\\\"\""
|
120
|
+
|
121
|
+
expect(composed_cmd).to eql expected
|
122
|
+
# Matches /bin/ls$ for portability, on fedora it's /usr/bin/ls
|
123
|
+
expect(%x{#{composed_cmd}}.strip).to match /\/bin\/ls$/
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context Loom::Shell::CmdRedirect do
|
128
|
+
|
129
|
+
let(:cmd_parts) { [:"/bin/ls"] }
|
130
|
+
|
131
|
+
it "redirects stdout to file" do
|
132
|
+
redirect = Loom::Shell::CmdRedirect.new "/my/file"
|
133
|
+
cmd = Loom::Shell::CmdWrapper.new *cmd_parts, redirect: redirect
|
134
|
+
|
135
|
+
expect(cmd.to_s).to eql "/bin/ls >/my/file"
|
136
|
+
end
|
137
|
+
|
138
|
+
it "redirects stderr to file" do
|
139
|
+
redirect = Loom::Shell::CmdRedirect.new "/my/file", fd: 2
|
140
|
+
cmd = Loom::Shell::CmdWrapper.new *cmd_parts, redirect: redirect
|
141
|
+
|
142
|
+
expect(cmd.to_s).to eql "/bin/ls 2>/my/file"
|
143
|
+
end
|
144
|
+
|
145
|
+
it "appends stdout to file" do
|
146
|
+
mode = Loom::Shell::CmdRedirect::Mode::APPEND
|
147
|
+
|
148
|
+
redirect = Loom::Shell::CmdRedirect.new "/my/file", mode: mode
|
149
|
+
cmd = Loom::Shell::CmdWrapper.new *cmd_parts, redirect: redirect
|
150
|
+
|
151
|
+
expect(cmd.to_s).to eql "/bin/ls >>/my/file"
|
152
|
+
end
|
153
|
+
|
154
|
+
it "appends stderr to file" do
|
155
|
+
mode = Loom::Shell::CmdRedirect::Mode::APPEND
|
156
|
+
|
157
|
+
redirect = Loom::Shell::CmdRedirect.new "/my/file", fd: 2, mode: mode
|
158
|
+
cmd = Loom::Shell::CmdWrapper.new *cmd_parts, redirect: redirect
|
159
|
+
|
160
|
+
expect(cmd.to_s).to eql "/bin/ls 2>>/my/file"
|
161
|
+
end
|
162
|
+
|
163
|
+
it "redirects stderr to stdout" do
|
164
|
+
redirect = Loom::Shell::CmdRedirect.new 1, fd: 2
|
165
|
+
cmd = Loom::Shell::CmdWrapper.new *cmd_parts, redirect: redirect
|
166
|
+
|
167
|
+
expect(cmd.to_s).to eql "/bin/ls 2>1"
|
168
|
+
end
|
169
|
+
|
170
|
+
it "redirects both stderr and stdout to file" do
|
171
|
+
mode = Loom::Shell::CmdRedirect::Mode::OUTPUT_12
|
172
|
+
|
173
|
+
redirect = Loom::Shell::CmdRedirect.new "/my/file", mode: mode
|
174
|
+
cmd = Loom::Shell::CmdWrapper.new *cmd_parts, redirect: redirect
|
175
|
+
|
176
|
+
expect(cmd.to_s).to eql "/bin/ls &>/my/file"
|
177
|
+
end
|
178
|
+
|
179
|
+
context "helper factories" do
|
180
|
+
|
181
|
+
it "appends to stdout" do
|
182
|
+
redirect = Loom::Shell::CmdRedirect.append_stdout "/my/file"
|
183
|
+
cmd = Loom::Shell::CmdWrapper.new *cmd_parts, redirect: redirect
|
184
|
+
|
185
|
+
expect(cmd.to_s).to eql "/bin/ls >>/my/file"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context "multiple redirects" do
|
190
|
+
it "redirects both stderr and stdout to file" do
|
191
|
+
|
192
|
+
redirects = [
|
193
|
+
Loom::Shell::CmdRedirect.new("/my/file"),
|
194
|
+
Loom::Shell::CmdRedirect.new(1, fd: 2)
|
195
|
+
]
|
196
|
+
cmd = Loom::Shell::CmdWrapper.new *cmd_parts, redirect: redirects
|
197
|
+
|
198
|
+
expect(cmd.to_s).to eql "/bin/ls >/my/file 2>1"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context "wrapped redirects" do
|
203
|
+
it "does not escape redirects" do
|
204
|
+
skip "fails - this is why I started implementing the harness see " +
|
205
|
+
"`git show 1196d2ec2` for info"
|
206
|
+
r = Loom::Shell::CmdRedirect.append_stdout "/my/file"
|
207
|
+
|
208
|
+
cmd_inner = Loom::Shell::CmdWrapper.new :echo, :hello, redirect: r
|
209
|
+
cmd = Loom::Shell::CmdWrapper.wrap_cmd :sudo, "-u", :root, cmd_inner
|
210
|
+
|
211
|
+
expect(cmd.to_s).to eql "sudo -u root echo hello >>/my/file"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context Loom::Shell::CmdPipeline do
|
217
|
+
|
218
|
+
let(:cmds) do
|
219
|
+
[
|
220
|
+
Loom::Shell::CmdWrapper.new(:find, ".", "-name", "*foo", "-print0"),
|
221
|
+
Loom::Shell::CmdWrapper.new(:xargs, "-0", "-I-", "ls", "-")
|
222
|
+
]
|
223
|
+
end
|
224
|
+
|
225
|
+
it "pipes commands together" do
|
226
|
+
pipeline = Loom::Shell::CmdPipeline.new cmds
|
227
|
+
|
228
|
+
expected = "find . -name \\*foo -print0 | xargs -0 -I- ls -"
|
229
|
+
expect(pipeline.to_s).to eql expected
|
230
|
+
end
|
231
|
+
|
232
|
+
it "accepts commands as pre-escaped strings" do
|
233
|
+
pipeline = Loom::Shell::CmdPipeline.new ["I'm already escaped", "me too!"]
|
234
|
+
|
235
|
+
expected = "I'm already escaped | me too!"
|
236
|
+
expect(pipeline.to_s).to eql expected
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
describe Loom::Shell::HarnessBlob do
|
2
|
+
|
3
|
+
HARNESS = "./scripts/harness.sh"
|
4
|
+
|
5
|
+
# Set debug_script to true in a context to see STDERR debugging.
|
6
|
+
let(:debug_script) { false }
|
7
|
+
|
8
|
+
let(:cmd) { 'echo hi there | (echo "from subshell"; cat);' }
|
9
|
+
let(:encoded_script) do
|
10
|
+
run_harnes_script "--print_base64", :stdin => cmd
|
11
|
+
end
|
12
|
+
let(:golden_checksum) do
|
13
|
+
run_harnes_script "--print_checksum", encoded_script
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def run_harnes_script(cmd, *args, stdin: nil)
|
18
|
+
cmd = %Q{./scripts/harness.sh 2>/dev/null #{cmd}}
|
19
|
+
|
20
|
+
heredoc = nil
|
21
|
+
if stdin
|
22
|
+
heredoc = "<<'EOS'\n#{stdin}\nEOS"
|
23
|
+
cmd << " - #{args.join " "} #{heredoc}"
|
24
|
+
else
|
25
|
+
cmd << " #{args.join " "}"
|
26
|
+
end
|
27
|
+
|
28
|
+
%x{#{cmd}}
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "scripts/harness.sh parity" do
|
32
|
+
|
33
|
+
subject { Loom::Shell::HarnessBlob.new cmd }
|
34
|
+
|
35
|
+
it "computes a valid script checksum" do
|
36
|
+
run_harnes_script "--check", golden_checksum, {
|
37
|
+
:stdin => subject.encoded_script
|
38
|
+
}
|
39
|
+
expect($?.exitstatus).to eq 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|