jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

414 lines
11KB

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