blob: 1d50a26426153ccc0f0a30e3cfc15dbd188ce100 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# Local file checksum cache implementation
2#
3# Copyright (C) 2012 Intel Corporation
4#
Brad Bishopc342db32019-05-15 21:57:59 -04005# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -05006#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05008import glob
9import operator
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010import os
11import stat
12import bb.utils
13import logging
14from bb.cache import MultiProcessCache
15
16logger = logging.getLogger("BitBake.Cache")
17
Patrick Williamsc124f4f2015-09-15 14:41:29 -050018# mtime cache (non-persistent)
19# based upon the assumption that files do not change during bitbake run
20class FileMtimeCache(object):
21 cache = {}
22
23 def cached_mtime(self, f):
24 if f not in self.cache:
25 self.cache[f] = os.stat(f)[stat.ST_MTIME]
26 return self.cache[f]
27
28 def cached_mtime_noerror(self, f):
29 if f not in self.cache:
30 try:
31 self.cache[f] = os.stat(f)[stat.ST_MTIME]
32 except OSError:
33 return 0
34 return self.cache[f]
35
36 def update_mtime(self, f):
37 self.cache[f] = os.stat(f)[stat.ST_MTIME]
38 return self.cache[f]
39
40 def clear(self):
41 self.cache.clear()
42
43# Checksum + mtime cache (persistent)
44class FileChecksumCache(MultiProcessCache):
45 cache_file_name = "local_file_checksum_cache.dat"
46 CACHE_VERSION = 1
47
48 def __init__(self):
49 self.mtime_cache = FileMtimeCache()
50 MultiProcessCache.__init__(self)
51
52 def get_checksum(self, f):
53 entry = self.cachedata[0].get(f)
54 cmtime = self.mtime_cache.cached_mtime(f)
55 if entry:
56 (mtime, hashval) = entry
57 if cmtime == mtime:
58 return hashval
59 else:
60 bb.debug(2, "file %s changed mtime, recompute checksum" % f)
61
62 hashval = bb.utils.md5_file(f)
63 self.cachedata_extras[0][f] = (cmtime, hashval)
64 return hashval
65
66 def merge_data(self, source, dest):
67 for h in source[0]:
68 if h in dest:
69 (smtime, _) = source[0][h]
70 (dmtime, _) = dest[0][h]
71 if smtime > dmtime:
72 dest[0][h] = source[0][h]
73 else:
74 dest[0][h] = source[0][h]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050075
Andrew Geissler82c905d2020-04-13 13:39:40 -050076 def get_checksums(self, filelist, pn, localdirsexclude):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050077 """Get checksums for a list of files"""
78
79 def checksum_file(f):
80 try:
81 checksum = self.get_checksum(f)
82 except OSError as e:
83 bb.warn("Unable to get checksum for %s SRC_URI entry %s: %s" % (pn, os.path.basename(f), e))
84 return None
85 return checksum
86
87 def checksum_dir(pth):
88 # Handle directories recursively
Brad Bishop220d5532018-08-14 00:59:39 +010089 if pth == "/":
90 bb.fatal("Refusing to checksum /")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050091 dirchecksums = []
Andrew Geissler82c905d2020-04-13 13:39:40 -050092 for root, dirs, files in os.walk(pth, topdown=True):
93 [dirs.remove(d) for d in list(dirs) if d in localdirsexclude]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050094 for name in files:
95 fullpth = os.path.join(root, name)
96 checksum = checksum_file(fullpth)
97 if checksum:
98 dirchecksums.append((fullpth, checksum))
99 return dirchecksums
100
101 checksums = []
102 for pth in filelist.split():
103 exist = pth.split(":")[1]
104 if exist == "False":
105 continue
106 pth = pth.split(":")[0]
107 if '*' in pth:
108 # Handle globs
109 for f in glob.glob(pth):
110 if os.path.isdir(f):
111 if not os.path.islink(f):
112 checksums.extend(checksum_dir(f))
113 else:
114 checksum = checksum_file(f)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600115 if checksum:
116 checksums.append((f, checksum))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500117 elif os.path.isdir(pth):
118 if not os.path.islink(pth):
119 checksums.extend(checksum_dir(pth))
120 else:
121 checksum = checksum_file(pth)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600122 if checksum:
123 checksums.append((pth, checksum))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500124
125 checksums.sort(key=operator.itemgetter(1))
126 return checksums