diff --git a/CHANGELOG.md b/CHANGELOG.md index b07f2d3e..894a250a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Rojo Changelog ## Unreleased Changes +* Fixed crash when malformed CSV files are put into a project. ([#310](https://github.com/rojo-rbx/rojo/issues/310)) ## [6.0.0 Release Candidate 1](https://github.com/rojo-rbx/rojo/releases/tag/v6.0.0-rc.1) (March 29, 2020) This release jumped from 0.6.0 to 6.0.0. Rojo has been in use in production for many users for quite a long times, and so 6.0 is a more accurate reflection of Rojo's version than a pre-1.0 version. diff --git a/src/snapshot_middleware/csv.rs b/src/snapshot_middleware/csv.rs index 9dca4747..72075a3e 100644 --- a/src/snapshot_middleware/csv.rs +++ b/src/snapshot_middleware/csv.rs @@ -8,6 +8,7 @@ use serde::Serialize; use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot}; use super::{ + error::SnapshotError, meta_file::AdjacentMetadata, middleware::{SnapshotInstanceResult, SnapshotMiddleware}, util::match_file_name, @@ -29,8 +30,10 @@ impl SnapshotMiddleware for SnapshotCsv { }; let meta_path = path.with_file_name(format!("{}.meta.json", instance_name)); + let contents = vfs.read(path)?; - let table_contents = convert_localization_csv(&vfs.read(path)?); + let table_contents = convert_localization_csv(&contents) + .map_err(|source| SnapshotError::malformed_l10n_csv(source, path))?; let mut snapshot = InstanceSnapshot::new() .name(instance_name) @@ -87,17 +90,15 @@ struct LocalizationEntry<'a> { /// https://github.com/BurntSushi/rust-csv/issues/151 /// /// This function operates in one step in order to minimize data-copying. -fn convert_localization_csv(contents: &[u8]) -> String { +fn convert_localization_csv(contents: &[u8]) -> Result { let mut reader = csv::Reader::from_reader(contents); - let headers = reader.headers().expect("TODO: Handle csv errors").clone(); + let headers = reader.headers()?.clone(); let mut records = Vec::new(); for record in reader.into_records() { - let record = record.expect("TODO: Handle csv errors"); - - records.push(record); + records.push(record?); } let mut entries = Vec::new(); @@ -128,7 +129,10 @@ fn convert_localization_csv(contents: &[u8]) -> String { entries.push(entry); } - serde_json::to_string(&entries).expect("Could not encode JSON for localization table") + let encoded = + serde_json::to_string(&entries).expect("Could not encode JSON for localization table"); + + Ok(encoded) } #[cfg(test)] diff --git a/src/snapshot_middleware/error.rs b/src/snapshot_middleware/error.rs index a686fcbc..a1c1665d 100644 --- a/src/snapshot_middleware/error.rs +++ b/src/snapshot_middleware/error.rs @@ -37,6 +37,9 @@ pub enum SnapshotError { path: PathBuf, }, + #[error("malformed CSV localization data at path {}", .path.display())] + MalformedLocalizationCsv { source: csv::Error, path: PathBuf }, + #[error(transparent)] Io { #[from] @@ -89,4 +92,11 @@ impl SnapshotError { path: path.into(), } } + + pub(crate) fn malformed_l10n_csv(source: csv::Error, path: impl Into) -> Self { + Self::MalformedLocalizationCsv { + source, + path: path.into(), + } + } }