@@ -139,6 +139,19 @@ impl ConfigSyncer for ToolchainSyncer {
139139 fn check ( & self , workspace_root : & Path , config : & crate :: config:: RailConfig ) -> RailResult < SyncStatus > {
140140 let toolchain_path = workspace_root. join ( "rust-toolchain.toml" ) ;
141141
142+ // If not managed by rail, skip sync
143+ if !config. toolchain . managed_by_rail {
144+ if toolchain_path. exists ( ) {
145+ return Ok ( SyncStatus :: InSync (
146+ "rust-toolchain.toml exists but not managed by rail (managed_by_rail = false)" . to_string ( ) ,
147+ ) ) ;
148+ } else {
149+ return Ok ( SyncStatus :: OutOfSync (
150+ "rust-toolchain.toml missing (set managed_by_rail = true to enable sync)" . to_string ( ) ,
151+ ) ) ;
152+ }
153+ }
154+
142155 // If rust-toolchain.toml doesn't exist, it's out of sync
143156 if !toolchain_path. exists ( ) {
144157 return Ok ( SyncStatus :: OutOfSync (
@@ -166,6 +179,19 @@ impl ConfigSyncer for ToolchainSyncer {
166179 fn sync ( & self , workspace_root : & Path , config : & crate :: config:: RailConfig ) -> RailResult < SyncStatus > {
167180 let toolchain_path = workspace_root. join ( "rust-toolchain.toml" ) ;
168181
182+ // If not managed by rail, skip sync
183+ if !config. toolchain . managed_by_rail {
184+ if toolchain_path. exists ( ) {
185+ return Ok ( SyncStatus :: InSync (
186+ "rust-toolchain.toml not managed by rail (skipping sync)" . to_string ( ) ,
187+ ) ) ;
188+ } else {
189+ return Ok ( SyncStatus :: InSync (
190+ "rust-toolchain.toml sync disabled (set managed_by_rail = true to enable)" . to_string ( ) ,
191+ ) ) ;
192+ }
193+ }
194+
169195 // Check if already in sync
170196 let check_status = self . check ( workspace_root, config) ?;
171197 if matches ! ( check_status, SyncStatus :: InSync ( _) ) {
@@ -183,6 +209,62 @@ impl ConfigSyncer for ToolchainSyncer {
183209 }
184210}
185211
212+ /// Parse existing rust-toolchain.toml and import into ToolchainConfig
213+ ///
214+ /// Returns None if file doesn't exist or can't be parsed
215+ pub fn import_rust_toolchain_toml ( workspace_root : & Path ) -> Option < crate :: config:: ToolchainConfig > {
216+ let toolchain_path = workspace_root. join ( "rust-toolchain.toml" ) ;
217+
218+ if !toolchain_path. exists ( ) {
219+ return None ;
220+ }
221+
222+ let content = std:: fs:: read_to_string ( & toolchain_path) . ok ( ) ?;
223+
224+ // Parse TOML using toml_edit which is already a dependency
225+ let parsed: toml_edit:: DocumentMut = content. parse ( ) . ok ( ) ?;
226+ let toolchain_table = parsed. get ( "toolchain" ) ?. as_table ( ) ?;
227+
228+ // Extract fields
229+ let channel = toolchain_table
230+ . get ( "channel" )
231+ . and_then ( |v| v. as_str ( ) )
232+ . unwrap_or ( "stable" )
233+ . to_string ( ) ;
234+
235+ let path = toolchain_table
236+ . get ( "path" )
237+ . and_then ( |v| v. as_str ( ) )
238+ . map ( |s| s. to_string ( ) ) ;
239+
240+ let profile = toolchain_table
241+ . get ( "profile" )
242+ . and_then ( |v| v. as_str ( ) )
243+ . unwrap_or ( "default" )
244+ . to_string ( ) ;
245+
246+ let components = toolchain_table
247+ . get ( "components" )
248+ . and_then ( |v| v. as_array ( ) )
249+ . map ( |arr| arr. iter ( ) . filter_map ( |v| v. as_str ( ) ) . map ( |s| s. to_string ( ) ) . collect ( ) )
250+ . unwrap_or_default ( ) ;
251+
252+ let targets = toolchain_table
253+ . get ( "targets" )
254+ . and_then ( |v| v. as_array ( ) )
255+ . map ( |arr| arr. iter ( ) . filter_map ( |v| v. as_str ( ) ) . map ( |s| s. to_string ( ) ) . collect ( ) )
256+ . unwrap_or_default ( ) ;
257+
258+ Some ( crate :: config:: ToolchainConfig {
259+ channel,
260+ path,
261+ profile,
262+ components,
263+ targets,
264+ managed_by_rail : true , // Set to true when importing
265+ } )
266+ }
267+
186268/// Generate rust-toolchain.toml content from ToolchainConfig
187269///
188270/// Supports all rust-toolchain.toml fields:
@@ -245,6 +327,7 @@ mod tests {
245327 profile : "default" . to_string ( ) ,
246328 components : vec ! [ ] ,
247329 targets : vec ! [ ] ,
330+ managed_by_rail : false ,
248331 } ;
249332
250333 let content = generate_rust_toolchain_toml ( & config) ;
@@ -266,6 +349,7 @@ mod tests {
266349 "x86_64-unknown-linux-gnu" . to_string( ) ,
267350 "aarch64-apple-darwin" . to_string( ) ,
268351 ] ,
352+ managed_by_rail : false ,
269353 } ;
270354
271355 let content = generate_rust_toolchain_toml ( & config) ;
@@ -285,6 +369,7 @@ mod tests {
285369 profile : "default" . to_string ( ) , // Ignored in path mode
286370 components : vec ! [ "clippy" . to_string( ) ] , // Ignored in path mode
287371 targets : vec ! [ "x86_64-unknown-linux-gnu" . to_string( ) ] , // Ignored in path mode
372+ managed_by_rail : false ,
288373 } ;
289374
290375 let content = generate_rust_toolchain_toml ( & config) ;
0 commit comments