0
0
mirror of https://github.com/TeFiLeDo/listload.git synced 2024-11-01 01:56:17 +01:00

prepare persistent state

This commit is contained in:
Adrian Wannenmacher 2023-06-27 19:06:07 +02:00
parent 5233cd679a
commit 8276d92741
Signed by: tfld
GPG Key ID: 19D986ECB1E492D5
2 changed files with 96 additions and 2 deletions

View File

@ -4,8 +4,10 @@ use anyhow::Context;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use config::Config; use config::Config;
use directories::{ProjectDirs, UserDirs}; use directories::{ProjectDirs, UserDirs};
use persistent_state::PersistentState;
mod config; mod config;
mod persistent_state;
static USER_DIRS: OnceLock<UserDirs> = OnceLock::new(); static USER_DIRS: OnceLock<UserDirs> = OnceLock::new();
static PROJ_DIRS: OnceLock<ProjectDirs> = OnceLock::new(); static PROJ_DIRS: OnceLock<ProjectDirs> = OnceLock::new();
@ -35,16 +37,22 @@ fn main() -> anyhow::Result<()> {
// prepare for operation // prepare for operation
let cfg = Config::read_from_default_file().context("failed to load config")?; let cfg = Config::read_from_default_file().context("failed to load config")?;
let downloader = cfg.downloader().context("failed to create downloader")?; let downloader = cfg.downloader().context("failed to create downloader")?;
let mut persistent =
PersistentState::read_from_default_file().context("failed to load persistent state")?;
match cli.command { match cli.command {
CMD::Config => { CMD::Config => {
println!("{cfg}"); println!("{cfg}");
Ok(())
} }
CMD::License => { CMD::License => {
panic!("license passed first check"); panic!("license passed first check");
} }
CMD::PersistentState => {
println!("{persistent}");
} }
}
persistent.save_to_default_file()
} }
#[derive(Parser)] #[derive(Parser)]
@ -56,8 +64,10 @@ struct CLI {
#[derive(Subcommand)] #[derive(Subcommand)]
enum CMD { enum CMD {
/// Print out the current configuration. /// Print the current configuration.
Config, Config,
/// Print the EUPL 1.2, under which this program is licensed. /// Print the EUPL 1.2, under which this program is licensed.
License, License,
/// Print the current persistent state.
PersistentState,
} }

84
src/persistent_state.rs Normal file
View File

@ -0,0 +1,84 @@
use std::{
fmt::Display,
fs::{create_dir_all, File},
io::{BufReader, BufWriter, Read, Write},
path::Path,
};
use anyhow::{bail, ensure, Context};
use serde::{Deserialize, Serialize};
use crate::PROJ_DIRS;
const PERSISTENT_FILE: &str = "persistent_state.json";
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct PersistentState {}
impl PersistentState {
pub fn read_from_default_file() -> anyhow::Result<Self> {
let dirs = PROJ_DIRS.get().expect("directories not initialized");
let mut path = dirs.preference_dir().to_path_buf();
path.push(PERSISTENT_FILE);
if path.is_file() {
Self::read_from_file(&path)
} else if !path.exists() {
Ok(Self::default())
} else {
bail!("persistent state file is neither file nor nonexistant")
}
}
pub fn read_from_file(path: &Path) -> anyhow::Result<Self> {
File::open(path)
.context("failed to open persistent state file")
.map(|r| BufReader::new(r))
.and_then(|r| Self::read_from(r))
}
pub fn read_from(reader: impl Read) -> anyhow::Result<Self> {
serde_json::from_reader(reader).context("failed to parse persistent state file")
}
pub fn save_to_default_file(&self) -> anyhow::Result<()> {
let dirs = PROJ_DIRS.get().expect("directories not initialized");
let mut path = dirs.preference_dir().to_path_buf();
ensure!(
path.is_dir() || !path.exists(),
"preference directory is neither directory nor nonexistent"
);
if !path.exists() {
create_dir_all(&path).context("failed to create program preference directory")?;
}
path.push(PERSISTENT_FILE);
ensure!(
path.is_file() || !path.exists(),
"persistent state file is neither file nor nonexistant"
);
self.save_to_file(&path)
}
pub fn save_to_file(&self, path: &Path) -> anyhow::Result<()> {
File::create(path)
.context("failed to create persistent state file")
.map(|w| BufWriter::new(w))
.and_then(|w| self.save_to(w))
}
pub fn save_to(&self, writer: impl Write) -> anyhow::Result<()> {
serde_json::to_writer(writer, &self).context("failed to write persistent state file")
}
}
impl Display for PersistentState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "no persistent state yet")
}
}