1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//! Auxiliary helper methods for directories
use crate::{constant::*, error::*, io::FileAux, str::*};
use camino::{Utf8Path, Utf8PathBuf};
use std::{fs::File, vec::IntoIter};
pub trait DirAux {
fn readdir(&self) -> Result<IntoIter<Utf8PathBuf>, Err>;
/// Acquire an exclusive advisory lock on the directory.
///
/// `lock_name` is a human-readable description shown to the user if another bpt instance
/// holds the lock (e.g. "package database", "repository cache").
///
/// The caller **must** hold the returned `File` for the duration of the locked operation;
/// dropping it releases the lock.
#[must_use = "dropping the returned File immediately releases the lock"]
fn lock_rw(&self, lock_name: &str) -> Result<File, Err>;
/// Acquire a shared advisory lock on the directory.
///
/// `lock_name` is a human-readable description shown to the user if another bpt instance
/// holds the lock (e.g. "package database", "repository cache").
///
/// The caller **must** hold the returned `File` for the duration of the locked operation;
/// dropping it releases the lock.
#[must_use = "dropping the returned File immediately releases the lock"]
fn lock_ro(&self, lock_name: &str) -> Result<File, Err>;
}
/// Rust's directory reading infrastructure has tedious error handling. Abstract it away here.
impl DirAux for Utf8Path {
fn readdir(&self) -> Result<IntoIter<Utf8PathBuf>, Err> {
std::fs::read_dir(self)
.map_err(|e| Err::ReadDir(self.to_string(), e))?
.map(|entry| {
entry
.map_err(|e| Err::ReadDir(self.to_string(), e))
.map(|entry| entry.path())
.and_then(|path| {
path.into_pathbuf()
.map_err(|e| Err::ReadDir(self.to_string(), e))
})
})
.collect::<Result<Vec<Utf8PathBuf>, Err>>()
.map(|v| v.into_iter())
}
fn lock_rw(&self, lock_name: &str) -> Result<File, Err> {
let lock_path = self.join(LOCK_FILE_NAME);
let file = File::create_or_open_rw(&lock_path)?;
file.lock_rw(lock_name).loc(lock_path)?;
Ok(file)
}
fn lock_ro(&self, lock_name: &str) -> Result<File, Err> {
let lock_path = self.join(LOCK_FILE_NAME);
let file = File::create_or_open_ro(&lock_path)?;
file.lock_ro(lock_name).loc(lock_path)?;
Ok(file)
}
}