vanagon 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/bin/build +1 -1
- data/lib/makefile.rb +67 -0
- data/lib/vanagon/component.rb +16 -2
- data/lib/vanagon/component/dsl.rb +34 -3
- data/lib/vanagon/component/rules.rb +217 -0
- data/lib/vanagon/component/source/http.rb +8 -3
- data/lib/vanagon/driver.rb +12 -5
- data/lib/vanagon/engine/hardware.rb +64 -0
- data/lib/vanagon/optparse.rb +16 -33
- data/lib/vanagon/patch.rb +39 -0
- data/lib/vanagon/platform.rb +3 -2
- data/lib/vanagon/platform/dsl.rb +23 -5
- data/lib/vanagon/platform/rpm/eos.rb +83 -0
- data/lib/vanagon/platform/solaris_10.rb +19 -4
- data/lib/vanagon/utilities/shell_utilities.rb +29 -0
- data/spec/lib/makefile_spec.rb +50 -0
- data/spec/lib/vanagon/component/dsl_spec.rb +61 -2
- data/spec/lib/vanagon/component/rules_spec.rb +302 -0
- data/spec/lib/vanagon/component_spec.rb +17 -0
- data/spec/lib/vanagon/engine/hardware_spec.rb +48 -0
- data/spec/lib/vanagon/optparse_spec.rb +40 -0
- data/spec/lib/vanagon/utilities/shell_utilities_spec.rb +32 -0
- data/templates/Makefile.erb +1 -58
- data/templates/rpm/project.spec.erb +1 -1
- metadata +33 -4
- data/lib/vanagon/platform/swix.rb +0 -35
@@ -0,0 +1,29 @@
|
|
1
|
+
class Vanagon
|
2
|
+
module Utilities
|
3
|
+
module ShellUtilities
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# join a combination of strings and arrays of strings into a single command
|
7
|
+
# joined with '&&'
|
8
|
+
#
|
9
|
+
# @param commands [Array<String, Array<String>>]
|
10
|
+
# @return [String]
|
11
|
+
def andand(*commands)
|
12
|
+
cmdjoin(commands, " && ")
|
13
|
+
end
|
14
|
+
|
15
|
+
# join a combination of strings and arrays of strings into a single command
|
16
|
+
# joined with '&&' and broken up with newlines after each '&&'
|
17
|
+
#
|
18
|
+
# @param commands [Array<String, Array<String>>]
|
19
|
+
# @return [String]
|
20
|
+
def andand_multiline(*commands)
|
21
|
+
cmdjoin(commands, " && \\\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
def cmdjoin(commands, sep)
|
25
|
+
commands.map { |o| Array(o) }.flatten.join(sep)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'makefile'
|
2
|
+
|
3
|
+
describe Makefile::Rule do
|
4
|
+
describe "a rule with no dependencies and an empty recipe" do
|
5
|
+
subject { described_class.new("empty") }
|
6
|
+
|
7
|
+
it "creates an empty rule" do
|
8
|
+
expect(subject.format).to eq "empty:\n"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "a rule with no dependencies and a simple recipe" do
|
13
|
+
subject { described_class.new("simple", recipe: ["touch simple"]) }
|
14
|
+
|
15
|
+
it "creates the rule with the recipe" do
|
16
|
+
expect(subject.format).to eq "simple:\n\ttouch simple\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "a rule with dependencies and no recipe" do
|
21
|
+
subject { described_class.new("depends", dependencies: ["mydeps"]) }
|
22
|
+
|
23
|
+
it "creates the rule with the recipe" do
|
24
|
+
expect(subject.format).to eq "depends: mydeps\n"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "a rule with dependencies and a recipe" do
|
29
|
+
subject { described_class.new("deluxe", recipe: ["touch deluxe"], dependencies: ["mydeps"]) }
|
30
|
+
|
31
|
+
it "creates the rule with the recipe" do
|
32
|
+
expect(subject.format).to eq "deluxe: mydeps\n\ttouch deluxe\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "a rule with a multiline recipe" do
|
37
|
+
subject do
|
38
|
+
described_class.new("multiline") do |rule|
|
39
|
+
rule.recipe = [
|
40
|
+
"[ -d build ] || mkdir -p build",
|
41
|
+
"cd build &&\ncmake .. &&\nmake &&\nmake install"
|
42
|
+
]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "inserts tabs after each newline in the recipe" do
|
47
|
+
expect(subject.format).to eq "multiline:\n\t[ -d build ] || mkdir -p build\n\tcd build &&\n\tcmake .. &&\n\tmake &&\n\tmake install\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -105,6 +105,21 @@ end" }
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
|
+
describe '#check' do
|
109
|
+
it 'sets check to the value if check is empty' do
|
110
|
+
comp = Vanagon::Component::DSL.new('check-test', {}, {})
|
111
|
+
comp.check { './check' }
|
112
|
+
expect(comp._component.check).to eq(['./check'])
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'appends to the existing check if not empty' do
|
116
|
+
comp = Vanagon::Component::DSL.new('check-test', {}, {})
|
117
|
+
comp.check { 'make test' }
|
118
|
+
comp.check { 'make cpplint' }
|
119
|
+
expect(comp._component.check).to eq(['make test', 'make cpplint'])
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
108
123
|
describe '#install' do
|
109
124
|
it 'sets install to the value if install is empty' do
|
110
125
|
comp = Vanagon::Component::DSL.new('install-test', {}, {})
|
@@ -136,8 +151,37 @@ end" }
|
|
136
151
|
comp.apply_patch('patch_file1', fuzz: 12, strip: 1000000)
|
137
152
|
expect(comp._component.patches.count).to eq 1
|
138
153
|
expect(comp._component.patches.first.path).to eq 'patch_file1'
|
139
|
-
expect(comp._component.patches.first.fuzz).to eq
|
140
|
-
expect(comp._component.patches.first.strip).to eq
|
154
|
+
expect(comp._component.patches.first.fuzz).to eq 12
|
155
|
+
expect(comp._component.patches.first.strip).to eq 1000000
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'can specify a directory where the patch should be applied' do
|
159
|
+
comp = Vanagon::Component::DSL.new('patch-test', {}, {})
|
160
|
+
comp.apply_patch('patch_file1', destination: 'random/install/directory')
|
161
|
+
expect(comp._component.patches.count).to eq 1
|
162
|
+
expect(comp._component.patches.first.path).to eq 'patch_file1'
|
163
|
+
expect(comp._component.patches.first.destination).to eq 'random/install/directory'
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'can specify when to try to apply the patch' do
|
167
|
+
comp = Vanagon::Component::DSL.new('patch-test', {}, {})
|
168
|
+
comp.apply_patch('patch_file1', after: 'install')
|
169
|
+
expect(comp._component.patches.count).to eq 1
|
170
|
+
expect(comp._component.patches.first.path).to eq 'patch_file1'
|
171
|
+
expect(comp._component.patches.first.after).to eq 'install'
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'will default the patch timing to after the source is unpacked' do
|
175
|
+
comp = Vanagon::Component::DSL.new('patch-test', {}, {})
|
176
|
+
comp.apply_patch('patch_file1')
|
177
|
+
expect(comp._component.patches.count).to eq 1
|
178
|
+
expect(comp._component.patches.first.path).to eq 'patch_file1'
|
179
|
+
expect(comp._component.patches.first.after).to eq 'unpack'
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'will fail if the user wants to install the patch at an unsupported step' do
|
183
|
+
comp = Vanagon::Component::DSL.new('patch-test', {}, {})
|
184
|
+
expect { comp.apply_patch('patch_file1', after: 'delivery') }.to raise_error(Vanagon::Error)
|
141
185
|
end
|
142
186
|
end
|
143
187
|
|
@@ -484,6 +528,21 @@ end" }
|
|
484
528
|
end
|
485
529
|
end
|
486
530
|
|
531
|
+
describe "#build_dir" do
|
532
|
+
it "sets the build_dir when given a relative path" do
|
533
|
+
comp = Vanagon::Component::DSL.new('build-dir-test', {}, platform)
|
534
|
+
comp.build_dir("build")
|
535
|
+
expect(comp._component.build_dir).to eq("build")
|
536
|
+
end
|
537
|
+
|
538
|
+
it "raises an error when given an absolute path" do
|
539
|
+
comp = Vanagon::Component::DSL.new('build-dir-test', {}, platform)
|
540
|
+
expect {
|
541
|
+
comp.build_dir("/build")
|
542
|
+
}.to raise_error(Vanagon::Error, %r[build_dir should be a relative path, but '/build' looks to be absolute\.])
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
487
546
|
describe '#link' do
|
488
547
|
it 'adds the correct command to the install for the component' do
|
489
548
|
comp = Vanagon::Component::DSL.new('link-test', {}, platform)
|
@@ -0,0 +1,302 @@
|
|
1
|
+
require 'vanagon/component'
|
2
|
+
require 'vanagon/component/dsl'
|
3
|
+
require 'vanagon/component/rules'
|
4
|
+
require 'vanagon/platform/osx'
|
5
|
+
require 'vanagon/project'
|
6
|
+
require 'vanagon/patch'
|
7
|
+
require 'ostruct'
|
8
|
+
|
9
|
+
RSpec.shared_examples "a rule that touches the target file" do
|
10
|
+
it "touches the target file as the last step of the recipe" do
|
11
|
+
expect(rule.recipe.last).to eq "touch #{rule.target}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Vanagon::Component::Rules do
|
16
|
+
let(:platform) do
|
17
|
+
OpenStruct.new(:patch => "/usr/bin/patch", :make => '/usr/bin/make')
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:project) do
|
21
|
+
Vanagon::Project.new("cpp-project", platform)
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:component) do
|
25
|
+
Vanagon::Component.new("leatherman", {}, platform).tap do |c|
|
26
|
+
c.dirname = "/foo/bar"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
subject { described_class.new(component, project, platform) }
|
31
|
+
|
32
|
+
describe "the component rule" do
|
33
|
+
it "depends on the component-install rule" do
|
34
|
+
rule = subject.component_rule
|
35
|
+
expect(rule.dependencies).to eq(["leatherman-install"])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "the unpack rule" do
|
40
|
+
let(:rule) { subject.unpack_rule }
|
41
|
+
|
42
|
+
it { expect(rule.dependencies).to eq(["file-list-before-build"]) }
|
43
|
+
|
44
|
+
it "extracts the source" do
|
45
|
+
component.extract_with = "/usr/bin/tar"
|
46
|
+
expect(rule.recipe.first).to eq ": && /usr/bin/tar"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "sets environment variables before running the unpack steps" do
|
50
|
+
component.extract_with = "/usr/bin/tar"
|
51
|
+
component.environment = {"PATH" => "/opt/pl-build-tools/bin:$$PATH"}
|
52
|
+
expect(rule.recipe.first).to eq(
|
53
|
+
[
|
54
|
+
"export PATH=\"/opt/pl-build-tools/bin:$$PATH\"",
|
55
|
+
"/usr/bin/tar"
|
56
|
+
].join(" && ")
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
it_behaves_like "a rule that touches the target file"
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "the patch rule" do
|
64
|
+
let(:rule) { subject.patch_rule }
|
65
|
+
|
66
|
+
it { expect(rule.dependencies).to eq(["leatherman-unpack"]) }
|
67
|
+
|
68
|
+
it "does nothing when there are no patches" do
|
69
|
+
expect(rule.recipe.size).to eq 1
|
70
|
+
end
|
71
|
+
|
72
|
+
it "applies each listed patch in order when patches are set" do
|
73
|
+
component.patches = [
|
74
|
+
Vanagon::Patch.new('/foo/patch0', '1', '0', 'unpack', '/foo/bar'),
|
75
|
+
Vanagon::Patch.new('/foo/patch1', '2', '1', 'unpack', '/foo/bar'),
|
76
|
+
Vanagon::Patch.new('/foo/postinstall/patch1', '2', '1', 'install', '/foo/bar')
|
77
|
+
]
|
78
|
+
expect(rule.recipe.first).to eq(
|
79
|
+
[
|
80
|
+
"cd /foo/bar",
|
81
|
+
"/usr/bin/patch --strip=1 --fuzz=0 --ignore-whitespace < $(workdir)/patches/patch0",
|
82
|
+
"/usr/bin/patch --strip=2 --fuzz=1 --ignore-whitespace < $(workdir)/patches/patch1"
|
83
|
+
].join(" && \\\n")
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
it_behaves_like "a rule that touches the target file"
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "the configure rule" do
|
91
|
+
let(:rule) { subject.configure_rule }
|
92
|
+
|
93
|
+
# TODO: cross-component dependencies
|
94
|
+
it { expect(rule.dependencies).to eq(['leatherman-patch']) }
|
95
|
+
|
96
|
+
describe "when a build directory is set" do
|
97
|
+
before do
|
98
|
+
component.build_dir = "build"
|
99
|
+
end
|
100
|
+
|
101
|
+
it "creates the build directory" do
|
102
|
+
expect(rule.recipe.first).to eq("[ -d /foo/bar/build ] || mkdir -p /foo/bar/build")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it "runs all of the configure commands when given" do
|
107
|
+
component.configure = ["./configure", "cmake .."]
|
108
|
+
expect(rule.recipe[1]).to eq(
|
109
|
+
[
|
110
|
+
"cd /foo/bar",
|
111
|
+
":",
|
112
|
+
"./configure",
|
113
|
+
"cmake .."
|
114
|
+
].join(" && \\\n")
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "sets environment variables before running the configure steps" do
|
119
|
+
component.configure = ["./configure", "cmake .."]
|
120
|
+
component.environment = {"PATH" => "/opt/pl-build-tools/bin:$$PATH"}
|
121
|
+
expect(rule.recipe[1]).to eq(
|
122
|
+
[
|
123
|
+
"cd /foo/bar",
|
124
|
+
"export PATH=\"/opt/pl-build-tools/bin:$$PATH\"",
|
125
|
+
"./configure",
|
126
|
+
"cmake .."
|
127
|
+
].join(" && \\\n")
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
it_behaves_like "a rule that touches the target file"
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "the build rule" do
|
135
|
+
let(:rule) { subject.build_rule }
|
136
|
+
|
137
|
+
it { expect(rule.dependencies).to eq(['leatherman-configure']) }
|
138
|
+
|
139
|
+
it "does nothing when the build step is empty" do
|
140
|
+
expect(rule.recipe.size).to eq 1
|
141
|
+
end
|
142
|
+
|
143
|
+
it "runs all of the build commands when given" do
|
144
|
+
component.build = ["make", "make test"]
|
145
|
+
expect(rule.recipe.first).to eq(
|
146
|
+
[
|
147
|
+
"cd /foo/bar",
|
148
|
+
":",
|
149
|
+
"make",
|
150
|
+
"make test",
|
151
|
+
].join(" && \\\n")
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "sets environment variables before running the build steps" do
|
156
|
+
component.build = ["make", "make test"]
|
157
|
+
component.environment = {"PATH" => "/opt/pl-build-tools/bin:$$PATH"}
|
158
|
+
expect(rule.recipe.first).to eq(
|
159
|
+
[
|
160
|
+
"cd /foo/bar",
|
161
|
+
"export PATH=\"/opt/pl-build-tools/bin:$$PATH\"",
|
162
|
+
"make",
|
163
|
+
"make test"
|
164
|
+
].join(" && \\\n")
|
165
|
+
)
|
166
|
+
end
|
167
|
+
|
168
|
+
it_behaves_like "a rule that touches the target file"
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "the check rule" do
|
172
|
+
let(:rule) { subject.check_rule }
|
173
|
+
|
174
|
+
it { expect(rule.dependencies).to eq(['leatherman-build']) }
|
175
|
+
|
176
|
+
it "does nothing when the check step is empty" do
|
177
|
+
expect(rule.recipe.size).to eq 1
|
178
|
+
end
|
179
|
+
|
180
|
+
it "does nothing when the project skipcheck flag is set" do
|
181
|
+
component.check = ["make cpplint", "make test"]
|
182
|
+
project.settings[:skipcheck] = true
|
183
|
+
expect(rule.recipe.size).to eq 1
|
184
|
+
end
|
185
|
+
|
186
|
+
it "runs all of the check commands when given" do
|
187
|
+
component.check = ["make cpplint", "make test"]
|
188
|
+
expect(rule.recipe.first).to eq(
|
189
|
+
[
|
190
|
+
"cd /foo/bar",
|
191
|
+
":",
|
192
|
+
"make cpplint",
|
193
|
+
"make test",
|
194
|
+
].join(" && \\\n")
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "sets environment variables before running the check steps" do
|
199
|
+
component.check = ["make cpplint", "make test"]
|
200
|
+
component.environment = {"PATH" => "/opt/pl-build-tools/bin:$$PATH"}
|
201
|
+
expect(rule.recipe.first).to eq(
|
202
|
+
[
|
203
|
+
"cd /foo/bar",
|
204
|
+
"export PATH=\"/opt/pl-build-tools/bin:$$PATH\"",
|
205
|
+
"make cpplint",
|
206
|
+
"make test"
|
207
|
+
].join(" && \\\n")
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
it_behaves_like "a rule that touches the target file"
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "the install rule" do
|
215
|
+
let(:rule) { subject.install_rule }
|
216
|
+
|
217
|
+
it { expect(rule.dependencies).to eq(['leatherman-check']) }
|
218
|
+
|
219
|
+
it "does nothing when the install step is empty" do
|
220
|
+
expect(rule.recipe.size).to eq 1
|
221
|
+
end
|
222
|
+
|
223
|
+
it "runs all of the install commands when given" do
|
224
|
+
component.install = ["make install", "make reallyinstall"]
|
225
|
+
expect(rule.recipe.first).to eq(
|
226
|
+
[
|
227
|
+
"cd /foo/bar",
|
228
|
+
":",
|
229
|
+
"make install",
|
230
|
+
"make reallyinstall",
|
231
|
+
].join(" && \\\n")
|
232
|
+
)
|
233
|
+
end
|
234
|
+
|
235
|
+
it "sets environment variables before running the install steps" do
|
236
|
+
component.install = ["make install", "make reallyinstall"]
|
237
|
+
component.environment = {"PATH" => "/opt/pl-build-tools/bin:$$PATH"}
|
238
|
+
expect(rule.recipe.first).to eq(
|
239
|
+
[
|
240
|
+
"cd /foo/bar",
|
241
|
+
"export PATH=\"/opt/pl-build-tools/bin:$$PATH\"",
|
242
|
+
"make install",
|
243
|
+
"make reallyinstall"
|
244
|
+
].join(" && \\\n")
|
245
|
+
)
|
246
|
+
end
|
247
|
+
|
248
|
+
it "applies any after-install patches" do
|
249
|
+
component.install = ["make install"]
|
250
|
+
component.patches = [
|
251
|
+
Vanagon::Patch.new('/foo/patch0', 1, 0, 'unpack', '/foo/bar'),
|
252
|
+
Vanagon::Patch.new('/foo/postinstall/patch0', 3, 9, 'install', '/foo/baz'),
|
253
|
+
Vanagon::Patch.new('/foo/postinstall/patch1', 4, 10, 'install', '/foo/quux'),
|
254
|
+
]
|
255
|
+
|
256
|
+
expect(rule.recipe[1]).to eq("cd /foo/baz && /usr/bin/patch --strip=3 --fuzz=9 --ignore-whitespace < $(workdir)/patches/patch0")
|
257
|
+
expect(rule.recipe[2]).to eq("cd /foo/quux && /usr/bin/patch --strip=4 --fuzz=10 --ignore-whitespace < $(workdir)/patches/patch1")
|
258
|
+
end
|
259
|
+
|
260
|
+
it_behaves_like "a rule that touches the target file"
|
261
|
+
end
|
262
|
+
|
263
|
+
describe "the cleanup rule" do
|
264
|
+
let(:rule) { subject.cleanup_rule }
|
265
|
+
|
266
|
+
it { expect(rule.dependencies).to eq(['leatherman-install']) }
|
267
|
+
|
268
|
+
it "runs the component source cleanup step" do
|
269
|
+
component.cleanup_source = "rm -rf leatherman"
|
270
|
+
expect(rule.recipe.first).to eq "rm -rf leatherman"
|
271
|
+
end
|
272
|
+
|
273
|
+
it_behaves_like "a rule that touches the target file"
|
274
|
+
end
|
275
|
+
|
276
|
+
describe "the clean rule" do
|
277
|
+
let(:rule) { subject.clean_rule }
|
278
|
+
|
279
|
+
it { expect(rule.dependencies).to be_empty }
|
280
|
+
|
281
|
+
it "runs a `make clean` in the build dir" do
|
282
|
+
expect(rule.recipe.first).to eq '[ -d /foo/bar ] && cd /foo/bar && /usr/bin/make clean'
|
283
|
+
end
|
284
|
+
|
285
|
+
it "remotes the touch files for the configure, build, and install steps" do
|
286
|
+
%w[configure build install].each_with_index do |type, i|
|
287
|
+
touchfile = "leatherman-#{type}"
|
288
|
+
expect(rule.recipe[i + 1]).to eq "[ -e #{touchfile} ] && rm #{touchfile}"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
describe "the clobber rule" do
|
294
|
+
let(:rule) { subject.clobber_rule }
|
295
|
+
|
296
|
+
it { expect(rule.dependencies).to eq(['leatherman-clean']) }
|
297
|
+
|
298
|
+
it "removes the source directory and unpack touchfile" do
|
299
|
+
expect(rule.recipe).to eq(["[ -d /foo/bar ] && rm -r /foo/bar", "[ -e leatherman-unpack ] && rm leatherman-unpack"])
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|