summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSebastian Thiel <sthiel@thoughtworks.com>2019-06-03 07:31:31 +0530
committerSebastian Thiel <sthiel@thoughtworks.com>2019-06-03 07:31:31 +0530
commit2ce606f607fa967f94d49c5413c4b347e628e88e (patch)
tree04212a76420c2cc93948f311bc9999364903270e /src
parent24097bd19ee53ca7a4a635e6ea63c3e3c63bdc2b (diff)
move modules into their own files
Diffstat (limited to 'src')
-rw-r--r--src/interactive.rs234
-rw-r--r--src/interactive/app.rs197
-rw-r--r--src/interactive/mod.rs4
-rw-r--r--src/interactive/widgets.rs29
4 files changed, 230 insertions, 234 deletions
diff --git a/src/interactive.rs b/src/interactive.rs
deleted file mode 100644
index 0d6cf0b..0000000
--- a/src/interactive.rs
+++ /dev/null
@@ -1,234 +0,0 @@
-mod widgets {
- use super::{Tree, TreeIndex};
- use petgraph::Direction;
- use tui::buffer::Buffer;
- use tui::layout::{Corner, Rect};
- use tui::widgets::{Block, Borders, List, Text, Widget};
-
- pub struct Entries<'a> {
- pub tree: &'a Tree,
- pub root: TreeIndex,
- }
-
- impl<'a> Widget for Entries<'a> {
- fn draw(&mut self, area: Rect, buf: &mut Buffer) {
- let Self { tree, root } = self;
- List::new(
- tree.neighbors_directed(*root, Direction::Outgoing)
- .filter_map(|w| {
- tree.node_weight(w).map(|w| {
- Text::Raw(
- format!("{} | ----- | {}", w.size, w.name.to_string_lossy()).into(),
- )
- })
- }),
- )
- .block(Block::default().borders(Borders::ALL).title("Entries"))
- .start_corner(Corner::TopLeft)
- .draw(area, buf);
- }
- }
-}
-
-mod app {
- use crate::{WalkOptions, WalkResult};
- use failure::Error;
- use petgraph::{prelude::NodeIndex, Directed, Direction, Graph};
- use std::time::{Duration, Instant};
- use std::{ffi::OsString, io, path::PathBuf};
- use termion::input::{Keys, TermReadEventsAndRaw};
- use tui::widgets::Widget;
- use tui::{backend::Backend, Terminal};
-
- pub type TreeIndexType = u32;
- pub type TreeIndex = NodeIndex<TreeIndexType>;
- pub type Tree = Graph<EntryData, (), Directed, TreeIndexType>;
-
- #[derive(Eq, PartialEq, Debug, Default)]
- pub struct EntryData {
- pub name: OsString,
- /// The entry's size in bytes. If it's a directory, the size is the aggregated file size of all children
- pub size: u64,
- /// If set, the item meta-data could not be obtained
- pub metadata_io_error: bool,
- }
-
- /// State and methods representing the interactive disk usage analyser for the terminal
- #[derive(Default, Debug)]
- pub struct TerminalApp {
- /// A tree representing the entire filestem traversal
- pub tree: Tree,
- /// The top-level node of the tree.
- pub root_index: TreeIndex,
- /// Amount of files or directories we have seen during the filesystem traversal
- pub entries_traversed: u64,
- /// Total amount of IO errors encountered when traversing the filesystem
- pub io_errors: u64,
- }
-
- const GUI_REFRESH_RATE: Duration = Duration::from_millis(100);
-
- impl TerminalApp {
- pub fn process_events<B, R>(
- &mut self,
- _terminal: &mut Terminal<B>,
- _keys: Keys<R>,
- ) -> Result<WalkResult, Error>
- where
- B: Backend,
- R: io::Read + TermReadEventsAndRaw,
- {
- unimplemented!()
- }
-
- pub fn initialize<B>(
- terminal: &mut Terminal<B>,
- options: WalkOptions,
- input: Vec<PathBuf>,
- ) -> Result<TerminalApp, Error>
- where
- B: Backend,
- {
- fn set_size_or_panic(
- tree: &mut Tree,
- parent_node_idx: TreeIndex,
- current_size_at_depth: u64,
- ) {
- tree.node_weight_mut(parent_node_idx)
- .expect("node for parent index we just retrieved")
- .size = current_size_at_depth;
- }
- fn parent_or_panic(tree: &mut Tree, parent_node_idx: TreeIndex) -> TreeIndex {
- tree.neighbors_directed(parent_node_idx, Direction::Incoming)
- .next()
- .expect("every node in the iteration has a parent")
- }
- fn pop_or_panic(v: &mut Vec<u64>) -> u64 {
- v.pop().expect("sizes per level to be in sync with graph")
- }
- let mut tree = Tree::new();
- let mut io_errors = 0u64;
- let mut entries_traversed = 0u64;
-
- let root_index = tree.add_node(EntryData::default());
- let (mut previous_node_idx, mut parent_node_idx) = (root_index, root_index);
- let mut sizes_per_depth_level = Vec::new();
- let mut current_size_at_depth = 0;
- let mut previous_depth = 0;
-
- let mut last_checked = Instant::now();
-
- const INITIAL_CHECK_INTERVAL: usize = 500;
- let mut check_instant_every = INITIAL_CHECK_INTERVAL;
- let mut last_seen_eid;
-
- for path in input.into_iter() {
- last_seen_eid = 0;
- for (eid, entry) in options
- .iter_from_path(path.as_ref())
- .into_iter()
- .enumerate()
- {
- entries_traversed += 1;
- let mut data = EntryData::default();
- match entry {
- Ok(entry) => {
- data.name = entry.file_name;
- let file_size = match entry.metadata {
- Some(Ok(ref m)) if !m.is_dir() => m.len(),
- Some(Ok(_)) => 0,
- Some(Err(_)) => {
- io_errors += 1;
- data.metadata_io_error = true;
- 0
- }
- None => unreachable!(
- "we ask for metadata, so we at least have Some(Err(..))). Issue in jwalk?"
- ),
- };
-
- match (entry.depth, previous_depth) {
- (n, p) if n > p => {
- sizes_per_depth_level.push(current_size_at_depth);
- current_size_at_depth = file_size;
- parent_node_idx = previous_node_idx;
- }
- (n, p) if n < p => {
- for _ in n..p {
- set_size_or_panic(
- &mut tree,
- parent_node_idx,
- current_size_at_depth,
- );
- current_size_at_depth +=
- pop_or_panic(&mut sizes_per_depth_level);
- parent_node_idx =
- parent_or_panic(&mut tree, parent_node_idx);
- }
- current_size_at_depth += file_size;
- set_size_or_panic(
- &mut tree,
- parent_node_idx,
- current_size_at_depth,
- );
- }
- _ => {
- current_size_at_depth += file_size;
- }
- };
-
- data.size = file_size;
- let entry_index = tree.add_node(data);
-
- tree.add_edge(parent_node_idx, entry_index, ());
- previous_node_idx = entry_index;
- previous_depth = entry.depth;
- }
- Err(_) => io_errors += 1,
- }
-
- if eid != 0
- && eid % check_instant_every == 0
- && last_checked.elapsed() >= GUI_REFRESH_RATE
- {
- let now = Instant::now();
- let elapsed = (now - last_checked).as_millis() as f64;
- check_instant_every = (INITIAL_CHECK_INTERVAL as f64
- * ((eid - last_seen_eid) as f64 / INITIAL_CHECK_INTERVAL as f64)
- * (GUI_REFRESH_RATE.as_millis() as f64 / elapsed))
- as usize;
- last_seen_eid = eid;
- last_checked = now;
-
- terminal.draw(|mut f| {
- let full_screen = f.size();
- super::widgets::Entries {
- tree: &tree,
- root: root_index,
- }
- .render(&mut f, full_screen)
- })?;
- }
- }
- }
-
- sizes_per_depth_level.push(current_size_at_depth);
- current_size_at_depth = 0;
- for _ in 0..previous_depth {
- current_size_at_depth += pop_or_panic(&mut sizes_per_depth_level);
- set_size_or_panic(&mut tree, parent_node_idx, current_size_at_depth);
- parent_node_idx = parent_or_panic(&mut tree, parent_node_idx);
- }
- set_size_or_panic(&mut tree, root_index, current_size_at_depth);
-
- Ok(TerminalApp {
- tree,
- root_index,
- entries_traversed,
- io_errors,
- })
- }
- }
-}
-
-pub use self::app::*;
diff --git a/src/interactive/app.rs b/src/interactive/app.rs
new file mode 100644
index 0000000..7021045
--- /dev/null
+++ b/src/interactive/app.rs
@@ -0,0 +1,197 @@
+use crate::{WalkOptions, WalkResult};
+use failure::Error;
+use petgraph::{prelude::NodeIndex, Directed, Direction, Graph};
+use std::time::{Duration, Instant};
+use std::{ffi::OsString, io, path::PathBuf};
+use termion::input::{Keys, TermReadEventsAndRaw};
+use tui::widgets::Widget;
+use tui::{backend::Backend, Terminal};
+
+pub type TreeIndexType = u32;
+pub type TreeIndex = NodeIndex<TreeIndexType>;
+pub type Tree = Graph<EntryData, (), Directed, TreeIndexType>;
+
+#[derive(Eq, PartialEq, Debug, Default)]
+pub struct EntryData {
+ pub name: OsString,
+ /// The entry's size in bytes. If it's a directory, the size is the aggregated file size of all children
+ pub size: u64,
+ /// If set, the item meta-data could not be obtained
+ pub metadata_io_error: bool,
+}
+
+/// State and methods representing the interactive disk usage analyser for the terminal
+#[derive(Default, Debug)]
+pub struct TerminalApp {
+ /// A tree representing the entire filestem traversal
+ pub tree: Tree,
+ /// The top-level node of the tree.
+ pub root_index: TreeIndex,
+ /// Amount of files or directories we have seen during the filesystem traversal
+ pub entries_traversed: u64,
+ /// Total amount of IO errors encountered when traversing the filesystem
+ pub io_errors: u64,
+}
+
+const GUI_REFRESH_RATE: Duration = Duration::from_millis(100);
+
+impl TerminalApp {
+ pub fn process_events<B, R>(
+ &mut self,
+ _terminal: &mut Terminal<B>,
+ _keys: Keys<R>,
+ ) -> Result<WalkResult, Error>
+ where
+ B: Backend,
+ R: io::Read + TermReadEventsAndRaw,
+ {
+ unimplemented!()
+ }
+
+ pub fn initialize<B>(
+ terminal: &mut Terminal<B>,
+ options: WalkOptions,
+ input: Vec<PathBuf>,
+ ) -> Result<TerminalApp, Error>
+ where
+ B: Backend,
+ {
+ fn set_size_or_panic(
+ tree: &mut Tree,
+ parent_node_idx: TreeIndex,
+ current_size_at_depth: u64,
+ ) {
+ tree.node_weight_mut(parent_node_idx)
+ .expect("node for parent index we just retrieved")
+ .size = current_size_at_depth;
+ }
+ fn parent_or_panic(tree: &mut Tree, parent_node_idx: TreeIndex) -> TreeIndex {
+ tree.neighbors_directed(parent_node_idx, Direction::Incoming)
+ .next()
+ .expect("every node in the iteration has a parent")
+ }
+ fn pop_or_panic(v: &mut Vec<u64>) -> u64 {
+ v.pop().expect("sizes per level to be in sync with graph")
+ }
+ let mut tree = Tree::new();
+ let mut io_errors = 0u64;
+ let mut entries_traversed = 0u64;
+
+ let root_index = tree.add_node(EntryData::default());
+ let (mut previous_node_idx, mut parent_node_idx) = (root_index, root_index);
+ let mut sizes_per_depth_level = Vec::new();
+ let mut current_size_at_depth = 0;
+ let mut previous_depth = 0;
+
+ let mut last_checked = Instant::now();
+
+ const INITIAL_CHECK_INTERVAL: usize = 500;
+ let mut check_instant_every = INITIAL_CHECK_INTERVAL;
+ let mut last_seen_eid;
+
+ for path in input.into_iter() {
+ last_seen_eid = 0;
+ for (eid, entry) in options
+ .iter_from_path(path.as_ref())
+ .into_iter()
+ .enumerate()
+ {
+ entries_traversed += 1;
+ let mut data = EntryData::default();
+ match entry {
+ Ok(entry) => {
+ data.name = entry.file_name;
+ let file_size = match entry.metadata {
+ Some(Ok(ref m)) if !m.is_dir() => m.len(),
+ Some(Ok(_)) => 0,
+ Some(Err(_)) => {
+ io_errors += 1;
+ data.metadata_io_error = true;
+ 0
+ }
+ None => unreachable!(
+ "we ask for metadata, so we at least have Some(Err(..))). Issue in jwalk?"
+ ),
+ };
+
+ match (entry.depth, previous_depth) {
+ (n, p) if n > p => {
+ sizes_per_depth_level.push(current_size_at_depth);
+ current_size_at_depth = file_size;
+ parent_node_idx = previous_node_idx;
+ }
+ (n, p) if n < p => {
+ for _ in n..p {
+ set_size_or_panic(
+ &mut tree,
+ parent_node_idx,
+ current_size_at_depth,
+ );
+ current_size_at_depth +=
+ pop_or_panic(&mut sizes_per_depth_level);
+ parent_node_idx = parent_or_panic(&mut tree, parent_node_idx);
+ }
+ current_size_at_depth += file_size;
+ set_size_or_panic(
+ &mut tree,
+ parent_node_idx,
+ current_size_at_depth,
+ );
+ }
+ _ => {
+ current_size_at_depth += file_size;
+ }
+ };
+
+ data.size = file_size;
+ let entry_index = tree.add_node(data);
+
+ tree.add_edge(parent_node_idx, entry_index, ());
+ previous_node_idx = entry_index;
+ previous_depth = entry.depth;
+ }
+ Err(_) => io_errors += 1,
+ }
+
+ if eid != 0
+ && eid % check_instant_every == 0
+ && last_checked.elapsed() >= GUI_REFRESH_RATE
+ {
+ let now = Instant::now();
+ let elapsed = (now - last_checked).as_millis() as f64;
+ check_instant_every = (INITIAL_CHECK_INTERVAL as f64
+ * ((eid - last_seen_eid) as f64 / INITIAL_CHECK_INTERVAL as f64)
+ * (GUI_REFRESH_RATE.as_millis() as f64 / elapsed))
+ as usize;
+ last_seen_eid = eid;
+ last_checked = now;
+
+ terminal.draw(|mut f| {
+ let full_screen = f.size();
+ super::widgets::Entries {
+ tree: &tree,
+ root: root_index,
+ }
+ .render(&mut f, full_screen)
+ })?;
+ }
+ }
+ }
+
+ sizes_per_depth_level.push(current_size_at_depth);
+ current_size_at_depth = 0;
+ for _ in 0..previous_depth {
+ current_size_at_depth += pop_or_panic(&mut sizes_per_depth_level);
+ set_size_or_panic(&mut tree, parent_node_idx, current_size_at_depth);
+ parent_node_idx = parent_or_panic(&mut tree, parent_node_idx);
+ }
+ set_size_or_panic(&mut tree, root_index, current_size_at_depth);
+
+ Ok(TerminalApp {
+ tree,
+ root_index,
+ entries_traversed,
+ io_errors,
+ })
+ }
+}
diff --git a/src/interactive/mod.rs b/src/interactive/mod.rs
new file mode 100644
index 0000000..2268008
--- /dev/null
+++ b/src/interactive/mod.rs
@@ -0,0 +1,4 @@
+mod app;
+mod widgets;
+
+pub use self::app::*;
diff --git a/src/interactive/widgets.rs b/src/interactive/widgets.rs
new file mode 100644
index 0000000..61095ba
--- /dev/null
+++ b/src/interactive/widgets.rs
@@ -0,0 +1,29 @@
+use super::{Tree, TreeIndex};
+use petgraph::Direction;
+use tui::buffer::Buffer;
+use tui::layout::{Corner, Rect};
+use tui::widgets::{Block, Borders, List, Text, Widget};
+
+pub struct Entries<'a> {
+ pub tree: &'a Tree,
+ pub root: TreeIndex,
+}
+
+impl<'a> Widget for Entries<'a> {
+ fn draw(&mut self, area: Rect, buf: &mut Buffer) {
+ let Self { tree, root } = self;
+ List::new(
+ tree.neighbors_directed(*root, Direction::Outgoing)
+ .filter_map(|w| {
+ tree.node_weight(w).map(|w| {
+ Text::Raw(
+ format!("{} | ----- | {}", w.size, w.name.to_string_lossy()).into(),
+ )
+ })
+ }),
+ )
+ .block(Block::default().borders(Borders::ALL).title("Entries"))
+ .start_corner(Corner::TopLeft)
+ .draw(area, buf);
+ }
+}