From b78218adc6f9a88de50ecf9d0cab96ee6287da19 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Fri, 9 Apr 2021 17:47:12 +0200 Subject: [PATCH] Exclude shared directories when creating environments If we try to create a new environment from a shared configuration inside the same repository, we can produce an infinite loop by copying the environment into itself. Ignore any existing environments directory during environment creation. Change-Id: Ic9d3d03192f515a055e41351a0bf25da7a7b0684 Story: 2002009 Task: 40038 --- doc/source/multiple-environments.rst | 5 ++-- kayobe/environment.py | 2 +- kayobe/tests/unit/test_environment.py | 3 ++- kayobe/utils.py | 33 +++++++++++++++++++-------- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/doc/source/multiple-environments.rst b/doc/source/multiple-environments.rst index 6d7b7722a..c0b2d9cbb 100644 --- a/doc/source/multiple-environments.rst +++ b/doc/source/multiple-environments.rst @@ -261,5 +261,6 @@ configurations. (kayobe) $ kayobe environment create --source-config-path ~/kayobe-config-staging/etc/kayobe \ --environment staging -This command recursively copies files and directories under the existing -configuration. Merging shared configuration must be done manually. +This command recursively copies files and directories (except the +``environments`` directory if one exists) under the existing configuration to a +new environment. Merging shared configuration must be done manually. diff --git a/kayobe/environment.py b/kayobe/environment.py index 218fe0f6c..cc0200e20 100644 --- a/kayobe/environment.py +++ b/kayobe/environment.py @@ -61,4 +61,4 @@ def create_kayobe_environment(parsed_args): source_config_path = parsed_args.source_config_path if source_config_path: - utils.copy_dir(source_config_path, env_path) + utils.copy_dir(source_config_path, env_path, exclude=["environments"]) diff --git a/kayobe/tests/unit/test_environment.py b/kayobe/tests/unit/test_environment.py index c03515349..376615b9b 100644 --- a/kayobe/tests/unit/test_environment.py +++ b/kayobe/tests/unit/test_environment.py @@ -80,4 +80,5 @@ class TestCase(unittest.TestCase): ] self.assertEqual(expected_calls, mock_mkdir.call_args_list) mock_copy_dir.assert_called_once_with( - "/path/to/foo", "/path/to/config/environments/foo") + "/path/to/foo", "/path/to/config/environments/foo", + exclude=["environments"]) diff --git a/kayobe/utils.py b/kayobe/utils.py index 389450d61..deaac12c4 100644 --- a/kayobe/utils.py +++ b/kayobe/utils.py @@ -225,14 +225,27 @@ def intersect_limits(args_limit, cli_limit): return separator.join(limits) -def copy_dir(src, dest): +def copy_dir(src, dest, exclude=None): + """Copy recursively a directory. + + :param src: path of the source directory + :param dest: destination path, will be created if it does not exist + :param exclude: names of files or directories at the root of the source + directory to exclude during copy + """ + if exclude is None: + exclude = [] + if not os.path.isdir(dest): - shutil.copytree(src, dest) - else: - for file in os.listdir(src): - src_path = os.path.join(src, file) - dest_path = os.path.join(dest, file) - if os.path.isdir(src_path): - copy_dir(src_path, dest_path) - else: - shutil.copy2(src_path, dest_path) + os.mkdir(dest) + + for file in os.listdir(src): + if file in exclude: + continue + + src_path = os.path.join(src, file) + dest_path = os.path.join(dest, file) + if os.path.isdir(src_path): + copy_dir(src_path, dest_path) + else: + shutil.copy2(src_path, dest_path)