3f51ca
From 25a6726a350fd4192b45a78b6312ab8345b02586 Mon Sep 17 00:00:00 2001
3f51ca
From: Fraser Tweedale <ftweedal@redhat.com>
3f51ca
Date: Tue, 5 Dec 2017 13:43:04 +1100
3f51ca
Subject: [PATCH] installutils: refactor set_directive
3f51ca
3f51ca
To separate concerns and make it easier to test set_directive,
3f51ca
extract function ``set_directive_lines`` to do the line-wise
3f51ca
search/replace, leaving ``set_directive`` to deal with the file
3f51ca
handling.
3f51ca
3f51ca
Part of: https://pagure.io/freeipa/issue/7288
3f51ca
3f51ca
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
3f51ca
---
3f51ca
 ipaserver/install/installutils.py | 56 +++++++++++++++++++++++----------------
3f51ca
 1 file changed, 33 insertions(+), 23 deletions(-)
3f51ca
3f51ca
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
3f51ca
index 821609beb533fcc9064500a88ccd07b35142f1df..b56cf591496c679e5fcf3e94f458c286216eb1e4 100644
3f51ca
--- a/ipaserver/install/installutils.py
3f51ca
+++ b/ipaserver/install/installutils.py
3f51ca
@@ -444,34 +444,44 @@ def set_directive(filename, directive, value, quotes=True, separator=' '):
3f51ca
     :param separator: character serving as separator between directive and
3f51ca
         value.  Correct value required even when dropping a directive.
3f51ca
     """
3f51ca
+    st = os.stat(filename)
3f51ca
+    with open(filename, 'r') as f:
3f51ca
+        lines = list(f)  # read the whole file
3f51ca
+        new_lines = set_directive_lines(
3f51ca
+            quotes, separator, directive, value, lines)
3f51ca
+    with open(filename, 'w') as f:
3f51ca
+        # don't construct the whole string; write line-wise
3f51ca
+        for line in new_lines:
3f51ca
+            f.write(line)
3f51ca
+    os.chown(filename, st.st_uid, st.st_gid)  # reset perms
3f51ca
 
3f51ca
-    new_directive_value = ""
3f51ca
-    if value is not None:
3f51ca
-        value_to_set = quote_directive_value(value, '"') if quotes else value
3f51ca
 
3f51ca
-        new_directive_value = "".join(
3f51ca
-            [directive, separator, value_to_set, '\n'])
3f51ca
+def set_directive_lines(quotes, separator, k, v, lines):
3f51ca
+    """Set a name/value pair in a configuration (iterable of lines).
3f51ca
 
3f51ca
-    valueset = False
3f51ca
-    st = os.stat(filename)
3f51ca
-    fd = open(filename)
3f51ca
-    newfile = []
3f51ca
-    for line in fd:
3f51ca
-        if re.match(r'\s*{}'.format(re.escape(directive + separator)), line):
3f51ca
-            valueset = True
3f51ca
-            if value is not None:
3f51ca
-                newfile.append(new_directive_value)
3f51ca
+    Replaces the value of the key if found, otherwise adds it at
3f51ca
+    end.  If value is ``None``, remove the key if found.
3f51ca
+
3f51ca
+    Takes an iterable of lines (with trailing newline).
3f51ca
+    Yields lines (with trailing newline).
3f51ca
+
3f51ca
+    """
3f51ca
+    new_line = ""
3f51ca
+    if v is not None:
3f51ca
+        v_quoted = quote_directive_value(v, '"') if quotes else v
3f51ca
+        new_line = ''.join([k, separator, v_quoted, '\n'])
3f51ca
+
3f51ca
+    found = False
3f51ca
+    for line in lines:
3f51ca
+        if re.match(r'\s*{}'.format(re.escape(k + separator)), line):
3f51ca
+            found = True
3f51ca
+            if v is not None:
3f51ca
+                yield new_line
3f51ca
         else:
3f51ca
-            newfile.append(line)
3f51ca
-    fd.close()
3f51ca
-    if not valueset:
3f51ca
-        if value is not None:
3f51ca
-            newfile.append(new_directive_value)
3f51ca
+            yield line
3f51ca
 
3f51ca
-    fd = open(filename, "w")
3f51ca
-    fd.write("".join(newfile))
3f51ca
-    fd.close()
3f51ca
-    os.chown(filename, st.st_uid, st.st_gid) # reset perms
3f51ca
+    if not found and v is not None:
3f51ca
+        yield new_line
3f51ca
 
3f51ca
 
3f51ca
 def get_directive(filename, directive, separator=' '):
3f51ca
-- 
3f51ca
2.13.6
3f51ca