From e35bedab48c5453474bbd466390b5412f8494c4d Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:57:47 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8=20Importable=20configuration.py=20?= =?UTF-8?q?for=20mc-apply.py=20(#28182)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PlatformIO/scripts/collect-code-tests.py | 2 +- .../share/PlatformIO/scripts/configuration.py | 69 ++++++---- .../share/PlatformIO/scripts/mc-apply.py | 127 ++++-------------- 3 files changed, 72 insertions(+), 126 deletions(-) diff --git a/buildroot/share/PlatformIO/scripts/collect-code-tests.py b/buildroot/share/PlatformIO/scripts/collect-code-tests.py index a5758e97d3..fc82e9072d 100644 --- a/buildroot/share/PlatformIO/scripts/collect-code-tests.py +++ b/buildroot/share/PlatformIO/scripts/collect-code-tests.py @@ -28,7 +28,7 @@ if pioutil.is_pio_build(): name = f"marlin_{name}", dependencies = None, actions = [ - f"echo ====== Configuring for marlin_{name} ======", + f"@echo ====== Configuring for marlin_{name} ======", "restore_configs", f"cp -f {path} ./Marlin/config.ini", "python ./buildroot/share/PlatformIO/scripts/configuration.py", diff --git a/buildroot/share/PlatformIO/scripts/configuration.py b/buildroot/share/PlatformIO/scripts/configuration.py index 7d811b47ed..71d4e3777c 100755 --- a/buildroot/share/PlatformIO/scripts/configuration.py +++ b/buildroot/share/PlatformIO/scripts/configuration.py @@ -7,27 +7,29 @@ import re, os, shutil, configparser, datetime from pathlib import Path verbose = 0 -def blab(str,level=1): - if verbose >= level: print(f"[config] {str}") +def blab(msg, level=1): + if verbose >= level: print(f"[config] {msg}") def config_path(cpath): return Path("Marlin", cpath) # Apply a single name = on/off ; name = value ; etc. # TODO: Limit to the given (optional) configuration -def apply_opt(name, val, conf=None): +def apply_opt(name, val): if name == "lcd": name, val = val, "on" - # Create a regex to match the option and capture parts of the line - # 1: Indentation - # 2: Comment - # 3: #define and whitespace - # 4: Option name - # 5: First space after name - # 6: Remaining spaces between name and value - # 7: Option value - # 8: Whitespace after value - # 9: End comment + """ + Create a regex to match the option and capture parts of the line + 1: Indentation + 2: Comment + 3: #define and whitespace + 4: Option name + 5: First space after name + 6: Remaining spaces between name and value + 7: Option value + 8: Whitespace after value + 9: End comment + """ regex = re.compile( rf"^(\s*)(//\s*)?(#define\s+)({name}\b)(\s?)(\s*)(.*?)(\s*)(//.*)?$", re.IGNORECASE @@ -101,11 +103,16 @@ def apply_opt(name, val, conf=None): # Everything in the named sections. Section hint for exceptions may be added. def disable_all_options(): # Create a regex to match the option and capture parts of the line + blab("Disabling all configuration options...") regex = re.compile(r'^(\s*)(#define\s+)([A-Z0-9_]+\b)(\s?)(\s*)(.*?)(\s*)(//.*)?$', re.IGNORECASE) # Disable all enabled options in both Config files for file in ("Configuration.h", "Configuration_adv.h"): fullpath = config_path(file) + if not fullpath.exists(): + blab(f"File not found: {fullpath}", 0) + continue + lines = fullpath.read_text(encoding='utf-8').split('\n') found = False for i in range(len(lines)): @@ -120,14 +127,18 @@ def disable_all_options(): # TODO: Comment more lines in a multi-line define with \ continuation lines[i] = re.sub(r'^(\s*)(#define)(\s{1,3})?(\s*)', r'\1//\2 \4', line) blab(f"Disable {name}") + #blab(f"Disable {name}", 2) + # TODO: Taken from mc-apply, not sure which # If the option was found, write the modified lines if found: fullpath.write_text('\n'.join(lines), encoding='utf-8') + blab(f"Updated {file}") # Fetch configuration files from GitHub given the path. # Return True if any files were fetched. def fetch_example(url): + blab(f"Fetching example configuration from: {url}") if url.endswith("/"): url = url[:-1] if not url.startswith('http'): brch = "bugfix-2.1.x" @@ -143,9 +154,12 @@ def fetch_example(url): fetch = "wget -q -O" else: blab("Couldn't find curl or wget", -1) + #blab("Couldn't find curl or wget", 0) + # TODO: Taken from mc-apply, not sure which return False # Reset configurations to default + blab("Resetting configurations to default...") os.system("git checkout HEAD Marlin/*.h") # Try to fetch the remote files @@ -154,9 +168,15 @@ def fetch_example(url): if os.system(f"{fetch} wgot {url}/{fn} >/dev/null 2>&1") == 0: shutil.move('wgot', config_path(fn)) gotfile = True + blab(f"Fetched {fn}", 2) if Path('wgot').exists(): shutil.rmtree('wgot') + if gotfile: + blab("Example configuration fetched successfully") + else: + blab("Failed to fetch example configuration", 0) + return gotfile def section_items(cp, sectkey): @@ -217,8 +237,6 @@ def apply_config_ini(cp): # For each ini_use_config item perform an action for ckey in config_keys: - addbase = False - # For a key ending in .ini load and parse another .ini file if ckey.endswith('.ini'): sect = 'base' @@ -278,12 +296,17 @@ else: # # From within PlatformIO use the loaded INI file # - import pioutil - if pioutil.is_pio_build(): - try: - verbose = int(pioutil.env.GetProjectOption('custom_verbose')) - except: - pass + try: + import pioutil + if pioutil.is_pio_build(): + try: + verbose = int(pioutil.env.GetProjectOption('custom_verbose')) + except: + pass - from platformio.project.config import ProjectConfig - apply_config_ini(ProjectConfig()) + from platformio.project.config import ProjectConfig + apply_config_ini(ProjectConfig()) + except AttributeError: + # Handle the 'IsIntegrationDump' error here, or just continue if + # the build is not a PlatformIO build where pioutil would be unavailable. + pass diff --git a/buildroot/share/PlatformIO/scripts/mc-apply.py b/buildroot/share/PlatformIO/scripts/mc-apply.py index 6ec7122688..7d04ad5585 100755 --- a/buildroot/share/PlatformIO/scripts/mc-apply.py +++ b/buildroot/share/PlatformIO/scripts/mc-apply.py @@ -1,32 +1,29 @@ #!/usr/bin/env python3 -# -# mc-apply.py -# -# Apply firmware configuration from a JSON file (marlin_config.json). -# -# usage: mc-apply.py [-h] [--opt] [--verbose] [config_file] -# -# Process Marlin firmware configuration. -# -# positional arguments: -# config_file Path to the configuration file. -# -# optional arguments: -# -h, --help show this help message and exit -# --opt Output as an option setting script. -# --verbose Enable verbose logging (0-2) -# -import json, sys, os, re, shutil, datetime +""" +mc-apply.py + + Apply firmware configuration from a JSON file (marlin_config.json). + + usage: mc-apply.py [-h] [--opt] [--verbose] [config_file] + + Process Marlin firmware configuration. + + positional arguments: + config_file Path to the configuration file. + + optional arguments: + -h, --help Show this help message and exit + --opt Output as an option setting script. + --verbose Enable verbose logging (0-2) +""" + +import json, sys, os, configuration import config import argparse -from pathlib import Path verbose = 0 -def blab(str, level=1): - if verbose >= level: print(f"[mc-apply] {str}") - -def config_path(cpath): - return Path("Marlin", cpath) +def blab(msg, level=1): + if verbose >= level: print(f"[mc-apply] {msg}") def normalize_value(v): """ @@ -55,80 +52,6 @@ def normalize_value(v): else: return ('set', v if not isinstance(v, bool) else v_str) -# Disable all (most) defined options in the configuration files. -def disable_all_options(): - blab("Disabling all configuration options...") - # Create a regex to match the option and capture parts of the line - regex = re.compile(r'^(\s*)(#define\s+)([A-Z0-9_]+\b)(\s?)(\s*)(.*?)(\s*)(//.*)?$', re.IGNORECASE) - - # Disable all enabled options in both Config files - for file in ("Configuration.h", "Configuration_adv.h"): - fullpath = config_path(file) - if not fullpath.exists(): - blab(f"File not found: {fullpath}", 0) - continue - - lines = fullpath.read_text(encoding='utf-8').split('\n') - found = False - for i in range(len(lines)): - line = lines[i] - match = regex.match(line) - if match: - name = match[3].upper() - if name in ('CONFIGURATION_H_VERSION', 'CONFIGURATION_ADV_H_VERSION', 'CONFIG_EXAMPLES_DIR'): continue - if name.startswith('_'): continue - found = True - # Comment out the define - lines[i] = re.sub(r'^(\s*)(#define)(\s{1,3})?(\s*)', r'\1//\2 \4', line) - blab(f"Disable {name}", 2) - - # If the option was found, write the modified lines - if found: - fullpath.write_text('\n'.join(lines), encoding='utf-8') - blab(f"Updated {file}") - -# Fetch configuration files from GitHub given the path. -# Return True if any files were fetched. -def fetch_example(url): - blab(f"Fetching example configuration from: {url}") - if url.endswith("/"): url = url[:-1] - if not url.startswith('http'): - brch = "bugfix-2.1.x" - if '@' in url: url, brch = map(str.strip, url.split('@')) - if url == 'examples/default': url = 'default' - url = f"https://raw.githubusercontent.com/MarlinFirmware/Configurations/{brch}/config/{url}" - url = url.replace("%", "%25").replace(" ", "%20") - - # Find a suitable fetch command - if shutil.which("curl") is not None: - fetch = "curl -L -s -S -f -o" - elif shutil.which("wget") is not None: - fetch = "wget -q -O" - else: - blab("Couldn't find curl or wget", 0) - return False - - # Reset configurations to default - blab("Resetting configurations to default...") - os.system("git checkout HEAD Marlin/*.h") - - # Try to fetch the remote files - gotfile = False - for fn in ("Configuration.h", "Configuration_adv.h", "_Bootscreen.h", "_Statusscreen.h"): - if os.system(f"{fetch} wgot {url}/{fn} >/dev/null 2>&1") == 0: - shutil.move('wgot', config_path(fn)) - gotfile = True - blab(f"Fetched {fn}", 2) - - if Path('wgot').exists(): shutil.rmtree('wgot') - - if gotfile: - blab("Example configuration fetched successfully") - else: - blab("Failed to fetch example configuration", 0) - - return gotfile - def report_version(conf): if 'VERSION' in conf: blab("Configuration version information:") @@ -142,7 +65,7 @@ def write_opt_file(conf, outpath='Marlin/apply_config.sh'): if key in ('__INITIAL_HASH', '__directives__', 'VERSION'): continue # Other keys are assumed to be configs - if not type(val) is dict: + if not isinstance(val, dict): continue # Write config commands to the script file @@ -198,17 +121,17 @@ def process_directives(directives): # Handle [disable] directive if directive == "[disable]": - disable_all_options() + configuration.disable_all_options() # Handle example fetching (examples/path or example/path) elif directive.startswith('examples/') or directive.startswith('example/'): if directive.startswith('example/'): directive = 'examples' + directive[7:] - fetch_example(directive) + configuration.fetch_example(directive) # Handle direct URLs elif directive.startswith('http://') or directive.startswith('https://'): - fetch_example(directive) + configuration.fetch_example(directive) else: blab(f"Unknown directive: {directive}", 0)