@@ -74,6 +74,17 @@ fn detect_git_worktree(path: &Path) -> anyhow::Result<Option<PathBuf>> {
7474/// Docker container image to use
7575const DOCKER_IMAGE : & str = "ghcr.io/shepherdjerred/dotfiles" ;
7676
77+ /// Shared cache volumes used across all mux Docker containers for faster Rust builds:
78+ /// - mux-cargo-registry: Downloaded crates from crates.io (/usr/local/cargo/registry)
79+ /// - mux-cargo-git: Git dependencies (/usr/local/cargo/git)
80+ /// - mux-sccache: Compilation cache (/root/.cache/sccache)
81+ ///
82+ /// sccache (Mozilla's compilation cache) is configured via RUSTC_WRAPPER environment variable.
83+ /// If sccache is not installed in the dotfiles image, cargo will show a warning but continue
84+ /// to work. To enable sccache compilation caching, install it in the dotfiles image:
85+ /// cargo install sccache
86+ /// or add it to the Dockerfile.
87+
7788/// Proxy configuration for Docker containers.
7889#[ derive( Debug , Clone , Default ) ]
7990pub struct DockerProxyConfig {
@@ -195,6 +206,29 @@ impl DockerBackend {
195206 "HOME=/workspace" . to_string( ) ,
196207 ] ;
197208
209+ // Mount shared Rust cargo and sccache cache volumes for faster builds
210+ // These are shared across ALL mux sessions and persist between container restarts
211+ // sccache provides compilation caching (path-independent, content-addressed)
212+ // cargo caches provide dependency download caching
213+ args. extend ( [
214+ "-v" . to_string ( ) ,
215+ "mux-cargo-registry:/usr/local/cargo/registry" . to_string ( ) ,
216+ "-v" . to_string ( ) ,
217+ "mux-cargo-git:/usr/local/cargo/git" . to_string ( ) ,
218+ "-v" . to_string ( ) ,
219+ "mux-sccache:/root/.cache/sccache" . to_string ( ) ,
220+ ] ) ;
221+
222+ // Configure sccache as Rust compiler wrapper (if installed in dotfiles image)
223+ // If sccache is not installed, cargo will show a clear warning but continue to work
224+ // This is a progressive enhancement - works without sccache, better with it
225+ args. extend ( [
226+ "-e" . to_string ( ) ,
227+ "RUSTC_WRAPPER=sccache" . to_string ( ) ,
228+ "-e" . to_string ( ) ,
229+ "SCCACHE_DIR=/root/.cache/sccache" . to_string ( ) ,
230+ ] ) ;
231+
198232 // Detect if workdir is a git worktree and mount parent .git directory
199233 match detect_git_worktree ( workdir) {
200234 Ok ( Some ( parent_git_dir) ) => {
@@ -686,6 +720,48 @@ mod tests {
686720 ) ;
687721 }
688722
723+ /// Test that Rust caching is configured with cargo and sccache volumes
724+ #[ test]
725+ fn test_rust_caching_configured ( ) {
726+ let args = DockerBackend :: build_create_args (
727+ "test-session" ,
728+ & PathBuf :: from ( "/workspace" ) ,
729+ "test prompt" ,
730+ 1000 ,
731+ None ,
732+ false ,
733+ false ,
734+ & [ ] ,
735+ )
736+ . expect ( "Failed to build args" ) ;
737+
738+ // Check cargo cache volumes
739+ let has_registry = args
740+ . iter ( )
741+ . any ( |a| a. contains ( "mux-cargo-registry:/usr/local/cargo/registry" ) ) ;
742+ assert ! ( has_registry, "Expected mux-cargo-registry volume mount" ) ;
743+
744+ let has_git = args
745+ . iter ( )
746+ . any ( |a| a. contains ( "mux-cargo-git:/usr/local/cargo/git" ) ) ;
747+ assert ! ( has_git, "Expected mux-cargo-git volume mount" ) ;
748+
749+ // Check sccache volume
750+ let has_sccache = args
751+ . iter ( )
752+ . any ( |a| a. contains ( "mux-sccache:/root/.cache/sccache" ) ) ;
753+ assert ! ( has_sccache, "Expected mux-sccache volume mount" ) ;
754+
755+ // Check sccache environment variables
756+ let has_rustc_wrapper = args. iter ( ) . any ( |a| a == "RUSTC_WRAPPER=sccache" ) ;
757+ assert ! ( has_rustc_wrapper, "Expected RUSTC_WRAPPER=sccache" ) ;
758+
759+ let has_sccache_dir = args
760+ . iter ( )
761+ . any ( |a| a == "SCCACHE_DIR=/root/.cache/sccache" ) ;
762+ assert ! ( has_sccache_dir, "Expected SCCACHE_DIR=/root/.cache/sccache" ) ;
763+ }
764+
689765 /// Test that attach command uses bash, not zsh (which doesn't exist in container)
690766 #[ test]
691767 fn test_attach_uses_bash_not_zsh ( ) {
@@ -1023,11 +1099,11 @@ mod tests {
10231099 & [ ] ,
10241100 ) . expect ( "Failed to build args" ) ;
10251101
1026- // Count volume mounts (should only have the workspace mount )
1102+ // Count volume mounts (should have workspace + 3 cargo/sccache cache mounts )
10271103 let mount_count = args. iter ( ) . filter ( |a| * a == "-v" ) . count ( ) ;
10281104 assert_eq ! (
1029- mount_count, 1 ,
1030- "Normal git repo should only have workspace mount , got {mount_count} mounts"
1105+ mount_count, 4 ,
1106+ "Normal git repo should have workspace + 3 cache mounts , got {mount_count} mounts"
10311107 ) ;
10321108 }
10331109
@@ -1138,11 +1214,11 @@ mod tests {
11381214 & [ ] ,
11391215 ) . expect ( "Failed to build args" ) ;
11401216
1141- // Should only have workspace mount (no git mount)
1217+ // Should have workspace + 3 cache mounts (no git parent mount)
11421218 let mount_count = args. iter ( ) . filter ( |a| * a == "-v" ) . count ( ) ;
11431219 assert_eq ! (
1144- mount_count, 1 ,
1145- "Malformed worktree should only have workspace mount , got {mount_count} mounts"
1220+ mount_count, 4 ,
1221+ "Malformed worktree should have workspace + 3 cache mounts , got {mount_count} mounts"
11461222 ) ;
11471223 }
11481224
@@ -1173,11 +1249,11 @@ mod tests {
11731249 & [ ] ,
11741250 ) . expect ( "Failed to build args" ) ;
11751251
1176- // Should only have workspace mount (no git mount due to validation failure)
1252+ // Should have workspace + 3 cache mounts (no git parent mount due to validation failure)
11771253 let mount_count = args. iter ( ) . filter ( |a| * a == "-v" ) . count ( ) ;
11781254 assert_eq ! (
1179- mount_count, 1 ,
1180- "Worktree with missing parent should only have workspace mount , got {mount_count} mounts"
1255+ mount_count, 4 ,
1256+ "Worktree with missing parent should have workspace + 3 cache mounts , got {mount_count} mounts"
11811257 ) ;
11821258 }
11831259
0 commit comments