@@ -85,46 +85,7 @@ def parse_modules(*, module_ctx, logger, _fail = fail):
85
85
86
86
config = _get_toolchain_config (modules = module_ctx .modules , _fail = _fail )
87
87
88
- default_python_version = None
89
- for mod in module_ctx .modules :
90
- defaults_attr_structs = _create_defaults_attr_structs (mod = mod )
91
- default_python_version_env = None
92
- default_python_version_file = None
93
-
94
- # Only the root module and rules_python are allowed to specify the default
95
- # toolchain for a couple reasons:
96
- # * It prevents submodules from specifying different defaults and only
97
- # one of them winning.
98
- # * rules_python needs to set a soft default in case the root module doesn't,
99
- # e.g. if the root module doesn't use Python itself.
100
- # * The root module is allowed to override the rules_python default.
101
- if mod .is_root or (mod .name == "rules_python" and not default_python_version ):
102
- for defaults_attr in defaults_attr_structs :
103
- default_python_version = _one_or_the_same (
104
- default_python_version ,
105
- defaults_attr .python_version ,
106
- onerror = _fail_multiple_defaults_python_version ,
107
- )
108
- default_python_version_env = _one_or_the_same (
109
- default_python_version_env ,
110
- defaults_attr .python_version_env ,
111
- onerror = _fail_multiple_defaults_python_version_env ,
112
- )
113
- default_python_version_file = _one_or_the_same (
114
- default_python_version_file ,
115
- defaults_attr .python_version_file ,
116
- onerror = _fail_multiple_defaults_python_version_file ,
117
- )
118
- if default_python_version_file :
119
- default_python_version = _one_or_the_same (
120
- default_python_version ,
121
- module_ctx .read (default_python_version_file , watch = "yes" ).strip (),
122
- )
123
- if default_python_version_env :
124
- default_python_version = module_ctx .getenv (
125
- default_python_version_env ,
126
- default_python_version ,
127
- )
88
+ default_python_version = _compute_default_python_version (module_ctx )
128
89
129
90
seen_versions = {}
130
91
for mod in module_ctx .modules :
@@ -152,13 +113,7 @@ def parse_modules(*, module_ctx, logger, _fail = fail):
152
113
# * rules_python needs to set a soft default in case the root module doesn't,
153
114
# e.g. if the root module doesn't use Python itself.
154
115
# * The root module is allowed to override the rules_python default.
155
- if default_python_version :
156
- is_default = default_python_version == toolchain_version
157
- if toolchain_attr .is_default and not is_default :
158
- fail ("The 'is_default' attribute doesn't work if you set " +
159
- "the default Python version with the `defaults` tag." )
160
- else :
161
- is_default = toolchain_attr .is_default
116
+ is_default = default_python_version == toolchain_version
162
117
163
118
# Also only the root module should be able to decide ignore_root_user_error.
164
119
# Modules being depended upon don't know the final environment, so they aren't
@@ -169,15 +124,15 @@ def parse_modules(*, module_ctx, logger, _fail = fail):
169
124
fail ("Toolchains in the root module must have consistent 'ignore_root_user_error' attributes" )
170
125
171
126
ignore_root_user_error = toolchain_attr .ignore_root_user_error
172
- elif mod .name == "rules_python" and not default_toolchain and not default_python_version :
173
- # We don't do the len() check because we want the default that rules_python
174
- # sets to be clearly visible.
175
- is_default = toolchain_attr . is_default
127
+ elif mod .name == "rules_python" and not default_toolchain :
128
+ # This branch handles when the root module doesn't declare a
129
+ # Python toolchain
130
+ is_default = default_python_version == toolchain_version
176
131
else :
177
132
is_default = False
178
133
179
134
if is_default and default_toolchain != None :
180
- _fail_multiple_default_toolchains (
135
+ _fail_multiple_default_toolchains_chosen (
181
136
first = default_toolchain .name ,
182
137
second = toolchain_name ,
183
138
)
@@ -577,14 +532,24 @@ def _fail_multiple_defaults_python_version_env(first, second):
577
532
second = second ,
578
533
))
579
534
580
- def _fail_multiple_default_toolchains (first , second ):
535
+ def _fail_multiple_default_toolchains_chosen (first , second ):
581
536
fail (("Multiple default toolchains: only one toolchain " +
582
- "can have is_default=True . First default " +
537
+ "can be chosen as a default . First default " +
583
538
"was toolchain '{first}'. Second was '{second}'" ).format (
584
539
first = first ,
585
540
second = second ,
586
541
))
587
542
543
+ def _fail_multiple_default_toolchains_in_module (mod , toolchain_attrs ):
544
+ fail (("Multiple default toolchains: only one toolchain " +
545
+ "can have is_default=True.\n " +
546
+ "Module '{module}' contains {count} toolchains with " +
547
+ "is_default=True: {versions}" ).format (
548
+ module = mod .name ,
549
+ count = len (toolchain_attrs ),
550
+ versions = ", " .join (sorted ([v .python_version for v in toolchain_attrs ])),
551
+ ))
552
+
588
553
def _validate_version (version_str , * , _fail = fail ):
589
554
v = version .parse (version_str , strict = True , _fail = _fail )
590
555
if v == None :
@@ -880,6 +845,72 @@ def _get_toolchain_config(*, modules, _fail = fail):
880
845
register_all_versions = register_all_versions ,
881
846
)
882
847
848
+ def _compute_default_python_version (mctx ):
849
+ default_python_version = None
850
+ for mod in mctx .modules :
851
+ # Only the root module and rules_python are allowed to specify the default
852
+ # toolchain for a couple reasons:
853
+ # * It prevents submodules from specifying different defaults and only
854
+ # one of them winning.
855
+ # * rules_python needs to set a soft default in case the root module doesn't,
856
+ # e.g. if the root module doesn't use Python itself.
857
+ # * The root module is allowed to override the rules_python default.
858
+ if not (mod .is_root or mod .name == "rules_python" ):
859
+ continue
860
+
861
+ defaults_attr_structs = _create_defaults_attr_structs (mod = mod )
862
+ default_python_version_env = None
863
+ default_python_version_file = None
864
+
865
+ for defaults_attr in defaults_attr_structs :
866
+ default_python_version = _one_or_the_same (
867
+ default_python_version ,
868
+ defaults_attr .python_version ,
869
+ onerror = _fail_multiple_defaults_python_version ,
870
+ )
871
+ default_python_version_env = _one_or_the_same (
872
+ default_python_version_env ,
873
+ defaults_attr .python_version_env ,
874
+ onerror = _fail_multiple_defaults_python_version_env ,
875
+ )
876
+ default_python_version_file = _one_or_the_same (
877
+ default_python_version_file ,
878
+ defaults_attr .python_version_file ,
879
+ onerror = _fail_multiple_defaults_python_version_file ,
880
+ )
881
+ if default_python_version_file :
882
+ default_python_version = _one_or_the_same (
883
+ default_python_version ,
884
+ mctx .read (default_python_version_file , watch = "yes" ).strip (),
885
+ )
886
+ if default_python_version_env :
887
+ default_python_version = mctx .getenv (
888
+ default_python_version_env ,
889
+ default_python_version ,
890
+ )
891
+
892
+ if default_python_version :
893
+ break
894
+
895
+ # Otherwise, look at legacy python.toolchain() calls for a default
896
+ toolchain_attrs = mod .tags .toolchain
897
+
898
+ # Convenience: if one python.toolchain() call exists, treat it as
899
+ # the default.
900
+ if len (toolchain_attrs ) == 1 :
901
+ default_python_version = toolchain_attrs [0 ].python_version
902
+ else :
903
+ sets_default = [v for v in toolchain_attrs if v .is_default ]
904
+ if len (sets_default ) == 1 :
905
+ default_python_version = sets_default [0 ].python_version
906
+ elif len (sets_default ) > 1 :
907
+ _fail_multiple_default_toolchains_in_module (mod , toolchain_attrs )
908
+
909
+ if default_python_version :
910
+ break
911
+
912
+ return default_python_version
913
+
883
914
def _create_defaults_attr_structs (* , mod ):
884
915
arg_structs = []
885
916
@@ -915,7 +946,11 @@ def _create_toolchain_attr_structs(*, mod, config, seen_versions):
915
946
916
947
return arg_structs
917
948
918
- def _create_toolchain_attrs_struct (* , tag = None , python_version = None , toolchain_tag_count = None ):
949
+ def _create_toolchain_attrs_struct (
950
+ * ,
951
+ tag = None ,
952
+ python_version = None ,
953
+ toolchain_tag_count = None ):
919
954
if tag and python_version :
920
955
fail ("Only one of tag and python version can be specified" )
921
956
if tag :
0 commit comments