helper: add fs (#67)

* helper: add `fs`

* fs: docs

* remove `cuprate_create_dir_all()`

Calling each function is better.

* fs: comments

* helper: fix `asynch` tokio import for tests

* fs: add sanity tests

* fs: add `is_absolute()` to tests

* fs: assert path is absolute

* Update helper/src/fs.rs

Co-authored-by: Boog900 <boog900@tutanota.com>

* Update helper/src/fs.rs

Co-authored-by: Boog900 <boog900@tutanota.com>

---------

Co-authored-by: Boog900 <boog900@tutanota.com>
This commit is contained in:
hinto-janai 2024-02-21 12:54:46 -05:00 committed by GitHub
parent f7bd1304e2
commit e287ea1d84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 198 additions and 3 deletions

1
Cargo.lock generated
View file

@ -590,6 +590,7 @@ version = "0.1.0"
dependencies = [
"chrono",
"crossbeam",
"dirs",
"futures",
"libc",
"rayon",

View file

@ -10,11 +10,12 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/consensus"
[features]
# All features on by default.
default = ["std", "atomic", "asynch", "num", "time", "thread", "constants"]
default = ["std", "atomic", "asynch", "fs", "num", "time", "thread", "constants"]
std = []
atomic = ["dep:crossbeam"]
asynch = ["dep:futures", "dep:rayon"]
constants = []
fs = ["dep:dirs"]
num = []
time = ["dep:chrono", "std"]
thread = ["std", "dep:target_os_lib"]
@ -22,6 +23,7 @@ thread = ["std", "dep:target_os_lib"]
[dependencies]
crossbeam = { workspace = true, optional = true }
chrono = { workspace = true, optional = true, features = ["std", "clock"] }
dirs = { workspace = true, optional = true }
futures = { workspace = true, optional = true, features = ["std"] }
rayon = { workspace = true, optional = true }
@ -34,4 +36,4 @@ target_os_lib = { package = "windows", version = ">=0.51", features = ["Win32_Sy
target_os_lib = { package = "libc", version = "0.2.151", optional = true }
[dev-dependencies]
tokio = { workspace = true }
tokio = { workspace = true, features = ["full"] }

View file

@ -2,7 +2,7 @@
//!
//! `#[no_std]` compatible.
//---------------------------------------------------------------------------------------------------- Use
//---------------------------------------------------------------------------------------------------- Commit
/// The current commit hash of the root Cuprate repository.
///
/// # Case & length

189
helper/src/fs.rs Normal file
View file

@ -0,0 +1,189 @@
//! Cuprate directories and filenames.
//!
//! # TODO
//! Document how environment variables can change these.
//!
//! # Reference
//! <https://github.com/Cuprate/cuprate/issues/46>
//! <https://docs.rs/dirs>
//---------------------------------------------------------------------------------------------------- Use
use std::{
path::{Path, PathBuf},
sync::OnceLock,
};
//---------------------------------------------------------------------------------------------------- Const
/// Cuprate's main directory.
///
/// This is the head PATH node used for any top-level Cuprate directories.
///
/// | OS | PATH |
/// |---------|-----------------------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
/// | Linux | `/home/alice/.config/cuprate/` |
///
/// This is shared between all Cuprate programs.
///
/// # Value
/// This is `Cuprate` on `Windows|macOS` and `cuprate` on everything else.
///
/// # Monero Equivalent
/// `.bitmonero`
pub const CUPRATE_DIR: &str = {
if cfg!(target_os = "windows") || cfg!(target_os = "macos") {
// The standard for main directories is capitalized.
"Cuprate"
} else {
// Standard on Linux + BSDs is lowercase.
"cuprate"
}
};
//---------------------------------------------------------------------------------------------------- Directories
/// Create a (private) `OnceLock` and accessor function for common PATHs used by Cuprate.
///
/// This currently creates these directories:
/// - [`cuprate_cache_dir()`]
/// - [`cuprate_config_dir()`]
/// - [`cuprate_data_dir()`]
///
/// FIXME: Use `LazyLock` when stabilized.
/// <https://github.com/rust-lang/rust/issues/109736>.
/// <https://doc.rust-lang.org/std/sync/struct.LazyLock.html>.
macro_rules! impl_dir_oncelock_and_fn {
($(
$(#[$attr:meta])* // Documentation and any `derive`'s.
$fn:ident, // Name of the corresponding access function.
$dirs_fn:ident, // Name of the `dirs` function to use, the PATH prefix.
$once_lock:ident // Name of the `OnceLock`.
),* $(,)?) => {$(
/// Local `OnceLock` containing the Path.
static $once_lock: OnceLock<PathBuf> = OnceLock::new();
// Create the `OnceLock` if needed, append
// the Cuprate directory string and return.
$(#[$attr])*
pub fn $fn() -> &'static Path {
$once_lock.get_or_init(|| {
// There's nothing we can do but panic if
// we cannot acquire critical system directories.
//
// Although, this realistically won't panic on
// normal systems for all OS's supported by `dirs`.
let mut path = dirs::$dirs_fn().unwrap();
// FIXME:
// Consider a user who does `HOME=/ ./cuprated`
//
// Should we say "that's stupid" and panic here?
// Or should it be respected?
// We really don't want a `rm -rf /` type of situation...
assert!(
path.parent().is_some(),
"SAFETY: returned OS PATH was either root or empty, aborting"
);
// Returned OS PATH should be absolute, not relative.
assert!(path.is_absolute(), "SAFETY: returned OS PATH was not absolute");
path.push(CUPRATE_DIR);
path
})
}
)*};
}
impl_dir_oncelock_and_fn! {
/// Cuprate's cache directory.
///
/// This is the PATH used for any Cuprate cache files.
///
/// | OS | PATH |
/// |---------|-----------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Local\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Caches/Cuprate/` |
/// | Linux | `/home/alice/.cache/cuprate/` |
cuprate_cache_dir,
cache_dir,
CUPRATE_CACHE_DIR,
/// Cuprate's config directory.
///
/// This is the PATH used for any Cuprate configuration files.
///
/// | OS | PATH |
/// |---------|-----------------------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
/// | Linux | `/home/alice/.config/cuprate/` |
cuprate_config_dir,
config_dir,
CUPRATE_CONFIG_DIR,
/// Cuprate's data directory.
///
/// This is the PATH used for any Cuprate data files.
///
/// | OS | PATH |
/// |---------|-----------------------------------------------------|
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
/// | Linux | `/home/alice/.local/share/cuprate/` |
cuprate_data_dir,
data_dir,
CUPRATE_DATA_DIR,
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {
use super::*;
#[test]
fn dir_sanity_check() {
assert!(cuprate_cache_dir().is_absolute());
assert!(cuprate_config_dir().is_absolute());
assert!(cuprate_data_dir().is_absolute());
if cfg!(target_os = "windows") {
let dir = cuprate_cache_dir();
println!("cuprate_cache_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Local\Cuprate"));
let dir = cuprate_config_dir();
println!("cuprate_config_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Roaming\Cuprate"));
let dir = cuprate_data_dir();
println!("cuprate_data_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Roaming\Cuprate"));
} else if cfg!(target_os = "macos") {
let dir = cuprate_cache_dir();
println!("cuprate_cache_dir: {dir:?}");
assert!(dir.ends_with("Library/Caches/Cuprate"));
let dir = cuprate_config_dir();
println!("cuprate_config_dir: {dir:?}");
assert!(dir.ends_with("Library/Application Support/Cuprate"));
let dir = cuprate_data_dir();
println!("cuprate_data_dir: {dir:?}");
assert!(dir.ends_with("Library/Application Support/Cuprate"));
} else {
// Assumes Linux.
let dir = cuprate_cache_dir();
println!("cuprate_cache_dir: {dir:?}");
assert!(dir.ends_with(".cache/cuprate"));
let dir = cuprate_config_dir();
println!("cuprate_config_dir: {dir:?}");
assert!(dir.ends_with(".config/cuprate"));
let dir = cuprate_data_dir();
println!("cuprate_data_dir: {dir:?}");
assert!(dir.ends_with(".local/share/cuprate"));
}
}
}

View file

@ -43,6 +43,9 @@ pub mod atomic;
#[cfg(feature = "constants")]
pub mod constants;
#[cfg(feature = "fs")]
pub mod fs;
pub mod network;
#[cfg(feature = "num")]