>(
    repo: &github::Repo,
    db: &database::Db,
    mirror_root: &str,
    base_cgitrc: Option,
    max_repo_size_bytes: Option,
) -> anyhow::Result<()> {
    if let Some(max_repo_size_bytes) = max_repo_size_bytes {
        if is_repo_oversize(repo.size, max_repo_size_bytes) {
            return Ok(());
        }
    }
    let id = repo.id;
    let path = clone_path(&mirror_root, &repo);
    let db_repo = database::Repo::from(repo);
    match db.repo_get(id) {
        // If we've already seen the repo and it's been updated, fetch the
        // latest.
        Ok(current_repo) => {
            if db.repo_is_updated(&db_repo)? {
                update(&path, ¤t_repo, &repo)?;
                db.repo_update(&db_repo)?;
            }
        },
        // If the repo doesn't exist, mirror it and store it in the
        // database.
        Err(database::Error::Db(rusqlite::Error::QueryReturnedNoRows)) => {
            mirror(
                path,
                &repo,
                base_cgitrc,
            )?;
            db.repo_insert(db_repo)?;
        },
        Err(e) => anyhow::bail!(e),
    }
    Ok(())
}
/// Return `true` if `size_kilobytes` is larger than `max_repo_size_bytes`.
fn is_repo_oversize(
    size_kilobytes: u64,
    max_repo_size_bytes: u64,
) -> bool {
    let size_bytes = size_kilobytes * 1000;
    if size_bytes > max_repo_size_bytes {
        return true;
    }
    false
}
/// Get the clone path for a repository.
///
/// If `repo` is a fork, add `/fork/` to `base_path`.
fn clone_path>(base_path: P, repo: &github::Repo) -> PathBuf {
    let git_dir = format!("{}.git", repo.name);
    if repo.fork {
        base_path
            .as_ref()
            .join("fork")
            .join(git_dir)
    } else {
        base_path
            .as_ref()
            .join(git_dir)
    }
}
/// Mirror a repository.
fn mirror(
    clone_path: P1,
    repo: &github::Repo,
    base_cgitrc: Option,
) -> anyhow::Result<()>
where
    P1: AsRef,
    P2: AsRef,
{
    git::mirror(
        &repo.git_url,
        &clone_path,
        repo.description(),
    )?;
    // Copy the base cgitrc file into the newly-cloned repository.
    if let Some(base_cgitrc) = base_cgitrc {
        let cgitrc_path = clone_path.as_ref().join("cgitrc");
        fs::copy(&base_cgitrc, &cgitrc_path)
            .with_context(|| format!(
                "unable to copy '{}' to '{}'",
                "./cgitrc",
                &cgitrc_path.display(),
            ))?;
    }
    update_mtime(&clone_path, &repo)?;
    Ok(())
}
/// Update a previously-mirrored repository.
fn update>(
    repo_path: P,
    current_repo: &database::Repo,
    updated_repo: &github::Repo,
) -> anyhow::Result<()> {
    git::update(&repo_path)?;
    let remote_description = updated_repo.description();
    if current_repo.description() != remote_description {
        git::update_description(&repo_path, remote_description)?;
    }
    update_mtime(&repo_path, &updated_repo)?;
    Ok(())
}
/// Set the mtime of the repository to GitHub's `updated_at` time.
///
/// Used for CGit "age" sorting.
fn update_mtime>(
    repo_path: P,
    repo: &github::Repo,
) -> anyhow::Result<()> {
    let default_branch_ref = repo_path
        .as_ref()
        .join("refs/heads")
        .join(&repo.default_branch);
    let update_time = filetime::FileTime::from_system_time(
        DateTime::parse_from_rfc3339(&repo.updated_at)?.into()
    );
    // Try updating times on the default ref.
    match filetime::set_file_times(
        &default_branch_ref,
        update_time,
        update_time,
    ) {
        Ok(_) => Ok(()),
        Err(e) => match e.kind() {
            // If the default ref file doesn't exist, update times on the
            // 'packed-refs' file.
            io::ErrorKind::NotFound => {
                let packed_refs_path = repo_path
                    .as_ref()
                    .join("packed-refs");
                Ok(
                    filetime::set_file_times(
                        &packed_refs_path,
                        update_time,
                        update_time,
                    )
                        .with_context(|| format!(
                            "unable to set mtime on '{}'",
                            &packed_refs_path.display(),
                        ))?
                )
            },
            _ => Err(e),
        },
    }
        .with_context(|| format!(
            "unable to set mtime on '{}'",
            &default_branch_ref.display(),
        ))?;
    Ok(())
}