app.py 6.6 KB

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