summaryrefslogtreecommitdiff
path: root/scripts/cleanup-workdir
blob: 86eae3702bbb7f6ba47367a99c0c467615119ccd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/usr/bin/env python3

# 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.decode('utf-8')

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)