@@ -47,31 +47,30 @@ pub struct SpawnResult {
4747 pub duration : Duration ,
4848}
4949
50- /// Tracking result from a spawned process for caching
50+ /// Tracked file accesses from fspy.
51+ /// Only populated when fspy tracking is enabled (includes_auto is true).
5152#[ derive( Default , Debug ) ]
52- pub struct SpawnTrackResult {
53- /// captured stdout/stderr
54- pub std_outputs : Vec < StdOutput > ,
55-
53+ pub struct TrackedPathAccesses {
5654 /// Tracked path reads
5755 pub path_reads : HashMap < RelativePathBuf , PathRead > ,
5856
5957 /// Tracked path writes
6058 pub path_writes : HashMap < RelativePathBuf , PathWrite > ,
6159}
6260
63- /// Spawn a command with file system tracking via fspy.
61+ /// Spawn a command with optional file system tracking via fspy.
6462///
65- /// Returns the execution result including captured outputs, exit status,
66- /// and tracked file accesses.
63+ /// Returns the execution result including exit status and duration.
6764///
6865/// - `on_output` is called in real-time as stdout/stderr data arrives.
69- /// - `track_result` if provided, will be populated with captured outputs and path accesses for caching. If `None`, tracking is disabled.
66+ /// - `std_outputs` if provided, will be populated with captured outputs for cache replay.
67+ /// - `path_accesses` if provided, fspy will be used to track file accesses. If `None`, fspy is disabled.
7068pub async fn spawn_with_tracking < F > (
7169 spawn_command : & SpawnCommand ,
7270 workspace_root : & AbsolutePath ,
7371 mut on_output : F ,
74- track_result : Option < & mut SpawnTrackResult > ,
72+ std_outputs : Option < & mut Vec < StdOutput > > ,
73+ path_accesses : Option < & mut TrackedPathAccesses > ,
7574) -> anyhow:: Result < SpawnResult >
7675where
7776 F : FnMut ( OutputKind , BString ) ,
@@ -82,36 +81,35 @@ where
8281 cmd. current_dir ( & * spawn_command. cwd ) ;
8382 cmd. stdout ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) ;
8483
85- /// The tracking state of the spawned process
86- enum TrackingState < ' a > {
87- /// Tacking is enabled, with the tracked child and result reference
88- Enabled ( fspy:: TrackedChild , & ' a mut SpawnTrackResult ) ,
84+ /// The tracking state of the spawned process.
85+ /// Determined by whether path_accesses is Some (fspy enabled) or None (fspy disabled).
86+ enum TrackingState {
87+ /// fspy tracking is enabled
88+ FspyEnabled ( fspy:: TrackedChild ) ,
8989
90- /// Tracking is disabled, with the tokio child process
91- Disabled ( tokio:: process:: Child ) ,
90+ /// fspy tracking is disabled, using plain tokio process
91+ FspyDisabled ( tokio:: process:: Child ) ,
9292 }
9393
94- let mut tracking_state = if let Some ( track_result ) = track_result {
95- // track_result is Some. Spawn with tracking enabled
96- TrackingState :: Enabled ( cmd. spawn ( ) . await ?, track_result )
94+ let mut tracking_state = if path_accesses . is_some ( ) {
95+ // path_accesses is Some, spawn with fspy tracking enabled
96+ TrackingState :: FspyEnabled ( cmd. spawn ( ) . await ?)
9797 } else {
98- // Spawn without tracking
99- TrackingState :: Disabled ( cmd. into_tokio_command ( ) . spawn ( ) ?)
98+ // path_accesses is None, spawn without fspy
99+ TrackingState :: FspyDisabled ( cmd. into_tokio_command ( ) . spawn ( ) ?)
100100 } ;
101101
102102 let mut child_stdout = match & mut tracking_state {
103- TrackingState :: Enabled ( tracked_child, _ ) => tracked_child. stdout . take ( ) . unwrap ( ) ,
104- TrackingState :: Disabled ( tokio_child) => tokio_child. stdout . take ( ) . unwrap ( ) ,
103+ TrackingState :: FspyEnabled ( tracked_child) => tracked_child. stdout . take ( ) . unwrap ( ) ,
104+ TrackingState :: FspyDisabled ( tokio_child) => tokio_child. stdout . take ( ) . unwrap ( ) ,
105105 } ;
106106 let mut child_stderr = match & mut tracking_state {
107- TrackingState :: Enabled ( tracked_child, _ ) => tracked_child. stderr . take ( ) . unwrap ( ) ,
108- TrackingState :: Disabled ( tokio_child) => tokio_child. stderr . take ( ) . unwrap ( ) ,
107+ TrackingState :: FspyEnabled ( tracked_child) => tracked_child. stderr . take ( ) . unwrap ( ) ,
108+ TrackingState :: FspyDisabled ( tokio_child) => tokio_child. stderr . take ( ) . unwrap ( ) ,
109109 } ;
110110
111- let mut outputs = match & mut tracking_state {
112- TrackingState :: Enabled ( _, track_result) => Some ( & mut track_result. std_outputs ) ,
113- TrackingState :: Disabled ( _) => None ,
114- } ;
111+ // Output capturing is independent of fspy tracking
112+ let mut outputs = std_outputs;
115113 let mut stdout_buf = [ 0u8 ; 8192 ] ;
116114 let mut stderr_buf = [ 0u8 ; 8192 ] ;
117115 let mut stdout_done = false ;
@@ -156,22 +154,20 @@ where
156154 }
157155 }
158156
159- let ( termination, track_result) = match tracking_state {
160- TrackingState :: Enabled ( tracked_child, track_result) => {
161- ( tracked_child. wait_handle . await ?, track_result)
162- }
163- TrackingState :: Disabled ( mut tokio_child) => {
164- return Ok ( SpawnResult {
165- exit_status : tokio_child. wait ( ) . await ?,
166- duration : start. elapsed ( ) ,
167- } ) ;
157+ let termination = match tracking_state {
158+ TrackingState :: FspyEnabled ( tracked_child) => Some ( tracked_child. wait_handle . await ?) ,
159+ TrackingState :: FspyDisabled ( mut tokio_child) => {
160+ let exit_status = tokio_child. wait ( ) . await ?;
161+ return Ok ( SpawnResult { exit_status, duration : start. elapsed ( ) } ) ;
168162 }
169163 } ;
170164 let duration = start. elapsed ( ) ;
171165
172- // Process path accesses
173- let path_reads = & mut track_result. path_reads ;
174- let path_writes = & mut track_result. path_writes ;
166+ // Process path accesses from fspy (only when fspy was enabled)
167+ let termination = termination. expect ( "fspy enabled but no termination" ) ;
168+ let path_accesses = path_accesses. expect ( "fspy enabled but no path_accesses" ) ;
169+ let path_reads = & mut path_accesses. path_reads ;
170+ let path_writes = & mut path_accesses. path_writes ;
175171
176172 for access in termination. path_accesses . iter ( ) {
177173 let relative_path = access. path . strip_path_prefix ( workspace_root, |strip_result| {
0 commit comments