ok/jj
1
0
Fork 0
forked from mirrors/jj
jj/lib/src/file_util.rs
Martin von Zweigbergk 7360589246 working_copy: consider it an error if temp file cannot be renamed to target
Unlike the other places I fixed in 134940d2bb, the calls in
`working_copy.rs` should not simply use an existing file if the target
file was open. They should probably try again instead, but I'll leave
that for later.
2021-06-16 10:52:55 -07:00

73 lines
2.3 KiB
Rust

// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::fs::File;
use std::path::Path;
use tempfile::{NamedTempFile, PersistError};
// Like NamedTempFile::persist(), but also succeeds if the target already
// exists.
pub fn persist_content_addressed_temp_file<P: AsRef<Path>>(
temp_file: NamedTempFile,
new_path: P,
) -> Result<File, PersistError> {
match temp_file.persist(&new_path) {
Ok(file) => Ok(file),
Err(PersistError { error, file }) => {
if let Ok(existing_file) = File::open(new_path) {
Ok(existing_file)
} else {
Err(PersistError { error, file })
}
}
}
}
#[cfg(test)]
mod tests {
use std::env::temp_dir;
use std::io::Write;
use test_case::test_case;
use super::*;
#[test]
fn test_persist_no_existing_file() {
let temp_dir = temp_dir();
let target = temp_dir.join("file");
let mut temp_file = NamedTempFile::new_in(&temp_dir).unwrap();
temp_file.write_all(b"contents").unwrap();
assert!(persist_content_addressed_temp_file(temp_file, &target).is_ok());
}
#[test_case(false ; "existing file open")]
#[test_case(true ; "existing file closed")]
fn test_persist_target_exists(existing_file_closed: bool) {
let temp_dir = temp_dir();
let target = temp_dir.join("file");
let mut temp_file = NamedTempFile::new_in(&temp_dir).unwrap();
temp_file.write_all(b"contents").unwrap();
let mut file = File::create(&target).unwrap();
file.write_all(b"contents").unwrap();
if existing_file_closed {
drop(file);
}
assert!(persist_content_addressed_temp_file(temp_file, &target).is_ok());
}
}