Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/build-package/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Note that this example may create resources which cost money. Run `terraform des
| <a name="module_package_dir_poetry"></a> [package\_dir\_poetry](#module\_package\_dir\_poetry) | ../../ | n/a |
| <a name="module_package_dir_poetry_no_docker"></a> [package\_dir\_poetry\_no\_docker](#module\_package\_dir\_poetry\_no\_docker) | ../../ | n/a |
| <a name="module_package_dir_with_npm_install"></a> [package\_dir\_with\_npm\_install](#module\_package\_dir\_with\_npm\_install) | ../../ | n/a |
| <a name="module_package_dir_with_npm_install_lock_file"></a> [package\_dir\_with\_npm\_install\_lock\_file](#module\_package\_dir\_with\_npm\_install\_lock\_file) | ../../ | n/a |
| <a name="module_package_dir_without_npm_install"></a> [package\_dir\_without\_npm\_install](#module\_package\_dir\_without\_npm\_install) | ../../ | n/a |
| <a name="module_package_dir_without_pip_install"></a> [package\_dir\_without\_pip\_install](#module\_package\_dir\_without\_pip\_install) | ../../ | n/a |
| <a name="module_package_file"></a> [package\_file](#module\_package\_file) | ../../ | n/a |
Expand All @@ -53,6 +54,7 @@ Note that this example may create resources which cost money. Run `terraform des
| <a name="module_package_src_poetry2"></a> [package\_src\_poetry2](#module\_package\_src\_poetry2) | ../../ | n/a |
| <a name="module_package_with_commands_and_patterns"></a> [package\_with\_commands\_and\_patterns](#module\_package\_with\_commands\_and\_patterns) | ../../ | n/a |
| <a name="module_package_with_docker"></a> [package\_with\_docker](#module\_package\_with\_docker) | ../../ | n/a |
| <a name="module_package_with_npm_lock_in_docker"></a> [package\_with\_npm\_lock\_in\_docker](#module\_package\_with\_npm\_lock\_in\_docker) | ../../ | n/a |
| <a name="module_package_with_npm_requirements_in_docker"></a> [package\_with\_npm\_requirements\_in\_docker](#module\_package\_with\_npm\_requirements\_in\_docker) | ../../ | n/a |
| <a name="module_package_with_patterns"></a> [package\_with\_patterns](#module\_package\_with\_patterns) | ../../ | n/a |
| <a name="module_package_with_pip_requirements_in_docker"></a> [package\_with\_pip\_requirements\_in\_docker](#module\_package\_with\_pip\_requirements\_in\_docker) | ../../ | n/a |
Expand Down
26 changes: 26 additions & 0 deletions examples/build-package/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,18 @@ module "package_dir_with_npm_install" {
source_path = "${path.module}/../fixtures/nodejs14.x-app1"
}

# Create zip-archive of a single directory where "npm install" will also be
# executed (default for nodejs runtime). This example has package-lock.json which
# is respected when installing dependencies.
module "package_dir_with_npm_install_lock_file" {
source = "../../"

create_function = false

runtime = "nodejs14.x"
source_path = "${path.module}/../fixtures/nodejs14.x-app2"
}

# Create zip-archive of a single directory without running "npm install" (which is the default for nodejs runtime)
module "package_dir_without_npm_install" {
source = "../../"
Expand Down Expand Up @@ -393,6 +405,20 @@ module "package_with_npm_requirements_in_docker" {
hash_extra = "something-unique-to-not-conflict-with-module.package_dir_with_npm_install"
}

# Create zip-archive of a single directory where "npm install" will also be
# executed using docker. This example has package-lock.json which is respected
# when installing dependencies.
module "package_with_npm_lock_in_docker" {
source = "../../"

create_function = false

runtime = "nodejs14.x"
source_path = "${path.module}/../fixtures/nodejs14.x-app2"
build_in_docker = true
hash_extra = "something-unique-to-not-conflict-with-module.package_dir_with_npm_install"
}

################################
# Build package in Docker and
# use it to deploy Lambda Layer
Expand Down
16 changes: 16 additions & 0 deletions examples/fixtures/nodejs14.x-app2/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';

module.exports.hello = async (event) => {
console.log(event);
return {
statusCode: 200,
body: JSON.stringify(
{
message: `Go Serverless.tf! Your Nodejs function executed successfully!`,
input: event,
},
null,
2
),
};
};
83 changes: 83 additions & 0 deletions examples/fixtures/nodejs14.x-app2/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions examples/fixtures/nodejs14.x-app2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "nodejs14.x-app1",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"requests": "^0.2.0"
}
}
78 changes: 70 additions & 8 deletions package.py
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,14 @@ def npm_requirements_step(path, prefix=None, required=False, tmp_dir=None):
requirements = path
if os.path.isdir(path):
requirements = os.path.join(path, "package.json")
npm_lock_file = os.path.join(path, "package-lock.json")
else:
npm_lock_file = os.path.join(os.path.dirname(path), "package-lock.json")

if os.path.isfile(npm_lock_file):
hash(npm_lock_file)
log.info("Added npm lock file: %s", npm_lock_file)

if not os.path.isfile(requirements):
if required:
raise RuntimeError("File not found: {}".format(requirements))
Expand Down Expand Up @@ -1088,7 +1096,7 @@ def install_pip_requirements(query, requirements_file, tmp_dir):
ok = True
elif docker_file or docker_build_root:
raise ValueError(
"docker_image must be specified " "for a custom image future references"
"docker_image must be specified for a custom image future references"
)

working_dir = os.getcwd()
Expand All @@ -1108,7 +1116,7 @@ def install_pip_requirements(query, requirements_file, tmp_dir):
elif OSX:
# Workaround for OSX when XCode command line tools'
# python becomes the main system python interpreter
os_path = "{}:/Library/Developer/CommandLineTools" "/usr/bin".format(
os_path = "{}:/Library/Developer/CommandLineTools/usr/bin".format(
os.environ["PATH"]
)
subproc_env = os.environ.copy()
Expand Down Expand Up @@ -1390,14 +1398,15 @@ def install_npm_requirements(query, requirements_file, tmp_dir):
ok = True
elif docker_file or docker_build_root:
raise ValueError(
"docker_image must be specified " "for a custom image future references"
"docker_image must be specified for a custom image future references"
)

log.info("Installing npm requirements: %s", requirements_file)
with tempdir(tmp_dir) as temp_dir:
requirements_filename = os.path.basename(requirements_file)
target_file = os.path.join(temp_dir, requirements_filename)
shutil.copyfile(requirements_file, target_file)
temp_copy = TemporaryCopy(os.path.dirname(requirements_file), temp_dir, log)
temp_copy.add(os.path.basename(requirements_file))
temp_copy.add("package-lock.json", required=False)
temp_copy.copy_to_target_dir()

subproc_env = None
npm_exec = "npm"
Expand Down Expand Up @@ -1442,10 +1451,63 @@ def install_npm_requirements(query, requirements_file, tmp_dir):
"available in system PATH".format(runtime)
) from e

os.remove(target_file)
temp_copy.remove_from_target_dir()
yield temp_dir


class TemporaryCopy:
"""Temporarily copy files to a specified location and remove them when
not needed.
"""

def __init__(self, source_dir_path, target_dir_path, logger=None):
"""Initialise with a target and a source directories."""
self.source_dir_path = source_dir_path
self.target_dir_path = target_dir_path
self._filenames = []
self._logger = logger

def _make_source_path(self, filename):
return os.path.join(self.source_dir_path, filename)

def _make_target_path(self, filename):
return os.path.join(self.target_dir_path, filename)

def add(self, filename, *, required=True):
"""Add a file to be copied from from source to target directory
when `TemporaryCopy.copy_to_target_dir()` is called.

By default, the file must exist in the source directory. Set `required`
to `False` if the file is optional.
"""
if os.path.exists(self._make_source_path(filename)):
self._filenames.append(filename)
elif required:
raise RuntimeError("File not found: {}".format(filename))

def copy_to_target_dir(self):
"""Copy files (added so far) to the target directory."""
for filename in self._filenames:
if self._logger:
self._logger.info("Copying temporarily '%s'", filename)

shutil.copyfile(
self._make_source_path(filename),
self._make_target_path(filename),
)

def remove_from_target_dir(self):
"""Remove files (added so far) from the target directory."""
for filename in self._filenames:
if self._logger:
self._logger.info("Removing temporarily copied '%s'", filename)

try:
os.remove(self._make_target_path(filename))
except FileNotFoundError:
pass


def docker_image_id_command(tag):
""""""
docker_cmd = ["docker", "images", "--format={{.ID}}", tag]
Expand Down Expand Up @@ -1649,7 +1711,7 @@ def prepare_command(args):
timestamp = timestamp_now_ns()
was_missing = True
else:
timestamp = "<WARNING: Missing lambda zip artifacts " "wouldn't be restored>"
timestamp = "<WARNING: Missing lambda zip artifacts wouldn't be restored>"

# Replace variables in the build command with calculated values.
build_data = {
Expand Down