@@ -96,6 +96,145 @@ 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+ self: implicitly added
129+ value: the value to set.
130+ """
131+ if len (self ._value ) == 0 :
132+ self ._value .append (value )
133+ else :
134+ self ._value [0 ] = value
135+
136+ def _Optional_get (self ):
137+ """Gets the value of the optional, or error.
138+
139+ Args:
140+ self: implicitly added
141+
142+ Returns:
143+ The stored value, or error if not set.
144+ """
145+ if not len (self ._value ):
146+ fail ("Value not present" )
147+ return self ._value [0 ]
148+
149+ def _Optional_present (self ):
150+ """Tells if a value is present.
151+
152+ Args:
153+ self: implicitly added
154+
155+ Returns:
156+ {type}`bool` True if the value is set, False if not.
157+ """
158+ return len (self ._value ) > 0
159+
160+ def _RuleBuilder (implementation = None , ** kwargs ):
161+ """Builder for creating rules.
162+
163+ Args:
164+ implementation: {type}`callable` The rule implementation function.
165+ **kwargs: The same as the `rule()` function, but using builders
166+ for the non-mutable Bazel objects.
167+ """
168+
169+ # buildifier: disable=uninitialized
170+ self = struct (
171+ attrs = dict (kwargs .pop ("attrs" , None ) or {}),
172+ cfg = kwargs .pop ("cfg" , None ) or _TransitionBuilder (),
173+ exec_groups = dict (kwargs .pop ("exec_groups" , None ) or {}),
174+ executable = _Optional (),
175+ fragments = list (kwargs .pop ("fragments" , None ) or []),
176+ implementation = _Optional (implementation ),
177+ extra_kwargs = kwargs ,
178+ provides = list (kwargs .pop ("provides" , None ) or []),
179+ test = _Optional (),
180+ toolchains = list (kwargs .pop ("toolchains" , None ) or []),
181+ build = lambda * a , ** k : _RuleBuilder_build (self , * a , ** k ),
182+ to_kwargs = lambda * a , ** k : _RuleBuilder_to_kwargs (self , * a , ** k ),
183+ )
184+ if "test" in kwargs :
185+ self .test .set (kwargs .pop ("test" ))
186+ if "executable" in kwargs :
187+ self .executable .set (kwargs .pop ("executable" ))
188+ return self
189+
190+ def _RuleBuilder_build (self , debug = "" ):
191+ """Builds a `rule` object
192+
193+ Args:
194+ self: implicitly added
195+ debug: {type}`str` If set, prints the args used to create the rule.
196+
197+ Returns:
198+ {type}`rule`
199+ """
200+ kwargs = self .to_kwargs ()
201+ if debug :
202+ lines = ["=" * 80 , "rule kwargs: {}:" .format (debug )]
203+ for k , v in sorted (kwargs .items ()):
204+ lines .append (" {}={}" .format (k , v ))
205+ print ("\n " .join (lines )) # buildifier: disable=print
206+ return rule (** kwargs )
207+
208+ def _RuleBuilder_to_kwargs (self ):
209+ """Builds the arguments for calling `rule()`.
210+
211+ Args:
212+ self: implicitly added
213+
214+ Returns:
215+ {type}`dict`
216+ """
217+ kwargs = {}
218+ if self .executable .present ():
219+ kwargs ["executable" ] = self .executable .get ()
220+ if self .test .present ():
221+ kwargs ["test" ] = self .test .get ()
222+
223+ kwargs .update (
224+ implementation = self .implementation .get (),
225+ cfg = self .cfg .build () if self .cfg .implementation .present () else None ,
226+ attrs = {
227+ k : (v .build () if hasattr (v , "build" ) else v )
228+ for k , v in self .attrs .items ()
229+ },
230+ exec_groups = self .exec_groups ,
231+ fragments = self .fragments ,
232+ provides = self .provides ,
233+ toolchains = self .toolchains ,
234+ )
235+ kwargs .update (self .extra_kwargs )
236+ return kwargs
237+
99238def _RunfilesBuilder ():
100239 """Creates a `RunfilesBuilder`.
101240
@@ -177,41 +316,60 @@ def _RunfilesBuilder_build(self, ctx, **kwargs):
177316 ** kwargs
178317 ).merge_all (self .runfiles )
179318
180- # Skylib's types module doesn't have is_file, so roll our own
181- def _is_file (value ):
182- return type (value ) == "File"
319+ def _SetBuilder (initial = None ):
320+ """Builder for list of unique values.
183321
184- def _is_runfiles ( value ) :
185- return type ( value ) == "runfiles"
322+ Args :
323+ initial: { type}`list | None` The initial values.
186324
187- def _Optional (* initial ):
188- if len (initial ) > 1 :
189- fail ("only one positional arg allowed" )
325+ Returns:
326+ {type}`SetBuilder`
327+ """
328+ initial = {} if not initial else {v : None for v in initial }
190329
191330 # buildifier: disable=uninitialized
192331 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 ),
332+ # TODO - Switch this to use set() builtin when available
333+ # https://bazel.build/rules/lib/core/set
334+ _values = initial ,
335+ update = lambda * a , ** k : _SetBuilder_update (self , * a , ** k ),
336+ build = lambda * a , ** k : _SetBuilder_build (self , * a , ** k ),
197337 )
198338 return self
199339
200- def _Optional_set (self , v ):
201- if len (self ._value ) == 0 :
202- self ._value .append (v )
203- else :
204- self ._value [0 ] = v
340+ def _SetBuilder_build (self ):
341+ """Builds the values into a list
205342
206- def _Optional_get ( self ) :
207- if not len ( self . _value ):
208- fail ( "Value not present" )
209- return self ._value [ 0 ]
343+ Returns :
344+ {type}`list`
345+ """
346+ return self ._values . keys ()
210347
211- def _Optional_present (self ):
212- return len (self ._value ) > 0
348+ def _SetBuilder_update (self , * others ):
349+ """Adds values to the builder.
350+
351+ Args:
352+ self: implicitly added
353+ *others: {type}`list` values to add to the set.
354+ """
355+ for other in others :
356+ for value in other :
357+ if value not in self ._values :
358+ self ._values [value ] = None
213359
214360def _TransitionBuilder (implementation = None , inputs = None , outputs = None , ** kwargs ):
361+ """Builder for transition objects.
362+
363+ Args:
364+ implementation: {type}`callable` the transition implementation function.
365+ inputs: {type}`list[str]` the inputs for the transition.
366+ outputs: {type}`list[str]` the outputs of the transition.
367+ **kwargs: Extra keyword args to use when building.
368+
369+ Returns:
370+ {type}`TransitionBuilder`
371+ """
372+
215373 # buildifier: disable=uninitialized
216374 self = struct (
217375 implementation = _Optional (implementation ),
@@ -231,87 +389,24 @@ def _TransitionBuilder(implementation = None, inputs = None, outputs = None, **k
231389 return self
232390
233391def _TransitionBuilder_build (self ):
392+ """Creates a transition from the builder.
393+
394+ Returns:
395+ {type}`transition`
396+ """
234397 return transition (
235398 implementation = self .implementation .get (),
236399 inputs = self .inputs .build (),
237400 outputs = self .outputs .build (),
238401 ** self .extra_kwargs
239402 )
240403
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 ()
404+ # Skylib's types module doesn't have is_file, so roll our own
405+ def _is_file (value ):
406+ return type (value ) == "File"
300407
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
408+ def _is_runfiles (value ):
409+ return type (value ) == "runfiles"
315410
316411builders = struct (
317412 DepsetBuilder = _DepsetBuilder ,
0 commit comments