| ... | ... | @@ -241,33 +241,75 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 241 | 241 | ); |
| 242 | 242 | } |
| 243 | 243 | |
| 244 | | var options_dir = try b.cache_root.handle.makeOpenPath("options", .{}); |
| 245 | | defer options_dir.close(); |
| 246 | | |
| 247 | | const basename = self.hashContentsToFileName(); |
| 248 | | |
| 249 | | try options_dir.writeFile(&basename, self.contents.items); |
| 250 | | |
| 251 | | self.generated_file.path = try b.cache_root.join(b.allocator, &.{ "options", &basename }); |
| 252 | | } |
| 253 | | |
| 254 | | fn hashContentsToFileName(self: *OptionsStep) [64]u8 { |
| 255 | | // TODO update to use the cache system instead of this |
| 256 | | // This implementation is copied from `WriteFileStep.make` |
| 257 | | |
| 258 | | var hash = std.crypto.hash.blake2.Blake2b384.init(.{}); |
| 259 | | |
| 260 | | // Random bytes to make OptionsStep unique. Refresh this with |
| 261 | | // new random bytes when OptionsStep implementation is modified |
| 262 | | // in a non-backwards-compatible way. |
| 263 | | hash.update("yL0Ya4KkmcCjBlP8"); |
| 264 | | hash.update(self.contents.items); |
| 265 | | |
| 266 | | var digest: [48]u8 = undefined; |
| 267 | | hash.final(&digest); |
| 268 | | var hash_basename: [64]u8 = undefined; |
| 269 | | _ = fs.base64_encoder.encode(&hash_basename, &digest); |
| 270 | | return hash_basename; |
| 244 | const basename = "options.zig"; |
| 245 | |
| 246 | // Hash contents to file name. |
| 247 | var hash = b.cache.hash; |
| 248 | // Random bytes to make unique. Refresh this with new random bytes when |
| 249 | // implementation is modified in a non-backwards-compatible way. |
| 250 | hash.add(@as(u32, 0x38845ef8)); |
| 251 | hash.addBytes(self.contents.items); |
| 252 | const sub_path = "c" ++ fs.path.sep_str ++ hash.final() ++ fs.path.sep_str ++ basename; |
| 253 | |
| 254 | self.generated_file.path = try b.cache_root.join(b.allocator, &.{sub_path}); |
| 255 | |
| 256 | // Optimize for the hot path. Stat the file, and if it already exists, |
| 257 | // cache hit. |
| 258 | if (b.cache_root.handle.access(sub_path, .{})) |_| { |
| 259 | // This is the hot path, success. |
| 260 | step.result_cached = true; |
| 261 | return; |
| 262 | } else |outer_err| switch (outer_err) { |
| 263 | error.FileNotFound => { |
| 264 | const sub_dirname = fs.path.dirname(sub_path).?; |
| 265 | b.cache_root.handle.makePath(sub_dirname) catch |e| { |
| 266 | return step.fail("unable to make path '{}{s}': {s}", .{ |
| 267 | b.cache_root, sub_dirname, @errorName(e), |
| 268 | }); |
| 269 | }; |
| 270 | |
| 271 | const rand_int = std.crypto.random.int(u64); |
| 272 | const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ |
| 273 | std.Build.hex64(rand_int) ++ fs.path.sep_str ++ |
| 274 | basename; |
| 275 | const tmp_sub_path_dirname = fs.path.dirname(tmp_sub_path).?; |
| 276 | |
| 277 | b.cache_root.handle.makePath(tmp_sub_path_dirname) catch |err| { |
| 278 | return step.fail("unable to make temporary directory '{}{s}': {s}", .{ |
| 279 | b.cache_root, tmp_sub_path_dirname, @errorName(err), |
| 280 | }); |
| 281 | }; |
| 282 | |
| 283 | b.cache_root.handle.writeFile(tmp_sub_path, self.contents.items) catch |err| { |
| 284 | return step.fail("unable to write options to '{}{s}': {s}", .{ |
| 285 | b.cache_root, tmp_sub_path, @errorName(err), |
| 286 | }); |
| 287 | }; |
| 288 | |
| 289 | b.cache_root.handle.rename(tmp_sub_path, sub_path) catch |err| switch (err) { |
| 290 | error.PathAlreadyExists => { |
| 291 | // Other process beat us to it. Clean up the temp file. |
| 292 | b.cache_root.handle.deleteFile(tmp_sub_path) catch |e| { |
| 293 | try step.addError("warning: unable to delete temp file '{}{s}': {s}", .{ |
| 294 | b.cache_root, tmp_sub_path, @errorName(e), |
| 295 | }); |
| 296 | }; |
| 297 | step.result_cached = true; |
| 298 | return; |
| 299 | }, |
| 300 | else => { |
| 301 | return step.fail("unable to rename options from '{}{s}' to '{}{s}': {s}", .{ |
| 302 | b.cache_root, tmp_sub_path, |
| 303 | b.cache_root, sub_path, |
| 304 | @errorName(err), |
| 305 | }); |
| 306 | }, |
| 307 | }; |
| 308 | }, |
| 309 | else => |e| return step.fail("unable to access options file '{}{s}': {s}", .{ |
| 310 | b.cache_root, sub_path, @errorName(e), |
| 311 | }), |
| 312 | } |
| 271 | 313 | } |
| 272 | 314 | |
| 273 | 315 | const OptionArtifactArg = struct { |