diff --git a/.github/workflows/run.yml b/.github/workflows/run.yml index 413333f..78f9be6 100644 --- a/.github/workflows/run.yml +++ b/.github/workflows/run.yml @@ -49,6 +49,9 @@ jobs: chmod +x ~/.cargo/bin/os-checker os-checker layout --help + # - name: Test get_release_count + # run: cargo test -- test_get_release_count --nocapture + # # - name: Test os-checker layout --list-targets # run: cargo test -- test_sel4 --nocapture # diff --git a/src/crates_io.rs b/src/crates_io.rs new file mode 100644 index 0000000..8e89824 --- /dev/null +++ b/src/crates_io.rs @@ -0,0 +1,55 @@ +fn url(pkg: &str) -> String { + const PREFIX: &str = + "https://raw.githubusercontent.com/rust-lang/crates.io-index/refs/heads/master"; + + // ref: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-files + let components = match pkg.len() { + 1 => &["1", pkg][..], + 2 => &["2", pkg], + 3 => { + let (a, b) = pkg.split_at(1); + &["3", a, b, pkg] + } + _ => { + let (a, b) = pkg.split_at(2); + let (b, _) = b.split_at(2); + &[a, b, pkg] + } + }; + + // e.g. https://raw.githubusercontent.com/rust-lang/crates.io-index/refs/heads/master/os/-c/os-checker + let mut buf = String::with_capacity(128); + buf.push_str(PREFIX); + + for c in components { + buf.push('/'); + buf.push_str(c); + } + + buf +} + +/// NOTE: the result might be spurious due to network failure or invalid text; +/// +/// None means no release found; 0 is an invalid value because there at least one +/// release if found. +pub fn get_release_count(pkg: &str) -> Option { + let url = url(pkg); + let output = duct::cmd!("wget", &url, "-O", "-") + .stdout_capture() + .stderr_null() + .run() + .ok()?; + + let text = std::str::from_utf8(&output.stdout).ok()?.trim(); + let count = text.lines().count(); + if count == 0 { + error!(pkg, url, text, "count is an invalid value 0") + } + Some(count) +} + +#[test] +fn test_get_release_count() { + dbg!(get_release_count("os-checker")); +} diff --git a/src/lib.rs b/src/lib.rs index b9cffb1..6715485 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ extern crate eyre; #[macro_use] extern crate tracing; +pub mod crates_io; pub mod database; pub mod logger; pub mod nextest; diff --git a/src/repo/mod.rs b/src/repo/mod.rs index 08aed6c..2172cbd 100644 --- a/src/repo/mod.rs +++ b/src/repo/mod.rs @@ -1,4 +1,4 @@ -use crate::{database::diag_total_count, prelude::*}; +use crate::{crates_io::get_release_count, database::diag_total_count, prelude::*}; use cargo_metadata::Package; use eyre::ContextCompat; use output::Output; @@ -83,6 +83,7 @@ impl Repo { let pkg_name = pkg.name.as_str(); let mut output = Output::new(pkg, test_cases.swap_remove(pkg_name)); output.diag_total_count = diag_total_count([&self.user, &self.repo, pkg_name]); + output.release_count = get_release_count(pkg_name); assert!( outputs.insert(pkg_name, output).is_none(), "os-checker can't handle duplicated package names in a repo" @@ -114,8 +115,13 @@ impl Repo { } pub fn local_base_dir() -> &'static Utf8Path { - static GIT_CLONE_DIR: LazyLock = - LazyLock::new(|| Utf8PathBuf::from_iter(["/tmp", "os-checker-plugin-cargo"])); + static GIT_CLONE_DIR: LazyLock = LazyLock::new(|| { + let path = Utf8PathBuf::from_iter(["/tmp", "os-checker-plugin-cargo"]); + if let Err(err) = std::fs::create_dir_all(&path) { + error!(?err, ?path, "directory is not created"); + }; + path + }); &GIT_CLONE_DIR } diff --git a/src/repo/output.rs b/src/repo/output.rs index 04da7ac..f317bf0 100644 --- a/src/repo/output.rs +++ b/src/repo/output.rs @@ -21,6 +21,8 @@ pub struct Output { pub categories: Vec, pub os_categories: Vec, pub diag_total_count: Option, + /// crates.io 发版次数 + pub release_count: Option, } impl Output { @@ -55,6 +57,7 @@ impl Output { }) .unwrap_or_default(), diag_total_count: None, + release_count: None, } } }