def init(self): if not self.config: error('config file not loaded; call "load_config" first!') else: self.server = Server() if self.server.has_session(self.session_name): self.session = self.server.find_where( {"session_name": self.session_name}) debug('found running session %s on server' % self.session_name) else: info('starting new session %s on server' % self.session_name) self.session = self.server.new_session( session_name=self.session_name) for win in self.config['windows']: # print win, "***", self.config['windows'] window = self.session.find_where({"window_name": win['name']}) if window: debug('window %s already exists' % win['name']) else: info('create window %s' % win['name']) window = self.session.new_window(win['name']) exist_num_panes = len(window.list_panes()) while exist_num_panes < len(win['panes']): info('new pane needed in window %s' % win['name']) window.split_window(vertical=1) exist_num_panes = len(window.list_panes()) window.cmd('select-layout', 'tiled')
def test_88_colors(server): myserver = Server(colors=88) assert myserver.colors == 88 proc = myserver.cmd("list-sessions") assert "-8" in proc.cmd assert "-2" not in proc.cmd
def test_256_colors(server): myserver = Server(colors=256) assert myserver.colors == 256 proc = myserver.cmd('list-servers') assert '-2' in proc.cmd assert '-8' not in proc.cmd
def test_88_colors(server): myserver = Server(colors=88) assert myserver.colors == 88 proc = myserver.cmd('list-servers') assert '-8' in proc.cmd assert '-2' not in proc.cmd
def spawn_session(name: str, kubeconfig_location: str, server: libtmux.Server): if server.has_session(name): return else: session = server.new_session(name) session.set_environment("KUBECONFIG", kubeconfig_location) # the new_session will create default window and pane which will not contain KUBECONFIG, add manually session.attached_window.attached_pane.send_keys( "export KUBECONFIG={}".format(kubeconfig_location))
def test_256_colors(server): myserver = Server(colors=256) assert myserver.colors == 256 print(myserver.colors) proc = myserver.cmd("list-sessions") print("list-sessions", proc) assert "-2" in proc.cmd assert "-8" not in proc.cmd
def command_shell( session_name, window_name, socket_name, socket_path, command, shell, use_pythonrc, use_vi_mode, ): """Launch python shell for tmux server, session, window and pane. Priority given to loaded session/wndow/pane objects: - session_name and window_name arguments - current shell: envvar ``TMUX_PANE`` for determining window and session - :attr:`libtmux.Server.attached_sessions`, :attr:`libtmux.Session.attached_window`, :attr:`libtmux.Window.attached_pane` """ server = Server(socket_name=socket_name, socket_path=socket_path) util.raise_if_tmux_not_running(server=server) current_pane = util.get_current_pane(server=server) session = util.get_session(server=server, session_name=session_name, current_pane=current_pane) window = util.get_window(session=session, window_name=window_name, current_pane=current_pane) pane = util.get_pane(window=window, current_pane=current_pane) # NOQA: F841 if command is not None: exec(command) else: if shell == "pdb" or (os.getenv("PYTHONBREAKPOINT") and PY3 and PYMINOR >= 7): from ._compat import breakpoint as tmuxp_breakpoint tmuxp_breakpoint() return else: from ..shell import launch launch( shell=shell, use_pythonrc=use_pythonrc, # shell: code use_vi_mode=use_vi_mode, # shell: ptpython, ptipython # tmux environment / libtmux variables server=server, session=session, window=window, pane=pane, )
def test_socket_name(server): """``-L`` socket_name. ``-L`` socket_name file name of socket. which will be stored in env TMUX_TMPDIR or /tmp if unset.) """ myserver = Server(socket_name="test") assert myserver.socket_name == "test"
def main(plots_data: Path, runs_data: Path, limit: int, perform_copy: bool): with plots_data.open() as plots_file, runs_data.open() as runs_file: names = [] paths = [] def copy(origin_path, local_path, **_): cmd = f"""\ rsync -avr --include="**/" --include="**/*.hdf5" --exclude="*" {origin_path} {Path(local_path).expanduser()}\ """ subprocess.run([cmd], shell=True) def append(algorithm, local_path, **_): names.append(f"'{algorithm}'") paths.append(f"'{path_to_str(local_path)}'") for row in csv.DictReader(runs_file): if perform_copy: copy(**row) append(**row) plots_reader = csv.DictReader(plots_file) session = Server().new_session(session_name="plots", kill_session=True) def new_window(tag, start, stop, path): cmd = " ".join(["python", "plot.py"] + ["--names", *names] + ["--line-length-range", start, stop] + ["--paths", *paths] + ["--tag", tag] + ["--limit", str(limit)] + ["--fname", path_to_str(path)]) print(cmd) window = session.new_window(window_name=str(path), attach=True, window_shell=cmd) for row in plots_reader: new_window(**row)
def test_socket_path(server): """``-S`` socket_path (alternative path for server socket).""" myserver = Server(socket_path="test") assert myserver.socket_path == "test"
class TMux: def __init__(self, session_name=None, configfile=None, sleep_sec=0.0): self.session_name = 'tmule' self.configfile = configfile if self.configfile: self.load_config() if 'session' in self.config: self.session_name = self.config['session'] else: self.config = None if session_name: self.session_name = session_name self.sleep_sec = sleep_sec # max number of loops to wait for process to come up self.maxCheckLoops = 16 # time to wait between checks (factor multiplied by loop) self.sleepCheckLoop = 1 def _on_terminate(self, proc): info("process {} terminated with exit code {}".format( proc, proc.returncode)) def _terminate(self, pid): procs = Process(pid).children(recursive=True) for p in procs: info("trying to terminate %s" % p) p.terminate() _, still_alive = wait_procs(procs, timeout=1, callback=self._on_terminate) for p in still_alive: info("killing %s" % p) p.kill() def _get_children_pids(self, pid): return Process(pid).children(recursive=True) def var_substitute(self, root): if type(root) == dict: for d in root: root[d] = self.var_substitute(root[d]) elif type(root) == list: for l in range(0, len(root)): root[l] = self.var_substitute(root[l]) elif type(root) == str: for vs in self.var_dict: root = root.replace('@%s@' % vs, self.var_dict[vs]) return root def load_config(self): with open(self.configfile) as data_file: self.config = load(data_file, Loader) self.var_dict = { 'TMULE_CONFIG_FILE': abspath(self.configfile), 'TMULE_CONFIG_DIR': dirname(abspath(self.configfile)), 'TMULE_SESSION_NAME': self.session_name } self.config = self.var_substitute(self.config) self.known_tags = set([]) for w in self.config['windows']: if 'tags' in w: for t in w['tags']: self.known_tags.add(t) def init(self): if not self.config: error('config file not loaded; call "load_config" first!') else: self.server = Server() if self.server.has_session(self.session_name): self.session = self.server.find_where( {"session_name": self.session_name}) debug('found running session %s on server' % self.session_name) else: info('starting new session %s on server' % self.session_name) self.session = self.server.new_session( session_name=self.session_name) for win in self.config['windows']: # print win, "***", self.config['windows'] window = self.session.find_where({"window_name": win['name']}) if window: debug('window %s already exists' % win['name']) else: info('create window %s' % win['name']) window = self.session.new_window(win['name']) exist_num_panes = len(window.list_panes()) while exist_num_panes < len(win['panes']): info('new pane needed in window %s' % win['name']) window.split_window(vertical=1) exist_num_panes = len(window.list_panes()) window.cmd('select-layout', 'tiled') def find_window(self, window_name): for win in self.config['windows']: if win['name'] == window_name: window = self.session.find_where({"window_name": win['name']}) # window.select_window() return win, window def send_ctrlc(self, pane): datestr = datetime.now().strftime('%c') pane.cmd("send-keys", "", "C-c") pane.cmd("send-keys", "", "C-c") pane.cmd("send-keys", "", "C-c") pane.send_keys('# tmux-controller sent Ctrl-C at %s' % datestr, enter=True, suppress_history=True) def launch_window(self, window_name, enter=True): info('launch %s' % window_name) winconf, window = self.find_window(window_name) pane_no = 0 datestr = datetime.now().strftime('%c') for cmd in winconf['panes']: pane = window.select_pane( '%s:%s.%d' % (window.session.name, window_name, pane_no)) debug('pane: %d -> %s' % (pane_no, pane)) self.send_ctrlc(pane) pane.send_keys('# tmux-controller starts new command %s' % datestr, enter=True, suppress_history=True) if 'init_cmd' in self.config: pane.send_keys(self.config['init_cmd'], enter=enter, suppress_history=False) pane.send_keys(cmd, enter=enter, suppress_history=False) pane_no += 1 winconf['_running'] = True def launch_all_windows(self, tags=set([])): for winconf in self.config['windows']: selected = 'skip' not in winconf or not winconf['skip'] if selected and tags: if 'tags' in winconf: selected = set(winconf['tags']).intersection(tags) else: selected = False if selected: self.launch_window(winconf['name']) w = self.sleep_sec if 'wait' in winconf: w = float(winconf['wait']) if w > 0: info('sleep %f seconds after launch of %s' % (w, winconf['name'])) sleep(w) if 'check' in winconf: debug('need to run check command') running = False loop = 0 check_cmd = '\n' if 'init_cmd' in self.config: check_cmd += self.config['init_cmd'] + '\n' check_cmd += winconf['check'] while not running and loop < self.maxCheckLoops: loop += 1 sleep(loop * self.sleepCheckLoop) #running = (call(winconf['check'], shell=True) == 0) running = (call(check_cmd, executable='/bin/bash', shell=True, stdout=None, stdin=None) == 0) info('ran check for %s (loop %d) => %s' % (winconf['name'], loop, running)) if loop >= self.maxCheckLoops: error('window %s failed to come up in time, ' 'not continuing launch.' % winconf['name']) break def stop_all_windows(self, tags=set([])): for winconf in self.config['windows'][::-1]: selected = 'skip' not in winconf or not winconf['skip'] if selected and tags: if 'tags' in winconf: selected = set(winconf['tags']).intersection(tags) if selected: self.stop_window(winconf['name']) def get_children_pids_all_windows(self): pids = [] for winconf in self.config['windows']: pids.extend(self.get_children_pids_window(winconf['name'])) return pids def kill_all_windows(self): for winconf in self.config['windows'][::-1]: try: self.kill_window(winconf['name']) except Exception as e: warning('There was an exception shutting down, ' 'carrying on regardless: %s' % str(e)) self.server.kill_session(self.session_name) def stop_window(self, window_name): info('stop %s' % window_name) winconf, window = self.find_window(window_name) self._stop_window(winconf, window) def __pids_clean_up(self, pids): sleep(1) for p in pids: try: self._terminate(p) except Exception as e: info('exception in termination, can be ignored: %s' % str(e)) def _stop_window(self, winconf, window): pane_no = 0 for _ in winconf['panes']: pane = window.select_pane( '%s:%s.%d' % (window.session.name, window.name, pane_no)) self.send_ctrlc(pane) pane_no += 1 pids = self._get_pids_window(window) Thread(target=self.__pids_clean_up, args=(pids, )).start() #for p in pids: #self._terminate(p) winconf['_running'] = False def kill_window(self, window_name): info('terminate %s' % window_name) winconf, window = self.find_window(window_name) # "-F '#{pane_active} #{pane_pid}") self._stop_window(winconf, window) pids = self._get_pids_window(window) sleep(1) Thread(target=self.__pids_clean_up, args=(pids, )).start() winconf['_running'] = False def list_windows(self): return [w['name'] for w in self.config['windows']] def get_pids_window(self, window_name): winconf, window = self.find_window(window_name) return self._get_pids_window(window) def _get_pids_window(self, window): r = window.cmd('list-panes', "-F #{pane_pid}") return [int(p) for p in r.stdout] def get_children_pids_window(self, window_name): _, window = self.find_window(window_name) return self._get_children_pids_window(window) def _get_children_pids_window(self, window): winpids = self._get_pids_window(window) pids = [] for pid in winpids: pids.extend(self._get_children_pids(pid)) return [p.pid for p in pids] def is_running(self, window_name): winconf, window = self.find_window(window_name) pids = self._get_children_pids_window(window) if len(pids) < 1: return False if 'check' in winconf: debug('need to run check command') check_cmd = '\n' if 'init_cmd' in self.config: check_cmd += self.config['init_cmd'] + '\n' check_cmd += winconf['check'] running = (call(check_cmd, executable='/bin/bash', shell=True, stdout=None, stdin=None) == 0) return running else: return True def _server(self, port=9999, keepalive=True): from .ws_protocol import JsonWSProtocol import web from web.httpserver import StaticMiddleware, StaticApp from autobahn.twisted.websocket import WebSocketServerProtocol, \ WebSocketServerFactory from autobahn.twisted.resource import WebSocketResource, WSGIRootResource from twisted.internet import reactor from twisted.web.server import Site from twisted.web.wsgi import WSGIResource from twisted.python import log from twisted.web.static import File tmux_self = self class TMuxWebServer(web.auto_application): def __init__(self): web.auto_application.__init__(self) self._renderer = web.template.render(path.realpath( path.join(path.dirname(__file__), 'www')), base="base", globals=globals()) self_app = self class Index(self.page): path = '/' def GET(self): tmux_self.load_config() tmux_self.init() ws_uri = '%s://%s%sws' % ( 'ws' if web.ctx['protocol'] == 'http' else 'wss', web.ctx['host'], web.ctx['fullpath']) return self_app._renderer.index( ws_uri, tmux_self.config, tmux_self.known_tags) class Log(self.page): path = '/log' def GET(self): lines = tmux_self.server.cmd('capture-pane', '-p', '-C', '-S', '-100000').stdout return '\n'.join(lines) class TMuxWSProtocol(JsonWSProtocol): def __init__(self): super(TMuxWSProtocol, self).__init__() def on_button(self, payload): debug('button pressed: \n%s' % pformat(payload)) window_name = payload['id'] cmd = payload['cmd'] if cmd == 'launch': if window_name == '': tmux_self.launch_all_windows() else: tmux_self.launch_window(window_name) elif cmd == 'launch-tag': tmux_self.launch_all_windows(tags={window_name}) elif cmd == 'stop': if window_name == '': tmux_self.stop_all_windows() else: tmux_self.stop_window(window_name) elif cmd == 'stop-tag': tmux_self.stop_all_windows(tags={window_name}) elif cmd == 'terminate': tmux_self.kill_all_windows() sleep(1) tmux_self.init() sleep(1) self.sendJSON(self.on_status()) def on_status(self, payload=None): debug('status-requested: ') res = {'windows': {}, 'method': 'update_status'} for w in tmux_self.config['windows']: res['windows'][w['name']] = tmux_self.is_running(w['name']) return res # return {'button_outcome': True} log.startLogging(sys.stdout) wsFactory = WebSocketServerFactory() wsFactory.protocol = TMuxWSProtocol wsResource = WebSocketResource(wsFactory) staticResource = File( path.realpath(path.join(path.dirname(__file__), 'www/static'))) app = TMuxWebServer() # create a Twisted Web WSGI resource for our Flask server wsgiResource = WSGIResource(reactor, reactor.getThreadPool(), app.wsgifunc()) # create a root resource serving everything via WSGI/Flask, but # the path "/ws" served by our WebSocket stuff rootResource = WSGIRootResource(wsgiResource, { b'ws': wsResource, b'static': staticResource }) # create a Twisted Web Site and run everything site = Site(rootResource) reactor.listenTCP(port, site) reactor.run() # kill everything when server dies if not keepalive: self.kill_all_windows()
class TMux: def __init__(self, session_name="tmule", configfile=None): if configfile: self.load_config(configfile) else: self.config = None self.session_name = session_name def _on_terminate(self, proc): info("process {} terminated with exit code {}".format( proc, proc.returncode)) def _terminate(self, pid): procs = Process(pid).children() for p in procs: p.terminate() gone, still_alive = wait_procs(procs, timeout=1, callback=self._on_terminate) for p in still_alive: p.kill() def _get_children_pids(self, pid): return Process(pid).children(recursive=True) def load_config(self, filename="sample_config.json"): with open(filename) as data_file: self.config = load(data_file, Loader) def init(self): if not self.config: error('config file not loaded; call "load_config" first!') else: self.server = Server() if self.server.has_session(self.session_name): self.session = self.server.find_where( {"session_name": self.session_name}) info('found running session %s on server' % self.session_name) else: info('starting new session %s on server' % self.session_name) self.session = self.server.new_session( session_name=self.session_name) for win in self.config['windows']: print win, "***", self.config['windows'] window = self.session.find_where({"window_name": win['name']}) if window: info('window %s already exists' % win['name']) else: info('create window %s' % win['name']) window = self.session.new_window(win['name']) exist_num_panes = len(window.list_panes()) while exist_num_panes < len(win['panes']): info('new pane needed in window %s' % win['name']) window.split_window(vertical=1) exist_num_panes = len(window.list_panes()) window.cmd('select-layout', 'tiled') def find_window(self, window_name): for win in self.config['windows']: if win['name'] == window_name: window = self.session.find_where({"window_name": win['name']}) #window.select_window() return win, window def send_ctrlc(self, pane): datestr = datetime.now().strftime('%c') pane.cmd("send-keys", "", "C-c") pane.cmd("send-keys", "", "C-c") pane.cmd("send-keys", "", "C-c") pane.send_keys('# tmux-controller sent Ctrl-C at %s' % datestr, enter=True, suppress_history=True) def launch_window(self, window_name, enter=True): info('launch %s' % window_name) winconf, window = self.find_window(window_name) pane_no = 0 datestr = datetime.now().strftime('%c') for cmd in winconf['panes']: pane = window.select_pane(pane_no) self.send_ctrlc(pane) pane.send_keys('# tmux-controller starts new command %s' % datestr, enter=True, suppress_history=True) if 'init_cmd' in self.config: pane.send_keys(self.config['init_cmd'], enter=enter, suppress_history=False) pane.send_keys(cmd, enter=enter, suppress_history=False) pane_no += 1 winconf['_running'] = True def launch_all_windows(self): for winconf in self.config['windows']: self.launch_window(winconf['name']) def stop_all_windows(self): for winconf in self.config['windows']: self.stop_window(winconf['name']) def get_children_pids_all_windows(self): pids = [] for winconf in self.config['windows']: pids.extend(self.get_children_pids_window(winconf['name'])) return pids def kill_all_windows(self): for winconf in self.config['windows']: self.kill_window(winconf['name']) self.server.kill_session(self.session_name) def stop_window(self, window_name): info('stop %s' % window_name) winconf, window = self.find_window(window_name) self._stop_window(winconf, window) def _stop_window(self, winconf, window): pane_no = 0 for cmd in winconf['panes']: pane = window.select_pane(pane_no) self.send_ctrlc(pane) pane_no += 1 pids = self._get_pids_window(window) sleep(.1) for p in pids: self._terminate(p) winconf['_running'] = False def kill_window(self, window_name): info('terminate %s' % window_name) winconf, window = self.find_window(window_name) # "-F '#{pane_active} #{pane_pid}") self._stop_window(winconf, window) pids = self._get_pids_window(window) for pid in pids: Process(pid).terminate() winconf['_running'] = False def list_windows(self): return [w['name'] for w in self.config['windows']] def get_pids_window(self, window_name): winconf, window = self.find_window(window_name) return self._get_pids_window(window) def _get_pids_window(self, window): r = window.cmd('list-panes', "-F #{pane_pid}") return [int(p) for p in r.stdout] def get_children_pids_window(self, window_name): winconf, window = self.find_window(window_name) return self._get_children_pids_window(window) def _get_children_pids_window(self, window): winpids = self._get_pids_window(window) pids = [] for pid in winpids: pids.extend(self._get_children_pids(pid)) return [p.pid for p in pids] def is_running(self, window_name): winconf, window = self.find_window(window_name) pids = self._get_children_pids_window(window) if len(pids) < 1: return False if 'check' in winconf: info('need to run check command') if call(winconf['check'], shell=True) == 0: return True else: return False else: return True def _server(self): import webnsock import web tmux_self = self class TMuxWebServer(webnsock.WebServer): def __init__(self): webnsock.WebServer.__init__(self) self._render = web.template.render(path.realpath( path.join(path.dirname(__file__), 'www')), base="base", globals=globals()) self_app = self class Index(self.page): path = '/' def GET(self): return self_app._render.index(tmux_self.config) class Log(self.page): path = '/log' def GET(self): lines = tmux_self.server.cmd('capture-pane', '-p', '-C', '-S', '-100000').stdout return '\n'.join(lines) class TMuxWSProtocol(webnsock.JsonWSProtocol): def __init__(self): super(TMuxWSProtocol, self).__init__() def on_button(self, payload): info('button pressed: \n%s' % pformat(payload)) window_name = payload['id'] cmd = payload['cmd'] if cmd == 'launch': if window_name == '': tmux_self.launch_all_windows() else: tmux_self.launch_window(window_name) elif cmd == 'stop': if window_name == '': tmux_self.stop_all_windows() else: tmux_self.stop_window(window_name) elif cmd == 'terminate': tmux_self.kill_all_windows() sleep(1) tmux_self.init() sleep(1) self.sendJSON(self.on_status()) def on_status(self, payload=None): info('status-requested: ') res = {'windows': {}, 'method': 'update_status'} for w in tmux_self.config['windows']: res['windows'][w['name']] = tmux_self.is_running(w['name']) return res #return {'button_outcome': True} self.webserver = webnsock.WebserverThread(TMuxWebServer(), port=9999) self.backend = webnsock.WSBackend(TMuxWSProtocol) signal.signal( signal.SIGINT, lambda s, f: webnsock.signal_handler( self.webserver, self.backend, s, f)) self.webserver.start() self.backend.talker(port=9998)
import os import subprocess from libtmux import Server from libtmux.exc import LibTmuxException from pystdlib import shell_cmd tmux_server = Server() def term_create_window(cmd, term_cmd=None): if type(term_cmd) not in [list, str]: raise ValueError(f"invalid `term_cmd` type: {type(term_cmd)}") if type(term_cmd) is str: term_cmd = term_cmd.split() if len(cmd) > 0: term_cmd.extend(cmd.split(" ")) shell_cmd(" ".join(term_cmd)) def tmux_create_window(cmd, session_name, window_title, create_if_not=True, attach=True, attach_window=True, start_directory=None): window = None try: session = tmux_server.find_where({"session_name": session_name})
# Check if executable file exists. if not os.path.isfile(args.executable): raise SystemExit('%s: file does not exist!' % args.elf) uae = FSUAE() uae.configure(floppy=args.floppy, rom=args.rom, executable=args.executable) ser_port = SOCAT('serial') ser_port.configure(tcp_port=8000) par_port = SOCAT('parallel') par_port.configure(tcp_port=8001) subprocess.run(['tmux', '-f', TMUX_CONF, '-L', SOCKET, 'start-server']) server = Server(config_file=TMUX_CONF, socket_name=SOCKET) if server.has_session(SESSION): server.kill_session(SESSION) session = server.new_session(session_name=SESSION, attach=False, window_name=':0', window_command='sleep 1') try: uae.start(session) ser_port.start(session) par_port.start(session) session.kill_window(':0')
enter=True) ntsim = logging.split_window(attach=False, vertical=True) ntsim.send_keys('echo "ntsim"', enter=True) ntsim.send_keys( 'docker exec -it ntsim-ng-o-du-1122 tail -f /opt/dev/ntsim-ng/log/log.txt', enter=True) ves = logging.split_window(attach=False, vertical=False) ves.send_keys('echo "ves"', enter=True) ves.send_keys('docker logs -f ves-collector', enter=True) env = ntsim.split_window(attach=False, vertical=False) env.send_keys('htop', enter=True) # main server = Server() session = server.find_where({"session_name": "integration"}) workspace = session.select_window("workspace") pane = workspace.list_panes()[0] # pane.send_keys('clear', enter=True) pane.send_keys('cat README.md', enter=True) pane.send_keys('docker ps -a', enter=True) # create logging window, if needed logging = session.find_where({'window_name': 'logging'}) if logging is None: createLoggingWindow()
def test_config(server): """``-f`` file for tmux(1) configuration.""" myserver = Server(config_file="test") assert myserver.config_file == "test"