1+ use std:: collections:: HashMap ;
12use std:: env;
23use std:: fs;
34use std:: io:: { self , Read } ;
45use std:: path:: { Path , PathBuf } ;
5-
6- const NUGET_FEED : & str = "https://api.nuget.org/v3/index.json" ;
6+ use std:: sync:: Mutex ;
7+
8+ /// Feeds tried in order. Primary: nuget.org (stable releases). Fallback:
9+ /// the public ORT-Nightly Azure DevOps NuGet feed (where dev / pre-release
10+ /// builds of Foundry Local Core, ONNX Runtime and ONNX Runtime GenAI live
11+ /// before they reach nuget.org). If a download from a feed fails for any
12+ /// reason, the next feed is tried.
13+ const FEEDS : & [ & str ] = & [
14+ "https://api.nuget.org/v3/index.json" ,
15+ "https://pkgs.dev.azure.com/aiinfra/PublicPackages/_packaging/ORT-Nightly/nuget/v3/index.json" ,
16+ ] ;
717
818/// Versions loaded from deps_versions.json (or deps_versions_winml.json).
919/// Both files share the same key structure — the build script picks the
@@ -67,7 +77,6 @@ fn load_deps_versions() -> DepsVersions {
6777struct NuGetPackage {
6878 name : & ' static str ,
6979 version : String ,
70- feed_url : & ' static str ,
7180}
7281
7382fn get_rid ( ) -> Option < & ' static str > {
@@ -106,51 +115,56 @@ fn get_packages(rid: &str) -> Vec<NuGetPackage> {
106115 packages. push ( NuGetPackage {
107116 name : "Microsoft.AI.Foundry.Local.Core.WinML" ,
108117 version : deps. core . clone ( ) ,
109- feed_url : NUGET_FEED ,
110118 } ) ;
111119 packages. push ( NuGetPackage {
112120 name : "Microsoft.ML.OnnxRuntime.Foundry" ,
113121 version : deps. ort . clone ( ) ,
114- feed_url : NUGET_FEED ,
115122 } ) ;
116123 packages. push ( NuGetPackage {
117124 name : "Microsoft.ML.OnnxRuntimeGenAI.Foundry" ,
118125 version : deps. genai . clone ( ) ,
119- feed_url : NUGET_FEED ,
120126 } ) ;
121127 } else {
122128 packages. push ( NuGetPackage {
123129 name : "Microsoft.AI.Foundry.Local.Core" ,
124130 version : deps. core . clone ( ) ,
125- feed_url : NUGET_FEED ,
126131 } ) ;
127132
128133 if is_linux {
129134 packages. push ( NuGetPackage {
130135 name : "Microsoft.ML.OnnxRuntime.Gpu.Linux" ,
131136 version : deps. ort . clone ( ) ,
132- feed_url : NUGET_FEED ,
133137 } ) ;
134138 } else {
135139 packages. push ( NuGetPackage {
136140 name : "Microsoft.ML.OnnxRuntime.Foundry" ,
137141 version : deps. ort . clone ( ) ,
138- feed_url : NUGET_FEED ,
139142 } ) ;
140143 }
141144
142145 packages. push ( NuGetPackage {
143146 name : "Microsoft.ML.OnnxRuntimeGenAI.Foundry" ,
144147 version : deps. genai . clone ( ) ,
145- feed_url : NUGET_FEED ,
146148 } ) ;
147149 }
148150
149151 packages
150152}
151153
152- /// Resolve the PackageBaseAddress from a NuGet v3 service index.
154+ /// Resolve the PackageBaseAddress from a NuGet v3 service index. The result
155+ /// is cached per feed URL so repeated calls within a single build (e.g. one
156+ /// per package, plus retries on fallback feeds) only hit the network once.
153157fn resolve_base_address ( feed_url : & str ) -> Result < String , String > {
158+ static BASE_ADDRESS_CACHE : Mutex < Option < HashMap < String , String > > > = Mutex :: new ( None ) ;
159+ {
160+ let guard = BASE_ADDRESS_CACHE . lock ( ) . unwrap ( ) ;
161+ if let Some ( map) = guard. as_ref ( ) {
162+ if let Some ( cached) = map. get ( feed_url) {
163+ return Ok ( cached. clone ( ) ) ;
164+ }
165+ }
166+ }
167+
154168 let body: String = ureq:: get ( feed_url)
155169 . call ( )
156170 . map_err ( |e| format ! ( "Failed to fetch NuGet feed index at {feed_url}: {e}" ) ) ?
@@ -174,6 +188,10 @@ fn resolve_base_address(feed_url: &str) -> Result<String, String> {
174188 } else {
175189 format ! ( "{id}/" )
176190 } ;
191+ let mut guard = BASE_ADDRESS_CACHE . lock ( ) . unwrap ( ) ;
192+ guard
193+ . get_or_insert_with ( HashMap :: new)
194+ . insert ( feed_url. to_string ( ) , base. clone ( ) ) ;
177195 return Ok ( base) ;
178196 }
179197 }
@@ -184,49 +202,37 @@ fn resolve_base_address(feed_url: &str) -> Result<String, String> {
184202 ) )
185203}
186204
187- /// Download a .nupkg and extract native libraries for the given RID into `out_dir`.
188- /// Skips download if native files from this package are already present.
189- fn download_and_extract ( pkg : & NuGetPackage , rid : & str , out_dir : & Path ) -> Result < ( ) , String > {
190- // Skip if this package's main native library is already in out_dir
191- // (e.g. pre-populated from FOUNDRY_NATIVE_OVERRIDE_DIR).
192- let ext = native_lib_extension ( ) ;
193- let prefix = if env:: consts:: OS == "windows" {
194- ""
195- } else {
196- "lib"
197- } ;
198- let expected_file = if pkg. name . contains ( "Foundry.Local.Core" ) {
199- format ! ( "Microsoft.AI.Foundry.Local.Core.{ext}" )
200- } else if pkg. name . contains ( "OnnxRuntimeGenAI" ) {
201- format ! ( "{prefix}onnxruntime-genai.{ext}" )
202- } else if pkg. name . contains ( "OnnxRuntime" ) {
203- format ! ( "{prefix}onnxruntime.{ext}" )
204- } else {
205- String :: new ( )
206- } ;
207- if !expected_file. is_empty ( ) && out_dir. join ( & expected_file) . exists ( ) {
208- println ! (
209- "cargo:warning={} already present, skipping download." ,
210- pkg. name
211- ) ;
212- return Ok ( ( ) ) ;
213- }
214-
215- let base_address = resolve_base_address ( pkg. feed_url ) ?;
205+ /// Try to download and extract a single package from a specific feed. Returns
206+ /// `Ok(())` on success, `Err(reason)` on any failure (network, HTTP error,
207+ /// zip parse error, etc.).
208+ fn try_download_from_feed (
209+ pkg : & NuGetPackage ,
210+ rid : & str ,
211+ out_dir : & Path ,
212+ feed_url : & str ,
213+ ) -> Result < ( ) , String > {
214+ let base_address = resolve_base_address ( feed_url) ?;
216215 let lower_name = pkg. name . to_lowercase ( ) ;
217216 let lower_version = pkg. version . to_lowercase ( ) ;
218217 let url =
219218 format ! ( "{base_address}{lower_name}/{lower_version}/{lower_name}.{lower_version}.nupkg" ) ;
220219
220+ let feed_host = feed_url
221+ . split ( "://" )
222+ . nth ( 1 )
223+ . and_then ( |s| s. split ( '/' ) . next ( ) )
224+ . unwrap_or ( feed_url) ;
225+
221226 println ! (
222- "cargo:warning=Downloading {name} {ver} from NuGet.org " ,
227+ "cargo:warning=Downloading {name} {ver} from {host} " ,
223228 name = pkg. name,
224229 ver = pkg. version,
230+ host = feed_host,
225231 ) ;
226232
227233 let mut response = ureq:: get ( & url)
228234 . call ( )
229- . map_err ( |e| format ! ( "Failed to download {}: {e}" , pkg. name) ) ?;
235+ . map_err ( |e| format ! ( "Failed to download {} from {feed_host} : {e}" , pkg. name) ) ?;
230236
231237 let mut bytes = Vec :: new ( ) ;
232238 response
@@ -285,6 +291,57 @@ fn download_and_extract(pkg: &NuGetPackage, rid: &str, out_dir: &Path) -> Result
285291 Ok ( ( ) )
286292}
287293
294+ /// Download a .nupkg and extract native libraries for the given RID into `out_dir`.
295+ /// Skips download if native files from this package are already present.
296+ /// Tries each configured feed in order; on failure falls back to the next.
297+ fn download_and_extract ( pkg : & NuGetPackage , rid : & str , out_dir : & Path ) -> Result < ( ) , String > {
298+ // Skip if this package's main native library is already in out_dir
299+ // (e.g. pre-populated from FOUNDRY_NATIVE_OVERRIDE_DIR).
300+ let ext = native_lib_extension ( ) ;
301+ let prefix = if env:: consts:: OS == "windows" {
302+ ""
303+ } else {
304+ "lib"
305+ } ;
306+ let expected_file = if pkg. name . contains ( "Foundry.Local.Core" ) {
307+ format ! ( "Microsoft.AI.Foundry.Local.Core.{ext}" )
308+ } else if pkg. name . contains ( "OnnxRuntimeGenAI" ) {
309+ format ! ( "{prefix}onnxruntime-genai.{ext}" )
310+ } else if pkg. name . contains ( "OnnxRuntime" ) {
311+ format ! ( "{prefix}onnxruntime.{ext}" )
312+ } else {
313+ String :: new ( )
314+ } ;
315+ if !expected_file. is_empty ( ) && out_dir. join ( & expected_file) . exists ( ) {
316+ println ! (
317+ "cargo:warning={} already present, skipping download." ,
318+ pkg. name
319+ ) ;
320+ return Ok ( ( ) ) ;
321+ }
322+
323+ let mut last_error = String :: new ( ) ;
324+ for ( i, feed_url) in FEEDS . iter ( ) . enumerate ( ) {
325+ match try_download_from_feed ( pkg, rid, out_dir, feed_url) {
326+ Ok ( ( ) ) => return Ok ( ( ) ) ,
327+ Err ( e) => {
328+ let is_last = i == FEEDS . len ( ) - 1 ;
329+ if !is_last {
330+ println ! (
331+ "cargo:warning={} {}: {e}; trying next feed..." ,
332+ pkg. name, pkg. version
333+ ) ;
334+ }
335+ last_error = e;
336+ }
337+ }
338+ }
339+ Err ( format ! (
340+ "Failed to download {} {} from any configured feed: {last_error}" ,
341+ pkg. name, pkg. version
342+ ) )
343+ }
344+
288345/// Check whether all required native libraries are already present in `out_dir`.
289346fn libs_already_present ( out_dir : & Path ) -> bool {
290347 let ext = native_lib_extension ( ) ;
0 commit comments