Reimplement TotalDownload functionality

Add a new totaldlcb callback function to libalpm and make pacman utilize it
when the TotalDownload option is enabled. This callback function is pretty
simple- it is meant to be called once at the beginning of a "list download"
action, and once at the end (with value 0 to indicate the list has been
finished). The frontend is responsible for keeping track of adding
individual file download amounts to the total xfered amount in order to
display some sort of overall progress.

Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Dan McGee 2008-06-01 23:10:30 -05:00
parent 0669c9bfac
commit fe781e4ce4
7 changed files with 107 additions and 21 deletions

View File

@ -82,19 +82,21 @@ int alpm_logaction(char *fmt, ...);
typedef void (*alpm_cb_download)(const char *filename, typedef void (*alpm_cb_download)(const char *filename,
off_t xfered, off_t total); off_t xfered, off_t total);
typedef void (*alpm_cb_totaldl)(off_t total);
/* /*
* Options * Options
*/ */
#define PM_DLFNM_LEN 22
alpm_cb_log alpm_option_get_logcb(); alpm_cb_log alpm_option_get_logcb();
void alpm_option_set_logcb(alpm_cb_log cb); void alpm_option_set_logcb(alpm_cb_log cb);
alpm_cb_download alpm_option_get_dlcb(); alpm_cb_download alpm_option_get_dlcb();
void alpm_option_set_dlcb(alpm_cb_download cb); 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(); const char *alpm_option_get_root();
int alpm_option_set_root(const char *root); int alpm_option_set_root(const char *root);

View File

@ -115,6 +115,15 @@ alpm_cb_download SYMEXPORT alpm_option_get_dlcb()
return handle->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() const char SYMEXPORT *alpm_option_get_root()
{ {
if (handle == NULL) { if (handle == NULL) {
@ -268,6 +277,15 @@ void SYMEXPORT alpm_option_set_dlcb(alpm_cb_download cb)
handle->dlcb = 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) int SYMEXPORT alpm_option_set_root(const char *root)
{ {
struct stat st; struct stat st;

View File

@ -39,6 +39,7 @@ typedef struct _pmhandle_t {
/* callback functions */ /* callback functions */
alpm_cb_log logcb; /* Log callback function */ alpm_cb_log logcb; /* Log callback function */
alpm_cb_download dlcb; /* Download callback function */ alpm_cb_download dlcb; /* Download callback function */
alpm_cb_totaldl totaldlcb; /* Total download callback function */
/* filesystem paths */ /* filesystem paths */
char *root; /* Root path, default '/' */ char *root; /* Root path, default '/' */

View File

@ -811,12 +811,25 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
ALPM_LOG_FUNC; ALPM_LOG_FUNC;
ASSERT(db_local != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
cachedir = _alpm_filecache_setup(); cachedir = _alpm_filecache_setup();
trans->state = STATE_DOWNLOADING; 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 */ /* group sync records by repository and download */
for(i = handle->dbs_sync; i; i = i->next) { for(i = handle->dbs_sync; i; i = i->next) {
pmdb_t *current = i->data; 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); return(0);
} }
/* clear out value to let callback know we are done */
if(handle->totaldlcb) {
handle->totaldlcb(0);
}
if(handle->usedelta) { if(handle->usedelta) {
int ret = 0; int ret = 0;

View File

@ -38,6 +38,8 @@
/* download progress bar */ /* download progress bar */
static float rate_last; static float rate_last;
static off_t xfered_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; static struct timeval initial_time;
/* transaction progress bar */ /* transaction progress bar */
@ -84,14 +86,15 @@ static float get_update_timediff(int first_call)
} }
/* refactored from cb_trans_progress */ /* 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 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; static unsigned int lasthash = 0, mouth = 0;
unsigned int i; unsigned int i;
if(percent == 0) { if(bar_percent == 0) {
lasthash = 0; lasthash = 0;
mouth = 0; mouth = 0;
} }
@ -136,10 +139,12 @@ static void fill_progress(const int percent, const int proglen)
} }
/* print percent after progress bar */ /* print percent after progress bar */
if(proglen > 5) { 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"); printf("\n");
} else { } else {
printf("\r"); printf("\r");
@ -395,7 +400,7 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent,
free(wcstr); free(wcstr);
/* call refactored fill progress function */ /* call refactored fill progress function */
fill_progress(percent, getcols() - infolen); fill_progress(percent, percent, getcols() - infolen);
if(percent == 100) { if(percent == 100) {
alpm_list_t *i = NULL; 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 */ /* 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 infolen = 50;
const int filenamelen = infolen - 27; 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; int len, wclen, wcwid, padwid;
wchar_t *wcfname; wchar_t *wcfname;
off_t xfered, total;
float rate = 0.0, timediff = 0.0, f_xfered = 0.0; float rate = 0.0, timediff = 0.0, f_xfered = 0.0;
unsigned int eta_h = 0, eta_m = 0, eta_s = 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'; char rate_size = 'K', xfered_size = 'K';
if(config->noprogressbar) { if(config->noprogressbar) {
return; 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 /* this is basically a switch on xfered: 0, total, and
* anything else */ * anything else */
if(xfered == 0) { if(file_xfered == 0) {
/* set default starting values */ /* set default starting values, ensure we only call this once
gettimeofday(&initial_time, NULL); * if TotalDownload is enabled */
xfered_last = (off_t)0; if(!(config->totaldownload)
rate_last = 0.0; || (config->totaldownload && list_xfered == 0)) {
timediff = get_update_timediff(1); gettimeofday(&initial_time, NULL);
} else if(xfered == total) { xfered_last = (off_t)0;
rate_last = 0.0;
timediff = get_update_timediff(1);
}
} else if(file_xfered == file_total) {
/* compute final values */ /* compute final values */
struct timeval current_time; struct timeval current_time;
float diff_sec, diff_usec; 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_sec = current_time.tv_sec - initial_time.tv_sec;
diff_usec = current_time.tv_usec - initial_time.tv_usec; diff_usec = current_time.tv_usec - initial_time.tv_usec;
timediff = diff_sec + (diff_usec / 1000000.0); timediff = diff_sec + (diff_usec / 1000000.0);
rate = total / (timediff * 1024.0); rate = xfered / (timediff * 1024.0);
/* round elapsed time to the nearest second */ /* round elapsed time to the nearest second */
eta_s = (int)(timediff + 0.5); 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; 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 */ /* fix up time for display */
eta_h = eta_s / 3600; 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(fname);
free(wcfname); free(wcfname);
fill_progress(percent, getcols() - infolen); fill_progress(file_percent, total_percent, getcols() - infolen);
return; return;
} }

View File

@ -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, void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent,
int howmany, int remain); 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 */ /* callback to handle display of download progress */
void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total); void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total);

View File

@ -850,6 +850,11 @@ int main(int argc, char *argv[])
cleanup(ret); cleanup(ret);
} }
/* set TotalDownload callback if option enabled */
if(config->totaldownload) {
alpm_option_set_totaldlcb(cb_dl_total);
}
#if defined(HAVE_GETEUID) && !defined(CYGWIN) #if defined(HAVE_GETEUID) && !defined(CYGWIN)
/* check if we have sufficient permission for the requested operation */ /* check if we have sufficient permission for the requested operation */
if(myuid > 0 && needs_transaction()) { if(myuid > 0 && needs_transaction()) {