3
# Thomas Nagy, 2006 (ita)
7
- execute a function everytime
8
- copy a file somewhere else
12
import TaskGen, Node, Task, Utils, Build, Constants
13
from TaskGen import feature, taskgen, after, before
14
from Logs import debug
17
"Make a file copy. This might be used to make other kinds of file processing (even calling a compiler is possible)"
19
infile = tsk.inputs[0].abspath(env)
20
outfile = tsk.outputs[0].abspath(env)
22
shutil.copy2(infile, outfile)
23
except (OSError, IOError):
26
if tsk.chmod: os.chmod(outfile, tsk.chmod)
29
def action_process_file_func(tsk):
30
"Ask the function attached to the task to process it"
31
if not tsk.fun: raise Utils.WafError('task must have a function attached to it for copy_func to work!')
34
class cmd_taskgen(TaskGen.task_gen):
35
def __init__(self, *k, **kw):
36
TaskGen.task_gen.__init__(self, *k, **kw)
40
"call a command everytime"
41
if not self.fun: raise Utils.WafError('cmdobj needs a function!')
45
self.tasks.append(tsk)
46
tsk.install_path = self.install_path
48
class copy_taskgen(TaskGen.task_gen):
49
"By default, make a file copy, if fun is provided, fun will make the copy (or call a compiler, etc)"
50
def __init__(self, *k, **kw):
51
TaskGen.task_gen.__init__(self, *k, **kw)
56
Utils.def_attrs(self, fun=copy_func)
57
self.default_install_path = 0
59
lst = self.to_list(self.source)
60
self.meths.remove('apply_core')
63
node = self.path.find_resource(filename)
64
if not node: raise Utils.WafError('cannot find input file %s for processing' % filename)
67
if not target or len(lst)>1: target = node.name
69
# TODO the file path may be incorrect
70
newnode = self.path.find_or_declare(target)
72
tsk = self.create_task('copy', node, newnode)
74
tsk.chmod = self.chmod
78
raise Utils.WafError('task without an environment')
81
"Substitutes variables in a .in file"
83
m4_re = re.compile('@(\w+)@', re.M)
86
infile = tsk.inputs[0].abspath(env)
87
outfile = tsk.outputs[0].abspath(env)
89
code = Utils.readf(infile)
91
# replace all % by %% to prevent errors by % signs in the input file while string formatting
92
code = code.replace('%', '%%')
94
s = m4_re.sub(r'%(\1)s', code)
98
names = m4_re.findall(code)
100
di[i] = env.get_flat(i) or env.get_flat(i.upper())
102
file = open(outfile, 'w')
105
if tsk.chmod: os.chmod(outfile, tsk.chmod)
107
class subst_taskgen(TaskGen.task_gen):
108
def __init__(self, *k, **kw):
109
TaskGen.task_gen.__init__(self, *k, **kw)
112
@before('apply_core')
113
def apply_subst(self):
114
Utils.def_attrs(self, fun=subst_func)
115
self.default_install_path = 0
116
lst = self.to_list(self.source)
117
self.meths.remove('apply_core')
119
self.dict = getattr(self, 'dict', {})
122
node = self.path.find_resource(filename)
123
if not node: raise Utils.WafError('cannot find input file %s for processing' % filename)
126
newnode = self.path.find_or_declare(self.target)
128
newnode = node.change_ext('')
131
self.dict = self.dict.get_merged_dict()
132
except AttributeError:
135
if self.dict and not self.env['DICT_HASH']:
136
self.env = self.env.copy()
137
keys = list(self.dict.keys())
139
lst = [self.dict[x] for x in keys]
140
self.env['DICT_HASH'] = str(Utils.h_list(lst))
142
tsk = self.create_task('copy', node, newnode)
145
tsk.dep_vars = ['DICT_HASH']
146
tsk.install_path = self.install_path
147
tsk.chmod = self.chmod
151
raise Utils.WafError('task without an environment')
154
## command-output ####
157
class cmd_arg(object):
158
"""command-output arguments for representing files or folders"""
159
def __init__(self, name, template='%s'):
161
self.template = template
164
class input_file(cmd_arg):
165
def find_node(self, base_path):
166
assert isinstance(base_path, Node.Node)
167
self.node = base_path.find_resource(self.name)
168
if self.node is None:
169
raise Utils.WafError("Input file %s not found in " % (self.name, base_path))
171
def get_path(self, env, absolute):
173
return self.template % self.node.abspath(env)
175
return self.template % self.node.srcpath(env)
177
class output_file(cmd_arg):
178
def find_node(self, base_path):
179
assert isinstance(base_path, Node.Node)
180
self.node = base_path.find_or_declare(self.name)
181
if self.node is None:
182
raise Utils.WafError("Output file %s not found in " % (self.name, base_path))
184
def get_path(self, env, absolute):
186
return self.template % self.node.abspath(env)
188
return self.template % self.node.bldpath(env)
190
class cmd_dir_arg(cmd_arg):
191
def find_node(self, base_path):
192
assert isinstance(base_path, Node.Node)
193
self.node = base_path.find_dir(self.name)
194
if self.node is None:
195
raise Utils.WafError("Directory %s not found in " % (self.name, base_path))
197
class input_dir(cmd_dir_arg):
198
def get_path(self, dummy_env, dummy_absolute):
199
return self.template % self.node.abspath()
201
class output_dir(cmd_dir_arg):
202
def get_path(self, env, dummy_absolute):
203
return self.template % self.node.abspath(env)
206
class command_output(Task.Task):
208
def __init__(self, env, command, command_node, command_args, stdin, stdout, cwd, os_env, stderr):
209
Task.Task.__init__(self, env, normal=1)
210
assert isinstance(command, (str, Node.Node))
211
self.command = command
212
self.command_args = command_args
219
if command_node is not None: self.dep_nodes = [command_node]
220
self.dep_vars = [] # additional environment variables to look
224
#assert len(task.inputs) > 0
226
def input_path(node, template):
228
return template % node.bldpath(task.env)
230
return template % node.abspath()
231
def output_path(node, template):
233
if task.cwd is None: fun = node.bldpath
234
return template % fun(task.env)
236
if isinstance(task.command, Node.Node):
237
argv = [input_path(task.command, '%s')]
239
argv = [task.command]
241
for arg in task.command_args:
242
if isinstance(arg, str):
245
assert isinstance(arg, cmd_arg)
246
argv.append(arg.get_path(task.env, (task.cwd is not None)))
249
stdin = open(input_path(task.stdin, '%s'))
254
stdout = open(output_path(task.stdout, '%s'), "w")
259
stderr = open(output_path(task.stderr, '%s'), "w")
264
cwd = ('None (actually %r)' % os.getcwd())
267
debug("command-output: cwd=%s, stdin=%r, stdout=%r, argv=%r" %
268
(cwd, stdin, stdout, argv))
270
if task.os_env is None:
274
command = Utils.pproc.Popen(argv, stdin=stdin, stdout=stdout, stderr=stderr, cwd=task.cwd, env=os_env)
275
return command.wait()
277
class cmd_output_taskgen(TaskGen.task_gen):
278
def __init__(self, *k, **kw):
279
TaskGen.task_gen.__init__(self, *k, **kw)
281
@feature('command-output')
282
def init_cmd_output(self):
283
Utils.def_attrs(self,
287
# the command to execute
290
# whether it is an external command; otherwise it is assumed
291
# to be an executable binary or script that lives in the
292
# source or build tree.
293
command_is_external = False,
295
# extra parameters (argv) to pass to the command (excluding
296
# the command itself)
299
# dependencies to other objects -> this is probably not what you want (ita)
300
# values must be 'task_gen' instances (not names!)
303
# dependencies on env variable contents
306
# input files that are implicit, i.e. they are not
307
# stdin, nor are they mentioned explicitly in argv
310
# output files that are implicit, i.e. they are not
311
# stdout, nor are they mentioned explicitly in argv
314
# change the subprocess to this cwd (must use obj.input_dir() or output_dir() here)
317
# OS environment variables to pass to the subprocess
318
# if None, use the default environment variables unchanged
321
@feature('command-output')
322
@after('init_cmd_output')
323
def apply_cmd_output(self):
324
if self.command is None:
325
raise Utils.WafError("command-output missing command")
326
if self.command_is_external:
330
cmd_node = self.path.find_resource(self.command)
331
assert cmd_node is not None, ('''Could not find command '%s' in source tree.
332
Hint: if this is an external command,
333
use command_is_external=True''') % (self.command,)
339
assert isinstance(cwd, CmdDirArg)
340
self.cwd.find_node(self.path)
346
for arg in self.argv:
347
if isinstance(arg, cmd_arg):
348
arg.find_node(self.path)
349
if isinstance(arg, input_file):
350
inputs.append(arg.node)
351
if isinstance(arg, output_file):
352
outputs.append(arg.node)
354
if self.stdout is None:
357
assert isinstance(self.stdout, str)
358
stdout = self.path.find_or_declare(self.stdout)
360
raise Utils.WafError("File %s not found" % (self.stdout,))
361
outputs.append(stdout)
363
if self.stderr is None:
366
assert isinstance(self.stderr, str)
367
stderr = self.path.find_or_declare(self.stderr)
369
raise Utils.WafError("File %s not found" % (self.stderr,))
370
outputs.append(stderr)
372
if self.stdin is None:
375
assert isinstance(self.stdin, str)
376
stdin = self.path.find_resource(self.stdin)
378
raise Utils.WafError("File %s not found" % (self.stdin,))
381
for hidden_input in self.to_list(self.hidden_inputs):
382
node = self.path.find_resource(hidden_input)
384
raise Utils.WafError("File %s not found in dir %s" % (hidden_input, self.path))
387
for hidden_output in self.to_list(self.hidden_outputs):
388
node = self.path.find_or_declare(hidden_output)
390
raise Utils.WafError("File %s not found in dir %s" % (hidden_output, self.path))
393
if not (inputs or getattr(self, 'no_inputs', None)):
394
raise Utils.WafError('command-output objects must have at least one input file or give self.no_inputs')
395
if not (outputs or getattr(self, 'no_outputs', None)):
396
raise Utils.WafError('command-output objects must have at least one output file or give self.no_outputs')
398
task = command_output(self.env, cmd, cmd_node, self.argv, stdin, stdout, cwd, self.os_env, stderr)
399
Utils.copy_attrs(self, task, 'before after ext_in ext_out', only_if_set=True)
400
self.tasks.append(task)
403
task.outputs = outputs
404
task.dep_vars = self.to_list(self.dep_vars)
406
for dep in self.dependencies:
407
assert dep is not self
409
for dep_task in dep.tasks:
410
task.set_run_after(dep_task)
413
# the case for svnversion, always run, and update the output nodes
414
task.runnable_status = type(Task.TaskBase.run)(runnable_status, task, task.__class__) # always run
415
task.post_run = type(Task.TaskBase.run)(post_run, task, task.__class__)
417
# TODO the case with no outputs?
420
for x in self.outputs:
421
h = Utils.h_file(x.abspath(self.env))
422
self.generator.bld.node_sigs[self.env.variant()][x.id] = h
424
def runnable_status(self):
425
return Constants.RUN_ME
427
Task.task_type_from_func('copy', vars=[], func=action_process_file_func)
428
TaskGen.task_gen.classes['command-output'] = cmd_output_taskgen