PSTAGE2_MANIFESTS = "${TMPDIR}/pstagelogs" PSTAGE2_MANFILEPREFIX = "${PSTAGE2_MANIFESTS}/manifest-${PSTAGE2_PKGARCH}-${PN}" PSTAGE2_PKGARCH = "${BASE_PACKAGE_ARCH}" PSTAGE2_PKGVERSION = "${PV}-${PR}" PSTAGE2_PKGPN = "${@bb.data.expand('staging-${PN}-${MULTIMACH_ARCH}${TARGET_VENDOR}-${TARGET_OS}', d).replace('_', '-')}" PSTAGE2_PKGNAME = "${PSTAGE2_PKGPN}_${PSTAGE2_PKGVERSION}_${PSTAGE2_PKGARCH}" PSTAGE2_EXTRAPATH ?= "" PSTAGE2_PKGPATH = "${DISTRO}/${OELAYOUT_ABI}${PSTAGE2_EXTRAPATH}" PSTAGE2_PKG = "${PSTAGE_DIR}2/${PSTAGE2_PKGPATH}/${PSTAGE2_PKGNAME}" PSTAGE2_SCAN_CMD ?= "find ${PSTAGE2_BUILDDIR} \( -name "*.la" -o -name "*-config" \) -type f" python () { if bb.data.inherits_class('native', d): bb.data.setVar('PSTAGE2_PKGARCH', bb.data.getVar('BUILD_ARCH', d), d) elif bb.data.inherits_class('cross', d) or bb.data.inherits_class('crosssdk', d): bb.data.setVar('PSTAGE2_PKGARCH', bb.data.expand("${BUILD_ARCH}_${BASE_PACKAGE_ARCH}", d), d) elif bb.data.inherits_class('nativesdk', d): bb.data.setVar('PSTAGE2_PKGARCH', bb.data.expand("${SDK_ARCH}", d), d) elif bb.data.inherits_class('cross-canadian', d): bb.data.setVar('PSTAGE2_PKGARCH', bb.data.expand("${SDK_ARCH}_${BASE_PACKAGE_ARCH}", d), d) # These classes encode staging paths into their scripts data so can only be # reused if we manipulate the paths 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): scan_cmd = "grep -Irl ${STAGING_DIR} ${PSTAGE2_BUILDDIR}" bb.data.setVar('PSTAGE2_SCAN_CMD', scan_cmd, d) for task in (bb.data.getVar('SSTATETASKS', d, True) or "").split(): funcs = bb.data.getVarFlag(task, 'prefuncs', d) or "" funcs = "sstate_task_prefunc " + funcs bb.data.setVarFlag(task, 'prefuncs', funcs, d) funcs = bb.data.getVarFlag(task, 'postfuncs', d) or "" funcs = "sstate_task_postfunc " + funcs bb.data.setVarFlag(task, 'postfuncs', funcs, d) } def sstate_init(name, d): ss = {} ss['name'] = name ss['dirs'] = [] ss['plaindirs'] = [] ss['lockfiles'] = [] return ss def sstate_state_fromvars(d): task = bb.data.getVar('BB_CURRENTTASK', d, True) if not task: bb.fatal("sstate code running without task context?!") task = task.replace("_setscene", "") name = bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-name', d), d) inputs = (bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-inputdirs', d) or "", d)).split() outputs = (bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-outputdirs', d) or "", d)).split() plaindirs = (bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-plaindirs', d) or "", d)).split() lockfiles = (bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-lockfile', d) or "", d)).split() if not name or len(inputs) != len(outputs): bb.fatal("sstate variables not setup correctly?!") ss = sstate_init(name, d) for i in range(len(inputs)): sstate_add(ss, inputs[i], outputs[i], d) ss['lockfiles'] = lockfiles ss['plaindirs'] = plaindirs return ss def sstate_add(ss, source, dest, d): srcbase = os.path.basename(source) ss['dirs'].append([srcbase, source, dest]) return ss def sstate_install(ss, d): import oe.path sharedfiles = [] shareddirs = [] bb.mkdirhier(bb.data.expand("${PSTAGE2_MANIFESTS}", d)) manifest = bb.data.expand("${PSTAGE2_MANFILEPREFIX}.%s" % ss['name'], d) if os.access(manifest, os.R_OK): bb.fatal("Package already staged (%s)?!" % manifest) locks = [] for lock in ss['lockfiles']: locks.append(bb.utils.lockfile(lock)) for state in ss['dirs']: oe.path.copytree(state[1], state[2]) for walkroot, dirs, files in os.walk(state[1]): for file in files: srcpath = os.path.join(walkroot, file) dstpath = srcpath.replace(state[1], state[2]) bb.debug(2, "Staging %s to %s" % (srcpath, dstpath)) sharedfiles.append(dstpath) for dir in dirs: srcdir = os.path.join(walkroot, dir) dstdir = srcdir.replace(state[1], state[2]) bb.debug(2, "Staging %s to %s" % (srcdir, dstdir)) if not dstdir.endswith("/"): dstdir = dstdir + "/" shareddirs.append(dstdir) f = open(manifest, "w") for file in sharedfiles: f.write(file + "\n") # We want to ensure that directories appear at the end of the manifest # so that when we test to see if they should be deleted any contents # added by the task will have been removed first. for dir in shareddirs: f.write(dir + "\n") f.close() for lock in locks: bb.utils.unlockfile(lock) def sstate_installpkg(ss, d): import oe.path pstageinst = bb.data.expand("${WORKDIR}/pstage-install-%s/" % ss['name'], d) pstagepkg = bb.data.getVar('PSTAGE2_PKG', d, True) + '_' + ss['name'] + ".tgz" if not os.path.exists(pstagepkg): pstaging_fetch(pstagepkg, d) if not os.path.isfile(pstagepkg): bb.note("Staging package %s does not exist" % pstagepkg) return False sstate_clean(ss, d) bb.data.setVar('PSTAGE2_INSTDIR', pstageinst, d) bb.data.setVar('PSTAGE2_PKG', pstagepkg, d) bb.build.exec_func('sstate_unpack_package', d) # Fixup hardcoded paths fixmefn = pstageinst + "fixmepath" if os.path.isfile(fixmefn): staging = bb.data.getVar('STAGING_DIR', d, True) fixmefd = open(fixmefn, "r") fixmefiles = fixmefd.readlines() fixmefd.close() for file in fixmefiles: os.system("sed -i -e s:FIXMESTAGINGDIR:%s:g %s" % (staging, pstageinst + file)) for state in ss['dirs']: if os.path.exists(state[1]): oe.path.remove(state[1]) oe.path.copytree(pstageinst + state[0], state[1]) sstate_install(ss, d) for plain in ss['plaindirs']: bb.mkdirhier(pstageinst + plain) oe.path.copytree(pstageinst + plain, bb.data.getVar('WORKDIR', d, True) + plain) return True def sstate_clean_manifest(manifest, d): import oe.path if not os.path.exists(manifest): return mfile = open(manifest) entries = mfile.readlines() mfile.close() for entry in entries: entry = entry.strip() bb.debug(2, "Removing manifest: %s" % entry) if entry.endswith("/"): if os.path.islink(entry[:-1]): os.remove(entry[:-1]) elif os.path.exists(entry) and len(os.listdir(entry)) == 0: os.rmdir(entry[:-1]) else: oe.path.remove(entry) oe.path.remove(manifest) def sstate_clean(ss, d): manifest = bb.data.expand("${PSTAGE2_MANFILEPREFIX}.%s" % ss['name'], d) locks = [] for lock in ss['lockfiles']: locks.append(bb.utils.lockfile(lock)) sstate_clean_manifest(manifest, d) for lock in locks: bb.utils.unlockfile(lock) SCENEFUNCS += "sstate_cleanall" CLEANFUNCS += "sstate_cleanall" python sstate_cleanall() { import fnmatch bb.note("Removing shared state for package %s" % bb.data.getVar('PN', d, True)) manifest_dir = bb.data.getVar('PSTAGE2_MANIFESTS', d, True) manifest_prefix = bb.data.getVar("PSTAGE2_MANFILEPREFIX", d, True) manifest_pattern = os.path.basename(manifest_prefix) + ".*" if not os.path.exists(manifest_dir): return for manifest in (os.listdir(manifest_dir)): if fnmatch.fnmatch(manifest, manifest_pattern): sstate_clean_manifest(manifest_dir + "/" + manifest, d) } def sstate_package(ss, d): import oe.path pstagebuild = bb.data.expand("${WORKDIR}/pstage-build-%s/" % ss['name'], d) pstagepkg = bb.data.getVar('PSTAGE2_PKG', d, True) + '_'+ ss['name'] + ".tgz" bb.mkdirhier(pstagebuild) bb.mkdirhier(os.path.dirname(pstagepkg)) for state in ss['dirs']: srcbase = state[0].rstrip("/").rsplit('/', 1)[0] oe.path.copytree(state[1], pstagebuild + state[0]) for walkroot, dirs, files in os.walk(state[1]): for file in files: srcpath = os.path.join(walkroot, file) dstpath = srcpath.replace(state[1], pstagebuild + state[0]) bb.debug(2, "Preparing %s for packaging at %s" % (srcpath, dstpath)) workdir = bb.data.getVar('WORKDIR', d, True) for plain in ss['plaindirs']: pdir = plain.replace(workdir, pstagebuild) bb.mkdirhier(plain) bb.mkdirhier(pdir) oe.path.copytree(plain, pdir) bb.data.setVar('PSTAGE2_BUILDDIR', pstagebuild, d) bb.data.setVar('PSTAGE2_PKG', pstagepkg, d) bb.build.exec_func('sstate_create_package', d) return def pstaging_fetch(pstagepkg, d): import bb.fetch # only try and fetch if the user has configured a mirror if bb.data.getVar('PSTAGE_MIRROR', d) != "": # Copy the data object and override DL_DIR and SRC_URI pd = d.createCopy() dldir = bb.data.expand("${PSTAGE_DIR}/${PSTAGE_PKGPATH}", pd) mirror = bb.data.expand("${PSTAGE_MIRROR}/${PSTAGE_PKGPATH}/", pd) srcuri = mirror + os.path.basename(pstagepkg) bb.data.setVar('DL_DIR', dldir, pd) bb.data.setVar('SRC_URI', srcuri, pd) # Try a fetch from the pstage mirror, if it fails just return and # we will build the package try: bb.fetch.init([srcuri], pd) bb.fetch.go(pd, [srcuri]) except: return def sstate_setscene(d): shared_state = sstate_state_fromvars(d) accelerate = sstate_installpkg(shared_state, d) if not accelerate: raise bb.build.FuncFailed("No suitable staging package found") python sstate_task_prefunc () { shared_state = sstate_state_fromvars(d) sstate_clean(shared_state, d) } python sstate_task_postfunc () { shared_state = sstate_state_fromvars(d) sstate_install(shared_state, d) sstate_package(shared_state, d) } # # Shell function to generate a pstage package from a directory # set as PSTAGE2_BUILDDIR # sstate_create_package () { # Need to remove hardcoded paths and fix these when we install the # staging packages. for i in `${PSTAGE2_SCAN_CMD}` ; do \ sed -i -e s:${STAGING_DIR}:FIXMESTAGINGDIR:g $i echo $i | sed -e 's:${PSTAGE2_BUILDDIR}::' >> ${PSTAGE2_BUILDDIR}fixmepath done cd ${PSTAGE2_BUILDDIR} tar -cvzf ${PSTAGE2_PKG} * } # # Shell function to decompress and prepare a package for installation # sstate_unpack_package () { mkdir -p ${PSTAGE2_INSTDIR} cd ${PSTAGE2_INSTDIR} tar -xvzf ${PSTAGE2_PKG} }