From ade8d0b4e9c206ab67dc8ef2006e8070011aae83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Mon, 17 Jun 2013 17:13:14 +0300 Subject: [PATCH] cache: implement progress bar (ref #1170) --- src/apk_database.h | 3 ++- src/apk_io.h | 3 ++- src/cache.c | 29 +++++++++++++++++++++++++---- src/commit.c | 7 ++++--- src/database.c | 14 +++++++++----- src/io.c | 11 +++++++++-- 6 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/apk_database.h b/src/apk_database.h index 02ba196..03a0751 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -226,7 +226,8 @@ unsigned int apk_db_get_pinning_mask_repos(struct apk_database *db, unsigned sho int apk_db_cache_active(struct apk_database *db); int apk_cache_download(struct apk_database *db, struct apk_repository *repo, - struct apk_package *pkg, int verify); + struct apk_package *pkg, int verify, + apk_progress_cb cb, void *cb_ctx); typedef void (*apk_cache_item_cb)(struct apk_database *db, int dirfd, const char *name, diff --git a/src/apk_io.h b/src/apk_io.h index c79a9f5..76165b7 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -98,7 +98,8 @@ struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream); struct apk_bstream *apk_bstream_from_fd_pid(int fd, pid_t pid, int (*translate_status)(int)); struct apk_bstream *apk_bstream_from_file(int atfd, const char *file); struct apk_bstream *apk_bstream_from_fd_url(int atfd, const char *url); -struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to); +struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to, + apk_progress_cb cb, void *cb_ctx); static inline struct apk_bstream *apk_bstream_from_fd(int fd) { diff --git a/src/cache.c b/src/cache.c index f25f05a..babfaa6 100644 --- a/src/cache.c +++ b/src/cache.c @@ -26,13 +26,26 @@ #define CACHE_CLEAN BIT(0) #define CACHE_DOWNLOAD BIT(1) +struct progress { + size_t done, total; + int flags; +}; + +static void progress_cb(void *ctx, size_t bytes_done) +{ + struct progress *prog = (struct progress *) ctx; + apk_print_progress(muldiv(100, prog->done + bytes_done, prog->total) | prog->flags); + prog->flags = 0; +} + static int cache_download(struct apk_database *db) { struct apk_changeset changeset = {}; struct apk_change *change; struct apk_package *pkg; struct apk_repository *repo; - int i, r, ret = 0; + struct progress prog = { 0, 0 }; + int r, ret = 0; r = apk_solver_solve(db, 0, db->world, &changeset); if (r < 0) { @@ -40,8 +53,13 @@ static int cache_download(struct apk_database *db) return r; } - for (i = 0; i < changeset.changes->num; i++) { - change = &changeset.changes->item[i]; + foreach_array_item(change, changeset.changes) { + pkg = change->new_pkg; + if ((pkg != NULL) && !(pkg->repos & db->local_repos)) + prog.total += pkg->size; + } + + foreach_array_item(change, changeset.changes) { pkg = change->new_pkg; if ((pkg == NULL) || (pkg->repos & db->local_repos)) continue; @@ -50,11 +68,14 @@ static int cache_download(struct apk_database *db) if (repo == NULL) continue; - r = apk_cache_download(db, repo, pkg, APK_SIGN_VERIFY_IDENTITY); + prog.flags = APK_PRINT_PROGRESS_FORCE; + r = apk_cache_download(db, repo, pkg, APK_SIGN_VERIFY_IDENTITY, + progress_cb, &prog); if (r) { apk_error(PKG_VER_FMT ": %s", PKG_VER_PRINTF(pkg), apk_error_str(r)); ret++; } + prog.done += pkg->size; } return ret; diff --git a/src/commit.c b/src/commit.c index 8030692..857c7bc 100644 --- a/src/commit.c +++ b/src/commit.c @@ -122,6 +122,7 @@ struct progress { struct apk_stats done; struct apk_stats total; struct apk_package *pkg; + int flags; }; static void progress_cb(void *ctx, size_t pkg_percent) @@ -137,9 +138,8 @@ static void progress_cb(void *ctx, size_t pkg_percent) prog->total.bytes + prog->total.packages); else percent = 0; - if (pkg_percent == 0) - percent |= APK_PRINT_PROGRESS_FORCE; - apk_print_progress(percent); + apk_print_progress(percent | prog->flags); + prog->flags = 0; } static int dump_packages(struct apk_changeset *changeset, @@ -298,6 +298,7 @@ int apk_solver_commit_changeset(struct apk_database *db, if (print_change(db, change, prog.done.changes, prog.total.changes)) { prog.pkg = change->new_pkg; + prog.flags = APK_PRINT_PROGRESS_FORCE; progress_cb(&prog, 0); if (!(apk_flags & APK_SIMULATE)) { diff --git a/src/database.c b/src/database.c index db8bb5e..bdfb5fb 100644 --- a/src/database.c +++ b/src/database.c @@ -624,7 +624,8 @@ int apk_repo_format_item(struct apk_database *db, struct apk_repository *repo, s } int apk_cache_download(struct apk_database *db, struct apk_repository *repo, - struct apk_package *pkg, int verify) + struct apk_package *pkg, int verify, + apk_progress_cb cb, void *cb_ctx) { struct apk_istream *is; struct apk_bstream *bs; @@ -651,10 +652,13 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo, if (apk_flags & APK_SIMULATE) return 0; + if (cb) + cb(cb_ctx, 0); + if (verify != APK_SIGN_NONE) { apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd); bs = apk_bstream_from_url(url); - bs = apk_bstream_tee(bs, db->cache_fd, tmpcacheitem); + bs = apk_bstream_tee(bs, db->cache_fd, tmpcacheitem, cb, cb_ctx); is = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &sctx); r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE, &db->id_cache); apk_sign_ctx_free(&sctx); @@ -662,7 +666,7 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo, is = apk_istream_from_url(url); fd = openat(db->cache_fd, tmpcacheitem, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); if (fd >= 0) { - r = apk_istream_splice(is, fd, APK_SPLICE_ALL, NULL, NULL); + r = apk_istream_splice(is, fd, APK_SPLICE_ALL, cb, cb_ctx); close(fd); } else { r = -errno; @@ -1977,7 +1981,7 @@ static int apk_repository_update(struct apk_database *db, struct apk_repository { int r, verify = (apk_flags & APK_ALLOW_UNTRUSTED) ? APK_SIGN_NONE : APK_SIGN_VERIFY; - r = apk_cache_download(db, repo, NULL, verify); + r = apk_cache_download(db, repo, NULL, verify, NULL, NULL); if (r != 0) apk_error("%s: %s", repo->url, apk_error_str(r)); @@ -2568,7 +2572,7 @@ static int apk_db_unpack_pkg(struct apk_database *db, apk_blob_t b = APK_BLOB_BUF(tmpcacheitem); apk_blob_push_blob(&b, tmpprefix); apk_pkg_format_cache_pkg(b, pkg); - bs = apk_bstream_tee(bs, db->cache_fd, tmpcacheitem); + bs = apk_bstream_tee(bs, db->cache_fd, tmpcacheitem, NULL, NULL); if (bs == NULL) { action = "unable cache package: "; r = -errno; diff --git a/src/io.c b/src/io.c index 667d9aa..20ea28a 100644 --- a/src/io.c +++ b/src/io.c @@ -385,6 +385,8 @@ struct apk_tee_bstream { struct apk_bstream *inner_bs; int fd; size_t size; + apk_progress_cb cb; + void *cb_ctx; }; static apk_blob_t tee_read(void *stream, apk_blob_t token) @@ -394,8 +396,11 @@ static apk_blob_t tee_read(void *stream, apk_blob_t token) apk_blob_t blob; blob = tbs->inner_bs->read(tbs->inner_bs, token); - if (!APK_BLOB_IS_NULL(blob)) + if (!APK_BLOB_IS_NULL(blob)) { tbs->size += write(tbs->fd, blob.ptr, blob.len); + if (tbs->cb) + tbs->cb(tbs->cb_ctx, tbs->size); + } return blob; } @@ -412,7 +417,7 @@ static void tee_close(void *stream, size_t *size) free(tbs); } -struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to) +struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to, apk_progress_cb cb, void *cb_ctx) { struct apk_tee_bstream *tbs; int fd; @@ -435,6 +440,8 @@ struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const ch tbs->inner_bs = from; tbs->fd = fd; tbs->size = 0; + tbs->cb = cb; + tbs->cb_ctx = cb_ctx; return &tbs->bs; }