[117044] trunk/base/src
cal at macports.org
cal at macports.org
Thu Feb 13 13:46:10 PST 2014
Revision: 117044
https://trac.macports.org/changeset/117044
Author: cal at macports.org
Date: 2014-02-13 13:46:10 -0800 (Thu, 13 Feb 2014)
Log Message:
-----------
base: display a progress indicator for slow downloads
Modified Paths:
--------------
trunk/base/src/macports1.0/macports.tcl
trunk/base/src/package1.0/portarchivefetch.tcl
trunk/base/src/pextlib1.0/curl.c
trunk/base/src/port/port.tcl
trunk/base/src/port1.0/portfetch.tcl
Modified: trunk/base/src/macports1.0/macports.tcl
===================================================================
--- trunk/base/src/macports1.0/macports.tcl 2014-02-13 21:28:21 UTC (rev 117043)
+++ trunk/base/src/macports1.0/macports.tcl 2014-02-13 21:46:10 UTC (rev 117044)
@@ -1276,8 +1276,11 @@
foreach phase $macports::port_phases {
$workername alias ui_${priority}_$phase ui_${priority}_$phase
}
-
}
+ # add the UI progress call-back
+ if {[info exists macports::ui_options(progress_download)]} {
+ $workername alias ui_progress_download $macports::ui_options(progress_download)
+ }
$workername alias ui_prefix ui_prefix
$workername alias ui_channels ui_channels
@@ -1435,7 +1438,7 @@
# @param local one, if the URL is local, zero otherwise
# @return a path to a directory containing the Portfile, or an error code
proc macports::fetch_port {url {local 0}} {
- global macports::portdbpath macports::ui_prefix macports::portverbose
+ global macports::portdbpath macports::ui_prefix macports::portverbose macports::ui_options
set fetchdir [file join $portdbpath portdirs]
file mkdir $fetchdir
@@ -1448,11 +1451,13 @@
} else {
ui_msg "$macports::ui_prefix Fetching port $url"
set fetchfile [file tail $url]
- set verboseflag {}
+ set progressflag {}
if {$macports::portverbose eq {yes}} {
- set verboseflag -v
+ set progressflag "--progress builtin"
+ } elseif {[info exists macports::ui_options(progress_download)]} {
+ set progressflag "--progress ${macports::ui_options(progress_download)}"
}
- if {[catch {eval curl fetch $verboseflag {$url} {[file join $fetchdir $fetchfile]}} result]} {
+ if {[catch {eval curl fetch $progressflag {$url} {[file join $fetchdir $fetchfile]}} result]} {
return -code error "Port remote fetch failed: $result"
}
}
@@ -2262,7 +2267,8 @@
proc mportsync {{optionslist {}}} {
global macports::sources macports::portdbpath macports::rsync_options \
tcl_platform macports::portverbose macports::autoconf::rsync_path \
- macports::autoconf::tar_path macports::autoconf::openssl_path
+ macports::autoconf::tar_path macports::autoconf::openssl_path \
+ macports::ui_options
array set options $optionslist
if {[info exists options(no_reindex)]} {
upvar $options(needed_portindex_var) any_needed_portindex
@@ -2505,12 +2511,14 @@
file mkdir $destdir
- set verboseflag {}
+ set progressflag {}
if {$macports::portverbose eq {yes}} {
- set verboseflag -v
+ set progressflag "--progress builtin"
+ } elseif {[info exists macports::ui_options(progress_download)]} {
+ set progressflag "--progress ${macports::ui_options(progress_download)}"
}
- if {[catch {eval curl fetch $verboseflag {$source} {$tarpath}} error]} {
+ if {[catch {eval curl fetch $progressflag {$source} {$tarpath}} error]} {
ui_error "Fetching $source failed ($error)"
incr numfailed
continue
Modified: trunk/base/src/package1.0/portarchivefetch.tcl
===================================================================
--- trunk/base/src/package1.0/portarchivefetch.tcl 2014-02-13 21:28:21 UTC (rev 117043)
+++ trunk/base/src/package1.0/portarchivefetch.tcl 2014-02-13 21:46:10 UTC (rev 117044)
@@ -187,7 +187,11 @@
lappend fetch_options "--ignore-ssl-cert"
}
if {$portverbose eq "yes"} {
- lappend fetch_options "-v"
+ lappend fetch_options "--progress"
+ lappend fetch_options "builtin"
+ } elseif {[llength [info commands ui_progress_download]] > 0} {
+ lappend fetch_options "--progress"
+ lappend fetch_options "ui_progress_download"
}
set sorted no
Modified: trunk/base/src/pextlib1.0/curl.c
===================================================================
--- trunk/base/src/pextlib1.0/curl.c 2014-02-13 21:28:21 UTC (rev 117043)
+++ trunk/base/src/pextlib1.0/curl.c 2014-02-13 21:46:10 UTC (rev 117044)
@@ -56,6 +56,7 @@
#define _CURL_CONNECTION_TIMEOUT ((long)(30)) /* 30 seconds */
#define _CURL_MINIMUM_XFER_SPEED ((long)1024) /* 1KB/sec */
#define _CURL_MINIMUM_XFER_TIMEOUT ((long)(60)) /* 1 minute */
+#define _CURL_MINIMUM_PROGRESS_INTERVAL ((double)(0.2)) /* 0.2 seconds */
/* ========================================================================= **
* Definitions
@@ -78,6 +79,15 @@
int CurlGetSizeCmd(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]);
int CurlPostCmd(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]);
+typedef struct {
+ Tcl_Interp *interp;
+ const char *proc;
+ double prevcalltime;
+} tcl_callback_t;
+
+static int CurlProgressHandler(tcl_callback_t *callback, double dltotal, double dlnow, double ultotal, double ulnow);
+static void CurlProgressCleanup(tcl_callback_t *callback);
+
void CurlInit(void);
/* ========================================================================= **
@@ -112,7 +122,7 @@
/**
* curl fetch subcommand entry point.
*
- * syntax: curl fetch [-v] [--disable-epsv] [--ignore-ssl-cert] [--remote-time] [-u userpass] [--effective-url lasturlvar] url filename
+ * syntax: curl fetch [--disable-epsv] [--ignore-ssl-cert] [--remote-time] [-u userpass] [--effective-url lasturlvar] [--progress "builtin"|callback] url filename
*
* @param interp current interpreter
* @param objc number of parameters
@@ -133,6 +143,11 @@
int remotetime = 0;
const char* theUserPassString = NULL;
const char* effectiveURLVarName = NULL;
+ tcl_callback_t progressCallback = {
+ .interp = interp,
+ .proc = NULL,
+ .prevcalltime = 0.0
+ };
char* effectiveURL = NULL;
char* userAgent = PACKAGE_NAME "/" PACKAGE_VERSION " libcurl/" LIBCURL_VERSION;
int optioncrsr;
@@ -152,9 +167,7 @@
/* get the option */
const char* theOption = Tcl_GetString(objv[optioncrsr]);
- if (strcmp(theOption, "-v") == 0) {
- noprogress = 0;
- } else if (strcmp(theOption, "--disable-epsv") == 0) {
+ if (strcmp(theOption, "--disable-epsv") == 0) {
useepsv = 0;
} else if (strcmp(theOption, "--ignore-ssl-cert") == 0) {
ignoresslcert = 1;
@@ -196,6 +209,19 @@
theResult = TCL_ERROR;
break;
}
+ } else if (strcmp(theOption, "--progress") == 0) {
+ /* check we also have the parameter */
+ if (optioncrsr < lastoption) {
+ optioncrsr++;
+ noprogress = 0;
+ progressCallback.proc = Tcl_GetString(objv[optioncrsr]);
+ } else {
+ Tcl_SetResult(interp,
+ "curl fetch: --progress option requires a parameter",
+ TCL_STATIC);
+ theResult = TCL_ERROR;
+ break;
+ }
} else {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "curl fetch: unknown option ", theOption, NULL);
@@ -340,6 +366,21 @@
break;
}
+ /* we want/don't want a custom progress function */
+ if (noprogress == 0 && strcmp(progressCallback.proc, "builtin") != 0) {
+ theCurlCode = curl_easy_setopt(theHandle, CURLOPT_PROGRESSDATA, &progressCallback);
+ if (theCurlCode != CURLE_OK) {
+ theResult = SetResultFromCurlErrorCode(interp, theCurlCode);
+ break;
+ }
+
+ theCurlCode = curl_easy_setopt(theHandle, CURLOPT_PROGRESSFUNCTION, CurlProgressHandler);
+ if (theCurlCode != CURLE_OK) {
+ theResult = SetResultFromCurlErrorCode(interp, theCurlCode);
+ break;
+ }
+ }
+
/* we want/don't want to use epsv */
theCurlCode = curl_easy_setopt(theHandle, CURLOPT_FTP_USE_EPSV, useepsv);
if (theCurlCode != CURLE_OK) {
@@ -398,6 +439,11 @@
break;
}
+ /* signal cleanup to the progress callback */
+ if (noprogress == 0 && strcmp(progressCallback.proc, "builtin") != 0) {
+ CurlProgressCleanup(&progressCallback);
+ }
+
/* close the file */
(void) fclose(theFile);
theFile = NULL;
@@ -926,6 +972,8 @@
/**
* curl post postdata url
*
+ * syntax: curl post [--user-agent useragentstring] [--progress "builtin"|callback] postdata url
+ *
* @param interp current interpreter
* @param objc number of parameters
* @param objv parameters
@@ -941,19 +989,80 @@
const char* theURL;
const char* thePostData;
CURLcode theCurlCode;
+ int noprogress = 1;
+ tcl_callback_t progressCallback = {
+ .interp = interp,
+ .proc = NULL,
+ .prevcalltime = 0.0
+ };
+ char* userAgent = PACKAGE_NAME "/" PACKAGE_VERSION " libcurl/" LIBCURL_VERSION;
+ int optioncrsr;
+ int lastoption;
- /* check the number of parameters */
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 1, objv, "postdata url");
+ /* we might have options and then postdata and the url */
+ /* let's process the options first */
+
+ optioncrsr = 2;
+ lastoption = objc - 3;
+ while (optioncrsr <= lastoption) {
+ /* get the option */
+ const char* theOption = Tcl_GetString(objv[optioncrsr]);
+
+ if (strcmp(theOption, "--user-agent") == 0) {
+ /* check we also have the parameter */
+ if (optioncrsr < lastoption) {
+ optioncrsr++;
+ userAgent = Tcl_GetString(objv[optioncrsr]);
+ } else {
+ Tcl_SetResult(interp,
+ "curl post: --user-agent option requires a parameter",
+ TCL_STATIC);
+ theResult = TCL_ERROR;
+ break;
+ }
+ } else if (strcmp(theOption, "--progress") == 0) {
+ /* check we also have the parameter */
+ if (optioncrsr < lastoption) {
+ optioncrsr++;
+ noprogress = 0;
+ progressCallback.proc = Tcl_GetString(objv[optioncrsr]);
+ } else {
+ Tcl_SetResult(interp,
+ "curl post: --progress option requires a parameter",
+ TCL_STATIC);
+ theResult = TCL_ERROR;
+ break;
+ }
+ } else {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "curl post: unknown option ", theOption, NULL);
+ theResult = TCL_ERROR;
+ break;
+ }
+
+ optioncrsr++;
+ }
+
+ if (optioncrsr <= lastoption) {
+ /* something went wrong */
+ break;
+ }
+
+ /* first (second) parameter is -v or the url,
+ second (third) parameter is the file */
+
+ if (objc >= 4) {
+ /* Retrieve the url - it is the last parameter */
+ theURL = Tcl_GetString(objv[objc - 1]);
+
+ /* Retrieve the post data - it's before the url */
+ thePostData = Tcl_GetString(objv[objc - 2]);
+ } else {
+ Tcl_WrongNumArgs(interp, 1, objv, "post [options] postdata file");
theResult = TCL_ERROR;
break;
}
- /* Retrieve the url - it is the last parameter */
- theURL = Tcl_GetString(objv[objc - 1]);
-
- /* Retrieve the post data - it's before the url */
- thePostData = Tcl_GetString(objv[objc - 2]);
/* Open the file (dev/null) */
theFile = fopen("/dev/null", "a");
if (theFile == NULL) {
@@ -1012,6 +1121,13 @@
break;
}
+ /* -A option */
+ theCurlCode = curl_easy_setopt(theHandle, CURLOPT_USERAGENT, userAgent);
+ if (theCurlCode != CURLE_OK) {
+ theResult = SetResultFromCurlErrorCode(interp, theCurlCode);
+ break;
+ }
+
/* set timeout on connections */
theCurlCode = curl_easy_setopt(theHandle, CURLOPT_CONNECTTIMEOUT, _CURL_CONNECTION_TIMEOUT);
if (theCurlCode != CURLE_OK) {
@@ -1047,13 +1163,28 @@
break;
}
- /* we do not want any progress */
- theCurlCode = curl_easy_setopt(theHandle, CURLOPT_NOPROGRESS, 1);
+ /* we want/don't want progress */
+ theCurlCode = curl_easy_setopt(theHandle, CURLOPT_NOPROGRESS, noprogress);
if (theCurlCode != CURLE_OK) {
theResult = SetResultFromCurlErrorCode(interp, theCurlCode);
break;
}
+ /* we want/don't want a custom progress function */
+ if (noprogress == 0 && strcmp(progressCallback.proc, "builtin") != 0) {
+ theCurlCode = curl_easy_setopt(theHandle, CURLOPT_PROGRESSDATA, &progressCallback);
+ if (theCurlCode != CURLE_OK) {
+ theResult = SetResultFromCurlErrorCode(interp, theCurlCode);
+ break;
+ }
+
+ theCurlCode = curl_easy_setopt(theHandle, CURLOPT_PROGRESSFUNCTION, CurlProgressHandler);
+ if (theCurlCode != CURLE_OK) {
+ theResult = SetResultFromCurlErrorCode(interp, theCurlCode);
+ break;
+ }
+ }
+
/* actually perform the POST */
theCurlCode = curl_easy_perform(theHandle);
if (theCurlCode != CURLE_OK) {
@@ -1061,6 +1192,11 @@
break;
}
+ /* signal cleanup to the progress callback */
+ if (noprogress == 0 && strcmp(progressCallback.proc, "builtin") != 0) {
+ CurlProgressCleanup(&progressCallback);
+ }
+
/* close the file */
(void) fclose(theFile);
theFile = NULL;
@@ -1151,3 +1287,141 @@
{
curl_global_init(CURL_GLOBAL_ALL);
}
+
+/* ========================================================================= **
+ * Callback function
+ * ========================================================================= */
+#pragma mark -
+#pragma mark Callback function
+static int CurlProgressHandler(
+ tcl_callback_t *callback,
+ double dltotal,
+ double dlnow,
+ double ultotal,
+ double ulnow)
+{
+ if (dltotal == 0.0 && ultotal == 0.0 && dlnow == 0.0 && ulnow == 0.0) {
+ /*
+ * We have no idea whether this is an up- or download. Do nothing for now.
+ */
+ return 0;
+ }
+
+ enum {
+ UPLOAD,
+ DOWNLOAD
+ } transferType;
+
+ double total, now, speed, curtime;
+
+ if (dltotal != 0.0 || dlnow != 0.0) {
+ /* This is a download */
+ transferType = DOWNLOAD;
+ total = dltotal;
+ now = dlnow;
+ } else {
+ /* This is an upload */
+ transferType = UPLOAD;
+ total = ultotal;
+ now = ulnow;
+ }
+
+ /* Only send updates once a second */
+ curl_easy_getinfo(theHandle, CURLINFO_TOTAL_TIME, &curtime);
+ if ((curtime - callback->prevcalltime) < _CURL_MINIMUM_PROGRESS_INTERVAL) {
+ return 0;
+ }
+
+ if (callback->prevcalltime == 0.0) {
+ /* this is the first time we're calling the callback, call start
+ * subcommand first */
+
+ /*
+ * Command string, a space followed "start", another space and "dl" or
+ * "ul" plus the trailing \0.
+ */
+ char startCommandBuffer[strlen(callback->proc) + (1 + 5) + (1 + 2) + 1];
+ int startLen = 0;
+
+ startLen = snprintf(startCommandBuffer, sizeof(startCommandBuffer), "%s start %s",
+ callback->proc, (transferType == DOWNLOAD) ? "dl" : "ul");
+ if (startLen < 0 || (size_t) startLen >= sizeof(startCommandBuffer)) {
+ /* overflow */
+ fprintf(stderr, "pextlib1.0: buffer overflow in " __FILE__ ":%d. Buffer is: %s\n", __LINE__, startCommandBuffer);
+ abort();
+ }
+
+ if (TCL_ERROR == Tcl_EvalEx(callback->interp, startCommandBuffer, startLen, TCL_EVAL_GLOBAL)) {
+ fprintf(stderr, "curl progress callback failed: %s\n", Tcl_GetStringResult(callback->interp));
+ return 1;
+ }
+ }
+
+ callback->prevcalltime = curtime;
+
+ /* Get the average speed from curl */
+ if (transferType == DOWNLOAD) {
+ curl_easy_getinfo(theHandle, CURLINFO_SPEED_DOWNLOAD, &speed);
+ } else {
+ curl_easy_getinfo(theHandle, CURLINFO_SPEED_UPLOAD, &speed);
+ }
+
+ /*
+ * We need the command string, a space and "update", another space and "dl"
+ * or "ul", three doubles converted to string (see comment below), plus
+ * a space character for separation per argument, so 3 * (1 + LEN_DOUBLE)
+ * plus one character for the null-byte.
+ */
+ char commandBuffer[strlen(callback->proc) + (1 + 6) + (1 + 2) + 3 * (1 + 12) + 1];
+ int len = 0;
+
+ /*
+ * Format numbers using % .6g format specifier so we can always be sure
+ * what the total length will be: .6g tells us we're using at most
+ * 6 significant digits; that means 6 characters, another one for
+ * a possible decimal point, another 4 for e+XX where 00 <= XX <= 99 for
+ * exponents, and another one for a possible sign (or " " for positive
+ * numbers). In total, the maximum length will be 12 per double formatted.
+ */
+ len = snprintf(commandBuffer, sizeof(commandBuffer), "%s update %s % .6g % .6g % .6g",
+ callback->proc, (transferType == DOWNLOAD) ? "dl" : "ul", total, now, speed);
+ if (len < 0 || (size_t) len >= sizeof(commandBuffer)) {
+ /* overflow */
+ fprintf(stderr, "pextlib1.0: buffer overflow in " __FILE__ ":%d. Buffer is: %s\n", __LINE__, commandBuffer);
+ abort();
+ }
+
+ /*
+ * Execute directly rather than compiling to bytecode first - the script is
+ * likely to change in the next call anyway.
+ */
+ if (TCL_ERROR == Tcl_EvalEx(callback->interp, commandBuffer, len, TCL_EVAL_GLOBAL)) {
+ fprintf(stderr, "curl progress callback failed: %s\n", Tcl_GetStringResult(callback->interp));
+ return 1;
+ }
+
+ return 0;
+}
+
+static void CurlProgressCleanup(
+ tcl_callback_t *callback)
+{
+ /*
+ * Transfer complete, signal the progress callback
+ */
+
+ /*
+ * Command string, a space followed "finish" plus the trailing \0.
+ */
+ char commandBuffer[strlen(callback->proc) + (1 + 6) + 1];
+ int len = 0;
+
+ len = snprintf(commandBuffer, sizeof(commandBuffer), "%s finish", callback->proc);
+ if (len < 0 || (size_t) len >= sizeof(commandBuffer)) {
+ /* overflow */
+ fprintf(stderr, "pextlib1.0: buffer overflow in " __FILE__ ":%d. Buffer is: %s\n", __LINE__, commandBuffer);
+ abort();
+ }
+
+ Tcl_EvalEx(callback->interp, commandBuffer, len, TCL_EVAL_GLOBAL);
+}
Modified: trunk/base/src/port/port.tcl
===================================================================
--- trunk/base/src/port/port.tcl 2014-02-13 21:28:21 UTC (rev 117043)
+++ trunk/base/src/port/port.tcl 2014-02-13 21:46:10 UTC (rev 117044)
@@ -34,6 +34,8 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
+package require term::ansi::send
+
source [file join "@macports_tcl_dir@" macports1.0 macports_fastload.tcl]
package require macports
package require Pextlib 1.0
@@ -155,7 +157,7 @@
# Format an integer representing bytes using given units
-proc bytesize {siz {unit {}}} {
+proc bytesize {siz {unit {}} {format {%.3f}}} {
if {$unit == {}} {
if {$siz > 0x40000000} {
set unit "GiB"
@@ -193,7 +195,7 @@
}
}
if {[expr {round($siz)}] != $siz} {
- set siz [format {%.3f} $siz]
+ set siz [format $format $siz]
}
return "$siz $unit"
}
@@ -4787,7 +4789,170 @@
return $exit_status
}
+##
+# Progress callback for downloads executed by macports 1.0.
+#
+# This is essentially a cURL progress callback.
+#
+# @param action
+# One of "start", "update" or "finish", where start will be called
+# before any number of change calls, followed by one call to finish.
+# @param args
+# A list of variadic args that differ for each action.
+# For "start": contains a single argument "ul" or "dl" indicating
+# whether this is an up- or download.
+# For "update": contains the arguments ("ul"|"dl") total now speed where
+# ul/dl are as for start, and total, now and speed are doubles
+# indicating the total transfer size, currently transferred amount and
+# average speed per second in bytes.
+# For "finish": empty.
+proc port_progress_download {action args} {
+ global _port_progress_starttime _port_progress_display_bar
+ switch -nocase -- $action {
+ start {
+ set _port_progress_starttime [clock milliseconds]
+ set _port_progress_display_bar no
+ }
+ update {
+ # the for loop is a simple hack because Tcl 8.4 doesn't have
+ # lassign
+ foreach {type total now speed} $args {
+ if {${_port_progress_display_bar} ne yes} {
+ # check whether we should show a progress bar for this transfer
+ if {[expr {[clock milliseconds] - ${_port_progress_starttime}}] > 500 && ($total == 0 || [expr {$now / $total}] < 0.5)} {
+ # wait 500ms, then, if we don't know the total or we're
+ # not past 50% yet, display a progress bar.
+ set _port_progress_display_bar yes
+ }
+ }
+ if {${_port_progress_display_bar} eq yes} {
+ set barprefix " "
+ if {$total != 0} {
+ set barsuffix [format " speed: %-13s" "[bytesize $speed {} "%.1f"]/s"]
+ progress_bar $now $total 20 $barprefix $barsuffix
+ } else {
+ set barsuffix [format " %-10s speed: %-13s" [bytesize $now {} "%6.1f"] "[bytesize $speed {} "%.1f"]/s"]
+ unprogress_bar $now 20 $barprefix $barsuffix
+ }
+ }
+ }
+ }
+ finish {
+ # erase to start of line
+ ::term::ansi::send::esol
+ # return cursor to start of line
+ puts -nonewline "\r"
+ flush stdout
+ }
+ }
+ return 0
+}
+
+##
+# Draw a progress bar using unicode block drawing characters
+#
+# @param current
+# the current progress value
+# @param total
+# the progress value representing 100%
+# @param halfwidth
+# the half width in characters of the progress bar
+# @param prefix
+# prefix to be printed in front of the progress bar
+# @param suffix
+# suffix to be printed after the progress bar
+proc progress_bar {current total halfwidth {prefix ""} {suffix ""}} {
+ # we use 8 different states per character, so let's multiply the width by
+ # 8 and map the percentage to this range
+ set percent [expr {($current * 100 / $total)}]
+ set progress [expr {int(round(($current * $halfwidth * 8) / $total))}]
+ set fullfields [expr {int($progress / 8)}]
+ set remainder [expr {$progress % 8}]
+
+ # clear the current line
+ set progressbar ""
+ for {set i 0} {$i < $fullfields} {incr i} {
+ # U+2588 FULL BLOCK doesn't match the other blocks in some fonts :/
+ # Use two half blocks instead
+ # Since we use two chars here, make sure to remove a space for each of
+ # those used!
+ append progressbar "\u258c\u258c"
+ }
+
+ if {$remainder == 0 && $fullfields < $halfwidth} {
+ append progressbar " "
+ } elseif {$remainder == 1} {
+ # U+258F LEFT ONE EIGHTH BLOCK
+ append progressbar "\u258f"
+ } elseif {$remainder == 2} {
+ # U+258E LEFT ONE QUARTER BLOCK
+ append progressbar "\u258e"
+ } elseif {$remainder == 3} {
+ # U+258D LEFT THREE EIGHTHS BLOCK
+ append progressbar "\u258d"
+ } elseif {$remainder == 4} {
+ # U+258C LEFT HALF BLOCK
+ append progressbar "\u258c"
+ } elseif {$remainder == 5} {
+ # U+258B LEFT FIVE EIGHTHS BLOCK
+ append progressbar "\u258b"
+ } elseif {$remainder == 6} {
+ # U+258A LEFT THREE QUARTERS BLOCK
+ append progressbar "\u258a"
+ } elseif {$remainder == 7} {
+ # U+2589 LEFT SEVEN EIGHTHS BLOCK
+ append progressbar "\u2589"
+ }
+
+ for {set i [expr {[string length $progressbar]}]} {$i < [expr {2 * $halfwidth}]} {incr i} {
+ append progressbar " "
+ }
+ set percentagesuffix [format " %5.1f %%" $percent]
+
+ puts -nonewline "\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}"
+ flush stdout
+}
+
+##
+# Draw a progress indicator
+#
+# @param current
+# the number of bytes currently downloaded
+# @param halfwidth
+# the half width in characters of the progress indicator
+# @param prefix
+# prefix to be printed in front of the progress indicator
+# @param suffix
+# suffix to be printed after the progress indicator
+proc unprogress_bar {current halfwidth {prefix ""} {suffix ""}} {
+ global _port_progress_unprogressbar_state
+
+ set numstates 4
+
+ if {![info exists _port_progress_unprogressbar_state]} {
+ set _port_progress_unprogressbar_state 0
+ } else {
+ set _port_progress_unprogressbar_state [expr {(${_port_progress_unprogressbar_state} + 1) % $numstates}]
+ }
+
+ # clear the current line
+ set progressbar ""
+
+ for {set i 0} {$i < [expr {2 * $halfwidth}]} {incr i} {
+ if {[expr $i % $numstates] == ${_port_progress_unprogressbar_state}} {
+ # U+2022 BULLET
+ append progressbar "\u2022"
+ } else {
+ append progressbar " "
+ }
+ }
+
+ puts -nonewline "\r${prefix}\[${progressbar}\]${suffix}"
+ flush stdout
+}
+
+
##########################################
# Main
##########################################
@@ -4835,6 +5000,10 @@
exit 1
}
+if {[isatty stdout] && (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne "yes")} {
+ set ui_options(progress_download) port_progress_download
+}
+
# Get arguments remaining after option processing
set remaining_args [lrange $cmd_argv $cmd_argn end]
Modified: trunk/base/src/port1.0/portfetch.tcl
===================================================================
--- trunk/base/src/port1.0/portfetch.tcl 2014-02-13 21:28:21 UTC (rev 117043)
+++ trunk/base/src/port1.0/portfetch.tcl 2014-02-13 21:46:10 UTC (rev 117044)
@@ -502,7 +502,11 @@
lappend fetch_options "--remote-time"
}
if {$portverbose eq "yes"} {
- lappend fetch_options "-v"
+ lappend fetch_options "--progress"
+ lappend fetch_options "builtin"
+ } elseif {[llength [info commands ui_progress_download]] > 0} {
+ lappend fetch_options "--progress"
+ lappend fetch_options "ui_progress_download"
}
set sorted no
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20140213/70da082e/attachment-0001.html>
More information about the macports-changes
mailing list