third_party/waf: upgrade to waf 2.0.8
[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 Make sure to set bld.post_mode = waflib.Build.POST_AT_ONCE
18 """
19
20 from waflib import Logs, Build
21 from waflib.Runner import Parallel
22
23 DYNAMIC_EXT = [] # add your non-cleanable files/extensions here
24 MOC_H_EXTS = '.cpp .cxx .hpp .hxx .h'.split()
25
26 def can_delete(node):
27         """Imperfect moc cleanup which does not look for a Q_OBJECT macro in the files"""
28         if not node.name.endswith('.moc'):
29                 return True
30         base = node.name[:-4]
31         p1 = node.parent.get_src()
32         p2 = node.parent.get_bld()
33         for k in MOC_H_EXTS:
34                 h_name = base + k
35                 n = p1.search_node(h_name)
36                 if n:
37                         return False
38                 n = p2.search_node(h_name)
39                 if n:
40                         return False
41
42                 # foo.cpp.moc, foo.h.moc, etc.
43                 if base.endswith(k):
44                         return False
45
46         return True
47
48 # recursion over the nodes to find the stale files
49 def stale_rec(node, nodes):
50         if node.abspath() in node.ctx.env[Build.CFG_FILES]:
51                 return
52
53         if getattr(node, 'children', []):
54                 for x in node.children.values():
55                         if x.name != "c4che":
56                                 stale_rec(x, nodes)
57         else:
58                 for ext in DYNAMIC_EXT:
59                         if node.name.endswith(ext):
60                                 break
61                 else:
62                         if not node in nodes:
63                                 if can_delete(node):
64                                         Logs.warn('Removing stale file -> %r', node)
65                                         node.delete()
66
67 old = Parallel.refill_task_list
68 def refill_task_list(self):
69         iit = old(self)
70         bld = self.bld
71
72         # execute this operation only once
73         if getattr(self, 'stale_done', False):
74                 return iit
75         self.stale_done = True
76
77         # this does not work in partial builds
78         if bld.targets != '*':
79                 return iit
80
81         # this does not work in dynamic builds
82         if getattr(bld, 'post_mode') == Build.POST_AT_ONCE:
83                 return iit
84
85         # obtain the nodes to use during the build
86         nodes = []
87         for tasks in bld.groups:
88                 for x in tasks:
89                         try:
90                                 nodes.extend(x.outputs)
91                         except AttributeError:
92                                 pass
93
94         stale_rec(bld.bldnode, nodes)
95         return iit
96
97 Parallel.refill_task_list = refill_task_list
98