Skip to content

Commit

Permalink
Merge pull request #29 from mdpadberg/15-fix-interactive-issue
Browse files Browse the repository at this point in the history
15 fix interactive issue
  • Loading branch information
mdpadberg authored Apr 28, 2023
2 parents c1753ae + 3aedd23 commit e178574
Show file tree
Hide file tree
Showing 9 changed files with 334 additions and 107 deletions.
1 change: 1 addition & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ log = "0.4.0"
env_logger = "0.9.0"
prettytable-rs = "0.10.0"
lib = { path = "../lib" }
tokio = { version = "1", features = ["full"] }
36 changes: 22 additions & 14 deletions cli/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::{environment, subcommands::Subcommands};
use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use clap::{CommandFactory, Parser};
use clap_complete::{generate, Generator};
use lib::{cf::login, exec::exec, options::Options, settings::Settings};
use std::{io, path::PathBuf};
use lib::{
cf::login, exec::exec, options::Options, settings::Settings,
};
use std::{io, path::PathBuf, sync::Arc};

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
Expand All @@ -22,7 +24,7 @@ struct Mcf {
cf_binary_name: Option<String>,
}

pub fn parse() -> Result<()> {
pub async fn parse() -> Result<()> {
let mcf: Mcf = Mcf::parse();

let options = Options::new(mcf.cf_binary_name, mcf.override_path);
Expand All @@ -35,16 +37,22 @@ pub fn parse() -> Result<()> {
Subcommands::Login { name } => {
login(&settings, &options, name, &PathBuf::from(&options.mcf_home))
}
Subcommands::Exec { names, command } => exec(
&settings,
&options,
names,
command,
&dirs::home_dir()
.context("Could not find home dir")?
.join(".cf"),
&PathBuf::from(&options.mcf_home),
),
Subcommands::Exec { names, command, sequential_mode } => {
exec(
&settings,
Arc::new(options.clone()),
names,
Arc::new(command.to_vec()),
Arc::new(
dirs::home_dir()
.context("Could not find home dir")?
.join(".cf"),
),
Arc::new(PathBuf::from(options.mcf_home)),
sequential_mode
)
.await
}
Subcommands::Completion { shell } => {
let mut cmd = Mcf::command();
eprintln!("Generating completion file for {:?}...", shell);
Expand Down
5 changes: 3 additions & 2 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ mod environment;
mod subcommands;
extern crate log;

fn main() -> Result<(), anyhow::Error> {
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
env_logger::init();
cli::parse()
cli::parse().await
}
3 changes: 3 additions & 0 deletions cli/src/subcommands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ pub enum Subcommands {
names: String,
/// Command you want to execute (example "logs your-application --recent")
command: Vec<String>,
/// Execute command sequentially (example "ssh your-application")
#[clap(short, long)]
sequential_mode: bool
},
/// Generate shell autocompletion files
Completion {
Expand Down
8 changes: 6 additions & 2 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "lib"
version = "0.1.0"
edition = "2021"
build = "build.rs"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand All @@ -15,10 +16,13 @@ opt-level = 0
[dependencies]
anyhow = "1.0.62"
dirs = "4.0.0"
rayon = "1.5.3"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9.9"
tokio = { version = "1", features = ["full"] }
futures = "0.3.26"
strum = { version = "0.24", features = ["derive"] }

[dev-dependencies]
tempfile = "3.3.0"
env_logger = "0.9.0"
env_logger = "0.9.0"
gag = "1.0.0"
3 changes: 3 additions & 0 deletions lib/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("cargo:rustc-env=RUST_TEST_NOCAPTURE=1");
}
74 changes: 46 additions & 28 deletions lib/src/cf.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
use std::path::Path;
use std::path::PathBuf;
use std::process::Stdio;
use std::sync::Arc;

use anyhow::{bail, Context, Result};
use strum::{AsRefStr, EnumIter, IntoEnumIterator};
use tokio::process::Command;

use crate::options::Options;
use crate::settings::Settings;
use anyhow::{bail, Context, Result};
use std::path::Path;
use std::{
path::PathBuf,
process::{self, Command, Stdio},
};

#[derive(Debug, EnumIter, AsRefStr)]
pub enum CFSubCommandsThatRequireSequentialMode {
Ssh,
Delete,
}

impl CFSubCommandsThatRequireSequentialMode {
pub fn check_if_contains(input: String) -> bool {
let input_lowercase = input.to_lowercase();
CFSubCommandsThatRequireSequentialMode::iter()
.any(|cfsubcommand| input_lowercase.contains(&cfsubcommand.as_ref().to_lowercase()))
}
}

pub fn login(
settings: &Settings,
Expand All @@ -15,7 +32,7 @@ pub fn login(
) -> Result<()> {
if let Some(some) = settings.environments.iter().find(|env| &env.name == name) {
let cf_binary_name = &options.cf_binary_name;
let mut cf: Command = cf_command(cf_binary_name, &some.name, mcf_home);
let mut cf: Command = cf_command_tokio(cf_binary_name, &some.name, mcf_home);
cf.arg("login").arg("-a").arg(&some.url);
if some.skip_ssl_validation {
cf.arg("--skip-ssl-validation");
Expand All @@ -35,24 +52,24 @@ pub fn login(
Ok(())
}

pub fn stdout(
cf_binary_name: &String,
command: &Vec<String>,
pub fn child_tokio(
options: Arc<Options>,
command: Arc<Vec<String>>,
env_name: &String,
original_cf_home: &PathBuf,
mcf_folder: &PathBuf,
) -> Result<process::ChildStdout> {
prepare_plugins(env_name, original_cf_home, mcf_folder)?;
Ok(cf_command(cf_binary_name, env_name, mcf_folder)
.args(command)
.stdout(Stdio::piped())
.spawn()
.context("Could not spawn")?
.stdout
.context("Could get stdout")?)
original_cf_home: Arc<PathBuf>,
mcf_folder: Arc<PathBuf>,
sequential_mode: &bool,
) -> Result<tokio::process::Child> {
prepare_plugins(env_name, &original_cf_home, &mcf_folder)?;
let mut tokio_command = cf_command_tokio(&options.cf_binary_name, env_name, &mcf_folder);
tokio_command.args(command.to_vec());
if !sequential_mode {
tokio_command.stdout(Stdio::piped());
}
Ok(tokio_command.spawn().context("Could not spawn")?)
}

pub fn cf_command(cf_binary_name: &String, name: &String, mcf_folder: &PathBuf) -> Command {
pub fn cf_command_tokio(cf_binary_name: &String, name: &String, mcf_folder: &PathBuf) -> Command {
let mut cf: Command = Command::new(cf_binary_name);
let cf_home: PathBuf = get_cf_home_from_mcf_environment(name, mcf_folder);
cf.env("CF_HOME", cf_home);
Expand Down Expand Up @@ -100,30 +117,31 @@ fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(source: P, destination: Q) ->

#[cfg(test)]
mod tests {
use crate::environment::Environment;

use super::*;
use crate::environment::Environment;
use std::ffi::OsStr;
use tempfile::tempdir;

#[test]
fn test_cf_command() {
let tempdir: PathBuf = tempdir().unwrap().into_path();
let result = cf_command(
let result = cf_command_tokio(
&String::from("echo"),
&String::from("envname"),
&tempdir.join("mcf-lib-test"),
);
assert_eq!(result.get_program().to_str().unwrap(), "echo");
assert_eq!(result.as_std().get_program().to_str().unwrap(), "echo");
assert_eq!(
result
.as_std()
.get_envs()
.map(|(key, _)| key)
.collect::<Vec<&OsStr>>(),
vec![OsStr::new("CF_HOME")]
);
assert_eq!(
result
.as_std()
.get_envs()
.map(|(_, value)| value)
.filter(|value| value.is_some())
Expand Down Expand Up @@ -300,8 +318,8 @@ mod tests {
assert_eq!(result.unwrap_err().to_string(), "could not find \"p02\" in environment list [\n Environment {\n name: \"p01\",\n url: \"url\",\n sso: false,\n skip_ssl_validation: false,\n },\n]");
}

#[test]
fn test_login_happy_case() {
#[tokio::test]
async fn test_login_happy_case() {
let tempdir: PathBuf = tempdir().unwrap().into_path();
let result = login(
&Settings {
Expand Down
Loading

0 comments on commit e178574

Please sign in to comment.