a1e63ee58f0c3f1395263f5cc61dcd7ec0eeea72
[amitay/samba.git] / third_party / waf / waflib / extras / stale.py
1 #! /usr/bin/env python
2 # encoding: UTF-8
3 # Thomas Nagy, 2006-2015 (ita)
4
5 """
6 Add a pre-build hook to remove build files (declared in the system)
7 that do not have a corresponding target
8
9 This can be used for example to remove the targets
10 that have changed name without performing
11 a full 'waf clean'
12
13 Of course, it will only work if there are no dynamically generated
14 nodes/tasks, in which case the method will have to be modified
15 to exclude some folders for example.
16 """
17
18 from waflib import Logs, Build
19 from waflib.Runner import Parallel
20
21 DYNAMIC_EXT = [] # add your non-cleanable files/extensions here
22 MOC_H_EXTS = '.cpp .cxx .hpp .hxx .h'.split()
23
24 def can_delete(node):
25         """Imperfect moc cleanup which does not look for a Q_OBJECT macro in the files"""
26         if not node.name.endswith('.moc'):
27                 return True
28         base = node.name[:-4]
29         p1 = node.parent.get_src()
30         p2 = node.parent.get_bld()
31         for k in MOC_H_EXTS:
32                 h_name = base + k
33                 n = p1.search_node(h_name)
34                 if n:
35                         return False
36                 n = p2.search_node(h_name)
37                 if n:
38                         return False
39
40                 # foo.cpp.moc, foo.h.moc, etc.
41                 if base.endswith(k):
42                         return False
43
44         return True
45
46 # recursion over the nodes to find the stale files
47 def stale_rec(node, nodes):
48         if node.abspath() in node.ctx.env[Build.CFG_FILES]:
49                 return
50
51         if getattr(node, 'children', []):
52                 for x in node.children.values():
53                         if x.name != "c4che":
54                                 stale_rec(x, nodes)
55         else:
56                 for ext in DYNAMIC_EXT:
57                         if node.name.endswith(ext):
58                                 break
59                 else:
60                         if not node in nodes:
61                                 if can_delete(node):
62                                         Logs.warn("Removing stale file -> %s" % node.abspath())
63                                         node.delete()
64
65 old = Parallel.refill_task_list
66 def refill_task_list(self):
67         iit = old(self)
68         bld = self.bld
69
70         # execute this operation only once
71         if getattr(self, 'stale_done', False):
72                 return iit
73         self.stale_done = True
74
75         # this does not work in partial builds
76         if hasattr(bld, 'options') and bld.options.targets and bld.options.targets != '*':
77                 return iit
78
79         # this does not work in dynamic builds
80         if not hasattr(bld, 'post_mode') or bld.post_mode == Build.POST_LAZY:
81                 return iit
82
83         # obtain the nodes to use during the build
84         nodes = []
85         for i in range(len(bld.groups)):
86                 tasks = bld.get_tasks_group(i)
87                 for x in tasks:
88                         try:
89                                 nodes.extend(x.outputs)
90                         except:
91                                 pass
92
93         stale_rec(bld.bldnode, nodes)
94         return iit
95
96 Parallel.refill_task_list = refill_task_list