Skip to content
This repository has been archived by the owner on Jul 14, 2023. It is now read-only.

Commit

Permalink
Progress spinners that fit every parallelism scheme
Browse files Browse the repository at this point in the history
  • Loading branch information
fosskers committed Jun 28, 2020
1 parent d9dea9d commit c2843f8
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 12 deletions.
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ anyhow = "1.0"
chrono = { version = "0.4", features = ["serde"] }
counter = "0.5"
gumdrop = "0.8"
indicatif = { version = "0.15", features = ["rayon"] }
indicatif = "0.15"
isahc = { version = "0.9", features = ["json"] }
itertools = "0.9"
parse_link_header = "0.2"
rayon = "1.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
33 changes: 26 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub use github::rate_limit;
use anyhow::Context;
use chrono::{DateTime, Utc};
use counter::Counter;
use indicatif::ProgressBar;
use isahc::prelude::*;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -435,20 +436,28 @@ pub fn client(token: &str) -> anyhow::Result<HttpClient> {

/// Given a repository name, look up the [`Thread`](struct.Thread.html)
/// statistics of all its Issues.
pub fn repository_threads(
pub fn repo_threads(
client: &HttpClient,
serial: bool,
issue_pb: &ProgressBar,
pr_pb: &ProgressBar,
owner: &str,
repo: &str,
) -> anyhow::Result<Postings> {
let issue_msg = format!("Fetching Issues for {}/{}...", owner, repo);
let pr_msg = format!("Fetching Pull Requests for {}/{}...", owner, repo);

// Too much parallelism can trigger Github's abuse detection, so we offer
// the "serial" option here.
let (issues, prs) = if serial {
let issues = all_issues(client, owner, repo);
let prs = all_prs(client, owner, repo);
let issues = with_progress(issue_pb, &issue_msg, || all_issues(client, owner, repo));
let prs = with_progress(pr_pb, &pr_msg, || all_prs(client, owner, repo));

(issues, prs)
} else {
rayon::join(
|| all_issues(client, owner, repo),
|| all_prs(client, owner, repo),
|| with_progress(issue_pb, &issue_msg, || all_issues(client, owner, repo)),
|| with_progress(pr_pb, &pr_msg, || all_prs(client, owner, repo)),
)
};

Expand All @@ -458,14 +467,24 @@ pub fn repository_threads(
})
}

/// Perform some action with an associated `ProgressBar`.
fn with_progress<F, A>(progress: &ProgressBar, msg: &str, f: F) -> A
where
F: FnOnce() -> A,
{
progress.enable_steady_tick(120);
progress.set_message(&msg);
let result = f();
progress.finish_and_clear();
result
}

fn all_issues(client: &HttpClient, owner: &str, repo: &str) -> anyhow::Result<Vec<Issue>> {
eprintln!("Fetching Issues for {}/{}...", owner, repo);
github::issues(client, &github::Mode::Issues, owner, repo)
.map(|is| is.into_iter().map(|i| Issue(issue_thread(i))).collect())
}

fn all_prs(client: &HttpClient, owner: &str, repo: &str) -> anyhow::Result<Vec<PR>> {
eprintln!("Fetching Pull Requests for {}/{}...", owner, repo);
github::issues(client, &github::Mode::PRs, owner, repo).map(|is| {
is.into_iter()
.map(|i| {
Expand Down
24 changes: 21 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
use anyhow::anyhow;
use gumdrop::{Options, ParsingStyle};
use indicatif::{MultiProgress, ProgressBar};
use itertools::Itertools;
use rayon::prelude::*;
use std::io::{self, Read};
use std::process;
use std::{process, thread};

/// A tool for measuring repository contributions.
#[derive(Options)]
Expand Down Expand Up @@ -114,10 +115,27 @@ fn repo(r: Repo) -> anyhow::Result<String> {
if r.repos.is_empty() {
Err(anyhow!("No repositories given!"))
} else {
let (bads, goods): (Vec<_>, Vec<_>) = r
let m = MultiProgress::new();

let spinners = r
.repos
.iter()
.map(|(owner, repo)| {
let issue_pb = m.add(ProgressBar::new_spinner());
let pr_pb = m.add(ProgressBar::new_spinner());
(issue_pb, pr_pb, owner, repo)
})
.collect::<Vec<_>>();

// Apparently the thread itself doesn't need to be `join`ed for the
// spinners to appear.
thread::spawn(move || m.join_and_clear());

let (bads, goods): (Vec<_>, Vec<_>) = spinners
.par_iter()
.map(|(owner, repo)| credit::repository_threads(&client, r.serial, &owner, &repo))
.map(|(ipb, ppb, owner, repo)| {
credit::repo_threads(&client, r.serial, &ipb, &ppb, &owner, &repo)
})
.partition_map(From::from);

if !bads.is_empty() {
Expand Down

0 comments on commit c2843f8

Please sign in to comment.