Skip to content

Commit a7cbb3d

Browse files
committed
Merge remote-tracking branch 'upstream/master' into update-itertools-log
2 parents 7414dc5 + c0327a3 commit a7cbb3d

35 files changed

+503
-244
lines changed

.diesel_version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.3.0
1+
1.4.0

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ install:
3030
- cargo install --force diesel_cli --vers `cat .diesel_version` --no-default-features --features postgres && export PATH=$HOME/.cargo/bin:$PATH
3131

3232
before_script:
33-
- diesel database setup
33+
- diesel database setup --locked-schema
3434

3535
addons:
3636
chrome: stable

Cargo.lock

Lines changed: 253 additions & 110 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ htmlescape = "0.3.1"
4747
license-exprs = "^1.4"
4848
dotenv = "0.11.0"
4949
toml = "0.4"
50-
diesel = { version = "1.3.0", features = ["postgres", "serde_json", "chrono", "r2d2"] }
50+
diesel = { version = "1.4.0", features = ["postgres", "serde_json", "chrono", "r2d2"] }
5151
diesel_full_text_search = "1.0.0"
5252
diesel_ltree = "0.1.3"
5353
serde_json = "1.0.0"
@@ -62,14 +62,15 @@ scheduled-thread-pool = "0.2.0"
6262
derive_deref = "1.0.0"
6363
reqwest = "0.9.1"
6464
tempdir = "0.3.7"
65+
parking_lot = "0.7.1"
6566

6667
lettre = {git = "https://github.com/lettre/lettre", version = "0.9"}
6768
lettre_email = {git = "https://github.com/lettre/lettre", version = "0.9"}
6869

6970
conduit = "0.8"
7071
conduit-conditional-get = "0.8"
71-
conduit-cookie = "0.8"
72-
cookie = "0.9"
72+
conduit-cookie = "0.8.5"
73+
cookie = "0.11"
7374
conduit-middleware = "0.8"
7475
conduit-router = "0.8"
7576
conduit-static = "0.8"
@@ -89,7 +90,3 @@ tokio-service = "0.1"
8990
dotenv = "0.11"
9091
diesel = { version = "1.3.0", features = ["postgres"] }
9192
diesel_migrations = { version = "1.3.0", features = ["postgres"] }
92-
93-
# Remove once cookie depends on ring >= 0.13.0
94-
[patch.crates-io]
95-
ring = { git = "https://github.com/SergioBenitez/ring", branch = "v0.11" }

Procfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
web: bin/diesel migration run && bin/start-nginx ./target/release/server
1+
web: bin/diesel migration run --locked-schema && bin/start-nginx ./target/release/server
22
worker: ./target/release/update-downloads daemon 300

src/app.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ impl App {
7373
let db_connection_timeout = match (env::var("DB_TIMEOUT"), config.env) {
7474
(Ok(num), _) => num.parse().expect("couldn't parse DB_TIMEOUT"),
7575
(_, Env::Production) => 10,
76+
(_, Env::Test) => 1,
7677
_ => 30,
7778
};
7879

@@ -88,7 +89,7 @@ impl App {
8889
let repo = git2::Repository::open(&config.git_repo_checkout).unwrap();
8990

9091
App {
91-
diesel_database: db::diesel_pool(&config.db_url, diesel_db_config),
92+
diesel_database: db::diesel_pool(&config.db_url, config.env, diesel_db_config),
9293
github,
9394
session_key: config.session_key.clone(),
9495
git_repo: Mutex::new(repo),

src/bin/update-downloads.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![deny(warnings)]
2-
#![allow(unknown_lints, proc_macro_derive_resolution_fallback)] // This can be removed after diesel-1.4
32

43
#[macro_use]
54
extern crate diesel;
@@ -138,7 +137,7 @@ mod test {
138137
name: "foo",
139138
..Default::default()
140139
}
141-
.create_or_update(&conn, None, user_id)
140+
.create_or_update(conn, None, user_id)
142141
.unwrap();
143142
let version = NewVersion::new(
144143
krate.id,
@@ -149,7 +148,7 @@ mod test {
149148
0,
150149
)
151150
.unwrap();
152-
let version = version.save(&conn, &[]).unwrap();
151+
let version = version.save(conn, &[]).unwrap();
153152
(krate, version)
154153
}
155154

src/controllers/crate_owner_invitation.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ struct OwnerInvitation {
3232

3333
/// Handles the `PUT /me/crate_owner_invitations/:crate_id` route.
3434
pub fn handle_invite(req: &mut dyn Request) -> CargoResult<Response> {
35-
let conn = &*req.db_conn()?;
36-
3735
let mut body = String::new();
3836
req.body().read_to_string(&mut body)?;
3937

38+
let conn = &*req.db_conn()?;
39+
4040
let crate_invite: OwnerInvitation =
4141
serde_json::from_str(&body).map_err(|_| human("invalid json request"))?;
4242

@@ -50,7 +50,7 @@ pub fn handle_invite(req: &mut dyn Request) -> CargoResult<Response> {
5050
}
5151

5252
fn accept_invite(
53-
req: &mut dyn Request,
53+
req: &dyn Request,
5454
conn: &PgConnection,
5555
crate_invite: InvitationResponse,
5656
) -> CargoResult<Response> {
@@ -88,7 +88,7 @@ fn accept_invite(
8888
}
8989

9090
fn decline_invite(
91-
req: &mut dyn Request,
91+
req: &dyn Request,
9292
conn: &PgConnection,
9393
crate_invite: InvitationResponse,
9494
) -> CargoResult<Response> {

src/controllers/krate/publish.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub fn publish(req: &mut dyn Request) -> CargoResult<Response> {
6363
let categories = new_crate.categories.as_ref().map(|s| &s[..]).unwrap_or(&[]);
6464
let categories: Vec<_> = categories.iter().map(|k| &***k).collect();
6565

66-
let conn = req.db_conn()?;
66+
let conn = app.diesel_database.get()?;
6767

6868
let mut other_warnings = vec![];
6969
if !user.has_verified_email(&conn)? {

src/controllers/krate/search.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ pub fn search(req: &mut dyn Request) -> CargoResult<Response> {
171171

172172
let badges = CrateBadge::belonging_to(&crates)
173173
.select((badges::crate_id, badges::all_columns))
174-
.load::<CrateBadge>(&conn)?
174+
.load::<CrateBadge>(&*conn)?
175175
.grouped_by(&crates)
176176
.into_iter()
177177
.map(|badges| badges.into_iter().map(|cb| cb.badge).collect());

src/controllers/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ mod prelude {
3939

4040
fn redirect(&self, url: String) -> Response {
4141
let mut headers = HashMap::new();
42-
headers.insert("Location".to_string(), vec![url.to_string()]);
42+
headers.insert("Location".to_string(), vec![url]);
4343
Response {
4444
status: (302, "Found"),
4545
headers,

src/controllers/user/session.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,7 @@ pub fn github_access_token(req: &mut dyn Request) -> CargoResult<Response> {
9494
}
9595

9696
// Fetch the access token from github using the code we just got
97-
let token = req
98-
.app()
99-
.github
100-
.exchange(code.clone())
101-
.map_err(|s| human(&s))?;
97+
let token = req.app().github.exchange(code).map_err(|s| human(&s))?;
10298

10399
let ghuser = github::github::<GithubUser>(req.app(), "/user", &token)?;
104100

src/controllers/version/deprecated.rs

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@
77
88
use crate::controllers::prelude::*;
99

10-
use crate::models::Version;
10+
use crate::models::{Crate, Version};
1111
use crate::schema::*;
1212
use crate::views::EncodableVersion;
1313

14-
use super::version_and_crate;
15-
1614
/// Handles the `GET /versions` route.
1715
pub fn index(req: &mut dyn Request) -> CargoResult<Response> {
1816
use diesel::dsl::any;
@@ -40,28 +38,18 @@ pub fn index(req: &mut dyn Request) -> CargoResult<Response> {
4038
Ok(req.json(&R { versions }))
4139
}
4240

43-
/// Handles the `GET /versions/:version_id` and
44-
/// `GET /crates/:crate_id/:version` routes.
45-
///
46-
/// The frontend doesn't appear to hit either of these endpoints. Instead the
47-
/// version information appears to be returned by `krate::show`.
48-
///
49-
/// FIXME: These two routes have very different semantics and should be split into
50-
/// a separate function for each endpoint.
51-
pub fn show(req: &mut dyn Request) -> CargoResult<Response> {
52-
let (version, krate) = match req.params().find("crate_id") {
53-
Some(..) => version_and_crate(req)?,
54-
None => {
55-
let id = &req.params()["version_id"];
56-
let id = id.parse().unwrap_or(0);
57-
let conn = req.db_conn()?;
58-
versions::table
59-
.find(id)
60-
.inner_join(crates::table)
61-
.select((versions::all_columns, crate::models::krate::ALL_COLUMNS))
62-
.first(&*conn)?
63-
}
64-
};
41+
/// Handles the `GET /versions/:version_id` route.
42+
/// The frontend doesn't appear to hit this endpoint. Instead, the version information appears to
43+
/// be returned by `krate::show`.
44+
pub fn show_by_id(req: &mut dyn Request) -> CargoResult<Response> {
45+
let id = &req.params()["version_id"];
46+
let id = id.parse().unwrap_or(0);
47+
let conn = req.db_conn()?;
48+
let (version, krate): (Version, Crate) = versions::table
49+
.find(id)
50+
.inner_join(crates::table)
51+
.select((versions::all_columns, crate::models::krate::ALL_COLUMNS))
52+
.first(&*conn)?;
6553

6654
#[derive(Serialize)]
6755
struct R {

src/controllers/version/metadata.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::controllers::prelude::*;
88

99
use crate::schema::*;
10-
use crate::views::{EncodableDependency, EncodablePublicUser};
10+
use crate::views::{EncodableDependency, EncodablePublicUser, EncodableVersion};
1111

1212
use super::version_and_crate;
1313

@@ -61,3 +61,19 @@ pub fn authors(req: &mut dyn Request) -> CargoResult<Response> {
6161
meta: Meta { names },
6262
}))
6363
}
64+
65+
/// Handles the `GET /crates/:crate/:version` route.
66+
///
67+
/// The frontend doesn't appear to hit this endpoint, but our tests do, and it seems to be a useful
68+
/// API route to have.
69+
pub fn show(req: &mut dyn Request) -> CargoResult<Response> {
70+
let (version, krate) = version_and_crate(req)?;
71+
72+
#[derive(Serialize)]
73+
struct R {
74+
version: EncodableVersion,
75+
}
76+
Ok(req.json(&R {
77+
version: version.encodable(&krate.name),
78+
}))
79+
}

src/db.rs

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,56 @@ use std::env;
33
use conduit::Request;
44
use diesel::prelude::*;
55
use diesel::r2d2::{self, ConnectionManager, CustomizeConnection};
6+
use parking_lot::{ReentrantMutex, ReentrantMutexGuard};
7+
use std::ops::Deref;
68
use url::Url;
79

810
use crate::middleware::app::RequestApp;
911
use crate::util::CargoResult;
12+
use crate::Env;
1013

11-
pub type DieselPool = r2d2::Pool<ConnectionManager<PgConnection>>;
12-
type DieselPooledConn = r2d2::PooledConnection<ConnectionManager<PgConnection>>;
14+
#[allow(missing_debug_implementations)]
15+
pub enum DieselPool {
16+
Pool(r2d2::Pool<ConnectionManager<PgConnection>>),
17+
Test(ReentrantMutex<PgConnection>),
18+
}
19+
20+
impl DieselPool {
21+
pub fn get(&self) -> CargoResult<DieselPooledConn> {
22+
match self {
23+
DieselPool::Pool(pool) => Ok(DieselPooledConn::Pool(pool.get()?)),
24+
DieselPool::Test(conn) => Ok(DieselPooledConn::Test(conn.lock())),
25+
}
26+
}
27+
28+
pub fn state(&self) -> r2d2::State {
29+
match self {
30+
DieselPool::Pool(pool) => pool.state(),
31+
DieselPool::Test(_) => panic!("Cannot get the state of a test pool"),
32+
}
33+
}
34+
35+
fn test_conn(conn: PgConnection) -> Self {
36+
DieselPool::Test(ReentrantMutex::new(conn))
37+
}
38+
}
39+
40+
#[allow(missing_debug_implementations)]
41+
pub enum DieselPooledConn<'a> {
42+
Pool(r2d2::PooledConnection<ConnectionManager<PgConnection>>),
43+
Test(ReentrantMutexGuard<'a, PgConnection>),
44+
}
45+
46+
impl Deref for DieselPooledConn<'_> {
47+
type Target = PgConnection;
48+
49+
fn deref(&self) -> &Self::Target {
50+
match self {
51+
DieselPooledConn::Pool(conn) => conn.deref(),
52+
DieselPooledConn::Test(conn) => conn.deref(),
53+
}
54+
}
55+
}
1356

1457
pub fn connect_now() -> ConnectionResult<PgConnection> {
1558
use diesel::Connection;
@@ -22,14 +65,22 @@ pub fn connect_now() -> ConnectionResult<PgConnection> {
2265

2366
pub fn diesel_pool(
2467
url: &str,
68+
env: Env,
2569
config: r2d2::Builder<ConnectionManager<PgConnection>>,
2670
) -> DieselPool {
2771
let mut url = Url::parse(url).expect("Invalid database URL");
2872
if env::var("HEROKU").is_ok() && !url.query_pairs().any(|(k, _)| k == "sslmode") {
2973
url.query_pairs_mut().append_pair("sslmode", "require");
3074
}
31-
let manager = ConnectionManager::new(url.into_string());
32-
config.build(manager).unwrap()
75+
76+
if env == Env::Test {
77+
let conn =
78+
PgConnection::establish(&url.into_string()).expect("failed to establish connection");
79+
DieselPool::test_conn(conn)
80+
} else {
81+
let manager = ConnectionManager::new(url.into_string());
82+
DieselPool::Pool(config.build(manager).unwrap())
83+
}
3384
}
3485

3586
pub trait RequestTransaction {

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#![deny(missing_debug_implementations, missing_copy_implementations)]
88
#![deny(bare_trait_objects)]
99
#![recursion_limit = "256"]
10-
#![allow(unknown_lints, proc_macro_derive_resolution_fallback)] // TODO: This can be removed after diesel-1.4
1110

1211
#[macro_use]
1312
extern crate derive_deref;

src/middleware/current_user.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub enum AuthenticationSource {
2020

2121
impl Middleware for CurrentUser {
2222
fn before(&self, req: &mut dyn Request) -> Result<(), Box<dyn Error + Send>> {
23+
use std::mem::drop;
24+
2325
// Check if the request has a session cookie with a `user_id` property inside
2426
let id = {
2527
req.session()
@@ -32,6 +34,7 @@ impl Middleware for CurrentUser {
3234
if let Some(id) = id {
3335
// If it did, look for a user in the database with the given `user_id`
3436
let maybe_user = users::table.find(id).first::<User>(&*conn);
37+
drop(conn);
3538
if let Ok(user) = maybe_user {
3639
// Attach the `User` model from the database to the request
3740
req.mut_extensions().insert(user);
@@ -46,6 +49,7 @@ impl Middleware for CurrentUser {
4649
} else {
4750
None
4851
};
52+
drop(conn);
4953
if let Some(user) = user {
5054
// Attach the `User` model from the database to the request
5155
req.mut_extensions().insert(user);

0 commit comments

Comments
 (0)