Hallo,
ich konnte es nicht sein lassen. Jetzt machen wir es richtig oder gar nicht.
Version 1.2.0. Ist auch Spielwiese für mich. Die meisten verwenden mehrere Controller-Architekturen, wie ich auch, also musste ein Auswahlmenü her. Ich wurde hier Lysander Menü Snippets fündig wie man sowas erstellt. Sehr interessant zum Lesen. Tja und dann sollte noch ein Backup vorm Überschreiben her. Wer weiß wofür das gut ist. 
Den gemeinsamen Pfad für die Backups gibt man in Zeile 28 an.
Der Dateiname boards.local.txt, falls schon vorhanden, wird um Datum und Uhrzeit modifiziert und in den Backup Ordner kopiert.
Mit der copy2 Methode werden die Metadaten der Datei beibehalten. Der neue Dateiname vom Backup erhält den aktuellen Zeitstempel im Namen, aber Windows zeigt in der Spalte "Änderungsdatum" noch das alte originale Datum an, an dem die Datei damals erstellt/geändert wurde. Wer das nicht möchte ändert copy2 auf copy. Findet man in der Funktion erstelleBackup().
Wenn man zu erstellende .txt von Cores Packages löschen oder hinzufügen möchte, dann löscht oder legt man neue pathDir... und boardNames... Definitionen an. Zeilen 12 bis 26.
Dazu passende Funktion boards… erstellen. Zeilen 114 bis 154.
Danach noch das Menü entsprechend anpassen mit Anzeige und Funktionsnamen. Zeile 209 bis 215.
Ich denke damit ist erstmal Schluß. 
Quellcode
# https://forum.arduino.cc/t/boards-local-txt-vollautomatisch-erstellen/1373353
# Code für das Auswahlmenü von https://github.com/Lysander/snippets
import sys
import shutil
import os
import re
from datetime import datetime
# --- Benutzer Definitionen --------------------------------------------------------------------------------
# Pfade zum Core Packages definieren
pathDirAVR: str = r"G:\Arduino IDE Portable\Mega2560_stdCpp2\arduino-1.8.19\portable\packages\arduino\hardware\avr\1.8.6"
pathDirDxCore: str = r"G:\Arduino IDE Portable\AVRxDB\arduino-1.8.19\portable\packages\DxCore\hardware\megaavr\1.5.11"
pathDirMegaAVR: str = r"G:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\packages\arduino\hardware\megaavr\1.8.8"
pathDirMegaCoreX: str = r"G:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\packages\MegaCoreX\hardware\megaavr\1.1.2"
pathDirESP32: str = r"C:\Users\Worker\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0"
pathDirESP8266: str = r"C:\Users\Worker\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2"
# Boards zur Verwendung definieren, die man im Auswahlmenü sehen möchte
boardNamesAVR = ['uno', 'mega']
boardNamesDxCore = ['avrdb', 'avrdbopti']
boardNamesMegaAVR = ['nona4809'] # Arduino megaavr - Nano Every
boardNamesMegaCoreX = ['4809'] # MCUdude MegaCoreX
boardNamesESP32 = ['XIAO_ESP32S3', 'XIAO_ESP32S3_Plus', 'nano_nora']
boardNamesESP8266 = ['d1']
pathDirBackup: str = r"C:\Users\Worker\Documents"
# --- Ende der Benutzer Definitionen ------------------------------------------------------------------------
ZIELDATEI = "boards.local.txt"
QUELLDATEI = "boards.txt"
# --- Hilfsfunktionen ---------------------------------------------------------------------------------------
def getDatumUhrzeit():
# aktuelles Datum und Uhrzeit zusammenbauen
zeitstempel = datetime.now().strftime("%Y%m%d_%H%M%S")
print("Zeitstempel: ", zeitstempel) # Debug
return zeitstempel
def modifiziereBackupName(suffix):
dateiname, dateiendung = os.path.splitext(ZIELDATEI)
#print("Dateiname: ", dateiname) # Debug
#print("Dateiendung: ", dateiendung) # Debug
neuerDateiname = f"{dateiname}_{suffix}_{getDatumUhrzeit()}{dateiendung}"
#print("neuer Dateiname: ", neuerDateiname) # Debug
return neuerDateiname
def erstelleBackup(quellPfad, zielPfad, suffix):
if os.path.exists(quellPfad):
neuerBackupPfad = os.path.join(zielPfad, modifiziereBackupName(suffix))
shutil.copy2(quellPfad, neuerBackupPfad) # copy2 behält die Metadaten der Datei
print(f"Backup im Pfad: {neuerBackupPfad} angelegt.")
else:
print(f'Die Datei {quellPfad} existiert (noch) nicht.')
print("Es wurde kein Backup angelegt.")
# Ausdruck Read Write
def modifiziereDatei(regAusdruck, quellDatei, zielDatei, pathDirCore, boardNames):
pathFileRead = os.sep.join([pathDirCore, quellDatei])
pathFileWrite = os.sep.join([pathDirCore, zielDatei])
fileRead = open(pathFileRead, "r")
fileWrite = open(pathFileWrite, "w")
dataLine = fileRead.readlines()
for zeile in dataLine:
if regAusdruck in zeile:
# jeweilige Kopfzeile erzeugen
# Teile der Zeile nach dem 'regAusdruck' behalten
tempLineA = ("# " + zeile.split(regAusdruck,1)[1])
fileWrite.write(tempLineA)
#print("tempLineA:", tempLineA) # Debug
# ab hier dazugehörige Menüzeile erzeugen
# Nur den Teil bis zum 'regAusdruck' ausgeben und den 'regAusdruck' ersetzen
tempLineB = (zeile.split(regAusdruck)[0])
#print("tempLineB: ", tempLineB) # Debug
# Suche nach kompletter Übereinstimmung mit einem 'BoardNames' Eintrag
# Wenn es übereinstimmt, in IDE Version Abhänggkeit ...
# IDE 2.x: '.hide=false' dahinter
# IDE 1.9: '#' davor & '.hide=true' dahinter (ist zu beiden IDEs kompatibel)
# ansonsten ohne Übereinstimmung: hänge nur '.hide=true' dahinter
meineBoards = [] # Debug
fertigeZeile = []
if any(re.fullmatch(m, tempLineB) for m in boardNames):
meineBoards.append(tempLineB) # Debug
#print("meineBoards:", meineBoards) # Debug
# --------------------------------------------------
# ### nur für Arduino IDE 2.x ######################
#fertigeZeile = (tempLineB + ".hide=false")
# --------------------------------------------------
# ### für Arduino IDE 1.9.x und IDE 2.x ############
fertigeZeile = ("# " + tempLineB + ".hide=true")
# --------------------------------------------------
#print("meine Boards: ", fertigeZeile) # Debug - Board Übereinstimmung
else: fertigeZeile = (tempLineB + ".hide=true")
#print(fertigeZeile) # finales Debug - Was wird geschrieben?
fileWrite.write(fertigeZeile)
fileWrite.write("\n\n")
fileWrite.close()
fileRead.close()
print(f'Die Datei {ZIELDATEI} wurde in {pathDirCore} neu erstellt.')
# --- Funktionen die von der Menüauswahl aufgerufen werden --------------------------------------------------
def boardsAVR():
SUFFIX = "AVR"
print(SUFFIX)
pathQuelle = os.path.join(pathDirAVR, ZIELDATEI)
erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)
modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirAVR, boardNamesAVR)
def boardsDxCore():
SUFFIX = "DxCore"
print(SUFFIX)
pathQuelle = os.path.join(pathDirDxCore, ZIELDATEI)
erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)
modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirDxCore, boardNamesDxCore)
def boardsMegaAVR():
SUFFIX = "MegaAVR"
print(SUFFIX)
pathQuelle = os.path.join(pathDirMegaAVR, ZIELDATEI)
erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)
modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirMegaAVR, boardNamesMegaAVR)
def boardsMegaCoreX():
SUFFIX = "MegaCoreX"
print(SUFFIX)
pathQuelle = os.path.join(pathDirMegaCoreX, ZIELDATEI)
erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)
modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirMegaCoreX, boardNamesMegaCoreX)
def boardsESP32():
SUFFIX = "ESP32"
print(SUFFIX)
pathQuelle = os.path.join(pathDirESP32, ZIELDATEI)
erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)
modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirESP32, boardNamesESP32)
def boardsESP8266():
SUFFIX = "ESP8266"
print(SUFFIX)
pathQuelle = os.path.join(pathDirESP8266, ZIELDATEI)
erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)
modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirESP8266, boardNamesESP8266)
# --- Menü --------------------------------------------------------------------------------------------------
#
# Core functions of our simple menu system
#
def print_menu(menu):
"""
Function that prints our menu items. It adds an numeric index to each
item in order to make that the choosebale index for the user.
:param menu: tuple with menu definition
"""
print() # Leerzeile vor dem Menü erzeugen
for index, item in enumerate(menu, 1):
print("{} {}".format(index, item[0]))
def get_user_input(menu):
"""
This function implements a simple user input with validation. As the
input data should match with existing menu items, we check, if the value
is valid.
:param menu: tuple with menu definition
:returns: int
"""
while True:
try:
choice = int(input("Deine Wahl? Nummer?: ")) - 1
if 0 <= choice < len(menu):
return choice
else:
raise IndexError
except (ValueError, IndexError):
print("Bitte nur Zahlen aus dem Bereich 1 - {} eingeben".format(
len(menu)))
def handle_menu(menu):
"""
Core function of our menu system. It handles the complete process of
printing the menu, getting the user input and calling the corresponding
function.
:param menu: tuple with menu definition
"""
while True:
print_menu(menu)
choice = get_user_input(menu)
menu[choice][1]()
def main():
# Auswahlmenü:
menu = (
("AVR", boardsAVR),
("DxCore", boardsDxCore),
("MegaAVR", boardsMegaAVR),
("MegaCoreX", boardsMegaCoreX),
("ESP32", boardsESP32),
("ESP8266", boardsESP8266),
("Exit", lambda: sys.exit(0))
)
# run the menu-"handler" :-)
handle_menu(menu)
if __name__ == "__main__":
main()
Script
SuchenErsetzen_v1.2.0.zip (2,9 KB)