Skip to main content

lore/store/
mod.rs

1//! On-disk locations and readers for everything lore persists.
2
3pub mod definitions;
4pub mod stats;
5
6use std::env;
7use std::path::PathBuf;
8
9use anyhow::{Context, Result};
10use directories::ProjectDirs;
11
12/// Overrides for the two directories lore writes to.
13///
14/// A portable install keeps everything beside the binary, and a test needs a
15/// directory of its own. `ProjectDirs` cannot be redirected on Windows, so the
16/// override has to sit in front of it rather than inside it.
17const CONFIG_DIR: &str = "LORE_CONFIG_DIR";
18const DATA_DIR: &str = "LORE_DATA_DIR";
19
20fn project_dirs() -> Result<ProjectDirs> {
21    ProjectDirs::from("", "", "lore").context("could not determine this platform's home directory")
22}
23
24fn overridden(variable: &str) -> Option<PathBuf> {
25    env::var_os(variable)
26        .filter(|value| !value.is_empty())
27        .map(PathBuf::from)
28}
29
30/// The user's editable command library.
31///
32/// Kept in the config directory because users are expected to track it in their
33/// own git repository. Usage statistics deliberately live somewhere else so that
34/// syncing definitions never produces churn or merge conflicts.
35pub fn user_library() -> Result<PathBuf> {
36    let directory = match overridden(CONFIG_DIR) {
37        Some(directory) => directory,
38        None => project_dirs()?.config_dir().to_path_buf(),
39    };
40
41    Ok(directory.join("commands.yaml"))
42}
43
44/// The usage statistics database.
45///
46/// Machine local and never synced.
47pub fn stats_database() -> Result<PathBuf> {
48    let directory = match overridden(DATA_DIR) {
49        Some(directory) => directory,
50        None => project_dirs()?.data_dir().to_path_buf(),
51    };
52
53    Ok(directory.join("stats.db"))
54}
55
56/// lore's own clone of the repository the library syncs through.
57///
58/// In the data directory rather than beside the library, so the user's config
59/// directory never becomes a git checkout they did not ask for, and so the
60/// statistics that live next to the library on some platforms can never be
61/// committed by accident.
62pub fn sync_dir() -> Result<PathBuf> {
63    let directory = match overridden(DATA_DIR) {
64        Some(directory) => directory,
65        None => project_dirs()?.data_dir().to_path_buf(),
66    };
67
68    Ok(directory.join("sync"))
69}