rscons 1.15.0 → 1.19.1

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 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