diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4bf4e13..c74fb75 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,6 +8,11 @@ updates: - "dependencies" - "rust" - "skip changelog" + groups: + libcnb: + patterns: + - "libcnb*" + - "libherokubuildpack" - package-ecosystem: "github-actions" directory: "/" schedule: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55bc9a3..ce36991 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - name: Update Rust toolchain run: rustup update - name: Rust Cache - uses: Swatinem/rust-cache@v2.5.0 + uses: Swatinem/rust-cache@v2.5.1 - name: Clippy run: cargo clippy --all-targets --locked -- --deny warnings - name: rustfmt @@ -36,7 +36,7 @@ jobs: - name: Update Rust toolchain run: rustup update - name: Rust Cache - uses: Swatinem/rust-cache@v2.5.0 + uses: Swatinem/rust-cache@v2.5.1 - name: Run unit tests run: cargo test --locked @@ -58,9 +58,9 @@ jobs: - name: Install Rust linux-musl target run: rustup target add x86_64-unknown-linux-musl - name: Rust Cache - uses: Swatinem/rust-cache@v2.5.0 + uses: Swatinem/rust-cache@v2.5.1 - name: Install Pack CLI - uses: buildpacks/github-actions/setup-pack@v5.2.0 + uses: buildpacks/github-actions/setup-pack@v5.3.0 - name: Pull builder image run: docker pull ${{ env.INTEGRATION_TEST_CNB_BUILDER }} # The integration tests are annotated with the `ignore` attribute, allowing us to run diff --git a/CHANGELOG.md b/CHANGELOG.md index 007939f..238d071 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,23 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Removed + +- Removed support for Salesforce Functions. ([#83](https://github.com/heroku/buildpacks-python/pull/83)) + +## [0.5.0] - 2023-07-24 + ### Changed +- User-provided environment variables are now propagated to subprocesses such as `pip install`. ([#65](https://github.com/heroku/buildpacks-python/pull/65)) +- Updated pip from 23.1.2 to 23.2.1. ([#67](https://github.com/heroku/buildpacks-python/pull/67) and [#76](https://github.com/heroku/buildpacks-python/pull/76)) - Updated setuptools from 67.8.0 to 68.0.0. ([#51](https://github.com/heroku/buildpacks-python/pull/51)) +- Updated wheel from 0.40.0 to 0.41.0. ([#78](https://github.com/heroku/buildpacks-python/pull/78)) ## [0.4.0] - 2023-06-07 @@ -37,10 +46,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- The `PYTHONHOME` environment variable is now set to work around uWSGI not handling relocated Python installs correctly. ([#25](https://github.com/heroku/buildpacks-python/pull/25)) +- The `PYTHONHOME` environment variable is now set, to work around uWSGI not handling relocated Python installs correctly. ([#25](https://github.com/heroku/buildpacks-python/pull/25)) ## [0.1.0] - 2023-03-06 ### Added - Initial implementation. ([#3](https://github.com/heroku/buildpacks-python/pull/3)) + +[unreleased]: https://github.com/heroku/buildpacks-python/compare/v0.5.0...HEAD +[0.5.0]: https://github.com/heroku/buildpacks-python/compare/v0.4.0...v0.5.0 +[0.4.0]: https://github.com/heroku/buildpacks-python/compare/v0.3.0...v0.4.0 +[0.3.0]: https://github.com/heroku/buildpacks-python/compare/v0.2.0...v0.3.0 +[0.2.0]: https://github.com/heroku/buildpacks-python/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/heroku/buildpacks-python/releases/tag/v0.1.0 diff --git a/Cargo.lock b/Cargo.lock index 6d2ccc0..460ba66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,30 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -29,6 +47,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -62,6 +95,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "bollard" version = "0.14.0" @@ -115,18 +154,18 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "camino" -version = "1.1.4" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" dependencies = [ "serde", ] @@ -185,23 +224,32 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "deranged" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" +dependencies = [ + "serde", +] + [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -228,15 +276,6 @@ dependencies = [ "regex", ] -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.0.0" @@ -345,6 +384,12 @@ dependencies = [ "slab", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "h2" version = "0.3.20" @@ -378,18 +423,9 @@ checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -433,9 +469,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -524,35 +560,15 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" - -[[package]] -name = "instant" -version = "0.1.12" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys", -] +checksum = "2c785eefb63ebd0e33416dfcb8d6da0bf27ce752843a45632a67bf10d4d4b5c4" [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" @@ -635,7 +651,7 @@ checksum = "0b41b862dfd56b90b266cc5eeb7387bbe1d7912f713af70d988bc9a52d7fe935" dependencies = [ "bollard", "cargo_metadata", - "fastrand 2.0.0", + "fastrand", "fs_extra", "libcnb-data", "libcnb-package", @@ -656,9 +672,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.9" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" dependencies = [ "cc", "pkg-config", @@ -667,9 +683,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" [[package]] name = "log" @@ -705,23 +721,32 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -746,18 +771,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", @@ -766,9 +791,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -784,9 +809,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -802,15 +827,14 @@ dependencies = [ "libherokubuildpack", "serde", "tar", - "toml", "ureq", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -821,7 +845,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -830,23 +854,37 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.8.4" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "ring" @@ -863,15 +901,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustix" -version = "0.37.20" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ - "bitflags", + "bitflags 2.3.3", "errno", - "io-lifetimes", "libc", "linux-raw-sys", "windows-sys", @@ -879,13 +922,13 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" +checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.2", "sct", ] @@ -899,11 +942,21 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.101.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "sct" @@ -917,27 +970,27 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.164" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "0a5bf42b8d227d4abf38a1ddb08602e229108a517cd4e5bb28f9c7eaafdce5c0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "741e124f5485c7e60c03b043f79f320bff3527f4bbf12cf3831750dc46a0ec2c" dependencies = [ "proc-macro2", "quote", @@ -946,9 +999,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -957,9 +1010,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.12" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" +checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" dependencies = [ "proc-macro2", "quote", @@ -1029,9 +1082,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "syn" -version = "2.0.22" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -1040,24 +1093,22 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" dependencies = [ "filetime", "libc", - "xattr", ] [[package]] name = "tempfile" -version = "3.6.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" dependencies = [ - "autocfg", "cfg-if", - "fastrand 1.9.0", + "fastrand", "redox_syscall 0.3.5", "rustix", "windows-sys", @@ -1074,18 +1125,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", @@ -1094,10 +1145,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" dependencies = [ + "deranged", "itoa", "serde", "time-core", @@ -1112,9 +1164,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ "time-core", ] @@ -1136,11 +1188,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -1177,9 +1230,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", @@ -1198,9 +1251,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.11" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ "indexmap 2.0.0", "serde", @@ -1249,9 +1302,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -1278,7 +1331,7 @@ dependencies = [ "log", "once_cell", "rustls", - "rustls-webpki", + "rustls-webpki 0.100.1", "url", "webpki-roots", ] @@ -1395,7 +1448,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" dependencies = [ - "rustls-webpki", + "rustls-webpki 0.100.1", ] [[package]] @@ -1460,9 +1513,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1517,18 +1570,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.7" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "8bd122eb777186e60c3fdf765a58ac76e41c582f1f535fbf3314434c6b58f3f7" dependencies = [ "memchr", ] - -[[package]] -name = "xattr" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" -dependencies = [ - "libc", -] diff --git a/Cargo.toml b/Cargo.toml index 86790b7..8a5143d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,7 @@ indoc = "2" libcnb = "0.13" libherokubuildpack = { version = "0.13", default-features = false, features = ["log"] } serde = "1" -tar = "0.4" -toml = "0.7" +tar = { version = "0.4", default-features = false } ureq = { version = "2", default-features = false, features = ["tls"] } [dev-dependencies] diff --git a/buildpack.toml b/buildpack.toml index c56de8b..b401acd 100644 --- a/buildpack.toml +++ b/buildpack.toml @@ -2,12 +2,11 @@ api = "0.9" [buildpack] id = "heroku/python" -version = "0.4.0" +version = "0.5.0" name = "Python" homepage = "https://github.com/heroku/buildpacks-python" description = "Heroku's official Python Cloud Native Buildpack." keywords = ["python", "heroku"] -clear-env = true [[buildpack.licenses]] type = "BSD-3-Clause" diff --git a/requirements/pip.txt b/requirements/pip.txt index 240ab1a..0fe1be6 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -1 +1 @@ -pip==23.1.2 +pip==23.2.1 diff --git a/requirements/wheel.txt b/requirements/wheel.txt index e8f5aac..1244ba1 100644 --- a/requirements/wheel.txt +++ b/requirements/wheel.txt @@ -1 +1 @@ -wheel==0.40.0 +wheel==0.41.0 diff --git a/src/errors.rs b/src/errors.rs index efdd9f2..8373ffb 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,10 +1,8 @@ use crate::layers::pip_dependencies::PipDependenciesLayerError; use crate::layers::python::PythonLayerError; use crate::package_manager::DeterminePackageManagerError; -use crate::project_descriptor::ProjectDescriptorError; use crate::python_version::{PythonVersion, PythonVersionError, DEFAULT_PYTHON_VERSION}; use crate::runtime_txt::{ParseRuntimeTxtError, RuntimeTxtError}; -use crate::salesforce_functions::{CheckSalesforceFunctionError, FUNCTION_RUNTIME_PROGRAM_NAME}; use crate::utils::{CommandError, DownloadUnpackArchiveError}; use crate::BuildpackError; use indoc::{formatdoc, indoc}; @@ -42,7 +40,6 @@ pub(crate) fn on_error(error: libcnb::Error) { fn on_buildpack_error(error: BuildpackError) { match error { - BuildpackError::CheckSalesforceFunction(error) => on_check_salesforce_function_error(error), BuildpackError::DetectIo(io_error) => log_io_error( "Unable to complete buildpack detection", "determining if the Python buildpack should be run for this application", @@ -50,30 +47,11 @@ fn on_buildpack_error(error: BuildpackError) { ), BuildpackError::DeterminePackageManager(error) => on_determine_package_manager_error(error), BuildpackError::PipDependenciesLayer(error) => on_pip_dependencies_layer_error(error), - BuildpackError::ProjectDescriptor(error) => on_project_descriptor_error(error), BuildpackError::PythonLayer(error) => on_python_layer_error(error), BuildpackError::PythonVersion(error) => on_python_version_error(error), }; } -fn on_project_descriptor_error(error: ProjectDescriptorError) { - match error { - ProjectDescriptorError::Io(io_error) => log_io_error( - "Unable to read project.toml", - "reading the (optional) project.toml file", - &io_error, - ), - ProjectDescriptorError::Parse(toml_error) => log_error( - "Invalid project.toml", - formatdoc! {" - A parsing/validation error error occurred whilst loading the project.toml file. - - Details: {toml_error} - "}, - ), - }; -} - fn on_determine_package_manager_error(error: DeterminePackageManagerError) { match error { DeterminePackageManagerError::Io(io_error) => log_io_error( @@ -239,42 +217,6 @@ fn on_pip_dependencies_layer_error(error: PipDependenciesLayerError) { }; } -fn on_check_salesforce_function_error(error: CheckSalesforceFunctionError) { - match error { - CheckSalesforceFunctionError::Io(io_error) => log_io_error( - "Unable to run the Salesforce Functions self-check command", - &format!("running the '{FUNCTION_RUNTIME_PROGRAM_NAME} check' command"), - &io_error, - ), - CheckSalesforceFunctionError::NonZeroExitStatus(output) => log_error( - "The Salesforce Functions self-check failed", - formatdoc! {" - The '{FUNCTION_RUNTIME_PROGRAM_NAME} check' command failed ({exit_status}), indicating - there is a problem with the Python Salesforce Function in this project. - - Details: - {stderr} - ", - exit_status = output.status, - stderr = String::from_utf8_lossy(&output.stderr), - }, - ), - CheckSalesforceFunctionError::ProgramNotFound => log_error( - "The Salesforce Functions package is not installed", - formatdoc! {" - The '{FUNCTION_RUNTIME_PROGRAM_NAME}' program that is required for Python Salesforce - Functions could not be found. - - Check that the 'salesforce-functions' Python package is listed as a - dependency in 'requirements.txt'. - - If this project is not intended to be a Salesforce Function, remove the - 'type = \"function\"' declaration from 'project.toml' to skip this check. - "}, - ), - }; -} - fn log_io_error(header: &str, occurred_whilst: &str, io_error: &io::Error) { // We don't suggest opening a support ticket, since a subset of I/O errors can be caused // by issues in the application. In the future, perhaps we should try and split these out? diff --git a/src/layers/python.rs b/src/layers/python.rs index 8b75d66..8656628 100644 --- a/src/layers/python.rs +++ b/src/layers/python.rs @@ -321,6 +321,8 @@ fn generate_layer_env(layer_path: &Path, python_version: &PythonVersion) -> Laye // However, the uWSGI package uses the wrong `sysconfig` APIs so tries to reference the old // compile location, unless we override that by setting `PYTHONHOME`: // https://github.com/unbit/uwsgi/issues/2525 + // In addition, some legacy apps have `PYTHONHOME` set to an invalid value, so if we did not + // set it explicitly here, Python would fail to run both during the build and at runtime. .chainable_insert( Scope::All, ModificationBehavior::Override, diff --git a/src/main.rs b/src/main.rs index 6a2b637..6de0acf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,10 +9,8 @@ mod errors; mod layers; mod package_manager; mod packaging_tool_versions; -mod project_descriptor; mod python_version; mod runtime_txt; -mod salesforce_functions; mod utils; use crate::layers::pip_cache::PipCacheLayer; @@ -20,9 +18,7 @@ use crate::layers::pip_dependencies::{PipDependenciesLayer, PipDependenciesLayer use crate::layers::python::{PythonLayer, PythonLayerError}; use crate::package_manager::{DeterminePackageManagerError, PackageManager}; use crate::packaging_tool_versions::PackagingToolVersions; -use crate::project_descriptor::ProjectDescriptorError; use crate::python_version::PythonVersionError; -use crate::salesforce_functions::CheckSalesforceFunctionError; use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; use libcnb::data::layer_name; use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; @@ -55,8 +51,6 @@ impl Buildpack for PythonBuildpack { fn build(&self, context: BuildContext) -> libcnb::Result { // We perform all project analysis up front, so the build can fail early if the config is invalid. // TODO: Add a "Build config" header and list all config in one place? - let is_function = salesforce_functions::is_function_project(&context.app_dir) - .map_err(BuildpackError::ProjectDescriptor)?; let package_manager = package_manager::determine_package_manager(&context.app_dir) .map_err(BuildpackError::DeterminePackageManager)?; @@ -66,10 +60,10 @@ impl Buildpack for PythonBuildpack { let packaging_tool_versions = PackagingToolVersions::default(); // We inherit the current process's env vars, since we want `PATH` and `HOME` from the OS - // to be set, so that later commands can find tools like Git in the stack image. We exclude - // user-provided env vars (by setting `clear-env` to true in `buildpack.toml`) to prevent an - // app's env vars from breaking internal buildpack commands. Any buildpack steps that need - // user-provided env vars must explicitly retrieve them via `context.platform.env`. + // to be set (so that later commands can find tools like Git in the stack image), along + // with previous-buildpack or user-provided env vars (so that features like env vars in + // in requirements files work). We protect against broken user-provided env vars by + // making sure that buildpack env vars take precedence in layers envs and command usage. let mut command_env = Env::from_current(); // Create the layer containing the Python runtime, and the packages `pip`, `setuptools` and `wheel`. @@ -86,7 +80,7 @@ impl Buildpack for PythonBuildpack { // Create the layers for the application dependencies and package manager cache. // In the future support will be added for package managers other than pip. - let dependencies_layer_env = match package_manager { + match package_manager { PackageManager::Pip => { log_header("Installing dependencies using Pip"); let pip_cache_layer = context.handle_layer( @@ -106,20 +100,8 @@ impl Buildpack for PythonBuildpack { pip_layer.env } }; - command_env = dependencies_layer_env.apply(Scope::Build, &command_env); - if is_function { - log_header("Validating Salesforce Function"); - salesforce_functions::check_function(&command_env) - .map_err(BuildpackError::CheckSalesforceFunction)?; - log_info("Function passed validation."); - - BuildResultBuilder::new() - .launch(salesforce_functions::launch_config()) - .build() - } else { - BuildResultBuilder::new().build() - } + BuildResultBuilder::new().build() } fn on_error(&self, error: libcnb::Error) { @@ -129,16 +111,12 @@ impl Buildpack for PythonBuildpack { #[derive(Debug)] pub(crate) enum BuildpackError { - /// Errors running the `sf-functions-python check` command. - CheckSalesforceFunction(CheckSalesforceFunctionError), /// IO errors when performing buildpack detection. DetectIo(io::Error), /// Errors determining which Python package manager to use for a project. DeterminePackageManager(DeterminePackageManagerError), /// Errors installing the project's dependencies into a layer using Pip. PipDependenciesLayer(PipDependenciesLayerError), - /// Errors reading and parsing a `project.toml` file. - ProjectDescriptor(ProjectDescriptorError), /// Errors installing Python and required packaging tools into a layer. PythonLayer(PythonLayerError), /// Errors determining which Python version to use for a project. diff --git a/src/project_descriptor.rs b/src/project_descriptor.rs deleted file mode 100644 index f5d3f1e..0000000 --- a/src/project_descriptor.rs +++ /dev/null @@ -1,279 +0,0 @@ -use crate::utils; -use serde::Deserialize; -use std::io; -use std::path::Path; - -/// Reads the `com.salesforce.type` field from any `project.toml` in the specified directory. -/// -/// It is permitted for the `project.toml` file not to exist, or for there to be no `com.salesforce` -/// table within the TOML document, in which case `Ok(None)` will be returned. -/// -/// However, an error will be returned if any other IO error occurred, the file is not valid TOML, -/// or the TOML document does not adhere to the schema. -pub(crate) fn read_salesforce_project_type( - app_dir: &Path, -) -> Result, ProjectDescriptorError> { - read_project_descriptor(app_dir).map(|descriptor| { - descriptor - .unwrap_or_default() - .com - .unwrap_or_default() - .salesforce - .map(|salesforce| salesforce.project_type) - }) -} - -/// Reads any `project.toml` file in the specified directory, parsing it into a [`ProjectDescriptor`]. -/// -/// It is permitted for the `project.toml` file not to exist, in which case `Ok(None)` will be returned. -/// -/// However, an error will be returned if any other IO error occurred, the file is not valid TOML, -/// or the TOML document does not adhere to the schema. -fn read_project_descriptor( - app_dir: &Path, -) -> Result, ProjectDescriptorError> { - let project_descriptor_path = app_dir.join("project.toml"); - - utils::read_optional_file(&project_descriptor_path) - .map_err(ProjectDescriptorError::Io)? - .map(|contents| parse(&contents).map_err(ProjectDescriptorError::Parse)) - .transpose() -} - -/// Parse the contents of a project descriptor TOML file into a [`ProjectDescriptor`]. -/// -/// An error will be returned if the string is not valid TOML, or the TOML document does not -/// adhere to the schema. -fn parse(contents: &str) -> Result { - toml::from_str::(contents) -} - -/// Represents a Cloud Native Buildpack project descriptor file (`project.toml`). -/// -/// Currently only fields used by the buildpack are enforced, so this represents only a -/// subset of the upstream CNB project descriptor schema. -/// -/// See: -#[derive(Debug, Default, Deserialize, PartialEq)] -struct ProjectDescriptor { - com: Option, -} - -/// Represents the `com` table in the project descriptor. -#[derive(Debug, Default, Deserialize, PartialEq)] -struct ComTable { - salesforce: Option, -} - -/// Represents the `com.salesforce` table in the project descriptor. -/// -/// Currently only fields used by the buildpack are enforced, so this represents only a -/// subset of the Salesforce-specific project descriptor schema. -/// -/// See: -#[derive(Debug, Deserialize, PartialEq)] -struct SalesforceTable { - #[serde(rename = "type")] - project_type: SalesforceProjectType, -} - -/// The type of a Salesforce project. -/// -/// For now `Function` is the only valid type, however others will be added in the future. -/// -/// Unknown project types are intentionally rejected, since we're prioritising the UX for -/// functions projects where the type may have been mis-spelt, over forward-compatibility. -#[derive(Debug, Deserialize, PartialEq)] -pub(crate) enum SalesforceProjectType { - #[serde(rename = "function")] - Function, -} - -/// Errors that can occur when reading and parsing a `project.toml` file. -#[derive(Debug)] -pub(crate) enum ProjectDescriptorError { - Io(io::Error), - Parse(toml::de::Error), -} - -#[cfg(test)] -mod tests { - use super::*; - use libcnb_test::assert_contains; - - #[test] - fn deserialize_empty_descriptor() { - assert_eq!(parse("").unwrap(), ProjectDescriptor { com: None }); - } - - #[test] - fn deserialize_non_salesforce_descriptor() { - let toml_str = r#" - [_] - schema-version = "0.2" - - [io.buildpacks] - builder = "my-builder" - - [com.example] - key = "value" - "#; - - assert_eq!( - parse(toml_str), - Ok(ProjectDescriptor { - com: Some(ComTable { salesforce: None }) - }) - ); - } - - #[test] - fn deserialize_function_descriptor() { - let toml_str = r#" - [_] - schema-version = "0.2" - - [com.salesforce] - schema-version = "0.1" - id = "example" - description = "Example function" - type = "function" - salesforce-api-version = "56.0" - "#; - - assert_eq!( - parse(toml_str), - Ok(ProjectDescriptor { - com: Some(ComTable { - salesforce: Some(SalesforceTable { - project_type: SalesforceProjectType::Function - }) - }) - }) - ); - } - - #[test] - fn deserialize_minimal_function_descriptor() { - let toml_str = r#" - [com.salesforce] - type = "function" - "#; - - assert_eq!( - parse(toml_str), - Ok(ProjectDescriptor { - com: Some(ComTable { - salesforce: Some(SalesforceTable { - project_type: SalesforceProjectType::Function - }) - }) - }) - ); - } - - #[test] - fn reject_salesforce_table_with_no_project_type() { - let toml_str = r#" - [com.salesforce] - schema-version = "0.1" - id = "example" - "#; - - let error = parse(toml_str).unwrap_err(); - assert_contains!(error.to_string(), "missing field `type`"); - } - - #[test] - fn reject_unknown_salesforce_project_type() { - let toml_str = r#" - [com.salesforce] - type = "some_unknown_type" - "#; - - let error = parse(toml_str).unwrap_err(); - assert_contains!( - error.to_string(), - "unknown variant `some_unknown_type`, expected `function`" - ); - } - - #[test] - fn read_project_descriptor_no_project_toml_file() { - let app_dir = Path::new("tests/fixtures/empty"); - - assert_eq!(read_project_descriptor(app_dir).unwrap(), None); - } - - #[test] - fn read_project_descriptor_non_salesforce() { - let app_dir = Path::new("tests/fixtures/project_toml_non_salesforce"); - - assert_eq!( - read_project_descriptor(app_dir).unwrap(), - Some(ProjectDescriptor { - com: Some(ComTable { salesforce: None }) - }) - ); - } - - #[test] - fn read_project_descriptor_function() { - let app_dir = Path::new("tests/fixtures/salesforce_function_template"); - - assert_eq!( - read_project_descriptor(app_dir).unwrap(), - Some(ProjectDescriptor { - com: Some(ComTable { - salesforce: Some(SalesforceTable { - project_type: SalesforceProjectType::Function - }) - }) - }) - ); - } - - #[test] - fn read_project_descriptor_invalid_project_toml_file() { - let app_dir = Path::new("tests/fixtures/project_toml_invalid"); - - assert!(matches!( - read_project_descriptor(app_dir).unwrap_err(), - ProjectDescriptorError::Parse(_) - )); - } - - #[test] - fn get_salesforce_project_type_missing() { - let app_dir = Path::new("tests/fixtures/empty"); - - assert_eq!(read_salesforce_project_type(app_dir).unwrap(), None); - } - - #[test] - fn get_salesforce_project_type_non_salesforce() { - let app_dir = Path::new("tests/fixtures/project_toml_non_salesforce"); - - assert_eq!(read_salesforce_project_type(app_dir).unwrap(), None); - } - - #[test] - fn get_salesforce_project_type_function() { - let app_dir = Path::new("tests/fixtures/salesforce_function_template"); - - assert_eq!( - read_salesforce_project_type(app_dir).unwrap(), - Some(SalesforceProjectType::Function) - ); - } - - #[test] - fn get_salesforce_project_type_invalid_project_toml_file() { - let app_dir = Path::new("tests/fixtures/project_toml_invalid"); - - assert!(matches!( - read_salesforce_project_type(app_dir).unwrap_err(), - ProjectDescriptorError::Parse(_) - )); - } -} diff --git a/src/salesforce_functions.rs b/src/salesforce_functions.rs deleted file mode 100644 index 90b7476..0000000 --- a/src/salesforce_functions.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::project_descriptor::{self, ProjectDescriptorError, SalesforceProjectType}; -use libcnb::data::launch::{Launch, LaunchBuilder, ProcessBuilder}; -use libcnb::data::process_type; -use libcnb::Env; -use std::io; -use std::path::Path; -use std::process::{Command, Output}; - -/// The program/script name of the Python Functions runtime's CLI. -pub(crate) const FUNCTION_RUNTIME_PROGRAM_NAME: &str = "sf-functions-python"; - -/// Detect whether the specified project directory is that of a Salesforce Function. -/// -/// Returns `Ok(true)` if the specified project directory contains a `project.toml` file with a -/// `com.salesforce.type` of "function". -/// -/// It is permitted for the `project.toml` file not to exist, or for there to be no `com.salesforce` -/// TOML table within the file, in which case `Ok(false)` will be returned. -/// -/// However, an error will be returned if any other IO error occurred, if the `project.toml` file -/// is not valid TOML, or the TOML document does not adhere to the schema. -pub(crate) fn is_function_project(app_dir: &Path) -> Result { - project_descriptor::read_salesforce_project_type(app_dir) - .map(|project_type| project_type == Some(SalesforceProjectType::Function)) -} - -/// Validate the function using the `sf-functions-python check` command. -pub(crate) fn check_function(command_env: &Env) -> Result<(), CheckSalesforceFunctionError> { - // Not using `utils::run_command` since we want to capture output and only - // display it if the check command fails. - Command::new(FUNCTION_RUNTIME_PROGRAM_NAME) - .args(["check", "."]) - .env_clear() - .envs(command_env) - .output() - .map_err(|io_error| match io_error.kind() { - io::ErrorKind::NotFound => CheckSalesforceFunctionError::ProgramNotFound, - _ => CheckSalesforceFunctionError::Io(io_error), - }) - .and_then(|output| { - if output.status.success() { - Ok(()) - } else { - Err(CheckSalesforceFunctionError::NonZeroExitStatus(output)) - } - }) -} - -/// Generate a `launch.toml` configuration for running Python Salesforce Functions. -/// -/// Runs the `sf-functions-python serve` command with suitable options for production. -pub(crate) fn launch_config() -> Launch { - LaunchBuilder::new() - .process( - // TODO: Stop running via bash once the launcher supports env var interpolation: - // https://github.com/buildpacks/rfcs/issues/258 - ProcessBuilder::new(process_type!("web"), ["bash"]) - .args([ - "-c", - &[ - "exec", - FUNCTION_RUNTIME_PROGRAM_NAME, - "serve", - "--host", - "0.0.0.0", - "--port", - "\"${PORT:-8080}\"", - // TODO: Determine optimal number of workers. - "--workers", - "4", - ".", - ] - .join(" "), - ]) - .default(true) - .build(), - ) - .build() -} - -/// Errors that can occur when running the `sf-functions-python check` command. -#[derive(Debug)] -pub(crate) enum CheckSalesforceFunctionError { - Io(io::Error), - NonZeroExitStatus(Output), - ProgramNotFound, -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn is_function_project_no_project_toml() { - assert!(!is_function_project(Path::new("tests/fixtures/empty")).unwrap()); - } - - #[test] - fn is_function_project_non_salesforce_project_toml() { - assert!( - !is_function_project(Path::new("tests/fixtures/project_toml_non_salesforce")).unwrap() - ); - } - - #[test] - fn is_function_project_valid_function_project_toml() { - assert!( - is_function_project(Path::new("tests/fixtures/salesforce_function_template")).unwrap() - ); - } - - #[test] - fn is_function_project_invalid_project_toml() { - assert!(matches!( - is_function_project(Path::new("tests/fixtures/project_toml_invalid")).unwrap_err(), - ProjectDescriptorError::Parse(_) - )); - } -} diff --git a/tests/fixtures/pip_basic/requirements.txt b/tests/fixtures/pip_basic/requirements.txt index fd0f81c..21e4839 100644 --- a/tests/fixtures/pip_basic/requirements.txt +++ b/tests/fixtures/pip_basic/requirements.txt @@ -1,2 +1,2 @@ # This package has been picked since it has no dependencies and is small/fast to install. -typing-extensions==4.4.0 +typing-extensions==4.7.1 diff --git a/tests/fixtures/pip_editable_git_compiled/requirements.txt b/tests/fixtures/pip_editable_git_compiled/requirements.txt index a6710b5..a9b27b0 100644 --- a/tests/fixtures/pip_editable_git_compiled/requirements.txt +++ b/tests/fixtures/pip_editable_git_compiled/requirements.txt @@ -4,5 +4,8 @@ # # A C-based package is used instead of a pure Python package, in order to test that the # Python headers can be found in the `include/pythonX.Y/` directory of the Python layer. +# +# The URL to the package is specified via env var, to test that user-provided env vars +# are propagated to pip for use by its env var interpolation feature. --e git+https://github.com/pypa/wheel@0.40.0#egg=extension.dist&subdirectory=tests/testdata/extension.dist +-e git+${WHEEL_PACKAGE_URL}@0.40.0#egg=extension.dist&subdirectory=tests/testdata/extension.dist diff --git a/tests/fixtures/project_toml_invalid/project.toml b/tests/fixtures/project_toml_invalid/project.toml deleted file mode 100644 index 7a6399a..0000000 --- a/tests/fixtures/project_toml_invalid/project.toml +++ /dev/null @@ -1,5 +0,0 @@ -[_] -schema-version = "0.2" - -[com.salesforce] -# The required fields here are missing. diff --git a/tests/fixtures/project_toml_invalid/requirements.txt b/tests/fixtures/project_toml_invalid/requirements.txt deleted file mode 100644 index e69de29..0000000 diff --git a/tests/fixtures/project_toml_non_salesforce/project.toml b/tests/fixtures/project_toml_non_salesforce/project.toml deleted file mode 100644 index dd8b5ef..0000000 --- a/tests/fixtures/project_toml_non_salesforce/project.toml +++ /dev/null @@ -1,8 +0,0 @@ -[_] -schema-version = "0.2" - -[io.buildpacks] -builder = "my-builder" - -[com.example] -key = "value" diff --git a/tests/fixtures/salesforce_function_fails_self_check/main.py b/tests/fixtures/salesforce_function_fails_self_check/main.py deleted file mode 100644 index b46ee45..0000000 --- a/tests/fixtures/salesforce_function_fails_self_check/main.py +++ /dev/null @@ -1,5 +0,0 @@ -from salesforce_functions import Context, InvocationEvent - - -def function(_event: InvocationEvent[None], _context: Context) -> None: - return None diff --git a/tests/fixtures/salesforce_function_fails_self_check/project.toml b/tests/fixtures/salesforce_function_fails_self_check/project.toml deleted file mode 100644 index 2a44a3a..0000000 --- a/tests/fixtures/salesforce_function_fails_self_check/project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[com.salesforce] -type = "function" -salesforce-api-version = "invalid" diff --git a/tests/fixtures/salesforce_function_fails_self_check/requirements.txt b/tests/fixtures/salesforce_function_fails_self_check/requirements.txt deleted file mode 100644 index ced5be3..0000000 --- a/tests/fixtures/salesforce_function_fails_self_check/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -salesforce-functions diff --git a/tests/fixtures/salesforce_function_missing_package/main.py b/tests/fixtures/salesforce_function_missing_package/main.py deleted file mode 100644 index 80920de..0000000 --- a/tests/fixtures/salesforce_function_missing_package/main.py +++ /dev/null @@ -1,5 +0,0 @@ -from salesforce_functions import Context, InvocationEvent - - -async def function(_event: InvocationEvent[None], _context: Context) -> None: - return None diff --git a/tests/fixtures/salesforce_function_missing_package/project.toml b/tests/fixtures/salesforce_function_missing_package/project.toml deleted file mode 100644 index ef6d5f8..0000000 --- a/tests/fixtures/salesforce_function_missing_package/project.toml +++ /dev/null @@ -1,2 +0,0 @@ -[com.salesforce] -type = "function" diff --git a/tests/fixtures/salesforce_function_missing_package/requirements.txt b/tests/fixtures/salesforce_function_missing_package/requirements.txt deleted file mode 100644 index fbb9d22..0000000 --- a/tests/fixtures/salesforce_function_missing_package/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -# The salesforce-functions package is missing from here. diff --git a/tests/fixtures/salesforce_function_template/README.md b/tests/fixtures/salesforce_function_template/README.md deleted file mode 100644 index 4bcafa9..0000000 --- a/tests/fixtures/salesforce_function_template/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Pythonexample Function - - diff --git a/tests/fixtures/salesforce_function_template/main.py b/tests/fixtures/salesforce_function_template/main.py deleted file mode 100644 index 4c05d20..0000000 --- a/tests/fixtures/salesforce_function_template/main.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Any - -from salesforce_functions import Context, InvocationEvent, get_logger - -# The type of the data payload sent with the invocation event. -# Change this to a more specific type matching the expected payload for -# improved IDE auto-completion and linting coverage. For example: -# `EventPayloadType = dict[str, Any]` -EventPayloadType = Any - -logger = get_logger() - - -async def function(event: InvocationEvent[EventPayloadType], context: Context): - """Describe the function here.""" - - result = await context.org.data_api.query("SELECT Id, Name FROM Account") - logger.info(f"Function successfully queried {result.total_size} account records!") - - return result.records diff --git a/tests/fixtures/salesforce_function_template/payload.json b/tests/fixtures/salesforce_function_template/payload.json deleted file mode 100644 index 0967ef4..0000000 --- a/tests/fixtures/salesforce_function_template/payload.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/tests/fixtures/salesforce_function_template/project.toml b/tests/fixtures/salesforce_function_template/project.toml deleted file mode 100644 index ac505f2..0000000 --- a/tests/fixtures/salesforce_function_template/project.toml +++ /dev/null @@ -1,9 +0,0 @@ -[_] -schema-version = "0.2" - -[com.salesforce] -schema-version = "0.1" -id = "pythonexample" -description = "A Salesforce Function" -type = "function" -salesforce-api-version = "56.0" diff --git a/tests/fixtures/salesforce_function_template/requirements.txt b/tests/fixtures/salesforce_function_template/requirements.txt deleted file mode 100644 index ced5be3..0000000 --- a/tests/fixtures/salesforce_function_template/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -salesforce-functions diff --git a/tests/integration/mod.rs b/tests/integration/mod.rs index 0d295ef..97f548c 100644 --- a/tests/integration/mod.rs +++ b/tests/integration/mod.rs @@ -7,7 +7,6 @@ mod detect; mod package_manager; mod pip; mod python_version; -mod salesforce_functions; const LATEST_PYTHON_3_7: &str = "3.7.17"; const LATEST_PYTHON_3_8: &str = "3.8.17"; diff --git a/tests/integration/pip.rs b/tests/integration/pip.rs index 061c025..0a14caf 100644 --- a/tests/integration/pip.rs +++ b/tests/integration/pip.rs @@ -33,10 +33,12 @@ fn pip_basic_install_and_cache_reuse() { [Installing dependencies using Pip] Running pip install - Collecting typing-extensions==4.4.0 (from -r requirements.txt (line 2)) - Downloading typing_extensions-4.4.0-py3-none-any.whl (26 kB) + Collecting typing-extensions==4.7.1 (from -r requirements.txt (line 2)) + Obtaining dependency information for typing-extensions==4.7.1 from https://files.pythonhosted.org/packages/ec/6b/63cc3df74987c36fe26157ee12e09e8f9db4de771e0f3404263117e75b95/typing_extensions-4.7.1-py3-none-any.whl.metadata + Downloading typing_extensions-4.7.1-py3-none-any.whl.metadata (3.1 kB) + Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) Installing collected packages: typing-extensions - Successfully installed typing-extensions-4.4.0 + Successfully installed typing-extensions-4.7.1 ===> EXPORTING "} ); @@ -59,7 +61,7 @@ fn pip_basic_install_and_cache_reuse() { ----------------- ------- pip {pip_version} setuptools {setuptools_version} - typing_extensions 4.4.0 + typing_extensions 4.7.1 wheel {wheel_version} Defaulting to user installation because normal site-packages is not writeable Requirement already satisfied: typing-extensions in /layers/heroku_python/dependencies/lib/" @@ -84,10 +86,12 @@ fn pip_basic_install_and_cache_reuse() { [Installing dependencies using Pip] Using cached pip download/wheel cache Running pip install - Collecting typing-extensions==4.4.0 (from -r requirements.txt (line 2)) - Using cached typing_extensions-4.4.0-py3-none-any.whl (26 kB) + Collecting typing-extensions==4.7.1 (from -r requirements.txt (line 2)) + Obtaining dependency information for typing-extensions==4.7.1 from https://files.pythonhosted.org/packages/ec/6b/63cc3df74987c36fe26157ee12e09e8f9db4de771e0f3404263117e75b95/typing_extensions-4.7.1-py3-none-any.whl.metadata + Using cached typing_extensions-4.7.1-py3-none-any.whl.metadata (3.1 kB) + Using cached typing_extensions-4.7.1-py3-none-any.whl (33 kB) Installing collected packages: typing-extensions - Successfully installed typing-extensions-4.4.0 + Successfully installed typing-extensions-4.7.1 ===> EXPORTING "} ); @@ -137,10 +141,12 @@ fn pip_cache_invalidation_and_metadata_compatibility() { [Installing dependencies using Pip] Discarding cached pip download/wheel cache Running pip install - Collecting typing-extensions==4.4.0 (from -r requirements.txt (line 2)) - Downloading typing_extensions-4.4.0-py3-none-any.whl (26 kB) + Collecting typing-extensions==4.7.1 (from -r requirements.txt (line 2)) + Obtaining dependency information for typing-extensions==4.7.1 from https://files.pythonhosted.org/packages/ec/6b/63cc3df74987c36fe26157ee12e09e8f9db4de771e0f3404263117e75b95/typing_extensions-4.7.1-py3-none-any.whl.metadata + Downloading typing_extensions-4.7.1-py3-none-any.whl.metadata (3.1 kB) + Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) Installing collected packages: typing-extensions - Successfully installed typing-extensions-4.4.0 + Successfully installed typing-extensions-4.7.1 ===> EXPORTING "} ); @@ -150,6 +156,7 @@ fn pip_cache_invalidation_and_metadata_compatibility() { } // This tests that: +// - Requirements file env var interpolation works (ie: user-provided env vars have been propagated to pip). // - Git from the stack image can be found (ie: the system PATH has been correctly propagated to pip). // - The editable mode repository clone is saved into the dependencies layer not the app dir. // - Compiling a source distribution package (as opposed to a pre-built wheel) works. @@ -158,7 +165,8 @@ fn pip_cache_invalidation_and_metadata_compatibility() { #[ignore = "integration test"] fn pip_editable_git_compiled() { TestRunner::default().build( - BuildConfig::new(builder(), "tests/fixtures/pip_editable_git_compiled"), + BuildConfig::new(builder(), "tests/fixtures/pip_editable_git_compiled") + .env("WHEEL_PACKAGE_URL", "https://github.com/pypa/wheel"), |context| { assert_contains!( context.pack_stdout, diff --git a/tests/integration/python_version.rs b/tests/integration/python_version.rs index dbc1e3e..cb872db 100644 --- a/tests/integration/python_version.rs +++ b/tests/integration/python_version.rs @@ -76,9 +76,17 @@ fn builds_with_python_version(fixture_path: &str, python_version: &str) { } = PackagingToolVersions::default(); let mut config = BuildConfig::new(builder(), fixture_path); - // Checks that potentially broken user-provided env vars are not being passed unfiltered to - // subprocesses we launch (such as `pip install`), thanks to `clear-env` in `buildpack.toml`. - config.env("PYTHONHOME", "/invalid-path"); + // Checks that potentially broken user-provided env vars don't take precedence over those + // set by this buildpack and break running Python. These are based on the env vars that + // used to be set by `bin/release` by very old versions of the classic Python buildpack: + // https://github.com/heroku/heroku-buildpack-python/blob/27abdfe7d7ad104dabceb45641415251e965671c/bin/release#L11-L18 + config.envs([ + ("LD_LIBRARY_PATH", "/invalid-path"), + ("LIBRARY_PATH", "/invalid-path"), + ("PATH", "/invalid-path"), + ("PYTHONHOME", "/invalid-path"), + ("PYTHONPATH", "/invalid-path"), + ]); TestRunner::default().build(config, |context| { assert_empty!(context.pack_stderr); diff --git a/tests/integration/salesforce_functions.rs b/tests/integration/salesforce_functions.rs deleted file mode 100644 index c6d4ed8..0000000 --- a/tests/integration/salesforce_functions.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::integration_tests::builder; -use indoc::indoc; -use libcnb_test::{ - assert_contains, assert_empty, BuildConfig, ContainerConfig, PackResult, TestRunner, -}; -use std::thread; -use std::time::Duration; - -const TEST_PORT: u16 = 12345; - -#[test] -#[ignore = "integration test"] -fn salesforce_function_template() { - TestRunner::default().build( - BuildConfig::new(builder(), "tests/fixtures/salesforce_function_template"), - |context| { - assert_empty!(context.pack_stderr); - assert_contains!( - context.pack_stdout, - indoc! {" - [Validating Salesforce Function] - Function passed validation. - ===> EXPORTING - "} - ); - assert_contains!(context.pack_stdout, "Setting default process type 'web'"); - - // Test that the `sf-functions-python` web process the buildpack configures works correctly. - context.start_container( - ContainerConfig::new() - .env("PORT", TEST_PORT.to_string()) - .expose_port(TEST_PORT), - |container| { - let address_on_host = container.address_for_port(TEST_PORT).unwrap(); - let url = format!("http://{}:{}", address_on_host.ip(), address_on_host.port()); - - // Retries needed since the server takes a moment to start up. - let mut attempts_remaining = 5; - let response = loop { - let response = ureq::post(&url).set("x-health-check", "true").call(); - if response.is_ok() || attempts_remaining == 0 { - break response; - } - attempts_remaining -= 1; - thread::sleep(Duration::from_secs(1)); - }; - - let server_log_output = container.logs_now(); - assert_contains!( - server_log_output.stderr, - &format!("Uvicorn running on http://0.0.0.0:{TEST_PORT}") - ); - - let body = response.unwrap().into_string().unwrap(); - assert_eq!(body, r#""OK""#); - }, - ); - }, - ); -} - -#[test] -#[ignore = "integration test"] -fn salesforce_function_missing_package() { - TestRunner::default().build( - BuildConfig::new( - builder(), - "tests/fixtures/salesforce_function_missing_package", - ) - .expected_pack_result(PackResult::Failure), - |context| { - assert_contains!( - context.pack_stderr, - indoc! {r#" - [Error: The Salesforce Functions package is not installed] - The 'sf-functions-python' program that is required for Python Salesforce - Functions could not be found. - - Check that the 'salesforce-functions' Python package is listed as a - dependency in 'requirements.txt'. - - If this project is not intended to be a Salesforce Function, remove the - 'type = "function"' declaration from 'project.toml' to skip this check. - "#} - ); - }, - ); -} - -#[test] -#[ignore = "integration test"] -fn salesforce_function_fails_self_check() { - TestRunner::default().build( - BuildConfig::new( - builder(), - "tests/fixtures/salesforce_function_fails_self_check", - ) - .expected_pack_result(PackResult::Failure), - |context| { - assert_contains!( - context.pack_stderr, - indoc! {" - [Error: The Salesforce Functions self-check failed] - The 'sf-functions-python check' command failed (exit status: 1), indicating - there is a problem with the Python Salesforce Function in this project. - - Details: - Function failed validation: 'invalid' isn't a valid Salesforce REST API version." - } - ); - }, - ); -} - -#[test] -#[ignore = "integration test"] -fn project_toml_invalid() { - TestRunner::default().build( - BuildConfig::new(builder(), "tests/fixtures/project_toml_invalid") - .expected_pack_result(PackResult::Failure), - |context| { - assert_contains!( - context.pack_stderr, - indoc! {r#" - [Error: Invalid project.toml] - A parsing/validation error error occurred whilst loading the project.toml file. - - Details: TOML parse error at line 4, column 1 - | - 4 | [com.salesforce] - | ^^^^^^^^^^^^^^^^ - missing field `type` - "#} - ); - }, - ); -}