-
Notifications
You must be signed in to change notification settings - Fork 148
feat: Makefile based builder for provided runtimes #166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Why is this change necessary? * provided runtimes are runtimes that are custom built with own bootstraps etc, and its hard to determine which language it actually is. A generic makefile based builder gives the control back to the user on how the project needs to be built. How does it address the issue? * Provide a way to build for provided runtimes, which does not exist today.
* Which environment variables are usable in this makefile? | ||
* There are a series of whitelisted environment variables that need to be defined and not be overriden within the Makefile to work. Currently that is just `$ARTIFACTS_DIR` | ||
|
||
* Can this be used even for runtimes that have builders associated with it? eg: python3.8? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably something we need to address in the design now. Even if it is not supported immediately, how will it be added.
Perhaps an optional build parameter where you can specify a Makefile
explicitly, which then overrides any auto-detected build process? I can see though how this could be a problem across many functions, but that's a starting point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact there are complexities may be a reason to come up with an answer before shipping this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@awood45 This is something that should be considered in SAM CLI not lambda builders. Lambda builders is a library of builders that someone can run, how SAM CLI picks which one is completely within SAM CLI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this would be choosing a workflow based on the manifest in SAM CLI. for eg: if a makefile is present and a build target is present, we choose the makefile workflow, else if we choose the bundled the workflow.
The logic to choose an appropriate workflow would need to be added there.
https://github.com/awslabs/aws-sam-cli/blob/develop/samcli/lib/build/workflow_config.py#L137
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even in sam-cli do we need to provide use of makefile for known workflows. I understand it is adding one more feature with some flexibility. But is it needed? What problem will this be solving? I think it'll add another case which then need lot of testing to make sure we didn't miss an edge case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would think it would be opting on a makefile workflow if necessary. Not neccesarily forced. if you are using a makefile based build approach, you would be responsible for the build instead.
0ccce7b
to
b7080bf
Compare
Why is this change necessary? * Tests to ensure that the makefile based approach for provided runtimes works.
5634fe5
to
0e0d1a9
Compare
Why is this change necessary? * On Windows, certain env variables are required for functioning of binaries within the Makefile How does it address the issue? * pass current environmental variables along with new ones over to the subprocess runner. What side effects does this change have? * None
3658e58
to
8698121
Compare
8698121
to
1fddb92
Compare
59ae79a
to
20d786c
Compare
Why is this change necessary? * on powershell on windows vs git bash on windows, paths are treated differently. How does it address the issue? * Dynamically change path by looking up `sh`. If present, its unix path else its windows paths. What side effects does this change have? * `sh` is the check which determines which path to use. If `sh` aint present, this will end up in breaking the workflow.
20d786c
to
aafed9b
Compare
Sample Makefile: | ||
|
||
```` | ||
build-HelloWorldFunction: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be HelloWorldFunction-build
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is how the design and implementation are designed at this point. Is there a reason you prefer it the other way around?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope in line 21 it says {Function_Logical_Id]-build
that is why I said.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
* Which environment variables are usable in this makefile? | ||
* There are a series of whitelisted environment variables that need to be defined and not be overriden within the Makefile to work. Currently that is just `$ARTIFACTS_DIR` | ||
|
||
* Can this be used even for runtimes that have builders associated with it? eg: python3.8? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even in sam-cli do we need to provide use of makefile for known workflows. I understand it is adding one more feature with some flexibility. But is it needed? What problem will this be solving? I think it'll add another case which then need lot of testing to make sure we didn't miss an edge case.
def _artifact_dir_path(self): | ||
# This is required when running on windows to determine if we are running in linux | ||
# subsystem or on native cmd or powershell. | ||
return Path(self.artifacts_dir).as_posix() if self.osutils.which("sh") else self.artifacts_dir |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this consider other types of shells? like zsh, csh etc? On that note, I think we should have special case for windows environment, which have rather low number of shells. Linux have lot of shells.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a good point, we can check if we are on windows before we start looking for any shell.
LOG.debug("executing Make: %s", invoke_make) | ||
|
||
p = self.osutils.popen( | ||
invoke_make, stdout=self.osutils.pipe, stderr=self.osutils.pipe, cwd=cwd, env=env if env else {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: why don't we default env to {}
instead of None
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure,we can.
|
||
LOG.debug("executing Make: %s", invoke_make) | ||
|
||
p = self.osutils.popen( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have noticed that we have an OSUtil for os
specific calls. Should have a POpenUtil
for open specific calls with consistent logging around the actual call for all workflows? It'll also avoid some code duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably. but the osutils are desinged in a manner such that each is independent, so that each workflow can in essence be its own module. But open to considering it.
Why is this change necessary? * on unix, its not necessary to transform the artifacts_dir path. How does it address the issue? * Do a check if we are windows, before attempting to look for binaries. What side effects does this change have? * None.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this looks really good. Nothing major in my feedback, mostly just small things or suggestions.
When the makefile is called through a lambda builder workflow, the appropriate target is triggered and artifacts should be copied to the exposed environmental variable `$ARTIFACTS_DIR`. This environment variable is seeded by the lambda builder with a value set to it. The targets are defined as | ||
|
||
``` | ||
build-{Function_Logical_Id} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a great place to start, but think customers will be asking for a make build
target as well. This would allow additional support for common builds between functions and remove the need to maintain a build for each Logical Id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its easy to setup such a target by the user themselves and throw common stuff there. if there is a general target it becomes hard to do logical separation from building perspective, especially when multiple functions might share the same Makefile.
LOG = logging.getLogger(__name__) | ||
|
||
|
||
class ProvidedMakeAction(BaseAction): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be labeling this Provided? I can see us wanting to expand this out to other runtimes, like Go/Python/etc in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can rename it to just custom. its more generic that way.
:type osutils: aws_lambda_builders.workflows.provided_make.utils.OSUtils | ||
:param osutils: An instance of OS Utilities for file manipulation | ||
|
||
:type subprocess_make aws_lambda_builders.workflows.provided_make.make.SubprocessMake |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot build_logical_id
doc strings.
self.subprocess_make = subprocess_make | ||
self.build_logical_id = build_logical_id | ||
|
||
def _artifact_dir_path(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these be a @property
?
:type args: list | ||
:param args: Command line arguments to pass to Make | ||
|
||
:type args: dict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be env?
:type args: dict | |
:type env: dict |
from aws_lambda_builders.utils import which | ||
|
||
|
||
class OSUtils(object): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The famous Copy-paste OSUtils. We should make a generic one eventually
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah. we should.
return p | ||
|
||
def environ(self): | ||
return os.environ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be a os.environ.copy()? That way we don't risk mutating customers env var by accident? Some workflows already do this (like Go Dep for example).
|
||
# Find the logical id of the function to be built. | ||
options = kwargs.get("options") or {} | ||
build_logical_id = options.get("build_logical_id", None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when this is not provided?
Should we just error out here if it is a requirement of the builder?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah we would error out saying that the required make file target was not present.
self.assertEquals(expected_files, output_files) | ||
|
||
def test_must_build_python_project_through_makefile_unknown_target(self): | ||
with self.assertRaises(WorkflowFailedError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have a way to make this more specific of an Error?
|
||
class TestProvidedMakeAction(TestCase): | ||
def setUp(self): | ||
self.original_env = os.environ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.copy()?
Why is this change necessary? * Without this, the make manifest file is always assumed to be present with the source_dir. How does it address the issue? * An explicitly passed in manifest file path is now not ignored. What side effects does this change have? * None.
self.osutils.makedirs(self.artifacts_dir) | ||
|
||
try: | ||
current_env = self.osutils.environ().copy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should just do this in OSUtils so we don't have to remember to copy anytime we access the self.osutils.environ()
.
aeddcf7
to
6af13ee
Compare
Why is this change necessary?
bootstraps etc, and its hard to determine which language it actually is.
A generic makefile based builder gives the control back to the user on
how the project needs to be built.
How does it address the issue?
today.
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.