diff options
Diffstat (limited to 'meta/classes/sstate.bbclass')
-rw-r--r-- | meta/classes/sstate.bbclass | 297 |
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 @@ | |||
1 | PSTAGE2_MANIFESTS = "${TMPDIR}/pstagelogs" | ||
2 | PSTAGE2_MANFILEPREFIX = "${PSTAGE2_MANIFESTS}/manifest-${PSTAGE2_PKGARCH}-${PN}" | ||
3 | |||
4 | |||
5 | PSTAGE2_PKGARCH = "${TARGET_ARCH}" | ||
6 | PSTAGE2_PKGVERSION = "${PV}-${PR}" | ||
7 | PSTAGE2_PKGPN = "${@bb.data.expand('staging-${PN}-${MULTIMACH_ARCH}${TARGET_VENDOR}-${TARGET_OS}', d).replace('_', '-')}" | ||
8 | |||
9 | PSTAGE2_PKGNAME = "${PSTAGE2_PKGPN}_${PSTAGE2_PKGVERSION}_${PSTAGE2_PKGARCH}" | ||
10 | PSTAGE2_EXTRAPATH ?= "" | ||
11 | PSTAGE2_PKGPATH = "${DISTRO}/${OELAYOUT_ABI}${PSTAGE2_EXTRAPATH}" | ||
12 | PSTAGE2_PKG = "${PSTAGE_DIR}2/${PSTAGE2_PKGPATH}/${PSTAGE2_PKGNAME}" | ||
13 | |||
14 | PSTAGE2_SCAN_CMD ?= "find ${PSTAGE2_BUILDDIR} \( -name "*.la" -o -name "*-config" \) -type f" | ||
15 | |||
16 | python () { | ||
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 | |||
41 | def sstate_init(name, d): | ||
42 | ss = {} | ||
43 | ss['name'] = name | ||
44 | ss['dirs'] = [] | ||
45 | ss['plaindirs'] = [] | ||
46 | ss['lockfiles'] = [] | ||
47 | return ss | ||
48 | |||
49 | def 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 | |||
70 | def sstate_add(ss, source, dest, d): | ||
71 | srcbase = os.path.basename(source) | ||
72 | ss['dirs'].append([srcbase, source, dest]) | ||
73 | return ss | ||
74 | |||
75 | def 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 | |||
116 | def 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 | |||
157 | def 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 | |||
177 | def 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 | |||
190 | python 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 | |||
203 | do_clean[postfuncs] += "sstate_cleanall" | ||
204 | do_clean[dirs] += "${PSTAGE2_MANIFESTS}" | ||
205 | |||
206 | def 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 | |||
235 | def 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 | |||
256 | def 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 | |||
262 | python sstate_task_prefunc () { | ||
263 | shared_state = sstate_state_fromvars(d) | ||
264 | sstate_clean(shared_state, d) | ||
265 | } | ||
266 | |||
267 | python 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 | # | ||
278 | sstate_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 | # | ||
293 | sstate_unpack_package () { | ||
294 | mkdir -p ${PSTAGE2_INSTDIR} | ||
295 | cd ${PSTAGE2_INSTDIR} | ||
296 | tar -xvzf ${PSTAGE2_PKG} | ||
297 | } | ||