build:wafsamba: Remove unnecessary parameters to cmd_and_log
[amitay/samba.git] / third_party / waf / waflib / extras / misc.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Thomas Nagy, 2006-2010 (ita)
4
5 """
6 This tool is totally deprecated
7
8 Try using:
9         .pc.in files for .pc files
10         the feature intltool_in - see demos/intltool
11         make-like rules
12 """
13
14 import shutil, re, os
15 from waflib import Node, Task, Utils, Errors
16 from waflib.TaskGen import feature, after_method, before_method
17 from waflib.Logs import debug
18
19 def copy_attrs(orig, dest, names, only_if_set=False):
20         """
21         copy class attributes from an object to another
22         """
23         for a in Utils.to_list(names):
24                 u = getattr(orig, a, ())
25                 if u or not only_if_set:
26                         setattr(dest, a, u)
27
28 def copy_func(tsk):
29         "Make a file copy. This might be used to make other kinds of file processing (even calling a compiler is possible)"
30         infile = tsk.inputs[0].abspath()
31         outfile = tsk.outputs[0].abspath()
32         try:
33                 shutil.copy2(infile, outfile)
34         except EnvironmentError:
35                 return 1
36         else:
37                 if tsk.chmod: os.chmod(outfile, tsk.chmod)
38                 return 0
39
40 def action_process_file_func(tsk):
41         "Ask the function attached to the task to process it"
42         if not tsk.fun: raise Errors.WafError('task must have a function attached to it for copy_func to work!')
43         return tsk.fun(tsk)
44
45 @feature('cmd')
46 def apply_cmd(self):
47         "call a command everytime"
48         if not self.fun: raise Errors.WafError('cmdobj needs a function!')
49         tsk = Task.TaskBase()
50         tsk.fun = self.fun
51         tsk.env = self.env
52         self.tasks.append(tsk)
53         tsk.install_path = self.install_path
54
55 @feature('copy')
56 @before_method('process_source')
57 def apply_copy(self):
58         Utils.def_attrs(self, fun=copy_func)
59         self.default_install_path = 0
60
61         lst = self.to_list(self.source)
62         self.meths.remove('process_source')
63
64         for filename in lst:
65                 node = self.path.find_resource(filename)
66                 if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)
67
68                 target = self.target
69                 if not target or len(lst)>1: target = node.name
70
71                 # TODO the file path may be incorrect
72                 newnode = self.path.find_or_declare(target)
73
74                 tsk = self.create_task('copy', node, newnode)
75                 tsk.fun = self.fun
76                 tsk.chmod = getattr(self, 'chmod', Utils.O644)
77
78                 if not tsk.env:
79                         tsk.debug()
80                         raise Errors.WafError('task without an environment')
81
82 def subst_func(tsk):
83         "Substitutes variables in a .in file"
84
85         m4_re = re.compile('@(\w+)@', re.M)
86
87         code = tsk.inputs[0].read() #Utils.readf(infile)
88
89         # replace all % by %% to prevent errors by % signs in the input file while string formatting
90         code = code.replace('%', '%%')
91
92         s = m4_re.sub(r'%(\1)s', code)
93
94         env = tsk.env
95         di = getattr(tsk, 'dict', {}) or getattr(tsk.generator, 'dict', {})
96         if not di:
97                 names = m4_re.findall(code)
98                 for i in names:
99                         di[i] = env.get_flat(i) or env.get_flat(i.upper())
100
101         tsk.outputs[0].write(s % di)
102
103 @feature('subst')
104 @before_method('process_source')
105 def apply_subst(self):
106         Utils.def_attrs(self, fun=subst_func)
107         lst = self.to_list(self.source)
108         self.meths.remove('process_source')
109
110         self.dict = getattr(self, 'dict', {})
111
112         for filename in lst:
113                 node = self.path.find_resource(filename)
114                 if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)
115
116                 if self.target:
117                         newnode = self.path.find_or_declare(self.target)
118                 else:
119                         newnode = node.change_ext('')
120
121                 try:
122                         self.dict = self.dict.get_merged_dict()
123                 except AttributeError:
124                         pass
125
126                 if self.dict and not self.env['DICT_HASH']:
127                         self.env = self.env.derive()
128                         keys = list(self.dict.keys())
129                         keys.sort()
130                         lst = [self.dict[x] for x in keys]
131                         self.env['DICT_HASH'] = str(Utils.h_list(lst))
132
133                 tsk = self.create_task('copy', node, newnode)
134                 tsk.fun = self.fun
135                 tsk.dict = self.dict
136                 tsk.dep_vars = ['DICT_HASH']
137                 tsk.chmod = getattr(self, 'chmod', Utils.O644)
138
139                 if not tsk.env:
140                         tsk.debug()
141                         raise Errors.WafError('task without an environment')
142
143 ####################
144 ## command-output ####
145 ####################
146
147 class cmd_arg(object):
148         """command-output arguments for representing files or folders"""
149         def __init__(self, name, template='%s'):
150                 self.name = name
151                 self.template = template
152                 self.node = None
153
154 class input_file(cmd_arg):
155         def find_node(self, base_path):
156                 assert isinstance(base_path, Node.Node)
157                 self.node = base_path.find_resource(self.name)
158                 if self.node is None:
159                         raise Errors.WafError("Input file %s not found in " % (self.name, base_path))
160
161         def get_path(self, env, absolute):
162                 if absolute:
163                         return self.template % self.node.abspath()
164                 else:
165                         return self.template % self.node.srcpath()
166
167 class output_file(cmd_arg):
168         def find_node(self, base_path):
169                 assert isinstance(base_path, Node.Node)
170                 self.node = base_path.find_or_declare(self.name)
171                 if self.node is None:
172                         raise Errors.WafError("Output file %s not found in " % (self.name, base_path))
173
174         def get_path(self, env, absolute):
175                 if absolute:
176                         return self.template % self.node.abspath()
177                 else:
178                         return self.template % self.node.bldpath()
179
180 class cmd_dir_arg(cmd_arg):
181         def find_node(self, base_path):
182                 assert isinstance(base_path, Node.Node)
183                 self.node = base_path.find_dir(self.name)
184                 if self.node is None:
185                         raise Errors.WafError("Directory %s not found in " % (self.name, base_path))
186
187 class input_dir(cmd_dir_arg):
188         def get_path(self, dummy_env, dummy_absolute):
189                 return self.template % self.node.abspath()
190
191 class output_dir(cmd_dir_arg):
192         def get_path(self, env, dummy_absolute):
193                 return self.template % self.node.abspath()
194
195
196 class command_output(Task.Task):
197         color = "BLUE"
198         def __init__(self, env, command, command_node, command_args, stdin, stdout, cwd, os_env, stderr):
199                 Task.Task.__init__(self, env=env)
200                 assert isinstance(command, (str, Node.Node))
201                 self.command = command
202                 self.command_args = command_args
203                 self.stdin = stdin
204                 self.stdout = stdout
205                 self.cwd = cwd
206                 self.os_env = os_env
207                 self.stderr = stderr
208
209                 if command_node is not None: self.dep_nodes = [command_node]
210                 self.dep_vars = [] # additional environment variables to look
211
212         def run(self):
213                 task = self
214                 #assert len(task.inputs) > 0
215
216                 def input_path(node, template):
217                         if task.cwd is None:
218                                 return template % node.bldpath()
219                         else:
220                                 return template % node.abspath()
221                 def output_path(node, template):
222                         fun = node.abspath
223                         if task.cwd is None: fun = node.bldpath
224                         return template % fun()
225
226                 if isinstance(task.command, Node.Node):
227                         argv = [input_path(task.command, '%s')]
228                 else:
229                         argv = [task.command]
230
231                 for arg in task.command_args:
232                         if isinstance(arg, str):
233                                 argv.append(arg)
234                         else:
235                                 assert isinstance(arg, cmd_arg)
236                                 argv.append(arg.get_path(task.env, (task.cwd is not None)))
237
238                 if task.stdin:
239                         stdin = open(input_path(task.stdin, '%s'))
240                 else:
241                         stdin = None
242
243                 if task.stdout:
244                         stdout = open(output_path(task.stdout, '%s'), "w")
245                 else:
246                         stdout = None
247
248                 if task.stderr:
249                         stderr = open(output_path(task.stderr, '%s'), "w")
250                 else:
251                         stderr = None
252
253                 if task.cwd is None:
254                         cwd = ('None (actually %r)' % os.getcwd())
255                 else:
256                         cwd = repr(task.cwd)
257                 debug("command-output: cwd=%s, stdin=%r, stdout=%r, argv=%r" %
258                              (cwd, stdin, stdout, argv))
259
260                 if task.os_env is None:
261                         os_env = os.environ
262                 else:
263                         os_env = task.os_env
264                 command = Utils.subprocess.Popen(argv, stdin=stdin, stdout=stdout, stderr=stderr, cwd=task.cwd, env=os_env)
265                 return command.wait()
266
267 @feature('command-output')
268 def init_cmd_output(self):
269         Utils.def_attrs(self,
270                 stdin = None,
271                 stdout = None,
272                 stderr = None,
273                 # the command to execute
274                 command = None,
275
276                 # whether it is an external command; otherwise it is assumed
277                 # to be an executable binary or script that lives in the
278                 # source or build tree.
279                 command_is_external = False,
280
281                 # extra parameters (argv) to pass to the command (excluding
282                 # the command itself)
283                 argv = [],
284
285                 # dependencies to other objects -> this is probably not what you want (ita)
286                 # values must be 'task_gen' instances (not names!)
287                 dependencies = [],
288
289                 # dependencies on env variable contents
290                 dep_vars = [],
291
292                 # input files that are implicit, i.e. they are not
293                 # stdin, nor are they mentioned explicitly in argv
294                 hidden_inputs = [],
295
296                 # output files that are implicit, i.e. they are not
297                 # stdout, nor are they mentioned explicitly in argv
298                 hidden_outputs = [],
299
300                 # change the subprocess to this cwd (must use obj.input_dir() or output_dir() here)
301                 cwd = None,
302
303                 # OS environment variables to pass to the subprocess
304                 # if None, use the default environment variables unchanged
305                 os_env = None)
306
307 @feature('command-output')
308 @after_method('init_cmd_output')
309 def apply_cmd_output(self):
310         if self.command is None:
311                 raise Errors.WafError("command-output missing command")
312         if self.command_is_external:
313                 cmd = self.command
314                 cmd_node = None
315         else:
316                 cmd_node = self.path.find_resource(self.command)
317                 assert cmd_node is not None, ('''Could not find command '%s' in source tree.
318 Hint: if this is an external command,
319 use command_is_external=True''') % (self.command,)
320                 cmd = cmd_node
321
322         if self.cwd is None:
323                 cwd = None
324
325         inputs = []
326         outputs = []
327
328         for arg in self.argv:
329                 if isinstance(arg, cmd_arg):
330                         arg.find_node(self.path)
331                         if isinstance(arg, input_file):
332                                 inputs.append(arg.node)
333                         if isinstance(arg, output_file):
334                                 outputs.append(arg.node)
335
336         if self.stdout is None:
337                 stdout = None
338         else:
339                 assert isinstance(self.stdout, str)
340                 stdout = self.path.find_or_declare(self.stdout)
341                 if stdout is None:
342                         raise Errors.WafError("File %s not found" % (self.stdout,))
343                 outputs.append(stdout)
344
345         if self.stderr is None:
346                 stderr = None
347         else:
348                 assert isinstance(self.stderr, str)
349                 stderr = self.path.find_or_declare(self.stderr)
350                 if stderr is None:
351                         raise Errors.WafError("File %s not found" % (self.stderr,))
352                 outputs.append(stderr)
353
354         if self.stdin is None:
355                 stdin = None
356         else:
357                 assert isinstance(self.stdin, str)
358                 stdin = self.path.find_resource(self.stdin)
359                 if stdin is None:
360                         raise Errors.WafError("File %s not found" % (self.stdin,))
361                 inputs.append(stdin)
362
363         for hidden_input in self.to_list(self.hidden_inputs):
364                 node = self.path.find_resource(hidden_input)
365                 if node is None:
366                         raise Errors.WafError("File %s not found in dir %s" % (hidden_input, self.path))
367                 inputs.append(node)
368
369         for hidden_output in self.to_list(self.hidden_outputs):
370                 node = self.path.find_or_declare(hidden_output)
371                 if node is None:
372                         raise Errors.WafError("File %s not found in dir %s" % (hidden_output, self.path))
373                 outputs.append(node)
374
375         if not (inputs or getattr(self, 'no_inputs', None)):
376                 raise Errors.WafError('command-output objects must have at least one input file or give self.no_inputs')
377         if not (outputs or getattr(self, 'no_outputs', None)):
378                 raise Errors.WafError('command-output objects must have at least one output file or give self.no_outputs')
379
380         cwd = self.bld.variant_dir
381         task = command_output(self.env, cmd, cmd_node, self.argv, stdin, stdout, cwd, self.os_env, stderr)
382         task.generator = self
383         copy_attrs(self, task, 'before after ext_in ext_out', only_if_set=True)
384         self.tasks.append(task)
385
386         task.inputs = inputs
387         task.outputs = outputs
388         task.dep_vars = self.to_list(self.dep_vars)
389
390         for dep in self.dependencies:
391                 assert dep is not self
392                 dep.post()
393                 for dep_task in dep.tasks:
394                         task.set_run_after(dep_task)
395
396         if not task.inputs:
397                 # the case for svnversion, always run, and update the output nodes
398                 task.runnable_status = type(Task.TaskBase.run)(runnable_status, task, task.__class__) # always run
399                 task.post_run = type(Task.TaskBase.run)(post_run, task, task.__class__)
400
401         # TODO the case with no outputs?
402
403 def post_run(self):
404         for x in self.outputs:
405                 x.sig = Utils.h_file(x.abspath())
406
407 def runnable_status(self):
408         return self.RUN_ME
409
410 Task.task_factory('copy', vars=[], func=action_process_file_func)