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
- CACHE_FILE =
Name of the file to store cache information in
".rsconscache"
- PHONY_PREFIX =
Prefix for phony cache entries.
":PHONY:"
Class Method Summary collapse
-
.instance ⇒ Object
Access the singleton instance.
Instance Method Summary collapse
-
#clear ⇒ void
Remove the cache file.
-
#clear_checksum_cache! ⇒ void
Clear the cached file checksums.
-
#directories ⇒ 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.
-
#lookup_checksum(file) ⇒ String
Return a file’s checksum, or the previously calculated checksum for the same file.
-
#mkdir_p(path) ⇒ void
Make any needed directories and record the ones that are created for removal upon a “clean” operation.
-
#register_build(targets, command, deps, env) ⇒ void
Store cache information about target(s) built by a builder.
-
#targets ⇒ Array<String>
Return a list of targets that have been built.
-
#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.
69 70 71 |
# File 'lib/rscons/cache.rb', line 69 def initialize initialize! end |
Class Method Details
Instance Method Details
#clear ⇒ void
This method returns an undefined value.
Remove the cache file.
76 77 78 79 |
# File 'lib/rscons/cache.rb', line 76 def clear FileUtils.rm_f(CACHE_FILE) initialize! end |
#clear_checksum_cache! ⇒ void
This method returns an undefined value.
Clear the cached file checksums.
84 85 86 |
# File 'lib/rscons/cache.rb', line 84 def clear_checksum_cache! @lookup_checksums = {} end |
#directories ⇒ Array<String>
Return a list of directories which were created as a part of the build.
281 282 283 |
# File 'lib/rscons/cache.rb', line 281 def directories @cache["directories"].keys end |
#lookup_checksum(file) ⇒ String
Return a file’s checksum, or the previously calculated checksum for the same file.
291 292 293 |
# File 'lib/rscons/cache.rb', line 291 def lookup_checksum(file) @lookup_checksums[file] || calculate_checksum(file) end |
#mkdir_p(path) ⇒ void
This method returns an undefined value.
Make any needed directories and record the ones that are created for removal upon a “clean” operation.
265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/rscons/cache.rb', line 265 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] = true end end end |
#register_build(targets, command, deps, env) ⇒ void
This method returns an undefined value.
Store cache information about target(s) built by a builder.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/rscons/cache.rb', line 230 def register_build(targets, command, deps, env) Array(targets).each do |target| target_checksum = Rscons.phony_target?(target) ? "" : calculate_checksum(target) @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, } end end |
#targets ⇒ Array<String>
Return a list of targets that have been built.
255 256 257 |
# File 'lib/rscons/cache.rb', line 255 def targets @cache["targets"].keys end |
#up_to_date?(targets, command, deps, env, options = {}) ⇒ Boolean
Check if target(s) are up to date.
131 132 133 134 135 136 137 138 139 140 141 142 143 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 |
# File 'lib/rscons/cache.rb', line 131 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.
91 92 93 94 95 96 |
# File 'lib/rscons/cache.rb', line 91 def write @cache["version"] = VERSION File.open(CACHE_FILE, "w") do |fh| fh.puts(JSON.dump(@cache)) end end |