summaryrefslogtreecommitdiffstats
path: root/meta/classes/buildhistory.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes/buildhistory.bbclass')
-rw-r--r--meta/classes/buildhistory.bbclass628
1 files changed, 628 insertions, 0 deletions
diff --git a/meta/classes/buildhistory.bbclass b/meta/classes/buildhistory.bbclass
new file mode 100644
index 0000000000..3da03c8485
--- /dev/null
+++ b/meta/classes/buildhistory.bbclass
@@ -0,0 +1,628 @@
1#
2# Records history of build output in order to detect regressions
3#
4# Based in part on testlab.bbclass and packagehistory.bbclass
5#
6# Copyright (C) 2013 Intel Corporation
7# Copyright (C) 2007-2011 Koen Kooi <koen@openembedded.org>
8#
9
10BUILDHISTORY_FEATURES ?= "image package sdk"
11BUILDHISTORY_DIR ?= "${TOPDIR}/buildhistory"
12BUILDHISTORY_DIR_IMAGE = "${BUILDHISTORY_DIR}/images/${MACHINE_ARCH}/${TCLIBC}/${IMAGE_BASENAME}"
13BUILDHISTORY_DIR_PACKAGE = "${BUILDHISTORY_DIR}/packages/${MULTIMACH_TARGET_SYS}/${PN}"
14BUILDHISTORY_DIR_SDK = "${BUILDHISTORY_DIR}/sdk/${SDK_NAME}/${IMAGE_BASENAME}"
15BUILDHISTORY_IMAGE_FILES ?= "/etc/passwd /etc/group"
16BUILDHISTORY_COMMIT ?= "0"
17BUILDHISTORY_COMMIT_AUTHOR ?= "buildhistory <buildhistory@${DISTRO}>"
18BUILDHISTORY_PUSH_REPO ?= ""
19
20# Must inherit package first before changing PACKAGEFUNCS
21inherit package
22PACKAGEFUNCS += "buildhistory_emit_pkghistory"
23
24# We don't want to force a rerun of do_package for everything
25# if the buildhistory_emit_pkghistory function or any of the
26# variables it refers to changes
27do_package[vardepsexclude] += "buildhistory_emit_pkghistory"
28
29#
30# Called during do_package to write out metadata about this package
31# for comparision when writing future packages
32#
33python buildhistory_emit_pkghistory() {
34 import re
35
36 if not "package" in (d.getVar('BUILDHISTORY_FEATURES', True) or "").split():
37 return 0
38
39 pkghistdir = d.getVar('BUILDHISTORY_DIR_PACKAGE', True)
40
41 class RecipeInfo:
42 def __init__(self, name):
43 self.name = name
44 self.pe = "0"
45 self.pv = "0"
46 self.pr = "r0"
47 self.depends = ""
48 self.packages = ""
49 self.bbfile = ""
50 self.src_uri = ""
51 self.srcrev = ""
52 self.srcrev_autorev = ""
53
54
55 class PackageInfo:
56 def __init__(self, name):
57 self.name = name
58 self.pe = "0"
59 self.pv = "0"
60 self.pr = "r0"
61 # pkg/pkge/pkgv/pkgr should be empty because we want to be able to default them
62 self.pkg = ""
63 self.pkge = ""
64 self.pkgv = ""
65 self.pkgr = ""
66 self.size = 0
67 self.depends = ""
68 self.rprovides = ""
69 self.rdepends = ""
70 self.rrecommends = ""
71 self.rsuggests = ""
72 self.rreplaces = ""
73 self.rconflicts = ""
74 self.files = ""
75 self.filelist = ""
76 # Variables that need to be written to their own separate file
77 self.filevars = dict.fromkeys(['pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm'])
78
79 # Should check PACKAGES here to see if anything removed
80
81 def getpkgvar(pkg, var):
82 val = bb.data.getVar('%s_%s' % (var, pkg), d, 1)
83 if val:
84 return val
85 val = bb.data.getVar('%s' % (var), d, 1)
86
87 return val
88
89 def readPackageInfo(pkg, histfile):
90 pkginfo = PackageInfo(pkg)
91 with open(histfile, "r") as f:
92 for line in f:
93 lns = line.split('=')
94 name = lns[0].strip()
95 value = lns[1].strip(" \t\r\n").strip('"')
96 if name == "PE":
97 pkginfo.pe = value
98 elif name == "PV":
99 pkginfo.pv = value
100 elif name == "PR":
101 pkginfo.pr = value
102 elif name == "PKG":
103 pkginfo.pkg = value
104 elif name == "PKGE":
105 pkginfo.pkge = value
106 elif name == "PKGV":
107 pkginfo.pkgv = value
108 elif name == "PKGR":
109 pkginfo.pkgr = value
110 elif name == "RPROVIDES":
111 pkginfo.rprovides = value
112 elif name == "RDEPENDS":
113 pkginfo.rdepends = value
114 elif name == "RRECOMMENDS":
115 pkginfo.rrecommends = value
116 elif name == "RSUGGESTS":
117 pkginfo.rsuggests = value
118 elif name == "RREPLACES":
119 pkginfo.rreplaces = value
120 elif name == "RCONFLICTS":
121 pkginfo.rconflicts = value
122 elif name == "PKGSIZE":
123 pkginfo.size = long(value)
124 elif name == "FILES":
125 pkginfo.files = value
126 elif name == "FILELIST":
127 pkginfo.filelist = value
128 # Apply defaults
129 if not pkginfo.pkg:
130 pkginfo.pkg = pkginfo.name
131 if not pkginfo.pkge:
132 pkginfo.pkge = pkginfo.pe
133 if not pkginfo.pkgv:
134 pkginfo.pkgv = pkginfo.pv
135 if not pkginfo.pkgr:
136 pkginfo.pkgr = pkginfo.pr
137 return pkginfo
138
139 def getlastpkgversion(pkg):
140 try:
141 histfile = os.path.join(pkghistdir, pkg, "latest")
142 return readPackageInfo(pkg, histfile)
143 except EnvironmentError:
144 return None
145
146 def sortpkglist(string):
147 pkgiter = re.finditer(r'[a-zA-Z0-9.+-]+( \([><=]+ [^ )]+\))?', string, 0)
148 pkglist = [p.group(0) for p in pkgiter]
149 pkglist.sort()
150 return ' '.join(pkglist)
151
152 def sortlist(string):
153 items = string.split(' ')
154 items.sort()
155 return ' '.join(items)
156
157 pn = d.getVar('PN', True)
158 pe = d.getVar('PE', True) or "0"
159 pv = d.getVar('PV', True)
160 pr = d.getVar('PR', True)
161
162 bbfile = d.getVar('BB_FILENAME', True)
163 src_uri = d.getVar('SRC_URI', True)
164 srcrev = d.getVar('SRCREV', True)
165 srcrev_autorev = 'yes' if d.getVar('SRCREV', False) == 'AUTOINC' else 'no'
166
167 packages = squashspaces(d.getVar('PACKAGES', True))
168
169 packagelist = packages.split()
170 if not os.path.exists(pkghistdir):
171 bb.utils.mkdirhier(pkghistdir)
172 else:
173 # Remove files for packages that no longer exist
174 for item in os.listdir(pkghistdir):
175 if item != "latest" and item != "latest_srcrev":
176 if item not in packagelist:
177 subdir = os.path.join(pkghistdir, item)
178 for subfile in os.listdir(subdir):
179 os.unlink(os.path.join(subdir, subfile))
180 os.rmdir(subdir)
181
182 rcpinfo = RecipeInfo(pn)
183 rcpinfo.pe = pe
184 rcpinfo.pv = pv
185 rcpinfo.pr = pr
186 rcpinfo.depends = sortlist(squashspaces(d.getVar('DEPENDS', True) or ""))
187 rcpinfo.bbfile = bbfile
188 rcpinfo.src_uri = src_uri
189 rcpinfo.srcrev = srcrev
190 rcpinfo.srcrev_autorev = srcrev_autorev
191 rcpinfo.packages = packages
192 write_recipehistory(rcpinfo, d)
193
194 pkgdest = d.getVar('PKGDEST', True)
195 for pkg in packagelist:
196 pkge = getpkgvar(pkg, 'PKGE') or "0"
197 pkgv = getpkgvar(pkg, 'PKGV')
198 pkgr = getpkgvar(pkg, 'PKGR')
199 #
200 # Find out what the last version was
201 # Make sure the version did not decrease
202 #
203 lastversion = getlastpkgversion(pkg)
204 if lastversion:
205 last_pkge = lastversion.pkge
206 last_pkgv = lastversion.pkgv
207 last_pkgr = lastversion.pkgr
208 r = bb.utils.vercmp((pkge, pkgv, pkgr), (last_pkge, last_pkgv, last_pkgr))
209 if r < 0:
210 msg = "Package version for package %s went backwards which would break package feeds from (%s:%s-%s to %s:%s-%s)" % (pkg, last_pkge, last_pkgv, last_pkgr, pkge, pkgv, pkgr)
211 package_qa_handle_error("version-going-backwards", msg, d)
212
213 pkginfo = PackageInfo(pkg)
214 # Apparently the version can be different on a per-package basis (see Python)
215 pkginfo.pe = getpkgvar(pkg, 'PE') or "0"
216 pkginfo.pv = getpkgvar(pkg, 'PV')
217 pkginfo.pr = getpkgvar(pkg, 'PR')
218 pkginfo.pkg = getpkgvar(pkg, 'PKG') or pkg
219 pkginfo.pkge = pkge
220 pkginfo.pkgv = pkgv
221 pkginfo.pkgr = pkgr
222 pkginfo.rprovides = sortpkglist(squashspaces(getpkgvar(pkg, 'RPROVIDES') or ""))
223 pkginfo.rdepends = sortpkglist(squashspaces(getpkgvar(pkg, 'RDEPENDS') or ""))
224 pkginfo.rrecommends = sortpkglist(squashspaces(getpkgvar(pkg, 'RRECOMMENDS') or ""))
225 pkginfo.rsuggests = sortpkglist(squashspaces(getpkgvar(pkg, 'RSUGGESTS') or ""))
226 pkginfo.rreplaces = sortpkglist(squashspaces(getpkgvar(pkg, 'RREPLACES') or ""))
227 pkginfo.rconflicts = sortpkglist(squashspaces(getpkgvar(pkg, 'RCONFLICTS') or ""))
228 pkginfo.files = squashspaces(getpkgvar(pkg, 'FILES') or "")
229 for filevar in pkginfo.filevars:
230 pkginfo.filevars[filevar] = getpkgvar(pkg, filevar)
231
232 # Gather information about packaged files
233 pkgdestpkg = os.path.join(pkgdest, pkg)
234 filelist = []
235 pkginfo.size = 0
236 for f in pkgfiles[pkg]:
237 relpth = os.path.relpath(f, pkgdestpkg)
238 fstat = os.lstat(f)
239 pkginfo.size += fstat.st_size
240 filelist.append(os.sep + relpth)
241 filelist.sort()
242 pkginfo.filelist = " ".join(filelist)
243
244 write_pkghistory(pkginfo, d)
245}
246
247
248def write_recipehistory(rcpinfo, d):
249 bb.debug(2, "Writing recipe history")
250
251 pkghistdir = d.getVar('BUILDHISTORY_DIR_PACKAGE', True)
252
253 infofile = os.path.join(pkghistdir, "latest")
254 with open(infofile, "w") as f:
255 if rcpinfo.pe != "0":
256 f.write("PE = %s\n" % rcpinfo.pe)
257 f.write("PV = %s\n" % rcpinfo.pv)
258 f.write("PR = %s\n" % rcpinfo.pr)
259 f.write("DEPENDS = %s\n" % rcpinfo.depends)
260 f.write("PACKAGES = %s\n" % rcpinfo.packages)
261
262
263def write_pkghistory(pkginfo, d):
264 bb.debug(2, "Writing package history for package %s" % pkginfo.name)
265
266 pkghistdir = d.getVar('BUILDHISTORY_DIR_PACKAGE', True)
267
268 pkgpath = os.path.join(pkghistdir, pkginfo.name)
269 if not os.path.exists(pkgpath):
270 bb.utils.mkdirhier(pkgpath)
271
272 infofile = os.path.join(pkgpath, "latest")
273 with open(infofile, "w") as f:
274 if pkginfo.pe != "0":
275 f.write("PE = %s\n" % pkginfo.pe)
276 f.write("PV = %s\n" % pkginfo.pv)
277 f.write("PR = %s\n" % pkginfo.pr)
278
279 pkgvars = {}
280 pkgvars['PKG'] = pkginfo.pkg if pkginfo.pkg != pkginfo.name else ''
281 pkgvars['PKGE'] = pkginfo.pkge if pkginfo.pkge != pkginfo.pe else ''
282 pkgvars['PKGV'] = pkginfo.pkgv if pkginfo.pkgv != pkginfo.pv else ''
283 pkgvars['PKGR'] = pkginfo.pkgr if pkginfo.pkgr != pkginfo.pr else ''
284 for pkgvar in pkgvars:
285 val = pkgvars[pkgvar]
286 if val:
287 f.write("%s = %s\n" % (pkgvar, val))
288
289 f.write("RPROVIDES = %s\n" % pkginfo.rprovides)
290 f.write("RDEPENDS = %s\n" % pkginfo.rdepends)
291 f.write("RRECOMMENDS = %s\n" % pkginfo.rrecommends)
292 if pkginfo.rsuggests:
293 f.write("RSUGGESTS = %s\n" % pkginfo.rsuggests)
294 if pkginfo.rreplaces:
295 f.write("RREPLACES = %s\n" % pkginfo.rreplaces)
296 if pkginfo.rconflicts:
297 f.write("RCONFLICTS = %s\n" % pkginfo.rconflicts)
298 f.write("PKGSIZE = %d\n" % pkginfo.size)
299 f.write("FILES = %s\n" % pkginfo.files)
300 f.write("FILELIST = %s\n" % pkginfo.filelist)
301
302 for filevar in pkginfo.filevars:
303 filevarpath = os.path.join(pkgpath, "latest.%s" % filevar)
304 val = pkginfo.filevars[filevar]
305 if val:
306 with open(filevarpath, "w") as f:
307 f.write(val)
308 else:
309 if os.path.exists(filevarpath):
310 os.unlink(filevarpath)
311
312
313buildhistory_get_installed() {
314 mkdir -p $1
315
316 # Get list of installed packages
317 pkgcache="$1/installed-packages.tmp"
318 list_installed_packages file | sort > $pkgcache
319
320 cat $pkgcache | awk '{ print $1 }' > $1/installed-package-names.txt
321 if [ -s $pkgcache ] ; then
322 cat $pkgcache | awk '{ print $2 }' | xargs -n1 basename > $1/installed-packages.txt
323 else
324 printf "" > $1/installed-packages.txt
325 fi
326
327 # Produce dependency graph
328 # First, quote each name to handle characters that cause issues for dot
329 rootfs_list_installed_depends | sed 's:\([^| ]*\):"\1":g' > $1/depends.tmp
330 # Change delimiter from pipe to -> and set style for recommend lines
331 sed -i -e 's:|: -> :' -e 's:"\[REC\]":[style=dotted]:' -e 's:$:;:' $1/depends.tmp
332 # Add header, sorted and de-duped contents and footer and then delete the temp file
333 printf "digraph depends {\n node [shape=plaintext]\n" > $1/depends.dot
334 cat $1/depends.tmp | sort | uniq >> $1/depends.dot
335 echo "}" >> $1/depends.dot
336 rm $1/depends.tmp
337
338 # Produce installed package sizes list
339 printf "" > $1/installed-package-sizes.tmp
340 cat $pkgcache | while read pkg pkgfile pkgarch
341 do
342 for vendor in ${TARGET_VENDOR} ${MULTILIB_VENDORS} ; do
343 size=`oe-pkgdata-util read-value ${PKGDATA_DIR} "PKGSIZE" ${pkg}_${pkgarch}`
344 if [ "$size" != "" ] ; then
345 echo "$size $pkg" >> $1/installed-package-sizes.tmp
346 fi
347 done
348 done
349 cat $1/installed-package-sizes.tmp | sort -n -r | awk '{print $1 "\tKiB " $2}' > $1/installed-package-sizes.txt
350 rm $1/installed-package-sizes.tmp
351
352 # We're now done with the cache, delete it
353 rm $pkgcache
354
355 if [ "$2" != "sdk" ] ; then
356 # Produce some cut-down graphs (for readability)
357 grep -v kernel_image $1/depends.dot | grep -v kernel-2 | grep -v kernel-3 > $1/depends-nokernel.dot
358 grep -v libc6 $1/depends-nokernel.dot | grep -v libgcc > $1/depends-nokernel-nolibc.dot
359 grep -v update- $1/depends-nokernel-nolibc.dot > $1/depends-nokernel-nolibc-noupdate.dot
360 grep -v kernel-module $1/depends-nokernel-nolibc-noupdate.dot > $1/depends-nokernel-nolibc-noupdate-nomodules.dot
361 fi
362
363 # add complementary package information
364 if [ -e ${WORKDIR}/complementary_pkgs.txt ]; then
365 cp ${WORKDIR}/complementary_pkgs.txt $1
366 fi
367}
368
369buildhistory_get_image_installed() {
370 # Anything requiring the use of the packaging system should be done in here
371 # in case the packaging files are going to be removed for this image
372
373 if [ "${@base_contains('BUILDHISTORY_FEATURES', 'image', '1', '0', d)}" = "0" ] ; then
374 return
375 fi
376
377 buildhistory_get_installed ${BUILDHISTORY_DIR_IMAGE}
378}
379
380buildhistory_get_sdk_installed() {
381 # Anything requiring the use of the packaging system should be done in here
382 # in case the packaging files are going to be removed for this SDK
383
384 if [ "${@base_contains('BUILDHISTORY_FEATURES', 'sdk', '1', '0', d)}" = "0" ] ; then
385 return
386 fi
387
388 buildhistory_get_installed ${BUILDHISTORY_DIR_SDK}/$1 sdk
389}
390
391buildhistory_list_files() {
392 # List the files in the specified directory, but exclude date/time etc.
393 # This awk script is somewhat messy, but handles where the size is not printed for device files under pseudo
394 ( cd $1 && find . -ls | awk '{ if ( $7 ~ /[0-9]/ ) printf "%s %10-s %10-s %10s %s %s %s\n", $3, $5, $6, $7, $11, $12, $13 ; else printf "%s %10-s %10-s %10s %s %s %s\n", $3, $5, $6, 0, $10, $11, $12 }' | sort -k5 | sed 's/ *$//' > $2 )
395}
396
397
398buildhistory_get_imageinfo() {
399 if [ "${@base_contains('BUILDHISTORY_FEATURES', 'image', '1', '0', d)}" = "0" ] ; then
400 return
401 fi
402
403 buildhistory_list_files ${IMAGE_ROOTFS} ${BUILDHISTORY_DIR_IMAGE}/files-in-image.txt
404
405 # Collect files requested in BUILDHISTORY_IMAGE_FILES
406 rm -rf ${BUILDHISTORY_DIR_IMAGE}/image-files
407 for f in ${BUILDHISTORY_IMAGE_FILES}; do
408 if [ -f ${IMAGE_ROOTFS}/$f ] ; then
409 mkdir -p ${BUILDHISTORY_DIR_IMAGE}/image-files/`dirname $f`
410 cp ${IMAGE_ROOTFS}/$f ${BUILDHISTORY_DIR_IMAGE}/image-files/$f
411 fi
412 done
413
414 # Record some machine-readable meta-information about the image
415 printf "" > ${BUILDHISTORY_DIR_IMAGE}/image-info.txt
416 cat >> ${BUILDHISTORY_DIR_IMAGE}/image-info.txt <<END
417${@buildhistory_get_imagevars(d)}
418END
419 imagesize=`du -ks ${IMAGE_ROOTFS} | awk '{ print $1 }'`
420 echo "IMAGESIZE = $imagesize" >> ${BUILDHISTORY_DIR_IMAGE}/image-info.txt
421
422 # Add some configuration information
423 echo "${MACHINE}: ${IMAGE_BASENAME} configured for ${DISTRO} ${DISTRO_VERSION}" > ${BUILDHISTORY_DIR_IMAGE}/build-id
424
425 cat >> ${BUILDHISTORY_DIR_IMAGE}/build-id <<END
426${@buildhistory_get_layers(d)}
427END
428}
429
430buildhistory_get_sdkinfo() {
431 if [ "${@base_contains('BUILDHISTORY_FEATURES', 'sdk', '1', '0', d)}" = "0" ] ; then
432 return
433 fi
434
435 buildhistory_list_files ${SDK_OUTPUT} ${BUILDHISTORY_DIR_SDK}/files-in-sdk.txt
436
437 # Record some machine-readable meta-information about the SDK
438 printf "" > ${BUILDHISTORY_DIR_SDK}/sdk-info.txt
439 cat >> ${BUILDHISTORY_DIR_SDK}/sdk-info.txt <<END
440${@buildhistory_get_sdkvars(d)}
441END
442 sdksize=`du -ks ${SDK_OUTPUT} | awk '{ print $1 }'`
443 echo "SDKSIZE = $sdksize" >> ${BUILDHISTORY_DIR_SDK}/sdk-info.txt
444}
445
446# By prepending we get in before the removal of packaging files
447ROOTFS_POSTPROCESS_COMMAND =+ "buildhistory_get_image_installed ; "
448
449IMAGE_POSTPROCESS_COMMAND += " buildhistory_get_imageinfo ; "
450
451# We want these to be the last run so that we get called after complementary package installation
452POPULATE_SDK_POST_TARGET_COMMAND_append = "buildhistory_get_sdk_installed target ; "
453POPULATE_SDK_POST_HOST_COMMAND_append = "buildhistory_get_sdk_installed host ; "
454
455SDK_POSTPROCESS_COMMAND += "buildhistory_get_sdkinfo ; "
456
457def buildhistory_get_layers(d):
458 layertext = "Configured metadata layers:\n%s\n" % '\n'.join(get_layers_branch_rev(d))
459 return layertext
460
461def buildhistory_get_metadata_revs(d):
462 # We want an easily machine-readable format here, so get_layers_branch_rev isn't quite what we want
463 layers = (d.getVar("BBLAYERS", True) or "").split()
464 medadata_revs = ["%-17s = %s:%s" % (os.path.basename(i), \
465 base_get_metadata_git_branch(i, None).strip(), \
466 base_get_metadata_git_revision(i, None)) \
467 for i in layers]
468 return '\n'.join(medadata_revs)
469
470
471def squashspaces(string):
472 import re
473 return re.sub("\s+", " ", string).strip()
474
475def outputvars(vars, listvars, d):
476 vars = vars.split()
477 listvars = listvars.split()
478 ret = ""
479 for var in vars:
480 value = d.getVar(var, True) or ""
481 if var in listvars:
482 # Squash out spaces
483 value = squashspaces(value)
484 ret += "%s = %s\n" % (var, value)
485 return ret.rstrip('\n')
486
487def buildhistory_get_imagevars(d):
488 imagevars = "DISTRO DISTRO_VERSION USER_CLASSES IMAGE_CLASSES IMAGE_FEATURES IMAGE_LINGUAS IMAGE_INSTALL BAD_RECOMMENDATIONS ROOTFS_POSTPROCESS_COMMAND IMAGE_POSTPROCESS_COMMAND"
489 listvars = "USER_CLASSES IMAGE_CLASSES IMAGE_FEATURES IMAGE_LINGUAS IMAGE_INSTALL BAD_RECOMMENDATIONS"
490 return outputvars(imagevars, listvars, d)
491
492def buildhistory_get_sdkvars(d):
493 sdkvars = "DISTRO DISTRO_VERSION SDK_NAME SDK_VERSION SDKMACHINE SDKIMAGE_FEATURES BAD_RECOMMENDATIONS"
494 listvars = "SDKIMAGE_FEATURES BAD_RECOMMENDATIONS"
495 return outputvars(sdkvars, listvars, d)
496
497
498def buildhistory_get_cmdline(d):
499 if sys.argv[0].endswith('bin/bitbake'):
500 bincmd = 'bitbake'
501 else:
502 bincmd = sys.argv[0]
503 return '%s %s' % (bincmd, ' '.join(sys.argv[1:]))
504
505
506buildhistory_commit() {
507 if [ ! -d ${BUILDHISTORY_DIR} ] ; then
508 # Code above that creates this dir never executed, so there can't be anything to commit
509 return
510 fi
511
512 # Create a machine-readable list of metadata revisions for each layer
513 cat > ${BUILDHISTORY_DIR}/metadata-revs <<END
514${@buildhistory_get_metadata_revs(d)}
515END
516
517 ( cd ${BUILDHISTORY_DIR}/
518 # Initialise the repo if necessary
519 if [ ! -d .git ] ; then
520 git init -q
521 else
522 git tag -f build-minus-3 build-minus-2 > /dev/null 2>&1 || true
523 git tag -f build-minus-2 build-minus-1 > /dev/null 2>&1 || true
524 git tag -f build-minus-1 > /dev/null 2>&1 || true
525 fi
526 # Check if there are new/changed files to commit (other than metadata-revs)
527 repostatus=`git status --porcelain | grep -v " metadata-revs$"`
528 HOSTNAME=`hostname 2>/dev/null || echo unknown`
529 CMDLINE="${@buildhistory_get_cmdline(d)}"
530 if [ "$repostatus" != "" ] ; then
531 git add -A .
532 # porcelain output looks like "?? packages/foo/bar"
533 # Ensure we commit metadata-revs with the first commit
534 for entry in `echo "$repostatus" | awk '{print $2}' | awk -F/ '{print $1}' | sort | uniq` ; do
535 git commit $entry metadata-revs -m "$entry: Build ${BUILDNAME} of ${DISTRO} ${DISTRO_VERSION} for machine ${MACHINE} on $HOSTNAME" -m "cmd: $CMDLINE" --author "${BUILDHISTORY_COMMIT_AUTHOR}" > /dev/null
536 done
537 if [ "${BUILDHISTORY_PUSH_REPO}" != "" ] ; then
538 git push -q ${BUILDHISTORY_PUSH_REPO}
539 fi
540 else
541 git commit ${BUILDHISTORY_DIR}/ --allow-empty -m "No changes: Build ${BUILDNAME} of ${DISTRO} ${DISTRO_VERSION} for machine ${MACHINE} on $HOSTNAME" -m "cmd: $CMDLINE" --author "${BUILDHISTORY_COMMIT_AUTHOR}" > /dev/null
542 fi) || true
543}
544
545python buildhistory_eventhandler() {
546 if e.data.getVar('BUILDHISTORY_FEATURES', True).strip():
547 if e.data.getVar("BUILDHISTORY_COMMIT", True) == "1":
548 bb.note("Writing buildhistory")
549 bb.build.exec_func("buildhistory_commit", e.data)
550}
551
552addhandler buildhistory_eventhandler
553buildhistory_eventhandler[eventmask] = "bb.event.BuildCompleted"
554
555
556# FIXME this ought to be moved into the fetcher
557def _get_srcrev_values(d):
558 """
559 Return the version strings for the current recipe
560 """
561
562 scms = []
563 fetcher = bb.fetch.Fetch(d.getVar('SRC_URI', True).split(), d)
564 urldata = fetcher.ud
565 for u in urldata:
566 if urldata[u].method.supports_srcrev():
567 scms.append(u)
568
569 autoinc_templ = 'AUTOINC+'
570 dict_srcrevs = {}
571 dict_tag_srcrevs = {}
572 for scm in scms:
573 ud = urldata[scm]
574 for name in ud.names:
575 rev = ud.method.sortable_revision(scm, ud, d, name)
576 # Clean this up when we next bump bitbake version
577 if type(rev) != str:
578 autoinc, rev = rev
579 elif rev.startswith(autoinc_templ):
580 rev = rev[len(autoinc_templ):]
581 dict_srcrevs[name] = rev
582 if 'tag' in ud.parm:
583 tag = ud.parm['tag'];
584 key = name+'_'+tag
585 dict_tag_srcrevs[key] = rev
586 return (dict_srcrevs, dict_tag_srcrevs)
587
588do_fetch[postfuncs] += "write_srcrev"
589python write_srcrev() {
590 pkghistdir = d.getVar('BUILDHISTORY_DIR_PACKAGE', True)
591 srcrevfile = os.path.join(pkghistdir, 'latest_srcrev')
592
593 srcrevs, tag_srcrevs = _get_srcrev_values(d)
594 if srcrevs:
595 if not os.path.exists(pkghistdir):
596 bb.utils.mkdirhier(pkghistdir)
597 old_tag_srcrevs = {}
598 if os.path.exists(srcrevfile):
599 with open(srcrevfile) as f:
600 for line in f:
601 if line.startswith('# tag_'):
602 key, value = line.split("=", 1)
603 key = key.replace('# tag_', '').strip()
604 value = value.replace('"', '').strip()
605 old_tag_srcrevs[key] = value
606 with open(srcrevfile, 'w') as f:
607 orig_srcrev = d.getVar('SRCREV', False) or 'INVALID'
608 if orig_srcrev != 'INVALID':
609 f.write('# SRCREV = "%s"\n' % orig_srcrev)
610 if len(srcrevs) > 1:
611 for name, srcrev in srcrevs.items():
612 orig_srcrev = d.getVar('SRCREV_%s' % name, False)
613 if orig_srcrev:
614 f.write('# SRCREV_%s = "%s"\n' % (name, orig_srcrev))
615 f.write('SRCREV_%s = "%s"\n' % (name, srcrev))
616 else:
617 f.write('SRCREV = "%s"\n' % srcrevs.itervalues().next())
618 if len(tag_srcrevs) > 0:
619 for name, srcrev in tag_srcrevs.items():
620 f.write('# tag_%s = "%s"\n' % (name, srcrev))
621 if name in old_tag_srcrevs and old_tag_srcrevs[name] != srcrev:
622 pkg = d.getVar('PN', True)
623 bb.warn("Revision for tag %s in package %s was changed since last build (from %s to %s)" % (name, pkg, old_tag_srcrevs[name], srcrev))
624
625 else:
626 if os.path.exists(srcrevfile):
627 os.remove(srcrevfile)
628}