scripts: edtlib: Add support for 'deprecated'
Add the ability to mark a property as 'deprecated' to get a warning that it will be removed in the future. Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
This commit is contained in:
parent
b1503ac66c
commit
33db7b5b01
|
@ -87,6 +87,7 @@ on-bus: <string describing bus type, e.g. "i2c">
|
||||||
# A typical property entry looks like this:
|
# A typical property entry looks like this:
|
||||||
#
|
#
|
||||||
# <property name>:
|
# <property name>:
|
||||||
|
# deprecated: <true | false>
|
||||||
# required: <true | false>
|
# required: <true | false>
|
||||||
# type: <string | int | boolean | array | uint8-array | string-array |
|
# type: <string | int | boolean | array | uint8-array | string-array |
|
||||||
# phandle | phandles | phandle-array | path | compound>
|
# phandle | phandles | phandle-array | path | compound>
|
||||||
|
@ -213,6 +214,11 @@ on-bus: <string describing bus type, e.g. "i2c">
|
||||||
# Note that it only makes sense to combine 'default:' with 'required: false'.
|
# Note that it only makes sense to combine 'default:' with 'required: false'.
|
||||||
# Combining it with 'required: true' will raise an error.
|
# Combining it with 'required: true' will raise an error.
|
||||||
#
|
#
|
||||||
|
# A property with 'deprecated: True' indicates to both the user and the tooling
|
||||||
|
# that the property is meant to be phased out. The tooling will report a
|
||||||
|
# warning if the devicetree includes the property that is flagged as deprecated.
|
||||||
|
# There will be no other impact to having 'deprecated: True' set on the property.
|
||||||
|
#
|
||||||
# See below for examples of 'default:'. Putting 'default:' on any property type
|
# See below for examples of 'default:'. Putting 'default:' on any property type
|
||||||
# besides those used in the examples will raise an error.
|
# besides those used in the examples will raise an error.
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -886,7 +886,7 @@ class Node:
|
||||||
for name in node.props:
|
for name in node.props:
|
||||||
if name in _DEFAULT_PROP_TYPES:
|
if name in _DEFAULT_PROP_TYPES:
|
||||||
prop_type = _DEFAULT_PROP_TYPES[name]
|
prop_type = _DEFAULT_PROP_TYPES[name]
|
||||||
val = self._prop_val(name, prop_type, False, None)
|
val = self._prop_val(name, prop_type, False, False, None)
|
||||||
prop = Property()
|
prop = Property()
|
||||||
prop.node = self
|
prop.node = self
|
||||||
prop.name = name
|
prop.name = name
|
||||||
|
@ -906,8 +906,8 @@ class Node:
|
||||||
if not prop_type:
|
if not prop_type:
|
||||||
_err("'{}' in {} lacks 'type'".format(name, self.binding_path))
|
_err("'{}' in {} lacks 'type'".format(name, self.binding_path))
|
||||||
|
|
||||||
val = self._prop_val(name, prop_type, prop_spec.required,
|
val = self._prop_val(name, prop_type, prop_spec.deprecated,
|
||||||
prop_spec.default)
|
prop_spec.required, prop_spec.default)
|
||||||
|
|
||||||
if val is None:
|
if val is None:
|
||||||
# 'required: false' property that wasn't there, or a property type
|
# 'required: false' property that wasn't there, or a property type
|
||||||
|
@ -945,7 +945,7 @@ class Node:
|
||||||
|
|
||||||
self.props[name] = prop
|
self.props[name] = prop
|
||||||
|
|
||||||
def _prop_val(self, name, prop_type, required, default):
|
def _prop_val(self, name, prop_type, deprecated, required, default):
|
||||||
# _init_prop() helper for getting the property's value
|
# _init_prop() helper for getting the property's value
|
||||||
#
|
#
|
||||||
# name:
|
# name:
|
||||||
|
@ -954,6 +954,9 @@ class Node:
|
||||||
# prop_type:
|
# prop_type:
|
||||||
# Property type from binding (a string like "int")
|
# Property type from binding (a string like "int")
|
||||||
#
|
#
|
||||||
|
# deprecated:
|
||||||
|
# True if the property is deprecated
|
||||||
|
#
|
||||||
# required:
|
# required:
|
||||||
# True if the property is required to exist
|
# True if the property is required to exist
|
||||||
#
|
#
|
||||||
|
@ -964,6 +967,10 @@ class Node:
|
||||||
node = self._node
|
node = self._node
|
||||||
prop = node.props.get(name)
|
prop = node.props.get(name)
|
||||||
|
|
||||||
|
if prop and deprecated:
|
||||||
|
self.edt._warn("'{}' is marked as deprecated in 'properties:' in {} "
|
||||||
|
"for node {}.".format(name, self.binding_path, node.path))
|
||||||
|
|
||||||
if not prop:
|
if not prop:
|
||||||
if required and self.status == "okay":
|
if required and self.status == "okay":
|
||||||
_err("'{}' is marked as required in 'properties:' in {}, but "
|
_err("'{}' is marked as required in 'properties:' in {}, but "
|
||||||
|
@ -1648,7 +1655,7 @@ class Binding:
|
||||||
return
|
return
|
||||||
|
|
||||||
ok_prop_keys = {"description", "type", "required",
|
ok_prop_keys = {"description", "type", "required",
|
||||||
"enum", "const", "default"}
|
"enum", "const", "default", "deprecated"}
|
||||||
|
|
||||||
for prop_name, options in raw["properties"].items():
|
for prop_name, options in raw["properties"].items():
|
||||||
for key in options:
|
for key in options:
|
||||||
|
@ -1662,12 +1669,17 @@ class Binding:
|
||||||
options.get("default"),
|
options.get("default"),
|
||||||
self.path)
|
self.path)
|
||||||
|
|
||||||
if "required" in options:
|
for true_false_opt in ["required", "deprecated"]:
|
||||||
required = options["required"]
|
if true_false_opt in options:
|
||||||
if not isinstance(required, bool):
|
option = options[true_false_opt]
|
||||||
_err(f"malformed 'required:' setting '{required}' "
|
if not isinstance(option, bool):
|
||||||
f"for '{prop_name}' in 'properties' in {self.path}, "
|
_err(f"malformed '{true_false_opt}:' setting '{option}' "
|
||||||
"expected true/false")
|
f"for '{prop_name}' in 'properties' in {self.path}, "
|
||||||
|
"expected true/false")
|
||||||
|
|
||||||
|
if options.get("deprecated") and options.get("required"):
|
||||||
|
_err(f"'{prop_name}' in 'properties' in {self.path} should not "
|
||||||
|
"have both 'deprecated' and 'required' set")
|
||||||
|
|
||||||
if "description" in options and \
|
if "description" in options and \
|
||||||
not isinstance(options["description"], str):
|
not isinstance(options["description"], str):
|
||||||
|
@ -1722,6 +1734,9 @@ class PropertySpec:
|
||||||
default:
|
default:
|
||||||
The property's default value as given in the binding, or None.
|
The property's default value as given in the binding, or None.
|
||||||
|
|
||||||
|
deprecated:
|
||||||
|
True if the property is deprecated; False otherwise.
|
||||||
|
|
||||||
required:
|
required:
|
||||||
True if the property is marked required; False otherwise.
|
True if the property is marked required; False otherwise.
|
||||||
"""
|
"""
|
||||||
|
@ -1769,6 +1784,10 @@ class PropertySpec:
|
||||||
"See the class docstring"
|
"See the class docstring"
|
||||||
return self._raw.get("required", False)
|
return self._raw.get("required", False)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def deprecated(self):
|
||||||
|
"See the class docstring"
|
||||||
|
return self._raw.get("deprecated", False)
|
||||||
|
|
||||||
class EDTError(Exception):
|
class EDTError(Exception):
|
||||||
"Exception raised for devicetree- and binding-related errors"
|
"Exception raised for devicetree- and binding-related errors"
|
||||||
|
|
15
scripts/dts/test-bindings/deprecated.yaml
Normal file
15
scripts/dts/test-bindings/deprecated.yaml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
description: Property deprecated value test
|
||||||
|
|
||||||
|
compatible: "test-deprecated"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
oldprop:
|
||||||
|
type: int
|
||||||
|
deprecated: true
|
||||||
|
required: false
|
||||||
|
|
||||||
|
curprop:
|
||||||
|
type: int
|
||||||
|
required: false
|
|
@ -386,6 +386,16 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// For testing deprecated property
|
||||||
|
//
|
||||||
|
test-deprecated {
|
||||||
|
compatible = "test-deprecated";
|
||||||
|
oldprop = <4>; /* deprecated property */
|
||||||
|
curprop = <5>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// For testing deprecated features
|
// For testing deprecated features
|
||||||
//
|
//
|
||||||
|
|
|
@ -30,7 +30,8 @@ def test_warnings():
|
||||||
warnings = io.StringIO()
|
warnings = io.StringIO()
|
||||||
edtlib.EDT("test.dts", ["test-bindings"], warnings)
|
edtlib.EDT("test.dts", ["test-bindings"], warnings)
|
||||||
|
|
||||||
assert warnings.getvalue() == """\
|
assert warnings.getvalue() == f"""\
|
||||||
|
warning: 'oldprop' is marked as deprecated in 'properties:' in {hpath('test-bindings/deprecated.yaml')} for node /test-deprecated.
|
||||||
warning: unit address and first address in 'reg' (0x1) don't match for /reg-zero-size-cells/node
|
warning: unit address and first address in 'reg' (0x1) don't match for /reg-zero-size-cells/node
|
||||||
warning: unit address and first address in 'reg' (0x5) don't match for /reg-ranges/parent/node
|
warning: unit address and first address in 'reg' (0x5) don't match for /reg-ranges/parent/node
|
||||||
warning: unit address and first address in 'reg' (0x30000000200000001) don't match for /reg-nested-ranges/grandparent/parent/node
|
warning: unit address and first address in 'reg' (0x30000000200000001) don't match for /reg-nested-ranges/grandparent/parent/node
|
||||||
|
|
Loading…
Reference in a new issue