55from pathlib import Path
66
77from conda .base .context import context
8+ from rattler_build .build_result import BuildResult
89from rattler_build .progress import RichProgressCallback
910from rattler_build .render import RenderConfig
1011from rattler_build .stage0 import Stage0Recipe
1112from rattler_build .tool_config import PlatformConfig , ToolConfiguration
1213from rattler_build .variant_config import VariantConfig
1314
1415from ..config import CondaPkgFormat , Config
16+ from ..exceptions import CondaBuildUserError
1517
1618CONFIG_FILES = {"conda_build_config.yaml" , "variants.yaml" }
1719
@@ -87,28 +89,126 @@ def check_arguments_rattler(
8789 )
8890
8991
92+ def process_recipes (
93+ recipes : list [str ],
94+ variant_config : VariantConfig ,
95+ render_config : RenderConfig ,
96+ tool_config : ToolConfiguration ,
97+ command : str ,
98+ output_dir : str ,
99+ channels : list [str ],
100+ show_logs : bool ,
101+ no_build_id : bool ,
102+ package_format : str ,
103+ no_include_recipe : bool ,
104+ debug : bool ,
105+ ) -> list [BuildResult ]:
106+ import yaml
107+
108+ results : list = []
109+ succeeded : list [str ] = []
110+ failed : dict [str , str ] = {}
111+
112+ for recipe_path in recipes :
113+ recipe_path_str = str (recipe_path )
114+ try :
115+ # load the recipe file
116+ try :
117+ recipe = Stage0Recipe .from_file (Path (recipe_path ))
118+ except Exception as e :
119+ raise CondaBuildUserError (
120+ f"Failed to process recipe { recipe_path } : { str (e )} "
121+ )
122+
123+ # render the recipe
124+ try :
125+ rendered = recipe .render (variant_config , render_config )
126+ except Exception as e :
127+ raise CondaBuildUserError (
128+ f"Failed to render recipe { recipe_path } : { str (e )} "
129+ )
130+
131+ if command == "render" :
132+ data = rendered [0 ].recipe .to_dict ()
133+ print (yaml .safe_dump (data , indent = 2 , sort_keys = False ))
134+ succeeded .append (recipe_path_str )
135+ continue
136+
137+ # build all rendered variants
138+ for i , variant in enumerate (rendered , 1 ):
139+ print (
140+ f"\n 🔨 Building variant { i } /{ len (rendered )} "
141+ f"for recipe { recipe_path } "
142+ )
143+
144+ try :
145+ with RichProgressCallback (show_logs = show_logs ) as progress_callback :
146+ result = variant .run_build (
147+ tool_config = tool_config ,
148+ output_dir = output_dir ,
149+ channels = channels ,
150+ progress_callback = progress_callback ,
151+ no_build_id = no_build_id ,
152+ package_format = package_format ,
153+ no_include_recipe = no_include_recipe ,
154+ debug = debug ,
155+ )
156+ results .append (result )
157+ except Exception as e :
158+ print (f"❌ Build failed for recipe { recipe_path } : { str (e )} " )
159+ raise
160+
161+ # if all variants built without raising, mark recipe as succeeded
162+ succeeded .append (recipe_path_str )
163+
164+ except Exception as e :
165+ # catch any failure for this recipe and continue with the next
166+ failed [recipe_path_str ] = str (e )
167+ print (f"Skipping remaining work for recipe { recipe_path } ." )
168+
169+ # summary
170+ print ("\n === Build summary ===" )
171+ if succeeded :
172+ print ("Succeeded:" )
173+ for path in succeeded :
174+ print (f" - { path } " )
175+ else :
176+ print ("Succeeded: none" )
177+
178+ if failed :
179+ print ("\n Failed:" )
180+ for path , error in failed .items ():
181+ print (f" - { path } : { error } " )
182+ else :
183+ print ("\n Failed: none" )
184+
185+ return results
186+
187+
90188def run_rattler (command : str , parsed_args : argparse .Namespace , config : Config ) -> int :
91189 """Run rattler-build for v1 recipes"""
92190 if command not in ("build" , "render" , "debug" ):
93191 raise ValueError (f"Unrecognized subcommand: { command } " )
94192
95193 # 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 )
194+ test_strategy : str | None = None
195+ skip_existing : bool | None = None
196+ noarch_build_platform : str | None = None
197+ channel_priority : str | None = None
198+ output_dir : str = config .croot
199+ no_include_recipe : bool = False
200+ no_build_id : bool = False
201+ package_format : str | None = None
202+ debug : bool = False
203+ channels : list [str ] = []
204+ extra_context : dict [str ] = {}
205+ show_logs : bool = getattr (parsed_args , "quiet" , False ) is False
206+ target_platform : str = config .variant .get ("host_platform" , config .subdir )
207+ build_platform : str = config .variant .get ("build_platform" , config .subdir )
208+ host_platform : str = config .variant .get ("target_platform" , config .subdir )
209+ noarch_build_platform : str = config .variant .get (
210+ "noarch_build_platform" , config .subdir
211+ )
112212
113213 # TODO: investigate why is config.channel_urls
114214 # does not pick up condarc settings, need to use context.channels
@@ -169,7 +269,7 @@ def run_rattler(command: str, parsed_args: argparse.Namespace, config: Config) -
169269 # TODO: output_name does not exist in python bindings
170270 # if parsed_args.output_id:
171271 # cmd.extend(["--output-name", parsed_args.output_id])
172- elif command == "build" :
272+ if command == "build" :
173273 if parsed_args .extra_meta :
174274 extra_context .update (parsed_args .extra_meta )
175275 if parsed_args .output_folder :
@@ -204,7 +304,7 @@ def run_rattler(command: str, parsed_args: argparse.Namespace, config: Config) -
204304 for variant in config_files :
205305 variant_config = VariantConfig .from_file (variant )
206306
207- # coon tool / platform / render configuration
307+ # common tool / platform / render configuration
208308 tool_config = ToolConfiguration (
209309 test_strategy = test_strategy ,
210310 skip_existing = skip_existing ,
@@ -223,51 +323,19 @@ def run_rattler(command: str, parsed_args: argparse.Namespace, config: Config) -
223323 extra_context = extra_context ,
224324 )
225325
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- )
326+ results = process_recipes (
327+ recipes = recipes ,
328+ variant_config = variant_config ,
329+ render_config = render_config ,
330+ tool_config = tool_config ,
331+ command = command ,
332+ output_dir = output_dir ,
333+ channels = channels ,
334+ show_logs = show_logs ,
335+ no_build_id = no_build_id ,
336+ package_format = package_format ,
337+ no_include_recipe = no_include_recipe ,
338+ debug = debug ,
339+ )
250340
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
341+ return results
0 commit comments