1*4882a593SmuzhiyunSSTATE_VERSION = "10" 2*4882a593Smuzhiyun 3*4882a593SmuzhiyunSSTATE_ZSTD_CLEVEL ??= "8" 4*4882a593Smuzhiyun 5*4882a593SmuzhiyunSSTATE_MANIFESTS ?= "${TMPDIR}/sstate-control" 6*4882a593SmuzhiyunSSTATE_MANFILEPREFIX = "${SSTATE_MANIFESTS}/manifest-${SSTATE_MANMACH}-${PN}" 7*4882a593Smuzhiyun 8*4882a593Smuzhiyundef generate_sstatefn(spec, hash, taskname, siginfo, d): 9*4882a593Smuzhiyun if taskname is None: 10*4882a593Smuzhiyun return "" 11*4882a593Smuzhiyun extension = ".tar.zst" 12*4882a593Smuzhiyun # 8 chars reserved for siginfo 13*4882a593Smuzhiyun limit = 254 - 8 14*4882a593Smuzhiyun if siginfo: 15*4882a593Smuzhiyun limit = 254 16*4882a593Smuzhiyun extension = ".tar.zst.siginfo" 17*4882a593Smuzhiyun if not hash: 18*4882a593Smuzhiyun hash = "INVALID" 19*4882a593Smuzhiyun fn = spec + hash + "_" + taskname + extension 20*4882a593Smuzhiyun # If the filename is too long, attempt to reduce it 21*4882a593Smuzhiyun if len(fn) > limit: 22*4882a593Smuzhiyun components = spec.split(":") 23*4882a593Smuzhiyun # Fields 0,5,6 are mandatory, 1 is most useful, 2,3,4 are just for information 24*4882a593Smuzhiyun # 7 is for the separators 25*4882a593Smuzhiyun avail = (limit - len(hash + "_" + taskname + extension) - len(components[0]) - len(components[1]) - len(components[5]) - len(components[6]) - 7) // 3 26*4882a593Smuzhiyun components[2] = components[2][:avail] 27*4882a593Smuzhiyun components[3] = components[3][:avail] 28*4882a593Smuzhiyun components[4] = components[4][:avail] 29*4882a593Smuzhiyun spec = ":".join(components) 30*4882a593Smuzhiyun fn = spec + hash + "_" + taskname + extension 31*4882a593Smuzhiyun if len(fn) > limit: 32*4882a593Smuzhiyun bb.fatal("Unable to reduce sstate name to less than 255 chararacters") 33*4882a593Smuzhiyun return hash[:2] + "/" + hash[2:4] + "/" + fn 34*4882a593Smuzhiyun 35*4882a593SmuzhiyunSSTATE_PKGARCH = "${PACKAGE_ARCH}" 36*4882a593SmuzhiyunSSTATE_PKGSPEC = "sstate:${PN}:${PACKAGE_ARCH}${TARGET_VENDOR}-${TARGET_OS}:${PV}:${PR}:${SSTATE_PKGARCH}:${SSTATE_VERSION}:" 37*4882a593SmuzhiyunSSTATE_SWSPEC = "sstate:${PN}::${PV}:${PR}::${SSTATE_VERSION}:" 38*4882a593SmuzhiyunSSTATE_PKGNAME = "${SSTATE_EXTRAPATH}${@generate_sstatefn(d.getVar('SSTATE_PKGSPEC'), d.getVar('BB_UNIHASH'), d.getVar('SSTATE_CURRTASK'), False, d)}" 39*4882a593SmuzhiyunSSTATE_PKG = "${SSTATE_DIR}/${SSTATE_PKGNAME}" 40*4882a593SmuzhiyunSSTATE_EXTRAPATH = "" 41*4882a593SmuzhiyunSSTATE_EXTRAPATHWILDCARD = "" 42*4882a593SmuzhiyunSSTATE_PATHSPEC = "${SSTATE_DIR}/${SSTATE_EXTRAPATHWILDCARD}*/*/${SSTATE_PKGSPEC}*_${SSTATE_PATH_CURRTASK}.tar.zst*" 43*4882a593Smuzhiyun 44*4882a593Smuzhiyun# explicitly make PV to depend on evaluated value of PV variable 45*4882a593SmuzhiyunPV[vardepvalue] = "${PV}" 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun# We don't want the sstate to depend on things like the distro string 48*4882a593Smuzhiyun# of the system, we let the sstate paths take care of this. 49*4882a593SmuzhiyunSSTATE_EXTRAPATH[vardepvalue] = "" 50*4882a593SmuzhiyunSSTATE_EXTRAPATHWILDCARD[vardepvalue] = "" 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun# For multilib rpm the allarch packagegroup files can overwrite (in theory they're identical) 53*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES = "${DEPLOY_DIR}/licenses/" 54*4882a593Smuzhiyun# Avoid docbook/sgml catalog warnings for now 55*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES += "${STAGING_ETCDIR_NATIVE}/sgml ${STAGING_DATADIR_NATIVE}/sgml" 56*4882a593Smuzhiyun# sdk-provides-dummy-nativesdk and nativesdk-buildtools-perl-dummy overlap for different SDKMACHINE 57*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES += "${DEPLOY_DIR_RPM}/sdk_provides_dummy_nativesdk/ ${DEPLOY_DIR_IPK}/sdk-provides-dummy-nativesdk/" 58*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES += "${DEPLOY_DIR_RPM}/buildtools_dummy_nativesdk/ ${DEPLOY_DIR_IPK}/buildtools-dummy-nativesdk/" 59*4882a593Smuzhiyun# target-sdk-provides-dummy overlaps that allarch is disabled when multilib is used 60*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES += "${COMPONENTS_DIR}/sdk-provides-dummy-target/ ${DEPLOY_DIR_RPM}/sdk_provides_dummy_target/ ${DEPLOY_DIR_IPK}/sdk-provides-dummy-target/" 61*4882a593Smuzhiyun# Archive the sources for many architectures in one deploy folder 62*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES += "${DEPLOY_DIR_SRC}" 63*4882a593Smuzhiyun# ovmf/grub-efi/systemd-boot/intel-microcode multilib recipes can generate identical overlapping files 64*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES += "${DEPLOY_DIR_IMAGE}/ovmf" 65*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES += "${DEPLOY_DIR_IMAGE}/grub-efi" 66*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES += "${DEPLOY_DIR_IMAGE}/systemd-boot" 67*4882a593SmuzhiyunSSTATE_ALLOW_OVERLAP_FILES += "${DEPLOY_DIR_IMAGE}/microcode" 68*4882a593Smuzhiyun 69*4882a593SmuzhiyunSSTATE_SCAN_FILES ?= "*.la *-config *_config postinst-*" 70*4882a593SmuzhiyunSSTATE_SCAN_CMD ??= 'find ${SSTATE_BUILDDIR} \( -name "${@"\" -o -name \"".join(d.getVar("SSTATE_SCAN_FILES").split())}" \) -type f' 71*4882a593SmuzhiyunSSTATE_SCAN_CMD_NATIVE ??= 'grep -Irl -e ${RECIPE_SYSROOT} -e ${RECIPE_SYSROOT_NATIVE} -e ${HOSTTOOLS_DIR} ${SSTATE_BUILDDIR}' 72*4882a593SmuzhiyunSSTATE_HASHEQUIV_FILEMAP ?= " \ 73*4882a593Smuzhiyun populate_sysroot:*/postinst-useradd-*:${TMPDIR} \ 74*4882a593Smuzhiyun populate_sysroot:*/postinst-useradd-*:${COREBASE} \ 75*4882a593Smuzhiyun populate_sysroot:*/postinst-useradd-*:regex-\s(PATH|PSEUDO_IGNORE_PATHS|HOME|LOGNAME|OMP_NUM_THREADS|USER)=.*\s \ 76*4882a593Smuzhiyun populate_sysroot:*/crossscripts/*:${TMPDIR} \ 77*4882a593Smuzhiyun populate_sysroot:*/crossscripts/*:${COREBASE} \ 78*4882a593Smuzhiyun " 79*4882a593Smuzhiyun 80*4882a593SmuzhiyunBB_HASHFILENAME = "False ${SSTATE_PKGSPEC} ${SSTATE_SWSPEC}" 81*4882a593Smuzhiyun 82*4882a593SmuzhiyunSSTATE_ARCHS = " \ 83*4882a593Smuzhiyun ${BUILD_ARCH} \ 84*4882a593Smuzhiyun ${BUILD_ARCH}_${ORIGNATIVELSBSTRING} \ 85*4882a593Smuzhiyun ${BUILD_ARCH}_${SDK_ARCH}_${SDK_OS} \ 86*4882a593Smuzhiyun ${SDK_ARCH}_${SDK_OS} \ 87*4882a593Smuzhiyun ${SDK_ARCH}_${PACKAGE_ARCH} \ 88*4882a593Smuzhiyun allarch \ 89*4882a593Smuzhiyun ${PACKAGE_ARCH} \ 90*4882a593Smuzhiyun ${PACKAGE_EXTRA_ARCHS} \ 91*4882a593Smuzhiyun ${MACHINE_ARCH}" 92*4882a593SmuzhiyunSSTATE_ARCHS[vardepsexclude] = "ORIGNATIVELSBSTRING" 93*4882a593Smuzhiyun 94*4882a593SmuzhiyunSSTATE_MANMACH ?= "${SSTATE_PKGARCH}" 95*4882a593Smuzhiyun 96*4882a593SmuzhiyunSSTATECREATEFUNCS += "sstate_hardcode_path" 97*4882a593SmuzhiyunSSTATECREATEFUNCS[vardeps] = "SSTATE_SCAN_FILES" 98*4882a593SmuzhiyunSSTATEPOSTCREATEFUNCS = "" 99*4882a593SmuzhiyunSSTATEPREINSTFUNCS = "" 100*4882a593SmuzhiyunSSTATEPOSTUNPACKFUNCS = "sstate_hardcode_path_unpack" 101*4882a593SmuzhiyunSSTATEPOSTINSTFUNCS = "" 102*4882a593SmuzhiyunEXTRA_STAGING_FIXMES ?= "HOSTTOOLS_DIR" 103*4882a593Smuzhiyun 104*4882a593Smuzhiyun# Check whether sstate exists for tasks that support sstate and are in the 105*4882a593Smuzhiyun# locked signatures file. 106*4882a593SmuzhiyunSIGGEN_LOCKEDSIGS_SSTATE_EXISTS_CHECK ?= 'error' 107*4882a593Smuzhiyun 108*4882a593Smuzhiyun# Check whether the task's computed hash matches the task's hash in the 109*4882a593Smuzhiyun# locked signatures file. 110*4882a593SmuzhiyunSIGGEN_LOCKEDSIGS_TASKSIG_CHECK ?= "error" 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun# The GnuPG key ID and passphrase to use to sign sstate archives (or unset to 113*4882a593Smuzhiyun# not sign) 114*4882a593SmuzhiyunSSTATE_SIG_KEY ?= "" 115*4882a593SmuzhiyunSSTATE_SIG_PASSPHRASE ?= "" 116*4882a593Smuzhiyun# Whether to verify the GnUPG signatures when extracting sstate archives 117*4882a593SmuzhiyunSSTATE_VERIFY_SIG ?= "0" 118*4882a593Smuzhiyun# List of signatures to consider valid. 119*4882a593SmuzhiyunSSTATE_VALID_SIGS ??= "" 120*4882a593SmuzhiyunSSTATE_VALID_SIGS[vardepvalue] = "" 121*4882a593Smuzhiyun 122*4882a593SmuzhiyunSSTATE_HASHEQUIV_METHOD ?= "oe.sstatesig.OEOuthashBasic" 123*4882a593SmuzhiyunSSTATE_HASHEQUIV_METHOD[doc] = "The fully-qualified function used to calculate \ 124*4882a593Smuzhiyun the output hash for a task, which in turn is used to determine equivalency. \ 125*4882a593Smuzhiyun " 126*4882a593Smuzhiyun 127*4882a593SmuzhiyunSSTATE_HASHEQUIV_REPORT_TASKDATA ?= "0" 128*4882a593SmuzhiyunSSTATE_HASHEQUIV_REPORT_TASKDATA[doc] = "Report additional useful data to the \ 129*4882a593Smuzhiyun hash equivalency server, such as PN, PV, taskname, etc. This information \ 130*4882a593Smuzhiyun is very useful for developers looking at task data, but may leak sensitive \ 131*4882a593Smuzhiyun data if the equivalence server is public. \ 132*4882a593Smuzhiyun " 133*4882a593Smuzhiyun 134*4882a593Smuzhiyunpython () { 135*4882a593Smuzhiyun if bb.data.inherits_class('native', d): 136*4882a593Smuzhiyun d.setVar('SSTATE_PKGARCH', d.getVar('BUILD_ARCH', False)) 137*4882a593Smuzhiyun elif bb.data.inherits_class('crosssdk', d): 138*4882a593Smuzhiyun d.setVar('SSTATE_PKGARCH', d.expand("${BUILD_ARCH}_${SDK_ARCH}_${SDK_OS}")) 139*4882a593Smuzhiyun elif bb.data.inherits_class('cross', d): 140*4882a593Smuzhiyun d.setVar('SSTATE_PKGARCH', d.expand("${BUILD_ARCH}")) 141*4882a593Smuzhiyun elif bb.data.inherits_class('nativesdk', d): 142*4882a593Smuzhiyun d.setVar('SSTATE_PKGARCH', d.expand("${SDK_ARCH}_${SDK_OS}")) 143*4882a593Smuzhiyun elif bb.data.inherits_class('cross-canadian', d): 144*4882a593Smuzhiyun d.setVar('SSTATE_PKGARCH', d.expand("${SDK_ARCH}_${PACKAGE_ARCH}")) 145*4882a593Smuzhiyun elif bb.data.inherits_class('allarch', d) and d.getVar("PACKAGE_ARCH") == "all": 146*4882a593Smuzhiyun d.setVar('SSTATE_PKGARCH', "allarch") 147*4882a593Smuzhiyun else: 148*4882a593Smuzhiyun d.setVar('SSTATE_MANMACH', d.expand("${PACKAGE_ARCH}")) 149*4882a593Smuzhiyun 150*4882a593Smuzhiyun if bb.data.inherits_class('native', d) or bb.data.inherits_class('crosssdk', d) or bb.data.inherits_class('cross', d): 151*4882a593Smuzhiyun d.setVar('SSTATE_EXTRAPATH', "${NATIVELSBSTRING}/") 152*4882a593Smuzhiyun d.setVar('BB_HASHFILENAME', "True ${SSTATE_PKGSPEC} ${SSTATE_SWSPEC}") 153*4882a593Smuzhiyun d.setVar('SSTATE_EXTRAPATHWILDCARD', "${NATIVELSBSTRING}/") 154*4882a593Smuzhiyun 155*4882a593Smuzhiyun unique_tasks = sorted(set((d.getVar('SSTATETASKS') or "").split())) 156*4882a593Smuzhiyun d.setVar('SSTATETASKS', " ".join(unique_tasks)) 157*4882a593Smuzhiyun for task in unique_tasks: 158*4882a593Smuzhiyun d.prependVarFlag(task, 'prefuncs', "sstate_task_prefunc ") 159*4882a593Smuzhiyun d.appendVarFlag(task, 'postfuncs', " sstate_task_postfunc") 160*4882a593Smuzhiyun d.setVarFlag(task, 'network', '1') 161*4882a593Smuzhiyun d.setVarFlag(task + "_setscene", 'network', '1') 162*4882a593Smuzhiyun} 163*4882a593Smuzhiyun 164*4882a593Smuzhiyundef sstate_init(task, d): 165*4882a593Smuzhiyun ss = {} 166*4882a593Smuzhiyun ss['task'] = task 167*4882a593Smuzhiyun ss['dirs'] = [] 168*4882a593Smuzhiyun ss['plaindirs'] = [] 169*4882a593Smuzhiyun ss['lockfiles'] = [] 170*4882a593Smuzhiyun ss['lockfiles-shared'] = [] 171*4882a593Smuzhiyun return ss 172*4882a593Smuzhiyun 173*4882a593Smuzhiyundef sstate_state_fromvars(d, task = None): 174*4882a593Smuzhiyun if task is None: 175*4882a593Smuzhiyun task = d.getVar('BB_CURRENTTASK') 176*4882a593Smuzhiyun if not task: 177*4882a593Smuzhiyun bb.fatal("sstate code running without task context?!") 178*4882a593Smuzhiyun task = task.replace("_setscene", "") 179*4882a593Smuzhiyun 180*4882a593Smuzhiyun if task.startswith("do_"): 181*4882a593Smuzhiyun task = task[3:] 182*4882a593Smuzhiyun inputs = (d.getVarFlag("do_" + task, 'sstate-inputdirs') or "").split() 183*4882a593Smuzhiyun outputs = (d.getVarFlag("do_" + task, 'sstate-outputdirs') or "").split() 184*4882a593Smuzhiyun plaindirs = (d.getVarFlag("do_" + task, 'sstate-plaindirs') or "").split() 185*4882a593Smuzhiyun lockfiles = (d.getVarFlag("do_" + task, 'sstate-lockfile') or "").split() 186*4882a593Smuzhiyun lockfilesshared = (d.getVarFlag("do_" + task, 'sstate-lockfile-shared') or "").split() 187*4882a593Smuzhiyun interceptfuncs = (d.getVarFlag("do_" + task, 'sstate-interceptfuncs') or "").split() 188*4882a593Smuzhiyun fixmedir = d.getVarFlag("do_" + task, 'sstate-fixmedir') or "" 189*4882a593Smuzhiyun if not task or len(inputs) != len(outputs): 190*4882a593Smuzhiyun bb.fatal("sstate variables not setup correctly?!") 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun if task == "populate_lic": 193*4882a593Smuzhiyun d.setVar("SSTATE_PKGSPEC", "${SSTATE_SWSPEC}") 194*4882a593Smuzhiyun d.setVar("SSTATE_EXTRAPATH", "") 195*4882a593Smuzhiyun d.setVar('SSTATE_EXTRAPATHWILDCARD', "") 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun ss = sstate_init(task, d) 198*4882a593Smuzhiyun for i in range(len(inputs)): 199*4882a593Smuzhiyun sstate_add(ss, inputs[i], outputs[i], d) 200*4882a593Smuzhiyun ss['lockfiles'] = lockfiles 201*4882a593Smuzhiyun ss['lockfiles-shared'] = lockfilesshared 202*4882a593Smuzhiyun ss['plaindirs'] = plaindirs 203*4882a593Smuzhiyun ss['interceptfuncs'] = interceptfuncs 204*4882a593Smuzhiyun ss['fixmedir'] = fixmedir 205*4882a593Smuzhiyun return ss 206*4882a593Smuzhiyun 207*4882a593Smuzhiyundef sstate_add(ss, source, dest, d): 208*4882a593Smuzhiyun if not source.endswith("/"): 209*4882a593Smuzhiyun source = source + "/" 210*4882a593Smuzhiyun if not dest.endswith("/"): 211*4882a593Smuzhiyun dest = dest + "/" 212*4882a593Smuzhiyun source = os.path.normpath(source) 213*4882a593Smuzhiyun dest = os.path.normpath(dest) 214*4882a593Smuzhiyun srcbase = os.path.basename(source) 215*4882a593Smuzhiyun ss['dirs'].append([srcbase, source, dest]) 216*4882a593Smuzhiyun return ss 217*4882a593Smuzhiyun 218*4882a593Smuzhiyundef sstate_install(ss, d): 219*4882a593Smuzhiyun import oe.path 220*4882a593Smuzhiyun import oe.sstatesig 221*4882a593Smuzhiyun import subprocess 222*4882a593Smuzhiyun 223*4882a593Smuzhiyun sharedfiles = [] 224*4882a593Smuzhiyun shareddirs = [] 225*4882a593Smuzhiyun bb.utils.mkdirhier(d.expand("${SSTATE_MANIFESTS}")) 226*4882a593Smuzhiyun 227*4882a593Smuzhiyun sstateinst = d.expand("${WORKDIR}/sstate-install-%s/" % ss['task']) 228*4882a593Smuzhiyun 229*4882a593Smuzhiyun manifest, d2 = oe.sstatesig.sstate_get_manifest_filename(ss['task'], d) 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun if os.access(manifest, os.R_OK): 232*4882a593Smuzhiyun bb.fatal("Package already staged (%s)?!" % manifest) 233*4882a593Smuzhiyun 234*4882a593Smuzhiyun d.setVar("SSTATE_INST_POSTRM", manifest + ".postrm") 235*4882a593Smuzhiyun 236*4882a593Smuzhiyun locks = [] 237*4882a593Smuzhiyun for lock in ss['lockfiles-shared']: 238*4882a593Smuzhiyun locks.append(bb.utils.lockfile(lock, True)) 239*4882a593Smuzhiyun for lock in ss['lockfiles']: 240*4882a593Smuzhiyun locks.append(bb.utils.lockfile(lock)) 241*4882a593Smuzhiyun 242*4882a593Smuzhiyun for state in ss['dirs']: 243*4882a593Smuzhiyun bb.debug(2, "Staging files from %s to %s" % (state[1], state[2])) 244*4882a593Smuzhiyun for walkroot, dirs, files in os.walk(state[1]): 245*4882a593Smuzhiyun for file in files: 246*4882a593Smuzhiyun srcpath = os.path.join(walkroot, file) 247*4882a593Smuzhiyun dstpath = srcpath.replace(state[1], state[2]) 248*4882a593Smuzhiyun #bb.debug(2, "Staging %s to %s" % (srcpath, dstpath)) 249*4882a593Smuzhiyun sharedfiles.append(dstpath) 250*4882a593Smuzhiyun for dir in dirs: 251*4882a593Smuzhiyun srcdir = os.path.join(walkroot, dir) 252*4882a593Smuzhiyun dstdir = srcdir.replace(state[1], state[2]) 253*4882a593Smuzhiyun #bb.debug(2, "Staging %s to %s" % (srcdir, dstdir)) 254*4882a593Smuzhiyun if os.path.islink(srcdir): 255*4882a593Smuzhiyun sharedfiles.append(dstdir) 256*4882a593Smuzhiyun continue 257*4882a593Smuzhiyun if not dstdir.endswith("/"): 258*4882a593Smuzhiyun dstdir = dstdir + "/" 259*4882a593Smuzhiyun shareddirs.append(dstdir) 260*4882a593Smuzhiyun 261*4882a593Smuzhiyun # Check the file list for conflicts against files which already exist 262*4882a593Smuzhiyun overlap_allowed = (d.getVar("SSTATE_ALLOW_OVERLAP_FILES") or "").split() 263*4882a593Smuzhiyun match = [] 264*4882a593Smuzhiyun for f in sharedfiles: 265*4882a593Smuzhiyun if os.path.exists(f) and not os.path.islink(f): 266*4882a593Smuzhiyun f = os.path.normpath(f) 267*4882a593Smuzhiyun realmatch = True 268*4882a593Smuzhiyun for w in overlap_allowed: 269*4882a593Smuzhiyun w = os.path.normpath(w) 270*4882a593Smuzhiyun if f.startswith(w): 271*4882a593Smuzhiyun realmatch = False 272*4882a593Smuzhiyun break 273*4882a593Smuzhiyun if realmatch: 274*4882a593Smuzhiyun match.append(f) 275*4882a593Smuzhiyun sstate_search_cmd = "grep -rlF '%s' %s --exclude=master.list | sed -e 's:^.*/::'" % (f, d.expand("${SSTATE_MANIFESTS}")) 276*4882a593Smuzhiyun search_output = subprocess.Popen(sstate_search_cmd, shell=True, stdout=subprocess.PIPE).communicate()[0] 277*4882a593Smuzhiyun if search_output: 278*4882a593Smuzhiyun match.append(" (matched in %s)" % search_output.decode('utf-8').rstrip()) 279*4882a593Smuzhiyun else: 280*4882a593Smuzhiyun match.append(" (not matched to any task)") 281*4882a593Smuzhiyun if match: 282*4882a593Smuzhiyun bb.error("The recipe %s is trying to install files into a shared " \ 283*4882a593Smuzhiyun "area when those files already exist. Those files and their manifest " \ 284*4882a593Smuzhiyun "location are:\n %s\nPlease verify which recipe should provide the " \ 285*4882a593Smuzhiyun "above files.\n\nThe build has stopped, as continuing in this scenario WILL " \ 286*4882a593Smuzhiyun "break things - if not now, possibly in the future (we've seen builds fail " \ 287*4882a593Smuzhiyun "several months later). If the system knew how to recover from this " \ 288*4882a593Smuzhiyun "automatically it would, however there are several different scenarios " \ 289*4882a593Smuzhiyun "which can result in this and we don't know which one this is. It may be " \ 290*4882a593Smuzhiyun "you have switched providers of something like virtual/kernel (e.g. from " \ 291*4882a593Smuzhiyun "linux-yocto to linux-yocto-dev), in that case you need to execute the " \ 292*4882a593Smuzhiyun "clean task for both recipes and it will resolve this error. It may be " \ 293*4882a593Smuzhiyun "you changed DISTRO_FEATURES from systemd to udev or vice versa. Cleaning " \ 294*4882a593Smuzhiyun "those recipes should again resolve this error, however switching " \ 295*4882a593Smuzhiyun "DISTRO_FEATURES on an existing build directory is not supported - you " \ 296*4882a593Smuzhiyun "should really clean out tmp and rebuild (reusing sstate should be safe). " \ 297*4882a593Smuzhiyun "It could be the overlapping files detected are harmless in which case " \ 298*4882a593Smuzhiyun "adding them to SSTATE_ALLOW_OVERLAP_FILES may be the correct solution. It could " \ 299*4882a593Smuzhiyun "also be your build is including two different conflicting versions of " \ 300*4882a593Smuzhiyun "things (e.g. bluez 4 and bluez 5 and the correct solution for that would " \ 301*4882a593Smuzhiyun "be to resolve the conflict. If in doubt, please ask on the mailing list, " \ 302*4882a593Smuzhiyun "sharing the error and filelist above." % \ 303*4882a593Smuzhiyun (d.getVar('PN'), "\n ".join(match))) 304*4882a593Smuzhiyun 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.") 305*4882a593Smuzhiyun 306*4882a593Smuzhiyun if ss['fixmedir'] and os.path.exists(ss['fixmedir'] + "/fixmepath.cmd"): 307*4882a593Smuzhiyun sharedfiles.append(ss['fixmedir'] + "/fixmepath.cmd") 308*4882a593Smuzhiyun sharedfiles.append(ss['fixmedir'] + "/fixmepath") 309*4882a593Smuzhiyun 310*4882a593Smuzhiyun # Write out the manifest 311*4882a593Smuzhiyun f = open(manifest, "w") 312*4882a593Smuzhiyun for file in sharedfiles: 313*4882a593Smuzhiyun f.write(file + "\n") 314*4882a593Smuzhiyun 315*4882a593Smuzhiyun # We want to ensure that directories appear at the end of the manifest 316*4882a593Smuzhiyun # so that when we test to see if they should be deleted any contents 317*4882a593Smuzhiyun # added by the task will have been removed first. 318*4882a593Smuzhiyun dirs = sorted(shareddirs, key=len) 319*4882a593Smuzhiyun # Must remove children first, which will have a longer path than the parent 320*4882a593Smuzhiyun for di in reversed(dirs): 321*4882a593Smuzhiyun f.write(di + "\n") 322*4882a593Smuzhiyun f.close() 323*4882a593Smuzhiyun 324*4882a593Smuzhiyun # Append to the list of manifests for this PACKAGE_ARCH 325*4882a593Smuzhiyun 326*4882a593Smuzhiyun i = d2.expand("${SSTATE_MANIFESTS}/index-${SSTATE_MANMACH}") 327*4882a593Smuzhiyun l = bb.utils.lockfile(i + ".lock") 328*4882a593Smuzhiyun filedata = d.getVar("STAMP") + " " + d2.getVar("SSTATE_MANFILEPREFIX") + " " + d.getVar("WORKDIR") + "\n" 329*4882a593Smuzhiyun manifests = [] 330*4882a593Smuzhiyun if os.path.exists(i): 331*4882a593Smuzhiyun with open(i, "r") as f: 332*4882a593Smuzhiyun manifests = f.readlines() 333*4882a593Smuzhiyun # We append new entries, we don't remove older entries which may have the same 334*4882a593Smuzhiyun # manifest name but different versions from stamp/workdir. See below. 335*4882a593Smuzhiyun if filedata not in manifests: 336*4882a593Smuzhiyun with open(i, "a+") as f: 337*4882a593Smuzhiyun f.write(filedata) 338*4882a593Smuzhiyun bb.utils.unlockfile(l) 339*4882a593Smuzhiyun 340*4882a593Smuzhiyun # Run the actual file install 341*4882a593Smuzhiyun for state in ss['dirs']: 342*4882a593Smuzhiyun if os.path.exists(state[1]): 343*4882a593Smuzhiyun oe.path.copyhardlinktree(state[1], state[2]) 344*4882a593Smuzhiyun 345*4882a593Smuzhiyun for postinst in (d.getVar('SSTATEPOSTINSTFUNCS') or '').split(): 346*4882a593Smuzhiyun # All hooks should run in the SSTATE_INSTDIR 347*4882a593Smuzhiyun bb.build.exec_func(postinst, d, (sstateinst,)) 348*4882a593Smuzhiyun 349*4882a593Smuzhiyun for lock in locks: 350*4882a593Smuzhiyun bb.utils.unlockfile(lock) 351*4882a593Smuzhiyun 352*4882a593Smuzhiyunsstate_install[vardepsexclude] += "SSTATE_ALLOW_OVERLAP_FILES STATE_MANMACH SSTATE_MANFILEPREFIX" 353*4882a593Smuzhiyunsstate_install[vardeps] += "${SSTATEPOSTINSTFUNCS}" 354*4882a593Smuzhiyun 355*4882a593Smuzhiyundef sstate_installpkg(ss, d): 356*4882a593Smuzhiyun from oe.gpg_sign import get_signer 357*4882a593Smuzhiyun 358*4882a593Smuzhiyun sstateinst = d.expand("${WORKDIR}/sstate-install-%s/" % ss['task']) 359*4882a593Smuzhiyun d.setVar("SSTATE_CURRTASK", ss['task']) 360*4882a593Smuzhiyun sstatefetch = d.getVar('SSTATE_PKGNAME') 361*4882a593Smuzhiyun sstatepkg = d.getVar('SSTATE_PKG') 362*4882a593Smuzhiyun 363*4882a593Smuzhiyun if not os.path.exists(sstatepkg): 364*4882a593Smuzhiyun pstaging_fetch(sstatefetch, d) 365*4882a593Smuzhiyun 366*4882a593Smuzhiyun if not os.path.isfile(sstatepkg): 367*4882a593Smuzhiyun bb.note("Sstate package %s does not exist" % sstatepkg) 368*4882a593Smuzhiyun return False 369*4882a593Smuzhiyun 370*4882a593Smuzhiyun sstate_clean(ss, d) 371*4882a593Smuzhiyun 372*4882a593Smuzhiyun d.setVar('SSTATE_INSTDIR', sstateinst) 373*4882a593Smuzhiyun 374*4882a593Smuzhiyun if bb.utils.to_boolean(d.getVar("SSTATE_VERIFY_SIG"), False): 375*4882a593Smuzhiyun if not os.path.isfile(sstatepkg + '.sig'): 376*4882a593Smuzhiyun bb.warn("No signature file for sstate package %s, skipping acceleration..." % sstatepkg) 377*4882a593Smuzhiyun return False 378*4882a593Smuzhiyun signer = get_signer(d, 'local') 379*4882a593Smuzhiyun if not signer.verify(sstatepkg + '.sig', d.getVar("SSTATE_VALID_SIGS")): 380*4882a593Smuzhiyun bb.warn("Cannot verify signature on sstate package %s, skipping acceleration..." % sstatepkg) 381*4882a593Smuzhiyun return False 382*4882a593Smuzhiyun 383*4882a593Smuzhiyun # Empty sstateinst directory, ensure its clean 384*4882a593Smuzhiyun if os.path.exists(sstateinst): 385*4882a593Smuzhiyun oe.path.remove(sstateinst) 386*4882a593Smuzhiyun bb.utils.mkdirhier(sstateinst) 387*4882a593Smuzhiyun 388*4882a593Smuzhiyun sstateinst = d.getVar("SSTATE_INSTDIR") 389*4882a593Smuzhiyun d.setVar('SSTATE_FIXMEDIR', ss['fixmedir']) 390*4882a593Smuzhiyun 391*4882a593Smuzhiyun for f in (d.getVar('SSTATEPREINSTFUNCS') or '').split() + ['sstate_unpack_package']: 392*4882a593Smuzhiyun # All hooks should run in the SSTATE_INSTDIR 393*4882a593Smuzhiyun bb.build.exec_func(f, d, (sstateinst,)) 394*4882a593Smuzhiyun 395*4882a593Smuzhiyun return sstate_installpkgdir(ss, d) 396*4882a593Smuzhiyun 397*4882a593Smuzhiyundef sstate_installpkgdir(ss, d): 398*4882a593Smuzhiyun import oe.path 399*4882a593Smuzhiyun import subprocess 400*4882a593Smuzhiyun 401*4882a593Smuzhiyun sstateinst = d.getVar("SSTATE_INSTDIR") 402*4882a593Smuzhiyun d.setVar('SSTATE_FIXMEDIR', ss['fixmedir']) 403*4882a593Smuzhiyun 404*4882a593Smuzhiyun for f in (d.getVar('SSTATEPOSTUNPACKFUNCS') or '').split(): 405*4882a593Smuzhiyun # All hooks should run in the SSTATE_INSTDIR 406*4882a593Smuzhiyun bb.build.exec_func(f, d, (sstateinst,)) 407*4882a593Smuzhiyun 408*4882a593Smuzhiyun def prepdir(dir): 409*4882a593Smuzhiyun # remove dir if it exists, ensure any parent directories do exist 410*4882a593Smuzhiyun if os.path.exists(dir): 411*4882a593Smuzhiyun oe.path.remove(dir) 412*4882a593Smuzhiyun bb.utils.mkdirhier(dir) 413*4882a593Smuzhiyun oe.path.remove(dir) 414*4882a593Smuzhiyun 415*4882a593Smuzhiyun for state in ss['dirs']: 416*4882a593Smuzhiyun prepdir(state[1]) 417*4882a593Smuzhiyun bb.utils.rename(sstateinst + state[0], state[1]) 418*4882a593Smuzhiyun sstate_install(ss, d) 419*4882a593Smuzhiyun 420*4882a593Smuzhiyun for plain in ss['plaindirs']: 421*4882a593Smuzhiyun workdir = d.getVar('WORKDIR') 422*4882a593Smuzhiyun sharedworkdir = os.path.join(d.getVar('TMPDIR'), "work-shared") 423*4882a593Smuzhiyun src = sstateinst + "/" + plain.replace(workdir, '') 424*4882a593Smuzhiyun if sharedworkdir in plain: 425*4882a593Smuzhiyun src = sstateinst + "/" + plain.replace(sharedworkdir, '') 426*4882a593Smuzhiyun dest = plain 427*4882a593Smuzhiyun bb.utils.mkdirhier(src) 428*4882a593Smuzhiyun prepdir(dest) 429*4882a593Smuzhiyun bb.utils.rename(src, dest) 430*4882a593Smuzhiyun 431*4882a593Smuzhiyun return True 432*4882a593Smuzhiyun 433*4882a593Smuzhiyunpython sstate_hardcode_path_unpack () { 434*4882a593Smuzhiyun # Fixup hardcoded paths 435*4882a593Smuzhiyun # 436*4882a593Smuzhiyun # Note: The logic below must match the reverse logic in 437*4882a593Smuzhiyun # sstate_hardcode_path(d) 438*4882a593Smuzhiyun import subprocess 439*4882a593Smuzhiyun 440*4882a593Smuzhiyun sstateinst = d.getVar('SSTATE_INSTDIR') 441*4882a593Smuzhiyun sstatefixmedir = d.getVar('SSTATE_FIXMEDIR') 442*4882a593Smuzhiyun fixmefn = sstateinst + "fixmepath" 443*4882a593Smuzhiyun if os.path.isfile(fixmefn): 444*4882a593Smuzhiyun staging_target = d.getVar('RECIPE_SYSROOT') 445*4882a593Smuzhiyun staging_host = d.getVar('RECIPE_SYSROOT_NATIVE') 446*4882a593Smuzhiyun 447*4882a593Smuzhiyun if bb.data.inherits_class('native', d) or bb.data.inherits_class('cross-canadian', d): 448*4882a593Smuzhiyun sstate_sed_cmd = "sed -i -e 's:FIXMESTAGINGDIRHOST:%s:g'" % (staging_host) 449*4882a593Smuzhiyun elif bb.data.inherits_class('cross', d) or bb.data.inherits_class('crosssdk', d): 450*4882a593Smuzhiyun sstate_sed_cmd = "sed -i -e 's:FIXMESTAGINGDIRTARGET:%s:g; s:FIXMESTAGINGDIRHOST:%s:g'" % (staging_target, staging_host) 451*4882a593Smuzhiyun else: 452*4882a593Smuzhiyun sstate_sed_cmd = "sed -i -e 's:FIXMESTAGINGDIRTARGET:%s:g'" % (staging_target) 453*4882a593Smuzhiyun 454*4882a593Smuzhiyun extra_staging_fixmes = d.getVar('EXTRA_STAGING_FIXMES') or '' 455*4882a593Smuzhiyun for fixmevar in extra_staging_fixmes.split(): 456*4882a593Smuzhiyun fixme_path = d.getVar(fixmevar) 457*4882a593Smuzhiyun sstate_sed_cmd += " -e 's:FIXME_%s:%s:g'" % (fixmevar, fixme_path) 458*4882a593Smuzhiyun 459*4882a593Smuzhiyun # Add sstateinst to each filename in fixmepath, use xargs to efficiently call sed 460*4882a593Smuzhiyun sstate_hardcode_cmd = "sed -e 's:^:%s:g' %s | xargs %s" % (sstateinst, fixmefn, sstate_sed_cmd) 461*4882a593Smuzhiyun 462*4882a593Smuzhiyun # Defer do_populate_sysroot relocation command 463*4882a593Smuzhiyun if sstatefixmedir: 464*4882a593Smuzhiyun bb.utils.mkdirhier(sstatefixmedir) 465*4882a593Smuzhiyun with open(sstatefixmedir + "/fixmepath.cmd", "w") as f: 466*4882a593Smuzhiyun sstate_hardcode_cmd = sstate_hardcode_cmd.replace(fixmefn, sstatefixmedir + "/fixmepath") 467*4882a593Smuzhiyun sstate_hardcode_cmd = sstate_hardcode_cmd.replace(sstateinst, "FIXMEFINALSSTATEINST") 468*4882a593Smuzhiyun sstate_hardcode_cmd = sstate_hardcode_cmd.replace(staging_host, "FIXMEFINALSSTATEHOST") 469*4882a593Smuzhiyun sstate_hardcode_cmd = sstate_hardcode_cmd.replace(staging_target, "FIXMEFINALSSTATETARGET") 470*4882a593Smuzhiyun f.write(sstate_hardcode_cmd) 471*4882a593Smuzhiyun bb.utils.copyfile(fixmefn, sstatefixmedir + "/fixmepath") 472*4882a593Smuzhiyun return 473*4882a593Smuzhiyun 474*4882a593Smuzhiyun bb.note("Replacing fixme paths in sstate package: %s" % (sstate_hardcode_cmd)) 475*4882a593Smuzhiyun subprocess.check_call(sstate_hardcode_cmd, shell=True) 476*4882a593Smuzhiyun 477*4882a593Smuzhiyun # Need to remove this or we'd copy it into the target directory and may 478*4882a593Smuzhiyun # conflict with another writer 479*4882a593Smuzhiyun os.remove(fixmefn) 480*4882a593Smuzhiyun} 481*4882a593Smuzhiyun 482*4882a593Smuzhiyundef sstate_clean_cachefile(ss, d): 483*4882a593Smuzhiyun import oe.path 484*4882a593Smuzhiyun 485*4882a593Smuzhiyun if d.getVarFlag('do_%s' % ss['task'], 'task'): 486*4882a593Smuzhiyun d.setVar("SSTATE_PATH_CURRTASK", ss['task']) 487*4882a593Smuzhiyun sstatepkgfile = d.getVar('SSTATE_PATHSPEC') 488*4882a593Smuzhiyun bb.note("Removing %s" % sstatepkgfile) 489*4882a593Smuzhiyun oe.path.remove(sstatepkgfile) 490*4882a593Smuzhiyun 491*4882a593Smuzhiyundef sstate_clean_cachefiles(d): 492*4882a593Smuzhiyun for task in (d.getVar('SSTATETASKS') or "").split(): 493*4882a593Smuzhiyun ld = d.createCopy() 494*4882a593Smuzhiyun ss = sstate_state_fromvars(ld, task) 495*4882a593Smuzhiyun sstate_clean_cachefile(ss, ld) 496*4882a593Smuzhiyun 497*4882a593Smuzhiyundef sstate_clean_manifest(manifest, d, canrace=False, prefix=None): 498*4882a593Smuzhiyun import oe.path 499*4882a593Smuzhiyun 500*4882a593Smuzhiyun mfile = open(manifest) 501*4882a593Smuzhiyun entries = mfile.readlines() 502*4882a593Smuzhiyun mfile.close() 503*4882a593Smuzhiyun 504*4882a593Smuzhiyun for entry in entries: 505*4882a593Smuzhiyun entry = entry.strip() 506*4882a593Smuzhiyun if prefix and not entry.startswith("/"): 507*4882a593Smuzhiyun entry = prefix + "/" + entry 508*4882a593Smuzhiyun bb.debug(2, "Removing manifest: %s" % entry) 509*4882a593Smuzhiyun # We can race against another package populating directories as we're removing them 510*4882a593Smuzhiyun # so we ignore errors here. 511*4882a593Smuzhiyun try: 512*4882a593Smuzhiyun if entry.endswith("/"): 513*4882a593Smuzhiyun if os.path.islink(entry[:-1]): 514*4882a593Smuzhiyun os.remove(entry[:-1]) 515*4882a593Smuzhiyun elif os.path.exists(entry) and len(os.listdir(entry)) == 0 and not canrace: 516*4882a593Smuzhiyun # Removing directories whilst builds are in progress exposes a race. Only 517*4882a593Smuzhiyun # do it in contexts where it is safe to do so. 518*4882a593Smuzhiyun os.rmdir(entry[:-1]) 519*4882a593Smuzhiyun else: 520*4882a593Smuzhiyun os.remove(entry) 521*4882a593Smuzhiyun except OSError: 522*4882a593Smuzhiyun pass 523*4882a593Smuzhiyun 524*4882a593Smuzhiyun postrm = manifest + ".postrm" 525*4882a593Smuzhiyun if os.path.exists(manifest + ".postrm"): 526*4882a593Smuzhiyun import subprocess 527*4882a593Smuzhiyun os.chmod(postrm, 0o755) 528*4882a593Smuzhiyun subprocess.check_call(postrm, shell=True) 529*4882a593Smuzhiyun oe.path.remove(postrm) 530*4882a593Smuzhiyun 531*4882a593Smuzhiyun oe.path.remove(manifest) 532*4882a593Smuzhiyun 533*4882a593Smuzhiyundef sstate_clean(ss, d): 534*4882a593Smuzhiyun import oe.path 535*4882a593Smuzhiyun import glob 536*4882a593Smuzhiyun 537*4882a593Smuzhiyun d2 = d.createCopy() 538*4882a593Smuzhiyun stamp_clean = d.getVar("STAMPCLEAN") 539*4882a593Smuzhiyun extrainf = d.getVarFlag("do_" + ss['task'], 'stamp-extra-info') 540*4882a593Smuzhiyun if extrainf: 541*4882a593Smuzhiyun d2.setVar("SSTATE_MANMACH", extrainf) 542*4882a593Smuzhiyun wildcard_stfile = "%s.do_%s*.%s" % (stamp_clean, ss['task'], extrainf) 543*4882a593Smuzhiyun else: 544*4882a593Smuzhiyun wildcard_stfile = "%s.do_%s*" % (stamp_clean, ss['task']) 545*4882a593Smuzhiyun 546*4882a593Smuzhiyun manifest = d2.expand("${SSTATE_MANFILEPREFIX}.%s" % ss['task']) 547*4882a593Smuzhiyun 548*4882a593Smuzhiyun if os.path.exists(manifest): 549*4882a593Smuzhiyun locks = [] 550*4882a593Smuzhiyun for lock in ss['lockfiles-shared']: 551*4882a593Smuzhiyun locks.append(bb.utils.lockfile(lock)) 552*4882a593Smuzhiyun for lock in ss['lockfiles']: 553*4882a593Smuzhiyun locks.append(bb.utils.lockfile(lock)) 554*4882a593Smuzhiyun 555*4882a593Smuzhiyun sstate_clean_manifest(manifest, d, canrace=True) 556*4882a593Smuzhiyun 557*4882a593Smuzhiyun for lock in locks: 558*4882a593Smuzhiyun bb.utils.unlockfile(lock) 559*4882a593Smuzhiyun 560*4882a593Smuzhiyun # Remove the current and previous stamps, but keep the sigdata. 561*4882a593Smuzhiyun # 562*4882a593Smuzhiyun # The glob() matches do_task* which may match multiple tasks, for 563*4882a593Smuzhiyun # example: do_package and do_package_write_ipk, so we need to 564*4882a593Smuzhiyun # exactly match *.do_task.* and *.do_task_setscene.* 565*4882a593Smuzhiyun rm_stamp = '.do_%s.' % ss['task'] 566*4882a593Smuzhiyun rm_setscene = '.do_%s_setscene.' % ss['task'] 567*4882a593Smuzhiyun # For BB_SIGNATURE_HANDLER = "noop" 568*4882a593Smuzhiyun rm_nohash = ".do_%s" % ss['task'] 569*4882a593Smuzhiyun for stfile in glob.glob(wildcard_stfile): 570*4882a593Smuzhiyun # Keep the sigdata 571*4882a593Smuzhiyun if ".sigdata." in stfile or ".sigbasedata." in stfile: 572*4882a593Smuzhiyun continue 573*4882a593Smuzhiyun # Preserve taint files in the stamps directory 574*4882a593Smuzhiyun if stfile.endswith('.taint'): 575*4882a593Smuzhiyun continue 576*4882a593Smuzhiyun if rm_stamp in stfile or rm_setscene in stfile or \ 577*4882a593Smuzhiyun stfile.endswith(rm_nohash): 578*4882a593Smuzhiyun oe.path.remove(stfile) 579*4882a593Smuzhiyun 580*4882a593Smuzhiyunsstate_clean[vardepsexclude] = "SSTATE_MANFILEPREFIX" 581*4882a593Smuzhiyun 582*4882a593SmuzhiyunCLEANFUNCS += "sstate_cleanall" 583*4882a593Smuzhiyun 584*4882a593Smuzhiyunpython sstate_cleanall() { 585*4882a593Smuzhiyun bb.note("Removing shared state for package %s" % d.getVar('PN')) 586*4882a593Smuzhiyun 587*4882a593Smuzhiyun manifest_dir = d.getVar('SSTATE_MANIFESTS') 588*4882a593Smuzhiyun if not os.path.exists(manifest_dir): 589*4882a593Smuzhiyun return 590*4882a593Smuzhiyun 591*4882a593Smuzhiyun tasks = d.getVar('SSTATETASKS').split() 592*4882a593Smuzhiyun for name in tasks: 593*4882a593Smuzhiyun ld = d.createCopy() 594*4882a593Smuzhiyun shared_state = sstate_state_fromvars(ld, name) 595*4882a593Smuzhiyun sstate_clean(shared_state, ld) 596*4882a593Smuzhiyun} 597*4882a593Smuzhiyun 598*4882a593Smuzhiyunpython sstate_hardcode_path () { 599*4882a593Smuzhiyun import subprocess, platform 600*4882a593Smuzhiyun 601*4882a593Smuzhiyun # Need to remove hardcoded paths and fix these when we install the 602*4882a593Smuzhiyun # staging packages. 603*4882a593Smuzhiyun # 604*4882a593Smuzhiyun # Note: the logic in this function needs to match the reverse logic 605*4882a593Smuzhiyun # in sstate_installpkg(ss, d) 606*4882a593Smuzhiyun 607*4882a593Smuzhiyun staging_target = d.getVar('RECIPE_SYSROOT') 608*4882a593Smuzhiyun staging_host = d.getVar('RECIPE_SYSROOT_NATIVE') 609*4882a593Smuzhiyun sstate_builddir = d.getVar('SSTATE_BUILDDIR') 610*4882a593Smuzhiyun 611*4882a593Smuzhiyun sstate_sed_cmd = "sed -i -e 's:%s:FIXMESTAGINGDIRHOST:g'" % staging_host 612*4882a593Smuzhiyun if bb.data.inherits_class('native', d) or bb.data.inherits_class('cross-canadian', d): 613*4882a593Smuzhiyun sstate_grep_cmd = "grep -l -e '%s'" % (staging_host) 614*4882a593Smuzhiyun elif bb.data.inherits_class('cross', d) or bb.data.inherits_class('crosssdk', d): 615*4882a593Smuzhiyun sstate_grep_cmd = "grep -l -e '%s' -e '%s'" % (staging_target, staging_host) 616*4882a593Smuzhiyun sstate_sed_cmd += " -e 's:%s:FIXMESTAGINGDIRTARGET:g'" % staging_target 617*4882a593Smuzhiyun else: 618*4882a593Smuzhiyun sstate_grep_cmd = "grep -l -e '%s' -e '%s'" % (staging_target, staging_host) 619*4882a593Smuzhiyun sstate_sed_cmd += " -e 's:%s:FIXMESTAGINGDIRTARGET:g'" % staging_target 620*4882a593Smuzhiyun 621*4882a593Smuzhiyun extra_staging_fixmes = d.getVar('EXTRA_STAGING_FIXMES') or '' 622*4882a593Smuzhiyun for fixmevar in extra_staging_fixmes.split(): 623*4882a593Smuzhiyun fixme_path = d.getVar(fixmevar) 624*4882a593Smuzhiyun sstate_sed_cmd += " -e 's:%s:FIXME_%s:g'" % (fixme_path, fixmevar) 625*4882a593Smuzhiyun sstate_grep_cmd += " -e '%s'" % (fixme_path) 626*4882a593Smuzhiyun 627*4882a593Smuzhiyun fixmefn = sstate_builddir + "fixmepath" 628*4882a593Smuzhiyun 629*4882a593Smuzhiyun sstate_scan_cmd = d.getVar('SSTATE_SCAN_CMD') 630*4882a593Smuzhiyun sstate_filelist_cmd = "tee %s" % (fixmefn) 631*4882a593Smuzhiyun 632*4882a593Smuzhiyun # fixmepath file needs relative paths, drop sstate_builddir prefix 633*4882a593Smuzhiyun sstate_filelist_relative_cmd = "sed -i -e 's:^%s::g' %s" % (sstate_builddir, fixmefn) 634*4882a593Smuzhiyun 635*4882a593Smuzhiyun xargs_no_empty_run_cmd = '--no-run-if-empty' 636*4882a593Smuzhiyun if platform.system() == 'Darwin': 637*4882a593Smuzhiyun xargs_no_empty_run_cmd = '' 638*4882a593Smuzhiyun 639*4882a593Smuzhiyun # Limit the fixpaths and sed operations based on the initial grep search 640*4882a593Smuzhiyun # This has the side effect of making sure the vfs cache is hot 641*4882a593Smuzhiyun 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) 642*4882a593Smuzhiyun 643*4882a593Smuzhiyun bb.note("Removing hardcoded paths from sstate package: '%s'" % (sstate_hardcode_cmd)) 644*4882a593Smuzhiyun subprocess.check_output(sstate_hardcode_cmd, shell=True, cwd=sstate_builddir) 645*4882a593Smuzhiyun 646*4882a593Smuzhiyun # If the fixmefn is empty, remove it.. 647*4882a593Smuzhiyun if os.stat(fixmefn).st_size == 0: 648*4882a593Smuzhiyun os.remove(fixmefn) 649*4882a593Smuzhiyun else: 650*4882a593Smuzhiyun bb.note("Replacing absolute paths in fixmepath file: '%s'" % (sstate_filelist_relative_cmd)) 651*4882a593Smuzhiyun subprocess.check_output(sstate_filelist_relative_cmd, shell=True) 652*4882a593Smuzhiyun} 653*4882a593Smuzhiyun 654*4882a593Smuzhiyundef sstate_package(ss, d): 655*4882a593Smuzhiyun import oe.path 656*4882a593Smuzhiyun import time 657*4882a593Smuzhiyun 658*4882a593Smuzhiyun tmpdir = d.getVar('TMPDIR') 659*4882a593Smuzhiyun 660*4882a593Smuzhiyun fixtime = False 661*4882a593Smuzhiyun if ss['task'] == "package": 662*4882a593Smuzhiyun fixtime = True 663*4882a593Smuzhiyun 664*4882a593Smuzhiyun def fixtimestamp(root, path): 665*4882a593Smuzhiyun f = os.path.join(root, path) 666*4882a593Smuzhiyun if os.lstat(f).st_mtime > sde: 667*4882a593Smuzhiyun os.utime(f, (sde, sde), follow_symlinks=False) 668*4882a593Smuzhiyun 669*4882a593Smuzhiyun sstatebuild = d.expand("${WORKDIR}/sstate-build-%s/" % ss['task']) 670*4882a593Smuzhiyun sde = int(d.getVar("SOURCE_DATE_EPOCH") or time.time()) 671*4882a593Smuzhiyun d.setVar("SSTATE_CURRTASK", ss['task']) 672*4882a593Smuzhiyun bb.utils.remove(sstatebuild, recurse=True) 673*4882a593Smuzhiyun bb.utils.mkdirhier(sstatebuild) 674*4882a593Smuzhiyun for state in ss['dirs']: 675*4882a593Smuzhiyun if not os.path.exists(state[1]): 676*4882a593Smuzhiyun continue 677*4882a593Smuzhiyun srcbase = state[0].rstrip("/").rsplit('/', 1)[0] 678*4882a593Smuzhiyun # Find and error for absolute symlinks. We could attempt to relocate but its not 679*4882a593Smuzhiyun # clear where the symlink is relative to in this context. We could add that markup 680*4882a593Smuzhiyun # to sstate tasks but there aren't many of these so better just avoid them entirely. 681*4882a593Smuzhiyun for walkroot, dirs, files in os.walk(state[1]): 682*4882a593Smuzhiyun for file in files + dirs: 683*4882a593Smuzhiyun if fixtime: 684*4882a593Smuzhiyun fixtimestamp(walkroot, file) 685*4882a593Smuzhiyun srcpath = os.path.join(walkroot, file) 686*4882a593Smuzhiyun if not os.path.islink(srcpath): 687*4882a593Smuzhiyun continue 688*4882a593Smuzhiyun link = os.readlink(srcpath) 689*4882a593Smuzhiyun if not os.path.isabs(link): 690*4882a593Smuzhiyun continue 691*4882a593Smuzhiyun if not link.startswith(tmpdir): 692*4882a593Smuzhiyun continue 693*4882a593Smuzhiyun bb.error("sstate found an absolute path symlink %s pointing at %s. Please replace this with a relative link." % (srcpath, link)) 694*4882a593Smuzhiyun bb.debug(2, "Preparing tree %s for packaging at %s" % (state[1], sstatebuild + state[0])) 695*4882a593Smuzhiyun bb.utils.rename(state[1], sstatebuild + state[0]) 696*4882a593Smuzhiyun 697*4882a593Smuzhiyun workdir = d.getVar('WORKDIR') 698*4882a593Smuzhiyun sharedworkdir = os.path.join(d.getVar('TMPDIR'), "work-shared") 699*4882a593Smuzhiyun for plain in ss['plaindirs']: 700*4882a593Smuzhiyun pdir = plain.replace(workdir, sstatebuild) 701*4882a593Smuzhiyun if sharedworkdir in plain: 702*4882a593Smuzhiyun pdir = plain.replace(sharedworkdir, sstatebuild) 703*4882a593Smuzhiyun bb.utils.mkdirhier(plain) 704*4882a593Smuzhiyun bb.utils.mkdirhier(pdir) 705*4882a593Smuzhiyun bb.utils.rename(plain, pdir) 706*4882a593Smuzhiyun if fixtime: 707*4882a593Smuzhiyun fixtimestamp(pdir, "") 708*4882a593Smuzhiyun for walkroot, dirs, files in os.walk(pdir): 709*4882a593Smuzhiyun for file in files + dirs: 710*4882a593Smuzhiyun fixtimestamp(walkroot, file) 711*4882a593Smuzhiyun 712*4882a593Smuzhiyun d.setVar('SSTATE_BUILDDIR', sstatebuild) 713*4882a593Smuzhiyun d.setVar('SSTATE_INSTDIR', sstatebuild) 714*4882a593Smuzhiyun 715*4882a593Smuzhiyun if d.getVar('SSTATE_SKIP_CREATION') == '1': 716*4882a593Smuzhiyun return 717*4882a593Smuzhiyun 718*4882a593Smuzhiyun sstate_create_package = ['sstate_report_unihash', 'sstate_create_package'] 719*4882a593Smuzhiyun if d.getVar('SSTATE_SIG_KEY'): 720*4882a593Smuzhiyun sstate_create_package.append('sstate_sign_package') 721*4882a593Smuzhiyun 722*4882a593Smuzhiyun for f in (d.getVar('SSTATECREATEFUNCS') or '').split() + \ 723*4882a593Smuzhiyun sstate_create_package + \ 724*4882a593Smuzhiyun (d.getVar('SSTATEPOSTCREATEFUNCS') or '').split(): 725*4882a593Smuzhiyun # All hooks should run in SSTATE_BUILDDIR. 726*4882a593Smuzhiyun bb.build.exec_func(f, d, (sstatebuild,)) 727*4882a593Smuzhiyun 728*4882a593Smuzhiyun # SSTATE_PKG may have been changed by sstate_report_unihash 729*4882a593Smuzhiyun siginfo = d.getVar('SSTATE_PKG') + ".siginfo" 730*4882a593Smuzhiyun if not os.path.exists(siginfo): 731*4882a593Smuzhiyun bb.siggen.dump_this_task(siginfo, d) 732*4882a593Smuzhiyun else: 733*4882a593Smuzhiyun try: 734*4882a593Smuzhiyun os.utime(siginfo, None) 735*4882a593Smuzhiyun except PermissionError: 736*4882a593Smuzhiyun pass 737*4882a593Smuzhiyun except OSError as e: 738*4882a593Smuzhiyun # Handle read-only file systems gracefully 739*4882a593Smuzhiyun import errno 740*4882a593Smuzhiyun if e.errno != errno.EROFS: 741*4882a593Smuzhiyun raise e 742*4882a593Smuzhiyun 743*4882a593Smuzhiyun return 744*4882a593Smuzhiyun 745*4882a593Smuzhiyunsstate_package[vardepsexclude] += "SSTATE_SIG_KEY" 746*4882a593Smuzhiyun 747*4882a593Smuzhiyundef pstaging_fetch(sstatefetch, d): 748*4882a593Smuzhiyun import bb.fetch2 749*4882a593Smuzhiyun 750*4882a593Smuzhiyun # Only try and fetch if the user has configured a mirror 751*4882a593Smuzhiyun mirrors = d.getVar('SSTATE_MIRRORS') 752*4882a593Smuzhiyun if not mirrors: 753*4882a593Smuzhiyun return 754*4882a593Smuzhiyun 755*4882a593Smuzhiyun # Copy the data object and override DL_DIR and SRC_URI 756*4882a593Smuzhiyun localdata = bb.data.createCopy(d) 757*4882a593Smuzhiyun 758*4882a593Smuzhiyun dldir = localdata.expand("${SSTATE_DIR}") 759*4882a593Smuzhiyun bb.utils.mkdirhier(dldir) 760*4882a593Smuzhiyun 761*4882a593Smuzhiyun localdata.delVar('MIRRORS') 762*4882a593Smuzhiyun localdata.setVar('FILESPATH', dldir) 763*4882a593Smuzhiyun localdata.setVar('DL_DIR', dldir) 764*4882a593Smuzhiyun localdata.setVar('PREMIRRORS', mirrors) 765*4882a593Smuzhiyun localdata.setVar('SRCPV', d.getVar('SRCPV')) 766*4882a593Smuzhiyun 767*4882a593Smuzhiyun # if BB_NO_NETWORK is set but we also have SSTATE_MIRROR_ALLOW_NETWORK, 768*4882a593Smuzhiyun # we'll want to allow network access for the current set of fetches. 769*4882a593Smuzhiyun if bb.utils.to_boolean(localdata.getVar('BB_NO_NETWORK')) and \ 770*4882a593Smuzhiyun bb.utils.to_boolean(localdata.getVar('SSTATE_MIRROR_ALLOW_NETWORK')): 771*4882a593Smuzhiyun localdata.delVar('BB_NO_NETWORK') 772*4882a593Smuzhiyun 773*4882a593Smuzhiyun # Try a fetch from the sstate mirror, if it fails just return and 774*4882a593Smuzhiyun # we will build the package 775*4882a593Smuzhiyun uris = ['file://{0};downloadfilename={0}'.format(sstatefetch), 776*4882a593Smuzhiyun 'file://{0}.siginfo;downloadfilename={0}.siginfo'.format(sstatefetch)] 777*4882a593Smuzhiyun if bb.utils.to_boolean(d.getVar("SSTATE_VERIFY_SIG"), False): 778*4882a593Smuzhiyun uris += ['file://{0}.sig;downloadfilename={0}.sig'.format(sstatefetch)] 779*4882a593Smuzhiyun 780*4882a593Smuzhiyun for srcuri in uris: 781*4882a593Smuzhiyun localdata.setVar('SRC_URI', srcuri) 782*4882a593Smuzhiyun try: 783*4882a593Smuzhiyun fetcher = bb.fetch2.Fetch([srcuri], localdata, cache=False) 784*4882a593Smuzhiyun fetcher.checkstatus() 785*4882a593Smuzhiyun fetcher.download() 786*4882a593Smuzhiyun 787*4882a593Smuzhiyun except bb.fetch2.BBFetchException: 788*4882a593Smuzhiyun pass 789*4882a593Smuzhiyun 790*4882a593Smuzhiyunpstaging_fetch[vardepsexclude] += "SRCPV" 791*4882a593Smuzhiyun 792*4882a593Smuzhiyun 793*4882a593Smuzhiyundef sstate_setscene(d): 794*4882a593Smuzhiyun shared_state = sstate_state_fromvars(d) 795*4882a593Smuzhiyun accelerate = sstate_installpkg(shared_state, d) 796*4882a593Smuzhiyun if not accelerate: 797*4882a593Smuzhiyun msg = "No sstate archive obtainable, will run full task instead." 798*4882a593Smuzhiyun bb.warn(msg) 799*4882a593Smuzhiyun raise bb.BBHandledException(msg) 800*4882a593Smuzhiyun 801*4882a593Smuzhiyunpython sstate_task_prefunc () { 802*4882a593Smuzhiyun shared_state = sstate_state_fromvars(d) 803*4882a593Smuzhiyun sstate_clean(shared_state, d) 804*4882a593Smuzhiyun} 805*4882a593Smuzhiyunsstate_task_prefunc[dirs] = "${WORKDIR}" 806*4882a593Smuzhiyun 807*4882a593Smuzhiyunpython sstate_task_postfunc () { 808*4882a593Smuzhiyun shared_state = sstate_state_fromvars(d) 809*4882a593Smuzhiyun 810*4882a593Smuzhiyun for intercept in shared_state['interceptfuncs']: 811*4882a593Smuzhiyun bb.build.exec_func(intercept, d, (d.getVar("WORKDIR"),)) 812*4882a593Smuzhiyun 813*4882a593Smuzhiyun omask = os.umask(0o002) 814*4882a593Smuzhiyun if omask != 0o002: 815*4882a593Smuzhiyun bb.note("Using umask 0o002 (not %0o) for sstate packaging" % omask) 816*4882a593Smuzhiyun sstate_package(shared_state, d) 817*4882a593Smuzhiyun os.umask(omask) 818*4882a593Smuzhiyun 819*4882a593Smuzhiyun sstateinst = d.getVar("SSTATE_INSTDIR") 820*4882a593Smuzhiyun d.setVar('SSTATE_FIXMEDIR', shared_state['fixmedir']) 821*4882a593Smuzhiyun 822*4882a593Smuzhiyun sstate_installpkgdir(shared_state, d) 823*4882a593Smuzhiyun 824*4882a593Smuzhiyun bb.utils.remove(d.getVar("SSTATE_BUILDDIR"), recurse=True) 825*4882a593Smuzhiyun} 826*4882a593Smuzhiyunsstate_task_postfunc[dirs] = "${WORKDIR}" 827*4882a593Smuzhiyun 828*4882a593Smuzhiyun 829*4882a593Smuzhiyun# 830*4882a593Smuzhiyun# Shell function to generate a sstate package from a directory 831*4882a593Smuzhiyun# set as SSTATE_BUILDDIR. Will be run from within SSTATE_BUILDDIR. 832*4882a593Smuzhiyun# 833*4882a593Smuzhiyunsstate_create_package () { 834*4882a593Smuzhiyun # Exit early if it already exists 835*4882a593Smuzhiyun if [ -e ${SSTATE_PKG} ]; then 836*4882a593Smuzhiyun touch ${SSTATE_PKG} 2>/dev/null || true 837*4882a593Smuzhiyun return 838*4882a593Smuzhiyun fi 839*4882a593Smuzhiyun 840*4882a593Smuzhiyun mkdir --mode=0775 -p `dirname ${SSTATE_PKG}` 841*4882a593Smuzhiyun TFILE=`mktemp ${SSTATE_PKG}.XXXXXXXX` 842*4882a593Smuzhiyun 843*4882a593Smuzhiyun OPT="-cS" 844*4882a593Smuzhiyun ZSTD="zstd -${SSTATE_ZSTD_CLEVEL} -T${ZSTD_THREADS}" 845*4882a593Smuzhiyun # Use pzstd if available 846*4882a593Smuzhiyun if [ -x "$(command -v pzstd)" ]; then 847*4882a593Smuzhiyun ZSTD="pzstd -${SSTATE_ZSTD_CLEVEL} -p ${ZSTD_THREADS}" 848*4882a593Smuzhiyun fi 849*4882a593Smuzhiyun 850*4882a593Smuzhiyun # Need to handle empty directories 851*4882a593Smuzhiyun if [ "$(ls -A)" ]; then 852*4882a593Smuzhiyun set +e 853*4882a593Smuzhiyun tar -I "$ZSTD" $OPT -f $TFILE * 854*4882a593Smuzhiyun ret=$? 855*4882a593Smuzhiyun if [ $ret -ne 0 ] && [ $ret -ne 1 ]; then 856*4882a593Smuzhiyun exit 1 857*4882a593Smuzhiyun fi 858*4882a593Smuzhiyun set -e 859*4882a593Smuzhiyun else 860*4882a593Smuzhiyun tar -I "$ZSTD" $OPT --file=$TFILE --files-from=/dev/null 861*4882a593Smuzhiyun fi 862*4882a593Smuzhiyun chmod 0664 $TFILE 863*4882a593Smuzhiyun # Skip if it was already created by some other process 864*4882a593Smuzhiyun if [ -h ${SSTATE_PKG} ] && [ ! -e ${SSTATE_PKG} ]; then 865*4882a593Smuzhiyun # There is a symbolic link, but it links to nothing. 866*4882a593Smuzhiyun # Forcefully replace it with the new file. 867*4882a593Smuzhiyun ln -f $TFILE ${SSTATE_PKG} || true 868*4882a593Smuzhiyun elif [ ! -e ${SSTATE_PKG} ]; then 869*4882a593Smuzhiyun # Move into place using ln to attempt an atomic op. 870*4882a593Smuzhiyun # Abort if it already exists 871*4882a593Smuzhiyun ln $TFILE ${SSTATE_PKG} || true 872*4882a593Smuzhiyun else 873*4882a593Smuzhiyun touch ${SSTATE_PKG} 2>/dev/null || true 874*4882a593Smuzhiyun fi 875*4882a593Smuzhiyun rm $TFILE 876*4882a593Smuzhiyun} 877*4882a593Smuzhiyun 878*4882a593Smuzhiyunpython sstate_sign_package () { 879*4882a593Smuzhiyun from oe.gpg_sign import get_signer 880*4882a593Smuzhiyun 881*4882a593Smuzhiyun 882*4882a593Smuzhiyun signer = get_signer(d, 'local') 883*4882a593Smuzhiyun sstate_pkg = d.getVar('SSTATE_PKG') 884*4882a593Smuzhiyun if os.path.exists(sstate_pkg + '.sig'): 885*4882a593Smuzhiyun os.unlink(sstate_pkg + '.sig') 886*4882a593Smuzhiyun signer.detach_sign(sstate_pkg, d.getVar('SSTATE_SIG_KEY', False), None, 887*4882a593Smuzhiyun d.getVar('SSTATE_SIG_PASSPHRASE'), armor=False) 888*4882a593Smuzhiyun} 889*4882a593Smuzhiyun 890*4882a593Smuzhiyunpython sstate_report_unihash() { 891*4882a593Smuzhiyun report_unihash = getattr(bb.parse.siggen, 'report_unihash', None) 892*4882a593Smuzhiyun 893*4882a593Smuzhiyun if report_unihash: 894*4882a593Smuzhiyun ss = sstate_state_fromvars(d) 895*4882a593Smuzhiyun report_unihash(os.getcwd(), ss['task'], d) 896*4882a593Smuzhiyun} 897*4882a593Smuzhiyun 898*4882a593Smuzhiyun# 899*4882a593Smuzhiyun# Shell function to decompress and prepare a package for installation 900*4882a593Smuzhiyun# Will be run from within SSTATE_INSTDIR. 901*4882a593Smuzhiyun# 902*4882a593Smuzhiyunsstate_unpack_package () { 903*4882a593Smuzhiyun ZSTD="zstd -T${ZSTD_THREADS}" 904*4882a593Smuzhiyun # Use pzstd if available 905*4882a593Smuzhiyun if [ -x "$(command -v pzstd)" ]; then 906*4882a593Smuzhiyun ZSTD="pzstd -p ${ZSTD_THREADS}" 907*4882a593Smuzhiyun fi 908*4882a593Smuzhiyun 909*4882a593Smuzhiyun tar -I "$ZSTD" -xvpf ${SSTATE_PKG} 910*4882a593Smuzhiyun # update .siginfo atime on local/NFS mirror if it is a symbolic link 911*4882a593Smuzhiyun [ ! -h ${SSTATE_PKG}.siginfo ] || [ ! -e ${SSTATE_PKG}.siginfo ] || touch -a ${SSTATE_PKG}.siginfo 2>/dev/null || true 912*4882a593Smuzhiyun # update each symbolic link instead of any referenced file 913*4882a593Smuzhiyun touch --no-dereference ${SSTATE_PKG} 2>/dev/null || true 914*4882a593Smuzhiyun [ ! -e ${SSTATE_PKG}.sig ] || touch --no-dereference ${SSTATE_PKG}.sig 2>/dev/null || true 915*4882a593Smuzhiyun [ ! -e ${SSTATE_PKG}.siginfo ] || touch --no-dereference ${SSTATE_PKG}.siginfo 2>/dev/null || true 916*4882a593Smuzhiyun} 917*4882a593Smuzhiyun 918*4882a593SmuzhiyunBB_HASHCHECK_FUNCTION = "sstate_checkhashes" 919*4882a593Smuzhiyun 920*4882a593Smuzhiyundef sstate_checkhashes(sq_data, d, siginfo=False, currentcount=0, summary=True, **kwargs): 921*4882a593Smuzhiyun found = set() 922*4882a593Smuzhiyun missed = set() 923*4882a593Smuzhiyun 924*4882a593Smuzhiyun def gethash(task): 925*4882a593Smuzhiyun return sq_data['unihash'][task] 926*4882a593Smuzhiyun 927*4882a593Smuzhiyun def getpathcomponents(task, d): 928*4882a593Smuzhiyun # Magic data from BB_HASHFILENAME 929*4882a593Smuzhiyun splithashfn = sq_data['hashfn'][task].split(" ") 930*4882a593Smuzhiyun spec = splithashfn[1] 931*4882a593Smuzhiyun if splithashfn[0] == "True": 932*4882a593Smuzhiyun extrapath = d.getVar("NATIVELSBSTRING") + "/" 933*4882a593Smuzhiyun else: 934*4882a593Smuzhiyun extrapath = "" 935*4882a593Smuzhiyun 936*4882a593Smuzhiyun tname = bb.runqueue.taskname_from_tid(task)[3:] 937*4882a593Smuzhiyun 938*4882a593Smuzhiyun if tname in ["fetch", "unpack", "patch", "populate_lic", "preconfigure"] and splithashfn[2]: 939*4882a593Smuzhiyun spec = splithashfn[2] 940*4882a593Smuzhiyun extrapath = "" 941*4882a593Smuzhiyun 942*4882a593Smuzhiyun return spec, extrapath, tname 943*4882a593Smuzhiyun 944*4882a593Smuzhiyun def getsstatefile(tid, siginfo, d): 945*4882a593Smuzhiyun spec, extrapath, tname = getpathcomponents(tid, d) 946*4882a593Smuzhiyun return extrapath + generate_sstatefn(spec, gethash(tid), tname, siginfo, d) 947*4882a593Smuzhiyun 948*4882a593Smuzhiyun for tid in sq_data['hash']: 949*4882a593Smuzhiyun 950*4882a593Smuzhiyun sstatefile = d.expand("${SSTATE_DIR}/" + getsstatefile(tid, siginfo, d)) 951*4882a593Smuzhiyun 952*4882a593Smuzhiyun if os.path.exists(sstatefile): 953*4882a593Smuzhiyun found.add(tid) 954*4882a593Smuzhiyun bb.debug(2, "SState: Found valid sstate file %s" % sstatefile) 955*4882a593Smuzhiyun else: 956*4882a593Smuzhiyun missed.add(tid) 957*4882a593Smuzhiyun bb.debug(2, "SState: Looked for but didn't find file %s" % sstatefile) 958*4882a593Smuzhiyun 959*4882a593Smuzhiyun foundLocal = len(found) 960*4882a593Smuzhiyun mirrors = d.getVar("SSTATE_MIRRORS") 961*4882a593Smuzhiyun if mirrors: 962*4882a593Smuzhiyun # Copy the data object and override DL_DIR and SRC_URI 963*4882a593Smuzhiyun localdata = bb.data.createCopy(d) 964*4882a593Smuzhiyun 965*4882a593Smuzhiyun dldir = localdata.expand("${SSTATE_DIR}") 966*4882a593Smuzhiyun localdata.delVar('MIRRORS') 967*4882a593Smuzhiyun localdata.setVar('FILESPATH', dldir) 968*4882a593Smuzhiyun localdata.setVar('DL_DIR', dldir) 969*4882a593Smuzhiyun localdata.setVar('PREMIRRORS', mirrors) 970*4882a593Smuzhiyun 971*4882a593Smuzhiyun bb.debug(2, "SState using premirror of: %s" % mirrors) 972*4882a593Smuzhiyun 973*4882a593Smuzhiyun # if BB_NO_NETWORK is set but we also have SSTATE_MIRROR_ALLOW_NETWORK, 974*4882a593Smuzhiyun # we'll want to allow network access for the current set of fetches. 975*4882a593Smuzhiyun if bb.utils.to_boolean(localdata.getVar('BB_NO_NETWORK')) and \ 976*4882a593Smuzhiyun bb.utils.to_boolean(localdata.getVar('SSTATE_MIRROR_ALLOW_NETWORK')): 977*4882a593Smuzhiyun localdata.delVar('BB_NO_NETWORK') 978*4882a593Smuzhiyun 979*4882a593Smuzhiyun from bb.fetch2 import FetchConnectionCache 980*4882a593Smuzhiyun def checkstatus_init(thread_worker): 981*4882a593Smuzhiyun thread_worker.connection_cache = FetchConnectionCache() 982*4882a593Smuzhiyun 983*4882a593Smuzhiyun def checkstatus_end(thread_worker): 984*4882a593Smuzhiyun thread_worker.connection_cache.close_connections() 985*4882a593Smuzhiyun 986*4882a593Smuzhiyun def checkstatus(thread_worker, arg): 987*4882a593Smuzhiyun (tid, sstatefile) = arg 988*4882a593Smuzhiyun 989*4882a593Smuzhiyun localdata2 = bb.data.createCopy(localdata) 990*4882a593Smuzhiyun srcuri = "file://" + sstatefile 991*4882a593Smuzhiyun localdata2.setVar('SRC_URI', srcuri) 992*4882a593Smuzhiyun bb.debug(2, "SState: Attempting to fetch %s" % srcuri) 993*4882a593Smuzhiyun 994*4882a593Smuzhiyun import traceback 995*4882a593Smuzhiyun 996*4882a593Smuzhiyun try: 997*4882a593Smuzhiyun fetcher = bb.fetch2.Fetch(srcuri.split(), localdata2, 998*4882a593Smuzhiyun connection_cache=thread_worker.connection_cache) 999*4882a593Smuzhiyun fetcher.checkstatus() 1000*4882a593Smuzhiyun bb.debug(2, "SState: Successful fetch test for %s" % srcuri) 1001*4882a593Smuzhiyun found.add(tid) 1002*4882a593Smuzhiyun missed.remove(tid) 1003*4882a593Smuzhiyun except bb.fetch2.FetchError as e: 1004*4882a593Smuzhiyun bb.debug(2, "SState: Unsuccessful fetch test for %s (%s)\n%s" % (srcuri, repr(e), traceback.format_exc())) 1005*4882a593Smuzhiyun except Exception as e: 1006*4882a593Smuzhiyun bb.error("SState: cannot test %s: %s\n%s" % (srcuri, repr(e), traceback.format_exc())) 1007*4882a593Smuzhiyun 1008*4882a593Smuzhiyun if progress: 1009*4882a593Smuzhiyun bb.event.fire(bb.event.ProcessProgress(msg, len(tasklist) - thread_worker.tasks.qsize()), d) 1010*4882a593Smuzhiyun 1011*4882a593Smuzhiyun tasklist = [] 1012*4882a593Smuzhiyun for tid in missed: 1013*4882a593Smuzhiyun sstatefile = d.expand(getsstatefile(tid, siginfo, d)) 1014*4882a593Smuzhiyun tasklist.append((tid, sstatefile)) 1015*4882a593Smuzhiyun 1016*4882a593Smuzhiyun if tasklist: 1017*4882a593Smuzhiyun nproc = min(int(d.getVar("BB_NUMBER_THREADS")), len(tasklist)) 1018*4882a593Smuzhiyun 1019*4882a593Smuzhiyun progress = len(tasklist) >= 100 1020*4882a593Smuzhiyun if progress: 1021*4882a593Smuzhiyun msg = "Checking sstate mirror object availability" 1022*4882a593Smuzhiyun bb.event.fire(bb.event.ProcessStarted(msg, len(tasklist)), d) 1023*4882a593Smuzhiyun 1024*4882a593Smuzhiyun # Have to setup the fetcher environment here rather than in each thread as it would race 1025*4882a593Smuzhiyun fetcherenv = bb.fetch2.get_fetcher_environment(d) 1026*4882a593Smuzhiyun with bb.utils.environment(**fetcherenv): 1027*4882a593Smuzhiyun bb.event.enable_threadlock() 1028*4882a593Smuzhiyun pool = oe.utils.ThreadedPool(nproc, len(tasklist), 1029*4882a593Smuzhiyun worker_init=checkstatus_init, worker_end=checkstatus_end, 1030*4882a593Smuzhiyun name="sstate_checkhashes-") 1031*4882a593Smuzhiyun for t in tasklist: 1032*4882a593Smuzhiyun pool.add_task(checkstatus, t) 1033*4882a593Smuzhiyun pool.start() 1034*4882a593Smuzhiyun pool.wait_completion() 1035*4882a593Smuzhiyun bb.event.disable_threadlock() 1036*4882a593Smuzhiyun 1037*4882a593Smuzhiyun if progress: 1038*4882a593Smuzhiyun bb.event.fire(bb.event.ProcessFinished(msg), d) 1039*4882a593Smuzhiyun 1040*4882a593Smuzhiyun inheritlist = d.getVar("INHERIT") 1041*4882a593Smuzhiyun if "toaster" in inheritlist: 1042*4882a593Smuzhiyun evdata = {'missed': [], 'found': []}; 1043*4882a593Smuzhiyun for tid in missed: 1044*4882a593Smuzhiyun sstatefile = d.expand(getsstatefile(tid, False, d)) 1045*4882a593Smuzhiyun evdata['missed'].append((bb.runqueue.fn_from_tid(tid), bb.runqueue.taskname_from_tid(tid), gethash(tid), sstatefile ) ) 1046*4882a593Smuzhiyun for tid in found: 1047*4882a593Smuzhiyun sstatefile = d.expand(getsstatefile(tid, False, d)) 1048*4882a593Smuzhiyun evdata['found'].append((bb.runqueue.fn_from_tid(tid), bb.runqueue.taskname_from_tid(tid), gethash(tid), sstatefile ) ) 1049*4882a593Smuzhiyun bb.event.fire(bb.event.MetadataEvent("MissedSstate", evdata), d) 1050*4882a593Smuzhiyun 1051*4882a593Smuzhiyun if summary: 1052*4882a593Smuzhiyun # Print some summary statistics about the current task completion and how much sstate 1053*4882a593Smuzhiyun # reuse there was. Avoid divide by zero errors. 1054*4882a593Smuzhiyun total = len(sq_data['hash']) 1055*4882a593Smuzhiyun complete = 0 1056*4882a593Smuzhiyun if currentcount: 1057*4882a593Smuzhiyun complete = (len(found) + currentcount) / (total + currentcount) * 100 1058*4882a593Smuzhiyun match = 0 1059*4882a593Smuzhiyun if total: 1060*4882a593Smuzhiyun match = len(found) / total * 100 1061*4882a593Smuzhiyun bb.plain("Sstate summary: Wanted %d Local %d Mirrors %d Missed %d Current %d (%d%% match, %d%% complete)" % 1062*4882a593Smuzhiyun (total, foundLocal, len(found)-foundLocal, len(missed), currentcount, match, complete)) 1063*4882a593Smuzhiyun 1064*4882a593Smuzhiyun if hasattr(bb.parse.siggen, "checkhashes"): 1065*4882a593Smuzhiyun bb.parse.siggen.checkhashes(sq_data, missed, found, d) 1066*4882a593Smuzhiyun 1067*4882a593Smuzhiyun return found 1068*4882a593Smuzhiyunsetscene_depvalid[vardepsexclude] = "SSTATE_EXCLUDEDEPS_SYSROOT" 1069*4882a593Smuzhiyun 1070*4882a593SmuzhiyunBB_SETSCENE_DEPVALID = "setscene_depvalid" 1071*4882a593Smuzhiyun 1072*4882a593Smuzhiyundef setscene_depvalid(task, taskdependees, notneeded, d, log=None): 1073*4882a593Smuzhiyun # taskdependees is a dict of tasks which depend on task, each being a 3 item list of [PN, TASKNAME, FILENAME] 1074*4882a593Smuzhiyun # task is included in taskdependees too 1075*4882a593Smuzhiyun # Return - False - We need this dependency 1076*4882a593Smuzhiyun # - True - We can skip this dependency 1077*4882a593Smuzhiyun import re 1078*4882a593Smuzhiyun 1079*4882a593Smuzhiyun def logit(msg, log): 1080*4882a593Smuzhiyun if log is not None: 1081*4882a593Smuzhiyun log.append(msg) 1082*4882a593Smuzhiyun else: 1083*4882a593Smuzhiyun bb.debug(2, msg) 1084*4882a593Smuzhiyun 1085*4882a593Smuzhiyun logit("Considering setscene task: %s" % (str(taskdependees[task])), log) 1086*4882a593Smuzhiyun 1087*4882a593Smuzhiyun directtasks = ["do_populate_lic", "do_deploy_source_date_epoch", "do_shared_workdir", "do_stash_locale", "do_gcc_stash_builddir", "do_create_spdx", "do_deploy_archives"] 1088*4882a593Smuzhiyun 1089*4882a593Smuzhiyun def isNativeCross(x): 1090*4882a593Smuzhiyun return x.endswith("-native") or "-cross-" in x or "-crosssdk" in x or x.endswith("-cross") 1091*4882a593Smuzhiyun 1092*4882a593Smuzhiyun # We only need to trigger deploy_source_date_epoch through direct dependencies 1093*4882a593Smuzhiyun if taskdependees[task][1] in directtasks: 1094*4882a593Smuzhiyun return True 1095*4882a593Smuzhiyun 1096*4882a593Smuzhiyun # We only need to trigger packagedata through direct dependencies 1097*4882a593Smuzhiyun # but need to preserve packagedata on packagedata links 1098*4882a593Smuzhiyun if taskdependees[task][1] == "do_packagedata": 1099*4882a593Smuzhiyun for dep in taskdependees: 1100*4882a593Smuzhiyun if taskdependees[dep][1] == "do_packagedata": 1101*4882a593Smuzhiyun return False 1102*4882a593Smuzhiyun return True 1103*4882a593Smuzhiyun 1104*4882a593Smuzhiyun for dep in taskdependees: 1105*4882a593Smuzhiyun logit(" considering dependency: %s" % (str(taskdependees[dep])), log) 1106*4882a593Smuzhiyun if task == dep: 1107*4882a593Smuzhiyun continue 1108*4882a593Smuzhiyun if dep in notneeded: 1109*4882a593Smuzhiyun continue 1110*4882a593Smuzhiyun # do_package_write_* and do_package doesn't need do_package 1111*4882a593Smuzhiyun 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']: 1112*4882a593Smuzhiyun continue 1113*4882a593Smuzhiyun # do_package_write_* need do_populate_sysroot as they're mainly postinstall dependencies 1114*4882a593Smuzhiyun if taskdependees[task][1] == "do_populate_sysroot" and taskdependees[dep][1] in ['do_package_write_deb', 'do_package_write_ipk', 'do_package_write_rpm']: 1115*4882a593Smuzhiyun return False 1116*4882a593Smuzhiyun # do_package/packagedata/package_qa/deploy don't need do_populate_sysroot 1117*4882a593Smuzhiyun if taskdependees[task][1] == "do_populate_sysroot" and taskdependees[dep][1] in ['do_package', 'do_packagedata', 'do_package_qa', 'do_deploy']: 1118*4882a593Smuzhiyun continue 1119*4882a593Smuzhiyun # Native/Cross packages don't exist and are noexec anyway 1120*4882a593Smuzhiyun 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']: 1121*4882a593Smuzhiyun continue 1122*4882a593Smuzhiyun 1123*4882a593Smuzhiyun # This is due to the [depends] in useradd.bbclass complicating matters 1124*4882a593Smuzhiyun # The logic *is* reversed here due to the way hard setscene dependencies are injected 1125*4882a593Smuzhiyun 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': 1126*4882a593Smuzhiyun continue 1127*4882a593Smuzhiyun 1128*4882a593Smuzhiyun # Consider sysroot depending on sysroot tasks 1129*4882a593Smuzhiyun if taskdependees[task][1] == 'do_populate_sysroot' and taskdependees[dep][1] == 'do_populate_sysroot': 1130*4882a593Smuzhiyun # Allow excluding certain recursive dependencies. If a recipe needs it should add a 1131*4882a593Smuzhiyun # specific dependency itself, rather than relying on one of its dependees to pull 1132*4882a593Smuzhiyun # them in. 1133*4882a593Smuzhiyun # See also http://lists.openembedded.org/pipermail/openembedded-core/2018-January/146324.html 1134*4882a593Smuzhiyun not_needed = False 1135*4882a593Smuzhiyun excludedeps = d.getVar('_SSTATE_EXCLUDEDEPS_SYSROOT') 1136*4882a593Smuzhiyun if excludedeps is None: 1137*4882a593Smuzhiyun # Cache the regular expressions for speed 1138*4882a593Smuzhiyun excludedeps = [] 1139*4882a593Smuzhiyun for excl in (d.getVar('SSTATE_EXCLUDEDEPS_SYSROOT') or "").split(): 1140*4882a593Smuzhiyun excludedeps.append((re.compile(excl.split('->', 1)[0]), re.compile(excl.split('->', 1)[1]))) 1141*4882a593Smuzhiyun d.setVar('_SSTATE_EXCLUDEDEPS_SYSROOT', excludedeps) 1142*4882a593Smuzhiyun for excl in excludedeps: 1143*4882a593Smuzhiyun if excl[0].match(taskdependees[dep][0]): 1144*4882a593Smuzhiyun if excl[1].match(taskdependees[task][0]): 1145*4882a593Smuzhiyun not_needed = True 1146*4882a593Smuzhiyun break 1147*4882a593Smuzhiyun if not_needed: 1148*4882a593Smuzhiyun continue 1149*4882a593Smuzhiyun # For meta-extsdk-toolchain we want all sysroot dependencies 1150*4882a593Smuzhiyun if taskdependees[dep][0] == 'meta-extsdk-toolchain': 1151*4882a593Smuzhiyun return False 1152*4882a593Smuzhiyun # Native/Cross populate_sysroot need their dependencies 1153*4882a593Smuzhiyun if isNativeCross(taskdependees[task][0]) and isNativeCross(taskdependees[dep][0]): 1154*4882a593Smuzhiyun return False 1155*4882a593Smuzhiyun # Target populate_sysroot depended on by cross tools need to be installed 1156*4882a593Smuzhiyun if isNativeCross(taskdependees[dep][0]): 1157*4882a593Smuzhiyun return False 1158*4882a593Smuzhiyun # Native/cross tools depended upon by target sysroot are not needed 1159*4882a593Smuzhiyun # Add an exception for shadow-native as required by useradd.bbclass 1160*4882a593Smuzhiyun if isNativeCross(taskdependees[task][0]) and taskdependees[task][0] != 'shadow-native': 1161*4882a593Smuzhiyun continue 1162*4882a593Smuzhiyun # Target populate_sysroot need their dependencies 1163*4882a593Smuzhiyun return False 1164*4882a593Smuzhiyun 1165*4882a593Smuzhiyun if taskdependees[dep][1] in directtasks: 1166*4882a593Smuzhiyun continue 1167*4882a593Smuzhiyun 1168*4882a593Smuzhiyun # Safe fallthrough default 1169*4882a593Smuzhiyun logit(" Default setscene dependency fall through due to dependency: %s" % (str(taskdependees[dep])), log) 1170*4882a593Smuzhiyun return False 1171*4882a593Smuzhiyun return True 1172*4882a593Smuzhiyun 1173*4882a593Smuzhiyunaddhandler sstate_eventhandler 1174*4882a593Smuzhiyunsstate_eventhandler[eventmask] = "bb.build.TaskSucceeded" 1175*4882a593Smuzhiyunpython sstate_eventhandler() { 1176*4882a593Smuzhiyun d = e.data 1177*4882a593Smuzhiyun writtensstate = d.getVar('SSTATE_CURRTASK') 1178*4882a593Smuzhiyun if not writtensstate: 1179*4882a593Smuzhiyun taskname = d.getVar("BB_RUNTASK")[3:] 1180*4882a593Smuzhiyun spec = d.getVar('SSTATE_PKGSPEC') 1181*4882a593Smuzhiyun swspec = d.getVar('SSTATE_SWSPEC') 1182*4882a593Smuzhiyun if taskname in ["fetch", "unpack", "patch", "populate_lic", "preconfigure"] and swspec: 1183*4882a593Smuzhiyun d.setVar("SSTATE_PKGSPEC", "${SSTATE_SWSPEC}") 1184*4882a593Smuzhiyun d.setVar("SSTATE_EXTRAPATH", "") 1185*4882a593Smuzhiyun d.setVar("SSTATE_CURRTASK", taskname) 1186*4882a593Smuzhiyun siginfo = d.getVar('SSTATE_PKG') + ".siginfo" 1187*4882a593Smuzhiyun if not os.path.exists(siginfo): 1188*4882a593Smuzhiyun bb.siggen.dump_this_task(siginfo, d) 1189*4882a593Smuzhiyun else: 1190*4882a593Smuzhiyun try: 1191*4882a593Smuzhiyun os.utime(siginfo, None) 1192*4882a593Smuzhiyun except PermissionError: 1193*4882a593Smuzhiyun pass 1194*4882a593Smuzhiyun except OSError as e: 1195*4882a593Smuzhiyun # Handle read-only file systems gracefully 1196*4882a593Smuzhiyun import errno 1197*4882a593Smuzhiyun if e.errno != errno.EROFS: 1198*4882a593Smuzhiyun raise e 1199*4882a593Smuzhiyun 1200*4882a593Smuzhiyun} 1201*4882a593Smuzhiyun 1202*4882a593SmuzhiyunSSTATE_PRUNE_OBSOLETEWORKDIR ?= "1" 1203*4882a593Smuzhiyun 1204*4882a593Smuzhiyun# 1205*4882a593Smuzhiyun# Event handler which removes manifests and stamps file for recipes which are no 1206*4882a593Smuzhiyun# longer 'reachable' in a build where they once were. 'Reachable' refers to 1207*4882a593Smuzhiyun# whether a recipe is parsed so recipes in a layer which was removed would no 1208*4882a593Smuzhiyun# longer be reachable. Switching between systemd and sysvinit where recipes 1209*4882a593Smuzhiyun# became skipped would be another example. 1210*4882a593Smuzhiyun# 1211*4882a593Smuzhiyun# Also optionally removes the workdir of those tasks/recipes 1212*4882a593Smuzhiyun# 1213*4882a593Smuzhiyunaddhandler sstate_eventhandler_reachablestamps 1214*4882a593Smuzhiyunsstate_eventhandler_reachablestamps[eventmask] = "bb.event.ReachableStamps" 1215*4882a593Smuzhiyunpython sstate_eventhandler_reachablestamps() { 1216*4882a593Smuzhiyun import glob 1217*4882a593Smuzhiyun d = e.data 1218*4882a593Smuzhiyun stamps = e.stamps.values() 1219*4882a593Smuzhiyun removeworkdir = (d.getVar("SSTATE_PRUNE_OBSOLETEWORKDIR", False) == "1") 1220*4882a593Smuzhiyun preservestampfile = d.expand('${SSTATE_MANIFESTS}/preserve-stamps') 1221*4882a593Smuzhiyun preservestamps = [] 1222*4882a593Smuzhiyun if os.path.exists(preservestampfile): 1223*4882a593Smuzhiyun with open(preservestampfile, 'r') as f: 1224*4882a593Smuzhiyun preservestamps = f.readlines() 1225*4882a593Smuzhiyun seen = [] 1226*4882a593Smuzhiyun 1227*4882a593Smuzhiyun # The machine index contains all the stamps this machine has ever seen in this build directory. 1228*4882a593Smuzhiyun # We should only remove things which this machine once accessed but no longer does. 1229*4882a593Smuzhiyun machineindex = set() 1230*4882a593Smuzhiyun bb.utils.mkdirhier(d.expand("${SSTATE_MANIFESTS}")) 1231*4882a593Smuzhiyun mi = d.expand("${SSTATE_MANIFESTS}/index-machine-${MACHINE}") 1232*4882a593Smuzhiyun if os.path.exists(mi): 1233*4882a593Smuzhiyun with open(mi, "r") as f: 1234*4882a593Smuzhiyun machineindex = set(line.strip() for line in f.readlines()) 1235*4882a593Smuzhiyun 1236*4882a593Smuzhiyun for a in sorted(list(set(d.getVar("SSTATE_ARCHS").split()))): 1237*4882a593Smuzhiyun toremove = [] 1238*4882a593Smuzhiyun i = d.expand("${SSTATE_MANIFESTS}/index-" + a) 1239*4882a593Smuzhiyun if not os.path.exists(i): 1240*4882a593Smuzhiyun continue 1241*4882a593Smuzhiyun manseen = set() 1242*4882a593Smuzhiyun ignore = [] 1243*4882a593Smuzhiyun with open(i, "r") as f: 1244*4882a593Smuzhiyun lines = f.readlines() 1245*4882a593Smuzhiyun for l in reversed(lines): 1246*4882a593Smuzhiyun try: 1247*4882a593Smuzhiyun (stamp, manifest, workdir) = l.split() 1248*4882a593Smuzhiyun # The index may have multiple entries for the same manifest as the code above only appends 1249*4882a593Smuzhiyun # new entries and there may be an entry with matching manifest but differing version in stamp/workdir. 1250*4882a593Smuzhiyun # The last entry in the list is the valid one, any earlier entries with matching manifests 1251*4882a593Smuzhiyun # should be ignored. 1252*4882a593Smuzhiyun if manifest in manseen: 1253*4882a593Smuzhiyun ignore.append(l) 1254*4882a593Smuzhiyun continue 1255*4882a593Smuzhiyun manseen.add(manifest) 1256*4882a593Smuzhiyun if stamp not in stamps and stamp not in preservestamps and stamp in machineindex: 1257*4882a593Smuzhiyun toremove.append(l) 1258*4882a593Smuzhiyun if stamp not in seen: 1259*4882a593Smuzhiyun bb.debug(2, "Stamp %s is not reachable, removing related manifests" % stamp) 1260*4882a593Smuzhiyun seen.append(stamp) 1261*4882a593Smuzhiyun except ValueError: 1262*4882a593Smuzhiyun bb.fatal("Invalid line '%s' in sstate manifest '%s'" % (l, i)) 1263*4882a593Smuzhiyun 1264*4882a593Smuzhiyun if toremove: 1265*4882a593Smuzhiyun msg = "Removing %d recipes from the %s sysroot" % (len(toremove), a) 1266*4882a593Smuzhiyun bb.event.fire(bb.event.ProcessStarted(msg, len(toremove)), d) 1267*4882a593Smuzhiyun 1268*4882a593Smuzhiyun removed = 0 1269*4882a593Smuzhiyun for r in toremove: 1270*4882a593Smuzhiyun (stamp, manifest, workdir) = r.split() 1271*4882a593Smuzhiyun for m in glob.glob(manifest + ".*"): 1272*4882a593Smuzhiyun if m.endswith(".postrm"): 1273*4882a593Smuzhiyun continue 1274*4882a593Smuzhiyun sstate_clean_manifest(m, d) 1275*4882a593Smuzhiyun bb.utils.remove(stamp + "*") 1276*4882a593Smuzhiyun if removeworkdir: 1277*4882a593Smuzhiyun bb.utils.remove(workdir, recurse = True) 1278*4882a593Smuzhiyun lines.remove(r) 1279*4882a593Smuzhiyun removed = removed + 1 1280*4882a593Smuzhiyun bb.event.fire(bb.event.ProcessProgress(msg, removed), d) 1281*4882a593Smuzhiyun 1282*4882a593Smuzhiyun bb.event.fire(bb.event.ProcessFinished(msg), d) 1283*4882a593Smuzhiyun 1284*4882a593Smuzhiyun with open(i, "w") as f: 1285*4882a593Smuzhiyun for l in lines: 1286*4882a593Smuzhiyun if l in ignore: 1287*4882a593Smuzhiyun continue 1288*4882a593Smuzhiyun f.write(l) 1289*4882a593Smuzhiyun machineindex |= set(stamps) 1290*4882a593Smuzhiyun with open(mi, "w") as f: 1291*4882a593Smuzhiyun for l in machineindex: 1292*4882a593Smuzhiyun f.write(l + "\n") 1293*4882a593Smuzhiyun 1294*4882a593Smuzhiyun if preservestamps: 1295*4882a593Smuzhiyun os.remove(preservestampfile) 1296*4882a593Smuzhiyun} 1297*4882a593Smuzhiyun 1298*4882a593Smuzhiyun 1299*4882a593Smuzhiyun# 1300*4882a593Smuzhiyun# Bitbake can generate an event showing which setscene tasks are 'stale', 1301*4882a593Smuzhiyun# i.e. which ones will be rerun. These are ones where a stamp file is present but 1302*4882a593Smuzhiyun# it is stable (e.g. taskhash doesn't match). With that list we can go through 1303*4882a593Smuzhiyun# the manifests for matching tasks and "uninstall" those manifests now. We do 1304*4882a593Smuzhiyun# this now rather than mid build since the distribution of files between sstate 1305*4882a593Smuzhiyun# objects may have changed, new tasks may run first and if those new tasks overlap 1306*4882a593Smuzhiyun# with the stale tasks, we'd see overlapping files messages and failures. Thankfully 1307*4882a593Smuzhiyun# removing these files is fast. 1308*4882a593Smuzhiyun# 1309*4882a593Smuzhiyunaddhandler sstate_eventhandler_stalesstate 1310*4882a593Smuzhiyunsstate_eventhandler_stalesstate[eventmask] = "bb.event.StaleSetSceneTasks" 1311*4882a593Smuzhiyunpython sstate_eventhandler_stalesstate() { 1312*4882a593Smuzhiyun d = e.data 1313*4882a593Smuzhiyun tasks = e.tasks 1314*4882a593Smuzhiyun 1315*4882a593Smuzhiyun bb.utils.mkdirhier(d.expand("${SSTATE_MANIFESTS}")) 1316*4882a593Smuzhiyun 1317*4882a593Smuzhiyun for a in list(set(d.getVar("SSTATE_ARCHS").split())): 1318*4882a593Smuzhiyun toremove = [] 1319*4882a593Smuzhiyun i = d.expand("${SSTATE_MANIFESTS}/index-" + a) 1320*4882a593Smuzhiyun if not os.path.exists(i): 1321*4882a593Smuzhiyun continue 1322*4882a593Smuzhiyun with open(i, "r") as f: 1323*4882a593Smuzhiyun lines = f.readlines() 1324*4882a593Smuzhiyun for l in lines: 1325*4882a593Smuzhiyun try: 1326*4882a593Smuzhiyun (stamp, manifest, workdir) = l.split() 1327*4882a593Smuzhiyun for tid in tasks: 1328*4882a593Smuzhiyun for s in tasks[tid]: 1329*4882a593Smuzhiyun if s.startswith(stamp): 1330*4882a593Smuzhiyun taskname = bb.runqueue.taskname_from_tid(tid)[3:] 1331*4882a593Smuzhiyun manname = manifest + "." + taskname 1332*4882a593Smuzhiyun if os.path.exists(manname): 1333*4882a593Smuzhiyun bb.debug(2, "Sstate for %s is stale, removing related manifest %s" % (tid, manname)) 1334*4882a593Smuzhiyun toremove.append((manname, tid, tasks[tid])) 1335*4882a593Smuzhiyun break 1336*4882a593Smuzhiyun except ValueError: 1337*4882a593Smuzhiyun bb.fatal("Invalid line '%s' in sstate manifest '%s'" % (l, i)) 1338*4882a593Smuzhiyun 1339*4882a593Smuzhiyun if toremove: 1340*4882a593Smuzhiyun msg = "Removing %d stale sstate objects for arch %s" % (len(toremove), a) 1341*4882a593Smuzhiyun bb.event.fire(bb.event.ProcessStarted(msg, len(toremove)), d) 1342*4882a593Smuzhiyun 1343*4882a593Smuzhiyun removed = 0 1344*4882a593Smuzhiyun for (manname, tid, stamps) in toremove: 1345*4882a593Smuzhiyun sstate_clean_manifest(manname, d) 1346*4882a593Smuzhiyun for stamp in stamps: 1347*4882a593Smuzhiyun bb.utils.remove(stamp) 1348*4882a593Smuzhiyun removed = removed + 1 1349*4882a593Smuzhiyun bb.event.fire(bb.event.ProcessProgress(msg, removed), d) 1350*4882a593Smuzhiyun 1351*4882a593Smuzhiyun bb.event.fire(bb.event.ProcessFinished(msg), d) 1352*4882a593Smuzhiyun} 1353