Repository: mesonbuild/meson

Issue:
meson wrongly tries to parse % sign in command line options
Hello all,
I recently a weird situation started to happen where my command line option causes meson to fail.
Specifically when I have an invocation of the type meson -Dmyoption='something with %' I get the following stack trace:

```
Traceback (most recent call last):
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/site-packages/mesonbuild/mesonmain.py", line 112, in run
|     return options.run_func(options)
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/site-packages/mesonbuild/msetup.py", line 232, in run
|     app.generate()
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/site-packages/mesonbuild/msetup.py", line 163, in generate
|     self._generate(env)
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/site-packages/mesonbuild/msetup.py", line 217, in _generate
|     coredata.write_cmd_line_file(self.build_dir, self.options)
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/site-packages/mesonbuild/coredata.py", line 548, in write_cmd_line_file
|     config['options'] = options.cmd_line_options
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/configparser.py", line 971, in __setitem__
|     self.read_dict({key: value})
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/configparser.py", line 753, in read_dict
|     self.set(section, key, value)
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/configparser.py", line 1198, in set
|     super().set(section, option, value)
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/configparser.py", line 893, in set
|     value)
|   File "/opt/builds/tmp/work/armv5e-poky-linux-gnueabi/drotagx/1.0-r0/recipe-sysroot-native/usr/lib/python3.7/configparser.py", line 402, in before_set
|     "position %d" % (value, tmp_value.find('%')))
| ValueError: invalid interpolation syntax in 'socat tcp:192.168.3.123:5760 PTY,link=%s,cfmakeraw,ispeed=b115200,ospeed=b115200' at position 38
```


Discussion:
Just a hint, I was able to fix this by setting in coredata.py. I can submit a patch if this is an acceptable solution.

```
- super().__init__(delimiters=['='])
+ super().__init__(delimiters=['='], interpolation=None)
```
I don't see anything in the `meson setup` docs that specify a need to interpolate the command line. In this type of use case, an alternative would be to use Meson `run_command()`.

I am not immediately thinking of any cases where Meson would need to interpolate this input. It would seem to make `meson setup` more robust even without this specific application.

I would thus be for this patch.

Resolving patch:
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -776,7 +776,7 @@ class CmdLineFileParser(configparser.ConfigParser):
     def __init__(self):
         # We don't want ':' as key delimiter, otherwise it would break when
         # storing subproject options like "subproject:option=value"
-        super().__init__(delimiters=['='])
+        super().__init__(delimiters=['='], interpolation=None)
 
 def get_cmd_line_file(build_dir):
     return os.path.join(build_dir, 'meson-private', 'cmd_line.txt')
diff --git a/run_unittests.py b/run_unittests.py
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -3382,6 +3382,11 @@ def test_command_line(self):
         self.assertEqual(obj.compiler_options.host['c_args'].value, ['foo bar', 'one', 'two'])
         self.wipe()
 
+        self.init(testdir, extra_args=['-Dset_percent_opt=myoption%'])
+        obj = mesonbuild.coredata.load(self.builddir)
+        self.assertEqual(obj.user_options['set_percent_opt'].value, 'myoption%')
+        self.wipe()
+
         # Setting a 2nd time the same option should override the first value
         try:
             self.init(testdir, extra_args=['--bindir=foo', '--bindir=bar',


Test patch:
diff --git a/test cases/unit/34 command line/meson_options.txt b/test cases/unit/34 command line/meson_options.txt
--- a/test cases/unit/34 command line/meson_options.txt	
+++ b/test cases/unit/34 command line/meson_options.txt	
@@ -1 +1,2 @@
 option('set_sub_opt', type : 'boolean', value : false)
+option('set_percent_opt', type : 'string', value: 'not_set')