Add new error variant to frontend; ensure errors are mapped appropriately

This commit is contained in:
Damien Elmes 2022-03-17 20:58:35 +10:00
parent bdfa8387a5
commit f8ed4d89ba
9 changed files with 29 additions and 7 deletions

View file

@ -58,6 +58,8 @@ message BackendError {
SEARCH_ERROR = 14;
CUSTOM_STUDY_ERROR = 15;
IMPORT_ERROR = 16;
// Collection imported, but media import failed.
IMPORT_MEDIA_ERROR = 17;
}
// localized error description suitable for displaying to the user

View file

@ -33,8 +33,8 @@ message PackageMetadata {
VERSION_LEGACY_1 = 1;
// When `meta` missing, and collection.anki21 file present.
VERSION_LEGACY_2 = 2;
/// Implies MediaEntry media map, and zstd compression.
/// collection.21b file
// Implies MediaEntry media map, and zstd compression.
// collection.21b file
VERSION_LATEST = 3;
}

View file

@ -24,6 +24,7 @@ from ..errors import (
DBError,
ExistsError,
FilteredDeckError,
ImportMediaError,
Interrupted,
InvalidInput,
LocalizedError,
@ -219,6 +220,9 @@ def backend_exception_to_pylib(err: backend_pb2.BackendError) -> Exception:
elif val == kind.CUSTOM_STUDY_ERROR:
return CustomStudyError(err.localized)
elif val == kind.IMPORT_MEDIA_ERROR:
return ImportMediaError(err.localized)
else:
# sadly we can't do exhaustiveness checking on protobuf enums
# assert_exhaustive(val)

View file

@ -80,6 +80,10 @@ class AbortSchemaModification(Exception):
pass
class ImportMediaError(LocalizedError):
pass
# legacy
DeckRenameError = FilteredDeckError
AnkiError = AbortSchemaModification

View file

@ -11,7 +11,7 @@ import anki.importing as importing
import aqt.deckchooser
import aqt.forms
import aqt.modelchooser
from anki.errors import Interrupted
from anki.errors import ImportMediaError, Interrupted
from anki.importing.anki2 import V2ImportIntoV1
from anki.importing.apkg import AnkiPackageImporter
from aqt import AnkiQt, gui_hooks
@ -457,7 +457,8 @@ def replace_with_apkg(
mw: aqt.AnkiQt, filename: str, callback: Callable[[bool], None]
) -> None:
"""Tries to replace the provided collection with the provided backup,
then calls the callback. True if success.
then calls the callback. True if collection file was imported (even
if media failed).
"""
dialog = mw.progress.start(immediate=True)
timer = QTimer()
@ -495,7 +496,8 @@ def replace_with_apkg(
except Exception as error:
if not isinstance(error, Interrupted):
showWarning(str(error))
callback(False)
collection_file_imported = isinstance(error, ImportMediaError)
callback(collection_file_imported)
else:
callback(True)

View file

@ -4,7 +4,7 @@
use crate::{
backend_proto as pb,
backend_proto::backend_error::Kind,
error::{AnkiError, SyncErrorKind},
error::{AnkiError, ImportError, SyncErrorKind},
prelude::*,
};
@ -34,6 +34,7 @@ impl AnkiError {
AnkiError::MultipleNotetypesSelected => Kind::InvalidInput,
AnkiError::DatabaseCheckRequired => Kind::InvalidInput,
AnkiError::CustomStudyError(_) => Kind::CustomStudyError,
AnkiError::ImportError(ImportError::MediaImportFailed(_)) => Kind::ImportMediaError,
AnkiError::ImportError(_) => Kind::ImportError,
AnkiError::FileIoError(_) => Kind::IoError,
AnkiError::MediaCheckRequired => Kind::InvalidInput,

View file

@ -39,6 +39,7 @@ impl ImportExportService for Backend {
&input.backup_path,
&input.col_path,
&input.media_folder,
&self.tr,
self.import_progress_fn(),
)
.map(Into::into)

View file

@ -57,6 +57,7 @@ pub fn import_colpkg(
colpkg_path: &str,
target_col_path: &str,
target_media_folder: &str,
tr: &I18n,
mut progress_fn: impl FnMut(ImportProgress) -> Result<()>,
) -> Result<()> {
progress_fn(ImportProgress::Collection)?;
@ -76,7 +77,12 @@ pub fn import_colpkg(
progress_fn(ImportProgress::Collection)?;
let media_folder = Path::new(target_media_folder);
let media_import_result = restore_media(&meta, progress_fn, &mut archive, media_folder);
let media_import_result = restore_media(&meta, progress_fn, &mut archive, media_folder)
.map_err(|err| {
AnkiError::ImportError(ImportError::MediaImportFailed(
err.localized_description(tr),
))
});
// Proceed with replacing collection, regardless of media import result
tempfile.as_file().sync_all()?;

View file

@ -40,6 +40,7 @@ fn roundtrip() -> Result<()> {
for (legacy, name) in [(true, "legacy"), (false, "v3")] {
// export to a file
let col = collection_with_media(dir, name)?;
let tr = col.tr.clone();
let colpkg_name = dir.join(format!("{name}.colpkg"));
col.export_colpkg(&colpkg_name, true, legacy, |_| ())?;
// import into a new collection
@ -52,6 +53,7 @@ fn roundtrip() -> Result<()> {
&colpkg_name.to_string_lossy(),
&anki2_name,
import_media_dir.to_str().unwrap(),
&tr,
|_| Ok(()),
)?;
// confirm collection imported