diff --git a/samcli/lib/init/__init__.py b/samcli/lib/init/__init__.py index 56a948c6b2..089d81f18e 100644 --- a/samcli/lib/init/__init__.py +++ b/samcli/lib/init/__init__.py @@ -3,6 +3,7 @@ """ import itertools import logging +import platform from pathlib import Path @@ -11,6 +12,7 @@ from samcli.local.common.runtime_template import RUNTIME_DEP_TEMPLATE_MAPPING from samcli.lib.utils.packagetype import ZIP +from samcli.lib.utils import osutils from .exceptions import GenerateProjectFailedError, InvalidLocationError from .arbitrary_project import generate_non_cookiecutter_project @@ -90,6 +92,12 @@ def generate_project( try: LOG.debug("Baking a new template with cookiecutter with all parameters") cookiecutter(**params) + # Fixes gradlew line ending issue caused by Windows git + # gradlew is a shell script which should not have CR LF line endings + # Putting the conversion after cookiecutter as cookiecutter processing will also change the line endings + # https://github.com/cookiecutter/cookiecutter/pull/1407 + if platform.system().lower() == "windows": + osutils.convert_files_to_unix_line_endings(output_dir, ["gradlew"]) except RepositoryNotFound as e: # cookiecutter.json is not found in the template. Let's just clone it directly without using cookiecutter # and call it done. diff --git a/samcli/lib/utils/osutils.py b/samcli/lib/utils/osutils.py index bdff5ea3b2..68b6fa02d1 100644 --- a/samcli/lib/utils/osutils.py +++ b/samcli/lib/utils/osutils.py @@ -8,6 +8,7 @@ import sys import tempfile from contextlib import contextmanager +from typing import List, Optional LOG = logging.getLogger(__name__) @@ -154,3 +155,21 @@ def copytree(source, destination, ignore=None): copytree(new_source, new_destination, ignore=ignore) else: shutil.copy2(new_source, new_destination) + + +def convert_files_to_unix_line_endings(path: str, target_files: Optional[List[str]] = None) -> None: + for subdirectory, _, files in os.walk(path): + for file in files: + if target_files is not None and file not in target_files: + continue + + file_path = os.path.join(subdirectory, file) + convert_to_unix_line_ending(file_path) + + +def convert_to_unix_line_ending(file_path: str) -> None: + with open(file_path, "rb") as file: + content = file.read() + content = content.replace(b"\r\n", b"\n") + with open(file_path, "wb") as file: + file.write(content) diff --git a/tests/integration/buildcmd/test_build_cmd.py b/tests/integration/buildcmd/test_build_cmd.py index 712698d7a1..8eab44ed32 100644 --- a/tests/integration/buildcmd/test_build_cmd.py +++ b/tests/integration/buildcmd/test_build_cmd.py @@ -336,8 +336,6 @@ class TestBuildCommand_Java(BuildIntegBase): USING_GRADLEW_PATH = os.path.join("Java", "gradlew") USING_GRADLE_KOTLIN_PATH = os.path.join("Java", "gradle-kotlin") USING_MAVEN_PATH = os.path.join("Java", "maven") - WINDOWS_LINE_ENDING = b"\r\n" - UNIX_LINE_ENDING = b"\n" @parameterized.expand( [ @@ -402,7 +400,7 @@ def _test_with_building_java(self, runtime, code_path, expected_files, use_conta cmdlist = self.get_command_list(use_container=use_container, parameter_overrides=overrides) cmdlist += ["--skip-pull-image"] if code_path == self.USING_GRADLEW_PATH and use_container and IS_WINDOWS: - self._change_to_unix_line_ending(os.path.join(self.test_data_path, self.USING_GRADLEW_PATH, "gradlew")) + osutils.convert_to_unix_line_ending(os.path.join(self.test_data_path, self.USING_GRADLEW_PATH, "gradlew")) LOG.info("Running Command: {}".format(cmdlist)) run_command(cmdlist, cwd=self.working_dir) @@ -465,15 +463,6 @@ def _verify_built_artifact(self, build_dir, function_logical_id, expected_files, lib_dir_contents = set(os.listdir(str(resource_artifact_dir.joinpath("lib")))) self.assertEqual(lib_dir_contents, expected_modules) - def _change_to_unix_line_ending(self, path): - with open(os.path.abspath(path), "rb") as open_file: - content = open_file.read() - - content = content.replace(self.WINDOWS_LINE_ENDING, self.UNIX_LINE_ENDING) - - with open(os.path.abspath(path), "wb") as open_file: - open_file.write(content) - @skipIf( ((IS_WINDOWS and RUNNING_ON_CI) and not CI_OVERRIDE), diff --git a/tests/unit/lib/utils/test_osutils.py b/tests/unit/lib/utils/test_osutils.py index d7633509b0..fbcdb10a81 100644 --- a/tests/unit/lib/utils/test_osutils.py +++ b/tests/unit/lib/utils/test_osutils.py @@ -61,3 +61,19 @@ def test_must_return_sys_stdout(self): expected_stdout = sys.stdout.buffer self.assertEqual(expected_stdout, osutils.stdout()) + + +class Test_convert_files_to_unix_line_endings: + @patch("os.walk") + @patch("builtins.open") + def test_must_return_sys_stdout(self, patched_open, os_walk): + target_file = "target_file" + os_walk.return_value = [ + ("a", "_", ("file_a_1", "file_a_2", target_file)), + ("b", "_", ("file_b_1", target_file)), + ] + osutils.convert_files_to_unix_line_endings("path", [target_file]) + patched_open.assert_any_call(os.path.join("a", target_file), "rb") + patched_open.assert_any_call(os.path.join("b", target_file), "rb") + patched_open.assert_any_call(os.path.join("a", target_file), "wb") + patched_open.assert_any_call(os.path.join("b", target_file), "wb")