Store repo names and selected repo in state
This commit is contained in:
parent
427dce3e48
commit
3a3a2de8dc
4 changed files with 97 additions and 10 deletions
|
|
@ -9,12 +9,22 @@ pub struct Command {}
|
||||||
impl Command {
|
impl Command {
|
||||||
pub fn run(self, env: &Environment) -> anyhow::Result<()> {
|
pub fn run(self, env: &Environment) -> anyhow::Result<()> {
|
||||||
let data_dir = gdn::data::open(env.data_dir.clone())?;
|
let data_dir = gdn::data::open(env.data_dir.clone())?;
|
||||||
|
let state = gdn::data::load_state(&data_dir)?;
|
||||||
|
|
||||||
println!("Data dir version: {}", gdn::data::VERSION);
|
println!("Data dir version: {}", gdn::data::VERSION);
|
||||||
|
|
||||||
let state = gdn::data::load_state(&data_dir)?;
|
println!();
|
||||||
match state.name {
|
if state.repos.is_empty() {
|
||||||
Some(name) => println!("Name: {name}"),
|
println!("No repos");
|
||||||
None => println!("No name"),
|
} else {
|
||||||
|
println!("Repos ({}):", state.repos.len());
|
||||||
|
for (id, name) in &state.repos {
|
||||||
|
if state.selected_repo == Some(*id) {
|
||||||
|
println!("- {name} ({id}, selected)");
|
||||||
|
} else {
|
||||||
|
println!("- {name} ({id})");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ mod v1;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
datadir::{LockedDataDir, UnlockedDataDir},
|
datadir::{LockedDataDir, UnlockedDataDir},
|
||||||
v1::{State, VERSION, load_state, save_state},
|
v1::{State, VERSION, load_state, tidy},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn migrate(dir: &LockedDataDir) -> anyhow::Result<()> {
|
fn migrate(dir: &LockedDataDir) -> anyhow::Result<()> {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ pub const VERSION: u32 = 0;
|
||||||
|
|
||||||
pub fn migrate(dir: &LockedDataDir) -> anyhow::Result<()> {
|
pub fn migrate(dir: &LockedDataDir) -> anyhow::Result<()> {
|
||||||
dir.require_version(VERSION)?;
|
dir.require_version(VERSION)?;
|
||||||
v1::save_state(dir, &v1::State::default())?;
|
v1::save_state(dir, v1::State::default())?;
|
||||||
dir.write_version(v1::VERSION)?;
|
dir.write_version(v1::VERSION)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,101 @@
|
||||||
use std::path::PathBuf;
|
use std::{collections::HashMap, fs, path::PathBuf};
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::ids::RepoId;
|
||||||
|
|
||||||
use super::{LockedDataDir, UnlockedDataDir};
|
use super::{LockedDataDir, UnlockedDataDir};
|
||||||
|
|
||||||
pub const VERSION: u32 = 1;
|
pub const VERSION: u32 = 1;
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub name: Option<String>,
|
pub repos: HashMap<RepoId, String>,
|
||||||
|
pub selected_repo: Option<RepoId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn normalize(&mut self) {
|
||||||
|
if let Some(selected) = self.selected_repo {
|
||||||
|
if !self.repos.contains_key(&selected) {
|
||||||
|
self.selected_repo = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state_file(dir: &UnlockedDataDir) -> PathBuf {
|
pub fn state_file(dir: &UnlockedDataDir) -> PathBuf {
|
||||||
dir.path().join("state.json")
|
dir.path().join("state.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn repos_dir(dir: &UnlockedDataDir) -> PathBuf {
|
||||||
|
dir.path().join("repos")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repo_dir(dir: &UnlockedDataDir, id: RepoId) -> PathBuf {
|
||||||
|
repos_dir(dir).join(id.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_state(dir: &UnlockedDataDir) -> anyhow::Result<State> {
|
pub fn load_state(dir: &UnlockedDataDir) -> anyhow::Result<State> {
|
||||||
dir.read_json(&state_file(dir))
|
dir.read_json(&state_file(dir))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_state(dir: &LockedDataDir, state: &State) -> anyhow::Result<()> {
|
pub fn save_state(dir: &LockedDataDir, mut state: State) -> anyhow::Result<()> {
|
||||||
dir.write_json(&state_file(dir), state)
|
state.normalize();
|
||||||
|
dir.write_json(&state_file(dir), &state)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_repo(dir: &LockedDataDir, name: String) -> anyhow::Result<RepoId> {
|
||||||
|
let id = RepoId::new();
|
||||||
|
|
||||||
|
let mut state = load_state(dir)?;
|
||||||
|
state.repos.insert(id, name);
|
||||||
|
save_state(dir, state)?;
|
||||||
|
|
||||||
|
fs::create_dir_all(repos_dir(dir))?;
|
||||||
|
// TODO Initialize bare repo
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_repo(dir: &LockedDataDir, id: RepoId) -> anyhow::Result<()> {
|
||||||
|
let mut state = load_state(dir)?;
|
||||||
|
state.repos.remove(&id).is_none();
|
||||||
|
save_state(dir, state)?;
|
||||||
|
|
||||||
|
// TODO Check if this works with read-only files
|
||||||
|
fs::remove_dir_all(repo_dir(dir, id))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_repo_name(dir: &LockedDataDir, id: RepoId, name: String) -> anyhow::Result<()> {
|
||||||
|
let mut state = load_state(dir)?;
|
||||||
|
*state
|
||||||
|
.repos
|
||||||
|
.get_mut(&id)
|
||||||
|
.ok_or_else(|| anyhow!("no repo with id {id}"))? = name;
|
||||||
|
save_state(dir, state)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_repo(dir: &LockedDataDir, id: Option<RepoId>) -> anyhow::Result<()> {
|
||||||
|
let mut state = load_state(dir)?;
|
||||||
|
state.selected_repo = id;
|
||||||
|
save_state(dir, state)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tidy(dir: &LockedDataDir) -> anyhow::Result<()> {
|
||||||
|
let state = load_state(dir)?;
|
||||||
|
|
||||||
|
// TODO Detect repo dirs that should not exist, and let the user now.
|
||||||
|
//
|
||||||
|
// The repo dir contains very important user data. To avoid data loss, we
|
||||||
|
// must not delete files or directories that should not exist. Instead, we
|
||||||
|
// should let the user know so they can check if they want to keep them.
|
||||||
|
|
||||||
|
// TODO Create repos that don't exist.
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue