blob: b79f39630e808cf8f494d51b30e0143fd5a5f83f [file] [log] [blame]
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Wrap everything we do with builds in a dash class."""
import commands
import json
import logging
import os
import re
import time
import urllib
import dash_util
# String resources.
from dash_strings import BUILDTIME_PREFIX
from dash_strings import LOCAL_TMP_DIR
from dash_strings import WGET_CMD
class BuildInfo(object):
"""Data and functions from build log."""
class __impl:
"""Nested class implements code wrapped by singleton."""
def __init__(self):
# Store build entries as {started_time, finished_time, chrome_version}
# indexed by board and build#.
self._build_time_cache = {}
self._formatted_time_cache = {}
self._chrome_version_cache = {}
self._chrome_parse = re.compile(
"^Started chromeos-base/chromeos-chrome-([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3})_rc.*", re.M)
def GetChromeVersion(self, board, build):
# Get the string w.x.y.z Chrome version and a zzzz svn revision.
self.FetchBuildInfo(board, build)
return self._build_time_cache[board][build]['chrome_version']
def GetStartedTime(self, board, build):
# This is a float - seconds since the epoch.
self.FetchBuildInfo(board, build)
return self._build_time_cache[board][build]['started_time']
def GetFinishedTime(self, board, build):
# This is a float - seconds since the epoch.
self.FetchBuildInfo(board, build)
return self._build_time_cache[board][build]['finished_time']
def GetElapsedTime(self, board, build):
# This is a float.
return (
self.GetFinishedTime(board, build) -
self.GetStartedTime(board, build))
def GetFormattedTime(self, time_seconds, short=None):
if short:
# Formatted as: Wed 09/08 12:37.
result = time.strftime('%a %m/%d %H:%M', time.localtime(time_seconds))
else:
# Formatted as: Wed Sep 8 12:37:56 2010.
result = time.ctime(time_seconds)
return result
def GetFormattedStartedTime(self, board, build, short=None):
return self.GetFormattedTime(
self.GetStartedTime(board, build), short)
def GetFormattedFinishedTime(self, board, build, short=None):
return self.GetFormattedTime(
self.GetFinishedTime(board, build), short)
def GetFormattedElapsedTime(self, board, build, short=None):
time_seconds = self.GetElapsedTime(board, build)
if short:
# Formatted as: 06:16:12.
result = time.strftime('%H:%M:%S', time.gmtime(time_seconds))
else:
# Formatted as: 04 hrs, 27 mins, 03 secs.
result = time.strftime(
'%H hrs, %M mins, %S secs', time.gmtime(time_seconds))
return result
def GetFormattedBuildTimes(self, board, build):
"""Perf optimize on the pattern on repeat/retrieval of all."""
time_key = (board, build)
if time_key in self._formatted_time_cache:
return self._formatted_time_cache[time_key]
result = (self.GetFormattedStartedTime(board, build),
self.GetFormattedFinishedTime(board, build),
self.GetFormattedElapsedTime(board, build),
self.GetFormattedFinishedTime(board, build, True))
self._formatted_time_cache[time_key] = result
return result
def FetchChromeVersion(self, full_build):
"""Grab the Chrome version from the chromeos-images version map."""
chromeos_build = full_build.split('_')[-1].split('-')[0]
if chromeos_build in self._chrome_version_cache:
return self._chrome_version_cache[chromeos_build]
map_file = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'chromeos-chrome-version.json')
if not os.path.exists(map_file):
return (None, None)
chrome_versions = json.load(open(map_file))
if not chrome_versions or not chromeos_build in chrome_versions:
return (None, None)
dot_version = chrome_versions[chromeos_build]
omaha_url = 'http://omahaproxy.appspot.com/revision?version=%s' % (
dot_version)
omaha_wget = '%s "%s"' % (WGET_CMD, omaha_url)
svn_revision = commands.getoutput(omaha_wget)
results = (dot_version, svn_revision)
self._chrome_version_cache[chromeos_build] = results
return results
def GetCacheFilename(self, board, build, dir=True):
filename = '%s%s_%s' % (BUILDTIME_PREFIX, board, build)
if dir:
return '%s/%s' % (LOCAL_TMP_DIR, filename)
else:
return filename
def FetchBuildInfo(self, board, build):
"""Load start_time, end_time into memory from file cache or web lookup."""
# Use an in-memory cache (dictionary) for repeats.
board_builds = self._build_time_cache.setdefault(board, {})
build_keys = board_builds.setdefault(build, {})
if not build_keys:
build_keys['started_time'] = 0.0
build_keys['finished_time'] = 0.0
build_keys['chrome_version'] = [None, None]
build_log_json = None
cache_filename = self.GetCacheFilename(board, build)
if os.path.isfile(cache_filename):
f = open(cache_filename, 'r')
build_log_text = f.read()
if build_log_text:
build_log_json = json.loads(build_log_text)
f.close()
else:
if not os.path.exists(LOCAL_TMP_DIR):
os.makedirs(LOCAL_TMP_DIR, 0755)
dash_util.SaveHTML(cache_filename, '')
def PruneTmpFiles(self, dash_view):
"""Remove cached build_time data that is no longer useful."""
build_set = set()
for board in dash_view.GetBoardTypes():
for build in dash_view.GetBoardtypeBuilds(board):
build_set.add(unicode(self.GetCacheFilename(board, build, False)))
files_set = set(os.listdir(LOCAL_TMP_DIR))
for f in files_set - build_set:
if f.find(BUILDTIME_PREFIX) > -1:
logging.info('Pruning %s from %s.', f, LOCAL_TMP_DIR)
os.remove('%s/%s' % (LOCAL_TMP_DIR, f))
def ShowCache(self):
logging.debug("*")
logging.debug("*BUILDINFO CACHE***************")
logging.debug("*")
for board, build_times in self._build_time_cache.iteritems():
for build, time_info in build_times.iteritems():
logging.debug(" %s: %s: %s ~ %s (%s).",
board, build,
time_info['started_time'],
time_info['finished_time'],
time_info['chrome_version'])
# Instance reference for singleton behavior.
__instance = None
__refs = 0
def __init__(self):
if BuildInfo.__instance is None:
BuildInfo.__instance = BuildInfo.__impl()
self.__dict__["_BuildInfo__instance"] = BuildInfo.__instance
BuildInfo.__refs += 1
def __del__(self):
BuildInfo.__refs -= 1
if not BuildInfo.__instance is None and BuildInfo.__refs == 0:
BuildInfo.__instance.ShowCache()
del BuildInfo.__instance
BuildInfo.__instance = None
def __getattr__(self, attr):
return getattr(BuildInfo.__instance, attr)
def __setattr__(self, attr, value):
return setattr(BuildInfo.__instance, attr, value)