diff --git a/src/config.rs b/src/config.rs index 923823d52..14750a24f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -119,6 +119,7 @@ pub struct Config { pub(crate) build_cpu_limit: Option, pub(crate) build_default_memory_limit: Option, pub(crate) include_default_targets: bool, + #[allow(dead_code)] pub(crate) disable_memory_limit: bool, // automatic rebuild configuration diff --git a/src/docbuilder/rustwide_builder.rs b/src/docbuilder/rustwide_builder.rs index 0b215ee34..c7c2d0ee3 100644 --- a/src/docbuilder/rustwide_builder.rs +++ b/src/docbuilder/rustwide_builder.rs @@ -299,10 +299,34 @@ impl RustwideBuilder { } pub fn add_essential_files(&mut self) -> Result<()> { + // Check if toolchain is available, install if needed + match self.detect_rustc_version() { + Ok(_) => { + info!("Toolchain is already installed"); + } + Err(err) => { + // Check if the error is specifically due to missing toolchain + let err_msg = err.to_string(); + if err_msg.contains("No such file or directory") + || err_msg.contains("command not found") + || err_msg.contains("not installed") + { + info!("Installing nightly toolchain because it was not found"); + self.update_toolchain()?; + } else { + // Don't try to install the toolchain if some other error occurred + return Err(anyhow!( + "Failed to detect rustc version: {}\n\nThis might indicate the nightly toolchain is not properly installed. Please run 'cratesfyi build update-toolchain' first.", + err + )); + } + } + } + let rustc_version = self.rustc_version()?; let parsed_rustc_version = parse_rustc_version(&rustc_version)?; - info!("building a dummy crate to get essential files"); + info!("building a dummy crate to get essential files for {rustc_version}"); let limits = self.get_limits(DUMMY_CRATE_NAME)?; @@ -2100,4 +2124,68 @@ mod tests { Ok(()) } + + #[test] + fn test_add_essential_files_with_toolchain() { + wrapper(|env: &TestEnvironment| { + let mut builder = RustwideBuilder::init(env).unwrap(); + + builder.update_toolchain()?; + + // Should not fail on missing toolchain + match builder.add_essential_files() { + Ok(_) => println!("add_essential_files succeeded with toolchain"), + Err(err) => { + let error_message = err.to_string(); + let is_toolchain_error = error_message.contains("toolchain") + && (error_message.contains("not found") + || error_message.contains("not installed") + || error_message.contains("missing") + || error_message.contains("invalid toolchain")); + + assert!( + !is_toolchain_error, + "Should not fail due to missing toolchain, but got: {error_message}" + ); + println!("add_essential_files failed for expected reason: {error_message}"); + } + } + + Ok(()) + }) + } + + #[test] + fn test_add_essential_files_without_toolchain() { + wrapper(|env: &TestEnvironment| { + let mut builder = RustwideBuilder::init(env).unwrap(); + + // First: Set an invalid toolchain + env.runtime().block_on(async { + let mut conn = env.async_db().await.async_conn().await; + crate::utils::set_config( + &mut conn, + crate::utils::ConfigName::Toolchain, + "invalid-toolchain-name!@#", + ) + .await + })?; + + // Should fail on missing toolchain + match builder.add_essential_files() { + Ok(_) => panic!("add_essential_files should fail when toolchain is missing"), + Err(e) => { + let error_message = e.to_string(); + println!("add_essential_files correctly failed with: {error_message}"); + + assert!( + !error_message.contains("success"), + "Should not succeed when toolchain is missing" + ); + } + } + + Ok(()) + }) + } }