1212from rattler_build .variant_config import VariantConfig
1313
1414from ..config import CondaPkgFormat , Config
15+ from ..exceptions import CondaBuildUserError
1516
1617CONFIG_FILES = {"conda_build_config.yaml" , "variants.yaml" }
1718
@@ -87,28 +88,124 @@ def check_arguments_rattler(
8788 )
8889
8990
91+ def process_recipes (
92+ recipes : list [str ],
93+ variant_config : VariantConfig ,
94+ render_config : RenderConfig ,
95+ tool_config : ToolConfiguration ,
96+ command : str ,
97+ output_dir : str ,
98+ channels : list [str ],
99+ show_logs : bool ,
100+ no_build_id : bool ,
101+ package_format : str ,
102+ no_include_recipe : bool ,
103+ debug : bool ,
104+ ) -> int :
105+ import yaml
106+
107+ succeeded : list [str ] = []
108+ failed : dict [str , str ] = {}
109+
110+ for recipe_path in recipes :
111+ recipe_path_str = str (recipe_path )
112+ try :
113+ # load the recipe file
114+ try :
115+ recipe = Stage0Recipe .from_file (Path (recipe_path ))
116+ except Exception as e :
117+ raise CondaBuildUserError (
118+ f"Failed to process recipe { recipe_path } : { str (e )} "
119+ )
120+
121+ # render the recipe
122+ try :
123+ rendered = recipe .render (variant_config , render_config )
124+ except Exception as e :
125+ raise CondaBuildUserError (
126+ f"Failed to render recipe { recipe_path } : { str (e )} "
127+ )
128+
129+ if command == "render" :
130+ data = rendered [0 ].recipe .to_dict ()
131+ print (yaml .safe_dump (data , indent = 2 , sort_keys = False ))
132+ succeeded .append (recipe_path_str )
133+ continue
134+
135+ # build all rendered variants
136+ for i , variant in enumerate (rendered , 1 ):
137+ print (
138+ f"\n 🔨 Building variant { i } /{ len (rendered )} "
139+ f"for recipe { recipe_path } "
140+ )
141+
142+ try :
143+ with RichProgressCallback (show_logs = show_logs ) as progress_callback :
144+ variant .run_build (
145+ tool_config = tool_config ,
146+ output_dir = output_dir ,
147+ channels = channels ,
148+ progress_callback = progress_callback ,
149+ no_build_id = no_build_id ,
150+ package_format = package_format ,
151+ no_include_recipe = no_include_recipe ,
152+ debug = debug ,
153+ )
154+ except Exception as e :
155+ print (f"Build failed for recipe { recipe_path } : { str (e )} " )
156+ raise
157+
158+ # if all variants built without raising, mark recipe as succeeded
159+ succeeded .append (recipe_path_str )
160+
161+ except Exception as e :
162+ # catch any failure for this recipe and continue with the next
163+ failed [recipe_path_str ] = str (e )
164+ print (f"Skipping remaining work for recipe { recipe_path } ." )
165+
166+ # summary
167+ print ("\n === Build summary ===" )
168+ if succeeded :
169+ print ("Succeeded:" )
170+ for path in succeeded :
171+ print (f" - { path } " )
172+ else :
173+ print ("Succeeded: none" )
174+
175+ if failed :
176+ print ("\n Failed:" )
177+ for path , error in failed .items ():
178+ print (f" - { path } : { error } " )
179+ else :
180+ print ("\n Failed: none" )
181+
182+ return 1 if failed else 0
183+
184+
90185def run_rattler (command : str , parsed_args : argparse .Namespace , config : Config ) -> int :
91186 """Run rattler-build for v1 recipes"""
92187 if command not in ("build" , "render" , "debug" ):
93188 raise ValueError (f"Unrecognized subcommand: { command } " )
94189
95190 # Initialize configuration defaults
96- test_strategy = None
97- skip_existing = None
98- noarch_build_platform = None
99- channel_priority = None
100- output_dir = config .croot
101- no_include_recipe = False
102- no_build_id = False
103- package_format = None
104- debug = False
105- channels = []
106- extra_context = {}
107- show_logs = not parsed_args .quiet
108- target_platform = config .variant .get ("host_platform" , config .subdir )
109- build_platform = config .variant .get ("build_platform" , config .subdir )
110- host_platform = config .variant .get ("target_platform" , config .subdir )
111- noarch_build_platform = config .variant .get ("noarch_build_platform" , config .subdir )
191+ test_strategy : str | None = None
192+ skip_existing : bool | None = None
193+ noarch_build_platform : str | None = None
194+ channel_priority : str | None = None
195+ output_dir : str = config .croot
196+ no_include_recipe : bool = False
197+ no_build_id : bool = False
198+ package_format : str | None = None
199+ debug : bool = False
200+ channels : list [str ] = []
201+ extra_context : dict [str ] = {}
202+ show_logs : bool = getattr (parsed_args , "quiet" , False ) is False
203+ target_platform : str = config .variant .get ("host_platform" , config .subdir )
204+ build_platform : str = config .variant .get ("build_platform" , config .subdir )
205+ host_platform : str = config .variant .get ("target_platform" , config .subdir )
206+ noarch_build_platform : str = config .variant .get (
207+ "noarch_build_platform" , config .subdir
208+ )
112209
113210 # TODO: investigate why is config.channel_urls
114211 # does not pick up condarc settings, need to use context.channels
@@ -169,7 +266,7 @@ def run_rattler(command: str, parsed_args: argparse.Namespace, config: Config) -
169266 # TODO: output_name does not exist in python bindings
170267 # if parsed_args.output_id:
171268 # cmd.extend(["--output-name", parsed_args.output_id])
172- elif command == "build" :
269+ if command == "build" :
173270 if parsed_args .extra_meta :
174271 extra_context .update (parsed_args .extra_meta )
175272 if parsed_args .output_folder :
@@ -198,13 +295,11 @@ def run_rattler(command: str, parsed_args: argparse.Namespace, config: Config) -
198295
199296 from ..variants import find_config_files
200297
201- results = []
202-
203298 # configure variant
204299 for variant in config_files :
205300 variant_config = VariantConfig .from_file (variant )
206301
207- # coon tool / platform / render configuration
302+ # common tool / platform / render configuration
208303 tool_config = ToolConfiguration (
209304 test_strategy = test_strategy ,
210305 skip_existing = skip_existing ,
@@ -223,51 +318,17 @@ def run_rattler(command: str, parsed_args: argparse.Namespace, config: Config) -
223318 extra_context = extra_context ,
224319 )
225320
226- # iterate over all recipes
227- for recipe_path in recipes :
228- recipe = Stage0Recipe .from_file (Path (recipe_path ))
229-
230- variant_config = None
231- for variant_file in config_files :
232- variant_config = VariantConfig .from_file (variant_file )
233-
234- # render the recipe
235- rendered = recipe .render (variant_config , render_config )
236-
237- if command == "render" :
238- import json
239-
240- data = rendered [0 ].recipe .to_dict ()
241- print (json .dumps (data , indent = 2 , sort_keys = True ))
242- continue
243-
244- # build all rendered variants
245- for i , variant in enumerate (rendered , 1 ):
246- print (
247- f"\n 🔨 Building variant { i } /{ len (rendered )} "
248- f"for recipe { recipe_path } "
249- )
250-
251- with RichProgressCallback (show_logs = show_logs ) as progress_callback :
252- result = variant .run_build (
253- tool_config = tool_config ,
254- output_dir = output_dir ,
255- channels = channels ,
256- progress_callback = progress_callback ,
257- recipe_path = recipe_path ,
258- no_build_id = no_build_id ,
259- package_format = package_format ,
260- no_include_recipe = no_include_recipe ,
261- debug = debug ,
262- )
263- results .append (result )
264-
265- print ("\n " + "=" * 60 )
266- print ("Build Result:" )
267- print ("=" * 60 )
268- print (f" Package: { result .name } { result .version } " )
269- print (f" Build string: { result .build_string } " )
270- print (f" Platform: { result .platform } " )
271- print (f" Build time: { result .build_time :.2f} s" )
272-
273- return 0
321+ return process_recipes (
322+ recipes = recipes ,
323+ variant_config = variant_config ,
324+ render_config = render_config ,
325+ tool_config = tool_config ,
326+ command = command ,
327+ output_dir = output_dir ,
328+ channels = channels ,
329+ show_logs = show_logs ,
330+ no_build_id = no_build_id ,
331+ package_format = package_format ,
332+ no_include_recipe = no_include_recipe ,
333+ debug = debug ,
334+ )
0 commit comments