From 5cf1705784118c3c75ebe0a59a28777a292ed7ab Mon Sep 17 00:00:00 2001 From: RumovZ Date: Fri, 8 Apr 2022 10:22:47 +0200 Subject: [PATCH] Add import_decks() --- .../src/import_export/package/apkg/import.rs | 81 ++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/rslib/src/import_export/package/apkg/import.rs b/rslib/src/import_export/package/apkg/import.rs index 861797c81..d3595bb3f 100644 --- a/rslib/src/import_export/package/apkg/import.rs +++ b/rslib/src/import_export/package/apkg/import.rs @@ -16,6 +16,7 @@ use zip::ZipArchive; use crate::{ collection::CollectionBuilder, + decks::NormalDeck, import_export::{ gather::ExchangeData, package::{ @@ -37,6 +38,7 @@ struct Context<'a> { guid_map: HashMap, remapped_notetypes: HashMap, remapped_notes: HashMap, + remapped_decks: HashMap, data: ExchangeData, usn: Usn, /// Map of source media files, that do not already exist in the target. @@ -97,8 +99,7 @@ impl Collection { ctx.prepare_media()?; ctx.import_notetypes()?; ctx.import_notes()?; - - ctx.target_col.insert_data(&ctx.data)?; + ctx.import_decks()?; ctx.copy_media()?; Ok(()) } @@ -147,6 +148,7 @@ impl<'a> Context<'a> { conflicting_notes: HashSet::new(), remapped_notetypes: HashMap::new(), remapped_notes: HashMap::new(), + remapped_decks: HashMap::new(), used_media_entries: HashMap::new(), normalize_notes, }) @@ -322,6 +324,49 @@ impl<'a> Context<'a> { }) } + fn import_decks(&mut self) -> Result<()> { + // TODO: ensure alphabetical order, so parents are seen first + let mut renamed_parents = Vec::new(); + + for mut deck in mem::take(&mut self.data.decks) { + deck.maybe_reparent(&renamed_parents); + if let Some(original) = self.get_deck_by_name(&deck)? { + if original.is_filtered() { + deck.uniquify_name(&mut renamed_parents); + self.add_deck(&mut deck)?; + } else { + self.update_deck(&deck, original)?; + } + } else { + self.add_deck(&mut deck)?; + } + } + + Ok(()) + } + + fn add_deck(&mut self, deck: &mut Deck) -> Result<()> { + let old_id = mem::take(&mut deck.id); + self.target_col.add_deck_inner(deck, self.usn)?; + self.remapped_decks.insert(old_id, deck.id); + Ok(()) + } + + /// Caller must ensure decks are normal. + fn update_deck(&mut self, deck: &Deck, original: Deck) -> Result<()> { + let mut new_deck = original.clone(); + new_deck.normal_mut()?.update_with_other(deck.normal()?); + self.remapped_decks.insert(deck.id, new_deck.id); + self.target_col + .update_deck_inner(&mut new_deck, original, self.usn) + } + + fn get_deck_by_name(&mut self, deck: &Deck) -> Result> { + self.target_col + .storage + .get_deck_by_name(deck.name.as_native_str()) + } + fn copy_media(&mut self) -> Result<()> { for (used, entry) in self.used_media_entries.values() { if *used { @@ -332,6 +377,38 @@ impl<'a> Context<'a> { } } +impl Deck { + fn maybe_reparent(&mut self, renamed_parents: &[(String, String)]) { + if let Some(new_name) = reparented_name(self.name.as_native_str(), renamed_parents) { + self.name = NativeDeckName::from_native_str(new_name); + } + } + + fn uniquify_name(&mut self, renamed_parents: &mut Vec<(String, String)>) { + let name = self.name.as_native_str(); + let new_name = format!("{name} {}", TimestampSecs::now()); + renamed_parents.push((format!("{name}\x1f"), format!("{new_name}\x1f"))); + self.name = NativeDeckName::from_native_str(new_name); + } +} + +impl NormalDeck { + fn update_with_other(&mut self, other: &Self) { + self.markdown_description = other.markdown_description; + self.description = other.description.clone(); + if other.config_id != 1 { + self.config_id = other.config_id; + } + } +} + +fn reparented_name(name: &str, renamed_parents: &[(String, String)]) -> Option { + renamed_parents.iter().find_map(|(old_parent, new_parent)| { + name.starts_with(old_parent) + .then(|| name.replacen(old_parent, new_parent, 1)) + }) +} + impl Notetype { fn schema_hash(&self) -> [u8; 20] { let mut hasher = Sha1::new();