@@ -90,6 +90,9 @@ pub struct SourceBuildSpec {
9090 /// The protocols that are enabled for this source
9191 #[ serde( skip_serializing_if = "crate::is_default" ) ]
9292 pub enabled_protocols : EnabledProtocols ,
93+
94+ /// Force rebuild even if the build cache is up to date.
95+ pub force : bool ,
9396}
9497
9598#[ derive( Debug , Clone ) ]
@@ -127,58 +130,87 @@ impl SourceBuildSpec {
127130 ) -> Result < SourceBuildResult , CommandDispatcherError < SourceBuildError > > {
128131 // If the output directory is not set, we want to use the build cache. Read the
129132 // build cache in that case.
130- let ( output_directory, build_cache) =
131- if let Some ( output_directory) = self . output_directory . clone ( ) {
132- ( output_directory, None )
133- } else {
134- // Query the source build cache.
135- let build_cache = command_dispatcher
136- . source_build_cache_status ( SourceBuildCacheStatusSpec {
137- package : self . package . clone ( ) ,
138- build_environment : self . build_environment . clone ( ) ,
139- source : self . source . clone ( ) ,
140- channels : self . channels . clone ( ) ,
141- channel_config : self . channel_config . clone ( ) ,
142- enabled_protocols : self . enabled_protocols . clone ( ) ,
143- } )
144- . await
145- . map_err_with ( SourceBuildError :: from) ?;
146-
147- if let CachedBuildStatus :: UpToDate ( cached_build) = & build_cache. cached_build {
133+ let ( output_directory, build_cache) = if let Some ( output_directory) =
134+ self . output_directory . clone ( )
135+ {
136+ ( output_directory, None )
137+ } else {
138+ // Query the source build cache.
139+ let build_cache = command_dispatcher
140+ . source_build_cache_status ( SourceBuildCacheStatusSpec {
141+ package : self . package . clone ( ) ,
142+ build_environment : self . build_environment . clone ( ) ,
143+ source : self . source . clone ( ) ,
144+ channels : self . channels . clone ( ) ,
145+ channel_config : self . channel_config . clone ( ) ,
146+ enabled_protocols : self . enabled_protocols . clone ( ) ,
147+ } )
148+ . await
149+ . map_err_with ( SourceBuildError :: from) ?;
150+
151+ // If the build is up to date and we are not forcing a rebuild, return the cached build.
152+ // but if we force a rebuild, and we already have an new cached build, we can reuse the cache entry.
153+ if let CachedBuildStatus :: UpToDate ( cached_build) =
154+ & * build_cache. cached_build . lock ( ) . await
155+ {
156+ if !self . force {
148157 // If the build is up to date, we can return the cached build.
149158 tracing:: debug!(
150159 source = %self . source,
151160 package = ?cached_build. record. package_record. name,
152161 build = %cached_build. record. package_record. build,
153162 output = %cached_build. record. file_name,
154- "using cached source build" ,
163+ "using cached up-to-date source build" ,
155164 ) ;
156165 return Ok ( SourceBuildResult {
157166 output_file : build_cache. cache_dir . join ( & cached_build. record . file_name ) ,
158167 record : cached_build. record . clone ( ) ,
159168 } ) ;
160169 }
170+ tracing:: debug!(
171+ "source build for {} is up to date, but force rebuild is set, rebuilding anyway" ,
172+ self . package. name. as_normalized( )
173+ ) ;
174+ }
175+ if let CachedBuildStatus :: New ( cached_build) = & * build_cache. cached_build . lock ( ) . await {
176+ tracing:: debug!(
177+ "source build for {} is already built and marked as new, reusing the cache entry" ,
178+ self . package. name. as_normalized( )
179+ ) ;
180+ tracing:: debug!(
181+ source = %self . source,
182+ package = ?cached_build. record. package_record. name,
183+ build = %cached_build. record. package_record. build,
184+ output = %cached_build. record. file_name,
185+ "using cached new source build" ,
186+ ) ;
187+ // dont matter if we forceit , we can reuse the cache entry
188+ return Ok ( SourceBuildResult {
189+ output_file : build_cache. cache_dir . join ( & cached_build. record . file_name ) ,
190+ record : cached_build. record . clone ( ) ,
191+ } ) ;
192+ }
161193
162- match & build_cache. cached_build {
163- CachedBuildStatus :: Stale ( existing) => {
164- tracing:: debug!(
165- source = %self . source,
166- package = ?existing. record. package_record. name,
167- build = %existing. record. package_record. build,
168- "rebuilding stale source build" ,
169- ) ;
170- }
171- CachedBuildStatus :: Missing => {
172- tracing:: debug!(
173- source = %self . source,
174- "no cached source build; starting fresh build" ,
175- ) ;
176- }
177- CachedBuildStatus :: UpToDate ( _) => { }
194+ match & * build_cache. cached_build . lock ( ) . await {
195+ CachedBuildStatus :: Stale ( existing) => {
196+ tracing:: debug!(
197+ source = %self . source,
198+ package = ?existing. record. package_record. name,
199+ build = %existing. record. package_record. build,
200+ "rebuilding stale source build" ,
201+ ) ;
202+ }
203+ CachedBuildStatus :: Missing => {
204+ tracing:: debug!(
205+ source = %self . source,
206+ "no cached source build; starting fresh build" ,
207+ ) ;
178208 }
209+ CachedBuildStatus :: UpToDate ( _) | CachedBuildStatus :: New ( _) => { }
210+ }
179211
180- ( build_cache. cache_dir . clone ( ) , Some ( build_cache) )
181- } ;
212+ ( build_cache. cache_dir . clone ( ) , Some ( build_cache) )
213+ } ;
182214
183215 // Check out the source code.
184216 let source_checkout = command_dispatcher
@@ -335,14 +367,21 @@ impl SourceBuildSpec {
335367 // Update the cache entry if we have one.
336368 if let Some ( build_cache) = build_cache {
337369 let mut entry = build_cache. entry . lock ( ) . await ;
370+ // set the status that its a new cache
371+ // so on the next run we can distinguish between up to date ( was already saved from previous session)
372+ // and new that was just build now
373+ let cached_build = CachedBuild {
374+ source : source_checkout
375+ . pinned
376+ . is_mutable ( )
377+ . then_some ( built_source. metadata . clone ( ) ) ,
378+ record : record. clone ( ) ,
379+ } ;
380+
381+ let mut cached_entry = build_cache. cached_build . lock ( ) . await ;
382+ * cached_entry = CachedBuildStatus :: New ( cached_build. clone ( ) ) ;
338383 entry
339- . insert ( CachedBuild {
340- source : source_checkout
341- . pinned
342- . is_mutable ( )
343- . then_some ( built_source. metadata ) ,
344- record : record. clone ( ) ,
345- } )
384+ . insert ( cached_build)
346385 . await
347386 . map_err ( SourceBuildError :: BuildCache )
348387 . map_err ( CommandDispatcherError :: Failed ) ?;
0 commit comments