cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# -*- coding: utf-8 -*-
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# $Id$
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncTest Manager WUI - Log viewer
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync__copyright__ = \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCopyright (C) 2012-2014 Oracle Corporation
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThis file is part of VirtualBox Open Source Edition (OSE), as
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncavailable from http://www.virtualbox.org. This file is free software;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncyou can redistribute it and/or modify it under the terms of the GNU
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncGeneral Public License (GPL) as published by the Free Software
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncFoundation, in version 2 as it comes in the "COPYING" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution. VirtualBox OSE is distributed in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsynchope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThe contents of this file may alternatively be used under the terms
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncof the Common Development and Distribution License Version 1.0
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync(CDDL) only, as it comes in the "COPYING.CDDL" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution, in which case the provisions of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCDDL are applicable instead of those of the GPL.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncYou may elect to license modified versions of this file under the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncterms and conditions of either the GPL or the CDDL or both.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync__version__ = "$Revision$"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Validation Kit imports.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom common import webutils;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.testset import TestSetData;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.webui.wuicontentbase import WuiContentBase, WuiTmLink;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.webui.wuimain import WuiMain;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass WuiLogViewer(WuiContentBase):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Log viewer."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def __init__(self, oTestSet, oLogFile, cbChunk, iChunk, oDisp = None, fnDPrint = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiContentBase.__init__(self, oDisp = oDisp, fnDPrint = fnDPrint);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oTestSet = oTestSet;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oLogFile = oLogFile;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._cbChunk = cbChunk;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._iChunk = iChunk;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _generateNavigation(self, cbFile):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Generate the HTML for the log navigation."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dParams = {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamAction: WuiMain.ksActionViewLog,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamLogSetId: self._oTestSet.idTestSet,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamLogFileId: self._oLogFile.idTestResultFile,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamLogChunkSize: self._cbChunk,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamLogChunkNo: self._iChunk,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync };
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # The page walker.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dParams2 = dict(dParams);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync del dParams2[WuiMain.ksParamLogChunkNo];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHrefFmt = '<a href="?%s&%s=%%s" title="%%s">%%s</a>' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (webutils.encodeUrlParams(dParams2).replace('%', '%%'), WuiMain.ksParamLogChunkNo,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtmlWalker = self.genericPageWalker(self._iChunk, (cbFile + self._cbChunk - 1) / self._cbChunk,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHrefFmt, 11, 0, 'chunk');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # The chunk size selector.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dParams2 = dict(dParams);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync del dParams2[WuiMain.ksParamLogChunkSize];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtmlSize = '<form name="ChunkSizeForm" method="GET">\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' Max <select name="%s" onchange="window.location=\'?%s&%s=\' + ' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'this.options[this.selectedIndex].value;" title="Max items per page">\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % ( WuiMain.ksParamLogChunkSize, webutils.encodeUrlParams(dParams2), WuiMain.ksParamLogChunkSize,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for cbChunk in [ 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 4194304, 8388608, 16777216 ]:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtmlSize += ' <option value="%d" %s>%d bytes</option>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (cbChunk, 'selected="selected"' if cbChunk == self._cbChunk else '', cbChunk);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtmlSize += ' </select> per page\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync '</form>\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Download links.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oRawLink = WuiTmLink('View Raw', '',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { WuiMain.ksParamAction: WuiMain.ksActionGetFile,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamGetFileSetId: self._oTestSet.idTestSet,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamGetFileId: self._oLogFile.idTestResultFile,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamGetFileDownloadIt: False,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTitle = '%u MiB' % ((cbFile + 1048576 - 1) / 1048576,) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oDownloadLink = WuiTmLink('Download Log', '',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { WuiMain.ksParamAction: WuiMain.ksActionGetFile,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamGetFileSetId: self._oTestSet.idTestSet,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamGetFileId: self._oLogFile.idTestResultFile,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WuiMain.ksParamGetFileDownloadIt: True,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTitle = '%u MiB' % ((cbFile + 1048576 - 1) / 1048576,) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestSetLink = WuiTmLink('Test Set', '',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { WuiMain.ksParamAction: WuiMain.ksActionTestResultDetails,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TestSetData.ksParam_idTestSet: self._oTestSet.idTestSet,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync });
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Combine the elements and return.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return '<div class="tmlogviewernavi">\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <table width=100%>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <tr>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td width=20%>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' ' + oTestSetLink.toHtml() + '\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' ' + oRawLink.toHtml() + '\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' ' + oDownloadLink.toHtml() + '\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' </td>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td width=60% align=center>' + sHtmlWalker + '</td>' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' <td width=20% align=right>' + sHtmlSize + '</td>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' </tr>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' </table>\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync '</div>\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _displayLog(self, oFile, offFile, cbFile):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Displays the current section of the log file."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offEnd = offFile + self._cbChunk;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if offEnd > cbFile:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offEnd = cbFile;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Here is an annoying thing, we cannot seek in zip file members. So,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # since we have to read from the start, we can just as well count line
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # numbers while we're at it.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offCur = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iLine = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync while True:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sLine = oFile.readline().decode('utf-8', 'replace');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offLine = offCur;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iLine += 1;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offCur += len(sLine);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if offCur >= offFile or len(sLine) == 0:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Got to where we wanted, format the chunk.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtml = '\n<div class="tmlog">\n<pre>\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync while True:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtml += '<a id="L%d" href="#L%d">%05d</a><a id="O%d"> </a>%s\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (iLine, iLine, iLine, offLine, webutils.escapeElem(sLine.rstrip()));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if offCur >= offEnd:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sLine = oFile.readline().decode('utf-8', 'replace');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offLine = offCur;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iLine += 1;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offCur += len(sLine);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if len(sLine) == 0:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtml += '<pre/></div>\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return sHtml;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def show(self):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Shows the log."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self._oLogFile.sDescription not in [ '', None ]:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTitle = '%s - %s' % (self._oLogFile.sFile, self._oLogFile.sDescription);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTitle = '%s' % (self._oLogFile.sFile,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Open the log file. No universal line endings here.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (oFile, oSizeOrError, _) = self._oTestSet.openFile(self._oLogFile.sFile, 'rb');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oFile is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return (sTitle, '<p>%s</p>\n' % (webutils.escapeElem(oSizeOrError),),);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cbFile = oSizeOrError;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Generate the page.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Start with a focus hack.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtml = '<div id="tmlogoutdiv" tabindex="0">\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync '<script lang="text/javascript">\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'document.getElementById(\'tmlogoutdiv\').focus();\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync '</script>\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sNaviHtml = self._generateNavigation(cbFile);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtml += sNaviHtml;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offFile = self._iChunk * self._cbChunk;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if offFile < cbFile:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtml += self._displayLog(oFile, offFile, cbFile);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtml += sNaviHtml;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sHtml += '<p>End Of File</p>';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return (sTitle, sHtml);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync