cnf 0.6.1

Distribution-agnostic 'command not found'-handler
Documentation
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: (C) 2023 Andreas Hartmann <hartan@7x.de>
// This file is part of cnf, available at <https://gitlab.com/hartang/rust/cnf>

//! # Common directories for CNF
use anyhow::Context;
use directories::ProjectDirs;
use logerr::LoggableError;
use std::{path::PathBuf, sync::OnceLock};

/// Globally static directory storage. Accessed through the [`get()`] function of this module.
static DIRS: OnceLock<Directories> = OnceLock::new();

/// Initialize application directories.
pub(crate) fn init() {
    let project_dirs = ProjectDirs::from("de", "7x", crate::config::APP_NAME)
        .expect("cannot determine application base directories");
    let dirs = Directories::new(project_dirs);
    DIRS.set(dirs)
        .expect("app directories must be initialized exactly once");
}

pub(crate) fn get() -> &'static Directories {
    DIRS.get().expect("directories weren't initialized yet")
}

#[derive(Debug)]
pub(crate) struct Directories(ProjectDirs);

impl Directories {
    fn new(dirs: ProjectDirs) -> Self {
        Self(dirs)
    }

    /// Application alias storage directory.
    ///
    /// This directory stores all shell-based aliases created through `cnf` (e.g. in the
    /// interactive TUI with the "create alias" keybinding). Add this to your `$PATH` to make sure
    /// th aliases are picked up by e.g. your shell.
    pub(crate) fn aliases(&self) -> PathBuf {
        let path = crate::config::get()
            .alias_path
            .clone()
            .unwrap_or(self.0.data_dir().join("aliases"));
        std::fs::create_dir_all(&path)
            .with_context(|| format!("failed to create aliases directory at '{:?}'", path))
            .to_log()
            .unwrap();
        path
    }
}