@@ -536,6 +536,40 @@ def print_repo_hashes(args, config):
536
536
print ("{:<35}: {:<35}" .format (repo_name , repo_hash ))
537
537
538
538
539
+ def merge_no_duplicates (a : dict , b : dict ) -> dict :
540
+ result = {** a }
541
+ for key , value in b .items ():
542
+ if key in a :
543
+ raise ValueError (f"Duplicate scheme { key } " )
544
+
545
+ result [key ] = value
546
+ return result
547
+
548
+
549
+ def merge_config (config : dict , new_config : dict ) -> dict :
550
+ """
551
+ Merge two configs, with a 'last-wins' strategy.
552
+
553
+ The branch-schemes are rejected if they define duplicate schemes.
554
+ """
555
+
556
+ result = {** config }
557
+ for key , value in new_config .items ():
558
+ if key == "branch-schemes" :
559
+ # We reject duplicates here since this is the most conservative
560
+ # behavior, so it can be relaxed in the future.
561
+ # TODO: Another semantics might be nicer, define that as it is needed.
562
+ result [key ] = merge_no_duplicates (config .get (key , {}), value )
563
+ elif key == "repos" :
564
+ # The "repos" object is last-wins on a key-by-key basis
565
+ result [key ] = {** config .get (key , {}), ** value }
566
+ else :
567
+ # Anything else is just last-wins
568
+ result [key ] = value
569
+
570
+ return result
571
+
572
+
539
573
def validate_config (config ):
540
574
# Make sure that our branch-names are unique.
541
575
scheme_names = config ['branch-schemes' ].keys ()
@@ -669,9 +703,12 @@ def main():
669
703
)
670
704
parser .add_argument (
671
705
"--config" ,
672
- default = os .path .join (SCRIPT_DIR , os .pardir ,
673
- "update-checkout-config.json" ),
674
- help = "Configuration file to use" )
706
+ help = """The configuration file to use. Can be specified multiple times,
707
+ each config will be merged together with a 'last-wins' strategy.
708
+ Overwriting branch-schemes is not allowed.""" ,
709
+ action = "append" ,
710
+ default = [],
711
+ dest = "configs" )
675
712
parser .add_argument (
676
713
"--github-comment" ,
677
714
help = """Check out related pull requests referenced in the given
@@ -734,8 +771,15 @@ def main():
734
771
all_repos = args .all_repositories
735
772
use_submodules = args .use_submodules
736
773
737
- with open (args .config ) as f :
738
- config = json .load (f )
774
+ # Set the default config path if none are specified
775
+ if not args .configs :
776
+ default_path = os .path .join (SCRIPT_DIR , os .pardir ,
777
+ "update-checkout-config.json" )
778
+ args .configs .append (default_path )
779
+ config = {}
780
+ for config_path in args .configs :
781
+ with open (config_path ) as f :
782
+ config = merge_config (config , json .load (f ))
739
783
validate_config (config )
740
784
741
785
cross_repos_pr = {}
@@ -783,8 +827,10 @@ def main():
783
827
prefix = "[swift] " )
784
828
785
829
# Re-read the config after checkout.
786
- with open (args .config ) as f :
787
- config = json .load (f )
830
+ config = {}
831
+ for config_path in args .configs :
832
+ with open (config_path ) as f :
833
+ config = merge_config (config , json .load (f ))
788
834
validate_config (config )
789
835
scheme_map = get_scheme_map (config , scheme_name )
790
836
0 commit comments