Search code examples
pythonmakefileaws-lambdaaws-serverlessaws-lambda-layers

Is there any way to see the output of a shell script when launched through make, for SAM


I'm trying to build a multi-layer Python SAM (AWS Serverless Application Model) app.

Nothing too fancy, but it has some dependencies, which are managed using pipenv.

SAM has a sam build command which behind the scenes uses make. I have a Makefile that looks like this:

# Empty build target for "sam build". Why?
# 1. "sam build Layers" works
# 2. "sam build" for the main function doesn't (it tries to use pip and crashes)
# With this empty target the main build is skipped and only the layers are built, which is enough.
build-Function: ;

build-Layers:
    bash pip-install.sh "$(ARTIFACTS_DIR)"

pip-install.sh looks like this:

#!/bin/bash
ARTIFACTS_DIR="${1}"

set -eu

# Detect Cygwin: https://stackoverflow.com/a/20691293/1320143
uname="$(uname -s)"
if [[ "${uname}" =~ "Cygwin" ]]
then
    # AWS SAM for Windows passes a Windows path Cygwin tools (make, etc.) don't understand.
    ARTIFACTS_DIR="$(cygpath -u "${ARTIFACTS_DIR}")"
fi

PROJECT_PATH="$(echo "${ARTIFACTS_DIR}" | sed 's@/.aws-sam.*@@')"
PIPFILE_PATH="$(echo "${ARTIFACTS_DIR}" | sed 's@/.aws-sam.*@/../Pipfile.lock@' | xargs readlink -f)"

mkdir -p "${ARTIFACTS_DIR}/python"
# We're using pipenv, which does not use requirements.txt.
# requirements.txt is used by SAM to automatically package and deploy layers (dependencies).
# To avoid dependency/version duplication, we extract the info from the pipenv info.

jq -r '.default | to_entries[] | .key + .value.version' "${PIPFILE_PATH}" > requirements.txt

# For debugging purposes.
ls -lha

python -m pip install -r "${PROJECT_PATH}/requirements.txt" -t "${ARTIFACTS_DIR}/python"

The important part is that this project uses pipenv to manage dependencies, not pip, and SAM uses make as the build tool but after that, it only has a pip extension. This script basically creates a dependency list that pip understands and then pip downloads all the dependencies in a folder, which will then be packaged as a big layer.

The main issue is debugging.

I've seen that for some (IMHO dumb) reason make hides the output of shell scripts it launches. Supposedly make can be tricked to show it, with this: See output of shell script in Makefile

I've tried it and it doesn't work. I run sam build Layers and I only see the sam output. I've tried --debug, same thing.

Is there a way to show that output? I want to be able to debug the script in the make/sam build context as I don't understand some errors I'm getting 😔


Solution

  • At re:Invent 2020, AWS announced that Lambda can now use Docker images.

    Instead of using the mix of Make and proprietary setup SAM provides for building Lambda layers, just use standard Dockerfiles and save a lot of time 🙂