From 741d22bbe0bdd5aaa72c9cec8810622de3188984 Mon Sep 17 00:00:00 2001 From: Sriram Madapusi Vasudevan <3770774+sriram-mv@users.noreply.github.com> Date: Fri, 3 Jan 2020 12:43:31 -0800 Subject: [PATCH] fix: change permissions and remove files on rmtree (#1694) * fix: change permissions and remove files on rmtree * fix: add `onerror` rmtreecallback docstring --- samcli/commands/init/init_templates.py | 3 ++- samcli/lib/utils/osutils.py | 29 +++++++++++++++++--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/samcli/commands/init/init_templates.py b/samcli/commands/init/init_templates.py index eda51bc07a..27598e9c8d 100644 --- a/samcli/commands/init/init_templates.py +++ b/samcli/commands/init/init_templates.py @@ -17,6 +17,7 @@ from samcli.cli.main import global_cfg from samcli.commands.exceptions import UserException, AppTemplateUpdateException from samcli.lib.utils import osutils +from samcli.lib.utils.osutils import rmtree_callback from samcli.local.common.runtime_template import RUNTIME_DEP_TEMPLATE_MAPPING LOG = logging.getLogger(__name__) @@ -164,7 +165,7 @@ def _overwrite_existing_templates(self, shared_dir, expected_path): def _replace_app_templates(self, temp_path, dest_path): try: LOG.debug("Removing old templates from %s", str(dest_path)) - shutil.rmtree(dest_path) + shutil.rmtree(dest_path, onerror=rmtree_callback) LOG.debug("Copying templates from %s to %s", str(temp_path), str(dest_path)) shutil.copytree(temp_path, dest_path, ignore=shutil.ignore_patterns("*.git")) except (OSError, shutil.Error): diff --git a/samcli/lib/utils/osutils.py b/samcli/lib/utils/osutils.py index 74f2f98d70..e7aa765542 100644 --- a/samcli/lib/utils/osutils.py +++ b/samcli/lib/utils/osutils.py @@ -1,17 +1,14 @@ """ Common OS utilities """ - -import sys +import logging import os import shutil +import stat +import sys import tempfile -import logging -import contextlib - from contextlib import contextmanager - LOG = logging.getLogger(__name__) @@ -47,13 +44,25 @@ def mkdir_temp(mode=0o755, ignore_errors=False): finally: if temp_dir: if ignore_errors: - shutil.rmtree(temp_dir, False, _rmtree_callback) + shutil.rmtree(temp_dir, False, rmtree_callback) else: shutil.rmtree(temp_dir) -def _rmtree_callback(function, path, excinfo): - LOG.debug("rmtree failed in %s for %s, details: %s", function, path, excinfo) +def rmtree_callback(function, path, excinfo): + """ + Callback function for shutil.rmtree to change permissions on the file path, so that + it's delete-able incase the file path is read-only. + :param function: platform and implementation dependent function. + :param path: argument to the function that caused it to fail. + :param excinfo: tuple returned by sys.exc_info() + :return: + """ + try: + os.chmod(path=path, mode=stat.S_IWRITE) + os.remove(path) + except OSError: + LOG.debug("rmtree failed in %s for %s, details: %s", function, path, excinfo) def stdout(): @@ -88,7 +97,7 @@ def remove(path): pass -@contextlib.contextmanager +@contextmanager def tempfile_platform_independent(): # NOTE(TheSriram): Setting delete=False is specific to windows. # https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile