blob: ed2c52c626de979000dcc03a3725c7348b742b2a [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright (c) 2010 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.
"""Google Factory Tools Common Library
This module includes several common utilities for Google Factory Tools
A detailed description of gft_common.
"""
import os
import subprocess
import sys
import tempfile
import time
########################################################################
# Global Variables
_debug = False
_verbose = False
_log_path = None
DEFAULT_CONSOLE_LOG_PATH = '/var/log/factory.log'
########################################################################
# Common Utilities
class GFTError(Exception):
""" Exception for unrecoverable errors for GFT related functions. """
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
def SetDebugLevel(level):
""" Sets the debugging level. """
global _debug
_debug = level
def SetVerboseLevel(level, log_path=None):
""" Sets the verbosity level and log output path. """
global _verbose, _log_path
_verbose = level
if log_path:
DebugMsg("Set log path to: " + log_path, log=False)
_log_path = log_path
def Log(msg):
""" Writes a message to pre-configured log file. """
if not _log_path:
return
try:
with open(_log_path, "at") as log_handle:
lines = ["(GFT) %s %s\n" % (time.strftime("%Y%m%d %H:%M:%S"), entry)
for entry in msg.splitlines()]
log_handle.writelines(lines)
except:
sys.stderr.write("FAILED TO WRITE TO LOG FILE %s.\n" % _log_path)
def WarningMsg(msg):
""" Prints warning messages (to stderr) as-is. """
sys.stderr.write("%s\n" % msg)
Log(msg)
def VerboseMsg(msg):
""" Prints verbose message, if SetVerboseLevel was called with True. """
if _verbose:
WarningMsg(msg)
else:
Log(msg)
def DebugMsg(msg, log=True):
""" Prints message when debug is enabled. """
for entry in msg.splitlines():
if _debug:
WarningMsg("(DEBUG) %s" % entry)
elif log:
Log("(DEBUG) %s" % entry)
def ErrorMsg(msg):
""" Prints messages to stderr with prefix "ERROR". """
for entry in msg.splitlines():
WarningMsg("ERROR: %s" % entry)
def ErrorDie(msg):
""" Raises a GFTError exception. """
raise GFTError(msg)
def GFTConsole(f):
"""Decorator for all Google Factory Test Tools console programs.
log path will be redirectd to DEFAULT_CONSOLE_LOG_PATH by default,
and all GFTError will be catched, logged, and exit as failure.
"""
def main_wrapper(*args, **kw):
# override the default log path
global _log_path
_log_path = DEFAULT_CONSOLE_LOG_PATH
try:
return f(*args, **kw)
except GFTError, e:
ErrorMsg(e.value)
sys.exit(1)
return main_wrapper
def GetTemporaryFileName(prefix='gft', suffix=''):
""" Gets a unique file name for temporary usage. """
(fd, filename) = tempfile.mkstemp(prefix=prefix, suffix=suffix)
os.close(fd)
return filename
def SystemOutput(command,
ignore_status=False,
show_progress=False,
progress_messsage=None,
return_exit_code=False):
""" Retrieves the output of a shell command.
Returns the output string.
Args:
ignore_status: False to raise exectopion when execution result is not zero
show_progress: Shows progress by messages and dots
progress_messsage: Messages printed before starting.
return_exit_code: True if we want the exit code value, or the console output
Returns:
If return_exit_code is True, return value is an integer of exit code.
Otherwise, return value is a string of stdout by command.
"""
DebugMsg("SystemOutput: %s" % command, log=False)
temp_stderr = tempfile.TemporaryFile()
temp_stdout = tempfile.TemporaryFile()
proc = subprocess.Popen(command,
stderr=temp_stderr,
stdout=temp_stdout,
shell=True)
if show_progress:
sys.stdout.flush()
if progress_messsage:
sys.stderr.write(progress_messsage)
while proc.poll() is None:
sys.stderr.write('.')
time.sleep(1)
if progress_messsage:
sys.stderr.write('\n')
else:
proc.communicate()
temp_stdout.seek(0)
out = temp_stdout.read()
temp_stdout.close()
exit_code = proc.wait()
if exit_code:
# prepare to log the error message.
temp_stderr.seek(0)
err = temp_stderr.read()
temp_stderr.close()
message = ('Failed executing command: %s\n'
'Output and Error Messages: %s\n%s' % (command, out, err))
if ignore_status:
DebugMsg(message)
else:
ErrorDie(message)
if return_exit_code:
return exit_code
if out[-1:] == '\n':
out = out[:-1]
return out
def ReadOneLine(filename):
""" Reads one line from file. """
with open(filename) as opened_file:
return opened_file.readline().strip()
def ReadFile(filename):
""" Reads whole file. """
with open(filename) as opened_file:
return opened_file.read().strip()
def ReadBinaryFile(filename):
""" Reads whole binary file. """
with open(filename, "rb") as opened_file:
return opened_file.read()
def WriteFile(filename, data):
""" Writes one file and exit. """
with open(filename, "w") as opened_file:
opened_file.write(data)
########################################################################
# Components Databases
def LoadComponentsDatabaseFile(filename):
""" Loads a components database file. """
with open(filename) as database:
return eval(database.read())
def GetComponentsDatabaseBase(database_file):
""" Gets the base folder of a components database file. """
# Currently the database file is assuming properties sit in its parent folder.
base = os.path.join(os.path.split(os.path.abspath(database_file))[0], '..')
return os.path.abspath(base)
if __name__ == '__main__':
print "Google Factory Tool Common Library."