3 from buildbot
import util
5 class Properties(util
.ComparableMixin
):
7 I represent a set of properties that can be interpolated into various
10 @ivar properties: dictionary mapping property values to tuples
11 (value, source), where source is a string identifing the source
14 Objects of this class can be read like a dictionary -- in this case,
15 only the property value is returned.
17 As a special case, a property value of None is returned as an empty
18 string when used as a mapping.
21 compare_attrs
= ('properties',)
23 def __init__(self
, **kwargs
):
25 @param kwargs: initial property values (for testing)
28 self
.pmap
= PropertyMap(self
)
29 if kwargs
: self
.update(kwargs
, "TEST")
31 def __getstate__(self
):
32 d
= self
.__dict
__.copy()
36 def __setstate__(self
, d
):
38 self
.pmap
= PropertyMap(self
)
40 def __contains__(self
, name
):
41 return name
in self
.properties
43 def __getitem__(self
, name
):
44 """Just get the value for this property."""
45 rv
= self
.properties
[name
][0]
48 def has_key(self
, name
):
49 return self
.properties
.has_key(name
)
51 def getProperty(self
, name
, default
=None):
52 """Get the value for the given property."""
53 return self
.properties
.get(name
, (default
,))[0]
55 def getPropertySource(self
, name
):
56 return self
.properties
[name
][1]
59 """Return the properties as a sorted list of (name, value, source)"""
60 l
= [ (k
, v
[0], v
[1]) for k
,v
in self
.properties
.items() ]
65 return repr(dict([ (k
,v
[0]) for k
,v
in self
.properties
.iteritems() ]))
67 def setProperty(self
, name
, value
, source
):
68 self
.properties
[name
] = (value
, source
)
70 def update(self
, dict, source
):
71 """Update this object from a dictionary, with an explicit source specified."""
72 for k
, v
in dict.items():
73 self
.properties
[k
] = (v
, source
)
75 def updateFromProperties(self
, other
):
76 """Update this object based on another object; the other object's """
77 self
.properties
.update(other
.properties
)
79 def render(self
, value
):
81 Return a variant of value that has any WithProperties objects
82 substituted. This recurses into Python's compound data types.
84 # we use isinstance to detect Python's standard data types, and call
85 # this function recursively for the values in those types
86 if isinstance(value
, (str, unicode)):
88 elif isinstance(value
, WithProperties
):
89 return value
.render(self
.pmap
)
90 elif isinstance(value
, list):
91 return [ self
.render(e
) for e
in value
]
92 elif isinstance(value
, tuple):
93 return tuple([ self
.render(e
) for e
in value
])
94 elif isinstance(value
, dict):
95 return dict([ (self
.render(k
), self
.render(v
)) for k
,v
in value
.iteritems() ])
101 Privately-used mapping object to implement WithProperties' substitutions,
102 including the rendering of None as ''.
104 colon_minus_re
= re
.compile(r
"(.*):-(.*)")
105 colon_plus_re
= re
.compile(r
"(.*):\+(.*)")
106 def __init__(self
, properties
):
107 # use weakref here to avoid a reference loop
108 self
.properties
= weakref
.ref(properties
)
110 def __getitem__(self
, key
):
111 properties
= self
.properties()
112 assert properties
is not None
115 # if prop exists, use it; otherwise, use repl
116 mo
= self
.colon_minus_re
.match(key
)
118 prop
, repl
= mo
.group(1,2)
119 if properties
.has_key(prop
):
120 rv
= properties
[prop
]
125 # if prop exists, use repl; otherwise, an empty string
126 mo
= self
.colon_plus_re
.match(key
)
128 prop
, repl
= mo
.group(1,2)
129 if properties
.has_key(prop
):
136 # translate 'None' to an empty string
137 if rv
is None: rv
= ''
140 class WithProperties(util
.ComparableMixin
):
142 This is a marker class, used fairly widely to indicate that we
143 want to interpolate build properties.
146 compare_attrs
= ('fmtstring', 'args')
148 def __init__(self
, fmtstring
, *args
):
149 self
.fmtstring
= fmtstring
152 def render(self
, pmap
):
155 for name
in self
.args
:
156 strings
.append(pmap
[name
])
157 s
= self
.fmtstring
% tuple(strings
)
159 s
= self
.fmtstring
% pmap