3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 class ValueNodeInfo(SCons
.Node
.NodeInfoBase
):
33 current_version_id
= 2
37 def str_to_node(self
, s
):
38 return ValueWithMemo(s
)
40 def __getstate__(self
):
42 Return all fields that shall be pickled. Walk the slots in the class
43 hierarchy and add those to the state dictionary. If a '__dict__' slot
44 is available, copy all entries to the dictionary. Also include the
45 version id, which is fixed for all instances of a class.
47 state
= getattr(self
, '__dict__', {}).copy()
48 for obj
in type(self
).mro():
49 for name
in getattr(obj
, '__slots__', ()):
50 if hasattr(self
, name
):
51 state
[name
] = getattr(self
, name
)
53 state
['_version_id'] = self
.current_version_id
55 del state
['__weakref__']
61 def __setstate__(self
, state
) -> None:
63 Restore the attributes from a pickled state.
65 # TODO check or discard version
66 del state
['_version_id']
67 for key
, value
in state
.items():
68 if key
not in ('__weakref__',):
69 setattr(self
, key
, value
)
72 class ValueBuildInfo(SCons
.Node
.BuildInfoBase
):
74 current_version_id
= 2
77 class Value(SCons
.Node
.Node
):
78 """A Node class for values represented by Python expressions.
80 Values are typically passed on the command line or generated
81 by a script, but not from a file or some other source.
83 .. versionchanged:: 4.0
84 the *name* parameter was added.
87 NodeInfo
= ValueNodeInfo
88 BuildInfo
= ValueBuildInfo
90 def __init__(self
, value
, built_value
=None, name
=None) -> None:
93 self
.changed_since_last_build
= 6
95 if built_value
is not None:
96 self
.built_value
= built_value
98 # Set a name so it can be a child of a node and not break
99 # its parent's implementation of Node.get_contents.
103 self
.name
= str(value
)
105 def str_for_display(self
):
106 return repr(self
.value
)
108 def __str__(self
) -> str:
109 return str(self
.value
)
111 def make_ready(self
) -> None:
114 def build(self
, **kw
) -> None:
115 if not hasattr(self
, 'built_value'):
116 SCons
.Node
.Node
.build(self
, **kw
)
118 is_up_to_date
= SCons
.Node
.Node
.children_are_up_to_date
120 def is_under(self
, dir) -> bool:
121 # Make Value nodes get built regardless of
122 # what directory scons was run from. Value nodes
123 # are outside the filesystem:
126 def write(self
, built_value
) -> None:
127 """Set the value of the node."""
128 self
.built_value
= built_value
131 """Return the value. If necessary, the value is built."""
133 if not hasattr(self
, 'built_value'):
134 self
.built_value
= self
.value
135 return self
.built_value
137 def get_text_contents(self
) -> str:
138 """By the assumption that the node.built_value is a
139 deterministic product of the sources, the contents of a Value
140 are the concatenation of all the contents of its sources. As
141 the value need not be built when get_contents() is called, we
142 cannot use the actual node.built_value."""
143 ###TODO: something reasonable about universal newlines
144 contents
= str(self
.value
)
145 for kid
in self
.children(None):
146 # Get csig() value of child as this is more efficent
147 contents
= contents
+ kid
.get_csig()
150 def get_contents(self
) -> bytes
:
151 """Get contents for signature calculations."""
152 return self
.get_text_contents().encode()
154 def get_csig(self
, calc
=None):
155 """Because we're a Python value node and don't have a real
156 timestamp, we get to ignore the calculator and just use the
159 Returns string. Ideally string of hex digits. (Not bytes)
162 return self
.ninfo
.csig
163 except AttributeError:
166 contents
= self
.get_text_contents()
168 self
.get_ninfo().csig
= contents
172 def ValueWithMemo(value
, built_value
=None, name
=None):
173 """Memoized :class:`Value` node factory.
175 .. versionchanged:: 4.0
176 the *name* parameter was added.
178 global _memo_lookup_map
180 # No current support for memoizing a value that needs to be built.
182 return Value(value
, built_value
, name
=name
)
185 memo_lookup_key
= hash((value
, name
))
187 # Non-primitive types will hit this codepath.
188 return Value(value
, name
=name
)
191 return _memo_lookup_map
[memo_lookup_key
]
193 v
= Value(value
, built_value
, name
)
194 _memo_lookup_map
[memo_lookup_key
] = v
200 # indent-tabs-mode:nil
202 # vim: set expandtab tabstop=4 shiftwidth=4: