nushell / nushell

A new type of shell
https://www.nushell.sh/
MIT License
31.63k stars 1.62k forks source link

Lua doesn't read environment variables correctly #12856

Closed rayanamal closed 4 months ago

rayanamal commented 4 months ago

Describe the bug

Lua doesn't read environment variables LUA_PATH and LUA_CPATH correctly from nushell while it reads them when run under bash, in the exact same environment. These variables are needed for lua to find packages installed via luarocks lua package manager.

How to reproduce

~> bash 05/13/2024 06:30:35 PM username@textadept:~$ eval $(luarocks path) username@textadept:~$ echo $LUA_PATH /usr/local/share/lua/5.4/?.lua;/usr/local/share/lua/5.4/?/init.lua;/usr/local/lib/lua/5.4/?.lua;/usr/local/lib/lua/5.4/?/init.lua;/usr/share/lua/5.4/?.lua;/usr/share/lua/5.4/?/init.lua;./?.lua;./?/init.lua;/home/username/.luarocks/share/lua/5.4/?.lua;/home/username/.luarocks/share/lua/5.4/?/init.lua username@textadept:~$ echo $LUA_CPATH /usr/local/lib/lua/5.4/?.so;/usr/lib/x86_64-linux-gnu/lua/5.4/?.so;/usr/lib/lua/5.4/?.so;/usr/local/lib/lua/5.4/loadall.so;./?.so;/home/username/.luarocks/lib/lua/5.4/?.so username@textadept:~$ lua Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio

print(package.path) /usr/local/share/lua/5.4/?.lua;/usr/local/share/lua/5.4/?/init.lua;/usr/local/lib/lua/5.4/?.lua;/usr/local/lib/lua/5.4/?/init.lua;/usr/share/lua/5.4/?.lua;/usr/share/lua/5.4/?/init.lua;./?.lua;./?/init.lua;/home/username/.luarocks/share/lua/5.4/?.lua;/home/username/.luarocks/share/lua/5.4/?/init.lua lpeg = require('lpeg') lpeg table: 0x555bb13572a0

Notice that package.path variable in Lua REPL when invoked from nushell vs when invoked from bash is not the same, even though environment variables for both shells are the same. When invoked from nushell, lua loads default variables and doesn't see the environment variable for some reason.

Expected behavior

The package.path output of Lua REPL shouldn't change when invoked from nushell, and lpeg module should be able to load without error as a result.

Configuration

key value
version 0.92.2
branch
commit_hash 2a08a18b26865a86c793d183b9b042220ecb733a
build_os linux-x86_64
build_target x86_64-unknown-linux-musl
rust_version rustc 1.77.2 (25ef9e3d8 2024-04-09)
rust_channel 1.77.2-x86_64-unknown-linux-gnu
cargo_version cargo 1.77.2 (e52e36006 2024-03-26)
build_time 2024-04-10 21:20:54 +00:00
build_rust_channel release
allocator mimalloc
features dataframe, default, sqlite, static-link-openssl, trash, which
installed_plugins

Additional context

fdncred commented 4 months ago

My guess is this could be because you have ? in some of your $env.LUA_PATH/CPATH and lua is expecting something to expand those illegal paths into "real" paths. Just a guess though.

rayanamal commented 4 months ago

No, this is not the case. I updated the issue with detailed information. You can see package.path variable in both LUA_REPLs include ? characters.

IanManske commented 4 months ago

I think you need to set an environment conversion to convert the environment variables from nushell values back into strings. https://www.nushell.sh/book/environment.html#environment-variable-conversions

rayanamal commented 4 months ago

Thank you, this was the culprit. The updated code to make it work:

env.nu:

$env.ENV_CONVERSIONS = {
    ...
    "LUA_PATH": {
        from_string: { |s| $s | split row ';' | path expand --no-symlink }
        to_string: { |v| $v | path expand --no-symlink | str join ';' }
    }
    "LUA_CPATH": {
        from_string: { |s| $s | split row ';' | path expand --no-symlink }
        to_string: { |v| $v | path expand --no-symlink | str join ';' }
    }
}

config.nu:

def --env load_luarocks_path_vars [] {
    def make_record [] { reduce -f {} {|it, acc| $acc| merge $it }}
    # 'luarocks path' command gives 3 bash export commands
    luarocks path | split row "\n" 
    | each {|cmd|
        let env_var = $cmd | parse "export {name}='{value}'"
        let var_name = $env_var.name.0
        # Assumption: multiple consecutive colon/semicolons in path string doesn't mean anything.
        let paths = $env_var.value.0 
        | split row -r ';+|:+' | each {{$in: true}} | make_record
        let old_value = $env 
        | get -i $var_name 
        | if $in == null {{}} else { split row -r ';+|:+' | each {{$in: true}} | make_record }
        let new_value = $old_value | merge $paths | columns
        {$var_name: $new_value}
    }
    | make_record
    | load-env
}

load_luarocks_path_vars

Is it possible to put this solution somewhere more permanent than Github issues? Idk whether there is a wiki or something. I just buried several hours on this issue (and learned the nu lang along the way ;) )

fdncred commented 4 months ago

Maybe a place for things like this is probably our cookbook.