Skip to content

Commit 117da99

Browse files
committed
rewrite consistency check & make it execute fixes
1 parent 6b1505d commit 117da99

File tree

11 files changed

+602
-235
lines changed

11 files changed

+602
-235
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ exclude = [
1616
]
1717

1818
[features]
19-
consistency_check = ["crates-index", "rayon"]
19+
consistency_check = ["crates-index", "rayon", "itertools"]
2020

2121
[dependencies]
2222
sentry = "0.29.0"
@@ -67,6 +67,7 @@ zip = {version = "0.6.2", default-features = false, features = ["bzip2"]}
6767
bzip2 = "0.4.2"
6868
serde_cbor = "0.11.1"
6969
getrandom = "0.2.1"
70+
itertools = { version = "0.10.5", optional = true}
7071

7172
# Async
7273
tokio = { version = "1.0", features = ["rt-multi-thread", "signal", "macros"] }

src/bin/cratesfyi.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ impl DatabaseSubcommand {
469469

470470
#[cfg(feature = "consistency_check")]
471471
Self::Synchronize { dry_run } => {
472-
docs_rs::utils::consistency::run_check(&mut *ctx.conn()?, &*ctx.index()?, dry_run)?;
472+
docs_rs::utils::consistency::run_check(&ctx, dry_run)?;
473473
}
474474
}
475475
Ok(())

src/build_queue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ fn retry<T>(mut f: impl FnMut() -> Result<T>, max_attempts: u32) -> Result<T> {
266266
}
267267

268268
#[instrument(skip(conn))]
269-
fn set_yanked(conn: &mut postgres::Client, name: &str, version: &str, yanked: bool) {
269+
pub fn set_yanked(conn: &mut postgres::Client, name: &str, version: &str, yanked: bool) {
270270
let activity = if yanked { "yanked" } else { "unyanked" };
271271

272272
match conn

src/db/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub use self::pool::{Pool, PoolClient, PoolError};
1111

1212
mod add_package;
1313
pub mod blacklist;
14-
mod delete;
14+
pub mod delete;
1515
pub(crate) mod file;
1616
mod migrate;
1717
mod pool;

src/index/mod.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,7 @@ impl Index {
8989

9090
#[cfg(feature = "consistency_check")]
9191
pub(crate) fn crates(&self) -> Result<crates_index::Index> {
92-
use tracing::debug;
93-
// First ensure the index is up to date, peeking will pull the latest changes without
94-
// affecting anything else.
95-
debug!("Updating index");
96-
self.diff()?.peek_changes()?;
97-
debug!("Opening with `crates_index`");
92+
tracing::debug!("Opening with `crates_index`");
9893
// crates_index requires the repo url to match the existing origin or it tries to reinitialize the repo
9994
let repo_url = self
10095
.repository_url

src/utils/consistency/data.rs

+10-43
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,15 @@
1-
use std::{
2-
cmp::PartialEq,
3-
collections::BTreeMap,
4-
fmt::{self, Debug, Display, Formatter},
5-
};
6-
7-
#[derive(Default, Debug)]
8-
pub(crate) struct Data {
9-
pub(crate) crates: BTreeMap<CrateName, Crate>,
10-
}
11-
12-
#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Default, Debug)]
13-
pub(crate) struct CrateName(pub(crate) String);
14-
15-
#[derive(Default, Debug)]
16-
pub(crate) struct Crate {
17-
pub(crate) releases: BTreeMap<Version, Release>,
18-
}
19-
20-
#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Default, Debug)]
21-
pub(crate) struct Version(pub(crate) String);
22-
23-
#[derive(Default, Debug)]
24-
pub(crate) struct Release {}
25-
26-
impl PartialEq<String> for CrateName {
27-
fn eq(&self, other: &String) -> bool {
28-
self.0 == *other
29-
}
1+
#[derive(Clone, PartialEq, Debug)]
2+
pub(super) struct Crate {
3+
pub(super) name: String,
4+
pub(super) releases: Releases,
305
}
316

32-
impl PartialEq<String> for Version {
33-
fn eq(&self, other: &String) -> bool {
34-
self.0 == *other
35-
}
36-
}
7+
pub(super) type Crates = Vec<Crate>;
378

38-
impl Display for CrateName {
39-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
40-
Display::fmt(&self.0, f)
41-
}
42-
}
9+
pub(super) type Releases = Vec<Release>;
4310

44-
impl Display for Version {
45-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
46-
Display::fmt(&self.0, f)
47-
}
11+
#[derive(Clone, Debug, PartialEq)]
12+
pub(super) struct Release {
13+
pub(super) version: String,
14+
pub(super) yanked: Option<bool>,
4815
}

src/utils/consistency/db.rs

+99-51
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,108 @@
1-
use super::data::{Crate, CrateName, Data, Release, Version};
2-
use std::collections::BTreeMap;
3-
4-
pub(crate) fn load(conn: &mut postgres::Client) -> Result<Data, anyhow::Error> {
5-
let rows = conn.query(
6-
"
7-
SELECT
8-
crates.name,
9-
releases.version
10-
FROM crates
11-
INNER JOIN releases ON releases.crate_id = crates.id
12-
ORDER BY crates.id, releases.id
13-
",
14-
&[],
1+
use super::data::{Crate, Crates, Release, Releases};
2+
use crate::Config;
3+
use anyhow::Result;
4+
use itertools::Itertools;
5+
use postgres::fallible_iterator::FallibleIterator;
6+
use std::iter;
7+
8+
pub(super) fn load(conn: &mut postgres::Client, config: &Config) -> Result<Crates> {
9+
let rows = conn.query_raw(
10+
"SELECT name, version, yanked
11+
FROM (
12+
SELECT
13+
crates.name,
14+
releases.version,
15+
releases.yanked
16+
FROM crates
17+
INNER JOIN releases ON releases.crate_id = crates.id
18+
UNION ALL
19+
-- crates & releases that are already queued
20+
-- don't have to be requeued.
21+
SELECT queue.name, queue.version, NULL as yanked
22+
FROM queue
23+
LEFT OUTER JOIN crates ON crates.name = queue.name
24+
LEFT OUTER JOIN releases ON (
25+
releases.crate_id = crates.id AND
26+
releases.version = queue.version
27+
)
28+
WHERE queue.attempt < $1 AND (
29+
crates.id IS NULL OR
30+
releases.id IS NULL
31+
)
32+
) AS inp
33+
ORDER BY name, version",
34+
iter::once(config.build_attempts as i32),
1535
)?;
1636

17-
let mut data = Data {
18-
crates: BTreeMap::new(),
19-
};
37+
let mut crates = Crates::new();
2038

21-
let mut rows = rows.iter();
39+
for (crate_name, release_rows) in &rows
40+
// `rows` is a `FallibleIterator` which needs to be converted before
41+
// we can use Itertools.group_by on it.
42+
.iterator()
43+
.map(|row| row.expect("error fetching rows"))
44+
.into_iter()
45+
.group_by(|row| row.get("name"))
46+
{
47+
let releases: Releases = release_rows
48+
.map(|row| Release {
49+
version: row.get("version"),
50+
yanked: row.get("yanked"),
51+
})
52+
.collect();
2253

23-
struct Current {
24-
name: CrateName,
25-
krate: Crate,
54+
crates.push(Crate {
55+
name: crate_name,
56+
releases,
57+
});
2658
}
2759

28-
let mut current = if let Some(row) = rows.next() {
29-
Current {
30-
name: CrateName(row.get("name")),
31-
krate: Crate {
32-
releases: {
33-
let mut releases = BTreeMap::new();
34-
releases.insert(Version(row.get("version")), Release {});
35-
releases
36-
},
37-
},
38-
}
39-
} else {
40-
return Ok(data);
41-
};
42-
43-
for row in rows {
44-
let name = row.get("name");
45-
if current.name != name {
46-
data.crates.insert(
47-
std::mem::replace(&mut current.name, CrateName(name)),
48-
std::mem::take(&mut current.krate),
49-
);
50-
}
51-
current
52-
.krate
53-
.releases
54-
.insert(Version(row.get("version")), Release::default());
55-
}
60+
Ok(crates)
61+
}
5662

57-
data.crates.insert(current.name, current.krate);
63+
#[cfg(test)]
64+
mod tests {
65+
use super::*;
66+
use super::{Crate, Release};
67+
use crate::test::wrapper;
5868

59-
Ok(data)
69+
#[test]
70+
fn test_load() {
71+
wrapper(|env| {
72+
env.build_queue().add_crate("queued", "0.0.1", 0, None)?;
73+
env.fake_release().name("krate").version("0.0.2").create()?;
74+
env.fake_release()
75+
.name("krate")
76+
.version("0.0.3")
77+
.yanked(true)
78+
.create()?;
79+
80+
assert_eq!(
81+
load(&mut env.db().conn(), &env.config())?,
82+
vec![
83+
Crate {
84+
name: "krate".into(),
85+
releases: vec![
86+
Release {
87+
version: "0.0.2".into(),
88+
yanked: Some(false),
89+
},
90+
Release {
91+
version: "0.0.3".into(),
92+
yanked: Some(true),
93+
}
94+
]
95+
},
96+
Crate {
97+
name: "queued".into(),
98+
releases: vec![Release {
99+
version: "0.0.1".into(),
100+
yanked: None,
101+
}]
102+
},
103+
]
104+
);
105+
Ok(())
106+
})
107+
}
60108
}

0 commit comments

Comments
 (0)