| #!/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) |