#! /usr/bin/env python3 import cairo import datetime import gi import os import shlex import sys import time gi.require_version('Gdk', '3.0') gi.require_version('Gtk', '3.0') from gi.repository import Gdk from gi.repository import GLib from gi.repository import Gtk import uproctrace.processes def cmdline2str(cmdline: list) -> str: """ Convert command line to string. """ if cmdline is None: return "???" return ' '.join([shlex.quote(s) for s in cmdline]) def timestamp2str(timestamp: float) -> str: """ Convert a timestamp to a human-reable time string." """ if timestamp is None: return "???" sec = int(timestamp) nsec = int((timestamp - sec) * 1e9) time_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(sec)) return time_str + f'.{nsec:09d}' class UptGui: def __init__(self, proto_filename): """ Construct the GUI. """ self.builder = Gtk.Builder() script_dir = os.path.dirname(os.path.abspath(__file__)) self.builder.add_from_file(os.path.join(script_dir, 'upt-gui.glade')) self.widProcessesTree = self.builder.get_object('ProcessesTree') self.widProcessesView = self.builder.get_object('ProcessesView') handlers = {'onDestroy': self.onDestroy} self.builder.connect_signals(handlers) # open trace file self.openTrace(proto_filename) def onDestroy(self, widget): """ Window will be destroyed. """ Gtk.main_quit() def openTrace(self, proto_filename: str): """ Open a trace file. """ # forget old data self.widProcessesTree.clear() # lead new data with open(proto_filename, 'rb') as proto_file: self._processes = uproctrace.processes.Processes(proto_file) # add processes to processes tree store to_be_output = [(self._processes.toplevel, None)] while to_be_output: procs, parent_iter = to_be_output[-1] if not procs: del to_be_output[-1] continue proc = procs[0] del procs[0] proc_iter = self.widProcessesTree.append(parent_iter) self.widProcessesTree.set_value(proc_iter, 0, proc.proc_id) self.widProcessesTree.set_value(proc_iter, 1, timestamp2str(proc.begin_timestamp)) self.widProcessesTree.set_value(proc_iter, 2, timestamp2str(proc.end_timestamp)) self.widProcessesTree.set_value(proc_iter, 3, cmdline2str(proc.cmdline)) to_be_output.append((proc.children, proc_iter)) # show all processes self.widProcessesView.expand_all() def main(argv): """ Main program. """ if len(argv) < 2: print('usage: ' + argv[0] + ' ', file=sys.stderr) return 2 proto_filename = argv[1] app = UptGui(proto_filename) try: Gtk.main() except KeyboardInterrupt: pass return 0 if __name__ == '__main__': sys.exit(main(sys.argv))