1# -*- coding: utf-8 -*- 2# 3# Copyright 2016 Jerome Duval 4# Distributed under the terms of the MIT License. 5 6# -- Modules ------------------------------------------------------------------ 7 8import curses 9import datetime 10import time 11 12 13class DisplayContext(object): 14 def __init__(self): 15 self.stdscr = None 16 def __enter__(self): 17 self.stdscr = curses.initscr() 18 curses.noecho() 19 curses.cbreak() 20 self.stdscr.keypad(1) 21 try: 22 curses.start_color() 23 curses.curs_set(0) 24 except: 25 pass 26 return self 27 def __exit__(self, ignoredType, value, traceback): 28 if self.stdscr: 29 curses.curs_set(2) 30 self.stdscr.keypad(0) 31 curses.echo() 32 curses.nocbreak() 33 curses.endwin() 34 35 36class Display(object): 37 def __init__(self, stdscr, builders_used): 38 self.builders_used = builders_used 39 40 termsize = stdscr.getmaxyx() 41 y, x = termsize 42 ncols = 80 43 44 curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK) 45 curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK) 46 curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK) 47 curses.init_pair(4, curses.COLOR_YELLOW, curses.COLOR_BLACK) 48 curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_BLACK) 49 curses.init_pair(6, curses.COLOR_CYAN, curses.COLOR_BLACK) 50 curses.init_pair(7, curses.COLOR_BLUE, curses.COLOR_BLACK) 51 curses.init_pair(8, curses.COLOR_MAGENTA, curses.COLOR_BLACK) 52 curses.init_pair(9, curses.COLOR_BLUE, curses.COLOR_WHITE) 53 self.c_standard = curses.color_pair(1) 54 self.c_success = curses.color_pair(2) 55 self.c_failure = curses.color_pair(3) 56 self.c_lost = curses.color_pair(4) 57 self.c_blocked = curses.color_pair(5) 58 self.c_sumlabel = curses.color_pair(6) | curses.A_BOLD 59 self.c_dashes = curses.color_pair(7) | curses.A_BOLD 60 self.c_duration = curses.color_pair(4) 61 self.c_tableheader = curses.color_pair(1) 62 self.c_portname = curses.color_pair(6) 63 self.c_bldphase = curses.color_pair(4) 64 self.c_shutdown = curses.color_pair(1) 65 self.c_advisory = curses.color_pair(4) 66 67 self.c_slave = [] 68 self.c_slave.append(curses.color_pair(1) | curses.A_BOLD) 69 self.c_slave.append(curses.color_pair(2) | curses.A_BOLD) 70 self.c_slave.append(curses.color_pair(4) | curses.A_BOLD) 71 self.c_slave.append(curses.color_pair(8) | curses.A_BOLD) 72 self.c_slave.append(curses.color_pair(3) | curses.A_BOLD) 73 self.c_slave.append(curses.color_pair(7) | curses.A_BOLD) 74 self.c_slave.append(curses.color_pair(6) | curses.A_BOLD) 75 self.c_slave.append(curses.color_pair(5) | curses.A_BOLD) 76 self.c_slave.append(curses.color_pair(1)) 77 self.c_slave.append(curses.color_pair(2)) 78 self.c_slave.append(curses.color_pair(4)) 79 self.c_slave.append(curses.color_pair(8)) 80 self.c_slave.append(curses.color_pair(3)) 81 self.c_slave.append(curses.color_pair(7)) 82 self.c_slave.append(curses.color_pair(6)) 83 self.c_slave.append(curses.color_pair(9)) 84 85 for i in range(16): 86 self.c_slave.append(self.c_slave[i] | curses.A_UNDERLINE) 87 for i in range(32): 88 self.c_slave.append(self.c_slave[i]) 89 90 self.zone_summary = curses.newwin(2, ncols, 0, 0) 91 self.zone_builders = curses.newwin(self.builders_used+4, ncols, 2, 0) 92 self.maxrows = y - (self.builders_used+4+2) 93 self.zone_history = curses.newwin(self.maxrows, ncols, 94 self.builders_used+4+2, 0) 95 96 self.zone_summary.addstr(0, 0, 97 " Total Built Ignored Load 0.00 Pkg/hour ", 98 self.c_sumlabel) 99 self.zone_summary.addstr(1, 0, 100 " Left Failed Skipped Swap 0.0% Impulse 0:00:00 ", 101 self.c_sumlabel) 102 103 dashes = "=" * (ncols-1) 104 self.zone_builders.addstr(0, 0, dashes, self.c_dashes) 105 self.zone_builders.addstr(2, 0, dashes, self.c_dashes) 106 self.zone_builders.addstr(self.builders_used+4-1, 0, dashes, 107 self.c_dashes) 108 109 self.zone_builders.addstr(1, 0, 110 " ID Duration Build Phase Port Name Lines ", 111 self.c_tableheader) 112 for i in range(3, self.builders_used + 4 - 1): 113 self.zone_builders.addstr(i, 0, " " * ncols, self.c_standard) 114 115 stdscr.refresh() 116 self.zone_summary.refresh() 117 self.zone_builders.refresh() 118 self.zone_history.refresh() 119 120 def updateSummary(self, data): 121 self.zone_summary.addstr(0, 7, str(data['builds']['total']).ljust(4), 122 self.c_standard) 123 self.zone_summary.addstr(0, 21, str(data['builds']['complete']).ljust(4), 124 self.c_success) 125 self.zone_summary.addstr(0, 37, str(data['builds']['blocked']).ljust(4), 126 self.c_blocked) 127 self.zone_summary.addstr(0, 64, str(data['pkg_hour']).ljust(5), 128 self.c_standard) 129 self.zone_summary.addstr(1, 7, str(data['builds']['scheduled'] 130 + data['builds']['active'] + data['builds']['blocked']).ljust(4), 131 self.c_standard) 132 self.zone_summary.addstr(1, 21, str(data['builds']['failed']).ljust(4), 133 self.c_failure) 134 self.zone_summary.addstr(0, 37, str(data['builds']['lost']).ljust(4), 135 self.c_lost) 136 self.zone_summary.addstr(1, 64, str(data['impulse']).ljust(5), 137 self.c_standard) 138 self.zone_summary.addstr(1, 70, str(datetime.timedelta( 139 seconds=int(data['duration']))).zfill(8) if data['duration'] 140 else ' ', self.c_duration) 141 self.zone_summary.refresh() 142 143 def updateBuilders(self, data): 144 builders = data['builders']['active'] 145 for i in range(0, self.builders_used): 146 currentBuild = builders[i]['currentBuild'] 147 self.zone_builders.addstr(3+i, 1, str(i+1).zfill(2)[:2], 148 self.c_slave[i]) 149 if currentBuild is None: 150 self.zone_builders.addstr(3+i, 5, ' ' * 75, self.c_standard) 151 continue 152 portName = currentBuild['build']['port']['revisionedName'] 153 self.zone_builders.addstr(3+i, 5, str(datetime.timedelta( 154 seconds=int(currentBuild['duration'])) 155 ).zfill(8)[:8] if currentBuild['duration'] else ' ', 156 self.c_standard) 157 self.zone_builders.addstr(3+i, 15, 158 currentBuild['phase'].ljust(12)[:12], self.c_bldphase) 159 self.zone_builders.addstr(3+i, 32, portName.ljust(38)[:38], 160 self.c_portname) 161 self.zone_builders.addstr(3+i, 71, 162 str(currentBuild['lines']).rjust(7)[:7], self.c_standard) 163 164 self.zone_builders.refresh() 165 166 def updateHistory(self, data): 167 row = 0 168 for build in list(reversed(data)): 169 current = build.status 170 if current is None: 171 self.zone_builders.addstr(row, 5, ' ' * 75, self.c_standard) 172 continue 173 self.zone_history.addstr(row, 10, 174 '[' + str(int(current['builderId'])+1).zfill(2)[:2] + ']', 175 self.c_slave[int(current['builderId'])]) 176 portName = current['port']['revisionedName'] 177 self.zone_history.addstr(row, 70, str(datetime.timedelta( 178 seconds=int(current['duration'])) 179 ).zfill(8)[:8] if current['duration'] else ' ', 180 self.c_standard) 181 self.zone_history.addstr(row, 15, 182 'success' if current['buildSuccess'] else 'failed ', 183 self.c_success if current['buildSuccess'] else self.c_failure) 184 self.zone_history.addstr(row, 24, portName.ljust(38)[:38], 185 self.c_portname) 186 self.zone_history.addstr(row, 1, time.strftime('%X', 187 time.localtime(current['startTime'])), self.c_standard) 188 row += 1 189 if row >= self.maxrows: 190 break 191 192 self.zone_history.refresh() 193