2016-02-29 01:18:41 -04:00
|
|
|
#!/usr/bin/python
|
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import re
|
2019-04-29 03:46:18 -03:00
|
|
|
import fnmatch
|
2019-04-29 23:36:07 -03:00
|
|
|
import gen_stable
|
2019-06-26 23:21:25 -03:00
|
|
|
import subprocess
|
2019-04-29 03:46:18 -03:00
|
|
|
|
2019-10-24 08:35:47 -03:00
|
|
|
FIRMWARE_TYPES = ["AntennaTracker", "Copter", "Plane", "Rover", "Sub", "AP_Periph"]
|
2019-06-26 16:14:41 -03:00
|
|
|
RELEASE_TYPES = ["beta", "latest", "stable", "stable-*", "dirty"]
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2019-05-05 00:52:15 -03:00
|
|
|
# mapping for board names to brand name and manufacturer
|
|
|
|
brand_map = {
|
|
|
|
'Pixhawk4' : ('Pixhawk 4', 'Holybro'),
|
2019-07-31 23:57:10 -03:00
|
|
|
'Durandal' : ('Durandal', 'Holybro'),
|
2019-05-05 00:52:15 -03:00
|
|
|
'PH4-mini' : ('Pixhawk 4 Mini', 'Holybro'),
|
|
|
|
'KakuteF4' : ('KakuteF4', 'Holybro'),
|
|
|
|
'KakuteF7' : ('KakuteF7', 'Holybro'),
|
2019-12-27 14:41:11 -04:00
|
|
|
'KakuteF7Mini' : ('KakuteF7Mini', 'Holybro'),
|
2019-05-05 00:52:15 -03:00
|
|
|
'CubeBlack' : ('CubeBlack', 'Hex/ProfiCNC'),
|
|
|
|
'CubeYellow' : ('CubeYellow', 'Hex/ProfiCNC'),
|
|
|
|
'CubeOrange' : ('CubeOrange', 'Hex/ProfiCNC'),
|
|
|
|
'CubePurple' : ('CubePurple', 'Hex/ProfiCNC'),
|
|
|
|
'CubeSolo' : ('CubeSolo', '3DR'),
|
|
|
|
'CubeGreen-solo' : ('CubeGreen Solo', 'Hex/ProfiCNC'),
|
|
|
|
'CUAVv5' : ('CUAVv5', 'CUAV'),
|
|
|
|
'CUAVv5Nano' : ('CUAVv5 Nano', 'CUAV'),
|
2020-02-11 23:55:32 -04:00
|
|
|
'CUAV-Nora' : ('CUAV Nora', 'CUAV'),
|
2020-04-11 02:37:24 -03:00
|
|
|
'CUAV-X7' : ('CUAV X7', 'CUAV'),
|
2019-05-05 00:52:15 -03:00
|
|
|
'DrotekP3Pro' : ('Pixhawk 3 Pro', 'Drotek'),
|
|
|
|
'MatekF405' : ('Matek F405', 'Matek'),
|
|
|
|
'MatekF405-STD' : ('Matek F405 STD', 'Matek'),
|
|
|
|
'MatekF405-Wing' : ('Matek F405 Wing', 'Matek'),
|
|
|
|
'mini-pix' : ('MiniPix', 'Radiolink'),
|
|
|
|
'Pixhawk1' : ('Pixhawk1', 'mRobotics'),
|
|
|
|
'Pixracer' : ('PixRacer', 'mRobotics'),
|
|
|
|
'mRoX21' : ('mRo X2.1', 'mRobotics'),
|
|
|
|
'mRoX21-777' : ('mRo X2.1-777', 'mRobotics'),
|
2020-04-22 05:26:44 -03:00
|
|
|
'mRoNexus' : ('mRo Nexus', 'mRobotics'),
|
2019-05-05 00:52:15 -03:00
|
|
|
'TBS-Colibri-F7' : ('Colibri F7', 'TBS'),
|
|
|
|
'sparky2' : ('Sparky2', 'TauLabs'),
|
|
|
|
'mindpx-v2' : ('MindPX V2', 'AirMind'),
|
|
|
|
'OMNIBUSF7V2' : ('Omnibus F7 V2', 'Airbot'),
|
|
|
|
'omnibusf4pro' : ('Omnibus F4 Pro', 'Airbot'),
|
|
|
|
'omnibusf4v6' : ('Omnibus F4 V6', 'Airbot'),
|
|
|
|
'OmnibusNanoV6' : ('Omnibus Nano V6', 'Airbot'),
|
|
|
|
'speedybeef4' : ('SpeedyBee F4', 'SpeedyBee'),
|
|
|
|
}
|
2017-10-26 20:30:53 -03:00
|
|
|
|
2016-02-29 01:18:41 -04:00
|
|
|
class Firmware():
|
2017-10-26 20:30:53 -03:00
|
|
|
def __init__(self,
|
|
|
|
date=None,
|
|
|
|
platform=None,
|
|
|
|
vehicletype=None,
|
|
|
|
filepath=None,
|
|
|
|
git_sha=None,
|
|
|
|
frame=None):
|
2016-02-29 01:18:41 -04:00
|
|
|
self.atts = dict()
|
|
|
|
self.atts["date"] = date
|
|
|
|
self.atts["platform"] = platform
|
|
|
|
self.atts["vehicletype"] = vehicletype
|
|
|
|
self.atts["filepath"] = filepath
|
|
|
|
self.atts["git_sha"] = git_sha
|
|
|
|
self.atts["frame"] = frame
|
|
|
|
self.atts["release-type"] = None
|
|
|
|
self.atts["firmware-version"] = None
|
|
|
|
|
2017-10-26 20:30:53 -03:00
|
|
|
def __getitem__(self, what):
|
2016-02-29 01:18:41 -04:00
|
|
|
return self.atts[what]
|
|
|
|
|
2017-10-26 20:30:53 -03:00
|
|
|
def __setitem__(self, name, value):
|
2016-02-29 01:18:41 -04:00
|
|
|
self.atts[name] = value
|
|
|
|
|
2017-10-26 20:30:53 -03:00
|
|
|
|
2016-02-29 01:18:41 -04:00
|
|
|
class ManifestGenerator():
|
2017-10-26 20:30:53 -03:00
|
|
|
'''Return a JSON string describing "binary" directory contents under
|
|
|
|
basedir'''
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2017-10-26 20:30:53 -03:00
|
|
|
def __init__(self, basedir, baseurl):
|
2016-02-29 01:18:41 -04:00
|
|
|
self.basedir = basedir
|
|
|
|
self.baseurl = baseurl
|
|
|
|
|
|
|
|
def frame_map(self, frame):
|
2017-10-26 20:30:53 -03:00
|
|
|
'''translate from ArduPilot frame type terminology into mavlink
|
|
|
|
terminology'''
|
2016-02-29 01:18:41 -04:00
|
|
|
frame_to_mavlink_dict = {
|
|
|
|
"quad": "QUADROTOR",
|
|
|
|
"hexa": "HEXAROTOR",
|
|
|
|
"y6": "ARDUPILOT_Y6",
|
|
|
|
"tri": "TRICOPTER",
|
|
|
|
"octa": "OCTOROTOR",
|
|
|
|
"octa-quad": "ARDUPILOT_OCTAQUAD",
|
|
|
|
"heli": "HELICOPTER",
|
|
|
|
"Plane": "FIXED_WING",
|
|
|
|
"AntennaTracker": "ANTENNA_TRACKER",
|
|
|
|
"Rover": "GROUND_ROVER",
|
2019-10-24 08:35:47 -03:00
|
|
|
"Sub": "SUBMARINE",
|
|
|
|
"AP_Periph": "CAN_PERIPHERAL",
|
2016-02-29 01:18:41 -04:00
|
|
|
}
|
|
|
|
if frame in frame_to_mavlink_dict:
|
|
|
|
return frame_to_mavlink_dict[frame]
|
|
|
|
|
|
|
|
return frame
|
|
|
|
|
|
|
|
def releasetype_map(self, releasetype):
|
2017-10-26 20:30:53 -03:00
|
|
|
'''translate from ArduPilot release type terminology into mavlink
|
|
|
|
terminology'''
|
|
|
|
if releasetype == 'stable':
|
|
|
|
return 'OFFICIAL'
|
2016-02-29 01:18:41 -04:00
|
|
|
return releasetype.upper()
|
|
|
|
|
|
|
|
def looks_like_binaries_directory(self, dir):
|
2017-10-26 20:30:53 -03:00
|
|
|
'''returns True if dir looks like it is a build_binaries.py output
|
|
|
|
directory'''
|
2016-02-29 01:18:41 -04:00
|
|
|
for entry in os.listdir(dir):
|
2019-04-29 03:46:18 -03:00
|
|
|
if entry in FIRMWARE_TYPES:
|
2016-02-29 01:18:41 -04:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def git_sha_from_git_version(self, filepath):
|
2017-10-26 20:30:53 -03:00
|
|
|
'''parses get-version.txt (as emitted by build_binaries.py, returns
|
|
|
|
git sha from it'''
|
2016-02-29 01:18:41 -04:00
|
|
|
content = open(filepath).read()
|
|
|
|
sha_regex = re.compile("commit (?P<sha>[0-9a-f]+)")
|
|
|
|
m = sha_regex.search(content)
|
|
|
|
if m is None:
|
2017-10-26 20:30:53 -03:00
|
|
|
raise Exception(
|
|
|
|
"filepath (%s) does not contain a git sha" % (filepath,))
|
2016-02-29 01:18:41 -04:00
|
|
|
return m.group("sha")
|
|
|
|
|
2019-04-29 03:46:18 -03:00
|
|
|
def add_USB_IDs_PX4(self, firmware):
|
|
|
|
'''add USB IDs to a .px4 firmware'''
|
|
|
|
url = firmware['url']
|
|
|
|
suffix = url.split('-')[-1]
|
|
|
|
if suffix == "v1.px4":
|
|
|
|
firmware['USBID'] = ['0x26AC/0x0010']
|
|
|
|
firmware['board_id'] = 5
|
|
|
|
firmware['bootloader_str'] = ['PX4 BL FMU v1.x']
|
|
|
|
elif suffix in ["v2.px4", "v3.px4"]:
|
|
|
|
firmware['USBID'] = ['0x26AC/0x0011']
|
|
|
|
firmware['board_id'] = 9
|
|
|
|
firmware['bootloader_str'] = ['PX4 BL FMU v2.x']
|
|
|
|
elif suffix == "v4.px4":
|
|
|
|
firmware['USBID'] = ['0x26AC/0x0012']
|
|
|
|
firmware['board_id'] = 11
|
|
|
|
firmware['bootloader_str'] = ['PX4 BL FMU v4.x']
|
|
|
|
elif suffix == "v4pro.px4":
|
|
|
|
firmware['USBID'] = ['0x26AC/0x0013']
|
|
|
|
firmware['board_id'] = 13
|
|
|
|
firmware['bootloader_str'] = ['PX4 BL FMU v4.x PRO']
|
|
|
|
|
|
|
|
def add_USB_IDs_ChibiOS(self, firmware):
|
|
|
|
'''add USB IDs to a ChbiOS apj firmware'''
|
|
|
|
url = firmware['url'][len(self.baseurl)+1:]
|
|
|
|
apj_path = os.path.join(self.basedir, url)
|
|
|
|
if not os.path.exists(apj_path):
|
|
|
|
print("bad apj path %s" % apj_path, file=sys.stderr)
|
|
|
|
return
|
2019-04-29 05:16:12 -03:00
|
|
|
apj_json = json.load(open(apj_path, 'r'))
|
|
|
|
if 'board_id' not in apj_json:
|
2019-04-29 03:46:18 -03:00
|
|
|
print("no board_id in %s" % apj_path, file=sys.stderr)
|
|
|
|
return
|
2019-04-29 05:16:12 -03:00
|
|
|
if 'platform' not in firmware:
|
2019-04-29 03:46:18 -03:00
|
|
|
print("no platform for %s" % apj_path, file=sys.stderr)
|
|
|
|
return
|
|
|
|
board_id = apj_json['board_id']
|
|
|
|
platform = firmware['platform']
|
|
|
|
|
|
|
|
# all ChibiOS builds can have platform as bootloader_str and board_id from
|
|
|
|
# hwdef.dat
|
|
|
|
firmware['board_id'] = board_id
|
|
|
|
firmware['bootloader_str'] = [platform+"-BL"]
|
|
|
|
|
|
|
|
# map of vendor specific USB IDs
|
|
|
|
USBID_MAP = {
|
2019-04-29 05:16:12 -03:00
|
|
|
'CubeBlack': ['0x2DAE/0x1011'],
|
2019-04-29 03:46:18 -03:00
|
|
|
'CubeOrange': ['0x2DAE/0x1016'],
|
|
|
|
'CubePurple': ['0x2DAE/0x1005'],
|
|
|
|
'CubeYellow': ['0x2DAE/0x1002'],
|
2019-04-29 05:16:12 -03:00
|
|
|
'Pixhawk4': ['0x3162/0x0047'],
|
|
|
|
'PH4-mini': ['0x3162/0x0049'],
|
2019-07-31 23:57:10 -03:00
|
|
|
'Durandal': ['0x3162/0x004B'],
|
2019-04-29 05:16:12 -03:00
|
|
|
'VRBrain-v51': ['0x27AC/0x1151'],
|
|
|
|
'VRBrain-v52': ['0x27AC/0x1152'],
|
|
|
|
'VRBrain-v54': ['0x27AC/0x1154'],
|
2019-04-29 03:46:18 -03:00
|
|
|
'VRCore-v10': ['0x27AC/0x1910'],
|
2019-04-29 05:16:12 -03:00
|
|
|
'VRUBrain-v51': ['0x27AC/0x1351']
|
2019-04-29 03:46:18 -03:00
|
|
|
}
|
2019-12-25 17:50:03 -04:00
|
|
|
if 'USBID' in apj_json:
|
|
|
|
# newer APJ files have USBID in the json data
|
2020-01-26 19:16:49 -04:00
|
|
|
firmware['USBID'] = [apj_json['USBID']]
|
2019-12-25 17:50:03 -04:00
|
|
|
elif platform in USBID_MAP:
|
2019-04-29 03:46:18 -03:00
|
|
|
firmware['USBID'] = USBID_MAP[platform]
|
|
|
|
else:
|
|
|
|
# all others use a single USB VID/PID
|
|
|
|
firmware['USBID'] = ['0x0483/0x5740']
|
|
|
|
|
|
|
|
if board_id == 50:
|
|
|
|
# special case for FMUv5, they always get the px4 bootloader IDs as an option
|
|
|
|
firmware['bootloader_str'].append('PX4 BL FMU v5.x')
|
|
|
|
firmware['USBID'].append('0x26AC/0x0032')
|
|
|
|
|
|
|
|
if board_id == 9:
|
|
|
|
# special case for FMUv3, they always get the px4 bootloader IDs as an option
|
|
|
|
firmware['bootloader_str'].append('PX4 BL FMU v2.x')
|
|
|
|
firmware['USBID'].append('0x26AC/0x0011')
|
|
|
|
|
|
|
|
if board_id == 11:
|
|
|
|
# special case for FMUv4, they always get the px4 bootloader IDs as an option
|
|
|
|
firmware['bootloader_str'].append('PX4 BL FMU v4.x')
|
|
|
|
firmware['USBID'].append('0x26AC/0x0012')
|
|
|
|
|
|
|
|
if board_id == 13:
|
|
|
|
# special case for FMUv4pro, they always get the px4 bootloader IDs as an option
|
|
|
|
firmware['bootloader_str'].append('PX4 BL FMU v4.x PRO')
|
|
|
|
firmware['USBID'].append('0x26AC/0x0013')
|
|
|
|
|
|
|
|
if board_id == 88:
|
|
|
|
# special case for MindPX-v2 boards
|
|
|
|
firmware['bootloader_str'].append('MindPX BL FMU v2.x')
|
|
|
|
firmware['USBID'].append('0x26AC/0x0030')
|
|
|
|
|
2019-05-05 00:52:15 -03:00
|
|
|
if platform in brand_map:
|
|
|
|
(brand_name, manufacturer) = brand_map[platform]
|
|
|
|
firmware['brand_name'] = brand_name
|
|
|
|
firmware['manufacturer'] = manufacturer
|
2020-03-10 19:43:06 -03:00
|
|
|
# copy over some extra information if available
|
|
|
|
extra_tags = [ 'image_size' ]
|
|
|
|
for tag in extra_tags:
|
|
|
|
if tag in apj_json:
|
|
|
|
firmware[tag] = apj_json[tag]
|
2019-05-05 00:52:15 -03:00
|
|
|
|
2019-04-29 03:46:18 -03:00
|
|
|
def add_USB_IDs(self, firmware):
|
|
|
|
'''add USB IDs to a firmware'''
|
|
|
|
fmt = firmware['format']
|
|
|
|
if fmt == "px4":
|
|
|
|
self.add_USB_IDs_PX4(firmware)
|
|
|
|
return
|
|
|
|
if fmt == "apj":
|
|
|
|
self.add_USB_IDs_ChibiOS(firmware)
|
|
|
|
return
|
|
|
|
|
2019-06-26 23:21:25 -03:00
|
|
|
def firmware_format_for_filepath(self, filepath):
|
|
|
|
filename = os.path.basename(filepath)
|
|
|
|
if "." in filename:
|
|
|
|
return "".join(filename.split(".")[-1:])
|
|
|
|
# no extension; ensure this is an elf:
|
|
|
|
text = subprocess.check_output(["file", "-b", filepath])
|
|
|
|
if re.match("^ELF", text):
|
|
|
|
return "ELF"
|
|
|
|
print("Unknown file type (%s)" % filepath)
|
|
|
|
print("Got: %s" % text)
|
|
|
|
return "Unknown" # should raise an error somehow
|
|
|
|
|
2017-10-26 20:30:53 -03:00
|
|
|
def add_firmware_data_from_dir(self,
|
|
|
|
dir,
|
|
|
|
firmware_data,
|
|
|
|
vehicletype,
|
|
|
|
releasetype="dev"):
|
|
|
|
'''accumulate additional information about firmwares from directory'''
|
2016-02-29 01:18:41 -04:00
|
|
|
variant_firmware_regex = re.compile("[^-]+-(?P<variant>v\d+)[.px4]")
|
2019-03-11 01:44:28 -03:00
|
|
|
if not os.path.isdir(dir):
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
dlist = os.listdir(dir)
|
|
|
|
except Exception:
|
|
|
|
print("Error listing '%s'" % dir)
|
|
|
|
return
|
|
|
|
for platformdir in dlist:
|
2019-04-29 18:32:54 -03:00
|
|
|
if platformdir.startswith("."):
|
|
|
|
continue
|
2016-02-29 01:18:41 -04:00
|
|
|
some_dir = os.path.join(dir, platformdir)
|
2019-04-29 18:32:54 -03:00
|
|
|
if not os.path.isdir(some_dir):
|
|
|
|
continue
|
|
|
|
git_version_txt = os.path.join(some_dir, "git-version.txt")
|
|
|
|
if not os.path.exists(git_version_txt):
|
|
|
|
print("No file %s" % git_version_txt, file=sys.stderr)
|
|
|
|
continue
|
2016-02-29 01:18:41 -04:00
|
|
|
try:
|
2019-04-29 18:32:54 -03:00
|
|
|
git_sha = self.git_sha_from_git_version(git_version_txt)
|
|
|
|
except Exception as ex:
|
|
|
|
print("Failed to parse %s" % git_version_txt, ex, file=sys.stderr)
|
2016-02-29 01:18:41 -04:00
|
|
|
continue
|
2019-04-29 19:53:08 -03:00
|
|
|
|
|
|
|
# we require a firmware-version.txt. These files have been added to
|
|
|
|
# old builds that didn't have them
|
2017-10-26 20:30:53 -03:00
|
|
|
firmware_version_file = os.path.join(some_dir,
|
|
|
|
"firmware-version.txt")
|
2019-04-29 19:53:08 -03:00
|
|
|
if not os.path.exists(firmware_version_file):
|
|
|
|
print("Missing %s" % firmware_version_file, file=sys.stderr)
|
|
|
|
continue
|
|
|
|
|
2016-02-29 01:18:41 -04:00
|
|
|
try:
|
2016-10-25 01:16:01 -03:00
|
|
|
firmware_version = open(firmware_version_file).read()
|
2016-02-29 01:18:41 -04:00
|
|
|
firmware_version = firmware_version.strip()
|
2019-09-21 03:04:51 -03:00
|
|
|
(_, _) = firmware_version.split("-")
|
2019-04-29 05:16:12 -03:00
|
|
|
except ValueError:
|
2019-04-29 18:32:54 -03:00
|
|
|
print("malformed firmware-version.txt at (%s)" % (firmware_version_file,), file=sys.stderr)
|
2019-04-29 19:53:08 -03:00
|
|
|
continue
|
2019-04-29 18:32:54 -03:00
|
|
|
except Exception as ex:
|
|
|
|
print("bad file %s" % firmware_version_file, file=sys.stderr)
|
2016-02-29 01:18:41 -04:00
|
|
|
# this exception is swallowed.... the current archive
|
|
|
|
# is incomplete.
|
2019-04-29 19:53:08 -03:00
|
|
|
continue
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2019-06-26 16:14:41 -03:00
|
|
|
# Directory names for heli builds end in -heli
|
|
|
|
platform_frame_regex = re.compile("(?P<board>.+)(-(?P<frame>heli)$)")
|
2016-02-29 01:18:41 -04:00
|
|
|
m = platform_frame_regex.match(platformdir)
|
|
|
|
if m is not None:
|
2019-06-26 16:19:08 -03:00
|
|
|
# This is a heli build
|
2017-10-26 20:30:53 -03:00
|
|
|
platform = m.group("board") # e.g. navio
|
2019-06-26 16:14:41 -03:00
|
|
|
frame = "heli"
|
2016-02-29 01:18:41 -04:00
|
|
|
else:
|
2019-06-26 16:14:41 -03:00
|
|
|
# Non-heli build
|
2017-10-26 20:30:53 -03:00
|
|
|
frame = vehicletype # e.g. Plane
|
|
|
|
platform = platformdir # e.g. apm2
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2019-06-26 23:21:25 -03:00
|
|
|
for filename in os.listdir(some_dir):
|
|
|
|
if filename in ["git-version.txt", "firmware-version.txt", "files.html"]:
|
2016-10-24 23:53:18 -03:00
|
|
|
continue
|
2019-06-26 23:21:25 -03:00
|
|
|
if filename.startswith("."):
|
2019-04-29 03:46:18 -03:00
|
|
|
continue
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2019-06-26 23:21:25 -03:00
|
|
|
m = variant_firmware_regex.match(filename)
|
2016-02-29 01:18:41 -04:00
|
|
|
if m:
|
|
|
|
# the platform variant is
|
|
|
|
# encoded in the firmware filename
|
|
|
|
# (e.g. the "v1" in
|
|
|
|
# ArduCopter-v1.px4)
|
|
|
|
variant = m.group("variant")
|
2017-10-26 20:30:53 -03:00
|
|
|
file_platform = "-".join([platform, variant])
|
2016-02-29 01:18:41 -04:00
|
|
|
else:
|
|
|
|
file_platform = platform
|
|
|
|
|
2019-06-26 23:21:25 -03:00
|
|
|
filepath = os.path.join(some_dir, filename)
|
|
|
|
firmware_format = self.firmware_format_for_filepath(filepath)
|
2019-12-29 04:57:06 -04:00
|
|
|
if firmware_format not in [ "ELF", "abin", "apj", "hex", "px4", "bin" ]:
|
2019-06-26 23:21:25 -03:00
|
|
|
print("Unknown firmware format (%s)" % firmware_format)
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2019-04-29 19:53:08 -03:00
|
|
|
firmware = Firmware()
|
2016-02-29 01:18:41 -04:00
|
|
|
|
|
|
|
# translate from supplied "release type" into both a
|
2019-04-29 18:32:54 -03:00
|
|
|
# "latest" flag and an actual release type. Also sort
|
2016-02-29 01:18:41 -04:00
|
|
|
# out which filepath we should use:
|
2017-10-26 20:30:53 -03:00
|
|
|
firmware["latest"] = 0
|
2016-02-29 01:18:41 -04:00
|
|
|
if releasetype == "dev":
|
|
|
|
if firmware["filepath"] is None:
|
2019-06-26 23:21:25 -03:00
|
|
|
firmware["filepath"] = filepath
|
2016-02-29 01:18:41 -04:00
|
|
|
if firmware["release-type"] is None:
|
|
|
|
firmware["release-type"] = "dev"
|
|
|
|
elif releasetype == "latest":
|
|
|
|
firmware["latest"] = 1
|
2019-06-26 23:21:25 -03:00
|
|
|
firmware["filepath"] = filepath
|
2016-02-29 01:18:41 -04:00
|
|
|
if firmware["release-type"] is None:
|
|
|
|
firmware["release-type"] = "dev"
|
|
|
|
else:
|
|
|
|
if (not firmware["latest"]):
|
2019-06-26 23:21:25 -03:00
|
|
|
firmware["filepath"] = filepath
|
2016-02-29 01:18:41 -04:00
|
|
|
firmware["release-type"] = releasetype
|
|
|
|
|
|
|
|
firmware["platform"] = file_platform
|
|
|
|
firmware["vehicletype"] = vehicletype
|
|
|
|
firmware["git_sha"] = git_sha
|
|
|
|
firmware["frame"] = frame
|
|
|
|
firmware["timestamp"] = os.path.getctime(firmware["filepath"])
|
|
|
|
firmware["format"] = firmware_format
|
|
|
|
firmware["firmware-version"] = firmware_version
|
|
|
|
|
2019-04-29 19:53:08 -03:00
|
|
|
firmware_data.append(firmware)
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2019-04-29 05:16:12 -03:00
|
|
|
def valid_release_type(self, tag):
|
2019-04-29 03:46:18 -03:00
|
|
|
'''check for valid release type'''
|
|
|
|
for r in RELEASE_TYPES:
|
|
|
|
if fnmatch.fnmatch(tag, r):
|
|
|
|
return True
|
|
|
|
return False
|
2016-02-29 01:18:41 -04:00
|
|
|
|
|
|
|
def parse_fw_version(self, version):
|
2017-10-26 20:30:53 -03:00
|
|
|
(version_numbers, release_type) = version.split("-")
|
|
|
|
(major, minor, patch) = version_numbers.split(".")
|
|
|
|
return (major, minor, patch, version)
|
2016-02-29 01:18:41 -04:00
|
|
|
|
|
|
|
def walk_directory(self, basedir):
|
2017-10-26 20:30:53 -03:00
|
|
|
'''walks directory structure created by build_binaries, returns Python
|
|
|
|
structure representing releases in that structure'''
|
2016-02-29 01:18:41 -04:00
|
|
|
year_month_regex = re.compile("(?P<year>\d{4})-(?P<month>\d{2})")
|
|
|
|
|
2019-04-29 19:53:08 -03:00
|
|
|
firmwares = []
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2017-10-26 20:30:53 -03:00
|
|
|
# used to listdir basedir here, but since this is also a web
|
|
|
|
# document root, there's a lot of other stuff accumulated...
|
2019-04-29 03:46:18 -03:00
|
|
|
vehicletypes = FIRMWARE_TYPES
|
2016-02-29 01:18:41 -04:00
|
|
|
for vehicletype in vehicletypes:
|
2017-09-04 19:59:21 -03:00
|
|
|
try:
|
2019-04-29 03:46:18 -03:00
|
|
|
# the sort means we prefer 'stable' to 'stable-x.y.z' when they
|
|
|
|
# both contain the same contents
|
|
|
|
vdir = sorted(os.listdir(os.path.join(basedir, vehicletype)), reverse=True)
|
2017-09-04 19:59:21 -03:00
|
|
|
except OSError as e:
|
|
|
|
if e.errno == 2:
|
|
|
|
continue
|
2016-02-29 01:18:41 -04:00
|
|
|
for firstlevel in vdir:
|
2019-04-29 03:46:18 -03:00
|
|
|
if firstlevel == "files.html" or firstlevel.startswith("."):
|
2016-10-24 23:53:18 -03:00
|
|
|
# generated file which should be ignored
|
|
|
|
continue
|
|
|
|
# skip any non-directories (e.g. "files.html"):
|
2016-02-29 01:18:41 -04:00
|
|
|
if year_month_regex.match(firstlevel):
|
|
|
|
# this is a dated directory e.g. binaries/Copter/2016-02
|
2019-03-21 04:49:37 -03:00
|
|
|
# we do not include dated directories in the manifest ATM:
|
|
|
|
continue
|
2019-04-29 19:53:08 -03:00
|
|
|
|
|
|
|
# assume this is a release directory such as
|
|
|
|
# "beta", or the "latest" directory (treated as a
|
|
|
|
# release and handled specially later)
|
|
|
|
tag = firstlevel
|
|
|
|
if not self.valid_release_type(tag):
|
|
|
|
print("Unknown tag (%s) in directory (%s)" %
|
|
|
|
(tag, os.path.join(vdir)), file=sys.stderr)
|
|
|
|
continue
|
|
|
|
tag_path = os.path.join(basedir, vehicletype, tag)
|
|
|
|
if not os.path.isdir(tag_path):
|
|
|
|
continue
|
|
|
|
self.add_firmware_data_from_dir(tag_path,
|
|
|
|
firmwares,
|
|
|
|
vehicletype,
|
|
|
|
releasetype=tag)
|
2016-02-29 01:18:41 -04:00
|
|
|
|
|
|
|
# convert from ardupilot-naming conventions to common JSON format:
|
|
|
|
firmware_json = []
|
|
|
|
for firmware in firmwares:
|
|
|
|
filepath = firmware["filepath"]
|
|
|
|
# replace the base directory with the base URL
|
|
|
|
urlifier = re.compile("^" + re.escape(basedir))
|
|
|
|
url = re.sub(urlifier, self.baseurl, filepath)
|
2017-10-26 20:30:53 -03:00
|
|
|
version_type = self.releasetype_map(firmware["release-type"])
|
2016-02-29 01:18:41 -04:00
|
|
|
some_json = dict({
|
|
|
|
"mav-autopilot": "ARDUPILOTMEGA",
|
2019-05-30 02:36:41 -03:00
|
|
|
"vehicletype": firmware["vehicletype"],
|
2016-02-29 01:18:41 -04:00
|
|
|
"platform": firmware["platform"],
|
|
|
|
"git-sha": firmware["git_sha"],
|
|
|
|
"url": url,
|
|
|
|
"mav-type": self.frame_map(firmware["frame"]),
|
2017-10-26 20:30:53 -03:00
|
|
|
"mav-firmware-version-type": version_type,
|
2016-02-29 01:18:41 -04:00
|
|
|
"latest": firmware["latest"],
|
|
|
|
"format": firmware["format"],
|
|
|
|
})
|
|
|
|
if firmware["firmware-version"]:
|
2019-04-29 19:53:08 -03:00
|
|
|
try:
|
|
|
|
(major, minor, patch, release_type) = self.parse_fw_version(
|
|
|
|
firmware["firmware-version"])
|
|
|
|
except Exception:
|
|
|
|
print("Badly formed firmware-version.txt %s" % firmware["firmware-version"], file=sys.stderr)
|
|
|
|
continue
|
2017-10-26 20:30:53 -03:00
|
|
|
some_json["mav-firmware-version"] = ".".join([major,
|
|
|
|
minor,
|
|
|
|
patch])
|
2016-02-29 01:18:41 -04:00
|
|
|
some_json["mav-firmware-version-major"] = major
|
|
|
|
some_json["mav-firmware-version-minor"] = minor
|
|
|
|
some_json["mav-firmware-version-patch"] = patch
|
|
|
|
|
2019-04-29 03:46:18 -03:00
|
|
|
self.add_USB_IDs(some_json)
|
|
|
|
|
2019-04-29 18:32:54 -03:00
|
|
|
#print(some_json['url'])
|
2016-02-29 01:18:41 -04:00
|
|
|
firmware_json.append(some_json)
|
|
|
|
|
|
|
|
ret = {
|
2017-10-26 20:30:53 -03:00
|
|
|
"format-version": "1.0.0", # semantic versioning
|
2016-02-29 01:18:41 -04:00
|
|
|
"firmware": firmware_json
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def json(self):
|
|
|
|
'''walk directory supplied in constructor, return json string'''
|
|
|
|
if not self.looks_like_binaries_directory(self.basedir):
|
2017-10-26 20:30:53 -03:00
|
|
|
print("Warning: this does not look like a binaries directory",
|
|
|
|
file=sys.stderr)
|
2016-02-29 01:18:41 -04:00
|
|
|
|
|
|
|
structure = self.walk_directory(self.basedir)
|
2020-04-09 06:54:00 -03:00
|
|
|
return json.dumps(structure, indent=4, separators=(',', ': '))
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2017-10-26 20:30:53 -03:00
|
|
|
|
2016-02-29 01:18:41 -04:00
|
|
|
def usage():
|
|
|
|
return '''Usage:
|
2019-04-29 03:46:18 -03:00
|
|
|
generate-manifest.py basedir'''
|
2016-02-29 01:18:41 -04:00
|
|
|
|
2017-10-26 20:30:53 -03:00
|
|
|
|
2016-02-29 01:18:41 -04:00
|
|
|
if __name__ == "__main__":
|
2019-04-29 03:46:18 -03:00
|
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description='generate manifest.json')
|
|
|
|
|
|
|
|
parser.add_argument('--outfile', type=str, default=None, help='output file, default stdout')
|
2019-12-07 16:44:14 -04:00
|
|
|
parser.add_argument('--baseurl', type=str, default="https://firmware.ardupilot.org", help='base binaries directory')
|
2019-04-29 03:46:18 -03:00
|
|
|
parser.add_argument('basedir', type=str, default="-", help='base binaries directory')
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
2019-04-29 23:36:07 -03:00
|
|
|
# ensure all stable directories are created
|
|
|
|
gen_stable.make_all_stable(args.basedir)
|
|
|
|
|
2019-04-29 03:46:18 -03:00
|
|
|
generator = ManifestGenerator(args.basedir, args.baseurl)
|
|
|
|
if args.outfile is None:
|
|
|
|
print(generator.json())
|
|
|
|
else:
|
2019-04-29 05:16:12 -03:00
|
|
|
f = open(args.outfile, "w")
|
2019-04-29 03:46:18 -03:00
|
|
|
f.write(generator.json())
|
|
|
|
f.close()
|