@@ -34,7 +34,7 @@ fn lstat_mtime_ns(p: &Path) -> i64 {
3434 Ok ( m) => m
3535 . mtime ( )
3636 . saturating_mul ( 1_000_000_000 )
37- . saturating_add ( m. mtime_nsec ( ) as i64 ) ,
37+ . saturating_add ( m. mtime_nsec ( ) ) ,
3838 Err ( _) => 0 ,
3939 }
4040}
@@ -65,7 +65,7 @@ fn is_already_equal(root: &Path, entry: &Entry) -> bool {
6565 let mt = meta
6666 . mtime ( )
6767 . saturating_mul ( 1_000_000_000 )
68- . saturating_add ( meta. mtime_nsec ( ) as i64 ) ;
68+ . saturating_add ( meta. mtime_nsec ( ) ) ;
6969 if mt == entry. mtime {
7070 return true ;
7171 }
@@ -116,10 +116,8 @@ pub fn apply_symlink(root: &Path, entry: &Entry) -> Result<()> {
116116 if let Some ( parent) = full. parent ( ) {
117117 fs:: create_dir_all ( parent) ?;
118118 }
119- if fs:: symlink_metadata ( & full) . is_ok ( ) {
120- if fs:: remove_file ( & full) . is_err ( ) {
121- let _ = fs:: remove_dir_all ( & full) ;
122- }
119+ if fs:: symlink_metadata ( & full) . is_ok ( ) && fs:: remove_file ( & full) . is_err ( ) {
120+ let _ = fs:: remove_dir_all ( & full) ;
123121 }
124122 let target = entry
125123 . link_target
@@ -716,6 +714,17 @@ impl Suppression {
716714// Live mode: a generic bidirectional loop driven by tokio::select.
717715// ─────────────────────────────────────────────────────────────
718716
717+ /// Static per-session configuration shared between `live_loop`,
718+ /// `handle_incoming`, and helpers. Pulled out into a struct so those
719+ /// signatures stay narrow.
720+ pub struct SessionCtx {
721+ pub root : PathBuf ,
722+ pub mode : SyncMode ,
723+ pub compress : bool ,
724+ pub is_client : bool ,
725+ pub ignores : Arc < IgnoreStack > ,
726+ }
727+
719728fn directions ( mode : SyncMode , is_client : bool ) -> ( bool , bool ) {
720729 match ( mode, is_client) {
721730 ( SyncMode :: Both , _) => ( true , true ) ,
@@ -727,13 +736,9 @@ fn directions(mode: SyncMode, is_client: bool) -> (bool, bool) {
727736}
728737
729738pub async fn live_loop < R , W > (
730- root : PathBuf ,
739+ ctx : SessionCtx ,
731740 mut reader : R ,
732741 writer : Arc < Mutex < W > > ,
733- mode : SyncMode ,
734- compress : bool ,
735- is_client : bool ,
736- ignores : Arc < IgnoreStack > ,
737742 // Carried over from the init-sync apply phase: marks for every file we
738743 // wrote during initial sync stay valid here (TTL 60s) so the watcher's
739744 // FSEvents/inotify echoes for those writes are filtered, not bounced
@@ -749,7 +754,7 @@ where
749754 R : AsyncRead + AsyncReadExt + Unpin + Send + ' static ,
750755 W : AsyncWrite + AsyncWriteExt + Unpin + Send ,
751756{
752- let ( send_local, apply_remote) = directions ( mode, is_client) ;
757+ let ( send_local, apply_remote) = directions ( ctx . mode , ctx . is_client ) ;
753758
754759 // Dedicated reader task → channel. read_exact is not cancel-safe in select!.
755760 let ( msg_tx, mut msg_rx) =
@@ -785,7 +790,7 @@ where
785790 _ = & mut sigint => {
786791 tracing:: info!( "ctrl+c — closing" ) ;
787792 let mut w = writer. lock( ) . await ;
788- let _ = write_message( & mut * w, & Message :: Bye , compress) . await ;
793+ let _ = write_message( & mut * w, & Message :: Bye , ctx . compress) . await ;
789794 break ;
790795 }
791796
@@ -796,10 +801,10 @@ where
796801 // Per-op apply errors are non-fatal — log and
797802 // continue. Connection-level failures appear as
798803 // Err from the reader task (the next arm).
799- if let Err ( e) = handle_incoming( & root , m, & suppress, & pending, compress , & writer, apply_remote, Some ( & ignores ) , is_client ) . await {
804+ if let Err ( e) = handle_incoming( & ctx , m, & suppress, & pending, & writer, apply_remote) . await {
800805 tracing:: warn!( "apply failed: {}" , e) ;
801806 let mut w = writer. lock( ) . await ;
802- let _ = write_message( & mut * w, & Message :: Error ( format!( "{e}" ) ) , compress) . await ;
807+ let _ = write_message( & mut * w, & Message :: Error ( format!( "{e}" ) ) , ctx . compress) . await ;
803808 }
804809 }
805810 Some ( Err ( e) ) => {
@@ -813,7 +818,7 @@ where
813818 ev = event_rx. recv( ) => {
814819 let Some ( events) = ev else { break } ;
815820 if send_local {
816- forward_local_events( & root, events, & writer, compress, & suppress, is_client) . await ?;
821+ forward_local_events( & ctx . root, events, & writer, ctx . compress, & suppress, ctx . is_client) . await ?;
817822 }
818823 }
819824 }
@@ -823,32 +828,26 @@ where
823828 Ok ( ( ) )
824829}
825830
826- /// True if `ignores` rejects this path. `None` means "no filter".
827- fn ignored ( ignores : Option < & IgnoreStack > , rel : & Path , is_dir : bool ) -> bool {
828- match ignores {
829- Some ( s) => s. is_ignored_rel ( rel, is_dir) ,
830- None => false ,
831- }
832- }
833-
834831pub async fn handle_incoming < W > (
835- root : & Path ,
832+ ctx : & SessionCtx ,
836833 msg : Message ,
837834 suppress : & Suppression ,
838835 pending : & Pending ,
839- compress : bool ,
840836 writer : & Arc < Mutex < W > > ,
841837 apply_remote : bool ,
842- ignores : Option < & IgnoreStack > ,
843- is_client : bool ,
844838) -> Result < ( ) >
845839where
846840 W : AsyncWriteExt + Unpin ,
847841{
842+ // Locals so the existing body reads naturally and we don't repeat
843+ // `ctx.foo` access dozens of times. Cheap; nothing is cloned.
844+ let root: & Path = & ctx. root ;
845+ let compress = ctx. compress ;
846+ let ignores = & ctx. ignores ;
848847 // Only the client prints user-facing event lines. The agent's stderr is
849848 // forwarded over SSH to the same terminal, so any logs there would just
850849 // duplicate the client's transcript.
851- let log_event = is_client;
850+ let log_event = ctx . is_client ;
852851 // If git is mid-operation locally, refuse to apply any change under
853852 // `.git/`. Otherwise the peer (who may NOT be busy) would clobber our
854853 // in-progress rebase/merge state and break ref locking.
@@ -881,7 +880,7 @@ where
881880 if !apply_remote {
882881 return Ok ( ( ) ) ;
883882 }
884- if ignored ( ignores, & entry. path , false ) {
883+ if ignores. is_ignored_rel ( & entry. path , false ) {
885884 tracing:: debug!( "ignored (recv FileData): {}" , entry. path. display( ) ) ;
886885 return Ok ( ( ) ) ;
887886 }
@@ -925,7 +924,7 @@ where
925924 if !apply_remote {
926925 return Ok ( ( ) ) ;
927926 }
928- if ignored ( ignores, & entry. path , false ) {
927+ if ignores. is_ignored_rel ( & entry. path , false ) {
929928 tracing:: debug!( "ignored (recv FileStart): {}" , entry. path. display( ) ) ;
930929 return Ok ( ( ) ) ;
931930 }
@@ -953,7 +952,7 @@ where
953952 if !apply_remote {
954953 return Ok ( ( ) ) ;
955954 }
956- if ignored ( ignores, & path, false ) {
955+ if ignores. is_ignored_rel ( & path, false ) {
957956 return Ok ( ( ) ) ;
958957 }
959958 pending. chunk ( & path, & data) . await ?;
@@ -962,7 +961,7 @@ where
962961 if !apply_remote {
963962 return Ok ( ( ) ) ;
964963 }
965- if ignored ( ignores, & path, false ) {
964+ if ignores. is_ignored_rel ( & path, false ) {
966965 return Ok ( ( ) ) ;
967966 }
968967 if let Some ( entry) = pending. end ( root, & path) . await ? {
@@ -982,7 +981,7 @@ where
982981 if !apply_remote {
983982 return Ok ( ( ) ) ;
984983 }
985- if ignored ( ignores, & path, false ) {
984+ if ignores. is_ignored_rel ( & path, false ) {
986985 return Ok ( ( ) ) ;
987986 }
988987 let full = root. join ( & path) ;
@@ -1018,7 +1017,7 @@ where
10181017 if !apply_remote {
10191018 return Ok ( ( ) ) ;
10201019 }
1021- if ignored ( ignores, & entry. path , true ) {
1020+ if ignores. is_ignored_rel ( & entry. path , true ) {
10221021 tracing:: debug!( "ignored (recv MkDir): {}" , entry. path. display( ) ) ;
10231022 return Ok ( ( ) ) ;
10241023 }
@@ -1045,7 +1044,7 @@ where
10451044 if !apply_remote {
10461045 return Ok ( ( ) ) ;
10471046 }
1048- if ignored ( ignores, & entry. path , false ) {
1047+ if ignores. is_ignored_rel ( & entry. path , false ) {
10491048 return Ok ( ( ) ) ;
10501049 }
10511050 if is_already_equal ( root, & entry) {
@@ -1069,25 +1068,21 @@ where
10691068 if !apply_remote {
10701069 return Ok ( ( ) ) ;
10711070 }
1072- if ignored ( ignores, & path, false ) && ignored ( ignores, & path, true ) {
1071+ if ignores. is_ignored_rel ( & path, false ) && ignores. is_ignored_rel ( & path, true ) {
10731072 return Ok ( ( ) ) ;
10741073 }
10751074 let existed_before = fs:: symlink_metadata ( root. join ( & path) ) . is_ok ( ) ;
10761075 apply_delete ( root, & path) ?;
10771076 suppress. mark_deleted ( path. clone ( ) ) ;
10781077 if existed_before && log_event {
1079- eprintln ! (
1080- " {} {}" ,
1081- "←" . bright_cyan( ) ,
1082- format!( "× {}" , path. display( ) )
1083- ) ;
1078+ eprintln ! ( " {} × {}" , "←" . bright_cyan( ) , path. display( ) ) ;
10841079 }
10851080 }
10861081 Message :: Rename { from, to } => {
10871082 if !apply_remote {
10881083 return Ok ( ( ) ) ;
10891084 }
1090- if ignored ( ignores, & from, false ) || ignored ( ignores, & to, false ) {
1085+ if ignores. is_ignored_rel ( & from, false ) || ignores. is_ignored_rel ( & to, false ) {
10911086 tracing:: debug!(
10921087 "ignored (recv Rename): {} → {}" ,
10931088 from. display( ) ,
@@ -1112,7 +1107,7 @@ where
11121107 suppress. mark_mtime ( to, mt) ;
11131108 }
11141109 Message :: FileGet { path } => {
1115- if ignored ( ignores, & path, false ) && ignored ( ignores, & path, true ) {
1110+ if ignores. is_ignored_rel ( & path, false ) && ignores. is_ignored_rel ( & path, true ) {
11161111 return Ok ( ( ) ) ;
11171112 }
11181113 if let Some ( entry) = build_entry ( root, & path, None ) ? {
@@ -1246,7 +1241,7 @@ where
12461241 // (FSEvents on macOS is chatty during `rm`). The
12471242 // user's intent is a delete — treat it as such.
12481243 if log_event {
1249- eprintln ! ( " {} {}" , "→" . bright_green( ) , format! ( "× {}" , p. display( ) ) ) ;
1244+ eprintln ! ( " {} × {}" , "→" . bright_green( ) , p. display( ) ) ;
12501245 }
12511246 {
12521247 let mut w = writer. lock ( ) . await ;
@@ -1355,7 +1350,7 @@ where
13551350 }
13561351 FsEvent :: Removed ( p) => {
13571352 if log_event {
1358- eprintln ! ( " {} {}" , "→" . bright_green( ) , format! ( "× {}" , p. display( ) ) ) ;
1353+ eprintln ! ( " {} × {}" , "→" . bright_green( ) , p. display( ) ) ;
13591354 }
13601355 {
13611356 let mut w = writer. lock ( ) . await ;
0 commit comments