diff --git a/crates/uv/src/commands/project/add.rs b/crates/uv/src/commands/project/add.rs index 034726f67..c5d419426 100644 --- a/crates/uv/src/commands/project/add.rs +++ b/crates/uv/src/commands/project/add.rs @@ -597,7 +597,7 @@ pub(crate) async fn add( // Initialize any shared state. let state = SharedState::default(); - project::sync::do_sync( + if let Err(err) = project::sync::do_sync( &project, &venv, &lock, @@ -613,7 +613,14 @@ pub(crate) async fn add( cache, printer, ) - .await?; + .await + { + // Revert the changes to the `pyproject.toml`, if necessary. + if modified { + fs_err::write(project.root().join("pyproject.toml"), existing)?; + } + return Err(err.into()); + } Ok(ExitStatus::Success) } diff --git a/crates/uv/tests/edit.rs b/crates/uv/tests/edit.rs index 536dadcbe..87971a33a 100644 --- a/crates/uv/tests/edit.rs +++ b/crates/uv/tests/edit.rs @@ -3873,3 +3873,69 @@ fn add_git_to_script() -> Result<()> { }); Ok(()) } + +// Revert changes to pyproject.toml if add fails +#[test] +fn fail_to_add_revert_project() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! {r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + dependencies = [] + "#})?; + + // Adding `pytorch==1.0.2` should produce an error + let filters = std::iter::once((r"exit code: 1", "exit status: 1")) + .chain(context.filters()) + .collect::>(); + uv_snapshot!(filters, context.add(&["pytorch==1.0.2"]), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Resolved 2 packages in [TIME] + error: Failed to prepare distributions + Caused by: Failed to fetch wheel: pytorch==1.0.2 + Caused by: Build backend failed to build wheel through `build_wheel()` with exit status: 1 + --- stdout: + + --- stderr: + Traceback (most recent call last): + File "", line 11, in + File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 410, in build_wheel + return self._build_with_temp_dir( + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 395, in _build_with_temp_dir + self.run_setup() + File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 487, in run_setup + super().run_setup(setup_script=setup_script) + File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 311, in run_setup + exec(code, locals()) + File "", line 15, in + Exception: You tried to install "pytorch". The package named for PyTorch is "torch" + --- + "###); + + let pyproject_toml = fs_err::read_to_string(context.temp_dir.join("pyproject.toml"))?; + + insta::with_settings!({ + filters => context.filters(), + }, { + assert_snapshot!( + pyproject_toml, @r###" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + dependencies = [] + "### + ); + }); + + Ok(()) +}