Commit d2cdc63664daa5fa39c9a6398c33f3724650bfe9

Stefan Sperling 2020-03-18T16:11:32

send pack file download progress information over imsg

diff --git a/got/got.c b/got/got.c
index a3cf252..e4bbfb0 100644
--- a/got/got.c
+++ b/got/got.c
@@ -38,6 +38,7 @@
 #include <paths.h>
 #include <regex.h>
 #include <getopt.h>
+#include <util.h>
 
 #include "got_version.h"
 #include "got_error.h"
@@ -969,10 +970,18 @@ done:
 }
 
 static const struct got_error *
-fetch_progress(void *arg, const char *message)
+fetch_progress(void *arg, const char *message, off_t packfile_size)
 {
-	char *servername = arg;
-	printf("\rserver %s: %s", servername, message);
+	int *did_something = arg;
+	char scaled[FMT_SCALED_STRSIZE];
+	
+	if (message) {
+		printf("\rserver: %s", message);
+		*did_something = 1;
+	} else if (packfile_size > 0 && fmt_scaled(packfile_size, scaled) == 0) {
+		printf("\rfetching... %*s", FMT_SCALED_STRSIZE, scaled);
+		*did_something = 1;
+	}
 	fflush(stdout);
 	return NULL;
 }
@@ -990,6 +999,7 @@ cmd_clone(int argc, char *argv[])
 	struct got_pathlist_entry *pe;
 	struct got_object_id *pack_hash = NULL;
 	int ch, fetchfd = -1;
+	int did_something = 0;
 
 	TAILQ_INIT(&refs);
 	TAILQ_INIT(&symrefs);
@@ -1045,9 +1055,11 @@ cmd_clone(int argc, char *argv[])
 		goto done;
 
 	err = got_fetch_pack(&pack_hash, &refs, &symrefs, fetchfd,
-	    repo, fetch_progress, host);
+	    repo, fetch_progress, &did_something);
 	if (err)
 		goto done;
+	if (did_something)
+		printf("\n");
 
 	err = got_object_id_str(&id_str, pack_hash);
 	if (err)
diff --git a/include/got_fetch.h b/include/got_fetch.h
index e3e0144..773e689 100644
--- a/include/got_fetch.h
+++ b/include/got_fetch.h
@@ -40,7 +40,7 @@ const struct got_error *got_fetch_connect(int *, const char *, const char *,
 
 /* A callback function which gets invoked with progress information to print. */
 typedef const struct got_error *(*got_fetch_progress_cb)(void *,
-    const char *);
+    const char *, off_t);
 
 /*
  * Attempt to fetch a packfile from a server. This pack file will contain
diff --git a/lib/fetch.c b/lib/fetch.c
index 15ecb2b..4936c36 100644
--- a/lib/fetch.c
+++ b/lib/fetch.c
@@ -313,6 +313,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struct got_pathlist_head *refs,
 	const char *repo_path = got_repo_get_path(repo);
 	struct got_pathlist_head have_refs;
 	struct got_pathlist_entry *pe;
+	off_t packfile_size = 0;
 	char *path;
 
 	*pack_hash = NULL;
@@ -385,13 +386,16 @@ got_fetch_pack(struct got_object_id **pack_hash, struct got_pathlist_head *refs,
 		goto done;
 	}
 
+	packfile_size = 0;
 	while (!done) {
 		struct got_object_id *id = NULL;
 		char *refname = NULL;
 		char *server_progress = NULL;
+		off_t packfile_size_cur;
 
 		err = got_privsep_recv_fetch_progress(&done,
-		    &id, &refname, symrefs, &server_progress, &ibuf);
+		    &id, &refname, symrefs, &server_progress,
+		    &packfile_size_cur, &ibuf);
 		if (err != NULL)
 			goto done;
 		if (done)
@@ -405,13 +409,19 @@ got_fetch_pack(struct got_object_id **pack_hash, struct got_pathlist_head *refs,
 			while ((s = strsep(&s0, "\r")) != NULL) {
 				if (*s == '\0')
 					continue;
-				err = progress_cb(progress_arg, s);
+				err = progress_cb(progress_arg, s, 0);
 				if (err)
 					break;
 			}
 			free(server_progress);
 			if (err)
 				goto done;
+		} else if (packfile_size_cur != packfile_size) {
+			err = progress_cb(progress_arg, NULL,
+			    packfile_size_cur);
+			if (err)
+				break;
+			packfile_size = packfile_size_cur;
 		}
 	}
 	if (waitpid(pid, &status, 0) == -1) {
diff --git a/lib/got_lib_privsep.h b/lib/got_lib_privsep.h
index 5b5d6f6..c557473 100644
--- a/lib/got_lib_privsep.h
+++ b/lib/got_lib_privsep.h
@@ -113,6 +113,7 @@ enum got_imsg_type {
 	GOT_IMSG_FETCH_SYMREFS,
 	GOT_IMSG_FETCH_REF,
 	GOT_IMSG_FETCH_SERVER_PROGRESS,
+	GOT_IMSG_FETCH_DOWNLOAD_PROGRESS,
 	GOT_IMSG_FETCH_DONE,
 	GOT_IMSG_IDXPACK_REQUEST,
 	GOT_IMSG_IDXPACK_DONE,
@@ -269,6 +270,12 @@ struct got_imsg_fetch_ref {
 	/* Followed by reference name in remaining data of imsg buffer. */
 };
 
+/* Structure for GOT_IMSG_FETCH_DOWNLOAD_PROGRESS data. */
+struct got_imsg_fetch_download_progress {
+	/* Number of packfile data bytes downloaded so far. */
+	off_t packfile_bytes;
+};
+
 /* Structure for GOT_IMSG_PACKIDX. */
 struct got_imsg_packidx {
 	size_t len;
@@ -359,9 +366,11 @@ const struct got_error *got_privsep_send_fetch_ref(struct imsgbuf *,
     struct got_object_id *, const char *);
 const struct got_error *got_privsep_send_fetch_server_progress(struct imsgbuf *,
     const char *, size_t);
+const struct got_error *got_privsep_send_fetch_download_progress(struct imsgbuf *,
+    off_t);
 const struct got_error *got_privsep_recv_fetch_progress(int *,
     struct got_object_id **, char **, struct got_pathlist_head *,
-    char **, struct imsgbuf *);
+    char **, off_t *, struct imsgbuf *);
 const struct got_error *got_privsep_send_fetch_done(struct imsgbuf *,
     struct got_object_id);
 const struct got_error *got_privsep_get_imsg_obj(struct got_object **,
diff --git a/lib/privsep.c b/lib/privsep.c
index 6aabc63..96c8759 100644
--- a/lib/privsep.c
+++ b/lib/privsep.c
@@ -588,6 +588,17 @@ got_privsep_send_fetch_server_progress(struct imsgbuf *ibuf, const char *msg,
 }
 
 const struct got_error *
+got_privsep_send_fetch_download_progress(struct imsgbuf *ibuf, off_t bytes)
+{
+	if (imsg_compose(ibuf, GOT_IMSG_FETCH_DOWNLOAD_PROGRESS, 0, 0, -1,
+	    &bytes, sizeof(bytes)) == -1)
+		return got_error_from_errno(
+		    "imsg_compose FETCH_DOWNLOAD_PROGRESS");
+
+	return flush_imsg(ibuf);
+}
+
+const struct got_error *
 got_privsep_send_fetch_done(struct imsgbuf *ibuf, struct got_object_id hash)
 {
 	if (imsg_compose(ibuf, GOT_IMSG_FETCH_DONE, 0, 0, -1,
@@ -600,7 +611,7 @@ got_privsep_send_fetch_done(struct imsgbuf *ibuf, struct got_object_id hash)
 const struct got_error *
 got_privsep_recv_fetch_progress(int *done, struct got_object_id **id,
     char **refname, struct got_pathlist_head *symrefs, char **server_progress,
-    struct imsgbuf *ibuf)
+    off_t *packfile_size, struct imsgbuf *ibuf)
 {
 	const struct got_error *err = NULL;
 	struct imsg imsg;
@@ -720,6 +731,13 @@ got_privsep_recv_fetch_progress(int *done, struct got_object_id **id,
 			}
 		}
 		break;
+	case GOT_IMSG_FETCH_DOWNLOAD_PROGRESS:
+		if (datalen < sizeof(*packfile_size)) {
+			err = got_error(GOT_ERR_PRIVSEP_MSG);
+			break;
+		}
+		memcpy(packfile_size, imsg.data, sizeof(*packfile_size));
+		break;
 	case GOT_IMSG_FETCH_DONE:
 		*id = malloc(sizeof(**id));
 		if (*id == NULL) {
diff --git a/libexec/got-fetch-pack/got-fetch-pack.c b/libexec/got-fetch-pack/got-fetch-pack.c
index 17c6151..14fb915 100644
--- a/libexec/got-fetch-pack/got-fetch-pack.c
+++ b/libexec/got-fetch-pack/got-fetch-pack.c
@@ -774,6 +774,9 @@ fetch_pack(int fd, int packfd, struct got_object_id *packid,
 			goto done;
 		}
 		packsz += w;
+		err = got_privsep_send_fetch_download_progress(ibuf, packsz);
+		if (err)
+			goto done;
 	}
 	if (lseek(packfd, 0, SEEK_SET) == -1) {
 		err = got_error_from_errno("lseek");