@@ -174,6 +174,10 @@ impl Repository {
174
174
/// Note that depending on the underlying configuration, there might be a significant delay until the first
175
175
/// item is received due to the buffering necessary to perform rename tracking and/or sorting.
176
176
///
177
+ /// ### Submodules
178
+ ///
179
+ /// Note that submodules can be set to 'inactive' which automatically excludes them from the status operation.
180
+ ///
177
181
/// ### Index Changes
178
182
///
179
183
/// Changes to the index are collected and it's possible to write the index back using [iter::Outcome::write_changes()].
@@ -200,6 +204,7 @@ pub mod iter {
200
204
use crate :: status:: index_worktree:: iter;
201
205
use crate :: status:: { index_worktree, Platform } ;
202
206
use crate :: worktree:: IndexPersistedOrInMemory ;
207
+ use crate :: ThreadSafeRepository ;
203
208
use std:: sync:: atomic:: { AtomicBool , Ordering } ;
204
209
use std:: sync:: Arc ;
205
210
@@ -420,9 +425,7 @@ pub mod iter {
420
425
}
421
426
}
422
427
423
- /// The status of a submodule
424
- #[ derive( Clone , PartialEq , Eq , PartialOrd , Ord , Debug ) ]
425
- pub struct SubmoduleStatus { }
428
+ type SubmoduleStatus = crate :: submodule:: Status ;
426
429
427
430
/// The error returned by [Platform::into_index_worktree_iter()](crate::status::Platform::into_index_worktree_iter()).
428
431
#[ derive( Debug , thiserror:: Error ) ]
@@ -434,6 +437,8 @@ pub mod iter {
434
437
SpawnThread ( #[ source] std:: io:: Error ) ,
435
438
#[ error( transparent) ]
436
439
ConfigSkipHash ( #[ from] crate :: config:: boolean:: Error ) ,
440
+ #[ error( transparent) ]
441
+ PrepareSubmodules ( #[ from] crate :: submodule:: modules:: Error ) ,
437
442
}
438
443
439
444
/// Lifecycle
@@ -454,7 +459,6 @@ pub mod iter {
454
459
let should_interrupt = Arc :: new ( AtomicBool :: default ( ) ) ;
455
460
let ( tx, rx) = std:: sync:: mpsc:: channel ( ) ;
456
461
let mut collect = Collect { tx } ;
457
- let submodule = ComputeSubmoduleStatus { _mode : self . submodules } ;
458
462
let skip_hash = self
459
463
. repo
460
464
. config
@@ -464,6 +468,7 @@ pub mod iter {
464
468
. transpose ( )
465
469
. with_lenient_default ( self . repo . config . lenient_config ) ?
466
470
. unwrap_or_default ( ) ;
471
+ let submodule = ComputeSubmoduleStatus :: new ( self . repo . clone ( ) . into_sync ( ) , self . submodules ) ?;
467
472
let join = std:: thread:: Builder :: new ( )
468
473
. name ( "gix::status::index_worktree::iter::producer" . into ( ) )
469
474
. spawn ( {
@@ -568,19 +573,53 @@ pub mod iter {
568
573
569
574
#[ derive( Clone ) ]
570
575
struct ComputeSubmoduleStatus {
571
- _mode : crate :: status:: Submodule ,
576
+ mode : crate :: status:: Submodule ,
577
+ repo : ThreadSafeRepository ,
578
+ submodule_paths : Vec < BString > ,
572
579
}
573
580
581
+ ///
574
582
mod submodule_status {
583
+ use crate :: bstr;
575
584
use crate :: bstr:: BStr ;
576
585
use crate :: status:: index_worktree:: iter:: { ComputeSubmoduleStatus , SubmoduleStatus } ;
586
+ use crate :: status:: Submodule ;
587
+ use std:: borrow:: Cow ;
588
+
589
+ impl ComputeSubmoduleStatus {
590
+ pub ( super ) fn new (
591
+ repo : crate :: ThreadSafeRepository ,
592
+ mode : crate :: status:: Submodule ,
593
+ ) -> Result < Self , crate :: submodule:: modules:: Error > {
594
+ let local_repo = repo. to_thread_local ( ) ;
595
+ let submodule_paths = match local_repo. submodules ( ) ? {
596
+ Some ( sm) => {
597
+ let mut v: Vec < _ > = sm
598
+ . filter ( |sm| sm. is_active ( ) . unwrap_or_default ( ) )
599
+ . filter_map ( |sm| sm. path ( ) . ok ( ) . map ( Cow :: into_owned) )
600
+ . collect ( ) ;
601
+ v. sort ( ) ;
602
+ v
603
+ }
604
+ None => Vec :: new ( ) ,
605
+ } ;
606
+ Ok ( Self {
607
+ mode,
608
+ repo,
609
+ submodule_paths,
610
+ } )
611
+ }
612
+ }
577
613
578
- /// The error returned by the submodule status implementation - it will be turned into a box, hence it doesn't have to
579
- /// be private.
614
+ /// The error returned submodule status checks.
580
615
#[ derive( Debug , thiserror:: Error ) ]
581
616
#[ allow( missing_docs) ]
582
- #[ error( "TBD" ) ]
583
- pub enum Error { }
617
+ pub ( super ) enum Error {
618
+ #[ error( transparent) ]
619
+ SubmoduleStatus ( #[ from] crate :: submodule:: status:: Error ) ,
620
+ #[ error( transparent) ]
621
+ IgnoreConfig ( #[ from] crate :: submodule:: config:: Error ) ,
622
+ }
584
623
585
624
impl gix_status:: index_as_worktree:: traits:: SubmoduleStatus for ComputeSubmoduleStatus {
586
625
type Output = SubmoduleStatus ;
@@ -589,9 +628,29 @@ pub mod iter {
589
628
fn status (
590
629
& mut self ,
591
630
_entry : & gix_index:: Entry ,
592
- _rela_path : & BStr ,
631
+ rela_path : & BStr ,
593
632
) -> Result < Option < Self :: Output > , Self :: Error > {
594
- todo ! ( "impl in Submodule itself, it will be calling this exact implementation under the hood, maybe with reduced threads" )
633
+ use bstr:: ByteSlice ;
634
+ if self
635
+ . submodule_paths
636
+ . binary_search_by ( |path| path. as_bstr ( ) . cmp ( rela_path) )
637
+ . is_err ( )
638
+ {
639
+ return Ok ( None ) ;
640
+ }
641
+ let repo = self . repo . to_thread_local ( ) ;
642
+ let Ok ( Some ( mut submodules) ) = repo. submodules ( ) else {
643
+ return Ok ( None ) ;
644
+ } ;
645
+ let Some ( sm) = submodules. find ( |sm| sm. path ( ) . map_or ( false , |path| path == rela_path) ) else {
646
+ return Ok ( None ) ;
647
+ } ;
648
+ let ( ignore, check_dirty) = match self . mode {
649
+ Submodule :: AsConfigured { check_dirty } => ( sm. ignore ( ) ?. unwrap_or_default ( ) , check_dirty) ,
650
+ Submodule :: Given { ignore, check_dirty } => ( ignore, check_dirty) ,
651
+ } ;
652
+ let status = sm. status ( ignore, check_dirty) ?;
653
+ Ok ( status. is_dirty ( ) . and_then ( |dirty| dirty. then_some ( status) ) )
595
654
}
596
655
}
597
656
}
0 commit comments