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.bbclass297
1 files changed, 297 insertions, 0 deletions
diff --git a/meta/classes/sstate.bbclass b/meta/classes/sstate.bbclass
new file mode 100644
index 0000000000..6476257fc8
--- /dev/null
+++ b/meta/classes/sstate.bbclass
@@ -0,0 +1,297 @@
1PSTAGE2_MANIFESTS = "${TMPDIR}/pstagelogs"
2PSTAGE2_MANFILEPREFIX = "${PSTAGE2_MANIFESTS}/manifest-${PSTAGE2_PKGARCH}-${PN}"
3
4
5PSTAGE2_PKGARCH = "${TARGET_ARCH}"
6PSTAGE2_PKGVERSION = "${PV}-${PR}"
7PSTAGE2_PKGPN = "${@bb.data.expand('staging-${PN}-${MULTIMACH_ARCH}${TARGET_VENDOR}-${TARGET_OS}', d).replace('_', '-')}"
8
9PSTAGE2_PKGNAME = "${PSTAGE2_PKGPN}_${PSTAGE2_PKGVERSION}_${PSTAGE2_PKGARCH}"
10PSTAGE2_EXTRAPATH ?= ""
11PSTAGE2_PKGPATH = "${DISTRO}/${OELAYOUT_ABI}${PSTAGE2_EXTRAPATH}"
12PSTAGE2_PKG = "${PSTAGE_DIR}2/${PSTAGE2_PKGPATH}/${PSTAGE2_PKGNAME}"
13
14PSTAGE2_SCAN_CMD ?= "find ${PSTAGE2_BUILDDIR} \( -name "*.la" -o -name "*-config" \) -type f"
15
16python () {
17 if bb.data.inherits_class('native', d):
18 bb.data.setVar('PSTAGE2_PKGARCH', bb.data.getVar('BUILD_ARCH', d), d)
19 elif bb.data.inherits_class('cross', d) or bb.data.inherits_class('crosssdk', d):
20 bb.data.setVar('PSTAGE2_PKGARCH', bb.data.expand("${BUILD_ARCH}_${TARGET_ARCH}", d), d)
21 elif bb.data.inherits_class('nativesdk', d):
22 bb.data.setVar('PSTAGE2_PKGARCH', bb.data.expand("${SDK_ARCH}", d), d)
23 elif bb.data.inherits_class('cross-canadian', d):
24 bb.data.setVar('PSTAGE2_PKGARCH', bb.data.expand("${SDK_ARCH}_${TARGET_ARCH}", d), d)
25
26 # These classes encode staging paths into their scripts data so can only be
27 # reused if we manipulate the paths
28 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):
29 scan_cmd = "grep -Irl ${STAGING_DIR} ${PSTAGE2_BUILDDIR}"
30 bb.data.setVar('PSTAGE2_SCAN_CMD', scan_cmd, d)
31
32 for task in (bb.data.getVar('SSTATETASKS', d, True) or "").split():
33 funcs = bb.data.getVarFlag(task, 'prefuncs', d) or ""
34 funcs = "sstate_task_prefunc " + funcs
35 bb.data.setVarFlag(task, 'prefuncs', funcs, d)
36 funcs = bb.data.getVarFlag(task, 'postfuncs', d) or ""
37 funcs = "sstate_task_postfunc " + funcs
38 bb.data.setVarFlag(task, 'postfuncs', funcs, d)
39}
40
41def sstate_init(name, d):
42 ss = {}
43 ss['name'] = name
44 ss['dirs'] = []
45 ss['plaindirs'] = []
46 ss['lockfiles'] = []
47 return ss
48
49def sstate_state_fromvars(d):
50 task = bb.data.getVar('BB_CURRENTTASK', d, True)
51 if not task:
52 bb.fatal("sstate code running without task context?!")
53 task = task.replace("_setscene", "")
54
55 name = bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-name', d), d)
56 inputs = (bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-inputdirs', d) or "", d)).split()
57 outputs = (bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-outputdirs', d) or "", d)).split()
58 plaindirs = (bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-plaindirs', d) or "", d)).split()
59 lockfiles = (bb.data.expand(bb.data.getVarFlag("do_" + task, 'sstate-lockfile', d) or "", d)).split()
60 if not name or len(inputs) != len(outputs):
61 bb.fatal("sstate variables not setup correctly?!")
62
63 ss = sstate_init(name, d)
64 for i in range(len(inputs)):
65 sstate_add(ss, inputs[i], outputs[i], d)
66 ss['lockfiles'] = lockfiles
67 ss['plaindirs'] = plaindirs
68 return ss
69
70def sstate_add(ss, source, dest, d):
71 srcbase = os.path.basename(source)
72 ss['dirs'].append([srcbase, source, dest])
73 return ss
74
75def sstate_install(ss, d):
76 import oe.path
77
78 sharedfiles = []
79 shareddirs = []
80 bb.mkdirhier(bb.data.expand("${PSTAGE2_MANIFESTS}", d))
81 manifest = bb.data.expand("${PSTAGE2_MANFILEPREFIX}.%s" % ss['name'], d)
82
83 if os.access(manifest, os.R_OK):
84 bb.fatal("Package already staged (%s)?!" % manifest)
85
86 locks = []
87 for lock in ss['lockfiles']:
88 locks.append(bb.utils.lockfile(lock))
89
90 for state in ss['dirs']:
91 oe.path.copytree(state[1], state[2])
92 for walkroot, dirs, files in os.walk(state[1]):
93 for file in files:
94 srcpath = os.path.join(walkroot, file)
95 dstpath = srcpath.replace(state[1], state[2])
96 bb.debug(2, "Staging %s to %s" % (srcpath, dstpath))
97 sharedfiles.append(dstpath)
98 for dir in dirs:
99 dir = os.path.join(state[2], dir)
100 if not dir.endswith("/"):
101 dir = dir + "/"
102 shareddirs.append(dir)
103 f = open(manifest, "w")
104 for file in sharedfiles:
105 f.write(file + "\n")
106 # We want to ensure that directories appear at the end of the manifest
107 # so that when we test to see if they should be deleted any contents
108 # added by the task will have been removed first.
109 for dir in shareddirs:
110 f.write(dir + "\n")
111 f.close()
112
113 for lock in locks:
114 bb.utils.unlockfile(lock)
115
116def sstate_installpkg(ss, d):
117 import oe.path
118
119 pstageinst = bb.data.expand("${WORKDIR}/pstage-install-%s/" % ss['name'], d)
120 pstagepkg = bb.data.getVar('PSTAGE2_PKG', d, True) + '_' + ss['name'] + ".tgz"
121
122 if not os.path.exists(pstagepkg):
123 pstaging_fetch(pstagepkg, d)
124
125 if not os.path.isfile(pstagepkg):
126 bb.note("Staging package %s does not exist" % pstagepkg)
127 return False
128
129 sstate_clean(ss, d)
130
131 bb.data.setVar('PSTAGE2_INSTDIR', pstageinst, d)
132 bb.data.setVar('PSTAGE2_PKG', pstagepkg, d)
133 bb.build.exec_func('sstate_unpack_package', d)
134
135 # Fixup hardcoded paths
136 fixmefn = pstageinst + "fixmepath"
137 if os.path.isfile(fixmefn):
138 staging = bb.data.getVar('STAGING_DIR', d, True)
139 fixmefd = open(fixmefn, "r")
140 fixmefiles = fixmefd.readlines()
141 fixmefd.close()
142 for file in fixmefiles:
143 os.system("sed -i -e s:FIXMESTAGINGDIR:%s:g %s" % (staging, pstageinst + file))
144
145 for state in ss['dirs']:
146 if os.path.exists(state[1]):
147 oe.path.remove(state[1])
148 oe.path.copytree(pstageinst + state[0], state[1])
149 sstate_install(ss, d)
150
151 for plain in ss['plaindirs']:
152 bb.mkdirhier(pstageinst + plain)
153 oe.path.copytree(pstageinst + plain, bb.data.getVar('WORKDIR', d, True) + plain)
154
155 return True
156
157def sstate_clean_manifest(manifest, d):
158 import oe.path
159
160 if not os.path.exists(manifest):
161 return
162
163 mfile = open(manifest)
164 entries = mfile.readlines()
165 mfile.close()
166
167 for entry in entries:
168 entry = entry.strip()
169 if entry.endswith("/"):
170 if os.path.exists(entry) and len(os.listdir(entry)) == 0:
171 os.rmdir(entry)
172 else:
173 oe.path.remove(entry)
174
175 oe.path.remove(manifest)
176
177def sstate_clean(ss, d):
178
179 manifest = bb.data.expand("${PSTAGE2_MANFILEPREFIX}.%s" % ss['name'], d)
180
181 locks = []
182 for lock in ss['lockfiles']:
183 locks.append(bb.utils.lockfile(lock))
184
185 sstate_clean_manifest(manifest, d)
186
187 for lock in locks:
188 bb.utils.unlockfile(lock)
189
190python sstate_cleanall() {
191 import fnmatch
192
193 bb.note("Removing %s from staging" % bb.data.getVar('PN', d, True))
194
195 manifest_dir = bb.data.getVar('PSTAGE2_MANIFESTS', d, True)
196 manifest_pattern = bb.data.expand("manifest-${PN}.*", d)
197
198 for manifest in (os.listdir(manifest_dir)):
199 if fnmatch.fnmatch(manifest, manifest_pattern):
200 sstate_clean_manifest(manifest_dir + "/" + manifest, d)
201}
202
203do_clean[postfuncs] += "sstate_cleanall"
204do_clean[dirs] += "${PSTAGE2_MANIFESTS}"
205
206def sstate_package(ss, d):
207 import oe.path
208
209 pstagebuild = bb.data.expand("${WORKDIR}/pstage-build-%s/" % ss['name'], d)
210 pstagepkg = bb.data.getVar('PSTAGE2_PKG', d, True) + '_'+ ss['name'] + ".tgz"
211 bb.mkdirhier(pstagebuild)
212 bb.mkdirhier(os.path.dirname(pstagepkg))
213 for state in ss['dirs']:
214 srcbase = state[0].rstrip("/").rsplit('/', 1)[0]
215 oe.path.copytree(state[1], pstagebuild + state[0])
216 for walkroot, dirs, files in os.walk(state[1]):
217 for file in files:
218 srcpath = os.path.join(walkroot, file)
219 dstpath = srcpath.replace(state[1], pstagebuild + state[0])
220 bb.debug(2, "Preparing %s for packaging at %s" % (srcpath, dstpath))
221
222 workdir = bb.data.getVar('WORKDIR', d, True)
223 for plain in ss['plaindirs']:
224 pdir = plain.replace(workdir, pstagebuild)
225 bb.mkdirhier(plain)
226 bb.mkdirhier(pdir)
227 oe.path.copytree(plain, pdir)
228
229 bb.data.setVar('PSTAGE2_BUILDDIR', pstagebuild, d)
230 bb.data.setVar('PSTAGE2_PKG', pstagepkg, d)
231 bb.build.exec_func('sstate_create_package', d)
232
233 return
234
235def pstaging_fetch(pstagepkg, d):
236 import bb.fetch
237
238 # only try and fetch if the user has configured a mirror
239 if bb.data.getVar('PSTAGE_MIRROR', d) != "":
240 # Copy the data object and override DL_DIR and SRC_URI
241 pd = d.createCopy()
242 dldir = bb.data.expand("${PSTAGE_DIR}/${PSTAGE_PKGPATH}", pd)
243 mirror = bb.data.expand("${PSTAGE_MIRROR}/${PSTAGE_PKGPATH}/", pd)
244 srcuri = mirror + os.path.basename(pstagepkg)
245 bb.data.setVar('DL_DIR', dldir, pd)
246 bb.data.setVar('SRC_URI', srcuri, pd)
247
248 # Try a fetch from the pstage mirror, if it fails just return and
249 # we will build the package
250 try:
251 bb.fetch.init([srcuri], pd)
252 bb.fetch.go(pd, [srcuri])
253 except:
254 return
255
256def sstate_setscene(d):
257 shared_state = sstate_state_fromvars(d)
258 accelerate = sstate_installpkg(shared_state, d)
259 if not accelerate:
260 raise bb.build.FuncFailed("No suitable staging package found")
261
262python sstate_task_prefunc () {
263 shared_state = sstate_state_fromvars(d)
264 sstate_clean(shared_state, d)
265}
266
267python sstate_task_postfunc () {
268 shared_state = sstate_state_fromvars(d)
269 sstate_install(shared_state, d)
270 sstate_package(shared_state, d)
271}
272
273
274#
275# Shell function to generate a pstage package from a directory
276# set as PSTAGE2_BUILDDIR
277#
278sstate_create_package () {
279 # Need to remove hardcoded paths and fix these when we install the
280 # staging packages.
281 for i in `${PSTAGE2_SCAN_CMD}` ; do \
282 sed -i -e s:${STAGING_DIR}:FIXMESTAGINGDIR:g $i
283 echo $i | sed -e 's:${PSTAGE2_BUILDDIR}::' >> ${PSTAGE2_BUILDDIR}fixmepath
284 done
285
286 cd ${PSTAGE2_BUILDDIR}
287 tar -cvzf ${PSTAGE2_PKG} *
288}
289
290#
291# Shell function to decompress and prepare a package for installation
292#
293sstate_unpack_package () {
294 mkdir -p ${PSTAGE2_INSTDIR}
295 cd ${PSTAGE2_INSTDIR}
296 tar -xvzf ${PSTAGE2_PKG}
297}