Fetches the bytes for a table of repository files (as produced by
repo_check()), writing each into a per-session temp directory or a
persistent on-disk cache, and fills in file_location for every file it
successfully retrieves. For Dryad (stash:download endpoint), GitHub
(zipball) and GitLab (archive.zip), a whole-repo archive download is used
instead of one HTTP request per file. None of these archives reports its
size in advance, so the size is estimated from the listed file sizes: an
archive with no listed sizes, or an estimate above twice
max_download_size, is not used, and a download that grows past twice
max_download_size is stopped. A repo whose archive is not used or fails
falls back to file-by-file fetching automatically, as do all other hosts.
Usage
download_repo_files(
files,
max_file_size = 100,
max_download_size = 500,
max_files_per_repo = Inf,
repo_file_counts = NULL,
zip_timeout_s = 120,
cache = FALSE,
skip_on_api_limit = FALSE,
pb = NULL
)Arguments
- files
a data.frame of files (as returned by
repo_check()'stable): needsrepo_url,file_url, andfile_pathorfile_name- max_file_size
largest single file to download, in MB
- max_download_size
largest total cached footprint per repository, in MB
- max_files_per_repo
largest file COUNT a single repository may have before it is refused outright (same
"gated"reporting as the size caps above), defaultInf(no cap). Unlikemax_file_size/max_download_size, this catches a repo whose FILE COUNT (not byte size) makes it impractical to process one file at a time – confirmed live 2026-09-07 against a real Zenodo record (SAPFLUXNET, ~4000 files) whose per-file classification and full-content read (in data_check, downstream of this function) took hours and multiple GB of memory for a single paper's repository.- repo_file_counts
optional named vector/table,
repo_url-> TRUE total row count for that repo in the caller's FULL listing, before any filtering to "still need downloading".fileshere is routinely a filtered subset (data_check()/code_check() only pass rows that are wanted and not yet on disk), solength(idx)for a repo withinfilesundercounts its real size – confirmed live 2026-09-09: the SAME SAPFLUXNET record above (~4000 files total) had undermax_files_per_repo"still need downloading" rows on one run, so the gate never fired, and several hundred individual files were then requested from a host that was, at the time, answering every one with a persistent (not transient) 403 – each retried independently, compounding into a multi-hour stall with no single wait long enough to look like the real problem. When a repo's URL is not a name in this vector (e.g. NULL, the default, for a caller that has not been updated to pass it), falls back tolength(idx)exactly as before.- zip_timeout_s
timeout (seconds) for a whole-repo zip download attempt before falling back to file-by-file fetching
- cache
if
TRUE, write into the lasting cache (seerepo_cache_dir(); survives across sessions, never cleared automatically — seerepo_cache_clear()); ifFALSE(default), write into a per-session temp directory that R removes on exit- skip_on_api_limit
if
FALSE(the default), a download that hits a host-confirmed exhausted rate limit (a 429 whose response carriesRateLimit-Remaining: 0/X-RateLimit-Remaining: 0and a parseable reset time — currently known to apply to Dryad, Zenodo, GitHub, and GitLab; other hosts do not expose this and are unaffected either way) waits for the host's own stated reset before retrying, however long that is — appropriate for an unattended corpus build, where completeness matters more than wall-clock time. SetTRUEto give up on that file immediately instead: it is recorded in the"failed"attribute with an"API rate limit exhausted: "-prefixed message, filterable from every other kind of failure, so a caller can re-run later (once the quota has reset) targeting only those specific files rather than waiting inline. An ordinary transient refusal (a 429 without a confirmed exhausted-quota signal, a 403/5xx) still retries with ordinary backoff regardless of this setting — it only changes what happens once a real quota exhaustion is confirmed.- pb
an optional progress bar object (see
pb()), ticked as files download
Value
files with file_location filled in for every file retrieved
(unchanged, i.e. NA, for files that were skipped or failed), and three
attributes: "gated" (data.frame: repo_url, message — repositories
refused outright by the size caps), "oversize_skipped" (data.frame:
repo_url, file_name, file_size — individual files skipped under
max_file_size), and "failed" (data.frame: repo_url, file_name,
file_url, paper_id, error — files whose download was attempted but
errored, e.g. a transient network failure, or — when skip_on_api_limit = TRUE and the host confirmed it — an exhausted API rate limit; see
skip_on_api_limit. file_url is carried along so a caller can point
someone at the file directly instead of re-deriving the link. paper_id
is files$paper_id[i] when files carries that column (e.g. a
paperlist batch), NA otherwise — lets a caller attribute a failure back
to the paper it belongs to without re-joining on repo_url).
Details
Two independent size gates apply: max_file_size skips oversize files
individually (the rest of the repository still downloads); max_download_size
is a budget on the repository's TOTAL cached footprint (already-cached plus
newly-downloaded), not on a single run's increment — already-cached files are
kept for free, then the smallest still-missing files are added until the next
one would exceed the budget, so re-running never grows a repository's cache
past the budget and the canonical "files we ever download" set is fixed.
Examples
# \donttest{
if (online("raw.githubusercontent.com")) {
files <- data.frame(
repo_url = "https://github.com/scienceverse/metacheck",
file_url = "https://raw.githubusercontent.com/scienceverse/metacheck/main/DESCRIPTION",
file_name = "DESCRIPTION", file_path = "DESCRIPTION", file_size = 3000)
# kept in this session's temporary folder (cache = FALSE)
dl <- download_repo_files(files)
dl$file_location
}
#> Downloading https://github.com/scienceverse/metacheck as zip (1 file)...
#> [1] "/tmp/RtmpNCKKS0/metacheck-repo-files/github.com_scienceverse_metacheck/DESCRIPTION"
# }
