1# encoding: utf-8
2# Thomas Nagy, 2006-2010 (ita)
3
4"""
5Add a pre-build hook to remove all build files
6which do not have a corresponding target
7
8This can be used for example to remove the targets
9that have changed name without performing
10a full 'waf clean'
11
12Of course, it will only work if there are no dynamically generated
13nodes/tasks, in which case the method will have to be modified
14to exclude some folders for example.
15"""
16
17from waflib import Logs, Build, Options, Utils, Errors
18import os
19from wafsamba import samba_utils
20from Runner import Parallel
21
22old_refill_task_list = Parallel.refill_task_list
23def replace_refill_task_list(self):
24    '''replacement for refill_task_list() that deletes stale files'''
25
26    iit = old_refill_task_list(self)
27    bld = self.bld
28
29    if not getattr(bld, 'new_rules', False):
30        # we only need to check for stale files if the build rules changed
31        return iit
32
33    if Options.options.compile_targets:
34        # not safe when --target is used
35        return iit
36
37    # execute only once
38    if getattr(self, 'cleanup_done', False):
39        return iit
40    self.cleanup_done = True
41
42    def group_name(g):
43        tm = self.bld.task_manager
44        return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
45
46    bin_base = bld.bldnode.abspath()
47    bin_base_len = len(bin_base)
48
49    # paranoia
50    if bin_base[-4:] != '/bin':
51        raise Errors.WafError("Invalid bin base: %s" % bin_base)
52
53    # obtain the expected list of files
54    expected = []
55    for i in range(len(bld.task_manager.groups)):
56        g = bld.task_manager.groups[i]
57        tasks = g.tasks_gen
58        for x in tasks:
59            try:
60                if getattr(x, 'target'):
61                    tlist = samba_utils.TO_LIST(getattr(x, 'target'))
62                    ttype = getattr(x, 'samba_type', None)
63                    task_list = getattr(x, 'compiled_tasks', [])
64                    if task_list:
65                        # this gets all of the .o files, including the task
66                        # ids, so foo.c maps to foo_3.o for idx=3
67                        for tsk in task_list:
68                            for output in tsk.outputs:
69                                objpath = os.path.normpath(output.abspath(bld.env))
70                                expected.append(objpath)
71                    for t in tlist:
72                        if ttype in ['LIBRARY','MODULE']:
73                            t = samba_utils.apply_pattern(t, bld.env.shlib_PATTERN)
74                        if ttype == 'PYTHON':
75                            t = samba_utils.apply_pattern(t, bld.env.pyext_PATTERN)
76                        p = os.path.join(x.path.abspath(bld.env), t)
77                        p = os.path.normpath(p)
78                        expected.append(p)
79                for n in x.allnodes:
80                    p = n.abspath(bld.env)
81                    if p[0:bin_base_len] == bin_base:
82                        expected.append(p)
83            except:
84                pass
85
86    for root, dirs, files in os.walk(bin_base):
87        for f in files:
88            p = root + '/' + f
89            if os.path.islink(p):
90                link = os.readlink(p)
91                if link[0:bin_base_len] == bin_base:
92                    p = link
93            if f in ['config.h']:
94                continue
95            (froot, fext) = os.path.splitext(f)
96            if fext not in [ '.c', '.h', '.so', '.o' ]:
97                continue
98            if f[-7:] == '.inst.h':
99                continue
100            if p.find("/.conf") != -1:
101                continue
102            if not p in expected and os.path.exists(p):
103                Logs.warn("Removing stale file: %s" % p)
104                os.unlink(p)
105    return iit
106
107
108def AUTOCLEANUP_STALE_FILES(bld):
109    """automatically clean up any files in bin that shouldn't be there"""
110    old_refill_task_list = Parallel.refill_task_list
111    Parallel.refill_task_list = replace_refill_task_list
112    Parallel.bld = bld
113Build.BuildContext.AUTOCLEANUP_STALE_FILES = AUTOCLEANUP_STALE_FILES
114