From 364e2cea4c3dffca12afad51a93524b5834106aa Mon Sep 17 00:00:00 2001 From: Marco Studerus Date: Wed, 13 May 2020 13:54:40 +0200 Subject: [PATCH] Fix: `conan config install` - overwrite read-only files / don't copy file permissions (#7004) * `conan config install` - overwrite read-only files * `conan config install` - shouldn't copy file permission * use `conans.util.files.remove()` to remove file * use `conans.util.files` to make file read only --- conans/client/conf/config_installer.py | 7 +++--- .../functional/command/config_install_test.py | 22 +++++++++++++++++-- conans/util/files.py | 12 ++++++---- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/conans/client/conf/config_installer.py b/conans/client/conf/config_installer.py index 91186cff1b4..c46367afb3f 100644 --- a/conans/client/conf/config_installer.py +++ b/conans/client/conf/config_installer.py @@ -1,6 +1,7 @@ import json import os import shutil +import stat from datetime import datetime from dateutil.tz import gettz @@ -14,7 +15,7 @@ from conans.client.tools import Git from conans.client.tools.files import unzip from conans.errors import ConanException -from conans.util.files import mkdir, rmdir, walk, save, touch +from conans.util.files import mkdir, rmdir, walk, save, touch, remove from conans.client.cache.cache import ClientCache @@ -80,8 +81,8 @@ def _filecopy(src, filename, dst): src = os.path.join(src, filename) dst = os.path.join(dst, filename) if os.path.exists(dst): - os.remove(dst) - shutil.copy(src, dst) + remove(dst) + shutil.copyfile(src, dst) def _process_folder(config, folder, cache, output): diff --git a/conans/test/functional/command/config_install_test.py b/conans/test/functional/command/config_install_test.py index 605a90378b1..b89109ea713 100644 --- a/conans/test/functional/command/config_install_test.py +++ b/conans/test/functional/command/config_install_test.py @@ -16,8 +16,7 @@ from conans.errors import ConanException from conans.test.utils.test_files import temp_folder from conans.test.utils.tools import TestClient, StoppableThreadBottle -from conans.util.files import load, mkdir, save, save_files - +from conans.util.files import load, mkdir, save, save_files, make_file_read_only win_profile = """[settings] os: Windows @@ -528,6 +527,25 @@ def get_zip(): self.assertIn("Unzipping", self.client.out) http_server.stop() + def test_overwrite_read_only_file(self): + source_folder = self._create_profile_folder() + self.client.run('config install "%s"' % source_folder) + # make existing settings.yml read-only + make_file_read_only(self.client.cache.settings_path) + self.assertFalse(os.access(self.client.cache.settings_path, os.W_OK)) + + # config install should overwrite the existing read-only file + self.client.run('config install "%s"' % source_folder) + self.assertTrue(os.access(self.client.cache.settings_path, os.W_OK)) + + def test_dont_copy_file_permissions(self): + source_folder = self._create_profile_folder() + # make source settings.yml read-only + make_file_read_only(os.path.join(source_folder, 'remotes.txt')) + + self.client.run('config install "%s"' % source_folder) + self.assertTrue(os.access(self.client.cache.settings_path, os.W_OK)) + class ConfigInstallSchedTest(unittest.TestCase): diff --git a/conans/util/files.py b/conans/util/files.py index 983ebc4b52e..c6adc0bf029 100644 --- a/conans/util/files.py +++ b/conans/util/files.py @@ -31,12 +31,16 @@ def walk(top, **kwargs): return os.walk(top, **kwargs) -def make_read_only(path): - for root, _, files in walk(path): +def make_read_only(folder_path): + for root, _, files in walk(folder_path): for f in files: full_path = os.path.join(root, f) - mode = os.stat(full_path).st_mode - os.chmod(full_path, mode & ~ stat.S_IWRITE) + make_file_read_only(full_path) + + +def make_file_read_only(file_path): + mode = os.stat(file_path).st_mode + os.chmod(file_path, mode & ~ stat.S_IWRITE) _DIRTY_FOLDER = ".dirty"