rscons 1.15.0 → 1.19.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2bb3ac572e885e3bd9a0e44c261c2208cc79b315
4
- data.tar.gz: c857eec695f9b829f773adff9f814e86e625cd04
2
+ SHA256:
3
+ metadata.gz: dda25ef5e4dd644cd868bb86d6fc3ba9230f694ea7bf0c31577f5ab687c8409f
4
+ data.tar.gz: e8993bd5dc123252060eef9ba22da1750d1ae0162ce20ad17a6d6b52096cd959
5
5
  SHA512:
6
- metadata.gz: c15ed61445c6f8fda20b6750c081e217a04054389e70b24a854d98c04da0e8c83dfeb843dedcd59109fd06f0cd489b633e7539d4131b8f4586752bc6e49f735b
7
- data.tar.gz: b2af19434c5baa99f800e176527641ae747744d35507eaa61eac5ffc1cf62a17a8c5225efed3533356c39f79d4fc154c4ce0c39dc70c62d1a8bb16564fa4d72f
6
+ metadata.gz: a19b6cde13d0b98aaeee43e55ef525da74bd2f0376788ac871d69186d4e511d606193a7c5f81255547273e05b1d2e7334f4a5f4639ff461f9ce3e89eb1f08fe6
7
+ data.tar.gz: 91f7d0caebfeb99ec2245b00c76ce4693312fce401987995b13200c28ebb08de2c7c7310a76ad9a9397090cb80c4db361d021edac571d8d931b06c56e02765b2
data/bin/rscons CHANGED
@@ -1,3 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
1
3
  require "rscons/cli"
2
4
 
3
5
  Rscons::Cli.run(ARGV)
data/lib/rscons.rb CHANGED
@@ -5,6 +5,7 @@ require_relative "rscons/cache"
5
5
  require_relative "rscons/environment"
6
6
  require_relative "rscons/job_set"
7
7
  require_relative "rscons/threaded_command"
8
+ require_relative "rscons/util"
8
9
  require_relative "rscons/varset"
9
10
  require_relative "rscons/version"
10
11
 
@@ -55,6 +56,11 @@ module Rscons
55
56
  # Whether to output ANSI color escape sequences.
56
57
  attr_accessor :do_ansi_color
57
58
 
59
+ # @since 1.16.0
60
+ # @return [VarSet]
61
+ # Access any variables set on the rscons command-line.
62
+ attr_reader :vars
63
+
58
64
  # Remove all generated files.
59
65
  #
60
66
  # @return [void]
@@ -165,6 +171,35 @@ module Rscons
165
171
  @command_executer = val
166
172
  end
167
173
 
174
+ # Return a list of paths matching the specified pattern(s).
175
+ #
176
+ # @since 1.16.0
177
+ #
178
+ # A pattern can contain a "/**" component to recurse through directories.
179
+ # If the pattern ends with "/**" then only the recursive list of
180
+ # directories will be returned.
181
+ #
182
+ # Examples:
183
+ # - "src/**": return all directories under "src", recursively (including
184
+ # "src" itself).
185
+ # - "src/**/*": return all files and directories recursively under the src
186
+ # directory.
187
+ # - "src/**/*.c": return all .c files recursively under the src directory.
188
+ # - "dir/*/": return all directories in dir, but no files.
189
+ #
190
+ # @return [Array<String>] Paths matching the specified pattern(s).
191
+ def glob(*patterns)
192
+ require "pathname"
193
+ patterns.reduce([]) do |result, pattern|
194
+ if pattern.end_with?("/**")
195
+ pattern += "/"
196
+ end
197
+ result += Dir.glob(pattern).map do |path|
198
+ Pathname.new(path.gsub("\\", "/")).cleanpath.to_s
199
+ end
200
+ end.sort
201
+ end
202
+
168
203
  private
169
204
 
170
205
  # Determine the number of threads to use by default.
@@ -203,6 +238,7 @@ module Rscons
203
238
  end
204
239
 
205
240
  @n_threads = determine_n_threads
241
+ @vars = VarSet.new
206
242
 
207
243
  end
208
244
 
@@ -47,6 +47,7 @@ module Rscons
47
47
  printed_message = true
48
48
  end
49
49
  cache.mkdir_p(File.dirname(dest))
50
+ FileUtils.rm_f(dest)
50
51
  FileUtils.cp(src, dest, :preserve => true)
51
52
  end
52
53
  cache.register_build(dest, :Copy, [src], env)
@@ -54,8 +54,9 @@ module Rscons
54
54
  'DC' => 'gdc',
55
55
  'DFLAGS' => [],
56
56
  'DSUFFIX' => ['.d'],
57
+ 'DDEPGEN' => ['-MMD', '-MF', '${_DEPFILE}'],
57
58
  'D_IMPORT_PATH' => [],
58
- 'DCCMD' => ['${DC}', '-c', '-o', '${_TARGET}', '${INCPREFIX}${D_IMPORT_PATH}', '${DFLAGS}', '${_SOURCES}'],
59
+ 'DCCMD' => ['${DC}', '-c', '-o', '${_TARGET}', '${DDEPGEN}', '${INCPREFIX}${D_IMPORT_PATH}', '${DFLAGS}', '${_SOURCES}'],
59
60
  }
60
61
  end
61
62
 
@@ -114,7 +115,7 @@ module Rscons
114
115
  if options[:command_status]
115
116
  target, deps, cache, env, vars = options.values_at(:target, :sources, :cache, :env, :vars)
116
117
  if File.exists?(vars['_DEPFILE'])
117
- deps += Environment.parse_makefile_deps(vars['_DEPFILE'], target)
118
+ deps += Environment.parse_makefile_deps(vars['_DEPFILE'])
118
119
  FileUtils.rm_f(vars['_DEPFILE'])
119
120
  end
120
121
  cache.register_build(target, options[:tc].command, deps.uniq, env)
@@ -55,7 +55,7 @@ module Rscons
55
55
  if options[:command_status]
56
56
  target, deps, cache, env, vars = options.values_at(:target, :sources, :cache, :env, :vars)
57
57
  if File.exists?(vars['_DEPFILE'])
58
- deps += Environment.parse_makefile_deps(vars['_DEPFILE'], nil)
58
+ deps += Environment.parse_makefile_deps(vars['_DEPFILE'])
59
59
  FileUtils.rm_f(vars['_DEPFILE'])
60
60
  end
61
61
  cache.register_build(target, options[:tc].command, deps.uniq, env)
@@ -100,7 +100,7 @@ module Rscons
100
100
  if options[:command_status]
101
101
  target, deps, cache, env, vars = options.values_at(:target, :sources, :cache, :env, :vars)
102
102
  if File.exists?(vars['_DEPFILE'])
103
- deps += Environment.parse_makefile_deps(vars['_DEPFILE'], target)
103
+ deps += Environment.parse_makefile_deps(vars['_DEPFILE'])
104
104
  FileUtils.rm_f(vars['_DEPFILE'])
105
105
  end
106
106
  cache.register_build(target, options[:tc].command, deps.uniq, env)
data/lib/rscons/cache.rb CHANGED
@@ -85,17 +85,14 @@ module Rscons
85
85
  @lookup_checksums = {}
86
86
  end
87
87
 
88
- # Write the cache to disk to be loaded next time.
88
+ # Write the cache to disk.
89
89
  #
90
90
  # @return [void]
91
91
  def write
92
- if @dirty || (@cache["version"] != VERSION)
93
- @cache["version"] = VERSION
94
- File.open(CACHE_FILE, "w") do |fh|
95
- fh.puts(JSON.dump(@cache))
96
- end
92
+ @cache["version"] = VERSION
93
+ File.open(CACHE_FILE, "w") do |fh|
94
+ fh.puts(JSON.dump(@cache))
97
95
  end
98
- @dirty = false
99
96
  end
100
97
 
101
98
  # Check if target(s) are up to date.
@@ -111,6 +108,10 @@ module Rscons
111
108
  # @param deps [Array<String>] List of the target's dependency files.
112
109
  # @param env [Environment] The Rscons::Environment.
113
110
  # @param options [Hash] Optional options.
111
+ # @option options [Boolean] :debug
112
+ # If turned on, this causes the Cache to print messages explaining why
113
+ # a build target is out of date. This could aid a builder author in
114
+ # debugging the operation of their builder.
114
115
  # @option options [Boolean] :strict_deps
115
116
  # Only consider a target up to date if its list of dependencies is
116
117
  # exactly equal (including order) to the cached list of dependencies
@@ -133,39 +134,79 @@ module Rscons
133
134
 
134
135
  unless Rscons.phony_target?(target)
135
136
  # target file must exist on disk
136
- return false unless File.exists?(target)
137
+ unless File.exists?(target)
138
+ if options[:debug]
139
+ puts "Target #{target} needs rebuilding because it does not exist on disk"
140
+ end
141
+ return false
142
+ end
137
143
  end
138
144
 
139
145
  # target must be registered in the cache
140
- return false unless @cache["targets"].has_key?(cache_key)
146
+ unless @cache["targets"].has_key?(cache_key)
147
+ if options[:debug]
148
+ puts "Target #{target} needs rebuilding because there is no cached build information for it"
149
+ end
150
+ return false
151
+ end
141
152
 
142
153
  unless Rscons.phony_target?(target)
143
154
  # target must have the same checksum as when it was built last
144
- return false unless @cache["targets"][cache_key]["checksum"] == lookup_checksum(target)
155
+ unless @cache["targets"][cache_key]["checksum"] == lookup_checksum(target)
156
+ if options[:debug]
157
+ puts "Target #{target} needs rebuilding because it has been changed on disk since being built last"
158
+ end
159
+ return false
160
+ end
145
161
  end
146
162
 
147
163
  # command used to build target must be identical
148
- return false unless @cache["targets"][cache_key]["command"] == Digest::MD5.hexdigest(command.inspect)
164
+ unless @cache["targets"][cache_key]["command"] == Digest::MD5.hexdigest(command.inspect)
165
+ if options[:debug]
166
+ puts "Target #{target} needs rebuilding because the command used to build it has changed"
167
+ end
168
+ return false
169
+ end
149
170
 
150
171
  cached_deps = @cache["targets"][cache_key]["deps"] || []
151
172
  cached_deps_fnames = cached_deps.map { |dc| dc["fname"] }
152
173
  if options[:strict_deps]
153
174
  # depedencies passed in must exactly equal those in the cache
154
- return false unless deps == cached_deps_fnames
175
+ unless deps == cached_deps_fnames
176
+ if options[:debug]
177
+ puts "Target #{target} needs rebuilding because the :strict_deps option is given and the set of dependencies does not match the previous set of dependencies"
178
+ end
179
+ return false
180
+ end
155
181
  else
156
182
  # all dependencies passed in must exist in cache (but cache may have more)
157
- return false unless (Set.new(deps) - Set.new(cached_deps_fnames)).empty?
183
+ unless (Set.new(deps) - Set.new(cached_deps_fnames)).empty?
184
+ if options[:debug]
185
+ puts "Target #{target} needs rebuilding because there are new dependencies"
186
+ end
187
+ return false
188
+ end
158
189
  end
159
190
 
160
191
  # set of user dependencies must match
161
192
  user_deps = env.get_user_deps(target) || []
162
193
  cached_user_deps = @cache["targets"][cache_key]["user_deps"] || []
163
194
  cached_user_deps_fnames = cached_user_deps.map { |dc| dc["fname"] }
164
- return false unless user_deps == cached_user_deps_fnames
195
+ unless user_deps == cached_user_deps_fnames
196
+ if options[:debug]
197
+ puts "Target #{target} needs rebuilding because the set of user-specified dependency files has changed"
198
+ end
199
+ return false
200
+ end
165
201
 
166
202
  # all cached dependencies must have their checksums match
167
203
  (cached_deps + cached_user_deps).each do |dep_cache|
168
- return false unless dep_cache["checksum"] == lookup_checksum(dep_cache["fname"])
204
+ unless dep_cache["checksum"] == lookup_checksum(dep_cache["fname"])
205
+ if options[:debug]
206
+ puts "Target #{target} needs rebuilding because dependency file #{dep_cache["fname"]} has changed"
207
+ end
208
+ return false
209
+ end
169
210
  end
170
211
  end
171
212
 
@@ -205,7 +246,6 @@ module Rscons
205
246
  }
206
247
  end,
207
248
  }
208
- @dirty = true
209
249
  end
210
250
  end
211
251
 
@@ -228,9 +268,8 @@ module Rscons
228
268
  next if parts[i] == ""
229
269
  subpath = File.join(*parts[0, i + 1])
230
270
  unless File.exists?(subpath)
231
- FileUtils.mkdir(subpath)
271
+ FileUtils.mkdir_p(subpath)
232
272
  @cache["directories"][subpath] = true
233
- @dirty = true
234
273
  end
235
274
  end
236
275
  end
@@ -243,6 +282,16 @@ module Rscons
243
282
  @cache["directories"].keys
244
283
  end
245
284
 
285
+ # Return a file's checksum, or the previously calculated checksum for
286
+ # the same file.
287
+ #
288
+ # @param file [String] The file name.
289
+ #
290
+ # @return [String] The file's checksum.
291
+ def lookup_checksum(file)
292
+ @lookup_checksums[file] || calculate_checksum(file)
293
+ end
294
+
246
295
  private
247
296
 
248
297
  # Return a String key based on the target name to use in the on-disk cache.
@@ -271,17 +320,6 @@ module Rscons
271
320
  @cache["targets"] ||= {}
272
321
  @cache["directories"] ||= {}
273
322
  @lookup_checksums = {}
274
- @dirty = false
275
- end
276
-
277
- # Return a file's checksum, or the previously calculated checksum for
278
- # the same file.
279
- #
280
- # @param file [String] The file name.
281
- #
282
- # @return [String] The file's checksum.
283
- def lookup_checksum(file)
284
- @lookup_checksums[file] || calculate_checksum(file)
285
323
  end
286
324
 
287
325
  # Calculate and return a file's checksum.
data/lib/rscons/cli.rb CHANGED
@@ -60,6 +60,12 @@ module Rscons
60
60
 
61
61
  end.parse!(argv)
62
62
 
63
+ argv.each do |arg|
64
+ if arg =~ /^([^=]+)=(.*)$/
65
+ Rscons.vars[$1] = $2
66
+ end
67
+ end
68
+
63
69
  if rsconsfile
64
70
  unless File.exists?(rsconsfile)
65
71
  $stderr.puts "Cannot read #{rsconsfile}"
@@ -1,7 +1,6 @@
1
1
  require "fileutils"
2
2
  require "set"
3
3
  require "shellwords"
4
- require "thwait"
5
4
 
6
5
  module Rscons
7
6
  # The Environment class is the main programmatic interface to Rscons. It
@@ -280,6 +279,24 @@ module Rscons
280
279
  @varset.send(:[], *args)
281
280
  end
282
281
 
282
+ # Access the value of a construction variable.
283
+ #
284
+ # @since 1.18.0
285
+ #
286
+ # This method is similar to #[] but does not make a copy-on-access copy of
287
+ # the variable accessed. This means that the returned value is NOT safe to
288
+ # be modified by the caller. Thus the caller must guarantee that it does
289
+ # not modify the returned value.
290
+ #
291
+ # @param key [String, Symbol]
292
+ # The construction variable name.
293
+ #
294
+ # @return [Object]
295
+ # The construction variable's value.
296
+ def get_var(key)
297
+ @varset.get_var(key)
298
+ end
299
+
283
300
  # Set a construction variable's value.
284
301
  #
285
302
  # @see VarSet#[]=
@@ -323,6 +340,7 @@ module Rscons
323
340
  cache.clear_checksum_cache!
324
341
 
325
342
  if job
343
+ validate_user_deps(job[:target], @user_deps[job[:target]], cache)
326
344
  result = run_builder(job[:builder],
327
345
  job[:target],
328
346
  job[:sources],
@@ -385,12 +403,12 @@ module Rscons
385
403
 
386
404
  # Expand a construction variable reference.
387
405
  #
388
- # @param varref [Array, String] Variable reference to expand.
406
+ # @param varref [nil, String, Array, Proc, Symbol, TrueClass, FalseClass] Variable reference to expand.
389
407
  # @param extra_vars [Hash, VarSet]
390
408
  # Extra variables to use in addition to (or replace) the Environment's
391
409
  # construction variables when expanding the variable reference.
392
410
  #
393
- # @return [Array, String] Expansion of the variable reference.
411
+ # @return [nil, String, Array, Symbol, TrueClass, FalseClass] Expansion of the variable reference.
394
412
  def expand_varref(varref, extra_vars = nil)
395
413
  vars = if extra_vars.nil?
396
414
  @varset
@@ -782,7 +800,7 @@ module Rscons
782
800
  append["LDFLAGS", ["-arch", val]]
783
801
  end
784
802
  skip = true
785
- elsif word =~ /^#{self["CPPDEFPREFIX"]}(.*)$/
803
+ elsif word =~ /^#{get_var("CPPDEFPREFIX")}(.*)$/
786
804
  handle["CPPDEFINES", $1]
787
805
  elsif word == "-include"
788
806
  if val = words[i + 1]
@@ -795,11 +813,11 @@ module Rscons
795
813
  append["LDFLAGS", ["-isysroot", val]]
796
814
  end
797
815
  skip = true
798
- elsif word =~ /^#{self["INCPREFIX"]}(.*)$/
816
+ elsif word =~ /^#{get_var("INCPREFIX")}(.*)$/
799
817
  handle["CPPPATH", $1]
800
- elsif word =~ /^#{self["LIBLINKPREFIX"]}(.*)$/
818
+ elsif word =~ /^#{get_var("LIBLINKPREFIX")}(.*)$/
801
819
  handle["LIBS", $1]
802
- elsif word =~ /^#{self["LIBDIRPREFIX"]}(.*)$/
820
+ elsif word =~ /^#{get_var("LIBDIRPREFIX")}(.*)$/
803
821
  handle["LIBPATH", $1]
804
822
  elsif word == "-mno-cygwin"
805
823
  append["CCFLAGS", [word]]
@@ -848,7 +866,7 @@ module Rscons
848
866
  # @return [void]
849
867
  def merge_flags(flags)
850
868
  flags.each_pair do |key, val|
851
- if self[key].is_a?(Array) and val.is_a?(Array)
869
+ if self.get_var(key).is_a?(Array) and val.is_a?(Array)
852
870
  self[key] += val
853
871
  else
854
872
  self[key] = val
@@ -993,10 +1011,7 @@ module Rscons
993
1011
  !thread.alive?
994
1012
  end
995
1013
  else
996
- if threads.empty?
997
- raise "No threads to wait for"
998
- end
999
- ThreadsWait.new(*threads).next_wait
1014
+ Util.wait_for_thread(*threads)
1000
1015
  end
1001
1016
  end
1002
1017
 
@@ -1065,16 +1080,14 @@ module Rscons
1065
1080
  end
1066
1081
  end
1067
1082
 
1068
- # Parse dependencies for a given target from a Makefile.
1083
+ # Parse dependencies from a Makefile.
1069
1084
  #
1070
1085
  # This method is used internally by Rscons builders.
1071
1086
  #
1072
1087
  # @param mf_fname [String] File name of the Makefile to read.
1073
- # @param target [String, nil]
1074
- # Name of the target to gather dependencies for, nil for any/all.
1075
1088
  #
1076
1089
  # @return [Array<String>] Paths of dependency files.
1077
- def self.parse_makefile_deps(mf_fname, target)
1090
+ def self.parse_makefile_deps(mf_fname)
1078
1091
  deps = []
1079
1092
  buildup = ''
1080
1093
  File.read(mf_fname).each_line do |line|
@@ -1082,16 +1095,34 @@ module Rscons
1082
1095
  buildup += ' ' + $1
1083
1096
  else
1084
1097
  buildup += ' ' + line
1085
- if buildup =~ /^(.*): (.*)$/
1086
- mf_target, mf_deps = $1.strip, $2
1087
- if target.nil? or mf_target == target
1088
- deps += mf_deps.split(' ').map(&:strip)
1089
- end
1098
+ if buildup =~ /^.*: (.*)$/
1099
+ mf_deps = $1
1100
+ deps += mf_deps.split(' ').map(&:strip)
1090
1101
  end
1091
1102
  buildup = ''
1092
1103
  end
1093
1104
  end
1094
1105
  deps
1095
1106
  end
1107
+
1108
+ # Ensures that user dependencies exist with valid checksums in the
1109
+ # cache. Raises an exception if any dependency is invalid.
1110
+ #
1111
+ # @param target [String]
1112
+ # Target to be built
1113
+ # @param user_deps [Array<String>, nil]
1114
+ # User dependencies of the target
1115
+ # @param cache [Cache]
1116
+ # Rscons cache instance
1117
+ #
1118
+ # @return [void]
1119
+ def validate_user_deps(target, user_deps, cache)
1120
+ return if user_deps.nil?
1121
+ user_deps.each do |dep|
1122
+ if cache.lookup_checksum(dep) == ""
1123
+ raise "User dependency #{dep} of target #{target} is invalid"
1124
+ end
1125
+ end
1126
+ end
1096
1127
  end
1097
1128
  end
@@ -0,0 +1,34 @@
1
+ module Rscons
2
+ # A collection of stand-alone utility methods.
3
+ module Util
4
+ class << self
5
+
6
+ # Wait for any of a number of threads to complete.
7
+ #
8
+ # @param threads [Array<Thread>]
9
+ # Threads to wait for.
10
+ #
11
+ # @return [Thread]
12
+ # The Thread that completed.
13
+ def wait_for_thread(*threads)
14
+ if threads.empty?
15
+ raise "No threads to wait for"
16
+ end
17
+ queue = Queue.new
18
+ threads.each do |thread|
19
+ # Create a wait thread for each thread we're waiting for.
20
+ Thread.new do
21
+ begin
22
+ thread.join
23
+ ensure
24
+ queue.push(thread)
25
+ end
26
+ end
27
+ end
28
+ # Wait for any thread to complete.
29
+ queue.pop
30
+ end
31
+
32
+ end
33
+ end
34
+ end
data/lib/rscons/varset.rb CHANGED
@@ -11,11 +11,13 @@ module Rscons
11
11
  append(vars)
12
12
  end
13
13
 
14
- # Access the value of variable.
14
+ # Access the value of a variable.
15
15
  #
16
- # @param key [String, Symbol] The variable name.
16
+ # @param key [String, Symbol]
17
+ # The variable name.
17
18
  #
18
- # @return [Object] The variable's value.
19
+ # @return [Object]
20
+ # The variable's value.
19
21
  def [](key)
20
22
  if @my_vars.include?(key)
21
23
  @my_vars[key]
@@ -30,11 +32,38 @@ module Rscons
30
32
  end
31
33
  end
32
34
 
35
+ # Access the value of a variable.
36
+ #
37
+ # This method is similar to #[] but does not make a copy-on-access copy of
38
+ # the variable accessed. This means that the returned value is NOT safe to
39
+ # be modified by the caller. Thus the caller must guarantee that it does
40
+ # not modify the returned value.
41
+ #
42
+ # @param key [String, Symbol]
43
+ # The variable name.
44
+ #
45
+ # @return [Object]
46
+ # The variable's value.
47
+ def get_var(key)
48
+ if @my_vars.include?(key)
49
+ @my_vars[key]
50
+ else
51
+ @coa_vars.each do |coa_vars|
52
+ if coa_vars.include?(key)
53
+ return coa_vars[key]
54
+ end
55
+ end
56
+ nil
57
+ end
58
+ end
59
+
33
60
  # Assign a value to a variable.
34
61
  #
35
- # @param key [String, Symbol] The variable name.
62
+ # @param key [String, Symbol]
63
+ # The variable name.
36
64
  #
37
- # @param val [Object] The value to set.
65
+ # @param val [Object]
66
+ # The value to set.
38
67
  def []=(key, val)
39
68
  @my_vars[key] = val
40
69
  end
@@ -86,40 +115,50 @@ module Rscons
86
115
  # Replace "$!{var}" variable references in varref with the expanded
87
116
  # variables' values, recursively.
88
117
  #
89
- # @param varref [nil, String, Array, Proc]
118
+ # @param varref [nil, String, Array, Proc, Symbol, TrueClass, FalseClass]
90
119
  # Value containing references to variables.
91
120
  # @param lambda_args [Array]
92
121
  # Arguments to pass to any lambda variable values to be expanded.
93
122
  #
94
- # @return [nil, String, Array]
123
+ # @return [nil, String, Array, Symbol, TrueClass, FalseClass]
95
124
  # Expanded value with "$!{var}" variable references replaced.
96
125
  def expand_varref(varref, lambda_args)
97
- if varref.is_a?(String)
126
+ case varref
127
+ when String
98
128
  if varref =~ /^(.*)\$\{([^}]+)\}(.*)$/
99
129
  prefix, varname, suffix = $1, $2, $3
100
- varval = expand_varref(self[varname], lambda_args)
101
- if varval.is_a?(String) or varval.nil?
102
- expand_varref("#{prefix}#{varval}#{suffix}", lambda_args)
103
- elsif varval.is_a?(Array)
104
- varval.map {|vv| expand_varref("#{prefix}#{vv}#{suffix}", lambda_args)}.flatten
130
+ prefix = expand_varref(prefix, lambda_args) unless prefix.empty?
131
+ varval = expand_varref(get_var(varname), lambda_args)
132
+ # suffix needs no expansion since the regex matches the last occurence
133
+ case varval
134
+ when Array
135
+ if prefix.is_a?(Array)
136
+ varval.map {|vv| prefix.map {|p| "#{p}#{vv}#{suffix}"}}.flatten
137
+ else
138
+ varval.map {|vv| "#{prefix}#{vv}#{suffix}"}
139
+ end
140
+ when String, Symbol, true, false, nil
141
+ if prefix.is_a?(Array)
142
+ prefix.map {|p| "#{p}#{varval}#{suffix}"}
143
+ else
144
+ "#{prefix}#{varval}#{suffix}"
145
+ end
105
146
  else
106
- raise "I do not know how to expand a variable reference to a #{varval.class.name} (from #{varname.inspect} => #{self[varname].inspect})"
147
+ raise "Unknown construction variable type: #{varval.class} (from #{varname.inspect} => #{get_var(varname).inspect})"
107
148
  end
108
149
  else
109
150
  varref
110
151
  end
111
- elsif varref.is_a?(Array)
152
+ when Array
112
153
  varref.map do |ent|
113
154
  expand_varref(ent, lambda_args)
114
155
  end.flatten
115
- elsif varref.is_a?(Proc)
116
- expand_varref(varref[*lambda_args], lambda_args)
117
- elsif varref.nil?
118
- nil
119
- elsif varref.is_a?(Symbol)
156
+ when Symbol, true, false, nil
120
157
  varref
158
+ when Proc
159
+ expand_varref(varref[*lambda_args], lambda_args)
121
160
  else
122
- raise "Unknown varref type: #{varref.class} (#{varref.inspect})"
161
+ raise "Unknown construction variable type: #{varref.class} (#{varref.inspect})"
123
162
  end
124
163
  end
125
164
 
@@ -143,6 +182,13 @@ module Rscons
143
182
  end
144
183
  end
145
184
 
185
+ # Return a String representing the VarSet.
186
+ #
187
+ # @return [String] Representation of the VarSet.
188
+ def inspect
189
+ to_h.inspect
190
+ end
191
+
146
192
  # Return an array containing the values associated with the given keys.
147
193
  #
148
194
  # @param keys [Array<String, Symbol>]
@@ -177,16 +223,16 @@ module Rscons
177
223
  #
178
224
  # @return [Object] Deep copied value.
179
225
  def deep_dup(obj)
180
- obj_class = obj.class
181
- if obj_class == Hash
226
+ case obj
227
+ when String
228
+ obj.dup
229
+ when Array
230
+ obj.map { |v| deep_dup(v) }
231
+ when Hash
182
232
  obj.reduce({}) do |result, (k, v)|
183
233
  result[k] = deep_dup(v)
184
234
  result
185
235
  end
186
- elsif obj_class == Array
187
- obj.map { |v| deep_dup(v) }
188
- elsif obj_class == String
189
- obj.dup
190
236
  else
191
237
  obj
192
238
  end
@@ -1,4 +1,4 @@
1
1
  module Rscons
2
2
  # gem version
3
- VERSION = "1.15.0"
3
+ VERSION = "1.19.1"
4
4
  end
data/rscons.gemspec CHANGED
@@ -22,8 +22,7 @@ Gem::Specification.new do |gem|
22
22
 
23
23
  gem.add_development_dependency "rspec"
24
24
  gem.add_development_dependency "rake"
25
- gem.add_development_dependency "simplecov"
25
+ gem.add_development_dependency "simplecov", "~> 0.15.0"
26
26
  gem.add_development_dependency "yard"
27
27
  gem.add_development_dependency "rdoc"
28
- gem.add_development_dependency "redcarpet"
29
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rscons
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.0
4
+ version: 1.19.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Holtrop
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-08 00:00:00.000000000 Z
11
+ date: 2021-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -62,16 +62,16 @@ dependencies:
62
62
  name: simplecov
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - ">="
65
+ - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '0'
67
+ version: 0.15.0
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - ">="
72
+ - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0'
74
+ version: 0.15.0
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: yard
77
77
  requirement: !ruby/object:Gem::Requirement
@@ -100,20 +100,6 @@ dependencies:
100
100
  - - ">="
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0'
103
- - !ruby/object:Gem::Dependency
104
- name: redcarpet
105
- requirement: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - ">="
108
- - !ruby/object:Gem::Version
109
- version: '0'
110
- type: :development
111
- prerelease: false
112
- version_requirements: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - ">="
115
- - !ruby/object:Gem::Version
116
- version: '0'
117
103
  description: Software construction library inspired by SCons and implemented in Ruby.
118
104
  email:
119
105
  - jholtrop@gmail.com
@@ -145,6 +131,7 @@ files:
145
131
  - lib/rscons/environment.rb
146
132
  - lib/rscons/job_set.rb
147
133
  - lib/rscons/threaded_command.rb
134
+ - lib/rscons/util.rb
148
135
  - lib/rscons/varset.rb
149
136
  - lib/rscons/version.rb
150
137
  - rscons.gemspec
@@ -167,8 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
154
  - !ruby/object:Gem::Version
168
155
  version: '0'
169
156
  requirements: []
170
- rubyforge_project:
171
- rubygems_version: 2.6.13
157
+ rubygems_version: 3.1.4
172
158
  signing_key:
173
159
  specification_version: 4
174
160
  summary: Software construction library inspired by SCons and implemented in Ruby