/web2py/applications/admin/controllers/gae.py

https://gitlab.com/sunkistm/gitlab-web2py · Python · 105 lines · 90 code · 14 blank · 1 comment · 18 complexity · aaab48963ece61f126334c5dbefb9862 MD5 · raw file

  1. ### this works on linux only
  2. import re
  3. try:
  4. import fcntl
  5. import subprocess
  6. import signal
  7. import os
  8. import shutil
  9. from gluon.fileutils import read_file, write_file
  10. except:
  11. session.flash = 'sorry, only on Unix systems'
  12. redirect(URL(request.application, 'default', 'site'))
  13. if MULTI_USER_MODE and not is_manager():
  14. session.flash = 'Not Authorized'
  15. redirect(URL('default', 'site'))
  16. from gluon.settings import settings
  17. if not settings.is_source:
  18. session.flash = 'Requires running web2py from source'
  19. redirect(URL(request.application, 'default', 'site'))
  20. forever = 10 ** 8
  21. def kill():
  22. p = cache.ram('gae_upload', lambda: None, forever)
  23. if not p or p.poll() is not None:
  24. return 'oops'
  25. os.kill(p.pid, signal.SIGKILL)
  26. cache.ram('gae_upload', lambda: None, -1)
  27. class EXISTS(object):
  28. def __init__(self, error_message='file not found'):
  29. self.error_message = error_message
  30. def __call__(self, value):
  31. if os.path.exists(value):
  32. return (value, None)
  33. return (value, self.error_message)
  34. def deploy():
  35. regex = re.compile('^\w+$')
  36. apps = sorted(
  37. file for file in os.listdir(apath(r=request)) if regex.match(file))
  38. form = SQLFORM.factory(
  39. Field('appcfg', default=GAE_APPCFG, label=T('Path to appcfg.py'),
  40. requires=EXISTS(error_message=T('file not found'))),
  41. Field('google_application_id', requires=IS_MATCH(
  42. '[\w\-]+'), label=T('Google Application Id')),
  43. Field('applications', 'list:string',
  44. requires=IS_IN_SET(apps, multiple=True),
  45. label=T('web2py apps to deploy')),
  46. Field('email', requires=IS_EMAIL(), label=T('GAE Email')),
  47. Field('password', 'password', requires=IS_NOT_EMPTY(), label=T('GAE Password')))
  48. cmd = output = errors = ""
  49. if form.accepts(request, session):
  50. try:
  51. kill()
  52. except:
  53. pass
  54. ignore_apps = [item for item in apps
  55. if not item in form.vars.applications]
  56. regex = re.compile('\(applications/\(.*')
  57. yaml = apath('../app.yaml', r=request)
  58. if not os.path.exists(yaml):
  59. example = apath('../app.example.yaml', r=request)
  60. shutil.copyfile(example, yaml)
  61. data = read_file(yaml)
  62. data = re.sub('application:.*', 'application: %s' %
  63. form.vars.google_application_id, data)
  64. data = regex.sub(
  65. '(applications/(%s)/.*)|' % '|'.join(ignore_apps), data)
  66. write_file(yaml, data)
  67. path = request.env.applications_parent
  68. cmd = '%s --email=%s --passin update %s' % \
  69. (form.vars.appcfg, form.vars.email, path)
  70. p = cache.ram('gae_upload',
  71. lambda s=subprocess, c=cmd: s.Popen(c, shell=True,
  72. stdin=s.PIPE,
  73. stdout=s.PIPE,
  74. stderr=s.PIPE, close_fds=True), -1)
  75. p.stdin.write(form.vars.password + '\n')
  76. fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
  77. fcntl.fcntl(p.stderr.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
  78. return dict(form=form, command=cmd)
  79. def callback():
  80. p = cache.ram('gae_upload', lambda: None, forever)
  81. if not p or p.poll() is not None:
  82. return '<done/>'
  83. try:
  84. output = p.stdout.read()
  85. except:
  86. output = ''
  87. try:
  88. errors = p.stderr.read()
  89. except:
  90. errors = ''
  91. return (output + errors).replace('\n', '<br/>')