-
Notifications
You must be signed in to change notification settings - Fork 137
/
workflow.py
142 lines (123 loc) · 5.24 KB
/
workflow.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""
Python PIP Workflow
"""
import logging
from aws_lambda_builders.actions import CleanUpAction, CopySourceAction, LinkSourceAction
from aws_lambda_builders.path_resolver import PathResolver
from aws_lambda_builders.workflow import BaseWorkflow, BuildDirectory, BuildInSourceSupport, Capability
from aws_lambda_builders.workflows.python_pip.validator import PythonRuntimeValidator
from .actions import PythonPipBuildAction
from .utils import OSUtils, is_experimental_build_improvements_enabled
LOG = logging.getLogger(__name__)
class PythonPipWorkflow(BaseWorkflow):
NAME = "PythonPipBuilder"
CAPABILITY = Capability(language="python", dependency_manager="pip", application_framework=None)
# Common source files to exclude from build artifacts output
# Trimmed version of https://github.com/github/gitignore/blob/master/Python.gitignore
EXCLUDED_FILES = (
".aws-sam",
".chalice",
".git",
".gitignore",
# Compiled files
"*.pyc",
"__pycache__",
"*.so",
# Distribution / packaging
".Python",
"*.egg-info",
"*.egg",
# Installer logs
"pip-log.txt",
"pip-delete-this-directory.txt",
# Unit test / coverage reports
"htmlcov",
".tox",
".nox",
".coverage",
".cache",
".pytest_cache",
# pyenv
".python-version",
# mypy, Pyre
".mypy_cache",
".dmypy.json",
".pyre",
# environments
".env",
".venv",
"venv",
"venv.bak",
"env.bak",
"ENV",
"env",
# Editors
# TODO: Move the commonly ignored files to base class
".vscode",
".idea",
)
PYTHON_VERSION_THREE = "3"
DEFAULT_BUILD_DIR = BuildDirectory.SCRATCH
BUILD_IN_SOURCE_SUPPORT = BuildInSourceSupport.NOT_SUPPORTED
def __init__(self, source_dir, artifacts_dir, scratch_dir, manifest_path, runtime=None, osutils=None, **kwargs):
super(PythonPipWorkflow, self).__init__(
source_dir, artifacts_dir, scratch_dir, manifest_path, runtime=runtime, **kwargs
)
if osutils is None:
osutils = OSUtils()
if not self.download_dependencies and not self.dependencies_dir:
LOG.info(
"download_dependencies is False and dependencies_dir is None. Copying the source files into the "
"artifacts directory. "
)
self.actions = []
if not osutils.file_exists(manifest_path):
LOG.warning("requirements.txt file not found. Continuing the build without dependencies.")
self.actions.append(CopySourceAction(source_dir, artifacts_dir, excludes=self.EXCLUDED_FILES))
return
# If a requirements.txt exists, run pip builder before copy action.
if self.download_dependencies:
if self.dependencies_dir:
# clean up the dependencies folder before installing
self.actions.append(CleanUpAction(self.dependencies_dir))
self.actions.append(
PythonPipBuildAction(
artifacts_dir,
scratch_dir,
manifest_path,
runtime,
self.dependencies_dir,
binaries=self.binaries,
architecture=self.architecture,
)
)
# if dependencies folder is provided, copy dependencies from dependencies folder to build folder
# if combine_dependencies is false, will not copy the dependencies from dependencies folder to artifact
# folder
if self.dependencies_dir and self.combine_dependencies:
# when copying downloaded dependencies back to artifacts folder, don't exclude anything
# symlinking python dependencies is disabled for now since it is breaking sam local commands
if False and is_experimental_build_improvements_enabled(self.experimental_flags):
self.actions.append(LinkSourceAction(self.dependencies_dir, artifacts_dir))
else:
self.actions.append(CopySourceAction(self.dependencies_dir, artifacts_dir))
self.actions.append(CopySourceAction(source_dir, artifacts_dir, excludes=self.EXCLUDED_FILES))
def get_resolvers(self):
"""
Specialized Python path resolver that looks for additional binaries in addition to the language specific binary.
"""
return [
PathResolver(
runtime=self.runtime,
binary=self.CAPABILITY.language,
additional_binaries=self._get_additional_binaries(),
executable_search_paths=self.executable_search_paths,
)
]
def _get_additional_binaries(self):
# python3 is an additional binary that has to be considered in addition to the original python binary, when
# the specified python runtime is 3.x
major, _ = self.runtime.replace(self.CAPABILITY.language, "").split(".")
return [f"{self.CAPABILITY.language}{major}"] if major == self.PYTHON_VERSION_THREE else None
def get_validators(self):
return [PythonRuntimeValidator(runtime=self.runtime, architecture=self.architecture)]