feat(core): add csv dep + import error variants
Adds csv = "1" to relicario-core; introduces ImportCsvHeader and ImportCsvFormat. Foundation for the import_lastpass module landing in Task 2. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
28
Cargo.lock
generated
28
Cargo.lock
generated
@@ -437,6 +437,27 @@ dependencies = [
|
|||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
|
||||||
|
dependencies = [
|
||||||
|
"csv-core",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv-core"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "curve25519-dalek"
|
name = "curve25519-dalek"
|
||||||
version = "4.1.3"
|
version = "4.1.3"
|
||||||
@@ -1609,6 +1630,7 @@ dependencies = [
|
|||||||
"bip39",
|
"bip39",
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"csv",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"getrandom 0.2.17",
|
"getrandom 0.2.17",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -1696,6 +1718,12 @@ version = "1.0.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
|||||||
@@ -29,5 +29,6 @@ getrandom = "0.2"
|
|||||||
zstd = { version = "0.13", default-features = false }
|
zstd = { version = "0.13", default-features = false }
|
||||||
tar = { version = "0.4", default-features = false }
|
tar = { version = "0.4", default-features = false }
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
|
csv = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -51,6 +51,17 @@ pub enum RelicarioError {
|
|||||||
#[error("backup envelope schema v{found}; this relicario reads v{expected}")]
|
#[error("backup envelope schema v{found}; this relicario reads v{expected}")]
|
||||||
BackupSchemaMismatch { found: u32, expected: u32 },
|
BackupSchemaMismatch { found: u32, expected: u32 },
|
||||||
|
|
||||||
|
/// CSV header doesn't match the LastPass column layout.
|
||||||
|
#[error("unrecognized CSV header — expected LastPass export format ({0})")]
|
||||||
|
ImportCsvHeader(String),
|
||||||
|
|
||||||
|
/// CSV body could not be parsed (mismatched quoting, encoding, etc.).
|
||||||
|
/// Per-row record errors that the importer recovers from become
|
||||||
|
/// `ImportWarning` entries — this variant is reserved for failures
|
||||||
|
/// that abort the whole import.
|
||||||
|
#[error("CSV parse failed: {0}")]
|
||||||
|
ImportCsvFormat(String),
|
||||||
|
|
||||||
/// An item was looked up by ID but does not exist in the manifest.
|
/// An item was looked up by ID but does not exist in the manifest.
|
||||||
#[error("item not found: {0}")]
|
#[error("item not found: {0}")]
|
||||||
ItemNotFound(String),
|
ItemNotFound(String),
|
||||||
@@ -156,4 +167,15 @@ mod tests {
|
|||||||
let s = format!("{}", schema);
|
let s = format!("{}", schema);
|
||||||
assert!(s.contains("v2") && s.contains("v1"));
|
assert!(s.contains("v2") && s.contains("v1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn import_errors_carry_useful_messages() {
|
||||||
|
let h = RelicarioError::ImportCsvHeader("missing 'name' column".into());
|
||||||
|
assert!(format!("{}", h).contains("LastPass"));
|
||||||
|
assert!(format!("{}", h).contains("missing 'name'"));
|
||||||
|
|
||||||
|
let f = RelicarioError::ImportCsvFormat("unterminated quote at line 12".into());
|
||||||
|
assert!(format!("{}", f).contains("CSV parse failed"));
|
||||||
|
assert!(format!("{}", f).contains("unterminated quote"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user