From 359ece4d279dae27c79c0f2f57566a6754557260 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Mon, 21 Sep 2026 15:46:38 +0200 Subject: [PATCH 1/3] fix parsing of cargo locate-project output Deserializing the output of `cargo locate-project --workspace` failed for a windows user, with the error message from serde that `root` is a string and not a path. Hopefully, using a string directly will also work on Windows. --- src/init.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.rs b/src/init.rs index 3ccef756d8..cc6d855280 100644 --- a/src/init.rs +++ b/src/init.rs @@ -20,7 +20,7 @@ use crate::{ #[derive(Deserialize)] struct CargoLocateProject<'a> { #[serde(borrow)] - root: &'a Path, + root: &'a str, } pub fn init() -> Result<()> { @@ -74,7 +74,7 @@ pub fn init() -> Result<()> { .root; let workspace_manifest_content = fs::read_to_string(workspace_manifest) - .with_context(|| format!("Failed to read the file {}", workspace_manifest.display()))?; + .with_context(|| format!("Failed to read the file {}", workspace_manifest))?; if !workspace_manifest_content.contains("[workspace]") && !workspace_manifest_content.contains("workspace.") { From cf3a66fe5e796fb3592ecce5d8ad00925ffbec08 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Mon, 21 Sep 2026 16:34:34 +0200 Subject: [PATCH 2/3] use --message-format=plain for `cargo locate-project` This avoids the deserialization step. --- src/init.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/init.rs b/src/init.rs index cc6d855280..683d5c090e 100644 --- a/src/init.rs +++ b/src/init.rs @@ -3,7 +3,6 @@ use crossterm::{ QueueableCommand, style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor}, }; -use serde::Deserialize; use std::{ env::{current_dir, set_current_dir}, fs::{self, create_dir}, @@ -17,12 +16,6 @@ use crate::{ info_file::InfoFile, term::press_enter_prompt, }; -#[derive(Deserialize)] -struct CargoLocateProject<'a> { - #[serde(borrow)] - root: &'a str, -} - pub fn init() -> Result<()> { let rustlings_dir = Path::new("rustlings"); if rustlings_dir.exists() { @@ -33,6 +26,7 @@ pub fn init() -> Result<()> { .arg("locate-project") .arg("-q") .arg("--workspace") + .arg("--message-format=plain") .stdin(Stdio::null()) .stderr(Stdio::null()) .output() @@ -66,15 +60,15 @@ pub fn init() -> Result<()> { bail!(IN_INITIALIZED_DIR_ERR); } - let workspace_manifest = - serde_json::de::from_slice::(&locate_project_output.stdout) - .context( - "Failed to read the field `root` from the output of `cargo locate-project …`", - )? - .root; + let workspace_manifest = { + let mut stdout = String::try_from(locate_project_output.stdout) + .context("Failed to convert the output of `cargo locate-project …` to a string")?; + stdout.truncate(stdout.trim_end().len()); // trim trailing newline + stdout + }; - let workspace_manifest_content = fs::read_to_string(workspace_manifest) - .with_context(|| format!("Failed to read the file {}", workspace_manifest))?; + let workspace_manifest_content = fs::read_to_string(&workspace_manifest) + .with_context(|| format!("Failed to read the file {workspace_manifest}"))?; if !workspace_manifest_content.contains("[workspace]") && !workspace_manifest_content.contains("workspace.") { From b677a2c20f602a40ab476dad1aa8c9c3bcd5c3c1 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Tue, 29 Sep 2026 12:12:15 +0200 Subject: [PATCH 3/3] parse command output consistently --- src/init.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/init.rs b/src/init.rs index 683d5c090e..139e922763 100644 --- a/src/init.rs +++ b/src/init.rs @@ -22,7 +22,7 @@ pub fn init() -> Result<()> { bail!(RUSTLINGS_DIR_ALREADY_EXISTS_ERR); } - let locate_project_output = Command::new("cargo") + let mut locate_project_output = Command::new("cargo") .arg("locate-project") .arg("-q") .arg("--workspace") @@ -60,12 +60,11 @@ pub fn init() -> Result<()> { bail!(IN_INITIALIZED_DIR_ERR); } - let workspace_manifest = { - let mut stdout = String::try_from(locate_project_output.stdout) - .context("Failed to convert the output of `cargo locate-project …` to a string")?; - stdout.truncate(stdout.trim_end().len()); // trim trailing newline - stdout - }; + // Remove newline + locate_project_output.stdout.pop(); + + let workspace_manifest = String::try_from(locate_project_output.stdout) + .context("Failed to convert the output of `cargo locate-project …` to a string")?; let workspace_manifest_content = fs::read_to_string(&workspace_manifest) .with_context(|| format!("Failed to read the file {workspace_manifest}"))?;