Skip to content
Snippets Groups Projects

Draft: Rclone support

Open Sasha requested to merge rclone into main
Compare and
2 files
+ 102
1
Preferences
File browser
Compare changes
use crate::result::Error;
use regex::Regex;
use std::io::BufRead;
use std::process::{Command, Stdio};
use which::which;
/// Returns whether rclone is installed on the system or not
#[allow(dead_code)]
fn is_rclone_installed() -> bool {
match which("rclone") {
Ok(_pathbuff) => true,
Err(_error) => false,
}
}
/// Uses rclone to copy files from a source to a destination path. Returns -1 if rclone is not installed and the usual rclone status code otherwise.
///
/// # Arguments
///
/// *`source` - The path of the folder we want to copy
///
/// *`destination` - The path of the destination folder
///
/// *`handle_function` - A function that receives the current progress percentage of the copy.
///
#[allow(dead_code)]
fn rclone_with_progress(
source: &str,
destination: &str,
handle_function: fn(usize),
) -> Result<i32, Error> {
if !is_rclone_installed() {
return Err(Error::PackageNotInstalled(String::from("rclone")));
}
//rclone copy -P -l --create-empty-src-dirs --transfers=12 --check-first <source> <destination>
let mut progress = Command::new("rclone")
.args([
"-lP",
"--create-empty-src-dirs",
"--transfers=12",
"--check-first",
"--stats-one-line",
source,
destination,
])
.stdout(Stdio::piped())
.spawn()
.unwrap();
if let Some(progress) = progress.stdout.take() {
let reader = std::io::BufReader::new(progress);
let progress_percentage_regex = Regex::new(r"(\d+)%").unwrap();
for line in reader.lines().flatten() {
if let Some(progress_percentage) = progress_percentage_regex.find(&line) {
let mut progress = progress_percentage.as_str().to_string();
// Remove trailing %;
progress.pop();
handle_function(progress.parse::<usize>().unwrap());
}
}
}
Ok(progress.wait().unwrap().code().unwrap())
}
#[cfg(test)]
mod tests {
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use tempfile::tempdir;
use super::rclone_with_progress;
#[test]
fn test_rclone_with_progress() {
let temp_source_dir = tempdir().unwrap();
let temp_destination_dir = tempdir().unwrap();
for i in 1..1000 {
let temp_file = temp_source_dir.path().join(format!("{}", i));
let mut file = File::create(temp_file).unwrap();
file.write_all(format!("{}", i).as_bytes()).unwrap();
}
let handle_function = |percentage: usize| println!("{percentage}");
let result = rclone_with_progress(
temp_source_dir.path().to_str().unwrap(),
temp_destination_dir.path().to_str().unwrap(),
handle_function,
);
assert_eq!(result.unwrap(), 0);
let destination_directory = temp_destination_dir.path().join(temp_source_dir.path());
for i in 1..1000 {
let destination_file = destination_directory.join(format!("{}", i));
let file_content = fs::read_to_string(destination_file).unwrap();
assert_eq!(file_content, format!("{}", i));
}
drop(temp_source_dir);
drop(temp_destination_dir);
}
}