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:
Kumar Gala 2020-10-17 11:46:03 -05:00 committed by Kumar Gala
parent b1503ac66c
commit 33db7b5b01
5 changed files with 63 additions and 12 deletions

View file

@ -87,6 +87,7 @@ on-bus: <string describing bus type, e.g. "i2c">
# A typical property entry looks like this:
#
# <property name>:
# deprecated: <true | false>
# required: <true | false>
# type: <string | int | boolean | array | uint8-array | string-array |
# 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'.
# 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
# besides those used in the examples will raise an error.
properties:

View file

@ -886,7 +886,7 @@ class Node:
for name in node.props:
if name in _DEFAULT_PROP_TYPES:
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.node = self
prop.name = name
@ -906,8 +906,8 @@ class Node:
if not prop_type:
_err("'{}' in {} lacks 'type'".format(name, self.binding_path))
val = self._prop_val(name, prop_type, prop_spec.required,
prop_spec.default)
val = self._prop_val(name, prop_type, prop_spec.deprecated,
prop_spec.required, prop_spec.default)
if val is None:
# 'required: false' property that wasn't there, or a property type
@ -945,7 +945,7 @@ class Node:
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
#
# name:
@ -954,6 +954,9 @@ class Node:
# prop_type:
# Property type from binding (a string like "int")
#
# deprecated:
# True if the property is deprecated
#
# required:
# True if the property is required to exist
#
@ -964,6 +967,10 @@ class Node:
node = self._node
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 required and self.status == "okay":
_err("'{}' is marked as required in 'properties:' in {}, but "
@ -1648,7 +1655,7 @@ class Binding:
return
ok_prop_keys = {"description", "type", "required",
"enum", "const", "default"}
"enum", "const", "default", "deprecated"}
for prop_name, options in raw["properties"].items():
for key in options:
@ -1662,12 +1669,17 @@ class Binding:
options.get("default"),
self.path)
if "required" in options:
required = options["required"]
if not isinstance(required, bool):
_err(f"malformed 'required:' setting '{required}' "
f"for '{prop_name}' in 'properties' in {self.path}, "
"expected true/false")
for true_false_opt in ["required", "deprecated"]:
if true_false_opt in options:
option = options[true_false_opt]
if not isinstance(option, bool):
_err(f"malformed '{true_false_opt}:' setting '{option}' "
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 \
not isinstance(options["description"], str):
@ -1722,6 +1734,9 @@ class PropertySpec:
default:
The property's default value as given in the binding, or None.
deprecated:
True if the property is deprecated; False otherwise.
required:
True if the property is marked required; False otherwise.
"""
@ -1769,6 +1784,10 @@ class PropertySpec:
"See the class docstring"
return self._raw.get("required", False)
@property
def deprecated(self):
"See the class docstring"
return self._raw.get("deprecated", False)
class EDTError(Exception):
"Exception raised for devicetree- and binding-related errors"

View 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

View file

@ -386,6 +386,16 @@
};
};
//
// For testing deprecated property
//
test-deprecated {
compatible = "test-deprecated";
oldprop = <4>; /* deprecated property */
curprop = <5>;
};
//
// For testing deprecated features
//

View file

@ -30,7 +30,8 @@ def test_warnings():
warnings = io.StringIO()
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' (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