fix: Implement atomic file write with temporary file in PatchWheel

This commit is contained in:
Denis Bilenko (aider) 2025-03-03 21:10:11 +01:00
parent 4afaf98324
commit fc48cff153
1 changed files with 20 additions and 3 deletions

View File

@ -165,7 +165,16 @@ func PatchWheel(ctx context.Context, path, outputDir string) (string, error) {
}
// Target wheel doesn't exist, proceed with patching
// AI TODO: write to a temporary file in the same location. Then do rename atomically. Use .tmp<pid> suffix for temp file. Use defer to ensure .tmp<pid> is removed if this function exits early.
// Create a temporary file in the same directory with a unique name
tmpFile := outpath + fmt.Sprintf(".tmp%d", os.Getpid())
// Ensure the temporary file is removed if we exit early
defer func() {
if _, statErr := os.Stat(tmpFile); statErr == nil {
os.Remove(tmpFile)
}
}()
r, err := zip.OpenReader(path)
if err != nil {
return "", err
@ -235,8 +244,8 @@ func PatchWheel(ctx context.Context, path, outputDir string) (string, error) {
return "", err
}
// We already calculated the output path earlier
outFile, err := os.Create(outpath)
// Write to the temporary file first
outFile, err := os.Create(tmpFile)
if err != nil {
return "", err
}
@ -296,6 +305,14 @@ func PatchWheel(ctx context.Context, path, outputDir string) (string, error) {
if err := zipw.Close(); err != nil {
return "", err
}
// Close the file before renaming
outFile.Close()
// Rename the temporary file to the final output path (atomic operation)
if err := os.Rename(tmpFile, outpath); err != nil {
return "", err
}
return outpath, nil
}