Updates the build script
This commit is contained in:
+110
-58
@@ -7,12 +7,14 @@
|
|||||||
# Copyright (C) 2018 - 2023 rjwats
|
# Copyright (C) 2018 - 2023 rjwats
|
||||||
# Copyright (C) 2023 theelims
|
# Copyright (C) 2023 theelims
|
||||||
# Copyright (C) 2023 Maxtrium B.V. [ code available under dual license ]
|
# Copyright (C) 2023 Maxtrium B.V. [ code available under dual license ]
|
||||||
|
# Copyright (C) 2024 runeharlyk
|
||||||
#
|
#
|
||||||
# All Rights Reserved. This software may be modified and distributed under
|
# All Rights Reserved. This software may be modified and distributed under
|
||||||
# the terms of the LGPL v3 license. See the LICENSE file for details.
|
# the terms of the LGPL v3 license. See the LICENSE file for details.
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shutil import copyfileobj
|
from shutil import copytree, rmtree, copyfileobj
|
||||||
|
from os.path import exists, getmtime
|
||||||
import os
|
import os
|
||||||
import gzip
|
import gzip
|
||||||
import mimetypes
|
import mimetypes
|
||||||
@@ -20,31 +22,35 @@ import glob
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
Import("env")
|
Import("env")
|
||||||
buildFlags = env.ParseFlags(env["BUILD_FLAGS"])
|
|
||||||
project_dir = env["PROJECT_DIR"]
|
|
||||||
|
|
||||||
app_dir = project_dir + "/../app2"
|
project_dir = env["PROJECT_DIR"]
|
||||||
output_file = project_dir + "/lib/ESP32-sveltekit/WWWData.h"
|
buildFlags = env.ParseFlags(env["BUILD_FLAGS"])
|
||||||
source_www_dir = app_dir + "/src"
|
|
||||||
build_www_dir = app_dir + "/build"
|
interface_dir = project_dir + "/../app"
|
||||||
www_dir = "www"
|
output_file = project_dir + "/lib/ESP32-Sveltekit/WWWData.h"
|
||||||
|
source_www_dir = interface_dir + "/src"
|
||||||
|
build_dir = interface_dir + "/build"
|
||||||
|
filesystem_dir = project_dir + "/data/www"
|
||||||
|
|
||||||
|
|
||||||
def find_latest_timestamp_for_app():
|
def find_latest_timestamp_for_app():
|
||||||
return max((os.path.getmtime(f) for f in glob.glob(f'{source_www_dir}/**/*', recursive=True)))
|
return max(
|
||||||
|
(getmtime(f) for f in glob.glob(f"{source_www_dir}/**/*", recursive=True))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def should_regenerate_output_file():
|
def should_regenerate_output_file():
|
||||||
if not flag_exists("EMBED_WWW") or not os.path.exists(output_file):
|
if not flag_exists("EMBED_WWW") or not exists(output_file):
|
||||||
return True
|
return True
|
||||||
last_source_change = find_latest_timestamp_for_app()
|
last_source_change = find_latest_timestamp_for_app()
|
||||||
last_build = os.path.getmtime(output_file)
|
last_build = getmtime(output_file)
|
||||||
|
|
||||||
print(f'Newest file: {datetime.fromtimestamp(last_source_change)}, output file: {datetime.fromtimestamp(last_build)}')
|
print(
|
||||||
|
f"Newest file: {datetime.fromtimestamp(last_source_change)}, output file: {datetime.fromtimestamp(last_build)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return last_build < last_source_change
|
||||||
|
|
||||||
if last_build < last_source_change:
|
|
||||||
print("Svelte files updated. Regenerating.")
|
|
||||||
return True
|
|
||||||
print("Output file up-to-date.")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def gzip_file(file):
|
def gzip_file(file):
|
||||||
with open(file, 'rb') as f_in:
|
with open(file, 'rb') as f_in:
|
||||||
@@ -56,58 +62,104 @@ def flag_exists(flag):
|
|||||||
for define in buildFlags.get("CPPDEFINES"):
|
for define in buildFlags.get("CPPDEFINES"):
|
||||||
if (define == flag or (isinstance(define, list) and define[0] == flag)):
|
if (define == flag or (isinstance(define, list) and define[0] == flag)):
|
||||||
return True
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def build_progmem():
|
|
||||||
mimetypes.init()
|
|
||||||
with open(output_file, "w") as progmem:
|
|
||||||
progmem.write("#include <functional>\n")
|
|
||||||
progmem.write("#include <Arduino.h>\n\n")
|
|
||||||
|
|
||||||
assetMap = {}
|
def get_package_manager():
|
||||||
|
if exists(os.path.join(interface_dir, "pnpm-lock.yaml")):
|
||||||
|
return "pnpm"
|
||||||
|
if exists(os.path.join(interface_dir, "yarn.lock")):
|
||||||
|
return "yarn"
|
||||||
|
if exists(os.path.join(interface_dir, "package-lock.json")):
|
||||||
|
return "npm"
|
||||||
|
|
||||||
for idx, path in enumerate(Path(www_dir).rglob("*.*")):
|
|
||||||
asset_path = path.relative_to(www_dir).as_posix()
|
|
||||||
filetype, asset_mime = path.suffix.lstrip('.'), mimetypes.guess_type(asset_path)[0] or 'application/octet-stream'
|
|
||||||
print(f"Converting {asset_path}")
|
|
||||||
asset_var = f'WEB_ASSET_DATA_{idx}'
|
|
||||||
|
|
||||||
progmem.write(f'// {asset_path}\n')
|
|
||||||
progmem.write(f'const uint8_t {asset_var}[] = {{\n ')
|
|
||||||
file_data = gzip.compress(path.read_bytes())
|
|
||||||
|
|
||||||
for i, byte in enumerate(file_data):
|
|
||||||
if i and not (i % 16):
|
|
||||||
progmem.write('\n\t')
|
|
||||||
progmem.write(f"0x{byte:02X},")
|
|
||||||
|
|
||||||
progmem.write('\n};\n\n')
|
|
||||||
assetMap[asset_path] = { "name": asset_var, "mime": asset_mime, "size": len(file_data) }
|
|
||||||
|
|
||||||
progmem.write('typedef std::function<void(const String& uri, const String& contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler;\n\n')
|
|
||||||
progmem.write('class WWWData {\n')
|
|
||||||
progmem.write('\tpublic:\n')
|
|
||||||
progmem.write('\t\tstatic void registerRoutes(RouteRegistrationHandler handler) {\n')
|
|
||||||
|
|
||||||
for asset_path, asset in assetMap.items():
|
|
||||||
progmem.write(f'\t\t\thandler("/{asset_path}", "{asset["mime"]}", {asset["name"]}, {asset["size"]});\n')
|
|
||||||
|
|
||||||
progmem.write('\t\t}\n')
|
|
||||||
progmem.write('};\n\n')
|
|
||||||
|
|
||||||
def build_webapp():
|
def build_webapp():
|
||||||
os.chdir("../app2")
|
if package_manager := get_package_manager():
|
||||||
print("Building app with pnpm")
|
print(f"Building interface with {package_manager}")
|
||||||
env.Execute("pnpm install")
|
os.chdir(interface_dir)
|
||||||
env.Execute("pnpm run build")
|
env.Execute(f"{package_manager} install")
|
||||||
os.chdir("../esp32")
|
env.Execute(f"{package_manager} run build")
|
||||||
|
os.chdir("..")
|
||||||
|
else:
|
||||||
|
raise Exception(
|
||||||
|
"No lock-file found. Please install dependencies for interface (eg. npm install)"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def embed_webapp():
|
def embed_webapp():
|
||||||
if flag_exists("EMBED_WWW"):
|
if flag_exists("EMBED_WWW"):
|
||||||
print("Converting interface to PROGMEM")
|
print("Converting interface to PROGMEM")
|
||||||
build_progmem()
|
build_progmem()
|
||||||
return
|
return
|
||||||
|
add_app_to_filesystem()
|
||||||
|
|
||||||
|
|
||||||
|
def build_progmem():
|
||||||
|
mimetypes.init()
|
||||||
|
with open(output_file, "w") as progmem:
|
||||||
|
progmem.write("#include <functional>\n")
|
||||||
|
progmem.write("#include <Arduino.h>\n")
|
||||||
|
|
||||||
|
assetMap = {}
|
||||||
|
|
||||||
|
for idx, path in enumerate(Path(build_dir).rglob("*.*")):
|
||||||
|
asset_path = path.relative_to(build_dir).as_posix()
|
||||||
|
asset_mime = (
|
||||||
|
mimetypes.guess_type(asset_path)[0] or "application/octet-stream"
|
||||||
|
)
|
||||||
|
print(f"Converting {asset_path}")
|
||||||
|
|
||||||
|
asset_var = f"ESP_SVELTEKIT_DATA_{idx}"
|
||||||
|
progmem.write(f"// {asset_path}\n")
|
||||||
|
progmem.write(f"const uint8_t {asset_var}[] = {{\n\t")
|
||||||
|
file_data = gzip.compress(path.read_bytes())
|
||||||
|
|
||||||
|
for i, byte in enumerate(file_data):
|
||||||
|
if i and not (i % 16):
|
||||||
|
progmem.write("\n\t")
|
||||||
|
progmem.write(f"0x{byte:02X},")
|
||||||
|
|
||||||
|
progmem.write("\n};\n\n")
|
||||||
|
assetMap[asset_path] = {
|
||||||
|
"name": asset_var,
|
||||||
|
"mime": asset_mime,
|
||||||
|
"size": len(file_data),
|
||||||
|
}
|
||||||
|
|
||||||
|
progmem.write(
|
||||||
|
"typedef std::function<void(const String& uri, const String& contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler;\n\n"
|
||||||
|
)
|
||||||
|
progmem.write("class WWWData {\n")
|
||||||
|
progmem.write("\tpublic:\n")
|
||||||
|
progmem.write(
|
||||||
|
"\t\tstatic void registerRoutes(RouteRegistrationHandler handler) {\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
for asset_path, asset in assetMap.items():
|
||||||
|
progmem.write(
|
||||||
|
f'\t\t\thandler("/{asset_path}", "{asset["mime"]}", {asset["name"]}, {asset["size"]});\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
progmem.write("\t\t}\n")
|
||||||
|
progmem.write("};\n\n")
|
||||||
|
|
||||||
|
|
||||||
|
def add_app_to_filesystem():
|
||||||
|
build_path = Path(build_dir)
|
||||||
|
www_path = Path(filesystem_dir)
|
||||||
|
if www_path.exists() and www_path.is_dir():
|
||||||
|
rmtree(www_path)
|
||||||
|
print("Copying and compress interface to data directory")
|
||||||
|
copytree(build_path, www_path)
|
||||||
|
for current_path, _, files in os.walk(www_path):
|
||||||
|
for file in files:
|
||||||
|
gzip_file(os.path.join(current_path, file))
|
||||||
|
print("Build LittleFS file system image and upload to ESP32")
|
||||||
|
env.Execute("pio run --target uploadfs")
|
||||||
|
|
||||||
|
|
||||||
print("running: build_interface.py")
|
print("running: build_interface.py")
|
||||||
if (should_regenerate_output_file()):
|
if should_regenerate_output_file():
|
||||||
build_webapp()
|
build_webapp()
|
||||||
embed_webapp()
|
embed_webapp()
|
||||||
|
|||||||
Reference in New Issue
Block a user