Skip to content

Commit 5aab974

Browse files
authored
fix: Symlinks to non-existent directories, symlinks re-creating (#578)
* fix: Symlinks to non-existent directories, symlinks re-creating * Fix test mocking * Add debug logging * Fix wording * Add source path to log
1 parent 9ba72e5 commit 5aab974

File tree

4 files changed

+43
-7
lines changed

4 files changed

+43
-7
lines changed

aws_lambda_builders/actions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,12 @@ def __init__(self, source: Union[str, os.PathLike], dest: Union[str, os.PathLike
156156
self._dest = dest
157157

158158
def execute(self):
159+
source_path = Path(self._source)
159160
destination_path = Path(self._dest)
161+
if not source_path.exists():
162+
# Source path doesn't exist, nothing to symlink
163+
LOG.debug("Source path %s does not exist, skipping generating symlink", source_path)
164+
return
160165
if not destination_path.exists():
161166
os.makedirs(destination_path.parent, exist_ok=True)
162167
utils.create_symlink_or_copy(str(self._source), str(destination_path))

aws_lambda_builders/utils.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ def create_symlink_or_copy(source: str, destination: str) -> None:
198198
"""Tries to create symlink, if it fails it will copy source into destination"""
199199
LOG.debug("Creating symlink; source: %s, destination: %s", source, destination)
200200
try:
201+
if Path(destination).exists() and Path(destination).is_symlink():
202+
# The symlink is already in place, don't try re-creating it
203+
LOG.debug("Symlink between %s and %s already exists, skipping generating symlink", source, destination)
204+
return
201205
os.symlink(Path(source).absolute(), Path(destination).absolute())
202206
except OSError as ex:
203207
LOG.warning(

tests/unit/test_actions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
MoveDependenciesAction,
1313
CleanUpAction,
1414
DependencyManager,
15+
LinkSinglePathAction,
1516
)
1617

1718

@@ -262,3 +263,15 @@ def test_excludes_dependencies_from_source(
262263
@staticmethod
263264
def _convert_strings_to_paths(source_dest_list):
264265
return map(lambda item: (Path(item[0]), Path(item[1])), source_dest_list)
266+
267+
268+
class TestLinkSinglePathAction(TestCase):
269+
@patch("aws_lambda_builders.actions.os.makedirs")
270+
@patch("aws_lambda_builders.utils.create_symlink_or_copy")
271+
def test_skips_non_existent_source(self, mock_create_symlink_or_copy, mock_makedirs):
272+
src = "src/path"
273+
dest = "dest/path"
274+
275+
LinkSinglePathAction(source=src, dest=dest).execute()
276+
mock_create_symlink_or_copy.assert_not_called()
277+
mock_makedirs.assert_not_called()

tests/unit/test_utils.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
import platform
2+
from pathlib import Path
23

34
from unittest import TestCase
4-
from unittest.mock import patch
5+
from unittest.mock import patch, Mock, MagicMock
56

67
from aws_lambda_builders import utils
78
from aws_lambda_builders.utils import decode
89

910

1011
class Test_create_symlink_or_copy(TestCase):
11-
@patch("aws_lambda_builders.utils.Path")
1212
@patch("aws_lambda_builders.utils.os")
1313
@patch("aws_lambda_builders.utils.copytree")
14-
def test_must_create_symlink_with_absolute_path(self, patched_copy_tree, pathced_os, patched_path):
14+
def test_must_create_symlink_with_absolute_path(self, patched_copy_tree, patched_os):
1515
source_path = "source/path"
1616
destination_path = "destination/path"
17-
utils.create_symlink_or_copy(source_path, destination_path)
1817

19-
pathced_os.symlink.assert_called_with(
20-
patched_path(source_path).absolute(), patched_path(destination_path).absolute()
21-
)
18+
p = MagicMock()
19+
p.return_value = False
20+
21+
with patch("aws_lambda_builders.utils.Path.is_symlink", p):
22+
utils.create_symlink_or_copy(source_path, destination_path)
23+
24+
patched_os.symlink.assert_called_with(Path(source_path).absolute(), Path(destination_path).absolute())
2225
patched_copy_tree.assert_not_called()
2326

2427
@patch("aws_lambda_builders.utils.Path")
@@ -34,6 +37,17 @@ def test_must_copy_if_symlink_fails(self, patched_copy_tree, pathced_os, patched
3437
pathced_os.symlink.assert_called_once()
3538
patched_copy_tree.assert_called_with(source_path, destination_path)
3639

40+
@patch("aws_lambda_builders.utils.Path")
41+
@patch("aws_lambda_builders.utils.os")
42+
@patch("aws_lambda_builders.utils.copytree")
43+
def test_must_copy_if_symlink_fails(self, patched_copy_tree, pathced_os, patched_path):
44+
source_path = "source/path"
45+
destination_path = "destination/path"
46+
utils.create_symlink_or_copy(source_path, destination_path)
47+
48+
pathced_os.symlink.assert_not_called()
49+
patched_copy_tree.assert_not_called()
50+
3751

3852
class TestDecode(TestCase):
3953
def test_does_not_crash_non_utf8_encoding(self):

0 commit comments

Comments
 (0)