| 1 | const UpdateSourceFiles = @This(); |
| 2 | |
| 3 | const std = @import("std"); |
| 4 | const Io = std.Io; |
| 5 | const Path = std.Build.Cache.Path; |
| 6 | const Configuration = std.Build.Configuration; |
| 7 | |
| 8 | const Step = @import("../Step.zig"); |
| 9 | const Maker = @import("../../Maker.zig"); |
| 10 | |
| 11 | pub fn make( |
| 12 | usf: *UpdateSourceFiles, |
| 13 | step_index: Configuration.Step.Index, |
| 14 | maker: *Maker, |
| 15 | progress_node: std.Progress.Node, |
| 16 | ) Step.ExtendedMakeError!void { |
| 17 | _ = usf; |
| 18 | const graph = maker.graph; |
| 19 | const arena = maker.graph.arena; // TODO don't leak into process arena |
| 20 | const io = graph.io; |
| 21 | const step = maker.stepByIndex(step_index); |
| 22 | const conf = &maker.scanned_config.configuration; |
| 23 | const conf_step = step_index.ptr(conf); |
| 24 | const conf_usf = conf_step.extended.get(conf.extra).update_source_files; |
| 25 | const build_root = graph.build_root_directory; |
| 26 | |
| 27 | if (conf_step.owner != .root) |
| 28 | return step.fail(maker, "non-root package attempted to update its source files", .{}); |
| 29 | |
| 30 | var any_miss = false; |
| 31 | |
| 32 | progress_node.setEstimatedTotalItems(conf_usf.embeds.slice.len + conf_usf.copies.slice.len); |
| 33 | |
| 34 | step.clearWatchInputs(maker); |
| 35 | |
| 36 | for (conf_usf.embeds.slice) |*embed| { |
| 37 | const dest_path: Path = .{ |
| 38 | .root_dir = build_root, |
| 39 | .sub_path = embed.sub_path.slice(conf), |
| 40 | }; |
| 41 | if (Io.Dir.path.dirname(dest_path.sub_path)) |dirname| { |
| 42 | const dirname_path: Path = .{ |
| 43 | .root_dir = build_root, |
| 44 | .sub_path = dirname, |
| 45 | }; |
| 46 | dirname_path.root_dir.handle.createDirPath(io, dirname_path.sub_path) catch |err| |
| 47 | return step.fail(maker, "failed creating path {f}: {t}", .{ dirname_path, err }); |
| 48 | } |
| 49 | dest_path.root_dir.handle.writeFile(io, .{ |
| 50 | .sub_path = dest_path.sub_path, |
| 51 | .data = embed.contents.slice(conf), |
| 52 | }) catch |err| return step.fail(maker, "failed writing file {f}: {t}", .{ dest_path, err }); |
| 53 | any_miss = true; |
| 54 | progress_node.completeOne(); |
| 55 | } |
| 56 | |
| 57 | for (conf_usf.copies.slice) |*copy| { |
| 58 | const dest_path: Path = .{ |
| 59 | .root_dir = build_root, |
| 60 | .sub_path = copy.sub_path.slice(conf), |
| 61 | }; |
| 62 | if (Io.Dir.path.dirname(dest_path.sub_path)) |dirname| { |
| 63 | const dirname_path: Path = .{ |
| 64 | .root_dir = build_root, |
| 65 | .sub_path = dirname, |
| 66 | }; |
| 67 | dirname_path.root_dir.handle.createDirPath(io, dirname_path.sub_path) catch |err| |
| 68 | return step.fail(maker, "failed creating path {f}: {t}", .{ dirname_path, err }); |
| 69 | } |
| 70 | const src_lazy_path = copy.src_file.get(conf); |
| 71 | const source_path = try maker.resolveLazyPath(arena, src_lazy_path, step_index); |
| 72 | try step.addWatchInput(maker, arena, src_lazy_path); |
| 73 | |
| 74 | const prev_status = source_path.root_dir.handle.updateFile( |
| 75 | io, |
| 76 | source_path.sub_path, |
| 77 | dest_path.root_dir.handle, |
| 78 | dest_path.sub_path, |
| 79 | .{}, |
| 80 | ) catch |err| return step.fail(maker, "failed updating file from {f} to {f}: {t}", .{ |
| 81 | source_path, dest_path, err, |
| 82 | }); |
| 83 | any_miss = any_miss or prev_status == .stale; |
| 84 | progress_node.completeOne(); |
| 85 | } |
| 86 | |
| 87 | step.result_cached = !any_miss; |
| 88 | } |