Commit c566ca49 authored by Brad King's avatar Brad King Committed by Kitware Robot

Merge topic 'remove-error-chain'

150ee490 errors: make error enumerations non-exhaustive
e44727a1 error-chain: remove from the crate
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !66
parents 63f49cd4 150ee490
......@@ -8,6 +8,9 @@
* The lifetime for merging has been moved to the `MergeCommand` structure.
This prevents the command from outliving the workarea it uses for conflict
files.
* `error-chain` is no longer used. Instead, custom error types are used. This
means that errors from this crate no longer allocate (except where a
`String` needs to be stored for messaging purposes).
# v3.1.2
......
......@@ -22,4 +22,3 @@ regex = "^1.0"
tempdir = "~0.3"
chrono = "~0.4"
error-chain = ">= 0.9, < 0.11"
// Copyright 2016 Kitware, Inc.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
error_chain! {
errors {
/// A git error occurred.
Git(msg: String) {
description("git error")
display("git error: '{}'", msg)
}
/// An invalid ref was used.
InvalidRef(msg: String) {
description("invalid ref")
display("invalid git ref: '{}'", msg)
}
}
}
......@@ -6,18 +6,125 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use error::*;
use prepare::GitWorkArea;
use prepare::{GitWorkArea, WorkAreaResult};
use std::borrow::Cow;
use std::error::Error;
use std::ffi::OsStr;
use std::fmt::{self, Display};
use std::io;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::result::Result;
/// The Git object id of a commit.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CommitId(String);
/// Errors which may occur when working with workareas.
#[derive(Debug)]
// TODO: #[non_exhaustive]
pub enum GitError {
/// Command preparation failure.
Subcommand {
/// The git subcommand which failed.
subcommand: &'static str,
/// The root cause of the failure.
source: io::Error,
},
/// A git error occurred.
Git {
/// Message describing what failed.
msg: Cow<'static, str>,
/// The root cause of the failure (if available).
source: Option<io::Error>,
},
/// An invalid ref was used.
InvalidRef {
/// The invalid ref (or description of what was wrong).
ref_: Cow<'static, str>,
},
/// This is here to force `_` matching right now.
///
/// **DO NOT USE**
#[doc(hidden)]
_NonExhaustive,
}
impl GitError {
pub(crate) fn subcommand(subcommand: &'static str, source: io::Error) -> Self {
GitError::Subcommand {
subcommand,
source,
}
}
pub(crate) fn git<M>(msg: M) -> Self
where
M: Into<Cow<'static, str>>,
{
GitError::Git {
msg: msg.into(),
source: None,
}
}
pub(crate) fn git_with_source<M>(msg: M, source: io::Error) -> Self
where
M: Into<Cow<'static, str>>,
{
GitError::Git {
msg: msg.into(),
source: Some(source),
}
}
pub(crate) fn invalid_ref<R>(ref_: R) -> Self
where
R: Into<Cow<'static, str>>,
{
GitError::InvalidRef {
ref_: ref_.into(),
}
}
}
impl fmt::Display for GitError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GitError::Subcommand {
subcommand, ..
} => write!(f, "failed to construct 'git {}' command", subcommand),
GitError::Git {
msg, ..
} => write!(f, "git error: '{}'", msg),
GitError::InvalidRef {
ref_,
} => write!(f, "invalid git ref: '{}'", ref_),
nonexhaustive => unreachable!("unhandled git error: {:?}", nonexhaustive),
}
}
}
impl Error for GitError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
GitError::InvalidRef {
..
} => None,
GitError::Subcommand {
source, ..
} => Some(source),
GitError::Git {
source, ..
} => source.as_ref().map(|err| err as &dyn Error),
nonexhaustive => unreachable!("unhandled git error: {:?}", nonexhaustive),
}
}
}
pub(crate) type GitResult<T> = Result<T, GitError>;
impl CommitId {
/// Create a new `CommitId`.
pub fn new<I: ToString>(id: I) -> Self {
......@@ -147,7 +254,7 @@ impl GitContext {
/// Fetch references from the given remote.
///
/// The remote is interpreted by Git, so it can be a remote or a specific URL.
pub fn fetch<R, I, N>(&self, remote: R, refnames: I) -> Result<()>
pub fn fetch<R, I, N>(&self, remote: R, refnames: I) -> GitResult<()>
where
R: AsRef<str>,
I: IntoIterator<Item = N>,
......@@ -159,9 +266,9 @@ impl GitContext {
.arg(remote.as_ref())
.args(refnames.into_iter())
.output()
.chain_err(|| "failed to construct fetch command")?;
.map_err(|err| GitError::subcommand("fetch", err))?;
if !fetch.status.success() {
bail!(ErrorKind::Git(format!(
return Err(GitError::git(format!(
"fetch from {} failed: {}",
remote.as_ref(),
String::from_utf8_lossy(&fetch.stderr)
......@@ -172,7 +279,7 @@ impl GitContext {
}
/// Fetch a commit from the given remote into a specific local refname.
pub fn fetch_into<R, N, T>(&self, remote: R, refname: N, target: T) -> Result<()>
pub fn fetch_into<R, N, T>(&self, remote: R, refname: N, target: T) -> GitResult<()>
where
R: AsRef<str>,
N: AsRef<str>,
......@@ -185,7 +292,7 @@ impl GitContext {
}
/// Fetch a commit from the given remote into a specific local refname, allowing rewinds.
pub fn force_fetch_into<R, N, T>(&self, remote: R, refname: N, target: T) -> Result<()>
pub fn force_fetch_into<R, N, T>(&self, remote: R, refname: N, target: T) -> GitResult<()>
where
R: AsRef<str>,
N: AsRef<str>,
......@@ -199,7 +306,7 @@ impl GitContext {
}
/// Create a tree where further work on the given revision can occur.
pub fn prepare(&self, rev: &CommitId) -> Result<GitWorkArea> {
pub fn prepare(&self, rev: &CommitId) -> WorkAreaResult<GitWorkArea> {
GitWorkArea::new(self.clone(), rev)
}
......@@ -209,7 +316,7 @@ impl GitContext {
///
/// The reserved reference is created as `refs/{name}/heads/{id}` where `id` is a unique
/// integer (which is also returned).
pub fn reserve_ref<N>(&self, name: N, commit: &CommitId) -> Result<(String, usize)>
pub fn reserve_ref<N>(&self, name: N, commit: &CommitId) -> GitResult<(String, usize)>
where
N: AsRef<str>,
{
......@@ -225,9 +332,9 @@ impl GitContext {
.arg("--")
.arg(&ref_prefix)
.output()
.chain_err(|| "failed to construct for-each-ref command")?;
.map_err(|err| GitError::subcommand("for-each-ref", err))?;
if !for_each_ref.status.success() {
bail!(ErrorKind::Git(format!(
return Err(GitError::git(format!(
"listing all {} refs: {}",
ref_prefix,
String::from_utf8_lossy(&for_each_ref.stderr)
......@@ -248,7 +355,7 @@ impl GitContext {
.arg("0000000000000000000000000000000000000000")
.stdout(Stdio::null())
.output()
.chain_err(|| "failed to construct update-ref command")?;
.map_err(|err| GitError::git_with_source("update-ref", err))?;
if lock_ref.status.success() {
debug!(target: "git", "successfully reserved {}", new_ref);
......@@ -258,9 +365,9 @@ impl GitContext {
let err = String::from_utf8_lossy(&lock_ref.stderr);
if err.contains("with nonexistent object") {
bail!(ErrorKind::InvalidRef("no such commit".to_string()));
return Err(GitError::invalid_ref("no such commit"));
} else if err.contains("not a valid SHA1") {
bail!(ErrorKind::InvalidRef("invalid SHA".to_string()));
return Err(GitError::invalid_ref("invalid SHA"));
}
}
}
......@@ -276,7 +383,7 @@ impl GitContext {
///
/// It is assumed that the `bases` refs are aligned with the `heads` references and not used
/// for other purposes.
pub fn reserve_refs<N>(&self, name: N, commit: &CommitId) -> Result<(String, String)>
pub fn reserve_refs<N>(&self, name: N, commit: &CommitId) -> GitResult<(String, String)>
where
N: AsRef<str>,
{
......@@ -289,7 +396,7 @@ impl GitContext {
}
/// Check if a topic commit is mergeable into a target branch.
pub fn mergeable(&self, base: &CommitId, topic: &CommitId) -> Result<MergeStatus> {
pub fn mergeable(&self, base: &CommitId, topic: &CommitId) -> GitResult<MergeStatus> {
let merge_base = self
.git()
.arg("merge-base")
......@@ -297,7 +404,7 @@ impl GitContext {
.arg(base.as_str())
.arg(topic.as_str())
.output()
.chain_err(|| "failed to construct merge-base command")?;
.map_err(|err| GitError::subcommand("merge-base", err))?;
if !merge_base.status.success() {
return Ok(MergeStatus::NoCommonHistory);
}
......
......@@ -14,9 +14,6 @@
//! except that its on-disk representation is minimal so that operations are not constrained by
//! disk speed.
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lazy_static;
......@@ -26,7 +23,6 @@ extern crate log;
mod crates {
// public
pub extern crate chrono;
// pub extern crate error_chain;
// private
pub extern crate log;
......@@ -37,17 +33,12 @@ mod crates {
pub extern crate itertools;
}
mod error;
mod git;
mod prepare;
pub use error::Error;
pub use error::ErrorKind;
pub use error::Result;
pub use error::ResultExt;
pub use git::CommitId;
pub use git::GitContext;
pub use git::GitError;
pub use git::Identity;
pub use git::MergeStatus;
......@@ -56,6 +47,7 @@ pub use prepare::GitWorkArea;
pub use prepare::MergeCommand;
pub use prepare::MergeResult;
pub use prepare::SubmoduleConfig;
pub use prepare::WorkAreaError;
#[cfg(test)]
mod test;
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment