Something went wrong. Try again.
npx ccusage
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170use std::{ ffi::{OsStr, OsString}, fs, path::{Path, PathBuf}, sync::{Mutex, MutexGuard},};
use assert_fs::{ TempDir, fixture::{ChildPath, FileWriteStr, PathChild, PathCreateDir},};
static ENV_LOCK: Mutex<()> = Mutex::new(());
fn env_lock() -> MutexGuard<'static, ()> { ENV_LOCK.lock().unwrap_or_else(|error| error.into_inner())}
pub struct EnvVarGuard { key: &'static str, previous: Option<OsString>, _guard: MutexGuard<'static, ()>,}
impl EnvVarGuard { pub fn set(key: &'static str, value: impl AsRef<OsStr>) -> Self { let guard = env_lock(); let previous = std::env::var_os(key); unsafe { std::env::set_var(key, value) }; Self { key, previous, _guard: guard, } }}
impl Drop for EnvVarGuard { fn drop(&mut self) { match self.previous.take() { Some(value) => unsafe { std::env::set_var(self.key, value) }, None => unsafe { std::env::remove_var(self.key) }, } }}
pub struct EnvVarsGuard { previous: Vec<(&'static str, Option<OsString>)>, _guard: MutexGuard<'static, ()>,}
impl EnvVarsGuard { pub fn set_many(vars: impl IntoIterator<Item = (&'static str, Option<OsString>)>) -> Self { let guard = env_lock(); let mut previous = Vec::new(); for (key, value) in vars { previous.push((key, std::env::var_os(key))); match value { Some(value) => unsafe { std::env::set_var(key, value) }, None => unsafe { std::env::remove_var(key) }, } } Self { previous, _guard: guard, } }}
impl Drop for EnvVarsGuard { fn drop(&mut self) { for (key, value) in self.previous.drain(..).rev() { match value { Some(value) => unsafe { std::env::set_var(key, value) }, None => unsafe { std::env::remove_var(key) }, } } }}
pub struct Fixture { dir: TempDir,}
impl Fixture { pub fn new() -> Self { Self { dir: TempDir::new().expect("failed to create temporary fixture directory"), } }
pub fn root(&self) -> &Path { self.dir.path() }
#[must_use] pub fn path(&self, path: impl AsRef<Path>) -> PathBuf { self.dir.path().join(path) }
fn child(&self, path: impl AsRef<Path>) -> ChildPath { self.dir.child(path) }
#[must_use] pub fn write_file(&self, path: impl AsRef<Path>, contents: impl AsRef<str>) -> PathBuf { let child = self.child(path); if let Some(parent) = child.path().parent() { fs::create_dir_all(parent).expect("failed to create fixture file parent directory"); } child .write_str(contents.as_ref()) .expect("failed to write fixture file"); child.path().to_path_buf() }
#[must_use] pub fn create_dir_all(&self, path: impl AsRef<Path>) -> PathBuf { let child = self.child(path); child .create_dir_all() .expect("failed to create fixture directory"); child.path().to_path_buf() }}
impl Default for Fixture { fn default() -> Self { Self::new() }}
#[macro_export]macro_rules! fs_fixture { ({ $($path:literal : $contents:expr_2021),* $(,)? }) => {{ let fixture = $crate::Fixture::new(); $( let _ = fixture.write_file($path, $contents); )* fixture }};}
#[cfg(test)]mod tests { #[test] fn creates_inline_fixture_tree() { let fixture = fs_fixture!({ "projects/example/session.jsonl": "{}\n", });
assert_eq!( std::fs::read_to_string(fixture.path("projects/example/session.jsonl")).unwrap(), "{}\n" ); }
#[test] fn creates_incremental_fixture_tree() { let fixture = fs_fixture!({}); let _ = fixture.write_file("projects/example/session/chat.jsonl", "{}\n");
assert!( fixture .path("projects/example/session/chat.jsonl") .is_file() ); }}