Show progress during downloads
This commit is contained in:
parent
f08449ccbd
commit
21ecd106ed
2 changed files with 47 additions and 8 deletions
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue