From d3f79a81d63d9dbac2ebe7c8b87f7c8b79217379 Mon Sep 17 00:00:00 2001 From: yeetfield <79176764+yeetfield@users.noreply.github.com> Date: Fri, 10 Feb 2023 11:39:46 -0600 Subject: [PATCH] Send installer output to stderr (#47) --- rozy/Cargo.lock | 11 +++++++++++ rozy/Cargo.toml | 1 + rozy/src/installers/conda.rs | 29 ++++++++++++---------------- rozy/src/installers/installer.rs | 33 +++++++++++++++++++++++++++++++- rozy/src/installers/pip.rs | 24 ++++++++++++----------- rozy/src/installers/shell.rs | 21 ++++++++++---------- 6 files changed, 80 insertions(+), 39 deletions(-) diff --git a/rozy/Cargo.lock b/rozy/Cargo.lock index 3142f3a..4fc8f83 100644 --- a/rozy/Cargo.lock +++ b/rozy/Cargo.lock @@ -893,6 +893,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "os_pipe" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6a252f1f8c11e84b3ab59d7a488e48e4478a93937e027076638c49536204639" +dependencies = [ + "libc", + "windows-sys 0.42.0", +] + [[package]] name = "os_str_bytes" version = "6.4.1" @@ -911,6 +921,7 @@ dependencies = [ "flate2", "infer", "openssl", + "os_pipe", "regex", "reqwest", "semver", diff --git a/rozy/Cargo.toml b/rozy/Cargo.toml index 6273781..da7f141 100644 --- a/rozy/Cargo.toml +++ b/rozy/Cargo.toml @@ -25,4 +25,5 @@ zip = "0.6.3" openssl = { version = "0.10.45", features = ["vendored"] } exec = "0.3.1" semver = "1.0.16" +os_pipe = "1.1.2" infer = "0.12.0" diff --git a/rozy/src/installers/conda.rs b/rozy/src/installers/conda.rs index c0c5de7..5ff9182 100644 --- a/rozy/src/installers/conda.rs +++ b/rozy/src/installers/conda.rs @@ -1,5 +1,5 @@ -use super::super::files::delete_if_exists; -use super::installer::Installer; +use super::installer::{run_subcommand_for_installer, Installer}; +use crate::files::delete_if_exists; use anyhow::{anyhow, Error, Result}; use tempfile::tempdir; @@ -13,7 +13,7 @@ pub struct Conda { } pub fn conda_install( - conda_bin: &String, + conda_bin: &str, channels: &[String], to_dir: &std::path::Path, to_install: &[String], @@ -26,27 +26,22 @@ pub fn conda_install( delete_if_exists(to_dir)?; let conda_cache_dir = tempdir()?; - let mut command = std::process::Command::new(conda_bin); - command.env("CONDA_PKGS_DIRS", conda_cache_dir.path()); - - command.arg("create"); - command.arg("-y"); + let env = vec![("CONDA_PKGS_DIRS", conda_cache_dir.path().to_str().unwrap())]; + let mut args = vec!["create", "-y", "-p", to_dir.to_str().unwrap()]; for arg in channels.iter() { - command.arg("-c"); - command.arg(arg); + args.push("-c"); + args.push(arg); } - command.arg("-p"); - command.arg(to_dir); - for arg in to_install.iter() { - command.arg(arg); + args.push(arg); } - let output = command.output().unwrap(); - if !output.status.success() { - return Err(anyhow!("Conda installation exited with {:#?}", output)); + let subcommand_result = + run_subcommand_for_installer(conda_bin, args.into_iter(), env.into_iter()); + if subcommand_result.is_err() { + return Err(anyhow!("Conda installation exited with error")); } Ok(()) diff --git a/rozy/src/installers/installer.rs b/rozy/src/installers/installer.rs index 425b787..088d105 100644 --- a/rozy/src/installers/installer.rs +++ b/rozy/src/installers/installer.rs @@ -1,6 +1,37 @@ -use anyhow::Result; +use anyhow::{anyhow, Result}; +use std::process::{Command, Stdio}; pub trait Installer { fn install(&self, to_dir: &std::path::Path) -> Result<()>; fn describe(&self) -> String; } + +pub fn run_subcommand_for_installer<'a>( + command: &str, + args: impl Iterator, + env: impl Iterator, +) -> Result<()> { + let mut command = Command::new(command); + // Directing /dev/null to stdin breaks Conda's progress bar, for some reason + // command.stdin(Stdio::null()) + command.stderr(Stdio::inherit()); + command.stdout(os_pipe::dup_stderr()?); + + for (env_key, env_val) in env { + command.env(env_key, env_val); + } + + for arg in args { + command.arg(arg); + } + + let mut output = command.spawn().unwrap(); + if !output.wait()?.success() { + return Err(anyhow!( + "Installer subcommand {:?} exited with error", + command + )); + } + + Ok(()) +} diff --git a/rozy/src/installers/pip.rs b/rozy/src/installers/pip.rs index 3703d9f..5548c61 100644 --- a/rozy/src/installers/pip.rs +++ b/rozy/src/installers/pip.rs @@ -1,7 +1,5 @@ -use crate::installers::conda::conda_install; - use super::installer::Installer; - +use crate::installers::{conda::conda_install, installer::run_subcommand_for_installer}; use anyhow::{anyhow, Error, Result}; pub struct Pip { @@ -41,14 +39,18 @@ impl Installer for Pip { to_dir, &[String::from("pip")], )?; - let pip_path = to_dir.join("bin").join("pip"); - let mut command = std::process::Command::new(pip_path); - command.arg("install"); - command.arg(format!("{}=={}", self.package, self.version)); - - let output = command.output().unwrap(); - if !output.status.success() { - return Err(anyhow!("Pip installation exited with {:?}", output)); + + let pip_command = to_dir.join("bin").join("pip"); + let version_arg = format!("{}=={}", self.package, self.version); + let args = vec!["install", &version_arg]; + + let subcommand_result = run_subcommand_for_installer( + pip_command.to_str().unwrap(), + args.into_iter(), + std::iter::empty(), + ); + if subcommand_result.is_err() { + return Err(anyhow!("Pip installation exited with error")); } Ok(()) diff --git a/rozy/src/installers/shell.rs b/rozy/src/installers/shell.rs index 11c2674..0483fa0 100644 --- a/rozy/src/installers/shell.rs +++ b/rozy/src/installers/shell.rs @@ -1,5 +1,5 @@ use super::installer::Installer; -use crate::utils::download_to; +use crate::{installers::installer::run_subcommand_for_installer, utils::download_to}; use tempfile::tempdir; use anyhow::{anyhow, Context, Error, Result}; @@ -58,26 +58,27 @@ impl Installer for Shell { let file = dir.path().join("installer.sh"); download_to(&file, &self.url)?; - let mut command = std::process::Command::new("/bin/bash"); + let path; + let mut env = vec![("INSTALL_DIR", to_dir.as_os_str().to_str().unwrap())]; if let Some(extra_path) = &self.extra_path_during_install { - let path = format!( + path = format!( "{}:{}", extra_path, std::env::var("PATH").context("While checking $PATH")? ); - command.env("PATH", path); + env.push(("PATH", &path)); } - command.env("INSTALL_DIR", to_dir.as_os_str().to_str().unwrap()); - command.arg(file.as_os_str().to_str().unwrap()); + let mut args = vec![file.as_os_str().to_str().unwrap()]; for arg in &self.shell_args { - command.arg(arg); + args.push(arg); } - let output = command.output().unwrap(); - if !output.status.success() { - return Err(anyhow!("Shell installer exited with {:?}", output)); + let subcommand_result = + run_subcommand_for_installer("/bin/bash", args.into_iter(), env.into_iter()); + if subcommand_result.is_err() { + return Err(anyhow!("Conda installation exited with error")); } Ok(())