Skip to content

Commit

Permalink
Merge pull request #32 from a-wai/version-check-improvements
Browse files Browse the repository at this point in the history
Version check improvements
  • Loading branch information
alexanderkjall committed Nov 26, 2023
2 parents 956c9ab + 122912d commit 7c0f41c
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
run: cargo test --verbose -- --include-ignored
- name: Run debstatus on itself
run: cargo run -- debstatus

Expand Down
130 changes: 99 additions & 31 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,26 @@ use std::time::{Duration, SystemTime};
const POSTGRES: &str = "postgresql://udd-mirror:udd-mirror@udd-mirror.debian.net/udd";
const CACHE_EXPIRE: Duration = Duration::from_secs(90 * 60);

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub enum PkgStatus {
NotFound,
Outdated,
Compatible,
Found,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PkgInfo {
pub status: PkgStatus,
pub version: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CacheEntry {
pub from: SystemTime,
pub found: bool,
pub info: PkgInfo,
}

// TODO: also use this for outdated check(?)
fn is_compatible(debversion: &str, crateversion: &VersionReq) -> Result<bool, Error> {
let debversion = debversion.replace('~', "-");
let debversion = Version::parse(&debversion)?;
Expand Down Expand Up @@ -56,20 +69,28 @@ impl Connection {
target: &str,
package: &str,
version: &Version,
) -> Result<Option<bool>, Error> {
) -> Result<Option<PkgInfo>, Error> {
let path = self.cache_path(target, package, version);

if !path.exists() {
return Ok(None);
}

let buf = fs::read(path)?;
let cache: CacheEntry = serde_json::from_slice(&buf)?;
let buf = fs::read(&path)?;
// If the cache entry can't be deserialized, it's probably using an old
// entry format, so let's discard it
let cache: CacheEntry = match serde_json::from_slice(&buf) {
Ok(e) => e,
_ => {
fs::remove_file(path)?;
return Ok(None);
}
};

if SystemTime::now().duration_since(cache.from)? > CACHE_EXPIRE {
Ok(None)
} else {
Ok(Some(cache.found))
Ok(Some(cache.info))
}
}

Expand All @@ -78,69 +99,82 @@ impl Connection {
target: &str,
package: &str,
version: &Version,
found: bool,
info: &PkgInfo,
) -> Result<(), Error> {
let cache = CacheEntry {
from: SystemTime::now(),
found,
info: info.clone(),
};
let buf = serde_json::to_vec(&cache)?;
fs::write(self.cache_path(target, package, version), buf)?;
Ok(())
}

pub fn search(&mut self, package: &str, version: &Version) -> Result<bool, Error> {
if let Some(found) = self.check_cache("sid", package, version)? {
return Ok(found);
pub fn search(&mut self, package: &str, version: &Version) -> Result<PkgInfo, Error> {
if let Some(info) = self.check_cache("sid", package, version)? {
return Ok(info);
}

// config.shell().status("Querying", format!("sid: {}", package))?;
info!("Querying -> sid: {}", package);
let found = self.search_generic(
let info = self.search_generic(
"SELECT version::text FROM sources WHERE source in ($1, $2) AND release='sid';",
package,
version,
)?;

self.write_cache("sid", package, version, found)?;
Ok(found)
self.write_cache("sid", package, version, &info)?;
Ok(info)
}

pub fn search_new(&mut self, package: &str, version: &Version) -> Result<bool, Error> {
if let Some(found) = self.check_cache("new", package, version)? {
return Ok(found);
pub fn search_new(&mut self, package: &str, version: &Version) -> Result<PkgInfo, Error> {
if let Some(info) = self.check_cache("new", package, version)? {
return Ok(info);
}

// config.shell().status("Querying", format!("new: {}", package))?;
info!("Querying -> new: {}", package);
let found = self.search_generic(
let info = self.search_generic(
"SELECT version::text FROM new_sources WHERE source in ($1, $2);",
package,
version,
)?;

self.write_cache("new", package, version, found)?;
Ok(found)
self.write_cache("new", package, version, &info)?;
Ok(info)
}

pub fn search_generic(
&mut self,
query: &str,
package: &str,
version: &Version,
) -> Result<bool, Error> {
) -> Result<PkgInfo, Error> {
let mut info = PkgInfo {
status: PkgStatus::NotFound,
version: String::new(),
};
let package = package.replace('_', "-");
let semver_package = if version.major == 0 {
format!("rust-{package}-{}.{}", version.major, version.minor)
let semver_version = if version.major == 0 {
if version.minor == 0 {
format!("{}.{}.{}", version.major, version.minor, version.patch)
} else {
format!("{}.{}", version.major, version.minor)
}
} else {
format!("rust-{package}-{}", version.major)
format!("{}", version.major)
};
let rows = self
.sock
.query(query, &[&format!("rust-{package}"), &semver_package])?;
let rows = self.sock.query(
query,
&[
&format!("rust-{package}"),
&format!("rust-{package}-{}", semver_version),
],
)?;

let version = version.to_string();
let version = VersionReq::parse(&version)?;
let semver_version = VersionReq::parse(&semver_version)?;
for row in &rows {
let debversion: String = row.get(0);

Expand All @@ -152,18 +186,26 @@ impl Connection {
// println!("{:?} ({:?}) => {:?}", debversion, version, is_compatible(debversion, version)?);

if is_compatible(debversion, &version)? {
return Ok(true);
info.version = debversion.to_string();
info.status = PkgStatus::Found;
return Ok(info);
} else if is_compatible(debversion, &semver_version)? {
info.version = debversion.to_string();
info.status = PkgStatus::Compatible;
} else if info.status == PkgStatus::NotFound {
info.version = debversion.to_string();
info.status = PkgStatus::Outdated;
}
}

Ok(false)
Ok(info)
}
}

#[cfg(test)]
mod tests {
use crate::db::is_compatible;
use semver::VersionReq;
use crate::db::{is_compatible, Connection, PkgStatus};
use semver::{Version, VersionReq};

#[test]
fn is_compatible_with_tilde() {
Expand All @@ -180,4 +222,30 @@ mod tests {
assert!(!is_compatible("0.1.0", &VersionReq::parse("0.1.1").unwrap()).unwrap());
assert!(is_compatible("1.1.0", &VersionReq::parse("1").unwrap()).unwrap());
}

#[test]
#[ignore]
fn check_version_reqs() {
let mut db = Connection::new().unwrap();
// Debian bullseye has rust-serde v1.0.106 and shouldn't be updated anymore
let query =
"SELECT version::text FROM sources WHERE source in ($1, $2) AND release='bullseye';";
let info = db
.search_generic(query, "serde", &Version::parse("1.0.100").unwrap())
.unwrap();
assert_eq!(info.status, PkgStatus::Found);
assert_eq!(info.version, "1.0.106");
let info = db
.search_generic(query, "serde", &Version::parse("1.0.150").unwrap())
.unwrap();
assert_eq!(info.status, PkgStatus::Compatible);
let info = db
.search_generic(query, "serde", &Version::parse("2.0.0").unwrap())
.unwrap();
assert_eq!(info.status, PkgStatus::Outdated);
let info = db
.search_generic(query, "notacrate", &Version::parse("1.0.0").unwrap())
.unwrap();
assert_eq!(info.status, PkgStatus::NotFound);
}
}
24 changes: 20 additions & 4 deletions src/debian.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::db::Connection;
use crate::db::{Connection, PkgStatus};
use crate::errors::*;
use crate::graph::Graph;
use cargo_metadata::{Package, PackageId, Source};
Expand Down Expand Up @@ -52,19 +52,35 @@ pub struct DebianInfo {
pub in_unstable: bool,
pub in_new: bool,
pub outdated: bool,
pub compatible: bool,
pub version: String,
}

fn run_task(db: &mut Connection, pkg: Pkg) -> Result<DebianInfo> {
let mut deb = DebianInfo {
in_unstable: false,
in_new: false,
outdated: false,
compatible: false,
version: String::new(),
};

if db.search(&pkg.name, &pkg.version).unwrap() {
let mut info = db.search(&pkg.name, &pkg.version).unwrap();
if info.status == PkgStatus::NotFound {
info = db.search_new(&pkg.name, &pkg.version).unwrap();
if info.status != PkgStatus::NotFound {
deb.in_new = true;
deb.version = info.version;
}
} else {
deb.in_unstable = true;
} else if db.search_new(&pkg.name, &pkg.version).unwrap() {
deb.in_new = true;
deb.version = info.version;
}

match info.status {
PkgStatus::Outdated => deb.outdated = true,
PkgStatus::Compatible => deb.compatible = true,
_ => (),
}

Ok(deb)
Expand Down
24 changes: 21 additions & 3 deletions src/format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,29 @@ impl<'a> fmt::Display for Display<'a> {
let pkg = format!("{} v{}", self.package.name, self.package.version);
if let Some(deb) = &self.package.debinfo {
if deb.in_unstable {
write!(fmt, "{} (in debian)", pkg.green())?;
if deb.compatible {
write!(
fmt,
"{} ({} in debian)",
pkg.green(),
deb.version.yellow()
)?;
} else {
write!(fmt, "{} (in debian)", pkg.green())?;
}
} else if deb.in_new {
write!(fmt, "{} (in debian NEW queue)", pkg.blue())?;
if deb.compatible {
write!(
fmt,
"{} ({} in debian NEW queue)",
pkg.blue(),
deb.version.yellow()
)?;
} else {
write!(fmt, "{} (in debian NEW queue)", pkg.blue())?;
}
} else if deb.outdated {
write!(fmt, "{} (outdated)", pkg.yellow())?;
write!(fmt, "{} (outdated, {})", pkg.red(), deb.version)?;
} else {
write!(fmt, "{pkg}")?;
}
Expand Down

0 comments on commit 7c0f41c

Please sign in to comment.