summaryrefslogtreecommitdiff
path: root/src/cmd/backup.rs
blob: 8f195eb8e6a6fe0561ddaf6de268672d722d6b80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use crate::client::{BackupClient, ClientConfig};
use crate::fsiter::FsIterator;
use crate::generation::Generation;
use indicatif::{ProgressBar, ProgressStyle};
use std::path::Path;
use tempfile::NamedTempFile;

const GUESS_FILE_COUNT: u64 = 0;

pub fn backup(config: &Path, buffer_size: usize) -> anyhow::Result<()> {
    let config = ClientConfig::read_config(config)?;
    let client = BackupClient::new(&config.server_url)?;

    // Create a named temporary file. We don't meed the open file
    // handle, so we discard that.
    let dbname = {
        let temp = NamedTempFile::new()?;
        let (_, dbname) = temp.keep()?;
        dbname
    };

    {
        // Create the SQLite database using the named temporary file.
        // The fetching is in its own block so that the file handles
        // get closed and data flushed to disk.
        let mut gen = Generation::create(&dbname)?;
        let progress = create_progress_bar(GUESS_FILE_COUNT);
        progress.enable_steady_tick(100);
        gen.insert_iter(FsIterator::new(&config.root).map(|entry| {
            progress.inc(1);
            match entry {
                Err(err) => Err(err),
                Ok(entry) => {
                    progress.set_message(&format!("{}", entry.path().display()));
                    client.upload_filesystem_entry(entry, buffer_size)
                }
            }
        }))?;
        progress.set_length(gen.file_count());
        progress.finish();
        println!("file count: {}", gen.file_count());
    }

    // Upload the SQLite file, i.e., the named temporary file, which
    // still exists, since we persisted it above.
    let gen_id = client.upload_generation(&dbname, buffer_size)?;
    println!("gen id: {}", gen_id);

    // Delete the temporary file.
    std::fs::remove_file(&dbname)?;

    Ok(())
}

fn create_progress_bar(file_count: u64) -> ProgressBar {
    let progress = ProgressBar::new(file_count);
    let parts = vec![
        "{wide_bar}",
        "elapsed: {elapsed}",
        "files: {pos}/{len}",
        "current: {wide_msg}",
        "{spinner}",
    ];
    progress.set_style(ProgressStyle::default_bar().template(&parts.join("\n")));
    progress
}