Class: Rscons::Cache
- Inherits:
-
Object
- Object
- Rscons::Cache
- Defined in:
- lib/rscons/cache.rb
Overview
The Cache class keeps track of file checksums, build target commands and dependencies in a JSON file which persists from one invocation to the next. Example cache:
{
"version" => "1.2.3",
"targets" => {
"program" => {
"checksum" => "A1B2C3D4",
"command" => "13543518FE",
"deps" => [
{
"fname" => "program.o",
"checksum" => "87654321",
},
],
"user_deps" => [
{
"fname" => "lscript.ld",
"checksum" => "77551133",
},
],
},
"program.o" => {
"checksum" => "87654321",
"command" => "98765ABCD",
"deps" => [
{
"fname" => "program.c",
"checksum" => "456789ABC",
},
{
"fname" => "program.h",
"checksum" => "7979764643",
},
],
"user_deps" => [],
}
},
"directories" => {
"build" => true,
"build/one" => true,
"build/two" => true,
},
}
Constant Summary collapse
- PHONY_PREFIX =
Prefix for phony cache entries.
":PHONY:"
Class Method Summary collapse
-
.instance ⇒ Object
Access the singleton instance.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Access cache value.
-
#[]=(key, value) ⇒ Object
Assign cache value.
-
#cache_file ⇒ Object
Get the path to the cache file.
-
#clear ⇒ void
Remove the cache file.
-
#clear_checksum_cache! ⇒ void
Clear the cached file checksums.
-
#directories(install) ⇒ Array<String>
Return a list of directories which were created as a part of the build.
-
#initialize ⇒ Cache
constructor
Create a Cache object and load in the previous contents from the cache file.
-
#mkdir_p(path, options = {}) ⇒ void
Create any needed directory components for a build or install operation.
-
#register_build(targets, command, deps, env, options = {}) ⇒ void
Store cache information about target(s) built by a builder.
-
#remove_directory(directory) ⇒ void
Remove a directory from the cache.
-
#remove_target(target) ⇒ void
Remove a target from the cache.
-
#targets(install) ⇒ Array<String>
Return a list of targets that have been built or installed.
-
#up_to_date?(targets, command, deps, env, options = {}) ⇒ Boolean
Check if target(s) are up to date.
-
#write ⇒ void
Write the cache to disk.
Constructor Details
#initialize ⇒ Cache
Create a Cache object and load in the previous contents from the cache file.
66 67 68 |
# File 'lib/rscons/cache.rb', line 66 def initialize initialize! end |
Class Method Details
Instance Method Details
#[](key) ⇒ Object
Access cache value.
76 77 78 |
# File 'lib/rscons/cache.rb', line 76 def [](key) @cache[key] end |
#[]=(key, value) ⇒ Object
Assign cache value.
81 82 83 |
# File 'lib/rscons/cache.rb', line 81 def []=(key, value) @cache[key] = value end |
#cache_file ⇒ Object
Get the path to the cache file.
71 72 73 |
# File 'lib/rscons/cache.rb', line 71 def cache_file File.join(Rscons.application.build_dir, ".rsconscache") end |
#clear ⇒ void
This method returns an undefined value.
Remove the cache file.
88 89 90 91 |
# File 'lib/rscons/cache.rb', line 88 def clear FileUtils.rm_f(cache_file) initialize! end |
#clear_checksum_cache! ⇒ void
This method returns an undefined value.
Clear the cached file checksums.
96 97 98 |
# File 'lib/rscons/cache.rb', line 96 def clear_checksum_cache! @lookup_checksums = {} end |
#directories(install) ⇒ Array<String>
Return a list of directories which were created as a part of the build.
325 326 327 328 329 330 |
# File 'lib/rscons/cache.rb', line 325 def directories(install) install = !!install @cache["directories"].select do |key, d_install| d_install == install end.map(&:first) end |
#mkdir_p(path, options = {}) ⇒ void
This method returns an undefined value.
Create any needed directory components for a build or install operation.
Build directories will be removed if empty upon a “clean” operation. Install directories will be removed if empty upon an “uninstall” operation.
305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/rscons/cache.rb', line 305 def mkdir_p(path, = {}) parts = path.split(/[\\\/]/) parts.each_index do |i| next if parts[i] == "" subpath = File.join(*parts[0, i + 1]) unless File.exists?(subpath) FileUtils.mkdir_p(subpath) @cache["directories"][subpath] = !![:install] end end end |
#register_build(targets, command, deps, env, options = {}) ⇒ void
This method returns an undefined value.
Store cache information about target(s) built by a builder.
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/rscons/cache.rb', line 248 def register_build(targets, command, deps, env, = {}) Array(targets).each do |target| target_checksum = if [:side_effect] or Rscons.phony_target?(target) "" else calculate_checksum(target) end @cache["targets"][get_cache_key(target)] = { "command" => Digest::MD5.hexdigest(command.inspect), "checksum" => target_checksum, "deps" => deps.map do |dep| { "fname" => dep, "checksum" => lookup_checksum(dep), } end, "user_deps" => (env.get_user_deps(target) || []).map do |dep| { "fname" => dep, "checksum" => lookup_checksum(dep), } end, "install" => !![:install], } end end |
#remove_directory(directory) ⇒ void
This method returns an undefined value.
Remove a directory from the cache.
342 343 344 |
# File 'lib/rscons/cache.rb', line 342 def remove_directory(directory) @cache["directories"].delete(directory) end |
#remove_target(target) ⇒ void
This method returns an undefined value.
Remove a target from the cache.
335 336 337 |
# File 'lib/rscons/cache.rb', line 335 def remove_target(target) @cache["targets"].delete(target) end |
#targets(install) ⇒ Array<String>
Return a list of targets that have been built or installed.
284 285 286 287 288 289 |
# File 'lib/rscons/cache.rb', line 284 def targets(install) install = !!install @cache["targets"].select do |key, target| target["install"] == install end.map(&:first) end |
#up_to_date?(targets, command, deps, env, options = {}) ⇒ Boolean
Check if target(s) are up to date.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/rscons/cache.rb', line 144 def up_to_date?(targets, command, deps, env, = {}) Array(targets).each do |target| cache_key = get_cache_key(target) unless Rscons.phony_target?(target) # target file must exist on disk unless File.exists?(target) if [:debug] puts "Target #{target} needs rebuilding because it does not exist on disk" end return false end end # target must be registered in the cache unless @cache["targets"].has_key?(cache_key) if [:debug] puts "Target #{target} needs rebuilding because there is no cached build information for it" end return false end unless Rscons.phony_target?(target) # target must have the same checksum as when it was built last unless @cache["targets"][cache_key]["checksum"] == lookup_checksum(target) if [:debug] puts "Target #{target} needs rebuilding because it has been changed on disk since being built last" end return false end end # command used to build target must be identical unless @cache["targets"][cache_key]["command"] == Digest::MD5.hexdigest(command.inspect) if [:debug] puts "Target #{target} needs rebuilding because the command used to build it has changed" end return false end cached_deps = @cache["targets"][cache_key]["deps"] || [] cached_deps_fnames = cached_deps.map { |dc| dc["fname"] } if [:strict_deps] # depedencies passed in must exactly equal those in the cache unless deps == cached_deps_fnames if [:debug] 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" end return false end else # all dependencies passed in must exist in cache (but cache may have more) unless (Set.new(deps) - Set.new(cached_deps_fnames)).empty? if [:debug] puts "Target #{target} needs rebuilding because there are new dependencies" end return false end end # set of user dependencies must match user_deps = env.get_user_deps(target) || [] cached_user_deps = @cache["targets"][cache_key]["user_deps"] || [] cached_user_deps_fnames = cached_user_deps.map { |dc| dc["fname"] } unless user_deps == cached_user_deps_fnames if [:debug] puts "Target #{target} needs rebuilding because the set of user-specified dependency files has changed" end return false end # all cached dependencies must have their checksums match (cached_deps + cached_user_deps).each do |dep_cache| unless dep_cache["checksum"] == lookup_checksum(dep_cache["fname"]) if [:debug] puts "Target #{target} needs rebuilding because dependency file #{dep_cache["fname"]} has changed" end return false end end end true end |
#write ⇒ void
This method returns an undefined value.
Write the cache to disk.
103 104 105 106 107 108 109 |
# File 'lib/rscons/cache.rb', line 103 def write return unless Dir.exist?(File.dirname(cache_file)) @cache["version"] = VERSION File.open(cache_file, "w") do |fh| fh.puts(JSON.dump(@cache)) end end |