Skip to content

Commit 071f9a1

Browse files
authored
feat: add recursive file transfer support for upload/download commands (#4)
* update: use Rust 2024 edition * add: recursive upload / download * fix: rust 2024 version * fix: update test patterns to include recursive field for upload/download commands * fix: resolve all clippy warnings - Refactor upload_file and download_file to use FileTransferParams struct to reduce arguments - Fix needless_borrow issues by removing unnecessary references - Update format! macros to use inline variable syntax - Replace map_or with is_ok_and for cleaner code - Remove needless_borrows_for_generic_args * fix: cargo fmt * refactor: simplify nested if statements with let-chains * add: Cargo.lock
1 parent 26213df commit 071f9a1

16 files changed

Lines changed: 5268 additions & 102 deletions

Cargo.lock

Lines changed: 2975 additions & 0 deletions
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
@@ -1,7 +1,7 @@
11
[package]
22
name = "bssh"
33
version = "0.3.0"
4-
edition = "2021"
4+
edition = "2024"
55
authors = ["Jeongkyu Shin"]
66
description = "Parallel SSH command execution tool for cluster management"
77
license = "Apache-2.0"

src/cli.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ pub enum Commands {
108108

109109
#[arg(help = "Remote destination path")]
110110
destination: String,
111+
112+
#[arg(short = 'r', long, help = "Recursively upload directories")]
113+
recursive: bool,
111114
},
112115

113116
#[command(about = "Download files from remote hosts")]
@@ -117,6 +120,9 @@ pub enum Commands {
117120

118121
#[arg(help = "Local destination directory")]
119122
destination: PathBuf,
123+
124+
#[arg(short = 'r', long, help = "Recursively download directories")]
125+
recursive: bool,
120126
},
121127
}
122128

src/config.rs

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -152,19 +152,19 @@ impl Config {
152152

153153
// Try current directory config.yaml
154154
let current_dir_config = PathBuf::from("config.yaml");
155-
if current_dir_config.exists() {
156-
if let Ok(config) = Self::load(&current_dir_config).await {
157-
return Ok(config);
158-
}
155+
if current_dir_config.exists()
156+
&& let Ok(config) = Self::load(&current_dir_config).await
157+
{
158+
return Ok(config);
159159
}
160160

161161
// Try ~/.config/bssh/config.yaml
162162
if let Some(home_dir) = dirs::home_dir() {
163163
let home_config = home_dir.join(".config").join("bssh").join("config.yaml");
164-
if home_config.exists() {
165-
if let Ok(config) = Self::load(&home_config).await {
166-
return Ok(config);
167-
}
164+
if home_config.exists()
165+
&& let Ok(config) = Self::load(&home_config).await
166+
{
167+
return Ok(config);
168168
}
169169
}
170170

@@ -234,25 +234,23 @@ impl Config {
234234
}
235235

236236
pub fn get_ssh_key(&self, cluster_name: Option<&str>) -> Option<String> {
237-
if let Some(cluster_name) = cluster_name {
238-
if let Some(cluster) = self.get_cluster(cluster_name) {
239-
if let Some(key) = &cluster.defaults.ssh_key {
240-
return Some(key.clone());
241-
}
242-
}
237+
if let Some(cluster_name) = cluster_name
238+
&& let Some(cluster) = self.get_cluster(cluster_name)
239+
&& let Some(key) = &cluster.defaults.ssh_key
240+
{
241+
return Some(key.clone());
243242
}
244243

245244
self.defaults.ssh_key.clone()
246245
}
247246
}
248247

249248
fn expand_tilde(path: &Path) -> PathBuf {
250-
if let Some(path_str) = path.to_str() {
251-
if path_str.starts_with("~/") {
252-
if let Ok(home) = std::env::var("HOME") {
253-
return PathBuf::from(path_str.replacen("~", &home, 1));
254-
}
255-
}
249+
if let Some(path_str) = path.to_str()
250+
&& path_str.starts_with("~/")
251+
&& let Ok(home) = std::env::var("HOME")
252+
{
253+
return PathBuf::from(path_str.replacen("~", &home, 1));
256254
}
257255
path.to_path_buf()
258256
}
@@ -328,8 +326,10 @@ mod tests {
328326

329327
#[test]
330328
fn test_expand_env_vars() {
331-
std::env::set_var("TEST_VAR", "test_value");
332-
std::env::set_var("TEST_USER", "testuser");
329+
unsafe {
330+
std::env::set_var("TEST_VAR", "test_value");
331+
std::env::set_var("TEST_USER", "testuser");
332+
}
333333

334334
// Test ${VAR} syntax
335335
assert_eq!(expand_env_vars("Hello ${TEST_VAR}!"), "Hello test_value!");
@@ -355,7 +355,9 @@ mod tests {
355355

356356
#[test]
357357
fn test_expand_tilde() {
358-
std::env::set_var("HOME", "/home/user");
358+
unsafe {
359+
std::env::set_var("HOME", "/home/user");
360+
}
359361
let path = Path::new("~/.ssh/config");
360362
let expanded = expand_tilde(path);
361363
assert_eq!(expanded, PathBuf::from("/home/user/.ssh/config"));
@@ -401,10 +403,12 @@ clusters:
401403
#[test]
402404
fn test_backendai_env_parsing() {
403405
// Set up Backend.AI environment variables
404-
std::env::set_var("BACKENDAI_CLUSTER_HOSTS", "sub1,main1");
405-
std::env::set_var("BACKENDAI_CLUSTER_HOST", "main1");
406-
std::env::set_var("BACKENDAI_CLUSTER_ROLE", "main");
407-
std::env::set_var("USER", "testuser");
406+
unsafe {
407+
std::env::set_var("BACKENDAI_CLUSTER_HOSTS", "sub1,main1");
408+
std::env::set_var("BACKENDAI_CLUSTER_HOST", "main1");
409+
std::env::set_var("BACKENDAI_CLUSTER_ROLE", "main");
410+
std::env::set_var("USER", "testuser");
411+
}
408412

409413
let cluster = Config::from_backendai_env().unwrap();
410414

@@ -420,7 +424,9 @@ clusters:
420424
}
421425

422426
// Test with sub role - should skip the first (main) node
423-
std::env::set_var("BACKENDAI_CLUSTER_ROLE", "sub");
427+
unsafe {
428+
std::env::set_var("BACKENDAI_CLUSTER_ROLE", "sub");
429+
}
424430
let cluster = Config::from_backendai_env().unwrap();
425431
assert_eq!(cluster.nodes.len(), 1);
426432

@@ -432,8 +438,10 @@ clusters:
432438
}
433439

434440
// Clean up
435-
std::env::remove_var("BACKENDAI_CLUSTER_HOSTS");
436-
std::env::remove_var("BACKENDAI_CLUSTER_HOST");
437-
std::env::remove_var("BACKENDAI_CLUSTER_ROLE");
441+
unsafe {
442+
std::env::remove_var("BACKENDAI_CLUSTER_HOSTS");
443+
std::env::remove_var("BACKENDAI_CLUSTER_HOST");
444+
std::env::remove_var("BACKENDAI_CLUSTER_ROLE");
445+
}
438446
}
439447
}

src/executor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::sync::Arc;
2020
use tokio::sync::Semaphore;
2121

2222
use crate::node::Node;
23-
use crate::ssh::{client::CommandResult, known_hosts::StrictHostKeyChecking, SshClient};
23+
use crate::ssh::{SshClient, client::CommandResult, known_hosts::StrictHostKeyChecking};
2424

2525
pub struct ParallelExecutor {
2626
nodes: Vec<Node>,

0 commit comments

Comments
 (0)