• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lpenz / ogle / 16092339124

05 Jul 2025 09:45PM UTC coverage: 62.041% (+16.6%) from 45.475%
16092339124

push

github

lpenz
Complete refactoring using layers that should be easier to test

Layers connected via streams, which we can mock and test.
This combines a bunch of commits that documented this slow conversion.

344 of 539 new or added lines in 12 files covered. (63.82%)

2 existing lines in 2 files now uncovered.

389 of 627 relevant lines covered (62.04%)

1.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/lib.rs
1
// Copyright (C) 2020 Leandro Lisboa Penz <lpenz@lpenz.org>
2
// This file is subject to the terms and conditions defined in
3
// file 'LICENSE', which is part of this source code package.
4

5
#![deny(future_incompatible)]
6
#![deny(nonstandard_style)]
7
#![deny(missing_docs)]
8
#![deny(rustdoc::broken_intra_doc_links)]
9
#![allow(rustdoc::private_intra_doc_links)]
10

11
//! **ogle** is a program that runs the given command-line periodically,
12
//! showing the output only when it is different than the last.
13
//!
14
//! The simplest way to show most of the features of *ogle* is by asking
15
//! it to run `date; sleep` in a shell, with a waiting period of 3s:
16
//!
17
//! ![demo](https://raw.githubusercontent.com/lpenz/ogle/main/demos/demo-sleep.gif)
18
//!
19
//! Lines that were written by ogle all start with `=>`. On the first
20
//! execution, ogle shows a spinner while the command is running. On the
21
//! next executions, ogle shows a progress bar, where the total
22
//! corresponds to the duration of the previous execution. The sleep time
23
//! is also shown, as a countdown. If the command returns an error to the
24
//! shell, the error value is displayed.
25
//!
26
//!
27
//! # Installation
28
//!
29
//! If you're a **Rust programmer**, ogle can be installed with `cargo`:
30
//!
31
//! ```bash
32
//! $ cargo install ogle
33
//! ```
34
//!
35
//! If you're a **Debian** user, ogle is available in
36
//! [packagecloud](https://packagecloud.io/app/lpenz/debian/search?q=ogle). Follow
37
//! these
38
//! [instruction](https://packagecloud.io/lpenz/debian/install#manual) to
39
//! use the package repository.
40
//!
41
//!
42
//! # Internals
43
//!
44
//! To make it fully testable, it uses a layered architecture based on
45
//! tokio streams which ends up being similar to how we use pipes in a
46
//! shell. We can divide it in the following layers:
47
//! - wrappers: we have 3 wrapper modules that abtract external
48
//!   libraries to provide us simpler types or types that provide that
49
//!   `impl` traits we need. They also make it easier to replate the
50
//!   underlying implementation in the future, if necessary. Namely:
51
//!   - [`process_wrapper`]: wraps process instantiation and I/O, and
52
//!     provides an [`Item`](process_wrapper::Item) that implements
53
//!     `Eq` so that we can use it in tests.
54
//!   - [`term_wrapper`]: implements terminal functions, mostly for
55
//!     output. As we are currently wrapping [`console`] and its
56
//!     functions require a [`console::Term`] object, we end up using
57
//!     a mutex here to abstract the singleton.
58
//!   - [`time_wrapper`]: home of the
59
//!     [`Instant`](time_wrapper::Instant) and
60
//!     [`Duration`](time_wrapper::Duration) types, which use types
61
//!     from [`chrono`] at the moment.
62
//! - [`sys`]: most of the ogle code doesn't really call functions
63
//!   that interact with the host system - we have the `sys` module
64
//!   for that. The module does that by providing a [`sys::SysApi`]
65
//!   trait that is then implemented by both the [`sys::SysReal`]
66
//!   type, which calls the system functions; and by the
67
//!   [`sys::SysVirtual`] type, which can be used to mock these calls
68
//!   in various ways.
69
//!
70
//! ```no_compile
71
//! sys -> input -> view -> output
72
//! ```
73
//!
74
//! [watch (1)]: https://linux.die.net/man/1/watch
75
//!
76

77
use clap::Parser;
78
use std::error::Error;
79

80
#[macro_use]
81
mod misc;
82

83
mod cli;
84
mod differ;
85
mod orchestrator;
86
mod progbar;
87

88
mod process_wrapper;
89
mod term_wrapper;
90
mod time_wrapper;
91

92
mod sys;
93

94
mod input;
95

96
mod view;
97

98
mod output;
99

100
/// Ogle main function, the single pub function in this lib.
101
#[tokio::main]
102
pub async fn main() -> Result<(), Box<dyn Error>> {
×
103
    color_eyre::install()?;
×
NEW
104
    tracing_subscriber::fmt()
×
NEW
105
        .with_span_events(tracing_subscriber::fmt::format::FmtSpan::ACTIVE)
×
NEW
106
        .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
×
NEW
107
        .init();
×
108
    let args = cli::Cli::parse();
×
NEW
109
    let sys = sys::SysReal::default();
×
NEW
110
    orchestrator::run(args, sys).await?;
×
111
    Ok(())
×
112
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc