<pre style='margin:0'>
Landon Fuller (landonf) pushed a commit to branch master
in repository macports-base.
</pre>
<p><a href="https://github.com/macports/macports-base/commit/da3524e8a3006a9b9a2370b66fa91bb554dd768b">https://github.com/macports/macports-base/commit/da3524e8a3006a9b9a2370b66fa91bb554dd768b</a></p>
<pre style="white-space: pre; background: #F8F8F8">The following commit(s) were added to refs/heads/master by this push:
<span style='display:block; white-space:pre;color:#404040;'> new da3524e Basic target progress bar support (#150)
</span>da3524e is described below
<span style='display:block; white-space:pre;color:#808000;'>commit da3524e8a3006a9b9a2370b66fa91bb554dd768b
</span>Author: Landon Fuller <landonf@macports.org>
AuthorDate: Tue Feb 11 10:35:44 2020 -0700
<span style='display:block; white-space:pre;color:#404040;'> Basic target progress bar support (#150)
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> - Add callback event support for monitoring the progress of SystemCmd.
</span><span style='display:block; white-space:pre;color:#404040;'> - Use SystemCmd events to implement basic progress bar support for a subset of targets (including build).
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> Closes: https://trac.macports.org/ticket/15939
</span>---
src/macports1.0/macports.tcl | 10 +-
src/package1.0/portarchivefetch.tcl | 2 +-
src/pextlib1.0/system.c | 364 +++++++++++++++++++++++++++++++++---
src/port1.0/Makefile.in | 2 +-
src/port1.0/portbuild.tcl | 3 +-
src/port1.0/portconfigure.tcl | 15 +-
src/port1.0/portdestroot.tcl | 2 +-
src/port1.0/portfetch.tcl | 2 +-
src/port1.0/portprogress.tcl | 117 ++++++++++++
src/port1.0/porttest.tcl | 3 +-
src/port1.0/portutil.tcl | 56 ++++--
11 files changed, 516 insertions(+), 60 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/macports1.0/macports.tcl b/src/macports1.0/macports.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 620b21b..62841c1 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/macports1.0/macports.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/macports1.0/macports.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1440,9 +1440,13 @@ proc macports::worker_init {workername portpath porturl portbuildpath options va
</span> foreach priority $macports::ui_priorities {
$workername alias ui_$priority ui_$priority
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- # add the UI progress call-back
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[info exists macports::ui_options(progress_download)]} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- $workername alias ui_progress_download $macports::ui_options(progress_download)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # add the UI progress call-backs (or a no-op alias, if unavailable)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach pname {progress_download progress_generic} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[info exists macports::ui_options($pname)]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $workername alias ui_$pname $macports::ui_options($pname)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $workername alias ui_$pname return -level 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span> }
# notifications callback
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/package1.0/portarchivefetch.tcl b/src/package1.0/portarchivefetch.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 4791134..2bf4945 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/package1.0/portarchivefetch.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/package1.0/portarchivefetch.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -196,7 +196,7 @@ proc portarchivefetch::fetchfiles {args} {
</span> if {$portverbose eq "yes"} {
lappend fetch_options "--progress"
lappend fetch_options "builtin"
<span style='display:block; white-space:pre;background:#ffe0e0;'>- } elseif {[llength [info commands ui_progress_download]] > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span> lappend fetch_options "--progress"
lappend fetch_options "ui_progress_download"
}
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/pextlib1.0/system.c b/src/pextlib1.0/system.c
</span><span style='display:block; white-space:pre;color:#808080;'>index c043dd3..6f32bb8 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/pextlib1.0/system.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/pextlib1.0/system.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -49,7 +49,9 @@
</span> #include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <assert.h>
</span> #include <fcntl.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdbool.h>
</span> #include <stdlib.h>
#include <string.h>
#include <unistd.h>
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -79,6 +81,40 @@ extern char **environ;
</span> #define _PATH_DEVNULL "/dev/null"
#endif
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_TYPE_KEY "type"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_PID_KEY "pid"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_TYPE_EXEC "exec"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_TYPE_EXIT "exit"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_TYPE_STDIN "stdin"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_STDIN_LINE_KEY "line"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_EXIT_STATUS_KEY "exit_status"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_SIGNALED "signaled"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_SIGNAL_ID_KEY "signal_id"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_SIGNAL_MSG_KEY "signal_msg"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_EXITED "exited"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_EXITED_CODE_KEY "exit_code"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_IOERR "ioerr"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_EXIT_IOERR_ERRNO_KEY "io_errno"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSEVENT_EXIT_IOERR_MSG_KEY "io_message"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct SystemCmd_Callback {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Interp *interp; /**< interpreter */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *procs; /**< list of callback proc(s) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *pid; /**< child process pid, or NULL if child has not yet been executed */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Commonly used event keys and values */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *type_key; /**< cached event type dictionary key */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *pid_key; /**< cached event pid dictionary key */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *stdin_type; /**< cached stdin event type */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *stdin_line_key; /**< cached stdin line dictionary key */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} SystemCmd_Callback;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> static int check_sandboxing(Tcl_Interp *interp, char **sandbox_exec_path, char **profilestr)
{
Tcl_Obj *tcl_result;
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -104,12 +140,150 @@ static int check_sandboxing(Tcl_Interp *interp, char **sandbox_exec_path, char *
</span> return 1;
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+static int SystemCmd_Callback_Create(Tcl_Interp *interp, SystemCmd_Callback **cb)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback *result;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((result = malloc(sizeof(*result))) == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_SetResult(interp, strerror(errno), TCL_STATIC);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *result = (struct SystemCmd_Callback) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .interp = interp,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .procs = Tcl_NewListObj(0, NULL),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .type_key = Tcl_NewStringObj(SYSEVENT_TYPE_KEY, -1),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .pid_key = Tcl_NewStringObj(SYSEVENT_PID_KEY, -1),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .pid = NULL,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .stdin_type = Tcl_NewStringObj(SYSEVENT_TYPE_STDIN, -1),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .stdin_line_key = Tcl_NewStringObj(SYSEVENT_STDIN_LINE_KEY, -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_IncrRefCount(result->procs);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_IncrRefCount(result->type_key);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_IncrRefCount(result->pid_key);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_IncrRefCount(result->stdin_type);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_IncrRefCount(result->stdin_line_key);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *cb = result;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_OK;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void SystemCmd_Callback_Free(SystemCmd_Callback *cb)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DecrRefCount(cb->procs);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DecrRefCount(cb->type_key);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DecrRefCount(cb->pid_key);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DecrRefCount(cb->stdin_type);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DecrRefCount(cb->stdin_line_key);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cb->pid != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DecrRefCount(cb->pid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(cb);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int SystemCmd_Callback_Append(SystemCmd_Callback *cb, Tcl_Obj *callbackProc)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return Tcl_ListObjAppendElement(cb->interp, cb->procs, callbackProc);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int SystemCmd_Callback_NumProcs(SystemCmd_Callback *cb)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int status;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int len;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((status = Tcl_ListObjLength(cb->interp, cb->procs, &len)) != TCL_OK) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* We allocate this explicitly as a list; the type should not change */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Panic("SystemCmd: callbacks has non-list type");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return len;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static bool SystemCmd_Callback_Enabled(SystemCmd_Callback *cb)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (SystemCmd_Callback_NumProcs(cb) > 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void SystemCmd_Callback_SetPid(SystemCmd_Callback *cb, pid_t pid)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cb->pid != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DecrRefCount(cb->pid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cb->pid = Tcl_NewWideIntObj(pid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_IncrRefCount(cb->pid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int SystemCmd_Callback_Invoke(SystemCmd_Callback *cb, Tcl_Obj *event)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj **procs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int numProcs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_ListObjGetElements(cb->interp, cb->procs, &numProcs, &procs);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for (int i = 0; i < numProcs; i++) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *objv[] = { procs[i], event };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int status;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = Tcl_EvalObjv(cb->interp, (sizeof(objv)/sizeof(objv[0])), objv, TCL_EVAL_GLOBAL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (status != TCL_OK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return status;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_OK;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static Tcl_Obj *SystemCmd_Event_Create(SystemCmd_Callback *cb, Tcl_Obj *type)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *event = Tcl_NewDictObj();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ assert(cb->pid != NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DictObjPut(cb->interp, event, cb->type_key, type);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DictObjPut(cb->interp, event, cb->pid_key, cb->pid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_IncrRefCount(event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return event;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void SystemCmd_Event_Release(Tcl_Obj *event)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DecrRefCount(event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void SystemCmd_Event_SetExitType(SystemCmd_Callback *cb, Tcl_Obj *event, const char *exit_type)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DictObjPut(cb->interp, event, Tcl_NewStringObj(SYSEVENT_EXIT_STATUS_KEY,-1), Tcl_NewStringObj(exit_type, -1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void SystemCmd_Event_SetExitCode(SystemCmd_Callback *cb, Tcl_Obj *event, int exit_code)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DictObjPut(cb->interp, event, Tcl_NewStringObj(SYSEVENT_EXITED_CODE_KEY,-1), Tcl_NewIntObj(exit_code));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void SystemCmd_Event_SetLine(SystemCmd_Callback *cb, Tcl_Obj *event, Tcl_Obj *line)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DictObjPut(cb->interp, event, cb->stdin_line_key, line);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void SystemCmd_Event_SetIOError(SystemCmd_Callback *cb, Tcl_Obj *event, int error)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DictObjPut(cb->interp, event, Tcl_NewStringObj(SYSEVENT_EXIT_IOERR_ERRNO_KEY, -1), Tcl_NewIntObj(error));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DictObjPut(cb->interp, event, Tcl_NewStringObj(SYSEVENT_EXIT_IOERR_MSG_KEY, -1), Tcl_NewStringObj(strerror(error), -1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void SystemCmd_Event_SetSignaled(SystemCmd_Callback *cb, Tcl_Obj *event, int signal)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DictObjPut(cb->interp, event, Tcl_NewStringObj(SYSEVENT_SIGNAL_ID_KEY,-1), Tcl_NewStringObj(Tcl_SignalId(signal), -1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DictObjPut(cb->interp, event, Tcl_NewStringObj(SYSEVENT_SIGNAL_MSG_KEY,-1), Tcl_NewStringObj(Tcl_SignalMsg(signal), -1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> static volatile sig_atomic_t interrupted_by = 0;
static void handle_sigint(int s) {
interrupted_by = s;
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/* usage: system ?-notty? ?-nodup? ?-nice value? ?-W path? command */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* usage: system ?-callback proc? ?-notty? ?-nodup? ?-nice value? ?-W path? command */
</span> int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *args[7];
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -118,7 +292,8 @@ int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span> char *sandbox_exec_path = NULL;
char *profilestr = NULL;
FILE *pdes;
<span style='display:block; white-space:pre;background:#ffe0e0;'>- int fdset[2], nullfd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int fdset[2] = { -1, -1 };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int nullfd;
</span> int ret;
int osetsid = 0;
int odup = 1; /* redirect stdin/stdout/stderr by default */
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -127,39 +302,69 @@ int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span> pid_t pid;
uid_t euid;
Tcl_Obj *tcl_result;
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback *callback;
</span> int read_failed = 0;
int status;
int i;
if (objc < 2) {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_WrongNumArgs(interp, 1, objv, "?-notty? ?-nice value? ?-W path? command");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_WrongNumArgs(interp, 1, objv, "?-callback proc? ?-notty? ?-nice value? ?-W path? command");
</span> return TCL_ERROR;
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((status = SystemCmd_Callback_Create(interp, &callback)) != TCL_OK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return status;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> cmdstring = Tcl_GetString(objv[objc - 1]);
for (i = 1; i < objc - 1; i++) {
char *arg = Tcl_GetString(objv[i]);
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (strcmp(arg, "-notty") == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (strcmp(arg, "-callback") == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (++i >= objc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_WrongNumArgs(interp, 1, objv, "proc");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_Free(callback);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((status = SystemCmd_Callback_Append(callback, objv[i])) != TCL_OK) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_Free(callback);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return status;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (strcmp(arg, "-notty") == 0) {
</span> osetsid = 1;
} else if (strcmp(arg, "-nodup") == 0) {
odup = 0;
} else if (strcmp(arg, "-nice") == 0) {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- i++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (++i >= objc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_WrongNumArgs(interp, 1, objv, "value");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_Free(callback);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> if (Tcl_GetIntFromObj(interp, objv[i], &oniceval) != TCL_OK) {
Tcl_SetResult(interp, "invalid value for -nice", TCL_STATIC);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_Free(callback);
</span> return TCL_ERROR;
}
} else if (strcmp(arg, "-W") == 0) {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- i++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (++i >= objc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_WrongNumArgs(interp, 1, objv, "path");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_Free(callback);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> if ((path = Tcl_GetString(objv[i])) == NULL) {
Tcl_SetResult(interp, "invalid value for -W", TCL_STATIC);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_Free(callback);
</span> return TCL_ERROR;
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (strcmp(arg, "--") == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span> } else {
tcl_result = Tcl_NewStringObj("bad option ", -1);
Tcl_AppendObjToObj(tcl_result, Tcl_NewStringObj(arg, -1));
Tcl_SetObjResult(interp, tcl_result);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_Free(callback);
</span> return TCL_ERROR;
}
}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -181,6 +386,7 @@ int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span> if (odup) {
if (pipe(fdset) != 0) {
Tcl_SetResult(interp, strerror(errno), TCL_STATIC);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_Free(callback);
</span> return TCL_ERROR;
}
}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -213,6 +419,7 @@ int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span> case 0: /* child */
if (odup) {
close(fdset[0]);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ fdset[0] = -1;
</span>
if ((nullfd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
_exit(1);
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -278,11 +485,26 @@ int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span> exit(128);
/*NOTREACHED*/
default: /* parent */
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Must be done before creating any events from the callback context */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_SetPid(callback, pid);
</span> break;
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Inform the callback of our exec event */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (SystemCmd_Callback_Enabled(callback)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *event;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ event = SystemCmd_Event_Create(callback, Tcl_NewStringObj(SYSEVENT_TYPE_EXEC,-1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = SystemCmd_Callback_Invoke(callback, event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_Release(event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (status != TCL_OK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto cleanup;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> if (odup) {
close(fdset[1]);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ fdset[1] = -1;
</span>
/* read from simulated popen() pipe */
read_failed = 0;
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -292,64 +514,147 @@ int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span> size_t linesz = 0;
ssize_t linelen;
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = TCL_OK;
</span> while ((linelen = getline(&line, &linesz, pdes)) > 0) {
/* replace '\n' if it exists */
if (line[linelen - 1] == '\n') {
line[linelen - 1] = '\0';
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Provide the line event to our callback */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (SystemCmd_Callback_Enabled(callback)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *event = SystemCmd_Event_Create(callback, callback->stdin_type);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_SetLine(callback, event, Tcl_NewStringObj(line,linelen));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = SystemCmd_Callback_Invoke(callback, event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_Release(event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (status != TCL_OK) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(line);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fclose(pdes);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto cleanup;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> ui_info(interp, "%s", line);
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> free(line);
fclose(pdes);
} else {
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ int error = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Provide the exit event to our callback */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (SystemCmd_Callback_Enabled(callback)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *event = SystemCmd_Event_Create(callback, Tcl_NewStringObj(SYSEVENT_EXITED,-1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_SetExitType(callback, event, SYSEVENT_IOERR);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_SetIOError(callback, event, error);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = SystemCmd_Callback_Invoke(callback, event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_Release(event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (status != TCL_OK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto cleanup;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_SetResult(interp, strerror(error), TCL_STATIC);
</span> read_failed = 1;
<span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_SetResult(interp, strerror(errno), TCL_STATIC);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = TCL_ERROR;
</span> }
}
status = TCL_ERROR;
<span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span> if (wait(&ret) == pid && (WIFEXITED(ret) || WIFSIGNALED(ret)) && !read_failed) {
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *event = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Populate common exit event fields */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (SystemCmd_Callback_Enabled(callback)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Determine the exit status type */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *exit_type = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (WIFEXITED(ret)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit_type = SYSEVENT_EXITED;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (WIFSIGNALED(ret) || interrupted_by != 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit_type = SYSEVENT_SIGNALED;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_SetObjResult(interp, Tcl_ObjPrintf("unhandled exit status: %d", ret));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto cleanup;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Populate a new exit event with exit_status and exit_code */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ event = SystemCmd_Event_Create(callback, Tcl_NewStringObj(SYSEVENT_TYPE_EXIT,-1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_SetExitType(callback, event, exit_type);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_SetExitCode(callback, event, WEXITSTATUS(ret));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* Normal exit, and reading from the pipe didn't fail. */
if (WIFEXITED(ret) && WEXITSTATUS(ret) == 0) {
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Report the exit event to our callback */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (event != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = SystemCmd_Callback_Invoke(callback, event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_Release(event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (status != TCL_OK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto cleanup;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> status = TCL_OK;
} else {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_Obj* errorCode;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj *errorCode = Tcl_NewListObj(0, NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_IncrRefCount(errorCode);
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- /* print error */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ui_info(interp, "Command failed: %s", cmdstring);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (WIFEXITED(ret)) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ui_info(interp, "Exit code: %d", WEXITSTATUS(ret));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- } else if(WIFSIGNALED(ret)) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ui_info(interp, "Killed by signal: %d", WTERMSIG(ret));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- errorCode = Tcl_NewListObj(0, NULL);
</span> if (interrupted_by != 0) {
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Add signal keys to our exit event */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (event != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_SetSignaled(callback, event, interrupted_by);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* set errorCode [list POSIX SIG <SIGNAME> <signal descripton>] */
Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewStringObj("POSIX", -1));
Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewStringObj("SIG", -1));
Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewStringObj(Tcl_SignalId(interrupted_by), -1));
Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewStringObj(Tcl_SignalMsg(interrupted_by), -1));
<span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_SetObjErrorCode(interp, errorCode);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_SetObjResult(interp, Tcl_NewStringObj("interrupted by signal", -1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tcl_result = Tcl_NewStringObj("interrupted by signal", -1);
</span> } else if (WIFEXITED(ret)) {
/* set errorCode [list CHILDSTATUS <pid> <code>] */
Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewStringObj("CHILDSTATUS", -1));
<span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewIntObj(pid));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewWideIntObj(pid));
</span> Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewIntObj(WEXITSTATUS(ret)));
Tcl_SetObjErrorCode(interp, errorCode);
<span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_SetObjResult(interp, Tcl_NewStringObj("command execution failed", -1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tcl_result = Tcl_NewStringObj("command execution failed", -1);
</span> } else if (WIFSIGNALED(ret)) {
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Add signal keys to our exit event */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (event != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_SetSignaled(callback, event, WTERMSIG(ret));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* set errorCode [list CHILDKILLED <pid> <SIGNAME> <signal descripton>] */
Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewStringObj("CHILDKILLED", -1));
<span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewIntObj(pid));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewWideIntObj(pid));
</span> Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewStringObj(Tcl_SignalId(WTERMSIG(ret)), -1));
Tcl_ListObjAppendElement(interp, errorCode, Tcl_NewStringObj(Tcl_SignalMsg(WTERMSIG(ret)), -1));
<span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_SetObjErrorCode(interp, errorCode);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_SetObjResult(interp, Tcl_NewStringObj("command execution failed", -1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tcl_result = Tcl_NewStringObj("command execution failed", -1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Report the exit event to our callback */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (event != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = SystemCmd_Callback_Invoke(callback, event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Event_Release(event);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (status != TCL_OK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto cleanup;
</span> }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* print error */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_info(interp, "Command failed: %s", cmdstring);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (WIFEXITED(ret)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_info(interp, "Exit code: %d", WEXITSTATUS(ret));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if(WIFSIGNALED(ret)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_info(interp, "Killed by signal: %d", WTERMSIG(ret));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Set the error result */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_SetObjErrorCode(interp, errorCode);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_SetObjResult(interp, tcl_result);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_DecrRefCount(errorCode);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ status = TCL_ERROR;
</span> }
}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -358,10 +663,13 @@ cleanup:
</span> sigaction(SIGINT, &old_sa_int, NULL);
sigaction(SIGQUIT, &old_sa_quit, NULL);
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (odup) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* Cleanup. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Cleanup. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (fdset[0] >= 0)
</span> close(fdset[0]);
<span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (fdset[1] >= 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ close(fdset[1]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SystemCmd_Callback_Free(callback);
</span> return status;
}
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port1.0/Makefile.in b/src/port1.0/Makefile.in
</span><span style='display:block; white-space:pre;color:#808080;'>index 3ae95fc..f840d98 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port1.0/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port1.0/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -7,7 +7,7 @@ INSTALLDIR= ${TCL_PACKAGE_PATH}/port1.0
</span>
SRCS_AUTOCONF= port_autoconf.tcl
SRCS= port.tcl portchecksum.tcl portconfigure.tcl portextract.tcl \
<span style='display:block; white-space:pre;background:#ffe0e0;'>- portfetch.tcl portmain.tcl portbuild.tcl portpatch.tcl portutil.tcl \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portfetch.tcl portmain.tcl portbuild.tcl portpatch.tcl portprogress.tcl portutil.tcl \
</span> portinstall.tcl portuninstall.tcl portdepends.tcl portdestroot.tcl \
portlint.tcl portclean.tcl porttest.tcl portactivate.tcl portbump.tcl \
portdeactivate.tcl portstartupitem.tcl porttrace.tcl portlivecheck.tcl \
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port1.0/portbuild.tcl b/src/port1.0/portbuild.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 38e1f6c..c00b8a2 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port1.0/portbuild.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port1.0/portbuild.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -32,6 +32,7 @@
</span>
package provide portbuild 1.0
package require portutil 1.0
<span style='display:block; white-space:pre;background:#e0ffe0;'>+package require portprogress 1.0
</span>
set org.macports.build [target_new org.macports.build portbuild::build_main]
target_provides ${org.macports.build} build
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -199,7 +200,7 @@ proc portbuild::build_main {args} {
</span>
set realcmd ${build.cmd}
set build.cmd "${build.cmd}$jobs_suffix"
<span style='display:block; white-space:pre;background:#ffe0e0;'>- command_exec build
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ command_exec -callback portprogress::target_progress_callback build
</span> set build.cmd ${realcmd}
return 0
}
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port1.0/portconfigure.tcl b/src/port1.0/portconfigure.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 8b544c4..6d3dac3 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port1.0/portconfigure.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port1.0/portconfigure.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -32,6 +32,7 @@
</span>
package provide portconfigure 1.0
package require portutil 1.0
<span style='display:block; white-space:pre;background:#e0ffe0;'>+package require portprogress 1.0
</span>
set org.macports.configure [target_new org.macports.configure portconfigure::configure_main]
target_provides ${org.macports.configure} configure
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1522,32 +1523,34 @@ proc portconfigure::configure_main {args} {
</span> global configure.${flags} configure.universal_${flags}
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ set callback [list "-callback" portprogress::target_progress_callback]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> if {[tbool use_autoreconf]} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[catch {command_exec autoreconf} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[catch {command_exec {*}${callback} autoreconf} result]} {
</span> return -code error "[format [msgcat::mc "%s failure: %s"] autoreconf $result]"
}
}
if {[tbool use_automake]} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[catch {command_exec automake} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[catch {command_exec {*}${callback} automake} result]} {
</span> return -code error "[format [msgcat::mc "%s failure: %s"] automake $result]"
}
}
if {[tbool use_autoconf]} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[catch {command_exec autoconf} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[catch {command_exec {*}${callback} autoconf} result]} {
</span> return -code error "[format [msgcat::mc "%s failure: %s"] autoconf $result]"
}
}
if {[tbool use_xmkmf]} {
parse_environment xmkmf
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[catch {command_exec xmkmf} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[catch {command_exec {*}${callback} xmkmf} result]} {
</span> return -code error "[format [msgcat::mc "%s failure: %s"] xmkmf $result]"
}
parse_environment xmkmf
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[catch {command_exec "cd ${worksrcpath} && make Makefiles" -varprefix xmkmf} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[catch {command_exec {*}${callback} "cd ${worksrcpath} && make Makefiles" -varprefix xmkmf} result]} {
</span> return -code error "[format [msgcat::mc "%s failure: %s"] "make Makefiles" $result]"
}
} elseif {[tbool use_configure]} {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1637,7 +1640,7 @@ proc portconfigure::configure_main {args} {
</span> }
# Execute the command (with the new environment).
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[catch {command_exec configure} result]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[catch {command_exec {*}${callback} configure} result]} {
</span> global configure.dir
if {[file exists ${configure.dir}/config.log]} {
ui_error "[format [msgcat::mc "Failed to configure %s, consult %s/config.log"] [option subport] ${configure.dir}]"
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port1.0/portdestroot.tcl b/src/port1.0/portdestroot.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 35c5f80..c863dce 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port1.0/portdestroot.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port1.0/portdestroot.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -121,7 +121,7 @@ proc portdestroot::destroot_start {args} {
</span> }
proc portdestroot::destroot_main {args} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- command_exec destroot
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ command_exec -callback portprogress::target_progress_callback destroot
</span> return 0
}
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port1.0/portfetch.tcl b/src/port1.0/portfetch.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 7abac19..6eccec7 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port1.0/portfetch.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port1.0/portfetch.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -536,7 +536,7 @@ proc portfetch::fetchfiles {args} {
</span> if {$portverbose eq "yes"} {
lappend fetch_options "--progress"
lappend fetch_options "builtin"
<span style='display:block; white-space:pre;background:#ffe0e0;'>- } elseif {[llength [info commands ui_progress_download]] > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span> lappend fetch_options "--progress"
lappend fetch_options "ui_progress_download"
}
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port1.0/portprogress.tcl b/src/port1.0/portprogress.tcl
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..f0165e7
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port1.0/portprogress.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,117 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Copyright (c) 2019-2020 The MacPorts Project
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# All rights reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Redistribution and use in source and binary forms, with or without
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# modification, are permitted provided that the following conditions
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# are met:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# 1. Redistributions of source code must retain the above copyright
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# notice, this list of conditions and the following disclaimer.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# 2. Redistributions in binary form must reproduce the above copyright
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# notice, this list of conditions and the following disclaimer in the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# documentation and/or other materials provided with the distribution.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# 3. Neither the name of Apple Inc. nor the names of its contributors
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# may be used to endorse or promote products derived from this software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# without specific prior written permission.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# POSSIBILITY OF SUCH DAMAGE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package provide portprogress 1.0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require portutil 1.0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require Pextlib 1.0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace eval portprogress {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # The time in milliseconds to wait before we switch our progress bar from
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # determinate to indeterminate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable indeterminate_threshold 10000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # The time (in milliseconds since epoch) since our progress callback last
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # produced a determinate progress update.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable indeterminate_timer 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # If our progress callback should issue indeterminate progress updates
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable indeterminate yes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # ninja ([<completed tasks>/<pending tasks>])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable ninja_line_re {^\[([1-9][0-9]*)/([1-9][0-9]*)\].*}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # cmake makefiles ([<percentage>%])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable cmake_line_re {^\[\s*([1-9][0-9]*)%\].*}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# A SystemCmd callback that parses common target progress formats to display
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# a progress bar
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc portprogress::target_progress_callback {event} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ global portverbose
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable indeterminate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable indeterminate_timer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable indeterminate_threshold
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable ninja_line_re
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable cmake_line_re
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {${portverbose}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch -- [dict get $event type] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exec {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set indeterminate yes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set indeterminate_timer 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_progress_generic start
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ stdin {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set line [dict get $event line]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Try to parse the build line
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set determinate_match no
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set cur 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set total 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # ninja ([<completed tasks>/<pending tasks>])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[regexp $ninja_line_re ${line} -> cur total]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set determinate_match yes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # cmake makefiles ([<percentage>%])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } elseif {[regexp $cmake_line_re ${line} -> cur]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set total 100
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set determinate_match yes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # No match
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set cur 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set total 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {${determinate_match}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set indeterminate no
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set indeterminate_timer [clock milliseconds]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } elseif {!${indeterminate}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set time_last $indeterminate_timer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set time_now [clock milliseconds]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set time_diff [expr { $time_now - $time_last }]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {${time_diff} >= ${indeterminate_threshold}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set indeterminate yes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {${determinate_match} || ${indeterminate}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_progress_generic update ${cur} ${total}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_progress_generic finish
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port1.0/porttest.tcl b/src/port1.0/porttest.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 816c158..c8ce4b6 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port1.0/porttest.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port1.0/porttest.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -3,6 +3,7 @@
</span>
package provide porttest 1.0
package require portutil 1.0
<span style='display:block; white-space:pre;background:#e0ffe0;'>+package require portprogress 1.0
</span>
set org.macports.test [target_new org.macports.test porttest::test_main]
target_provides ${org.macports.test} test
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -32,7 +33,7 @@ proc porttest::test_start {args} {
</span> proc porttest::test_main {args} {
global subport test.run
if {[tbool test.run]} {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- command_exec test
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ command_exec -callback portprogress::target_progress_callback test
</span> } else {
return -code error [format [msgcat::mc "%s has no tests turned on. see 'test.run' in portfile(7)"] $subport]
}
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port1.0/portutil.tcl b/src/port1.0/portutil.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index d5c4ec4..2883a66 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port1.0/portutil.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port1.0/portutil.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -368,33 +368,55 @@ proc command_string {command} {
</span> }
# Given a command name, execute it with the options.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-# command_exec command [-notty] [-varprefix variable_prefix] [command_prefix [command_suffix]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# command_exec [-notty] [-callback proc] [-varprefix variable_prefix] command [command_prefix [command_suffix]]
</span> # command name of the command
# variable_prefix name of the variable prefix to use (defaults to command)
# command_prefix additional command prefix (typically pipe command)
# command_suffix additional command suffix (typically redirection)
<span style='display:block; white-space:pre;background:#ffe0e0;'>-proc command_exec {command args} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set varprefix "${command}"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc command_exec {args} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set callback ""
</span> set notty ""
set command_prefix ""
set command_suffix ""
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[llength $args] > 0} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[lindex $args 0] eq "-notty"} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set notty "-notty"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set args [lrange $args 1 end]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while {[llength $args] > 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch -glob -- [lindex $args 0] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ -notty {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set notty "-notty"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set args [lrange $args 1 end]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ -callback {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set callback [lrange $args 0 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set args [lrange $args 2 end]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ -varprefix {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set varprefix [lindex $args 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set args [lrange $args 2 end]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ -* {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return -code error "unknown option [lindex $args 0]"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ -- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set args [lrange $args 1 end]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ default {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span> }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[lindex $args 0] eq "-varprefix"} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set varprefix [lindex $args 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set args [lrange $args 2 end]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[llength $args] == 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return -code error "Missing command argument"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[llength $args] > 0} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set command_prefix [lindex $args 0]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if {[llength $args] > 1} {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- set command_suffix [lindex $args 1]
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set command [lindex $args 0]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set varprefix "${command}"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[llength $args] > 1} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set command_prefix [lindex $args 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {[llength $args] > 2} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set command_suffix [lindex $args 2]
</span> }
}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -453,7 +475,7 @@ proc command_exec {command args} {
</span> # Call the command.
set fullcmdstring "$command_prefix $cmdstring $command_suffix"
ui_info "Executing: $fullcmdstring"
<span style='display:block; white-space:pre;background:#ffe0e0;'>- set code [catch {system {*}$notty {*}$nice $fullcmdstring} result]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set code [catch {system {*}$notty {*}$callback {*}$nice $fullcmdstring} result]
</span> # Save variables in order to re-throw the same error code.
set errcode $::errorCode
set errinfo $::errorInfo
</pre><pre style='margin:0'>
</pre>