Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Fetch now uses progress events
Baptiste Daroussin committed 11 years ago
commit 1d7712b07aaab2bae5d8d8d44199071cce2057c8
parent ecab741
6 files changed +209 -22
modified libpkg/backup.c
@@ -91,6 +91,7 @@ copy_database(sqlite3 *src, sqlite3 *dst, const char *name)
	done = total = 0;
	start = time(NULL);

+
	pkg_emit_progress_start("Backing up");
	do {
		ret = sqlite3_backup_step(b, NPAGES);

@@ -109,12 +110,11 @@ copy_database(sqlite3 *src, sqlite3 *dst, const char *name)
		/* Callout no more than once a second */
		if (elapsed < time(NULL) - start) {
			elapsed = time(NULL) - start;
-
			pkg_emit_fetching(name, total, done, elapsed);
+
			pkg_emit_progress_tick(done, total);
		}
	} while(done < total);

	ret = sqlite3_backup_finish(b);
-
	pkg_emit_fetching(name, total, done, time(NULL) - start); 

	sqlite3_exec(dst, "PRAGMA main.locking_mode=NORMAL;"
			   "BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
modified libpkg/fetch.c
@@ -534,6 +534,8 @@ pkg_fetch_file_to_fd(struct pkg_repo *repo, const char *url, int dest, time_t *t
		sz = st.size;
	}

+
	pkg_emit_fetch_begin(url);
+
	pkg_emit_progress_start(NULL);
	begin_dl = time(NULL);
	while (done < sz) {
		time_t	now;
@@ -548,10 +550,11 @@ pkg_fetch_file_to_fd(struct pkg_repo *repo, const char *url, int dest, time_t *t
		}

		done += r;
+

		now = time(NULL);
		/* Only call the callback every second */
		if (now > last || done == sz) {
-
			pkg_emit_fetching(url, sz, done, (now - begin_dl));
+
			pkg_emit_progress_tick(done, sz);
			last = now;
		}
	}
@@ -561,6 +564,7 @@ pkg_fetch_file_to_fd(struct pkg_repo *repo, const char *url, int dest, time_t *t
		retcode = EPKG_FATAL;
		goto cleanup;
	}
+
	pkg_emit_fetch_finished(url);

	if (strcmp(u->scheme, "ssh") != 0 && ferror(remote)) {
		pkg_emit_error("%s: %s", url, fetchLastErrString);
modified libpkg/pkg.h.in
@@ -1372,6 +1372,8 @@ typedef enum {
	PKG_EVENT_UPGRADE_BEGIN,
	PKG_EVENT_UPGRADE_FINISHED,
	PKG_EVENT_FETCHING,
+
	PKG_EVENT_FETCH_BEGIN,
+
	PKG_EVENT_FETCH_FINISHED,
	PKG_EVENT_UPDATE_ADD,
	PKG_EVENT_UPDATE_REMOVE,
	PKG_EVENT_INTEGRITYCHECK_BEGIN,
@@ -1431,9 +1433,6 @@ struct pkg_event {
		} e_upd_remove;
		struct {
			const char *url;
-
			off_t total;
-
			off_t done;
-
			time_t elapsed;
		} e_fetching;
		struct {
			struct pkg *pkg;
modified libpkg/pkg_event.c
@@ -112,16 +112,20 @@ pipeevent(struct pkg_event *ev)
		    ev->e_upd_remove.total
		    );
		break;
-
	case PKG_EVENT_FETCHING:
-
		sbuf_printf(msg, "{ \"type\": \"INFO_FETCH\", "
+
	case PKG_EVENT_FETCH_BEGIN:
+
		sbuf_printf(msg, "{ \"type\": \"INFO_FETCH_BEGIN\", "
		    "\"data\": { "
-
		    "\"url\": \"%s\", "
-
		    "\"fetched\": %" PRId64 ", "
-
		    "\"total\": %" PRId64
+
		    "\"url\": \"%s\" "
+
		    "}}",
+
		    sbuf_json_escape(buf, ev->e_fetching.url)
+
		    );
+
		break;
+
	case PKG_EVENT_FETCH_FINISHED:
+
		sbuf_printf(msg, "{ \"type\": \"INFO_FETCH_FINISHED\", "
+
		    "\"data\": { "
+
		    "\"url\": \"%s\" "
		    "}}",
-
		    sbuf_json_escape(buf, ev->e_fetching.url),
-
		    ev->e_fetching.done,
-
		    ev->e_fetching.total
+
		    sbuf_json_escape(buf, ev->e_fetching.url)
		    );
		break;
	case PKG_EVENT_INSTALL_BEGIN:
@@ -469,15 +473,23 @@ pkg_emit_already_installed(struct pkg *p)
}

void
-
pkg_emit_fetching(const char *url, off_t total, off_t done, time_t elapsed)
+
pkg_emit_fetch_begin(const char *url)
+
{
+
	struct pkg_event ev;
+

+
	ev.type = PKG_EVENT_FETCH_BEGIN;
+
	ev.e_fetching.url = url;
+

+
	pkg_emit_event(&ev);
+
}
+

+
void
+
pkg_emit_fetch_finished(const char *url)
{
	struct pkg_event ev;

-
	ev.type = PKG_EVENT_FETCHING;
+
	ev.type = PKG_EVENT_FETCH_FINISHED;
	ev.e_fetching.url = url;
-
	ev.e_fetching.total = total;
-
	ev.e_fetching.done = done;
-
	ev.e_fetching.elapsed = elapsed;

	pkg_emit_event(&ev);
}
modified libpkg/private/event.h
@@ -33,7 +33,8 @@ void pkg_emit_error(const char *fmt, ...);
void pkg_emit_notice(const char *fmt, ...);
void pkg_emit_errno(const char *func, const char *arg);
void pkg_emit_already_installed(struct pkg *p);
-
void pkg_emit_fetching(const char *url, off_t total, off_t done, time_t elapsed);
+
void pkg_emit_fetch_begin(const char *url);
+
void pkg_emit_fetch_finished(const char *url);
void pkg_emit_update_add(int total, int done);
void pkg_emit_update_remove(int total, int done);
void pkg_emit_install_begin(struct pkg *p);
modified src/event.c
@@ -55,14 +55,89 @@
#include "pkg.h"
#include "pkgcli.h"

+
#define STALL_TIME 5
+

struct sbuf *messages = NULL;

static char *progress_message = NULL;
static struct sbuf *msg_buf = NULL;
static int last_progress_percent = -1;
-
static const int max_slots = 30;
static bool progress_alarm = false;
static bool progress_started = false;
+
static bool progress_debit = false;
+
static int64_t last_tick = 0;
+
static int64_t stalled;
+
static int64_t bytes_per_second;
+
static int64_t last_update;
+
static time_t begin = 0;
+

+
/* units for format_size */
+
static const char *unit_SI[] = { " ", "k", "M", "G", "T", };
+
static const char *unit_IEC[] = { "  ", "Ki", "Mi", "Gi", "Ti", };
+

+
static void
+
format_rate_IEC(char *buf, int size, off_t bytes)
+
{
+
	int i;
+

+
	bytes *= 100;
+
	for (i = 0; bytes >= 100*1000 && unit_IEC[i][0] != 'T'; i++)
+
		bytes = (bytes + 512) / 1024;
+
	if (i == 0) {
+
		i++;
+
		bytes = (bytes + 512) / 1024;
+
	}
+
	snprintf(buf, size, "%3lld.%1lld%s%s",
+
	    (long long) (bytes + 5) / 100,
+
	    (long long) (bytes + 5) / 10 % 10,
+
	    unit_IEC[i],
+
	    i ? "B" : " ");
+
}
+

+
static void
+
format_size_IEC(char *buf, int size, off_t bytes)
+
{
+
	int i;
+

+
	for (i = 0; bytes >= 10000 && unit_IEC[i][0] != 'T'; i++)
+
		bytes = (bytes + 512) / 1024;
+
	snprintf(buf, size, "%4lld%s%s",
+
	    (long long) bytes,
+
	    unit_IEC[i],
+
	    i ? "B" : " ");
+
}
+

+
static void
+
format_rate_SI(char *buf, int size, off_t bytes)
+
{
+
        int i;
+

+
        bytes *= 100;
+
        for (i = 0; bytes >= 100*1000 && unit_SI[i][0] != 'T'; i++)
+
                bytes = (bytes + 500) / 1000;
+
        if (i == 0) {
+
                i++;
+
                bytes = (bytes + 500) / 1000;
+
        }
+
        snprintf(buf, size, "%3lld.%1lld%s%s",
+
            (long long) (bytes + 5) / 100,
+
            (long long) (bytes + 5) / 10 % 10,
+
            unit_SI[i],
+
            i ? "B" : " ");
+
}
+

+
static void
+
format_size_SI(char *buf, int size, off_t bytes)
+
{
+
        int i;
+

+
        for (i = 0; bytes >= 10000 && unit_SI[i][0] != 'T'; i++)
+
                bytes = (bytes + 500) / 1000;
+
        snprintf(buf, size, "%4lld%s%s",
+
            (long long) bytes,
+
            unit_SI[i],
+
            i ? "B" : " ");
+
}

static void
print_status_end(struct sbuf *msg)
@@ -264,7 +339,7 @@ event_sandboxed_get_string(pkg_sandbox_cb func, char **result, int64_t *len,
static void
progress_alarm_handler(int signo)
{
-
	if (max_slots != last_progress_percent && progress_alarm && progress_started) {
+
	if (progress_alarm && progress_started) {
		last_progress_percent = -1;
		alarm(1);
	}
@@ -285,6 +360,13 @@ static void
draw_progressbar(int64_t current, int64_t total)
{
        int percent;
+
	int64_t transferred;
+
	time_t now;
+
	char buf[10];
+
	int64_t bytes_left;
+
	int cur_speed;
+
	int64_t elapsed;
+
	int hours, minutes, seconds;

	percent =  current * 100 / total;

@@ -292,6 +374,69 @@ draw_progressbar(int64_t current, int64_t total)
		last_progress_percent = percent;

		printf("\r%s: %d%%", progress_message, percent);
+
		if (progress_debit) {
+
			now = time(NULL);
+
			transferred = current - last_tick;
+
			last_tick = current;
+
			bytes_left = total - current;
+
			if (bytes_left > 0) {
+
				elapsed = (now > last_update) ? now - last_update : 0;
+
			} else {
+
				elapsed = now - begin;
+
			}
+

+
			if (elapsed != 0)
+
				cur_speed = (transferred / elapsed);  
+
			else
+
				cur_speed = transferred;
+

+
#define AGE_FACTOR 0.9
+
			if (bytes_per_second != 0) {
+
				bytes_per_second = (bytes_per_second * AGE_FACTOR) +
+
					(cur_speed * (1.0 - AGE_FACTOR));
+
			} else {
+
				bytes_per_second = cur_speed;
+
			}
+

+
			format_size_IEC(buf, sizeof(buf), current);
+
			printf(" %s", buf);
+

+
			format_rate_SI(buf, sizeof(buf), transferred);
+
			printf(" %s/s", buf);
+

+
			if (!transferred)
+
				stalled += elapsed;
+
			else
+
				stalled = 0;
+

+
			if (stalled >= STALL_TIME)
+
				printf(" - stalled -");
+
			else if (bytes_per_second == 0 && bytes_left)
+
				printf("   --:-- ETA");
+
			else {
+
				if (bytes_left > 0)
+
					seconds = bytes_left / bytes_per_second;
+
				else
+
					seconds = elapsed;
+

+
				hours = seconds / 3600;
+
				seconds -= hours * 3600;
+
				minutes = seconds / 60;
+
				seconds -= minutes * 60;
+

+
				if (hours != 0) {
+
					printf("%02d:%02d:%0d", hours, minutes, seconds);
+
				} else {
+
					printf("   %02d:%02d", minutes, seconds);
+
				}
+

+
				if (bytes_left > 0) {
+
					printf(" ETA");
+
				} else {
+
					printf("    ");
+
				}
+
			}
+
		}
		fflush(stdout);
	}
	if (current >= total) {
@@ -316,6 +461,8 @@ event_callback(void *data, struct pkg_event *ev)
	struct pkg *pkg = NULL, *pkg_new, *pkg_old;
	int *debug = data;
	struct pkg_event_conflict *cur_conflict;
+
	const char *filename;
+

	if (msg_buf == NULL) {
		msg_buf = sbuf_new_auto();
	}
@@ -358,6 +505,27 @@ event_callback(void *data, struct pkg_event *ev)
		if (ev->e_upd_remove.total == ev->e_upd_remove.done)
			printf("\n");
		break;
+
	case PKG_EVENT_FETCH_BEGIN:
+
		if (quiet)
+
			break;
+
		filename = strrchr(ev->e_fetching.url, '/');
+
		if (filename != NULL) {
+
			filename++;
+
		} else {
+
			/*
+
			 * We failed at being smart, so display
+
			 * the entire url.
+
			 */
+
			filename = ev->e_fetching.url;
+
		}
+
		print_status_begin(msg_buf);
+
		progress_debit = true;
+
		sbuf_printf(msg_buf, "Fetching %s", filename);
+

+
		break;
+
	case PKG_EVENT_FETCH_FINISHED:
+
		progress_debit = false;
+
		break;
	case PKG_EVENT_INSTALL_BEGIN:
		if (quiet)
			break;
@@ -581,6 +749,9 @@ event_callback(void *data, struct pkg_event *ev)
				progress_message = strdup(sbuf_data(msg_buf));
			}
			last_progress_percent = -1;
+
			last_tick = 0;
+
			begin = last_update = time(NULL);
+
			bytes_per_second = 0;
			if (isatty(STDOUT_FILENO)) {
				progress_started = true;
			}