Extract the logging decorator used in kernel.py into a common library
and add it to Autotest.install to provide logging of autotest
installation failure (and success).

Signed-off-by: John Admanski <jadmanski@google.com>



git-svn-id: http://test.kernel.org/svn/autotest/trunk@937 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/client/bin/kernel.py b/client/bin/kernel.py
index d9d818a..f7b1528 100755
--- a/client/bin/kernel.py
+++ b/client/bin/kernel.py
@@ -2,33 +2,10 @@
 
 import os,os.path,shutil,urllib,copy,pickle,re,glob,time
 from autotest_utils import *
+from common import logging
 import kernel_config, test, os_dep
 
 
-def record(fn):
-	""" Decorator for logging calls to specific kernel methods.
-	It also accepts a "logged=False" keyword argument to disable
-	the logging for particular calls.
-
-	Classes that make use of this dectorator will need to have job
-	and subdir attributes for the logging to function correctly.
-	"""
-	def recorded_func(self, *args, **dargs):
-		logged = dargs.pop('logged', True)
-		if not logged:
-			return fn(self, *args, **dargs)
-		# wrap the method call in success/failure logging
-		name = "kernel.%s" % fn.__name__
-		try:
-			result = fn(self, *args, **dargs)
-			self.job.record('GOOD', self.subdir, name)
-		except Exception, detail:
-			self.job.record('FAIL', self.subdir, name, str(detail))
-			raise
-		return result
-	return recorded_func
-
-
 class kernel:
 	""" Class for compiling kernels. 
 
@@ -138,7 +115,7 @@
 				self.patch(*base_components)
 
 
-	@record
+	@logging.record
 	def patch(self, *patches):
 		"""Apply a list of patches (in order)"""
 		if not patches:
@@ -147,7 +124,7 @@
 		self.apply_patches(self.get_patches(patches))
 
 
-	@record
+	@logging.record
 	def config(self, config_file = '', config_list = None, defconfig = False):
 		self.job.stdout.tee_redirect(os.path.join(self.log_dir, 'stdout'))
 		self.set_cross_cc()
@@ -220,7 +197,7 @@
 		system('sed "%s" < Makefile.old > Makefile' % p)
 
 
-	@record
+	@logging.record
 	def build(self, make_opts = '', logfile = '', extraversion='autotest'):
 		"""build the kernel
 
@@ -277,7 +254,7 @@
 			raise TestError("no vmlinux found, kernel build failed")
 
 
-	@record
+	@logging.record
 	def clean(self):
 		"""make clean in the kernel tree"""
 		os.chdir(self.build_dir) 
@@ -285,7 +262,7 @@
 		system('make clean > /dev/null 2> /dev/null')
 
 
-	@record
+	@logging.record
 	def mkinitrd(self, version, image, system_map, initrd):
 		"""Build kernel initrd image.
 		Try to use distro specific way to build initrd image.
@@ -331,7 +308,7 @@
 		self.build_image = image
 
 
-	@record
+	@logging.record
 	def install(self, tag='autotest', prefix = '/'):
 		"""make install in the kernel tree"""
 
@@ -626,7 +603,7 @@
 			self.changelist = None
 
 
-	@record
+	@logging.record
 	def install(self, tag='autotest'):
 		self.installed_as = tag
 
diff --git a/client/common_lib/__init__.py b/client/common_lib/__init__.py
index faa7f2f..7fbaa6e 100644
--- a/client/common_lib/__init__.py
+++ b/client/common_lib/__init__.py
@@ -1,4 +1,4 @@
-__all__ = []
+__all__ = ['logging']
 
 import site_libraries
 __all__ += site_libraries.libraries
diff --git a/client/common_lib/logging.py b/client/common_lib/logging.py
new file mode 100644
index 0000000..ded9abc
--- /dev/null
+++ b/client/common_lib/logging.py
@@ -0,0 +1,35 @@
+def record(fn):
+	"""
+	Generic method decorator for logging calls under the
+	assumption that return=GOOD, exception=FAIL. The method
+	determines parameters as:
+		subdir = self.subdir if it exists, or None
+		operation = "class name"."method name"
+		status = None on GOOD, str(exception) on FAIL
+	The object using this method must have a job attribute
+	for the logging to actually occur, otherwise the logging
+	will silently fail.
+
+	Logging can explicitly be disabled for a call by passing
+	a logged=False parameter
+	"""
+	def recorded_func(self, *args, **dargs):
+		logged = dargs.pop('logged', True)
+		job = getattr(self, 'job', None)
+		# if logging is disabled/unavailable, just
+		# call the method
+		if not logged or job is None:
+			return fn(self, *args, **dargs)
+		# logging is available, so wrap the method call
+		# in success/failure logging
+		subdir = getattr(self, 'subdir', None)
+		operation = '%s.%s' % (self.__class__.__name__,
+				       fn.__name__)
+		try:
+			result = fn(self, *args, **dargs)
+			job.record('GOOD', subdir, operation)
+		except Exception, detail:
+			job.record('FAIL', subdir, operation, str(detail))
+			raise
+		return result
+	return recorded_func
diff --git a/server/autotest.py b/server/autotest.py
index 481a147..48b638d 100644
--- a/server/autotest.py
+++ b/server/autotest.py
@@ -26,6 +26,7 @@
 import installable_object
 import errors
 import utils
+from common import logging
 
 
 AUTOTEST_SVN  = 'svn://test.kernel.org/autotest/trunk/client'
@@ -56,6 +57,9 @@
 	This is a leaf class in an abstract class hierarchy, it must
 	implement the unimplemented methods in parent classes.
 	"""
+	job = None
+
+
 	def __init__(self, host = None):
 		self.host = host
 		self.got = False
@@ -64,6 +68,7 @@
 		super(Autotest, self).__init__()
 
 
+	@logging.record
 	def install(self, host = None):
 		"""
 		Install autotest.  If get() was not called previously, an 
diff --git a/server/server_job.py b/server/server_job.py
index 1e81e4c..f756a41 100755
--- a/server/server_job.py
+++ b/server/server_job.py
@@ -31,6 +31,7 @@
 from subcommand import *
 from utils import run, get_tmp_dir, sh_escape
 
+autotest.Autotest.job = job
 hosts.SSHHost.job = job
 """