app.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import uuid
  2. import os
  3. import subprocess
  4. import zipfile
  5. import urllib.request
  6. import gzip
  7. from io import BytesIO
  8. import time
  9. import json
  10. from flask import Flask, render_template, request, flash
  11. # Directory of this file
  12. this_path = os.path.dirname(os.path.realpath(__file__))
  13. # Where the user requested tile are stored
  14. output_path = os.path.join(this_path, '..', 'userRequestFirmware')
  15. # Where the data database is
  16. tile_path = os.path.join(this_path, '..', 'data', 'tiles')
  17. # The output folder for all gzipped build requests
  18. app = Flask(__name__, static_url_path='/builds', static_folder=output_path,)
  19. def compressFiles(fileList, uuidkey):
  20. # create a zip file comprised of dat.gz tiles
  21. zipthis = os.path.join(output_path, uuidkey + '.zip')
  22. # create output dirs if needed
  23. try:
  24. os.makedirs(output_path)
  25. except OSError:
  26. pass
  27. try:
  28. os.makedirs(tile_path)
  29. except OSError:
  30. pass
  31. try:
  32. with zipfile.ZipFile(zipthis, 'w') as terrain_zip:
  33. for fn in fileList:
  34. if not os.path.exists(fn):
  35. #download if required
  36. print("Downloading " + os.path.basename(fn))
  37. g = urllib.request.urlopen('https://terrain.ardupilot.org/data/tiles/' +
  38. os.path.basename(fn))
  39. print("Downloaded " + os.path.basename(fn))
  40. with open(fn, 'b+w') as f:
  41. f.write(g.read())
  42. # need to decompress file and pass to zip
  43. with gzip.open(fn, 'r') as f_in:
  44. myio = BytesIO(f_in.read())
  45. print("Decomp " + os.path.basename(fn))
  46. # and add file to zip
  47. terrain_zip.writestr(os.path.basename(fn)[:-3], myio.read(),
  48. compress_type=zipfile.ZIP_DEFLATED)
  49. except Exception as ex:
  50. print("Unexpected error: {0}".format(ex))
  51. return False
  52. return True
  53. @app.route('/')
  54. def index():
  55. return render_template('index.html')
  56. def run_build(taskfile):
  57. # run a build with parameters from task
  58. task = json.loads(open(taskfile).read())
  59. builddir = '/tmp/build'
  60. subprocess.run(['./waf', 'configure',
  61. '--board', task['board'],
  62. '--out', builddir,
  63. '--extra-hwdef', task['extra_hwdef']],
  64. cwd = task['sourcedir'])
  65. subprocess.run(['./waf', 'clean'], cwd = task['sourcedir'])
  66. subprocess.run(['./waf', task['vehicle']], cwd = task['sourcedir'])
  67. @app.route('/generate', methods=['GET', 'POST'])
  68. def generate():
  69. if request.method == 'POST':
  70. features = []
  71. task = {}
  72. # fetch features from user input
  73. for i in range(1,8):
  74. value = request.form["option" + str(i)]
  75. features.append(value)
  76. undefine = "undef " + value.split()[1]
  77. features.insert(0,undefine)
  78. extra_hwdef = '\n'.join(features)
  79. print("features: ", features)
  80. # create extra_hwdef.dat file and obtain md5sum
  81. file = open('buildqueue/extra_hwdef.dat',"w")
  82. file.write(extra_hwdef)
  83. file.close()
  84. md5sum = subprocess.check_output(['md5sum', 'buildqueue/extra_hwdef.dat'],
  85. encoding = 'utf-8')
  86. md5sum = md5sum[:len(md5sum)-29]
  87. os.remove('buildqueue/extra_hwdef.dat')
  88. # define source and app directories
  89. sourcedir = os.path.abspath('../ardupilot/')
  90. appdir = os.path.abspath(os.curdir)
  91. # obtain git-hash of source
  92. git_hash = subprocess.check_output(['git', 'rev-parse', 'HEAD'],
  93. cwd = sourcedir,
  94. encoding = 'utf-8')
  95. git_hash = git_hash[:len(git_hash)-1]
  96. # create directories using concatenated token of git-hash and md5sum of hwdef
  97. token = git_hash + "-" + md5sum
  98. buildqueue_dir = os.path.join(appdir, 'buildqueue', token)
  99. if not os.path.isdir(buildqueue_dir):
  100. os.mkdir(buildqueue_dir)
  101. file = open(os.path.join(buildqueue_dir, 'extra_hwdef.dat'),"w")
  102. file.write(extra_hwdef)
  103. file.close()
  104. # fill dictionary of variables and create json file
  105. task['hwdef_md5sum'] = md5sum
  106. task['git_hash'] = git_hash
  107. task['sourcedir'] = sourcedir
  108. task['extra_hwdef'] = os.path.join(buildqueue_dir, 'extra_hwdef.dat')
  109. task['board'] = request.form["board"]
  110. task['vehicle'] = request.form["vehicle"]
  111. jfile = open('{}/q.json'.format(buildqueue_dir), "w")
  112. jfile.write(json.dumps(task))
  113. jfile.close()
  114. print(task)
  115. # run build and rename build directory
  116. builddir = os.path.join('/private/tmp/build', token)
  117. if os.path.isdir(builddir):
  118. print("Build already exists")
  119. else:
  120. run_build(os.path.join(buildqueue_dir, 'q.json'))
  121. os.rename(os.path.join('/private/tmp/build', task['board']), builddir)
  122. # remove working files
  123. os.remove(os.path.join(buildqueue_dir, 'extra_hwdef.dat'))
  124. os.remove(os.path.join(buildqueue_dir, 'q.json'))
  125. os.rmdir(buildqueue_dir)
  126. return render_template('generate.html')
  127. # remove duplicates
  128. #filelist = list(dict.fromkeys(filelist))
  129. #print(filelist)
  130. #compress
  131. #success = compressFiles(filelist, uuidkey)
  132. # as a cleanup, remove any generated terrain older than 24H
  133. #for f in os.listdir(output_path):
  134. # if os.stat(os.path.join(output_path, f)).st_mtime < time.time() - 24 * 60 * 60:
  135. # print("Removing old file: " + str(os.path.join(output_path, f)))
  136. # os.remove(os.path.join(output_path, f))
  137. #if success:
  138. # print("Generated " + "/terrain/" + uuidkey + ".zip")
  139. # return render_template('generate.html', urlkey="/terrain/" + uuidkey + ".zip",
  140. # uuidkey=uuidkey, outsideLat=outsideLat)
  141. #else:
  142. # print("Failed " + "/terrain/" + uuidkey + ".zip")
  143. # return render_template('generate.html', error="Cannot generate terrain",
  144. # uuidkey=uuidkey)
  145. else:
  146. print("Bad get")
  147. return render_template('generate.html', error="Need to use POST, not GET")
  148. if __name__ == "__main__":
  149. app.run()