buildcopy.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. # Calle Rosenquist, 2017 (xbreak)
  4. """
  5. Create task that copies source files to the associated build node.
  6. This is useful to e.g. construct a complete Python package so it can be unit tested
  7. without installation.
  8. Source files to be copied can be specified either in `buildcopy_source` attribute, or
  9. `source` attribute. If both are specified `buildcopy_source` has priority.
  10. Examples::
  11. def build(bld):
  12. bld(name = 'bar',
  13. features = 'py buildcopy',
  14. source = bld.path.ant_glob('src/bar/*.py'))
  15. bld(name = 'py baz',
  16. features = 'buildcopy',
  17. buildcopy_source = bld.path.ant_glob('src/bar/*.py') + ['src/bar/resource.txt'])
  18. """
  19. import os, shutil
  20. from waflib import Errors, Task, TaskGen, Utils, Node
  21. @TaskGen.before_method('process_source')
  22. @TaskGen.feature('buildcopy')
  23. def make_buildcopy(self):
  24. """
  25. Creates the buildcopy task.
  26. """
  27. def to_src_nodes(lst):
  28. """Find file nodes only in src, TaskGen.to_nodes will not work for this since it gives
  29. preference to nodes in build.
  30. """
  31. if isinstance(lst, Node.Node):
  32. if not lst.is_src():
  33. raise Errors.WafError('buildcopy: node %s is not in src'%lst)
  34. if not os.path.isfile(lst.abspath()):
  35. raise Errors.WafError('buildcopy: Cannot copy directory %s (unsupported action)'%lst)
  36. return lst
  37. if isinstance(lst, str):
  38. lst = [x for x in Utils.split_path(lst) if x and x != '.']
  39. node = self.bld.path.get_src().search_node(lst)
  40. if node:
  41. if not os.path.isfile(node.abspath()):
  42. raise Errors.WafError('buildcopy: Cannot copy directory %s (unsupported action)'%node)
  43. return node
  44. node = self.bld.path.get_src().find_node(lst)
  45. if node:
  46. if not os.path.isfile(node.abspath()):
  47. raise Errors.WafError('buildcopy: Cannot copy directory %s (unsupported action)'%node)
  48. return node
  49. raise Errors.WafError('buildcopy: File not found in src: %s'%os.path.join(*lst))
  50. nodes = [ to_src_nodes(n) for n in getattr(self, 'buildcopy_source', getattr(self, 'source', [])) ]
  51. node_pairs = [(n, n.get_bld()) for n in nodes]
  52. self.create_task('buildcopy', [n[0] for n in node_pairs], [n[1] for n in node_pairs], node_pairs=node_pairs)
  53. class buildcopy(Task.Task):
  54. """
  55. Copy for each pair `n` in `node_pairs`: n[0] -> n[1].
  56. Attribute `node_pairs` should contain a list of tuples describing source and target:
  57. node_pairs = [(in, out), ...]
  58. """
  59. color = 'PINK'
  60. def keyword(self):
  61. return 'Copying'
  62. def run(self):
  63. for f,t in self.node_pairs:
  64. t.parent.mkdir()
  65. shutil.copy2(f.abspath(), t.abspath())