Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ readme = "README.md"
description = "Dig into ClickHouse with TUI interface"
license = "MIT"
version = "25.6.2"
edition = "2021"
edition = "2024"

[lib]
name = "chdig"
Expand Down Expand Up @@ -93,6 +93,7 @@ lto = false
[lints.clippy]
needless_return = "allow"
type_complexity = "allow"
uninlined_format_args = "allow"

[lints.rust]
elided_lifetimes_in_paths = "deny"
6 changes: 3 additions & 3 deletions src/bin.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use backtrace::Backtrace;
use flexi_logger::{LogSpecification, Logger};
use std::ffi::OsString;
use std::panic::{self, PanicHookInfo};
use std::sync::Arc;

use crate::{
interpreter::{options, ClickHouse, Context, ContextArc},
interpreter::{ClickHouse, Context, ContextArc, options},
view::Navigation,
};

Expand Down Expand Up @@ -92,7 +92,7 @@ fn collect_args(argc: c_int, argv: *const *const c_char) -> Vec<OsString> {
}

use std::os::raw::{c_char, c_int};
#[no_mangle]
#[unsafe(no_mangle)]
pub extern "C" fn chdig_main(argc: c_int, argv: *const *const c_char) -> c_int {
tokio::runtime::Builder::new_current_thread()
.enable_all()
Expand Down
16 changes: 9 additions & 7 deletions src/interpreter/background_runner.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::sync::{atomic, Arc, Condvar, Mutex};
use std::sync::{Arc, Condvar, Mutex, atomic};
use std::thread;
use std::time::Duration;

Expand Down Expand Up @@ -52,13 +52,15 @@ impl BackgroundRunner {
let cv = self.cv.clone();
let exit = self.exit.clone();
let force = self.force.clone();
self.thread = Some(std::thread::spawn(move || loop {
let was_force = force.swap(false, atomic::Ordering::SeqCst);
callback(was_force);
self.thread = Some(std::thread::spawn(move || {
loop {
let was_force = force.swap(false, atomic::Ordering::SeqCst);
callback(was_force);

let _ = cv.1.wait_timeout(cv.0.lock().unwrap(), interval).unwrap();
if *exit.lock().unwrap() {
break;
let _ = cv.1.wait_timeout(cv.0.lock().unwrap(), interval).unwrap();
if *exit.lock().unwrap() {
break;
}
}
}));
// Explicitly trigger at least one update with force
Expand Down
4 changes: 2 additions & 2 deletions src/interpreter/clickhouse.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::interpreter::{options::ClickHouseOptions, ClickHouseAvailableQuirks, ClickHouseQuirks};
use crate::interpreter::{ClickHouseAvailableQuirks, ClickHouseQuirks, options::ClickHouseOptions};
use anyhow::{Error, Result};
use chrono::{DateTime, Local};
use clickhouse_rs::{
types::{Complex, FromSql},
Block, Options, Pool,
types::{Complex, FromSql},
};
use futures_util::StreamExt;
use std::collections::HashMap;
Expand Down
6 changes: 3 additions & 3 deletions src/interpreter/context.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::actions::ActionDescription;
use crate::interpreter::{options::ChDigOptions, ClickHouse, Worker};
use crate::interpreter::{ClickHouse, Worker, options::ChDigOptions};
use anyhow::Result;
use chrono::Duration;
use cursive::{event::Event, event::EventResult, views::Dialog, views::OnEventView, Cursive, View};
use std::sync::{atomic, Arc, Condvar, Mutex};
use cursive::{Cursive, View, event::Event, event::EventResult, views::Dialog, views::OnEventView};
use std::sync::{Arc, Condvar, Mutex, atomic};

pub type ContextArc = Arc<Mutex<Context>>;

Expand Down
14 changes: 7 additions & 7 deletions src/interpreter/flamegraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ use flamelens::flame::FlameGraph;
use flamelens::handler::handle_key_events;
use flamelens::ui;
use futures::channel::mpsc;
use ratatui::backend::CrosstermBackend;
use ratatui::Terminal;
use ratatui::backend::CrosstermBackend;
use std::io;
use tokio::time::{sleep, Duration};
use tokio::time::{Duration, sleep};
use urlencoding::encode;
use warp::http::header::{HeaderMap, HeaderValue};
use warp::Filter;
use warp::http::header::{HeaderMap, HeaderValue};

pub fn show(block: Columns) -> AppResult<()> {
let data = block
Expand Down Expand Up @@ -45,10 +45,10 @@ pub fn show(block: Columns) -> AppResult<()> {
while app.running {
terminal.draw(|frame| {
ui::render(&mut app, frame);
if let Some(input_buffer) = &app.input_buffer {
if let Some(cursor) = input_buffer.cursor {
frame.set_cursor_position((cursor.0, cursor.1));
}
if let Some(input_buffer) = &app.input_buffer
&& let Some(cursor) = input_buffer.cursor
{
frame.set_cursor_position((cursor.0, cursor.1));
}
})?;

Expand Down
143 changes: 69 additions & 74 deletions src/interpreter/options.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use chrono::{DateTime, Duration, Local, NaiveDate, NaiveDateTime};
use clap::{builder::ArgPredicate, ArgAction, Args, CommandFactory, Parser, Subcommand};
use clap_complete::{generate, Shell};
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use clap::{ArgAction, Args, CommandFactory, Parser, Subcommand, builder::ArgPredicate};
use clap_complete::{Shell, generate};
use percent_encoding::{NON_ALPHANUMERIC, utf8_percent_encode};
use quick_xml::de::Deserializer as XmlDeserializer;
use serde::Deserialize;
use serde_yaml::Deserializer as YamlDeserializer;
Expand Down Expand Up @@ -198,7 +198,7 @@ pub fn parse_datetime_or_date(value: &str) -> Result<DateTime<Local>, String> {
.and_hms_opt(0, 0, 0)
.unwrap()
.and_local_timezone(Local)
.unwrap())
.unwrap());
}
Err(err) => errors.push(err),
}
Expand Down Expand Up @@ -354,13 +354,13 @@ fn is_local_address(host: &str) -> bool {
}

fn set_password_from_opt(url: &mut url::Url, password: Option<String>, force: bool) -> Result<()> {
if let Some(password) = password {
if url.password().is_none() || force {
url.set_password(Some(
&utf8_percent_encode(&password, NON_ALPHANUMERIC).to_string(),
))
.map_err(|_| anyhow!("password is invalid"))?;
}
if let Some(password) = password
&& (url.password().is_none() || force)
{
url.set_password(Some(
&utf8_percent_encode(&password, NON_ALPHANUMERIC).to_string(),
))
.map_err(|_| anyhow!("password is invalid"))?;
}
Ok(())
}
Expand Down Expand Up @@ -415,51 +415,48 @@ fn clickhouse_url_defaults(
// config
//
if let Some(config) = config {
if url.username().is_empty() {
if let Some(user) = config.user {
url.set_username(user.as_str())
.map_err(|_| anyhow!("username is invalid"))?;
}
if url.username().is_empty()
&& let Some(user) = config.user
{
url.set_username(user.as_str())
.map_err(|_| anyhow!("username is invalid"))?;
}
set_password_from_opt(&mut url, config.password, false)?;
if secure.is_none() {
if let Some(conf_secure) = config.secure {
secure = Some(conf_secure);
}
if secure.is_none()
&& let Some(conf_secure) = config.secure
{
secure = Some(conf_secure);
}

let ssl_client = config.open_ssl.and_then(|ssl| ssl.client);
if skip_verify.is_none() {
if let Some(conf_skip_verify) = config
if skip_verify.is_none()
&& let Some(conf_skip_verify) = config
.skip_verify
.or(config.accept_invalid_certificate)
.or_else(|| {
ssl_client
.as_ref()
.map(|client| client.verification_mode == Some("none".to_string()))
})
{
skip_verify = Some(conf_skip_verify);
}
{
skip_verify = Some(conf_skip_verify);
}
if ca_certificate.is_none() {
if let Some(conf_ca_certificate) = ssl_client.as_ref().map(|v| v.ca_config.clone()) {
ca_certificate = conf_ca_certificate.clone();
}
if ca_certificate.is_none()
&& let Some(conf_ca_certificate) = ssl_client.as_ref().map(|v| v.ca_config.clone())
{
ca_certificate = conf_ca_certificate.clone();
}
if client_certificate.is_none() {
if let Some(conf_client_certificate) =
if client_certificate.is_none()
&& let Some(conf_client_certificate) =
ssl_client.as_ref().map(|v| v.certificate_file.clone())
{
client_certificate = conf_client_certificate.clone();
}
{
client_certificate = conf_client_certificate.clone();
}
if client_private_key.is_none() {
if let Some(conf_client_private_key) =
if client_private_key.is_none()
&& let Some(conf_client_private_key) =
ssl_client.as_ref().map(|v| v.private_key_file.clone())
{
client_private_key = conf_client_private_key.clone();
}
{
client_private_key = conf_client_private_key.clone();
}

//
Expand All @@ -476,48 +473,46 @@ fn clickhouse_url_defaults(
}

connection_found = true;
if !has_host {
if let Some(hostname) = &c.hostname {
url.set_host(Some(hostname.as_str()))?;
}
if !has_host && let Some(hostname) = &c.hostname {
url.set_host(Some(hostname.as_str()))?;
}
if url.port().is_none() {
if let Some(port) = c.port {
url.set_port(Some(port))
.map_err(|_| anyhow!("Cannot set port"))?;
}
if url.port().is_none()
&& let Some(port) = c.port
{
url.set_port(Some(port))
.map_err(|_| anyhow!("Cannot set port"))?;
}
if url.username().is_empty() {
if let Some(user) = &c.user {
url.set_username(user.as_str())
.map_err(|_| anyhow!("username is invalid"))?;
}
if url.username().is_empty()
&& let Some(user) = &c.user
{
url.set_username(user.as_str())
.map_err(|_| anyhow!("username is invalid"))?;
}
set_password_from_opt(&mut url, c.password.clone(), false)?;
if secure.is_none() {
if let Some(con_secure) = c.secure {
secure = Some(con_secure);
}
if secure.is_none()
&& let Some(con_secure) = c.secure
{
secure = Some(con_secure);
}
if skip_verify.is_none() {
if let Some(con_skip_verify) = c.skip_verify {
skip_verify = Some(con_skip_verify);
}
if skip_verify.is_none()
&& let Some(con_skip_verify) = c.skip_verify
{
skip_verify = Some(con_skip_verify);
}
if ca_certificate.is_none() {
if let Some(con_ca_certificate) = &c.ca_certificate {
ca_certificate = Some(con_ca_certificate.clone());
}
if ca_certificate.is_none()
&& let Some(con_ca_certificate) = &c.ca_certificate
{
ca_certificate = Some(con_ca_certificate.clone());
}
if client_certificate.is_none() {
if let Some(con_client_certificate) = &c.client_certificate {
client_certificate = Some(con_client_certificate.clone());
}
if client_certificate.is_none()
&& let Some(con_client_certificate) = &c.client_certificate
{
client_certificate = Some(con_client_certificate.clone());
}
if client_private_key.is_none() {
if let Some(con_client_private_key) = &c.client_private_key {
client_private_key = Some(con_client_private_key.clone());
}
if client_private_key.is_none()
&& let Some(con_client_private_key) = &c.client_private_key
{
client_private_key = Some(con_client_private_key.clone());
}
}

Expand Down
21 changes: 12 additions & 9 deletions src/interpreter/worker.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::{
common::Stopwatch,
interpreter::clickhouse::{Columns, TraceType},
interpreter::{flamegraph, ContextArc},
interpreter::{ContextArc, flamegraph},
utils::{highlight_sql, open_graph_in_browser},
view::{self, Navigation},
};
use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use chrono::{DateTime, Local};
// FIXME: "leaky abstractions"
use clickhouse_rs::errors::Error as ClickHouseError;
Expand Down Expand Up @@ -207,13 +207,16 @@ async fn start_tokio(context: ContextArc, receiver: ReceiverArc) {
.cluster
.as_ref()
.is_some_and(|v| !v.is_empty());
if has_cluster {
if let Some(ClickHouseError::Server(server_error)) = &err.downcast_ref::<ClickHouseError>() {
if server_error.code == CLICKHOUSE_ERROR_CODE_ALL_CONNECTION_TRIES_FAILED {
siv.add_layer(views::Dialog::info(format!("{}\n(consider adding skip_unavailable_shards=1 to the connection URL)", err)));
return;
}
}
if has_cluster
&& let Some(ClickHouseError::Server(server_error)) =
&err.downcast_ref::<ClickHouseError>()
&& server_error.code == CLICKHOUSE_ERROR_CODE_ALL_CONNECTION_TRIES_FAILED
{
siv.add_layer(views::Dialog::info(format!(
"{}\n(consider adding skip_unavailable_shards=1 to the connection URL)",
err
)));
return;
}

siv.add_layer(views::Dialog::info(err.to_string()));
Expand Down
2 changes: 1 addition & 1 deletion src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use cursive::utils::markup::StyledString;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{stdout, Write};
use std::io::{Write, stdout};
use std::process::{Command, Stdio};
use syntect::{highlighting::ThemeSet, parsing::SyntaxSet};
use tempfile::Builder;
Expand Down
Loading
Loading