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