fix: DOCKER_HOST env priority, config.toml fix

This commit is contained in:
Jack Wills
2026-01-27 16:32:20 +00:00
parent 307810391c
commit dc6206c55e
9 changed files with 132 additions and 32 deletions
+2 -2
View File
@@ -18,8 +18,8 @@
"show_timestamp": true,
// Don't draw gui - for debugging - mostly pointless
"gui": true,
// Docker host location
"host": "/var/run/docker.sock",
// Docker host location. Will take priority over a DOCKER_HOST env.
// "host": "/var/run/docker.sock",
// Display the timestamp in a custom format, if given option is invalid, it will default to %Y-%m-%dT%H:%M:%S.%8f -> 2025-02-18T12:34:56.01234567
// *Should* accept any valid strftime string up to 32 chars, see https://strftime.org/
"timestamp_format": "%Y-%m-%dT%H:%M:%S.%8f",
+2 -2
View File
@@ -24,8 +24,8 @@ show_timestamp = true
# Don't draw gui - for debugging - mostly pointless
gui = true
# Docker host location
host = "/var/run/docker.sock"
# Docker host location. Will take priority over a DOCKER_HOST env.
# host = "/var/run/docker.sock"
# Display the container logs timestamp with a given timezone, if timezone is unknown, defaults to UTC
timezone = "Etc/UTC"
+2 -2
View File
@@ -24,8 +24,8 @@ show_timestamp = true
# Don't draw gui - for debugging - mostly pointless
gui = true
# Docker host location
host = "/var/run/docker.sock"
# Docker host location. Will take priority over a DOCKER_HOST env.
# host = "/var/run/docker.sock"
# Display the container logs timestamp with a given timezone, if timezone is unknown, defaults to UTC
timezone = "Etc/UTC"
+4
View File
@@ -79,6 +79,8 @@ pub struct ConfigFile {
pub use_cli: Option<bool>,
}
impl ConfigFile {
/// Attempt to create a config.toml file, will attempt to recursively create the directories as well
fn crate_config_file(in_container: bool) -> Result<(), AppError> {
@@ -119,6 +121,8 @@ impl ConfigFile {
toml::from_str::<Self>(input).map_err(|i| AppError::Parse(i.message().to_owned()))
}
}
// TODO if on windows, omit the docker_host?
}
/// Read the config file path to string, then attempt to parse
+20 -14
View File
@@ -42,12 +42,16 @@ fn setup_tracing() {
tracing_subscriber::fmt().with_max_level(Level::INFO).init();
}
/// Read the optional docker_host path, the cli args take priority over the DOCKER_HOST env
/// Read the optional docker_host path, the DOCKER_HOST env take priority over cli or config
/// Bollard will use DOCKER_HOST env, so might be pointless here, although it will fix it's priority over any config setting
fn read_docker_host(config: &Config) -> Option<String> {
config
.host
.as_ref()
.map_or_else(|| std::env::var(DOCKER_HOST).ok(), |x| Some(x.clone()))
if let Ok(env) = std::env::var(DOCKER_HOST)
&& !env.trim().is_empty()
{
Some(env)
} else {
config.host.as_ref().cloned()
}
}
/// Create docker daemon handler, and only spawn up the docker data handler if a ping returns non-error
@@ -59,11 +63,11 @@ async fn docker_init(
) {
let host = read_docker_host(&app_data.lock().config);
let connection = host.map_or_else(Docker::connect_with_socket_defaults, |host| {
Docker::connect_with_socket(&host, 120, API_DEFAULT_VERSION)
});
if let Ok(docker) = connection
if let Ok(docker) = host
.as_ref()
.map_or_else(Docker::connect_with_defaults, |host| {
Docker::connect_with_socket(host, 120, API_DEFAULT_VERSION)
})
&& docker.ping().await.is_ok()
{
tokio::spawn(DockerData::start(
@@ -73,11 +77,13 @@ async fn docker_init(
docker_tx,
Arc::clone(gui_state),
));
return;
} else {
app_data.lock().set_error(
AppError::DockerConnect,
gui_state,
Status::DockerConnect(host),
);
}
app_data
.lock()
.set_error(AppError::DockerConnect, gui_state, Status::DockerConnect);
}
/// Create data for, and then spawn a tokio thread, for the input handler
+79 -6
View File
@@ -22,6 +22,7 @@ pub fn draw(
colors: AppColors,
error: &AppError,
f: &mut Frame,
host: Option<String>,
keymap: &Keymap,
seconds: Option<u8>,
) {
@@ -32,11 +33,17 @@ pub fn draw(
.borders(Borders::ALL);
let to_push = if matches!(error, AppError::DockerConnect) {
let s = if let Some(host) = host {
format!(" @ \"{host}\"")
} else {
String::new()
};
format!(
"\n\n {}::v{} closing in {:02} seconds",
"{}\n\n {}::v{} closing in {:02} seconds",
s,
NAME,
VERSION,
seconds.unwrap_or(5)
seconds.unwrap_or(5),
)
} else {
let clear_text = if keymap.clear == Keymap::new().clear {
@@ -107,6 +114,37 @@ mod tests {
/// Test that the error popup is centered, red background, white border, white text, and displays the correct text
fn test_draw_blocks_error_docker_connect_error() {
let mut setup = test_setup(46, 9, true, true);
setup
.terminal
.draw(|f| {
super::draw(
AppColors::new(),
&AppError::DockerConnect,
f,
None,
&Keymap::new(),
Some(4),
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
if let (0 | 8, _) = (row_index, result_cell_index) {
assert_eq!(result_cell.bg, Color::Reset);
assert_eq!(result_cell.fg, Color::Reset);
} else {
assert_eq!(result_cell.bg, Color::Red);
assert_eq!(result_cell.fg, Color::White);
}
}
}
}
#[test]
/// Test that the error popup is centered, red background, white border, white text, and displays the correct text with the custom docker host address
fn test_draw_blocks_error_docker_connect_error_custom_host() {
let mut setup = test_setup(46, 9, true, true);
setup
.terminal
@@ -115,6 +153,7 @@ mod tests {
AppColors::new(),
&AppError::DockerConnect,
f,
Some("/test/host.sock".to_owned()),
&Keymap::new(),
Some(4),
);
@@ -146,6 +185,8 @@ mod tests {
AppColors::new(),
&AppError::DockerExec,
f,
// TODO test me
None,
&Keymap::new(),
Some(4),
);
@@ -183,7 +224,15 @@ mod tests {
setup
.terminal
.draw(|f| {
super::draw(colors, &AppError::DockerExec, f, &Keymap::new(), Some(4));
// TODO test me
super::draw(
colors,
&AppError::DockerExec,
f,
None,
&Keymap::new(),
Some(4),
);
})
.unwrap();
@@ -218,7 +267,15 @@ mod tests {
setup
.terminal
.draw(|f| {
super::draw(AppColors::new(), &AppError::DockerExec, f, &keymap, None);
// TODO test me
super::draw(
AppColors::new(),
&AppError::DockerExec,
f,
None,
&keymap,
None,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
@@ -235,7 +292,15 @@ mod tests {
setup
.terminal
.draw(|f| {
super::draw(AppColors::new(), &AppError::DockerExec, f, &keymap, None);
// TODO test me
super::draw(
AppColors::new(),
&AppError::DockerExec,
f,
None,
&keymap,
None,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
@@ -252,7 +317,15 @@ mod tests {
setup
.terminal
.draw(|f| {
super::draw(AppColors::new(), &AppError::DockerExec, f, &keymap, None);
// TODO test me
super::draw(
AppColors::new(),
&AppError::DockerExec,
f,
None,
&keymap,
None,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
@@ -0,0 +1,13 @@
---
source: src/ui/draw_blocks/error.rs
expression: setup.terminal.backend()
---
" "
"╭────────────────── Error ───────────────────╮"
"│ │"
"│Unable to access docker daemon @ "/test/host│"
"│ │"
"│ oxker::v0.00.000 closing in 04 seconds │"
"│ │"
"╰────────────────────────────────────────────╯"
" "
+2 -2
View File
@@ -160,10 +160,10 @@ const FRAMES_LEN: u8 = 9;
/// The application gui state can be in multiple of these four states at the same time
/// Various functions (e.g input handler), operate differently depending upon current Status
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Status {
DeleteConfirm,
DockerConnect,
DockerConnect(Option<String>),
Error,
Exec,
Filter,
+8 -4
View File
@@ -132,7 +132,7 @@ impl Ui {
}
/// Draw the the error message ui, for 5 seconds, with a countdown
fn err_loop(&mut self) -> Result<(), AppError> {
fn err_loop(&mut self, host: Option<String>) -> Result<(), AppError> {
let mut seconds = 5;
let colors = self.app_data.lock().config.app_colors;
let keymap = self.app_data.lock().config.keymap.clone();
@@ -155,6 +155,7 @@ impl Ui {
colors,
&AppError::DockerConnect,
f,
host.clone(),
&keymap,
Some(seconds),
);
@@ -273,8 +274,11 @@ impl Ui {
/// Draw either the Error, or main oxker ui, to the terminal
async fn draw_ui(&mut self) -> Result<(), AppError> {
let status = self.gui_state.lock().get_status();
if status.contains(&Status::DockerConnect) {
self.err_loop()?;
if let Some(Status::DockerConnect(msg)) = status
.iter()
.find(|s| matches!(s, Status::DockerConnect(_)))
{
self.err_loop(msg.clone())?;
} else {
self.gui_loop().await?;
}
@@ -463,6 +467,6 @@ fn draw_frame(
}
if let Some(error) = fd.has_error.as_ref() {
draw_blocks::error::draw(colors, error, f, keymap, None);
draw_blocks::error::draw(colors, error, f, None, keymap, None);
}
}