summaryrefslogtreecommitdiffstats
path: root/crate_db
diff options
context:
space:
mode:
authorKornel <kornel@geekhood.net>2019-09-01 13:44:09 +0100
committerKornel <kornel@geekhood.net>2019-09-01 20:31:38 +0100
commit7df435223cf90ccb7adb182547cb9981cfc37ea2 (patch)
treec9c9b1e419bba7a30a2f86f54781956ae2d83b42 /crate_db
parent4f0f1b3b8b997dcf5487068cc93399940ac9681d (diff)
Parse semver in db
Diffstat (limited to 'crate_db')
-rw-r--r--crate_db/Cargo.toml1
-rw-r--r--crate_db/src/builddb.rs128
2 files changed, 105 insertions, 24 deletions
diff --git a/crate_db/Cargo.toml b/crate_db/Cargo.toml
index 2789d89..c0ab88a 100644
--- a/crate_db/Cargo.toml
+++ b/crate_db/Cargo.toml
@@ -22,6 +22,7 @@ parking_lot = "0.9"
rake = { git = "https://github.com/kornelski/rake-rs" }
rmp-serde = "0.14"
heck = "0.3.1"
+semver = "0.9.0"
[dev-dependencies]
tempfile = "3.1.0"
diff --git a/crate_db/src/builddb.rs b/crate_db/src/builddb.rs
index fdf512a..3a549c2 100644
--- a/crate_db/src/builddb.rs
+++ b/crate_db/src/builddb.rs
@@ -1,8 +1,11 @@
-use rich_crate::Origin;
-
use parking_lot::Mutex;
+use rich_crate::Origin;
use rusqlite::*;
+use semver::Version as SemVer;
use std::path::Path;
+use std::collections::HashMap;
+use std::collections::BTreeMap;
+use std::collections::BTreeSet;
pub struct BuildDb {
pub(crate) conn: Mutex<Connection>,
@@ -10,11 +13,24 @@ pub struct BuildDb {
#[derive(Debug, Clone)]
pub struct CompatibilityInfo {
- pub rustc_version: String,
- pub crate_version: String,
+ pub rustc_version: SemVer,
+ pub crate_version: SemVer,
pub compat: Compat,
}
+#[derive(Debug)]
+pub struct CompatRange {
+ pub oldest_ok: SemVer,
+ pub newest_bad: SemVer,
+ pub newest_ok: SemVer,
+}
+
+#[derive(Debug)]
+pub struct RustcCompatRange {
+ pub newest_ok: Option<SemVer>,
+ pub oldest_bad: Option<SemVer>,
+}
+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum Compat {
VerifiedWorks,
@@ -23,6 +39,27 @@ pub enum Compat {
Incompatible,
}
+impl Compat {
+ pub fn from_str(s: &str) -> Self {
+ match s {
+ "Y" => Compat::VerifiedWorks,
+ "y" => Compat::ProbablyWorks,
+ "n" => Compat::BrokenDeps,
+ "N" => Compat::Incompatible,
+ _ => panic!("bad compat str {}", s),
+ }
+ }
+
+ pub fn as_str(self) -> &'static str {
+ match self {
+ Compat::VerifiedWorks => "Y",
+ Compat::ProbablyWorks => "y",
+ Compat::BrokenDeps => "n",
+ Compat::Incompatible => "N",
+ }
+ }
+}
+
impl BuildDb {
pub fn new(path: impl AsRef<Path>) -> Result<Self> {
let db = Connection::open(path.as_ref())?;
@@ -51,33 +88,76 @@ impl BuildDb {
let conn = self.conn.lock();
let mut get = conn.prepare_cached(r"SELECT rustc_version, version, compat FROM build_results WHERE origin = ?1")?;
let origin_str = origin.to_str();
- let res = get.query_map(&[origin_str.as_str()], |row| {
- let compat = match row.get_raw(2).as_str().expect("strtype") {
- "Y" => Compat::VerifiedWorks,
- "y" => Compat::ProbablyWorks,
- "n" => Compat::BrokenDeps,
- "N" => Compat::Incompatible,
- _ => panic!("wat?"),
- };
- Ok(CompatibilityInfo {
- rustc_version: row.get(0)?,
- crate_version: row.get(1)?,
- compat
- })
- })?;
+ let res = get.query_map(&[origin_str.as_str()], Self::compat_row)?;
res.collect()
}
+ pub fn get_all_compat(&self) -> Result<Vec<(Origin, Vec<(SemVer, RustcCompatRange)>)>> {
+ let conn = self.conn.lock();
+ let mut get = conn.prepare_cached(r"SELECT rustc_version, version, compat, origin FROM build_results")?;
+
+ let mut by_crate = HashMap::with_capacity(10000);
+
+ let max_ver: SemVer = "999.999.999".parse().unwrap();
+ let min_ver: SemVer = "0.0.0".parse().unwrap();
+
+ for row in get.query_map(NO_PARAMS, |row| Ok((Origin::from_str(row.get_raw(3).as_str().unwrap()), Self::compat_row(row)?)))? {
+ let (origin, compat) = row?;
+ let by_ver = by_crate.entry(origin).or_insert_with(BTreeMap::default);
+ let t = by_ver.entry(compat.crate_version).or_insert_with(|| CompatRange {
+ oldest_ok: max_ver.clone(),
+ newest_ok: min_ver.clone(),
+ newest_bad: min_ver.clone(),
+ });
+ match compat.compat {
+ Compat::VerifiedWorks | Compat::ProbablyWorks => {
+ if compat.rustc_version < t.oldest_ok {
+ t.oldest_ok = compat.rustc_version.clone();
+ }
+ if compat.rustc_version > t.newest_ok {
+ t.newest_ok = compat.rustc_version;
+ }
+ },
+ Compat::Incompatible | Compat::BrokenDeps => {
+ if compat.rustc_version > t.newest_bad {
+ t.newest_bad = compat.rustc_version;
+ }
+ },
+ }
+ }
+ Ok(by_crate.into_iter().map(|(origin, compat)| {
+ let mut rustc_versions = BTreeSet::new();
+ for (_, c) in &compat {
+ if c.oldest_ok != max_ver {rustc_versions.insert(&c.oldest_ok);}
+ if c.newest_bad != min_ver {rustc_versions.insert(&c.newest_bad);}
+ if c.newest_ok != min_ver {rustc_versions.insert(&c.newest_ok);}
+ }
+ let rver = rustc_versions.into_iter().map(|rv| {
+ let oldest_bad = compat.iter().filter(|(_, rustc)| rv <= &rustc.newest_bad).map(|(crate_ver, _)| crate_ver).min();
+ let newest_ok = compat.iter().filter(|(_, rustc)| rv >= &rustc.oldest_ok).map(|(crate_ver, _)| crate_ver).max();
+ (rv.clone(), RustcCompatRange {
+ oldest_bad: oldest_bad.cloned(),
+ newest_ok: newest_ok.cloned(),
+ })
+ }).collect();
+ (origin, rver)
+ }).collect())
+ }
+
+ fn compat_row(row: &Row) -> Result<CompatibilityInfo> {
+ let compat = Compat::from_str(row.get_raw(2).as_str().expect("strtype"));
+ Ok(CompatibilityInfo {
+ rustc_version: SemVer::parse(row.get_raw(0).as_str().unwrap()).expect("semver"),
+ crate_version: SemVer::parse(row.get_raw(1).as_str().unwrap()).expect("semver"),
+ compat
+ })
+ }
+
pub fn set_compat(&self, origin: &Origin, ver: &str, rustc_version: &str, compat: Compat) -> Result<()> {
let conn = self.conn.lock();
let mut ins = conn.prepare_cached(r"INSERT OR REPLACE INTO build_results(origin, version, rustc_version, compat) VALUES(?1, ?2, ?3, ?4)")?;
let origin_str = origin.to_str();
- let result_str = match compat {
- Compat::VerifiedWorks => "Y",
- Compat::ProbablyWorks => "y",
- Compat::BrokenDeps => "n",
- Compat::Incompatible => "N",
- };
+ let result_str = compat.as_str();
ins.execute(&[origin_str.as_str(), ver, rustc_version, result_str])?;
Ok(())
}