diff --git a/index.js b/index.js index 58f330b..202d9a3 100644 --- a/index.js +++ b/index.js @@ -47,6 +47,7 @@ class RustPlugin { dockerTag: DEFAULT_DOCKER_TAG, dockerImage: DEFAULT_DOCKER_IMAGE, dockerless: false, + strictMode: true, }, (this.serverless.service.custom && this.serverless.service.custom.rust) || {} @@ -74,15 +75,13 @@ class RustPlugin { "" ).split(/\s+/); + let target = (funcArgs || {}).target || this.custom.target; - let target = (funcArgs || {}).target || this.custom.target - - const targetArgs = - target ? - ['--target', target] - : MUSL_PLATFORMS.includes(platform) - ? ["--target", "x86_64-unknown-linux-musl"] - : []; + const targetArgs = target + ? ["--target", target] + : MUSL_PLATFORMS.includes(platform) + ? ["--target", "x86_64-unknown-linux-musl"] + : []; return [ ...defaultArgs, ...profileArgs, @@ -94,30 +93,29 @@ class RustPlugin { localBuildEnv(funcArgs, env, platform) { const defaultEnv = { ...env }; - let target = (funcArgs || {}).target || this.custom.target - let linker = (funcArgs || {}).linker || this.custom.linker + let target = (funcArgs || {}).target || this.custom.target; + let linker = (funcArgs || {}).linker || this.custom.linker; - const platformEnv = - linker ? - { + const platformEnv = linker + ? { RUSTFLAGS: (env["RUSTFLAGS"] || "") + ` -Clinker=${linker}`, TARGET_CC: linker, - [`CC_${target || 'x86_64_unknown_linux_musl'}`]: linker, + [`CC_${target || "x86_64_unknown_linux_musl"}`]: linker, + } + : "win32" === platform + ? { + RUSTFLAGS: (env["RUSTFLAGS"] || "") + " -Clinker=rust-lld", + TARGET_CC: "rust-lld", + CC_x86_64_unknown_linux_musl: "rust-lld", } - : "win32" === platform - ? { - RUSTFLAGS: (env["RUSTFLAGS"] || "") + " -Clinker=rust-lld", - TARGET_CC: "rust-lld", - CC_x86_64_unknown_linux_musl: "rust-lld", - } - : "darwin" === platform - ? { - RUSTFLAGS: - (env["RUSTFLAGS"] || "") + " -Clinker=x86_64-linux-musl-gcc", - TARGET_CC: "x86_64-linux-musl-gcc", - CC_x86_64_unknown_linux_musl: "x86_64-linux-musl-gcc", - } - : {}; + : "darwin" === platform + ? { + RUSTFLAGS: + (env["RUSTFLAGS"] || "") + " -Clinker=x86_64-linux-musl-gcc", + TARGET_CC: "x86_64-linux-musl-gcc", + CC_x86_64_unknown_linux_musl: "x86_64-linux-musl-gcc", + } + : {}; return { ...defaultEnv, ...platformEnv, @@ -127,8 +125,11 @@ class RustPlugin { localSourceDir(funcArgs, profile, platform) { let executable = "target"; if (MUSL_PLATFORMS.includes(platform)) { - let target = (funcArgs || {}).target || this.custom.target - executable = path.join(executable, target ? target : "x86_64-unknown-linux-musl"); + let target = (funcArgs || {}).target || this.custom.target; + executable = path.join( + executable, + target ? target : "x86_64-unknown-linux-musl" + ); } return path.join(executable, profile !== "dev" ? "release" : "debug"); } @@ -281,6 +282,7 @@ class RustPlugin { /** the entry point for building functions */ build() { + const strictMode = this.custom.strictMode !== false; const service = this.serverless.service; if (service.provider.name != "aws") { return; @@ -289,51 +291,61 @@ class RustPlugin { this.functions().forEach((funcName) => { const func = service.getFunction(funcName); const runtime = func.runtime || service.provider.runtime; - if (runtime != RUST_RUNTIME) { + + func.tags = func.tags || {}; + if (!(runtime === RUST_RUNTIME || func.tags.language === "rust")) { // skip functions which don't apply to rust return; } rustFunctionsFound = true; - const { cargoPackage, binary } = this.cargoBinary(func); - - this.serverless.cli.log(`Building Rust ${func.handler} func...`); - let profile = (func.rust || {}).profile || this.custom.profile; - const res = this.buildLocally(func) - ? this.localBuild(func.rust, cargoPackage, binary, profile) - : this.dockerBuild(func.rust, cargoPackage, binary, profile); - if (res.error || res.status > 0) { + func.package = func.package || {}; + if (func.package.artifact && func.package.artifact !== "") { this.serverless.cli.log( - `Rust build encountered an error: ${res.error} ${res.status}.` + `Artifact defined for ${func.handler}, skipping build...` ); - throw new Error(res.error); - } - // If all went well, we should now have find a packaged compiled binary under `target/lambda/release`. - // - // The AWS "provided" lambda runtime requires executables to be named - // "bootstrap" -- https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html - // - // To avoid artifact naming conflicts when we potentially have more than one function - // we leverage the ability to declare a package artifact directly - // see https://serverless.com/framework/docs/providers/aws/guide/packaging/ - // for more information - const artifactPath = path.join( - this.srcPath, - `target/lambda/${"dev" === profile ? "debug" : "release"}`, - `${binary}.zip` - ); - func.package = func.package || {}; - func.package.artifact = artifactPath; + } else { + const { cargoPackage, binary } = this.cargoBinary(func); + + this.serverless.cli.log(`Building Rust ${func.handler} func...`); + let profile = (func.rust || {}).profile || this.custom.profile; + + const res = this.buildLocally(func) + ? this.localBuild(func.rust, cargoPackage, binary, profile) + : this.dockerBuild(func.rust, cargoPackage, binary, profile); + if (res.error || res.status > 0) { + this.serverless.cli.log( + `Rust build encountered an error: ${res.error} ${res.status}.` + ); + throw new Error(res.error); + } + // If all went well, we should now have find a packaged compiled binary under `target/lambda/release`. + // + // The AWS "provided" lambda runtime requires executables to be named + // "bootstrap" -- https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html + // + // To avoid artifact naming conflicts when we potentially have more than one function + // we leverage the ability to declare a package artifact directly + // see https://serverless.com/framework/docs/providers/aws/guide/packaging/ + // for more information + const artifactPath = path.join( + this.srcPath, + `target/lambda/${"dev" === profile ? "debug" : "release"}`, + `${binary}.zip` + ); + func.package = func.package || {}; + func.package.artifact = artifactPath; - // Ensure the runtime is set to a sane value for other plugins - if (func.runtime == RUST_RUNTIME) { - func.runtime = BASE_RUNTIME; + // Ensure the runtime is set to a sane value for other plugins + if (func.runtime == RUST_RUNTIME) { + func.runtime = BASE_RUNTIME; + } } }); if (service.provider.runtime === RUST_RUNTIME) { service.provider.runtime = BASE_RUNTIME; } - if (!rustFunctionsFound) { + if (!rustFunctionsFound && strictMode) { throw new Error( `Error: no Rust functions found. ` + `Use 'runtime: ${RUST_RUNTIME}' in global or ` + diff --git a/tests/unit/index.test.js b/tests/unit/index.test.js index 28714cd..77cee25 100644 --- a/tests/unit/index.test.js +++ b/tests/unit/index.test.js @@ -13,6 +13,7 @@ describe("RustPlugin", () => { dockerImage: "notsoftprops/lambda-rust", dockerTag: "latest", dockerless: true, + strictMode: true, }, }, package: {}, @@ -40,6 +41,7 @@ describe("RustPlugin", () => { dockerImage: "softprops/lambda-rust", dockerTag: "latest", dockerless: false, + strictMode: true, }); }); @@ -54,6 +56,7 @@ describe("RustPlugin", () => { dockerImage: "notsoftprops/lambda-rust", dockerTag: "custom-tag", dockerless: true, + strictMode: false, }, }, package: {}, @@ -67,6 +70,7 @@ describe("RustPlugin", () => { dockerImage: "notsoftprops/lambda-rust", dockerTag: "custom-tag", dockerless: true, + strictMode: false, }); }); @@ -128,9 +132,13 @@ describe("RustPlugin", () => { }); it("configures expected localBuildEnv", () => { - assert.deepEqual(plugin.localBuildEnv({}, "linux"), {}, "failed on linux"); assert.deepEqual( - plugin.localBuildEnv({}, "darwin"), + plugin.localBuildEnv({}, {}, "linux"), + {}, + "failed on linux" + ); + assert.deepEqual( + plugin.localBuildEnv({}, {}, "darwin"), { CC_x86_64_unknown_linux_musl: "x86_64-linux-musl-gcc", @@ -140,7 +148,7 @@ describe("RustPlugin", () => { "failed on osx" ); assert.deepEqual( - plugin.localBuildEnv({}, "win32"), + plugin.localBuildEnv({}, {}, "win32"), { CC_x86_64_unknown_linux_musl: "rust-lld", RUSTFLAGS: " -Clinker=rust-lld", @@ -152,32 +160,32 @@ describe("RustPlugin", () => { it("configures expected localSourceDir", () => { assert.equal( - plugin.localSourceDir("dev", "linux"), + plugin.localSourceDir({}, "dev", "linux"), path.join("target", "x86_64-unknown-linux-musl", "debug"), "failed on linux" ); assert.equal( - plugin.localSourceDir("release", "linux"), + plugin.localSourceDir({}, "release", "linux"), path.join("target", "x86_64-unknown-linux-musl", "release"), "failed on linux" ); assert.equal( - plugin.localSourceDir("dev", "darwin"), + plugin.localSourceDir({}, "dev", "darwin"), path.join("target", "x86_64-unknown-linux-musl", "debug"), "failed on osx" ); assert.equal( - plugin.localSourceDir("release", "darwin"), + plugin.localSourceDir({}, "release", "darwin"), path.join("target", "x86_64-unknown-linux-musl", "release"), "failed on osx" ); assert.equal( - plugin.localSourceDir("dev", "win32"), + plugin.localSourceDir({}, "dev", "win32"), path.join("target", "x86_64-unknown-linux-musl", "debug"), "failed on windows" ); assert.equal( - plugin.localSourceDir("release", "win32"), + plugin.localSourceDir({}, "release", "win32"), path.join("target", "x86_64-unknown-linux-musl", "release"), "failed on windows" );