third_party/waf: upgrade to waf 2.0.8
[samba.git] / third_party / waf / waflib / extras / run_py_script.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Hans-Martin von Gaudecker, 2012
4
5 """
6 Run a Python script in the directory specified by **ctx.bldnode**.
7
8 Select a Python version by specifying the **version** keyword for
9 the task generator instance as integer 2 or 3. Default is 3.
10
11 If the build environment has an attribute "PROJECT_PATHS" with
12 a key "PROJECT_ROOT", its value will be appended to the PYTHONPATH.
13 Same a string passed to the optional **add_to_pythonpath**
14 keyword (appended after the PROJECT_ROOT).
15
16 Usage::
17
18     ctx(features='run_py_script', version=3,
19         source='some_script.py',
20         target=['some_table.tex', 'some_figure.eps'],
21         deps='some_data.csv',
22         add_to_pythonpath='src/some/library')
23 """
24
25 import os, re
26 from waflib import Task, TaskGen, Logs
27
28
29 def configure(conf):
30         """TODO: Might need to be updated for Windows once
31         "PEP 397":http://www.python.org/dev/peps/pep-0397/ is settled.
32         """
33         conf.find_program('python', var='PY2CMD', mandatory=False)
34         conf.find_program('python3', var='PY3CMD', mandatory=False)
35         if not conf.env.PY2CMD and not conf.env.PY3CMD:
36                 conf.fatal("No Python interpreter found!")
37
38 class run_py_2_script(Task.Task):
39         """Run a Python 2 script."""
40         run_str = '${PY2CMD} ${SRC[0].abspath()}'
41         shell=True
42
43 class run_py_3_script(Task.Task):
44         """Run a Python 3 script."""
45         run_str = '${PY3CMD} ${SRC[0].abspath()}'
46         shell=True
47
48 @TaskGen.feature('run_py_script')
49 @TaskGen.before_method('process_source')
50 def apply_run_py_script(tg):
51         """Task generator for running either Python 2 or Python 3 on a single
52         script.
53
54         Attributes:
55
56                 * source -- A **single** source node or string. (required)
57                 * target -- A single target or list of targets (nodes or strings)
58                 * deps -- A single dependency or list of dependencies (nodes or strings)
59                 * add_to_pythonpath -- A string that will be appended to the PYTHONPATH environment variable
60
61         If the build environment has an attribute "PROJECT_PATHS" with
62         a key "PROJECT_ROOT", its value will be appended to the PYTHONPATH.
63         """
64
65         # Set the Python version to use, default to 3.
66         v = getattr(tg, 'version', 3)
67         if v not in (2, 3):
68                 raise ValueError("Specify the 'version' attribute for run_py_script task generator as integer 2 or 3.\n Got: %s" %v)
69
70         # Convert sources and targets to nodes
71         src_node = tg.path.find_resource(tg.source)
72         tgt_nodes = [tg.path.find_or_declare(t) for t in tg.to_list(tg.target)]
73
74         # Create the task.
75         tsk = tg.create_task('run_py_%d_script' %v, src=src_node, tgt=tgt_nodes)
76
77         # custom execution environment
78         # TODO use a list and  os.sep.join(lst) at the end instead of concatenating strings
79         tsk.env.env = dict(os.environ)
80         tsk.env.env['PYTHONPATH'] = tsk.env.env.get('PYTHONPATH', '')
81         project_paths = getattr(tsk.env, 'PROJECT_PATHS', None)
82         if project_paths and 'PROJECT_ROOT' in project_paths:
83                 tsk.env.env['PYTHONPATH'] += os.pathsep + project_paths['PROJECT_ROOT'].abspath()
84         if getattr(tg, 'add_to_pythonpath', None):
85                 tsk.env.env['PYTHONPATH'] += os.pathsep + tg.add_to_pythonpath
86
87         # Clean up the PYTHONPATH -- replace double occurrences of path separator
88         tsk.env.env['PYTHONPATH'] = re.sub(os.pathsep + '+', os.pathsep, tsk.env.env['PYTHONPATH'])
89
90         # Clean up the PYTHONPATH -- doesn't like starting with path separator
91         if tsk.env.env['PYTHONPATH'].startswith(os.pathsep):
92                  tsk.env.env['PYTHONPATH'] = tsk.env.env['PYTHONPATH'][1:]
93
94         # dependencies (if the attribute 'deps' changes, trigger a recompilation)
95         for x in tg.to_list(getattr(tg, 'deps', [])):
96                 node = tg.path.find_resource(x)
97                 if not node:
98                         tg.bld.fatal('Could not find dependency %r for running %r' % (x, src_node.abspath()))
99                 tsk.dep_nodes.append(node)
100         Logs.debug('deps: found dependencies %r for running %r', tsk.dep_nodes, src_node.abspath())
101
102         # Bypass the execution of process_source by setting the source to an empty list
103         tg.source = []
104