Skip to content

Ci wippersnapper boards local txt #217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 14 commits into
base: ci-wippersnapper
Choose a base branch
from
Draft
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 123 additions & 1 deletion build_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@
sys.argv.pop(sys.argv.index("--build_timeout") + 1)
sys.argv.remove("--build_timeout")

# optional --boards-local-txt argument to copy boards.local.txt
# to the appropriate folder after installing the platform BSP.
COPY_BOARDS_LOCAL_TXT = False
boards_local_txt = None
if "--boards-local-txt" in sys.argv:
COPY_BOARDS_LOCAL_TXT = True
if sys.argv.index("--boards-local-txt") + 1 >= len(sys.argv):
# check if in cwd
if os.path.exists("boards.local.txt"):
boards_local_txt = "boards.local.txt"
else:
sys.stderr.write("Error: --boards-local-txt option requires a path to boards.local.txt file or to be present in current directory\n")
sys.exit(1)
else:
# get the boards.local.txt file from the command line
if not os.path.exists(sys.argv[sys.argv.index("--boards-local-txt") + 1]):
sys.stderr.write("Error: boards.local.txt file does not exist\n")
sys.exit(1)
boards_local_txt = sys.argv[sys.argv.index("--boards-local-txt") + 1]
sys.argv.pop(sys.argv.index("--boards-local-txt") + 1)
sys.argv.remove("--boards-local-txt")

# add user bin to path!
BUILD_DIR = ''
# add user bin to path!
Expand Down Expand Up @@ -380,6 +402,16 @@ def test_examples_in_folder(platform, folderpath):
if os.path.exists(gen_file_name):
ColorPrint.print_info("generating")

# check if boards.local.txt should be copied
if COPY_BOARDS_LOCAL_TXT:
boards_local_txt = folderpath+"/."+platform+".boards.local.txt"
if os.path.exists(boards_local_txt):
ColorPrint.print_info("Copying boards.local.txt from "+boards_local_txt)
install_boards_local_txt(":".join(fqbn.split(':')[0:2]), boards_local_txt)
elif os.path.exists(folderpath+"/boards.local.txt"):
ColorPrint.print_info("Copying boards.local.txt from "+folderpath+"/boards.local.txt")
install_boards_local_txt(":".join(fqbn.split(':')[0:2]), folderpath+"/boards.local.txt")

if BUILD_WARN:
if os.path.exists(gen_file_name):
cmd = ['arduino-cli', 'compile', '--warnings', 'all', '--fqbn', fqbn, '-e', folderpath]
Expand Down Expand Up @@ -428,6 +460,89 @@ def test_examples_in_folder(platform, folderpath):
success = 1


def install_boards_local_txt(core_fqbn, boards_local_txt):
"""Copies boards.local.txt to the appropriate folder for the given core_fqbn.
:param str core_fqbn: The first two segments of fully qualified board
name, vendor:architecture (e.g., "adafruit:samd").
:param str boards_local_txt: The path to the boards.local.txt file.
"""
try:
local_app_data_dir = os.environ.get('HOME', '')
data_dir = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

place local_app_data_dir and data_dir above the try, it's referenced lower in the code too. If it fails, you dont have a reference to these when you need data_dir again on L479

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe this makes sense (with regards to line 479 of original review), as the try covers the entire function so the variables won't be reused in the event of a caught error, can you explain it to me?

if os.path.exists(os.path.join(local_app_data_dir, '.arduino15')):
data_dir = os.path.join(local_app_data_dir, '.arduino15')
elif os.path.exists(os.path.join(local_app_data_dir, '.arduino')):
data_dir = os.path.join(local_app_data_dir, '.arduino')

# Get arduino-cli data directory
import json
if data_dir:
config_output = subprocess.check_output(["arduino-cli", "config", "dump", "--format", "json", "--config-dir", data_dir]).decode()
else:
config_output = subprocess.check_output(["arduino-cli", "config", "dump", "--format", "json"]).decode()
config = json.loads(config_output)
ColorPrint.print_info(f"Using arduino-cli config: {config_output.strip()}")

# Extract data directory, with fallback to default
data_dir = config.get("directories", {}).get("data", "")
if not data_dir:
if os.path.exists(os.path.join(local_app_data_dir, 'Arduino')):
data_dir = os.path.join(local_app_data_dir, 'Arduino')
else:
ColorPrint.print_warn("No valid data directory found, cannot copy boards.local.txt")
return

ColorPrint.print_info(f"Using data directory: {data_dir}")

# Parse platform vendor and architecture from core_fqbn (e.g., "adafruit:samd")
parts = core_fqbn.split(':')
if len(parts) >= 2:
vendor = parts[0]
architecture = parts[1]
else:
vendor = core_fqbn
architecture = vendor

ColorPrint.print_info(f"Using vendor: {vendor}, architecture: {architecture}")

# Construct base platform path, fall back to architecture if vendor rebadged BSP.
platform_base = os.path.join(data_dir, "packages", vendor, "hardware", architecture) if \
os.path.exists(os.path.join(data_dir, "packages", vendor, "hardware", architecture)) else \
os.path.join(data_dir, "packages", architecture, "hardware", architecture) if \
os.path.exists(os.path.join(data_dir, "packages", architecture, "hardware", architecture)) else \
os.path.join(data_dir, "hardware", vendor, architecture) if \
os.path.exists(os.path.join(data_dir, "hardware", vendor, architecture)) else \
os.path.join(data_dir, "hardware", architecture, architecture)

# Find the latest version directory
if os.path.exists(platform_base):
if os.path.exists(os.path.join(platform_base, "boards.txt")):
shutil.copyfile(boards_local_txt, os.path.join(platform_base, "boards.local.txt"))
ColorPrint.print_info(f"Copied boards.local.txt to {os.path.join(platform_base, 'boards.local.txt')}")
else:
versions = [d for d in os.listdir(platform_base) if os.path.isdir(os.path.join(platform_base, d))]
ColorPrint.print_info(f"Found subdirectories for {platform_base}:\n {versions}")
# Filter out non-version directories (e.g., 'tools', 'libraries') while supporting 1.0-dev 1.0.0-offline-mode.102 etc
versions = [v for v in versions if re.match(r'^(v)?\d+\.\d+(\.\d+(-\w+)?)?(\.\d+)?$', v)]
ColorPrint.print_info(f"Filtered versions: {versions}")
if versions:
# Sort versions and take the latest (could be improved with proper version sorting)
latest_version = sorted(versions)[-1]
platform_path = os.path.join(platform_base, latest_version)

dest_path = os.path.join(platform_path, "boards.local.txt")
shutil.copyfile(boards_local_txt, dest_path)
ColorPrint.print_info(f"Copied boards.local.txt to {dest_path}")

else:
ColorPrint.print_warn(f"No version directories found in {platform_base}")
else:
ColorPrint.print_warn(f"Platform path {platform_base} does not exist")

except Exception as e:
ColorPrint.print_fail(f"Error injecting boards.local.txt for {core_fqbn}: {e}")


def main():
# Test platforms
platforms = []
Expand All @@ -451,8 +566,15 @@ def main():
fqbn = ALL_PLATFORMS[platform][0]
print('#'*80)
ColorPrint.print_info("SWITCHING TO "+fqbn)
install_platform(":".join(fqbn.split(':', 2)[0:2]), ALL_PLATFORMS[platform]) # take only first two elements
core_fqbn = ":".join(fqbn.split(':', 2)[0:2]) # take only first two elements
install_platform(core_fqbn, ALL_PLATFORMS[platform])

# Inject boards.local.txt if requested
if COPY_BOARDS_LOCAL_TXT and boards_local_txt:
install_boards_local_txt(core_fqbn, boards_local_txt)
print('#'*80)

# Test examples in the platform folder
if not IS_LEARNING_SYS:
test_examples_in_folder(platform, BUILD_DIR+"/examples")
else:
Expand Down