예제 #1
0
    def presentTaskFilter(self, args: ReportTaskArgs) -> XMLContent:
        yield 'Showing data from ',

        execState = args.execState
        if execState is not ExecutionState.ALL:
            yield xhtml.b[execState.name.lower()], ' '

        taskNames = args.task
        yield xhtml[', '].join(xhtml.b[name] for name in sorted(taskNames))
        yield ' tasks'

        owners = args.owner
        if owners:
            yield ' owned by '
            yield xhtml[', '].join(xhtml.b[name] for name in sorted(owners))

        targets = args.target
        if targets:
            yield ' for ', pluralize('target', len(targets)), ' '
            yield xhtml[', '].join(xhtml.b[name] for name in sorted(targets))

        ctabove = args.ctabove
        ctbelow = args.ctbelow
        if ctabove and ctbelow:
            yield (' created between ', xhtml.b[formatTime(ctabove)], ' and ',
                   xhtml.b[formatTime(ctbelow)])
        elif ctabove:
            yield ' created after ', xhtml.b[formatTime(ctabove)]
        elif ctbelow:
            yield ' created before ', xhtml.b[formatTime(ctbelow)]

        yield '.'
예제 #2
0
def testScheduleWeeklyStartCorrection(sim):
    """Test weekly schedule for which the start time should be corrected
    to the next available selected day.
    """

    configId = sim.createConfig().getId()

    def timeOnDay(day):
        return int(time.mktime((2007, 1, day, 13, 0, 0, 0, 1, 0)))

    # Create 3 schedules always for Wednesday:
    # 1st is dated 2007-01-01, should be corrected to 2007-01-03
    # 2nd is dated 2007-01-03, should not changed
    # 3rd is dated 2007-01-05, should be corrected to 2007-01-10
    scheduledTimes = []
    for scheduledDay, correctedDay in (1, 3), (3, 3), (5, 10):
        startTime = timeOnDay(scheduledDay)
        schedId = 'WeeklyStartCorrection_%d' % scheduledDay
        scheduledTimes.append((schedId, startTime, timeOnDay(correctedDay)))
        sim.createSchedule(schedId,
                           False,
                           startTime,
                           ScheduleRepeat.WEEKLY,
                           days='0010000',
                           configFactory=sharedConfigFactory(configId))
        scheduled = sim.databases.scheduleDB.get(schedId)
        assert getScheduleStatus(sim.databases.configDB, scheduled) == 'ok'

    # Run simulation for 4 weeks.
    sim.wait(4 * secondsPerWeek, check=lambda: None)

    # Validate the results.
    assert set(sim.databases.jobDB) == set(sim.jobs)
    for schedId, scheduledTime, correctedTime in scheduledTimes:
        jobsFromSchedule = [
            job for job in sim.jobs if job.getScheduledBy() == schedId
        ]
        assert 3 <= len(jobsFromSchedule) <= 4, jobsFromSchedule
        prevCreationTime = None
        for job in jobsFromSchedule:
            creationTime = job['timestamp']
            if prevCreationTime is None:
                assert scheduledTime <= creationTime, '%s > %s' % \
                    ( formatTime(scheduledTime), formatTime(creationTime) )
                assert creationTime == correctedTime, '%s != %s' % \
                    ( formatTime(creationTime), formatTime(correctedTime) )
            else:
                assert creationTime - prevCreationTime == secondsPerWeek, \
                    'There is not exactly 1 week between two job runs'
            prevCreationTime = creationTime
예제 #3
0
 def abort(self, user: Optional[str] = None) -> Tuple[bool, str]:
     '''Attempts to abort this task.
     Returns a pair of a boolean and a message string.
     The boolean is True if this task was cancelled or marked for abortion
     and False if this task cannot be aborted.
     '''
     whoAborted = ' by user%s at %s' % (
         '' if user is None else f' "{user}"', formatTime(getTime())
         )
     if self.isRunning():
         if 'abort' in self._properties:
             return False, 'was already being aborted'
         else:
             self._properties['abort'] = 'true'
             self._properties['summary'] = 'aborted' + whoAborted
             self._notify()
             return True, 'will be aborted shortly'
     elif self.isWaiting():
         self.cancelled('cancelled' + whoAborted)
         return True, 'has been aborted'
     elif self.isWaitingForInspection():
         self.__setState(
             ResultCode.ERROR, 'done',
             'postponed inspection cancelled' + whoAborted
             )
         return True, 'had its postponed inspection cancelled'
     else:
         return False, 'was not waiting or running'
예제 #4
0
    def iterRows(self, proc: Processor) -> Iterator[Sequence[str]]:
        tasks = proc.tasks
        taskRunDB = proc.taskRunDB

        # Determine all keys that exist for the given task names.
        keys = sorted(union(
            taskRunDB.getKeys(taskName) for taskName in proc.args.task
            ))

        yield [ 'create date', 'create time', 'result' ] + keys
        for task in tasks:
            taskName = task.getName()
            taskKeys = taskRunDB.getKeys(taskName)
            # TODO: Which properties are useful to export?
            timestamp = formatTime(task.getJob().getCreateTime())
            # Assuming format "2008-09-16 15:21"
            results = [timestamp[:10], timestamp[-5:], getTaskStatus(task)]
            for key in keys:
                if key in taskKeys:
                    # TODO: Querying one run at a time is not really efficient.
                    data = list(taskRunDB.getData(
                        taskName, [ task.getLatestRun().getId() ], key
                        ))
                    if len(data) == 0:
                        results.append('')
                    else:
                        assert len(data) == 1
                        value = data[0][1]
                        results.append(str(value))
                else:
                    results.append('')
            yield results
예제 #5
0
def describeNextRun(schedule: Scheduled) -> XMLContent:
    '''Returns a description of when the schedule is next expected to run.
    '''

    # A "once" schedule that is finished never runs again.
    if schedule.isDone():
        return 'done'

    # Compute some useful predicates.
    repeat = schedule.repeat
    waiting = repeat in (ScheduleRepeat.CONTINUOUSLY,
                         ScheduleRepeat.TRIGGERED) and schedule.isRunning()
    suspended = schedule.isSuspended()

    # Look for future start time.
    startTime = schedule.startTime
    if startTime != asap:
        return (('\u2265 ' if waiting or suspended else '= ')  # ">=" or "="
                + formatTime(startTime))

    # Schedule should start ASAP; tell user why it hasn't started yet.
    if repeat is ScheduleRepeat.TRIGGERED and not schedule['trigger']:
        return 'not triggered'
    if waiting:
        return 'waiting for last run to finish'

    # Suspend is checked last to be consistent with getScheduleStatus().
    if suspended:
        return 'suspended'

    # We are out of reasons.
    # This can happen between a schedule becoming ready to start and
    # the ScheduleManager actually starting it, but because that time
    # is really short, it is unlikely the user will see this value.
    return 'now'
예제 #6
0
 def iterRows(self, **kwargs: Any) -> Iterator[XMLContent]:
     job: Job = kwargs['job']
     for task in job.getTaskSequence():
         yield row(class_=task.result)[
             task.getName(),
             formatTime(task.startTime),
             cell(class_='rightalign')[formatDuration(task.getDuration())],
             taskSummary(task), task.result]
예제 #7
0
 def iterRows(self, **kwargs: object) -> Iterator[XMLContent]:
     proc = cast(FabPage.Processor, kwargs['proc'])
     yield 'Up since', (formatTime(getBootTime()))
     dbVersion = proc.project.dbVersion
     yield 'Database version', (
         dbVersion if parseVersion(dbVersion)[:2]
         == parseVersion(softFabVersion)[:2] else xhtml.span(
             style='color: red')[dbVersion +
                                 ' (database must be upgraded)'])
예제 #8
0
 def presentHeader(self, **kwargs: object) -> XMLContent:
     proc = cast(ProcT, kwargs['proc'])
     ccURL = cast(str, kwargs['ccURL'])
     userName = proc.user.name
     return xhtml.div(class_='titlebar')[
         xhtml.div(class_='title')[self.__title(proc)],
         xhtml.div(class_='info')[xhtml.a(
             href=ccURL +
             self.loginURL(**kwargs))['log in'] if userName is None else
                                  (createUserDetailsLink(userName).present(
                                      **kwargs), ' \u2013 ',
                                   xhtml.a(href=ccURL +
                                           logoutURL(proc.req))['log out']),
                                  xhtml.br,
                                  formatTime(getTime())],
         xhtml.div(
             class_='logo'
         )[xhtml.a(href=ccURL +
                   'About', title=f'SoftFab {VERSION}')[_logoIcon.present(
                       **kwargs)]]]
예제 #9
0
    def iterRows(self, **kwargs: object) -> Iterator[XMLContent]:
        proc = cast(TaskRunnerDetails_GET.Processor, kwargs['proc'])
        runner = proc.taskRunner
        if runner is None:
            # Note: This is also reachable through auto-refresh of older
            #       renderings of the page.
            yield '-', ('Task Runner ', xhtml.b[proc.args.runnerId],
                        ' does not exist (anymore).')
            return

        yield 'Description', runner.description
        yield 'Version', runner['runnerVersion']
        yield 'Host', runner['host']
        yield 'Token ID', runner.token.getId()
        targets = proc.project.getTargets()
        yield 'Targets', presentCapabilities(runner.capabilities & targets,
                                             taskRunnerResourceTypeName)
        yield 'Other capabilities', presentCapabilities(
            runner.capabilities - targets, taskRunnerResourceTypeName)
        lastSync = cast(Optional[int], runner['lastSync'])
        yield 'Time since last sync', formatDuration(lastSync)
        run = runner.getRun()
        yield 'Current job', ('-' if run is None else createJobLink(
            cast(str, run['jobId'])))
        yield 'Current task', createTaskLink(runner)
        yield 'Duration', formatDuration(run.getDuration() if run else None)
        status = getResourceStatus(runner)
        yield row(class_=status)['Status', status]
        yield 'Exit when idle', 'yes' if runner.shouldExit() else 'no'
        yield 'Suspended', 'yes' if runner.isSuspended() else 'no'

        label = 'Last suspended' if runner.isSuspended() else 'Last resumed'
        changedTime = runner.getChangedTime()
        if changedTime:
            changeDesc = 'by %s at %s' % (runner.getChangedUser() or 'unknown',
                                          formatTime(changedTime))
        else:
            changeDesc = 'never'
        yield label, changeDesc
예제 #10
0
 def generateBars() -> XMLContent:
     assert maxValue is not None  # work around mypy issue 2608
     for task, value in dataPoints:
         run = task.getLatestRun()
         if value is None:
             valueDescription = 'no value'
             barClass = 'graphbarnoval'
             height = graphHeight
         else:
             valueDescription = str(value)
             barClass = 'graphbar'
             # We cannot plot negative values, so clip to 0.
             height = max(value, 0) * graphHeight // maxValue
         url = createRunURL(run, 'data')
         yield xhtml.td(
             title='%s - %s' %
             (formatTime(run.getJob().getCreateTime()), valueDescription),
             onclick=f"document.location='{url}'")[xhtml.table(
                 class_=barClass,
                 style=f'width: {barWidth:d}px; height: {height:d}px')[
                     xhtml.tbody[xhtml.tr[xhtml.td]]]]
     yield xhtml.td(class_='raxis')[((str(mark * roundMarkValue), xhtml.br)
                                     for mark in range(numMarks, 0, -1))]
예제 #11
0
 def presentCell(self, record: Record, **kwargs: object) -> XMLContent:
     key = self.keyDisplay
     assert key is not None
     return formatTime(cast(Optional[int], record[key]))
예제 #12
0
def timeValue(seconds: Optional[int]) -> str:
    return '' if seconds is None else formatTime(seconds)
예제 #13
0
def createLastJobLink(schedule: Scheduled) -> XML:
    return maybeLink(createJobsURL(schedule.getLastJobs()))[formatTime(
        schedule.lastRunTime)]
예제 #14
0
 def externalize(self, value: Optional[int]) -> str:
     return formatTime(value)