daemon.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. # Matthias Jahn 2006
  4. # rewritten by Thomas Nagy 2009
  5. """
  6. Start a new build as soon as something changes in the build directory.
  7. PyInotify, Fam, Gamin or time-threshold are used for the detection
  8. For now only PyInotify and time threshold are supported
  9. Watching for new svn revisions could be added too
  10. """
  11. import select, errno, os, time
  12. from waflib import Utils, Scripting, Logs, Build, Node, Context, Options
  13. w_pyinotify = w_fam = w_gamin = None
  14. def check_support():
  15. global w_pyinotify, w_fam, w_gamin
  16. try:
  17. import pyinotify as w_pyinotify
  18. except ImportError:
  19. w_pyinotify = None
  20. else:
  21. try:
  22. wm = w_pyinotify.WatchManager()
  23. wm = w_pyinotify.Notifier(wm)
  24. wm = None
  25. except:
  26. raise
  27. w_pyinotify = None
  28. try:
  29. import gamin as w_gamin
  30. except ImportError:
  31. w_gamin = None
  32. else:
  33. try:
  34. test = w_gamin.WatchMonitor()
  35. test.disconnect()
  36. test = None
  37. except:
  38. w_gamin = None
  39. try:
  40. import _fam as w_fam
  41. except ImportError:
  42. w_fam = None
  43. else:
  44. try:
  45. test = w_fam.open()
  46. test.close()
  47. test = None
  48. except:
  49. w_fam = None
  50. def daemon(ctx):
  51. """waf command: rebuild as soon as something changes"""
  52. bld = None
  53. while True:
  54. bld = Context.create_context('build')
  55. try:
  56. bld.options = Options.options
  57. bld.cmd = 'build'
  58. bld.execute()
  59. except ctx.errors.WafError as e:
  60. print(e)
  61. except KeyboardInterrupt:
  62. Utils.pprint('RED', 'interrupted')
  63. break
  64. try:
  65. x = ctx.state
  66. except AttributeError:
  67. setattr(ctx, 'state', DirWatch())
  68. x = ctx.state
  69. x.wait(bld)
  70. def options(opt):
  71. """So this shows how to add new commands from tools"""
  72. Context.g_module.__dict__['daemon'] = daemon
  73. class DirWatch(object):
  74. def __init__(self):
  75. check_support()
  76. if w_pyinotify:
  77. self.sup = 'pyinotify'
  78. elif w_gamin:
  79. self.sup = 'gamin'
  80. elif w_fam:
  81. self.sup = 'fam'
  82. else:
  83. self.sup = 'dumb'
  84. #self.sup = 'dumb'
  85. def wait(self, bld):
  86. return getattr(self.__class__, 'wait_' + self.sup)(self, bld)
  87. def enumerate(self, node):
  88. if os.path.exists(node.abspath()):
  89. yield node.abspath()
  90. try:
  91. for x in node.children.values():
  92. for k in self.enumerate(x):
  93. yield k
  94. except AttributeError:
  95. pass
  96. def wait_pyinotify(self, bld):
  97. class PE(w_pyinotify.ProcessEvent):
  98. def stop(self, event):
  99. self.notif.ev = True
  100. self.notif.stop()
  101. raise ValueError("stop for delete")
  102. process_IN_DELETE = stop
  103. process_IN_CLOSE = stop
  104. process_default = stop
  105. proc = PE()
  106. wm = w_pyinotify.WatchManager()
  107. notif = w_pyinotify.Notifier(wm, proc)
  108. proc.notif = notif
  109. # well, we should add all the folders to watch here
  110. for x in self.enumerate(bld.srcnode):
  111. wm.add_watch(x, w_pyinotify.IN_DELETE | w_pyinotify.IN_CLOSE_WRITE)
  112. try:
  113. # pyinotify uses an infinite loop ... not too nice, so we have to use an exception
  114. notif.loop()
  115. except ValueError:
  116. pass
  117. if not hasattr(notif, 'ev'):
  118. raise KeyboardInterrupt
  119. def wait_dumb(self, bld):
  120. time.sleep(5)
  121. def wait_gamin(self, bld):
  122. time.sleep(5)
  123. def wait_fam(self, bld):
  124. time.sleep(5)