diff options
author | Kornel <kornel@geekhood.net> | 2020-02-22 10:40:44 +0000 |
---|---|---|
committer | Kornel <kornel@geekhood.net> | 2020-02-22 10:42:48 +0000 |
commit | 16f4af9eb1935263ac78ce9b3e609fa1b1e45038 (patch) | |
tree | 4024a4476e6cb06fbb7bd3f4df5f9a46a92005f9 | |
parent | e205b77278eb4aba35eb63563afcaf0afb2c6a2e (diff) |
Rev deps dl
-rw-r--r-- | front_end/src/cat_page.rs | 2 | ||||
-rw-r--r-- | front_end/src/reverse_dependencies.rs | 66 | ||||
-rw-r--r-- | front_end/templates/reverse_dependencies.rs.html | 14 | ||||
-rw-r--r-- | kitchen_sink/src/lib_kitchen_sink.rs | 31 | ||||
m--------- | style | 0 |
5 files changed, 102 insertions, 11 deletions
diff --git a/front_end/src/cat_page.rs b/front_end/src/cat_page.rs index 06c861a..84e078e 100644 --- a/front_end/src/cat_page.rs +++ b/front_end/src/cat_page.rs @@ -102,7 +102,7 @@ impl<'a> CatPage<'a> { /// Nicely rounded number of downloads /// /// To show that these numbers are just approximate. - pub fn downloads(&self, num: u32) -> (String, &str) { + pub fn downloads(&self, num: u32) -> (String, &'static str) { match num { a @ 0..=99 => (format!("{}", a), ""), a @ 0..=500 => (format!("{}", a / 10 * 10), ""), diff --git a/front_end/src/reverse_dependencies.rs b/front_end/src/reverse_dependencies.rs index 20faf12..8338ff6 100644 --- a/front_end/src/reverse_dependencies.rs +++ b/front_end/src/reverse_dependencies.rs @@ -9,6 +9,7 @@ use render_readme::Renderer; use rich_crate::RichCrateVersion; use semver::VersionReq; + use std::fmt::Display; pub struct CratePageRevDeps<'a> { @@ -16,6 +17,7 @@ pub struct CratePageRevDeps<'a> { pub deps: Vec<RevDepInf<'a>>, pub stats: Option<&'a RevDependencies>, pub has_download_columns: bool, + downloads_by_ver: Vec<(SemVer, u32)>, } pub struct RevDepInf<'a> { @@ -29,6 +31,18 @@ pub struct RevDepInf<'a> { pub rev_dep_count: u32, } +pub struct DlRow { + pub ver: SemVer, + pub num: u16, + pub num_str: String, + pub perc: f32, + pub num_width: f32, + pub dl: u32, + pub dl_str: (String, &'static str), + pub dl_perc: f32, + pub dl_num_width: f32, +} + impl<'a> CratePageRevDeps<'a> { pub async fn new(ver: &'a RichCrateVersion, kitchen_sink: &'a KitchenSink, _markup: &'a Renderer) -> CResult<CratePageRevDeps<'a>> { let all_deps_stats = kitchen_sink.index.deps_stats().await?; @@ -37,6 +51,9 @@ impl<'a> CratePageRevDeps<'a> { let latest_stable_semver = &kitchen_sink.index.crate_highest_version(&own_name, true)?.version().parse()?; let stats = all_deps_stats.counts.get(own_name.as_str()); + let mut downloads_by_ver: Vec<_> = kitchen_sink.recent_downloads_by_version(ver)?.into_iter().map(|(v,d)| (v.to_semver(), d)).collect(); + downloads_by_ver.sort_by(|a,b| b.0.cmp(&a.0)); + let mut deps: Vec<_> = match stats { Some(s) => futures::future::join_all(s.rev_dep_names.iter().map(|rev_dep| async move { let origin = Origin::from_crates_io_name(rev_dep); @@ -81,6 +98,7 @@ impl<'a> CratePageRevDeps<'a> { ver, deps, stats, + downloads_by_ver, has_download_columns, }) } @@ -88,7 +106,7 @@ impl<'a> CratePageRevDeps<'a> { /// Nicely rounded number of downloads /// /// To show that these numbers are just approximate. - pub fn downloads(&self, num: usize) -> (String, &str) { + pub fn downloads(&self, num: usize) -> (String, &'static str) { match num { a @ 0..=99 => (format!("{}", a), ""), a @ 0..=500 => (format!("{}", a / 10 * 10), ""), @@ -104,17 +122,51 @@ impl<'a> CratePageRevDeps<'a> { } // version, deps, normalized popularity 0..100 - pub fn version_breakdown(&self) -> Vec<(SemVer, u16, f32, f32)> { + pub fn version_breakdown(&self) -> Vec<DlRow> { + // fixmeL always add current ver there let mut ver: Vec<_> = self.stats.map(|s| s.versions.iter().map(|(k, v)| { - (k.to_semver(), *v, 0., 0.) + DlRow { + ver: k.to_semver(), + num: *v, + perc: 0., + num_width: 0., + dl: 0, + dl_perc: 0., + dl_num_width: 0., + num_str: String::new(), + dl_str: (String::new(),""), + } }).collect()).unwrap_or_default(); - let max = ver.iter().map(|(_, n, ..)| *n).max().unwrap_or(1) as f32; + // align selected versions and their (or older) downloads + let mut dl_vers = self.downloads_by_ver.iter().rev().peekable(); + ver.sort_by(|a, b| b.ver.cmp(&a.ver)); + for curr in ver.iter_mut().rev() { + let mut sum = 0; + while let Some((next_ver, dl)) = dl_vers.peek() { + if next_ver > &curr.ver { + break; + } + if next_ver.major == curr.ver.major && + (next_ver.major != 0 || next_ver.minor == curr.ver.minor) { + sum += dl; + } + dl_vers.next(); + } + curr.dl = sum; + } + + let max = ver.iter().map(|v| v.num).max().unwrap_or(1) as f32; + let dl_max = ver.iter().map(|v| v.dl).max().unwrap_or(1) as f32; for i in ver.iter_mut() { - i.2 = i.1 as f32 / max * 100.0; - i.3 = 3. + 5. * (i.1 as f32 + 1.).log10().ceil(); // approx visual width of the number + i.perc = i.num as f32 / max * 100.0; + i.num_str = self.format_number(i.num); + i.num_width = 4. + 7. * i.num_str.len() as f32; // approx visual width of the number + + i.dl_perc = i.dl as f32 / dl_max * 100.0; + i.dl_str = self.downloads(i.dl as usize); + i.dl_num_width = 4. + 7. * (i.dl_str.0.len() + i.dl_str.1.len()) as f32; // approx visual width of the number } - ver.sort_by(|a, b| b.0.cmp(&a.0)); ver } diff --git a/front_end/templates/reverse_dependencies.rs.html b/front_end/templates/reverse_dependencies.rs.html index 326f345..17ca7d9 100644 --- a/front_end/templates/reverse_dependencies.rs.html +++ b/front_end/templates/reverse_dependencies.rs.html @@ -38,9 +38,17 @@ @if stats.versions.len() > 1 { <table class="version-pop"> - <thead><th>Number of dependers</th><th>@p.ver.capitalized_name() version</th></thead> - @for (ver, num, perc, num_width) in p.version_breakdown() { - <tr><td>@if perc <= num_width {@num} <span style="width:@perc%">@if perc > num_width {@num}</span></td><th>@ver</th></tr> + <thead><th>Number of dependers</th><th>@p.ver.capitalized_name() version</th><th>Downloads/month</th></thead> + @for x in p.version_breakdown() { + <tr> + <td class="rv">@if x.perc <= x.num_width {@x.num_str} <span style="width:@x.perc%">@if x.perc > x.num_width {@x.num_str}</span></td> + <th>@x.ver</th> + <td class="dl"> + @if x.dl > 0 { + <span style="width:@x.dl_perc%">@if x.dl_perc > x.dl_num_width {@x.dl_str.0<b>@x.dl_str.1</b>}</span> + } + @if x.dl == 0 || x.dl_perc <= x.dl_num_width {@x.dl_str.0<b>@x.dl_str.1</b>} + </td> } </table> } diff --git a/kitchen_sink/src/lib_kitchen_sink.rs b/kitchen_sink/src/lib_kitchen_sink.rs index d55b389..f9aaac9 100644 --- a/kitchen_sink/src/lib_kitchen_sink.rs +++ b/kitchen_sink/src/lib_kitchen_sink.rs @@ -291,6 +291,37 @@ impl KitchenSink { Ok(summed_days) } + // Monthly downloads, sampled from last few days or weeks + pub fn recent_downloads_by_version(&self, k: &RichCrateVersion) -> CResult<HashMap<MiniVer, u32>> { + let now = Utc::today(); + let curr_year = now.year() as u16; + let curr_year_data = self.yearly.get_crate_year(k.name(), curr_year)?.unwrap_or_default(); + + let mut out = HashMap::new(); + let mut total = 0; + let mut days = 0; + let mut end_day = now.ordinal0() as usize; // we'll have garbage data in january… + loop { + let start_day = end_day.saturating_sub(4); + days += end_day - start_day; + + for (ver, dl) in &curr_year_data { + let cnt = out.entry(ver).or_insert(0); + for d in dl.0[start_day..end_day].iter().copied() { + *cnt += d; + total += d; + } + } + if start_day == 0 || total > 10000 || days >= 30 { + break; + } + end_day = start_day; + } + Ok(out.into_iter().map(|(k,v)| + (k.clone(), (v as usize * 30 / days) as u32) + ).collect()) + } + /// Gets cratesio download data, but not from the API, but from our local copy pub fn weekly_downloads(&self, k: &RichCrate, num_weeks: u16) -> CResult<Vec<DownloadWeek>> { let mut res = Vec::with_capacity(num_weeks.into()); diff --git a/style b/style -Subproject 9ff123e9bab08e7e6a024e724b2d537c3fda232 +Subproject d36318c14f1b2e00dd1cb9fb2de181b9b65aac6 |