Repository: netlify/zip-it-and-ship-it
Pull request #606 (2021-08-09 10:48:18)

feat: add `rustTargetDirectory` config property
**- Summary**

Currently, Rust functions are built into a temporary directory. The fact that the directory is different each time makes it impossible for build artefacts to be cached in between builds, which has serious performance implications, as building Rust functions from scratch each time is quite expensive.

This PR adds a new configuration property called `rustTargetDirectory`, which allows consumers to specify a target directory.

With https://github.com/netlify/build-image/pull/602 and https://github.com/netlify/build-image/pull/607, we'll be able to use a consistent target directory in our build system by making Netlify Build pass this new configuration property to zip-it-and-ship-it.

**- Test plan**

Existing test expanded.

**- A picture of a cute animal (not mandatory but encouraged)**

![80628c690c8140c90b5bce090b998002](https://user-images.githubusercontent.com/4162329/128695263-f1d2b710-ece8-4f38-9258-8e9184cfab05.jpg)


github-actions[bot]: ## ⏱ Benchmark results

*Comparing with 4a5a4922e0b8793c8b01af6aa55915ba518bc9bf*

### largeDepsEsbuild: 12.8s
 ⬆️ **9.22% increase** vs. 4a5a4922e0b8793c8b01af6aa55915ba518bc9bf
```
^          13.9s                            14s                                                           
│           ┌──┐                            ┌──┐                                                          
│  12.7s    |  |                            |  |           12.5s           12.7s                   12.8s  
│   ┌──┐    |  |                            |  |            ┌──┐            ┌──┐   12.2s            ┌──┐  
│ ──┼──┼────┼──┼───────────10.9s────────────┼──┼────────────┼──┼────────────┼──┼────┌──┐────────────|▒▒|──
│   |  |    |  |   10.6s    ┌──┐            |  |            |  |   10.6s    |  |    |  |            |▒▒|  
│   |  |    |  |    ┌──┐    |  |    9.8s    |  |    9.6s    |  |    ┌──┐    |  |    |  |    10s     |▒▒|  
│   |  |    |  |    |  |    |  |    ┌──┐    |  |    ┌──┐    |  |    |  |    |  |    |  |    ┌──┐    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
└───┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴──>
    T-12    T-11    T-10    T-9     T-8     T-7     T-6     T-5     T-4     T-3     T-2     T-1      T    
```
<details>
<summary>Legend</summary>

- T-30 (4a5a4922e0b8793c8b01af6aa55915ba518bc9bf): 11.6s
- T-29 (38f4d4753a7205b3ec242440b3d2a1bbd866131a): 10.2s
- T-28 (f41a7a28b9b049ade7b656b0dc79deb4f45c829e): 11.6s
- T-27 (65c4b941e2866aab49c77cb55504ddad4bdb50a2): 12.9s
- T-26 (e6490d61a256a27c70f3b602ec37e648d415b442): 10.9s
- T-25 (15787efd3bfac84e0036e96082d071afa67c42c5): 11.3s
- T-24 (1ce8157a7351adbc6c6c751ddc8499e9080536b8): 12.9s
- T-23 (96c833514c1b10081dee2a1c236e05186c2ebe01): 13.2s
- T-22 (5d48d64bea0d963efa9dbe64925baef24002a9a4): 12.4s
- T-21 (bd7206ea53810a73ea9938f4e34e2826a142ae2d): 14.3s
- T-20 (69fdb7b0f312a6e007e6cedd6a40494772756eef): 11.4s
- T-19 (57a644f24c7bfd2c0ab1e19360465a3301157162): 13.8s
- T-18 (a9a9e610e1324bbcbee604561605dd12c8a7c4c8): 13.2s
- T-17 (8e299a25c7449b440f7a07849d73b8f184a3245c): 12.6s
- T-16 (cebf521a0a5e42ee0244108aa86367f74524f1be): 10.5s
- T-15 (b789589e534a4cc26c6a56636039b9a22f07a2e3): 12.9s
- T-14 (2e25a52b4d23522c64a01c78f7dba16291a085cf): 12.3s
- T-13 (fec9333941c4b8d0a6a648fd755ddecca07fc892): 12.1s
- T-12 (bd61ad00330f73d247dac787734abc9efeaba4b1): 12.7s
- T-11 (9c3d239efb5f53d53ada4c2d92db6f48b7401096): 13.9s
- T-10 (d790873c4cfb82de3f9d5cc64c2ecb45f4c4112f): 10.6s
- T-9 (c18abffd799ee05a0336a34fffd9a1d48e71c550): 10.9s
- T-8 (a0b35e4de9ee40eb9eed4fdd85a16796983fe154): 9.8s
- T-7 (f9084030bf84398023793983490c294b7b8ff483): 14s
- T-6 (b8eb5f8da62d48468c4aff35f2ed65b175bb14c7): 9.6s
- T-5 (cc6070c8f5a0b44163e3167be9b0beab9bf1c644): 12.5s
- T-4 (d1f77ee0caf96a19702d81abd85b8814ed62ab1c): 10.6s
- T-3 (2a11f56404dfdb6d92881751e9a21ed11f432ec8): 12.7s
- T-2 (30ec7f6a4e97007c2f5e0c40b85b196884acd10f): 12.2s
- T-1 (49c33d8209130930cdeed3b953ac874047cba15a): 10s
- **T (current commit): 12.8s**</details>
### largeDepsZisi: 1m 10.2s
 ⬆️ **4.67% increase** vs. 4a5a4922e0b8793c8b01af6aa55915ba518bc9bf
```
^         1m 17.1s                                                                                        
│           ┌──┐                          1m 15.1s                                                        
│ 1m 7.9s   |  |                            ┌──┐                          1m 8.7s                 1m 10.2s
│   ┌──┐    |  |                            |  |          1m 4.1s           ┌──┐                    ┌──┐  
│   |  |    |  |                            |  |            ┌──┐            |  |  1m 1.5s           |▒▒|  
│ ──┼──┼────┼──┼───────────58.4s────────────┼──┼────────────┼──┼────────────┼──┼────┌──┐────────────|▒▒|──
│   |  |    |  |   54.3s    ┌──┐            |  |            |  |   54.9s    |  |    |  |   52.8s    |▒▒|  
│   |  |    |  |    ┌──┐    |  |   51.8s    |  |    51s     |  |    ┌──┐    |  |    |  |    ┌──┐    |▒▒|  
│   |  |    |  |    |  |    |  |    ┌──┐    |  |    ┌──┐    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
└───┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴──>
    T-12    T-11    T-10    T-9     T-8     T-7     T-6     T-5     T-4     T-3     T-2     T-1      T    
```
<details>
<summary>Legend</summary>

- T-30 (4a5a4922e0b8793c8b01af6aa55915ba518bc9bf): 1m 6.9s
- T-29 (38f4d4753a7205b3ec242440b3d2a1bbd866131a): 59.9s
- T-28 (f41a7a28b9b049ade7b656b0dc79deb4f45c829e): 1m 5.4s
- T-27 (65c4b941e2866aab49c77cb55504ddad4bdb50a2): 1m 15s
- T-26 (e6490d61a256a27c70f3b602ec37e648d415b442): 59s
- T-25 (15787efd3bfac84e0036e96082d071afa67c42c5): 55.9s
- T-24 (1ce8157a7351adbc6c6c751ddc8499e9080536b8): 1m 2.9s
- T-23 (96c833514c1b10081dee2a1c236e05186c2ebe01): 1m 3.6s
- T-22 (5d48d64bea0d963efa9dbe64925baef24002a9a4): 1m 2.1s
- T-21 (bd7206ea53810a73ea9938f4e34e2826a142ae2d): 1m 11.7s
- T-20 (69fdb7b0f312a6e007e6cedd6a40494772756eef): 54.7s
- T-19 (57a644f24c7bfd2c0ab1e19360465a3301157162): 1m 6.5s
- T-18 (a9a9e610e1324bbcbee604561605dd12c8a7c4c8): 1m 9.5s
- T-17 (8e299a25c7449b440f7a07849d73b8f184a3245c): 1m 3.8s
- T-16 (cebf521a0a5e42ee0244108aa86367f74524f1be): 51.2s
- T-15 (b789589e534a4cc26c6a56636039b9a22f07a2e3): 1m 8.3s
- T-14 (2e25a52b4d23522c64a01c78f7dba16291a085cf): 1m 3.4s
- T-13 (fec9333941c4b8d0a6a648fd755ddecca07fc892): 1m 4.1s
- T-12 (bd61ad00330f73d247dac787734abc9efeaba4b1): 1m 7.9s
- T-11 (9c3d239efb5f53d53ada4c2d92db6f48b7401096): 1m 17.1s
- T-10 (d790873c4cfb82de3f9d5cc64c2ecb45f4c4112f): 54.3s
- T-9 (c18abffd799ee05a0336a34fffd9a1d48e71c550): 58.4s
- T-8 (a0b35e4de9ee40eb9eed4fdd85a16796983fe154): 51.8s
- T-7 (f9084030bf84398023793983490c294b7b8ff483): 1m 15.1s
- T-6 (b8eb5f8da62d48468c4aff35f2ed65b175bb14c7): 51s
- T-5 (cc6070c8f5a0b44163e3167be9b0beab9bf1c644): 1m 4.1s
- T-4 (d1f77ee0caf96a19702d81abd85b8814ed62ab1c): 54.9s
- T-3 (2a11f56404dfdb6d92881751e9a21ed11f432ec8): 1m 8.7s
- T-2 (30ec7f6a4e97007c2f5e0c40b85b196884acd10f): 1m 1.5s
- T-1 (49c33d8209130930cdeed3b953ac874047cba15a): 52.8s
- **T (current commit): 1m 10.2s**</details>
<!--delta:benchmark@{}-->

Patch:
diff --git a/README.md b/README.md
index ad46964..fc45c25 100644
--- a/README.md
+++ b/README.md
@@ -134,6 +134,17 @@ The following properties are accepted:
   - `12.x` (or `nodejs12.x`)
   - `14.x` (or `nodejs14.x`)
 
+- `rustTargetDirectory`
+
+  - _Type_: `string`
+  - _Default value_: Path to a temporary directory
+
+  The path to use as the Cargo target directory when bundling Rust functions from source. When a value is not specified,
+  a random temporary directory will be used.
+
+  The `[name]` placeholder will be replaced by the name of the function, allowing you to use it to construct the path to
+  the target directory.
+
 #### `featureFlags`
 
 See [feature flags](#feature-flags).
diff --git a/src/runtimes/rust/builder.js b/src/runtimes/rust/builder.js
index a103c42..b199e4f 100644
--- a/src/runtimes/rust/builder.js
+++ b/src/runtimes/rust/builder.js
@@ -4,6 +4,7 @@ const { promisify } = require('util')
 
 const pReadFile = promisify(readFile)
 
+const makeDir = require('make-dir')
 const tmp = require('tmp-promise')
 const toml = require('toml')
 
@@ -12,12 +13,10 @@ const { runCommand } = require('../../utils/shell')
 
 const { BUILD_TARGET, MANIFEST_NAME } = require('./constants')
 
-const build = async ({ srcDir }) => {
+const build = async ({ config, name, srcDir }) => {
   await installBuildTarget()
 
-  // We compile the binary to a temporary directory so that we don't pollute
-  // the user's functions directory.
-  const { path: targetDirectory } = await tmp.dir()
+  const targetDirectory = await getTargetDirectory({ config, name })
   const functionName = basename(srcDir)
 
   try {
@@ -66,6 +65,26 @@ const checkRustToolchain = async () => {
   }
 }
 
+// Returns the path of the Cargo target directory.
+const getTargetDirectory = async ({ config, name }) => {
+  const { rustTargetDirectory } = config
+
+  // If the config includes a `rustTargetDirectory` path, we'll use that.
+  if (rustTargetDirectory) {
+    // We replace the [name] placeholder with the name of the function.
+    const path = rustTargetDirectory.replace(/\[name]/g, name)
+
+    await makeDir(path)
+
+    return path
+  }
+
+  // If the directory hasn't been configured, we'll use a temporary directory.
+  const { path } = await tmp.dir()
+
+  return path
+}
+
 let buildTargetInstallation
 
 // Installs the build target defined in `BUILD_TARGET`. The Promise is saved to
diff --git a/src/runtimes/rust/index.js b/src/runtimes/rust/index.js
index 37271ae..332c8da 100644
--- a/src/runtimes/rust/index.js
+++ b/src/runtimes/rust/index.js
@@ -99,7 +99,7 @@ const zipFunction = async function ({ config, destFolder, filename, mainFile, ru
   // the resulting binary. Otherwise, we're dealing with a binary so we zip it
   // directly.
   if (isSource) {
-    const { path: binaryPath, stat: binaryStat } = await build({ srcDir })
+    const { path: binaryPath, stat: binaryStat } = await build({ config, name: filename, srcDir })
 
     await zipBinary({ ...zipOptions, srcPath: binaryPath, stat: binaryStat })
   } else {


Test patch:
diff --git a/tests/fixtures/rust-source/rust-func-2/.gitignore b/tests/fixtures/rust-source/rust-func-2/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/tests/fixtures/rust-source/rust-func-2/.gitignore
@@ -0,0 +1,1 @@
+/target
diff --git a/tests/fixtures/rust-source/rust-func-2/Cargo.lock b/tests/fixtures/rust-source/rust-func-2/Cargo.lock
new file mode 100644
index 0000000..ec2c4de
--- /dev/null
+++ b/tests/fixtures/rust-source/rust-func-2/Cargo.lock
@@ -0,0 +1,713 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "async-stream"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "aws_lambda_events"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "663ef110325f68726f4bc51d12c610b9700f70e8bb8a55279cdeca01b12b5491"
+dependencies = [
+ "base64",
+ "bytes 0.5.6",
+ "chrono",
+ "http",
+ "http-serde",
+ "serde",
+ "serde_derive",
+ "serde_json",
+]
+
+[[package]]
+name = "base64"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
+
+[[package]]
+name = "bytes"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bytes"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+dependencies = [
+ "libc",
+ "num-integer",
+ "num-traits",
+ "serde",
+ "time",
+ "winapi",
+]
+
+[[package]]
+name = "colored"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
+dependencies = [
+ "atty",
+ "lazy_static",
+ "winapi",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "futures"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121"
+dependencies = [
+ "autocfg",
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282"
+
+[[package]]
+name = "futures-task"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae"
+
+[[package]]
+name = "futures-util"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967"
+dependencies = [
+ "autocfg",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "proc-macro-hack",
+ "proc-macro-nested",
+ "slab",
+]
+
+[[package]]
+name = "hello"
+version = "0.1.0"
+dependencies = [
+ "aws_lambda_events",
+ "http",
+ "lambda_runtime",
+ "log",
+ "simple_logger",
+ "tokio",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "http"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
+dependencies = [
+ "bytes 1.0.1",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9"
+dependencies = [
+ "bytes 1.0.1",
+ "http",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "http-serde"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25698ac7002625796d5a7df8f0602400571da944c2edc1d5c268a6947dd4f692"
+dependencies = [
+ "http",
+ "serde",
+]
+
+[[package]]
+name = "httparse"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
+
+[[package]]
+name = "httpdate"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
+
+[[package]]
+name = "hyper"
+version = "0.14.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7728a72c4c7d72665fde02204bcbd93b247721025b222ef78606f14513e0fd03"
+dependencies = [
+ "bytes 1.0.1",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+
+[[package]]
+name = "lambda_runtime"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9b08856997d11ca8122121b26b17a27ef1dce689d71ccd754e051f2417aebdd"
+dependencies = [
+ "async-stream",
+ "bytes 1.0.1",
+ "futures",
+ "http",
+ "hyper",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tokio-stream",
+ "tower-service",
+ "tracing",
+ "tracing-error",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
+
+[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
+
+[[package]]
+name = "mio"
+version = "0.7.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
+dependencies = [
+ "libc",
+ "log",
+ "miow",
+ "ntapi",
+ "winapi",
+]
+
+[[package]]
+name = "miow"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "ntapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
+[[package]]
+name = "proc-macro-nested"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
+name = "serde"
+version = "1.0.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "simple_logger"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd57f17c093ead1d4a1499dc9acaafdd71240908d64775465543b8d9a9f1d198"
+dependencies = [
+ "atty",
+ "chrono",
+ "colored",
+ "log",
+ "winapi",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
+
+[[package]]
+name = "socket2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.73"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "time"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
+dependencies = [
+ "libc",
+ "wasi",
+ "winapi",
+]
+
+[[package]]
+name = "tokio"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2602b8af3767c285202012822834005f596c811042315fa7e9f5b12b2a43207"
+dependencies = [
+ "autocfg",
+ "bytes 1.0.1",
+ "libc",
+ "memchr",
+ "mio",
+ "num_cpus",
+ "pin-project-lite",
+ "tokio-macros",
+ "winapi",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tower-service"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
+
+[[package]]
+name = "tracing"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
+dependencies = [
+ "cfg-if",
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "tracing-error"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4d7c0b83d4a500748fa5879461652b361edf5c9d51ede2a2ac03875ca185e24"
+dependencies = [
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab69019741fca4d98be3c62d2b75254528b5432233fd8a4d2739fec20278de48"
+dependencies = [
+ "sharded-slab",
+ "thread_local",
+ "tracing-core",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "want"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+dependencies = [
+ "log",
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/tests/fixtures/rust-source/rust-func-2/Cargo.toml b/tests/fixtures/rust-source/rust-func-2/Cargo.toml
new file mode 100644
index 0000000..99de224
--- /dev/null
+++ b/tests/fixtures/rust-source/rust-func-2/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+edition = "2018"
+name = "hello"
+version = "0.1.0"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+aws_lambda_events = "0.4.0"
+http = "0.2.4"
+lambda_runtime = "0.3.0"
+log = "0.4.14"
+simple_logger = "1.11.0"
+tokio = "1.6.1"
diff --git a/tests/fixtures/rust-source/rust-func-2/src/main.rs b/tests/fixtures/rust-source/rust-func-2/src/main.rs
new file mode 100644
index 0000000..f8987cb
--- /dev/null
+++ b/tests/fixtures/rust-source/rust-func-2/src/main.rs
@@ -0,0 +1,29 @@
+use aws_lambda_events::event::apigw::{ApiGatewayProxyRequest, ApiGatewayProxyResponse};
+use aws_lambda_events::encodings::Body;
+use http::header::HeaderMap;
+use lambda_runtime::{handler_fn, Context, Error};
+use log::LevelFilter;
+use simple_logger::SimpleLogger;
+
+#[tokio::main]
+async fn main() -> Result<(), Error> {
+    SimpleLogger::new().with_level(LevelFilter::Info).init().unwrap();
+
+    let func = handler_fn(my_handler);
+    lambda_runtime::run(func).await?;
+    Ok(())
+}
+
+pub(crate) async fn my_handler(event: ApiGatewayProxyRequest, _ctx: Context) -> Result<ApiGatewayProxyResponse, Error> {
+    let path = event.path.unwrap();
+
+    let resp = ApiGatewayProxyResponse {
+        status_code: 200,
+        headers: HeaderMap::new(),
+        multi_value_headers: HeaderMap::new(),
+        body: Some(Body::Text(format!("Hello from '{}'", path))),
+        is_base64_encoded: Some(false),
+    };
+
+    Ok(resp)
+}
\ No newline at end of file
diff --git a/tests/main.js b/tests/main.js
index 5cf5ad9..e6e6d7c 100644
--- a/tests/main.js
+++ b/tests/main.js
@@ -1661,13 +1661,24 @@ test.serial(
 )
 
 test.serial('Builds Rust functions from source if the `buildRustSource` feature flag is enabled', async (t) => {
+  const targetDirectory = await tmpName({ prefix: `zip-it-test-rust-function-[name]` })
+  const tmpDirectory = await tmpName({ prefix: `zip-it-test-` })
+
   shellUtilsStub.callsFake(async (...args) => {
-    const [rootCommand] = args
+    const [rootCommand, , { cwd, env: environment } = {}] = args
 
     if (rootCommand === 'cargo') {
-      const directory = join(args[2].env.CARGO_TARGET_DIR, args[1][2], 'release')
+      const directory = join(environment.CARGO_TARGET_DIR, args[1][2], 'release')
       const binaryPath = join(directory, 'hello')
 
+      if (cwd.endsWith('rust-func-1')) {
+        t.is(dirname(environment.CARGO_TARGET_DIR), dirname(tmpDirectory))
+      }
+
+      if (cwd.endsWith('rust-func-2')) {
+        t.is(environment.CARGO_TARGET_DIR, targetDirectory.replace('[name]', 'rust-func-2'))
+      }
+
       await makeDir(directory)
 
       return pWriteFile(binaryPath, '')
@@ -1676,17 +1687,25 @@ test.serial('Builds Rust functions from source if the `buildRustSource` feature
 
   const fixtureName = 'rust-source'
   const { files } = await zipFixture(t, fixtureName, {
+    length: 2,
     opts: {
+      config: {
+        'rust-func-2': {
+          rustTargetDirectory: targetDirectory,
+        },
+      },
       featureFlags: {
         buildRustSource: true,
       },
     },
   })
 
-  t.is(shellUtilsStub.callCount, 2)
+  t.is(files.length, 2)
+  t.is(shellUtilsStub.callCount, 3)
 
   const { args: call1 } = shellUtilsStub.getCall(0)
   const { args: call2 } = shellUtilsStub.getCall(1)
+  const { args: call3 } = shellUtilsStub.getCall(1)
 
   t.is(call1[0], 'rustup')
   t.is(call1[1][0], 'target')
@@ -1698,9 +1717,18 @@ test.serial('Builds Rust functions from source if the `buildRustSource` feature
   t.is(call2[1][1], '--target')
   t.is(call2[1][2], 'x86_64-unknown-linux-musl')
 
+  t.is(call2[0], call3[0])
+  t.is(call2[1][0], call3[1][0])
+  t.is(call2[1][1], call3[1][1])
+  t.is(call2[1][2], call3[1][2])
+
   t.is(files[0].mainFile, join(FIXTURES_DIR, fixtureName, 'rust-func-1', 'src', 'main.rs'))
   t.is(files[0].name, 'rust-func-1')
   t.is(files[0].runtime, 'rs')
+
+  t.is(files[1].mainFile, join(FIXTURES_DIR, fixtureName, 'rust-func-2', 'src', 'main.rs'))
+  t.is(files[1].name, 'rust-func-2')
+  t.is(files[1].runtime, 'rs')
 })
 
 test.serial('Throws an error with an informative message when the Rust toolchain is missing', async (t) => {