Skip to content

Dockerless build option #58

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

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
62 changes: 62 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/bash
# build and pack a rust lambda library
# https://aws.amazon.com/blogs/opensource/rust-runtime-for-aws-lambda/

set -eo pipefail
mkdir -p target/lambda
export PROFILE=${PROFILE:-release}
export DEBUGINFO=${DEBUGINFO}
# cargo uses different names for target
# of its build profiles
if [[ "${PROFILE}" == "release" ]]; then
TARGET_PROFILE="${PROFILE}"
else
TARGET_PROFILE="debug"
fi
export CARGO_TARGET_DIR=$PWD/target/lambda
(
if [[ $# -gt 0 ]]; then
yum install -y "$@"
fi
# source cargo
. $HOME/.cargo/env
# cargo only supports --release flag for release
# profiles. dev is implicit
if [ "${PROFILE}" == "release" ]; then
cargo build ${CARGO_FLAGS:-} --${PROFILE}
else
cargo build ${CARGO_FLAGS:-}
fi
) 1>&2

function package() {
file="$1"
if [[ "${PROFILE}" == "release" ]] && [[ -z "${DEBUGINFO}" ]]; then
objcopy --only-keep-debug "$file" "$file.debug"
objcopy --strip-debug --strip-unneeded "$file"
objcopy --add-gnu-debuglink="$file.debug" "$file"
fi
rm "$file.zip" > 2&>/dev/null || true
# note: would use printf "@ $(basename $file)\n@=bootstrap" | zipnote -w "$file.zip"
# if not for https://bugs.launchpad.net/ubuntu/+source/zip/+bug/519611
if [ "$file" != ./bootstrap ] && [ "$file" != bootstrap ]; then
mv "${file}" bootstrap
mv "${file}.debug" bootstrap.debug > 2&>/dev/null || true
fi
zip "$file.zip" bootstrap
rm bootstrap
}

cd "${CARGO_TARGET_DIR}/${TARGET_PROFILE}"
(
. $HOME/.cargo/env
if [ -z "$BIN" ]; then
IFS=$'\n'
for executable in $(cargo metadata --no-deps --format-version=1 | jq -r '.packages[] | .targets[] | select(.kind[] | contains("bin")) | .name'); do
package "$executable"
done
else
package "$BIN"
fi

) 1>&2
81 changes: 62 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// https://serverless.com/framework/docs/providers/aws/guide/plugins/
// https://github.com/softprops/lambda-rust/

const { spawnSync } = require("child_process");
const { spawnSync, execSync } = require("child_process");
const { homedir } = require("os");
const path = require("path");

Expand Down Expand Up @@ -50,11 +50,49 @@ class RustPlugin {
this.serverless.service.package.excludeDevDependencies = false;
}

runDocker(funcArgs, cargoPackage, binary, profile) {
compileFunctionBinary({
funcArgs,
cargoPackage,
binary,
profile,
dockerless
}) {
if (dockerless) {
return this.buildFromShell({ funcArgs, cargoPackage, binary, profile });
}
return this.buildInDocker({ funcArgs, cargoPackage, binary, profile });
}

buildInDocker({ funcArgs, cargoPackage, binary, profile }) {
const dockerTag = (funcArgs || {}).dockerTag || this.custom.dockerTag;
return spawnSync(
"docker",
[
...this.getDockerArgs({ funcArgs, cargoPackage, binary, profile }),
`softprops/lambda-rust:${dockerTag}`
],
NO_OUTPUT_CAPTURE
);
}

buildFromShell({ funcArgs, cargoPackage, binary, profile }) {
const buildCommand = [`BIN=${binary}`, `${__dirname}/build.sh`];
const cargoFlags = this.getCargoFlags(funcArgs, cargoPackage);
if (cargoFlags) {
buildCommand.unshift(`CARGO_FLAGS="${cargoFlags}"`);
}
if (profile) {
buildCommand.unshift(`PROFILE=${profile}`);
}

return execSync(`${buildCommand.join(" ")}`);
}

getDockerArgs({ funcArgs, cargoPackage, binary, profile }) {
const cargoHome = process.env.CARGO_HOME || path.join(homedir(), ".cargo");
const cargoRegistry = path.join(cargoHome, "registry");
const cargoDownloads = path.join(cargoHome, "git");
const defaultArgs = [
const args = [
"run",
"--rm",
"-t",
Expand All @@ -67,30 +105,29 @@ class RustPlugin {
`-v`,
`${cargoDownloads}:/root/.cargo/git`
];
const customArgs = [];

let cargoFlags = (funcArgs || {}).cargoFlags || this.custom.cargoFlags;
const cargoFlags = this.getCargoFlags(funcArgs, cargoPackage);
if (cargoFlags) {
// --features awesome-feature, ect
args.push("-e", `CARGO_FLAGS=${cargoFlags}`);
}
if (profile) {
// release or dev
customArgs.push("-e", `PROFILE=${profile}`);
args.push("-e", `PROFILE=${profile}`);
}
return args;
}

getCargoFlags(funcArgs, cargoPackage) {
let cargoFlags = (funcArgs || {}).cargoFlags || this.custom.cargoFlags;
if (cargoPackage != undefined) {
if (cargoFlags) {
cargoFlags = `${cargoFlags} -p ${cargoPackage}`;
} else {
cargoFlags = ` -p ${cargoPackage}`;
}
}
if (cargoFlags) {
// --features awesome-feature, ect
customArgs.push("-e", `CARGO_FLAGS=${cargoFlags}`);
}
const dockerTag = (funcArgs || {}).dockerTag || this.custom.dockerTag;
return spawnSync(
"docker",
[...defaultArgs, ...customArgs, `softprops/lambda-rust:${dockerTag}`],
NO_OUTPUT_CAPTURE
);

return cargoFlags;
}

functions() {
Expand Down Expand Up @@ -121,10 +158,16 @@ class RustPlugin {
}
this.serverless.cli.log(`Building native Rust ${func.handler} func...`);
let profile = (func.rust || {}).profile || this.custom.profile;
const res = this.runDocker(func.rust, cargoPackage, binary, profile);
const res = this.compileFunctionBinary({
rust: func.rust,
cargoPackage,
binary,
profile,
dockerless: this.custom.dockerless
});
if (res.error || res.status > 0) {
this.serverless.cli.log(
`Dockerized Rust build encountered an error: ${res.error} ${res.status}.`
`Rust build encountered an error: ${res.error} ${res.status}.`
);
throw new Error(res.error);
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"files": [
"index.js",
"package.json",
"build.sh",
"README.md"
]
}
2 changes: 1 addition & 1 deletion tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export SILENT=1

source "${HERE}"/bashtest.sh

for project in test-func test-func-dev; do
for project in test-func test-func-dev test-func-dockerless; do

cd "${HERE}"/"${project}"
echo "👩‍🔬 Running tests for $project"
Expand Down