1# based on playground/evil in the waf svn tree
2
3import os, datetime, fnmatch
4from waflib import Scripting, Utils, Options, Logs, Errors
5from waflib import ConfigSet, Context
6from samba_utils import LOCAL_CACHE, os_path_relpath
7
8def run_task(t, k):
9    '''run a single build task'''
10    ret = t.run()
11    if ret:
12        raise Errors.WafError("Failed to build %s: %u" % (k, ret))
13
14
15def run_named_build_task(cmd):
16    '''run a named build task, matching the cmd name using fnmatch
17    wildcards against inputs and outputs of all build tasks'''
18    bld = fake_build_environment(info=False)
19    found = False
20    cwd_node = bld.root.find_dir(os.getcwd())
21    top_node = bld.root.find_dir(bld.srcnode.abspath())
22
23    cmd = os.path.normpath(cmd)
24
25    # cope with builds of bin/*/*
26    if os.path.islink(cmd):
27        cmd = os_path_relpath(os.readlink(cmd), os.getcwd())
28
29    if cmd[0:12] == "bin/default/":
30        cmd = cmd[12:]
31
32    for g in bld.task_manager.groups:
33        for attr in ['outputs', 'inputs']:
34            for t in g.tasks:
35                s = getattr(t, attr, [])
36                for k in s:
37                    relpath1 = k.relpath_gen(cwd_node)
38                    relpath2 = k.relpath_gen(top_node)
39                    if (fnmatch.fnmatch(relpath1, cmd) or
40                        fnmatch.fnmatch(relpath2, cmd)):
41                        t.position = [0,0]
42                        print(t.display())
43                        run_task(t, k)
44                        found = True
45
46
47    if not found:
48        raise Errors.WafError("Unable to find build target matching %s" % cmd)
49
50
51def rewrite_compile_targets():
52    '''cope with the bin/ form of compile target'''
53    if not Options.options.compile_targets:
54        return
55
56    bld = fake_build_environment(info=False)
57    targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
58    tlist = []
59
60    for t in Options.options.compile_targets.split(','):
61        if not os.path.islink(t):
62            tlist.append(t)
63            continue
64        link = os.readlink(t)
65        list = link.split('/')
66        for name in [list[-1], '/'.join(list[-2:])]:
67            if name in targets:
68                tlist.append(name)
69                continue
70    Options.options.compile_targets = ",".join(tlist)
71
72
73
74def wildcard_main(missing_cmd_fn):
75    '''this replaces main from Scripting, allowing us to override the
76       behaviour for unknown commands
77
78       If a unknown command is found, then missing_cmd_fn() is called with
79       the name of the requested command
80       '''
81    Scripting.commands = Options.arg_line[:]
82
83    # rewrite the compile targets to cope with the bin/xx form
84    rewrite_compile_targets()
85
86    while Scripting.commands:
87        x = Scripting.commands.pop(0)
88
89        ini = datetime.datetime.now()
90        if x == 'configure':
91            fun = Scripting.configure
92        elif x == 'build':
93            fun = Scripting.build
94        else:
95            fun = getattr(Utils.g_module, x, None)
96
97        # this is the new addition on top of main from Scripting.py
98        if not fun:
99            missing_cmd_fn(x)
100            break
101
102        ctx = getattr(Utils.g_module, x + '_context', Utils.Context)()
103
104        if x in ['init', 'shutdown', 'dist', 'distclean', 'distcheck']:
105            try:
106                fun(ctx)
107            except TypeError:
108                fun()
109        else:
110            fun(ctx)
111
112        ela = ''
113        if not Options.options.progress_bar:
114            ela = ' (%s)' % Utils.get_elapsed_time(ini)
115
116        if x != 'init' and x != 'shutdown':
117            Logs.info('%r finished successfully%s' % (x, ela))
118
119        if not Scripting.commands and x != 'shutdown':
120            Scripting.commands.append('shutdown')
121
122
123
124
125def fake_build_environment(info=True, flush=False):
126    """create all the tasks for the project, but do not run the build
127    return the build context in use"""
128    bld = getattr(Context.g_module, 'build_context', Utils.Context)()
129    bld = Scripting.check_configured(bld)
130
131    Options.commands['install'] = False
132    Options.commands['uninstall'] = False
133
134    bld.is_install = 0 # False
135
136    try:
137        proj = ConfigSet.ConfigSet(Options.lockfile)
138    except IOError:
139        raise Errors.WafError("Project not configured (run 'waf configure' first)")
140
141    bld.load_envs()
142
143    if info:
144        Logs.info("Waf: Entering directory `%s'" % bld.bldnode.abspath())
145    bld.add_subdirs([os.path.split(Context.g_module.root_path)[0]])
146
147    bld.pre_build()
148    if flush:
149        bld.flush()
150    return bld
151
152