From 8b00faf07563f0dbee883e73b5e045dd477a8bb5 Mon Sep 17 00:00:00 2001 From: Dhruva Sagar Date: Mon, 9 Jan 2023 10:51:23 +0530 Subject: [PATCH 01/13] Fix Temporary File Path #6 Better cross platform support --- src/database.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/database.rs b/src/database.rs index 4713aa7..2982a4e 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,5 +1,6 @@ -use anyhow::Result; use crate::params::Params; +use anyhow::Result; +use std::env::temp_dir; #[derive(Debug, Clone)] pub struct File { @@ -8,9 +9,12 @@ pub struct File { } pub fn get_connection(args: &Params) -> Result { + let mut tmp_file = temp_dir(); + tmp_file.push("deduplicator.db"); + let connection_url = match args.nocache { - false => "/tmp/deduplicator.db", - true => ":memory:" + false => tmp_file.to_str().unwrap(), + true => ":memory:", }; sqlite::open(connection_url).and_then(|conn| { @@ -36,9 +40,7 @@ pub fn put(file: &File, connection: &sqlite::Connection) -> Result<()> { } pub fn indexed_paths(connection: &sqlite::Connection) -> Result> { - let query = format!( - "SELECT * FROM files" - ); + let query = format!("SELECT * FROM files"); let result: Vec = connection .prepare(query)? @@ -49,7 +51,7 @@ pub fn indexed_paths(connection: &sqlite::Connection) -> Result> { let hash = row.read::("hash").to_string(); File { path, hash } }) - .collect(); + .collect(); Ok(result) } @@ -65,7 +67,8 @@ pub fn duplicate_hashes(connection: &sqlite::Connection, path: &String) -> Resul ON a.hash = b.hash WHERE a.file_identifier LIKE \"{}%\" ORDER BY a.file_identifier - ", path + ", + path ); let result: Vec = connection From 27fef21be0a817d3c3c3b1aa7ee97fbdb0ad3154 Mon Sep 17 00:00:00 2001 From: Valentin Bersier Date: Mon, 9 Jan 2023 16:17:50 +0100 Subject: [PATCH 02/13] fix: no unwrap in params.rs --- src/params.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/params.rs b/src/params.rs index 0148b9b..5531c80 100644 --- a/src/params.rs +++ b/src/params.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; use clap::Parser; -use anyhow::Result; +use anyhow::{ anyhow, Result }; use std::fs; #[derive(Parser, Debug)] @@ -19,20 +19,16 @@ pub struct Params { impl Params { pub fn get_directory(&self) -> Result { - let dir_string: String = self + let dir_pathbuf: PathBuf = self .dir .clone() .unwrap_or(std::env::current_dir()?) - .as_os_str() - .to_str() - .unwrap() - .to_string(); + .as_os_str().into(); - let dir_pathbuf = PathBuf::from(&dir_string); - let dir = fs::canonicalize(&dir_pathbuf)? + let dir = fs::canonicalize(dir_pathbuf)? .as_os_str() .to_str() - .unwrap() + .ok_or_else(|| anyhow!("Invalid directory"))? .to_string(); Ok(dir) From a76163f24faf98937c3ac220adbedb5d50806808 Mon Sep 17 00:00:00 2001 From: Valentin Bersier Date: Mon, 9 Jan 2023 16:21:13 +0100 Subject: [PATCH 03/13] style: format --- src/params.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/params.rs b/src/params.rs index 5531c80..d2e84ed 100644 --- a/src/params.rs +++ b/src/params.rs @@ -1,7 +1,7 @@ -use std::path::PathBuf; +use std::{fs, path::PathBuf}; + +use anyhow::{anyhow, Result}; use clap::Parser; -use anyhow::{ anyhow, Result }; -use std::fs; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -23,7 +23,8 @@ impl Params { .dir .clone() .unwrap_or(std::env::current_dir()?) - .as_os_str().into(); + .as_os_str() + .into(); let dir = fs::canonicalize(dir_pathbuf)? .as_os_str() From 254e61cabea2605c92ddd38cc4bba2dc9d9ed61d Mon Sep 17 00:00:00 2001 From: Valentin Bersier Date: Mon, 9 Jan 2023 16:27:52 +0100 Subject: [PATCH 04/13] fix: clippy warnings --- src/database.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/database.rs b/src/database.rs index 4713aa7..ebf3ac4 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,4 +1,5 @@ use anyhow::Result; + use crate::params::Params; #[derive(Debug, Clone)] @@ -10,12 +11,12 @@ pub struct File { pub fn get_connection(args: &Params) -> Result { let connection_url = match args.nocache { false => "/tmp/deduplicator.db", - true => ":memory:" + true => ":memory:", }; - sqlite::open(connection_url).and_then(|conn| { + sqlite::open(connection_url).map(|conn| { setup(&conn).ok(); - Ok(conn) + conn }) } @@ -30,15 +31,12 @@ pub fn put(file: &File, connection: &sqlite::Connection) -> Result<()> { "INSERT INTO files (file_identifier, hash) VALUES (\"{}\", \"{}\")", file.path, file.hash ); - let result = connection.execute(query)?; - - Ok(result) + connection.execute(query)?; + Ok(()) } pub fn indexed_paths(connection: &sqlite::Connection) -> Result> { - let query = format!( - "SELECT * FROM files" - ); + let query = "SELECT * FROM files"; let result: Vec = connection .prepare(query)? @@ -49,7 +47,7 @@ pub fn indexed_paths(connection: &sqlite::Connection) -> Result> { let hash = row.read::("hash").to_string(); File { path, hash } }) - .collect(); + .collect(); Ok(result) } @@ -65,7 +63,8 @@ pub fn duplicate_hashes(connection: &sqlite::Connection, path: &String) -> Resul ON a.hash = b.hash WHERE a.file_identifier LIKE \"{}%\" ORDER BY a.file_identifier - ", path + ", + path ); let result: Vec = connection From c76ad81a55c7145a2f64ccda7da65036ed51309a Mon Sep 17 00:00:00 2001 From: Valentin Bersier Date: Mon, 9 Jan 2023 16:41:55 +0100 Subject: [PATCH 05/13] refactor: do no unwrap in database.rs --- src/database.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database.rs b/src/database.rs index ebf3ac4..2e06e7c 100644 --- a/src/database.rs +++ b/src/database.rs @@ -41,7 +41,7 @@ pub fn indexed_paths(connection: &sqlite::Connection) -> Result> { let result: Vec = connection .prepare(query)? .into_iter() - .map(|row_result| row_result.unwrap()) + .filter_map(|row_result| row_result.ok()) .map(|row| { let path = row.read::<&str, _>("file_identifier").to_string(); let hash = row.read::("hash").to_string(); @@ -52,7 +52,7 @@ pub fn indexed_paths(connection: &sqlite::Connection) -> Result> { Ok(result) } -pub fn duplicate_hashes(connection: &sqlite::Connection, path: &String) -> Result> { +pub fn duplicate_hashes(connection: &sqlite::Connection, path: &str) -> Result> { let query = format!( " SELECT a.* FROM files a @@ -70,7 +70,7 @@ pub fn duplicate_hashes(connection: &sqlite::Connection, path: &String) -> Resul let result: Vec = connection .prepare(query)? .into_iter() - .map(|row_result| row_result.unwrap()) + .filter_map(|row_result| row_result.ok()) .map(|row| { let path = row.read::<&str, _>("file_identifier").to_string(); let hash = row.read::("hash").to_string(); From bc170f139e5d22796274cc9f35328d2c928caeae Mon Sep 17 00:00:00 2001 From: Valentin Bersier Date: Mon, 9 Jan 2023 16:46:12 +0100 Subject: [PATCH 06/13] style: remove trailing spaces --- src/database.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/database.rs b/src/database.rs index 2e06e7c..857e9a5 100644 --- a/src/database.rs +++ b/src/database.rs @@ -54,10 +54,10 @@ pub fn indexed_paths(connection: &sqlite::Connection) -> Result> { pub fn duplicate_hashes(connection: &sqlite::Connection, path: &str) -> Result> { let query = format!( - " + " SELECT a.* FROM files a JOIN (SELECT file_identifier, hash, COUNT(*) - FROM files + FROM files GROUP BY hash HAVING count(*) > 1 ) b ON a.hash = b.hash From 138b66038fefe14c1da37a06b86a6a3a5a1020df Mon Sep 17 00:00:00 2001 From: Valentin Bersier Date: Mon, 9 Jan 2023 16:57:43 +0100 Subject: [PATCH 07/13] refactor: various clippy fixes --- src/app/event_handler.rs | 6 +++--- src/app/events.rs | 2 +- src/app/mod.rs | 24 +++++++++++++----------- src/app/ui.rs | 3 ++- src/main.rs | 7 ++++--- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/app/event_handler.rs b/src/app/event_handler.rs index 69260ae..da7129b 100644 --- a/src/app/event_handler.rs +++ b/src/app/event_handler.rs @@ -1,7 +1,8 @@ use std::time::Duration; -use crossterm::event::{self, KeyCode, KeyEvent}; use anyhow::Result; +use crossterm::event::{self, KeyCode, KeyEvent}; + use super::events; pub struct EventHandler; @@ -21,8 +22,7 @@ impl EventHandler { fn handle_keypress(keyevent: KeyEvent) -> Result { match keyevent.code { KeyCode::Char('q') => Ok(events::Event::Exit), - _ => Ok(events::Event::Noop) + _ => Ok(events::Event::Noop), } } } - diff --git a/src/app/events.rs b/src/app/events.rs index a889cc3..c7167d0 100644 --- a/src/app/events.rs +++ b/src/app/events.rs @@ -1,4 +1,4 @@ pub enum Event { Exit, - Noop + Noop, } diff --git a/src/app/mod.rs b/src/app/mod.rs index 92f6736..3a8b102 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,18 +1,13 @@ mod event_handler; mod events; -mod ui; mod formatter; +mod ui; + +use std::{io, thread, time::Duration}; -use crate::database; -use crate::output; -use crate::params::Params; -use crate::scanner; use anyhow::{anyhow, Result}; use crossterm::{event, execute, terminal}; use event_handler::EventHandler; -use std::io; -use std::thread; -use std::time::Duration; use tui::{ backend::CrosstermBackend, widgets::{Block, Borders, Widget}, @@ -20,19 +15,24 @@ use tui::{ }; use ui::Ui; +use crate::database; +use crate::output; +use crate::params::Params; +use crate::scanner; + pub struct App; impl App { pub fn init(app_args: &Params) -> Result<()> { // let mut term = Self::init_terminal()?; - let connection = database::get_connection(&app_args)?; - let duplicates = scanner::duplicates(&app_args, &connection)?; + let connection = database::get_connection(app_args)?; + let duplicates = scanner::duplicates(app_args, &connection)?; // Self::init_render_loop(&mut term)?; // Self::cleanup(&mut term)?; - output::print(duplicates, &app_args); /* TODO: APP TUI INIT FUNCTION */ + output::print(duplicates, app_args); /* TODO: APP TUI INIT FUNCTION */ Ok(()) } @@ -56,6 +56,8 @@ impl App { } fn init_render_loop(term: &mut Terminal>) -> Result<()> { + // this could be simplified with a `while Self::render_cycle(term).is_ok() {}` in the current state, but maybe + // it's good to keep it to handle errors in the future loop { match Self::render_cycle(term) { Ok(_) => continue, diff --git a/src/app/ui.rs b/src/app/ui.rs index 19413a4..9b8c63b 100644 --- a/src/app/ui.rs +++ b/src/app/ui.rs @@ -1,5 +1,6 @@ -use anyhow::Result; use std::io; + +use anyhow::Result; use tui::{ backend::{Backend, CrosstermBackend}, layout::{Constraint, Direction, Layout, Rect}, diff --git a/src/main.rs b/src/main.rs index 7cb8c91..21ac960 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,13 @@ -mod params; +#![allow(unused)] // TODO: remove this once TUI is implemented +mod app; mod database; mod output; +mod params; mod scanner; -mod app; use anyhow::Result; -use clap::Parser; use app::App; +use clap::Parser; #[tokio::main] async fn main() -> Result<()> { From 05f513735e5608360ebe14f2a5e0ddc8b6911cda Mon Sep 17 00:00:00 2001 From: sreedev Date: Mon, 9 Jan 2023 11:01:52 -0500 Subject: [PATCH 08/13] tempdir fixes --- src/database.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/database.rs b/src/database.rs index 2982a4e..ef6d565 100644 --- a/src/database.rs +++ b/src/database.rs @@ -8,16 +8,18 @@ pub struct File { pub hash: String, } +fn db_connection_url(args: &Params) -> String { + match args.nocache { + true => String::from(":memory:"), + false => { + let temp_dir_path = temp_dir(); + format!("{}/deduplicator.db", temp_dir_path.display()) + } + } +} + pub fn get_connection(args: &Params) -> Result { - let mut tmp_file = temp_dir(); - tmp_file.push("deduplicator.db"); - - let connection_url = match args.nocache { - false => tmp_file.to_str().unwrap(), - true => ":memory:", - }; - - sqlite::open(connection_url).and_then(|conn| { + sqlite::open(db_connection_url(args)).and_then(|conn| { setup(&conn).ok(); Ok(conn) }) From c32e64450f7c82ca9f2b42f7dc89f0f77f68d9c1 Mon Sep 17 00:00:00 2001 From: sreedev Date: Mon, 9 Jan 2023 11:04:29 -0500 Subject: [PATCH 09/13] bug fix: connection result issue --- src/database.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database.rs b/src/database.rs index cc226e0..371d41f 100644 --- a/src/database.rs +++ b/src/database.rs @@ -23,7 +23,7 @@ fn db_connection_url(args: &Params) -> String { pub fn get_connection(args: &Params) -> Result { sqlite::open(db_connection_url(args)).and_then(|conn| { setup(&conn).ok(); - conn + Ok(conn) }) } From 96fe667d3f4dd8858ed4d4cfd21f8470cc8ac5db Mon Sep 17 00:00:00 2001 From: sreedev Date: Mon, 9 Jan 2023 11:08:20 -0500 Subject: [PATCH 10/13] version 0.0.5 --- Cargo.lock | 2 +- Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 25328e7..de1b93e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,7 +269,7 @@ dependencies = [ [[package]] name = "deduplicator" -version = "0.0.4" +version = "0.0.5" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 8fe0b60..7a5cc1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "deduplicator" -version = "0.0.4" +version = "0.0.5" edition = "2021" description = "find,filter,delete Duplicates" license = "MIT" -authors = ["Sreedev Kodichath ", "Valentin Bersier "] +authors = ["Sreedev Kodichath ", "Valentin Bersier ", "Dhruva Sagar "] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From a0083cb571dfcb801b3e995cda2c7628457a3acc Mon Sep 17 00:00:00 2001 From: sreedev Date: Mon, 9 Jan 2023 22:15:44 -0500 Subject: [PATCH 11/13] table printing added --- Cargo.lock | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/output.rs | 35 +++++-------- 3 files changed, 154 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de1b93e..b6aa929 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,6 +40,18 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + [[package]] name = "bumpalo" version = "3.11.1" @@ -223,6 +235,28 @@ dependencies = [ "winapi", ] +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + [[package]] name = "cxx" version = "1.0.85" @@ -280,6 +314,7 @@ dependencies = [ "glob", "humansize", "itertools", + "prettytable-rs", "rayon", "sqlite", "thiserror", @@ -287,12 +322,39 @@ dependencies = [ "tui", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "either" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "errno" version = "0.2.8" @@ -323,6 +385,17 @@ dependencies = [ "byteorder", ] +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + [[package]] name = "glob" version = "0.3.0" @@ -417,6 +490,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "js-sys" version = "0.3.60" @@ -581,6 +660,20 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "prettytable-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" +dependencies = [ + "csv", + "encode_unicode", + "is-terminal", + "lazy_static", + "term", + "unicode-width", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -654,6 +747,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + [[package]] name = "rustix" version = "0.36.5" @@ -668,6 +778,18 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + [[package]] name = "scopeguard" version = "1.1.0" @@ -680,6 +802,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" + [[package]] name = "signal-hook" version = "0.3.14" @@ -773,6 +901,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.3" diff --git a/Cargo.toml b/Cargo.toml index 7a5cc1b..09c3b6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ fxhash = "0.2.1" glob = "0.3.0" humansize = "2.1.2" itertools = "0.10.5" +prettytable-rs = "0.10.0" rayon = "1.6.1" sqlite = "0.30.3" thiserror = "1.0.38" diff --git a/src/output.rs b/src/output.rs index 4824921..0724bd8 100644 --- a/src/output.rs +++ b/src/output.rs @@ -8,6 +8,7 @@ use humansize::{format_size, DECIMAL}; use crate::database::File; use crate::params::Params; +use prettytable::{row, Cell, Row, Table}; fn format_path(path: &str, opts: &Params) -> Result { let display_path = path.replace(&opts.get_directory()?, ""); @@ -37,20 +38,10 @@ fn modified_time(path: &String) -> Result { Ok(modified_time.format("%Y-%m-%d %H:%M:%S").to_string()) } -fn print_divider() { - println!("-------------------+-------------------------------------+------------------+----------------------------------+"); -} - pub fn print(duplicates: Vec, opts: &Params) { - print_divider(); - println!( - "| {0: <16} | {1: <35} | {2: <16} | {3: <32} |", - "hash", "filename", "size", "updated_at" - ); - print_divider(); - + let mut output_table = Table::new(); let mut dup_index: HashMap> = HashMap::new(); - + output_table.add_row(row!["hash", "duplicates"]); duplicates.into_iter().for_each(|file| { dup_index .entry(file.hash.clone()) @@ -58,16 +49,18 @@ pub fn print(duplicates: Vec, opts: &Params) { .or_insert_with(|| vec![file]); }); - dup_index.iter().for_each(|(_, group)| { + dup_index.iter().for_each(|(hash, group)| { + let mut inner_table = Table::new(); + inner_table.add_row(row!["filename", "size", "updated_at"]); group.iter().for_each(|file| { - println!( - "| {0: <16} | {1: <35} | {2: <16} | {3: <32} |", - file.hash.red(), - format_path(&file.path, opts).unwrap_or_default().yellow(), - file_size(&file.path).unwrap_or_default().blue(), - modified_time(&file.path).unwrap_or_default().blue() - ); + inner_table.add_row(row![ + format_path(&file.path, opts).unwrap_or_default().blue(), + file_size(&file.path).unwrap_or_default().red(), + modified_time(&file.path).unwrap_or_default().yellow() + ]); }); - print_divider(); + output_table.add_row(row![hash, inner_table]); }); + + output_table.printstd(); } From 6e412fc59c9c895842dfb2485aeb33cd0df028e7 Mon Sep 17 00:00:00 2001 From: sreedev Date: Mon, 9 Jan 2023 22:40:37 -0500 Subject: [PATCH 12/13] table display improvements --- src/output.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/output.rs b/src/output.rs index 0724bd8..0fedfea 100644 --- a/src/output.rs +++ b/src/output.rs @@ -8,7 +8,7 @@ use humansize::{format_size, DECIMAL}; use crate::database::File; use crate::params::Params; -use prettytable::{row, Cell, Row, Table}; +use prettytable::{row, Cell, Row, format, Table}; fn format_path(path: &str, opts: &Params) -> Result { let display_path = path.replace(&opts.get_directory()?, ""); @@ -22,12 +22,12 @@ fn format_path(path: &str, opts: &Params) -> Result { display_path }; - Ok(format!("...{}", display_range)) + Ok(format!("...{:<32}", display_range)) } fn file_size(path: &String) -> Result { let mdata = fs::metadata(path)?; - let formatted_size = format_size(mdata.len(), DECIMAL); + let formatted_size = format!("{:>12}", format_size(mdata.len(), DECIMAL)); Ok(formatted_size) } @@ -38,20 +38,28 @@ fn modified_time(path: &String) -> Result { Ok(modified_time.format("%Y-%m-%d %H:%M:%S").to_string()) } -pub fn print(duplicates: Vec, opts: &Params) { - let mut output_table = Table::new(); - let mut dup_index: HashMap> = HashMap::new(); - output_table.add_row(row!["hash", "duplicates"]); +fn group_duplicates(duplicates: Vec) -> HashMap> { + let mut duplicate_mapper: HashMap> = HashMap::new(); duplicates.into_iter().for_each(|file| { - dup_index + duplicate_mapper .entry(file.hash.clone()) .and_modify(|value| value.push(file.clone())) .or_insert_with(|| vec![file]); }); - dup_index.iter().for_each(|(hash, group)| { + duplicate_mapper +} + +pub fn print(duplicates: Vec, opts: &Params) { + let mut output_table = Table::new(); + let grouped_duplicates: HashMap> = group_duplicates(duplicates); + + output_table.set_titles(row!["hash", "duplicates"]); + grouped_duplicates.iter().for_each(|(hash, group)| { let mut inner_table = Table::new(); - inner_table.add_row(row!["filename", "size", "updated_at"]); + // inner_table.set_format(inner_table_format); + inner_table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR); + //inner_table.set_titles(row!["filename", "size", "updated_at"]); group.iter().for_each(|file| { inner_table.add_row(row![ format_path(&file.path, opts).unwrap_or_default().blue(), @@ -59,7 +67,7 @@ pub fn print(duplicates: Vec, opts: &Params) { modified_time(&file.path).unwrap_or_default().yellow() ]); }); - output_table.add_row(row![hash, inner_table]); + output_table.add_row(row![hash.green(), inner_table]); }); output_table.printstd(); From b5bb58b3ede9a100348868b3c112f98aa8391b21 Mon Sep 17 00:00:00 2001 From: sreedev Date: Mon, 9 Jan 2023 22:47:54 -0500 Subject: [PATCH 13/13] version changes --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6aa929..becd524 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -303,7 +303,7 @@ dependencies = [ [[package]] name = "deduplicator" -version = "0.0.5" +version = "0.0.6" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 09c3b6b..a4f2297 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deduplicator" -version = "0.0.5" +version = "0.0.6" edition = "2021" description = "find,filter,delete Duplicates" license = "MIT"