Skip to content

Add a dry_run flag to /crates/new #1517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/controllers/krate/publish.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Functionality related to publishing a new crate or version of a crate.

use std::collections::HashMap;
use std::io::empty;
use std::sync::Arc;

use hex::ToHex;
Expand All @@ -24,6 +25,8 @@ use views::{EncodableCrate, EncodableCrateUpload};
/// threads and return completion or error through other methods a `cargo publish
/// --status` command, via crates.io's front end, or email.
pub fn publish(req: &mut dyn Request) -> CargoResult<Response> {
use diesel::result::Error::{self as DieselError, RollbackTransaction};

let app = Arc::clone(req.app());

// The format of the req.body() of a publish request is as follows:
Expand Down Expand Up @@ -66,7 +69,7 @@ pub fn publish(req: &mut dyn Request) -> CargoResult<Response> {
let conn = req.db_conn()?;
// Create a transaction on the database, if there are no errors,
// commit the transactions to record a new or updated crate.
conn.transaction(|| {
let res = conn.transaction(|| {
// Persist the new crate, if it doesn't already exist
let persist = NewCrate {
name,
Expand Down Expand Up @@ -163,6 +166,10 @@ pub fn publish(req: &mut dyn Request) -> CargoResult<Response> {
None => None,
};

if req.query().get("dry_run").is_some() {
Err(RollbackTransaction)?;
}

// Upload the crate, return way to delete the crate from the server
// If the git commands fail below, we shouldn't keep the crate on the
// server.
Expand Down Expand Up @@ -216,6 +223,18 @@ pub fn publish(req: &mut dyn Request) -> CargoResult<Response> {
krate: krate.minimal_encodable(&max_version, None, false, None),
warnings,
}))
});

res.or_else(|err| {
if let Some(DieselError::RollbackTransaction) = err.downcast_ref::<DieselError>() {
Ok(Response {
status: (200, "OK"),
headers: Default::default(),
body: Box::new(empty()),
})
} else {
Err(err)
}
})
}

Expand Down
11 changes: 11 additions & 0 deletions src/tests/krate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2361,3 +2361,14 @@ fn new_krate_hard_links() {
let body = new_crate_to_body_with_tarball(&new_crate("foo", "1.1.0"), &tarball);
bad_resp!(middle.call(req.with_body(&body)));
}

#[test]
fn new_krate_dry_run() {
let (_b, app, middle) = app();
let mut req = new_req("new_crate_dry_run", "1.0.0");
req.with_query("dry_run=1");
sign_in(&mut req, &app);
ok_resp!(middle.call(&mut req));
// We know that nothing tried to talk to S3 or Github since there is no
// http-data file for this test.
}
78 changes: 29 additions & 49 deletions src/util/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::any::Any;
use std::any::{Any, TypeId};
use std::error::Error;
use std::fmt;

Expand Down Expand Up @@ -39,6 +39,26 @@ pub trait CargoError: Send + fmt::Display + 'static {
fn human(&self) -> bool {
false
}

fn get_type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}

impl dyn CargoError {
pub fn is<T: Any>(&self) -> bool {
self.get_type_id() == TypeId::of::<T>()
}

pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe {
Some(&*(self as *const Self as *const T))
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our own in-tree unsafe! Matches what is in std so should be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah is this really the first use of unsafe? \o/

} else {
None
}
}
}

impl fmt::Debug for Box<dyn CargoError> {
Expand All @@ -61,20 +81,6 @@ impl CargoError for Box<dyn CargoError> {
(**self).response()
}
}
impl<T: CargoError> CargoError for Box<T> {
fn description(&self) -> &str {
(**self).description()
}
fn cause(&self) -> Option<&dyn CargoError> {
(**self).cause()
}
fn human(&self) -> bool {
(**self).human()
}
fn response(&self) -> Option<Response> {
(**self).response()
}
}

pub type CargoResult<T> = Result<T, Box<dyn CargoError>>;

Expand Down Expand Up @@ -158,47 +164,21 @@ impl<E: CargoError> fmt::Display for ChainedError<E> {
// =============================================================================
// Error impls

impl<E: Any + Error + Send + 'static> From<E> for Box<dyn CargoError> {
fn from(err: E) -> Box<dyn CargoError> {
if let Some(err) = Any::downcast_ref::<DieselError>(&err) {
if let DieselError::NotFound = *err {
return Box::new(NotFound);
}
}

struct Shim<E>(E);
impl<E: Error + Send + 'static> CargoError for Shim<E> {
fn description(&self) -> &str {
Error::description(&self.0)
}
}
impl<E: fmt::Display> fmt::Display for Shim<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
Box::new(Shim(err))
}
}

impl CargoError for ::curl::Error {
impl<E: Error + Send + 'static> CargoError for E {
fn description(&self) -> &str {
Error::description(self)
}
}

impl CargoError for ::serde_json::Error {
fn description(&self) -> &str {
Error::description(self)
}
}

impl CargoError for ::std::io::Error {
fn description(&self) -> &str {
Error::description(self)
impl<E: Any + Error + Send + 'static> From<E> for Box<dyn CargoError> {
fn from(err: E) -> Box<dyn CargoError> {
if let Some(DieselError::NotFound) = Any::downcast_ref::<DieselError>(&err) {
Box::new(NotFound)
} else {
Box::new(err)
}
}
}

// =============================================================================
// Concrete errors

Expand Down