| 
40 | 40 |         if os.path.exists("boards.local.txt"):  | 
41 | 41 |             boards_local_txt = "boards.local.txt"  | 
42 | 42 |         else:  | 
43 |  | -            sys.stderr.write("Error: --boards-local-txt option requires a path to boards.local.txt file\n")  | 
 | 43 | +            sys.stderr.write("Error: --boards-local-txt option requires a path to boards.local.txt file or to be present in current directory\n")  | 
44 | 44 |             sys.exit(1)  | 
45 | 45 |     else:  | 
46 | 46 |         # get the boards.local.txt file from the command line  | 
@@ -450,6 +450,88 @@ def test_examples_in_folder(platform, folderpath):  | 
450 | 450 |             success = 1  | 
451 | 451 | 
 
  | 
452 | 452 | 
 
  | 
 | 453 | +def install_boards_local_txt(core_fqbn, boards_local_txt):  | 
 | 454 | +    """Copies boards.local.txt to the appropriate folder for the given core_fqbn.  | 
 | 455 | +    :param str core_fqbn: The first two segments of fully qualified board  | 
 | 456 | +      name, vendor:architecture (e.g., "adafruit:samd").  | 
 | 457 | +    :param str boards_local_txt: The path to the boards.local.txt file.  | 
 | 458 | +    """  | 
 | 459 | +    try:  | 
 | 460 | +        local_app_data_dir = os.environ.get('HOME', '')  | 
 | 461 | +        data_dir = None  | 
 | 462 | +        if os.path.exists(os.path.join(local_app_data_dir, 'Arduino')):  | 
 | 463 | +            data_dir = os.path.join(local_app_data_dir, 'Arduino')  | 
 | 464 | +        elif os.path.exists(os.path.join(local_app_data_dir, '.arduino15')):  | 
 | 465 | +            data_dir = os.path.join(local_app_data_dir, '.arduino15')  | 
 | 466 | +        elif os.path.exists(os.path.join(local_app_data_dir, '.arduino')):  | 
 | 467 | +            data_dir = os.path.join(local_app_data_dir, '.arduino')  | 
 | 468 | + | 
 | 469 | +        # Get arduino-cli data directory  | 
 | 470 | +        import json  | 
 | 471 | +        if data_dir:  | 
 | 472 | +            config_output = subprocess.check_output(["arduino-cli", "config", "dump", "--format", "json", "--config-dir", data_dir]).decode()  | 
 | 473 | +        else:  | 
 | 474 | +            config_output = subprocess.check_output(["arduino-cli", "config", "dump", "--format", "json"]).decode()  | 
 | 475 | +        config = json.loads(config_output)  | 
 | 476 | +        ColorPrint.print_info(f"Using arduino-cli config: {config_output.strip()}")  | 
 | 477 | +          | 
 | 478 | +        # Extract data directory, with fallback to default  | 
 | 479 | +        data_dir = config.get("directories", {}).get("data", data_dir)  | 
 | 480 | +        if not data_dir:  | 
 | 481 | +            ColorPrint.print_warn("No valid data directory found, cannot copy boards.local.txt")  | 
 | 482 | +            return  | 
 | 483 | + | 
 | 484 | +        ColorPrint.print_info(f"Using data directory: {data_dir}")  | 
 | 485 | + | 
 | 486 | +        # Parse platform vendor and architecture from core_fqbn (e.g., "adafruit:samd")  | 
 | 487 | +        parts = core_fqbn.split(':')  | 
 | 488 | +        if len(parts) >= 2:  | 
 | 489 | +            vendor = parts[0]  | 
 | 490 | +            architecture = parts[1]  | 
 | 491 | +        else:  | 
 | 492 | +            vendor = core_fqbn  | 
 | 493 | +            architecture = vendor  | 
 | 494 | + | 
 | 495 | +        ColorPrint.print_info(f"Using vendor: {vendor}, architecture: {architecture}")  | 
 | 496 | + | 
 | 497 | +        # Construct base platform path, fall back to architecture if vendor rebadged BSP.  | 
 | 498 | +        platform_base = os.path.join(data_dir, "packages", vendor, "hardware", architecture) if \  | 
 | 499 | +            os.path.exists(os.path.join(data_dir, "packages", vendor, "hardware", architecture)) else \  | 
 | 500 | +            os.path.join(data_dir, "packages", architecture, "hardware", architecture) if \  | 
 | 501 | +            os.path.exists(os.path.join(data_dir, "packages", architecture, "hardware", architecture)) else \  | 
 | 502 | +            os.path.join(data_dir, "hardware", vendor, architecture) if \  | 
 | 503 | +            os.path.exists(os.path.join(data_dir, "hardware", vendor, architecture)) else \  | 
 | 504 | +            os.path.join(data_dir, "hardware",  | 
 | 505 | +                            architecture, architecture)  | 
 | 506 | + | 
 | 507 | +        # Find the latest version directory  | 
 | 508 | +        if os.path.exists(platform_base):  | 
 | 509 | +            if os.path.exists(os.path.join(platform_base, "boards.txt")):  | 
 | 510 | +                shutil.copyfile(boards_local_txt, os.path.join(platform_base, "boards.local.txt"))  | 
 | 511 | +                ColorPrint.print_info(f"Copied boards.local.txt to {os.path.join(platform_base, 'boards.local.txt')}")  | 
 | 512 | +            else:  | 
 | 513 | +                versions = [d for d in os.listdir(platform_base) if os.path.isdir(os.path.join(platform_base, d))]  | 
 | 514 | +                ColorPrint.print_info(f"Found versions: {versions}")  | 
 | 515 | +                # Filter out non-version directories (e.g., 'tools', 'libraries') while supporting 1.0-dev 1.0.0-offline-mode.102 etc  | 
 | 516 | +                versions = [v for v in versions if re.match(r'^(v)?\d+\.\d+(\.\d+(-\w+)?)?(\.\d+)?$', v)]  | 
 | 517 | +                if versions:  | 
 | 518 | +                    # Sort versions and take the latest (could be improved with proper version sorting)  | 
 | 519 | +                    latest_version = sorted(versions)[-1]  | 
 | 520 | +                    platform_path = os.path.join(platform_base, latest_version)  | 
 | 521 | +                      | 
 | 522 | +                    dest_path = os.path.join(platform_path, "boards.local.txt")  | 
 | 523 | +                    shutil.copyfile(boards_local_txt, dest_path)  | 
 | 524 | +                    ColorPrint.print_info(f"Copied boards.local.txt to {dest_path}")  | 
 | 525 | + | 
 | 526 | +                else:  | 
 | 527 | +                    ColorPrint.print_warn(f"No version directories found in {platform_base}")  | 
 | 528 | +        else:  | 
 | 529 | +            ColorPrint.print_warn(f"Platform path {platform_base} does not exist")  | 
 | 530 | + | 
 | 531 | +    except Exception as e:  | 
 | 532 | +        ColorPrint.print_fail(f"Error injecting boards.local.txt for {core_fqbn}: {e}")  | 
 | 533 | + | 
 | 534 | + | 
453 | 535 | def main():  | 
454 | 536 |     # Test platforms  | 
455 | 537 |     platforms = []  | 
@@ -478,80 +560,7 @@ def main():  | 
478 | 560 | 
 
  | 
479 | 561 |         # Inject boards.local.txt if requested  | 
480 | 562 |         if COPY_BOARDS_LOCAL_TXT and boards_local_txt:  | 
481 |  | -            try:  | 
482 |  | -                local_app_data_dir = os.environ.get('HOME', '')  | 
483 |  | -                data_dir = None  | 
484 |  | -                if os.path.exists(os.path.join(local_app_data_dir, 'Arduino')):  | 
485 |  | -                    data_dir = os.path.join(local_app_data_dir, 'Arduino')  | 
486 |  | -                elif os.path.exists(os.path.join(local_app_data_dir, '.arduino15')):  | 
487 |  | -                    data_dir = os.path.join(local_app_data_dir, '.arduino15')  | 
488 |  | -                elif os.path.exists(os.path.join(local_app_data_dir, '.arduino')):  | 
489 |  | -                    data_dir = os.path.join(local_app_data_dir, '.arduino')  | 
490 |  | - | 
491 |  | -                # Get arduino-cli data directory  | 
492 |  | -                import json  | 
493 |  | -                if data_dir:  | 
494 |  | -                    config_output = subprocess.check_output(["arduino-cli", "config", "dump", "--format", "json", "--config-dir", data_dir]).decode()  | 
495 |  | -                else:  | 
496 |  | -                    config_output = subprocess.check_output(["arduino-cli", "config", "dump", "--format", "json"]).decode()  | 
497 |  | -                config = json.loads(config_output)  | 
498 |  | -                ColorPrint.print_info(f"Using arduino-cli config: {config_output.strip()}")  | 
499 |  | -                  | 
500 |  | -                # Extract data directory, with fallback to default  | 
501 |  | -                data_dir = config.get("directories", {}).get("data", data_dir)  | 
502 |  | -                if not data_dir:  | 
503 |  | -                    ColorPrint.print_warn("No valid data directory found, cannot copy boards.local.txt")  | 
504 |  | -                    continue  | 
505 |  | - | 
506 |  | -                ColorPrint.print_info(f"Using data directory: {data_dir}")  | 
507 |  | - | 
508 |  | -                # Parse platform vendor and architecture from core_fqbn (e.g., "adafruit:samd")  | 
509 |  | -                parts = core_fqbn.split(':')  | 
510 |  | -                if len(parts) >= 2:  | 
511 |  | -                    vendor = parts[0]  | 
512 |  | -                    architecture = parts[1]  | 
513 |  | -                else:  | 
514 |  | -                    vendor = core_fqbn  | 
515 |  | -                    architecture = vendor  | 
516 |  | - | 
517 |  | -                ColorPrint.print_info(f"Using vendor: {vendor}, architecture: {architecture}")  | 
518 |  | - | 
519 |  | -                # Construct base platform path, fall back to architecture if vendor rebadged BSP.  | 
520 |  | -                platform_base = os.path.join(data_dir, "packages", vendor, "hardware", architecture) if \  | 
521 |  | -                    os.path.exists(os.path.join(data_dir, "packages", vendor, "hardware", architecture)) else \  | 
522 |  | -                    os.path.join(data_dir, "packages", architecture, "hardware", architecture) if \  | 
523 |  | -                    os.path.exists(os.path.join(data_dir, "packages", architecture, "hardware", architecture)) else \  | 
524 |  | -                    os.path.join(data_dir, "hardware", vendor, architecture) if \  | 
525 |  | -                    os.path.exists(os.path.join(data_dir, "hardware", vendor, architecture)) else \  | 
526 |  | -                    os.path.join(data_dir, "hardware",  | 
527 |  | -                                 architecture, architecture)  | 
528 |  | - | 
529 |  | -                # Find the latest version directory  | 
530 |  | -                if os.path.exists(platform_base):  | 
531 |  | -                    if os.path.exists(os.path.join(platform_base, "boards.txt")):  | 
532 |  | -                        shutil.copyfile(boards_local_txt, os.path.join(platform_base, "boards.local.txt"))  | 
533 |  | -                        ColorPrint.print_info(f"Copied boards.local.txt to {os.path.join(platform_base, 'boards.local.txt')}")  | 
534 |  | -                    else:  | 
535 |  | -                        versions = [d for d in os.listdir(platform_base) if os.path.isdir(os.path.join(platform_base, d))]  | 
536 |  | -                        ColorPrint.print_info(f"Found versions: {versions}")  | 
537 |  | -                        # Filter out non-version directories (e.g., 'tools', 'libraries') while supporting 1.0-dev 1.0.0-offline-mode.102 etc  | 
538 |  | -                        versions = [v for v in versions if re.match(r'^(v)?\d+\.\d+(\.\d+(-\w+)?)?(\.\d+)?$', v)]  | 
539 |  | -                        if versions:  | 
540 |  | -                            # Sort versions and take the latest (could be improved with proper version sorting)  | 
541 |  | -                            latest_version = sorted(versions)[-1]  | 
542 |  | -                            platform_path = os.path.join(platform_base, latest_version)  | 
543 |  | -                              | 
544 |  | -                            dest_path = os.path.join(platform_path, "boards.local.txt")  | 
545 |  | -                            shutil.copyfile(boards_local_txt, dest_path)  | 
546 |  | -                            ColorPrint.print_info(f"Copied boards.local.txt to {dest_path}")  | 
547 |  | - | 
548 |  | -                        else:  | 
549 |  | -                            ColorPrint.print_warn(f"No version directories found in {platform_base}")  | 
550 |  | -                else:  | 
551 |  | -                    ColorPrint.print_warn(f"Platform path {platform_base} does not exist")  | 
552 |  | -    | 
553 |  | -            except Exception as e:  | 
554 |  | -                ColorPrint.print_fail(f"Error injecting boards.local.txt for {core_fqbn}: {e}")  | 
 | 563 | +            install_boards_local_txt(core_fqbn, boards_local_txt)  | 
555 | 564 |         print('#'*80)  | 
556 | 565 | 
 
  | 
557 | 566 |         # Test examples in the platform folder  | 
 | 
0 commit comments