commit:     3e3bb8e67abc421824ccbf978aea6a0040e0ca92
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Dec 10 21:13:12 2024 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sat Dec 28 02:04:57 2024 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=3e3bb8e6

Scheduler: Handle SIGWINCH for JobStatusDisplay

Do not use curses in the get_term_size function, since curses caches
the terminal width and does not account for resize.

Bug: https://bugs.gentoo.org/945382
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 NEWS                            |  2 ++
 lib/_emerge/JobStatusDisplay.py | 14 +++++++++-----
 lib/_emerge/Scheduler.py        | 11 +++++++++++
 lib/portage/output.py           | 15 +++++----------
 4 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/NEWS b/NEWS
index f79a11c991..c08f368815 100644
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,8 @@ Bug fixes:
 
 * Process elog messages for emerge --config (bug #904702).
 
+* Scheduler: Handle SIGWINCH for JobStatusDisplay (bug #945382).
+
 portage-3.0.66.1 (2024-09-18)
 --------------
 

diff --git a/lib/_emerge/JobStatusDisplay.py b/lib/_emerge/JobStatusDisplay.py
index 57495c5ae5..b98d4a8327 100644
--- a/lib/_emerge/JobStatusDisplay.py
+++ b/lib/_emerge/JobStatusDisplay.py
@@ -65,11 +65,9 @@ class JobStatusDisplay:
             if not isinstance(v, str):
                 self._term_codes[k] = v.decode(encoding, "replace")
 
-        if self._isatty:
-            width = portage.output.get_term_size()[1]
-        else:
-            width = self.max_display_width
-        self._set_width(width)
+        if not self._isatty:
+            self._set_width(self.max_display_width)
+        self.sigwinch()
 
     def _set_width(self, width):
         if width == getattr(self, "width", None):
@@ -79,6 +77,12 @@ class JobStatusDisplay:
         object.__setattr__(self, "width", width)
         object.__setattr__(self, "_jobs_column_width", width - 32)
 
+    def sigwinch(self):
+        if not self._isatty:
+            return
+        width = portage.output.get_term_size()[1]
+        self._set_width(width)
+
     @property
     def out(self):
         """Use a lazy reference to sys.stdout, in case the API consumer has

diff --git a/lib/_emerge/Scheduler.py b/lib/_emerge/Scheduler.py
index fea151d5d1..96843c96ee 100644
--- a/lib/_emerge/Scheduler.py
+++ b/lib/_emerge/Scheduler.py
@@ -1177,6 +1177,9 @@ class Scheduler(PollScheduler):
             )
             signal.siginterrupt(signal.SIGCONT, False)
 
+            earlier_sigwinch_handler = signal.signal(
+                signal.SIGWINCH, self._sigwinch_handler
+            )
             try:
                 rval = self._merge()
             finally:
@@ -1194,6 +1197,11 @@ class Scheduler(PollScheduler):
                 else:
                     signal.signal(signal.SIGCONT, signal.SIG_DFL)
 
+                if earlier_sigwinch_handler is not None:
+                    signal.signal(signal.SIGWINCH, earlier_sigwinch_handler)
+                else:
+                    signal.signal(signal.SIGWINCH, signal.SIG_DFL)
+
             self._termination_check()
             if received_signal:
                 sys.exit(received_signal[0])
@@ -1909,6 +1917,9 @@ class Scheduler(PollScheduler):
     def _sigcont_handler(self, signum, frame):
         self._sigcont_time = time.time()
 
+    def _sigwinch_handler(self, signum, frame):
+        self._status_display.sigwinch()
+
     def _job_delay(self):
         """
         @rtype: bool

diff --git a/lib/portage/output.py b/lib/portage/output.py
index 4408705c45..9c78a4c298 100644
--- a/lib/portage/output.py
+++ b/lib/portage/output.py
@@ -522,16 +522,11 @@ def get_term_size(fd=None):
         fd = sys.stdout
     if not hasattr(fd, "isatty") or not fd.isatty():
         return (0, 0)
-    try:
-        import curses
-
-        try:
-            curses.setupterm(term=os.environ.get("TERM", "unknown"), 
fd=fd.fileno())
-            return curses.tigetnum("lines"), curses.tigetnum("cols")
-        except curses.error:
-            pass
-    except ImportError:
-        pass
+
+    # Do not use curses.tigetnum("lines") or curses.tigetnum("cols") because it
+    # returns stale values after terminal resize. Do not use 
curses.initscr().getmaxyx()
+    # since that has unwanted side-effects, requiring a call to `stty sane` to 
restore a
+    # sane state.
 
     try:
         proc = subprocess.Popen(["stty", "size"], stdout=subprocess.PIPE, 
stderr=fd)

Reply via email to