rscons 0.0.14 → 0.1.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.
- data/.gitignore +1 -1
- data/README.md +128 -11
- data/{Rakefile → Rakefile.rb} +8 -3
- data/build_tests/d/main.d +6 -0
- data/lib/rscons/builders/library.rb +2 -2
- data/lib/rscons/builders/object.rb +27 -28
- data/lib/rscons/builders/program.rb +17 -19
- data/lib/rscons/cache.rb +9 -9
- data/lib/rscons/environment.rb +52 -65
- data/lib/rscons/varset.rb +7 -11
- data/lib/rscons/version.rb +1 -1
- data/spec/build_tests_spec.rb +153 -52
- data/spec/rscons/cache_spec.rb +204 -0
- data/spec/rscons/environment_spec.rb +257 -6
- data/spec/rscons/varset_spec.rb +16 -11
- data/spec/rscons_spec.rb +26 -0
- data/spec/spec_helper.rb +3 -1
- metadata +10 -14
- data/build_tests/build_dir/build.rb +0 -5
- data/build_tests/build_dir/tweaker_build.rb +0 -12
- data/build_tests/clone_env/build.rb +0 -11
- data/build_tests/custom_builder/build.rb +0 -15
- data/build_tests/header/build.rb +0 -3
- data/build_tests/library/build.rb +0 -4
- data/build_tests/simple/build.rb +0 -4
- data/build_tests/simple_cc/build.rb +0 -4
- data/build_tests/two_sources/build.rb +0 -4
data/lib/rscons/varset.rb
CHANGED
@@ -64,20 +64,16 @@ module Rscons
|
|
64
64
|
expand_varref(ent)
|
65
65
|
end.flatten
|
66
66
|
else
|
67
|
-
if varref =~ /^(.*)\$\[
|
68
|
-
# expand array with given prefix, suffix
|
67
|
+
if varref =~ /^(.*)\$\{([^}]+)\}(.*)$/
|
69
68
|
prefix, varname, suffix = $1, $2, $3
|
70
69
|
varval = expand_varref(@vars[varname])
|
71
|
-
|
72
|
-
|
70
|
+
if varval.is_a?(String)
|
71
|
+
expand_varref("#{prefix}#{varval}#{suffix}")
|
72
|
+
elsif varval.is_a?(Array)
|
73
|
+
varval.map {|vv| expand_varref("#{prefix}#{vv}#{suffix}")}.flatten
|
74
|
+
else
|
75
|
+
raise "I do not know how to expand a variable reference to a #{varval.class.name}"
|
73
76
|
end
|
74
|
-
varval.map {|e| "#{prefix}#{e}#{suffix}"}
|
75
|
-
elsif varref =~ /^\$(.*)$/
|
76
|
-
# expand a single variable reference
|
77
|
-
varname = $1
|
78
|
-
varval = expand_varref(@vars[varname])
|
79
|
-
varval or raise "Could not find variable #{varname.inspect}"
|
80
|
-
expand_varref(varval)
|
81
77
|
else
|
82
78
|
varref
|
83
79
|
end
|
data/lib/rscons/version.rb
CHANGED
data/spec/build_tests_spec.rb
CHANGED
@@ -1,45 +1,31 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
|
3
3
|
describe Rscons do
|
4
|
+
BUILD_TEST_RUN_DIR = "build_test_run"
|
5
|
+
|
4
6
|
before(:all) do
|
5
|
-
FileUtils.rm_rf(
|
7
|
+
FileUtils.rm_rf(BUILD_TEST_RUN_DIR)
|
6
8
|
@owd = Dir.pwd
|
7
9
|
end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
before(:each) do
|
12
|
+
@output = ""
|
13
|
+
$stdout.stub(:write) do |content|
|
14
|
+
@output += content
|
15
|
+
end
|
16
|
+
$stderr.stub(:write) do |content|
|
17
|
+
@output += content
|
18
|
+
end
|
12
19
|
end
|
13
20
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
File.open(build_script, "w") do |fh|
|
18
|
-
fh.puts(<<EOF + build_rb)
|
19
|
-
require "simplecov"
|
20
|
-
|
21
|
-
SimpleCov.start do
|
22
|
-
root("#{@owd}")
|
23
|
-
command_name("build_test_#{@build_test_name}")
|
24
|
-
add_filter("spec")
|
25
|
-
end
|
26
|
-
|
27
|
-
require "rscons"
|
28
|
-
EOF
|
29
|
-
end
|
30
|
-
IO.popen(%{ruby -I #{@owd}/lib #{build_script}}) do |io|
|
31
|
-
io.readlines.reject do |line|
|
32
|
-
line =~ /^Coverage report/
|
33
|
-
end
|
34
|
-
end.map(&:strip)
|
35
|
-
end
|
21
|
+
after(:each) do
|
22
|
+
Dir.chdir(@owd)
|
23
|
+
FileUtils.rm_rf(BUILD_TEST_RUN_DIR)
|
36
24
|
end
|
37
25
|
|
38
|
-
def test_dir(build_test_directory
|
39
|
-
|
40
|
-
|
41
|
-
Dir.chdir("build_tests_run")
|
42
|
-
build_testdir(build_script)
|
26
|
+
def test_dir(build_test_directory)
|
27
|
+
FileUtils.cp_r("build_tests/#{build_test_directory}", BUILD_TEST_RUN_DIR)
|
28
|
+
Dir.chdir(BUILD_TEST_RUN_DIR)
|
43
29
|
end
|
44
30
|
|
45
31
|
def file_sub(fname)
|
@@ -53,18 +39,31 @@ EOF
|
|
53
39
|
end
|
54
40
|
end
|
55
41
|
|
42
|
+
def lines
|
43
|
+
@output.lines.map(&:rstrip).tap do |v|
|
44
|
+
@output = ""
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
56
48
|
###########################################################################
|
57
49
|
# Tests
|
58
50
|
###########################################################################
|
59
51
|
|
60
52
|
it 'builds a C program with one source file' do
|
61
53
|
test_dir('simple')
|
54
|
+
Rscons::Environment.new do |env|
|
55
|
+
env.Program('simple', Dir['*.c'])
|
56
|
+
end
|
62
57
|
File.exists?('simple.o').should be_true
|
63
58
|
`./simple`.should == "This is a simple C program\n"
|
64
59
|
end
|
65
60
|
|
66
61
|
it 'prints commands as they are executed' do
|
67
|
-
|
62
|
+
test_dir('simple')
|
63
|
+
Rscons::Environment.new(echo: :command) do |env|
|
64
|
+
env["LD"] = "gcc"
|
65
|
+
env.Program('simple', Dir['*.c'])
|
66
|
+
end
|
68
67
|
lines.should == [
|
69
68
|
'gcc -c -o simple.o -MMD -MF simple.mf simple.c',
|
70
69
|
'gcc -o simple simple.o',
|
@@ -72,7 +71,10 @@ EOF
|
|
72
71
|
end
|
73
72
|
|
74
73
|
it 'prints short representations of the commands being executed' do
|
75
|
-
|
74
|
+
test_dir('header')
|
75
|
+
Rscons::Environment.new do |env|
|
76
|
+
env.Program('header', Dir['*.c'])
|
77
|
+
end
|
76
78
|
lines.should == [
|
77
79
|
'CC header.o',
|
78
80
|
'LD header',
|
@@ -81,61 +83,88 @@ EOF
|
|
81
83
|
|
82
84
|
it 'builds a C program with one source file and one header file' do
|
83
85
|
test_dir('header')
|
86
|
+
Rscons::Environment.new do |env|
|
87
|
+
env.Program('header', Dir['*.c'])
|
88
|
+
end
|
84
89
|
File.exists?('header.o').should be_true
|
85
90
|
`./header`.should == "The value is 2\n"
|
86
91
|
end
|
87
92
|
|
88
93
|
it 'rebuilds a C module when a header it depends on changes' do
|
89
94
|
test_dir('header')
|
95
|
+
env = Rscons::Environment.new do |env|
|
96
|
+
env.Program('header', Dir['*.c'])
|
97
|
+
end
|
90
98
|
`./header`.should == "The value is 2\n"
|
91
99
|
file_sub('header.h') {|line| line.sub(/2/, '5')}
|
92
|
-
|
100
|
+
env.process
|
93
101
|
`./header`.should == "The value is 5\n"
|
94
102
|
end
|
95
103
|
|
96
104
|
it 'does not rebuild a C module when its dependencies have not changed' do
|
97
|
-
|
105
|
+
test_dir('header')
|
106
|
+
env = Rscons::Environment.new do |env|
|
107
|
+
env.Program('header', Dir['*.c'])
|
108
|
+
end
|
98
109
|
`./header`.should == "The value is 2\n"
|
99
110
|
lines.should == [
|
100
111
|
'CC header.o',
|
101
112
|
'LD header',
|
102
113
|
]
|
103
|
-
|
114
|
+
env.process
|
104
115
|
lines.should == []
|
105
116
|
end
|
106
117
|
|
107
118
|
it "does not rebuild a C module when only the file's timestampe has changed" do
|
108
|
-
|
119
|
+
test_dir('header')
|
120
|
+
env = Rscons::Environment.new do |env|
|
121
|
+
env.Program('header', Dir['*.c'])
|
122
|
+
end
|
109
123
|
`./header`.should == "The value is 2\n"
|
110
124
|
lines.should == [
|
111
125
|
'CC header.o',
|
112
126
|
'LD header',
|
113
127
|
]
|
114
128
|
file_sub('header.c') {|line| line}
|
115
|
-
|
129
|
+
env.process
|
116
130
|
lines.should == []
|
117
131
|
end
|
118
132
|
|
119
133
|
it 're-links a program when the link flags have changed' do
|
120
|
-
|
134
|
+
test_dir('simple')
|
135
|
+
Rscons::Environment.new(echo: :command) do |env|
|
136
|
+
env.Program('simple', Dir['*.c'])
|
137
|
+
end
|
121
138
|
lines.should == [
|
122
139
|
'gcc -c -o simple.o -MMD -MF simple.mf simple.c',
|
123
140
|
'gcc -o simple simple.o',
|
124
141
|
]
|
125
|
-
|
126
|
-
|
142
|
+
Rscons::Environment.new(echo: :command) do |env|
|
143
|
+
env["LIBS"] += ["c"]
|
144
|
+
env.Program('simple', Dir['*.c'])
|
145
|
+
end
|
127
146
|
lines.should == ['gcc -o simple simple.o -lc']
|
128
147
|
end
|
129
148
|
|
130
149
|
it 'builds object files in a different build directory' do
|
131
|
-
|
150
|
+
test_dir('build_dir')
|
151
|
+
Rscons::Environment.new do |env|
|
152
|
+
env.append('CPPPATH' => Dir['src/**/*/'])
|
153
|
+
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
|
154
|
+
env.Program('build_dir', Dir['src/**/*.c'])
|
155
|
+
end
|
132
156
|
`./build_dir`.should == "Hello from two()\n"
|
133
157
|
File.exists?('build_one/one.o').should be_true
|
134
158
|
File.exists?('build_two/two.o').should be_true
|
135
159
|
end
|
136
160
|
|
137
161
|
it 'cleans built files' do
|
138
|
-
|
162
|
+
test_dir('build_dir')
|
163
|
+
Rscons::Environment.new do |env|
|
164
|
+
env.append('CPPPATH' => Dir['src/**/*/'])
|
165
|
+
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
|
166
|
+
env.Program('build_dir', Dir['src/**/*.c'])
|
167
|
+
end
|
139
168
|
`./build_dir`.should == "Hello from two()\n"
|
140
169
|
File.exists?('build_one/one.o').should be_true
|
141
170
|
File.exists?('build_two/two.o').should be_true
|
@@ -148,7 +177,12 @@ EOF
|
|
148
177
|
end
|
149
178
|
|
150
179
|
it 'does not clean created directories if other non-rscons-generated files reside there' do
|
151
|
-
|
180
|
+
test_dir('build_dir')
|
181
|
+
Rscons::Environment.new do |env|
|
182
|
+
env.append('CPPPATH' => Dir['src/**/*/'])
|
183
|
+
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
|
184
|
+
env.Program('build_dir', Dir['src/**/*.c'])
|
185
|
+
end
|
152
186
|
`./build_dir`.should == "Hello from two()\n"
|
153
187
|
File.exists?('build_one/one.o').should be_true
|
154
188
|
File.exists?('build_two/two.o').should be_true
|
@@ -162,14 +196,44 @@ EOF
|
|
162
196
|
end
|
163
197
|
|
164
198
|
it 'allows Ruby classes as custom builders to be used to construct files' do
|
165
|
-
|
199
|
+
test_dir('custom_builder')
|
200
|
+
class MySource < Rscons::Builder
|
201
|
+
def run(target, sources, cache, env, vars = {})
|
202
|
+
File.open(target, 'w') do |fh|
|
203
|
+
fh.puts <<EOF
|
204
|
+
#define THE_VALUE 5678
|
205
|
+
EOF
|
206
|
+
end
|
207
|
+
target
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
Rscons::Environment.new do |env|
|
212
|
+
env.add_builder(MySource.new)
|
213
|
+
env.MySource('inc.h', [])
|
214
|
+
env.Program('program', Dir['*.c'])
|
215
|
+
end
|
216
|
+
|
166
217
|
lines.should == ['CC program.o', 'LD program']
|
167
218
|
File.exists?('inc.h').should be_true
|
168
219
|
`./program`.should == "The value is 5678\n"
|
169
220
|
end
|
170
221
|
|
171
222
|
it 'allows cloning Environment objects' do
|
172
|
-
|
223
|
+
test_dir('clone_env')
|
224
|
+
|
225
|
+
debug = Rscons::Environment.new(echo: :command) do |env|
|
226
|
+
env.build_dir('src', 'debug')
|
227
|
+
env['CFLAGS'] = '-O2'
|
228
|
+
env['CPPFLAGS'] = '-DSTRING="Debug Version"'
|
229
|
+
env.Program('program-debug', Dir['src/*.c'])
|
230
|
+
end
|
231
|
+
|
232
|
+
release = debug.clone('CPPFLAGS' => '-DSTRING="Release Version"') do |env|
|
233
|
+
env.build_dir('src', 'release')
|
234
|
+
env.Program('program-release', Dir['src/*.c'])
|
235
|
+
end
|
236
|
+
|
173
237
|
lines.should == [
|
174
238
|
%q{gcc -c -o debug/program.o -MMD -MF debug/program.mf '-DSTRING="Debug Version"' -O2 src/program.c},
|
175
239
|
%q{gcc -o program-debug debug/program.o},
|
@@ -180,12 +244,19 @@ EOF
|
|
180
244
|
|
181
245
|
it 'builds a C++ program with one source file' do
|
182
246
|
test_dir('simple_cc')
|
247
|
+
Rscons::Environment.new do |env|
|
248
|
+
env.Program('simple', Dir['*.cc'])
|
249
|
+
end
|
183
250
|
File.exists?('simple.o').should be_true
|
184
251
|
`./simple`.should == "This is a simple C++ program\n"
|
185
252
|
end
|
186
253
|
|
187
254
|
it 'allows overriding construction variables for individual builder calls' do
|
188
|
-
|
255
|
+
test_dir('two_sources')
|
256
|
+
Rscons::Environment.new(echo: :command) do |env|
|
257
|
+
env.Object("one.o", "one.c", 'CPPFLAGS' => ['-DONE'])
|
258
|
+
env.Program('two_sources', ['one.o', 'two.c'])
|
259
|
+
end
|
189
260
|
lines.should == [
|
190
261
|
'gcc -c -o one.o -MMD -MF one.mf -DONE one.c',
|
191
262
|
'gcc -c -o two.o -MMD -MF two.mf two.c',
|
@@ -196,7 +267,11 @@ EOF
|
|
196
267
|
end
|
197
268
|
|
198
269
|
it 'builds a static library archive' do
|
199
|
-
|
270
|
+
test_dir('library')
|
271
|
+
Rscons::Environment.new(echo: :command) do |env|
|
272
|
+
env.Program('library', ['lib.a', 'three.c'])
|
273
|
+
env.Library("lib.a", ['one.c', 'two.c'], 'CPPFLAGS' => ['-Dmake_lib'])
|
274
|
+
end
|
200
275
|
lines.should == [
|
201
276
|
'gcc -c -o one.o -MMD -MF one.mf -Dmake_lib one.c',
|
202
277
|
'gcc -c -o two.o -MMD -MF two.mf -Dmake_lib two.c',
|
@@ -208,13 +283,39 @@ EOF
|
|
208
283
|
`ar t lib.a`.should == "one.o\ntwo.o\n"
|
209
284
|
end
|
210
285
|
|
211
|
-
it 'supports
|
212
|
-
|
213
|
-
|
286
|
+
it 'supports build hooks to override construction variables' do
|
287
|
+
test_dir("build_dir")
|
288
|
+
Rscons::Environment.new(echo: :command) do |env|
|
289
|
+
env.append('CPPPATH' => Dir['src/**/*/'])
|
290
|
+
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
|
291
|
+
env.add_build_hook do |build_op|
|
292
|
+
if build_op[:target] =~ %r{build_one/.*\.o}
|
293
|
+
build_op[:vars]["CFLAGS"] << "-O1"
|
294
|
+
elsif build_op[:target] =~ %r{build_two/.*\.o}
|
295
|
+
build_op[:vars]["CFLAGS"] << "-O2"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
env.Program('build_hook', Dir['src/**/*.c'])
|
299
|
+
end
|
300
|
+
`./build_hook`.should == "Hello from two()\n"
|
214
301
|
lines.should =~ [
|
215
302
|
'gcc -c -o build_one/one.o -MMD -MF build_one/one.mf -Isrc/one/ -Isrc/two/ -O1 src/one/one.c',
|
216
303
|
'gcc -c -o build_two/two.o -MMD -MF build_two/two.mf -Isrc/one/ -Isrc/two/ -O2 src/two/two.c',
|
217
|
-
'gcc -o
|
304
|
+
'gcc -o build_hook build_one/one.o build_two/two.o',
|
218
305
|
]
|
219
306
|
end
|
307
|
+
|
308
|
+
unless ENV["omit_gdc_tests"]
|
309
|
+
it "supports building D sources" do
|
310
|
+
test_dir("d")
|
311
|
+
Rscons::Environment.new(echo: :command) do |env|
|
312
|
+
env.Program("hello-d", Dir["*.d"])
|
313
|
+
end
|
314
|
+
lines.should == [
|
315
|
+
"gdc -c -o main.o main.d",
|
316
|
+
"gdc -o hello-d main.o",
|
317
|
+
]
|
318
|
+
`./hello-d`.rstrip.should == "Hello from D!"
|
319
|
+
end
|
320
|
+
end
|
220
321
|
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
module Rscons
|
2
|
+
describe Cache do
|
3
|
+
before do
|
4
|
+
File.stub(:read) { nil }
|
5
|
+
end
|
6
|
+
|
7
|
+
def build_from(cache)
|
8
|
+
YAML.should_receive(:load).and_return(cache)
|
9
|
+
Cache.new
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ".clear" do
|
13
|
+
it "removes the cache file" do
|
14
|
+
FileUtils.should_receive(:rm_f).with(Cache::CACHE_FILE)
|
15
|
+
Cache.clear
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#initialize" do
|
20
|
+
context "when corrupt" do
|
21
|
+
it "prints a warning and defaults to an empty hash" do
|
22
|
+
YAML.should_receive(:load).and_return("string")
|
23
|
+
$stderr.should_receive(:puts).with(/Warning:.*was.corrupt/)
|
24
|
+
Cache.new.instance_variable_get(:@cache).is_a?(Hash).should be_true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#write" do
|
30
|
+
it "should fill in :version and write to file" do
|
31
|
+
cache = {}
|
32
|
+
fh = $stdout
|
33
|
+
fh.should_receive(:puts)
|
34
|
+
File.should_receive(:open).and_yield(fh)
|
35
|
+
build_from(cache).write
|
36
|
+
cache[:version].should == Rscons::VERSION
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#up_to_date?" do
|
41
|
+
it "returns false when target file does not exist" do
|
42
|
+
File.should_receive(:exists?).with("target").and_return(false)
|
43
|
+
build_from({}).up_to_date?("target", "command", []).should be_false
|
44
|
+
end
|
45
|
+
|
46
|
+
it "returns false when target is not registered in the cache" do
|
47
|
+
File.should_receive(:exists?).with("target").and_return(true)
|
48
|
+
build_from({}).up_to_date?("target", "command", []).should be_false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "returns false when the target's checksum does not match" do
|
52
|
+
_cache = {targets: {"target" => {checksum: "abc"}}}
|
53
|
+
cache = build_from(_cache)
|
54
|
+
File.should_receive(:exists?).with("target").and_return(true)
|
55
|
+
cache.should_receive(:calculate_checksum).with("target").and_return("def")
|
56
|
+
cache.up_to_date?("target", "command", []).should be_false
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns false when the build command has changed" do
|
60
|
+
_cache = {targets: {"target" => {checksum: "abc", command: "old command"}}}
|
61
|
+
cache = build_from(_cache)
|
62
|
+
File.should_receive(:exists?).with("target").and_return(true)
|
63
|
+
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
64
|
+
cache.up_to_date?("target", "command", []).should be_false
|
65
|
+
end
|
66
|
+
|
67
|
+
it "returns false when there is a new dependency" do
|
68
|
+
_cache = {targets: {"target" => {checksum: "abc",
|
69
|
+
command: "command",
|
70
|
+
deps: [{fname: "dep.1"}]}}}
|
71
|
+
cache = build_from(_cache)
|
72
|
+
File.should_receive(:exists?).with("target").and_return(true)
|
73
|
+
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
74
|
+
cache.up_to_date?("target", "command", ["dep.1", "dep.2"]).should be_false
|
75
|
+
end
|
76
|
+
|
77
|
+
it "returns false when a dependency's checksum has changed" do
|
78
|
+
_cache = {targets: {"target" => {checksum: "abc",
|
79
|
+
command: "command",
|
80
|
+
deps: [{fname: "dep.1",
|
81
|
+
checksum: "dep.1.chk"},
|
82
|
+
{fname: "dep.2",
|
83
|
+
checksum: "dep.2.chk"},
|
84
|
+
{fname: "extra.dep",
|
85
|
+
checksum: "extra.dep.chk"}]}}}
|
86
|
+
cache = build_from(_cache)
|
87
|
+
File.should_receive(:exists?).with("target").and_return(true)
|
88
|
+
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
89
|
+
cache.should_receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk")
|
90
|
+
cache.should_receive(:calculate_checksum).with("dep.2").and_return("dep.2.changed")
|
91
|
+
cache.up_to_date?("target", "command", ["dep.1", "dep.2"]).should be_false
|
92
|
+
end
|
93
|
+
|
94
|
+
it "returns false with strict_deps=true when cache has an extra dependency" do
|
95
|
+
_cache = {targets: {"target" => {checksum: "abc",
|
96
|
+
command: "command",
|
97
|
+
deps: [{fname: "dep.1",
|
98
|
+
checksum: "dep.1.chk"},
|
99
|
+
{fname: "dep.2",
|
100
|
+
checksum: "dep.2.chk"},
|
101
|
+
{fname: "extra.dep",
|
102
|
+
checksum: "extra.dep.chk"}]}}}
|
103
|
+
cache = build_from(_cache)
|
104
|
+
File.should_receive(:exists?).with("target").and_return(true)
|
105
|
+
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
106
|
+
cache.up_to_date?("target", "command", ["dep.1", "dep.2"], strict_deps: true).should be_false
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns true when no condition for false is met" do
|
110
|
+
_cache = {targets: {"target" => {checksum: "abc",
|
111
|
+
command: "command",
|
112
|
+
deps: [{fname: "dep.1",
|
113
|
+
checksum: "dep.1.chk"},
|
114
|
+
{fname: "dep.2",
|
115
|
+
checksum: "dep.2.chk"},
|
116
|
+
{fname: "extra.dep",
|
117
|
+
checksum: "extra.dep.chk"}]}}}
|
118
|
+
cache = build_from(_cache)
|
119
|
+
File.should_receive(:exists?).with("target").and_return(true)
|
120
|
+
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
121
|
+
cache.should_receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk")
|
122
|
+
cache.should_receive(:calculate_checksum).with("dep.2").and_return("dep.2.chk")
|
123
|
+
cache.should_receive(:calculate_checksum).with("extra.dep").and_return("extra.dep.chk")
|
124
|
+
cache.up_to_date?("target", "command", ["dep.1", "dep.2"]).should be_true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#register_build" do
|
129
|
+
it "stores the given information in the cache" do
|
130
|
+
_cache = {}
|
131
|
+
cache = build_from(_cache)
|
132
|
+
cache.should_receive(:calculate_checksum).with("the target").and_return("the checksum")
|
133
|
+
cache.should_receive(:calculate_checksum).with("dep 1").and_return("dep 1 checksum")
|
134
|
+
cache.should_receive(:calculate_checksum).with("dep 2").and_return("dep 2 checksum")
|
135
|
+
cache.register_build("the target", "the command", ["dep 1", "dep 2"])
|
136
|
+
cached_target = cache.instance_variable_get(:@cache)[:targets]["the target"]
|
137
|
+
cached_target.should_not be_nil
|
138
|
+
cached_target[:command].should == "the command"
|
139
|
+
cached_target[:checksum].should == "the checksum"
|
140
|
+
cached_target[:deps].should == [
|
141
|
+
{fname: "dep 1", checksum: "dep 1 checksum"},
|
142
|
+
{fname: "dep 2", checksum: "dep 2 checksum"},
|
143
|
+
]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "#targets" do
|
148
|
+
it "returns a list of targets that are cached" do
|
149
|
+
cache = {targets: {"t1" => {}, "t2" => {}, "t3" => {}}}
|
150
|
+
build_from(cache).targets.should == ["t1", "t2", "t3"]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "#mkdir_p" do
|
155
|
+
it "makes directories and records any created in the cache" do
|
156
|
+
_cache = {}
|
157
|
+
cache = build_from(_cache)
|
158
|
+
File.should_receive(:exists?).with("one").and_return(true)
|
159
|
+
File.should_receive(:exists?).with("one/two").and_return(false)
|
160
|
+
FileUtils.should_receive(:mkdir).with("one/two")
|
161
|
+
File.should_receive(:exists?).with("one/two/three").and_return(false)
|
162
|
+
FileUtils.should_receive(:mkdir).with("one/two/three")
|
163
|
+
File.should_receive(:exists?).with("one").and_return(true)
|
164
|
+
File.should_receive(:exists?).with("one/two").and_return(true)
|
165
|
+
File.should_receive(:exists?).with("one/two/four").and_return(false)
|
166
|
+
FileUtils.should_receive(:mkdir).with("one/two/four")
|
167
|
+
cache.mkdir_p("one/two/three")
|
168
|
+
cache.mkdir_p("one\\two\\four")
|
169
|
+
cache.directories.should == ["one/two", "one/two/three", "one/two/four"]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "#directories" do
|
174
|
+
it "returns a list of directories that are cached" do
|
175
|
+
_cache = {directories: {"dir1" => true, "dir2" => true}}
|
176
|
+
build_from(_cache).directories.should == ["dir1", "dir2"]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "#lookup_checksum" do
|
181
|
+
it "does not re-calculate the checksum when it is already cached" do
|
182
|
+
cache = build_from({})
|
183
|
+
cache.instance_variable_set(:@lookup_checksums, {"f1" => "f1.chk"})
|
184
|
+
cache.should_not_receive(:calculate_checksum)
|
185
|
+
cache.send(:lookup_checksum, "f1").should == "f1.chk"
|
186
|
+
end
|
187
|
+
|
188
|
+
it "calls calculate_checksum when the checksum is not cached" do
|
189
|
+
cache = build_from({})
|
190
|
+
cache.should_receive(:calculate_checksum).with("f1").and_return("ck")
|
191
|
+
cache.send(:lookup_checksum, "f1").should == "ck"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe "#calculate_checksum" do
|
196
|
+
it "calculates the MD5 of the file contents" do
|
197
|
+
contents = "contents"
|
198
|
+
File.should_receive(:read).with("fname", mode: "rb").and_return(contents)
|
199
|
+
Digest::MD5.should_receive(:hexdigest).with(contents).and_return("the_checksum")
|
200
|
+
build_from({}).send(:calculate_checksum, "fname").should == "the_checksum"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|