scarb 0.5.2

The Cairo package manager
Documentation
use std::{fmt, path};

use camino::{Utf8Path, Utf8PathBuf};
use once_cell::sync::OnceCell;
use tracing::trace;

use crate::internal::fsx;

pub struct LazyDirectoryCreator<'p> {
    path: Utf8PathBuf,
    creation_lock: OnceCell<()>,
    parent: Option<&'p LazyDirectoryCreator<'p>>,
    is_output_dir: bool,
}

impl<'p> LazyDirectoryCreator<'p> {
    pub fn new(path: impl Into<Utf8PathBuf>) -> Self {
        Self {
            path: path.into(),
            creation_lock: OnceCell::new(),
            parent: None,
            is_output_dir: false,
        }
    }

    pub fn new_output_dir(path: impl Into<Utf8PathBuf>) -> Self {
        Self {
            is_output_dir: true,
            ..Self::new(path)
        }
    }

    pub fn child(&'p self, path: impl AsRef<Utf8Path>) -> Self {
        Self {
            path: self.path.join(path),
            creation_lock: OnceCell::new(),
            parent: Some(self),
            is_output_dir: false,
        }
    }

    pub fn as_unchecked(&self) -> &Utf8Path {
        &self.path
    }

    pub fn as_existent(&self) -> anyhow::Result<&Utf8Path> {
        self.ensure_created()?;
        Ok(&self.path)
    }

    pub const fn is_output_dir(&self) -> bool {
        self.is_output_dir
    }

    fn ensure_created(&self) -> anyhow::Result<()> {
        if let Some(parent) = self.parent {
            parent.ensure_created()?;
        }

        self.creation_lock
            .get_or_try_init(|| {
                trace!(
                    "creating directory {}; output_dir={}",
                    &self.path,
                    self.is_output_dir
                );

                if self.is_output_dir {
                    create_output_dir::create_output_dir(self.path.as_std_path())
                } else {
                    fsx::create_dir_all(&self.path)
                }
            })
            .copied()
    }
}

impl<'p> fmt::Display for LazyDirectoryCreator<'p> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_unchecked())
    }
}

impl<'p> fmt::Debug for LazyDirectoryCreator<'p> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let base = self
            .parent
            .map(|p| p.path.as_path())
            .unwrap_or_else(|| Utf8Path::new(""));
        if let Ok(stem) = self.path.strip_prefix(base) {
            write!(f, "<{base}>{}{stem}", path::MAIN_SEPARATOR)?;
        } else {
            write!(f, "{}", self.path)?;
            if let Some(parent) = self.parent {
                write!(f, r#", parent: "{}""#, parent.path)?;
            }
        }

        if self.creation_lock.get().is_some() {
            write!(f, ", created")?;
        }

        if self.is_output_dir {
            write!(f, ", output")?;
        }

        Ok(())
    }
}