Skip to content

Commit

Permalink
Merge branch 'develop' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
vst committed Jan 4, 2021
2 parents a1d27d9 + 96d28f6 commit 3973de0
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# Project specific ignores:
/config*.yaml
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "rrclone"
version = "0.0.1"
authors = ["Vehbi Sinan Tunalioglu <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.8"
chrono = "0.4"
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (c) 2021, Telostat
Copyright (c) 2021, Telostat Pte Ltd
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,31 @@
# rrclone
Rclone wrapper to use YAML/JSON configuration for backup tasks

`rrclone` is an Rclone wrapper to use YAML/JSON configuration for backup tasks.

> **TODO:** Provide full README.
> **NOTE:** This is a work-in-progress application with a very limited
> functionality. Expect breaking changes and improved functionality as we move
> on.
## Installation

1. Install [rclone](https://rclone.org/install/)
2. Put `rrclone` onto `$PATH`

## Usage

1. Configure rclone
2. Prepare configuration file for `rrclone`.
3. Run `rrclone` in dry-run mode:
```sh
rrclone ./config.yaml --dry-run
```
4. Run rrclone:
```sh
rrclone ./config.yaml
```

## License

See [LICENSE](./LICENSE) file.
16 changes: 16 additions & 0 deletions config.yaml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- source_remote: source1
source_path: /
target_remote: target1
target_path: /data/backups/source1
filters:
- "+ /data/**"
- "+ /home/**"
- "- *"
- source_remote: source2
source_path: /
target_remote: target1
target_path: /data/backups/source2
filters:
- "+ /data/**"
- "+ /home/**"
- "- *"
91 changes: 91 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use chrono::Utc;
use serde::{Deserialize, Serialize};
use std::env;
use std::fs;
use std::process::Command;
use std::process::Stdio;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Task {
source_remote: String,
source_path: String,
target_remote: String,
target_path: String,
filters: Vec<String>,
}

fn main() -> Result<(), serde_yaml::Error> {
let args: Vec<String> = env::args().collect();
let dryrun = args.len() == 3 && &args[2] == "--dry-run";

let contents =
fs::read_to_string(&args[1]).expect("Something went wrong while reading the YAML file");

let result: Result<Vec<Task>, _> = serde_yaml::from_str(&contents);

match result {
Ok(tasks) => run_tasks(&tasks, dryrun),
Err(x) => log(format!("Something went wrong while decoding the YAML file {:?}:", x)),
}

Ok(())
}

fn log(msg: String) -> () {
eprintln!(
"RRCLONE>> [{}] {}",
Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(),
msg
);
}

fn run_tasks(ts: &Vec<Task>, dryrun: bool) -> () {
for t in ts {
run_task(t, dryrun)
}
}

fn run_task(t: &Task, dryrun: bool) -> () {
let tstart = Utc::now();
let source = format!("{}:{}", t.source_remote, t.source_path);
let target = format!("{}:{}", t.target_remote, t.target_path);

log(format!("Syncing from \"{}\" to \"{}\"", &source, &target));

let mut args = vec![
"-v",
"--stats-log-level",
"NOTICE",
"--stats",
"10000m",
"sync",
&source,
&target,
];

if dryrun {
args.push("--dry-run");
}

for f in &t.filters {
args.push("--filter");
args.push(f);
}

let mut child = Command::new("rclone")
.args(&args)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.expect("Failed to execute process");

let output = child.wait().expect("Failed to read stdout from the task");

let elapsed = Utc::now() - tstart;

match output.code() {
Some(0) => log(format!("Tasks finished successfully in {:?} second(s).", elapsed.num_seconds())),
Some(code) => log(format!("Task finished with errors in {:?} second(s). Error code: {}", elapsed.num_seconds(), code)),
None => log(format!("Task terminated by signal in {:?} second(s).", elapsed.num_seconds())),
}
}

0 comments on commit 3973de0

Please sign in to comment.