From 411807efad24d5795839c4c707534c1ef9b9ce60 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 16 Jun 2016 17:33:43 +0100 Subject: [PATCH 1/3] Add support for tmux grouped sessions The default tmux behaviour when connecting multiple clients is a little unexpected. All of the clients are connected to the same view. When the view on one client is changed, all the other client views get changed also. With this behaviour it isn't possible to have a different view in each client connection as one would have with multiple xterm windows. This differs from the behaviour of screen where the viewport of each client is independent. Fix this by making use of the session group feature in tmux. With session groups, each client creates a new session, but groups it with an existing session so it can share windows. However, when a client detaches from a session in a session group, the session instance doesn't get removed. If one attaches and detaches from tmux many times, a lot of unused sessions will accumulate (as seen with the 'tmux list-sessions' command). Solve this by adding a "cull_zombies" step when connecting to a session. When attaching to a session, cull_zombies() checks if there are any detached group sessions that should be killed. --- usr/lib/byobu/include/select-session.py | 29 ++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/usr/lib/byobu/include/select-session.py b/usr/lib/byobu/include/select-session.py index 0fb28c9f..930736b4 100755 --- a/usr/lib/byobu/include/select-session.py +++ b/usr/lib/byobu/include/select-session.py @@ -85,6 +85,32 @@ def get_sessions(): i += 1 return sessions +def cull_zombies(session_name): + # When using tmux session groups, closing a client will leave + # unattached "zombie" sessions that will never be reattached. + # Search for and kill any unattached hidden sessions in the same group + if BYOBU_BACKEND == "tmux": + output = subprocess.Popen(["tmux", "list-sessions"], stdout=subprocess.PIPE).communicate()[0] + if sys.stdout.encoding is None: + output = output.decode("UTF-8") + else: + output = output.decode(sys.stdout.encoding) + if not output: + return + + # Find the master session to extract the group number. We use + # the group number to be extra sure the right session is getting + # killed. We don't want to accidentally kill the wrong one + pattern = "^%s:.+\\((group \\d+)\\).*$" % session_name + master = re.search(pattern, output, re.MULTILINE) + if not master: + return + + # Kill all the matching hidden & unattached sessions + pattern = "^_%s-\\d+:.+\\(%s\\)$" % (session_name, master.group(1)) + for s in re.findall(pattern, output, re.MULTILINE): + print("Killing", s.split(":")[0]); + subprocess.Popen(["tmux", "kill-session", "-t", s.split(":")[0]]) def update_environment(session): backend, session_name = session.split("____", 2) @@ -101,9 +127,10 @@ def update_environment(session): def attach_session(session): update_environment(session) backend, session_name = session.split("____", 2) + cull_zombies(session_name) # must use the binary, not the wrapper! if backend == "tmux": - os.execvp("tmux", ["", "-2", "attach", "-t", session_name]) + os.execvp("tmux", ["", "-2", "new-session", "-t", session_name, "-s", "_%s-%i" % (session_name, os.getpid())]) else: os.execvp("screen", ["", "-AOxRR", session_name]) From 705dbc66ecf9ef42dd263a398410b071986e25e6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 16 Jun 2016 22:26:04 +0100 Subject: [PATCH 2/3] select-session.py: Pass command name in argument list When calling os.execpv(), make sure the first argument in the argument list is the command name so that the command shows up in tools like ps. Example before: $ ps -a | grep 368 pts/4 S+ 0:00 -u -2 -f /usr/share/byobu/profiles/tmuxrc new-session -n - /usr/bin/byobu-shell 784 pts/5 S+ 0:00 -2 new-session -t 1 -s _1-784 8446 pts/3 S+ 0:00 -2 new-session -t 1 -s _1-8446 after: $ ps a [...] 368 pts/4 S+ 0:00 tmux -u -2 -f /usr/share/byobu/profiles/tmuxrc new-session -n - /usr/bin/byobu-shell 784 pts/5 S+ 0:00 tmux -2 new-session -t 1 -s _1-784 8446 pts/3 S+ 0:00 tmux -2 new-session -t 1 -s _1-8446 --- usr/lib/byobu/include/select-session.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/usr/lib/byobu/include/select-session.py b/usr/lib/byobu/include/select-session.py index 930736b4..76e26a22 100755 --- a/usr/lib/byobu/include/select-session.py +++ b/usr/lib/byobu/include/select-session.py @@ -130,9 +130,9 @@ def attach_session(session): cull_zombies(session_name) # must use the binary, not the wrapper! if backend == "tmux": - os.execvp("tmux", ["", "-2", "new-session", "-t", session_name, "-s", "_%s-%i" % (session_name, os.getpid())]) + os.execvp("tmux", ["tmux", "-2", "new-session", "-t", session_name, "-s", "_%s-%i" % (session_name, os.getpid())]) else: - os.execvp("screen", ["", "-AOxRR", session_name]) + os.execvp("screen", ["screen", "-AOxRR", session_name]) sessions = get_sessions() @@ -180,9 +180,9 @@ if choice >= 1: if sessions[choice - 1] == "NEW": # Create a new session if BYOBU_BACKEND == "tmux": - os.execvp("byobu", ["", "new-session", SHELL]) + os.execvp("byobu", ["byobu", "new-session", SHELL]) else: - os.execvp("byobu", ["", SHELL]) + os.execvp("byobu", ["byobu", SHELL]) elif sessions[choice - 1] == "SHELL": os.execvp(SHELL, [SHELL]) else: @@ -194,4 +194,4 @@ if BYOBU_BACKEND == "tmux": args = "" else: args = "-AOxRR" -os.execvp("byobu", ["", args]) +os.execvp("byobu", ["byobu", args]) From 362f849d62c4a990d63569706ecf8966e5a72049 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 17 Jun 2016 13:33:26 +0100 Subject: [PATCH 3/3] select-session.py: fix lintian bugs Commit 411807ef ("Add support for tmux grouped sessions) added a few policy violations in the python code. Fix them up. This change should be squashed into the original commit before merging upstream. --- usr/lib/byobu/include/select-session.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usr/lib/byobu/include/select-session.py b/usr/lib/byobu/include/select-session.py index 76e26a22..4a22b64b 100755 --- a/usr/lib/byobu/include/select-session.py +++ b/usr/lib/byobu/include/select-session.py @@ -85,6 +85,7 @@ def get_sessions(): i += 1 return sessions + def cull_zombies(session_name): # When using tmux session groups, closing a client will leave # unattached "zombie" sessions that will never be reattached. @@ -109,9 +110,9 @@ def cull_zombies(session_name): # Kill all the matching hidden & unattached sessions pattern = "^_%s-\\d+:.+\\(%s\\)$" % (session_name, master.group(1)) for s in re.findall(pattern, output, re.MULTILINE): - print("Killing", s.split(":")[0]); subprocess.Popen(["tmux", "kill-session", "-t", s.split(":")[0]]) + def update_environment(session): backend, session_name = session.split("____", 2) for var in BYOBU_UPDATE_ENVVARS: