/* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2023 metamuffin */ use crate::{Action, MigrateMode}; use anyhow::{bail, Context}; use indicatif::ProgressIterator; use jellybase::database::{typed_sled::Tree, Database}; use log::{info, warn}; use serde::Serialize; use std::{ fs::File, io::{BufRead, BufReader, BufWriter, Write}, path::Path, }; pub(crate) fn migrate(action: Action) -> anyhow::Result<()> { match action { Action::Migrate { mode, save_location, database, } => { std::fs::create_dir_all(&save_location)?; let db = Database::open(&database)?; info!("processing 'user'"); process_tree(mode, &save_location.join("user"), &db.user)?; info!("processing 'user_node'"); process_tree(mode, &save_location.join("user_node"), &db.user_node)?; info!("processing 'invite'"); process_tree(mode, &save_location.join("invite"), &db.invite)?; info!("processing 'node'"); process_tree(mode, &save_location.join("node"), &db.node)?; info!("done"); Ok(()) } _ => unreachable!(), } } fn process_tree< K: Serialize + for<'de> serde::Deserialize<'de>, V: Serialize + for<'de> serde::Deserialize<'de>, >( mode: MigrateMode, path: &Path, tree: &Tree, ) -> anyhow::Result<()> { match mode { MigrateMode::Export => export_tree(path, tree), MigrateMode::Import => import_tree(path, tree), } } fn export_tree< K: Serialize + for<'de> serde::Deserialize<'de>, V: Serialize + for<'de> serde::Deserialize<'de>, >( path: &Path, tree: &Tree, ) -> anyhow::Result<()> { let mut o = BufWriter::new(File::create(path)?); let len = tree.len(); for r in tree.iter().progress_count(len.try_into().unwrap()) { let (k, v) = r?; serde_json::to_writer(&mut o, &(k, v))?; writeln!(&mut o)?; } Ok(()) } fn import_tree< K: Serialize + for<'de> serde::Deserialize<'de>, V: Serialize + for<'de> serde::Deserialize<'de>, >( path: &Path, tree: &Tree, ) -> anyhow::Result<()> { if !tree.is_empty() { bail!("tree not empty, `rm -rf` your db please :)") } let Ok(i) = File::open(path) else { warn!("{path:?} does not exist; the import of that tree will be skipped."); return Ok(()); }; let i = BufReader::new(i); for l in i.lines() { let l = l?; let (k, v) = serde_json::from_str::<(K, V)>(&l).context("reading db dump item")?; tree.insert(&k, &v)?; } Ok(()) }