diff --git a/Cargo.lock b/Cargo.lock index 554df33f7..518421334 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,6 +83,7 @@ version = "0.0.0" dependencies = [ "ammonia", "anki_i18n", + "anki_io", "anki_proto", "anyhow", "async-compression", @@ -184,10 +185,19 @@ dependencies = [ "workspace-hack", ] +[[package]] +name = "anki_io" +version = "0.0.0" +dependencies = [ + "snafu", + "tempfile", +] + [[package]] name = "anki_proto" version = "0.0.0" dependencies = [ + "anki_io", "anyhow", "inflections", "num_enum", @@ -1148,13 +1158,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1935,13 +1945,13 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2033,9 +2043,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libsqlite3-sys" @@ -2117,9 +2127,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "lock_api" @@ -3415,16 +3425,16 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.37.5" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e78cc525325c06b4a7ff02db283472f3c042b7ff0c391f96c6d5ac6f4f91b75" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -3906,15 +3916,16 @@ checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e0babae9c..365f85b87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "rslib/i18n_helpers", "rslib/linkchecker", "rslib/proto", + "rslib/io", "pylib/rsbridge", "build/configure", "build/ninja_gen", diff --git a/rslib/Cargo.toml b/rslib/Cargo.toml index 6e9d73c14..e8060ca4b 100644 --- a/rslib/Cargo.toml +++ b/rslib/Cargo.toml @@ -43,6 +43,7 @@ features = ["json", "socks", "stream", "multipart"] [dependencies] anki_i18n = { path = "i18n" } +anki_io = { path = "io" } anki_proto = { path = "proto" } csv = { git = "https://github.com/ankitects/rust-csv.git", rev = "1c9d3aab6f79a7d815c69f925a46a4590c115f90" } diff --git a/rslib/io/Cargo.toml b/rslib/io/Cargo.toml new file mode 100644 index 000000000..5e26b924d --- /dev/null +++ b/rslib/io/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "anki_io" +publish = false +description = "Utils for better I/O error reporting" + +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true + +[dependencies] +snafu = "0.7.4" +tempfile = "3.6.0" diff --git a/rslib/src/error/file_io.rs b/rslib/io/src/error.rs similarity index 97% rename from rslib/src/error/file_io.rs rename to rslib/io/src/error.rs index bc3689ac8..656f994b7 100644 --- a/rslib/src/error/file_io.rs +++ b/rslib/io/src/error.rs @@ -65,7 +65,7 @@ impl FileIoError { ) } - pub(crate) fn is_not_found(&self) -> bool { + pub fn is_not_found(&self) -> bool { self.source.kind() == std::io::ErrorKind::NotFound } } diff --git a/rslib/src/io.rs b/rslib/io/src/lib.rs similarity index 78% rename from rslib/src/io.rs rename to rslib/io/src/lib.rs index b97715650..b4983be84 100644 --- a/rslib/src/io.rs +++ b/rslib/io/src/lib.rs @@ -1,23 +1,33 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +mod error; + use std::fs::File; use std::io::Read; use std::io::Seek; use std::path::Component; use std::path::Path; +use snafu::ResultExt; use tempfile::NamedTempFile; -use crate::error::FileIoError; -use crate::error::FileIoSnafu; -use crate::error::FileOp; -use crate::prelude::*; +pub use crate::error::FileIoError; +pub use crate::error::FileIoSnafu; +pub use crate::error::FileOp; -pub(crate) type Result = std::result::Result; +pub type Result = std::result::Result; + +/// See [File::create]. +pub fn create_file(path: impl AsRef) -> Result { + File::create(&path).context(FileIoSnafu { + path: path.as_ref(), + op: FileOp::Create, + }) +} /// See [File::open]. -pub(crate) fn open_file(path: impl AsRef) -> Result { +pub fn open_file(path: impl AsRef) -> Result { File::open(&path).context(FileIoSnafu { path: path.as_ref(), op: FileOp::Open, @@ -25,7 +35,7 @@ pub(crate) fn open_file(path: impl AsRef) -> Result { } /// See [std::fs::write]. -pub(crate) fn write_file(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result<()> { +pub fn write_file(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result<()> { std::fs::write(&path, contents).context(FileIoSnafu { path: path.as_ref(), op: FileOp::Write, @@ -34,7 +44,7 @@ pub(crate) fn write_file(path: impl AsRef, contents: impl AsRef<[u8]>) -> /// See [std::fs::remove_file]. #[allow(dead_code)] -pub(crate) fn remove_file(path: impl AsRef) -> Result<()> { +pub fn remove_file(path: impl AsRef) -> Result<()> { std::fs::remove_file(&path).context(FileIoSnafu { path: path.as_ref(), op: FileOp::Remove, @@ -42,7 +52,7 @@ pub(crate) fn remove_file(path: impl AsRef) -> Result<()> { } /// See [std::fs::create_dir]. -pub(crate) fn create_dir(path: impl AsRef) -> Result<()> { +pub fn create_dir(path: impl AsRef) -> Result<()> { std::fs::create_dir(&path).context(FileIoSnafu { path: path.as_ref(), op: FileOp::Create, @@ -50,7 +60,7 @@ pub(crate) fn create_dir(path: impl AsRef) -> Result<()> { } /// See [std::fs::create_dir_all]. -pub(crate) fn create_dir_all(path: impl AsRef) -> Result<()> { +pub fn create_dir_all(path: impl AsRef) -> Result<()> { std::fs::create_dir_all(&path).context(FileIoSnafu { path: path.as_ref(), op: FileOp::Create, @@ -58,7 +68,7 @@ pub(crate) fn create_dir_all(path: impl AsRef) -> Result<()> { } /// See [std::fs::read]. -pub(crate) fn read_file(path: impl AsRef) -> Result> { +pub fn read_file(path: impl AsRef) -> Result> { std::fs::read(&path).context(FileIoSnafu { path: path.as_ref(), op: FileOp::Read, @@ -67,7 +77,7 @@ pub(crate) fn read_file(path: impl AsRef) -> Result> { /// Like [read_file], but skips the section that is potentially locked by /// SQLite. -pub(crate) fn read_locked_db_file(path: impl AsRef) -> Result> { +pub fn read_locked_db_file(path: impl AsRef) -> Result> { read_locked_db_file_inner(&path).context(FileIoSnafu { path: path.as_ref(), op: FileOp::Read, @@ -94,28 +104,28 @@ fn read_locked_db_file_inner(path: impl AsRef) -> std::io::Result> } /// See [std::fs::metadata]. -pub(crate) fn metadata(path: impl AsRef) -> Result { +pub fn metadata(path: impl AsRef) -> Result { std::fs::metadata(&path).context(FileIoSnafu { path: path.as_ref(), op: FileOp::Metadata, }) } -pub(crate) fn new_tempfile() -> Result { +pub fn new_tempfile() -> Result { NamedTempFile::new().context(FileIoSnafu { path: std::env::temp_dir(), op: FileOp::Create, }) } -pub(crate) fn new_tempfile_in(dir: impl AsRef) -> Result { +pub fn new_tempfile_in(dir: impl AsRef) -> Result { NamedTempFile::new_in(&dir).context(FileIoSnafu { path: dir.as_ref(), op: FileOp::Create, }) } -pub(crate) fn new_tempfile_in_parent_of(file: &Path) -> Result { +pub fn new_tempfile_in_parent_of(file: &Path) -> Result { let dir = file.parent().unwrap_or(file); NamedTempFile::new_in(dir).context(FileIoSnafu { path: dir, @@ -129,7 +139,7 @@ pub(crate) fn new_tempfile_in_parent_of(file: &Path) -> Result { /// folder is synced on UNIX platforms after renaming. This minimizes the /// chances of corruption if there is a crash or power loss directly after the /// op, but it can be considerably slower. -pub(crate) fn atomic_rename(file: NamedTempFile, target: &Path, fsync: bool) -> Result<()> { +pub fn atomic_rename(file: NamedTempFile, target: &Path, fsync: bool) -> Result<()> { if fsync { file.as_file().sync_all().context(FileIoSnafu { path: file.path(), @@ -150,7 +160,7 @@ pub(crate) fn atomic_rename(file: NamedTempFile, target: &Path, fsync: bool) -> } /// Like [std::fs::read_dir], but only yielding files. [Err]s are not filtered. -pub(crate) fn read_dir_files(path: impl AsRef) -> Result { +pub fn read_dir_files(path: impl AsRef) -> Result { std::fs::read_dir(&path) .map(ReadDirFiles) .context(FileIoSnafu { @@ -160,7 +170,7 @@ pub(crate) fn read_dir_files(path: impl AsRef) -> Result { } /// True if name does not contain any path separators. -pub(crate) fn filename_is_safe(name: &str) -> bool { +pub fn filename_is_safe(name: &str) -> bool { let mut components = Path::new(name).components(); let first_element_normal = components .next() @@ -170,7 +180,7 @@ pub(crate) fn filename_is_safe(name: &str) -> bool { first_element_normal && components.next().is_none() } -pub(crate) struct ReadDirFiles(std::fs::ReadDir); +pub struct ReadDirFiles(std::fs::ReadDir); impl Iterator for ReadDirFiles { type Item = std::io::Result; diff --git a/rslib/proto/Cargo.toml b/rslib/proto/Cargo.toml index c3109e19e..2c01f6188 100644 --- a/rslib/proto/Cargo.toml +++ b/rslib/proto/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [build-dependencies] +anki_io = { version = "0.0.0", path = "../io" } anyhow = "1.0.71" inflections = "1.1.1" prost-build = "0.11.9" diff --git a/rslib/proto/python.rs b/rslib/proto/python.rs index 5b9ab966d..063306974 100644 --- a/rslib/proto/python.rs +++ b/rslib/proto/python.rs @@ -1,12 +1,11 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -use std::fs::File; use std::io::BufWriter; use std::io::Write; use std::path::Path; -use anyhow::Context; +use anki_io::create_file; use anyhow::Result; use inflections::Inflect; use prost_reflect::DescriptorPool; @@ -18,9 +17,7 @@ use prost_reflect::ServiceDescriptor; pub(crate) fn write_python_interface(pool: &DescriptorPool) -> Result<()> { let output_path = Path::new("../../out/pylib/anki/_backend_generated.py"); - let mut out = BufWriter::new( - File::create(output_path).with_context(|| format!("opening {output_path:?}"))?, - ); + let mut out = BufWriter::new(create_file(output_path)?); write_header(&mut out)?; for service in pool.services() { diff --git a/rslib/proto/rust.rs b/rslib/proto/rust.rs index 6762a9a4c..fb4247ee0 100644 --- a/rslib/proto/rust.rs +++ b/rslib/proto/rust.rs @@ -7,6 +7,8 @@ use std::fs; use std::path::Path; use std::path::PathBuf; +use anki_io::create_dir_all; +use anki_io::read_file; use anyhow::Context; use anyhow::Result; use prost_build::ServiceGenerator; @@ -17,13 +19,11 @@ pub fn write_backend_proto_rs(descriptors_path: &Path) -> Result let proto_dir = PathBuf::from("../../proto"); let paths = gather_proto_paths(&proto_dir)?; let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - fs::create_dir_all( + create_dir_all( descriptors_path .parent() - .context("no parent found for descriptors path")?, - ) - .with_context(|| format!("creating {descriptors_path:?}"))?; - + .context("missing parent of descriptor")?, + )?; prost_build::Config::new() .out_dir(&out_dir) .file_descriptor_set_path(descriptors_path) @@ -57,8 +57,7 @@ pub fn write_backend_proto_rs(descriptors_path: &Path) -> Result } fn write_service_index(out_dir: &Path, descriptors_path: &Path) -> Result { - let descriptors = fs::read(descriptors_path) - .with_context(|| format!("failed to read {descriptors_path:?}"))?; + let descriptors = read_file(descriptors_path)?; let pool = DescriptorPool::decode(descriptors.as_ref()).context("unable to decode descriptors")?; let mut buf = String::new(); diff --git a/rslib/src/collection/backup.rs b/rslib/src/collection/backup.rs index fd061f301..0918fc5a3 100644 --- a/rslib/src/collection/backup.rs +++ b/rslib/src/collection/backup.rs @@ -11,13 +11,13 @@ use std::thread; use std::thread::JoinHandle; use std::time::SystemTime; +use anki_io::read_locked_db_file; use anki_proto::config::preferences::BackupLimits; use chrono::prelude::*; use itertools::Itertools; use tracing::error; use crate::import_export::package::export_colpkg_from_data; -use crate::io::read_locked_db_file; use crate::prelude::*; const BACKUP_FORMAT_STRING: &str = "backup-%Y-%m-%d-%H.%M.%S.colpkg"; diff --git a/rslib/src/collection/mod.rs b/rslib/src/collection/mod.rs index 17d43f25c..0da766549 100644 --- a/rslib/src/collection/mod.rs +++ b/rslib/src/collection/mod.rs @@ -13,12 +13,12 @@ use std::path::PathBuf; use std::sync::Arc; use anki_i18n::I18n; +use anki_io::create_dir_all; use crate::browser_table; use crate::decks::Deck; use crate::decks::DeckId; use crate::error::Result; -use crate::io::create_dir_all; use crate::notetype::Notetype; use crate::notetype::NotetypeId; use crate::scheduler::queue::CardQueues; diff --git a/rslib/src/error/mod.rs b/rslib/src/error/mod.rs index 237ba13da..8a880f0a3 100644 --- a/rslib/src/error/mod.rs +++ b/rslib/src/error/mod.rs @@ -2,7 +2,6 @@ // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html mod db; -mod file_io; mod filtered; mod invalid_input; pub(crate) mod network; @@ -12,6 +11,8 @@ mod search; pub mod windows; use anki_i18n::I18n; +use anki_io::FileIoError; +use anki_io::FileOp; use anki_proto::ProtoError; pub use db::DbError; pub use db::DbErrorKind; @@ -25,9 +26,6 @@ pub use search::ParseError; pub use search::SearchErrorKind; use snafu::Snafu; -pub use self::file_io::FileIoError; -pub use self::file_io::FileIoSnafu; -pub use self::file_io::FileOp; pub use self::invalid_input::InvalidInputError; pub use self::invalid_input::OrInvalid; pub use self::not_found::NotFoundError; diff --git a/rslib/src/image_occlusion/imagedata.rs b/rslib/src/image_occlusion/imagedata.rs index 0dfd78303..c2ca96dac 100644 --- a/rslib/src/image_occlusion/imagedata.rs +++ b/rslib/src/image_occlusion/imagedata.rs @@ -4,14 +4,14 @@ use std::path::Path; use std::path::PathBuf; +use anki_io::metadata; +use anki_io::read_file; use anki_proto::image_occlusion::get_image_occlusion_note_response::ImageClozeNote; use anki_proto::image_occlusion::get_image_occlusion_note_response::Value; use anki_proto::image_occlusion::GetImageForOcclusionResponse; use anki_proto::image_occlusion::GetImageOcclusionNoteResponse; use regex::Regex; -use crate::io::metadata; -use crate::io::read_file; use crate::media::MediaManager; use crate::notetype::CardGenContext; use crate::prelude::*; diff --git a/rslib/src/import_export/gather.rs b/rslib/src/import_export/gather.rs index 917b304e0..3182defe5 100644 --- a/rslib/src/import_export/gather.rs +++ b/rslib/src/import_export/gather.rs @@ -4,12 +4,12 @@ use std::collections::HashMap; use std::collections::HashSet; +use anki_io::filename_is_safe; use itertools::Itertools; use super::ExportProgress; use super::IncrementableProgress; use crate::decks::immediate_parent_name; -use crate::io::filename_is_safe; use crate::latex::extract_latex; use crate::prelude::*; use crate::revlog::RevlogEntry; diff --git a/rslib/src/import_export/package/apkg/export.rs b/rslib/src/import_export/package/apkg/export.rs index 114fe242d..9fd5c2d56 100644 --- a/rslib/src/import_export/package/apkg/export.rs +++ b/rslib/src/import_export/package/apkg/export.rs @@ -5,6 +5,10 @@ use std::collections::HashSet; use std::path::Path; use std::path::PathBuf; +use anki_io::atomic_rename; +use anki_io::new_tempfile; +use anki_io::new_tempfile_in_parent_of; + use super::super::meta::MetaExt; use crate::collection::CollectionBuilder; use crate::import_export::gather::ExchangeData; @@ -13,9 +17,6 @@ use crate::import_export::package::media::MediaIter; use crate::import_export::package::Meta; use crate::import_export::ExportProgress; use crate::import_export::IncrementableProgress; -use crate::io::atomic_rename; -use crate::io::new_tempfile; -use crate::io::new_tempfile_in_parent_of; use crate::prelude::*; impl Collection { diff --git a/rslib/src/import_export/package/apkg/import/media.rs b/rslib/src/import_export/package/apkg/import/media.rs index 04221b30f..f9e7ca391 100644 --- a/rslib/src/import_export/package/apkg/import/media.rs +++ b/rslib/src/import_export/package/apkg/import/media.rs @@ -5,12 +5,12 @@ use std::collections::HashMap; use std::fs::File; use std::mem; +use anki_io::FileIoSnafu; +use anki_io::FileOp; use zip::ZipArchive; use super::super::super::meta::MetaExt; use super::Context; -use crate::error::FileIoSnafu; -use crate::error::FileOp; use crate::import_export::package::media::extract_media_entries; use crate::import_export::package::media::MediaCopier; use crate::import_export::package::media::SafeMediaEntry; diff --git a/rslib/src/import_export/package/apkg/import/mod.rs b/rslib/src/import_export/package/apkg/import/mod.rs index cebee9b69..ddc32384a 100644 --- a/rslib/src/import_export/package/apkg/import/mod.rs +++ b/rslib/src/import_export/package/apkg/import/mod.rs @@ -10,6 +10,10 @@ use std::collections::HashSet; use std::fs::File; use std::path::Path; +use anki_io::new_tempfile; +use anki_io::open_file; +use anki_io::FileIoSnafu; +use anki_io::FileOp; pub(crate) use notes::NoteMeta; use rusqlite::OptionalExtension; use tempfile::NamedTempFile; @@ -17,15 +21,11 @@ use zip::ZipArchive; use super::super::meta::MetaExt; use crate::collection::CollectionBuilder; -use crate::error::FileIoSnafu; -use crate::error::FileOp; use crate::import_export::gather::ExchangeData; use crate::import_export::package::Meta; use crate::import_export::ImportProgress; use crate::import_export::IncrementableProgress; use crate::import_export::NoteLog; -use crate::io::new_tempfile; -use crate::io::open_file; use crate::media::MediaManager; use crate::prelude::*; use crate::search::SearchNode; diff --git a/rslib/src/import_export/package/apkg/tests.rs b/rslib/src/import_export/package/apkg/tests.rs index 22aa10e5d..303812ab3 100644 --- a/rslib/src/import_export/package/apkg/tests.rs +++ b/rslib/src/import_export/package/apkg/tests.rs @@ -7,7 +7,8 @@ use std::collections::HashSet; use std::fs::File; use std::io::Write; -use crate::io::read_file; +use anki_io::read_file; + use crate::media::files::sha1_of_data; use crate::media::MediaManager; use crate::prelude::*; diff --git a/rslib/src/import_export/package/colpkg/export.rs b/rslib/src/import_export/package/colpkg/export.rs index a504c03a3..04073532a 100644 --- a/rslib/src/import_export/package/colpkg/export.rs +++ b/rslib/src/import_export/package/colpkg/export.rs @@ -9,6 +9,10 @@ use std::io::Write; use std::path::Path; use std::path::PathBuf; +use anki_io::atomic_rename; +use anki_io::new_tempfile; +use anki_io::new_tempfile_in_parent_of; +use anki_io::open_file; use prost::Message; use tempfile::NamedTempFile; use zip::write::FileOptions; @@ -30,10 +34,6 @@ use crate::import_export::package::media::MediaCopier; use crate::import_export::package::media::MediaIter; use crate::import_export::ExportProgress; use crate::import_export::IncrementableProgress; -use crate::io::atomic_rename; -use crate::io::new_tempfile; -use crate::io::new_tempfile_in_parent_of; -use crate::io::open_file; use crate::prelude::*; use crate::storage::SchemaVersion; diff --git a/rslib/src/import_export/package/colpkg/import.rs b/rslib/src/import_export/package/colpkg/import.rs index c306de87b..a028c86ec 100644 --- a/rslib/src/import_export/package/colpkg/import.rs +++ b/rslib/src/import_export/package/colpkg/import.rs @@ -7,24 +7,24 @@ use std::io::Write; use std::path::Path; use std::path::PathBuf; +use anki_io::atomic_rename; +use anki_io::create_dir_all; +use anki_io::new_tempfile_in_parent_of; +use anki_io::open_file; +use anki_io::FileIoSnafu; +use anki_io::FileOp; use zip::read::ZipFile; use zip::ZipArchive; use zstd::stream::copy_decode; use super::super::meta::MetaExt; use crate::collection::CollectionBuilder; -use crate::error::FileIoSnafu; -use crate::error::FileOp; use crate::import_export::package::media::extract_media_entries; use crate::import_export::package::media::SafeMediaEntry; use crate::import_export::package::Meta; use crate::import_export::ImportError; use crate::import_export::ImportProgress; use crate::import_export::IncrementableProgress; -use crate::io::atomic_rename; -use crate::io::create_dir_all; -use crate::io::new_tempfile_in_parent_of; -use crate::io::open_file; use crate::media::MediaManager; use crate::prelude::*; diff --git a/rslib/src/import_export/package/colpkg/tests.rs b/rslib/src/import_export/package/colpkg/tests.rs index 1fe5192e5..ebda63a7b 100644 --- a/rslib/src/import_export/package/colpkg/tests.rs +++ b/rslib/src/import_export/package/colpkg/tests.rs @@ -5,12 +5,12 @@ use std::path::Path; +use anki_io::create_dir_all; +use anki_io::read_file; use tempfile::tempdir; use crate::collection::CollectionBuilder; use crate::import_export::package::import_colpkg; -use crate::io::create_dir_all; -use crate::io::read_file; use crate::media::MediaManager; use crate::prelude::*; @@ -79,7 +79,7 @@ fn roundtrip() -> Result<()> { #[test] #[cfg(not(target_vendor = "apple"))] fn normalization_check_on_export() -> Result<()> { - use crate::io::write_file; + use anki_io::write_file; let _dir = tempdir()?; let dir = _dir.path(); diff --git a/rslib/src/import_export/package/media.rs b/rslib/src/import_export/package/media.rs index 2df102ec3..af5a092fe 100644 --- a/rslib/src/import_export/package/media.rs +++ b/rslib/src/import_export/package/media.rs @@ -12,6 +12,12 @@ use std::io::Write; use std::path::Path; use std::path::PathBuf; +use anki_io::atomic_rename; +use anki_io::filename_is_safe; +use anki_io::new_tempfile_in; +use anki_io::read_dir_files; +use anki_io::FileIoError; +use anki_io::FileOp; use prost::Message; use sha1::Digest; use sha1::Sha1; @@ -24,15 +30,9 @@ use super::meta::MetaExt; use super::MediaEntries; use super::MediaEntry; use super::Meta; -use crate::error::FileIoError; -use crate::error::FileOp; use crate::error::InvalidInputError; use crate::import_export::package::colpkg::export::MaybeEncodedWriter; use crate::import_export::ImportError; -use crate::io::atomic_rename; -use crate::io::filename_is_safe; -use crate::io::new_tempfile_in; -use crate::io::read_dir_files; use crate::media::files::filename_if_normalized; use crate::media::files::normalize_filename; use crate::prelude::*; diff --git a/rslib/src/import_export/text/csv/import.rs b/rslib/src/import_export/text/csv/import.rs index 0931ecfaf..936163b1c 100644 --- a/rslib/src/import_export/text/csv/import.rs +++ b/rslib/src/import_export/text/csv/import.rs @@ -7,6 +7,8 @@ use std::io::Read; use std::io::Seek; use std::io::SeekFrom; +use anki_io::open_file; + use crate::import_export::text::csv::metadata::CsvDeck; use crate::import_export::text::csv::metadata::CsvMetadata; use crate::import_export::text::csv::metadata::CsvMetadataHelpers; @@ -18,7 +20,6 @@ use crate::import_export::text::ForeignNote; use crate::import_export::text::NameOrId; use crate::import_export::ImportProgress; use crate::import_export::NoteLog; -use crate::io::open_file; use crate::prelude::*; use crate::text::strip_utf8_bom; diff --git a/rslib/src/import_export/text/csv/metadata.rs b/rslib/src/import_export/text/csv/metadata.rs index f755e13da..ef9c34f52 100644 --- a/rslib/src/import_export/text/csv/metadata.rs +++ b/rslib/src/import_export/text/csv/metadata.rs @@ -9,6 +9,7 @@ use std::io::Read; use std::io::Seek; use std::io::SeekFrom; +use anki_io::open_file; pub use anki_proto::import_export::csv_metadata::Deck as CsvDeck; pub use anki_proto::import_export::csv_metadata::Delimiter; pub use anki_proto::import_export::csv_metadata::DupeResolution; @@ -24,7 +25,6 @@ use crate::config::I32ConfigKey; use crate::import_export::text::csv::import::FieldSourceColumns; use crate::import_export::text::NameOrId; use crate::import_export::ImportError; -use crate::io::open_file; use crate::notetype::NoteField; use crate::prelude::*; use crate::text::html_to_text_line; diff --git a/rslib/src/import_export/text/json.rs b/rslib/src/import_export/text/json.rs index dc5f6d84f..ca7257037 100644 --- a/rslib/src/import_export/text/json.rs +++ b/rslib/src/import_export/text/json.rs @@ -1,10 +1,11 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +use anki_io::read_file; + use crate::import_export::text::ForeignData; use crate::import_export::ImportProgress; use crate::import_export::NoteLog; -use crate::io::read_file; use crate::prelude::*; impl Collection { diff --git a/rslib/src/lib.rs b/rslib/src/lib.rs index 1cb6e9ccd..aa9330218 100644 --- a/rslib/src/lib.rs +++ b/rslib/src/lib.rs @@ -18,7 +18,6 @@ pub mod error; pub mod findreplace; pub mod image_occlusion; pub mod import_export; -mod io; pub mod latex; pub mod links; pub mod log; diff --git a/rslib/src/media/check.rs b/rslib/src/media/check.rs index 7a0b9fcff..2e90fbb7c 100644 --- a/rslib/src/media/check.rs +++ b/rslib/src/media/check.rs @@ -521,13 +521,13 @@ pub(crate) mod test { use std::collections::HashMap; + use anki_io::create_dir; + use anki_io::write_file; use tempfile::tempdir; use tempfile::TempDir; use super::*; use crate::collection::CollectionBuilder; - use crate::io::create_dir; - use crate::io::write_file; fn common_setup() -> Result<(TempDir, MediaManager, Collection)> { let dir = tempdir()?; diff --git a/rslib/src/media/files.rs b/rslib/src/media/files.rs index 83e8b90ef..9a32629ac 100644 --- a/rslib/src/media/files.rs +++ b/rslib/src/media/files.rs @@ -9,6 +9,12 @@ use std::path::Path; use std::path::PathBuf; use std::time; +use anki_io::create_dir; +use anki_io::open_file; +use anki_io::write_file; +use anki_io::FileIoError; +use anki_io::FileIoSnafu; +use anki_io::FileOp; use lazy_static::lazy_static; use regex::Regex; use sha1::Digest; @@ -18,12 +24,6 @@ use unic_ucd_category::GeneralCategory; use unicode_normalization::is_nfc; use unicode_normalization::UnicodeNormalization; -use crate::error::FileIoError; -use crate::error::FileIoSnafu; -use crate::error::FileOp; -use crate::io::create_dir; -use crate::io::open_file; -use crate::io::write_file; use crate::prelude::*; use crate::sync::media::MAX_MEDIA_FILENAME_LENGTH; diff --git a/rslib/src/media/mod.rs b/rslib/src/media/mod.rs index a8b261ba0..effe56122 100644 --- a/rslib/src/media/mod.rs +++ b/rslib/src/media/mod.rs @@ -9,7 +9,8 @@ use std::collections::HashMap; use std::path::Path; use std::path::PathBuf; -use crate::io::create_dir_all; +use anki_io::create_dir_all; + use crate::media::files::add_data_to_folder_uniquely; use crate::media::files::mtime_as_i64; use crate::media::files::remove_files; diff --git a/rslib/src/search/sqlwriter.rs b/rslib/src/search/sqlwriter.rs index 5bde0fea5..c14429921 100644 --- a/rslib/src/search/sqlwriter.rs +++ b/rslib/src/search/sqlwriter.rs @@ -949,13 +949,13 @@ impl SearchNode { #[cfg(test)] mod test { + use anki_io::write_file; use tempfile::tempdir; use super::super::parser::parse; use super::*; use crate::collection::Collection; use crate::collection::CollectionBuilder; - use crate::io::write_file; // shortcut fn s(req: &mut Collection, search: &str) -> (String, Vec) { diff --git a/rslib/src/storage/upgrades/mod.rs b/rslib/src/storage/upgrades/mod.rs index bae147015..781db6ef0 100644 --- a/rslib/src/storage/upgrades/mod.rs +++ b/rslib/src/storage/upgrades/mod.rs @@ -77,9 +77,10 @@ impl SqliteStorage { #[cfg(test)] mod test { + use anki_io::new_tempfile; + use super::*; use crate::collection::CollectionBuilder; - use crate::io::new_tempfile; use crate::prelude::*; #[test] diff --git a/rslib/src/sync/collection/download.rs b/rslib/src/sync/collection/download.rs index 676d06cf0..6aa8bdacc 100644 --- a/rslib/src/sync/collection/download.rs +++ b/rslib/src/sync/collection/download.rs @@ -1,11 +1,12 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +use anki_io::atomic_rename; +use anki_io::new_tempfile_in_parent_of; +use anki_io::read_file; +use anki_io::write_file; + use crate::collection::CollectionBuilder; -use crate::io::atomic_rename; -use crate::io::new_tempfile_in_parent_of; -use crate::io::read_file; -use crate::io::write_file; use crate::prelude::*; use crate::storage::SchemaVersion; use crate::sync::collection::progress::FullSyncProgressFn; diff --git a/rslib/src/sync/collection/upload.rs b/rslib/src/sync/collection/upload.rs index 4c533a4ad..16c509a95 100644 --- a/rslib/src/sync/collection/upload.rs +++ b/rslib/src/sync/collection/upload.rs @@ -4,6 +4,9 @@ use std::fs; use std::io::Write; +use anki_io::atomic_rename; +use anki_io::new_tempfile_in_parent_of; +use anki_io::write_file; use axum::response::IntoResponse; use axum::response::Response; use flate2::write::GzEncoder; @@ -13,9 +16,6 @@ use tokio_util::io::ReaderStream; use crate::collection::CollectionBuilder; use crate::error::SyncErrorKind; -use crate::io::atomic_rename; -use crate::io::new_tempfile_in_parent_of; -use crate::io::write_file; use crate::prelude::*; use crate::storage::SchemaVersion; use crate::sync::collection::progress::FullSyncProgressFn; diff --git a/rslib/src/sync/http_server/media_manager/download.rs b/rslib/src/sync/http_server/media_manager/download.rs index 575d3efee..617858a37 100644 --- a/rslib/src/sync/http_server/media_manager/download.rs +++ b/rslib/src/sync/http_server/media_manager/download.rs @@ -4,10 +4,10 @@ use std::fs; use std::io::ErrorKind; +use anki_io::FileIoSnafu; +use anki_io::FileOp; use snafu::ResultExt; -use crate::error::FileIoSnafu; -use crate::error::FileOp; use crate::sync::error::HttpResult; use crate::sync::error::OrHttpErr; use crate::sync::http_server::media_manager::ServerMediaManager; diff --git a/rslib/src/sync/http_server/media_manager/mod.rs b/rslib/src/sync/http_server/media_manager/mod.rs index ca5214a20..8eae3d97f 100644 --- a/rslib/src/sync/http_server/media_manager/mod.rs +++ b/rslib/src/sync/http_server/media_manager/mod.rs @@ -7,7 +7,8 @@ pub mod upload; use std::path::Path; use std::path::PathBuf; -use crate::io::create_dir_all; +use anki_io::create_dir_all; + use crate::prelude::*; use crate::sync::error::HttpResult; use crate::sync::error::OrHttpErr; diff --git a/rslib/src/sync/http_server/media_manager/upload.rs b/rslib/src/sync/http_server/media_manager/upload.rs index be71070f0..cf6551c5a 100644 --- a/rslib/src/sync/http_server/media_manager/upload.rs +++ b/rslib/src/sync/http_server/media_manager/upload.rs @@ -5,14 +5,14 @@ use std::fs; use std::io::ErrorKind; use std::path::Path; +use anki_io::write_file; +use anki_io::FileIoError; +use anki_io::FileIoSnafu; +use anki_io::FileOp; use snafu::ResultExt; use tracing::info; use crate::error; -use crate::error::FileIoError; -use crate::error::FileIoSnafu; -use crate::error::FileOp; -use crate::io::write_file; use crate::sync::error::HttpResult; use crate::sync::error::OrHttpErr; use crate::sync::http_server::media_manager::ServerMediaManager; diff --git a/rslib/src/sync/http_server/mod.rs b/rslib/src/sync/http_server/mod.rs index 9e585c3c7..6189c4a4f 100644 --- a/rslib/src/sync/http_server/mod.rs +++ b/rslib/src/sync/http_server/mod.rs @@ -18,6 +18,7 @@ use std::pin::Pin; use std::sync::Arc; use std::sync::Mutex; +use anki_io::create_dir_all; use axum::extract::DefaultBodyLimit; use axum::Router; use snafu::whatever; @@ -27,7 +28,6 @@ use snafu::Whatever; use tracing::Span; use crate::error; -use crate::io::create_dir_all; use crate::media::files::sha1_of_data; use crate::sync::error::HttpResult; use crate::sync::error::OrHttpErr; diff --git a/rslib/src/sync/media/database/client/changetracker.rs b/rslib/src/sync/media/database/client/changetracker.rs index 30d51b588..5e34d324f 100644 --- a/rslib/src/sync/media/database/client/changetracker.rs +++ b/rslib/src/sync/media/database/client/changetracker.rs @@ -5,9 +5,9 @@ use std::collections::HashMap; use std::path::Path; use std::time; +use anki_io::read_dir_files; use tracing::debug; -use crate::io::read_dir_files; use crate::media::files::filename_if_normalized; use crate::media::files::mtime_as_i64; use crate::media::files::sha1_of_file; @@ -243,12 +243,12 @@ mod test { use std::time; use std::time::Duration; + use anki_io::create_dir; + use anki_io::write_file; use tempfile::tempdir; use super::*; use crate::error::Result; - use crate::io::create_dir; - use crate::io::write_file; use crate::media::files::sha1_of_data; use crate::media::MediaManager; use crate::sync::media::database::client::MediaEntry; diff --git a/rslib/src/sync/media/database/client/mod.rs b/rslib/src/sync/media/database/client/mod.rs index 3f0174fad..e58cb4fd9 100644 --- a/rslib/src/sync/media/database/client/mod.rs +++ b/rslib/src/sync/media/database/client/mod.rs @@ -321,10 +321,10 @@ fn initial_db_setup(db: &mut Connection) -> error::Result<()> { #[cfg(test)] mod test { + use anki_io::new_tempfile; use tempfile::TempDir; use crate::error::Result; - use crate::io::new_tempfile; use crate::media::files::sha1_of_data; use crate::media::MediaManager; use crate::sync::media::database::client::MediaEntry;