Skip to content

Commit 7c29f65

Browse files
authored
Merge pull request #371 from aws/develop
chore: merge develop to master
2 parents 080ca89 + 23b71aa commit 7c29f65

File tree

6 files changed

+94
-25
lines changed

6 files changed

+94
-25
lines changed

aws_lambda_builders/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
22
AWS Lambda Builder Library
33
"""
4-
__version__ = "1.17.0"
4+
__version__ = "1.18.0"
55
RPC_PROTOCOL_VERSION = "0.3"

aws_lambda_builders/actions.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import logging
66
import os
77
import shutil
8-
import six
8+
from typing import Set, Iterator, Tuple
99

1010
from aws_lambda_builders.utils import copytree
1111

@@ -58,7 +58,7 @@ def __new__(mcs, name, bases, class_dict):
5858

5959
# Validate class variables
6060
# All classes must provide a name
61-
if not isinstance(cls.NAME, six.string_types):
61+
if not isinstance(cls.NAME, str):
6262
raise ValueError("Action must provide a valid name")
6363

6464
if not Purpose.has_value(cls.PURPOSE):
@@ -67,7 +67,7 @@ def __new__(mcs, name, bases, class_dict):
6767
return cls
6868

6969

70-
class BaseAction(six.with_metaclass(_ActionMetaClass, object)):
70+
class BaseAction(object, metaclass=_ActionMetaClass):
7171
"""
7272
Base class for all actions. It does not provide any implementation.
7373
"""
@@ -125,14 +125,9 @@ def __init__(self, source_dir, artifact_dir, destination_dir):
125125
self.dest_dir = destination_dir
126126

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

130+
for dependencies_source, new_destination in deps_manager.yield_source_dest():
136131
if os.path.isdir(dependencies_source):
137132
copytree(dependencies_source, new_destination)
138133
else:
@@ -154,14 +149,9 @@ def __init__(self, source_dir, artifact_dir, destination_dir):
154149
self.dest_dir = destination_dir
155150

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

154+
for dependencies_source, new_destination in deps_manager.yield_source_dest():
165155
# shutil.move can't create subfolders if this is the first file in that folder
166156
if os.path.isfile(dependencies_source):
167157
os.makedirs(os.path.dirname(new_destination), exist_ok=True)
@@ -198,3 +188,36 @@ def execute(self):
198188
shutil.rmtree(target_path)
199189
else:
200190
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

aws_lambda_builders/workflow.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import logging
77

88
from collections import namedtuple
9-
import six
109

1110
from aws_lambda_builders.binary_path import BinaryPath
1211
from aws_lambda_builders.path_resolver import PathResolver
@@ -118,7 +117,7 @@ def __new__(mcs, name, bases, class_dict):
118117
# Validate class variables
119118

120119
# All classes must provide a name
121-
if not isinstance(cls.NAME, six.string_types):
120+
if not isinstance(cls.NAME, str):
122121
raise ValueError("Workflow must provide a valid name")
123122

124123
# All workflows must express their capabilities
@@ -131,7 +130,7 @@ def __new__(mcs, name, bases, class_dict):
131130
return cls
132131

133132

134-
class BaseWorkflow(six.with_metaclass(_WorkflowMetaClass, object)):
133+
class BaseWorkflow(object, metaclass=_WorkflowMetaClass):
135134
"""
136135
Default implementation of the builder workflow. It provides several useful capabilities out-of-box that help
137136
minimize the scope of build actions.

requirements/base.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
six~=1.11
1+

tests/integration/workflows/python_pip/test_python_pip.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import os
22
import shutil
3-
import six
43
import sys
54
import platform
65
import tempfile
@@ -146,7 +145,7 @@ def test_mismatch_runtime_python_project(self):
146145
"Binary validation failed" not in ex_s
147146
and "pip executable not found in your python environment" not in ex_s
148147
):
149-
six.raise_from(AssertionError("Unexpected exception"), ex)
148+
raise AssertionError("Unexpected exception") from ex
150149

151150
def test_runtime_validate_python_project_fail_open_unsupported_runtime(self):
152151
with self.assertRaises(WorkflowFailedError):

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 = list(
170+
TestDependencyManager._convert_strings_to_paths(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)