44from datetime import timedelta
55import json
66import os
7+ from packaging import version
78import re
89import shutil
910import subprocess
5253arch = arch_default
5354arduino_platform = arduino_platform_default
5455arduino_cli = ""
56+ arduino_cli_default_version = "0.10.0"
57+ arduino_cli_version = arduino_cli_default_version
5558
5659# List
5760sketch_list = []
@@ -117,9 +120,8 @@ def create_output_log_tree():
117120file .write (build_separator + "\n " )
118121# Folders
119122for board in board_fqbn :
123+ createFolder (os .path .join (output_dir ,board ,bin_dir ))
120124createFolder (os .path .join (output_dir ,board ))
121- if args .bin :
122- createFolder (os .path .join (output_dir ,board ,bin_dir ))
123125createFolder (os .path .join (build_output_dir ,board ))
124126
125127
@@ -152,6 +154,7 @@ def create_config():
152154
153155def check_config ():
154156global arduino_cli
157+ global arduino_cli_version
155158global arduino_cli_path
156159global sketches_path_list
157160global build_output_dir
@@ -193,37 +196,66 @@ def check_config():
193196else :
194197arduino_cli = "arduino-cli"
195198
199+ try :
200+ output = subprocess .check_output (
201+ [arduino_cli ,"version" ],stderr = subprocess .DEVNULL ,
202+ )
203+ except subprocess .CalledProcessError as e :
204+ print ('"' + " " .join (e .cmd )+ '" failed with code: {}!' .format (e .returncode ))
205+ print (e .stdout )
206+ quit (e .returncode )
207+ else :
208+ res = re .match (r".*Version:\s+(\d+\.\d+\.\d+).*" ,output .decode ("utf-8" ))
209+ if res :
210+ arduino_cli_version = res .group (1 )
211+ print ("Arduino CLI version used: " + arduino_cli_version )
212+ else :
213+ print (
214+ "Unable to define Arduino CLI version, use default: "
215+ + arduino_cli_default_version
216+ )
217+
196218try :
197219output = subprocess .check_output (
198220 [arduino_cli ,"core" ,"search" ,"stm32" ,"--additional-urls" ,stm32_url ],
199221stderr = subprocess .DEVNULL ,
200222 )
223+ except subprocess .CalledProcessError as e :
224+ print ('"' + " " .join (e .cmd )+ '" failed with code: {}!' .format (e .returncode ))
225+ print (e .stdout )
226+ quit (e .returncode )
227+ else :
201228if arduino_platform not in output .decode ("utf-8" ):
202- raise subprocess .CalledProcessError (1 ,"re" )
229+ print (arduino_platform + " is not installed!" )
230+ quit (1 )
203231# Add core and library path to sketches_path_list
204232try :
205233output = subprocess .check_output (
206234 [arduino_cli ,"config" ,"dump" ,"--format" ,"json" ],
207235stderr = subprocess .DEVNULL ,
208236 ).decode ("utf-8" )
237+ except subprocess .CalledProcessError as e :
238+ print (
239+ '"' + " " .join (e .cmd )+ '" failed with code: {}!' .format (e .returncode )
240+ )
241+ print (e .stdout )
242+ quit (e .returncode )
243+ else :
209244cli_config = json .loads (output )
210245if cli_config is not None :
211246if cli_config ["directories" ]["data" ]is not None :
212247sketches_path_list .append (cli_config ["directories" ]["data" ])
213248else :
214- raise subprocess .CalledProcessError (3 ,"No data directory" )
249+ print ("No data directory" )
250+ quit (1 )
215251if cli_config ["directories" ]["user" ]is not None :
216252sketches_path_list .append (cli_config ["directories" ]["user" ])
217253else :
218- raise subprocess .CalledProcessError (2 ,"No user directory" )
254+ print ("No user directory!" )
255+ quit (1 )
219256else :
220- raise subprocess .CalledProcessError (1 ,"No fqbn" )
221- except subprocess .CalledProcessError :
222- print ("No arduino-cli config!" )
223- quit ()
224- except subprocess .CalledProcessError :
225- print (arduino_platform + " is not installed!" )
226- quit ()
257+ print ("No arduino-cli config!" )
258+ quit (1 )
227259
228260
229261def load_core_config ():
@@ -366,7 +398,7 @@ def manage_inos():
366398break
367399else :
368400print ("Sketch {} path does not exist!" .format (args .ino ))
369- quit ()
401+ quit (1 )
370402# Sketches listed in a file
371403elif args .file :
372404assert os .path .exists (args .file ),"Sketches list file does not exist"
@@ -397,7 +429,7 @@ def manage_inos():
397429sketch_list .append (sketch_default )
398430if len (sketch_list )== 0 :
399431print ("No sketch to build for " + arduino_platform + "!" )
400- quit ()
432+ quit (1 )
401433
402434
403435# Find all .ino files and save directory
@@ -429,32 +461,41 @@ def find_board():
429461try :
430462output = subprocess .check_output (
431463 [arduino_cli ,"board" ,"listall" ,"--format" ,"json" ],
432- stderr = subprocess .DEVNULL ,
464+ stderr = subprocess .STDOUT ,
433465 ).decode ("utf-8" )
466+ except subprocess .CalledProcessError as e :
467+ print ('"' + " " .join (e .cmd )+ '" failed with code: {}!' .format (e .returncode ))
468+ print (e .stdout )
469+ quit (e .returncode )
470+ else :
434471boards_list = json .loads (output )
435472if boards_list is not None :
436473for board in boards_list ["boards" ]:
437474if arduino_platform in board ["FQBN" ]:
438475fqbn_list_tmp .append (board ["FQBN" ])
439- if not len (fqbn_list_tmp ):
440- raise subprocess .CalledProcessError (2 ,"No fqbn" )
441- else :
442- raise subprocess .CalledProcessError (1 ,"No fqbn" )
443- except subprocess .CalledProcessError :
444- print ("No fqbn found for " + arduino_platform + "!" )
445- quit ()
476+ if not len (fqbn_list_tmp ):
477+ print ("No boards found for " + arduino_platform )
478+ quit (1 )
446479
447480# For STM32 core, pnum is requested
448481for fqbn in fqbn_list_tmp :
449482try :
450483output = subprocess .check_output (
451484 [arduino_cli ,"board" ,"details" ,"--format" ,"json" ,fqbn ],
452- stderr = subprocess .DEVNULL ,
485+ stderr = subprocess .STDOUT ,
453486 ).decode ("utf-8" )
487+ except subprocess .CalledProcessError as e :
488+ print (
489+ '"' + " " .join (e .cmd )+ '" failed with code: {}!' .format (e .returncode )
490+ )
491+ print (e .stdout )
492+ quit (e .returncode )
493+ else :
454494board_detail = json .loads (output )
455495if board_detail is not None :
456496if "config_options" not in board_detail :
457- raise subprocess .CalledProcessError (3 ,"No config_options" )
497+ print ("No config_options found for " + fqbn )
498+ quit (1 )
458499for option in board_detail ["config_options" ]:
459500if option ["option" ]== "pnum" :
460501for value in option ["values" ]:
@@ -466,14 +507,12 @@ def find_board():
466507 )
467508break
468509else :
469- raise subprocess .CalledProcessError (1 ,"No fqbn" )
470- except subprocess .CalledProcessError as e :
471- print ("No fqbn detail found for " + e .cmd + "!" )
510+ print ('No detail found for:"' + fqbn + '"!' )
472511if board_found :
473512board_fqbn = collections .OrderedDict (sorted (board_found .items ()))
474513else :
475514print ("No board found for " + arduino_platform + "!" )
476- quit ()
515+ quit (1 )
477516
478517
479518# Check the status
@@ -484,14 +523,12 @@ def check_status(status, build_conf, boardKo):
484523
485524if status [1 ]== 0 :
486525result = "\033 [32msucceeded\033 [0m"
487- if args .bin :
488- bin_copy (build_conf [0 ],sketch_name )
489526nb_build_passed += 1
490527elif status [1 ]== 1 :
491528# Check if failed due to a region overflowed
492529logFile = os .path .join (build_conf [3 ],sketch_name + ".log" )
493530# error or fatal error
494- error_pattern = re .compile (r":\d+:\d+:\s.*error:\s" )
531+ error_pattern = re .compile (r":\d+:\d+:\s.*error:\s|^Error: " )
495532ld_pattern = re .compile ("arm-none-eabi/bin/ld:" )
496533overflow_pattern = re .compile (
497534r"(will not fit in |section .+ is not within )?region( .+ overflowed by [\d]+ bytes)?"
@@ -514,8 +551,6 @@ def check_status(status, build_conf, boardKo):
514551else :
515552# else consider it succeeded
516553result = "\033 [32msucceeded*\033 [0m"
517- if args .bin :
518- empty_bin (build_conf [0 ],sketch_name )
519554nb_build_passed += 1
520555else :
521556result = "\033 [31merror\033 [0m"
@@ -645,34 +680,6 @@ def log_final_result():
645680print (output_dir )
646681
647682
648- # Create an empty binary
649- def empty_bin (board_name ,sketch_name ):
650- empty_path = os .path .abspath (os .path .join (output_dir ,board_name ,bin_dir ))
651- createFolder (empty_path )
652- empty_file = os .path .join (
653- empty_path ,sketch_name + "_COULD_NOT_FIT_IN_THIS_BOARD.bin"
654- )
655- try :
656- f = open (empty_file ,"w" )
657- except IOError :
658- print ("Cannot create empty binary: " ,empty_file )
659- else :
660- f .close ()
661-
662-
663- # Create a "bin" directory for each board and copy all binary files
664- # from the builder output directory into it
665- def bin_copy (board_name ,sketch_name ):
666- try :
667- shutil .copy (
668- os .path .join (build_output_dir ,board_name ,sketch_name + ".bin" ),
669- os .path .abspath (os .path .join (output_dir ,board_name ,bin_dir )),
670- )
671- except OSError as e :
672- print ("Cannot copy the binary from the arduino-cli output: " + e .strerror )
673- raise
674-
675-
676683# Set up specific options to customise arduino builder command
677684def get_fqbn (b_name ):
678685if b_name in board_custom_fqbn and board_custom_fqbn [b_name ]:
@@ -696,8 +703,12 @@ def genBasicCommand(b_name):
696703cmd .append (build_output_cache_dir )
697704if args .verbose :
698705cmd .append ("--verbose" )
699- cmd .append ("-o" )
700- cmd .append (os .path .join (build_output_dir ,b_name ,"sketch" ))
706+ if version .parse (arduino_cli_version )<= version .parse (arduino_cli_default_version ):
707+ cmd .append ("--output" )
708+ cmd .append (os .path .join (output_dir ,b_name ,bin_dir ,"dummy_sketch" ))
709+ else :
710+ cmd .append ("--output-dir" )
711+ cmd .append (os .path .join (output_dir ,b_name ,bin_dir ))
701712cmd .append ("--fqbn" )
702713cmd .append (get_fqbn (b_name ))
703714cmd .append ("dummy_sketch" )
@@ -727,6 +738,9 @@ def build_config(sketch, boardSkipped):
727738
728739for idx in reversed (range (len (build_conf_list ))):
729740build_conf_list [idx ][4 ][- 1 ]= sketch
741+ build_conf_list [idx ][4 ][- 4 ]= build_conf_list [idx ][4 ][- 4 ].replace (
742+ "dummy_sketch" ,os .path .basename (sketch )
743+ )
730744if na_sketch_pattern :
731745if build_conf_list [idx ][0 ]in na_sketch_pattern :
732746for pattern in na_sketch_pattern [build_conf_list [idx ][0 ]]:
@@ -865,7 +879,6 @@ def build(build_conf):
865879)
866880
867881g1 = parser .add_mutually_exclusive_group ()
868- g1 .add_argument ("--bin" ,help = "save binaries" ,action = "store_true" )
869882g1 .add_argument ("--ci" ,help = "custom configuration for CI build" ,action = "store_true" )
870883
871884# Sketch options