sdkman / sdkman-cli

The SDKMAN! Command Line Interface
https://sdkman.io
Apache License 2.0
6.15k stars 631 forks source link

Bug: Variables set in ~/.bashrc are not available by default to programs started from a GUI in a desktop sessions for Ubuntu/Linux Mint #1312

Closed NoPhaseNoKill closed 2 months ago

NoPhaseNoKill commented 2 months ago

Bug report

For Linux Mint, or Ubuntu derivatives, sdkman configures itself into the .bashrc file. This causes issues when opening .desktop entries which are reliant on the JAVA_HOME environment variable, as any applications opened through a GUI, will not have the environment variables set in any of ~/.bashrc, ~/.bash_profile or ~/.bash_login. This causes extremely hard to diagnose bugs, and more often than not, will not present as a 'bug' - but will appear as though IDE's aren't picking up the configuration correctly. Having said that, it absolutely is a bug with sdkman IMO - as I would have expected that out of the box regardless of how I invoke an application (GUI or otherwise) - the expectation is that it will manage my JAVA_HOME environment variable correctly.

Taken from: https://help.ubuntu.com/community/EnvironmentVariables

"Shell config files such as ~/.bashrc, ~/.bash_profile, and ~/.bash_login are often suggested for setting environment variables. While this may work on Bash shells for programs started from the shell, variables set in those files are not available by default to programs started from the graphical environment in a desktop session."

To reproduce

  1. Install .sdkman on Linux Mint 22 Cinnamon
  2. Confirm that the below has been appended to the ~/.bashrc file:
# SDKMAN configuration for setting JAVA_HOME
export SDKMAN_DIR="$HOME/.sdkman"
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"
  1. Install any java 21 version, aka: sdk install java 21.0.4-ms

  2. Confirm that we are using current, aka: 'sdk current' which should print:

sdk current

Using:
java: 21.0.4-ms
  1. Run echo ${JAVA_HOME} which should print something like:
echo $JAVA_HOME
${HOME}/.sdkman/candidates/java/current
  1. Confirm that current is pointed towards our installed 21 version. By running: 'ls -la ~/.sdkman/candidates/java' we should see something roughly like:
ls -la ~/.sdkman/candidates/java
drwxr-xr-x  9 gardo gardo 4096 Jul 17 04:12 21.0.4-ms
lrwxrwxrwx  1 gardo gardo   45 Sep 17 03:38 current -> /home/gardo/.sdkman/candidates/java/21.0.4-ms
  1. Checkout commit from this repo: https://github.com/NoPhaseNoKill/monorepo/commit/13f2e78f97186599dd6fdb2f23099d3dbf986b77 . This has a check during gradle's configuration found here: https://github.com/NoPhaseNoKill/monorepo/blob/master/toolset/build-logic/structural-plugins/src/main/kotlin/com/nophasenokill/ComponentPlugin.kt#L30 which will error if the environment variable JAVA_HOME cannot be found

  2. Install jetbrains toolbox

  3. Install a version of intellij

  4. From a terminal, open intellij from the path that the toolbox exposes:

${HOME}/.local/share/JetBrains/Toolbox/apps/intellij-idea-ultimate/bin/idea
  1. Once intellij opens, open the downloaded project at the commit previously posted, and go to the top right hand corner of the gradle section that intellij uses, and run the build

This should be successful to prove that our v21 java is working.

image

  1. Open a GUI that needs to be JAVA_HOME aware (aka intellij) through the desktop icon.

To do this, create a file in /usr/share/applications named: custom-intellij.desktop

An example desktop entry/file can be found here:

// custom-intellij.desktop
[Desktop Entry]
Name=IntelliJ - Custom - 2024.2.1
# Opens intellij with proper JAVA_HOME setup
Exec=/home/gardo/.local/share/JetBrains/Toolbox/apps/intellij-idea-ultimate/bin/idea
Version=1.0
Type=Application
Categories=Development;IDE;
Terminal=true
Icon=/home/gardo/.local/share/JetBrains/Toolbox/apps/intellij-idea-ultimate/bin/idea.svg
Comment=Gardo - Custom Launcher
StartupWMClass=jetbrains-idea
StartupNotify=true
  1. Open your new desktop icon, which SHOULD mimic the exact behaviour of opening intellij like we did before. Please note, that no matter how you configure the exec command (for instance with sh -c before the idea script being called), this will NOT work due to aforementioned bug.

image

  1. Try running the build again, and see error indicating JAVA_HOME could not be found.

  2. However, if we now move the code that sdkman put in our ~/.bashrc file, into our ~/.profile file , and re-open the exact same desktop file - you will see the build pass - due to the environment variable now being available as per ubuntu's spec.

Please note: You will need to logout after updating the ~/.profile file, as sourcing it is not guaranteed to work for this particular issue.

Further implications/questions of this:

What happens if the sdkman script lives in both bashrc and profile files? Will they become out of sync/run into timing issues? This is the current solution for me, but I'm just not sure if there's anything else I should be aware of. Because we effectively need it on the path (~/.bashrc does this), as well as inside of the ~/.profile file, otherwise you will run into either:

Please let me know if you require any further info. This was incredibly hard to diagnose, and the above is the result of months of troubleshooting and confusion.

Thanks a lot for the contribution to the space, we really do appreciate it, even if you don't hear the community say it often :)

System info

System: Kernel: 6.8.0-44-generic arch: x86_64 bits: 64 compiler: gcc v: 13.2.0 clocksource: tsc Desktop: Cinnamon v: 6.2.9 tk: GTK v: 3.24.41 wm: Muffin v: 6.2.0 vt: 7 dm: LightDM v: 1.30.0 Distro: Linux Mint 22 Wilma base: Ubuntu 24.04 noble Machine: Type: Desktop Mobo: ASUSTeK model: ROG STRIX Z370-G GAMING (WI-FI AC) v: Rev X.0x serial: part-nu: SKU uuid: UEFI: American Megatrends v: 0605 date: 12/01/2017 CPU: Info: 6-core model: Intel Core i7-8700K bits: 64 type: MT MCP smt: enabled arch: Coffee Lake rev: A cache: L1: 384 KiB L2: 1.5 MiB L3: 12 MiB Speed (MHz): avg: 2831 high: 3900 min/max: 800/4700 cores: 1: 3802 2: 3842 3: 800 4: 800 5: 3900 6: 800 7: 800 8: 3900 9: 3827 10: 3804 11: 3800 12: 3897 bogomips: 88796 Flags: avx avx2 ht lm nx pae sse sse2 sse3 sse4_1 sse4_2 ssse3 vmx Graphics: Device-1: NVIDIA GP102 [GeForce GTX 1080 Ti] vendor: ASUSTeK driver: nvidia v: 550.107.02 arch: Pascal pcie: speed: 5 GT/s lanes: 8 ports: active: none off: DP-1 empty: DP-2, DVI-D-1, HDMI-A-1, HDMI-A-2 bus-ID: 02:00.0 chip-ID: 10de:1b06 class-ID: 0300 Display: x11 server: X.Org v: 21.1.11 with: Xwayland v: 23.2.6 driver: X: loaded: nvidia unloaded: fbdev,modesetting,nouveau,vesa gpu: nvidia,nvidia-nvswitch display-ID: :0 screens: 1 Screen-1: 0 s-res: 3840x2160 s-dpi: 139 s-size: 702x400mm (27.64x15.75") s-diag: 808mm (31.81") Monitor-1: DP-0 res: 3840x2160 hz: 60 dpi: 138 size: 708x399mm (27.87x15.71") diag: 813mm (32") modes: N/A API: EGL v: 1.5 hw: drv: nvidia platforms: device: 0 drv: nvidia device: 2 drv: swrast gbm: drv: nvidia surfaceless: drv: nvidia x11: drv: nvidia inactive: wayland,device-1 API: OpenGL v: 4.6.0 compat-v: 4.5 vendor: nvidia mesa v: 550.107.02 glx-v: 1.4 direct-render: yes renderer: NVIDIA GeForce GTX 1080 Ti/PCIe/SSE2 Audio: Device-1: Intel 200 Series PCH HD Audio vendor: ASUSTeK driver: snd_hda_intel v: kernel bus-ID: 00:1f.3 chip-ID: 8086:a2f0 class-ID: 0403 Device-2: NVIDIA GP102 HDMI Audio vendor: ASUSTeK driver: snd_hda_intel v: kernel pcie: speed: 8 GT/s lanes: 8 bus-ID: 02:00.1 chip-ID: 10de:10ef class-ID: 0403 Device-3: Razer USA Seiren driver: hid-generic,snd-usb-audio,usbhid type: USB rev: 2.0 speed: 480 Mb/s lanes: 1 bus-ID: 1-1:2 chip-ID: 1532:0503 class-ID: 0300 serial: API: ALSA v: k6.8.0-44-generic status: kernel-api Server-1: PipeWire v: 1.0.5 status: active with: 1: pipewire-pulse status: active 2: wireplumber status: active 3: pipewire-alsa type: plugin Network: Device-1: Intel Ethernet I219-V vendor: ASUSTeK driver: e1000e v: kernel port: N/A bus-ID: 00:1f.6 chip-ID: 8086:15b8 class-ID: 0200 IF: enp0s31f6 state: up speed: 1000 Mbps duplex: full mac: Device-2: Realtek RTL8822BE 802.11a/b/g/n/ac WiFi adapter vendor: ASUSTeK driver: rtw_8822be v: N/A pcie: speed: 2.5 GT/s lanes: 1 port: d000 bus-ID: 05:00.0 chip-ID: 10ec:b822 class-ID: 0280 IF: wlp5s0 state: down mac: Bluetooth: Device-1: ASUSTek Bluetooth Radio driver: btusb v: 0.8 type: USB rev: 1.1 speed: 12 Mb/s lanes: 1 bus-ID: 1-7:4 chip-ID: 0b05:185c class-ID: e001 serial: Report: hciconfig ID: hci0 rfk-id: 0 state: up address: bt-v: 4.2 lmp-v: 8 sub-v: 705c hci-v: 8 rev: ab6b class-ID: 7c0104 Drives: Local Storage: total: 1.36 TiB used: 53.34 GiB (3.8%) ID-1: /dev/sda vendor: Samsung model: SSD 850 EVO 500GB size: 465.76 GiB speed: 6.0 Gb/s tech: SSD serial: fw-rev: 2B6Q scheme: GPT ID-2: /dev/sdb vendor: Samsung model: SSD 860 EVO 1TB size: 931.51 GiB speed: 6.0 Gb/s tech: SSD serial: fw-rev: 4B6Q scheme: GPT Partition: ID-1: / size: 456.89 GiB used: 53.33 GiB (11.7%) fs: ext4 dev: /dev/sda2 ID-2: /boot/efi size: 511 MiB used: 6.1 MiB (1.2%) fs: vfat dev: /dev/sda1 Swap: ID-1: swap-1 type: file size: 2 GiB used: 0 KiB (0.0%) priority: -2 file: /swapfile USB: Hub-1: 1-0:1 info: hi-speed hub with single TT ports: 16 rev: 2.0 speed: 480 Mb/s lanes: 1 chip-ID: 1d6b:0002 class-ID: 0900 Device-1: 1-1:2 info: Razer USA Seiren type: audio,HID driver: hid-generic,snd-usb-audio,usbhid interfaces: 4 rev: 2.0 speed: 480 Mb/s lanes: 1 power: 500mA chip-ID: 1532:0503 class-ID: 0300 serial: Device-2: 1-2:3 info: Razer USA RZ01-0321 Gaming Mouse [DeathAdder V2] type: mouse,keyboard driver: hid-generic,usbhid interfaces: 4 rev: 2.0 speed: 12 Mb/s lanes: 1 power: 500mA chip-ID: 1532:0084 class-ID: 0300 Device-3: 1-7:4 info: ASUSTek Bluetooth Radio type: bluetooth driver: btusb interfaces: 2 rev: 1.1 speed: 12 Mb/s lanes: 1 power: 500mA chip-ID: 0b05:185c class-ID: e001 serial: Device-4: 1-10:5 info: Corsair Vengeance K70RGB keyboard type: keyboard,HID driver: hid-generic,usbhid interfaces: 4 rev: 2.0 speed: 12 Mb/s lanes: 1 power: 500mA chip-ID: 1b1c:1b13 class-ID: 0300 serial: Hub-2: 2-0:1 info: super-speed hub ports: 10 rev: 3.0 speed: 5 Gb/s lanes: 1 chip-ID: 1d6b:0003 class-ID: 0900 Hub-3: 3-0:1 info: hi-speed hub with single TT ports: 2 rev: 2.0 speed: 480 Mb/s lanes: 1 chip-ID: 1d6b:0002 class-ID: 0900 Hub-4: 4-0:1 info: super-speed hub ports: 2 rev: 3.1 speed: 10 Gb/s lanes: 1 chip-ID: 1d6b:0003 class-ID: 0900 Sensors: System Temperatures: cpu: 29.0 C mobo: N/A gpu: nvidia temp: 49 C Fan Speeds (rpm): N/A gpu: nvidia fan: 0% Repos: Packages: pm: dpkg pkgs: 2246 No active apt repos in: /etc/apt/sources.list Active apt repos in: /etc/apt/sources.list.d/docker.list 1: deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https: //download.docker.com/linux/ubuntu noble stable Active apt repos in: /etc/apt/sources.list.d/google-chrome.list 1: deb [arch=amd64] https: //dl.google.com/linux/chrome/deb/ stable main Active apt repos in: /etc/apt/sources.list.d/official-package-repositories.list 1: deb http: //packages.linuxmint.com wilma main upstream import backport 2: deb http: //mirror.aarnet.edu.au/pub/ubuntu/archive noble main restricted universe multiverse 3: deb http: //mirror.aarnet.edu.au/pub/ubuntu/archive noble-updates main restricted universe multiverse 4: deb http: //mirror.aarnet.edu.au/pub/ubuntu/archive noble-backports main restricted universe multiverse 5: deb http: //security.ubuntu.com/ubuntu/ noble-security main restricted universe multiverse Info: Memory: total: 64 GiB note: est. available: 62.73 GiB used: 10.27 GiB (16.4%) Processes: 340 Power: uptime: 2h 8m states: freeze,mem,disk suspend: deep wakeups: 0 hibernate: platform Init: systemd v: 255 target: graphical (5) default: graphical Compilers: gcc: 13.2.0 Client: Unknown python3.12 client inxi: 3.3.34

helpermethod commented 2 months ago

Hi @NoPhaseNoKill!

Wouldn't sourcing .bashrc from .profile solve the issue?

It's actually a common practice, and some dists even do this by default.

NoPhaseNoKill commented 2 months ago

@helpermethod My assumption is that your comment of 'sourcing .bashrc from .profile' would mean the equivalent of first section below, which forms a part of the default, Linux Mint ~/.profile file. However, if that were to be the case, I would have never faced the issue in the first place. So no, to my knowledge this would not fix the issue.

If you meant something else by that though, please let me know and I apologise for the misunderstanding.

# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
    PATH="$HOME/.local/bin:$PATH"
fi
NoPhaseNoKill commented 2 months ago

edit: To be clear, I also know how to fix the immediate issue (which helpermethods comment suggested I didn't). The main issue I have is SDKman should be managing this for me. Taken from your website: "Simplifying life. No more hunting for downloads, extracting archives, or tinkering with HOME and PATH environment variables." This implicitly includes the scenario where I want to open a graphical program that is reliant on JAVA_HOME (aka a desktop entry of intellij).

The fact that the first response was to suggest that I source my .bashrc from .profile, suggests two things:

  1. You acknowledge it is a bug
  2. This is a design flaw, and you're putting the onus on the user to manage this (which goes against the website text linked above) So while I can fix it, the original post was more letting you know I think it's a bug, and to also try and work together for a fix.

This type of thing can show in incredibly obscure ways (this originally reared it's head as a gradle invalidation of caching issue, which was then traced back to this after a fair amount of head scratching), and I would imagine would be affecting a reasonable amount of users, who are completely unaware of issues/implications.

end-edit

For more context and to help troubleshoot, please see the attached files I am using.

It includes examples of:

  1. Trying to run 'source ~/.bashrc' and '. ~/.bashrc' in the exec command of the desktop icon. It outputs the JAVA_HOME before and after each of these steps (before anything, after 'source ~/.bashrc', and after '. ~/.bashrc')
  2. Trying to run 'source ~/.profile' and '. ~/.profile' in the exec command of the desktop icon. It outputs the JAVA_HOME before and after each of these steps (before anything, after 'source ~/.profile', and after '. ~/.profile')
  3. All of the desktop files being used with each exec included. These are being put into my /usr/share/applications folder, and run from my start menu. But I have also tried running them outside of this with the exact same result
  4. My ~/.bashrc file with sdkman
  5. My ~/.profile file
  6. It also includes an example of whether the normal exec desktop entry is running in interactive or non-inteactive mode (in case it helps with playing around/testing things)

When your ~/.profile command does NOT have the ~/.bashrc, both attempts to source either the ~/.profile or the ~/.bashrc from within the executed .sh file from the desktop entry return:

#### START EXAMPLE DESKTOP SHORTCUT EXAMPLE ####
JAVA_HOME before sourcing happened: 
JAVA_HOME after sourcing using 'source' happaned: 
JAVA_HOME after sourcing using '.' happened: 
Should showcase the downfall with not including sdkman init script in $HOME/.profile
    JAVA_HOME before sourcing happened: 
    JAVA_HOME after sourcing with source keyword happened: 
    JAVA_HOME after sourcing with dot notation happened: 
Sleeping for 10s so we can grasp the issue

However, as soon as you uncomment the sdkman section from my ~/.profile file, log out, and log back (this is an important step), I get:

#### START EXAMPLE DESKTOP SHORTCUT EXAMPLE ####
JAVA_HOME before sourcing happened: $HOME/.sdkman/candidates/java/current
JAVA_HOME after sourcing using 'source' happaned: $HOME/.sdkman/candidates/java/current
JAVA_HOME after sourcing using '.' happened: $HOME/.sdkman/candidates/java/current
Should showcase the downfall with not including sdkman init script in $HOME/.profile
    JAVA_HOME before sourcing happened: $HOME/.sdkman/candidates/java/current
    JAVA_HOME after sourcing with source keyword happened: $HOME/.sdkman/candidates/java/current
    JAVA_HOME after sourcing with dot notation happened: $HOME/.sdkman/candidates/java/current
Sleeping for 10s so we can grasp the issue

shell-test.zip

marc0der commented 2 months ago

Hi @NoPhaseNoKill,

The fact that the first response was to suggest that I source my .bashrc from .profile, suggests two things:

  1. You acknowledge it is a bug
  2. This is a design flaw, and you're putting the onus on the user to manage this (which goes against the website text linked above) So while I can fix it, the original post was more letting you know I think it's a bug, and to also try and work together for a fix.

Firstly, I don't really like the tone of the above. Also, @helpermethod was trying to help you, so please be mindful and respectful of how he assisted you. Also, the two assumptions that you made above are incorrect.

Firstly, it's not a bug. Secondly, this is not a design flaw but my express intent when I wrote the tool. SDKMAN is a CLI tool. It's not intended to manage environment variables for your DE but to manage shell environments. If you want to set the environment variables for your DE, the workaround is easy as @helpermethod suggests.

In future, please talk to us in our Discord help channel as per the contributing guidelines before opening an issue here.