You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
5.3 KiB
180 lines
5.3 KiB
#!/usr/bin/env python3 |
|
''' |
|
script to build a html file showing flash free for current builds |
|
|
|
AP_FLAKE8_CLEAN |
|
''' |
|
|
|
import os |
|
import argparse |
|
import fnmatch |
|
import json |
|
from datetime import datetime |
|
|
|
parser = argparse.ArgumentParser(description='create builds.html for list of builds') |
|
parser.add_argument('basedir', default=None, help='base directory (binaries directory)') |
|
parser.add_argument('--outfile', default="builds.html", help='output file') |
|
|
|
build_dirs = ['latest', 'beta', 'stable'] |
|
builds = ['Plane', 'Copter', 'Rover', 'Sub', 'Blimp', 'AntennaTracker', 'AP_Periph'] |
|
|
|
args = parser.parse_args() |
|
|
|
warning_flash_free = 5000 |
|
warning_build_days = 3 |
|
|
|
|
|
class APJInfo: |
|
def __init__(self, vehicle, board, githash, mtime, flash_free): |
|
self.vehicle = vehicle |
|
self.board = board |
|
self.githash = githash |
|
self.mtime = mtime |
|
self.flash_free = flash_free |
|
self.warning = 0 |
|
|
|
|
|
def apj_list(basedir): |
|
'''list of APJInfo for one directory''' |
|
boards = [] |
|
for root, subdirs, files in os.walk(basedir): |
|
for f in files: |
|
if not fnmatch.fnmatch(f, "*.apj"): |
|
continue |
|
fname = os.path.join(root, f) |
|
board = os.path.basename(root) |
|
vehicle = fname.split('/')[-4] |
|
fw_json = json.load(open(fname, "r")) |
|
githash = fw_json['git_identity'] |
|
flash_free = fw_json.get('flash_free', -1) |
|
mtime = os.stat(fname).st_mtime |
|
apjinfo = APJInfo(vehicle, board, githash, mtime, flash_free) |
|
boards.append(apjinfo) |
|
return boards |
|
|
|
|
|
def write_headers(h): |
|
'''write html headers''' |
|
h.write(''' |
|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<script src="sorttable.js"></script> |
|
<script src="filtertable.js"></script> |
|
<link href="../../css/main.css" rel="stylesheet" type="text/css" /> |
|
<style> |
|
td { |
|
border-left:1px solid black; |
|
border-top:1px solid black; |
|
} |
|
th { |
|
text-align: left; |
|
border-left:1px solid black; |
|
border-top:1px solid black; |
|
} |
|
table { |
|
border-right:1px solid black; |
|
border-bottom:1px solid black; |
|
} |
|
a { |
|
color: inherit; |
|
} |
|
</style> |
|
<title>Build List</title> |
|
</head> |
|
<body> |
|
<div id="main"> |
|
<a href="https://firmware.ardupilot.org/"> |
|
<div id="logo" style="text-align:center;"> |
|
</div> |
|
</a> |
|
<h2 id='top'>Build List</h2> |
|
<p>This is an auto-generated list of current builds |
|
allowing us to quickly see how close we are to running out of flash space. |
|
<br>This page was most recently regenerated on %s UTC.</p> |
|
<p>Builds that are coloured red haven't built recently. Builds that are coloured yellow have low flash space remaining.</p> |
|
<p>Click on any column header to sort by that column, or filter by entering a search term in the box above each table.</p> |
|
<ul> |
|
<li>Jump to <a href='#latest'>latest</a></li> |
|
<li>Jump to <a href='#beta'>beta</a></li> |
|
<li>Jump to <a href='#stable'>stable</a></li> |
|
</ul> |
|
''' % datetime.now().strftime("%F %k:%M")) |
|
|
|
|
|
def write_footer(h): |
|
'''write html footer''' |
|
h.write(''' |
|
</div> |
|
</body> |
|
</html> |
|
''') |
|
|
|
|
|
def write_table(h, build_type): |
|
'''write table for one build type''' |
|
boards = [] |
|
|
|
for build in builds: |
|
boards.extend(apj_list(os.path.join(args.basedir, build, build_type))) |
|
|
|
max_mtime = 0 |
|
for apjinfo in boards: |
|
if apjinfo.mtime > max_mtime: |
|
max_mtime = apjinfo.mtime |
|
|
|
for apjinfo in boards: |
|
if apjinfo.flash_free < warning_flash_free and not apjinfo.flash_free == -1: |
|
apjinfo.warning = 1 |
|
if int(apjinfo.mtime) < int(max_mtime)-warning_build_days*86400 and build_type == "latest": |
|
apjinfo.warning = 2 |
|
|
|
boards.sort(key=lambda board: board.warning, reverse=True) |
|
|
|
try: |
|
idxs1 = [i for (i, e) in enumerate(boards) if e.warning == 1] |
|
boards[min(idxs1):max(idxs1)] = sorted(boards[min(idxs1):max(idxs1)], key=lambda board: board.flash_free) |
|
except ValueError: |
|
pass |
|
|
|
try: |
|
idxs2 = [i for (i, e) in enumerate(boards) if e.warning == 2] |
|
boards[min(idxs2):max(idxs2)] = sorted(boards[min(idxs2):max(idxs2)], key=lambda board: board.mtime) |
|
except ValueError: |
|
pass |
|
|
|
h.write(''' |
|
<h3 id='%s'>%s builds</h3> |
|
<p><input type="text" id="search_%s" onkeyup="searchFunc('%s')" placeholder="Filter..."></p> |
|
<table class="sortable" id="table_%s"> |
|
<tr><th style="width:90px">Vehicle</th><th style="width:250px">Board</th><th style="width:140px">Build Date</th> |
|
<th style="width:100px">git hash</th><th style="width:100px">Flash Free</th></tr> |
|
''' % (build_type, build_type.capitalize(), build_type, build_type, build_type)) |
|
|
|
for apjinfo in boards: |
|
if apjinfo.warning == 1: |
|
h.write('<tr style="color:#E6B800;">') |
|
elif apjinfo.warning == 2: |
|
h.write('<tr style="color:#FF0000;">') |
|
else: |
|
h.write('<tr>') |
|
h.write('''<td>%s</td> |
|
<td><a href="https://firmware.ardupilot.org/%s/%s/%s">%s</a></td> |
|
<td>%s</td> |
|
<td><a href="https://github.com/ArduPilot/ardupilot/commit/%s">%s</a></td> |
|
<td>%u</td></tr>\n''' % ( |
|
apjinfo.vehicle, apjinfo.vehicle, build_type, apjinfo.board, apjinfo.board, |
|
datetime.fromtimestamp(apjinfo.mtime).strftime("%F %k:%M"), |
|
apjinfo.githash, apjinfo.githash, apjinfo.flash_free)) |
|
|
|
h.write(''' |
|
</table> |
|
<p>Return to <a href='#top'>top</a></p> |
|
''') |
|
|
|
|
|
h = open(args.outfile, "w") |
|
write_headers(h) |
|
for t in build_dirs: |
|
write_table(h, t) |
|
write_footer(h)
|
|
|