Changelog keeping utility with multiple release channels
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
clpack/src/store.rs

105 lines
3.2 KiB

use crate::AppContext;
use anyhow::bail;
use faccess::PathExt;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::PathBuf;
pub struct Store<'a> {
ctx: &'a AppContext,
store_path: PathBuf,
}
impl<'a> Store<'a> {
pub fn new(ctx: &'a AppContext, init: bool) -> anyhow::Result<Self> {
let store_path = ctx.root.join(&ctx.config.data_folder);
if !store_path.is_dir() {
if init {
// Try to create it
eprintln!("Creating changelog dir: {}", store_path.display());
std::fs::create_dir_all(&store_path)?;
} else {
bail!(
"Changelog directory does not exist: {}. Use `{} init` to create it.",
ctx.binary_name,
store_path.display()
);
}
}
if !store_path.writable() {
bail!(
"Changelog directory is not writable: {}",
store_path.display()
);
}
let store = Self { store_path, ctx };
store.ensure_internal_subdirs_exist()?;
Ok(store)
}
/// Build a log entry file path.
/// This is a file in the entries storage
fn make_entry_path(&self, filename: &str) -> PathBuf {
self.store_path
.join("entries")
.join(format!("{filename}.md"))
}
/// Check if a changelog entry exists. Filename is passed without extension.
/// This only checks within the current epoch as older files are no longer present.
pub fn entry_exists(&self, name: &str) -> bool {
let path = self.make_entry_path(name);
path.exists()
}
/// Check and create internal subdirs for the clpack system
pub fn ensure_internal_subdirs_exist(&self) -> anyhow::Result<()> {
self.ensure_subdir_exists("entries")?;
// TODO
Ok(())
}
/// make sure a subdir exists, creating if needed.
///
/// Note there is no lock so there can be a TOCTOU bug later if someone deletes the path - must be checked and handled.
fn ensure_subdir_exists(&self, name: &str) -> anyhow::Result<()> {
let subdir = self.store_path.join(name);
if !subdir.is_dir() {
if subdir.exists() {
bail!(
"Changelog subdir path is clobbered, must be a writable directory or not exist (will be crated): {}",
subdir.display()
);
}
eprintln!("Creating changelog subdir: {}", subdir.display());
std::fs::create_dir_all(&subdir)?;
}
if !subdir.writable() {
bail!("Changelog subdir is not writable: {}", subdir.display());
}
std::fs::File::create(subdir.join(".gitkeep"))?;
Ok(())
}
/// Create a changelog entry file and write content to it
pub fn create_entry(&self, name: String, content: String) -> anyhow::Result<()> {
let path = self.make_entry_path(name.as_str());
let mut file = OpenOptions::new().write(true).create(true).open(&path)?;
eprintln!("Writing to file: {}", path.display());
file.write_all(content.as_bytes())?;
Ok(())
}
}