Improvement to start.py maintenance tools (#2438)

* Added last commit dates to lists of untested flight plans and airframes

* Improved paparazzi_health to include a list of all modules and their usage

* improved paparazzi_health to include a list of board makefiles not used by any airframe

* improved paparazzi_health to generate list of unused airframes, flightplans and boards sorted by most recently changed

* airframe details now stores modules as tuple of name and type: [(name, type), ...]

* added seeing includes in paparazzi_health

* Removed unneccesary print statements

* Added widget to start.py to generate html table of the module usage of the airframes for the selected conf

* improved html table readability and sorted airframe names alphabetically

* fixed alphabetical ordering of airframe name being case sensitive and added comments

* Added module class, more info about modules now gets printed. Commit dates should still be fixed

* Did speed improvement, but still slow

* split up more info and lists of untested files

* Added checkboxes to start.py to give user option to show airframe detail, or untested files, or both

* Cleaned up some code

* Added separator to make link between checkboxes and MoreInfo button clearer

* Fixed code style

* Added description to the module listing

* one should now be able to select which aspects to show in the maintenance tools

* Initial version of maintenance tools window

* Now also checks if modules are mentioned in the settings modules in an userconf

* Improved layout of maintenance tool window

* Improved variable names and tooltip information

* Small QoL changes to prepare for pull request

* Fixed a bug with the untested boards not showing correctly if airframes was not also selected and fixed some Codacy issues

* Added functionality to generate module overview by board name

* Module overview table now also displays the xml file and of the airframe

* Update health_monitor_update branch with master changes

* Bug-fixes and added description to maintenance tools
This commit is contained in:
Matteo Barbera
2019-06-24 21:56:14 +02:00
committed by Gautier Hattenberger
parent 208c37bc98
commit 8c145b7e49
2 changed files with 89 additions and 15 deletions
+43 -6
View File
@@ -21,6 +21,7 @@ from paparazzi_health import PaparazziOverview
import xml.etree.ElementTree
class ConfChooser(object):
# General Functions
@@ -29,10 +30,11 @@ class ConfChooser(object):
combo.set_sensitive(False)
combo.get_model().clear()
current_index = 0
combo.append_text("------None Selected------")
for (i, text) in enumerate(clist):
combo.append_text(text)
if os.path.join(paparazzi.conf_dir, text) == os.path.realpath(active):
current_index = i
if active is not None and os.path.join(paparazzi.conf_dir, text) == os.path.realpath(active):
current_index = i + 1 # Add one due to ---None Selected---
combo.set_active(current_index)
combo.set_sensitive(True)
@@ -70,6 +72,10 @@ class ConfChooser(object):
conf_files = paparazzi.get_list_of_conf_files(self.exclude_backups)
self.update_combo(combo, conf_files, self.conf_xml)
def find_board_files(self, combo):
board_files = paparazzi.get_list_of_boards()
self.update_combo(combo, board_files, None)
def find_controlpanel_files(self):
controlpanel_files = paparazzi.get_list_of_controlpanel_files(self.exclude_backups)
self.update_combo(self.controlpanel_file_combo, controlpanel_files, self.controlpanel_xml)
@@ -135,8 +141,10 @@ class ConfChooser(object):
show_modules=data["Modules"].get_active())
def module_usage(self, widget, data):
selected_conf = data.get_active_text()
self.obj.airframe_module_overview(selected_conf)
if data["Conf"].get_active() is not 0:
self.obj.airframe_module_overview(data["Conf"].get_active_text())
elif data["Board"].get_active() is not 0:
self.obj.airframe_module_overview(data["Board"].get_active_text() + ".makefile")
def launch(self, widget):
self.accept(widget)
@@ -263,20 +271,39 @@ class ConfChooser(object):
def changed_cb(self, widget, data):
self.count_airframes_in_conf(data["combo"], data["list"])
@staticmethod
def deactivate_cb(widget, combo):
current_selection = widget.get_active()
combo.set_active(0)
widget.set_active(current_selection)
def maintenance_window(self, widget):
mtn_window = gtk.Window()
mtn_window.set_position(gtk.WIN_POS_CENTER)
mtn_window.set_size_request(750, 300)
mtn_window.set_size_request(750, 360)
mtn_window.set_title("Maintenance Tools")
mnt_vbox = gtk.VBox()
mnt_desc_label = gtk.Label("")
desc_text = "Show module usage of all airframes in a selected conf file <b>or</b> all airframes " \
"with a specific board across all conf files."
mnt_desc_label.set_markup(desc_text)
mnt_desc_label.set_size_request(720, 40)
mnt_desc_label.set_line_wrap(True)
mnt_conf_label = gtk.Label("Conf:")
mnt_conf_label.set_size_request(100, 30)
mnt_conf_file_combo = gtk.combo_box_new_text()
self.find_conf_files(mnt_conf_file_combo)
mnt_conf_file_combo.set_size_request(500, 30)
mnt_board_label = gtk.Label("Board:")
mnt_board_label.set_size_request(100, 30)
mnt_board_file_combo = gtk.combo_box_new_text()
self.find_board_files(mnt_board_file_combo)
mnt_board_file_combo.set_size_request(500, 30)
mnt_conf_airframes = gtk.Label("")
self.count_airframes_in_conf(mnt_conf_file_combo, mnt_conf_airframes)
mnt_conf_airframes.set_size_request(650, 180)
@@ -284,14 +311,24 @@ class ConfChooser(object):
combo_list = {"combo": mnt_conf_file_combo, "list": mnt_conf_airframes}
mnt_conf_file_combo.connect("changed", self.changed_cb, combo_list)
mnt_conf_file_combo.connect("changed", self.deactivate_cb, mnt_board_file_combo)
mnt_board_file_combo.connect("changed", self.deactivate_cb, mnt_conf_file_combo)
mnt_combos = {"Conf": mnt_conf_file_combo, "Board": mnt_board_file_combo}
mnt_confbar = gtk.HBox()
mnt_confbar.pack_start(mnt_conf_label)
mnt_confbar.pack_start(mnt_conf_file_combo)
mnt_boardbar = gtk.HBox()
mnt_boardbar.pack_start(mnt_board_label)
mnt_boardbar.pack_start(mnt_board_file_combo)
mnt_vbox.pack_start(mnt_desc_label)
mnt_vbox.pack_start(mnt_confbar, False)
mnt_vbox.pack_start(mnt_boardbar, False)
btnModule = gtk.Button("Module\nUsage")
btnModule.connect("clicked", self.module_usage, mnt_conf_file_combo)
btnModule.connect("clicked", self.module_usage, mnt_combos)
btnModule.set_tooltip_text("More information on the modules used by these airframes")
mnt_caexbar = gtk.HBox()
+46 -9
View File
@@ -8,6 +8,7 @@ import datetime
from fnmatch import fnmatch
import re
import numpy as np
from functools import wraps
from collections import Counter
import paparazzi
import xml.etree.ElementTree
@@ -17,6 +18,34 @@ import subprocess
PIPE = subprocess.PIPE
def conf_board_decorator(module_overview_func):
"""
This decorator extends the function PaparazziOverview.airframe_module_overview to generate the html
table either for airframes in a conf file or all airframes with a specific board
"""
@wraps(module_overview_func)
def wrapper(self, selected_file):
if selected_file[-3:] == "xml":
airframes = self.list_airframes_in_conf(selected_file)
module_overview_func(self, iter(airframes))
elif selected_file[-8:] == "makefile":
board = selected_file[:-9]
conf_files = iter(paparazzi.get_list_of_conf_files())
airframes = []
for conf in conf_files:
afs_in_conf = iter(self.list_airframes_in_conf(conf))
for af in afs_in_conf:
ac = self.airframe_details(af.xml)
if board in ac.boards:
airframes.append(af)
module_overview_func(self, iter(airframes))
else:
raise ValueError("selected file is neither a conf.xml or board.makefile")
return wrapper
class Airframe:
name = ""
ac_id = ""
@@ -318,19 +347,25 @@ class PaparazziOverview(object):
def generate_sorted_list(self, lst):
commit_dates = [re.sub(r"( \n)$", "", self.get_last_commit_date(paparazzi.conf_dir + elm)) for elm in lst]
file_date_lst = sorted(zip(lst, commit_dates), key=lambda x: datetime.datetime.strptime(x[1], '%d-%m-%Y'),
untracked_zip = []
tracked_zip = []
for z in zip(lst, commit_dates):
if z[1] != "00-00-0000":
tracked_zip.append(z)
else:
untracked_zip.append((z[0], "Untracked file"))
file_date_lst = untracked_zip + sorted(tracked_zip, key=lambda x: datetime.datetime.strptime(x[1], '%d-%m-%Y'),
reverse=True)
return file_date_lst
def airframe_module_overview(self, selected_conf):
@conf_board_decorator
def airframe_module_overview(self, airframes):
"""
Creates a nested dictionary of the airframe names and the modules they use to generate an html table
that provides an overview of module usage of the airframes of interest
:param selected_conf: str of the name of conf file
:param airframes: list or iterator of airframes to be analyzed
"""
# Looks at airframes in selected conf (not the currently active conf)
airframes = self.list_airframes_in_conf(selected_conf)
# Structure of nested dictionary: {af name: {module name: module type}}
afs_mods = {}
@@ -350,14 +385,16 @@ class PaparazziOverview(object):
del unique_mods_ctr['xml']
# Table initialization, airframe names are ordered alphabetically, module names by most used
ac_mod_table = np.zeros((len(afs_mods.keys()) + 1, len(unique_mods_ctr.keys()) + 1), dtype=object)
ac_mod_table = np.zeros((len(afs_mods.keys()) + 1, len(unique_mods_ctr.keys()) + 2), dtype=object)
ac_mod_table[0, 0] = "Name \\ Modules"
ac_mod_table[0, 1] = "XML File"
ac_mod_table[1:, 0] = sorted(afs_mods.keys(), key=lambda s: s.lower())
ac_mod_table[0, 1:] = [i for i, _ in unique_mods_ctr.most_common()]
ac_mod_table[0, 2:] = [i for i, _ in unique_mods_ctr.most_common()]
for i in range(1, len(ac_mod_table[:, 0])):
for j in range(1, len(ac_mod_table[0, :])):
ac_name = ac_mod_table[i, 0]
ac_name = ac_mod_table[i, 0]
ac_mod_table[i, 1] = afs_mods[ac_name]["xml"][0]
for j in range(2, len(ac_mod_table[0, :])):
module_name = ac_mod_table[0, j]
if ac_mod_table[0, j] not in afs_mods[ac_name]:
ac_mod_table[i, j] = "\\"