Skip to content

Commit f53dc86

Browse files
sriram-mvjfuss
authored andcommitted
feat: Path Resolver and Validator (#55)
The function "which" at aws_lambda_builders/utils.py was copied from https://github.com/python/cpython/blob/3.7/Lib/shutil.py SPDX-License-Identifier: Python-2.0 Copyright 2019 by the Python Software Foundation
1 parent 3f24c82 commit f53dc86

32 files changed

+493
-159
lines changed

.appveyor.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ install:
1818
# To run Nodejs workflow integ tests
1919
- ps: Install-Product node 8.10
2020

21-
- "set PATH=%PYTHON%\\Scripts;%PYTHON%\\bin;%PATH%"
21+
- "set PATH=%PYTHON%;%PYTHON%\\Scripts;%PYTHON%\\bin;%PATH%"
2222
- "%PYTHON%\\python.exe -m pip install -r requirements/dev.txt"
2323
- "%PYTHON%\\python.exe -m pip install -e ."
2424
- "set PATH=C:\\Ruby25-x64\\bin;%PATH%"
2525
- "gem --version"
2626
- "gem install bundler -v 1.17.3 --no-ri --no-rdoc"
2727
- "bundler --version"
28+
- "echo %PATH%"
2829

2930
# setup go
3031
- rmdir c:\go /s /q

.pylintrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
# Add files or directories to the blacklist. They should be base names, not
1111
# paths.
12-
ignore=compat.py
12+
ignore=compat.py, utils.py
1313

1414
# Pickle collected data for later comparisons.
1515
persistent=yes
@@ -360,4 +360,4 @@ int-import-graph=
360360

361361
# Exceptions that will emit a warning when being caught. Defaults to
362362
# "Exception"
363-
overgeneral-exceptions=Exception
363+
overgeneral-exceptions=Exception

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ install:
1515
# To run Nodejs workflow integ tests
1616
- nvm install 8.10.0
1717
- nvm use 8.10.0
18+
# To run Ruby workflow integ tests
19+
- rvm install ruby-2.5.3
20+
- rvm use ruby-2.5.3
1821

1922
# Go workflow integ tests require Go 1.11+
2023
- eval "$(gimme 1.11.2)"

NOTICE

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
AWS Lambda Builders
22
Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
4+
The function "which" at aws_lambda_builders/utils.py was copied from https://github.com/python/cpython/blob/3.7/Lib/shutil.py
5+
SPDX-License-Identifier: Python-2.0
6+
Copyright 2019 by the Python Software Foundation

aws_lambda_builders/binary_path.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""
2+
Class containing resolved path of binary given a validator and a resolver and the name of the binary.
3+
"""
4+
5+
6+
class BinaryPath(object):
7+
8+
def __init__(self, resolver, validator, binary, binary_path=None):
9+
self.resolver = resolver
10+
self.validator = validator
11+
self.binary = binary
12+
self._binary_path = binary_path
13+
self.path_provided = True if self._binary_path else False
14+
15+
@property
16+
def binary_path(self):
17+
return self._binary_path
18+
19+
@binary_path.setter
20+
def binary_path(self, binary_path):
21+
self._binary_path = binary_path

aws_lambda_builders/builder.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import logging
88

99
from aws_lambda_builders.registry import get_workflow, DEFAULT_REGISTRY
10-
from aws_lambda_builders.validate import RuntimeValidator
1110
from aws_lambda_builders.workflow import Capability
1211

1312
LOG = logging.getLogger(__name__)
@@ -91,8 +90,6 @@ def build(self, source_dir, artifacts_dir, scratch_dir, manifest_path,
9190
:param options:
9291
Optional dictionary of options ot pass to build action. **Not supported**.
9392
"""
94-
if runtime:
95-
self._validate_runtime(runtime)
9693

9794
if not os.path.exists(scratch_dir):
9895
os.makedirs(scratch_dir)
@@ -107,16 +104,5 @@ def build(self, source_dir, artifacts_dir, scratch_dir, manifest_path,
107104

108105
return workflow.run()
109106

110-
def _validate_runtime(self, runtime):
111-
"""
112-
validate runtime and local runtime version to make sure they match
113-
114-
:type runtime: str
115-
:param runtime:
116-
String matching a lambda runtime eg: python3.6
117-
"""
118-
RuntimeValidator.validate_runtime(required_language=self.capability.language,
119-
required_runtime=runtime)
120-
121107
def _clear_workflows(self):
122108
DEFAULT_REGISTRY.clear()

aws_lambda_builders/exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class UnsupportedManifestError(LambdaBuilderError):
1818
class MisMatchRuntimeError(LambdaBuilderError):
1919
MESSAGE = "{language} executable found in your path does not " \
2020
"match runtime. " \
21-
"\n Expected version: {required_runtime}, Found version: {found_runtime}. " \
21+
"\n Expected version: {required_runtime}, Found version: {runtime_path}. " \
2222
"\n Possibly related: https://github.com/awslabs/aws-lambda-builders/issues/30"
2323

2424

aws_lambda_builders/path_resolver.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
Basic Path Resolver that looks for the executable by runtime first, before proceeding to 'language' in PATH.
3+
"""
4+
5+
from aws_lambda_builders.utils import which
6+
7+
8+
class PathResolver(object):
9+
10+
def __init__(self, binary, runtime):
11+
self.binary = binary
12+
self.runtime = runtime
13+
self.executables = [self.runtime, self.binary]
14+
15+
def _which(self):
16+
exec_paths = []
17+
for executable in [executable for executable in self.executables if executable is not None]:
18+
paths = which(executable)
19+
exec_paths.extend(paths)
20+
21+
if not exec_paths:
22+
raise ValueError("Path resolution for runtime: {} of binary: "
23+
"{} was not successful".format(self.runtime, self.binary))
24+
return exec_paths
25+
26+
@property
27+
def exec_paths(self):
28+
return self._which()

aws_lambda_builders/utils.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44

55
import shutil
6+
import sys
67
import os
78
import logging
89

@@ -57,3 +58,77 @@ def copytree(source, destination, ignore=None):
5758
copytree(new_source, new_destination, ignore=ignore)
5859
else:
5960
shutil.copy2(new_source, new_destination)
61+
62+
# NOTE: The below function is copied from Python source code and modified
63+
# slightly to return a list of paths that match a given command
64+
# instead of returning just the first match
65+
66+
# The function "which" at aws_lambda_builders/utils.py was copied from https://github.com/python/cpython/blob/3.7/Lib/shutil.py
67+
# SPDX-License-Identifier: Python-2.0
68+
# Copyright 2019 by the Python Software Foundation
69+
70+
71+
def which(cmd, mode=os.F_OK | os.X_OK, path=None): # pragma: no cover
72+
"""Given a command, mode, and a PATH string, return the paths which
73+
conforms to the given mode on the PATH, or None if there is no such
74+
file.
75+
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
76+
of os.environ.get("PATH"), or can be overridden with a custom search
77+
path.
78+
Note: This function was backported from the Python 3 source code.
79+
"""
80+
# Check that a given file can be accessed with the correct mode.
81+
# Additionally check that `file` is not a directory, as on Windows
82+
# directories pass the os.access check.
83+
84+
def _access_check(fn, mode):
85+
return os.path.exists(fn) and os.access(fn, mode) and not os.path.isdir(fn)
86+
87+
# If we're given a path with a directory part, look it up directly
88+
# rather than referring to PATH directories. This includes checking
89+
# relative to the current directory, e.g. ./script
90+
if os.path.dirname(cmd):
91+
if _access_check(cmd, mode):
92+
return cmd
93+
94+
return None
95+
96+
if path is None:
97+
path = os.environ.get("PATH", os.defpath)
98+
if not path:
99+
return None
100+
101+
path = path.split(os.pathsep)
102+
103+
if sys.platform == "win32":
104+
# The current directory takes precedence on Windows.
105+
if os.curdir not in path:
106+
path.insert(0, os.curdir)
107+
108+
# PATHEXT is necessary to check on Windows.
109+
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
110+
# See if the given file matches any of the expected path
111+
# extensions. This will allow us to short circuit when given
112+
# "python.exe". If it does match, only test that one, otherwise we
113+
# have to try others.
114+
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
115+
files = [cmd]
116+
else:
117+
files = [cmd + ext for ext in pathext]
118+
else:
119+
# On other platforms you don't have things like PATHEXT to tell you
120+
# what file suffixes are executable, so just pass on cmd as-is.
121+
files = [cmd]
122+
123+
seen = set()
124+
paths = []
125+
126+
for dir in path:
127+
normdir = os.path.normcase(dir)
128+
if normdir not in seen:
129+
seen.add(normdir)
130+
for thefile in files:
131+
name = os.path.join(dir, thefile)
132+
if _access_check(name, mode):
133+
paths.append(name)
134+
return paths

aws_lambda_builders/validate.py

Lines changed: 0 additions & 74 deletions
This file was deleted.

aws_lambda_builders/validator.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""
2+
No-op validator that does not validate the runtime_path for a specified language.
3+
"""
4+
5+
import logging
6+
7+
LOG = logging.getLogger(__name__)
8+
9+
10+
class RuntimeValidator(object):
11+
12+
def __init__(self, runtime):
13+
self.runtime = runtime
14+
self._runtime_path = None
15+
16+
def validate(self, runtime_path):
17+
self._runtime_path = runtime_path
18+
return runtime_path

0 commit comments

Comments
 (0)