1 Commits
1.0.5 ... 1.0.2

Author SHA1 Message Date
c699bf1849 Format Rust code using rustfmt 2023-07-03 12:54:56 +00:00
6 changed files with 49 additions and 108 deletions

2
.gitignore vendored
View File

@ -1,3 +1 @@
target target
pkg
*zst

View File

@ -6,12 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.4] - 2023-08-14
### Changed
- Expansion host strings.
## [1.0.1] - 2023-06-20 ## [1.0.1] - 2023-06-20
### Changed ### Changed

20
Cargo.lock generated
View File

@ -1043,17 +1043,17 @@ checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
[[package]] [[package]]
name = "rexec" name = "rexec"
version = "1.0.4" version = "1.0.2"
dependencies = [ dependencies = [
"brace-expand", "brace-expand",
"clap 4.3.4", "clap 4.3.4",
"colored", "colored",
"dialoguer", "dialoguer",
"dns-lookup", "dns-lookup",
"env_logger", "env_logger",
"itertools", "itertools",
"lazy-st", "lazy-st",
"log", "log",
"massh", "massh",
"regex", "regex",
"whoami", "whoami",

View File

@ -1,7 +1,6 @@
[package] [package]
name = "rexec" name = "rexec"
version = "1.0.5" version = "1.0.2"
readme = "https://github.com/house-of-vanity/rexec#readme"
edition = "2021" edition = "2021"
description = "Parallel SSH executor" description = "Parallel SSH executor"
repository = "https://github.com/house-of-vanity/rexec" repository = "https://github.com/house-of-vanity/rexec"

View File

@ -1,25 +0,0 @@
# Maintainer: AB <gh@hexor.ru>
pkgname=rexec
pkgver=1.0.4.r0.g3cf1e79
pkgrel=1
pkgdesc="Parallel SSH executor"
url="https://github.com/house-of-vanity/rexec"
license=("WTFPL")
arch=("x86_64")
makedepends=("cargo")
pkgver() {
(git describe --long --tags || echo "$pkgver") | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
}
build() {
return 0
}
package() {
cd ..
usrdir="$pkgdir/usr"
mkdir -p $usrdir
cargo install --no-track --path . --root "$usrdir"
}

View File

@ -24,17 +24,13 @@ struct Args {
#[arg(short, long, default_value_t = whoami::username())] #[arg(short, long, default_value_t = whoami::username())]
username: String, username: String,
#[arg( #[arg(short, long, help = "Use known_hosts to build servers list")]
short,
long,
help = "Use known_hosts to build servers list instead of string expansion."
)]
known_hosts: bool, known_hosts: bool,
#[arg( #[arg(
short, short,
long, long,
help = "Expression to build server list. List and range expansion are supported. Example: 'web-[1:12]-io-{prod,dev}'" help = "Expression to build server list. List and range expansion available. Example: 'web-[1:12]-io-{prod,dev}'"
)] )]
expression: String, expression: String,
@ -81,59 +77,48 @@ fn read_known_hosts() -> Vec<Host> {
result result
} }
fn expand_range(start: i32, end: i32) -> Vec<String> { fn expand_string(string: String) -> Vec<Host> {
(start..=end).map(|i| i.to_string()).collect() let mut result: Vec<String> = Vec::new();
} let mut _result: Vec<String> = Vec::new();
fn expand_list(list: &str) -> Vec<String> {
list.split(',').map(|s| s.to_string()).collect()
}
fn expand_string(s: &str) -> Vec<Host> {
let mut hosts: Vec<Host> = Vec::new(); let mut hosts: Vec<Host> = Vec::new();
let mut result = vec![s.to_string()];
while let Some(r) = result.iter().find(|s| s.contains('[')) { if let Some(open_bracket_index) = string.find('[') {
let r = r.clone(); if let Some(close_bracket_index) = string.find(']') {
let start = r.find('[').unwrap(); let prefix = &string[..open_bracket_index];
let end = match r[start..].find(']') { let range = &string[open_bracket_index + 1..close_bracket_index];
None => { let postfix = &string[close_bracket_index + 1..];
error!("Error parsing host expression. Wrong range expansion '[a:b]'");
process::exit(1); let parts: Vec<&str> = range.split(':').collect();
if parts.len() == 2 {
if let Ok(start) = parts[0].parse::<u32>() {
if let Ok(end) = parts[1].parse::<u32>() {
for num in start..=end {
_result.push(format!("{}{}{}", prefix, num, postfix));
}
}
}
} }
Some(s) => s + start,
};
let colon = match r[start..end].find(':') {
None => {
error!("Error parsing host expression. Missing colon in range expansion '[a:b]'");
process::exit(1);
}
Some(c) => c + start,
};
let low = r[start + 1..colon].parse::<i32>().unwrap();
let high = r[colon + 1..end].parse::<i32>().unwrap();
result.retain(|s| s != &r);
for val in expand_range(low, high) {
let new_str = format!("{}{}{}", &r[..start], val, &r[end + 1..]);
result.push(new_str);
} }
} else {
_result.push(String::from(string));
} }
while let Some(r) = result.iter().find(|s| s.contains('{')) { for string in _result {
let r = r.clone(); if let Some(open_brace_index) = string.find('{') {
let start = r.find('{').unwrap(); if let Some(close_brace_index) = string.find('}') {
let end = match r.find('}') { let prefix = &string[..open_brace_index];
None => { let list = &string[open_brace_index + 1..close_brace_index];
error!("Error parsing host expression. Wrong range expansion '{{one,two}}'"); let postfix = &string[close_brace_index + 1..];
process::exit(1);
let items: Vec<&str> = list.split(',').collect();
for item in items {
result.push(format!("{}{}{}", prefix, item, postfix));
}
} }
Some(s) => s, } else {
}; result.push(String::from(string));
let list = &r[start + 1..end];
result.retain(|s| s != &r);
for val in expand_list(list) {
let new_str = format!("{}{}{}", &r[..start], val, &r[end + 1..]);
result.push(new_str);
} }
} }
@ -171,7 +156,7 @@ fn main() {
.collect() .collect()
} else { } else {
info!("Using string expansion to build server list."); info!("Using string expansion to build server list.");
expand_string(&args.expression) expand_string(args.expression)
}; };
// Dedup hosts from known_hosts file // Dedup hosts from known_hosts file
@ -180,16 +165,6 @@ fn main() {
// Build MasshHostConfig hostnames list // Build MasshHostConfig hostnames list
let mut massh_hosts: Vec<MasshHostConfig> = vec![]; let mut massh_hosts: Vec<MasshHostConfig> = vec![];
let mut hosts_and_ips: HashMap<IpAddr, String> = HashMap::new(); let mut hosts_and_ips: HashMap<IpAddr, String> = HashMap::new();
if args.parallel != 100 {
warn!("Parallelism: {} thread{}", &args.parallel, {
if args.parallel != 1 {
"s."
} else {
"."
}
});
}
info!("Matched hosts:"); info!("Matched hosts:");
for host in matched_hosts.iter() { for host in matched_hosts.iter() {
let ip = match lookup_host(&host.name) { let ip = match lookup_host(&host.name) {