authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-10 17:14:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-12 00:14:08-07:00
log2e429697865ebcadc001a7d167ef964b3f1393a2
tree77ca360314e383cf737286577334e330e3ec0b51
parent6fcb1897d263130b5ff7a25dd12f027bddd75b2f

std.Build.Step.Run: integrate with --watch


2 files changed, 44 insertions(+), 4 deletions(-)

lib/std/Build/Step.zig+40
...@@ -582,11 +582,26 @@ pub fn allocPrintCmd2(...@@ -582,11 +582,26 @@ pub fn allocPrintCmd2(
582 return buf.toOwnedSlice(arena);582 return buf.toOwnedSlice(arena);
583}583}
584584
585/// Prefer `cacheHitAndWatch` unless you already added watch inputs
586/// separately from using the cache system.
585pub fn cacheHit(s: *Step, man: *Build.Cache.Manifest) !bool {587pub fn cacheHit(s: *Step, man: *Build.Cache.Manifest) !bool {
586 s.result_cached = man.hit() catch |err| return failWithCacheError(s, man, err);588 s.result_cached = man.hit() catch |err| return failWithCacheError(s, man, err);
587 return s.result_cached;589 return s.result_cached;
588}590}
589591
592/// Clears previous watch inputs, if any, and then populates watch inputs from
593/// the full set of files picked up by the cache manifest.
594///
595/// Must be accompanied with `writeManifestAndWatch`.
596pub fn cacheHitAndWatch(s: *Step, man: *Build.Cache.Manifest) !bool {
597 const is_hit = man.hit() catch |err| return failWithCacheError(s, man, err);
598 s.result_cached = is_hit;
599 // The above call to hit() populates the manifest with files, so in case of
600 // a hit, we need to populate watch inputs.
601 if (is_hit) try setWatchInputsFromManifest(s, man);
602 return is_hit;
603}
604
590fn failWithCacheError(s: *Step, man: *const Build.Cache.Manifest, err: anyerror) anyerror {605fn failWithCacheError(s: *Step, man: *const Build.Cache.Manifest, err: anyerror) anyerror {
591 const i = man.failed_file_index orelse return err;606 const i = man.failed_file_index orelse return err;
592 const pp = man.files.keys()[i].prefixed_path;607 const pp = man.files.keys()[i].prefixed_path;
...@@ -594,6 +609,8 @@ fn failWithCacheError(s: *Step, man: *const Build.Cache.Manifest, err: anyerror)...@@ -594,6 +609,8 @@ fn failWithCacheError(s: *Step, man: *const Build.Cache.Manifest, err: anyerror)
594 return s.fail("{s}: {s}/{s}", .{ @errorName(err), prefix, pp.sub_path });609 return s.fail("{s}: {s}/{s}", .{ @errorName(err), prefix, pp.sub_path });
595}610}
596611
612/// Prefer `writeManifestAndWatch` unless you already added watch inputs
613/// separately from using the cache system.
597pub fn writeManifest(s: *Step, man: *Build.Cache.Manifest) !void {614pub fn writeManifest(s: *Step, man: *Build.Cache.Manifest) !void {
598 if (s.test_results.isSuccess()) {615 if (s.test_results.isSuccess()) {
599 man.writeManifest() catch |err| {616 man.writeManifest() catch |err| {
...@@ -602,6 +619,29 @@ pub fn writeManifest(s: *Step, man: *Build.Cache.Manifest) !void {...@@ -602,6 +619,29 @@ pub fn writeManifest(s: *Step, man: *Build.Cache.Manifest) !void {
602 }619 }
603}620}
604621
622/// Clears previous watch inputs, if any, and then populates watch inputs from
623/// the full set of files picked up by the cache manifest.
624///
625/// Must be accompanied with `cacheHitAndWatch`.
626pub fn writeManifestAndWatch(s: *Step, man: *Build.Cache.Manifest) !void {
627 try writeManifest(s, man);
628 try setWatchInputsFromManifest(s, man);
629}
630
631fn setWatchInputsFromManifest(s: *Step, man: *Build.Cache.Manifest) !void {
632 const arena = s.owner.allocator;
633 const prefixes = man.cache.prefixes();
634 clearWatchInputs(s);
635 for (man.files.keys()) |file| {
636 // The file path data is freed when the cache manifest is cleaned up at the end of `make`.
637 const sub_path = try arena.dupe(u8, file.prefixed_path.sub_path);
638 try addWatchInputFromPath(s, .{
639 .root_dir = prefixes[file.prefixed_path.prefix],
640 .sub_path = std.fs.path.dirname(sub_path) orelse "",
641 }, std.fs.path.basename(sub_path));
642 }
643}
644
605/// For steps that have a single input that never changes when re-running `make`.645/// For steps that have a single input that never changes when re-running `make`.
606pub fn singleUnchangingWatchInput(step: *Step, lazy_path: Build.LazyPath) Allocator.Error!void {646pub fn singleUnchangingWatchInput(step: *Step, lazy_path: Build.LazyPath) Allocator.Error!void {
607 if (!step.inputs.populated()) try step.addWatchInput(lazy_path);647 if (!step.inputs.populated()) try step.addWatchInput(lazy_path);
lib/std/Build/Step/Run.zig+4-4
...@@ -615,7 +615,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void {...@@ -615,7 +615,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void {
615 // On Windows we don't have rpaths so we have to add .dll search paths to PATH615 // On Windows we don't have rpaths so we have to add .dll search paths to PATH
616 run.addPathForDynLibs(artifact);616 run.addPathForDynLibs(artifact);
617 }617 }
618 const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?; // the path is guaranteed to be set618 const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?;
619619
620 try argv_list.append(file_path);620 try argv_list.append(file_path);
621621
...@@ -665,7 +665,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void {...@@ -665,7 +665,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void {
665 _ = try man.addFile(lazy_path.getPath2(b, step), null);665 _ = try man.addFile(lazy_path.getPath2(b, step), null);
666 }666 }
667667
668 if (!has_side_effects and try step.cacheHit(&man)) {668 if (!has_side_effects and try step.cacheHitAndWatch(&man)) {
669 // cache hit, skip running command669 // cache hit, skip running command
670 const digest = man.final();670 const digest = man.final();
671671
...@@ -719,7 +719,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void {...@@ -719,7 +719,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void {
719 }719 }
720720
721 try runCommand(run, argv_list.items, has_side_effects, output_dir_path, prog_node);721 try runCommand(run, argv_list.items, has_side_effects, output_dir_path, prog_node);
722 if (!has_side_effects) try step.writeManifest(&man);722 if (!has_side_effects) try step.writeManifestAndWatch(&man);
723 return;723 return;
724 };724 };
725725
...@@ -795,7 +795,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void {...@@ -795,7 +795,7 @@ fn make(step: *Step, prog_node: std.Progress.Node) !void {
795 };795 };
796 }796 }
797797
798 if (!has_side_effects) try step.writeManifest(&man);798 if (!has_side_effects) try step.writeManifestAndWatch(&man);
799799
800 try populateGeneratedPaths(800 try populateGeneratedPaths(
801 arena,801 arena,