blob: 8c623271adc5401c91eedff966f0817dd75e66eb [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001SSTATE_VERSION = "3"
2
3SSTATE_MANIFESTS ?= "${TMPDIR}/sstate-control"
4SSTATE_MANFILEPREFIX = "${SSTATE_MANIFESTS}/manifest-${SSTATE_MANMACH}-${PN}"
5
6def generate_sstatefn(spec, hash, d):
7 if not hash:
8 hash = "INVALID"
9 return hash[:2] + "/" + spec + hash
10
11SSTATE_PKGARCH = "${PACKAGE_ARCH}"
12SSTATE_PKGSPEC = "sstate:${PN}:${PACKAGE_ARCH}${TARGET_VENDOR}-${TARGET_OS}:${PV}:${PR}:${SSTATE_PKGARCH}:${SSTATE_VERSION}:"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050013SSTATE_SWSPEC = "sstate:${PN}::${PV}:${PR}::${SSTATE_VERSION}:"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050014SSTATE_PKGNAME = "${SSTATE_EXTRAPATH}${@generate_sstatefn(d.getVar('SSTATE_PKGSPEC', True), d.getVar('BB_TASKHASH', True), d)}"
15SSTATE_PKG = "${SSTATE_DIR}/${SSTATE_PKGNAME}"
16SSTATE_EXTRAPATH = ""
17SSTATE_EXTRAPATHWILDCARD = ""
18SSTATE_PATHSPEC = "${SSTATE_DIR}/${SSTATE_EXTRAPATHWILDCARD}*/${SSTATE_PKGSPEC}"
19
20# We don't want the sstate to depend on things like the distro string
21# of the system, we let the sstate paths take care of this.
22SSTATE_EXTRAPATH[vardepvalue] = ""
23
24# For multilib rpm the allarch packagegroup files can overwrite (in theory they're identical)
25SSTATE_DUPWHITELIST = "${DEPLOY_DIR_IMAGE}/ ${DEPLOY_DIR}/licenses/ ${DEPLOY_DIR_RPM}/all/"
26# Avoid docbook/sgml catalog warnings for now
27SSTATE_DUPWHITELIST += "${STAGING_ETCDIR_NATIVE}/sgml ${STAGING_DATADIR_NATIVE}/sgml"
28# Archive the sources for many architectures in one deploy folder
29SSTATE_DUPWHITELIST += "${DEPLOY_DIR_SRC}"
30
31SSTATE_SCAN_FILES ?= "*.la *-config *_config"
32SSTATE_SCAN_CMD ?= 'find ${SSTATE_BUILDDIR} \( -name "${@"\" -o -name \"".join(d.getVar("SSTATE_SCAN_FILES", True).split())}" \) -type f'
33
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050034BB_HASHFILENAME = "False ${SSTATE_PKGSPEC} ${SSTATE_SWSPEC}"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050035
36SSTATE_ARCHS = " \
37 ${BUILD_ARCH} \
38 ${BUILD_ARCH}_${SDK_ARCH}_${SDK_OS} \
39 ${BUILD_ARCH}_${TARGET_ARCH} \
40 ${SDK_ARCH}_${SDK_OS} \
41 ${SDK_ARCH}_${PACKAGE_ARCH} \
42 allarch \
43 ${PACKAGE_ARCH} \
44 ${MACHINE}"
45
46SSTATE_MANMACH ?= "${SSTATE_PKGARCH}"
47
48SSTATECREATEFUNCS = "sstate_hardcode_path"
49SSTATEPOSTCREATEFUNCS = ""
50SSTATEPREINSTFUNCS = ""
51SSTATEPOSTUNPACKFUNCS = "sstate_hardcode_path_unpack"
52SSTATEPOSTINSTFUNCS = ""
53EXTRA_STAGING_FIXMES ?= ""
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050054SSTATECLEANFUNCS = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -050055
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050056# Check whether sstate exists for tasks that support sstate and are in the
57# locked signatures file.
58SIGGEN_LOCKEDSIGS_SSTATE_EXISTS_CHECK ?= 'error'
59
60# Check whether the task's computed hash matches the task's hash in the
61# locked signatures file.
62SIGGEN_LOCKEDSIGS_TASKSIG_CHECK ?= "error"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050063
64# The GnuPG key ID and passphrase to use to sign sstate archives (or unset to
65# not sign)
66SSTATE_SIG_KEY ?= ""
67SSTATE_SIG_PASSPHRASE ?= ""
68# Whether to verify the GnUPG signatures when extracting sstate archives
69SSTATE_VERIFY_SIG ?= "0"
70
Patrick Williamsc124f4f2015-09-15 14:41:29 -050071python () {
72 if bb.data.inherits_class('native', d):
73 d.setVar('SSTATE_PKGARCH', d.getVar('BUILD_ARCH', False))
74 elif bb.data.inherits_class('crosssdk', d):
75 d.setVar('SSTATE_PKGARCH', d.expand("${BUILD_ARCH}_${SDK_ARCH}_${SDK_OS}"))
76 elif bb.data.inherits_class('cross', d):
77 d.setVar('SSTATE_PKGARCH', d.expand("${BUILD_ARCH}_${TARGET_ARCH}"))
78 elif bb.data.inherits_class('nativesdk', d):
79 d.setVar('SSTATE_PKGARCH', d.expand("${SDK_ARCH}_${SDK_OS}"))
80 elif bb.data.inherits_class('cross-canadian', d):
81 d.setVar('SSTATE_PKGARCH', d.expand("${SDK_ARCH}_${PACKAGE_ARCH}"))
82 elif bb.data.inherits_class('allarch', d) and d.getVar("PACKAGE_ARCH", True) == "all":
83 d.setVar('SSTATE_PKGARCH', "allarch")
84 else:
85 d.setVar('SSTATE_MANMACH', d.expand("${PACKAGE_ARCH}"))
86
87 if bb.data.inherits_class('native', d) or bb.data.inherits_class('crosssdk', d) or bb.data.inherits_class('cross', d):
88 d.setVar('SSTATE_EXTRAPATH', "${NATIVELSBSTRING}/")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050089 d.setVar('BB_HASHFILENAME', "True ${SSTATE_PKGSPEC} ${SSTATE_SWSPEC}")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090 d.setVar('SSTATE_EXTRAPATHWILDCARD', "*/")
91
92 # These classes encode staging paths into their scripts data so can only be
93 # reused if we manipulate the paths
94 if bb.data.inherits_class('native', d) or bb.data.inherits_class('cross', d) or bb.data.inherits_class('sdk', d) or bb.data.inherits_class('crosssdk', d):
95 scan_cmd = "grep -Irl ${STAGING_DIR} ${SSTATE_BUILDDIR}"
96 d.setVar('SSTATE_SCAN_CMD', scan_cmd)
97
98 unique_tasks = set((d.getVar('SSTATETASKS', True) or "").split())
99 d.setVar('SSTATETASKS', " ".join(unique_tasks))
100 for task in unique_tasks:
101 d.prependVarFlag(task, 'prefuncs', "sstate_task_prefunc ")
102 d.appendVarFlag(task, 'postfuncs', " sstate_task_postfunc")
103}
104
105def sstate_init(task, d):
106 ss = {}
107 ss['task'] = task
108 ss['dirs'] = []
109 ss['plaindirs'] = []
110 ss['lockfiles'] = []
111 ss['lockfiles-shared'] = []
112 return ss
113
114def sstate_state_fromvars(d, task = None):
115 if task is None:
116 task = d.getVar('BB_CURRENTTASK', True)
117 if not task:
118 bb.fatal("sstate code running without task context?!")
119 task = task.replace("_setscene", "")
120
121 if task.startswith("do_"):
122 task = task[3:]
123 inputs = (d.getVarFlag("do_" + task, 'sstate-inputdirs', True) or "").split()
124 outputs = (d.getVarFlag("do_" + task, 'sstate-outputdirs', True) or "").split()
125 plaindirs = (d.getVarFlag("do_" + task, 'sstate-plaindirs', True) or "").split()
126 lockfiles = (d.getVarFlag("do_" + task, 'sstate-lockfile', True) or "").split()
127 lockfilesshared = (d.getVarFlag("do_" + task, 'sstate-lockfile-shared', True) or "").split()
128 interceptfuncs = (d.getVarFlag("do_" + task, 'sstate-interceptfuncs', True) or "").split()
129 if not task or len(inputs) != len(outputs):
130 bb.fatal("sstate variables not setup correctly?!")
131
132 if task == "populate_lic":
133 d.setVar("SSTATE_PKGSPEC", "${SSTATE_SWSPEC}")
134 d.setVar("SSTATE_EXTRAPATH", "")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500135 d.setVar('SSTATE_EXTRAPATHWILDCARD', "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500136
137 ss = sstate_init(task, d)
138 for i in range(len(inputs)):
139 sstate_add(ss, inputs[i], outputs[i], d)
140 ss['lockfiles'] = lockfiles
141 ss['lockfiles-shared'] = lockfilesshared
142 ss['plaindirs'] = plaindirs
143 ss['interceptfuncs'] = interceptfuncs
144 return ss
145
146def sstate_add(ss, source, dest, d):
147 if not source.endswith("/"):
148 source = source + "/"
149 if not dest.endswith("/"):
150 dest = dest + "/"
151 source = os.path.normpath(source)
152 dest = os.path.normpath(dest)
153 srcbase = os.path.basename(source)
154 ss['dirs'].append([srcbase, source, dest])
155 return ss
156
157def sstate_install(ss, d):
158 import oe.path
159 import oe.sstatesig
160 import subprocess
161
162 sharedfiles = []
163 shareddirs = []
164 bb.utils.mkdirhier(d.expand("${SSTATE_MANIFESTS}"))
165
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500166 sstateinst = d.expand("${WORKDIR}/sstate-install-%s/" % ss['task'])
167
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500168 manifest, d2 = oe.sstatesig.sstate_get_manifest_filename(ss['task'], d)
169
170 if os.access(manifest, os.R_OK):
171 bb.fatal("Package already staged (%s)?!" % manifest)
172
173 locks = []
174 for lock in ss['lockfiles-shared']:
175 locks.append(bb.utils.lockfile(lock, True))
176 for lock in ss['lockfiles']:
177 locks.append(bb.utils.lockfile(lock))
178
179 for state in ss['dirs']:
180 bb.debug(2, "Staging files from %s to %s" % (state[1], state[2]))
181 for walkroot, dirs, files in os.walk(state[1]):
182 for file in files:
183 srcpath = os.path.join(walkroot, file)
184 dstpath = srcpath.replace(state[1], state[2])
185 #bb.debug(2, "Staging %s to %s" % (srcpath, dstpath))
186 sharedfiles.append(dstpath)
187 for dir in dirs:
188 srcdir = os.path.join(walkroot, dir)
189 dstdir = srcdir.replace(state[1], state[2])
190 #bb.debug(2, "Staging %s to %s" % (srcdir, dstdir))
191 if not dstdir.endswith("/"):
192 dstdir = dstdir + "/"
193 shareddirs.append(dstdir)
194
195 # Check the file list for conflicts against files which already exist
196 whitelist = (d.getVar("SSTATE_DUPWHITELIST", True) or "").split()
197 match = []
198 for f in sharedfiles:
199 if os.path.exists(f):
200 f = os.path.normpath(f)
201 realmatch = True
202 for w in whitelist:
203 if f.startswith(w):
204 realmatch = False
205 break
206 if realmatch:
207 match.append(f)
208 sstate_search_cmd = "grep -rl '%s' %s --exclude=master.list | sed -e 's:^.*/::' -e 's:\.populate-sysroot::'" % (f, d.expand("${SSTATE_MANIFESTS}"))
209 search_output = subprocess.Popen(sstate_search_cmd, shell=True, stdout=subprocess.PIPE).communicate()[0]
210 if search_output != "":
211 match.append("Matched in %s" % search_output.rstrip())
212 if match:
213 bb.error("The recipe %s is trying to install files into a shared " \
214 "area when those files already exist. Those files and their manifest " \
215 "location are:\n %s\nPlease verify which recipe should provide the " \
216 "above files.\nThe build has stopped as continuing in this scenario WILL " \
217 "break things, if not now, possibly in the future (we've seen builds fail " \
218 "several months later). If the system knew how to recover from this " \
219 "automatically it would however there are several different scenarios " \
220 "which can result in this and we don't know which one this is. It may be " \
221 "you have switched providers of something like virtual/kernel (e.g. from " \
222 "linux-yocto to linux-yocto-dev), in that case you need to execute the " \
223 "clean task for both recipes and it will resolve this error. It may be " \
224 "you changed DISTRO_FEATURES from systemd to udev or vice versa. Cleaning " \
225 "those recipes should again resolve this error however switching " \
226 "DISTRO_FEATURES on an existing build directory is not supported, you " \
227 "should really clean out tmp and rebuild (reusing sstate should be safe). " \
228 "It could be the overlapping files detected are harmless in which case " \
229 "adding them to SSTATE_DUPWHITELIST may be the correct solution. It could " \
230 "also be your build is including two different conflicting versions of " \
231 "things (e.g. bluez 4 and bluez 5 and the correct solution for that would " \
232 "be to resolve the conflict. If in doubt, please ask on the mailing list, " \
233 "sharing the error and filelist above." % \
234 (d.getVar('PN', True), "\n ".join(match)))
235 bb.fatal("If the above message is too much, the simpler version is you're advised to wipe out tmp and rebuild (reusing sstate is fine). That will likely fix things in most (but not all) cases.")
236
237 # Write out the manifest
238 f = open(manifest, "w")
239 for file in sharedfiles:
240 f.write(file + "\n")
241
242 # We want to ensure that directories appear at the end of the manifest
243 # so that when we test to see if they should be deleted any contents
244 # added by the task will have been removed first.
245 dirs = sorted(shareddirs, key=len)
246 # Must remove children first, which will have a longer path than the parent
247 for di in reversed(dirs):
248 f.write(di + "\n")
249 f.close()
250
251 # Append to the list of manifests for this PACKAGE_ARCH
252
253 i = d2.expand("${SSTATE_MANIFESTS}/index-${SSTATE_MANMACH}")
254 l = bb.utils.lockfile(i + ".lock")
255 filedata = d.getVar("STAMP", True) + " " + d2.getVar("SSTATE_MANFILEPREFIX", True) + " " + d.getVar("WORKDIR", True) + "\n"
256 manifests = []
257 if os.path.exists(i):
258 with open(i, "r") as f:
259 manifests = f.readlines()
260 if filedata not in manifests:
261 with open(i, "a+") as f:
262 f.write(filedata)
263 bb.utils.unlockfile(l)
264
265 # Run the actual file install
266 for state in ss['dirs']:
267 if os.path.exists(state[1]):
268 oe.path.copyhardlinktree(state[1], state[2])
269
270 for postinst in (d.getVar('SSTATEPOSTINSTFUNCS', True) or '').split():
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500271 # All hooks should run in the SSTATE_INSTDIR
272 bb.build.exec_func(postinst, d, (sstateinst,))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500273
274 for lock in locks:
275 bb.utils.unlockfile(lock)
276
277sstate_install[vardepsexclude] += "SSTATE_DUPWHITELIST STATE_MANMACH SSTATE_MANFILEPREFIX"
278sstate_install[vardeps] += "${SSTATEPOSTINSTFUNCS}"
279
280def sstate_installpkg(ss, d):
281 import oe.path
282 import subprocess
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500283 from oe.gpg_sign import get_signer
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500284
285 def prepdir(dir):
286 # remove dir if it exists, ensure any parent directories do exist
287 if os.path.exists(dir):
288 oe.path.remove(dir)
289 bb.utils.mkdirhier(dir)
290 oe.path.remove(dir)
291
292 sstateinst = d.expand("${WORKDIR}/sstate-install-%s/" % ss['task'])
293 sstatefetch = d.getVar('SSTATE_PKGNAME', True) + '_' + ss['task'] + ".tgz"
294 sstatepkg = d.getVar('SSTATE_PKG', True) + '_' + ss['task'] + ".tgz"
295
296 if not os.path.exists(sstatepkg):
297 pstaging_fetch(sstatefetch, sstatepkg, d)
298
299 if not os.path.isfile(sstatepkg):
300 bb.note("Staging package %s does not exist" % sstatepkg)
301 return False
302
303 sstate_clean(ss, d)
304
305 d.setVar('SSTATE_INSTDIR', sstateinst)
306 d.setVar('SSTATE_PKG', sstatepkg)
307
308 if bb.utils.to_boolean(d.getVar("SSTATE_VERIFY_SIG", True), False):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500309 signer = get_signer(d, 'local')
310 if not signer.verify(sstatepkg + '.sig'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500311 bb.warn("Cannot verify signature on sstate package %s" % sstatepkg)
312
313 for f in (d.getVar('SSTATEPREINSTFUNCS', True) or '').split() + ['sstate_unpack_package'] + (d.getVar('SSTATEPOSTUNPACKFUNCS', True) or '').split():
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500314 # All hooks should run in the SSTATE_INSTDIR
315 bb.build.exec_func(f, d, (sstateinst,))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500316
317 for state in ss['dirs']:
318 prepdir(state[1])
319 os.rename(sstateinst + state[0], state[1])
320 sstate_install(ss, d)
321
322 for plain in ss['plaindirs']:
323 workdir = d.getVar('WORKDIR', True)
324 src = sstateinst + "/" + plain.replace(workdir, '')
325 dest = plain
326 bb.utils.mkdirhier(src)
327 prepdir(dest)
328 os.rename(src, dest)
329
330 return True
331
332python sstate_hardcode_path_unpack () {
333 # Fixup hardcoded paths
334 #
335 # Note: The logic below must match the reverse logic in
336 # sstate_hardcode_path(d)
337 import subprocess
338
339 sstateinst = d.getVar('SSTATE_INSTDIR', True)
340 fixmefn = sstateinst + "fixmepath"
341 if os.path.isfile(fixmefn):
342 staging = d.getVar('STAGING_DIR', True)
343 staging_target = d.getVar('STAGING_DIR_TARGET', True)
344 staging_host = d.getVar('STAGING_DIR_HOST', True)
345
346 if bb.data.inherits_class('native', d) or bb.data.inherits_class('nativesdk', d) or bb.data.inherits_class('crosssdk', d) or bb.data.inherits_class('cross-canadian', d):
347 sstate_sed_cmd = "sed -i -e 's:FIXMESTAGINGDIR:%s:g'" % (staging)
348 elif bb.data.inherits_class('cross', d):
349 sstate_sed_cmd = "sed -i -e 's:FIXMESTAGINGDIRTARGET:%s:g; s:FIXMESTAGINGDIR:%s:g'" % (staging_target, staging)
350 else:
351 sstate_sed_cmd = "sed -i -e 's:FIXMESTAGINGDIRHOST:%s:g'" % (staging_host)
352
353 extra_staging_fixmes = d.getVar('EXTRA_STAGING_FIXMES', True) or ''
354 for fixmevar in extra_staging_fixmes.split():
355 fixme_path = d.getVar(fixmevar, True)
356 sstate_sed_cmd += " -e 's:FIXME_%s:%s:g'" % (fixmevar, fixme_path)
357
358 # Add sstateinst to each filename in fixmepath, use xargs to efficiently call sed
359 sstate_hardcode_cmd = "sed -e 's:^:%s:g' %s | xargs %s" % (sstateinst, fixmefn, sstate_sed_cmd)
360
361 bb.note("Replacing fixme paths in sstate package: %s" % (sstate_hardcode_cmd))
362 subprocess.call(sstate_hardcode_cmd, shell=True)
363
364 # Need to remove this or we'd copy it into the target directory and may
365 # conflict with another writer
366 os.remove(fixmefn)
367}
368
369def sstate_clean_cachefile(ss, d):
370 import oe.path
371
372 sstatepkgfile = d.getVar('SSTATE_PATHSPEC', True) + "*_" + ss['task'] + ".tgz*"
373 bb.note("Removing %s" % sstatepkgfile)
374 oe.path.remove(sstatepkgfile)
375
376def sstate_clean_cachefiles(d):
377 for task in (d.getVar('SSTATETASKS', True) or "").split():
378 ld = d.createCopy()
379 ss = sstate_state_fromvars(ld, task)
380 sstate_clean_cachefile(ss, ld)
381
382def sstate_clean_manifest(manifest, d):
383 import oe.path
384
385 mfile = open(manifest)
386 entries = mfile.readlines()
387 mfile.close()
388
389 for entry in entries:
390 entry = entry.strip()
391 bb.debug(2, "Removing manifest: %s" % entry)
392 # We can race against another package populating directories as we're removing them
393 # so we ignore errors here.
394 try:
395 if entry.endswith("/"):
396 if os.path.islink(entry[:-1]):
397 os.remove(entry[:-1])
398 elif os.path.exists(entry) and len(os.listdir(entry)) == 0:
399 os.rmdir(entry[:-1])
400 else:
401 oe.path.remove(entry)
402 except OSError:
403 pass
404
405 oe.path.remove(manifest)
406
407def sstate_clean(ss, d):
408 import oe.path
409 import glob
410
411 d2 = d.createCopy()
412 stamp_clean = d.getVar("STAMPCLEAN", True)
413 extrainf = d.getVarFlag("do_" + ss['task'], 'stamp-extra-info', True)
414 if extrainf:
415 d2.setVar("SSTATE_MANMACH", extrainf)
416 wildcard_stfile = "%s.do_%s*.%s" % (stamp_clean, ss['task'], extrainf)
417 else:
418 wildcard_stfile = "%s.do_%s*" % (stamp_clean, ss['task'])
419
420 manifest = d2.expand("${SSTATE_MANFILEPREFIX}.%s" % ss['task'])
421
422 if os.path.exists(manifest):
423 locks = []
424 for lock in ss['lockfiles-shared']:
425 locks.append(bb.utils.lockfile(lock))
426 for lock in ss['lockfiles']:
427 locks.append(bb.utils.lockfile(lock))
428
429 sstate_clean_manifest(manifest, d)
430
431 for lock in locks:
432 bb.utils.unlockfile(lock)
433
434 # Remove the current and previous stamps, but keep the sigdata.
435 #
436 # The glob() matches do_task* which may match multiple tasks, for
437 # example: do_package and do_package_write_ipk, so we need to
438 # exactly match *.do_task.* and *.do_task_setscene.*
439 rm_stamp = '.do_%s.' % ss['task']
440 rm_setscene = '.do_%s_setscene.' % ss['task']
441 # For BB_SIGNATURE_HANDLER = "noop"
442 rm_nohash = ".do_%s" % ss['task']
443 for stfile in glob.glob(wildcard_stfile):
444 # Keep the sigdata
445 if ".sigdata." in stfile:
446 continue
447 # Preserve taint files in the stamps directory
448 if stfile.endswith('.taint'):
449 continue
450 if rm_stamp in stfile or rm_setscene in stfile or \
451 stfile.endswith(rm_nohash):
452 oe.path.remove(stfile)
453
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500454 # Removes the users/groups created by the package
455 for cleanfunc in (d.getVar('SSTATECLEANFUNCS', True) or '').split():
456 bb.build.exec_func(cleanfunc, d)
457
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500458sstate_clean[vardepsexclude] = "SSTATE_MANFILEPREFIX"
459
460CLEANFUNCS += "sstate_cleanall"
461
462python sstate_cleanall() {
463 bb.note("Removing shared state for package %s" % d.getVar('PN', True))
464
465 manifest_dir = d.getVar('SSTATE_MANIFESTS', True)
466 if not os.path.exists(manifest_dir):
467 return
468
469 tasks = d.getVar('SSTATETASKS', True).split()
470 for name in tasks:
471 ld = d.createCopy()
472 shared_state = sstate_state_fromvars(ld, name)
473 sstate_clean(shared_state, ld)
474}
475
476python sstate_hardcode_path () {
477 import subprocess, platform
478
479 # Need to remove hardcoded paths and fix these when we install the
480 # staging packages.
481 #
482 # Note: the logic in this function needs to match the reverse logic
483 # in sstate_installpkg(ss, d)
484
485 staging = d.getVar('STAGING_DIR', True)
486 staging_target = d.getVar('STAGING_DIR_TARGET', True)
487 staging_host = d.getVar('STAGING_DIR_HOST', True)
488 sstate_builddir = d.getVar('SSTATE_BUILDDIR', True)
489
490 if bb.data.inherits_class('native', d) or bb.data.inherits_class('nativesdk', d) or bb.data.inherits_class('crosssdk', d) or bb.data.inherits_class('cross-canadian', d):
491 sstate_grep_cmd = "grep -l -e '%s'" % (staging)
492 sstate_sed_cmd = "sed -i -e 's:%s:FIXMESTAGINGDIR:g'" % (staging)
493 elif bb.data.inherits_class('cross', d):
494 sstate_grep_cmd = "grep -l -e '%s' -e '%s'" % (staging_target, staging)
495 sstate_sed_cmd = "sed -i -e 's:%s:FIXMESTAGINGDIRTARGET:g; s:%s:FIXMESTAGINGDIR:g'" % (staging_target, staging)
496 else:
497 sstate_grep_cmd = "grep -l -e '%s'" % (staging_host)
498 sstate_sed_cmd = "sed -i -e 's:%s:FIXMESTAGINGDIRHOST:g'" % (staging_host)
499
500 extra_staging_fixmes = d.getVar('EXTRA_STAGING_FIXMES', True) or ''
501 for fixmevar in extra_staging_fixmes.split():
502 fixme_path = d.getVar(fixmevar, True)
503 sstate_sed_cmd += " -e 's:%s:FIXME_%s:g'" % (fixme_path, fixmevar)
504
505 fixmefn = sstate_builddir + "fixmepath"
506
507 sstate_scan_cmd = d.getVar('SSTATE_SCAN_CMD', True)
508 sstate_filelist_cmd = "tee %s" % (fixmefn)
509
510 # fixmepath file needs relative paths, drop sstate_builddir prefix
511 sstate_filelist_relative_cmd = "sed -i -e 's:^%s::g' %s" % (sstate_builddir, fixmefn)
512
513 xargs_no_empty_run_cmd = '--no-run-if-empty'
514 if platform.system() == 'Darwin':
515 xargs_no_empty_run_cmd = ''
516
517 # Limit the fixpaths and sed operations based on the initial grep search
518 # This has the side effect of making sure the vfs cache is hot
519 sstate_hardcode_cmd = "%s | xargs %s | %s | xargs %s %s" % (sstate_scan_cmd, sstate_grep_cmd, sstate_filelist_cmd, xargs_no_empty_run_cmd, sstate_sed_cmd)
520
521 bb.note("Removing hardcoded paths from sstate package: '%s'" % (sstate_hardcode_cmd))
522 subprocess.call(sstate_hardcode_cmd, shell=True)
523
524 # If the fixmefn is empty, remove it..
525 if os.stat(fixmefn).st_size == 0:
526 os.remove(fixmefn)
527 else:
528 bb.note("Replacing absolute paths in fixmepath file: '%s'" % (sstate_filelist_relative_cmd))
529 subprocess.call(sstate_filelist_relative_cmd, shell=True)
530}
531
532def sstate_package(ss, d):
533 import oe.path
534
535 def make_relative_symlink(path, outputpath, d):
536 # Replace out absolute TMPDIR paths in symlinks with relative ones
537 if not os.path.islink(path):
538 return
539 link = os.readlink(path)
540 if not os.path.isabs(link):
541 return
542 if not link.startswith(tmpdir):
543 return
544
545 depth = outputpath.rpartition(tmpdir)[2].count('/')
546 base = link.partition(tmpdir)[2].strip()
547 while depth > 1:
548 base = "/.." + base
549 depth -= 1
550 base = "." + base
551
552 bb.debug(2, "Replacing absolute path %s with relative path %s for %s" % (link, base, outputpath))
553 os.remove(path)
554 os.symlink(base, path)
555
556 tmpdir = d.getVar('TMPDIR', True)
557
558 sstatebuild = d.expand("${WORKDIR}/sstate-build-%s/" % ss['task'])
559 sstatepkg = d.getVar('SSTATE_PKG', True) + '_'+ ss['task'] + ".tgz"
560 bb.utils.remove(sstatebuild, recurse=True)
561 bb.utils.mkdirhier(sstatebuild)
562 bb.utils.mkdirhier(os.path.dirname(sstatepkg))
563 for state in ss['dirs']:
564 if not os.path.exists(state[1]):
565 continue
566 srcbase = state[0].rstrip("/").rsplit('/', 1)[0]
567 for walkroot, dirs, files in os.walk(state[1]):
568 for file in files:
569 srcpath = os.path.join(walkroot, file)
570 dstpath = srcpath.replace(state[1], state[2])
571 make_relative_symlink(srcpath, dstpath, d)
572 for dir in dirs:
573 srcpath = os.path.join(walkroot, dir)
574 dstpath = srcpath.replace(state[1], state[2])
575 make_relative_symlink(srcpath, dstpath, d)
576 bb.debug(2, "Preparing tree %s for packaging at %s" % (state[1], sstatebuild + state[0]))
577 oe.path.copyhardlinktree(state[1], sstatebuild + state[0])
578
579 workdir = d.getVar('WORKDIR', True)
580 for plain in ss['plaindirs']:
581 pdir = plain.replace(workdir, sstatebuild)
582 bb.utils.mkdirhier(plain)
583 bb.utils.mkdirhier(pdir)
584 oe.path.copyhardlinktree(plain, pdir)
585
586 d.setVar('SSTATE_BUILDDIR', sstatebuild)
587 d.setVar('SSTATE_PKG', sstatepkg)
588
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500589 for f in (d.getVar('SSTATECREATEFUNCS', True) or '').split() + \
590 ['sstate_create_package', 'sstate_sign_package'] + \
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500591 (d.getVar('SSTATEPOSTCREATEFUNCS', True) or '').split():
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500592 # All hooks should run in SSTATE_BUILDDIR.
593 bb.build.exec_func(f, d, (sstatebuild,))
594
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500595 bb.siggen.dump_this_task(sstatepkg + ".siginfo", d)
596
597 return
598
599def pstaging_fetch(sstatefetch, sstatepkg, d):
600 import bb.fetch2
601
602 # Only try and fetch if the user has configured a mirror
603 mirrors = d.getVar('SSTATE_MIRRORS', True)
604 if not mirrors:
605 return
606
607 # Copy the data object and override DL_DIR and SRC_URI
608 localdata = bb.data.createCopy(d)
609 bb.data.update_data(localdata)
610
611 dldir = localdata.expand("${SSTATE_DIR}")
612 bb.utils.mkdirhier(dldir)
613
614 localdata.delVar('MIRRORS')
615 localdata.setVar('FILESPATH', dldir)
616 localdata.setVar('DL_DIR', dldir)
617 localdata.setVar('PREMIRRORS', mirrors)
618
619 # if BB_NO_NETWORK is set but we also have SSTATE_MIRROR_ALLOW_NETWORK,
620 # we'll want to allow network access for the current set of fetches.
621 if localdata.getVar('BB_NO_NETWORK', True) == "1" and localdata.getVar('SSTATE_MIRROR_ALLOW_NETWORK', True) == "1":
622 localdata.delVar('BB_NO_NETWORK')
623
624 # Try a fetch from the sstate mirror, if it fails just return and
625 # we will build the package
626 uris = ['file://{0}'.format(sstatefetch),
627 'file://{0}.siginfo'.format(sstatefetch)]
628 if bb.utils.to_boolean(d.getVar("SSTATE_VERIFY_SIG", True), False):
629 uris += ['file://{0}.sig'.format(sstatefetch)]
630
631 for srcuri in uris:
632 localdata.setVar('SRC_URI', srcuri)
633 try:
634 fetcher = bb.fetch2.Fetch([srcuri], localdata, cache=False)
635 fetcher.download()
636
637 # Need to optimise this, if using file:// urls, the fetcher just changes the local path
638 # For now work around by symlinking
639 localpath = bb.data.expand(fetcher.localpath(srcuri), localdata)
640 if localpath != sstatepkg and os.path.exists(localpath) and not os.path.exists(sstatepkg):
641 os.symlink(localpath, sstatepkg)
642
643 except bb.fetch2.BBFetchException:
644 break
645
646def sstate_setscene(d):
647 shared_state = sstate_state_fromvars(d)
648 accelerate = sstate_installpkg(shared_state, d)
649 if not accelerate:
650 raise bb.build.FuncFailed("No suitable staging package found")
651
652python sstate_task_prefunc () {
653 shared_state = sstate_state_fromvars(d)
654 sstate_clean(shared_state, d)
655}
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500656sstate_task_prefunc[dirs] = "${WORKDIR}"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500657
658python sstate_task_postfunc () {
659 shared_state = sstate_state_fromvars(d)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500660
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500661 sstate_install(shared_state, d)
662 for intercept in shared_state['interceptfuncs']:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500663 bb.build.exec_func(intercept, d, (d.getVar("WORKDIR", True),))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500664 omask = os.umask(002)
665 if omask != 002:
666 bb.note("Using umask 002 (not %0o) for sstate packaging" % omask)
667 sstate_package(shared_state, d)
668 os.umask(omask)
669}
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500670sstate_task_postfunc[dirs] = "${WORKDIR}"
671
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500672
673#
674# Shell function to generate a sstate package from a directory
675# set as SSTATE_BUILDDIR. Will be run from within SSTATE_BUILDDIR.
676#
677sstate_create_package () {
678 TFILE=`mktemp ${SSTATE_PKG}.XXXXXXXX`
679 # Need to handle empty directories
680 if [ "$(ls -A)" ]; then
681 set +e
682 tar -czf $TFILE *
683 ret=$?
684 if [ $ret -ne 0 ] && [ $ret -ne 1 ]; then
685 exit 1
686 fi
687 set -e
688 else
689 tar -cz --file=$TFILE --files-from=/dev/null
690 fi
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500691 chmod 0664 $TFILE
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500692 mv -f $TFILE ${SSTATE_PKG}
693
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500694 cd ${WORKDIR}
695 rm -rf ${SSTATE_BUILDDIR}
696}
697
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500698python sstate_sign_package () {
699 from oe.gpg_sign import get_signer
700
701 if d.getVar('SSTATE_SIG_KEY', True):
702 signer = get_signer(d, 'local')
703 sstate_pkg = d.getVar('SSTATE_PKG', True)
704 if os.path.exists(sstate_pkg + '.sig'):
705 os.unlink(sstate_pkg + '.sig')
706 signer.detach_sign(sstate_pkg, d.getVar('SSTATE_SIG_KEY', False), None,
707 d.getVar('SSTATE_SIG_PASSPHRASE', True), armor=False)
708}
709
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500710#
711# Shell function to decompress and prepare a package for installation
712# Will be run from within SSTATE_INSTDIR.
713#
714sstate_unpack_package () {
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500715 tar -xvzf ${SSTATE_PKG}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500716 # Use "! -w ||" to return true for read only files
717 [ ! -w ${SSTATE_PKG} ] || touch --no-dereference ${SSTATE_PKG}
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500718 [ ! -w ${SSTATE_PKG}.sig ] || [ ! -e ${SSTATE_PKG}.sig ] || touch --no-dereference ${SSTATE_PKG}.sig
719 [ ! -w ${SSTATE_PKG}.siginfo ] || [ ! -e ${SSTATE_PKG}.siginfo ] || touch --no-dereference ${SSTATE_PKG}.siginfo
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500720}
721
722BB_HASHCHECK_FUNCTION = "sstate_checkhashes"
723
724def sstate_checkhashes(sq_fn, sq_task, sq_hash, sq_hashfn, d, siginfo=False):
725
726 ret = []
727 missed = []
728 extension = ".tgz"
729 if siginfo:
730 extension = extension + ".siginfo"
731
732 def getpathcomponents(task, d):
733 # Magic data from BB_HASHFILENAME
734 splithashfn = sq_hashfn[task].split(" ")
735 spec = splithashfn[1]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500736 if splithashfn[0] == "True":
737 extrapath = d.getVar("NATIVELSBSTRING", True) + "/"
738 else:
739 extrapath = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500740
741 tname = sq_task[task][3:]
742
743 if tname in ["fetch", "unpack", "patch", "populate_lic", "preconfigure"] and splithashfn[2]:
744 spec = splithashfn[2]
745 extrapath = ""
746
747 return spec, extrapath, tname
748
749
750 for task in range(len(sq_fn)):
751
752 spec, extrapath, tname = getpathcomponents(task, d)
753
754 sstatefile = d.expand("${SSTATE_DIR}/" + extrapath + generate_sstatefn(spec, sq_hash[task], d) + "_" + tname + extension)
755
756 if os.path.exists(sstatefile):
757 bb.debug(2, "SState: Found valid sstate file %s" % sstatefile)
758 ret.append(task)
759 continue
760 else:
761 missed.append(task)
762 bb.debug(2, "SState: Looked for but didn't find file %s" % sstatefile)
763
764 mirrors = d.getVar("SSTATE_MIRRORS", True)
765 if mirrors:
766 # Copy the data object and override DL_DIR and SRC_URI
767 localdata = bb.data.createCopy(d)
768 bb.data.update_data(localdata)
769
770 dldir = localdata.expand("${SSTATE_DIR}")
771 localdata.delVar('MIRRORS')
772 localdata.setVar('FILESPATH', dldir)
773 localdata.setVar('DL_DIR', dldir)
774 localdata.setVar('PREMIRRORS', mirrors)
775
776 bb.debug(2, "SState using premirror of: %s" % mirrors)
777
778 # if BB_NO_NETWORK is set but we also have SSTATE_MIRROR_ALLOW_NETWORK,
779 # we'll want to allow network access for the current set of fetches.
780 if localdata.getVar('BB_NO_NETWORK', True) == "1" and localdata.getVar('SSTATE_MIRROR_ALLOW_NETWORK', True) == "1":
781 localdata.delVar('BB_NO_NETWORK')
782
783 from bb.fetch2 import FetchConnectionCache
784 def checkstatus_init(thread_worker):
785 thread_worker.connection_cache = FetchConnectionCache()
786
787 def checkstatus_end(thread_worker):
788 thread_worker.connection_cache.close_connections()
789
790 def checkstatus(thread_worker, arg):
791 (task, sstatefile) = arg
792
793 localdata2 = bb.data.createCopy(localdata)
794 srcuri = "file://" + sstatefile
795 localdata.setVar('SRC_URI', srcuri)
796 bb.debug(2, "SState: Attempting to fetch %s" % srcuri)
797
798 try:
799 fetcher = bb.fetch2.Fetch(srcuri.split(), localdata2,
800 connection_cache=thread_worker.connection_cache)
801 fetcher.checkstatus()
802 bb.debug(2, "SState: Successful fetch test for %s" % srcuri)
803 ret.append(task)
804 if task in missed:
805 missed.remove(task)
806 except:
807 missed.append(task)
808 bb.debug(2, "SState: Unsuccessful fetch test for %s" % srcuri)
809 pass
810
811 tasklist = []
812 for task in range(len(sq_fn)):
813 if task in ret:
814 continue
815 spec, extrapath, tname = getpathcomponents(task, d)
816 sstatefile = d.expand(extrapath + generate_sstatefn(spec, sq_hash[task], d) + "_" + tname + extension)
817 tasklist.append((task, sstatefile))
818
819 if tasklist:
820 bb.note("Checking sstate mirror object availability (for %s objects)" % len(tasklist))
821 import multiprocessing
822 nproc = min(multiprocessing.cpu_count(), len(tasklist))
823
824 pool = oe.utils.ThreadedPool(nproc, len(tasklist),
825 worker_init=checkstatus_init, worker_end=checkstatus_end)
826 for t in tasklist:
827 pool.add_task(checkstatus, t)
828 pool.start()
829 pool.wait_completion()
830
831 inheritlist = d.getVar("INHERIT", True)
832 if "toaster" in inheritlist:
833 evdata = {'missed': [], 'found': []};
834 for task in missed:
835 spec, extrapath, tname = getpathcomponents(task, d)
836 sstatefile = d.expand(extrapath + generate_sstatefn(spec, sq_hash[task], d) + "_" + tname + ".tgz")
837 evdata['missed'].append( (sq_fn[task], sq_task[task], sq_hash[task], sstatefile ) )
838 for task in ret:
839 spec, extrapath, tname = getpathcomponents(task, d)
840 sstatefile = d.expand(extrapath + generate_sstatefn(spec, sq_hash[task], d) + "_" + tname + ".tgz")
841 evdata['found'].append( (sq_fn[task], sq_task[task], sq_hash[task], sstatefile ) )
842 bb.event.fire(bb.event.MetadataEvent("MissedSstate", evdata), d)
843
844 if hasattr(bb.parse.siggen, "checkhashes"):
845 bb.parse.siggen.checkhashes(missed, ret, sq_fn, sq_task, sq_hash, sq_hashfn, d)
846
847 return ret
848
849BB_SETSCENE_DEPVALID = "setscene_depvalid"
850
851def setscene_depvalid(task, taskdependees, notneeded, d):
852 # taskdependees is a dict of tasks which depend on task, each being a 3 item list of [PN, TASKNAME, FILENAME]
853 # task is included in taskdependees too
854
855 bb.debug(2, "Considering setscene task: %s" % (str(taskdependees[task])))
856
857 def isNativeCross(x):
858 return x.endswith("-native") or "-cross-" in x or "-crosssdk" in x
859
860 def isPostInstDep(x):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500861 if x in ["qemu-native", "gdk-pixbuf-native", "qemuwrapper-cross", "depmodwrapper-cross", "systemd-systemctl-native", "gtk-icon-utils-native", "ca-certificates-native"]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500862 return True
863 return False
864
865 # We only need to trigger populate_lic through direct dependencies
866 if taskdependees[task][1] == "do_populate_lic":
867 return True
868
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500869 # We only need to trigger packagedata through direct dependencies
870 # but need to preserve packagedata on packagedata links
871 if taskdependees[task][1] == "do_packagedata":
872 for dep in taskdependees:
873 if taskdependees[dep][1] == "do_packagedata":
874 return False
875 return True
876
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500877 for dep in taskdependees:
878 bb.debug(2, " considering dependency: %s" % (str(taskdependees[dep])))
879 if task == dep:
880 continue
881 if dep in notneeded:
882 continue
883 # do_package_write_* and do_package doesn't need do_package
884 if taskdependees[task][1] == "do_package" and taskdependees[dep][1] in ['do_package', 'do_package_write_deb', 'do_package_write_ipk', 'do_package_write_rpm', 'do_packagedata', 'do_package_qa']:
885 continue
886 # do_package_write_* and do_package doesn't need do_populate_sysroot, unless is a postinstall dependency
887 if taskdependees[task][1] == "do_populate_sysroot" and taskdependees[dep][1] in ['do_package', 'do_package_write_deb', 'do_package_write_ipk', 'do_package_write_rpm', 'do_packagedata', 'do_package_qa']:
888 if isPostInstDep(taskdependees[task][0]) and taskdependees[dep][1] in ['do_package_write_deb', 'do_package_write_ipk', 'do_package_write_rpm']:
889 return False
890 continue
891 # Native/Cross packages don't exist and are noexec anyway
892 if isNativeCross(taskdependees[dep][0]) and taskdependees[dep][1] in ['do_package_write_deb', 'do_package_write_ipk', 'do_package_write_rpm', 'do_packagedata', 'do_package', 'do_package_qa']:
893 continue
894
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500895 # This is due to the [depends] in useradd.bbclass complicating matters
896 # The logic *is* reversed here due to the way hard setscene dependencies are injected
897 if (taskdependees[task][1] == 'do_package' or taskdependees[task][1] == 'do_populate_sysroot') and taskdependees[dep][0].endswith(('shadow-native', 'shadow-sysroot', 'base-passwd', 'pseudo-native')) and taskdependees[dep][1] == 'do_populate_sysroot':
898 continue
899
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500900 # Consider sysroot depending on sysroot tasks
901 if taskdependees[task][1] == 'do_populate_sysroot' and taskdependees[dep][1] == 'do_populate_sysroot':
902 # base-passwd/shadow-sysroot don't need their dependencies
903 if taskdependees[dep][0].endswith(("base-passwd", "shadow-sysroot")):
904 continue
905 # Nothing need depend on libc-initial/gcc-cross-initial
906 if "-initial" in taskdependees[task][0]:
907 continue
908 # Native/Cross populate_sysroot need their dependencies
909 if isNativeCross(taskdependees[task][0]) and isNativeCross(taskdependees[dep][0]):
910 return False
911 # Target populate_sysroot depended on by cross tools need to be installed
912 if isNativeCross(taskdependees[dep][0]):
913 return False
914 # Native/cross tools depended upon by target sysroot are not needed
915 if isNativeCross(taskdependees[task][0]):
916 continue
917 # Target populate_sysroot need their dependencies
918 return False
919
920 if taskdependees[task][1] == 'do_shared_workdir':
921 continue
922
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500923 if taskdependees[dep][1] == "do_populate_lic":
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500924 continue
925
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500926
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500927 # Safe fallthrough default
928 bb.debug(2, " Default setscene dependency fall through due to dependency: %s" % (str(taskdependees[dep])))
929 return False
930 return True
931
932addhandler sstate_eventhandler
933sstate_eventhandler[eventmask] = "bb.build.TaskSucceeded"
934python sstate_eventhandler() {
935 d = e.data
936 # When we write an sstate package we rewrite the SSTATE_PKG
937 spkg = d.getVar('SSTATE_PKG', True)
938 if not spkg.endswith(".tgz"):
939 taskname = d.getVar("BB_RUNTASK", True)[3:]
940 spec = d.getVar('SSTATE_PKGSPEC', True)
941 swspec = d.getVar('SSTATE_SWSPEC', True)
942 if taskname in ["fetch", "unpack", "patch", "populate_lic", "preconfigure"] and swspec:
943 d.setVar("SSTATE_PKGSPEC", "${SSTATE_SWSPEC}")
944 d.setVar("SSTATE_EXTRAPATH", "")
945 sstatepkg = d.getVar('SSTATE_PKG', True)
946 bb.siggen.dump_this_task(sstatepkg + '_' + taskname + ".tgz" ".siginfo", d)
947}
948
949SSTATE_PRUNE_OBSOLETEWORKDIR = "1"
950
951# Event handler which removes manifests and stamps file for
952# recipes which are no longer reachable in a build where they
953# once were.
954# Also optionally removes the workdir of those tasks/recipes
955#
956addhandler sstate_eventhandler2
957sstate_eventhandler2[eventmask] = "bb.event.ReachableStamps"
958python sstate_eventhandler2() {
959 import glob
960 d = e.data
961 stamps = e.stamps.values()
962 removeworkdir = (d.getVar("SSTATE_PRUNE_OBSOLETEWORKDIR", False) == "1")
963 seen = []
964 for a in d.getVar("SSTATE_ARCHS", True).split():
965 toremove = []
966 i = d.expand("${SSTATE_MANIFESTS}/index-" + a)
967 if not os.path.exists(i):
968 continue
969 with open(i, "r") as f:
970 lines = f.readlines()
971 for l in lines:
972 (stamp, manifest, workdir) = l.split()
973 if stamp not in stamps:
974 toremove.append(l)
975 if stamp not in seen:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500976 bb.debug(2, "Stamp %s is not reachable, removing related manifests" % stamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500977 seen.append(stamp)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500978
979 if toremove:
980 bb.note("There are %d recipes to be removed from sysroot %s, removing..." % (len(toremove), a))
981
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500982 for r in toremove:
983 (stamp, manifest, workdir) = r.split()
984 for m in glob.glob(manifest + ".*"):
985 sstate_clean_manifest(m, d)
986 bb.utils.remove(stamp + "*")
987 if removeworkdir:
988 bb.utils.remove(workdir, recurse = True)
989 lines.remove(r)
990 with open(i, "w") as f:
991 for l in lines:
992 f.write(l)
993}