vanagon 0.4.1 → 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 +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
|