Skip to content

Commit

Permalink
Module not plugin (#36)
Browse files Browse the repository at this point in the history
Deprecate the plugin in favour of a radically simpler module
implementation.
  • Loading branch information
tesujimath authored Oct 20, 2024
1 parent e1e410a commit 87a4ad9
Show file tree
Hide file tree
Showing 7 changed files with 332 additions and 24 deletions.
13 changes: 12 additions & 1 deletion .github/workflows/test-suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- main
env:
NU_VERSION: 0.99.0
BASH_ENV_JSON_VERSION: 0.7.0

jobs:
test:
Expand All @@ -29,8 +30,18 @@ jobs:
uses: dtolnay/rust-toolchain@stable
- name: Build
run: cargo build
- name: Run Tests
- name: Run Plugin Tests
run: |
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"
- name: Download bash-env-json $BASH_ENV_JSON_VERSION
run: |
curl -L https://github.com/tesujimath/bash-env-json/archive/refs/tags/${BASH_ENV_JSON_VERSION}.tar.gz | tar xzf -
- name: Run Module Tests
run: |
# note that Nushell doesn't like relative paths on the $PATH
export PATH=$(pwd)/bash-env-json-${BASH_ENV_JSON_VERSION}:./nu-${NU_VERSION}-x86_64-unknown-linux-gnu:$PATH
which bash-env-json
nu --no-config-file --no-history -c "use bash-env.nu ; use tests.nu run_bash_env_tests ; run_bash_env_tests"
nu --no-config-file --no-history -c "use bash-env.nu ; use extra-module-tests.nu ; extra-module-tests"
197 changes: 182 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,177 @@
# nu_plugin_bash_env
# Bash environment for Nushell

A Bash environment plugin for Nushell.
Historically Bash environment for Nushell was provided via the `nu_plugin_bash_env` plugin in this repo.

That plugin is now deprecated in favour of the `bash-env` module, which is more feature rich and also embarrassingly simpler than the plugin.

## bash-env module

### Examples

#### Simple Usage
```
> bash-env ./tests/simple.env
╭───┬───╮
│ B │ b │
│ A │ a │
╰───┴───╯
> echo $env.A
Error: nu::shell::column_not_found
× Cannot find column 'A'
╭─[entry #77:1:6]
1 │ echo $env.A
· ───┬──┬
· │ ╰── value originates here
· ╰── cannot find column 'A'
╰────
> bash-env ./tests/simple.env | load-env
> echo $env.A
a
> echo $env.B
b
> bash-env tests/simple.env
╭──────────────╮
│ empty record │
╰──────────────╯
# no new or changed environment variables, so nothing returned
> ssh-agent | bash-env
╭───────────────┬─────────────────────────────────────╮
│ SSH_AUTH_SOCK │ /tmp/ssh-XXXXXXOjZtSh/agent.1612713 │
│ SSH_AGENT_PID │ 1612715 │
╰───────────────┴─────────────────────────────────────╯
```

#### Shell Variables

Rather than folding shell variables in with the environment variables as was done by the plugin, the `-s` or `--shellvars` option results in structured output with separate `env` and `shellvars`.

```
> echo "ABC=123" | bash-env
╭──────────────╮
│ empty record │
╰──────────────╯
> echo "ABC=123" | bash-env -s
╭───────────┬───────────────────╮
│ env │ {record 0 fields} │
│ │ ╭─────┬─────╮ │
│ shellvars │ │ ABC │ 123 │ │
│ │ ╰─────┴─────╯ │
╰───────────┴───────────────────╯
> (echo "ABC=123" | bash-env -s).shellvars
╭─────┬─────╮
│ ABC │ 123 │
╰─────┴─────╯
> bash-env /etc/os-release
╭──────────────╮
│ empty record │
╰──────────────╯
> (bash-env /etc/os-release -s).shellvars
╭───────────────────┬─────────────────────────────────────────╮
│ LOGO │ nix-snowflake │
│ NAME │ NixOS │
│ BUG_REPORT_URL │ https://github.com/NixOS/nixpkgs/issues │
│ HOME_URL │ https://nixos.org/ │
│ VERSION_CODENAME │ vicuna │
│ ANSI_COLOR │ 1;34 │
│ ID │ nixos │
│ PRETTY_NAME │ NixOS 24.11 (Vicuna) │
│ DOCUMENTATION_URL │ https://nixos.org/learn.html │
│ SUPPORT_URL │ https://nixos.org/community.html │
│ IMAGE_ID │ │
│ VERSION_ID │ 24.11 │
│ VERSION │ 24.11 (Vicuna) │
│ IMAGE_VERSION │ │
│ BUILD_ID │ 24.11.20240916.99dc878 │
╰───────────────────┴─────────────────────────────────────────╯
```

### Shell Functions

Shell functions may be run and their effect on the environment captured.

```
> cat ./tests/shell-functions.env
export A=1
export B=1
function f2() {
export A=2
export B=2
C2="I am shell variable C2"
}
function f3() {
export A=3
export B=3
C3="I am shell variable C3"
}
> bash-env ./tests/shell-functions.env
╭───┬───╮
│ B │ 1 │
│ A │ 1 │
╰───┴───╯
> bash-env -f [f2 f3] ./tests/shell-functions.env
╭───────────┬──────────────────────────────────────────────────────────╮
│ │ ╭───┬───╮ │
│ env │ │ B │ 1 │ │
│ │ │ A │ 1 │ │
│ │ ╰───┴───╯ │
│ shellvars │ {record 0 fields} │
│ │ ╭────┬─────────────────────────────────────────────────╮ │
│ fn │ │ │ ╭───────────┬─────────────────────────────────╮ │ │
│ │ │ f2 │ │ │ ╭───┬───╮ │ │ │
│ │ │ │ │ env │ │ B │ 2 │ │ │ │
│ │ │ │ │ │ │ A │ 2 │ │ │ │
│ │ │ │ │ │ ╰───┴───╯ │ │ │
│ │ │ │ │ │ ╭────┬────────────────────────╮ │ │ │
│ │ │ │ │ shellvars │ │ C2 │ I am shell variable C2 │ │ │ │
│ │ │ │ │ │ ╰────┴────────────────────────╯ │ │ │
│ │ │ │ ╰───────────┴─────────────────────────────────╯ │ │
│ │ │ │ ╭───────────┬─────────────────────────────────╮ │ │
│ │ │ f3 │ │ │ ╭───┬───╮ │ │ │
│ │ │ │ │ env │ │ B │ 3 │ │ │ │
│ │ │ │ │ │ │ A │ 3 │ │ │ │
│ │ │ │ │ │ ╰───┴───╯ │ │ │
│ │ │ │ │ │ ╭────┬────────────────────────╮ │ │ │
│ │ │ │ │ shellvars │ │ C3 │ I am shell variable C3 │ │ │ │
│ │ │ │ │ │ ╰────┴────────────────────────╯ │ │ │
│ │ │ │ ╰───────────┴─────────────────────────────────╯ │ │
│ │ ╰────┴─────────────────────────────────────────────────╯ │
╰───────────┴──────────────────────────────────────────────────────────╯
> (bash-env -f [f2 f3] ./tests/shell-functions.env).fn.f2.env
╭───┬───╮
│ B │ 2 │
│ A │ 2 │
╰───┴───╯
> (bash-env -f [f2 f3] ./tests/shell-functions.env).fn.f2.env | load-env
> echo $env.B
2
```

### Installation

Download the module, and add to `config.nu`:

```
use /path/to/bash-env.nu
```

In contrast to the plugin, the module requires [`bash-env-json`](https://github.com/tesujimath/bash-env-json) to be separately downloaded and installed as an executable on the `$PATH`.

## nu_plugin_bash_env (deprecated)

The plugin is unlikely to be maintained beyond the next plugin protocol change in Nushell. It is recommended to switch to the `bash-env` module instead.

For instructions on how to use this plugin, see the [Nushell book](https://www.nushell.sh/book/plugins.html).

Expand All @@ -10,7 +181,7 @@ 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`.

## Plugin Version Compatability
### Plugin Version Compatability

Since Nushell 0.91.0 the plugin protocol was enhanced and now requires version compatability between plugins and Nushell itself.

Expand All @@ -34,17 +205,17 @@ The following versions are compatible.

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
### Dependencies

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`.

Since version `0.15.0`, this plugin uses [`bash-env-json`](https://github.com/tesujimath/bash-env-json) instead of the previously bundled `bash_env.sh` script. However, this is fetched and embedded at build time, so there is no difference at runtime.

## Examples
### Examples

### Simple Usage
#### Simple Usage
```
> bash-env tests/simple.env
╭───┬───╮
Expand Down Expand Up @@ -81,7 +252,7 @@ Agent pid 98985
╰───────────────┴───────────────────────────────────╯
```

### Exporting Shell Variables
#### Exporting Shell Variables

The plugin supports `--export` for exporting shell variables into the environment.

Expand Down Expand Up @@ -113,7 +284,7 @@ The plugin supports `--export` for exporting shell variables into the environmen
╰─────────────┴──────────────────────╯
```

### Escaping Special Characters
#### Escaping Special Characters

Care has been taken to escape any special characters.

Expand All @@ -130,28 +301,24 @@ Care has been taken to escape any special characters.
"Well done!" is better than "Well said!"
```

## Implementation
### 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_JSON` environment variable, which is then expected to resolve to the path of the pre-installed script.

## Logging
### Logging

Logging is supported via the Rust `tracing-subscriber` crate, with log-level defined by the environment variable `NU_PLUGIN_BASH_ENV_LOG`.

## Nix flake

The plugin is installable from its flake using Nix Home Manager.
Both the module and the plugin are installable from its flake using Nix Home Manager.

See my own [Home Manager flake](https://github.com/tesujimath/home.nix/blob/main/flake.nix#L12) and [nushell module](https://github.com/tesujimath/home.nix/blob/main/modules/nushell/default.nix) for hints how to achieve this. Note in particular the requirement for [each-time plugin registration](https://github.com/tesujimath/home.nix/blob/main/modules/nushell/config.nu#L761).

## Notes

All local variables in the script are prefixed with underscore, in an attempt to mitigate Bash's inability to distinguish variables local to the shell and environment variables, but this is by no means bulletproof.

## Future work

- unsetting an environment variable ought to be possible
35 changes: 35 additions & 0 deletions bash-env.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export def main [
path?: string
--export: list
--shellvars (-s)
--fn (-f): list
] {
let fn_args = if ($fn | is-not-empty) {
['--shellfns' ($fn | str join ',')]
} else {
[]
}

let path_args = if $path != null {
[($path | path expand)]
} else {
[]
}

let raw = ($in | str join "\n") | bash-env-json ...($fn_args ++ $path_args) | from json

let error = $raw | get -i error
if $error != null {
error make { msg: $error }
}

if ($export | is-not-empty) {
print "warning: --export is deprecated, use --shellvars(-s) instead"
let exported_shellvars = ($raw.shellvars | select -i ...$export)
$raw.env | merge ($exported_shellvars)
} else if $shellvars or ($fn | is-not-empty) {
$raw
} else {
$raw.env
}
}
59 changes: 59 additions & 0 deletions extra-module-tests.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std assert

# TODO use testing.nu testing module,
# which wasn't working at the time I wrote these tests

#[test]
def test_shell_variables [] {
let actual = (echo "A=123" | bash-env -s).shellvars
let expected = { A: "123" }
assert equal $actual $expected
}

#[test]
def test_shell_variables_from_file [] {
let actual = bash-env -s tests/shell-variables.env
let expected = { shellvars: { A: "not exported" } env: { B: "exported" } }
assert equal $actual $expected
}

#[test]
def test_shell_functions [] {
let actual = bash-env -f [f2 f3] tests/shell-functions.env
let expected = {
"env": {
"B": "1",
"A": "1"
},
"shellvars": {},
"fn": {
"f2": {
"env": {
"B": "2",
"A": "2"
},
"shellvars": {
"C2": "I am shell variable C2"
}
},
"f3": {
"env": {
"B": "3",
"A": "3"
},
"shellvars": {
"C3": "I am shell variable C3"
}
}
}
}
assert equal $actual $expected
}

export def main [] {
test_shell_variables
test_shell_variables_from_file
test_shell_functions

print "All tests passed"
}
Loading

0 comments on commit 87a4ad9

Please sign in to comment.