1# Copyright 2011 Google Inc. All Rights Reserved.
2"""Compute image checksum."""
3
4from __future__ import print_function
5
6import os
7import threading
8
9from cros_utils import logger
10from cros_utils.file_utils import FileUtils
11
12
13class ImageChecksummer(object):
14  """Compute image checksum."""
15
16  class PerImageChecksummer(object):
17    """Compute checksum for an image."""
18
19    def __init__(self, label, log_level):
20      self._lock = threading.Lock()
21      self.label = label
22      self._checksum = None
23      self.log_level = log_level
24
25    def Checksum(self):
26      with self._lock:
27        if not self._checksum:
28          logger.GetLogger().LogOutput("Acquiring checksum for '%s'." %
29                                       self.label.name)
30          self._checksum = None
31          if self.label.image_type != 'local':
32            raise RuntimeError('Called Checksum on non-local image!')
33          if self.label.chromeos_image:
34            if os.path.exists(self.label.chromeos_image):
35              self._checksum = FileUtils().Md5File(
36                  self.label.chromeos_image, log_level=self.log_level)
37              logger.GetLogger().LogOutput('Computed checksum is '
38                                           ': %s' % self._checksum)
39          if not self._checksum:
40            raise RuntimeError('Checksum computing error.')
41          logger.GetLogger().LogOutput('Checksum is: %s' % self._checksum)
42        return self._checksum
43
44  _instance = None
45  _lock = threading.Lock()
46  _per_image_checksummers = {}
47
48  def __new__(cls, *args, **kwargs):
49    with cls._lock:
50      if not cls._instance:
51        cls._instance = super(ImageChecksummer, cls).__new__(cls, *args,
52                                                             **kwargs)
53      return cls._instance
54
55  def Checksum(self, label, log_level):
56    if label.image_type != 'local':
57      raise RuntimeError('Attempt to call Checksum on non-local image.')
58    with self._lock:
59      if label.name not in self._per_image_checksummers:
60        self._per_image_checksummers[label.name] = (
61            ImageChecksummer.PerImageChecksummer(label, log_level))
62      checksummer = self._per_image_checksummers[label.name]
63
64    try:
65      return checksummer.Checksum()
66    except:
67      logger.GetLogger().LogError('Could not compute checksum of image in label'
68                                  " '%s'." % label.name)
69      raise
70