| ... | ... | @@ -40,6 +40,22 @@ pub const Directory = struct { |
| 40 | 40 | .include_extensions = if (opts.include_extensions) |incs| b.dupeStrings(incs) else null, |
| 41 | 41 | }; |
| 42 | 42 | } |
| 43 | |
| 44 | pub fn pathIncluded(opts: Options, path: []const u8) bool { |
| 45 | for (opts.exclude_extensions) |ext| { |
| 46 | if (std.mem.endsWith(u8, path, ext)) |
| 47 | return false; |
| 48 | } |
| 49 | if (opts.include_extensions) |incs| { |
| 50 | for (incs) |inc| { |
| 51 | if (std.mem.endsWith(u8, path, inc)) |
| 52 | return true; |
| 53 | } else { |
| 54 | return false; |
| 55 | } |
| 56 | } |
| 57 | return true; |
| 58 | } |
| 43 | 59 | }; |
| 44 | 60 | }; |
| 45 | 61 | |
| ... | ... | @@ -158,7 +174,10 @@ fn maybeUpdateName(write_file: *WriteFile) void { |
| 158 | 174 | fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 159 | 175 | _ = prog_node; |
| 160 | 176 | const b = step.owner; |
| 177 | const arena = b.allocator; |
| 178 | const gpa = arena; |
| 161 | 179 | const write_file: *WriteFile = @fieldParentPtr("step", step); |
| 180 | step.clearWatchInputs(); |
| 162 | 181 | |
| 163 | 182 | // The cache is used here not really as a way to speed things up - because writing |
| 164 | 183 | // the data to a file would probably be very fast - but as a way to find a canonical |
| ... | ... | @@ -173,29 +192,67 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 173 | 192 | // Random bytes to make WriteFile unique. Refresh this with |
| 174 | 193 | // new random bytes when WriteFile implementation is modified |
| 175 | 194 | // in a non-backwards-compatible way. |
| 176 | | man.hash.add(@as(u32, 0xd767ee59)); |
| 195 | man.hash.add(@as(u32, 0xc2a287d0)); |
| 177 | 196 | |
| 178 | 197 | for (write_file.files.items) |file| { |
| 179 | 198 | man.hash.addBytes(file.sub_path); |
| 199 | |
| 180 | 200 | switch (file.contents) { |
| 181 | 201 | .bytes => |bytes| { |
| 182 | 202 | man.hash.addBytes(bytes); |
| 183 | 203 | }, |
| 184 | | .copy => |file_source| { |
| 185 | | _ = try man.addFile(file_source.getPath2(b, step), null); |
| 204 | .copy => |lazy_path| { |
| 205 | const path = lazy_path.getPath3(b, step); |
| 206 | _ = try man.addFilePath(path, null); |
| 207 | try step.addWatchInput(lazy_path); |
| 186 | 208 | }, |
| 187 | 209 | } |
| 188 | 210 | } |
| 189 | | for (write_file.directories.items) |dir| { |
| 190 | | man.hash.addBytes(dir.source.getPath2(b, step)); |
| 211 | |
| 212 | const open_dir_cache = try arena.alloc(fs.Dir, write_file.directories.items.len); |
| 213 | var open_dirs_count: usize = 0; |
| 214 | defer closeDirs(open_dir_cache[0..open_dirs_count]); |
| 215 | |
| 216 | for (write_file.directories.items, open_dir_cache) |dir, *open_dir_cache_elem| { |
| 191 | 217 | man.hash.addBytes(dir.sub_path); |
| 192 | 218 | for (dir.options.exclude_extensions) |ext| man.hash.addBytes(ext); |
| 193 | 219 | if (dir.options.include_extensions) |incs| for (incs) |inc| man.hash.addBytes(inc); |
| 220 | |
| 221 | const need_derived_inputs = try step.addDirectoryWatchInput(dir.source); |
| 222 | const src_dir_path = dir.source.getPath3(b, step); |
| 223 | |
| 224 | var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { |
| 225 | return step.fail("unable to open source directory '{}': {s}", .{ |
| 226 | src_dir_path, @errorName(err), |
| 227 | }); |
| 228 | }; |
| 229 | open_dir_cache_elem.* = src_dir; |
| 230 | open_dirs_count += 1; |
| 231 | |
| 232 | var it = try src_dir.walk(gpa); |
| 233 | defer it.deinit(); |
| 234 | while (try it.next()) |entry| { |
| 235 | if (!dir.options.pathIncluded(entry.path)) continue; |
| 236 | |
| 237 | switch (entry.kind) { |
| 238 | .directory => { |
| 239 | if (need_derived_inputs) { |
| 240 | const entry_path = try src_dir_path.join(arena, entry.path); |
| 241 | try step.addDirectoryWatchInputFromPath(entry_path); |
| 242 | } |
| 243 | }, |
| 244 | .file => { |
| 245 | const entry_path = try src_dir_path.join(arena, entry.path); |
| 246 | _ = try man.addFilePath(entry_path, null); |
| 247 | }, |
| 248 | else => continue, |
| 249 | } |
| 250 | } |
| 194 | 251 | } |
| 195 | 252 | |
| 196 | 253 | if (try step.cacheHit(&man)) { |
| 197 | 254 | const digest = man.final(); |
| 198 | | write_file.generated_directory.path = try b.cache_root.join(b.allocator, &.{ "o", &digest }); |
| 255 | write_file.generated_directory.path = try b.cache_root.join(arena, &.{ "o", &digest }); |
| 199 | 256 | step.result_cached = true; |
| 200 | 257 | return; |
| 201 | 258 | } |
| ... | ... | @@ -203,7 +260,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 203 | 260 | const digest = man.final(); |
| 204 | 261 | const cache_path = "o" ++ fs.path.sep_str ++ digest; |
| 205 | 262 | |
| 206 | | write_file.generated_directory.path = try b.cache_root.join(b.allocator, &.{ "o", &digest }); |
| 263 | write_file.generated_directory.path = try b.cache_root.join(arena, &.{ "o", &digest }); |
| 207 | 264 | |
| 208 | 265 | var cache_dir = b.cache_root.handle.makeOpenPath(cache_path, .{}) catch |err| { |
| 209 | 266 | return step.fail("unable to make path '{}{s}': {s}", .{ |
| ... | ... | @@ -256,8 +313,9 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 256 | 313 | }, |
| 257 | 314 | } |
| 258 | 315 | } |
| 259 | | for (write_file.directories.items) |dir| { |
| 260 | | const full_src_dir_path = dir.source.getPath2(b, step); |
| 316 | |
| 317 | for (write_file.directories.items, open_dir_cache) |dir, already_open_dir| { |
| 318 | const src_dir_path = dir.source.getPath3(b, step); |
| 261 | 319 | const dest_dirname = dir.sub_path; |
| 262 | 320 | |
| 263 | 321 | if (dest_dirname.len != 0) { |
| ... | ... | @@ -268,44 +326,25 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 268 | 326 | }; |
| 269 | 327 | } |
| 270 | 328 | |
| 271 | | var src_dir = b.build_root.handle.openDir(full_src_dir_path, .{ .iterate = true }) catch |err| { |
| 272 | | return step.fail("unable to open source directory '{s}': {s}", .{ |
| 273 | | full_src_dir_path, @errorName(err), |
| 274 | | }); |
| 275 | | }; |
| 276 | | defer src_dir.close(); |
| 329 | var it = try already_open_dir.walk(gpa); |
| 330 | defer it.deinit(); |
| 331 | while (try it.next()) |entry| { |
| 332 | if (!dir.options.pathIncluded(entry.path)) continue; |
| 277 | 333 | |
| 278 | | var it = try src_dir.walk(b.allocator); |
| 279 | | next_entry: while (try it.next()) |entry| { |
| 280 | | for (dir.options.exclude_extensions) |ext| { |
| 281 | | if (std.mem.endsWith(u8, entry.path, ext)) continue :next_entry; |
| 282 | | } |
| 283 | | if (dir.options.include_extensions) |incs| { |
| 284 | | for (incs) |inc| { |
| 285 | | if (std.mem.endsWith(u8, entry.path, inc)) break; |
| 286 | | } else { |
| 287 | | continue :next_entry; |
| 288 | | } |
| 289 | | } |
| 290 | | const full_src_entry_path = b.pathJoin(&.{ full_src_dir_path, entry.path }); |
| 334 | const src_entry_path = try src_dir_path.join(arena, entry.path); |
| 291 | 335 | const dest_path = b.pathJoin(&.{ dest_dirname, entry.path }); |
| 292 | 336 | switch (entry.kind) { |
| 293 | 337 | .directory => try cache_dir.makePath(dest_path), |
| 294 | 338 | .file => { |
| 295 | 339 | const prev_status = fs.Dir.updateFile( |
| 296 | | cwd, |
| 297 | | full_src_entry_path, |
| 340 | src_entry_path.root_dir.handle, |
| 341 | src_entry_path.sub_path, |
| 298 | 342 | cache_dir, |
| 299 | 343 | dest_path, |
| 300 | 344 | .{}, |
| 301 | 345 | ) catch |err| { |
| 302 | | return step.fail("unable to update file from '{s}' to '{}{s}{c}{s}': {s}", .{ |
| 303 | | full_src_entry_path, |
| 304 | | b.cache_root, |
| 305 | | cache_path, |
| 306 | | fs.path.sep, |
| 307 | | dest_path, |
| 308 | | @errorName(err), |
| 346 | return step.fail("unable to update file from '{}' to '{}{s}{c}{s}': {s}", .{ |
| 347 | src_entry_path, b.cache_root, cache_path, fs.path.sep, dest_path, @errorName(err), |
| 309 | 348 | }); |
| 310 | 349 | }; |
| 311 | 350 | _ = prev_status; |
| ... | ... | @@ -317,3 +356,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void { |
| 317 | 356 | |
| 318 | 357 | try step.writeManifest(&man); |
| 319 | 358 | } |
| 359 | |
| 360 | fn closeDirs(dirs: []fs.Dir) void { |
| 361 | for (dirs) |*d| d.close(); |
| 362 | } |