From da5322765d64027710804cacb98e8f4069a234de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20M=C3=B8ller?= <37707273+LupusE@users.noreply.github.com> Date: Tue, 5 Nov 2024 03:41:08 +0100 Subject: [PATCH] Add about_simple updater from github (#2328) * Generator for updating the about-page in PP from github. * Fixing typo * Rename generate_ui-about-simple.ccp.py to generate_ui-about-simple.cpp.py Rename file, fix typo --- firmware/tools/bitmap_tools/pp_png2hpp.py | 4 +- .../tools/generate_ui-about-simple.cpp.py | 184 ++++++++++++++++++ 2 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 firmware/tools/generate_ui-about-simple.cpp.py diff --git a/firmware/tools/bitmap_tools/pp_png2hpp.py b/firmware/tools/bitmap_tools/pp_png2hpp.py index e8f02439..f465115c 100755 --- a/firmware/tools/bitmap_tools/pp_png2hpp.py +++ b/firmware/tools/bitmap_tools/pp_png2hpp.py @@ -2,7 +2,7 @@ # Convert png icons to bitmap.hpp inspired by # make_bitmap.py - Copyright (C) 2016 Furrtek -# Convert bitmap.hpp to icons inspyred by +# Convert bitmap.hpp to icons inspired by # bitmap_arr_reverse_decode.py - Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. # bitmap_arr_reverse_decode.py - Copyleft (ɔ) 2024 zxkmm with the GPL license # Copysomething (c) 2024 LupusE with the license, needed by the PortaPack project @@ -138,6 +138,8 @@ def pp_write_bitmaphpp(pngicons_path, hpp_outpath): print("Find your bitmap.hpp at", hpp_outpath) + + ### Convert from a bitmap.hpp file one or all icons in png. ########################################################### diff --git a/firmware/tools/generate_ui-about-simple.cpp.py b/firmware/tools/generate_ui-about-simple.cpp.py new file mode 100644 index 00000000..3b920c06 --- /dev/null +++ b/firmware/tools/generate_ui-about-simple.cpp.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 + +# Copysomething (c) 2024 LupusE with the license, needed by the PortaPack project +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import argparse +import json +import os +import re +import requests +import sys + +cppheader = """#include "ui_about_simple.hpp" + +namespace ui { + +// Information: a line starting with a '#' will be yellow coloured +const std::""" + +cppfooter = """ +AboutView::AboutView(NavigationView& nav) { + add_children({&menu_view, + &button_ok}); + + button_ok.on_select = [&nav](Button&) { + nav.pop(); + }; + + menu_view.on_left = [this]() { + button_ok.focus(); + }; + + menu_view.on_right = [this]() { + button_ok.focus(); + }; + + for (const std::string& authors_line : authors_list) { + // if it's starting with #, it's a title and we have to substract the '#' and paint yellow + if (authors_line.size() > 0) { + if (authors_line[0] == '#') { + menu_view.add_item( + {authors_line.substr(1, authors_line.size() - 1), + ui::Theme::getInstance()->fg_yellow->foreground, + nullptr, + nullptr}); + } else { + menu_view.add_item( + {authors_line, + Theme::getInstance()->bg_darkest->foreground, + nullptr, + nullptr}); + } + } + } +} + +void AboutView::focus() { + menu_view.focus(); + // put focus on last text line to make it more obvious that list is scrollable + menu_view.set_highlighted(10); +} + +} /* namespace ui */ +""" + +def get_contributors(url): + contributors_list = [] ## Raw list of contributor names + logins = json.loads(requests.get(url).text) + try: + print(f"Could not reach URL - Error: {logins['status']} Messsage: {logins['message']}") + ## Status f.ex. 404 / message f.ex. "Not Found" or "API rate limit exceeded for...". + sys.exit() + except: + pass + + for gh_user in logins: + clean_ghuser = re.sub('[^a-zA-Z0-9-]', '.', gh_user['login']) ## replace non printable character with . + contributors_list.append(clean_ghuser) + + contributor_id = 0 + contrib_format = [] ## Formated list of contributors, max 30 char per line + for contributor in contributors_list: + contributor_id +=1 + contrib_format.append(contributor) + line_len = len(",".join(contrib_format).split("\n")[-1]) + if contributor_id < len(contributors_list) and line_len+len(contributors_list[contributor_id]) >=30: + contrib_format.append("\n") + + return(",".join(contrib_format).replace("\n,","\n")) # replace to erase first , in followup lines + +def generate_content(projects): + project_contrib = [] + project_contrib.append("string authors_list[] = {\n") + project_contrib.append(" \"# * List of contributors * \",\n") + for project in projects: + project_contrib.append(" \" \",\n") + project_contrib.append(f" \"#{project[0]}:\",\n") + + url = f"https://api.github.com/repos/{project[1]}/{project[2]}/contributors?per_page={project[3]}" + contrib_mayhem = get_contributors(url).split("\n") + for line in contrib_mayhem: + project_contrib.append(f" \"{line}\",\n") + + project_contrib.append(" \" \"};\n") + return("".join(project_contrib)) + + +def pp_create_ui_about_simple_cpp(cpp_file, cppheader, cppcontent, cppfooter): + uiaboutsimplecpp_file = [] + + uiaboutsimplecpp_file.append(cppheader) + uiaboutsimplecpp_file.append(cppcontent) + uiaboutsimplecpp_file.append(cppfooter) + + with open(cpp_file, "w", encoding="utf-8") as file: + file.writelines(uiaboutsimplecpp_file) + + print("Find your ui_simple_about.cpp at", cpp_file) + +def pp_change_ui_about_simple_cpp(cpp_file, cppcontent): + content = [] + content_pattern = re.compile(r"string authors_list\[\] = {\n(?:\s+(?:.*,\n)+\s+.*};\n)", re.MULTILINE) + + # Read original file + with open(cpp_file, 'r') as file: + filedata = file.read() + + # Replace regex content with generated list + for match in content_pattern.finditer(filedata): + content.append(match[0]) + + filedata = filedata.replace(content[0], cppcontent) + + # Write new file + with open(cpp_file, 'w') as file: + file.write(filedata) + + +projects = [] +## Format: Project title, Github name, Github repo, Amount of contributors +projects.append(["Mayhem-Firmware","portapack-mayhem","mayhem-firmware","50"]) +projects.append(["Havoc","furrtek","portapack-havoc","50"]) +projects.append(["PortaPack","sharebrained","portapack-hackrf","50"]) +projects.append(["HackRF","mossmann","hackrf","15"]) + + +## processing +############# + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="This tool updates the ui_about_simple.cpp from PortaPack firmware from Github contributors. If no file is given, the file will be generated.", + ) + parser.add_argument("--cpp", help="Path of the source ui_about_simple.cpp to update.", default="ui_about_simple.cpp") + parser.add_argument("--new","-n", help="Generate a new file") + + args = parser.parse_args() + + if args.cpp: + cpp_file = os.path.join(os.getcwd(),args.cpp) + else: + cpp_file = os.path.join(os.getcwd(),"ui_about_simple.cpp") + + cppcontent = generate_content(projects) + + if args.new or not os.path.isfile(args.cpp): + pp_create_ui_about_simple_cpp(cpp_file, cppheader, cppcontent, cppfooter) + else: + pp_change_ui_about_simple_cpp(cpp_file, cppcontent)