blob: 2f3b278fb3495630e05d3d275aa82ac2d7db5657 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# This bbclass is used for creating archive for:
5# 1) original (or unpacked) source: ARCHIVER_MODE[src] = "original"
6# 2) patched source: ARCHIVER_MODE[src] = "patched" (default)
7# 3) configured source: ARCHIVER_MODE[src] = "configured"
8# 4) The patches between do_unpack and do_patch:
9# ARCHIVER_MODE[diff] = "1"
10# And you can set the one that you'd like to exclude from the diff:
11# ARCHIVER_MODE[diff-exclude] ?= ".pc autom4te.cache patches"
12# 5) The environment data, similar to 'bitbake -e recipe':
13# ARCHIVER_MODE[dumpdata] = "1"
14# 6) The recipe (.bb and .inc): ARCHIVER_MODE[recipe] = "1"
15# 7) Whether output the .src.rpm package:
16# ARCHIVER_MODE[srpm] = "1"
17# 8) Filter the license, the recipe whose license in
18# COPYLEFT_LICENSE_INCLUDE will be included, and in
19# COPYLEFT_LICENSE_EXCLUDE will be excluded.
20# COPYLEFT_LICENSE_INCLUDE = 'GPL* LGPL*'
21# COPYLEFT_LICENSE_EXCLUDE = 'CLOSED Proprietary'
22# 9) The recipe type that will be archived:
23# COPYLEFT_RECIPE_TYPES = 'target'
24#
25
26# Don't filter the license by default
27COPYLEFT_LICENSE_INCLUDE ?= ''
28COPYLEFT_LICENSE_EXCLUDE ?= ''
29# Create archive for all the recipe types
30COPYLEFT_RECIPE_TYPES ?= 'target native nativesdk cross crosssdk cross-canadian'
31inherit copyleft_filter
32
33ARCHIVER_MODE[srpm] ?= "0"
34ARCHIVER_MODE[src] ?= "patched"
35ARCHIVER_MODE[diff] ?= "0"
36ARCHIVER_MODE[diff-exclude] ?= ".pc autom4te.cache patches"
37ARCHIVER_MODE[dumpdata] ?= "0"
38ARCHIVER_MODE[recipe] ?= "0"
39
40DEPLOY_DIR_SRC ?= "${DEPLOY_DIR}/sources"
41ARCHIVER_TOPDIR ?= "${WORKDIR}/deploy-sources"
42ARCHIVER_OUTDIR = "${ARCHIVER_TOPDIR}/${TARGET_SYS}/${PF}/"
43ARCHIVER_WORKDIR = "${WORKDIR}/archiver-work/"
44
45do_dumpdata[dirs] = "${ARCHIVER_OUTDIR}"
46do_ar_recipe[dirs] = "${ARCHIVER_OUTDIR}"
47do_ar_original[dirs] = "${ARCHIVER_OUTDIR} ${ARCHIVER_WORKDIR}"
48do_deploy_archives[dirs] = "${WORKDIR}"
49do_deploy_all_archives[dirs] = "${WORKDIR}"
50
51# This is a convenience for the shell script to use it
52
53
54python () {
55 pn = d.getVar('PN', True)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050056 assume_provided = (d.getVar("ASSUME_PROVIDED", True) or "").split()
57 if pn in assume_provided:
58 for p in d.getVar("PROVIDES", True).split():
59 if p != pn:
60 pn = p
61 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -050062
63 included, reason = copyleft_should_include(d)
64 if not included:
65 bb.debug(1, 'archiver: %s is excluded: %s' % (pn, reason))
66 return
67 else:
68 bb.debug(1, 'archiver: %s is included: %s' % (pn, reason))
69
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050070 # We just archive gcc-source for all the gcc related recipes
71 if d.getVar('BPN', True) in ['gcc', 'libgcc'] \
72 and not pn.startswith('gcc-source'):
73 bb.debug(1, 'archiver: %s is excluded, covered by gcc-source' % pn)
74 return
75
Patrick Williamsc124f4f2015-09-15 14:41:29 -050076 ar_src = d.getVarFlag('ARCHIVER_MODE', 'src', True)
77 ar_dumpdata = d.getVarFlag('ARCHIVER_MODE', 'dumpdata', True)
78 ar_recipe = d.getVarFlag('ARCHIVER_MODE', 'recipe', True)
79
80 if ar_src == "original":
81 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_ar_original' % pn)
82 elif ar_src == "patched":
83 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_ar_patched' % pn)
84 elif ar_src == "configured":
85 # We can't use "addtask do_ar_configured after do_configure" since it
86 # will cause the deptask of do_populate_sysroot to run not matter what
87 # archives we need, so we add the depends here.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050088
89 # There is a corner case with "gcc-source-${PV}" recipes, they don't have
90 # the "do_configure" task, so we need to use "do_preconfigure"
91 if pn.startswith("gcc-source-"):
92 d.appendVarFlag('do_ar_configured', 'depends', ' %s:do_preconfigure' % pn)
93 else:
94 d.appendVarFlag('do_ar_configured', 'depends', ' %s:do_configure' % pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050095 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_ar_configured' % pn)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050096
Patrick Williamsc124f4f2015-09-15 14:41:29 -050097 elif ar_src:
98 bb.fatal("Invalid ARCHIVER_MODE[src]: %s" % ar_src)
99
100 if ar_dumpdata == "1":
101 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_dumpdata' % pn)
102
103 if ar_recipe == "1":
104 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_ar_recipe' % pn)
105
106 # Output the srpm package
107 ar_srpm = d.getVarFlag('ARCHIVER_MODE', 'srpm', True)
108 if ar_srpm == "1":
109 if d.getVar('PACKAGES', True) != '' and d.getVar('IMAGE_PKGTYPE', True) == 'rpm':
110 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_package_write_rpm' % pn)
111 if ar_dumpdata == "1":
112 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_dumpdata' % pn)
113 if ar_recipe == "1":
114 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_ar_recipe' % pn)
115 if ar_src == "original":
116 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_ar_original' % pn)
117 elif ar_src == "patched":
118 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_ar_patched' % pn)
119 elif ar_src == "configured":
120 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_ar_configured' % pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500121}
122
123# Take all the sources for a recipe and puts them in WORKDIR/archiver-work/.
124# Files in SRC_URI are copied directly, anything that's a directory
125# (e.g. git repositories) is "unpacked" and then put into a tarball.
126python do_ar_original() {
127
128 import shutil, tarfile, tempfile
129
130 if d.getVarFlag('ARCHIVER_MODE', 'src', True) != "original":
131 return
132
133 ar_outdir = d.getVar('ARCHIVER_OUTDIR', True)
134 bb.note('Archiving the original source...')
135 fetch = bb.fetch2.Fetch([], d)
136 for url in fetch.urls:
137 local = fetch.localpath(url).rstrip("/");
138 if os.path.isfile(local):
139 shutil.copy(local, ar_outdir)
140 elif os.path.isdir(local):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141 tmpdir = tempfile.mkdtemp(dir=d.getVar('ARCHIVER_WORKDIR', True))
142 fetch.unpack(tmpdir, (url,))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500143 create_tarball(d, tmpdir + '/.', '', ar_outdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144
145 # Emit patch series files for 'original'
146 bb.note('Writing patch series files...')
147 for patch in src_patches(d):
148 _, _, local, _, _, parm = bb.fetch.decodeurl(patch)
149 patchdir = parm.get('patchdir')
150 if patchdir:
151 series = os.path.join(ar_outdir, 'series.subdir.%s' % patchdir.replace('/', '_'))
152 else:
153 series = os.path.join(ar_outdir, 'series')
154
155 with open(series, 'a') as s:
156 s.write('%s -p%s\n' % (os.path.basename(local), parm['striplevel']))
157}
158
159python do_ar_patched() {
160
161 if d.getVarFlag('ARCHIVER_MODE', 'src', True) != 'patched':
162 return
163
164 # Get the ARCHIVER_OUTDIR before we reset the WORKDIR
165 ar_outdir = d.getVar('ARCHIVER_OUTDIR', True)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500166 ar_workdir = d.getVar('ARCHIVER_WORKDIR', True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500167 bb.note('Archiving the patched source...')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500168 d.setVar('WORKDIR', ar_workdir)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500169 create_tarball(d, d.getVar('S', True), 'patched', ar_outdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500170}
171
172python do_ar_configured() {
173 import shutil
174
175 ar_outdir = d.getVar('ARCHIVER_OUTDIR', True)
176 if d.getVarFlag('ARCHIVER_MODE', 'src', True) == 'configured':
177 bb.note('Archiving the configured source...')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500178 pn = d.getVar('PN', True)
179 # "gcc-source-${PV}" recipes don't have "do_configure"
180 # task, so we need to run "do_preconfigure" instead
181 if pn.startswith("gcc-source-"):
182 d.setVar('WORKDIR', d.getVar('ARCHIVER_WORKDIR', True))
183 bb.build.exec_func('do_preconfigure', d)
184
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500185 # The libtool-native's do_configure will remove the
186 # ${STAGING_DATADIR}/aclocal/libtool.m4, so we can't re-run the
187 # do_configure, we archive the already configured ${S} to
188 # instead of.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500189 elif pn != 'libtool-native':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500190 # Change the WORKDIR to make do_configure run in another dir.
191 d.setVar('WORKDIR', d.getVar('ARCHIVER_WORKDIR', True))
192 if bb.data.inherits_class('kernel-yocto', d):
193 bb.build.exec_func('do_kernel_configme', d)
194 if bb.data.inherits_class('cmake', d):
195 bb.build.exec_func('do_generate_toolchain_file', d)
196 prefuncs = d.getVarFlag('do_configure', 'prefuncs', True)
197 for func in (prefuncs or '').split():
198 if func != "sysroot_cleansstate":
199 bb.build.exec_func(func, d)
200 bb.build.exec_func('do_configure', d)
201 postfuncs = d.getVarFlag('do_configure', 'postfuncs', True)
202 for func in (postfuncs or '').split():
203 if func != "do_qa_configure":
204 bb.build.exec_func(func, d)
205 srcdir = d.getVar('S', True)
206 builddir = d.getVar('B', True)
207 if srcdir != builddir:
208 if os.path.exists(builddir):
209 oe.path.copytree(builddir, os.path.join(srcdir, \
210 'build.%s.ar_configured' % d.getVar('PF', True)))
211 create_tarball(d, srcdir, 'configured', ar_outdir)
212}
213
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500214def create_tarball(d, srcdir, suffix, ar_outdir):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500215 """
216 create the tarball from srcdir
217 """
218 import tarfile
219
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500220 # Make sure we are only creating a single tarball for gcc sources
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500221 if (d.getVar('SRC_URI', True) == ""):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500222 return
223
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500224 bb.utils.mkdirhier(ar_outdir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500225 if suffix:
226 filename = '%s-%s.tar.gz' % (d.getVar('PF', True), suffix)
227 else:
228 filename = '%s.tar.gz' % d.getVar('PF', True)
229 tarname = os.path.join(ar_outdir, filename)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500230
231 srcdir = srcdir.rstrip('/')
232 dirname = os.path.dirname(srcdir)
233 basename = os.path.basename(srcdir)
234 os.chdir(dirname)
235 bb.note('Creating %s' % tarname)
236 tar = tarfile.open(tarname, 'w:gz')
237 tar.add(basename)
238 tar.close()
239
240# creating .diff.gz between source.orig and source
241def create_diff_gz(d, src_orig, src, ar_outdir):
242
243 import subprocess
244
245 if not os.path.isdir(src) or not os.path.isdir(src_orig):
246 return
247
248 # The diff --exclude can't exclude the file with path, so we copy
249 # the patched source, and remove the files that we'd like to
250 # exclude.
251 src_patched = src + '.patched'
252 oe.path.copyhardlinktree(src, src_patched)
253 for i in d.getVarFlag('ARCHIVER_MODE', 'diff-exclude', True).split():
254 bb.utils.remove(os.path.join(src_orig, i), recurse=True)
255 bb.utils.remove(os.path.join(src_patched, i), recurse=True)
256
257 dirname = os.path.dirname(src)
258 basename = os.path.basename(src)
259 os.chdir(dirname)
260 out_file = os.path.join(ar_outdir, '%s-diff.gz' % d.getVar('PF', True))
261 diff_cmd = 'diff -Naur %s.orig %s.patched | gzip -c > %s' % (basename, basename, out_file)
262 subprocess.call(diff_cmd, shell=True)
263 bb.utils.remove(src_patched, recurse=True)
264
265# Run do_unpack and do_patch
266python do_unpack_and_patch() {
267 if d.getVarFlag('ARCHIVER_MODE', 'src', True) not in \
268 [ 'patched', 'configured'] and \
269 d.getVarFlag('ARCHIVER_MODE', 'diff', True) != '1':
270 return
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500271 ar_outdir = d.getVar('ARCHIVER_OUTDIR', True)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500272 ar_workdir = d.getVar('ARCHIVER_WORKDIR', True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500273
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500274 # The kernel class functions require it to be on work-shared, so we dont change WORKDIR
275 if not bb.data.inherits_class('kernel-yocto', d):
276 # Change the WORKDIR to make do_unpack do_patch run in another dir.
277 d.setVar('WORKDIR', ar_workdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500278
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500279 # The changed 'WORKDIR' also caused 'B' changed, create dir 'B' for the
280 # possibly requiring of the following tasks (such as some recipes's
281 # do_patch required 'B' existed).
282 bb.utils.mkdirhier(d.getVar('B', True))
283
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500284 bb.build.exec_func('do_unpack', d)
285
286 # Save the original source for creating the patches
287 if d.getVarFlag('ARCHIVER_MODE', 'diff', True) == '1':
288 src = d.getVar('S', True).rstrip('/')
289 src_orig = '%s.orig' % src
290 oe.path.copytree(src, src_orig)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500291
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500292 # Make sure gcc and kernel sources are patched only once
293 if not ((d.getVar('SRC_URI', True) == "" or bb.data.inherits_class('kernel-yocto', d))):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500294 bb.build.exec_func('do_patch', d)
295
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500296 # Create the patches
297 if d.getVarFlag('ARCHIVER_MODE', 'diff', True) == '1':
298 bb.note('Creating diff gz...')
299 create_diff_gz(d, src_orig, src, ar_outdir)
300 bb.utils.remove(src_orig, recurse=True)
301}
302
303python do_ar_recipe () {
304 """
305 archive the recipe, including .bb and .inc.
306 """
307 import re
308 import shutil
309
310 require_re = re.compile( r"require\s+(.+)" )
311 include_re = re.compile( r"include\s+(.+)" )
312 bbfile = d.getVar('FILE', True)
313 outdir = os.path.join(d.getVar('WORKDIR', True), \
314 '%s-recipe' % d.getVar('PF', True))
315 bb.utils.mkdirhier(outdir)
316 shutil.copy(bbfile, outdir)
317
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500318 pn = d.getVar('PN', True)
319 bbappend_files = d.getVar('BBINCLUDED', True).split()
320 # If recipe name is aa, we need to match files like aa.bbappend and aa_1.1.bbappend
321 # Files like aa1.bbappend or aa1_1.1.bbappend must be excluded.
322 bbappend_re = re.compile( r".*/%s_[^/]*\.bbappend$" %pn)
323 bbappend_re1 = re.compile( r".*/%s\.bbappend$" %pn)
324 for file in bbappend_files:
325 if bbappend_re.match(file) or bbappend_re1.match(file):
326 shutil.copy(file, outdir)
327
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500328 dirname = os.path.dirname(bbfile)
329 bbpath = '%s:%s' % (dirname, d.getVar('BBPATH', True))
330 f = open(bbfile, 'r')
331 for line in f.readlines():
332 incfile = None
333 if require_re.match(line):
334 incfile = require_re.match(line).group(1)
335 elif include_re.match(line):
336 incfile = include_re.match(line).group(1)
337 if incfile:
338 incfile = bb.data.expand(incfile, d)
339 incfile = bb.utils.which(bbpath, incfile)
340 if incfile:
341 shutil.copy(incfile, outdir)
342
343 create_tarball(d, outdir, 'recipe', d.getVar('ARCHIVER_OUTDIR', True))
344 bb.utils.remove(outdir, recurse=True)
345}
346
347python do_dumpdata () {
348 """
349 dump environment data to ${PF}-showdata.dump
350 """
351
352 dumpfile = os.path.join(d.getVar('ARCHIVER_OUTDIR', True), \
353 '%s-showdata.dump' % d.getVar('PF', True))
354 bb.note('Dumping metadata into %s' % dumpfile)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500355 with open(dumpfile, "w") as f:
356 # emit variables and shell functions
357 bb.data.emit_env(f, d, True)
358 # emit the metadata which isn't valid shell
359 for e in d.keys():
360 if d.getVarFlag(e, "python", False):
361 f.write("\npython %s () {\n%s}\n" % (e, d.getVar(e, False)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500362}
363
364SSTATETASKS += "do_deploy_archives"
365do_deploy_archives () {
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500366 echo "Deploying source archive files from ${ARCHIVER_TOPDIR} to ${DEPLOY_DIR_SRC}."
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500367}
368python do_deploy_archives_setscene () {
369 sstate_setscene(d)
370}
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500371do_deploy_archives[dirs] = "${ARCHIVER_TOPDIR}"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500372do_deploy_archives[sstate-inputdirs] = "${ARCHIVER_TOPDIR}"
373do_deploy_archives[sstate-outputdirs] = "${DEPLOY_DIR_SRC}"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500374addtask do_deploy_archives_setscene
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500375
376addtask do_ar_original after do_unpack
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500377addtask do_unpack_and_patch after do_patch
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500378addtask do_ar_patched after do_unpack_and_patch
379addtask do_ar_configured after do_unpack_and_patch
380addtask do_dumpdata
381addtask do_ar_recipe
382addtask do_deploy_archives before do_build
383
384addtask do_deploy_all_archives after do_deploy_archives
385do_deploy_all_archives[recrdeptask] = "do_deploy_archives"
386do_deploy_all_archives[recideptask] = "do_${BB_DEFAULT_TASK}"
387do_deploy_all_archives() {
388 :
389}
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500390
391python () {
392 # Add tasks in the correct order, specifically for linux-yocto to avoid race condition
393 if bb.data.inherits_class('kernel-yocto', d):
394 bb.build.addtask('do_kernel_configme', 'do_configure', 'do_unpack_and_patch', d)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500395}