<commit_before>#
# Copyright (c) 2006-2007 rPath, Inc.  All Rights Reserved.
#
"""
Monitor replacement under test.

This monitor replacement is better for jobs that are building many troves at
once.  It doesn't try to print all of their logs at once.
"""
import fcntl
import os
import select
import sys
import time
import tempfile
import termios
import traceback

from conary.lib import util

from rmake import errors
from rmake import subscribers
from rmake.build import buildjob, buildtrove
from rmake.cmdline import query
from rmake.lib.apiutils import thaw, freeze
from rmake.lib import rpclib, localrpc
from rmake.subscribers import xmlrpc

from rmake.cmdline import monitor
from rmake.plugins import plugin

oldMonitorJob = monitor.monitorJob

class MonitorPlugin(plugin.ClientPlugin):
    def client_preInit(self, main, argv):
        if sys.stdout.isatty() and sys.stdin.isatty():
            monitor.monitorJob = monitorJob

def monitorJob(*args, **kw):
    kw.setdefault('displayClass', DisplayManager)
    return oldMonitorJob(*args, **kw)


def set_raw_mode():
    fd = sys.stdin.fileno()
    oldTerm = termios.tcgetattr(fd)
    newattr = termios.tcgetattr(fd)
    newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
    termios.tcsetattr(fd, termios.TCSANOW, newattr)
    oldFlags = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldFlags | os.O_NONBLOCK)
    return oldTerm, oldFlags

def restore_terminal(oldTerm, oldFlags):
    fd = sys.stdin.fileno()
    if oldTerm:
        termios.tcsetattr(fd, termios.TCSAFLUSH, oldTerm)
    if oldFlags:
        fcntl.fcntl(fd, fcntl.F_SETFL, oldFlags)


class _AbstractDisplay(xmlrpc.BasicXMLRPCStatusSubscriber):
    def __init__(self, client, showBuildLogs=True, out=None):
        self.client = client
        self.finished = False
        self.showBuildLogs = showBuildLogs
        self.troveStates = {}
        self.troveIndex = None
        self.troveDislay = False
        self.out = OutBuffer(out)

    def close(self):
        pass

    def _msg(self, msg, *args):
        self.out.write('\r[%s] %s\n' % (time.strftime('%X'), msg))
        self.out.write('(h for help)>')
        self.out.flush()

    def _jobStateUpdated(self, jobId, state, status):
        isFinished = (state in (buildjob.JOB_STATE_FAILED,
                                buildjob.JOB_STATE_BUILT))
        if isFinished:
            self._setFinished()

    def _setFinished(self):
        self.finished = True

    def _isFinished(self):
        return self.finished

    def _shouldExit(self):
        return self._isFinished() and self.exitOnFinish

    def _primeOutput(self, jobId):
        job = self.client.getJob(jobId, withTroves=False)
        if job.isFinished():
            self._setFinished()

    def _dispatch(self, methodname, (callData, responseHandler, args)):
        if methodname.startswith('_'):
            raise NoSuchMethodError(methodname)
        else:
            responseHandler.sendResponse('')
            getattr(self, methodname)(*args)

class SilentDisplay(_AbstractDisplay):
    def _updateBuildLog(self):
        pass

class JobLogDisplay(_AbstractDisplay):

    def __init__(self, client, state, out=None):
        _AbstractDisplay.__init__(self, client, out)
        self.troveToWatch = None
        self.watchTroves = False
        self.buildingTroves = {}
        self.state = state
        self.lastLen = 0
        self.promptFormat = '%(jobId)s %(name)s%(context)s - %(state)s - (%(tailing)s) ([h]elp)>'
        self.updatePrompt()

    def close(self):
        self.out.write('\n')
        self.out.flush()

    def _msg(self, msg, *args):
        self.erasePrompt()
        self.out.write('[%s] %s\n' % (time.strftime('%X'), msg))
        self.writePrompt()

    def updatePrompt(self):
        if self.troveToWatch:
            if self.troveToWatch not in self.state.troves:
                self.troveToWatch = self.state.troves[0]
            state = self.state.getTroveState(*self.troveToWatch)
            state = buildtrove._getStateName(state)
            name = self.troveToWatch[1][0].split(':', 1)[0] # remove :source
            context = self.troveToWatch[1][3]
            d = dict(jobId=self.troveToWatch[0], name=name, state=state,
                     context=(context and '{%s}' % context or ''))
        else:
            d = dict(jobId='(None)', name='(None)', state='', context='')
        if not self.state.jobActive():
            tailing = 'Job %s' % self.state.getJobStateName()
        elif self.watchTroves:
            tailing = 'Details on'
        else:
            tailing = 'Details off'
        d['tailing'] = tailing
        self.prompt = self.promptFormat % d
        self.erasePrompt()
        self.writePrompt()

    def erasePrompt(self):
        self.out.write('\r%s\r' % (' '*self.lastLen))

    def writePrompt(self):
        self.out.write(self.prompt)
        self.lastLen = len(self.prompt)
        self.out.flush()

    def setWatchTroves(self, watchTroves=True):
        self.watchTroves = watchTroves
        self.updatePrompt()

    def getWatchTroves(self):
        return self.watchTroves

    def setTroveToWatch(self, jobId, troveTuple):
        self.troveToWatch = jobId, troveTuple
        self.updatePrompt()

    def _watchTrove(self, jobId, troveTuple):
        if not self.watchTroves:
            return False
        return self.troveToWatch == (jobId, troveTuple)

    def displayTroveStates(self):
        self.erasePrompt()
        job = self.client.getJob(self.troveToWatch[0])
        query.displayTrovesByState(job, out=self.out)
        self.writePrompt()

    def setPrompt(self, promptFormat):
        self.promptFormat = promptFormat
        self.updatePrompt()

    def updateBuildLog(self, jobId, troveTuple):
        if not self._watchTrove(jobId, troveTuple):
            return
        mark = self.getMark(jobId, troveTuple)
        if mark is None:
            return
        try:
            moreData, data, mark = self.client.getTroveBuildLog(jobId,
                                                                troveTuple,
                                                                mark)
        except:
            return
        if data:
            self.erasePrompt()
            if data[0] == '\n':
                data = data[1:]
            self.out.write(data)
            if data[-1] != '\n':
                self.out.write('\n')
            self.writePrompt()
        if not moreData:
            mark = None<commit_msg>RMK-632 - if there are no troves to watch, status cannot work<commit_after>#
# Copyright (c) 2006-2007 rPath, Inc.  All Rights Reserved.
#
"""
Monitor replacement under test.

This monitor replacement is better for jobs that are building many troves at
once.  It doesn't try to print all of their logs at once.
"""
import fcntl
import os
import select
import sys
import time
import tempfile
import termios
import traceback

from conary.lib import util

from rmake import errors
from rmake import subscribers
from rmake.build import buildjob, buildtrove
from rmake.cmdline import query
from rmake.lib.apiutils import thaw, freeze
from rmake.lib import rpclib, localrpc
from rmake.subscribers import xmlrpc

from rmake.cmdline import monitor
from rmake.plugins import plugin

oldMonitorJob = monitor.monitorJob

class MonitorPlugin(plugin.ClientPlugin):
    def client_preInit(self, main, argv):
        if sys.stdout.isatty() and sys.stdin.isatty():
            monitor.monitorJob = monitorJob

def monitorJob(*args, **kw):
    kw.setdefault('displayClass', DisplayManager)
    return oldMonitorJob(*args, **kw)


def set_raw_mode():
    fd = sys.stdin.fileno()
    oldTerm = termios.tcgetattr(fd)
    newattr = termios.tcgetattr(fd)
    newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
    termios.tcsetattr(fd, termios.TCSANOW, newattr)
    oldFlags = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldFlags | os.O_NONBLOCK)
    return oldTerm, oldFlags

def restore_terminal(oldTerm, oldFlags):
    fd = sys.stdin.fileno()
    if oldTerm:
        termios.tcsetattr(fd, termios.TCSAFLUSH, oldTerm)
    if oldFlags:
        fcntl.fcntl(fd, fcntl.F_SETFL, oldFlags)


class _AbstractDisplay(xmlrpc.BasicXMLRPCStatusSubscriber):
    def __init__(self, client, showBuildLogs=True, out=None):
        self.client = client
        self.finished = False
        self.showBuildLogs = showBuildLogs
        self.troveStates = {}
        self.troveIndex = None
        self.troveDislay = False
        self.out = OutBuffer(out)

    def close(self):
        pass

    def _msg(self, msg, *args):
        self.out.write('\r[%s] %s\n' % (time.strftime('%X'), msg))
        self.out.write('(h for help)>')
        self.out.flush()

    def _jobStateUpdated(self, jobId, state, status):
        isFinished = (state in (buildjob.JOB_STATE_FAILED,
                                buildjob.JOB_STATE_BUILT))
        if isFinished:
            self._setFinished()

    def _setFinished(self):
        self.finished = True

    def _isFinished(self):
        return self.finished

    def _shouldExit(self):
        return self._isFinished() and self.exitOnFinish

    def _primeOutput(self, jobId):
        job = self.client.getJob(jobId, withTroves=False)
        if job.isFinished():
            self._setFinished()

    def _dispatch(self, methodname, (callData, responseHandler, args)):
        if methodname.startswith('_'):
            raise NoSuchMethodError(methodname)
        else:
            responseHandler.sendResponse('')
            getattr(self, methodname)(*args)

class SilentDisplay(_AbstractDisplay):
    def _updateBuildLog(self):
        pass

class JobLogDisplay(_AbstractDisplay):

    def __init__(self, client, state, out=None):
        _AbstractDisplay.__init__(self, client, out)
        self.troveToWatch = None
        self.watchTroves = False
        self.buildingTroves = {}
        self.state = state
        self.lastLen = 0
        self.promptFormat = '%(jobId)s %(name)s%(context)s - %(state)s - (%(tailing)s) ([h]elp)>'
        self.updatePrompt()

    def close(self):
        self.out.write('\n')
        self.out.flush()

    def _msg(self, msg, *args):
        self.erasePrompt()
        self.out.write('[%s] %s\n' % (time.strftime('%X'), msg))
        self.writePrompt()

    def updatePrompt(self):
        if self.troveToWatch:
            if self.troveToWatch not in self.state.troves:
                self.troveToWatch = self.state.troves[0]
            state = self.state.getTroveState(*self.troveToWatch)
            state = buildtrove._getStateName(state)
            name = self.troveToWatch[1][0].split(':', 1)[0] # remove :source
            context = self.troveToWatch[1][3]
            d = dict(jobId=self.troveToWatch[0], name=name, state=state,
                     context=(context and '{%s}' % context or ''))
        else:
            d = dict(jobId='(None)', name='(None)', state='', context='')
        if not self.state.jobActive():
            tailing = 'Job %s' % self.state.getJobStateName()
        elif self.watchTroves:
            tailing = 'Details on'
        else:
            tailing = 'Details off'
        d['tailing'] = tailing
        self.prompt = self.promptFormat % d
        self.erasePrompt()
        self.writePrompt()

    def erasePrompt(self):
        self.out.write('\r%s\r' % (' '*self.lastLen))

    def writePrompt(self):
        self.out.write(self.prompt)
        self.lastLen = len(self.prompt)
        self.out.flush()

    def setWatchTroves(self, watchTroves=True):
        self.watchTroves = watchTroves
        self.updatePrompt()

    def getWatchTroves(self):
        return self.watchTroves

    def setTroveToWatch(self, jobId, troveTuple):
        self.troveToWatch = jobId, troveTuple
        self.updatePrompt()

    def _watchTrove(self, jobId, troveTuple):
        if not self.watchTroves:
            return False
        return self.troveToWatch == (jobId, troveTuple)

    def displayTroveStates(self):
        if not self.troveToWatch:
            return
        self.erasePrompt()
        job = self.client.getJob(self.troveToWatch[0])
        query.displayTrovesByState(job, out=self.out)
        self.writePrompt()

    def setPrompt(self, promptFormat):
        self.promptFormat = promptFormat
        self.updatePrompt()

    def updateBuildLog(self, jobId, troveTuple):
        if not self._watchTrove(jobId, troveTuple):
            return
        mark = self.getMark(jobId, troveTuple)
        if mark is None:
            return
        try:
            moreData, data, mark = self.client.getTroveBuildLog(jobId,
                                                                troveTuple,
                                                                mark)
        except:
            return
        if data:
            self.erasePrompt()
            if data[0] == '\n':
                data = data[1:]
            self.out.write(data)
            if data[-1] != '\n':
                self.out.write('\n')
            self.writePrompt()
        if not moreData:
            mark = None
{'fraction_non_alphanumeric': 0.10980899474925805, 'fraction_numerical': 0.003728787763488319, 'mean_word_length': 2.2978670012547053, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7452796', 'n_tokens_mistral': 4228, 'n_tokens_neox': 4076, 'n_words': 912}