summaryrefslogtreecommitdiffstats
path: root/meta/classes/sstate.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes/sstate.bbclass')
-rw-r--r--meta/classes/sstate.bbclass837
1 files changed, 837 insertions, 0 deletions
diff --git a/meta/classes/sstate.bbclass b/meta/classes/sstate.bbclass
new file mode 100644
index 0000000000..ace6bdb57a
--- /dev/null
+++ b/meta/classes/sstate.bbclass
@@ -0,0 +1,837 @@
1SSTATE_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}:"
13SSTATE_SWSPEC = "sstate:${BPN}::${PV}:${PR}::${SSTATE_VERSION}:"
14SSTATE_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
29SSTATE_SCAN_FILES ?= "*.la *-config *_config"
30SSTATE_SCAN_CMD ?= 'find ${SSTATE_BUILDDIR} \( -name "${@"\" -o -name \"".join(d.getVar("SSTATE_SCAN_FILES", True).split())}" \) -type f'
31
32BB_HASHFILENAME = "${SSTATE_EXTRAPATH} ${SSTATE_PKGSPEC} ${SSTATE_SWSPEC}"
33
34SSTATE_MANMACH ?= "${SSTATE_PKGARCH}"
35
36SSTATECREATEFUNCS = "sstate_hardcode_path"
37SSTATEPOSTCREATEFUNCS = ""
38SSTATEPREINSTFUNCS = ""
39SSTATEPOSTUNPACKFUNCS = "sstate_hardcode_path_unpack"
40SSTATEPOSTINSTFUNCS = ""
41EXTRA_STAGING_FIXMES ?= ""
42
43SIGGEN_LOCKEDSIGS_CHECK_LEVEL ?= 'error'
44
45# Specify dirs in which the shell function is executed and don't use ${B}
46# as default dirs to avoid possible race about ${B} with other task.
47sstate_create_package[dirs] = "${SSTATE_BUILDDIR}"
48sstate_unpack_package[dirs] = "${SSTATE_INSTDIR}"
49
50# Do not run sstate_hardcode_path() in ${B}:
51# the ${B} maybe removed by cmake_do_configure() while
52# sstate_hardcode_path() running.
53sstate_hardcode_path[dirs] = "${SSTATE_BUILDDIR}"
54
55python () {
56 if bb.data.inherits_class('native', d):
57 d.setVar('SSTATE_PKGARCH', d.getVar('BUILD_ARCH'))
58 elif bb.data.inherits_class('crosssdk', d):
59 d.setVar('SSTATE_PKGARCH', d.expand("${BUILD_ARCH}_${SDK_ARCH}_${SDK_OS}"))
60 elif bb.data.inherits_class('cross', d):
61 d.setVar('SSTATE_PKGARCH', d.expand("${BUILD_ARCH}_${TARGET_ARCH}"))
62 elif bb.data.inherits_class('nativesdk', d):
63 d.setVar('SSTATE_PKGARCH', d.expand("${SDK_ARCH}_${SDK_OS}"))
64 elif bb.data.inherits_class('cross-canadian', d):
65 d.setVar('SSTATE_PKGARCH', d.expand("${SDK_ARCH}_${PACKAGE_ARCH}"))
66 elif bb.data.inherits_class('allarch', d) and d.getVar("PACKAGE_ARCH", True) == "all":
67 d.setVar('SSTATE_PKGARCH', "allarch")
68 else:
69 d.setVar('SSTATE_MANMACH', d.expand("${PACKAGE_ARCH}"))
70
71 if bb.data.inherits_class('native', d) or bb.data.inherits_class('crosssdk', d) or bb.data.inherits_class('cross', d):
72 d.setVar('SSTATE_EXTRAPATH', "${NATIVELSBSTRING}/")
73 d.setVar('SSTATE_EXTRAPATHWILDCARD', "*/")
74
75 # These classes encode staging paths into their scripts data so can only be
76 # reused if we manipulate the paths
77 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):
78 scan_cmd = "grep -Irl ${STAGING_DIR} ${SSTATE_BUILDDIR}"
79 d.setVar('SSTATE_SCAN_CMD', scan_cmd)
80
81 unique_tasks = set((d.getVar('SSTATETASKS', True) or "").split())
82 d.setVar('SSTATETASKS', " ".join(unique_tasks))
83 for task in unique_tasks:
84 d.prependVarFlag(task, 'prefuncs', "sstate_task_prefunc ")
85 d.appendVarFlag(task, 'postfuncs', " sstate_task_postfunc")
86}
87
88def sstate_init(task, d):
89 ss = {}
90 ss['task'] = task
91 ss['dirs'] = []
92 ss['plaindirs'] = []
93 ss['lockfiles'] = []
94 ss['lockfiles-shared'] = []
95 return ss
96
97def sstate_state_fromvars(d, task = None):
98 if task is None:
99 task = d.getVar('BB_CURRENTTASK', True)
100 if not task:
101 bb.fatal("sstate code running without task context?!")
102 task = task.replace("_setscene", "")
103
104 if task.startswith("do_"):
105 task = task[3:]
106 inputs = (d.getVarFlag("do_" + task, 'sstate-inputdirs', True) or "").split()
107 outputs = (d.getVarFlag("do_" + task, 'sstate-outputdirs', True) or "").split()
108 plaindirs = (d.getVarFlag("do_" + task, 'sstate-plaindirs', True) or "").split()
109 lockfiles = (d.getVarFlag("do_" + task, 'sstate-lockfile', True) or "").split()
110 lockfilesshared = (d.getVarFlag("do_" + task, 'sstate-lockfile-shared', True) or "").split()
111 interceptfuncs = (d.getVarFlag("do_" + task, 'sstate-interceptfuncs', True) or "").split()
112 if not task or len(inputs) != len(outputs):
113 bb.fatal("sstate variables not setup correctly?!")
114
115 if task == "populate_lic":
116 d.setVar("SSTATE_PKGSPEC", "${SSTATE_SWSPEC}")
117 d.setVar("SSTATE_EXTRAPATH", "")
118
119 ss = sstate_init(task, d)
120 for i in range(len(inputs)):
121 sstate_add(ss, inputs[i], outputs[i], d)
122 ss['lockfiles'] = lockfiles
123 ss['lockfiles-shared'] = lockfilesshared
124 ss['plaindirs'] = plaindirs
125 ss['interceptfuncs'] = interceptfuncs
126 return ss
127
128def sstate_add(ss, source, dest, d):
129 if not source.endswith("/"):
130 source = source + "/"
131 if not dest.endswith("/"):
132 dest = dest + "/"
133 source = os.path.normpath(source)
134 dest = os.path.normpath(dest)
135 srcbase = os.path.basename(source)
136 ss['dirs'].append([srcbase, source, dest])
137 return ss
138
139def sstate_install(ss, d):
140 import oe.path
141 import subprocess
142
143 sharedfiles = []
144 shareddirs = []
145 bb.utils.mkdirhier(d.expand("${SSTATE_MANIFESTS}"))
146
147 d2 = d.createCopy()
148 extrainf = d.getVarFlag("do_" + ss['task'], 'stamp-extra-info', True)
149 if extrainf:
150 d2.setVar("SSTATE_MANMACH", extrainf)
151 manifest = d2.expand("${SSTATE_MANFILEPREFIX}.%s" % ss['task'])
152
153 if os.access(manifest, os.R_OK):
154 bb.fatal("Package already staged (%s)?!" % manifest)
155
156 locks = []
157 for lock in ss['lockfiles-shared']:
158 locks.append(bb.utils.lockfile(lock, True))
159 for lock in ss['lockfiles']:
160 locks.append(bb.utils.lockfile(lock))
161
162 for state in ss['dirs']:
163 bb.debug(2, "Staging files from %s to %s" % (state[1], state[2]))
164 for walkroot, dirs, files in os.walk(state[1]):
165 for file in files:
166 srcpath = os.path.join(walkroot, file)
167 dstpath = srcpath.replace(state[1], state[2])
168 #bb.debug(2, "Staging %s to %s" % (srcpath, dstpath))
169 sharedfiles.append(dstpath)
170 for dir in dirs:
171 srcdir = os.path.join(walkroot, dir)
172 dstdir = srcdir.replace(state[1], state[2])
173 #bb.debug(2, "Staging %s to %s" % (srcdir, dstdir))
174 if not dstdir.endswith("/"):
175 dstdir = dstdir + "/"
176 shareddirs.append(dstdir)
177
178 # Check the file list for conflicts against files which already exist
179 whitelist = (d.getVar("SSTATE_DUPWHITELIST", True) or "").split()
180 match = []
181 for f in sharedfiles:
182 if os.path.exists(f):
183 f = os.path.normpath(f)
184 realmatch = True
185 for w in whitelist:
186 if f.startswith(w):
187 realmatch = False
188 break
189 if realmatch:
190 match.append(f)
191 sstate_search_cmd = "grep -rl '%s' %s --exclude=master.list | sed -e 's:^.*/::' -e 's:\.populate-sysroot::'" % (f, d.expand("${SSTATE_MANIFESTS}"))
192 search_output = subprocess.Popen(sstate_search_cmd, shell=True, stdout=subprocess.PIPE).communicate()[0]
193 if search_output != "":
194 match.append("Matched in %s" % search_output.rstrip())
195 if match:
196 bb.error("The recipe %s is trying to install files into a shared " \
197 "area when those files already exist. Those files and their manifest " \
198 "location are:\n %s\nPlease verify which recipe should provide the " \
199 "above files.\nThe build has stopped as continuing in this scenario WILL " \
200 "break things, if not now, possibly in the future (we've seen builds fail " \
201 "several months later). If the system knew how to recover from this " \
202 "automatically it would however there are several different scenarios " \
203 "which can result in this and we don't know which one this is. It may be " \
204 "you have switched providers of something like virtual/kernel (e.g. from " \
205 "linux-yocto to linux-yocto-dev), in that case you need to execute the " \
206 "clean task for both recipes and it will resolve this error. It may be " \
207 "you changed DISTRO_FEATURES from systemd to udev or vice versa. Cleaning " \
208 "those recipes should again resolve this error however switching " \
209 "DISTRO_FEATURES on an existing build directory is not supported, you " \
210 "should really clean out tmp and rebuild (reusing sstate should be safe). " \
211 "It could be the overlapping files detected are harmless in which case " \
212 "adding them to SSTATE_DUPWHITELIST may be the correct solution. It could " \
213 "also be your build is including two different conflicting versions of " \
214 "things (e.g. bluez 4 and bluez 5 and the correct solution for that would " \
215 "be to resolve the conflict. If in doubt, please ask on the mailing list, " \
216 "sharing the error and filelist above." % \
217 (d.getVar('PN', True), "\n ".join(match)))
218 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.")
219
220 # Write out the manifest
221 f = open(manifest, "w")
222 for file in sharedfiles:
223 f.write(file + "\n")
224
225 # We want to ensure that directories appear at the end of the manifest
226 # so that when we test to see if they should be deleted any contents
227 # added by the task will have been removed first.
228 dirs = sorted(shareddirs, key=len)
229 # Must remove children first, which will have a longer path than the parent
230 for di in reversed(dirs):
231 f.write(di + "\n")
232 f.close()
233
234 # Run the actual file install
235 for state in ss['dirs']:
236 if os.path.exists(state[1]):
237 oe.path.copyhardlinktree(state[1], state[2])
238
239 for postinst in (d.getVar('SSTATEPOSTINSTFUNCS', True) or '').split():
240 bb.build.exec_func(postinst, d)
241
242 for lock in locks:
243 bb.utils.unlockfile(lock)
244
245sstate_install[vardepsexclude] += "SSTATE_DUPWHITELIST STATE_MANMACH SSTATE_MANFILEPREFIX"
246sstate_install[vardeps] += "${SSTATEPOSTINSTFUNCS}"
247
248def sstate_installpkg(ss, d):
249 import oe.path
250 import subprocess
251
252 def prepdir(dir):
253 # remove dir if it exists, ensure any parent directories do exist
254 if os.path.exists(dir):
255 oe.path.remove(dir)
256 bb.utils.mkdirhier(dir)
257 oe.path.remove(dir)
258
259 sstateinst = d.expand("${WORKDIR}/sstate-install-%s/" % ss['task'])
260 sstatefetch = d.getVar('SSTATE_PKGNAME', True) + '_' + ss['task'] + ".tgz"
261 sstatepkg = d.getVar('SSTATE_PKG', True) + '_' + ss['task'] + ".tgz"
262
263 if not os.path.exists(sstatepkg):
264 pstaging_fetch(sstatefetch, sstatepkg, d)
265
266 if not os.path.isfile(sstatepkg):
267 bb.note("Staging package %s does not exist" % sstatepkg)
268 return False
269
270 sstate_clean(ss, d)
271
272 d.setVar('SSTATE_INSTDIR', sstateinst)
273 d.setVar('SSTATE_PKG', sstatepkg)
274
275 for f in (d.getVar('SSTATEPREINSTFUNCS', True) or '').split() + ['sstate_unpack_package'] + (d.getVar('SSTATEPOSTUNPACKFUNCS', True) or '').split():
276 bb.build.exec_func(f, d)
277
278 for state in ss['dirs']:
279 prepdir(state[1])
280 os.rename(sstateinst + state[0], state[1])
281 sstate_install(ss, d)
282
283 for plain in ss['plaindirs']:
284 workdir = d.getVar('WORKDIR', True)
285 src = sstateinst + "/" + plain.replace(workdir, '')
286 dest = plain
287 bb.utils.mkdirhier(src)
288 prepdir(dest)
289 os.rename(src, dest)
290
291 return True
292
293python sstate_hardcode_path_unpack () {
294 # Fixup hardcoded paths
295 #
296 # Note: The logic below must match the reverse logic in
297 # sstate_hardcode_path(d)
298 import subprocess
299
300 sstateinst = d.getVar('SSTATE_INSTDIR', True)
301 fixmefn = sstateinst + "fixmepath"
302 if os.path.isfile(fixmefn):
303 staging = d.getVar('STAGING_DIR', True)
304 staging_target = d.getVar('STAGING_DIR_TARGET', True)
305 staging_host = d.getVar('STAGING_DIR_HOST', True)
306
307 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):
308 sstate_sed_cmd = "sed -i -e 's:FIXMESTAGINGDIR:%s:g'" % (staging)
309 elif bb.data.inherits_class('cross', d):
310 sstate_sed_cmd = "sed -i -e 's:FIXMESTAGINGDIRTARGET:%s:g; s:FIXMESTAGINGDIR:%s:g'" % (staging_target, staging)
311 else:
312 sstate_sed_cmd = "sed -i -e 's:FIXMESTAGINGDIRHOST:%s:g'" % (staging_host)
313
314 extra_staging_fixmes = d.getVar('EXTRA_STAGING_FIXMES', True) or ''
315 for fixmevar in extra_staging_fixmes.split():
316 fixme_path = d.getVar(fixmevar, True)
317 sstate_sed_cmd += " -e 's:FIXME_%s:%s:g'" % (fixmevar, fixme_path)
318
319 # Add sstateinst to each filename in fixmepath, use xargs to efficiently call sed
320 sstate_hardcode_cmd = "sed -e 's:^:%s:g' %s | xargs %s" % (sstateinst, fixmefn, sstate_sed_cmd)
321
322 bb.note("Replacing fixme paths in sstate package: %s" % (sstate_hardcode_cmd))
323 subprocess.call(sstate_hardcode_cmd, shell=True)
324
325 # Need to remove this or we'd copy it into the target directory and may
326 # conflict with another writer
327 os.remove(fixmefn)
328}
329
330def sstate_clean_cachefile(ss, d):
331 import oe.path
332
333 sstatepkgfile = d.getVar('SSTATE_PATHSPEC', True) + "*_" + ss['task'] + ".tgz*"
334 bb.note("Removing %s" % sstatepkgfile)
335 oe.path.remove(sstatepkgfile)
336
337def sstate_clean_cachefiles(d):
338 for task in (d.getVar('SSTATETASKS', True) or "").split():
339 ld = d.createCopy()
340 ss = sstate_state_fromvars(ld, task)
341 sstate_clean_cachefile(ss, ld)
342
343def sstate_clean_manifest(manifest, d):
344 import oe.path
345
346 mfile = open(manifest)
347 entries = mfile.readlines()
348 mfile.close()
349
350 for entry in entries:
351 entry = entry.strip()
352 bb.debug(2, "Removing manifest: %s" % entry)
353 # We can race against another package populating directories as we're removing them
354 # so we ignore errors here.
355 try:
356 if entry.endswith("/"):
357 if os.path.islink(entry[:-1]):
358 os.remove(entry[:-1])
359 elif os.path.exists(entry) and len(os.listdir(entry)) == 0:
360 os.rmdir(entry[:-1])
361 else:
362 oe.path.remove(entry)
363 except OSError:
364 pass
365
366 oe.path.remove(manifest)
367
368def sstate_clean(ss, d):
369 import oe.path
370 import glob
371
372 d2 = d.createCopy()
373 stamp_clean = d.getVar("STAMPCLEAN", True)
374 extrainf = d.getVarFlag("do_" + ss['task'], 'stamp-extra-info', True)
375 if extrainf:
376 d2.setVar("SSTATE_MANMACH", extrainf)
377 wildcard_stfile = "%s.do_%s*.%s" % (stamp_clean, ss['task'], extrainf)
378 else:
379 wildcard_stfile = "%s.do_%s*" % (stamp_clean, ss['task'])
380
381 manifest = d2.expand("${SSTATE_MANFILEPREFIX}.%s" % ss['task'])
382
383 if os.path.exists(manifest):
384 locks = []
385 for lock in ss['lockfiles-shared']:
386 locks.append(bb.utils.lockfile(lock))
387 for lock in ss['lockfiles']:
388 locks.append(bb.utils.lockfile(lock))
389
390 sstate_clean_manifest(manifest, d)
391
392 for lock in locks:
393 bb.utils.unlockfile(lock)
394
395 # Remove the current and previous stamps, but keep the sigdata.
396 #
397 # The glob() matches do_task* which may match multiple tasks, for
398 # example: do_package and do_package_write_ipk, so we need to
399 # exactly match *.do_task.* and *.do_task_setscene.*
400 rm_stamp = '.do_%s.' % ss['task']
401 rm_setscene = '.do_%s_setscene.' % ss['task']
402 # For BB_SIGNATURE_HANDLER = "noop"
403 rm_nohash = ".do_%s" % ss['task']
404 for stfile in glob.glob(wildcard_stfile):
405 # Keep the sigdata
406 if ".sigdata." in stfile:
407 continue
408 # Preserve taint files in the stamps directory
409 if stfile.endswith('.taint'):
410 continue
411 if rm_stamp in stfile or rm_setscene in stfile or \
412 stfile.endswith(rm_nohash):
413 oe.path.remove(stfile)
414
415sstate_clean[vardepsexclude] = "SSTATE_MANFILEPREFIX"
416
417CLEANFUNCS += "sstate_cleanall"
418
419python sstate_cleanall() {
420 bb.note("Removing shared state for package %s" % d.getVar('PN', True))
421
422 manifest_dir = d.getVar('SSTATE_MANIFESTS', True)
423 if not os.path.exists(manifest_dir):
424 return
425
426 tasks = d.getVar('SSTATETASKS', True).split()
427 for name in tasks:
428 ld = d.createCopy()
429 shared_state = sstate_state_fromvars(ld, name)
430 sstate_clean(shared_state, ld)
431}
432
433python sstate_hardcode_path () {
434 import subprocess, platform
435
436 # Need to remove hardcoded paths and fix these when we install the
437 # staging packages.
438 #
439 # Note: the logic in this function needs to match the reverse logic
440 # in sstate_installpkg(ss, d)
441
442 staging = d.getVar('STAGING_DIR', True)
443 staging_target = d.getVar('STAGING_DIR_TARGET', True)
444 staging_host = d.getVar('STAGING_DIR_HOST', True)
445 sstate_builddir = d.getVar('SSTATE_BUILDDIR', True)
446
447 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):
448 sstate_grep_cmd = "grep -l -e '%s'" % (staging)
449 sstate_sed_cmd = "sed -i -e 's:%s:FIXMESTAGINGDIR:g'" % (staging)
450 elif bb.data.inherits_class('cross', d):
451 sstate_grep_cmd = "grep -l -e '%s' -e '%s'" % (staging_target, staging)
452 sstate_sed_cmd = "sed -i -e 's:%s:FIXMESTAGINGDIRTARGET:g; s:%s:FIXMESTAGINGDIR:g'" % (staging_target, staging)
453 else:
454 sstate_grep_cmd = "grep -l -e '%s'" % (staging_host)
455 sstate_sed_cmd = "sed -i -e 's:%s:FIXMESTAGINGDIRHOST:g'" % (staging_host)
456
457 extra_staging_fixmes = d.getVar('EXTRA_STAGING_FIXMES', True) or ''
458 for fixmevar in extra_staging_fixmes.split():
459 fixme_path = d.getVar(fixmevar, True)
460 sstate_sed_cmd += " -e 's:%s:FIXME_%s:g'" % (fixme_path, fixmevar)
461
462 fixmefn = sstate_builddir + "fixmepath"
463
464 sstate_scan_cmd = d.getVar('SSTATE_SCAN_CMD', True)
465 sstate_filelist_cmd = "tee %s" % (fixmefn)
466
467 # fixmepath file needs relative paths, drop sstate_builddir prefix
468 sstate_filelist_relative_cmd = "sed -i -e 's:^%s::g' %s" % (sstate_builddir, fixmefn)
469
470 xargs_no_empty_run_cmd = '--no-run-if-empty'
471 if platform.system() == 'Darwin':
472 xargs_no_empty_run_cmd = ''
473
474 # Limit the fixpaths and sed operations based on the initial grep search
475 # This has the side effect of making sure the vfs cache is hot
476 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)
477
478 bb.note("Removing hardcoded paths from sstate package: '%s'" % (sstate_hardcode_cmd))
479 subprocess.call(sstate_hardcode_cmd, shell=True)
480
481 # If the fixmefn is empty, remove it..
482 if os.stat(fixmefn).st_size == 0:
483 os.remove(fixmefn)
484 else:
485 bb.note("Replacing absolute paths in fixmepath file: '%s'" % (sstate_filelist_relative_cmd))
486 subprocess.call(sstate_filelist_relative_cmd, shell=True)
487}
488
489def sstate_package(ss, d):
490 import oe.path
491
492 def make_relative_symlink(path, outputpath, d):
493 # Replace out absolute TMPDIR paths in symlinks with relative ones
494 if not os.path.islink(path):
495 return
496 link = os.readlink(path)
497 if not os.path.isabs(link):
498 return
499 if not link.startswith(tmpdir):
500 return
501
502 depth = outputpath.rpartition(tmpdir)[2].count('/')
503 base = link.partition(tmpdir)[2].strip()
504 while depth > 1:
505 base = "/.." + base
506 depth -= 1
507 base = "." + base
508
509 bb.debug(2, "Replacing absolute path %s with relative path %s for %s" % (link, base, outputpath))
510 os.remove(path)
511 os.symlink(base, path)
512
513 tmpdir = d.getVar('TMPDIR', True)
514
515 sstatebuild = d.expand("${WORKDIR}/sstate-build-%s/" % ss['task'])
516 sstatepkg = d.getVar('SSTATE_PKG', True) + '_'+ ss['task'] + ".tgz"
517 bb.utils.remove(sstatebuild, recurse=True)
518 bb.utils.mkdirhier(sstatebuild)
519 bb.utils.mkdirhier(os.path.dirname(sstatepkg))
520 for state in ss['dirs']:
521 if not os.path.exists(state[1]):
522 continue
523 srcbase = state[0].rstrip("/").rsplit('/', 1)[0]
524 for walkroot, dirs, files in os.walk(state[1]):
525 for file in files:
526 srcpath = os.path.join(walkroot, file)
527 dstpath = srcpath.replace(state[1], state[2])
528 make_relative_symlink(srcpath, dstpath, d)
529 for dir in dirs:
530 srcpath = os.path.join(walkroot, dir)
531 dstpath = srcpath.replace(state[1], state[2])
532 make_relative_symlink(srcpath, dstpath, d)
533 bb.debug(2, "Preparing tree %s for packaging at %s" % (state[1], sstatebuild + state[0]))
534 oe.path.copyhardlinktree(state[1], sstatebuild + state[0])
535
536 workdir = d.getVar('WORKDIR', True)
537 for plain in ss['plaindirs']:
538 pdir = plain.replace(workdir, sstatebuild)
539 bb.utils.mkdirhier(plain)
540 bb.utils.mkdirhier(pdir)
541 oe.path.copyhardlinktree(plain, pdir)
542
543 d.setVar('SSTATE_BUILDDIR', sstatebuild)
544 d.setVar('SSTATE_PKG', sstatepkg)
545
546 for f in (d.getVar('SSTATECREATEFUNCS', True) or '').split() + ['sstate_create_package'] + \
547 (d.getVar('SSTATEPOSTCREATEFUNCS', True) or '').split():
548 bb.build.exec_func(f, d)
549
550 bb.siggen.dump_this_task(sstatepkg + ".siginfo", d)
551
552 return
553
554def pstaging_fetch(sstatefetch, sstatepkg, d):
555 import bb.fetch2
556
557 # Only try and fetch if the user has configured a mirror
558 mirrors = d.getVar('SSTATE_MIRRORS', True)
559 if not mirrors:
560 return
561
562 # Copy the data object and override DL_DIR and SRC_URI
563 localdata = bb.data.createCopy(d)
564 bb.data.update_data(localdata)
565
566 dldir = localdata.expand("${SSTATE_DIR}")
567 bb.utils.mkdirhier(dldir)
568
569 localdata.delVar('MIRRORS')
570 localdata.delVar('FILESPATH')
571 localdata.setVar('DL_DIR', dldir)
572 localdata.setVar('PREMIRRORS', mirrors)
573
574 # if BB_NO_NETWORK is set but we also have SSTATE_MIRROR_ALLOW_NETWORK,
575 # we'll want to allow network access for the current set of fetches.
576 if localdata.getVar('BB_NO_NETWORK', True) == "1" and localdata.getVar('SSTATE_MIRROR_ALLOW_NETWORK', True) == "1":
577 localdata.delVar('BB_NO_NETWORK')
578
579 # Try a fetch from the sstate mirror, if it fails just return and
580 # we will build the package
581 for srcuri in ['file://{0}'.format(sstatefetch),
582 'file://{0}.siginfo'.format(sstatefetch)]:
583 localdata.setVar('SRC_URI', srcuri)
584 try:
585 fetcher = bb.fetch2.Fetch([srcuri], localdata, cache=False)
586 fetcher.download()
587
588 # Need to optimise this, if using file:// urls, the fetcher just changes the local path
589 # For now work around by symlinking
590 localpath = bb.data.expand(fetcher.localpath(srcuri), localdata)
591 if localpath != sstatepkg and os.path.exists(localpath) and not os.path.exists(sstatepkg):
592 os.symlink(localpath, sstatepkg)
593
594 except bb.fetch2.BBFetchException:
595 break
596
597def sstate_setscene(d):
598 shared_state = sstate_state_fromvars(d)
599 accelerate = sstate_installpkg(shared_state, d)
600 if not accelerate:
601 raise bb.build.FuncFailed("No suitable staging package found")
602
603python sstate_task_prefunc () {
604 shared_state = sstate_state_fromvars(d)
605 sstate_clean(shared_state, d)
606}
607
608python sstate_task_postfunc () {
609 shared_state = sstate_state_fromvars(d)
610 sstate_install(shared_state, d)
611 for intercept in shared_state['interceptfuncs']:
612 bb.build.exec_func(intercept, d)
613 omask = os.umask(002)
614 if omask != 002:
615 bb.note("Using umask 002 (not %0o) for sstate packaging" % omask)
616 sstate_package(shared_state, d)
617 os.umask(omask)
618}
619
620
621#
622# Shell function to generate a sstate package from a directory
623# set as SSTATE_BUILDDIR
624#
625sstate_create_package () {
626 cd ${SSTATE_BUILDDIR}
627 TFILE=`mktemp ${SSTATE_PKG}.XXXXXXXX`
628 # Need to handle empty directories
629 if [ "$(ls -A)" ]; then
630 set +e
631 tar -czf $TFILE *
632 ret=$?
633 if [ $ret -ne 0 ] && [ $ret -ne 1 ]; then
634 exit 1
635 fi
636 set -e
637 else
638 tar -cz --file=$TFILE --files-from=/dev/null
639 fi
640 chmod 0664 $TFILE
641 mv -f $TFILE ${SSTATE_PKG}
642
643 cd ${WORKDIR}
644 rm -rf ${SSTATE_BUILDDIR}
645}
646
647#
648# Shell function to decompress and prepare a package for installation
649#
650sstate_unpack_package () {
651 mkdir -p ${SSTATE_INSTDIR}
652 cd ${SSTATE_INSTDIR}
653 tar -xmvzf ${SSTATE_PKG}
654 # Use "! -w ||" to return true for read only files
655 [ ! -w ${SSTATE_PKG} ] || touch --no-dereference ${SSTATE_PKG}
656}
657
658BB_HASHCHECK_FUNCTION = "sstate_checkhashes"
659
660def sstate_checkhashes(sq_fn, sq_task, sq_hash, sq_hashfn, d):
661
662 ret = []
663 missed = []
664
665 def getpathcomponents(task, d):
666 # Magic data from BB_HASHFILENAME
667 splithashfn = sq_hashfn[task].split(" ")
668 spec = splithashfn[1]
669 extrapath = splithashfn[0]
670
671 tname = sq_task[task][3:]
672
673 if tname in ["fetch", "unpack", "patch", "populate_lic", "preconfigure"] and splithashfn[2]:
674 spec = splithashfn[2]
675 extrapath = ""
676
677 return spec, extrapath, tname
678
679
680 for task in range(len(sq_fn)):
681
682 spec, extrapath, tname = getpathcomponents(task, d)
683
684 sstatefile = d.expand("${SSTATE_DIR}/" + extrapath + generate_sstatefn(spec, sq_hash[task], d) + "_" + tname + ".tgz.siginfo")
685
686 if os.path.exists(sstatefile):
687 bb.debug(2, "SState: Found valid sstate file %s" % sstatefile)
688 ret.append(task)
689 continue
690 else:
691 missed.append(task)
692 bb.debug(2, "SState: Looked for but didn't find file %s" % sstatefile)
693
694 mirrors = d.getVar("SSTATE_MIRRORS", True)
695 if mirrors:
696 # Copy the data object and override DL_DIR and SRC_URI
697 localdata = bb.data.createCopy(d)
698 bb.data.update_data(localdata)
699
700 dldir = localdata.expand("${SSTATE_DIR}")
701 localdata.setVar('DL_DIR', dldir)
702 localdata.setVar('PREMIRRORS', mirrors)
703
704 bb.debug(2, "SState using premirror of: %s" % mirrors)
705
706 # if BB_NO_NETWORK is set but we also have SSTATE_MIRROR_ALLOW_NETWORK,
707 # we'll want to allow network access for the current set of fetches.
708 if localdata.getVar('BB_NO_NETWORK', True) == "1" and localdata.getVar('SSTATE_MIRROR_ALLOW_NETWORK', True) == "1":
709 localdata.delVar('BB_NO_NETWORK')
710
711 for task in range(len(sq_fn)):
712 if task in ret:
713 continue
714
715 spec, extrapath, tname = getpathcomponents(task, d)
716
717 sstatefile = d.expand(extrapath + generate_sstatefn(spec, sq_hash[task], d) + "_" + tname + ".tgz.siginfo")
718
719 srcuri = "file://" + sstatefile
720 localdata.setVar('SRC_URI', srcuri)
721 bb.debug(2, "SState: Attempting to fetch %s" % srcuri)
722
723 try:
724 fetcher = bb.fetch2.Fetch(srcuri.split(), localdata)
725 fetcher.checkstatus()
726 bb.debug(2, "SState: Successful fetch test for %s" % srcuri)
727 ret.append(task)
728 if task in missed:
729 missed.remove(task)
730 except:
731 missed.append(task)
732 bb.debug(2, "SState: Unsuccessful fetch test for %s" % srcuri)
733 pass
734
735 inheritlist = d.getVar("INHERIT", True)
736 if "toaster" in inheritlist:
737 evdata = {'missed': [], 'found': []};
738 for task in missed:
739 spec, extrapath, tname = getpathcomponents(task, d)
740 sstatefile = d.expand(extrapath + generate_sstatefn(spec, sq_hash[task], d) + "_" + tname + ".tgz")
741 evdata['missed'].append( (sq_fn[task], sq_task[task], sq_hash[task], sstatefile ) )
742 for task in ret:
743 spec, extrapath, tname = getpathcomponents(task, d)
744 sstatefile = d.expand(extrapath + generate_sstatefn(spec, sq_hash[task], d) + "_" + tname + ".tgz")
745 evdata['found'].append( (sq_fn[task], sq_task[task], sq_hash[task], sstatefile ) )
746 bb.event.fire(bb.event.MetadataEvent("MissedSstate", evdata), d)
747
748 if hasattr(bb.parse.siggen, "checkhashes"):
749 bb.parse.siggen.checkhashes(missed, ret, sq_fn, sq_task, sq_hash, sq_hashfn, d)
750
751 return ret
752
753BB_SETSCENE_DEPVALID = "setscene_depvalid"
754
755def setscene_depvalid(task, taskdependees, notneeded, d):
756 # taskdependees is a dict of tasks which depend on task, each being a 3 item list of [PN, TASKNAME, FILENAME]
757 # task is included in taskdependees too
758
759 bb.debug(2, "Considering setscene task: %s" % (str(taskdependees[task])))
760
761 def isNativeCross(x):
762 return x.endswith("-native") or "-cross-" in x or "-crosssdk" in x
763
764 def isPostInstDep(x):
765 if x in ["qemu-native", "gdk-pixbuf-native", "qemuwrapper-cross", "depmodwrapper-cross", "systemd-systemctl-native", "gtk-update-icon-cache-native"]:
766 return True
767 return False
768
769 # We only need to trigger populate_lic through direct dependencies
770 if taskdependees[task][1] == "do_populate_lic":
771 return True
772
773 for dep in taskdependees:
774 bb.debug(2, " considering dependency: %s" % (str(taskdependees[dep])))
775 if task == dep:
776 continue
777 if dep in notneeded:
778 continue
779 # do_package_write_* and do_package doesn't need do_package
780 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']:
781 continue
782 # do_package_write_* and do_package doesn't need do_populate_sysroot, unless is a postinstall dependency
783 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']:
784 if isPostInstDep(taskdependees[task][0]) and taskdependees[dep][1] in ['do_package_write_deb', 'do_package_write_ipk', 'do_package_write_rpm']:
785 return False
786 continue
787 # Native/Cross packages don't exist and are noexec anyway
788 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']:
789 continue
790
791 # Consider sysroot depending on sysroot tasks
792 if taskdependees[task][1] == 'do_populate_sysroot' and taskdependees[dep][1] == 'do_populate_sysroot':
793 # base-passwd/shadow-sysroot don't need their dependencies
794 if taskdependees[dep][0].endswith(("base-passwd", "shadow-sysroot")):
795 continue
796 # Nothing need depend on libc-initial/gcc-cross-initial
797 if "-initial" in taskdependees[task][0]:
798 continue
799 # Native/Cross populate_sysroot need their dependencies
800 if isNativeCross(taskdependees[task][0]) and isNativeCross(taskdependees[dep][0]):
801 return False
802 # Target populate_sysroot depended on by cross tools need to be installed
803 if isNativeCross(taskdependees[dep][0]):
804 return False
805 # Native/cross tools depended upon by target sysroot are not needed
806 if isNativeCross(taskdependees[task][0]):
807 continue
808 # Target populate_sysroot need their dependencies
809 return False
810
811 # This is due to the [depends] in useradd.bbclass complicating matters
812 # The logic *is* reversed here due to the way hard setscene dependencies are injected
813 if taskdependees[task][1] == 'do_package' and taskdependees[dep][0].endswith(('shadow-native', 'shadow-sysroot', 'base-passwd', 'pseudo-native')) and taskdependees[dep][1] == 'do_populate_sysroot':
814 continue
815
816 # Safe fallthrough default
817 bb.debug(2, " Default setscene dependency fall through due to dependency: %s" % (str(taskdependees[dep])))
818 return False
819 return True
820
821addhandler sstate_eventhandler
822sstate_eventhandler[eventmask] = "bb.build.TaskSucceeded"
823python sstate_eventhandler() {
824 d = e.data
825 # When we write an sstate package we rewrite the SSTATE_PKG
826 spkg = d.getVar('SSTATE_PKG', True)
827 if not spkg.endswith(".tgz"):
828 taskname = d.getVar("BB_RUNTASK", True)[3:]
829 spec = d.getVar('SSTATE_PKGSPEC', True)
830 swspec = d.getVar('SSTATE_SWSPEC', True)
831 if taskname in ["fetch", "unpack", "patch", "populate_lic", "preconfigure"] and swspec:
832 d.setVar("SSTATE_PKGSPEC", "${SSTATE_SWSPEC}")
833 d.setVar("SSTATE_EXTRAPATH", "")
834 sstatepkg = d.getVar('SSTATE_PKG', True)
835 bb.siggen.dump_this_task(sstatepkg + '_' + taskname + ".tgz" ".siginfo", d)
836}
837