Skip to content

Commit

Permalink
chore: handle parsing filename errors
Browse files Browse the repository at this point in the history
  • Loading branch information
0xRichardH committed Sep 23, 2023
1 parent 5bd1585 commit 8f7cda3
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 23 deletions.
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
- https://github.com/rusqlite/rusqlite
- https://docs.rs/rusqlite/0.29.0/rusqlite/backup/index.html
- [ ] Restore SQLite backup
- [ ] Update backup file to Google Drive
- [x] Update backup file to ~Google Drive~ **Cloudflare R2**
Binary file removed backup.db
Binary file not shown.
8 changes: 5 additions & 3 deletions src/argument.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use anyhow::Result;
use anyhow::{bail, Result};

use crate::errors::SqliteBackupError;

pub struct Argument {
pub source_path: String,
}

impl Argument {
pub fn build(args: &[String]) -> Result<Self, &'static str> {
pub fn build(args: &[String]) -> Result<Self> {
if let Some(source_path) = args.get(1) {
let argument = Self {
source_path: source_path.clone(),
};
Ok(argument)
} else {
Err("No source path provided.")
bail!(SqliteBackupError::NoSourceFileError);
}
}
}
20 changes: 20 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::{error::Error, fmt::Display};

#[derive(Debug)]
pub enum SqliteBackupError {
SourceFileError(String),
NoSourceFileError,
}

impl Error for SqliteBackupError {}

impl Display for SqliteBackupError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SqliteBackupError::SourceFileError(source) => {
write!(f, "Source file error: {}", source)
}
SqliteBackupError::NoSourceFileError => write!(f, "No source path provided."),
}
}
}
44 changes: 42 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
pub mod argument;
pub mod config;
pub mod errors;
pub mod uploader;

use std::time::Duration;
use std::{ffi::OsStr, path::Path, time::Duration};

use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use errors::SqliteBackupError;
use rusqlite::{
backup::{self, Progress},
Connection,
Expand All @@ -14,6 +16,44 @@ pub trait Backup {
fn backup(&self) -> Result<()>;
}

pub struct SqliteSourceFile<'a> {
pub path: &'a Path,
pub filename: &'a str,
pub db_name: &'a str,
pub db_extension: &'a str,
}

impl<'a> SqliteSourceFile<'a> {
pub fn from(src_path: &'a str) -> Result<Self> {
let path = Path::new(src_path);
let filename = convert_os_str_result_to_str(path.file_name())?;
let db_name = convert_os_str_result_to_str(path.file_stem())?;
let db_extension = convert_os_str_result_to_str(path.extension())?;

Ok(Self {
path,
filename,
db_name,
db_extension,
})
}
}

fn convert_os_str_result_to_str(result: Option<&OsStr>) -> Result<&str> {
if result.is_none() {
bail!(SqliteBackupError::SourceFileError(
"failed to parse source file".to_string()
));
}
if let Some(s) = result.unwrap().to_str() {
return Ok(s);
}

bail!(SqliteBackupError::SourceFileError(
"failed to convert source file to str".to_string()
));
}

pub struct SqliteBackup {
src_conn: rusqlite::Connection,
dest: String,
Expand Down
36 changes: 19 additions & 17 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,33 @@ use sqlite_backup::{
argument,
config::Config,
uploader::{R2Uploader, Uploader},
Backup, SqliteBackup,
Backup, SqliteBackup, SqliteSourceFile,
};
use std::{env, path::Path};
use std::env;

#[tokio::main]
async fn main() -> Result<()> {
let cfg = Config::load().context("load env vars")?;
let args = env::args().collect::<Vec<String>>();
match argument::Argument::build(&args) {
Ok(arg) => run(&arg).await?,
Ok(arg) => run(&arg, &cfg).await?,

Err(err) => eprintln!("Application Error: {}", err),
}

println!("Done");

Ok(())
}

async fn run(arg: &argument::Argument) -> Result<()> {
// load config/env
let config = Config::load().context("load env vars")?;

// tempfile
// TODO: Remove unwrap
let src_path = Path::new(arg.source_path.as_str());
let file_name = src_path.file_name().unwrap();
let db_name = src_path.file_stem().unwrap().to_str().unwrap();
let db_extension = src_path.extension().unwrap().to_str().unwrap();
async fn run(arg: &argument::Argument, cfg: &Config) -> Result<()> {
// create temp dir
let tmp_dir = tempfile::tempdir()?;
let dest = tmp_dir.path().join(file_name);

// backup data
let src_conn = Connection::open(arg.source_path.clone()).context("create source connection")?;
let src_file = SqliteSourceFile::from(arg.source_path.as_str()).context("parse source path")?;
let src_conn = Connection::open(src_file.path).context("create source connection")?;
let dest = tmp_dir.path().join(src_file.filename);
SqliteBackup::new(src_conn, dest.display().to_string(), |p| {
println!(
"---Progress---- pagecount: {}, remaining: {}",
Expand All @@ -45,8 +41,14 @@ async fn run(arg: &argument::Argument) -> Result<()> {
.context("backup source to destination")?;

// upload
let uploader = R2Uploader::new(&config).await;
uploader.upload_object(dest, db_name, db_extension).await?;
let uploader = R2Uploader::new(cfg).await;
uploader
.upload_object(
dest,
format!("sqlite__{}", src_file.db_name).as_str(),
src_file.db_extension,
)
.await?;

// close temp dir
tmp_dir.close()?;
Expand Down

0 comments on commit 8f7cda3

Please sign in to comment.