@@ -300,20 +300,22 @@ impl FileStore {
300300
301301 fctx. inc_local ( fetched_since_last_time ( & state) ) ;
302302
303- if let Some ( lfs_cache) = lfs_client. as_ref ( ) . map ( |c| c. shared . as_ref ( ) ) {
304- assert ! (
305- format == SerializationFormat :: Hg ,
306- "LFS cannot be used with non-Hg serialization format"
307- ) ;
308- state. fetch_lfs ( lfs_cache, StoreLocation :: Cache ) ;
309- }
310-
311- if let Some ( lfs_local) = lfs_client. as_ref ( ) . and_then ( |c| c. local . as_ref ( ) ) {
312- assert ! (
313- format == SerializationFormat :: Hg ,
314- "LFS cannot be used with non-Hg serialization format"
315- ) ;
316- state. fetch_lfs ( lfs_local, StoreLocation :: Local ) ;
303+ if !fctx. skip_lfs ( ) {
304+ if let Some ( lfs_cache) = lfs_client. as_ref ( ) . map ( |c| c. shared . as_ref ( ) ) {
305+ assert ! (
306+ format == SerializationFormat :: Hg ,
307+ "LFS cannot be used with non-Hg serialization format"
308+ ) ;
309+ state. fetch_lfs ( lfs_cache, StoreLocation :: Cache ) ;
310+ }
311+
312+ if let Some ( lfs_local) = lfs_client. as_ref ( ) . and_then ( |c| c. local . as_ref ( ) ) {
313+ assert ! (
314+ format == SerializationFormat :: Hg ,
315+ "LFS cannot be used with non-Hg serialization format"
316+ ) ;
317+ state. fetch_lfs ( lfs_local, StoreLocation :: Local ) ;
318+ }
317319 }
318320
319321 fctx. inc_local ( fetched_since_last_time ( & state) ) ;
@@ -329,12 +331,14 @@ impl FileStore {
329331 ) ;
330332 }
331333
332- if let Some ( ref lfs_client) = lfs_client {
333- assert ! (
334- format == SerializationFormat :: Hg ,
335- "LFS cannot be used with non-Hg serialization format"
336- ) ;
337- state. fetch_lfs_remote ( lfs_client, lfs_buffer_in_memory) ;
334+ if !fctx. skip_lfs ( ) {
335+ if let Some ( ref lfs_client) = lfs_client {
336+ assert ! (
337+ format == SerializationFormat :: Hg ,
338+ "LFS cannot be used with non-Hg serialization format"
339+ ) ;
340+ state. fetch_lfs_remote ( lfs_client, lfs_buffer_in_memory) ;
341+ }
338342 }
339343
340344 fctx. inc_remote ( fetched_since_last_time ( & state) ) ;
@@ -708,3 +712,105 @@ impl HgIdMutableDeltaStore for FileStore {
708712 Ok ( None )
709713 }
710714}
715+
716+ #[ cfg( test) ]
717+ mod tests {
718+ use std:: collections:: BTreeMap ;
719+
720+ use :: types:: RepoPathBuf ;
721+ use :: types:: fetch_cause:: FetchCause ;
722+ use :: types:: fetch_mode:: FetchMode ;
723+ use tempfile:: TempDir ;
724+
725+ use super :: * ;
726+ use crate :: StoreType ;
727+ use crate :: indexedlogdatastore:: IndexedLogHgIdDataStoreConfig ;
728+
729+ fn make_indexedlog ( tempdir : & TempDir ) -> Arc < IndexedLogHgIdDataStore > {
730+ let config = IndexedLogHgIdDataStoreConfig {
731+ max_log_count : None ,
732+ max_bytes_per_log : None ,
733+ max_bytes : None ,
734+ btrfs_compression : false ,
735+ } ;
736+ Arc :: new (
737+ IndexedLogHgIdDataStore :: new (
738+ & BTreeMap :: < & str , & str > :: new ( ) ,
739+ tempdir,
740+ & config,
741+ StoreType :: Rotated ,
742+ SerializationFormat :: Hg ,
743+ )
744+ . unwrap ( ) ,
745+ )
746+ }
747+
748+ #[ test]
749+ fn test_skip_lfs_skips_lfs_fetch ( ) {
750+ let il_dir = TempDir :: new ( ) . unwrap ( ) ;
751+ let indexedlog = make_indexedlog ( & il_dir) ;
752+
753+ let lfs_key = Key :: new (
754+ RepoPathBuf :: from_string ( "large.bin" . to_string ( ) ) . unwrap ( ) ,
755+ HgId :: from_hex ( b"2222222222222222222222222222222222222222" ) . unwrap ( ) ,
756+ ) ;
757+ let content = Bytes :: from_static ( b"large file content here" ) ;
758+
759+ // Write file content to indexedlog with LFS flag set.
760+ let lfs_meta = Metadata {
761+ flags : Some ( Metadata :: LFS_FLAG ) ,
762+ size : None ,
763+ } ;
764+ indexedlog
765+ . put_entry ( Entry :: new ( lfs_key. hgid , content. clone ( ) , lfs_meta) )
766+ . unwrap ( ) ;
767+
768+ // Set up LFS store with the actual blob.
769+ let lfs_dir = TempDir :: new ( ) . unwrap ( ) ;
770+ let server = mockito:: Server :: new ( ) ;
771+ let lfs_config = crate :: testutil:: make_lfs_config ( & server, & lfs_dir, "skip_lfs" ) ;
772+ let lfs_store = Arc :: new ( crate :: lfs:: LfsStore :: rotated ( & lfs_dir, & lfs_config) . unwrap ( ) ) ;
773+ lfs_store
774+ . add_blob_and_pointer ( lfs_key. clone ( ) , content)
775+ . unwrap ( ) ;
776+ lfs_store. flush ( ) . unwrap ( ) ;
777+ let lfs_client = crate :: lfs:: LfsClient :: new ( lfs_store, None , & lfs_config) . unwrap ( ) ;
778+
779+ let make_store = || {
780+ let mut store = FileStore :: empty ( ) ;
781+ store. indexedlog_local = Some ( indexedlog. clone ( ) ) ;
782+ store. lfs_client = Some ( lfs_client. clone ( ) ) ;
783+ store. lfs_threshold_bytes = Some ( 1 ) ;
784+ store
785+ } ;
786+
787+ // Without skip_lfs, the LFS key resolves successfully.
788+ let fctx = FetchContext :: new_with_mode_and_cause (
789+ FetchMode :: LocalOnly ,
790+ FetchCause :: EdenWalkPrefetch ,
791+ ) ;
792+ let results: Vec < _ > = make_store ( )
793+ . fetch ( fctx, vec ! [ lfs_key. clone( ) ] , FileAttributes :: CONTENT )
794+ . into_iter ( )
795+ . collect ( ) ;
796+ assert ! (
797+ results[ 0 ] . is_ok( ) ,
798+ "LFS key should resolve without skip_lfs"
799+ ) ;
800+
801+ // With skip_lfs, the LFS fetch is skipped so the key is not found.
802+ let fctx = FetchContext :: new_with_mode_and_cause (
803+ FetchMode :: LocalOnly ,
804+ FetchCause :: EdenWalkPrefetch ,
805+ )
806+ . with_skip_lfs ( true ) ;
807+ let results: Vec < _ > = make_store ( )
808+ . fetch ( fctx, vec ! [ lfs_key. clone( ) ] , FileAttributes :: CONTENT )
809+ . into_iter ( )
810+ . collect ( ) ;
811+ assert ! (
812+ results[ 0 ] . is_err( ) ,
813+ "LFS key should not be found when skip_lfs=true"
814+ ) ;
815+ }
816+ }
0 commit comments