mirror of
				https://github.com/astral-sh/uv.git
				synced 2025-11-03 21:23:54 +00:00 
			
		
		
		
	Avoid overwriting symlinks in pip compile output (#6487)
				
					
				
			## Summary Closes https://github.com/astral-sh/uv/issues/6485.
This commit is contained in:
		
							parent
							
								
									1cd80139af
								
							
						
					
					
						commit
						9b42142fe7
					
				
					 2 changed files with 56 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
use std::borrow::Cow;
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::io::stdout;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
| 
						 | 
				
			
			@ -643,6 +644,10 @@ impl<'a> OutputWriter<'a> {
 | 
			
		|||
    /// Commit the buffer to the output file.
 | 
			
		||||
    async fn commit(self) -> std::io::Result<()> {
 | 
			
		||||
        if let Some(output_file) = self.output_file {
 | 
			
		||||
            // If the output file is an existing symlink, write to the destination instead.
 | 
			
		||||
            let output_file = fs_err::read_link(output_file)
 | 
			
		||||
                .map(Cow::Owned)
 | 
			
		||||
                .unwrap_or(Cow::Borrowed(output_file));
 | 
			
		||||
            let stream = anstream::adapter::strip_bytes(&self.buffer).into_vec();
 | 
			
		||||
            uv_fs::write_atomic(output_file, &stream).await?;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11907,3 +11907,54 @@ fn invalid_extra() -> Result<()> {
 | 
			
		|||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Respect symlinks of output files.
 | 
			
		||||
#[test]
 | 
			
		||||
#[cfg(not(windows))]
 | 
			
		||||
fn symlink() -> Result<()> {
 | 
			
		||||
    let context = TestContext::new("3.8");
 | 
			
		||||
    let requirements_in = context.temp_dir.child("requirements.in");
 | 
			
		||||
    requirements_in.write_str("anyio")?;
 | 
			
		||||
 | 
			
		||||
    // Create an output file.
 | 
			
		||||
    let requirements_txt = context.temp_dir.child("requirements.txt");
 | 
			
		||||
    requirements_txt.write_str("anyio")?;
 | 
			
		||||
 | 
			
		||||
    // Create a symlink to the output file.
 | 
			
		||||
    let symlink = context.temp_dir.child("requirements-symlink.txt");
 | 
			
		||||
    symlink.symlink_to_file(requirements_txt.path())?;
 | 
			
		||||
 | 
			
		||||
    // Write to the symlink.
 | 
			
		||||
    uv_snapshot!(context.pip_compile()
 | 
			
		||||
        .arg("requirements.in")
 | 
			
		||||
        .arg("--output-file")
 | 
			
		||||
        .arg("requirements-symlink.txt"), @r###"
 | 
			
		||||
    success: true
 | 
			
		||||
    exit_code: 0
 | 
			
		||||
    ----- stdout -----
 | 
			
		||||
    # This file was autogenerated by uv via the following command:
 | 
			
		||||
    #    uv pip compile --cache-dir [CACHE_DIR] requirements.in --output-file requirements-symlink.txt
 | 
			
		||||
    anyio==4.3.0
 | 
			
		||||
        # via -r requirements.in
 | 
			
		||||
    exceptiongroup==1.2.0
 | 
			
		||||
        # via anyio
 | 
			
		||||
    idna==3.6
 | 
			
		||||
        # via anyio
 | 
			
		||||
    sniffio==1.3.1
 | 
			
		||||
        # via anyio
 | 
			
		||||
    typing-extensions==4.10.0
 | 
			
		||||
        # via anyio
 | 
			
		||||
 | 
			
		||||
    ----- stderr -----
 | 
			
		||||
    Resolved 5 packages in [TIME]
 | 
			
		||||
    "###
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // The symlink should still be a symlink.
 | 
			
		||||
    assert!(symlink.path().symlink_metadata()?.file_type().is_symlink());
 | 
			
		||||
 | 
			
		||||
    // The destination of the symlink should be the same as the output file.
 | 
			
		||||
    assert_eq!(symlink.path().read_link()?, requirements_txt.path());
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue