Kettenoeler/Software/codegen/prepare_littlefs.py

155 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SCRIPT TO GZIP CRITICAL FILES FOR ACCELERATED WEBSERVING
# see also https://community.platformio.org/t/question-esp32-compress-files-in-data-to-gzip-before-upload-possible-to-spiffs/6274/10
import glob
import shutil
import gzip
import os
import subprocess
import platform
Import("env")
Import("projenv")
def ensure_node_tool(package_name, binary_name=None):
"""Installiert das Tool lokal, wenn es fehlt mit npm init bei Bedarf"""
if binary_name is None:
binary_name = package_name
project_dir = env.subst('$PROJECT_DIR')
tools_dir = os.path.join(project_dir, 'tools_node')
local_bin = os.path.join(tools_dir, 'node_modules', '.bin', binary_name)
os.makedirs(tools_dir, exist_ok=True)
# Wenn Binary schon vorhanden ist, einfach zurückgeben
if os.path.isfile(local_bin):
return local_bin
print(f"🛠️ Installing missing node tool: {package_name}")
# Initialisiere npm, falls noch nicht geschehen
if not os.path.isfile(os.path.join(tools_dir, 'package.json')):
print("📦 Initializing local npm project...")
subprocess.run(['npm', 'init', '-y'], cwd=tools_dir, check=True)
try:
subprocess.run(['npm', 'install', package_name], cwd=tools_dir, check=True)
except Exception as e:
print(f"❌ Fehler beim Installieren von {package_name}: {e}")
return binary_name # Fallback: globale binary
return local_bin if os.path.isfile(local_bin) else binary_name
# Tools sicherstellen
# Tools sicherstellen Package-Name und CLI-Binary ggf. unterschiedlich
html_minifier_path = ensure_node_tool("html-minifier")
terser_path = ensure_node_tool("terser")
cssnano_path = ensure_node_tool("cssnano-cli", "cssnano")
def minify_html(input_path, output_path):
subprocess.run([html_minifier_path, '--collapse-whitespace', '--remove-comments', input_path, '-o', output_path])
def minify_js(input_path, output_path):
subprocess.run([terser_path, input_path, '-o', output_path, '-c', '-m'])
def minify_css(input_path, output_path):
subprocess.run([cssnano_path, '--no-discardUnused', input_path, output_path])
def process_file(src_path, dest_path):
_, file_extension = os.path.splitext(src_path)
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
if file_extension.lower() == '.js':
minify_js(src_path, dest_path)
elif file_extension.lower() == '.css':
minify_css(src_path, dest_path)
elif file_extension.lower() in ['.html', '.htm']:
minify_html(src_path, dest_path)
else:
shutil.copy2(src_path, dest_path)
def strip_files(src_dir, dest_dir):
os.makedirs(dest_dir, exist_ok=True)
for root, _, files in os.walk(src_dir):
for filename in files:
src_path = os.path.join(root, filename)
rel_path = os.path.relpath(src_path, src_dir)
dest_path = os.path.join(dest_dir, rel_path)
process_file(src_path, dest_path)
def gzip_file(src_path, dst_path):
with open(src_path, 'rb') as src, gzip.open(dst_path, 'wb') as dst:
for chunk in iter(lambda: src.read(4096), b""):
dst.write(chunk)
def getListOfFiles(dirName):
entries = os.listdir(dirName)
allFiles = []
for entry in entries:
fullPath = os.path.join(dirName, entry)
if os.path.isdir(fullPath):
allFiles += getListOfFiles(fullPath)
else:
allFiles.append(fullPath)
return allFiles
def safe_relpath(path, start):
return os.path.relpath(path, start).replace("\\", "/")
def gzip_webfiles(source, target, env):
filetypes_to_gzip = ['.css', '.png', '.js', '.ico', '.woff2', '.json']
print('\nGZIP: Starting gzip-Process for LittleFS-Image...\n')
src_dir = os.path.join(env.get('PROJECT_DIR'), 'data_src')
temp_dir = os.path.join(env.get('PROJECT_DIR'), 'data_stripped')
dst_dir = env.get('PROJECT_DATA_DIR')
strip_files(src_dir, temp_dir)
if os.path.exists(dst_dir):
shutil.rmtree(dst_dir)
os.mkdir(dst_dir)
files_to_copy = []
files_to_gzip = []
for file in getListOfFiles(temp_dir):
_, ext = os.path.splitext(file)
if ext in filetypes_to_gzip:
files_to_gzip.append(file)
else:
files_to_copy.append(safe_relpath(file, temp_dir))
for file in files_to_copy:
full_dst = os.path.join(dst_dir, file)
os.makedirs(os.path.dirname(full_dst), exist_ok=True)
shutil.copy(os.path.join(temp_dir, file), full_dst)
was_error = False
try:
for src in files_to_gzip:
rel_path = safe_relpath(src, temp_dir)
dst_path = os.path.join(dst_dir, rel_path + '.gz')
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
print('GZIP: compressing... ' + rel_path)
gzip_file(src, dst_path)
except IOError as e:
was_error = True
print('GZIP: Fehler beim Komprimieren:', e)
if was_error:
print('⚠️ GZIP: Nicht alle Dateien konnten verarbeitet werden.\n')
else:
print('✅ GZIP: Komprimierung abgeschlossen.\n')
shutil.rmtree(temp_dir)
def gzip_binffiles(source, target, env):
littlefsbin = target[0].get_abspath()
tmpbin = os.path.join(os.path.dirname(littlefsbin), 'filesystem.fs')
shutil.copyfile(littlefsbin, tmpbin)
gzip_file(tmpbin, tmpbin + '.gz')
os.remove(tmpbin)
# Hooks setzen
env.AddPreAction('$BUILD_DIR/littlefs.bin', gzip_webfiles)
env.AddPostAction('$BUILD_DIR/littlefs.bin', gzip_binffiles)