Skip to content

Commit b317c5d

Browse files
authored
fix: Allow sync to work with dependencies in source (#368)
* fix: Allow sync to work with dependencies in source * Use Path for assertions * Add type annotations and make class members protected * Test through public method only * Compare paths
1 parent 63ed0fd commit b317c5d

File tree

2 files changed

+87
-15
lines changed

2 files changed

+87
-15
lines changed

aws_lambda_builders/actions.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import logging
66
import os
77
import shutil
8+
from typing import Set, Iterator, Tuple
89

910
from aws_lambda_builders.utils import copytree
1011

@@ -124,14 +125,9 @@ def __init__(self, source_dir, artifact_dir, destination_dir):
124125
self.dest_dir = destination_dir
125126

126127
def execute(self):
127-
source = set(os.listdir(self.source_dir))
128-
artifact = set(os.listdir(self.artifact_dir))
129-
dependencies = artifact - source
130-
131-
for name in dependencies:
132-
dependencies_source = os.path.join(self.artifact_dir, name)
133-
new_destination = os.path.join(self.dest_dir, name)
128+
deps_manager = DependencyManager(self.source_dir, self.artifact_dir, self.dest_dir)
134129

130+
for dependencies_source, new_destination in deps_manager.yield_source_dest():
135131
if os.path.isdir(dependencies_source):
136132
copytree(dependencies_source, new_destination)
137133
else:
@@ -153,14 +149,9 @@ def __init__(self, source_dir, artifact_dir, destination_dir):
153149
self.dest_dir = destination_dir
154150

155151
def execute(self):
156-
source = set(os.listdir(self.source_dir))
157-
artifact = set(os.listdir(self.artifact_dir))
158-
dependencies = artifact - source
159-
160-
for name in dependencies:
161-
dependencies_source = os.path.join(self.artifact_dir, name)
162-
new_destination = os.path.join(self.dest_dir, name)
152+
deps_manager = DependencyManager(self.source_dir, self.artifact_dir, self.dest_dir)
163153

154+
for dependencies_source, new_destination in deps_manager.yield_source_dest():
164155
# shutil.move can't create subfolders if this is the first file in that folder
165156
if os.path.isfile(dependencies_source):
166157
os.makedirs(os.path.dirname(new_destination), exist_ok=True)
@@ -197,3 +188,36 @@ def execute(self):
197188
shutil.rmtree(target_path)
198189
else:
199190
os.remove(target_path)
191+
192+
193+
class DependencyManager:
194+
"""
195+
Class for handling the management of dependencies between directories
196+
"""
197+
198+
# Ignore these files when comparing against which dependencies to move
199+
# This allows for the installation of dependencies in the source directory
200+
IGNORE_LIST = ["node_modules"]
201+
202+
def __init__(self, source_dir, artifact_dir, destination_dir) -> None:
203+
self._source_dir: str = source_dir
204+
self._artifact_dir: str = artifact_dir
205+
self._dest_dir: str = destination_dir
206+
self._dependencies: Set[str] = set()
207+
208+
def yield_source_dest(self) -> Iterator[Tuple[str, str]]:
209+
self._set_dependencies()
210+
for dep in self._dependencies:
211+
yield os.path.join(self._artifact_dir, dep), os.path.join(self._dest_dir, dep)
212+
213+
def _set_dependencies(self) -> None:
214+
source = self._get_source_files_exclude_deps()
215+
artifact = set(os.listdir(self._artifact_dir))
216+
self._dependencies = artifact - source
217+
218+
def _get_source_files_exclude_deps(self) -> Set[str]:
219+
source_files = set(os.listdir(self._source_dir))
220+
for item in self.IGNORE_LIST:
221+
if item in source_files:
222+
source_files.remove(item)
223+
return source_files

tests/unit/test_actions.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
from pathlib import Path
2+
from typing import List, Tuple
13
from unittest import TestCase
2-
from mock import patch, ANY
4+
from mock import patch, ANY, Mock
5+
from parameterized import parameterized
36

47
from aws_lambda_builders.actions import (
58
BaseAction,
@@ -8,6 +11,7 @@
811
CopyDependenciesAction,
912
MoveDependenciesAction,
1013
CleanUpAction,
14+
DependencyManager,
1115
)
1216

1317

@@ -128,3 +132,47 @@ def test_must_copy(self, path_mock, listdir_mock, isdir_mock, rmtree_mock, rm_mo
128132
listdir_mock.assert_any_call(target_dir)
129133
rmtree_mock.assert_any_call("dir")
130134
rm_mock.assert_any_call("file")
135+
136+
137+
class TestDependencyManager(TestCase):
138+
@parameterized.expand(
139+
[
140+
(
141+
["app.js", "package.js", "libs", "node_modules"],
142+
["app.js", "package.js", "libs", "node_modules"],
143+
[("artifacts/node_modules", "dest/node_modules")],
144+
None,
145+
),
146+
(
147+
["file1, file2", "dep1", "dep2"],
148+
["file1, file2", "dep1", "dep2"],
149+
[("artifacts/dep1", "dest/dep1"), ("artifacts/dep2", "dest/dep2")],
150+
["dep1", "dep2"],
151+
),
152+
(
153+
["file1, file2"],
154+
["file1, file2", "dep1", "dep2"],
155+
[("artifacts/dep1", "dest/dep1"), ("artifacts/dep2", "dest/dep2")],
156+
["dep1", "dep2"],
157+
),
158+
]
159+
)
160+
@patch("aws_lambda_builders.actions.os.listdir")
161+
def test_excludes_dependencies_from_source(
162+
self, source_files, artifact_files, expected, mock_dependencies, patched_list_dir
163+
):
164+
dependency_manager = DependencyManager("source", "artifacts", "dest")
165+
dependency_manager.IGNORE_LIST = (
166+
dependency_manager.IGNORE_LIST if mock_dependencies is None else mock_dependencies
167+
)
168+
patched_list_dir.side_effect = [source_files, artifact_files]
169+
source_destinations = TestDependencyManager._convert_strings_to_paths(
170+
list(dependency_manager.yield_source_dest())
171+
)
172+
expected_paths = TestDependencyManager._convert_strings_to_paths(expected)
173+
for expected_source_dest in expected_paths:
174+
self.assertIn(expected_source_dest, source_destinations)
175+
176+
@staticmethod
177+
def _convert_strings_to_paths(source_dest_list):
178+
return map(lambda item: (Path(item[0]), Path(item[1])), source_dest_list)

0 commit comments

Comments
 (0)