From 3b7de8bd73c24a32bad7c1a637e5b5a9930e5e29 Mon Sep 17 00:00:00 2001 From: Simon Guest Date: Fri, 23 Aug 2024 09:38:09 +1200 Subject: [PATCH] Switch to native Rust for nu_protocol handling (#26) Tracking changes in the Nu plugin protocol by hand was too onerous. This is a major change so that the plugin is now native Rust, and spawns the Bash script as a subprocess. Fixes #25 --- .github/workflows/test-suite.yml | 14 +- .gitignore | 2 + api/Cargo.lock => Cargo.lock | 860 ++++++++++++++++++++++--------- Cargo.toml | 24 + README.md | 25 +- api/.envrc | 1 - api/.gitignore | 2 - api/Cargo.toml | 13 - api/flake.lock | 130 ----- api/flake.nix | 31 -- api/src/main.rs | 100 ---- flake.lock | 37 +- flake.nix | 48 +- nu_plugin_bash_env | 469 ----------------- scripts/bash_env.sh | 195 +++++++ src/main.rs | 300 +++++++++++ 16 files changed, 1233 insertions(+), 1018 deletions(-) rename api/Cargo.lock => Cargo.lock (67%) create mode 100644 Cargo.toml delete mode 100644 api/.envrc delete mode 100644 api/.gitignore delete mode 100644 api/Cargo.toml delete mode 100644 api/flake.lock delete mode 100644 api/flake.nix delete mode 100644 api/src/main.rs delete mode 100755 nu_plugin_bash_env create mode 100755 scripts/bash_env.sh create mode 100644 src/main.rs diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index ec484af..fa03416 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -1,7 +1,7 @@ name: test suite on: [push, pull_request] env: - NU_VERSION: 0.96.1 + NU_VERSION: 0.97.1 jobs: test: @@ -15,10 +15,16 @@ jobs: curl -L https://github.com/nushell/nushell/releases/download/${NU_VERSION}/nu-${NU_VERSION}-x86_64-unknown-linux-gnu.tar.gz | tar xzf - - name: Version Check run: | - ./nu-${NU_VERSION}-x86_64-unknown-linux-gnu/nu --version + export PATH=./nu-${NU_VERSION}-x86_64-unknown-linux-gnu:$PATH + nu --version bash --version jq --version + - name: Install Rust Toolchain + uses: dtolnay/rust-toolchain@stable + - name: Build + run: cargo build - name: Run Tests run: | - ./nu-${NU_VERSION}-x86_64-unknown-linux-gnu/nu --no-config-file --no-history -c "plugin add --plugin-config plugin.msgpackz nu_plugin_bash_env" - ./nu-${NU_VERSION}-x86_64-unknown-linux-gnu/nu --no-config-file --no-history -c "plugin use --plugin-config plugin.msgpackz bash_env ; use tests.nu run_bash_env_tests ; run_bash_env_tests" + export PATH=./nu-${NU_VERSION}-x86_64-unknown-linux-gnu:$PATH + nu --no-config-file --no-history -c "plugin add --plugin-config plugin.msgpackz target/debug/nu_plugin_bash_env" + nu --no-config-file --no-history -c "plugin use --plugin-config plugin.msgpackz bash_env ; use tests.nu run_bash_env_tests ; run_bash_env_tests" diff --git a/.gitignore b/.gitignore index a865f31..01b03e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ +/target/ /.direnv/ +/result plugin.msgpackz \ No newline at end of file diff --git a/api/Cargo.lock b/Cargo.lock similarity index 67% rename from api/Cargo.lock rename to Cargo.lock index 484b33b..d65b02b 100644 --- a/api/Cargo.lock +++ b/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" @@ -57,9 +57,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-tzdata" @@ -76,17 +76,23 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bincode" @@ -106,7 +112,7 @@ dependencies = [ "bitflags", "cexpr", "clang-sys", - "itertools", + "itertools 0.12.1", "lazy_static", "lazycell", "proc-macro2", @@ -114,7 +120,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.58", + "syn 2.0.75", ] [[package]] @@ -134,9 +140,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -150,27 +156,36 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "borsh" -version = "1.4.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0901fc8eb0aca4c83be0106d6f2db17d86a08dfc2c25f0e84464bf381158add6" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" dependencies = [ "borsh-derive", - "cfg_aliases", + "cfg_aliases 0.2.1", ] [[package]] name = "borsh-derive" -version = "1.4.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51670c3aa053938b0ee3bd67c3817e471e626151131b934038e83c5bf8de48f5" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", "syn_derive", ] @@ -187,9 +202,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -197,9 +212,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-unit" @@ -242,15 +257,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.0.90" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +dependencies = [ + "shlex", +] [[package]] name = "cexpr" @@ -273,18 +291,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "pure-rust-locales", "serde", - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -298,9 +322,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -318,15 +342,24 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -352,9 +385,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crossterm_winapi" @@ -366,24 +399,44 @@ dependencies = [ ] [[package]] -name = "dirs-next" -version = "2.0.0" +name = "crypto-common" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "cfg-if", - "dirs-sys-next", + "generic-array", + "typenum", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "digest" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -394,9 +447,9 @@ checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" @@ -406,18 +459,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b73807008a3c7f171cc40312f37d95ef0396e048b5848d775f54b1a4dd4a0d3" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" dependencies = [ "serde", + "typeid", ] [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -430,15 +484,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" dependencies = [ "bit-set", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666" dependencies = [ "crc32fast", "miniz_oxide", @@ -450,11 +510,21 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -478,9 +548,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", "allocator-api2", @@ -517,19 +587,19 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] name = "interprocess" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67bafc2f5dbdad79a6d925649758d5472647b416028099f0b829d1b67fdd47d3" +checksum = "d2f4e4a06d42fab3e85ab1b419ad32b09eab58b901d40c57935ff92db3287a13" dependencies = [ "doctest-file", "libc", @@ -559,6 +629,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -567,18 +646,18 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" @@ -588,25 +667,25 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] name = "libproc" -version = "0.14.6" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb6497078a4c9c2aca63df56d8dce6eb4381d53a960f781a3a748f7ea97436d" +checksum = "ae9ea4b75e1a81675429dafe43441df1caea70081e82246a8cccf514884a88bb" dependencies = [ "bindgen", "errno", @@ -625,23 +704,23 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -650,7 +729,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53304fff6ab1e597661eee37e42ea8c47a146fca280af902bb76bff8a896e523" dependencies = [ - "nu-ansi-term", + "nu-ansi-term 0.50.1", ] [[package]] @@ -662,11 +741,20 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miette" @@ -694,7 +782,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", ] [[package]] @@ -705,11 +793,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -720,7 +808,7 @@ checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.1.1", "libc", ] @@ -745,60 +833,72 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ - "windows-sys 0.48.0", + "overload", + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +dependencies = [ + "windows-sys 0.52.0", ] [[package]] name = "nu-derive-value" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724b3754a25b2f8a2a7f1530e0a162fa57a3cadd0b5c3b52f75edcdb2070c09" +checksum = "4e4640556d6abc057dab7001bf5612f6b9b144ce739bfa0669d66fbf1ef7ad28" dependencies = [ "convert_case", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", ] [[package]] name = "nu-engine" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ed7cd7d34dd3e58292eaaa658f4b7342da99e979da54babd50c08d5d6d59e5" +checksum = "aa524164c6d87d9ce4dd1122525a539f92a77f4fbb6494452976cc2fa691742d" dependencies = [ + "log", "nu-glob", "nu-path", "nu-protocol", "nu-utils", + "terminal_size", ] [[package]] name = "nu-glob" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd2879444c53bbfb51a2ab060ae1257fe2c8446e6b2cd8a63c88a4d6a728a7a" +checksum = "f4097b0014c26a039018990a4fe8d8fd5658c00e94621b34751869649b0aa942" [[package]] name = "nu-path" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6633f681c4c92d86198d91f3a4b212e64a33901ca492dd5529631c8ac7dd6ca9" +checksum = "96b4a7d68a196e55c8e2c8685293bc1c17e9c13aa7dac5bcbe04a2a841e92770" dependencies = [ - "dirs-next", + "dirs", "omnipath", "pwd", ] [[package]] name = "nu-plugin" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7844c84c9319c0dc831bc6d595990dee2ba66aab9d0a0d4d64ab414e6520b0f" +checksum = "a6b2c69b4b0963fa2d1312a5df115a35b0f523e54b95d013eec87791806ff11d" dependencies = [ "log", "nix", @@ -806,14 +906,15 @@ dependencies = [ "nu-plugin-core", "nu-plugin-protocol", "nu-protocol", + "nu-utils", "thiserror", ] [[package]] name = "nu-plugin-core" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b400723e072a53a1ddff07f530758b17df97cb8bf632414c547a1ad2c1225ddb" +checksum = "3dddcc6ef62272eedaa18f7f004090781969b99c29d4973a4dac6e4ce4395097" dependencies = [ "interprocess", "log", @@ -827,9 +928,9 @@ dependencies = [ [[package]] name = "nu-plugin-protocol" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257069f3d77a7fbe47685deb3a53d2de4a4744f6869a7f977286dbadd8bdb2aa" +checksum = "2716cc05722738406c1714c9788969dd10d75a3d4eddbf86b3ad423df1a5d74a" dependencies = [ "bincode", "nu-protocol", @@ -841,17 +942,20 @@ dependencies = [ [[package]] name = "nu-protocol" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d22636a014d5db9f894db2e53fac656b686a35f1002ecc1b8b46b47474874" +checksum = "38ae5262aabe662ac1cc02a6e8d3fdb48fa8bb25c77be72d2e8a625a7c3e4812" dependencies = [ "brotli", "byte-unit", "chrono", "chrono-humanize", "convert_case", + "dirs", + "dirs-sys", "fancy-regex", "indexmap", + "log", "lru", "miette", "nix", @@ -865,16 +969,17 @@ dependencies = [ "serde", "thiserror", "typetag", + "windows-sys 0.48.0", ] [[package]] name = "nu-system" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c5e86b4e9ea84b4b12778a159adbbef5f4346213dcc4e9e58f3c40f5c9865af" +checksum = "52ed001bb4cb39b4235871cb00650b79497084fc46beaf019d226239119d3ef5" dependencies = [ "chrono", - "itertools", + "itertools 0.12.1", "libc", "libproc", "log", @@ -889,9 +994,9 @@ dependencies = [ [[package]] name = "nu-utils" -version = "0.95.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc747ba17d4762480a7569df44b49fb7f465b12b98aaa2a18aab2eeb585df79c" +checksum = "88d91a233afaa875d01784c898f4464755cbefb5eaf8845032d651e39ac6354f" dependencies = [ "crossterm_winapi", "log", @@ -905,11 +1010,22 @@ dependencies = [ ] [[package]] -name = "nu_plugin_bash_env_api" -version = "0.11.0" +name = "nu_plugin_bash_env" +version = "0.13.0" dependencies = [ + "anyhow", + "itertools 0.13.0", "nu-plugin", "nu-protocol", + "once_cell", + "rust-embed", + "serde", + "serde_json", + "shellexpand", + "subprocess", + "tempfile", + "tracing", + "tracing-subscriber", ] [[package]] @@ -924,9 +1040,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -943,16 +1059,28 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "os_pipe" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d73ba8daf8fac13b0501d1abeddcfe21ba7401ada61a819144b6c2a4f32209" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "owo-colors" version = "4.0.0" @@ -961,15 +1089,24 @@ checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro-crate" @@ -1005,9 +1142,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1076,9 +1213,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1147,9 +1284,9 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -1158,32 +1295,47 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.4", ] [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rend" @@ -1196,9 +1348,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", @@ -1214,9 +1366,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2", "quote", @@ -1245,11 +1397,45 @@ dependencies = [ "serde", ] +[[package]] +name = "rust-embed" +version = "8.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.75", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rust_decimal" -version = "1.35.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", "borsh", @@ -1269,9 +1455,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags", "errno", @@ -1282,9 +1468,18 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "seahash" @@ -1294,41 +1489,71 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shellexpand" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +dependencies = [ + "dirs", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1341,6 +1566,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "smawk" version = "0.3.2" @@ -1356,6 +1587,16 @@ dependencies = [ "vte", ] +[[package]] +name = "subprocess" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "supports-color" version = "3.0.0" @@ -1390,9 +1631,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" dependencies = [ "proc-macro2", "quote", @@ -1408,7 +1649,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", ] [[package]] @@ -1422,9 +1663,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.30.8" +version = "0.30.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b1a378e48fb3ce3a5cf04359c456c9c98ff689bcf1c1bc6e6a31f247686f275" +checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" dependencies = [ "cfg-if", "core-foundation-sys", @@ -1441,6 +1682,19 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "terminal_size" version = "0.3.0" @@ -1464,29 +1718,39 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -1499,9 +1763,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" @@ -1514,11 +1778,84 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term 0.46.0", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "typetag" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "661d18414ec032a49ece2d56eee03636e43c4e8d577047ab334c0ba892e29aaf" +checksum = "52ba3b6e86ffe0054b2c44f2d86407388b933b16cb0a70eea3929420db1d9bbe" dependencies = [ "erased-serde", "inventory", @@ -1529,13 +1866,13 @@ dependencies = [ [[package]] name = "typetag-impl" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac73887f47b9312552aa90ef477927ff014d63d1920ca8037c6c1951eab64bb1" +checksum = "70b20a22c42c8f1cd23ce5e34f165d4d37038f5b663ad20fb6adbdf029172483" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", ] [[package]] @@ -1567,9 +1904,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "utf8-width" @@ -1579,21 +1916,27 @@ checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vte" @@ -1607,14 +1950,24 @@ dependencies = [ [[package]] name = "vte_generate_state_changes" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" dependencies = [ "proc-macro2", "quote", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1623,34 +1976,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1658,22 +2012,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "widestring" @@ -1697,6 +2051,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1710,7 +2073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core 0.52.0", - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -1720,7 +2083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" dependencies = [ "windows-core 0.54.0", - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -1729,7 +2092,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -1739,16 +2102,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" dependencies = [ "windows-result", - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] name = "windows-result" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd19df78e5168dfb0aedc343d1d1b8d422ab2db6756d2dc3fef75035402a3f64" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -1766,7 +2129,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -1786,17 +2158,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1807,9 +2180,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -1819,9 +2192,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -1831,9 +2204,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -1843,9 +2222,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -1855,9 +2234,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -1867,9 +2246,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -1879,9 +2258,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -1903,20 +2282,21 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.75", ] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a33d3cd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "nu_plugin_bash_env" +version = "0.13.0" +edition = "2021" +license = "MIT" +description = "Nu plugin bash-env" +homepage = "https://github.com/tesujimath/nu_plugin_bash_env" +repository = "https://github.com/tesujimath/nu_plugin_bash_env" +readme = "README.md" + +[dependencies] +anyhow = "1.0.86" +itertools = "0.13.0" +nu-plugin = "0.97.1" +nu-protocol = "0.97.1" +once_cell = "1.19.0" +rust-embed = "8.5.0" +serde = "1.0.208" +serde_json = "1.0.125" +shellexpand = "3.1.0" +subprocess = "0.2.9" +tempfile = "3.12.0" +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } diff --git a/README.md b/README.md index d9ff5aa..a172822 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,9 @@ A Bash environment plugin for Nushell. For instructions on how to use this plugin, see the [Nushell book](https://www.nushell.sh/book/plugins.html). -In summary, save the `nu_plugin_bash_env` script in your Nu plugins directory (for example) and ensure it is executable. -For users of Nix, this is now installable as a flake (see below). +In summary, build the crate and add the resulting `nu_plugin_bash_env` executable as a plugin using `plugin add`, then `plugin use`. -Then in Nu: -``` -> register nu_plugin_bash_env -``` +For users of Nix, this is now installable as a flake (see below). The plugin reads the specified environment file (if any) and evaluates variables from `stdin` (if any) and returns any new or changed environment variables as a record, suitable for passing to Nu's `load-env`. @@ -31,14 +27,15 @@ The following versions are compatible. | 0.94 | 0.10.0 | | 0.95 | 0.11.0 | | 0.96 | 0.12.1 | +| 0.97 | 0.13.0 | If you find a new version of Nushell rejects this plugin as incompatible, please report an [issue](https://github.com/tesujimath/nu_plugin_bash_env/issues). ## Dependencies -The script uses `jq` for heavy lifting. [At least jq version 1.7 is required](https://github.com/tesujimath/nu_plugin_bash_env/issues/24). +The script uses `jq` for output formatting. Previous versions required at least `jq` version `1.7`, but that may be no longer the case. -Also I suspect at least Bash version 5.1. +Also I suspect at least Bash version `5.1`. ## Examples @@ -128,9 +125,17 @@ Care has been taken to escape any special characters. "Well done!" is better than "Well said!" ``` -## API +## Implementation + +Prior to 0.13.0 this plugin was written in Bash, with the Nu plugin protocol done by hand using `jq`, with insights from the [api](api) sub-directory which contained a Rust program to produce what is required, using the official Nu plugin library. This was too onerous to maintain through the evolution of the protocol, so was abandoned. + +Since 0.13.0, the plugin is written in Rust, with the much simplified Bash script embedded. + +By default the embedded Bash script is extracted at runtime into a temporary directory. This behaviour may be overridden by setting the ``NU_PLUGIN_BASH_ENV_SCRIPT` environment variable, which is then expected to resolve to the path of the pre-installed script. + +## Logging -Because this plugin is written in Bash, the API signatures must be written by hand. The [api](api) sub-directory contains a Rust program to produce what is required, using the official Nu plugin library. +Logging is supported via the Rust `tracing-subscriber` crate, with log-level defined by the environment variable `NU_PLUGIN_BASH_ENV_LOG`. ## Nix flake diff --git a/api/.envrc b/api/.envrc deleted file mode 100644 index 3550a30..0000000 --- a/api/.envrc +++ /dev/null @@ -1 +0,0 @@ -use flake diff --git a/api/.gitignore b/api/.gitignore deleted file mode 100644 index c2faf8a..0000000 --- a/api/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/.direnv/ -/target/ diff --git a/api/Cargo.toml b/api/Cargo.toml deleted file mode 100644 index 7266e31..0000000 --- a/api/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "nu_plugin_bash_env_api" -version = "0.11.0" -edition = "2021" -license = "MIT" -description = "API for Nu plugin bash-env" -homepage = "https://github.com/tesujimath/nu_plugin_bash_env" -repository = "https://github.com/tesujimath/nu_plugin_bash_env" -readme = "README.md" - -[dependencies] -nu-plugin = "0.96.1" -nu-protocol = "0.96.1" diff --git a/api/flake.lock b/api/flake.lock deleted file mode 100644 index 478ab2d..0000000 --- a/api/flake.lock +++ /dev/null @@ -1,130 +0,0 @@ -{ - "nodes": { - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1705309234, - "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1717112898, - "narHash": "sha256-7R2ZvOnvd9h8fDd65p0JnB7wXfUvreox3xFdYWd1BnY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "6132b0f6e344ce2fe34fc051b72fb46e34f668e0", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1706487304, - "narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "90f456026d284c22b3e3497be980b2e47d0b28ac", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay" - } - }, - "rust-overlay": { - "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1717294752, - "narHash": "sha256-QhlS52cEQyx+iVcgrEoCnEEpWUA6uLdmeLRxk935inI=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "b46857a406d207a1de74e792ef3b83e800c30e08", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/api/flake.nix b/api/flake.nix deleted file mode 100644 index f05d047..0000000 --- a/api/flake.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ - description = "A Rust development environment flake."; - - inputs = { - nixpkgs.url = github:NixOS/nixpkgs/nixpkgs-unstable; - rust-overlay.url = "github:oxalica/rust-overlay"; - flake-utils.url = "github:numtide/flake-utils"; - }; - - outputs = { self, nixpkgs, rust-overlay, flake-utils }: - flake-utils.lib.eachDefaultSystem - (system: - let - overlays = [ (import rust-overlay) ]; - pkgs = import nixpkgs { - inherit system overlays; - }; - in - with pkgs; - { - devShells.default = mkShell { - nativeBuildInputs = [ - bashInteractive - cargo-modules - cargo-udeps - rust-bin.stable.latest.default - ]; - }; - } - ); -} diff --git a/api/src/main.rs b/api/src/main.rs deleted file mode 100644 index 6f121cf..0000000 --- a/api/src/main.rs +++ /dev/null @@ -1,100 +0,0 @@ -use std::path::PathBuf; - -use nu_plugin::{serve_plugin, EvaluatedCall, JsonSerializer}; -use nu_plugin::{EngineInterface, Plugin, PluginCommand, SimplePluginCommand}; -use nu_protocol::{Category, LabeledError, Record, Signature, Span, SyntaxShape, Type, Value}; - -struct BashEnvApiPlugin; - -impl Plugin for BashEnvApiPlugin { - fn commands(&self) -> Vec>> { - vec![Box::new(BashEnvApi)] - } - - fn version(&self) -> String { - env!("CARGO_PKG_VERSION").to_string() - } -} - -struct BashEnvApi; - -impl SimplePluginCommand for BashEnvApi { - type Plugin = BashEnvApiPlugin; - - fn name(&self) -> &str { - "bash-env-api" - } - - fn usage(&self) -> &str { - "get environment variables from Bash format file and/or stdin" - } - - fn signature(&self) -> Signature { - Signature::build(PluginCommand::name(self)) - .usage("get environment variables from Bash format file and/or stdin") - .category(Category::Env) - .optional("path", SyntaxShape::String, "path to environment file") - .named( - "export", - SyntaxShape::List(Box::new(SyntaxShape::String)), - "list of shell variables to export", - None, - ) - .input_output_types(vec![(Type::Nothing, Type::Any), (Type::String, Type::Any)]) - .filter() - .allow_variants_without_examples(true) - } - - fn run( - &self, - _plugin: &BashEnvApiPlugin, - engine: &EngineInterface, - call: &EvaluatedCall, - input: &Value, - ) -> Result { - let _cwd = engine.get_current_dir(); - - let span = input.span(); - match call.positional.first() { - Some(value @ Value::String { val: path, .. }) => { - if PathBuf::from(path).exists() { - Ok(create_dummy_environment(span, call.head)) - } else { - Err(create_error(format!("no such file {}", path), value.span())) - } - } - None => Ok(create_dummy_environment(span, call.head)), - Some(value) => Err(create_error( - format!("positional requires string; got {}", value.get_type()), - call.head, - )), - } - } -} - -fn create_dummy_environment(input_span: Span, creation_site_span: Span) -> Value { - let cols_vals = [("A", "a"), ("B", "b"), ("C", "c")]; - let cols = cols_vals - .iter() - .map(|s| s.0.to_string()) - .collect::>(); - let vals = cols_vals - .iter() - .map(|s| Value::string(s.1.to_string(), Span::unknown())) - .collect::>(); - Value::record( - Record::from_raw_cols_vals(cols, vals, input_span, creation_site_span).unwrap(), - input_span, - ) -} - -fn create_error(msg: S, creation_site_span: Span) -> LabeledError -where - S: Into, -{ - LabeledError::new(msg).with_label("bash-env-api", creation_site_span) -} - -fn main() { - serve_plugin(&BashEnvApiPlugin, JsonSerializer) -} diff --git a/flake.lock b/flake.lock index 5ba78f0..c95a0e6 100644 --- a/flake.lock +++ b/flake.lock @@ -34,10 +34,45 @@ "type": "github" } }, + "nixpkgs_2": { + "locked": { + "lastModified": 1718428119, + "narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, "root": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1724206841, + "narHash": "sha256-L8dKaX4T3k+TR2fEHCfGbH4UXdspovz/pj87iai9qmc=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "45e98fbd62c32e5927e952d2833fa1ba4fb35a61", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" } }, "systems": { diff --git a/flake.nix b/flake.nix index 85e19fd..c391974 100644 --- a/flake.nix +++ b/flake.nix @@ -1,31 +1,45 @@ { - description = "Development environment for nu_plugin_bash_env."; + description = "nu_plugin_bash_env"; inputs = { - nixpkgs.url = github:NixOS/nixpkgs/nixpkgs-unstable; + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + rust-overlay.url = "github:oxalica/rust-overlay"; flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs, flake-utils }: + outputs = { self, nixpkgs, rust-overlay, flake-utils }: flake-utils.lib.eachDefaultSystem (system: let + overlays = [ (import rust-overlay) ]; pkgs = import nixpkgs { - inherit system; + inherit system overlays; }; - nu_plugin_bash_env = pkgs.writeShellScriptBin "nu_plugin_bash_env" - (builtins.replaceStrings ["jq" "(cat)" " sed "] ["${pkgs.jq}/bin/jq" "(${pkgs.coreutils}/bin/cat)" " ${pkgs.gnused}/bin/sed "] - (builtins.readFile ./nu_plugin_bash_env)); + # cargo-nightly based on https://github.com/oxalica/rust-overlay/issues/82 + nightly = pkgs.rust-bin.selectLatestNightlyWith (t: t.default); + cargo-nightly = pkgs.writeShellScriptBin "cargo-nightly" '' + export RUSTC="${nightly}/bin/rustc"; + exec "${nightly}/bin/cargo" "$@" + ''; + # TODO: + # nu_plugin_bash_env = pkgs.writeShellScriptBin "nu_plugin_bash_env" + # (builtins.replaceStrings [ "jq" "(cat)" " sed " ] [ "${pkgs.jq}/bin/jq" "(${pkgs.coreutils}/bin/cat)" " ${pkgs.gnused}/bin/sed " ] + # (builtins.readFile ./nu_plugin_bash_env)); in - with pkgs; - { - devShells.default = mkShell { - nativeBuildInputs = [ - bashInteractive - jq - ]; - }; - packages.default = nu_plugin_bash_env; - } + with pkgs; + { + devShells.default = mkShell { + nativeBuildInputs = [ + bashInteractive + jq + cargo-modules + cargo-nightly + cargo-udeps + rust-bin.stable.latest.default + ]; + }; + # TODO: build package from Rust crate + # packages.default = nu_plugin_bash_env; + } ); } diff --git a/nu_plugin_bash_env b/nu_plugin_bash_env deleted file mode 100755 index 948c812..0000000 --- a/nu_plugin_bash_env +++ /dev/null @@ -1,469 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright 2023 Simon Guest -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation files -# (the “Software”), to deal in the Software without restriction, -# including without limitation the rights to use, copy, modify, merge, -# publish, distribute, subl# icense, and/or sell copies of the -# Software, and to permit persons to whom the Software is furnished to -# do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -VERSION="0.12.1" -PROTOCOL_VERSION="0.96.1" - -shopt -s extglob - -function send_encoder() { - echo -en "\04json" -} - -function send_hello() { - jq -c <&2; then - send_error "$_call_id" "failed to load environment from '$_path'" - return 1 - fi - fi - - # eval from stdin until EOF - _source=$(cat) - if ! eval "$_source" >&2; then - send_error "$_call_id" "failed to load environment from stdin" - return 1 - fi - - # export shell variables to environment as specified, if any - for _export in "${_exports[@]}"; do - export "${_export}=${!_export}" - done - - # get new environment - declare -A _env_new - while IFS='=' read -r -d '' _name _value; do - _env_new[$_name]="${_value@Q}" - done < <(env -0) - - # determine what changed or became unset - declare -a _env_changed_or_unset - - # changes - for _name in "${!_env_new[@]}"; do - if test "${_env_new[$_name]}" != "${_env_old[$_name]}"; then - _env_changed_or_unset+=("$_name") - fi - done - - # unset - for _name in "${!_env_old[@]}"; do - if test ! -v "$_name"; then - _env_changed_or_unset+=("$_name") - fi - done - - send_environment "$_call_id" "${_env_changed_or_unset[@]}" | jq -c -} - -function read_stream() { - local _line _data_id _active_streams - local _stream_id="$1" - - declare -A _active_streams - _active_streams["$_stream_id"]=X - shift - - # get other active streams - while test -n "$1"; do - _active_streams["$1"]=X - shift - done - - while true; do - read -rs _line - - # blank line handling - if test -z "$_line"; then - break - fi - - case "$_line" in - \{\"Data\":\[+([0-9]),*) - _data_id=$(jq '.Data[0]' <<<"$_line") - if test "${_data_id}" = "${_stream_id}"; then - # sed is used to remove empty lines, to mitigate the double newline - jq -r '.Data[1].Raw.Ok | implode' <<<"$_line" | sed -r '/^$/d' - fi - ;; - \{\"End\":[0-9]*) - _end_id=$(jq '.End' <<<"$_line") - unset "_active_streams[$_end_id]" - ;; - esac - - if test "${#_active_streams[@]}" == 0; then - break - fi - done -} - -function get_current_dir_request() { - local _call_id - - _call_id="$1" - echo "{\"EngineCall\":{\"context\":$_call_id,\"id\":0,\"call\":\"GetCurrentDir\"}}" -} - -function get_current_dir_response() { - local _line - - read -rs _line - echo "$_line" | jq -r '.EngineCallResponse[1].PipelineData.Value.String.val' -} - -function run_as_plugin() { - local _line _path _stdinval _call_id _stdout_id _exports _cwd - declare -a _exports - send_encoder - - while true; do - read -rs _line - - # blank line handling - if test -z "$_line"; then - break - fi - - case "$_line" in - \{\"Hello\":*) - send_hello - ;; - \"Goodbye\") - exit - ;; - \{\"Call\":\[+([0-9]),*) - _call_id=$(jq '.Call[0]' <<<"$_line") - case "$_line" in - \{\"Call\":\[+([0-9]),\"Metadata\"*) - send_metadata "$_call_id" - ;; - \{\"Call\":\[+([0-9]),\"Signature\"*) - send_signature "$_call_id" - ;; - \{\"Call\":\[+([0-9]),\{\"Run\"*) - _path=$(echo "$_line" | jq -r '.Call[1].Run.call.positional[0].String.val // empty') - # Nushell may pass through ~ verbatim which we must cope with explicitly - _path="${_path/#\~/$HOME}" - - # relative path requires us to determine cwd from the engine - if test -n "$_path" -a "${_path::1}" != /; then - get_current_dir_request "$_call_id" - _cwd=$(get_current_dir_response) - _path="$_cwd/$_path" - fi - - # stdin could come in different ways, or not at all: - case $(echo "$_line" | jq -r '.Call[1].Run.input | if . == "Empty" then "Empty" elif .Value.String | has("val") then "String" elif has("ByteStream") then "ByteStream" else "Other" end') in - Empty) - _stdinval="" - ;; - String) - _stdinval=$(echo "$_line" | jq -r '.Call[1].Run.input.Value.String.val') - ;; - ByteStream) - _stdout_id=$(echo "$_line" | jq -r '.Call[1].Run.input.ByteStream.id') - _stdinval=$(read_stream "$_stdout_id") - ;; - esac - - # get exports, if any - mapfile -t _exports < <(echo "$_line" | jq -r '.Call[1].Run.call.named // [] | .[] | select(.[0].item == "export") | .[1].List.vals.[].String.val') - - echo "$_stdinval" | eval_and_or_source_then_send_environment "$_call_id" "$_path" "${_exports[@]}" - ;; - *) - echo >&2 "unexpected call: $_line" - ;; - esac - ;; - *) - echo >&2 "unexpected input: $_line" - ;; - esac - done -} - -function bad_usage() { - echo >&2 "usage: nu_plugin_bash_env [--stdio] [--standalone [sig | to-json ]]" - echo >&2 "Maybe this plugin doesn't support your version of Nushell" - echo >&2 "Please consider creating an issue at" - echo >&2 "https://github.com/tesujimath/nu_plugin_bash_env/issues" - test -n "$*" && echo >&2 "$*" -} - -# process args -unset stdio -unset standalone_hello -unset standalone_sig -unset standalone_to_json -while test -n "$1"; do - case "$1" in - --stdio) - stdio=1 - ;; - --standalone) - case "$2" in - hello) - standalone_hello=1 - shift - ;; - sig) - standalone_sig=1 - shift - ;; - to-json) - standalone_to_json="$3" - shift 2 - ;; - *) - echo >&2 "unsupported standalone operation: $2" - exit 1 - ;; - esac - ;; - *) - bad_usage "unexpected arg: $1" - exit 1 - ;; - esac - shift -done - -if test -n "$stdio"; then - run_as_plugin -elif test -n "$standalone_sig"; then - send_signature 99 -elif test -n "$standalone_hello"; then - send_hello -elif test -n "$standalone_to_json"; then - declare -a _exports - eval_and_or_source_then_send_environment 99 "$standalone_to_json" "${_exports[@]}" -else - bad_usage "need --stdio or --to-json" -fi diff --git a/scripts/bash_env.sh b/scripts/bash_env.sh new file mode 100755 index 0000000..9ca9c99 --- /dev/null +++ b/scripts/bash_env.sh @@ -0,0 +1,195 @@ +#!/usr/bin/env bash +# +# Copyright 2023-24 Simon Guest +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the “Software”), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, subl# icense, and/or sell copies of the +# Software, and to permit persons to whom the Software is furnished to +# do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +shopt -s extglob + +function send_value() { + # jq -R produces nothing on empty input, but we want "" + if test -n "$1"; then + echo -n "$1" | jq -R + else + echo -n '""' + fi +} + +function send_environment() { + local _n_env _head _tail _name _call_id + declare -a _tail + _call_id="$1" + shift + + _n_env=$# + + _head="$1" + shift + _tail=("$@") + + # header + echo -n "{\"Env\":[" + + # names and values + if test $_n_env -gt 0; then + echo -n "{\"k\":\"$_head\",\"v\":" + send_value "${!_head}" + echo -n "}" + + for _name in "${_tail[@]}"; do + if test -v "$_name"; then + echo -n ",{\"k\":\"$_name\",\"v\":" + send_value "${!_name}" + echo -n "}" + else + # unset, TODO + : + fi + done + fi + + # trailer + echo ']}' +} + +function send_error() { + local _msg + _msg="$1" + jq -c <&2; then + send_error "failed to load environment from '$_path'" + return 1 + fi + fi + + # eval from _source + if ! eval "$_source" >&2; then + send_error "failed to load environment from stdin" + return 1 + fi + + # export shell variables to environment as specified, if any + for _export in "${_exports[@]}"; do + export "${_export}=${!_export}" + done + + # get new environment + declare -A _env_new + while IFS='=' read -r -d '' _name _value; do + _env_new[$_name]="${_value@Q}" + done < <(env -0) + + # determine what changed or became unset + declare -a _env_changed_or_unset + + # changes + for _name in "${!_env_new[@]}"; do + if test "${_env_new[$_name]}" != "${_env_old[$_name]}"; then + _env_changed_or_unset+=("$_name") + fi + done + + # unset + for _name in "${!_env_old[@]}"; do + if test ! -v "$_name"; then + _env_changed_or_unset+=("$_name") + fi + done + + send_environment "$_call_id" "${_env_changed_or_unset[@]}" | jq -c +} + +function bad_usage() { + echo >&2 "usage: nu_plugin_bash_env [--stdin] []" + echo >&2 "Maybe this plugin doesn't support your version of Nushell" + echo >&2 "Please consider creating an issue at" + echo >&2 "https://github.com/tesujimath/nu_plugin_bash_env/issues" + test -n "$*" && echo >&2 "$*" +} + +# process args +unset stdinval +declare -a exports +exports=() +unset path +while test -n "$1"; do + case "$1" in + --stdin) + test -z "$stdinval" || { + bad_usage "repeated --stdio" + exit 1 + } + stdinval="$(cat)" + ;; + --export) + test "${#exports[@]}" -eq 0 || { + bad_usage "repeated --export" + exit 1 + } + IFS=, read -r -a exports <<<"$2" + shift + ;; + *) + test -z "$path" || { + bad_usage "repeated path" + exit 1 + } + path="$1" + ;; + esac + shift +done + +eval_and_or_source_then_send_environment "$stdinval" "$path" "${exports[@]}" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ded335a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,300 @@ +#![doc = include_str!("../README.md")] +use anyhow::{anyhow, Context}; +use nu_plugin::{ + serve_plugin, EngineInterface, EvaluatedCall, JsonSerializer, Plugin, PluginCommand, +}; +use nu_protocol::{ + Category, IntoPipelineData, LabeledError, PipelineData, Record, Signature, Span, SyntaxShape, + Type, Value, +}; +use once_cell::sync::OnceCell; +use rust_embed::Embed; +use serde::{Deserialize, Serialize}; +use shellexpand::tilde; +use std::{ + env, fs, + io::Write, + os::unix::fs::PermissionsExt, + path::{Path, PathBuf}, +}; +use subprocess::{Popen, PopenConfig}; +use tempfile::TempDir; +use tracing::{debug, info, trace}; +use tracing_subscriber::EnvFilter; + +struct BashEnvPlugin; + +impl Plugin for BashEnvPlugin { + fn commands(&self) -> Vec>> { + vec![Box::new(BashEnv)] + } + + fn version(&self) -> String { + env!("CARGO_PKG_VERSION").to_string() + } +} + +struct BashEnv; + +impl PluginCommand for BashEnv { + type Plugin = BashEnvPlugin; + + fn name(&self) -> &str { + "bash-env" + } + + fn usage(&self) -> &str { + "get environment variables from Bash format file and/or stdin" + } + + fn signature(&self) -> Signature { + Signature::build(PluginCommand::name(self)) + .usage("get environment variables from Bash format file and/or stdin") + .category(Category::Env) + .optional("path", SyntaxShape::String, "path to environment file") + .named( + "export", + SyntaxShape::List(Box::new(SyntaxShape::String)), + "shell variables to export", + None, + ) + .input_output_types(vec![(Type::Nothing, Type::Any), (Type::String, Type::Any)]) + .filter() + .allow_variants_without_examples(true) + } + + fn run( + &self, + _plugin: &Self::Plugin, + engine: &EngineInterface, + call: &EvaluatedCall, + input: nu_protocol::PipelineData, + ) -> std::result::Result { + let cwd = engine.get_current_dir()?; + + let span = input.span(); + let path = match call.positional.first() { + Some(value @ Value::String { val: path, .. }) => { + let path = PathBuf::from(tilde(path).into_owned()); + let abs_path = Path::new(&cwd).join(&path); + if abs_path.exists() { + Some(path.into_os_string().into_string().unwrap()) + } else { + Err(create_error( + format!("no such file {:?}", path), + value.span(), + ))? + } + } + None => None, + Some(value) => Err(create_error( + format!("positional requires string; got {}", value.get_type()), + value.span(), + ))?, + }; + + let export = call + .named + .iter() + .filter(|&(name, _value)| (name.item == "export")) + .map(|(_name, value)| { + if let Some(Value::List { vals, .. }) = value { + vals.iter() + .filter_map(|value| { + if let Value::String { val, .. } = value { + Some(val.clone()) + } else { + None + } + }) + .collect::>() + } else { + Vec::default() + } + }) + .next() + .unwrap_or_default(); + + trace!("PipelineData {:?}", &input); + let stdin = match input { + // TODO: pipe the stream into the subprocess rather than via a string + PipelineData::ByteStream(bytes, _metadata) => Some(bytes.into_string()?), + PipelineData::Value(Value::String { val: stdin, .. }, _metadata) => Some(stdin), + _ => None, + }; + + trace!( + "path={:?} stdin={:?} export={:?} cwd={:?}", + &path, + &stdin, + &export, + &cwd + ); + + bash_env( + span.unwrap_or(Span::unknown()), + call.head, + stdin, + path, + export, + cwd, + ) + .map(|value| value.into_pipeline_data()) + .map_err(|e| { + LabeledError::new(e.to_string()).with_label("bash-env", span.unwrap_or(Span::unknown())) + }) + } +} + +fn bash_env( + input_span: Span, + creation_site_span: Span, + stdin: Option, + path: Option, + export: Vec, + cwd: String, +) -> anyhow::Result { + let script_path = bash_env_script_path(); + let mut argv: Vec<_> = [script_path].into(); + if stdin.is_some() { + argv.push("--stdin"); + } + if let Some(ref path) = path { + argv.push(path.as_str()); + } + let exports = + itertools::Itertools::intersperse(export.into_iter(), ",".to_string()).collect::(); + argv.push("--export"); + argv.push(exports.as_str()); + + trace!("Popen::create({:?})", &argv); + + let mut p = Popen::create( + argv.as_slice(), + PopenConfig { + stdin: if stdin.is_some() { + subprocess::Redirection::Pipe + } else { + subprocess::Redirection::None + }, + stdout: subprocess::Redirection::Pipe, + cwd: Some(cwd.into()), + ..Default::default() + }, + ) + .with_context(|| format!("Popen::create({})", script_path))?; + + let (out, err) = p + .communicate(stdin.as_deref()) + .with_context(|| "Popen::communicate()")?; + if let Some(err) = err { + std::io::stderr() + .write_all(err.as_bytes()) + .with_context(|| "stderr.write_all()")?; + } + + match serde_json::from_str(out.as_ref().unwrap()) + .with_context(|| "serde_json::from_reader()")? + { + BashEnvResult::Env(env) => Ok(create_record(env, input_span, creation_site_span)), + BashEnvResult::Error(msg) => Err(anyhow!(msg)), + } +} + +fn create_record(env: Vec, input_span: Span, creation_site_span: Span) -> Value { + let cols = env.iter().map(|kv| kv.k.clone()).collect::>(); + let vals = env + .iter() + .map(|kv| Value::string(kv.v.clone(), Span::unknown())) + .collect::>(); + Value::record( + Record::from_raw_cols_vals(cols, vals, input_span, creation_site_span).unwrap(), + input_span, + ) +} + +#[derive(Serialize, Deserialize)] +enum BashEnvResult { + Env(Vec), + Error(String), +} + +#[derive(Serialize, Deserialize)] +struct KV { + k: String, + v: String, +} + +fn create_error(msg: S, creation_site_span: Span) -> LabeledError +where + S: Into, +{ + LabeledError::new(msg).with_label("bash-env", creation_site_span) +} + +fn main() { + let subscriber = tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_env("NU_PLUGIN_BASH_ENV_LOG")) + .finish(); + tracing::subscriber::set_global_default(subscriber) + .expect("failed to setup tracing subscriber"); + + debug!("starting"); + + // prefer to take the path from the environment variable, falling back to writing a temporary file + // with contents taken from the embedded script + let script_path_env_var = "NU_PLUGIN_BASH_ENV_SCRIPT"; + let script_path_from_env = env::var(script_path_env_var).ok(); + #[allow(unused_assignments)] + let mut tempdir: Option = None; + + let script_path = match script_path_from_env { + Some(path) => { + debug!("using {} from {}", &path, script_path_env_var); + path + } + None => { + tempdir = Some(TempDir::new().expect("failed to create tempdir for bash script")); + extract_embedded_script(tempdir.as_ref().unwrap()) + } + }; + + BASH_ENV_SCRIPT_PATH.get_or_init(|| script_path); + + serve_plugin(&BashEnvPlugin, JsonSerializer); + + if let Some(tempdir) = tempdir { + info!("removing {:?}", tempdir.path()); + } + + debug!("exiting"); +} + +fn extract_embedded_script(tempdir: &TempDir) -> String { + let script = "bash_env.sh"; + let path = tempdir.path().join(script).to_path_buf(); + fs::write(&path, Scripts::get(script).unwrap().data.as_ref()).unwrap(); + + // make executable + let mut perms = fs::metadata(&path) + .unwrap_or_else(|e| panic!("metadata({:?}): {}", &path, e)) + .permissions(); + perms.set_mode(0o755); + fs::set_permissions(&path, perms) + .unwrap_or_else(|e| panic!("set_permissions({:?}): {}", &path, e)); + + let path = path.into_os_string().into_string().unwrap(); + info!("extracted {} into {}", script, &path); + path +} + +fn bash_env_script_path() -> &'static str { + BASH_ENV_SCRIPT_PATH.get().unwrap() +} + +static BASH_ENV_SCRIPT_PATH: OnceCell = OnceCell::new(); + +// embed the bash script +#[derive(Embed)] +#[folder = "scripts"] +struct Scripts;