rscons 1.3.0 → 1.4.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 +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
|