poky/scripts/cleanup-workdir
Richard Purdie c37d5426b1 scripts, lib: Don't limit traceback lengths to arbitrary values
There appears to have been a lot of copy and pasting of the code
which prints tracebacks upon failure and limits the stack trace to
5 entries. This obscures the real error and is very confusing to the user
it look me an age to work out why some tracebacks weren't useful.

This patch removes the limit, making tracebacks much more useful for
debugging.

[YOCTO #9230]

(From OE-Core rev: 6069175e9bb97ace100bb5e99b6104d33163a3a2)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2016-03-31 23:01:36 +01:00

5.9 KiB
Executable File

#!/usr/bin/env python

Copyright (c) 2012 Wind River Systems, Inc.

This program is free software; you can redistribute it and/or modify

it under the terms of the GNU General Public License version 2 as

published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License

along with this program; if not, write to the Free Software

Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

import os import sys import optparse import re import subprocess import shutil

pkg_cur_dirs = {} obsolete_dirs = [] parser = None

def err_quit(msg): print msg parser.print_usage() sys.exit(1)

def parse_version(verstr): elems = verstr.split(':') epoch = elems[0] if len(epoch) == 0: return elems[1] else: return epoch + '_' + elems[1]

def run_command(cmd): pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) output = pipe.communicate()[0] if pipe.returncode != 0: print "Execute command '%s' failed." % cmd sys.exit(1) return output

def get_cur_arch_dirs(workdir, arch_dirs): pattern = workdir + '/(.*?)/'

cmd = "bitbake -e | grep ^SDK_ARCH="
output = run_command(cmd)
sdk_arch = output.split('"')[1]

# select thest 5 packages to get the dirs of current arch
pkgs = ['hicolor-icon-theme', 'base-files', 'acl-native', 'binutils-crosssdk-' + sdk_arch, 'nativesdk-autoconf']

for pkg in pkgs:
    cmd = "bitbake -e " + pkg + " | grep ^IMAGE_ROOTFS="
    output = run_command(cmd)
    output = output.split('"')[1]
    m = re.match(pattern, output)
    arch_dirs.append(m.group(1))

def main(): global parser parser = optparse.OptionParser( usage = """%prog

%prog removes the obsolete packages' build directories in WORKDIR. This script must be ran under BUILDDIR after source file "oe-init-build-env".

Any file or directory under WORKDIR which is not created by Yocto will be deleted. Be CAUTIOUS.""")

options, args = parser.parse_args(sys.argv)

builddir = run_command('echo $BUILDDIR').strip()
if len(builddir) == 0:
    err_quit("Please source file \"oe-init-build-env\" first.\n")

if os.getcwd() != builddir:
    err_quit("Please run %s under: %s\n" % (os.path.basename(args[0]), builddir))

print 'Updating bitbake caches...'
cmd = "bitbake -s"
output = run_command(cmd)

output = output.split('\n')
index = 0
while len(output[index]) > 0:
    index += 1
alllines = output[index+1:]

for line in alllines:
    # empty again means end of the versions output
    if len(line) == 0:
        break
    line = line.strip()
    line = re.sub('\s+', ' ', line)
    elems = line.split(' ')
    if len(elems) == 2:
        version = parse_version(elems[1])
    else:
        version = parse_version(elems[2])
    pkg_cur_dirs[elems[0]] = version

cmd = "bitbake -e"
output = run_command(cmd)

tmpdir = None
image_rootfs = None
output = output.split('\n')
for line in output:
    if tmpdir and image_rootfs:
        break

    if not tmpdir:
        m = re.match('TMPDIR="(.*)"', line)
        if m:
            tmpdir = m.group(1)

    if not image_rootfs:
        m = re.match('IMAGE_ROOTFS="(.*)"', line)
        if m:
            image_rootfs = m.group(1)

# won't fail just in case
if not tmpdir or not image_rootfs:
    print "Can't get TMPDIR or IMAGE_ROOTFS."
    return 1

pattern = tmpdir + '/(.*?)/(.*?)/'
m = re.match(pattern, image_rootfs)
if not m:
    print "Can't get WORKDIR."
    return 1

workdir = os.path.join(tmpdir, m.group(1))

# we only deal the dirs of current arch, total numbers of dirs are 6
cur_arch_dirs = [m.group(2)]
get_cur_arch_dirs(workdir, cur_arch_dirs)

for workroot, dirs, files in os.walk(workdir):
    # For the files, they should NOT exist in WORKDIR. Remove them.
    for f in files:
        obsolete_dirs.append(os.path.join(workroot, f))

    for d in dirs:
        if d not in cur_arch_dirs:
            continue

        for pkgroot, pkgdirs, filenames in os.walk(os.path.join(workroot, d)):
            for f in filenames:
                obsolete_dirs.append(os.path.join(pkgroot, f))

            for pkgdir in sorted(pkgdirs):
                if pkgdir not in pkg_cur_dirs:
                    obsolete_dirs.append(os.path.join(pkgroot, pkgdir))
                else:
                    for verroot, verdirs, verfiles in os.walk(os.path.join(pkgroot, pkgdir)):
                        for f in verfiles:
                            obsolete_dirs.append(os.path.join(pkgroot, f))
                        for v in sorted(verdirs):
                           if v not in pkg_cur_dirs[pkgdir]:
                               obsolete_dirs.append(os.path.join(pkgroot, pkgdir, v))
                        break

            # just process the top dir of every package under tmp/work/*/,
            # then jump out of the above os.walk()
            break

    # it is convenient to use os.walk() to get dirs and files at same time
    # both of them have been dealed in the loop, so jump out
    break

for d in obsolete_dirs:
    print "Deleting %s" % d
    shutil.rmtree(d, True)

if len(obsolete_dirs):
    print '\nTotal %d items.' % len(obsolete_dirs)
else:
    print '\nNo obsolete directory found under %s.' % workdir

return 0

if name == 'main': try: ret = main() except Exception: ret = 2 import traceback traceback.print_exc() sys.exit(ret)