Repository: mesonbuild/meson

Issue:
configure_file() should use line endings of input file for the output file
It currently seems to default to Windows line endings on Windows even if the input file has Unix line endings.

This normally wouldn't be a problem I guess, but gcc has a bug with Windows line endings on Windows which breaks parsing with gobject-introspection: https://gitlab.gnome.org/GNOME/gobject-introspection/issues/243


Discussion:

Resolving patch:
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -729,7 +729,7 @@ def do_mesondefine(line, confdata):
 
 def do_conf_file(src, dst, confdata, format, encoding='utf-8'):
     try:
-        with open(src, encoding=encoding) as f:
+        with open(src, encoding=encoding, newline='') as f:
             data = f.readlines()
     except Exception as e:
         raise MesonException('Could not read input file %s: %s' % (src, str(e)))
@@ -763,7 +763,7 @@ def do_conf_file(src, dst, confdata, format, encoding='utf-8'):
         result.append(line)
     dst_tmp = dst + '~'
     try:
-        with open(dst_tmp, 'w', encoding=encoding) as f:
+        with open(dst_tmp, 'w', encoding=encoding, newline='') as f:
             f.writelines(result)
     except Exception as e:
         raise MesonException('Could not write output file %s: %s' % (dst, str(e)))
diff --git a/run_unittests.py b/run_unittests.py
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -30,6 +30,7 @@
 from itertools import chain
 from unittest import mock
 from configparser import ConfigParser
+from contextlib import contextmanager
 from glob import glob
 from pathlib import (PurePath, Path)
 
@@ -192,6 +193,24 @@ def wrapped(*args, **kwargs):
     return actual
 
 
+@contextmanager
+def temp_filename():
+    '''A context manager which provides a filename to an empty temporary file.
+
+    On exit the file will be deleted.
+    '''
+
+    fd, filename = tempfile.mkstemp()
+    os.close(fd)
+    try:
+        yield filename
+    finally:
+        try:
+            os.remove(filename)
+        except OSError:
+            pass
+
+
 class PatchModule:
     '''
     Fancy monkey-patching! Whee! Can't use mock.patch because it only
@@ -1296,6 +1315,21 @@ def test_default_options_prefix(self):
                 prefix = opt['value']
         self.assertEqual(prefix, '/absoluteprefix')
 
+    def test_do_conf_file_preserve_newlines(self):
+
+        def conf_file(in_data, confdata):
+            with temp_filename() as fin:
+                with open(fin, 'wb') as fobj:
+                    fobj.write(in_data.encode('utf-8'))
+                with temp_filename() as fout:
+                    mesonbuild.mesonlib.do_conf_file(fin, fout, confdata, 'meson')
+                    with open(fout, 'rb') as fobj:
+                        return fobj.read().decode('utf-8')
+
+        confdata = {'VAR': ('foo', 'bar')}
+        self.assertEqual(conf_file('@VAR@\n@VAR@\n', confdata), 'foo\nfoo\n')
+        self.assertEqual(conf_file('@VAR@\r\n@VAR@\r\n', confdata), 'foo\r\nfoo\r\n')
+
     def test_absolute_prefix_libdir(self):
         '''
         Tests that setting absolute paths for --prefix and --libdir work. Can't


Test patch: