Skip to content

Commit f19b7bf

Browse files
committed
add initial functionality for rich CLI interfaces
1 parent ed99559 commit f19b7bf

File tree

20 files changed

+2187
-28
lines changed

20 files changed

+2187
-28
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/rugpi-bakery/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ toml = "0.8.8"
2727
url = { version = "2.4.0", features = ["serde"] }
2828
uuid = { version = "1.8.0", features = ["v4"] }
2929
xscript.workspace = true
30+
tracing.workspace = true
3031

3132
reportify.workspace = true
3233
rugpi-cli.workspace = true

crates/rugpi-bakery/src/bake/customize.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::{
1111
use reportify::{bail, ResultExt};
1212
use rugpi_common::mount::{MountStack, Mounted};
1313
use tempfile::tempdir;
14+
use tracing::{error, info};
1415
use xscript::{cmd, run, vars, ParentEnv, Run};
1516

1617
use crate::{

crates/rugpi-bakery/src/bake/image.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rugpi_common::{
1717
utils::{ascii_numbers, units::NumBytes},
1818
};
1919
use tempfile::tempdir;
20+
use tracing::info;
2021
use xscript::{run, Run};
2122

2223
use crate::{

crates/rugpi-bakery/src/bake/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::{
88
use reportify::{bail, whatever, ResultExt};
99
use rugpi_common::{loop_dev::LoopDevice, mount::Mounted};
1010
use tempfile::tempdir;
11+
use tracing::info;
1112
use url::Url;
1213
use xscript::{run, Run};
1314

crates/rugpi-bakery/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pub struct InitCommand {
123123

124124
/// Entrypoint of the CLI.
125125
fn main() -> BakeryResult<()> {
126-
rugpi_cli::init();
126+
rugpi_cli::Initializer::new().init();
127127

128128
let args = Args::parse();
129129
match &args.command {

crates/rugpi-bakery/src/project/recipes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use std::{
99
};
1010

1111
use reportify::{bail, whatever, ResultExt};
12-
use rugpi_cli::warn;
1312
use serde::{Deserialize, Serialize};
13+
use tracing::warn;
1414

1515
use super::repositories::RepositoryIdx;
1616
use crate::{

crates/rugpi-bakery/src/project/repositories.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,12 @@ use std::{
3131
use reportify::{bail, ResultExt};
3232
use serde::{Deserialize, Serialize};
3333
use sha1::{Digest, Sha1};
34+
use tracing::debug;
3435
use xscript::{read_str, run, LocalEnv, Run};
3536

3637
use super::Project;
3738
use crate::{
38-
utils::{
39-
idx_vec::{new_idx_type, IdxVec},
40-
prelude::*,
41-
},
39+
utils::idx_vec::{new_idx_type, IdxVec},
4240
BakeryResult,
4341
};
4442

crates/rugpi-bakery/src/test/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::{path::Path, time::Duration};
22

33
use reportify::{bail, Report, ResultExt};
4-
use rugpi_cli::info;
54
use tokio::{fs, task::spawn_blocking};
5+
use tracing::info;
66
use workflow::{TestStep, TestWorkflow};
77

88
use crate::{bake, project::Project};

crates/rugpi-bakery/src/test/qemu.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::{path::Path, process::Stdio, sync::Arc, time::Duration};
22

33
use async_trait::async_trait;
44
use reportify::{bail, whatever, ErrorExt, Report, ResultExt, Whatever};
5-
use rugpi_cli::{error, info};
65
use russh::{
76
client::Handle,
87
keys::{key::PrivateKeyWithHashAlg, load_secret_key, ssh_key, PrivateKey},
@@ -17,6 +16,7 @@ use tokio::{
1716
sync::{oneshot, Mutex},
1817
time,
1918
};
19+
use tracing::{error, info};
2020

2121
use super::{workflow::TestSystemConfig, RugpiTestResult};
2222

crates/rugpi-bakery/src/utils/caching.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use indicatif::{ProgressBar, ProgressStyle};
1111
use reportify::{bail, ResultExt};
1212
use serde::{Deserialize, Serialize};
1313
use sha1::{Digest, Sha1};
14+
use tracing::info;
1415
use url::Url;
1516

1617
use crate::{utils::prelude::*, BakeryResult};

crates/rugpi-bakery/src/utils/logging.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#[macro_export]
22
macro_rules! bug {
33
($msg:literal) => {
4-
rugpi_cli::error!("[BUG] {}", $msg)
4+
tracing::error!("[BUG] {}", $msg)
55
};
66
}
77

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
//! Custom prelude.
22
3-
pub use rugpi_cli::{debug, error, info, trace, warn};
4-
53
pub use super::{logging::bug, once_cell_ext::OnceCellExt};

crates/rugpi-cli/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ repository.workspace = true
88
homepage.workspace = true
99

1010
[dependencies]
11-
tracing.workspace = true
11+
console = "0.15.10"
1212
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
1313

14+
tracing.workspace = true
15+
1416
[lints]
1517
workspace = true

crates/rugpi-cli/examples/progress.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
use std::collections::VecDeque;
2+
use std::fmt::Display;
3+
use std::sync::Mutex;
4+
use std::time::Duration;
5+
6+
use tracing::info;
7+
8+
use rugpi_cli::style::{Styled, Stylize};
9+
use rugpi_cli::widgets::{Heading, ProgressBar, ProgressSpinner, Rule, Text, Widget};
10+
use rugpi_cli::{DrawCtx, StatusSegment};
11+
12+
pub fn cli() {
13+
let _hello_world = rugpi_cli::add_status(Styled::new("Hello World!").blue());
14+
let task_progress = rugpi_cli::add_status(TaskProgress {
15+
state: Mutex::new(TaskState {
16+
current_step: 0,
17+
total_steps: 1000,
18+
title: String::new(),
19+
message: String::new(),
20+
log_lines: VecDeque::new(),
21+
}),
22+
});
23+
let _rugpi_banner = rugpi_cli::add_status(
24+
r#"
25+
____ _ _
26+
| _ \ _ _ __ _ _ __ (_) __ _/ |
27+
| |_) | | | |/ _` | '_ \| | \ \ / / |
28+
| _ <| |_| | (_| | |_) | | \ V /| |
29+
|_| \_\\__,_|\__, | .__/|_| \_/ |_| by Silitics
30+
|___/|_|
31+
32+
For more information, visit https://oss.silitics.com/rugpi/.
33+
"#,
34+
);
35+
36+
for step in 0..=1000 {
37+
std::thread::sleep(Duration::from_millis(10));
38+
task_progress.set_step(step);
39+
if step % 10 == 0 {
40+
task_progress.push_log_line(format!("Position {step} reached!"));
41+
}
42+
if step % 100 == 0 {
43+
info!("Position {step} reached!");
44+
}
45+
if step % 400 == 0 {
46+
task_progress.set_message("Doing work...");
47+
} else if step % 400 == 200 {
48+
task_progress.set_message("");
49+
}
50+
if step == 500 {
51+
task_progress.set_title("Reached 500");
52+
}
53+
rugpi_cli::redraw();
54+
}
55+
56+
rugpi_cli::hide_status();
57+
58+
std::thread::sleep(Duration::from_secs(2));
59+
60+
rugpi_cli::show_status();
61+
62+
std::thread::sleep(Duration::from_secs(5));
63+
}
64+
65+
pub fn main() {
66+
rugpi_cli::Initializer::new().init();
67+
cli();
68+
rugpi_cli::force_redraw();
69+
}
70+
71+
struct TaskProgress {
72+
state: Mutex<TaskState>,
73+
}
74+
75+
impl TaskProgress {
76+
pub fn set_step(&self, step: u64) {
77+
self.state.lock().unwrap().current_step = step;
78+
}
79+
80+
pub fn set_title<D: Display>(&self, title: D) {
81+
self.state.lock().unwrap().title = title.to_string();
82+
}
83+
84+
pub fn set_message<D: Display>(&self, message: D) {
85+
self.state.lock().unwrap().message = message.to_string();
86+
}
87+
88+
pub fn push_log_line(&self, line: String) {
89+
let mut state = self.state.lock().unwrap();
90+
state.log_lines.push_back(line);
91+
while state.log_lines.len() > 5 {
92+
state.log_lines.pop_front();
93+
}
94+
}
95+
}
96+
97+
struct TaskState {
98+
current_step: u64,
99+
total_steps: u64,
100+
title: String,
101+
message: String,
102+
log_lines: VecDeque<String>,
103+
}
104+
105+
impl StatusSegment for TaskProgress {
106+
fn draw(&self, ctx: &mut DrawCtx) {
107+
let state = self.state.lock().unwrap();
108+
if state.title.is_empty() {
109+
Rule::new().draw(ctx)
110+
} else {
111+
Heading::new(&state.title).draw(ctx);
112+
};
113+
ProgressSpinner::new().draw(ctx);
114+
write!(ctx, " Step [{}/{}] ", state.current_step, state.total_steps);
115+
if !state.message.is_empty() {
116+
ctx.write_str(&state.message);
117+
ctx.write_char(' ');
118+
}
119+
ProgressBar::new(state.current_step, state.total_steps).draw(ctx);
120+
let remaining_height = ctx.measure_remaining_height();
121+
if !state.log_lines.is_empty() && remaining_height > 2 {
122+
let show_lines = state
123+
.log_lines
124+
.len()
125+
.min(5)
126+
.min(remaining_height.into_u64() as usize);
127+
let skip_lines = state.log_lines.len() - show_lines;
128+
Text::new(state.log_lines.iter().skip(skip_lines))
129+
.prefix("> ")
130+
.styled()
131+
.black()
132+
.draw(ctx);
133+
}
134+
}
135+
}

0 commit comments

Comments
 (0)