Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: pass config file to ssh and handle multiple config files #86

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
53 changes: 51 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ itertools = "0.12.1"
ratatui = "0.26.1"
regex = { version = "1.10.3", default-features = false, features = ["std"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115"
shellexpand = "3.1.0"
shlex = "1.3.0"
strum = "0.26.1"
strum_macros = "0.26.1"
tempfile = "3.10.1"
tui-input = "0.8.0"
unicode-width = "0.1.11"
6 changes: 5 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ struct Args {
sort: bool,

/// Handlebars template of the command to execute
#[arg(short, long, default_value = "ssh \"{{{name}}}\"")]
#[arg(
short,
long,
default_value = "ssh \"{{{name}}}\" -F \"{{{config_file}}}\""
)]
template: String,

/// Exit after ending the SSH session
Expand Down
39 changes: 37 additions & 2 deletions src/ssh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use itertools::Itertools;
use serde::Serialize;
use std::collections::VecDeque;
use std::process::Command;
use tempfile::NamedTempFile;

use crate::ssh_config::{self, parser_error::ParseError, HostVecExt};

Expand All @@ -27,9 +28,26 @@ impl Host {
/// # Panics
///
/// Will panic if the regex cannot be compiled.
pub fn run_command_template(&self, pattern: &str) -> anyhow::Result<()> {
pub fn run_command_template(
&self,
pattern: &str,
config_paths: &[String],
) -> anyhow::Result<()> {
let handlebars = Handlebars::new();
let rendered_command = handlebars.render_template(pattern, &self)?;

let temp_file = (config_paths.len() >= 2)
.then(|| single_config_file(config_paths))
.transpose()?;

let mut template_data = serde_json::to_value(self)?;

// If there are multiple config files, use the temporary file, otherwise use the first one
template_data["config_file"] = temp_file
.as_ref()
.map_or(&config_paths[0] as &str, |f| f.path().to_str().unwrap())
.into();

let rendered_command = handlebars.render_template(pattern, &template_data)?;

println!("Running command: {rendered_command}");

Expand All @@ -40,6 +58,8 @@ impl Host {
let command = args.pop_front().ok_or(anyhow!("Failed to get command"))?;

let status = Command::new(command).args(args).spawn()?.wait()?;
drop(temp_file);

if !status.success() {
std::process::exit(status.code().unwrap_or(1));
}
Expand All @@ -48,6 +68,21 @@ impl Host {
}
}

fn single_config_file(config_paths: &[String]) -> anyhow::Result<NamedTempFile> {
let temp_file = NamedTempFile::with_prefix("sshs-")?;

// Include all config files
let includes = config_paths
.iter()
.map(|path| format!("Include {path}"))
.join("\n");

// Write to temporary file
std::fs::write(temp_file.path(), includes)?;

Ok(temp_file)
}

#[derive(Debug)]
pub enum ParseConfigError {
Io(std::io::Error),
Expand Down
5 changes: 4 additions & 1 deletion src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,10 @@ impl App {

restore_terminal(terminal).expect("Failed to restore terminal");

host.run_command_template(&self.config.command_template)?;
host.run_command_template(
&self.config.command_template,
&self.config.config_paths,
)?;

setup_terminal(terminal).expect("Failed to setup terminal");

Expand Down