rscons 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +112 -10
- data/lib/rscons.rb +8 -2
- data/lib/rscons/builders/cfile.rb +40 -0
- data/lib/rscons/builders/disassemble.rb +25 -0
- data/lib/rscons/builders/library.rb +1 -1
- data/lib/rscons/builders/preprocess.rb +25 -0
- data/lib/rscons/builders/program.rb +1 -1
- data/lib/rscons/cache.rb +96 -80
- data/lib/rscons/environment.rb +63 -32
- data/lib/rscons/varset.rb +75 -18
- data/lib/rscons/version.rb +1 -1
- data/spec/build_tests_spec.rb +56 -0
- data/spec/rscons/builders/cfile_spec.rb +23 -0
- data/spec/rscons/cache_spec.rb +85 -68
- data/spec/rscons/environment_spec.rb +23 -6
- data/spec/rscons/varset_spec.rb +63 -17
- data/spec/rscons_spec.rb +2 -2
- metadata +7 -2
data/lib/rscons/environment.rb
CHANGED
@@ -86,7 +86,7 @@ module Rscons
|
|
86
86
|
env.add_builder(builder)
|
87
87
|
end
|
88
88
|
end
|
89
|
-
env.append(@varset
|
89
|
+
env.append(@varset) if clone.include?(:variables)
|
90
90
|
env.build_root = @build_root if clone.include?(:build_root)
|
91
91
|
if clone.include?(:build_dirs)
|
92
92
|
@build_dirs.each do |src_dir, obj_dir|
|
@@ -164,38 +164,44 @@ module Rscons
|
|
164
164
|
# Add a set of construction variables or environment options.
|
165
165
|
# @see VarSet#append
|
166
166
|
def append(*args)
|
167
|
-
@varset.
|
167
|
+
@varset.append(*args)
|
168
168
|
end
|
169
169
|
|
170
170
|
# Build all target specified in the Environment.
|
171
171
|
# When a block is passed to Environment.new, this method is automatically
|
172
172
|
# called after the block returns.
|
173
173
|
def process
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
174
|
+
unless @targets.empty?
|
175
|
+
clean_target_paths!
|
176
|
+
cache = Cache.instance
|
177
|
+
cache.clear_checksum_cache!
|
178
|
+
targets_processed = {}
|
179
|
+
process_target = proc do |target|
|
180
|
+
targets_processed[target] ||= begin
|
181
|
+
@targets[target][:sources].each do |src|
|
182
|
+
if @targets.include?(src) and not targets_processed.include?(src)
|
183
|
+
process_target.call(src)
|
184
|
+
end
|
181
185
|
end
|
186
|
+
result = run_builder(@targets[target][:builder],
|
187
|
+
target,
|
188
|
+
@targets[target][:sources],
|
189
|
+
cache,
|
190
|
+
@targets[target][:vars] || {})
|
191
|
+
unless result
|
192
|
+
raise BuildError.new("Failed to build #{target}")
|
193
|
+
end
|
194
|
+
result
|
182
195
|
end
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
@targets[target][:vars] || {})
|
188
|
-
unless result
|
189
|
-
cache.write
|
190
|
-
raise BuildError.new("Failed to build #{target}")
|
196
|
+
end
|
197
|
+
begin
|
198
|
+
@targets.each do |target, target_params|
|
199
|
+
process_target.call(target)
|
191
200
|
end
|
192
|
-
|
201
|
+
ensure
|
202
|
+
cache.write
|
193
203
|
end
|
194
204
|
end
|
195
|
-
@targets.each do |target, info|
|
196
|
-
process_target.call(target)
|
197
|
-
end
|
198
|
-
cache.write
|
199
205
|
end
|
200
206
|
|
201
207
|
# Clear all targets registered for the Environment.
|
@@ -246,25 +252,28 @@ module Rscons
|
|
246
252
|
end
|
247
253
|
end
|
248
254
|
|
249
|
-
alias_method :orig_method_missing, :method_missing
|
250
255
|
def method_missing(method, *args)
|
251
256
|
if @builders.has_key?(method.to_s)
|
252
|
-
target,
|
257
|
+
target, sources, vars, *rest = args
|
253
258
|
unless vars.nil? or vars.is_a?(Hash) or vars.is_a?(VarSet)
|
254
259
|
raise "Unexpected construction variable set: #{vars.inspect}"
|
255
260
|
end
|
256
|
-
|
257
|
-
@
|
258
|
-
builder: @builders[method.to_s],
|
259
|
-
source: source,
|
260
|
-
vars: vars,
|
261
|
-
args: rest,
|
262
|
-
}
|
261
|
+
sources = [sources] unless sources.is_a?(Array)
|
262
|
+
add_target(target, @builders[method.to_s], sources, vars, rest)
|
263
263
|
else
|
264
|
-
|
264
|
+
super
|
265
265
|
end
|
266
266
|
end
|
267
267
|
|
268
|
+
def add_target(target, builder, sources, vars, args)
|
269
|
+
@targets[target] = {
|
270
|
+
builder: builder,
|
271
|
+
sources: sources,
|
272
|
+
vars: vars,
|
273
|
+
args: args,
|
274
|
+
}
|
275
|
+
end
|
276
|
+
|
268
277
|
# Manually record a given target as depending on the specified
|
269
278
|
# dependency files.
|
270
279
|
def depends(target, *user_deps)
|
@@ -321,12 +330,34 @@ module Rscons
|
|
321
330
|
target: target,
|
322
331
|
sources: sources,
|
323
332
|
vars: vars,
|
333
|
+
env: self,
|
324
334
|
}
|
325
335
|
build_hook_block.call(build_operation)
|
326
336
|
end
|
327
337
|
builder.run(target, sources, cache, self, vars)
|
328
338
|
end
|
329
339
|
|
340
|
+
private
|
341
|
+
|
342
|
+
# Expand all target paths that begin with ^/ to be relative to the
|
343
|
+
# Environment's build root, if present
|
344
|
+
def clean_target_paths!
|
345
|
+
if @build_root
|
346
|
+
expand = lambda do |path|
|
347
|
+
path.sub(%r{^\^(?=[\\/])}, @build_root)
|
348
|
+
end
|
349
|
+
|
350
|
+
new_targets = {}
|
351
|
+
@targets.each_pair do |target, target_params|
|
352
|
+
target_params[:sources].map! do |source|
|
353
|
+
expand[source]
|
354
|
+
end
|
355
|
+
new_targets[expand[target]] = target_params
|
356
|
+
end
|
357
|
+
@targets = new_targets
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
330
361
|
# Parse dependencies for a given target from a Makefile.
|
331
362
|
# This method is used internally by Rscons builders.
|
332
363
|
# @param mf_fname [String] File name of the Makefile to read.
|
data/lib/rscons/varset.rb
CHANGED
@@ -1,45 +1,73 @@
|
|
1
1
|
module Rscons
|
2
2
|
# This class represents a collection of variables which can be accessed
|
3
|
-
# as certain types
|
3
|
+
# as certain types.
|
4
|
+
# Only nil, strings, arrays, and hashes should be stored in a VarSet.
|
4
5
|
class VarSet
|
5
|
-
#
|
6
|
-
attr_reader :vars
|
7
|
-
|
8
|
-
# Create a VarSet
|
6
|
+
# Create a VarSet.
|
9
7
|
# @param vars [Hash] Optional initial variables.
|
10
8
|
def initialize(vars = {})
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@vars = vars
|
15
|
-
end
|
9
|
+
@my_vars = {}
|
10
|
+
@coa_vars = []
|
11
|
+
append(vars)
|
16
12
|
end
|
17
13
|
|
18
14
|
# Access the value of variable as a particular type
|
19
15
|
# @param key [String, Symbol] The variable name.
|
16
|
+
# @return [Object] The variable's value.
|
20
17
|
def [](key)
|
21
|
-
@
|
18
|
+
if @my_vars.include?(key)
|
19
|
+
@my_vars[key]
|
20
|
+
else
|
21
|
+
@coa_vars.each do |coa_vars|
|
22
|
+
if coa_vars.include?(key)
|
23
|
+
@my_vars[key] = deep_dup(coa_vars[key])
|
24
|
+
return @my_vars[key]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
nil
|
28
|
+
end
|
22
29
|
end
|
23
30
|
|
24
31
|
# Assign a value to a variable.
|
25
32
|
# @param key [String, Symbol] The variable name.
|
26
|
-
# @param val [Object] The value.
|
33
|
+
# @param val [Object] The value to set.
|
27
34
|
def []=(key, val)
|
28
|
-
@
|
35
|
+
@my_vars[key] = val
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check if the VarSet contains a variable.
|
39
|
+
# @param key [String, Symbol] The variable name.
|
40
|
+
# @return [true, false] Whether the VarSet contains a variable.
|
41
|
+
def include?(key)
|
42
|
+
if @my_vars.include?(key)
|
43
|
+
true
|
44
|
+
else
|
45
|
+
@coa_vars.find do |coa_vars|
|
46
|
+
coa_vars.include?(key)
|
47
|
+
end
|
48
|
+
end
|
29
49
|
end
|
30
50
|
|
31
51
|
# Add or overwrite a set of variables
|
32
52
|
# @param values [VarSet, Hash] New set of variables.
|
33
53
|
def append(values)
|
34
|
-
|
35
|
-
|
54
|
+
coa!
|
55
|
+
if values.is_a?(VarSet)
|
56
|
+
values.send(:coa!)
|
57
|
+
@coa_vars = values.instance_variable_get(:@coa_vars) + @coa_vars
|
58
|
+
else
|
59
|
+
@my_vars = deep_dup(values)
|
60
|
+
end
|
36
61
|
self
|
37
62
|
end
|
38
63
|
|
39
64
|
# Create a new VarSet object based on the first merged with other.
|
40
65
|
# @param other [VarSet, Hash] Other variables to add or overwrite.
|
41
66
|
def merge(other = {})
|
42
|
-
|
67
|
+
coa!
|
68
|
+
varset = self.class.new
|
69
|
+
varset.instance_variable_set(:@coa_vars, @coa_vars.dup)
|
70
|
+
varset.append(other)
|
43
71
|
end
|
44
72
|
alias_method :clone, :merge
|
45
73
|
|
@@ -54,18 +82,47 @@ module Rscons
|
|
54
82
|
else
|
55
83
|
if varref =~ /^(.*)\$\{([^}]+)\}(.*)$/
|
56
84
|
prefix, varname, suffix = $1, $2, $3
|
57
|
-
varval = expand_varref(
|
85
|
+
varval = expand_varref(self[varname])
|
58
86
|
if varval.is_a?(String)
|
59
87
|
expand_varref("#{prefix}#{varval}#{suffix}")
|
60
88
|
elsif varval.is_a?(Array)
|
61
89
|
varval.map {|vv| expand_varref("#{prefix}#{vv}#{suffix}")}.flatten
|
62
90
|
else
|
63
|
-
raise "I do not know how to expand a variable reference to a #{varval.class.name} (from #{varname.inspect} => #{
|
91
|
+
raise "I do not know how to expand a variable reference to a #{varval.class.name} (from #{varname.inspect} => #{self[varname].inspect})"
|
64
92
|
end
|
65
93
|
else
|
66
94
|
varref
|
67
95
|
end
|
68
96
|
end
|
69
97
|
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# Move all VarSet variables into the copy-on-access list.
|
102
|
+
def coa!
|
103
|
+
unless @my_vars.empty?
|
104
|
+
@coa_vars.unshift(@my_vars)
|
105
|
+
@my_vars = {}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Create a deep copy of an object.
|
110
|
+
# @param obj [nil, String, Array, Hash] Object to deep copy.
|
111
|
+
# @return [nil, String, Array, Hash] Deep copied value.
|
112
|
+
def deep_dup(obj)
|
113
|
+
obj_class = obj.class
|
114
|
+
if obj_class == Hash
|
115
|
+
obj.reduce({}) do |result, (k, v)|
|
116
|
+
result[k] = deep_dup(v)
|
117
|
+
result
|
118
|
+
end
|
119
|
+
elsif obj_class == Array
|
120
|
+
obj.map { |v| deep_dup(v) }
|
121
|
+
elsif obj_class == String
|
122
|
+
obj.dup
|
123
|
+
else
|
124
|
+
obj
|
125
|
+
end
|
126
|
+
end
|
70
127
|
end
|
71
128
|
end
|
data/lib/rscons/version.rb
CHANGED
data/spec/build_tests_spec.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
|
3
|
+
class Dir
|
4
|
+
class << self
|
5
|
+
alias_method :orig_bracket, :[]
|
6
|
+
end
|
7
|
+
def self.[](*args)
|
8
|
+
orig_bracket(*args).sort
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
3
12
|
describe Rscons do
|
4
13
|
BUILD_TEST_RUN_DIR = "build_test_run"
|
5
14
|
|
@@ -180,6 +189,23 @@ describe Rscons do
|
|
180
189
|
lines.should == ["CC build_root/src/one/one.o", "CC build_root/src/two/two.o", "LD build_dir"]
|
181
190
|
end
|
182
191
|
|
192
|
+
it "expands target and source paths starting with ^/ to be relative to the build root" do
|
193
|
+
test_dir('build_dir')
|
194
|
+
Rscons::Environment.new(echo: :command) do |env|
|
195
|
+
env.append('CPPPATH' => Dir['src/**/*/'])
|
196
|
+
env.build_root = "build_root"
|
197
|
+
FileUtils.mkdir_p(env.build_root)
|
198
|
+
FileUtils.mv("src/one/one.c", "build_root")
|
199
|
+
env.Object("^/one.o", "^/one.c")
|
200
|
+
env.Program('build_dir', Dir['src/**/*.c'] + ["^/one.o"])
|
201
|
+
end
|
202
|
+
lines.should == [
|
203
|
+
%q{gcc -c -o build_root/one.o -MMD -MF build_root/one.mf -Isrc/one/ -Isrc/two/ build_root/one.c},
|
204
|
+
%q{gcc -c -o build_root/src/two/two.o -MMD -MF build_root/src/two/two.mf -Isrc/one/ -Isrc/two/ src/two/two.c},
|
205
|
+
%q{gcc -o build_dir build_root/src/two/two.o build_root/one.o},
|
206
|
+
]
|
207
|
+
end
|
208
|
+
|
183
209
|
it 'cleans built files' do
|
184
210
|
test_dir('build_dir')
|
185
211
|
Rscons::Environment.new do |env|
|
@@ -428,4 +454,34 @@ EOF
|
|
428
454
|
`./hello-d`.rstrip.should == "Hello from D!"
|
429
455
|
end
|
430
456
|
end
|
457
|
+
|
458
|
+
it "supports disassembling object files" do
|
459
|
+
test_dir("simple")
|
460
|
+
Rscons::Environment.new do |env|
|
461
|
+
env.Object("simple.o", "simple.c")
|
462
|
+
env.Disassemble("simple.txt", "simple.o")
|
463
|
+
end
|
464
|
+
File.exists?("simple.txt").should be_true
|
465
|
+
File.read("simple.txt").should =~ /Disassembly of section .text:/
|
466
|
+
end
|
467
|
+
|
468
|
+
it "supports preprocessing C sources" do
|
469
|
+
test_dir("simple")
|
470
|
+
Rscons::Environment.new do |env|
|
471
|
+
env.Preprocess("simplepp.c", "simple.c")
|
472
|
+
env.Program("simple", "simplepp.c")
|
473
|
+
end
|
474
|
+
File.read("simplepp.c").should =~ /# \d+ "simple.c"/
|
475
|
+
`./simple`.should == "This is a simple C program\n"
|
476
|
+
end
|
477
|
+
|
478
|
+
it "supports preprocessing C++ sources" do
|
479
|
+
test_dir("simple_cc")
|
480
|
+
Rscons::Environment.new do |env|
|
481
|
+
env.Preprocess("simplepp.cc", "simple.cc")
|
482
|
+
env.Program("simple", "simplepp.cc")
|
483
|
+
end
|
484
|
+
File.read("simplepp.cc").should =~ /# \d+ "simple.cc"/
|
485
|
+
`./simple`.should == "This is a simple C++ program\n"
|
486
|
+
end
|
431
487
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rscons
|
2
|
+
module Builders
|
3
|
+
describe CFile do
|
4
|
+
let(:env) {Environment.new}
|
5
|
+
subject {CFile.new}
|
6
|
+
|
7
|
+
it "invokes bison to create a .c file from a .y file" do
|
8
|
+
subject.should_receive(:standard_build).with("YACC parser.c", "parser.c", ["bison", "-d", "-o", "parser.c", "parser.y"], ["parser.y"], env, :cache)
|
9
|
+
subject.run("parser.c", ["parser.y"], :cache, env, {})
|
10
|
+
end
|
11
|
+
|
12
|
+
it "invokes a custom lexer to create a .cc file from a .ll file" do
|
13
|
+
env["LEX"] = "custom_lex"
|
14
|
+
subject.should_receive(:standard_build).with("LEX lexer.cc", "lexer.cc", ["custom_lex", "-o", "lexer.cc", "parser.ll"], ["parser.ll"], env, :cache)
|
15
|
+
subject.run("lexer.cc", ["parser.ll"], :cache, env, {})
|
16
|
+
end
|
17
|
+
|
18
|
+
it "raises an error when an unknown source file is specified" do
|
19
|
+
expect {subject.run("file.c", ["foo.bar"], :cache, env, {})}.to raise_error /Unknown source file .foo.bar. for CFile builder/
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/rscons/cache_spec.rb
CHANGED
@@ -5,35 +5,42 @@ module Rscons
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def build_from(cache)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
it "removes the cache file" do
|
14
|
-
FileUtils.should_receive(:rm_f).with(Cache::CACHE_FILE)
|
15
|
-
Cache.clear
|
8
|
+
JSON.stub(:load) do
|
9
|
+
cache
|
10
|
+
end
|
11
|
+
Cache.instance.tap do |cache|
|
12
|
+
cache.send(:initialize!)
|
16
13
|
end
|
17
14
|
end
|
18
15
|
|
19
16
|
describe "#initialize" do
|
20
17
|
context "when corrupt" do
|
21
18
|
it "prints a warning and defaults to an empty hash" do
|
22
|
-
|
19
|
+
JSON.should_receive(:load).and_return("string")
|
23
20
|
$stderr.should_receive(:puts).with(/Warning:.*was.corrupt/)
|
24
|
-
Cache.
|
21
|
+
c = Cache.instance
|
22
|
+
c.send(:initialize!)
|
23
|
+
c.instance_variable_get(:@cache).is_a?(Hash).should be_true
|
25
24
|
end
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
28
|
+
describe "#clear" do
|
29
|
+
it "removes the cache file" do
|
30
|
+
FileUtils.should_receive(:rm_f).with(Cache::CACHE_FILE)
|
31
|
+
JSON.stub(:load) {{}}
|
32
|
+
Cache.instance.clear
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
29
36
|
describe "#write" do
|
30
|
-
it "should fill in
|
37
|
+
it "should fill in 'version' and write to file" do
|
31
38
|
cache = {}
|
32
39
|
fh = $stdout
|
33
40
|
fh.should_receive(:puts)
|
34
41
|
File.should_receive(:open).and_yield(fh)
|
35
42
|
build_from(cache).write
|
36
|
-
cache[
|
43
|
+
cache["version"].should == Rscons::VERSION
|
37
44
|
end
|
38
45
|
end
|
39
46
|
|
@@ -54,7 +61,7 @@ module Rscons
|
|
54
61
|
end
|
55
62
|
|
56
63
|
it "returns false when the target's checksum does not match" do
|
57
|
-
_cache = {targets
|
64
|
+
_cache = {"targets" => {"target" => {"checksum" => "abc"}}}
|
58
65
|
cache = build_from(_cache)
|
59
66
|
File.should_receive(:exists?).with("target").and_return(true)
|
60
67
|
cache.should_receive(:calculate_checksum).with("target").and_return("def")
|
@@ -62,7 +69,7 @@ module Rscons
|
|
62
69
|
end
|
63
70
|
|
64
71
|
it "returns false when the build command has changed" do
|
65
|
-
_cache = {targets
|
72
|
+
_cache = {"targets" => {"target" => {"checksum" => "abc", "command" => Digest::MD5.hexdigest("old command".inspect)}}}
|
66
73
|
cache = build_from(_cache)
|
67
74
|
File.should_receive(:exists?).with("target").and_return(true)
|
68
75
|
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
@@ -70,9 +77,9 @@ module Rscons
|
|
70
77
|
end
|
71
78
|
|
72
79
|
it "returns false when there is a new dependency" do
|
73
|
-
_cache = {targets
|
74
|
-
command
|
75
|
-
deps
|
80
|
+
_cache = {"targets" => {"target" => {"checksum" => "abc",
|
81
|
+
"command" => Digest::MD5.hexdigest("command".inspect),
|
82
|
+
"deps" => [{"fname" => "dep.1"}]}}}
|
76
83
|
cache = build_from(_cache)
|
77
84
|
File.should_receive(:exists?).with("target").and_return(true)
|
78
85
|
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
@@ -80,15 +87,15 @@ module Rscons
|
|
80
87
|
end
|
81
88
|
|
82
89
|
it "returns false when a dependency's checksum has changed" do
|
83
|
-
_cache = {targets
|
84
|
-
command
|
85
|
-
deps
|
86
|
-
checksum
|
87
|
-
{fname
|
88
|
-
checksum
|
89
|
-
{fname
|
90
|
-
checksum
|
91
|
-
user_deps
|
90
|
+
_cache = {"targets" => {"target" => {"checksum" => "abc",
|
91
|
+
"command" => Digest::MD5.hexdigest("command".inspect),
|
92
|
+
"deps" => [{"fname" => "dep.1",
|
93
|
+
"checksum" => "dep.1.chk"},
|
94
|
+
{"fname" => "dep.2",
|
95
|
+
"checksum" => "dep.2.chk"},
|
96
|
+
{"fname" => "extra.dep",
|
97
|
+
"checksum" => "extra.dep.chk"}],
|
98
|
+
"user_deps" => []}}}
|
92
99
|
cache = build_from(_cache)
|
93
100
|
File.should_receive(:exists?).with("target").and_return(true)
|
94
101
|
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
@@ -98,15 +105,15 @@ module Rscons
|
|
98
105
|
end
|
99
106
|
|
100
107
|
it "returns false with strict_deps=true when cache has an extra dependency" do
|
101
|
-
_cache = {targets
|
102
|
-
command
|
103
|
-
deps
|
104
|
-
checksum
|
105
|
-
{fname
|
106
|
-
checksum
|
107
|
-
{fname
|
108
|
-
checksum
|
109
|
-
user_deps
|
108
|
+
_cache = {"targets" => {"target" => {"checksum" => "abc",
|
109
|
+
"command" => Digest::MD5.hexdigest("command".inspect),
|
110
|
+
"deps" => [{"fname" => "dep.1",
|
111
|
+
"checksum" => "dep.1.chk"},
|
112
|
+
{"fname" => "dep.2",
|
113
|
+
"checksum" => "dep.2.chk"},
|
114
|
+
{"fname" => "extra.dep",
|
115
|
+
"checksum" => "extra.dep.chk"}],
|
116
|
+
"user_deps" => []}}}
|
110
117
|
cache = build_from(_cache)
|
111
118
|
File.should_receive(:exists?).with("target").and_return(true)
|
112
119
|
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
@@ -114,10 +121,10 @@ module Rscons
|
|
114
121
|
end
|
115
122
|
|
116
123
|
it "returns false when there is a new user dependency" do
|
117
|
-
_cache = {targets
|
118
|
-
command
|
119
|
-
deps
|
120
|
-
user_deps
|
124
|
+
_cache = {"targets" => {"target" => {"checksum" => "abc",
|
125
|
+
"command" => Digest::MD5.hexdigest("command".inspect),
|
126
|
+
"deps" => [{"fname" => "dep.1"}],
|
127
|
+
"user_deps" => []}}}
|
121
128
|
cache = build_from(_cache)
|
122
129
|
env = "env"
|
123
130
|
env.should_receive(:get_user_deps).with("target").and_return(["file.ld"])
|
@@ -127,16 +134,16 @@ module Rscons
|
|
127
134
|
end
|
128
135
|
|
129
136
|
it "returns false when a user dependency checksum has changed" do
|
130
|
-
_cache = {targets
|
131
|
-
command
|
132
|
-
deps
|
133
|
-
checksum
|
134
|
-
{fname
|
135
|
-
checksum
|
136
|
-
{fname
|
137
|
-
checksum
|
138
|
-
user_deps
|
139
|
-
checksum
|
137
|
+
_cache = {"targets" => {"target" => {"checksum" => "abc",
|
138
|
+
"command" => Digest::MD5.hexdigest("command".inspect),
|
139
|
+
"deps" => [{"fname" => "dep.1",
|
140
|
+
"checksum" => "dep.1.chk"},
|
141
|
+
{"fname" => "dep.2",
|
142
|
+
"checksum" => "dep.2.chk"},
|
143
|
+
{"fname" => "extra.dep",
|
144
|
+
"checksum" => "extra.dep.chk"}],
|
145
|
+
"user_deps" => [{"fname" => "user.dep",
|
146
|
+
"checksum" => "user.dep.chk"}]}}}
|
140
147
|
cache = build_from(_cache)
|
141
148
|
env = "env"
|
142
149
|
env.should_receive(:get_user_deps).with("target").and_return(["user.dep"])
|
@@ -150,15 +157,15 @@ module Rscons
|
|
150
157
|
end
|
151
158
|
|
152
159
|
it "returns true when no condition for false is met" do
|
153
|
-
_cache = {targets
|
154
|
-
command
|
155
|
-
deps
|
156
|
-
checksum
|
157
|
-
{fname
|
158
|
-
checksum
|
159
|
-
{fname
|
160
|
-
checksum
|
161
|
-
user_deps
|
160
|
+
_cache = {"targets" => {"target" => {"checksum" => "abc",
|
161
|
+
"command" => Digest::MD5.hexdigest("command".inspect),
|
162
|
+
"deps" => [{"fname" => "dep.1",
|
163
|
+
"checksum" => "dep.1.chk"},
|
164
|
+
{"fname" => "dep.2",
|
165
|
+
"checksum" => "dep.2.chk"},
|
166
|
+
{"fname" => "extra.dep",
|
167
|
+
"checksum" => "extra.dep.chk"}],
|
168
|
+
"user_deps" => []}}}
|
162
169
|
cache = build_from(_cache)
|
163
170
|
File.should_receive(:exists?).with("target").and_return(true)
|
164
171
|
cache.should_receive(:calculate_checksum).with("target").and_return("abc")
|
@@ -180,23 +187,23 @@ module Rscons
|
|
180
187
|
cache.should_receive(:calculate_checksum).with("dep 2").and_return("dep 2 checksum")
|
181
188
|
cache.should_receive(:calculate_checksum).with("user.dep").and_return("user.dep checksum")
|
182
189
|
cache.register_build("the target", "the command", ["dep 1", "dep 2"], env)
|
183
|
-
cached_target = cache.instance_variable_get(:@cache)[
|
190
|
+
cached_target = cache.instance_variable_get(:@cache)["targets"]["the target"]
|
184
191
|
cached_target.should_not be_nil
|
185
|
-
cached_target[
|
186
|
-
cached_target[
|
187
|
-
cached_target[
|
188
|
-
{fname
|
189
|
-
{fname
|
192
|
+
cached_target["command"].should == Digest::MD5.hexdigest("the command".inspect)
|
193
|
+
cached_target["checksum"].should == "the checksum"
|
194
|
+
cached_target["deps"].should == [
|
195
|
+
{"fname" => "dep 1", "checksum" => "dep 1 checksum"},
|
196
|
+
{"fname" => "dep 2", "checksum" => "dep 2 checksum"},
|
190
197
|
]
|
191
|
-
cached_target[
|
192
|
-
{fname
|
198
|
+
cached_target["user_deps"].should == [
|
199
|
+
{"fname" => "user.dep", "checksum" => "user.dep checksum"},
|
193
200
|
]
|
194
201
|
end
|
195
202
|
end
|
196
203
|
|
197
204
|
describe "#targets" do
|
198
205
|
it "returns a list of targets that are cached" do
|
199
|
-
cache = {targets
|
206
|
+
cache = {"targets" => {"t1" => {}, "t2" => {}, "t3" => {}}}
|
200
207
|
build_from(cache).targets.should == ["t1", "t2", "t3"]
|
201
208
|
end
|
202
209
|
end
|
@@ -218,11 +225,21 @@ module Rscons
|
|
218
225
|
cache.mkdir_p("one\\two\\four")
|
219
226
|
cache.directories.should == ["one/two", "one/two/three", "one/two/four"]
|
220
227
|
end
|
228
|
+
|
229
|
+
it "handles absolute paths" do
|
230
|
+
_cache = {}
|
231
|
+
cache = build_from(_cache)
|
232
|
+
File.should_receive(:exists?).with("/one").and_return(true)
|
233
|
+
File.should_receive(:exists?).with("/one/two").and_return(false)
|
234
|
+
FileUtils.should_receive(:mkdir).with("/one/two")
|
235
|
+
cache.mkdir_p("/one/two")
|
236
|
+
cache.directories.should == ["/one/two"]
|
237
|
+
end
|
221
238
|
end
|
222
239
|
|
223
240
|
describe "#directories" do
|
224
241
|
it "returns a list of directories that are cached" do
|
225
|
-
_cache = {directories
|
242
|
+
_cache = {"directories" => {"dir1" => true, "dir2" => true}}
|
226
243
|
build_from(_cache).directories.should == ["dir1", "dir2"]
|
227
244
|
end
|
228
245
|
end
|