@@ -96,6 +96,134 @@ def _DepsetBuilder_build(self):
9696 kwargs ["order" ] = self ._order [0 ]
9797 return depset (direct = self .direct , transitive = self .transitive , ** kwargs )
9898
99+ def _Optional (* initial ):
100+ """A wrapper for a re-assignable value that may or may not be set.
101+
102+ This allows structs to have attributes that aren't inherently mutable
103+ and must be re-assigned to have their value updated.
104+
105+ Args:
106+ *initial: A single vararg to be the initial value, or no args
107+ to leave it unset.
108+
109+ Returns:
110+ {type}`Optional`
111+ """
112+ if len (initial ) > 1 :
113+ fail ("Only zero or one positional arg allowed" )
114+
115+ # buildifier: disable=uninitialized
116+ self = struct (
117+ _value = list (initial ),
118+ present = lambda * a , ** k : _Optional_present (self , * a , ** k ),
119+ set = lambda * a , ** k : _Optional_set (self , * a , ** k ),
120+ get = lambda * a , ** k : _Optional_get (self , * a , ** k ),
121+ )
122+ return self
123+
124+ def _Optional_set (self , value ):
125+ """Sets the value of the optional.
126+
127+ Args:
128+ value: the value to set.
129+ """
130+ if len (self ._value ) == 0 :
131+ self ._value .append (value )
132+ else :
133+ self ._value [0 ] = value
134+
135+ def _Optional_get (self ):
136+ """Gets the value of the optional, or error.
137+
138+ Returns:
139+ The stored value, or error if not set.
140+ """
141+ if not len (self ._value ):
142+ fail ("Value not present" )
143+ return self ._value [0 ]
144+
145+ def _Optional_present (self ):
146+ """Tells if a value is present.
147+
148+ Returns:
149+ {type}`bool` True if the value is set, False if not.
150+ """
151+ return len (self ._value ) > 0
152+
153+ def _RuleBuilder (implementation = None , ** kwargs ):
154+ """Builder for creating rules.
155+
156+ Args:
157+ implementation: {type}`callable` The rule implementation function.
158+ **kwargs: The same as the `rule()` function, but using builders
159+ for the non-mutable Bazel objects.
160+ """
161+
162+ # buildifier: disable=uninitialized
163+ self = struct (
164+ attrs = dict (kwargs .pop ("attrs" , None ) or {}),
165+ cfg = kwargs .pop ("cfg" , None ) or _TransitionBuilder (),
166+ exec_groups = dict (kwargs .pop ("exec_groups" , None ) or {}),
167+ executable = _Optional (),
168+ fragments = list (kwargs .pop ("fragments" , None ) or []),
169+ implementation = _Optional (implementation ),
170+ extra_kwargs = kwargs ,
171+ provides = list (kwargs .pop ("provides" , None ) or []),
172+ test = _Optional (),
173+ toolchains = list (kwargs .pop ("toolchains" , None ) or []),
174+ build = lambda * a , ** k : _RuleBuilder_build (self , * a , ** k ),
175+ to_kwargs = lambda * a , ** k : _RuleBuilder_to_kwargs (self , * a , ** k ),
176+ )
177+ if "test" in kwargs :
178+ self .test .set (kwargs .pop ("test" ))
179+ if "executable" in kwargs :
180+ self .executable .set (kwargs .pop ("executable" ))
181+ return self
182+
183+ def _RuleBuilder_build (self , debug = "" ):
184+ """Builds a `rule` object
185+
186+ Args:
187+ debug: {type}`str` If set, prints the args used to create the rule.
188+
189+ Returns:
190+ {type}`rule`
191+ """
192+ kwargs = self .to_kwargs ()
193+ if debug :
194+ lines = ["=" * 80 , "rule kwargs: {}:" .format (debug )]
195+ for k , v in sorted (kwargs .items ()):
196+ lines .append (" {}={}" .format (k , v ))
197+ print ("\n " .join (lines )) # buildifier: disable=print
198+ return rule (** kwargs )
199+
200+ def _RuleBuilder_to_kwargs (self ):
201+ """Builds the arguments for calling `rule()`.
202+
203+ Returns:
204+ {type}`dict`
205+ """
206+ kwargs = {}
207+ if self .executable .present ():
208+ kwargs ["executable" ] = self .executable .get ()
209+ if self .test .present ():
210+ kwargs ["test" ] = self .test .get ()
211+
212+ kwargs .update (
213+ implementation = self .implementation .get (),
214+ cfg = self .cfg .build () if self .cfg .implementation .present () else None ,
215+ attrs = {
216+ k : (v .build () if hasattr (v , "build" ) else v )
217+ for k , v in self .attrs .items ()
218+ },
219+ exec_groups = self .exec_groups ,
220+ fragments = self .fragments ,
221+ provides = self .provides ,
222+ toolchains = self .toolchains ,
223+ )
224+ kwargs .update (self .extra_kwargs )
225+ return kwargs
226+
99227def _RunfilesBuilder ():
100228 """Creates a `RunfilesBuilder`.
101229
@@ -177,41 +305,59 @@ def _RunfilesBuilder_build(self, ctx, **kwargs):
177305 ** kwargs
178306 ).merge_all (self .runfiles )
179307
180- # Skylib's types module doesn't have is_file, so roll our own
181- def _is_file (value ):
182- return type (value ) == "File"
308+ def _SetBuilder (initial = None ):
309+ """Builder for list of unique values.
183310
184- def _is_runfiles ( value ) :
185- return type ( value ) == "runfiles"
311+ Args :
312+ initial: { type}`list | None` The initial values.
186313
187- def _Optional (* initial ):
188- if len (initial ) > 1 :
189- fail ("only one positional arg allowed" )
314+ Returns:
315+ {type}`SetBuilder`
316+ """
317+ initial = {} if not initial else {v : None for v in initial }
190318
191319 # buildifier: disable=uninitialized
192320 self = struct (
193- _value = list (initial ),
194- present = lambda * a , ** k : _Optional_present (self , * a , ** k ),
195- set = lambda * a , ** k : _Optional_set (self , * a , ** k ),
196- get = lambda * a , ** k : _Optional_get (self , * a , ** k ),
321+ # TODO - Switch this to use set() builtin when available
322+ # https://bazel.build/rules/lib/core/set
323+ _values = initial ,
324+ update = lambda * a , ** k : _SetBuilder_update (self , * a , ** k ),
325+ build = lambda * a , ** k : _SetBuilder_build (self , * a , ** k ),
197326 )
198327 return self
199328
200- def _Optional_set (self , v ):
201- if len (self ._value ) == 0 :
202- self ._value .append (v )
203- else :
204- self ._value [0 ] = v
329+ def _SetBuilder_build (self ):
330+ """Builds the values into a list
205331
206- def _Optional_get ( self ) :
207- if not len ( self . _value ):
208- fail ( "Value not present" )
209- return self ._value [ 0 ]
332+ Returns :
333+ {type}`list`
334+ """
335+ return self ._values . keys ()
210336
211- def _Optional_present (self ):
212- return len (self ._value ) > 0
337+ def _SetBuilder_update (self , * others ):
338+ """Adds values to the builder.
339+
340+ Args:
341+ *others: {type}`list` values to add to the set.
342+ """
343+ for other in others :
344+ for value in other :
345+ if value not in self ._values :
346+ self ._values [value ] = None
213347
214348def _TransitionBuilder (implementation = None , inputs = None , outputs = None , ** kwargs ):
349+ """Builder for transition objects.
350+
351+ Args:
352+ implementation: {type}`callable` the transition implementation function.
353+ inputs: {type}`list[str]` the inputs for the transition.
354+ outputs: {type}`list[str]` the outputs of the transition.
355+ **kwargs: Extra keyword args to use when building.
356+
357+ Returns:
358+ {type}`TransitionBuilder`
359+ """
360+
215361 # buildifier: disable=uninitialized
216362 self = struct (
217363 implementation = _Optional (implementation ),
@@ -231,87 +377,24 @@ def _TransitionBuilder(implementation = None, inputs = None, outputs = None, **k
231377 return self
232378
233379def _TransitionBuilder_build (self ):
380+ """Creates a transition from the builder.
381+
382+ Returns:
383+ {type}`transition`
384+ """
234385 return transition (
235386 implementation = self .implementation .get (),
236387 inputs = self .inputs .build (),
237388 outputs = self .outputs .build (),
238389 ** self .extra_kwargs
239390 )
240391
241- def _SetBuilder (initial = None ):
242- initial = {} if not initial else {v : None for v in initial }
243-
244- # buildifier: disable=uninitialized
245- self = struct (
246- # TODO - Switch this to use set() builtin when available
247- # https://bazel.build/rules/lib/core/set
248- _values = initial ,
249- update = lambda * a , ** k : _SetBuilder_update (self , * a , ** k ),
250- build = lambda * a , ** k : _SetBuilder_build (self , * a , ** k ),
251- )
252- return self
253-
254- def _SetBuilder_build (self ):
255- return self ._values .keys ()
256-
257- def _SetBuilder_update (self , * others ):
258- for other in others :
259- for value in other :
260- if value not in self ._values :
261- self ._values [value ] = None
262-
263- def _RuleBuilder (implementation = None , ** kwargs ):
264- # buildifier: disable=uninitialized
265- self = struct (
266- attrs = dict (kwargs .pop ("attrs" , None ) or {}),
267- cfg = kwargs .pop ("cfg" , None ) or _TransitionBuilder (),
268- exec_groups = dict (kwargs .pop ("exec_groups" , None ) or {}),
269- executable = _Optional (),
270- fragments = list (kwargs .pop ("fragments" , None ) or []),
271- implementation = _Optional (implementation ),
272- extra_kwargs = kwargs ,
273- provides = list (kwargs .pop ("provides" , None ) or []),
274- test = _Optional (),
275- toolchains = list (kwargs .pop ("toolchains" , None ) or []),
276- build = lambda * a , ** k : _RuleBuilder_build (self , * a , ** k ),
277- to_kwargs = lambda * a , ** k : _RuleBuilder_to_kwargs (self , * a , ** k ),
278- )
279- if "test" in kwargs :
280- self .test .set (kwargs .pop ("test" ))
281- if "executable" in kwargs :
282- self .executable .set (kwargs .pop ("executable" ))
283- return self
284-
285- def _RuleBuilder_build (self , debug = "" ):
286- kwargs = self .to_kwargs ()
287- if debug :
288- lines = ["=" * 80 , "rule kwargs: {}:" .format (debug )]
289- for k , v in sorted (kwargs .items ()):
290- lines .append (" {}={}" .format (k , v ))
291- print ("\n " .join (lines )) # buildifier: disable=print
292- return rule (** kwargs )
293-
294- def _RuleBuilder_to_kwargs (self ):
295- kwargs = {}
296- if self .executable .present ():
297- kwargs ["executable" ] = self .executable .get ()
298- if self .test .present ():
299- kwargs ["test" ] = self .test .get ()
392+ # Skylib's types module doesn't have is_file, so roll our own
393+ def _is_file (value ):
394+ return type (value ) == "File"
300395
301- kwargs .update (
302- implementation = self .implementation .get (),
303- cfg = self .cfg .build (),
304- attrs = {
305- k : (v .build () if hasattr (v , "build" ) else v )
306- for k , v in self .attrs .items ()
307- },
308- exec_groups = self .exec_groups ,
309- fragments = self .fragments ,
310- provides = self .provides ,
311- toolchains = self .toolchains ,
312- )
313- kwargs .update (self .extra_kwargs )
314- return kwargs
396+ def _is_runfiles (value ):
397+ return type (value ) == "runfiles"
315398
316399builders = struct (
317400 DepsetBuilder = _DepsetBuilder ,
0 commit comments