Skip to content

Commit b3f4c97

Browse files
committed
Add command log dialog
1 parent 2e7f4e9 commit b3f4c97

File tree

8 files changed

+384
-100
lines changed

8 files changed

+384
-100
lines changed

src/application.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ use gtk::{gio, glib};
2828

2929
use crate::config::VERSION;
3030
use crate::distrobox::{
31-
CommandRunner, Distrobox, DistroboxCommandRunnerResponse, FlatpakCommandRunner,
32-
RealCommandRunner,
31+
CommandRunner, Distrobox, DistroboxCommandRunnerResponse
3332
};
3433
use crate::root_store::RootStore;
3534
use crate::DistroShelfWindow;
@@ -224,13 +223,15 @@ impl DistroShelfApplication {
224223
}
225224
_ => {
226225
if Self::get_is_in_flatpak() {
227-
Rc::new(FlatpakCommandRunner::new(Rc::new(RealCommandRunner {}))) as Rc<dyn CommandRunner>
226+
CommandRunner::new_flatpak_real()
228227
} else {
229-
Rc::new(RealCommandRunner {}) as Rc<dyn CommandRunner>
228+
CommandRunner::new_real()
230229
}
231230
}
232231
};
233232

233+
command_runner.output_tracker().enable();
234+
234235
self.set_root_store(RootStore::new(command_runner));
235236
let window =
236237
DistroShelfWindow::new(self.upcast_ref::<adw::Application>(), self.root_store());

src/distrobox/command.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{
2-
ffi::{OsStr, OsString},
3-
process::Stdio,
2+
ffi::{OsStr, OsString}, fmt::Display, process::Stdio
43
};
54

65
#[derive(Debug, Clone)]
@@ -88,6 +87,16 @@ impl Command {
8887
}
8988
}
9089

90+
impl Display for Command {
91+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92+
write!(f, "{}", self.program.to_string_lossy())?;
93+
for arg in &self.args {
94+
write!(f, " {}", arg.to_string_lossy())?;
95+
}
96+
Ok(())
97+
}
98+
}
99+
91100
impl From<Command> for async_process::Command {
92101
fn from(val: Command) -> Self {
93102
let mut cmd = async_process::Command::new(val.program);

src/distrobox/command_runner.rs

Lines changed: 105 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,10 @@
22
// returning predefined outputs, to ease code testing.
33

44
use std::{
5-
collections::HashMap,
6-
future::Future,
7-
io::{self},
8-
os::unix::process::ExitStatusExt,
9-
pin::Pin,
10-
process::ExitStatus,
11-
rc::Rc,
5+
collections::HashMap, future::Future, io::{self}, os::unix::process::ExitStatusExt, pin::Pin, process::ExitStatus, rc::Rc
126
};
137

14-
use crate::distrobox::Command;
8+
use crate::distrobox::{Command, OutputTracker};
159
use async_process::{Command as AsyncCommand, Output};
1610
use futures::{
1711
io::{AsyncRead, AsyncWrite, Cursor},
@@ -20,7 +14,100 @@ use futures::{
2014

2115
use super::wrap_flatpak_cmd;
2216

23-
pub trait CommandRunner {
17+
18+
#[derive(Debug, Clone)]
19+
pub enum CommandRunnerEvent {
20+
Spawned(usize, Command),
21+
/// Started command that will return the output
22+
Started(usize, Command),
23+
Output(usize, Result<(), ()>),
24+
}
25+
26+
impl CommandRunnerEvent {
27+
pub fn event_id(&self) -> usize {
28+
match self {
29+
CommandRunnerEvent::Spawned(id, _) => *id,
30+
CommandRunnerEvent::Started(id, _) => *id,
31+
CommandRunnerEvent::Output(id, _) => *id,
32+
}
33+
}
34+
pub fn command(&self) -> Option<&Command> {
35+
match self {
36+
CommandRunnerEvent::Spawned(_, cmd) => Some(cmd),
37+
CommandRunnerEvent::Started(_, cmd) => Some(cmd),
38+
CommandRunnerEvent::Output(_, _) => None,
39+
}
40+
}
41+
}
42+
43+
#[derive(Clone)]
44+
pub struct CommandRunner {
45+
pub inner: Rc<dyn InnerCommandRunner>,
46+
pub output_tracker: OutputTracker<CommandRunnerEvent>,
47+
}
48+
49+
impl CommandRunner {
50+
pub fn new(inner: Rc<dyn InnerCommandRunner>) -> Self {
51+
CommandRunner {
52+
inner,
53+
output_tracker: OutputTracker::new(),
54+
}
55+
}
56+
pub fn new_null() -> Self {
57+
CommandRunner::new(Rc::new(NullCommandRunner::default()))
58+
}
59+
pub fn new_real() -> Self {
60+
CommandRunner::new(Rc::new(RealCommandRunner {}))
61+
}
62+
pub fn new_flatpak_real() -> Self {
63+
CommandRunner::new(Rc::new(FlatpakCommandRunner::new(
64+
Rc::new(RealCommandRunner {}),
65+
)))
66+
}
67+
68+
pub fn output_tracker(&self) -> OutputTracker<CommandRunnerEvent> {
69+
self.output_tracker.enable();
70+
self.output_tracker.clone()
71+
}
72+
73+
fn event_id(&self) -> usize {
74+
self.output_tracker.len()
75+
}
76+
77+
pub fn spawn(&self, command: Command) -> io::Result<Box<dyn Child + Send>> {
78+
self.output_tracker.push(CommandRunnerEvent::Spawned(self.event_id(), command.clone()));
79+
self.inner.spawn(command)
80+
}
81+
82+
pub fn output(
83+
&self,
84+
command: Command,
85+
) -> Pin<Box<dyn Future<Output = io::Result<std::process::Output>>>> {
86+
let event_id = self.event_id();
87+
self.output_tracker.push(CommandRunnerEvent::Started(event_id, command.clone()));
88+
let fut = self.inner.output(command);
89+
let this = self.clone();
90+
fut.map(move |result| {
91+
let res_summary = match &result {
92+
Ok(_output) => {
93+
Ok(())
94+
}
95+
Err(_e) => Err(()),
96+
};
97+
this.output_tracker.push(CommandRunnerEvent::Output(event_id, res_summary));
98+
result
99+
})
100+
.boxed_local()
101+
}
102+
}
103+
104+
impl Default for CommandRunner {
105+
fn default() -> Self {
106+
CommandRunner::new_null()
107+
}
108+
}
109+
110+
pub trait InnerCommandRunner {
24111
fn spawn(&self, command: Command) -> io::Result<Box<dyn Child + Send>>;
25112
fn output(
26113
&self,
@@ -31,7 +118,7 @@ pub trait CommandRunner {
31118
#[derive(Clone, Debug)]
32119
pub struct RealCommandRunner {}
33120

34-
impl CommandRunner for RealCommandRunner {
121+
impl InnerCommandRunner for RealCommandRunner {
35122
fn spawn(&self, command: Command) -> io::Result<Box<dyn Child + Send>> {
36123
let mut command: AsyncCommand = command.into();
37124
Ok(Box::new(command.spawn()?))
@@ -47,15 +134,15 @@ impl CommandRunner for RealCommandRunner {
47134

48135
#[derive(Clone)]
49136
pub struct FlatpakCommandRunner {
50-
pub command_runner: Rc<dyn CommandRunner>,
137+
pub command_runner: Rc<dyn InnerCommandRunner>,
51138
}
52139
impl FlatpakCommandRunner {
53-
pub fn new(command_runner: Rc<dyn CommandRunner>) -> Self {
140+
pub fn new(command_runner: Rc<dyn InnerCommandRunner>) -> Self {
54141
FlatpakCommandRunner { command_runner }
55142
}
56143
}
57144

58-
impl CommandRunner for FlatpakCommandRunner {
145+
impl InnerCommandRunner for FlatpakCommandRunner {
59146
fn spawn(&self, command: Command) -> io::Result<Box<dyn Child + Send>> {
60147
self.command_runner.spawn(wrap_flatpak_cmd(command))
61148
}
@@ -98,11 +185,12 @@ impl NullCommandRunnerBuilder {
98185
self.fallback_exit_status = status;
99186
self
100187
}
101-
pub fn build(&self) -> NullCommandRunner {
102-
NullCommandRunner {
188+
pub fn build(&self) -> CommandRunner {
189+
let inner = Rc::new(NullCommandRunner {
103190
responses: self.responses.clone(),
104191
fallback_exit_status: self.fallback_exit_status,
105-
}
192+
});
193+
CommandRunner::new(inner)
106194
}
107195
}
108196

@@ -124,7 +212,7 @@ impl NullCommandRunner {
124212
}
125213
}
126214

127-
impl CommandRunner for NullCommandRunner {
215+
impl InnerCommandRunner for NullCommandRunner {
128216
fn spawn(&self, command: Command) -> io::Result<Box<dyn Child + Send>> {
129217
let key = Self::key_for_cmd(&command);
130218
let response = self

0 commit comments

Comments
 (0)