diff --git a/Cargo.lock b/Cargo.lock index 22aa2528..86d35c5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -226,6 +226,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + [[package]] name = "filetime" version = "0.2.23" @@ -351,6 +367,12 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "lock_api" version = "0.4.12" @@ -525,6 +547,19 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "rustlings" version = "6.1.0" @@ -538,6 +573,7 @@ dependencies = [ "rustlings-macros", "serde", "serde_json", + "tempfile", "toml_edit", ] @@ -709,6 +745,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "toml_datetime" version = "0.6.8" diff --git a/Cargo.toml b/Cargo.toml index 47e15301..456f738d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,9 @@ serde_json = "1.0.122" serde.workspace = true toml_edit.workspace = true +[dev-dependencies] +tempfile = "3.12.0" + [profile.release] panic = "abort" diff --git a/src/init.rs b/src/init.rs index dc23cbbf..94551c4c 100644 --- a/src/init.rs +++ b/src/init.rs @@ -4,7 +4,7 @@ use std::{ env::set_current_dir, fs::{self, create_dir}, io::{self, Write}, - path::Path, + path::{Path, PathBuf}, process::{Command, Stdio}, }; @@ -22,14 +22,27 @@ pub fn init() -> Result<()> { let mut stdout = io::stdout().lock(); let mut init_git = true; - if Path::new("Cargo.toml").exists() { + let manifest_path = Command::new("cargo") + .args(["locate-project", "--message-format=plain"]) + .output()?; + if manifest_path.status.success() { + let manifest_path: PathBuf = String::from_utf8_lossy(&manifest_path.stdout).trim().into(); + if Path::new("exercises").exists() && Path::new("solutions").exists() { bail!(IN_INITIALIZED_DIR_ERR); } - - stdout.write_all(CARGO_TOML_EXISTS_PROMPT_MSG)?; - press_enter_prompt(&mut stdout)?; - init_git = false; + if fs::read_to_string(manifest_path)?.contains("[workspace]") { + // make sure "rustlings" is added to `workspace.members` by making + // cargo initialize a new project + let output = Command::new("cargo").args(["new", "rustlings"]).output()?; + if !output.status.success() { + bail!("Failed to initilize new workspace member"); + } + fs::remove_dir_all("rustlings")?; + init_git = false; + } else { + bail!(IN_NON_WORKSPACE_CARGO_PROJECT_ERR); + } } stdout.write_all(b"This command will create the directory `rustlings/` which will contain the exercises.\nPress ENTER to continue ")?; @@ -128,19 +141,9 @@ You probably already initialized Rustlings. Run `cd rustlings` Then run `rustlings` again"; -const CARGO_TOML_EXISTS_PROMPT_MSG: &[u8] = br#"You are about to initialize Rustlings in a directory that already contains a `Cargo.toml` file! - - => It is recommended to abort with CTRL+C and initialize Rustlings in another directory <= - -If you know what you are doing and want to initialize Rustlings in a Cargo workspace, -then you need to add its directory to `members` in the `workspace` section of the `Cargo.toml` file: - -```toml -[workspace] -members = ["rustlings"] -``` - -Press ENTER if you are sure that you want to continue after reading the warning above "#; +const IN_NON_WORKSPACE_CARGO_PROJECT_ERR: &str = "\ +The current directory is already part of a cargo project. +Please initialize rustlings in a different directory."; const POST_INIT_MSG: &str = "Run `cd rustlings` to go into the generated directory. Then run `rustlings` to get started."; diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 3ab54f97..d821e20a 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -155,28 +155,28 @@ fn hint() { #[test] fn init() { - let _ = fs::remove_dir_all("tests/rustlings"); + let test_dir = tempfile::TempDir::new().unwrap(); + let initialized_dir = test_dir.path().join("rustlings"); + let test_dir = test_dir.path().to_str().unwrap(); - Cmd::default().current_dir("tests").fail(); + Cmd::default().current_dir(test_dir).fail(); Cmd::default() - .current_dir("tests") + .current_dir(test_dir) .args(&["init"]) .success(); // Running `init` after a successful initialization. Cmd::default() - .current_dir("tests") + .current_dir(test_dir) .args(&["init"]) .output(PartialStderr("`cd rustlings`")) .fail(); // Running `init` in the initialized directory. Cmd::default() - .current_dir("tests/rustlings") + .current_dir(initialized_dir.to_str().unwrap()) .args(&["init"]) .output(PartialStderr("already initialized")) .fail(); - - fs::remove_dir_all("tests/rustlings").unwrap(); }