[pacman-dev] [PATCH 2/3] always notify download callback when finished

Andrew Gregory andrew.gregory.8 at gmail.com
Sun Jan 25 17:29:15 UTC 2015


Move the final call outside of curl's progress callback so that we can
notify our callback of completion even if the download size was unknown
or we encounter an error.  Forces download total >= 0 within the
callback so that it can be used to indicate a download error.

Signed-off-by: Andrew Gregory <andrew.gregory.8 at gmail.com>
---
 lib/libalpm/dload.c   | 34 +++++++++++++++++++++-------------
 src/pacman/callback.c |  8 +++++++-
 2 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
index cae4b7c..677cb64 100644
--- a/lib/libalpm/dload.c
+++ b/lib/libalpm/dload.c
@@ -94,7 +94,7 @@ static int dload_progress_cb(void *file, double dltotal, double dlnow,
 		double UNUSED ultotal, double UNUSED ulnow)
 {
 	struct dload_payload *payload = (struct dload_payload *)file;
-	off_t current_size, total_size, xfer = dlnow, total = dltotal;
+	off_t current_size, xfer = dlnow, total = dltotal > 0.0 ? dltotal : 0;
 
 	/* avoid displaying progress bar for redirects with a body */
 	if(payload->respcode >= 300) {
@@ -119,14 +119,13 @@ static int dload_progress_cb(void *file, double dltotal, double dlnow,
 		return 0;
 	}
 
-	total_size = payload->initial_size + total;
-
-	if(total == 0 || payload->prevprogress == total_size) {
+	/* the initial and final calls are explicitly made elsewhere */
+	if(total == 0 || xfer == 0 || xfer == total) {
 		return 0;
 	}
 
-	/* initialize the progress bar here to avoid displaying it when
-	 * a repo is up to date and nothing gets downloaded */
+	/* initialize the progress callback here to avoid calling it
+	 * when nothing actually gets downloaded */
 	if(payload->prevprogress == 0) {
 		payload->handle->dlcb(payload->remote_name, 0, total);
 	}
@@ -463,6 +462,22 @@ static int curl_download_internal(struct dload_payload *payload,
 
 	/* perform transfer */
 	payload->curlerr = curl_easy_perform(curl);
+	curl_easy_getinfo(curl, CURLINFO_FILETIME, &remote_time);
+	curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &remote_size);
+	curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &bytes_dl);
+	curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &timecond);
+	curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
+
+	if(payload->prevprogress > 0) {
+		/* if we called the callback, notify it that we're done */
+		off_t xfer = bytes_dl, size = remote_size > 0 ? remote_size : bytes_dl;
+		if(payload->curlerr == CURLE_OK && payload->respcode < 400 && xfer == size) {
+			handle->dlcb(payload->remote_name, xfer, size);
+		} else {
+			handle->dlcb(payload->remote_name, -1, -1);
+		}
+	}
+
 	_alpm_log(handle, ALPM_LOG_DEBUG, "curl returned error %d from transfer\n",
 			payload->curlerr);
 
@@ -519,13 +534,6 @@ static int curl_download_internal(struct dload_payload *payload,
 			goto cleanup;
 	}
 
-	/* retrieve info about the state of the transfer */
-	curl_easy_getinfo(curl, CURLINFO_FILETIME, &remote_time);
-	curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &remote_size);
-	curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &bytes_dl);
-	curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &timecond);
-	curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
-
 	if(final_url != NULL) {
 		*final_url = effective_url;
 	}
diff --git a/src/pacman/callback.c b/src/pacman/callback.c
index 0d87fd3..3b3a74f 100644
--- a/src/pacman/callback.c
+++ b/src/pacman/callback.c
@@ -645,7 +645,13 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total)
 
 	const unsigned short cols = getcols();
 
-	if(config->noprogressbar || cols == 0 || file_total == -1) {
+	if(file_total == -1) {
+		/* an error occurred, move to the next line for the error message */
+		putchar('\n');
+		return;
+	}
+
+	if(config->noprogressbar || cols == 0) {
 		if(file_xfered == 0) {
 			printf(_("downloading %s...\n"), filename);
 			fflush(stdout);
-- 
2.2.1


More information about the pacman-dev mailing list