@@ -32,7 +32,7 @@ use std::cell::RefCell;
32
32
use std:: collections:: HashMap ;
33
33
use std:: env;
34
34
use std:: fs:: { self , File } ;
35
- use std:: path:: { PathBuf , Path } ;
35
+ use std:: path:: { Component , PathBuf , Path } ;
36
36
use std:: process:: Command ;
37
37
38
38
use build_helper:: { run_silent, output} ;
@@ -477,12 +477,32 @@ impl Build {
477
477
/// This will detect if any submodules are out of date an run the necessary
478
478
/// commands to sync them all with upstream.
479
479
fn update_submodules ( & self ) {
480
+ struct Submodule < ' a > {
481
+ path : & ' a Path ,
482
+ state : State ,
483
+ }
484
+
485
+ enum State {
486
+ // The submodule may have staged/unstaged changes
487
+ MaybeDirty ,
488
+ // Or could be initialized but never updated
489
+ NotInitialized ,
490
+ // The submodule, itself, has extra commits but those changes haven't been commited to
491
+ // the (outer) git repository
492
+ OutOfSync ,
493
+ }
494
+
480
495
if !self . config . submodules {
481
496
return
482
497
}
483
498
if fs:: metadata ( self . src . join ( ".git" ) ) . is_err ( ) {
484
499
return
485
500
}
501
+ let git = || {
502
+ let mut cmd = Command :: new ( "git" ) ;
503
+ cmd. current_dir ( & self . src ) ;
504
+ return cmd
505
+ } ;
486
506
let git_submodule = || {
487
507
let mut cmd = Command :: new ( "git" ) ;
488
508
cmd. current_dir ( & self . src ) . arg ( "submodule" ) ;
@@ -494,19 +514,67 @@ impl Build {
494
514
// of detecting whether we need to run all the submodule commands
495
515
// below.
496
516
let out = output ( git_submodule ( ) . arg ( "status" ) ) ;
497
- if !out. lines ( ) . any ( |l| l. starts_with ( "+" ) || l. starts_with ( "-" ) ) {
498
- return
517
+ let mut submodules = vec ! [ ] ;
518
+ for line in out. lines ( ) {
519
+ // NOTE `git submodule status` output looks like this:
520
+ //
521
+ // -5066b7dcab7e700844b0e2ba71b8af9dc627a59b src/liblibc
522
+ // +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/..)
523
+ // e058ca661692a8d01f8cf9d35939dfe3105ce968 src/jemalloc (3.6.0-533-ge058ca6)
524
+ //
525
+ // The first character can be '-', '+' or ' ' and denotes the `State` of the submodule
526
+ // Right next to this character is the SHA-1 of the submodule HEAD
527
+ // And after that comes the path to the submodule
528
+ let path = Path :: new ( line[ 1 ..] . split ( ' ' ) . skip ( 1 ) . next ( ) . unwrap ( ) ) ;
529
+ let state = if line. starts_with ( '-' ) {
530
+ State :: NotInitialized
531
+ } else if line. starts_with ( '*' ) {
532
+ State :: OutOfSync
533
+ } else if line. starts_with ( ' ' ) {
534
+ State :: MaybeDirty
535
+ } else {
536
+ panic ! ( "unexpected git submodule state: {:?}" , line. chars( ) . next( ) ) ;
537
+ } ;
538
+
539
+ submodules. push ( Submodule { path : path, state : state } )
499
540
}
500
541
501
542
self . run ( git_submodule ( ) . arg ( "sync" ) ) ;
502
- self . run ( git_submodule ( ) . arg ( "init" ) ) ;
503
- self . run ( git_submodule ( ) . arg ( "update" ) ) ;
504
- self . run ( git_submodule ( ) . arg ( "update" ) . arg ( "--recursive" ) ) ;
505
- self . run ( git_submodule ( ) . arg ( "status" ) . arg ( "--recursive" ) ) ;
506
- self . run ( git_submodule ( ) . arg ( "foreach" ) . arg ( "--recursive" )
507
- . arg ( "git" ) . arg ( "clean" ) . arg ( "-fdx" ) ) ;
508
- self . run ( git_submodule ( ) . arg ( "foreach" ) . arg ( "--recursive" )
509
- . arg ( "git" ) . arg ( "checkout" ) . arg ( "." ) ) ;
543
+
544
+ for submodule in submodules {
545
+ // If using llvm-root then don't touch the llvm submodule.
546
+ if submodule. path . components ( ) . any ( |c| c == Component :: Normal ( "llvm" . as_ref ( ) ) ) &&
547
+ self . config . target_config . get ( & self . config . build )
548
+ . and_then ( |c| c. llvm_config . as_ref ( ) ) . is_some ( )
549
+ {
550
+ continue
551
+ }
552
+
553
+ if submodule. path . components ( ) . any ( |c| c == Component :: Normal ( "jemalloc" . as_ref ( ) ) ) &&
554
+ !self . config . use_jemalloc
555
+ {
556
+ continue
557
+ }
558
+
559
+ match submodule. state {
560
+ State :: MaybeDirty => {
561
+ // drop staged changes
562
+ self . run ( git ( ) . arg ( "-C" ) . arg ( submodule. path ) . args ( & [ "reset" , "--hard" ] ) ) ;
563
+ // drops unstaged changes
564
+ self . run ( git ( ) . arg ( "-C" ) . arg ( submodule. path ) . args ( & [ "clean" , "-fdx" ] ) ) ;
565
+ } ,
566
+ State :: NotInitialized => {
567
+ self . run ( git_submodule ( ) . arg ( "init" ) . arg ( submodule. path ) ) ;
568
+ self . run ( git_submodule ( ) . arg ( "update" ) . arg ( submodule. path ) ) ;
569
+ } ,
570
+ State :: OutOfSync => {
571
+ // drops submodule commits that weren't reported to the (outer) git repository
572
+ self . run ( git_submodule ( ) . arg ( "update" ) . arg ( submodule. path ) ) ;
573
+ self . run ( git ( ) . arg ( "-C" ) . arg ( submodule. path ) . args ( & [ "reset" , "--hard" ] ) ) ;
574
+ self . run ( git ( ) . arg ( "-C" ) . arg ( submodule. path ) . args ( & [ "clean" , "-fdx" ] ) ) ;
575
+ } ,
576
+ }
577
+ }
510
578
}
511
579
512
580
/// Clear out `dir` if `input` is newer.
0 commit comments