Skip to content

Commit 82f2de2

Browse files
authored
Merge pull request #30 from rgwood/reload-units
Reload units
2 parents c1ec910 + baa91c6 commit 82f2de2

File tree

7 files changed

+65
-12
lines changed

7 files changed

+65
-12
lines changed

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ jobs:
88
matrix:
99
include:
1010
- target: aarch64-unknown-linux-musl
11-
os: ubuntu-latest
11+
os: ubuntu-24.04
1212
- target: x86_64-unknown-linux-musl
13-
os: ubuntu-latest
13+
os: ubuntu-24.04
1414
runs-on: ${{ matrix.os }}
1515
steps:
1616
- uses: actions/checkout@v4

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "systemctl-tui"
33
description = "A simple TUI for interacting with systemd services and their logs"
44
homepage = "https://github.com/rgwood/systemctl-tui"
55
repository = "https://github.com/rgwood/systemctl-tui"
6-
version = "0.3.9"
6+
version = "0.3.10"
77
edition = "2021"
88
authors = ["Reilly Wood"]
99
license = "MIT"

src/action.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ pub enum Action {
3333
ScrollDown(u16),
3434
ScrollToTop,
3535
ScrollToBottom,
36-
EditUnitFile { path: String },
36+
EditUnitFile { unit: UnitId, path: String },
3737
Noop,
3838
}

src/app.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{process::Command, sync::Arc};
22

33
use anyhow::{Context, Result};
4+
use log::error;
45
use tokio::sync::{mpsc, Mutex};
56
use tracing::debug;
67

@@ -93,16 +94,33 @@ impl App {
9394
Action::Suspend => self.should_suspend = true,
9495
Action::Resume => self.should_suspend = false,
9596
Action::Resize(_, _) => terminal.render().await,
96-
Action::EditUnitFile { path } => {
97+
// This would normally be in home.rs, but it needs to do some terminal and event handling stuff that's easier here
98+
Action::EditUnitFile { unit, path } => {
9799
event.stop();
98100
let mut tui = terminal.tui.lock().await;
99101
tui.exit()?;
102+
103+
let read_unit_file_contents = || match std::fs::read_to_string(&path) {
104+
Ok(contents) => contents,
105+
Err(e) => {
106+
error!("Failed to read unit file `{}`: {}", path, e);
107+
"".to_string()
108+
},
109+
};
110+
111+
let unit_file_contents = read_unit_file_contents();
100112
let editor = std::env::var("EDITOR").unwrap_or_else(|_| "nano".to_string());
101-
match Command::new(&editor).arg(path).status() {
113+
match Command::new(&editor).arg(&path).status() {
102114
Ok(_) => {
103115
tui.enter()?;
104116
tui.clear()?;
105117
event = EventHandler::new(self.home.clone(), action_tx.clone());
118+
119+
let new_unit_file_contents = read_unit_file_contents();
120+
if unit_file_contents != new_unit_file_contents {
121+
action_tx.send(Action::ReloadService(unit))?;
122+
}
123+
106124
action_tx.send(Action::EnterMode(Mode::ServiceList))?;
107125
},
108126
Err(e) => {

src/components/home.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,12 @@ impl Home {
272272
self.service_action(service, "Stop".into(), cancel_token, future);
273273
}
274274

275+
fn reload_service(&mut self, service: UnitId) {
276+
let cancel_token = CancellationToken::new();
277+
let future = systemd::reload(service.scope, cancel_token.clone());
278+
self.service_action(service, "Reload".into(), cancel_token, future);
279+
}
280+
275281
fn restart_service(&mut self, service: UnitId) {
276282
let cancel_token = CancellationToken::new();
277283
let future = systemd::restart_service(service.clone(), cancel_token.clone());
@@ -564,15 +570,18 @@ impl Component for Home {
564570
MenuItem::new("Start", Action::StartService(selected.id())),
565571
MenuItem::new("Stop", Action::StopService(selected.id())),
566572
MenuItem::new("Restart", Action::RestartService(selected.id())),
573+
MenuItem::new("Reload", Action::ReloadService(selected.id())),
567574
// TODO add these
568-
// MenuItem::new("Reload", Action::ReloadService(selected.clone())),
569575
// MenuItem::new("Enable", Action::EnableService(selected.clone())),
570576
// MenuItem::new("Disable", Action::DisableService(selected.clone())),
571577
];
572578

573579
if let Some(Ok(file_path)) = &selected.file_path {
574580
menu_items.push(MenuItem::new("Copy unit file path to clipboard", Action::CopyUnitFilePath));
575-
menu_items.push(MenuItem::new("Edit unit file", Action::EditUnitFile { path: file_path.clone() }));
581+
menu_items.push(MenuItem::new(
582+
"Edit unit file",
583+
Action::EditUnitFile { unit: selected.id(), path: file_path.clone() },
584+
));
576585
}
577586

578587
self.menu_items = StatefulList::with_items(menu_items);
@@ -652,6 +661,7 @@ impl Component for Home {
652661

653662
Action::StartService(service_name) => self.start_service(service_name),
654663
Action::StopService(service_name) => self.stop_service(service_name),
664+
Action::ReloadService(service_name) => self.reload_service(service_name),
655665
Action::RestartService(service_name) => self.restart_service(service_name),
656666
Action::RefreshServices => {
657667
let tx = self.action_tx.clone().unwrap();

src/systemd.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use core::str;
44
use std::process::Command;
55

6-
use anyhow::{bail, Result};
6+
use anyhow::{bail, Context, Result};
77
use log::error;
88
use tokio_util::sync::CancellationToken;
99
use tracing::info;
@@ -198,7 +198,6 @@ pub async fn start_service(service: UnitId, cancel_token: CancellationToken) ->
198198
// god these select macros are ugly, is there really no better way to select?
199199
tokio::select! {
200200
_ = cancel_token.cancelled() => {
201-
// The token was cancelled
202201
anyhow::bail!("cancelled");
203202
}
204203
result = start_service(service) => {
@@ -218,7 +217,6 @@ pub async fn stop_service(service: UnitId, cancel_token: CancellationToken) -> R
218217
// god these select macros are ugly, is there really no better way to select?
219218
tokio::select! {
220219
_ = cancel_token.cancelled() => {
221-
// The token was cancelled
222220
anyhow::bail!("cancelled");
223221
}
224222
result = stop_service(service) => {
@@ -227,6 +225,29 @@ pub async fn stop_service(service: UnitId, cancel_token: CancellationToken) -> R
227225
}
228226
}
229227

228+
pub async fn reload(scope: UnitScope, cancel_token: CancellationToken) -> Result<()> {
229+
async fn reload_(scope: UnitScope) -> Result<()> {
230+
let connection = get_connection(scope).await?;
231+
let manager_proxy: ManagerProxy<'_> = ManagerProxy::new(&connection).await?;
232+
let error_message = match scope {
233+
UnitScope::Global => "Failed to reload units, probably because superuser permissions are needed. Try running `sudo systemctl daemon-reload`",
234+
UnitScope::User => "Failed to reload units. Try running `systemctl --user daemon-reload`",
235+
};
236+
manager_proxy.reload().await.context(error_message)?;
237+
Ok(())
238+
}
239+
240+
// god these select macros are ugly, is there really no better way to select?
241+
tokio::select! {
242+
_ = cancel_token.cancelled() => {
243+
anyhow::bail!("cancelled");
244+
}
245+
result = reload_(scope) => {
246+
result
247+
}
248+
}
249+
}
250+
230251
async fn get_connection(scope: UnitScope) -> Result<Connection, anyhow::Error> {
231252
match scope {
232253
UnitScope::Global => Ok(Connection::system().await?),
@@ -285,6 +306,10 @@ pub trait Manager {
285306
#[dbus_proxy(name = "StopUnit")]
286307
fn stop_unit(&self, name: String, mode: String) -> zbus::Result<zvariant::OwnedObjectPath>;
287308

309+
/// [📖](https://www.freedesktop.org/software/systemd/man/systemd.directives.html#ReloadUnit()) Call interface method `ReloadUnit`.
310+
#[dbus_proxy(name = "ReloadUnit")]
311+
fn reload_unit(&self, name: String, mode: String) -> zbus::Result<zvariant::OwnedObjectPath>;
312+
288313
/// [📖](https://www.freedesktop.org/software/systemd/man/systemd.directives.html#RestartUnit()) Call interface method `RestartUnit`.
289314
#[dbus_proxy(name = "RestartUnit")]
290315
fn restart_unit(&self, name: String, mode: String) -> zbus::Result<zvariant::OwnedObjectPath>;

0 commit comments

Comments
 (0)