From e3c7e92f1090204ba945c063b7aba3b3b1d8095b Mon Sep 17 00:00:00 2001 From: Aaron Griffin Date: Sun, 4 Feb 2007 01:36:45 +0000 Subject: [PATCH] * unified the progress bars (fill_progress function) * fixed progress output (needs an fflush to move cursor properly) * broke display_targets function out, to display a list of syncpkgs in preparation for a -Qu option * added get_update_time function to deal with progress functions that shouldn't update too fast due to output redraw speeds --- src/pacman/downloadprog.c | 89 ++++++--------------- src/pacman/pacman.c | 6 +- src/pacman/sync.c | 54 +------------ src/pacman/trans.c | 82 ++++++------------- src/pacman/util.c | 162 ++++++++++++++++++++++++++++++++++++++ src/pacman/util.h | 6 ++ 6 files changed, 218 insertions(+), 181 deletions(-) diff --git a/src/pacman/downloadprog.c b/src/pacman/downloadprog.c index 4ea40535..35bbab72 100644 --- a/src/pacman/downloadprog.c +++ b/src/pacman/downloadprog.c @@ -40,58 +40,57 @@ /* progress bar */ static float rate_last; static int xfered_last; -static struct timeval last_time; static struct timeval initial_time; /* pacman options */ extern config_t *config; -#define FILENAME_TRIM_LEN 21 -#define UPDATE_SPEED_SEC 0.1 +#define FILENAME_TRIM_LEN 23 void log_progress(const char *filename, int xfered, int total) { - static unsigned int lasthash = 0, mouth = 0; - unsigned int i, hash; - /* a little hard to conceal easter eggs in open-source software, - * but they're still fun. ;) */ - const unsigned short chomp = alpm_option_get_chomp(); + const int infolen = 50; char *fname, *p; - unsigned int maxcols = getcols(); - unsigned int progresslen = maxcols - 57; - int percent = (int)((float)xfered) / ((float)total) * 100; + struct timeval current_time; float rate = 0.0; unsigned int eta_h = 0, eta_m = 0, eta_s = 0; float total_timediff, timediff; + if(config->noprogressbar) { + return; + } + + int percent = (int)((float)xfered) / ((float)total) * 100; + if(xfered == 0) { set_output_padding(1); /* we need padding from pm_fprintf output */ gettimeofday(&initial_time, NULL); - gettimeofday(&last_time, NULL); xfered_last = 0; rate_last = 0.0; + timediff = get_update_timediff(1); + } else { + timediff = get_update_timediff(0); } - if(config->noprogressbar) { + if(percent > 0 && percent < 100 && !timediff) { + /* only update the progress bar when + * a) we first start + * b) we end the progress + * c) it has been long enough since the last call + */ return; } gettimeofday(¤t_time, NULL); total_timediff = current_time.tv_sec-initial_time.tv_sec + (float)(current_time.tv_usec-initial_time.tv_usec) / 1000000; - timediff = current_time.tv_sec-last_time.tv_sec - + (float)(current_time.tv_usec-last_time.tv_usec) / 1000000; if(xfered == total) { /* compute final values */ rate = (float)total / (total_timediff * 1024); eta_s = (unsigned int)total_timediff; set_output_padding(0); /* shut off padding */ - } else if(timediff < UPDATE_SPEED_SEC) { - /* we avoid computing the ETA on too small periods of time, so that - results are more significant */ - return; } else { rate = (float)(xfered - xfered_last) / (timediff * 1024); rate = (float)(rate + 2*rate_last) / 3; @@ -99,7 +98,6 @@ void log_progress(const char *filename, int xfered, int total) } rate_last = rate; - last_time = current_time; xfered_last = xfered; /* fix up time for display */ @@ -116,61 +114,18 @@ void log_progress(const char *filename, int xfered, int total) fname[FILENAME_TRIM_LEN] = '\0'; } - /* hide the cursor i - prevent flicker - printf("\033[?25l\033[?1c"); - */ - - /* - * DL rate cap, for printf formatting - this should be sane for a while - * if anything we can change to MB/s if we need a higher rate - */ + /* DL rate cap, for printf formatting - this should be sane for a while + * if anything we can change to MB/s if we need a higher rate */ if(rate > 9999.9) { rate = 9999.9; } - printf(" %-*s %6dK %#6.1fK/s %02u:%02u:%02u [", FILENAME_TRIM_LEN, fname, + printf(" %-*s %6dK %#6.1fK/s %02u:%02u:%02u", FILENAME_TRIM_LEN, fname, xfered/1024, rate, eta_h, eta_m, eta_s); free(fname); - hash = (unsigned int)percent*progresslen/100; - for(i = progresslen; i > 0; --i) { - if(chomp) { - if(i > progresslen - hash) { - printf("-"); - } else if(i == progresslen - hash) { - if(lasthash == hash) { - if(mouth) { - printf("\033[1;33mC\033[m"); - } else { - printf("\033[1;33mc\033[m"); - } - } else { - lasthash = hash; - mouth = mouth == 1 ? 0 : 1; - if(mouth) { - printf("\033[1;33mC\033[m"); - } else { - printf("\033[1;33mc\033[m"); - } - } - } else if(i%3 == 0) { - printf("\033[0;37mo\033[m"); - } else { - printf("\033[0;37m \033[m"); - } - } else if(i > progresslen - hash) { - printf("#"); - } else { - printf("-"); - } - } - printf("] %3d%%\r", percent); - - if(percent == 100) { - printf("\n"); - } - fflush(stdout); + fill_progress(percent, getcols() - infolen); return; } diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 7f6f4192..c473227c 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -130,6 +130,7 @@ static void usage(int op, char *myname) printf(_(" -o, --owns query the package that owns \n")); printf(_(" -p, --file query the package file [package] instead of the database\n")); printf(_(" -s, --search search locally-installed packages for matching strings\n")); + printf(_(" -u, --upgrades list all packages that can be upgraded\n")); } else if(op == PM_OP_SYNC) { printf(_("usage: %s {-S --sync} [options] [package]\n"), myname); printf(_("options:\n")); @@ -369,7 +370,10 @@ static int parseargs(int argc, char *argv[]) config->op_q_search = 1; config->flags |= PM_TRANS_FLAG_RECURSE; break; - case 'u': config->op_s_upgrade = 1; break; + case 'u': + config->op_s_upgrade = 1; + /* TODO config->op_q_upgrade = 1; */ + break; case 'v': (config->verbose)++; break; case 'w': config->op_s_downloadonly = 1; diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 09f4587d..0a5ef72b 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -626,60 +626,8 @@ int pacman_sync(alpm_list_t *targets) goto cleanup; } - /* list targets and get confirmation */ if(!(alpm_trans_get_flags() & PM_TRANS_FLAG_PRINTURIS)) { - alpm_list_t *list_install = NULL, *list_remove = NULL; - - char *str; - unsigned long totalsize = 0; - unsigned long totalisize = 0; - double mb, umb; - - for(i = packages; i; i = alpm_list_next(i)) { - pmsyncpkg_t *sync = alpm_list_getdata(i); - pmpkg_t *pkg = alpm_sync_get_package(sync); - const char *pkgname, *pkgver; - - if(alpm_sync_get_type(sync) == PM_SYNC_TYPE_REPLACE) { - alpm_list_t *data = alpm_sync_get_data(sync); - for(j = data; j; j = alpm_list_next(j)) { - pmpkg_t *p = alpm_list_getdata(j); - const char *pkgname = alpm_pkg_get_name(p); - if(!alpm_list_find_str(list_remove, pkgname)) { - list_remove = alpm_list_add(list_remove, strdup(pkgname)); - } - } - } - - pkgname = alpm_pkg_get_name(pkg); - pkgver = alpm_pkg_get_version(pkg); - totalsize += alpm_pkg_get_size(pkg); - totalisize += alpm_pkg_get_isize(pkg); - - asprintf(&str, "%s-%s", pkgname, pkgver); - list_install = alpm_list_add(list_install, str); - } - if(list_remove) { - MSG(NL, "\n"); /* TODO ugly hack. printing a single NL should be easy */ - list_display(_("Remove:"), list_remove); - FREELIST(list_remove); - } - mb = (double)(totalsize / 1048576.0); - umb = (double)(totalisize / 1048576.0); - /* round up to 0.1 */ - if(mb < 0.1) { - mb = 0.1; - } - if(umb > 0 && umb < 0.1) { - umb = 0.1; - } - MSG(NL, "\n"); - list_display(_("Targets:"), list_install); - MSG(NL, _("\nTotal Package Size: %.1f MB\n"), mb); - if(umb > 0) { - MSG(NL, _("Total Installed Size: %.1f MB\n"), umb); - } - FREELIST(list_install); + display_targets(packages); if(config->op_s_downloadonly) { if(config->noconfirm) { diff --git a/src/pacman/trans.c b/src/pacman/trans.c index f2f7113c..e2dcf645 100644 --- a/src/pacman/trans.c +++ b/src/pacman/trans.c @@ -57,58 +57,6 @@ static void retrieve_local(void *data1, void *data2) fputs(_("] 100% LOCAL "), stdout); } -/* refactored from cb_trans_progress */ -/* TODO with a little more work, we may be able to incorporate this - * into the download progress bar as well. */ -static void fill_progress(const int percent, const int proglen) -{ - const unsigned short chomp = alpm_option_get_chomp(); - const unsigned int hashlen = proglen - 8; - const unsigned int hash = percent * hashlen / 100; - unsigned int lasthash = 0, mouth = 0; - unsigned int i; - - printf(" ["); - for(i = hashlen; i > 1; --i) { - /* if special progress bar enabled */ - if(chomp) { - if(i > hashlen - hash) { - printf("-"); - } else if(i == hashlen - hash) { - if(lasthash == hash) { - if(mouth) { - printf("\033[1;33mC\033[m"); - } else { - printf("\033[1;33mc\033[m"); - } - } else { - lasthash = hash; - mouth = mouth == 1 ? 0 : 1; - if(mouth) { - printf("\033[1;33mC\033[m"); - } else { - printf("\033[1;33mc\033[m"); - } - } - } else if(i%3 == 0) { - printf("\033[0;37mo\033[m"); - } else { - printf("\033[0;37m \033[m"); - } - } /* else regular progress bar */ - else if(i > hashlen - hash) { - printf("#"); - } else { - printf("-"); - } - } - printf("] %3d%%\r", percent); - - if(percent == 100) { - printf("\n"); - } -} - /* Callback to handle transaction events */ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) @@ -347,9 +295,11 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, void cb_trans_progress(pmtransprog_t event, char *pkgname, const int percent, const int howmany, const int remain) { + float timediff; + /* size of line to allocate for text printing (e.g. not progressbar) */ const int infolen = 50; - int i, digits, textlen, pkglen, proglen; + int i, digits, textlen, pkglen; char *ptr = NULL; if(config->noprogressbar) { @@ -358,12 +308,22 @@ void cb_trans_progress(pmtransprog_t event, char *pkgname, const int percent, if(percent == 0) { set_output_padding(1); /* turn on output padding with ' ' */ - } else if(percent == 100) { - set_output_padding(0); /* shut it off again */ + timediff = get_update_timediff(1); + } else { + timediff = get_update_timediff(0); + } + + if(percent > 0 && percent < 100 && !timediff) { + /* only update the progress bar when + * a) we first start + * b) we end the progress + * c) it has been long enough since the last call + */ + return; } /* if no pkgname, percent is too high or unchanged, then return */ - if (!pkgname || percent > 100 || percent == prevpercent) { + if(!pkgname || percent == prevpercent) { return; } @@ -403,17 +363,19 @@ void cb_trans_progress(pmtransprog_t event, char *pkgname, const int percent, printf("(%*d/%*d) %s %-*.*s", digits, remain, digits, howmany, ptr, pkglen, pkglen, pkgname); break; - case PM_TRANS_PROGRESS_CONFLICTS_START: printf("(%*d/%*d) %-*s", digits, remain, digits, howmany, textlen, ptr); break; - } /* call refactored fill progress function */ - proglen = getcols() - infolen; - fill_progress(percent, proglen); + fill_progress(percent, getcols() - infolen); + + if(percent >= 100) { + set_output_padding(0); /* restore padding */ + } + } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/util.c b/src/pacman/util.c index 7cff41b7..a30ae617 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -26,6 +26,7 @@ #include #include +#include #include "config.h" #include @@ -258,4 +259,165 @@ void list_display(const char *title, alpm_list_t *list) } } +/* Display a list of transaction targets. + * `pkgs` should be a list of pmsyncpkg_t's, + * retrieved from a transaction object + */ +void display_targets(alpm_list_t *pkgs) +{ + char *str; + alpm_list_t *i, *j; + alpm_list_t *targets = NULL, *to_remove = NULL; + unsigned long totalsize = 0, totalisize = 0, totalrsize = 0; + + for(i = pkgs; i; i = alpm_list_next(i)) { + pmsyncpkg_t *sync = alpm_list_getdata(i); + pmpkg_t *pkg = alpm_sync_get_package(sync); + + /* If this sync record is a replacement, the data member contains + * a list of packages to be removed due to the package that is being + * installed. */ + if(alpm_sync_get_type(sync) == PM_SYNC_TYPE_REPLACE) { + alpm_list_t *to_replace = alpm_sync_get_data(sync); + + for(j = to_replace; j; j = alpm_list_next(j)) { + pmpkg_t *rp = alpm_list_getdata(j); + const char *name = alpm_pkg_get_name(rp); + + if(!alpm_list_find_str(to_remove, name)) { + totalrsize += alpm_pkg_get_isize(rp); + to_remove = alpm_list_add(to_remove, strdup(name)); + } + } + } + + totalsize += alpm_pkg_get_size(pkg); + totalisize += alpm_pkg_get_isize(pkg); + + asprintf(&str, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); + targets = alpm_list_add(targets, str); + } + + if(to_remove) { + MSG(NL, "\n"); /* TODO ugly hack. printing a single NL should be easy */ + list_display(_("Remove:"), to_remove); + FREELIST(to_remove); + + double rmb = (double)(totalrsize) / (1024.0 * 1024.0); + if(rmb > 0) { + if(rmb < 0.1) { + rmb = 0.1; + } + MSG(NL, _("\nTotal Removed Size: %.2f MB\n"), rmb); + } + } + + MSG(NL, "\n"); /* TODO ugly hack. printing a single NL should be easy */ + list_display(_("Targets:"), targets); + + double mb = (double)(totalsize) / (1024.0 * 1024.0); + if(mb < 0.1) { + mb = 0.1; + } + MSG(NL, _("\nTotal Package Size: %.2f MB\n"), mb); + + double umb = (double)(totalisize) / (1024.0 * 1024.0); + if(umb > 0) { + if(umb < 0.1) { + umb = 0.1; + } + MSG(NL, _("Total Installed Size: %.2f MB\n"), umb); + } + + FREELIST(targets); +} + +/* Silly little helper function, determines if the caller needs a visual update + * since the last time this function was called. + * This is made for the two progress bar functions, to prevent flicker + * + * first_call indicates if this is the first time it is called, for + * initialization purposes */ +float get_update_timediff(int first_call) +{ + float retval = 0.0; + static struct timeval last_time = {0}; + struct timeval this_time; + + if(first_call) { + /* always update on the first call */ + retval = 1.0; + } else { + gettimeofday(&this_time, NULL); + + float diff_sec = this_time.tv_sec - last_time.tv_sec; + float diff_usec = this_time.tv_usec - last_time.tv_usec; + + retval = diff_sec + (diff_usec / 1000000.0f); + /*printf("update time: %fs %fus = %f\n", diff_sec, diff_usec, retval);*/ + + if(retval < UPDATE_SPEED_SEC) { + /* maintain the last_time value for the next call */ + return(0.0); + } + } + + /* set the time for the next call */ + gettimeofday(&last_time, NULL); + + return(retval); +} + +/* refactored from cb_trans_progress */ +void fill_progress(const int percent, const int proglen) +{ + const unsigned short chomp = alpm_option_get_chomp(); + const unsigned int hashlen = proglen - 8; + const unsigned int hash = percent * hashlen / 100; + unsigned int lasthash = 0, mouth = 0; + unsigned int i; + + printf(" ["); + for(i = hashlen; i > 1; --i) { + /* if special progress bar enabled */ + if(chomp) { + if(i > hashlen - hash) { + printf("-"); + } else if(i == hashlen - hash) { + if(lasthash == hash) { + if(mouth) { + printf("\033[1;33mC\033[m"); + } else { + printf("\033[1;33mc\033[m"); + } + } else { + lasthash = hash; + mouth = mouth == 1 ? 0 : 1; + if(mouth) { + printf("\033[1;33mC\033[m"); + } else { + printf("\033[1;33mc\033[m"); + } + } + } else if(i%3 == 0) { + printf("\033[0;37mo\033[m"); + } else { + printf("\033[0;37m \033[m"); + } + } /* else regular progress bar */ + else if(i > hashlen - hash) { + printf("#"); + } else { + printf("-"); + } + } + printf("] %3d%%\r", percent); + + if(percent == 100) { + printf("\n"); + } + fflush(stdout); +} + + /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/util.h b/src/pacman/util.h index 37509788..61bf09ee 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -47,6 +47,9 @@ s1[(len)-1] = 0; \ } while(0) +/* update speed for the fill_progress based functions */ +#define UPDATE_SPEED_SEC 0.2f + #define _(str) gettext(str) unsigned int getcols(); int makepath(char *path); @@ -56,6 +59,9 @@ char *strtoupper(char *str); char *strtrim(char *str); int reg_match(char *string, char *pattern); void list_display(const char *title, alpm_list_t *list); +void display_targets(alpm_list_t *pkgs); +float get_update_timediff(int first_call); +void fill_progress(const int percent, const int proglen); #endif /* _PM_UTIL_H */