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