Skip to content

Commit

Permalink
Ensure exit status is checked for git operations
Browse files Browse the repository at this point in the history
  • Loading branch information
Greg Soltis authored and Greg Soltis committed May 16, 2023
1 parent 16e80b3 commit e1032d0
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 71 deletions.
47 changes: 20 additions & 27 deletions crates/turborepo-scm/src/hash_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{
use nom::{Finish, IResult};
use turbopath::{AbsoluteSystemPathBuf, RelativeUnixPathBuf};

use crate::{package_deps::GitHashes, Error};
use crate::{package_deps::GitHashes, read_git_error, wait_for_success, Error};

pub(crate) fn hash_objects(
pkg_path: &AbsoluteSystemPathBuf,
Expand All @@ -26,33 +26,26 @@ pub(crate) fn hash_objects(
.stderr(Stdio::piped())
.stdin(Stdio::piped())
.spawn()?;
{
let stdout = git
.stdout
.as_mut()
.ok_or_else(|| Error::git_error("failed to get stdout for git hash-object"))?;
// We take, rather than borrow, stdin so that we can drop it and force the
// underlying file descriptor to close, signalling the end of input.
let stdin: std::process::ChildStdin = git
.stdin
.take()
.ok_or_else(|| Error::git_error("failed to get stdin for git hash-object"))?;
let mut stderr = git
.stderr
.take()
.ok_or_else(|| Error::git_error("failed to get stderr for git hash-object"))?;
let result = read_object_hashes(stdout, stdin, &to_hash, pkg_prefix, hashes);
if let Err(err) = result {
let mut buf = String::new();
let bytes_read = stderr.read_to_string(&mut buf)?;
if bytes_read > 0 {
// something failed with git, report that error
return Err(Error::git_error(buf));
}
return Err(err);
}

let stdout = git
.stdout
.as_mut()
.ok_or_else(|| Error::git_error("failed to get stdout for git hash-object"))?;
// We take, rather than borrow, stdin so that we can drop it and force the
// underlying file descriptor to close, signalling the end of input.
let stdin: std::process::ChildStdin = git
.stdin
.take()
.ok_or_else(|| Error::git_error("failed to get stdin for git hash-object"))?;
let mut stderr = git
.stderr
.take()
.ok_or_else(|| Error::git_error("failed to get stderr for git hash-object"))?;
let result = read_object_hashes(stdout, stdin, &to_hash, pkg_prefix, hashes);
if let Err(err) = result {
return Err(read_git_error(&mut stderr).unwrap_or(err));
}
git.wait()?;
wait_for_success(git, &mut stderr, "git hash-object", pkg_path)?;
Ok(())
}

Expand Down
50 changes: 48 additions & 2 deletions crates/turborepo-scm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
#![feature(provide_any)]
#![feature(assert_matches)]

use std::backtrace::{self, Backtrace};
use std::{
backtrace::{self, Backtrace},
io::Read,
process::Child,
};

use thiserror::Error;
use turbopath::PathError;
use turbopath::{AbsoluteSystemPath, PathError};

pub mod git;
mod hash_object;
Expand Down Expand Up @@ -34,4 +38,46 @@ impl Error {
pub(crate) fn git_error(s: impl Into<String>) -> Self {
Error::Git(s.into(), Backtrace::capture())
}

fn from_git_exit_code(cmd: &str, path: &AbsoluteSystemPath, exit_code: Option<i32>) -> Error {
let s = format!(
"'{}' in {} exited with status code {}",
cmd,
path.to_string(),
exit_code
.map(|code| code.to_string())
.unwrap_or("unknown".to_string())
);
Error::Git(s, Backtrace::capture())
}
}

pub(crate) fn read_git_error<R: Read>(stderr: &mut R) -> Option<Error> {
let mut buf = String::new();
if let Ok(bytes_read) = stderr.read_to_string(&mut buf) {
if bytes_read > 0 {
// something failed with git, report that error
Some(Error::git_error(buf))
} else {
None
}
} else {
None
}
}

pub(crate) fn wait_for_success<R: Read>(
mut child: Child,
stderr: &mut R,
command: &str,
root_path: impl AsRef<AbsoluteSystemPath>,
) -> Result<(), Error> {
let exit_status = child.wait()?;
if !exit_status.success() {
Err(read_git_error(stderr).unwrap_or_else(|| {
Error::from_git_exit_code(command, root_path.as_ref(), exit_status.code())
}))
} else {
Ok(())
}
}
35 changes: 14 additions & 21 deletions crates/turborepo-scm/src/ls_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
use nom::Finish;
use turbopath::{AbsoluteSystemPathBuf, RelativeUnixPathBuf};

use crate::{package_deps::GitHashes, Error};
use crate::{package_deps::GitHashes, read_git_error, wait_for_success, Error};

pub fn git_ls_tree(root_path: &AbsoluteSystemPathBuf) -> Result<GitHashes, Error> {
let mut hashes = GitHashes::new();
Expand All @@ -16,27 +16,20 @@ pub fn git_ls_tree(root_path: &AbsoluteSystemPathBuf) -> Result<GitHashes, Error
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
{
let stdout = git
.stdout
.as_mut()
.ok_or_else(|| Error::git_error("failed to get stdout for git ls-tree"))?;
let mut stderr = git
.stderr
.take()
.ok_or_else(|| Error::git_error("failed to get stderr for git ls-tree"))?;
let result = read_ls_tree(stdout, &mut hashes);
if result.is_err() {
let mut buf = String::new();
let bytes_read = stderr.read_to_string(&mut buf)?;
if bytes_read > 0 {
// something failed with git, report that error
return Err(Error::git_error(buf));
}
}
result?;

let stdout = git
.stdout
.as_mut()
.ok_or_else(|| Error::git_error("failed to get stdout for git ls-tree"))?;
let mut stderr = git
.stderr
.take()
.ok_or_else(|| Error::git_error("failed to get stderr for git ls-tree"))?;
let result = read_ls_tree(stdout, &mut hashes);
if let Err(err) = result {
return Err(read_git_error(&mut stderr).unwrap_or(err));
}
git.wait()?;
wait_for_success(git, &mut stderr, "git ls-tree", root_path)?;
Ok(hashes)
}

Expand Down
36 changes: 15 additions & 21 deletions crates/turborepo-scm/src/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
use nom::Finish;
use turbopath::{AbsoluteSystemPathBuf, RelativeUnixPathBuf};

use crate::{package_deps::GitHashes, Error};
use crate::{package_deps::GitHashes, read_git_error, wait_for_success, Error};

pub(crate) fn append_git_status(
root_path: &AbsoluteSystemPathBuf,
Expand All @@ -26,27 +26,21 @@ pub(crate) fn append_git_status(
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
let to_hash = {
let stdout = git
.stdout
.as_mut()
.ok_or_else(|| Error::git_error("failed to get stdout for git status"))?;
let mut stderr = git
.stderr
.take()
.ok_or_else(|| Error::git_error("failed to get stderr for git status"))?;
let result = read_status(stdout, pkg_prefix, hashes);
if result.is_err() {
let mut buf = String::new();
let bytes_read = stderr.read_to_string(&mut buf)?;
if bytes_read > 0 {
// something failed with git, report that error
return Err(Error::git_error(buf));
}
}
result?

let stdout = git
.stdout
.as_mut()
.ok_or_else(|| Error::git_error("failed to get stdout for git status"))?;
let mut stderr = git
.stderr
.take()
.ok_or_else(|| Error::git_error("failed to get stderr for git status"))?;
let result = read_status(stdout, pkg_prefix, hashes);
let to_hash = match result {
Err(err) => return Err(read_git_error(&mut stderr).unwrap_or(err)),
Ok(to_hash) => to_hash,
};
git.wait()?;
wait_for_success(git, &mut stderr, "git status", &root_path)?;
Ok(to_hash)
}

Expand Down

0 comments on commit e1032d0

Please sign in to comment.