rscons 0.0.14 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|