diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py index 4c5c269955a..4cb6ddd3fa3 100644 --- a/release/scripts/startup/bl_operators/userpref.py +++ b/release/scripts/startup/bl_operators/userpref.py @@ -49,6 +49,44 @@ def module_filesystem_remove(path_base, module_name): else: os.remove(f_full) +# This duplicates shutil.copytree from Python 3.8, with the new dirs_exist_ok +# argument that we need. Once we upgrade to 3.8 we can remove this. +def _preferences_copytree(entries, src, dst): + import shutil + import os + os.makedirs(dst, exist_ok=True) + errors = [] + + for srcentry in entries: + srcname = os.path.join(src, srcentry.name) + dstname = os.path.join(dst, srcentry.name) + srcobj = srcentry + try: + if srcentry.is_symlink(): + linkto = os.readlink(srcname) + os.symlink(linkto, dstname) + shutil.copystat(srcobj, dstname, follow_symlinks=False) + elif srcentry.is_dir(): + preferences_copytree(srcobj, dstname) + else: + shutil.copy2(srcentry, dstname) + except Error as err: + errors.extend(err.args[0]) + except OSError as why: + errors.append((srcname, dstname, str(why))) + try: + shutil.copystat(src, dst) + except OSError as why: + if getattr(why, 'winerror', None) is None: + errors.append((src, dst, str(why))) + if errors: + raise Error(errors) + return dst + +def preferences_copytree(src, dst): + import os + with os.scandir(src) as entries: + return _preferences_copytree(entries=entries, src=src, dst=dst) class PREFERENCES_OT_keyconfig_activate(Operator): bl_idname = "preferences.keyconfig_activate" @@ -110,9 +148,10 @@ class PREFERENCES_OT_copy_prev(Operator): return os.path.isfile(old_userpref) and not os.path.isfile(new_userpref) def execute(self, _context): - import shutil - - shutil.copytree(self._old_path(), self._new_path(), symlinks=True) + # Use this instead once we upgrade to Python 3.8 with dirs_exist_ok. + # import shutil + # shutil.copytree(self._old_path(), self._new_path(), dirs_exist_ok=True) + preferences_copytree(self._old_path(), self._new_path()) # reload preferences and recent-files.txt bpy.ops.wm.read_userpref()