aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2020-09-14 11:36:38 -0700
committerJussi Pakkanen <jpakkane@gmail.com>2020-10-05 23:10:35 +0300
commit94ac51fdda0408c6d1f61e7e5e89cebaa9182842 (patch)
tree58fd6d3b44c2cb2b57fb9c8f6dbfb17fe4c36cae
parentc4fa87692547a25f772b3da336147b4eb9114f64 (diff)
downloadmeson-94ac51fdda0408c6d1f61e7e5e89cebaa9182842.zip
meson-94ac51fdda0408c6d1f61e7e5e89cebaa9182842.tar.gz
meson-94ac51fdda0408c6d1f61e7e5e89cebaa9182842.tar.bz2
options: Handle updates to choices in options
Currently if you change the `choices` field in the meson_options.txt file, no update will be done until `meson setup --wipe` is called. Now if the choices change then the options will be properly merged. If the currently select value is still valid it is guaranteed to be kept, if it is now invalid the new default value will be used and a warning will be printed. Fixes #7386
-rw-r--r--mesonbuild/coredata.py20
-rwxr-xr-xrun_unittests.py40
-rw-r--r--test cases/unit/84 change option choices/meson.build1
-rw-r--r--test cases/unit/84 change option choices/meson_options.1.txt13
-rw-r--r--test cases/unit/84 change option choices/meson_options.2.txt13
5 files changed, 82 insertions, 5 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 4be828b..e3b3b01 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -689,14 +689,24 @@ class CoreData:
def get_external_link_args(self, for_machine: MachineChoice, lang):
return self.compiler_options[for_machine][lang]['link_args'].value
- def merge_user_options(self, options: T.Dict[str, T.Union[str, bool, int]]) -> None:
+ def merge_user_options(self, options: T.Dict[str, UserOption[T.Any]]) -> None:
for (name, value) in options.items():
if name not in self.user_options:
self.user_options[name] = value
- else:
- oldval = self.user_options[name]
- if type(oldval) != type(value):
- self.user_options[name] = value
+ continue
+
+ oldval = self.user_options[name]
+ if type(oldval) != type(value):
+ self.user_options[name] = value
+ elif oldval.choices != value.choices:
+ # If the choices have changed, use the new value, but attempt
+ # to keep the old options. If they are not valid keep the new
+ # defaults but warn.
+ self.user_options[name] = value
+ try:
+ value.set_value(oldval.value)
+ except MesonException as e:
+ mlog.warning('Old value(s) of {} are no longer valid, resetting to default ({}).'.format(name, value.value))
def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool:
if when_building_for == MachineChoice.BUILD:
diff --git a/run_unittests.py b/run_unittests.py
index 0385404..881b781 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -3325,6 +3325,46 @@ int main(int argc, char **argv) {
self.setconf("-Dfree_array_opt=['a,b', 'c,d']", will_build=False)
self.opt_has('free_array_opt', ['a,b', 'c,d'])
+ def test_options_with_choices_changing(self) -> None:
+ """Detect when options like arrays or combos have their choices change."""
+ testdir = Path(os.path.join(self.unit_test_dir, '84 change option choices'))
+ options1 = str(testdir / 'meson_options.1.txt')
+ options2 = str(testdir / 'meson_options.2.txt')
+
+ # Test that old options are changed to the new defaults if they are not valid
+ real_options = str(testdir / 'meson_options.txt')
+ self.addCleanup(os.unlink, real_options)
+
+ shutil.copy(options1, real_options)
+ self.init(str(testdir))
+ shutil.copy(options2, real_options)
+
+ self.build()
+ opts = self.introspect('--buildoptions')
+ for item in opts:
+ if item['name'] == 'combo':
+ self.assertEqual(item['value'], 'b')
+ self.assertEqual(item['choices'], ['b', 'c', 'd'])
+ elif item['name'] == 'arr':
+ self.assertEqual(item['value'], ['b'])
+ self.assertEqual(item['choices'], ['b', 'c', 'd'])
+
+ self.wipe()
+
+ # When the old options are valid they should remain
+ shutil.copy(options1, real_options)
+ self.init(str(testdir), extra_args=['-Dcombo=c', '-Darray=b,c'])
+ shutil.copy(options2, real_options)
+ self.build()
+ opts = self.introspect('--buildoptions')
+ for item in opts:
+ if item['name'] == 'combo':
+ self.assertEqual(item['value'], 'c')
+ self.assertEqual(item['choices'], ['b', 'c', 'd'])
+ elif item['name'] == 'arr':
+ self.assertEqual(item['value'], ['b', 'c'])
+ self.assertEqual(item['choices'], ['b', 'c', 'd'])
+
def test_subproject_promotion(self):
testdir = os.path.join(self.unit_test_dir, '12 promote')
workdir = os.path.join(self.builddir, 'work')
diff --git a/test cases/unit/84 change option choices/meson.build b/test cases/unit/84 change option choices/meson.build
new file mode 100644
index 0000000..d056d65
--- /dev/null
+++ b/test cases/unit/84 change option choices/meson.build
@@ -0,0 +1 @@
+project('change option choices')
diff --git a/test cases/unit/84 change option choices/meson_options.1.txt b/test cases/unit/84 change option choices/meson_options.1.txt
new file mode 100644
index 0000000..d0326a5
--- /dev/null
+++ b/test cases/unit/84 change option choices/meson_options.1.txt
@@ -0,0 +1,13 @@
+option(
+ 'combo',
+ type : 'combo',
+ choices : ['a', 'b', 'c'],
+ value : 'a',
+)
+
+option(
+ 'array',
+ type : 'array',
+ choices : ['a', 'b', 'c'],
+ value : ['a'],
+)
diff --git a/test cases/unit/84 change option choices/meson_options.2.txt b/test cases/unit/84 change option choices/meson_options.2.txt
new file mode 100644
index 0000000..4684673
--- /dev/null
+++ b/test cases/unit/84 change option choices/meson_options.2.txt
@@ -0,0 +1,13 @@
+option(
+ 'combo',
+ type : 'combo',
+ choices : ['b', 'c', 'd'],
+ value : 'b',
+)
+
+option(
+ 'array',
+ type : 'array',
+ choices : ['b', 'c', 'd'],
+ value : ['b'],
+)