Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package vis for openSUSE:Factory checked in 
at 2023-02-28 12:49:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/vis (Old)
 and      /work/SRC/openSUSE:Factory/.vis.new.31432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "vis"

Tue Feb 28 12:49:41 2023 rev:8 rq:1068161 version:0.8

Changes:
--------
--- /work/SRC/openSUSE:Factory/vis/vis.changes  2022-11-02 12:47:41.681736509 
+0100
+++ /work/SRC/openSUSE:Factory/.vis.new.31432/vis.changes       2023-02-28 
12:49:52.484916358 +0100
@@ -1,0 +2,6 @@
+Tue Feb 28 11:07:05 UTC 2023 - Matej Cepl <[email protected]>
+
+- Add 675-nb-subproc-runner.patch (gh#martanne/vis!675) with
+  support for the non-blocking subprocess runner.
+
+-------------------------------------------------------------------

New:
----
  675-nb-subproc-runner.patch

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ vis.spec ++++++
--- /var/tmp/diff_new_pack.KpVdQ7/_old  2023-02-28 12:49:53.096919718 +0100
+++ /var/tmp/diff_new_pack.KpVdQ7/_new  2023-02-28 12:49:53.096919718 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package vis
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -26,6 +26,9 @@
 URL:            https://github.com/martanne/vis
 Source0:        
https://github.com/martanne/%{name}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
 Source1:        
https://github.com/martanne/vis-test/releases/download/v%{test_version}/vis-test-%{test_version}.tar.gz
+# PATCH-FEATURE-UPSTREAM 675-nb-subproc-runner.patch gh#martanne/vis!675 
[email protected]
+# adds support for the non-blocking subprocess runner
+Patch0:         675-nb-subproc-runner.patch
 BuildRequires:  libselinux-devel
 BuildRequires:  libtermkey-devel
 BuildRequires:  lua-devel
@@ -35,6 +38,7 @@
 BuildRequires:  tre-devel
 Requires:       lua
 ExclusiveArch:  x86_64 %{ix86}
+Suggests:       par_text
 
 %description
 Vis aims to be a modern, legacy free, simple yet efficient editor combining 
the strengths of both vi(m) and sam.
@@ -42,7 +46,8 @@
 It extends vi's modal editing with built-in support for multiple 
cursors/selections and combines it with sam's structural regular expression 
based command language.
 
 %prep
-%setup -q
+%autosetup -p1
+
 tar -xC test/ --strip-components 1 -f %{SOURCE1}
 
 %build

++++++ 675-nb-subproc-runner.patch ++++++
>From 25713f5bf36f6a33333793e963142abe3753c9ab Mon Sep 17 00:00:00 2001
From: xomachine <[email protected]>
Date: Sun, 25 Feb 2018 01:55:48 +0300
Subject: [PATCH 01/19] Subprocess lua API extension

---
 Makefile         |    1 
 lua/vis.lua      |    2 
 vis-lua.c        |   82 +++++++++++++++++++++++++
 vis-lua.h        |    4 -
 vis-subprocess.c |  176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 vis-subprocess.h |   23 +++++++
 vis.c            |    5 +
 7 files changed, 291 insertions(+), 2 deletions(-)
 create mode 100644 vis-subprocess.c
 create mode 100644 vis-subprocess.h

--- a/Makefile
+++ b/Makefile
@@ -26,6 +26,7 @@ SRC = array.c \
        vis-prompt.c \
        vis-registers.c \
        vis-text-objects.c \
+       vis-subprocess.c \
        $(REGEX_SRC)
 
 ELF = vis vis-menu vis-digraph
--- a/lua/vis.lua
+++ b/lua/vis.lua
@@ -152,6 +152,7 @@ local events = {
        WIN_OPEN = "Event::WIN_OPEN", -- see @{win_open}
        WIN_STATUS = "Event::WIN_STATUS", -- see @{win_status}
        TERM_CSI = "Event::TERM_CSI", -- see @{term_csi}
+       PROCESS_RESPONSE = "Event::PROCESS_RESPONSE", -- see @{process_response}
 }
 
 events.file_close = function(...) events.emit(events.FILE_CLOSE, ...) end
@@ -167,6 +168,7 @@ events.win_highlight = function(...) eve
 events.win_open = function(...) events.emit(events.WIN_OPEN, ...) end
 events.win_status = function(...) events.emit(events.WIN_STATUS, ...) end
 events.term_csi = function(...) events.emit(events.TERM_CSI, ...) end
+events.process_response = function(...) events.emit(events.PROCESS_RESPONSE, 
...) end
 
 local handlers = {}
 
--- a/vis-lua.c
+++ b/vis-lua.c
@@ -23,6 +23,7 @@
 
 #include "vis-lua.h"
 #include "vis-core.h"
+#include "vis-subprocess.h"
 #include "text-motions.h"
 #include "util.h"
 
@@ -52,6 +53,13 @@
 #define debug(...) do { } while (0)
 #endif
 
+typedef struct {
+       /* Lua stream structure for the process input stream */
+       FILE *f;
+       lua_CFunction closef;
+       Process *handler;
+} ProcessStream;
+
 static void window_status_update(Vis *vis, Win *win) {
        char left_parts[4][255] = { "", "", "", "" };
        char right_parts[4][32] = { "", "", "", "" };
@@ -162,6 +170,9 @@ void vis_lua_win_close(Vis *vis, Win *wi
 void vis_lua_win_highlight(Vis *vis, Win *win) { }
 void vis_lua_win_status(Vis *vis, Win *win) { window_status_update(vis, win); }
 void vis_lua_term_csi(Vis *vis, const long *csi) { }
+void vis_lua_process_response(Vis *vis, const char *name,
+                              char *buffer, size_t len, ResponseType rtype) { }
+
 
 #else
 
@@ -1368,6 +1379,47 @@ static int redraw(lua_State *L) {
        return 0;
 }
 /***
+ * Closes a stream returned by @{Vis.communicate}.
+ *
+ * @function close
+ * @tparam io.file inputfd the stream to be closed
+ * @treturn bool the same with @{io.close}
+ */
+static int close_subprocess(lua_State *L) {
+       luaL_Stream *file = luaL_checkudata(L, -1, "FILE*");
+       int result = fclose(file->f);
+       if (result == 0) {
+               file->f = NULL;
+               file->closef = NULL;
+       }
+       return luaL_fileresult(L, result == 0, NULL);
+}
+/***
+ * Open new process and return its input handler.
+ * When the process will quit or will output anything to stdout or stderr,
+ * the @{process_response} event will be fired.
+ *
+ * The editor core won't be blocked while the external process is running.
+ *
+ * @function communicate
+ * @tparam string name the name of subprocess (to distinguish processes in the 
@{process_response} event)
+ * @tparam string command the command to execute
+ * @return the file handle to write data to the process, in case of error the 
return values are equivalent to @{io.open} error values.
+ */
+static int communicate_func(lua_State *L) {
+       Vis *vis = obj_ref_check(L, 1, "vis");
+       const char *name = luaL_checkstring(L, 2);
+       const char *cmd = luaL_checkstring(L, 3);
+       ProcessStream *inputfd = (ProcessStream *)lua_newuserdata(L, 
sizeof(ProcessStream));
+       luaL_setmetatable(L, LUA_FILEHANDLE);
+       inputfd->handler = vis_process_communicate(vis, name, cmd, (void 
**)(&(inputfd->closef)));
+       if (inputfd->handler) {
+               inputfd->f = fdopen(inputfd->handler->inpfd, "w");
+               inputfd->closef = &close_subprocess;
+       }
+       return inputfd->f ? 1 : luaL_fileresult(L, inputfd->f != NULL, name);
+}
+/***
  * Currently active window.
  * @tfield Window win
  * @see windows
@@ -1524,6 +1576,7 @@ static const struct luaL_Reg vis_lua[] =
        { "exit", exit_func },
        { "pipe", pipe_func },
        { "redraw", redraw },
+       { "communicate", communicate_func },
        { "__index", vis_index },
        { "__newindex", vis_newindex },
        { NULL, NULL },
@@ -3135,5 +3188,34 @@ void vis_lua_term_csi(Vis *vis, const lo
        }
        lua_pop(L, 1);
 }
+/***
+ * The response received from the process started via @{Vis:communicate}.
+ * @function process_response
+ * @tparam string name the name of process given to @{Vis:communicate}
+ * @tparam string response_type can be "STDOUT" or "STDERR" if new output was 
received in corresponding channel, "SIGNAL" if the process was terminated by a 
signal or "EXIT" when the process terminated normally
+ * @tparam string|int buffer the available content sent by process; it becomes 
the exit code number if response\_type is "EXIT", or the signal number if 
response\_type is "SIGNAL"
+ */
+void vis_lua_process_response(Vis *vis, const char *name,
+                              char *buffer, size_t len, ResponseType rtype) {
+       lua_State *L = vis->lua;
+       if (!L)
+               return;
+       vis_lua_event_get(L, "process_response");
+       if (lua_isfunction(L, -1)) {
+               lua_pushstring(L, name);
+               if (rtype == EXIT || rtype == SIGNAL)
+                       lua_pushinteger(L, len);
+               else
+                       lua_pushlstring(L, buffer, len);
+               switch (rtype){
+               case STDOUT: lua_pushstring(L, "STDOUT"); break;
+               case STDERR: lua_pushstring(L, "STDERR"); break;
+               case SIGNAL: lua_pushstring(L, "SIGNAL"); break;
+               case EXIT: lua_pushstring(L, "EXIT"); break;
+               }
+               pcall(vis, L, 3, 0);
+       }
+       lua_pop(L, 1);
+}
 
 #endif
--- a/vis-lua.h
+++ b/vis-lua.h
@@ -7,10 +7,11 @@
 #include <lauxlib.h>
 #else
 typedef struct lua_State lua_State;
+typedef void* lua_CFunction;
 #endif
 
 #include "vis.h"
-
+#include "vis-subprocess.h"
 /* add a directory to consider when loading lua files */
 bool vis_lua_path_add(Vis*, const char *path);
 /* get semicolon separated list of paths to load lua files
@@ -38,5 +39,6 @@ void vis_lua_win_close(Vis*, Win*);
 void vis_lua_win_highlight(Vis*, Win*);
 void vis_lua_win_status(Vis*, Win*);
 void vis_lua_term_csi(Vis*, const long *);
+void vis_lua_process_response(Vis *, const char *, char *, size_t, 
ResponseType);
 
 #endif
--- /dev/null
+++ b/vis-subprocess.c
@@ -0,0 +1,176 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/wait.h>
+#include "vis-lua.h"
+#include "vis-subprocess.h"
+
+/* Maximum amount of data what can be read from IPC pipe per event */
+#define MAXBUFFER 1024
+
+/* Pool of information about currently running subprocesses */
+static Process *process_pool;
+
+Process *new_in_pool() {
+       /* Adds new empty process information structure to the process pool and
+        * returns it */
+       Process *newprocess = (Process *)malloc(sizeof(Process));
+       if (!newprocess) return NULL;
+       newprocess->next = process_pool;
+       process_pool = newprocess;
+       return newprocess;
+}
+
+void destroy(Process **pointer) {
+       /* Removes the subprocess information from the pool, sets invalidator 
to NULL
+        * and frees resources. */
+       Process *target = *pointer;
+       if (target->outfd != -1) close(target->outfd);
+       if (target->errfd != -1) close(target->errfd);
+       if (target->inpfd != -1) close(target->inpfd);
+       /* marking stream as closed for lua */
+       if (target->invalidator) *(target->invalidator) = NULL;
+       if (target->name) free(target->name);
+       *pointer = target->next;
+       free(target);
+}
+
+Process *vis_process_communicate(Vis *vis, const char *name,
+                                 const char *command, void **invalidator) {
+       /* Starts new subprocess by passing the `command` to the shell and
+        * returns the subprocess information structure, containing file 
descriptors
+        * of the process.
+        * Also stores the subprocess information to the internal pool to track
+        * its status and responses.
+        * `name` - the string than should contain an unique name of the 
subprocess.
+        * This name will be passed to the PROCESS_RESPONSE event handler
+        * to distinguish running subprocesses.
+        * `invalidator` - a pointer to the pointer which shows that the 
subprocess
+        * is invalid when set to NULL. When subprocess dies, it is being set 
to NULL.
+        * If the pointer is set to NULL by an external code, the subprocess 
will be
+        * killed on the next main loop iteration. */
+       int pin[2], pout[2], perr[2];
+       pid_t pid = (pid_t)-1;
+       if (pipe(perr) == -1) goto closeerr;
+       if (pipe(pout) == -1) goto closeouterr;
+       if (pipe(pin) == -1) goto closeall;
+       pid = fork();
+       if (pid == -1)
+               vis_info_show(vis, "fork failed: %s", strerror(errno));
+       else if (pid == 0){ /* child process */
+               sigset_t sigterm_mask;
+               sigemptyset(&sigterm_mask);
+               sigaddset(&sigterm_mask, SIGTERM);
+               if (sigprocmask(SIG_UNBLOCK, &sigterm_mask, NULL) == -1) {
+                       fprintf(stderr, "failed to reset signal mask");
+                       exit(EXIT_FAILURE);
+               }
+               dup2(pin[0], STDIN_FILENO);
+               dup2(pout[1], STDOUT_FILENO);
+               dup2(perr[1], STDERR_FILENO);
+       }
+       else { /* main process */
+               Process *new = new_in_pool();
+               if (!new) {
+                       vis_info_show(vis, "Can not create process: %s", 
strerror(errno));
+                       goto closeall;
+               }
+               new->name = strdup(name);
+               if (!new->name) {
+                       vis_info_show(vis, "Can not copy process name: %s", 
strerror(errno));
+                       /* pop top element (which is `new`) from the pool */
+                       destroy(&process_pool);
+                       goto closeall;
+               }
+               new->outfd = pout[0];
+               new->errfd = perr[0];
+               new->inpfd = pin[1];
+               new->pid = pid;
+               new->invalidator = invalidator;
+               close(pin[0]);
+               close(pout[1]);
+               close(perr[1]);
+               return new;
+       }
+closeall:
+       close(pin[0]);
+       close(pin[1]);
+closeouterr:
+       close(pout[0]);
+       close(pout[1]);
+closeerr:
+       close(perr[0]);
+       close(perr[1]);
+       if (pid == 0) { /* start command in child process */
+               execlp(vis->shell, vis->shell, "-c", command, (char*)NULL);
+               fprintf(stderr, "exec failed: %s(%d)\n", strerror(errno), 
errno);
+               exit(1);
+       }
+       else
+               vis_info_show(vis, "process creation failed: %s", 
strerror(errno));
+       return NULL;
+}
+
+int vis_process_before_tick(fd_set *readfds) {
+       /* Adds file descriptors of currently running subprocesses to the 
`readfds`
+        * to track their readiness and returns maximum file descriptor value
+        * to pass it to the `pselect` call */
+       Process **pointer = &process_pool;
+       int maxfd = 0;
+       while (*pointer) {
+               Process *current = *pointer;
+               if (current->outfd != -1) {
+                       FD_SET(current->outfd, readfds);
+                       maxfd = maxfd < current->outfd ? current->outfd : maxfd;
+               }
+               if (current->errfd != -1) {
+                       FD_SET(current->errfd, readfds);
+                       maxfd = maxfd < current->errfd ? current->errfd : maxfd;
+               }
+               pointer = &current->next;
+       }
+       return maxfd;
+}
+
+void read_and_fire(Vis* vis, int fd, const char *name, ResponseType rtype) {
+       /* Reads data from the given subprocess file descriptor `fd` and fires
+        * the PROCESS_RESPONSE event in Lua with given subprocess `name`,
+        * `rtype` and the read data as arguments. */
+       static char buffer[MAXBUFFER];
+       size_t obtained = read(fd, &buffer, MAXBUFFER-1);
+       if (obtained > 0)
+               vis_lua_process_response(vis, name, buffer, obtained, rtype);
+}
+
+void vis_process_tick(Vis *vis, fd_set *readfds) {
+       /* Checks if `readfds` contains file discriptors of subprocesses from
+        * the pool. If so, reads the data from them and fires corresponding 
events.
+        * Also checks if subprocesses from pool is dead or need to be killed 
then
+        * raises event or kills it if necessary. */
+       Process **pointer = &process_pool;
+       while (*pointer) {
+               Process *current = *pointer;
+               if (current->outfd != -1 && FD_ISSET(current->outfd, readfds))
+                       read_and_fire(vis, current->outfd, current->name, 
STDOUT);
+               if (current->errfd != -1 && FD_ISSET(current->errfd, readfds))
+                       read_and_fire(vis, current->errfd, current->name, 
STDERR);
+               int status;
+               pid_t wpid = waitpid(current->pid, &status, WNOHANG);
+               if (wpid == -1) vis_message_show(vis, strerror(errno));
+               else if (wpid == current->pid) goto just_destroy;
+               else if(!*(current->invalidator)) goto kill_and_destroy;
+               pointer = &current->next;
+               continue;
+kill_and_destroy:
+               kill(current->pid, SIGTERM);
+               waitpid(current->pid, &status, 0);
+just_destroy:
+               if (WIFSIGNALED(status))
+                       vis_lua_process_response(vis, current->name, NULL, 
WTERMSIG(status), SIGNAL);
+               else
+                       vis_lua_process_response(vis, current->name, NULL, 
WEXITSTATUS(status), EXIT);
+               destroy(pointer);
+       }
+}
--- /dev/null
+++ b/vis-subprocess.h
@@ -0,0 +1,23 @@
+#ifndef VIS_SUBPROCESS_H
+#define VIS_SUBPROCESS_H
+#include "vis-core.h"
+#include <sys/select.h>
+
+struct Process {
+       char *name;
+       int outfd;
+       int errfd;
+       int inpfd;
+       pid_t pid;
+       void **invalidator;
+       struct Process *next;
+};
+
+typedef struct Process Process;
+typedef enum { STDOUT, STDERR, SIGNAL, EXIT } ResponseType;
+
+Process *vis_process_communicate(Vis *, const char *command, const char *name,
+                                 void **invalidator);
+int vis_process_before_tick(fd_set *);
+void vis_process_tick(Vis *, fd_set *);
+#endif
--- a/vis.c
+++ b/vis.c
@@ -28,6 +28,7 @@
 #include "vis-core.h"
 #include "sam.h"
 #include "ui.h"
+#include "vis-subprocess.h"
 
 
 static void macro_replay(Vis *vis, const Macro *macro);
@@ -1412,7 +1413,8 @@ int vis_run(Vis *vis) {
 
                vis_update(vis);
                idle.tv_sec = vis->mode->idle_timeout;
-               int r = pselect(1, &fds, NULL, NULL, timeout, &emptyset);
+               int r = pselect(vis_process_before_tick(&fds) + 1, &fds, NULL, 
NULL,
+                               timeout, &emptyset);
                if (r == -1 && errno == EINTR)
                        continue;
 
@@ -1420,6 +1422,7 @@ int vis_run(Vis *vis) {
                        /* TODO save all pending changes to a ~suffixed file */
                        vis_die(vis, "Error in mainloop: %s\n", 
strerror(errno));
                }
+               vis_process_tick(vis, &fds);
 
                if (!FD_ISSET(STDIN_FILENO, &fds)) {
                        if (vis->mode->idle)

Reply via email to