From 539fd0f26c83064b748bbd040fdf27f302f27cb7 Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Fri, 27 Oct 2023 18:57:08 -0500 Subject: feat: order localhost using tmux if enabled and remove history --- src/config.rs | 13 +--------- src/history.rs | 77 -------------------------------------------------------- src/lib.rs | 2 -- src/localhost.rs | 15 +++++++---- src/main.rs | 25 ++++++------------ src/session.rs | 20 +++++++++++---- src/tmux.rs | 30 +++++++++++++++++++++- 7 files changed, 63 insertions(+), 119 deletions(-) delete mode 100644 src/history.rs (limited to 'src') diff --git a/src/config.rs b/src/config.rs index 258255b..cdef063 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,7 @@ use clap::{Args, Parser}; use tracing::{metadata::LevelFilter, Level}; -use crate::{history, session, stdio, tmux}; +use crate::{session, stdio, tmux}; #[derive(Debug, Clone, Parser)] pub struct Config { @@ -14,9 +14,6 @@ pub struct Config { #[command(flatten)] pub sessions: session::Config, - #[command(flatten)] - pub history: history::History, - #[command(flatten)] pub tmux: tmux::Tmux, @@ -34,10 +31,6 @@ pub struct Flags { #[arg(short, long)] pub tmux: bool, - /// Include hosts from history file - #[arg(short = 'H', long)] - pub history: bool, - /// Include hosts from the ssh `known_hosts` #[arg(short, long)] pub ssh: bool, @@ -60,10 +53,6 @@ impl Flags { self.all || self.tmux } - pub fn history(&self) -> bool { - self.all || self.history - } - pub fn ssh(&self) -> bool { self.all || self.ssh } diff --git a/src/history.rs b/src/history.rs deleted file mode 100644 index 0394e3d..0000000 --- a/src/history.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::{ - fs::File, - io::{BufRead, BufReader, ErrorKind}, - path::PathBuf, -}; - -use clap::Args; -use directories::ProjectDirs; - -use crate::{session::SessionWriter, Session}; - -#[derive(Debug, Clone, Args)] -#[group(skip)] -pub struct History { - /// Update the history file from the current sessions - #[arg(short, long)] - pub update: bool, - - /// path to history file [default: $XDG_DATA_HOME/sshr/history] - #[arg(short = 'f', long = "history_file")] - path: Option, -} - -impl History { - pub fn new(History { update, path }: History) -> Self { - Self { - path: path.or_else(History::default_path), - update, - } - } - - pub fn read(&self) -> Result, std::io::Error> { - let Some(path) = &self.path() else { - tracing::warn!(?self.path, "History file does not exist"); - return Ok(Vec::new()); - }; - - let sessions = BufReader::new(File::open(path)?) - .lines() - .flatten() - .flat_map(|item| ron::from_str(&item)) - .collect(); - - Ok(sessions) - } - - fn default_path() -> Option { - ProjectDirs::from("", "", env!("CARGO_CRATE_NAME"))? - .state_dir()? - .join("history") - .into() - } - - pub fn path(&self) -> Option { - self.path.clone().or_else(History::default_path) - } -} - -impl SessionWriter for History { - type Writer = File; - type Error = ron::Error; - - fn format(&self, session: &Session) -> Result { - ron::to_string(session) - } - - fn filter(&self, session: &Session) -> bool { - self.update && !matches!(session.state, crate::State::Discovered) - } - - fn writer(&self) -> Result { - match &self.path { - Some(path) => File::create(path), - None => Err(std::io::Error::from(ErrorKind::NotFound)), - } - } -} diff --git a/src/lib.rs b/src/lib.rs index ebf9c8d..2d80b54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ pub use crate::{ config::Config, - history::History, localhost::HostName, session::{Session, Sessions, State}, ssh::KnownHosts, @@ -10,7 +9,6 @@ pub use crate::{ }; mod config; -mod history; mod localhost; mod session; mod ssh; diff --git a/src/localhost.rs b/src/localhost.rs index 45b14de..2115465 100644 --- a/src/localhost.rs +++ b/src/localhost.rs @@ -10,16 +10,21 @@ impl HostName { } } +impl From for Session { + fn from(value: HostName) -> Self { + Session { + name: value.0.to_string_lossy().into(), + state: State::LocalHost, + } + } +} + impl IntoIterator for HostName { type Item = Session; type IntoIter = std::option::IntoIter; fn into_iter(self) -> Self::IntoIter { - Some(Session { - name: self.0.to_string_lossy().into(), - state: State::LocalHost, - }) - .into_iter() + Some(self.into()).into_iter() } } diff --git a/src/main.rs b/src/main.rs index c32c246..9eaa978 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use anyhow::Context; use clap::Parser; -use sshr::{Config, HostName, Hosts, KnownHosts, Sessions, Stdout}; +use sshr::{Config, HostName, Hosts, KnownHosts, Sessions, Stdout, Tmux}; fn main() -> anyhow::Result<()> { let mut config = Config::parse(); @@ -14,8 +14,13 @@ fn main() -> anyhow::Result<()> { let mut sessions = Sessions::new(config.sessions); if config.enabled.localhost() { - let hostname = HostName::get().context("Failed to get hostname of localhost")?; - sessions.extend(hostname); + if config.enabled.tmux() { + let local_sessions = Tmux::local_session().context("Failed to get local sessions")?; + sessions.extend(local_sessions); + } else { + let hostname = HostName::get().context("Failed to get hostname of localhost")?; + sessions.extend(hostname); + } } if config.enabled.tmux() { @@ -38,20 +43,6 @@ fn main() -> anyhow::Result<()> { sessions.extend(hosts); } - if config.enabled.history() { - match config.history.read() { - Ok(h) => sessions.extend(h), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => { - tracing::warn!("Skipping non-existant history file") - } - Err(err) => return Err(err).context("Failed to read history file"), - } - } - - if config.history.update { - sessions.write_sessions(config.history)?; - } - sessions .write_sessions(Stdout::new(config.stdio)) .context("Failed to write to stdout") diff --git a/src/session.rs b/src/session.rs index aad299a..0118383 100644 --- a/src/session.rs +++ b/src/session.rs @@ -65,12 +65,12 @@ impl Sessions { let _guard = span.enter(); match self.inner.entry(item.name) { - Entry::Occupied(mut occupied) if &item.state > occupied.get() => { - tracing::trace!(?occupied, new_value=?item.state, "New entry is more recent, replacing"); - occupied.insert(item.state); + Entry::Occupied(mut o) if item.state.is_better_than(o.get()) => { + tracing::trace!(prev=?o, ?item.state, "New entry is more recent or accurate, replacing"); + o.insert(item.state); } - Entry::Occupied(occupied) => { - tracing::trace!(?occupied, new_value=?item.state, "Previous entry is more recent, skipping"); + Entry::Occupied(o) => { + tracing::trace!(existing=?o, ?item.state, "Existing entry is more recent or accurate, skipping"); } Entry::Vacant(v) => { tracing::trace!(?item.state, "No previous entry exists, inserting"); @@ -98,6 +98,16 @@ pub enum State { LocalHost, } +impl State { + pub fn is_better_than(&self, state: &State) -> bool { + match (self, state) { + (&State::LocalHost, _) => false, + (_, &State::LocalHost) => true, + _ => self > state, + } + } +} + mod epoch_timestamp { use std::time::Duration; diff --git a/src/tmux.rs b/src/tmux.rs index b1f1af2..b53c172 100644 --- a/src/tmux.rs +++ b/src/tmux.rs @@ -55,6 +55,29 @@ impl Tmux { .transpose()? .ok_or(Error::NotFound) } + + pub fn local_session() -> Result, Error> { + let hostname = hostname::get()?; + let stdout = Command::new("tmux") + .arg("-L") + .arg("default") + .arg("list-sessions") + .arg("-F") + .arg(Self::SESSION_FORMAT) + .output()? + .stdout; + + let sessions: Vec = std::str::from_utf8(&stdout)? + .lines() + .flat_map(ron::from_str) + .map(|mut s: Session| { + s.name = hostname.to_string_lossy().into(); + s + }) + .collect(); + + Ok(sessions) + } } #[cfg(test)] @@ -64,7 +87,6 @@ mod tests { const SOCKET: &str = "test"; #[test] - #[ignore] fn test_tmux_list() -> Result<(), Error> { let names = Vec::from(["test_1", "test_2", "test_3", "test_4"]); @@ -94,4 +116,10 @@ mod tests { Ok(()) } + + #[test] + fn test_host() -> Result<(), Error> { + let _local_session = Tmux::local_session()?; + Ok(()) + } } -- cgit v1.2.3-70-g09d2