diff --git a/src/build.rs b/src/build.rs index 5466a4c..e9c8f3c 100644 --- a/src/build.rs +++ b/src/build.rs @@ -173,10 +173,11 @@ pub fn build( // Twine has too many dependencies to install when the environment, like we do with `wheel`, and // for now, it's easier to install using pip // todo: Install using own tools instead of pip; this is the last dependence on pip. - Command::new(paths.bin.join("python")) + let output = Command::new(paths.bin.join("python")) .args(&["-m", "pip", "install", "twine"]) - .status() + .output() .expect("Problem installing Twine"); + util::check_command_output(&output, "failed to install twine"); // let twine_url = "https://files.pythonhosted.org/packages/c4/43/b9c56d378f5d0b9bee7be564b5c5fb65c65e5da6e82a97b6f50c2769249a/twine-2.0.0-py3-none-any.whl"; // install::download_and_install_package( @@ -197,10 +198,11 @@ pub fn build( println!("🛠️️ Building the package..."); // todo: Run build script first, right? if let Some(build_file) = &cfg.build { - Command::new(paths.bin.join("python")) + let output = Command::new(paths.bin.join("python")) .arg(&build_file) - .status() + .output() .unwrap_or_else(|_| panic!("Problem building using {}", build_file)); + util::check_command_output(&output, "failed to run build script"); } // Command::new(paths.bin.join("python")) @@ -228,10 +230,11 @@ pub(crate) fn publish(bin_path: &PathBuf, cfg: &crate::Config) { }; println!("Uploading to {}", repo_url); - Command::new(bin_path.join("twine")) + let output = Command::new(bin_path.join("twine")) .args(&["upload", "--repository-url", &repo_url, "dist/*"]) - .status() + .output() .expect("Problem publishing"); + util::check_command_output(&output, "publishing"); } #[cfg(test)] diff --git a/src/commands.rs b/src/commands.rs index 8cc6882..ce5b88b 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -83,10 +83,11 @@ pub fn find_py_version(alias: &str) -> Option { /// Additionally, create the __pypackages__ directory if not already created. pub fn create_venv(py_alias: &str, lib_path: &Path, name: &str) -> Result<(), Box> { // While creating the lib path, we're creating the __pypackages__ structure. - Command::new(py_alias) + let output = Command::new(py_alias) .args(&["-m", "venv", name]) .current_dir(lib_path.join("../")) .output()?; + util::check_command_output(&output, "creating virtual environment"); Ok(()) } @@ -94,10 +95,11 @@ pub fn create_venv(py_alias: &str, lib_path: &Path, name: &str) -> Result<(), Bo // todo: DRY for using a path instead of str. use impl Into ? pub fn create_venv2(py_alias: &Path, lib_path: &Path, name: &str) -> Result<(), Box> { // While creating the lib path, we're creating the __pypackages__ structure. - Command::new(py_alias) + let output = Command::new(py_alias) .args(&["-m", "venv", name]) .current_dir(lib_path.join("../")) .output()?; + util::check_command_output(&output, "creating virtual environment"); Ok(()) } @@ -108,7 +110,8 @@ pub fn run_python( args: &[String], ) -> Result<(), Box> { util::set_pythonpath(lib_paths); - Command::new(bin_path.join("python")).args(args).status()?; + let output = Command::new(bin_path.join("python")).args(args).output()?; + util::check_command_output(&output, "running python"); Ok(()) } @@ -119,18 +122,20 @@ pub fn download_git_repo(repo: &str, dest_path: &Path) -> Result<(), Box Result<(), Box> { - Command::new("git") + let output = Command::new("git") .current_dir(dir) .args(&["init", "--quiet"]) - .status()?; + .output()?; + util::check_command_output(&output, "initializing git repository"); Ok(()) } diff --git a/src/install.rs b/src/install.rs index 43f15c1..e99fcca 100644 --- a/src/install.rs +++ b/src/install.rs @@ -351,38 +351,65 @@ pub fn download_and_install_package( replace_distutils(&extracted_parent.join("setup.py")); #[cfg(target_os = "windows")] - Command::new(paths.bin.join("python")) - .current_dir(&extracted_parent) - .args(&["setup.py", "bdist_wheel"]) - .output() - .expect(&format!( - "Problem running setup.py bdist_wheel in folder: {:?}. Py path: {:?}", - &extracted_parent, - paths.bin.join("python") - )); - + { + let output = Command::new(paths.bin.join("python")) + .current_dir(&extracted_parent) + .args(&["setup.py", "bdist_wheel"]) + .output() + .expect(&format!( + "Problem running setup.py bdist_wheel in folder: {:?}. Py path: {:?}", + &extracted_parent, + paths.bin.join("python") + )); + util::check_command_output_with(&output, |s| { + panic!( + "running setup.py bdist_wheel in folder {:?}. Py path: {:?}: {}", + s + ) + }); + } // The Linux and Mac builds appear to be unable to build wheels due to // missing the ctypes library; revert to system python. #[cfg(target_os = "linux")] - Command::new("python3") - .current_dir(&extracted_parent) - .args(&["setup.py", "bdist_wheel"]) - .output() - .expect(&format!( - "Problem running setup.py bdist_wheel in folder: {:?}. Py path: {:?}", - &extracted_parent, - paths.bin.join("python") - )); + { + let output = Command::new("python3") + .current_dir(&extracted_parent) + .args(&["setup.py", "bdist_wheel"]) + .output() + .expect(&format!( + "Problem running setup.py bdist_wheel in folder: {:?}. Py path: {:?}", + &extracted_parent, + paths.bin.join("python") + )); + util::check_command_output_with(&output, |s| { + panic!( + "running setup.py bdist_wheel in folder {:?}. Py path: {:?}: {}", + &extracted_parent, + paths.bin.join("python"), + s + ); + }); + } #[cfg(target_os = "macos")] - Command::new("python3") - .current_dir(&extracted_parent) - .args(&["setup.py", "bdist_wheel"]) - .output() - .expect(&format!( - "Problem running setup.py bdist_wheel in folder: {:?}. Py path: {:?}", - &extracted_parent, - paths.bin.join("python") - )); + { + let output = Command::new("python3") + .current_dir(&extracted_parent) + .args(&["setup.py", "bdist_wheel"]) + .output() + .expect(&format!( + "Problem running setup.py bdist_wheel in folder: {:?}. Py path: {:?}", + &extracted_parent, + paths.bin.join("python") + )); + util::check_command_output_with(&output, |s| { + panic!( + "running setup.py bdist_wheel in folder {:?}. Py path: {:?}: {}", + &extracted_parent, + paths.bin.join("python"), + s + ); + }); + } let dist_path = &extracted_parent.join("dist"); if !dist_path.exists() { @@ -621,13 +648,14 @@ pub fn download_and_install_git( //} // Build a wheel from the repo - Command::new(paths.bin.join("python")) + let output = Command::new(paths.bin.join("python")) // We assume that the module code is in the repo's immediate subfolder that has // the package's name. .current_dir(&git_path.join(&folder_name)) .args(&["setup.py", "bdist_wheel"]) .output() .expect("Problem running setup.py bdist_wheel"); + util::check_command_output(&output, "running setup.py bdist_wheel"); let archive_path = util::find_first_file(&git_path.join(folder_name).join("dist")); let filename = archive_path diff --git a/src/util.rs b/src/util.rs index 0277a36..051c41c 100644 --- a/src/util.rs +++ b/src/util.rs @@ -888,3 +888,21 @@ pub fn find_dont_uninstall(reqs: &[Req], dev_reqs: &[Req]) -> Vec { result } + +// Internal function to handle error reporting for commands. +// +// Panics on subprocess failure printing error message +pub(crate) fn check_command_output(output: &process::Output, msg: &str) { + check_command_output_with(output, |s| panic!("{}: {}", msg, s)); +} + +// Internal function to handle error reporting for commands. +// +// Panics on subprocess failure printing error message +pub(crate) fn check_command_output_with(output: &process::Output, f: impl Fn(&str)) { + if !output.status.success() { + let stderr = + std::str::from_utf8(&output.stderr).expect("building string from command output"); + f(&stderr) + } +}