build_handler.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. """Tornado handlers for frontend config storage."""
  2. # Copyright (c) Jupyter Development Team.
  3. # Distributed under the terms of the Modified BSD License.
  4. import json
  5. from tornado import gen, web
  6. from notebook.base.handlers import APIHandler
  7. from .commands import build_async, clean, should_build
  8. class Builder(object):
  9. building = False
  10. canceled = False
  11. _canceling = False
  12. _future = None
  13. def __init__(self, log, core_mode, app_dir):
  14. self.log = log
  15. self.core_mode = core_mode
  16. self.app_dir = app_dir
  17. def get_status(self):
  18. if self.core_mode:
  19. return dict(status='stable', message='')
  20. if self.building:
  21. return dict(status='building', message='')
  22. needed, message = should_build(self.app_dir)
  23. status = 'needed' if needed else 'stable'
  24. return dict(status=status, message=message)
  25. @gen.coroutine
  26. def build(self):
  27. if self._canceling:
  28. raise ValueError('Cancel in progress')
  29. if not self.building:
  30. self.canceled = False
  31. self._future = future = gen.Future()
  32. self.building = True
  33. try:
  34. yield self._run_build()
  35. future.set_result(True)
  36. except Exception as e:
  37. if str(e) == 'Aborted':
  38. future.set_result(False)
  39. else:
  40. future.set_exception(e)
  41. finally:
  42. self.building = False
  43. try:
  44. yield self._future
  45. except Exception as e:
  46. raise e
  47. @gen.coroutine
  48. def cancel(self):
  49. if not self.building:
  50. raise ValueError('No current build')
  51. self._canceling = True
  52. yield self._future
  53. self._canceling = False
  54. self.canceled = True
  55. @gen.coroutine
  56. def _run_build(self):
  57. app_dir = self.app_dir
  58. log = self.log
  59. callback = self._abort_callback
  60. try:
  61. yield build_async(app_dir, logger=log, abort_callback=callback)
  62. except Exception as e:
  63. if str(e) == 'Aborted':
  64. raise e
  65. self.log.warn('Build failed, running a clean and rebuild')
  66. clean(app_dir)
  67. yield build_async(app_dir, logger=log, abort_callback=callback)
  68. def _abort_callback(self):
  69. return self._canceling
  70. class BuildHandler(APIHandler):
  71. def initialize(self, builder):
  72. self.builder = builder
  73. @web.authenticated
  74. @gen.coroutine
  75. def get(self):
  76. data = self.builder.get_status()
  77. self.finish(json.dumps(data))
  78. @web.authenticated
  79. @gen.coroutine
  80. def delete(self):
  81. self.log.warn('Canceling build')
  82. try:
  83. yield self.builder.cancel()
  84. except Exception as e:
  85. raise web.HTTPError(500, str(e))
  86. self.set_status(204)
  87. @web.authenticated
  88. @gen.coroutine
  89. def post(self):
  90. self.log.debug('Starting build')
  91. try:
  92. yield self.builder.build()
  93. except Exception as e:
  94. raise web.HTTPError(500, str(e))
  95. if self.builder.canceled:
  96. raise web.HTTPError(400, 'Build canceled')
  97. self.log.debug('Build succeeded')
  98. self.set_status(200)
  99. # The path for lab build.
  100. build_path = r"/lab/api/build"