Use create_new instead of atomic-file-write (#2914)

* Use `create_new` instead of `atomic-file-write`

This provides the same functionality but without temporary files, platform-specific code, fragility of `O_TMPFILE` support, and an extra dependency.

* Properly handle acceptable failure cases

* Consider `PermissionDenied` as acceptable

Apparently this can occur on Windows.

---------

Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
This commit is contained in:
Matt Fellenz 2024-02-24 01:49:51 -08:00 committed by GitHub
parent 02f196b4ac
commit b615d2a826
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 31 additions and 46 deletions

37
Cargo.lock generated
View file

@ -334,16 +334,6 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "atomic-write-file"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c232177ba50b16fe7a4588495bd474a62a9e45a8e4ca6fd7d0b7ac29d164631e"
dependencies = [
"nix 0.26.4",
"rand",
]
[[package]]
name = "atty"
version = "0.2.14"
@ -1916,7 +1906,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4863ee94f19ed315bf3bc00299338d857d4b5bc856af375cc97d237382ad3856"
dependencies = [
"nix 0.23.2",
"nix",
"winapi",
]
@ -1951,15 +1941,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "memoffset"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
dependencies = [
"autocfg",
]
[[package]]
name = "memoffset"
version = "0.9.0"
@ -2069,19 +2050,6 @@ dependencies = [
"memoffset 0.6.5",
]
[[package]]
name = "nix"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
"libc",
"memoffset 0.7.1",
"pin-utils",
]
[[package]]
name = "nom"
version = "7.1.3"
@ -2848,7 +2816,7 @@ dependencies = [
"libc",
"log",
"memchr",
"nix 0.23.2",
"nix",
"radix_trie",
"scopeguard",
"smallvec",
@ -3402,7 +3370,6 @@ name = "sqlx-macros-core"
version = "0.7.3"
dependencies = [
"async-std",
"atomic-write-file",
"dotenvy",
"either",
"heck 0.4.1",

View file

@ -48,7 +48,6 @@ tokio = { workspace = true, optional = true }
dotenvy = { workspace = true }
atomic-write-file = { version = "0.1" }
hex = { version = "0.4.3" }
heck = { version = "0.4", features = ["unicode"] }
either = "1.6.1"

View file

@ -151,22 +151,41 @@ where
}
pub(super) fn save_in(&self, dir: impl AsRef<Path>) -> crate::Result<()> {
let path = dir.as_ref().join(format!("query-{}.json", self.hash));
let mut file = atomic_write_file::AtomicWriteFile::open(&path)
.map_err(|err| format!("failed to open the temporary file: {err:?}"))?;
use std::io::ErrorKind;
serde_json::to_writer_pretty(file.as_file_mut(), self)
.map_err(|err| format!("failed to serialize query data to file: {err:?}"))?;
let path = dir.as_ref().join(format!("query-{}.json", self.hash));
match std::fs::remove_file(&path) {
Ok(()) => {}
Err(err)
if matches!(
err.kind(),
ErrorKind::NotFound | ErrorKind::PermissionDenied,
) => {}
Err(err) => return Err(format!("failed to delete {path:?}: {err:?}").into()),
}
let mut file = match std::fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(&path)
{
Ok(file) => file,
// We overlapped with a concurrent invocation and the other one succeeded.
Err(err) if matches!(err.kind(), ErrorKind::AlreadyExists) => return Ok(()),
Err(err) => {
return Err(format!("failed to exclusively create {path:?}: {err:?}").into())
}
};
let data = serde_json::to_string_pretty(self)
.map_err(|err| format!("failed to serialize query data: {err:?}"))?;
file.write_all(data.as_bytes())
.map_err(|err| format!("failed to write query data to file: {err:?}"))?;
// Ensure there is a newline at the end of the JSON file to avoid
// accidental modification by IDE and make github diff tool happier.
file.as_file_mut()
.write_all(b"\n")
file.write_all(b"\n")
.map_err(|err| format!("failed to append a newline to file: {err:?}"))?;
file.commit()
.map_err(|err| format!("failed to commit the query data to {path:?}: {err:?}"))?;
Ok(())
}
}