mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-12-29 21:00:54 +00:00
* fix(macros): smarter `.env` loading, caching, and invalidation * feat(mysql): test `.env` loading in CI * feat(postgres): test `.env` loading in CI * feat(macros): allow `DATABASE_URL` to be empty * fix(examples/postgres): make `cargo-sqlx` executable * fix(examples/postgres): `cargo sqlx` invocation * feat(examples/postgres): check offline prepare on more examples * fix(examples/postgres): the name of this step * fix(cli): don't suppress error from `dotenv()` * fix(ci/examples/postgres): don't use heredoc in this step * fix(ci/examples/postgres): multi-tenant * fix(ci/examples/sqlite): test `.env` loading * chore: add CHANGELOG entry
98 lines
2.4 KiB
Rust
98 lines
2.4 KiB
Rust
use std::path::{Path, PathBuf};
|
|
use std::sync::Mutex;
|
|
use std::time::SystemTime;
|
|
|
|
/// A cached value derived from one or more files, which is automatically invalidated
|
|
/// if the modified-time of any watched file changes.
|
|
pub struct MtimeCache<T> {
|
|
inner: Mutex<Option<MtimeCacheInner<T>>>,
|
|
}
|
|
|
|
pub struct MtimeCacheBuilder {
|
|
file_mtimes: Vec<(PathBuf, Option<SystemTime>)>,
|
|
}
|
|
|
|
struct MtimeCacheInner<T> {
|
|
builder: MtimeCacheBuilder,
|
|
cached: T,
|
|
}
|
|
|
|
impl<T: Clone> MtimeCache<T> {
|
|
pub fn new() -> Self {
|
|
MtimeCache {
|
|
inner: Mutex::new(None),
|
|
}
|
|
}
|
|
|
|
/// Get the cached value, or (re)initialize it if it does not exist or a file's mtime has changed.
|
|
pub fn get_or_try_init<E>(
|
|
&self,
|
|
init: impl FnOnce(&mut MtimeCacheBuilder) -> Result<T, E>,
|
|
) -> Result<T, E> {
|
|
let mut inner = self.inner.lock().unwrap_or_else(|e| {
|
|
// Reset the cache on-panic.
|
|
let mut locked = e.into_inner();
|
|
*locked = None;
|
|
locked
|
|
});
|
|
|
|
if let Some(inner) = &*inner {
|
|
if !inner.builder.any_modified() {
|
|
return Ok(inner.cached.clone());
|
|
}
|
|
}
|
|
|
|
let mut builder = MtimeCacheBuilder::new();
|
|
|
|
let value = init(&mut builder)?;
|
|
|
|
*inner = Some(MtimeCacheInner {
|
|
builder,
|
|
cached: value.clone(),
|
|
});
|
|
|
|
Ok(value)
|
|
}
|
|
}
|
|
|
|
impl MtimeCacheBuilder {
|
|
fn new() -> Self {
|
|
MtimeCacheBuilder {
|
|
file_mtimes: Vec::new(),
|
|
}
|
|
}
|
|
|
|
/// Add a file path to watch.
|
|
///
|
|
/// The cached value will be automatically invalidated if the modified-time of the file changes,
|
|
/// or if the file does not exist but is created sometime after this call.
|
|
pub fn add_path(&mut self, path: PathBuf) {
|
|
let mtime = get_mtime(&path);
|
|
|
|
#[cfg(any(sqlx_macros_unstable, procmacro2_semver_exempt))]
|
|
{
|
|
proc_macro::tracked_path::path(&path);
|
|
}
|
|
|
|
self.file_mtimes.push((path, mtime));
|
|
}
|
|
|
|
fn any_modified(&self) -> bool {
|
|
for (path, expected_mtime) in &self.file_mtimes {
|
|
let actual_mtime = get_mtime(path);
|
|
|
|
if expected_mtime != &actual_mtime {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
false
|
|
}
|
|
}
|
|
|
|
fn get_mtime(path: &Path) -> Option<SystemTime> {
|
|
std::fs::metadata(path)
|
|
.and_then(|metadata| metadata.modified())
|
|
.ok()
|
|
}
|