diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index fd3be0d3..9ed2c676 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -82,19 +82,21 @@ int alpm_logaction(char *fmt, ...); typedef void (*alpm_cb_download)(const char *filename, off_t xfered, off_t total); +typedef void (*alpm_cb_totaldl)(off_t total); /* * Options */ -#define PM_DLFNM_LEN 22 - alpm_cb_log alpm_option_get_logcb(); void alpm_option_set_logcb(alpm_cb_log cb); alpm_cb_download alpm_option_get_dlcb(); void alpm_option_set_dlcb(alpm_cb_download cb); +alpm_cb_totaldl alpm_option_get_totaldlcb(); +void alpm_option_set_totaldlcb(alpm_cb_totaldl cb); + const char *alpm_option_get_root(); int alpm_option_set_root(const char *root); diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index c01dd551..af1cc78b 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -115,6 +115,15 @@ alpm_cb_download SYMEXPORT alpm_option_get_dlcb() return handle->dlcb; } +alpm_cb_totaldl SYMEXPORT alpm_option_get_totaldlcb() +{ + if (handle == NULL) { + pm_errno = PM_ERR_HANDLE_NULL; + return NULL; + } + return handle->totaldlcb; +} + const char SYMEXPORT *alpm_option_get_root() { if (handle == NULL) { @@ -268,6 +277,15 @@ void SYMEXPORT alpm_option_set_dlcb(alpm_cb_download cb) handle->dlcb = cb; } +void SYMEXPORT alpm_option_set_totaldlcb(alpm_cb_totaldl cb) +{ + if (handle == NULL) { + pm_errno = PM_ERR_HANDLE_NULL; + return; + } + handle->totaldlcb = cb; +} + int SYMEXPORT alpm_option_set_root(const char *root) { struct stat st; diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 9c537b14..bec0a6f1 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -39,6 +39,7 @@ typedef struct _pmhandle_t { /* callback functions */ alpm_cb_log logcb; /* Log callback function */ alpm_cb_download dlcb; /* Download callback function */ + alpm_cb_totaldl totaldlcb; /* Total download callback function */ /* filesystem paths */ char *root; /* Root path, default '/' */ diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 2dad8bf7..3dc54d0a 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -811,12 +811,25 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) ALPM_LOG_FUNC; - ASSERT(db_local != NULL, RET_ERR(PM_ERR_DB_NULL, -1)); ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); cachedir = _alpm_filecache_setup(); trans->state = STATE_DOWNLOADING; + /* Total progress - figure out the total download size if required to + * pass to the callback. This function is called once, and it is up to the + * frontend to compute incremental progress. */ + if(handle->totaldlcb) { + off_t total_size = (off_t)0; + /* sum up the download size for each package and store total */ + for(i = trans->packages; i; i = i->next) { + pmsyncpkg_t *sync = i->data; + pmpkg_t *spkg = sync->pkg; + total_size += spkg->download_size; + } + handle->totaldlcb(total_size); + } + /* group sync records by repository and download */ for(i = handle->dbs_sync; i; i = i->next) { pmdb_t *current = i->data; @@ -877,6 +890,11 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) return(0); } + /* clear out value to let callback know we are done */ + if(handle->totaldlcb) { + handle->totaldlcb(0); + } + if(handle->usedelta) { int ret = 0; diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 1942aefd..ff125c36 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -38,6 +38,8 @@ /* download progress bar */ static float rate_last; static off_t xfered_last; +static off_t list_xfered = 0.0; +static off_t list_total = 0.0; static struct timeval initial_time; /* transaction progress bar */ @@ -84,14 +86,15 @@ static float get_update_timediff(int first_call) } /* refactored from cb_trans_progress */ -static void fill_progress(const int percent, const int proglen) +static void fill_progress(const int bar_percent, const int disp_percent, + const int proglen) { const unsigned int hashlen = proglen - 8; - const unsigned int hash = percent * hashlen / 100; + const unsigned int hash = bar_percent * hashlen / 100; static unsigned int lasthash = 0, mouth = 0; unsigned int i; - if(percent == 0) { + if(bar_percent == 0) { lasthash = 0; mouth = 0; } @@ -136,10 +139,12 @@ static void fill_progress(const int percent, const int proglen) } /* print percent after progress bar */ if(proglen > 5) { - printf(" %3d%%", percent); + /* use disp_percent if it is not 0, else show bar_percent */ + int p = disp_percent ? disp_percent : bar_percent; + printf(" %3d%%", p); } - if(percent == 100) { + if(bar_percent == 100) { printf("\n"); } else { printf("\r"); @@ -395,7 +400,7 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent, free(wcstr); /* call refactored fill progress function */ - fill_progress(percent, getcols() - infolen); + fill_progress(percent, percent, getcols() - infolen); if(percent == 100) { alpm_list_t *i = NULL; @@ -410,8 +415,19 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent, } } +/* callback to handle receipt of total download value */ +void cb_dl_total(off_t total) +{ + list_total = total; + /* if we get a 0 value, it means this list has finished downloading, + * so clear out our list_xfered as well */ + if(total == 0) { + list_xfered = 0; + } +} + /* callback to handle display of download progress */ -void cb_dl_progress(const char *filename, off_t xfered, off_t total) +void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) { const int infolen = 50; const int filenamelen = infolen - 27; @@ -420,24 +436,38 @@ void cb_dl_progress(const char *filename, off_t xfered, off_t total) int len, wclen, wcwid, padwid; wchar_t *wcfname; + off_t xfered, total; float rate = 0.0, timediff = 0.0, f_xfered = 0.0; unsigned int eta_h = 0, eta_m = 0, eta_s = 0; - int percent; + int file_percent = 0, total_percent = 0; char rate_size = 'K', xfered_size = 'K'; if(config->noprogressbar) { return; } + /* only use TotalDownload if enabled and we have a callback value */ + if(config->totaldownload && list_total) { + xfered = list_xfered + file_xfered; + total = list_total; + } else { + xfered = file_xfered; + total = file_total; + } + /* this is basically a switch on xfered: 0, total, and * anything else */ - if(xfered == 0) { - /* set default starting values */ - gettimeofday(&initial_time, NULL); - xfered_last = (off_t)0; - rate_last = 0.0; - timediff = get_update_timediff(1); - } else if(xfered == total) { + if(file_xfered == 0) { + /* set default starting values, ensure we only call this once + * if TotalDownload is enabled */ + if(!(config->totaldownload) + || (config->totaldownload && list_xfered == 0)) { + gettimeofday(&initial_time, NULL); + xfered_last = (off_t)0; + rate_last = 0.0; + timediff = get_update_timediff(1); + } + } else if(file_xfered == file_total) { /* compute final values */ struct timeval current_time; float diff_sec, diff_usec; @@ -446,7 +476,7 @@ void cb_dl_progress(const char *filename, off_t xfered, off_t total) diff_sec = current_time.tv_sec - initial_time.tv_sec; diff_usec = current_time.tv_usec - initial_time.tv_usec; timediff = diff_sec + (diff_usec / 1000000.0); - rate = total / (timediff * 1024.0); + rate = xfered / (timediff * 1024.0); /* round elapsed time to the nearest second */ eta_s = (int)(timediff + 0.5); @@ -466,7 +496,17 @@ void cb_dl_progress(const char *filename, off_t xfered, off_t total) xfered_last = xfered; } - percent = (int)((float)xfered) / ((float)total) * 100; + file_percent = (int)((float)file_xfered) / ((float)file_total) * 100; + + if(config->totaldownload && list_total) { + total_percent = (int)((float)list_xfered + file_xfered) / + ((float)list_total) * 100; + + /* if we are at the end, add the completed file to list_xfered */ + if(file_xfered == file_total) { + list_xfered += file_total; + } + } /* fix up time for display */ eta_h = eta_s / 3600; @@ -539,7 +579,7 @@ void cb_dl_progress(const char *filename, off_t xfered, off_t total) free(fname); free(wcfname); - fill_progress(percent, getcols() - infolen); + fill_progress(file_percent, total_percent, getcols() - infolen); return; } diff --git a/src/pacman/callback.h b/src/pacman/callback.h index 28d396e8..2961be84 100644 --- a/src/pacman/callback.h +++ b/src/pacman/callback.h @@ -34,6 +34,8 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent, int howmany, int remain); +/* callback to handle receipt of total download value */ +void cb_dl_total(off_t total); /* callback to handle display of download progress */ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total); diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 0ce9c1e8..7aa1bf69 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -850,6 +850,11 @@ int main(int argc, char *argv[]) cleanup(ret); } + /* set TotalDownload callback if option enabled */ + if(config->totaldownload) { + alpm_option_set_totaldlcb(cb_dl_total); + } + #if defined(HAVE_GETEUID) && !defined(CYGWIN) /* check if we have sufficient permission for the requested operation */ if(myuid > 0 && needs_transaction()) {