Show progress during downloads

This commit is contained in:
Eelco Dolstra 2015-10-07 17:31:50 +02:00
parent f08449ccbd
commit 21ecd106ed
2 changed files with 47 additions and 8 deletions

View file

@ -6,8 +6,18 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <iostream>
namespace nix { namespace nix {
double getTime()
{
struct timeval tv;
gettimeofday(&tv, 0);
return tv.tv_sec + (tv.tv_usec / 1000000.0);
}
struct Curl struct Curl
{ {
CURL * curl; CURL * curl;
@ -16,6 +26,10 @@ struct Curl
struct curl_slist * requestHeaders; struct curl_slist * requestHeaders;
bool showProgress;
double prevProgressTime{0}, startTime{0};
unsigned int moveBack{1};
static size_t writeCallback(void * contents, size_t size, size_t nmemb, void * userp) static size_t writeCallback(void * contents, size_t size, size_t nmemb, void * userp)
{ {
Curl & c(* (Curl *) userp); Curl & c(* (Curl *) userp);
@ -56,11 +70,30 @@ struct Curl
return realSize; return realSize;
} }
static int progressCallback(void * clientp, double dltotal, double dlnow, double ultotal, double ulnow) int xferInfoCallback(curl_off_t dltotal, curl_off_t dlnow)
{ {
if (showProgress) {
double now = getTime();
if (prevProgressTime <= now - 1) {
string s = (format(" [%1$.0f/%2$.0f KiB, %3$.1f KiB/s]")
% (dlnow / 1024.0)
% (dltotal / 1024.0)
% (now == startTime ? 0 : dlnow / 1024.0 / (now - startTime))).str();
std::cerr << "\e[" << moveBack << "D" << s;
moveBack = s.size();
std::cerr.flush();
prevProgressTime = now;
}
}
return _isInterrupted; return _isInterrupted;
} }
static int xferInfoCallback_(void * userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
Curl & c(* (Curl *) userp);
return c.xferInfoCallback(dltotal, dlnow);
}
Curl() Curl()
{ {
requestHeaders = 0; requestHeaders = 0;
@ -79,8 +112,11 @@ struct Curl
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headerCallback); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headerCallback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *) &curl); curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *) &curl);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallback); curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferInfoCallback_);
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, (void *) &curl);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
showProgress = isatty(STDERR_FILENO);
} }
~Curl() ~Curl()
@ -107,7 +143,16 @@ struct Curl
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, requestHeaders); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, requestHeaders);
if (showProgress) {
std::cerr << (format("downloading %1%... ") % url);
std::cerr.flush();
startTime = getTime();
}
CURLcode res = curl_easy_perform(curl); CURLcode res = curl_easy_perform(curl);
if (showProgress)
//std::cerr << "\e[" << moveBack << "D\e[K\n";
std::cerr << "\n";
checkInterrupt(); checkInterrupt();
if (res == CURLE_WRITE_ERROR && etag == expectedETag) return false; if (res == CURLE_WRITE_ERROR && etag == expectedETag) return false;
if (res != CURLE_OK) if (res != CURLE_OK)
@ -178,11 +223,6 @@ Path downloadFileCached(const string & url, bool unpack)
if (!skip) { if (!skip) {
if (storePath.empty())
printMsg(lvlInfo, format("downloading %1%...") % url);
else
printMsg(lvlInfo, format("checking %1%...") % url);
try { try {
auto res = downloadFile(url, expectedETag); auto res = downloadFile(url, expectedETag);

View file

@ -158,7 +158,6 @@ int main(int argc, char * * argv)
auto actualUri = resolveMirrorUri(state, uri); auto actualUri = resolveMirrorUri(state, uri);
/* Download the file. */ /* Download the file. */
printMsg(lvlInfo, format("downloading %1%...") % actualUri);
auto result = downloadFile(actualUri); auto result = downloadFile(actualUri);
AutoDelete tmpDir(createTempDir(), true); AutoDelete tmpDir(createTempDir(), true);