diff options
| author | Eli Schwartz <eschwartz93@gmail.com> | 2024-07-05 13:52:40 -0400 |
|---|---|---|
| committer | Eli Schwartz <eschwartz93@gmail.com> | 2024-07-05 13:52:40 -0400 |
| commit | f2112d0baa379e01d7ce8a961005f5b7c102d9a9 (patch) | |
| tree | dd3ab36af18e2c78a756bcf81be15a780ed2cb6c | |
| parent | 1ca002a78a48faaf74aa61fcd28b4f2fa5937b47 (diff) | |
| download | meson-f2112d0baa379e01d7ce8a961005f5b7c102d9a9.tar.gz | |
Revert "Clarify mutable objects usage"
This reverts commit 9f02d0a3e5a5ffc82256391c244b1af38e41ef78.
It turns out that this does introduce a behavioral change in existing
users of ConfigurationData, which it wasn't supposed to (it was supposed
to preserve behavior there, and add a new *warning* for
EnvironmentVariables).
This breaks projects such as pulseaudio, libvirt, and probably more.
Roll back the change and try again after 1.5.0 is released.
Fixes: #13372
| -rw-r--r-- | docs/markdown/Configuration.md | 2 | ||||
| -rw-r--r-- | docs/yaml/objects/cfg_data.yaml | 12 | ||||
| -rw-r--r-- | docs/yaml/objects/env.yaml | 13 | ||||
| -rw-r--r-- | mesonbuild/interpreter/interpreterobjects.py | 26 | ||||
| -rw-r--r-- | mesonbuild/interpreterbase/_unholder.py | 4 | ||||
| -rw-r--r-- | mesonbuild/interpreterbase/baseobjects.py | 21 | ||||
| -rwxr-xr-x | test cases/common/113 interpreter copy mutable var on assignment/check_env.py | 7 | ||||
| -rw-r--r-- | test cases/common/113 interpreter copy mutable var on assignment/meson.build | 34 | ||||
| -rw-r--r-- | test cases/failing/70 configuration immutable/input | 0 | ||||
| -rw-r--r-- | test cases/failing/70 configuration immutable/meson.build | 12 | ||||
| -rw-r--r-- | test cases/failing/70 configuration immutable/test.json | 7 |
11 files changed, 36 insertions, 102 deletions
diff --git a/docs/markdown/Configuration.md b/docs/markdown/Configuration.md index b5875e55e..48f071e6c 100644 --- a/docs/markdown/Configuration.md +++ b/docs/markdown/Configuration.md @@ -39,7 +39,7 @@ use a single `configuration_data` object as many times as you like, but it becomes immutable after being passed to the `configure_file` function. That is, after it has been used once to generate output the `set` function becomes unusable and trying to call it causes an error. -*Since 1.5.0* Copy of immutable `configuration_data` is however mutable. +Copy of immutable `configuration_data` is still immutable. For more complex configuration file generation Meson provides a second form. To use it, put a line like this in your configuration file. diff --git a/docs/yaml/objects/cfg_data.yaml b/docs/yaml/objects/cfg_data.yaml index 069cadbf6..03abb1709 100644 --- a/docs/yaml/objects/cfg_data.yaml +++ b/docs/yaml/objects/cfg_data.yaml @@ -1,14 +1,10 @@ name: cfg_data long_name: Configuration data object description: | - This object encapsulates configuration values to be used for generating - configuration files. A more in-depth description can be found in the - [the configuration page](Configuration.md). - - This object becomes immutable after first use. This means that - calling set() or merge_from() will cause an error if this object has - already been used in any function arguments. However, assignment creates a - mutable copy. + This object encapsulates + configuration values to be used for generating configuration files. A + more in-depth description can be found in the [the configuration wiki + page](Configuration.md). methods: - name: set diff --git a/docs/yaml/objects/env.yaml b/docs/yaml/objects/env.yaml index 3b2e2a851..714da4fe4 100644 --- a/docs/yaml/objects/env.yaml +++ b/docs/yaml/objects/env.yaml @@ -9,11 +9,6 @@ description: | on the same `varname`. Earlier Meson versions would warn and only the last operation took effect. - *Since 1.5.0* This object becomes immutable after first use. This means that - calling append(), prepend() or set() will cause a deprecation warning if this - object has already been used in any function arguments. However, assignment - creates a mutable copy. - example: | ```meson env = environment() @@ -23,14 +18,6 @@ example: | env.append('MY_PATH', '2') env.append('MY_PATH', '3') env.prepend('MY_PATH', '0') - - # Deprecated since 1.5.0 - run_command('script.py', env: env) - env.append('MY_PATH', '4') - - # Allowed and only env2 is modified - env2 = env - env2.append('MY_PATH', '4') ``` methods: diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 32f05bafb..d5c1efaa8 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -284,7 +284,6 @@ class EnvironmentVariablesHolder(ObjectHolder[mesonlib.EnvironmentVariables], Mu def __init__(self, obj: mesonlib.EnvironmentVariables, interpreter: 'Interpreter'): super().__init__(obj, interpreter) - MutableInterpreterObject.__init__(self) self.methods.update({'set': self.set_method, 'unset': self.unset_method, 'append': self.append_method, @@ -309,14 +308,12 @@ class EnvironmentVariablesHolder(ObjectHolder[mesonlib.EnvironmentVariables], Mu @typed_kwargs('environment.set', ENV_SEPARATOR_KW) def set_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None: name, values = args - self.check_used(self.interpreter, fatal=False) self.held_object.set(name, values, kwargs['separator']) @FeatureNew('environment.unset', '1.4.0') @typed_pos_args('environment.unset', str) @noKwargs def unset_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> None: - self.check_used(self.interpreter, fatal=False) self.held_object.unset(args[0]) @typed_pos_args('environment.append', str, varargs=str, min_varargs=1) @@ -324,7 +321,6 @@ class EnvironmentVariablesHolder(ObjectHolder[mesonlib.EnvironmentVariables], Mu def append_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None: name, values = args self.warn_if_has_name(name) - self.check_used(self.interpreter, fatal=False) self.held_object.append(name, values, kwargs['separator']) @typed_pos_args('environment.prepend', str, varargs=str, min_varargs=1) @@ -332,7 +328,6 @@ class EnvironmentVariablesHolder(ObjectHolder[mesonlib.EnvironmentVariables], Mu def prepend_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None: name, values = args self.warn_if_has_name(name) - self.check_used(self.interpreter, fatal=False) self.held_object.prepend(name, values, kwargs['separator']) @@ -343,7 +338,6 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte def __init__(self, obj: build.ConfigurationData, interpreter: 'Interpreter'): super().__init__(obj, interpreter) - MutableInterpreterObject.__init__(self) self.methods.update({'set': self.set_method, 'set10': self.set10_method, 'set_quoted': self.set_quoted_method, @@ -355,31 +349,32 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte }) def __deepcopy__(self, memo: T.Dict) -> 'ConfigurationDataHolder': - obj = ConfigurationDataHolder(copy.deepcopy(self.held_object), self.interpreter) + return ConfigurationDataHolder(copy.deepcopy(self.held_object), self.interpreter) + + def is_used(self) -> bool: + return self.held_object.used + + def __check_used(self) -> None: if self.is_used(): - # Copies of used ConfigurationData used to be immutable. It is now - # allowed but we need this flag to print a FeatureNew warning if - # that happens. - obj.mutable_feature_new = True - return obj + raise InterpreterException("Can not set values on configuration object that has been used.") @typed_pos_args('configuration_data.set', str, (str, int, bool)) @typed_kwargs('configuration_data.set', _CONF_DATA_SET_KWS) def set_method(self, args: T.Tuple[str, T.Union[str, int, bool]], kwargs: 'kwargs.ConfigurationDataSet') -> None: - self.check_used(self.interpreter) + self.__check_used() self.held_object.values[args[0]] = (args[1], kwargs['description']) @typed_pos_args('configuration_data.set_quoted', str, str) @typed_kwargs('configuration_data.set_quoted', _CONF_DATA_SET_KWS) def set_quoted_method(self, args: T.Tuple[str, str], kwargs: 'kwargs.ConfigurationDataSet') -> None: - self.check_used(self.interpreter) + self.__check_used() escaped_val = '\\"'.join(args[1].split('"')) self.held_object.values[args[0]] = (f'"{escaped_val}"', kwargs['description']) @typed_pos_args('configuration_data.set10', str, (int, bool)) @typed_kwargs('configuration_data.set10', _CONF_DATA_SET_KWS) def set10_method(self, args: T.Tuple[str, T.Union[int, bool]], kwargs: 'kwargs.ConfigurationDataSet') -> None: - self.check_used(self.interpreter) + self.__check_used() # bool is a subclass of int, so we need to check for bool explicitly. # We already have typed_pos_args checking that this is either a bool or # an int. @@ -442,7 +437,6 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte @noKwargs def merge_from_method(self, args: T.Tuple[build.ConfigurationData], kwargs: TYPE_kwargs) -> None: from_object = args[0] - self.check_used(self.interpreter) self.held_object.values.update(from_object.values) diff --git a/mesonbuild/interpreterbase/_unholder.py b/mesonbuild/interpreterbase/_unholder.py index e32b77fc7..c62aafe8e 100644 --- a/mesonbuild/interpreterbase/_unholder.py +++ b/mesonbuild/interpreterbase/_unholder.py @@ -5,7 +5,7 @@ from __future__ import annotations import typing as T -from .baseobjects import InterpreterObject, MesonInterpreterObject, ObjectHolder, HoldableTypes, MutableInterpreterObject +from .baseobjects import InterpreterObject, MesonInterpreterObject, ObjectHolder, HoldableTypes from .exceptions import InvalidArguments from ..mesonlib import HoldableObject, MesonBugException @@ -13,8 +13,6 @@ if T.TYPE_CHECKING: from .baseobjects import TYPE_var def _unholder(obj: InterpreterObject) -> TYPE_var: - if isinstance(obj, MutableInterpreterObject): - obj.mark_used() if isinstance(obj, ObjectHolder): assert isinstance(obj.held_object, HoldableTypes) return obj.held_object diff --git a/mesonbuild/interpreterbase/baseobjects.py b/mesonbuild/interpreterbase/baseobjects.py index c6864a478..9a119a98a 100644 --- a/mesonbuild/interpreterbase/baseobjects.py +++ b/mesonbuild/interpreterbase/baseobjects.py @@ -120,27 +120,6 @@ class MesonInterpreterObject(InterpreterObject): class MutableInterpreterObject: ''' Dummy class to mark the object type as mutable ''' - def __init__(self) -> None: - self.used = False - self.mutable_feature_new = False - - def mark_used(self) -> None: - self.used = True - - def is_used(self) -> bool: - return self.used - - def check_used(self, interpreter: Interpreter, fatal: bool = True) -> None: - from .decorators import FeatureDeprecated, FeatureNew - if self.is_used(): - if fatal: - raise InvalidArguments('Can not modify object after it has been used.') - FeatureDeprecated.single_use('Modify object after it has been used', '1.5.0', - interpreter.subproject, location=interpreter.current_node) - elif self.mutable_feature_new: - FeatureNew.single_use('Modify a copy of an immutable object', '1.5.0', - interpreter.subproject, location=interpreter.current_node) - self.mutable_feature_new = False HoldableTypes = (HoldableObject, int, bool, str, list, dict) TYPE_HoldableTypes = T.Union[TYPE_elementary, HoldableObject] diff --git a/test cases/common/113 interpreter copy mutable var on assignment/check_env.py b/test cases/common/113 interpreter copy mutable var on assignment/check_env.py deleted file mode 100755 index 034d29243..000000000 --- a/test cases/common/113 interpreter copy mutable var on assignment/check_env.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys - -if sys.argv[1] not in os.environ: - exit(42) diff --git a/test cases/common/113 interpreter copy mutable var on assignment/meson.build b/test cases/common/113 interpreter copy mutable var on assignment/meson.build index 3d4f3b039..d414bfc74 100644 --- a/test cases/common/113 interpreter copy mutable var on assignment/meson.build +++ b/test cases/common/113 interpreter copy mutable var on assignment/meson.build @@ -1,4 +1,4 @@ -project('foo', meson_version: '>=1.5') +project('foo') a = configuration_data() a.set('HELLO', 1) @@ -10,15 +10,6 @@ assert(b.has('HELLO'), 'Original config data should be set on copy') configure_file(output : 'b.h', configuration : b) -testcase expect_error('Can not modify object after it has been used.') - b.set('WORLD', 1) -endtestcase - -# A copy of immutable object is mutable. This should print FeatureNew warning -# if meson_version is lower than 1.5. -c = b -c.set('WORLD', 1) - # This should still work, as we didn't use the original above but a copy! a.set('WORLD', 1) @@ -26,26 +17,3 @@ assert(a.has('WORLD'), 'New config data should have been set') assert(not b.has('WORLD'), 'New config data set should not affect var copied earlier') configure_file(output : 'a.h', configuration : a) - -env1 = environment() -env1.set('FOO', '1') -env2 = env1 -env1.set('BAR', '1') - -# FOO should be in env1 and env2 -run_command('check_env.py', 'FOO', env: env1, check: true) -run_command('check_env.py', 'FOO', env: env2, check: true) - -# BAR should be only in env1 -run_command('check_env.py', 'BAR', env: env1, check: true) -assert(run_command('check_env.py', 'BAR', env: env2, check: false).returncode() == 42) - -# This should print deprecation warning but still work -env1.set('PLOP', '1') -run_command('check_env.py', 'PLOP', env: env1, check: true) - -# A copy of used env should be mutable and not print warning -env3 = env1 -env3.set('BAZ', '1') -run_command('check_env.py', 'PLOP', env: env3, check: true) -run_command('check_env.py', 'BAZ', env: env3, check: true) diff --git a/test cases/failing/70 configuration immutable/input b/test cases/failing/70 configuration immutable/input new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test cases/failing/70 configuration immutable/input diff --git a/test cases/failing/70 configuration immutable/meson.build b/test cases/failing/70 configuration immutable/meson.build new file mode 100644 index 000000000..b6cac4126 --- /dev/null +++ b/test cases/failing/70 configuration immutable/meson.build @@ -0,0 +1,12 @@ +project('configuration_data is immutable') + +a = configuration_data() + +configure_file( + configuration : a, + input : 'input', + output : 'output', +) + +still_immutable = a +still_immutable.set('hello', 'world') diff --git a/test cases/failing/70 configuration immutable/test.json b/test cases/failing/70 configuration immutable/test.json new file mode 100644 index 000000000..fc735fa38 --- /dev/null +++ b/test cases/failing/70 configuration immutable/test.json @@ -0,0 +1,7 @@ +{ + "stdout": [ + { + "line": "test cases/failing/70 configuration immutable/meson.build:12:16: ERROR: Can not set values on configuration object that has been used." + } + ] +} |
