Skip to content

Commit

Permalink
decouple libfoldiff from indicatif
Browse files Browse the repository at this point in the history
  • Loading branch information
yellowsink committed Sep 28, 2024
1 parent 93b418d commit ee63381
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 111 deletions.
134 changes: 110 additions & 24 deletions foldiff/src/cliutils.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anyhow::Result;
use dialoguer::Confirm;
use indicatif::{ProgressBar, ProgressStyle};
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use std::sync::LazyLock;
use std::time::Duration;
use libfoldiff::reporting::{CanBeWrappedBy, Reporter, ReporterSized, ReportingMultiWrapper};

pub fn confirm(msg: &str) -> Result<bool> {
Ok(Confirm::new().with_prompt(msg).interact()?)
Expand Down Expand Up @@ -45,34 +45,120 @@ static PROGRESS_STYLE_FINISHED: LazyLock<ProgressStyle> = LazyLock::new(|| {
).unwrap().tick_strings(SPINNER_TICKS)
});

pub fn create_spinner(msg: &str, count: bool, auto: bool) -> ProgressBar {
let s = ProgressBar::new_spinner().with_message(msg.to_string()).with_style(
if count { SPINNER_STYLE_COUNT.clone() } else { SPINNER_STYLE_SIMPLE.clone() }
);
if auto {
s.enable_steady_tick(Duration::from_millis(50));
s.tick();
// implement libfoldiff::reporting for indicatif

pub struct Spinner<const COUNT: bool>(ProgressBar);

impl<const COUNT: bool> Reporter for Spinner<COUNT> {
fn new(msg: &str) -> Self {
Self(ProgressBar::new_spinner()
.with_message(msg.to_string())
.with_style(
if COUNT { SPINNER_STYLE_COUNT.clone() } else { SPINNER_STYLE_SIMPLE.clone() }
))
}

fn incr(&self, n: usize) {
// TODO: retain normal steady-tick implementation of incr() not ticking it
self.0.inc(n as u64);
}

fn count(&self) -> usize {
self.0.position() as usize
}

fn tick(&self) {
self.0.tick();
}

fn done_clear(&self) {
self.0.finish_and_clear();
}

fn done(&self) {
self.0.set_style(
if COUNT { SPINNER_STYLE_FINISHED_COUNT.clone() } else { SPINNER_STYLE_FINISHED_SIMPLE.clone() }
);
self.0.abandon();
}

fn suspend<F: FnOnce() -> R, R>(&self, f: F) -> R {
self.0.suspend(f)
}
s
}

pub fn finish_spinner(s: &ProgressBar, count: bool) {
s.set_style(
if count { SPINNER_STYLE_FINISHED_COUNT.clone() } else { SPINNER_STYLE_FINISHED_SIMPLE.clone() }
);
s.abandon();
pub struct Bar(ProgressBar);

impl Reporter for Bar {
fn new(msg: &str) -> Self {
Self(ProgressBar::new(0)
.with_message(msg.to_string())
.with_style(PROGRESS_STYLE.clone()))
}

fn incr(&self, n: usize) {
self.0.inc(n as u64);
}

fn count(&self) -> usize {
self.0.position() as usize
}

fn tick(&self) {
self.0.tick();
}

fn done_clear(&self) {
self.0.finish_and_clear();
}

fn done(&self) {
self.0.set_style(PROGRESS_STYLE_FINISHED.clone());
self.0.abandon();
}

fn suspend<F: FnOnce() -> R, R>(&self, f: F) -> R {
self.0.suspend(f)
}
}

impl ReporterSized for Bar {
fn new(msg: &str, len: usize) -> Self {
Self(ProgressBar::new(len as u64)
.with_message(msg.to_string())
.with_style(PROGRESS_STYLE.clone()))
}

fn set_len(&self, len: usize) {
self.0.set_length(len as u64);
}

fn length(&self) -> usize {
self.0.length().unwrap() as usize
}
}

// this is really unnecessary but ok rust, sure, foreign trait implementation rules
pub struct MultiWrapper(MultiProgress);

impl ReportingMultiWrapper for MultiWrapper {
fn new() -> Self {
MultiWrapper(MultiProgress::new())
}

fn suspend<F: FnOnce() -> R, R>(&self, f: F) -> R {
self.0.suspend(f)
}
}

pub fn create_bar(msg: &str, len: u64, auto: bool) -> ProgressBar {
let b = ProgressBar::new(len).with_message(msg.to_string()).with_style(PROGRESS_STYLE.clone());
if auto {
b.enable_steady_tick(Duration::from_millis(50));
b.tick();
impl<const COUNT: bool> CanBeWrappedBy<MultiWrapper> for Spinner<COUNT> {
fn add_to(self, w: &MultiWrapper) -> Self {
Spinner(w.0.add(self.0))
}
b
}

pub fn finish_bar(b: &ProgressBar) {
b.set_style(PROGRESS_STYLE_FINISHED.clone());
b.abandon();
impl CanBeWrappedBy<MultiWrapper> for Bar {
fn add_to(self, w: &MultiWrapper) -> Self {
Bar(w.0.add(self.0))
}
}
16 changes: 10 additions & 6 deletions foldiff/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ fn main() -> Result<()> {
}

// scan the file system
let mut diff_state = libfoldiff::diffing::scan_to_diff(old_root, new_root)?;
let mut diff_state = libfoldiff::diffing::scan_to_diff::<cliutils::Spinner<true>>(old_root, new_root)?;
//println!("{diff_state:?}");

// emit the diff to disk
diff_state.write_to_file(Path::new(diff), &cfg)?;
diff_state.write_to_file::<cliutils::Bar, cliutils::Spinner<false>>(Path::new(diff), &cfg)?;

}
Commands::Apply { old, diff, new } => {
Expand All @@ -159,16 +159,20 @@ fn main() -> Result<()> {
}

let mut diff_state = libfoldiff::applying::read_diff_from_file(&PathBuf::from(diff))?;
diff_state.apply(old_root, new_root)?;
diff_state.apply::<
cliutils::MultiWrapper,
cliutils::Spinner<false>,
cliutils::Bar
>(old_root, new_root)?;
},
Commands::Verify { new, old, diff } => {
if let Some(diff) = diff {
let f = File::open(diff).context("Failed to open diff file to verify with")?;
let manifest = DiffManifest::read_from(f).context("Failed to read diff file to verify with")?;
libfoldiff::verify::verify_against_diff(Path::new(old), Path::new(new), &manifest)?;
libfoldiff::verify::verify_against_diff::<cliutils::Spinner<true>>(Path::new(old), Path::new(new), &manifest)?;
}
else {
libfoldiff::verify::test_dir_equality(Path::new(old), Path::new(new))?;
libfoldiff::verify::test_dir_equality::<cliutils::Spinner<true>>(Path::new(old), Path::new(new))?;
}
},
Commands::Upgrade { new, old } => {
Expand All @@ -186,7 +190,7 @@ fn main() -> Result<()> {
let fold = File::open(old).context("Failed to open old diff file")?;
let fnew = File::create(new).context("Failed to create destination file")?;

libfoldiff::upgrade::auto_upgrade(fold, fnew)?;
libfoldiff::upgrade::auto_upgrade::<cliutils::Spinner<false>>(fold, fnew)?;
},
}

Expand Down
63 changes: 35 additions & 28 deletions libfoldiff/src/applying.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use crate::common::create_file;
use crate::manifest::DiffManifest;
use crate::reporting::{AutoSpin, CanBeWrappedBy, Reporter, ReporterSized, ReportingMultiWrapper};
use crate::{aggregate_errors, handle_res_parit, hash, zstddiff};
use anyhow::{anyhow, Context};
use memmap2::Mmap;
use rayon::prelude::*;
use std::fs::File;
use std::io::{Cursor, Read, Seek};
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use std::time::Duration;
use anyhow::{anyhow, Context};
use memmap2::Mmap;
use crate::manifest::DiffManifest;
use rayon::prelude::*;
use crate::{aggregate_errors, handle_res_parit, hash, zstddiff};
use crate::common::create_file;

/// An in-memory representation of a diff, used for the applying process
#[derive(Debug, Default)]
Expand All @@ -22,7 +22,11 @@ pub struct ApplyingDiff {
}

impl ApplyingDiff {
pub fn apply(&mut self, old_root: PathBuf, new_root: PathBuf) -> anyhow::Result<()> {
pub fn apply<
TWrap: ReportingMultiWrapper,
TSpin: Reporter + CanBeWrappedBy<TWrap> + Sync,
TBar: ReporterSized + CanBeWrappedBy<TWrap> + Sync
>(&mut self, old_root: PathBuf, new_root: PathBuf) -> anyhow::Result<()> {
self.old_root = old_root;
self.new_root = new_root;

Expand All @@ -31,31 +35,31 @@ impl ApplyingDiff {
let num_duped_files: u64 = self.manifest.duplicated_files.iter().map(|d| d.new_paths.len() as u64).sum();

// incr bar and finish if done
let inc_n = |n: u64, b: &ProgressBar| {
b.inc(n);
if Some(b.position()) == b.length() {
cliutils::finish_bar(b);
let inc_n = |n: usize, b: &TBar| {
b.incr(n);
if b.count() == b.length() {
b.done();
}
};
let inc = |b: &ProgressBar| inc_n(1, b);
let inc = |b: &TBar| inc_n(1, b);

// progress reporting
let wrap = MultiProgress::new();
let spn = wrap.add(cliutils::create_spinner("Applying diff", false, false));
let bar_untouched = wrap.add(cliutils::create_bar("Copying unchanged files", (self.manifest.untouched_files.len() as u64) + num_duped_files, false));
let bar_new = wrap.add(cliutils::create_bar("Creating new files", self.manifest.new_files.len() as u64, false));
let bar_patched = wrap.add(cliutils::create_bar("Applying patched files", self.manifest.patched_files.len() as u64, false));

// need to do this manually because of it being in a wrap
for b in [&spn, &bar_untouched, &bar_new, &bar_patched] {
b.enable_steady_tick(Duration::from_millis(50));
}
let wrap = TWrap::new();
let spn = TSpin::new("Applying diff").add_to(&wrap);
let bar_untouched = <TBar as ReporterSized>::new("Copying unchanged files", self.manifest.untouched_files.len() + (num_duped_files as usize)).add_to(&wrap);
let bar_new = <TBar as ReporterSized>::new("Creating new files", self.manifest.new_files.len()).add_to(&wrap);
let bar_patched = <TBar as ReporterSized>::new("Applying patched files", self.manifest.patched_files.len()).add_to(&wrap);

let as1 = AutoSpin::spin(&spn);
let as2 = AutoSpin::spin(&bar_untouched);
let as3 = AutoSpin::spin(&bar_new);
let as4 = AutoSpin::spin(&bar_patched);

// let's spawn some threads!
let errs = Mutex::new(Vec::new());
rayon::scope(|s| {
if self.manifest.untouched_files.is_empty() && self.manifest.duplicated_files.is_empty() {
bar_untouched.finish_and_clear();
bar_untouched.done_clear();
}
else {
s.spawn(|_| {
Expand Down Expand Up @@ -161,12 +165,12 @@ impl ApplyingDiff {
return;
}

inc_n(d.new_paths.len() as u64, &bar_untouched);
inc_n(d.new_paths.len(), &bar_untouched);
}
});
}
if self.manifest.new_files.is_empty() {
bar_new.finish_and_clear();
bar_new.done_clear();
}
else {
s.spawn(|_| {
Expand Down Expand Up @@ -212,7 +216,7 @@ impl ApplyingDiff {
});
}
if self.manifest.patched_files.is_empty() {
bar_patched.finish_and_clear();
bar_patched.done_clear();
}
else {
s.spawn(|_| {
Expand Down Expand Up @@ -267,7 +271,10 @@ impl ApplyingDiff {

aggregate_errors!(errs.into_inner()?);

cliutils::finish_spinner(&spn, false);
as1.all_good();
drop(as2);
drop(as3);
drop(as4);
Ok(())
}
}
Expand Down
Loading

0 comments on commit ee63381

Please sign in to comment.