>From 9822676b7f00cc7e78d42c50c2506a289ed9c1c6 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 20 Dec 2016 17:59:18 +0100
Subject: [PATCH] Refactored pki_copytree().

The pki_copytree() has been moved from pkihelper.py into
pki/util.py such that it can be reused in non-deployment
scenarios.
---
 base/common/python/pki/util.py                     | 76 ++++++++++++++++++++
 .../python/pki/server/deployment/pkihelper.py      | 80 +---------------------
 2 files changed, 78 insertions(+), 78 deletions(-)

diff --git a/base/common/python/pki/util.py b/base/common/python/pki/util.py
index 95a36705535f5bde76a35f398c837b541a1fb553..8a75ff6f500f86aa0e442577e48daf6913251d75 100644
--- a/base/common/python/pki/util.py
+++ b/base/common/python/pki/util.py
@@ -26,6 +26,11 @@ Module containing utility functions and classes for the Dogtag python code
 from __future__ import absolute_import
 import os
 import shutil
+from shutil import Error
+try:
+    from shutil import WindowsError  # pylint: disable=E0611
+except ImportError:
+    WindowsError = None
 
 
 def copy(source, dest):
@@ -136,3 +141,74 @@ def customize_file(input_file, output_file, params):
             for src, target in params.items():
                 line = line.replace(src, target)
             outfile.write(line)
+
+
+def copytree(src, dst, symlinks=False, ignore=None):
+    """
+    Recursively copy a directory tree using copy2().
+
+    PATCH:  This code was copied from 'shutil.py' and patched to
+            allow 'The destination directory to already exist.'
+
+    If exception(s) occur, an Error is raised with a list of reasons.
+
+    If the optional symlinks flag is true, symbolic links in the
+    source tree result in symbolic links in the destination tree; if
+    it is false, the contents of the files pointed to by symbolic
+    links are copied.
+
+    The optional ignore argument is a callable. If given, it
+    is called with the `src` parameter, which is the directory
+    being visited by copytree(), and `names` which is the list of
+    `src` contents, as returned by os.listdir():
+
+        callable(src, names) -> ignored_names
+
+    Since copytree() is called recursively, the callable will be
+    called once for each directory that is copied. It returns a
+    list of names relative to the `src` directory that should
+    not be copied.
+
+    Consider this example code rather than the ultimate tool.
+    """
+    names = os.listdir(src)
+    if ignore is not None:
+        ignored_names = ignore(src, names)
+    else:
+        ignored_names = set()
+
+    # PATCH:  ONLY execute 'os.makedirs(dst)' if the top-level
+    #         destination directory does NOT exist!
+    if not os.path.exists(dst):
+        os.makedirs(dst)
+    errors = []
+    for name in names:
+        if name in ignored_names:
+            continue
+        srcname = os.path.join(src, name)
+        dstname = os.path.join(dst, name)
+        try:
+            if symlinks and os.path.islink(srcname):
+                linkto = os.readlink(srcname)
+                os.symlink(linkto, dstname)
+            elif os.path.isdir(srcname):
+                copytree(srcname, dstname, symlinks, ignore)
+            else:
+                # Will raise a SpecialFileError for unsupported file types
+                shutil.copy2(srcname, dstname)
+        # catch the Error from the recursive copytree so that we can
+        # continue with other files
+        except Error as err:
+            errors.extend(err.args[0])
+        except EnvironmentError as why:
+            errors.append((srcname, dstname, str(why)))
+    try:
+        shutil.copystat(src, dst)
+    except OSError as why:
+        if WindowsError is not None and isinstance(why, WindowsError):
+            # Copying file access times may fail on Windows
+            pass
+        else:
+            errors.extend((src, dst, str(why)))
+    if errors:
+        raise Error(errors)
diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py
index 7ca6519c93be71908905bc8294b41d8709241922..1a09f4964e98be8010510cefadcd4be8327a1de7 100644
--- a/base/server/python/pki/server/deployment/pkihelper.py
+++ b/base/server/python/pki/server/deployment/pkihelper.py
@@ -28,11 +28,6 @@ import fileinput
 import re
 import requests.exceptions
 import shutil
-from shutil import Error
-try:
-    from shutil import WindowsError  # pylint: disable=E0611
-except ImportError:
-    WindowsError = None
 import subprocess
 import time
 from datetime import datetime
@@ -52,6 +47,7 @@ from . import pkimessages as log
 from .pkiparser import PKIConfigParser
 import pki.client
 import pki.system
+import pki.util
 
 # special care for SELinux
 import selinux
@@ -66,78 +62,6 @@ if selinux.is_selinux_enabled():
             raise
 
 
-# PKI Deployment Helper Functions
-def pki_copytree(src, dst, symlinks=False, ignore=None):
-    """Recursively copy a directory tree using copy2().
-
-    PATCH:  This code was copied from 'shutil.py' and patched to
-            allow 'The destination directory to already exist.'
-
-    If exception(s) occur, an Error is raised with a list of reasons.
-
-    If the optional symlinks flag is true, symbolic links in the
-    source tree result in symbolic links in the destination tree; if
-    it is false, the contents of the files pointed to by symbolic
-    links are copied.
-
-    The optional ignore argument is a callable. If given, it
-    is called with the `src` parameter, which is the directory
-    being visited by pki_copytree(), and `names` which is the list of
-    `src` contents, as returned by os.listdir():
-
-        callable(src, names) -> ignored_names
-
-    Since pki_copytree() is called recursively, the callable will be
-    called once for each directory that is copied. It returns a
-    list of names relative to the `src` directory that should
-    not be copied.
-
-    *** Consider this example code rather than the ultimate tool.
-
-    """
-    names = os.listdir(src)
-    if ignore is not None:
-        ignored_names = ignore(src, names)
-    else:
-        ignored_names = set()
-
-    # PATCH:  ONLY execute 'os.makedirs(dst)' if the top-level
-    #         destination directory does NOT exist!
-    if not os.path.exists(dst):
-        os.makedirs(dst)
-    errors = []
-    for name in names:
-        if name in ignored_names:
-            continue
-        srcname = os.path.join(src, name)
-        dstname = os.path.join(dst, name)
-        try:
-            if symlinks and os.path.islink(srcname):
-                linkto = os.readlink(srcname)
-                os.symlink(linkto, dstname)
-            elif os.path.isdir(srcname):
-                pki_copytree(srcname, dstname, symlinks, ignore)
-            else:
-                # Will raise a SpecialFileError for unsupported file types
-                shutil.copy2(srcname, dstname)
-        # catch the Error from the recursive pki_copytree so that we can
-        # continue with other files
-        except Error as err:
-            errors.extend(err.args[0])
-        except EnvironmentError as why:
-            errors.append((srcname, dstname, str(why)))
-    try:
-        shutil.copystat(src, dst)
-    except OSError as why:
-        if WindowsError is not None and isinstance(why, WindowsError):
-            # Copying file access times may fail on Windows
-            pass
-        else:
-            errors.extend((src, dst, str(why)))
-    if errors:
-        raise Error(errors)
-
-
 class Identity:
     """PKI Deployment Identity Class"""
 
@@ -1481,7 +1405,7 @@ class Directory:
                     # implementation's unchecked call to 'os.makedirs(dst)'.
                     # Consequently, a 'patched' local copy of this routine has
                     # been included in this file with the appropriate fix.
-                    pki_copytree(old_name, new_name, ignore=ignore_cb)
+                    pki.util.copytree(old_name, new_name, ignore=ignore_cb)
                 else:
                     # cp -p <old_name> <new_name>
                     config.pki_log.info(log.PKIHELPER_CP_P_2,
-- 
2.5.5

