blob: 41a552c76bde7f3fcaf827538e8c991c18ec4cef [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)
56
57 included, reason = copyleft_should_include(d)
58 if not included:
59 bb.debug(1, 'archiver: %s is excluded: %s' % (pn, reason))
60 return
61 else:
62 bb.debug(1, 'archiver: %s is included: %s' % (pn, reason))
63
64 ar_src = d.getVarFlag('ARCHIVER_MODE', 'src', True)
65 ar_dumpdata = d.getVarFlag('ARCHIVER_MODE', 'dumpdata', True)
66 ar_recipe = d.getVarFlag('ARCHIVER_MODE', 'recipe', True)
67
68 if ar_src == "original":
69 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_ar_original' % pn)
70 elif ar_src == "patched":
71 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_ar_patched' % pn)
72 elif ar_src == "configured":
73 # We can't use "addtask do_ar_configured after do_configure" since it
74 # will cause the deptask of do_populate_sysroot to run not matter what
75 # archives we need, so we add the depends here.
76 d.appendVarFlag('do_ar_configured', 'depends', ' %s:do_configure' % pn)
77 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_ar_configured' % pn)
78 elif ar_src:
79 bb.fatal("Invalid ARCHIVER_MODE[src]: %s" % ar_src)
80
81 if ar_dumpdata == "1":
82 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_dumpdata' % pn)
83
84 if ar_recipe == "1":
85 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_ar_recipe' % pn)
86
87 # Output the srpm package
88 ar_srpm = d.getVarFlag('ARCHIVER_MODE', 'srpm', True)
89 if ar_srpm == "1":
90 if d.getVar('PACKAGES', True) != '' and d.getVar('IMAGE_PKGTYPE', True) == 'rpm':
91 d.appendVarFlag('do_deploy_archives', 'depends', ' %s:do_package_write_rpm' % pn)
92 if ar_dumpdata == "1":
93 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_dumpdata' % pn)
94 if ar_recipe == "1":
95 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_ar_recipe' % pn)
96 if ar_src == "original":
97 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_ar_original' % pn)
98 elif ar_src == "patched":
99 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_ar_patched' % pn)
100 elif ar_src == "configured":
101 d.appendVarFlag('do_package_write_rpm', 'depends', ' %s:do_ar_configured' % pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500102}
103
104# Take all the sources for a recipe and puts them in WORKDIR/archiver-work/.
105# Files in SRC_URI are copied directly, anything that's a directory
106# (e.g. git repositories) is "unpacked" and then put into a tarball.
107python do_ar_original() {
108
109 import shutil, tarfile, tempfile
110
111 if d.getVarFlag('ARCHIVER_MODE', 'src', True) != "original":
112 return
113
114 ar_outdir = d.getVar('ARCHIVER_OUTDIR', True)
115 bb.note('Archiving the original source...')
116 fetch = bb.fetch2.Fetch([], d)
117 for url in fetch.urls:
118 local = fetch.localpath(url).rstrip("/");
119 if os.path.isfile(local):
120 shutil.copy(local, ar_outdir)
121 elif os.path.isdir(local):
122 basename = os.path.basename(local)
123
124 tmpdir = tempfile.mkdtemp(dir=d.getVar('ARCHIVER_WORKDIR', True))
125 fetch.unpack(tmpdir, (url,))
126
127 os.chdir(tmpdir)
128 # We eliminate any AUTOINC+ in the revision.
129 try:
130 src_rev = bb.fetch2.get_srcrev(d).replace('AUTOINC+','')
131 except:
132 src_rev = 'NOREV'
133 tarname = os.path.join(ar_outdir, basename + '.' + src_rev + '.tar.gz')
134 tar = tarfile.open(tarname, 'w:gz')
135 tar.add('.')
136 tar.close()
137
138 # Emit patch series files for 'original'
139 bb.note('Writing patch series files...')
140 for patch in src_patches(d):
141 _, _, local, _, _, parm = bb.fetch.decodeurl(patch)
142 patchdir = parm.get('patchdir')
143 if patchdir:
144 series = os.path.join(ar_outdir, 'series.subdir.%s' % patchdir.replace('/', '_'))
145 else:
146 series = os.path.join(ar_outdir, 'series')
147
148 with open(series, 'a') as s:
149 s.write('%s -p%s\n' % (os.path.basename(local), parm['striplevel']))
150}
151
152python do_ar_patched() {
153
154 if d.getVarFlag('ARCHIVER_MODE', 'src', True) != 'patched':
155 return
156
157 # Get the ARCHIVER_OUTDIR before we reset the WORKDIR
158 ar_outdir = d.getVar('ARCHIVER_OUTDIR', True)
159 bb.note('Archiving the patched source...')
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500160 d.setVar('WORKDIR', ar_outdir)
161 create_tarball(d, d.getVar('S', True), 'patched', ar_outdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162}
163
164python do_ar_configured() {
165 import shutil
166
167 ar_outdir = d.getVar('ARCHIVER_OUTDIR', True)
168 if d.getVarFlag('ARCHIVER_MODE', 'src', True) == 'configured':
169 bb.note('Archiving the configured source...')
170 # The libtool-native's do_configure will remove the
171 # ${STAGING_DATADIR}/aclocal/libtool.m4, so we can't re-run the
172 # do_configure, we archive the already configured ${S} to
173 # instead of.
174 if d.getVar('PN', True) != 'libtool-native':
175 # Change the WORKDIR to make do_configure run in another dir.
176 d.setVar('WORKDIR', d.getVar('ARCHIVER_WORKDIR', True))
177 if bb.data.inherits_class('kernel-yocto', d):
178 bb.build.exec_func('do_kernel_configme', d)
179 if bb.data.inherits_class('cmake', d):
180 bb.build.exec_func('do_generate_toolchain_file', d)
181 prefuncs = d.getVarFlag('do_configure', 'prefuncs', True)
182 for func in (prefuncs or '').split():
183 if func != "sysroot_cleansstate":
184 bb.build.exec_func(func, d)
185 bb.build.exec_func('do_configure', d)
186 postfuncs = d.getVarFlag('do_configure', 'postfuncs', True)
187 for func in (postfuncs or '').split():
188 if func != "do_qa_configure":
189 bb.build.exec_func(func, d)
190 srcdir = d.getVar('S', True)
191 builddir = d.getVar('B', True)
192 if srcdir != builddir:
193 if os.path.exists(builddir):
194 oe.path.copytree(builddir, os.path.join(srcdir, \
195 'build.%s.ar_configured' % d.getVar('PF', True)))
196 create_tarball(d, srcdir, 'configured', ar_outdir)
197}
198
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500199def create_tarball(d, srcdir, suffix, ar_outdir):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500200 """
201 create the tarball from srcdir
202 """
203 import tarfile
204
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500205 # Make sure we are only creating a single tarball for gcc sources
206 if d.getVar('SRC_URI', True) == "" and 'gcc' in d.getVar('PN', True):
207 return
208
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500209 bb.utils.mkdirhier(ar_outdir)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500210 tarname = os.path.join(ar_outdir, '%s-%s.tar.gz' % \
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500211 (d.getVar('PF', True), suffix))
212
213 srcdir = srcdir.rstrip('/')
214 dirname = os.path.dirname(srcdir)
215 basename = os.path.basename(srcdir)
216 os.chdir(dirname)
217 bb.note('Creating %s' % tarname)
218 tar = tarfile.open(tarname, 'w:gz')
219 tar.add(basename)
220 tar.close()
221
222# creating .diff.gz between source.orig and source
223def create_diff_gz(d, src_orig, src, ar_outdir):
224
225 import subprocess
226
227 if not os.path.isdir(src) or not os.path.isdir(src_orig):
228 return
229
230 # The diff --exclude can't exclude the file with path, so we copy
231 # the patched source, and remove the files that we'd like to
232 # exclude.
233 src_patched = src + '.patched'
234 oe.path.copyhardlinktree(src, src_patched)
235 for i in d.getVarFlag('ARCHIVER_MODE', 'diff-exclude', True).split():
236 bb.utils.remove(os.path.join(src_orig, i), recurse=True)
237 bb.utils.remove(os.path.join(src_patched, i), recurse=True)
238
239 dirname = os.path.dirname(src)
240 basename = os.path.basename(src)
241 os.chdir(dirname)
242 out_file = os.path.join(ar_outdir, '%s-diff.gz' % d.getVar('PF', True))
243 diff_cmd = 'diff -Naur %s.orig %s.patched | gzip -c > %s' % (basename, basename, out_file)
244 subprocess.call(diff_cmd, shell=True)
245 bb.utils.remove(src_patched, recurse=True)
246
247# Run do_unpack and do_patch
248python do_unpack_and_patch() {
249 if d.getVarFlag('ARCHIVER_MODE', 'src', True) not in \
250 [ 'patched', 'configured'] and \
251 d.getVarFlag('ARCHIVER_MODE', 'diff', True) != '1':
252 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500253 # Change the WORKDIR to make do_unpack do_patch run in another dir.
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500254 ar_outdir = d.getVar('ARCHIVER_OUTDIR', True)
255 d.setVar('WORKDIR', ar_outdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500256
257 # The changed 'WORKDIR' also casued 'B' changed, create dir 'B' for the
258 # possibly requiring of the following tasks (such as some recipes's
259 # do_patch required 'B' existed).
260 bb.utils.mkdirhier(d.getVar('B', True))
261
262 # The kernel source is ready after do_validate_branches
263 if bb.data.inherits_class('kernel-yocto', d):
264 bb.build.exec_func('do_unpack', d)
265 bb.build.exec_func('do_kernel_checkout', d)
266 bb.build.exec_func('do_validate_branches', d)
267 else:
268 bb.build.exec_func('do_unpack', d)
269
270 # Save the original source for creating the patches
271 if d.getVarFlag('ARCHIVER_MODE', 'diff', True) == '1':
272 src = d.getVar('S', True).rstrip('/')
273 src_orig = '%s.orig' % src
274 oe.path.copytree(src, src_orig)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500275
276 # Make sure gcc sources are patched only once
277 if not ((d.getVar('SRC_URI', True) == "" and 'gcc' in d.getVar('PN', True))):
278 bb.build.exec_func('do_patch', d)
279
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280 # Create the patches
281 if d.getVarFlag('ARCHIVER_MODE', 'diff', True) == '1':
282 bb.note('Creating diff gz...')
283 create_diff_gz(d, src_orig, src, ar_outdir)
284 bb.utils.remove(src_orig, recurse=True)
285}
286
287python do_ar_recipe () {
288 """
289 archive the recipe, including .bb and .inc.
290 """
291 import re
292 import shutil
293
294 require_re = re.compile( r"require\s+(.+)" )
295 include_re = re.compile( r"include\s+(.+)" )
296 bbfile = d.getVar('FILE', True)
297 outdir = os.path.join(d.getVar('WORKDIR', True), \
298 '%s-recipe' % d.getVar('PF', True))
299 bb.utils.mkdirhier(outdir)
300 shutil.copy(bbfile, outdir)
301
302 dirname = os.path.dirname(bbfile)
303 bbpath = '%s:%s' % (dirname, d.getVar('BBPATH', True))
304 f = open(bbfile, 'r')
305 for line in f.readlines():
306 incfile = None
307 if require_re.match(line):
308 incfile = require_re.match(line).group(1)
309 elif include_re.match(line):
310 incfile = include_re.match(line).group(1)
311 if incfile:
312 incfile = bb.data.expand(incfile, d)
313 incfile = bb.utils.which(bbpath, incfile)
314 if incfile:
315 shutil.copy(incfile, outdir)
316
317 create_tarball(d, outdir, 'recipe', d.getVar('ARCHIVER_OUTDIR', True))
318 bb.utils.remove(outdir, recurse=True)
319}
320
321python do_dumpdata () {
322 """
323 dump environment data to ${PF}-showdata.dump
324 """
325
326 dumpfile = os.path.join(d.getVar('ARCHIVER_OUTDIR', True), \
327 '%s-showdata.dump' % d.getVar('PF', True))
328 bb.note('Dumping metadata into %s' % dumpfile)
329 f = open(dumpfile, 'w')
330 # emit variables and shell functions
331 bb.data.emit_env(f, d, True)
332 # emit the metadata which isn't valid shell
333 for e in d.keys():
334 if bb.data.getVarFlag(e, 'python', d):
335 f.write("\npython %s () {\n%s}\n" % (e, bb.data.getVar(e, d, True)))
336 f.close()
337}
338
339SSTATETASKS += "do_deploy_archives"
340do_deploy_archives () {
341 echo "Deploying source archive files ..."
342}
343python do_deploy_archives_setscene () {
344 sstate_setscene(d)
345}
346do_deploy_archives[sstate-inputdirs] = "${ARCHIVER_TOPDIR}"
347do_deploy_archives[sstate-outputdirs] = "${DEPLOY_DIR_SRC}"
348
349addtask do_ar_original after do_unpack
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500350addtask do_ar_patched after do_unpack_and_patch
351addtask do_ar_configured after do_unpack_and_patch
352addtask do_dumpdata
353addtask do_ar_recipe
354addtask do_deploy_archives before do_build
355
356addtask do_deploy_all_archives after do_deploy_archives
357do_deploy_all_archives[recrdeptask] = "do_deploy_archives"
358do_deploy_all_archives[recideptask] = "do_${BB_DEFAULT_TASK}"
359do_deploy_all_archives() {
360 :
361}
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500362
363python () {
364 # Add tasks in the correct order, specifically for linux-yocto to avoid race condition
365 if bb.data.inherits_class('kernel-yocto', d):
366 bb.build.addtask('do_kernel_configme', 'do_configure', 'do_unpack_and_patch', d)
367 else:
368 bb.build.addtask('do_unpack_and_patch', None, 'do_patch', d)
369}