summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKornel <kornel@geekhood.net>2020-02-22 10:40:44 +0000
committerKornel <kornel@geekhood.net>2020-02-22 10:42:48 +0000
commit16f4af9eb1935263ac78ce9b3e609fa1b1e45038 (patch)
tree4024a4476e6cb06fbb7bd3f4df5f9a46a92005f9
parente205b77278eb4aba35eb63563afcaf0afb2c6a2e (diff)
Rev deps dl
-rw-r--r--front_end/src/cat_page.rs2
-rw-r--r--front_end/src/reverse_dependencies.rs66
-rw-r--r--front_end/templates/reverse_dependencies.rs.html14
-rw-r--r--kitchen_sink/src/lib_kitchen_sink.rs31
m---------style0
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